001package net.minecraft.client.particle;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.util.ArrayList;
006import java.util.List;
007import java.util.Random;
008import net.minecraft.block.Block;
009import net.minecraft.client.renderer.ActiveRenderInfo;
010import net.minecraft.client.renderer.RenderEngine;
011import net.minecraft.client.renderer.Tessellator;
012import net.minecraft.entity.Entity;
013import net.minecraft.util.MathHelper;
014import net.minecraft.util.MovingObjectPosition;
015import net.minecraft.world.World;
016import org.lwjgl.opengl.GL11;
017
018@SideOnly(Side.CLIENT)
019public class EffectRenderer
020{
021    /** Reference to the World object. */
022    protected World worldObj;
023    private List[] fxLayers = new List[4];
024    private RenderEngine renderer;
025
026    /** RNG. */
027    private Random rand = new Random();
028
029    public EffectRenderer(World par1World, RenderEngine par2RenderEngine)
030    {
031        if (par1World != null)
032        {
033            this.worldObj = par1World;
034        }
035
036        this.renderer = par2RenderEngine;
037
038        for (int i = 0; i < 4; ++i)
039        {
040            this.fxLayers[i] = new ArrayList();
041        }
042    }
043
044    public void addEffect(EntityFX par1EntityFX)
045    {
046        int i = par1EntityFX.getFXLayer();
047
048        if (this.fxLayers[i].size() >= 4000)
049        {
050            this.fxLayers[i].remove(0);
051        }
052
053        this.fxLayers[i].add(par1EntityFX);
054    }
055
056    public void updateEffects()
057    {
058        for (int i = 0; i < 4; ++i)
059        {
060            for (int j = 0; j < this.fxLayers[i].size(); ++j)
061            {
062                EntityFX entityfx = (EntityFX)this.fxLayers[i].get(j);
063
064                if (entityfx != null)
065                {
066                    entityfx.onUpdate();
067                }
068
069                if (entityfx == null || entityfx.isDead)
070                {
071                    this.fxLayers[i].remove(j--);
072                }
073            }
074        }
075    }
076
077    /**
078     * Renders all current particles. Args player, partialTickTime
079     */
080    public void renderParticles(Entity par1Entity, float par2)
081    {
082        float f1 = ActiveRenderInfo.rotationX;
083        float f2 = ActiveRenderInfo.rotationZ;
084        float f3 = ActiveRenderInfo.rotationYZ;
085        float f4 = ActiveRenderInfo.rotationXY;
086        float f5 = ActiveRenderInfo.rotationXZ;
087        EntityFX.interpPosX = par1Entity.lastTickPosX + (par1Entity.posX - par1Entity.lastTickPosX) * (double)par2;
088        EntityFX.interpPosY = par1Entity.lastTickPosY + (par1Entity.posY - par1Entity.lastTickPosY) * (double)par2;
089        EntityFX.interpPosZ = par1Entity.lastTickPosZ + (par1Entity.posZ - par1Entity.lastTickPosZ) * (double)par2;
090
091        for (int i = 0; i < 3; ++i)
092        {
093            if (!this.fxLayers[i].isEmpty())
094            {
095                switch (i)
096                {
097                    case 0:
098                    default:
099                        this.renderer.bindTexture("/particles.png");
100                        break;
101                    case 1:
102                        this.renderer.bindTexture("/terrain.png");
103                        break;
104                    case 2:
105                        this.renderer.bindTexture("/gui/items.png");
106                }
107
108                Tessellator tessellator = Tessellator.instance;
109                GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
110                GL11.glDepthMask(false);
111                GL11.glEnable(GL11.GL_BLEND);
112                GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
113                GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F);
114                tessellator.startDrawingQuads();
115
116                for (int j = 0; j < this.fxLayers[i].size(); ++j)
117                {
118                    EntityFX entityfx = (EntityFX)this.fxLayers[i].get(j);
119                    if (entityfx == null) continue;
120                    tessellator.setBrightness(entityfx.getBrightnessForRender(par2));
121                    entityfx.renderParticle(tessellator, par2, f1, f5, f2, f3, f4);
122                }
123
124                tessellator.draw();
125                GL11.glDisable(GL11.GL_BLEND);
126                GL11.glDepthMask(true);
127                GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F);
128            }
129        }
130    }
131
132    public void renderLitParticles(Entity par1Entity, float par2)
133    {
134        float f1 = MathHelper.cos(par1Entity.rotationYaw * 0.017453292F);
135        float f2 = MathHelper.sin(par1Entity.rotationYaw * 0.017453292F);
136        float f3 = -f2 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F);
137        float f4 = f1 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F);
138        float f5 = MathHelper.cos(par1Entity.rotationPitch * 0.017453292F);
139        byte b0 = 3;
140
141        if (!this.fxLayers[b0].isEmpty())
142        {
143            Tessellator tessellator = Tessellator.instance;
144
145            for (int i = 0; i < this.fxLayers[b0].size(); ++i)
146            {
147                EntityFX entityfx = (EntityFX)this.fxLayers[b0].get(i);
148                if (entityfx == null) continue;
149                tessellator.setBrightness(entityfx.getBrightnessForRender(par2));
150                entityfx.renderParticle(tessellator, par2, f1, f5, f2, f3, f4);
151            }
152        }
153    }
154
155    public void clearEffects(World par1World)
156    {
157        this.worldObj = par1World;
158
159        for (int i = 0; i < 4; ++i)
160        {
161            this.fxLayers[i].clear();
162        }
163    }
164
165    public void addBlockDestroyEffects(int par1, int par2, int par3, int par4, int par5)
166    {
167        Block block = Block.blocksList[par4];
168        if (block != null && !block.addBlockDestroyEffects(worldObj, par1, par2, par3, par5, this))
169        {
170            byte b0 = 4;
171
172            for (int j1 = 0; j1 < b0; ++j1)
173            {
174                for (int k1 = 0; k1 < b0; ++k1)
175                {
176                    for (int l1 = 0; l1 < b0; ++l1)
177                    {
178                        double d0 = (double)par1 + ((double)j1 + 0.5D) / (double)b0;
179                        double d1 = (double)par2 + ((double)k1 + 0.5D) / (double)b0;
180                        double d2 = (double)par3 + ((double)l1 + 0.5D) / (double)b0;
181                        int i2 = this.rand.nextInt(6);
182                        this.addEffect((new EntityDiggingFX(this.worldObj, d0, d1, d2, d0 - (double)par1 - 0.5D, d1 - (double)par2 - 0.5D, d2 - (double)par3 - 0.5D, block, i2, par5, this.renderer)).func_70596_a(par1, par2, par3));
183                    }
184                }
185            }
186        }
187    }
188
189    /**
190     * Adds block hit particles for the specified block. Args: x, y, z, sideHit
191     */
192    public void addBlockHitEffects(int par1, int par2, int par3, int par4)
193    {
194        int i1 = this.worldObj.getBlockId(par1, par2, par3);
195
196        if (i1 != 0)
197        {
198            Block block = Block.blocksList[i1];
199            float f = 0.1F;
200            double d0 = (double)par1 + this.rand.nextDouble() * (block.getBlockBoundsMaxX() - block.getBlockBoundsMinX() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinX();
201            double d1 = (double)par2 + this.rand.nextDouble() * (block.getBlockBoundsMaxY() - block.getBlockBoundsMinY() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinY();
202            double d2 = (double)par3 + this.rand.nextDouble() * (block.getBlockBoundsMaxZ() - block.getBlockBoundsMinZ() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinZ();
203
204            if (par4 == 0)
205            {
206                d1 = (double)par2 + block.getBlockBoundsMinY() - (double)f;
207            }
208
209            if (par4 == 1)
210            {
211                d1 = (double)par2 + block.getBlockBoundsMaxY() + (double)f;
212            }
213
214            if (par4 == 2)
215            {
216                d2 = (double)par3 + block.getBlockBoundsMinZ() - (double)f;
217            }
218
219            if (par4 == 3)
220            {
221                d2 = (double)par3 + block.getBlockBoundsMaxZ() + (double)f;
222            }
223
224            if (par4 == 4)
225            {
226                d0 = (double)par1 + block.getBlockBoundsMinX() - (double)f;
227            }
228
229            if (par4 == 5)
230            {
231                d0 = (double)par1 + block.getBlockBoundsMaxX() + (double)f;
232            }
233
234            this.addEffect((new EntityDiggingFX(this.worldObj, d0, d1, d2, 0.0D, 0.0D, 0.0D, block, par4, this.worldObj.getBlockMetadata(par1, par2, par3), this.renderer)).func_70596_a(par1, par2, par3).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F));
235        }
236    }
237
238    public String getStatistics()
239    {
240        return "" + (this.fxLayers[0].size() + this.fxLayers[1].size() + this.fxLayers[2].size());
241    }
242
243    public void addBlockHitEffects(int x, int y, int z, MovingObjectPosition target)
244    {
245        Block block = Block.blocksList[worldObj.getBlockId(x, y, z)];
246        if (block != null && !block.addBlockHitEffects(worldObj, target, this))
247        {
248            addBlockHitEffects(x, y, z, target.sideHit);
249        }
250     }
251}