    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}