001 package net.minecraft.client.renderer;
002
003 import cpw.mods.fml.relauncher.Side;
004 import cpw.mods.fml.relauncher.SideOnly;
005 import java.util.ArrayList;
006 import java.util.HashSet;
007 import java.util.List;
008 import net.minecraft.block.Block;
009 import net.minecraft.client.renderer.culling.ICamera;
010 import net.minecraft.client.renderer.entity.RenderItem;
011 import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
012 import net.minecraft.entity.Entity;
013 import net.minecraft.tileentity.TileEntity;
014 import net.minecraft.util.AxisAlignedBB;
015 import net.minecraft.world.ChunkCache;
016 import net.minecraft.world.World;
017 import net.minecraft.world.chunk.Chunk;
018 import org.lwjgl.opengl.GL11;
019
020 import net.minecraftforge.client.ForgeHooksClient;
021
022 @SideOnly(Side.CLIENT)
023 public class WorldRenderer
024 {
025 /** Reference to the World object. */
026 public World worldObj;
027 private int glRenderList = -1;
028 //private static Tessellator tessellator = Tessellator.instance;
029 public static int chunksUpdated = 0;
030 public int posX;
031 public int posY;
032 public int posZ;
033
034 /** Pos X minus */
035 public int posXMinus;
036
037 /** Pos Y minus */
038 public int posYMinus;
039
040 /** Pos Z minus */
041 public int posZMinus;
042
043 /** Pos X clipped */
044 public int posXClip;
045
046 /** Pos Y clipped */
047 public int posYClip;
048
049 /** Pos Z clipped */
050 public int posZClip;
051 public boolean isInFrustum = false;
052
053 /** Should this renderer skip this render pass */
054 public boolean[] skipRenderPass = new boolean[2];
055
056 /** Pos X plus */
057 public int posXPlus;
058
059 /** Pos Y plus */
060 public int posYPlus;
061
062 /** Pos Z plus */
063 public int posZPlus;
064
065 /** Boolean for whether this renderer needs to be updated or not */
066 public boolean needsUpdate;
067
068 /** Axis aligned bounding box */
069 public AxisAlignedBB rendererBoundingBox;
070
071 /** Chunk index */
072 public int chunkIndex;
073
074 /** Is this renderer visible according to the occlusion query */
075 public boolean isVisible = true;
076
077 /** Is this renderer waiting on the result of the occlusion query */
078 public boolean isWaitingOnOcclusionQuery;
079
080 /** OpenGL occlusion query */
081 public int glOcclusionQuery;
082
083 /** Is the chunk lit */
084 public boolean isChunkLit;
085 private boolean isInitialized = false;
086
087 /** All the tile entities that have special rendering code for this chunk */
088 public List tileEntityRenderers = new ArrayList();
089 private List tileEntities;
090
091 /** Bytes sent to the GPU */
092 private int bytesDrawn;
093
094 public WorldRenderer(World par1World, List par2List, int par3, int par4, int par5, int par6)
095 {
096 this.worldObj = par1World;
097 this.tileEntities = par2List;
098 this.glRenderList = par6;
099 this.posX = -999;
100 this.setPosition(par3, par4, par5);
101 this.needsUpdate = false;
102 }
103
104 /**
105 * Sets a new position for the renderer and setting it up so it can be reloaded with the new data for that position
106 */
107 public void setPosition(int par1, int par2, int par3)
108 {
109 if (par1 != this.posX || par2 != this.posY || par3 != this.posZ)
110 {
111 this.setDontDraw();
112 this.posX = par1;
113 this.posY = par2;
114 this.posZ = par3;
115 this.posXPlus = par1 + 8;
116 this.posYPlus = par2 + 8;
117 this.posZPlus = par3 + 8;
118 this.posXClip = par1 & 1023;
119 this.posYClip = par2;
120 this.posZClip = par3 & 1023;
121 this.posXMinus = par1 - this.posXClip;
122 this.posYMinus = par2 - this.posYClip;
123 this.posZMinus = par3 - this.posZClip;
124 float var4 = 6.0F;
125 this.rendererBoundingBox = AxisAlignedBB.getBoundingBox((double)((float)par1 - var4), (double)((float)par2 - var4), (double)((float)par3 - var4), (double)((float)(par1 + 16) + var4), (double)((float)(par2 + 16) + var4), (double)((float)(par3 + 16) + var4));
126 GL11.glNewList(this.glRenderList + 2, GL11.GL_COMPILE);
127 RenderItem.renderAABB(AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)((float)this.posXClip - var4), (double)((float)this.posYClip - var4), (double)((float)this.posZClip - var4), (double)((float)(this.posXClip + 16) + var4), (double)((float)(this.posYClip + 16) + var4), (double)((float)(this.posZClip + 16) + var4)));
128 GL11.glEndList();
129 this.markDirty();
130 }
131 }
132
133 private void setupGLTranslation()
134 {
135 GL11.glTranslatef((float)this.posXClip, (float)this.posYClip, (float)this.posZClip);
136 }
137
138 /**
139 * Will update this chunk renderer
140 */
141 public void updateRenderer()
142 {
143 if (this.needsUpdate)
144 {
145 this.needsUpdate = false;
146 int var1 = this.posX;
147 int var2 = this.posY;
148 int var3 = this.posZ;
149 int var4 = this.posX + 16;
150 int var5 = this.posY + 16;
151 int var6 = this.posZ + 16;
152
153 for (int var7 = 0; var7 < 2; ++var7)
154 {
155 this.skipRenderPass[var7] = true;
156 }
157
158 Chunk.isLit = false;
159 HashSet var21 = new HashSet();
160 var21.addAll(this.tileEntityRenderers);
161 this.tileEntityRenderers.clear();
162 byte var8 = 1;
163 ChunkCache var9 = new ChunkCache(this.worldObj, var1 - var8, var2 - var8, var3 - var8, var4 + var8, var5 + var8, var6 + var8);
164
165 if (!var9.extendedLevelsInChunkCache())
166 {
167 ++chunksUpdated;
168 RenderBlocks var10 = new RenderBlocks(var9);
169 this.bytesDrawn = 0;
170
171 for (int var11 = 0; var11 < 2; ++var11)
172 {
173 boolean var12 = false;
174 boolean var13 = false;
175 boolean var14 = false;
176
177 for (int var15 = var2; var15 < var5; ++var15)
178 {
179 for (int var16 = var3; var16 < var6; ++var16)
180 {
181 for (int var17 = var1; var17 < var4; ++var17)
182 {
183 int var18 = var9.getBlockId(var17, var15, var16);
184
185 if (var18 > 0)
186 {
187 if (!var14)
188 {
189 var14 = true;
190 GL11.glNewList(this.glRenderList + var11, GL11.GL_COMPILE);
191 GL11.glPushMatrix();
192 this.setupGLTranslation();
193 float var19 = 1.000001F;
194 GL11.glTranslatef(-8.0F, -8.0F, -8.0F);
195 GL11.glScalef(var19, var19, var19);
196 GL11.glTranslatef(8.0F, 8.0F, 8.0F);
197 ForgeHooksClient.beforeRenderPass(var11);
198 Tessellator.instance.startDrawingQuads();
199 Tessellator.instance.setTranslation((double)(-this.posX), (double)(-this.posY), (double)(-this.posZ));
200 }
201
202 Block var23 = Block.blocksList[var18];
203
204 if (var23 != null)
205 {
206 if (var11 == 0 && var23.hasTileEntity(var9.getBlockMetadata(var17, var15, var16)))
207 {
208 TileEntity var20 = var9.getBlockTileEntity(var17, var15, var16);
209
210 if (TileEntityRenderer.instance.hasSpecialRenderer(var20))
211 {
212 this.tileEntityRenderers.add(var20);
213 }
214 }
215
216 int var24 = var23.getRenderBlockPass();
217
218 if (var24 > var11)
219 {
220 var12 = true;
221 }
222 if (!var23.canRenderInPass(var11))
223 {
224 continue;
225 }
226 ForgeHooksClient.beforeBlockRender(var23, var10);
227 var13 |= var10.renderBlockByRenderType(var23, var17, var15, var16);
228 ForgeHooksClient.afterBlockRender(var23, var10);
229 }
230 }
231 }
232 }
233 }
234
235 if (var14)
236 {
237 ForgeHooksClient.afterRenderPass(var11);
238 this.bytesDrawn += Tessellator.instance.draw();
239 GL11.glPopMatrix();
240 GL11.glEndList();
241 Tessellator.instance.setTranslation(0.0D, 0.0D, 0.0D);
242 }
243 else
244 {
245 var13 = false;
246 }
247
248 if (var13)
249 {
250 this.skipRenderPass[var11] = false;
251 }
252
253 if (!var12)
254 {
255 break;
256 }
257 }
258 }
259
260 HashSet var22 = new HashSet();
261 var22.addAll(this.tileEntityRenderers);
262 var22.removeAll(var21);
263 this.tileEntities.addAll(var22);
264 var21.removeAll(this.tileEntityRenderers);
265 this.tileEntities.removeAll(var21);
266 this.isChunkLit = Chunk.isLit;
267 this.isInitialized = true;
268 }
269 }
270
271 /**
272 * Returns the distance of this chunk renderer to the entity without performing the final normalizing square root,
273 * for performance reasons.
274 */
275 public float distanceToEntitySquared(Entity par1Entity)
276 {
277 float var2 = (float)(par1Entity.posX - (double)this.posXPlus);
278 float var3 = (float)(par1Entity.posY - (double)this.posYPlus);
279 float var4 = (float)(par1Entity.posZ - (double)this.posZPlus);
280 return var2 * var2 + var3 * var3 + var4 * var4;
281 }
282
283 /**
284 * When called this renderer won't draw anymore until its gets initialized again
285 */
286 public void setDontDraw()
287 {
288 for (int var1 = 0; var1 < 2; ++var1)
289 {
290 this.skipRenderPass[var1] = true;
291 }
292
293 this.isInFrustum = false;
294 this.isInitialized = false;
295 }
296
297 public void stopRendering()
298 {
299 this.setDontDraw();
300 this.worldObj = null;
301 }
302
303 /**
304 * Takes in the pass the call list is being requested for. Args: renderPass
305 */
306 public int getGLCallListForPass(int par1)
307 {
308 return !this.isInFrustum ? -1 : (!this.skipRenderPass[par1] ? this.glRenderList + par1 : -1);
309 }
310
311 public void updateInFrustum(ICamera par1ICamera)
312 {
313 this.isInFrustum = par1ICamera.isBoundingBoxInFrustum(this.rendererBoundingBox);
314 }
315
316 /**
317 * Renders the occlusion query GL List
318 */
319 public void callOcclusionQueryList()
320 {
321 GL11.glCallList(this.glRenderList + 2);
322 }
323
324 /**
325 * Checks if all render passes are to be skipped. Returns false if the renderer is not initialized
326 */
327 public boolean skipAllRenderPasses()
328 {
329 return !this.isInitialized ? false : this.skipRenderPass[0] && this.skipRenderPass[1];
330 }
331
332 /**
333 * Marks the current renderer data as dirty and needing to be updated.
334 */
335 public void markDirty()
336 {
337 this.needsUpdate = true;
338 }
339 }