001package net.minecraft.client.renderer; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.ArrayList; 006import java.util.HashSet; 007import java.util.List; 008import net.minecraft.block.Block; 009import net.minecraft.client.renderer.culling.ICamera; 010import net.minecraft.client.renderer.entity.RenderItem; 011import net.minecraft.client.renderer.tileentity.TileEntityRenderer; 012import net.minecraft.entity.Entity; 013import net.minecraft.tileentity.TileEntity; 014import net.minecraft.util.AxisAlignedBB; 015import net.minecraft.world.ChunkCache; 016import net.minecraft.world.World; 017import net.minecraft.world.chunk.Chunk; 018import org.lwjgl.opengl.GL11; 019 020import net.minecraftforge.client.ForgeHooksClient; 021 022@SideOnly(Side.CLIENT) 023public 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 f = 6.0F; 125 this.rendererBoundingBox = AxisAlignedBB.getBoundingBox((double)((float)par1 - f), (double)((float)par2 - f), (double)((float)par3 - f), (double)((float)(par1 + 16) + f), (double)((float)(par2 + 16) + f), (double)((float)(par3 + 16) + f)); 126 GL11.glNewList(this.glRenderList + 2, GL11.GL_COMPILE); 127 RenderItem.renderAABB(AxisAlignedBB.getAABBPool().getAABB((double)((float)this.posXClip - f), (double)((float)this.posYClip - f), (double)((float)this.posZClip - f), (double)((float)(this.posXClip + 16) + f), (double)((float)(this.posYClip + 16) + f), (double)((float)(this.posZClip + 16) + f))); 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 i = this.posX; 147 int j = this.posY; 148 int k = this.posZ; 149 int l = this.posX + 16; 150 int i1 = this.posY + 16; 151 int j1 = this.posZ + 16; 152 153 for (int k1 = 0; k1 < 2; ++k1) 154 { 155 this.skipRenderPass[k1] = true; 156 } 157 158 Chunk.isLit = false; 159 HashSet hashset = new HashSet(); 160 hashset.addAll(this.tileEntityRenderers); 161 this.tileEntityRenderers.clear(); 162 byte b0 = 1; 163 ChunkCache chunkcache = new ChunkCache(this.worldObj, i - b0, j - b0, k - b0, l + b0, i1 + b0, j1 + b0); 164 165 if (!chunkcache.extendedLevelsInChunkCache()) 166 { 167 ++chunksUpdated; 168 RenderBlocks renderblocks = new RenderBlocks(chunkcache); 169 this.bytesDrawn = 0; 170 171 for (int l1 = 0; l1 < 2; ++l1) 172 { 173 boolean flag = false; 174 boolean flag1 = false; 175 boolean flag2 = false; 176 177 for (int i2 = j; i2 < i1; ++i2) 178 { 179 for (int j2 = k; j2 < j1; ++j2) 180 { 181 for (int k2 = i; k2 < l; ++k2) 182 { 183 int l2 = chunkcache.getBlockId(k2, i2, j2); 184 185 if (l2 > 0) 186 { 187 if (!flag2) 188 { 189 flag2 = true; 190 GL11.glNewList(this.glRenderList + l1, GL11.GL_COMPILE); 191 GL11.glPushMatrix(); 192 this.setupGLTranslation(); 193 float f = 1.000001F; 194 GL11.glTranslatef(-8.0F, -8.0F, -8.0F); 195 GL11.glScalef(f, f, f); 196 GL11.glTranslatef(8.0F, 8.0F, 8.0F); 197 //ForgeHooksClient.beforeRenderPass(l1); Noop fo now, TODO: Event if anyone needs 198 Tessellator.instance.startDrawingQuads(); 199 Tessellator.instance.setTranslation((double)(-this.posX), (double)(-this.posY), (double)(-this.posZ)); 200 } 201 202 Block block = Block.blocksList[l2]; 203 204 if (block != null) 205 { 206 if (l1 == 0 && block.hasTileEntity(chunkcache.getBlockMetadata(k2, i2, j2))) 207 { 208 TileEntity tileentity = chunkcache.getBlockTileEntity(k2, i2, j2); 209 210 if (TileEntityRenderer.instance.hasSpecialRenderer(tileentity)) 211 { 212 this.tileEntityRenderers.add(tileentity); 213 } 214 } 215 216 int i3 = block.getRenderBlockPass(); 217 218 if (i3 > l1) 219 { 220 flag = true; 221 } 222 if (!block.canRenderInPass(l1)) 223 { 224 continue; 225 } 226 flag1 |= renderblocks.renderBlockByRenderType(block, k2, i2, j2); 227 } 228 } 229 } 230 } 231 } 232 233 if (flag2) 234 { 235 //ForgeHooksClient.afterRenderPass(l1); Noop fo now, TODO: Event if anyone needs 236 this.bytesDrawn += Tessellator.instance.draw(); 237 GL11.glPopMatrix(); 238 GL11.glEndList(); 239 Tessellator.instance.setTranslation(0.0D, 0.0D, 0.0D); 240 } 241 else 242 { 243 flag1 = false; 244 } 245 246 if (flag1) 247 { 248 this.skipRenderPass[l1] = false; 249 } 250 251 if (!flag) 252 { 253 break; 254 } 255 } 256 } 257 258 HashSet hashset1 = new HashSet(); 259 hashset1.addAll(this.tileEntityRenderers); 260 hashset1.removeAll(hashset); 261 this.tileEntities.addAll(hashset1); 262 hashset.removeAll(this.tileEntityRenderers); 263 this.tileEntities.removeAll(hashset); 264 this.isChunkLit = Chunk.isLit; 265 this.isInitialized = true; 266 } 267 } 268 269 /** 270 * Returns the distance of this chunk renderer to the entity without performing the final normalizing square root, 271 * for performance reasons. 272 */ 273 public float distanceToEntitySquared(Entity par1Entity) 274 { 275 float f = (float)(par1Entity.posX - (double)this.posXPlus); 276 float f1 = (float)(par1Entity.posY - (double)this.posYPlus); 277 float f2 = (float)(par1Entity.posZ - (double)this.posZPlus); 278 return f * f + f1 * f1 + f2 * f2; 279 } 280 281 /** 282 * When called this renderer won't draw anymore until its gets initialized again 283 */ 284 public void setDontDraw() 285 { 286 for (int i = 0; i < 2; ++i) 287 { 288 this.skipRenderPass[i] = true; 289 } 290 291 this.isInFrustum = false; 292 this.isInitialized = false; 293 } 294 295 public void stopRendering() 296 { 297 this.setDontDraw(); 298 this.worldObj = null; 299 } 300 301 /** 302 * Takes in the pass the call list is being requested for. Args: renderPass 303 */ 304 public int getGLCallListForPass(int par1) 305 { 306 return !this.isInFrustum ? -1 : (!this.skipRenderPass[par1] ? this.glRenderList + par1 : -1); 307 } 308 309 public void updateInFrustum(ICamera par1ICamera) 310 { 311 this.isInFrustum = par1ICamera.isBoundingBoxInFrustum(this.rendererBoundingBox); 312 } 313 314 /** 315 * Renders the occlusion query GL List 316 */ 317 public void callOcclusionQueryList() 318 { 319 GL11.glCallList(this.glRenderList + 2); 320 } 321 322 /** 323 * Checks if all render passes are to be skipped. Returns false if the renderer is not initialized 324 */ 325 public boolean skipAllRenderPasses() 326 { 327 return !this.isInitialized ? false : this.skipRenderPass[0] && this.skipRenderPass[1]; 328 } 329 330 /** 331 * Marks the current renderer data as dirty and needing to be updated. 332 */ 333 public void markDirty() 334 { 335 this.needsUpdate = true; 336 } 337}