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 }