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