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.Iterator;
007import java.util.List;
008import java.util.Map.Entry;
009import java.util.Random;
010import net.minecraft.block.Block;
011import net.minecraft.client.renderer.ActiveRenderInfo;
012import net.minecraft.client.renderer.RenderEngine;
013import net.minecraft.client.renderer.Tessellator;
014import net.minecraft.entity.Entity;
015import net.minecraft.item.Item;
016import net.minecraft.util.MathHelper;
017import net.minecraft.util.MovingObjectPosition;
018import net.minecraft.world.World;
019import org.lwjgl.opengl.GL11;
020
021import net.minecraftforge.client.ForgeHooksClient;
022import net.minecraftforge.common.ForgeHooks;
023import com.google.common.collect.ArrayListMultimap;
024import com.google.common.collect.Multimap;
025
026@SideOnly(Side.CLIENT)
027public class EffectRenderer
028{
029    /** Reference to the World object. */
030    protected World worldObj;
031    private List[] fxLayers = new List[4];
032    private RenderEngine renderer;
033
034    /** RNG. */
035    private Random rand = new Random();
036
037    private Multimap<String, EntityFX> effectList = ArrayListMultimap.create();
038
039    public EffectRenderer(World par1World, RenderEngine par2RenderEngine)
040    {
041        if (par1World != null)
042        {
043            this.worldObj = par1World;
044        }
045
046        this.renderer = par2RenderEngine;
047
048        for (int var3 = 0; var3 < 4; ++var3)
049        {
050            this.fxLayers[var3] = new ArrayList();
051        }
052    }
053
054    public void addEffect(EntityFX par1EntityFX)
055    {
056        int var2 = par1EntityFX.getFXLayer();
057
058        if (this.fxLayers[var2].size() >= 4000)
059        {
060            this.fxLayers[var2].remove(0);
061        }
062
063        this.fxLayers[var2].add(par1EntityFX);
064    }
065
066    public void updateEffects()
067    {
068        for (int var1 = 0; var1 < 4; ++var1)
069        {
070            for (int var2 = 0; var2 < this.fxLayers[var1].size(); ++var2)
071            {
072                EntityFX var3 = (EntityFX)this.fxLayers[var1].get(var2);
073
074                if (var3 != null)
075                {
076                    var3.onUpdate();
077                }
078
079                if (var3 == null || var3.isDead)
080                {
081                    this.fxLayers[var1].remove(var2--);
082                }
083            }
084        }
085
086        Iterator<Entry<String, EntityFX>> itr = effectList.entries().iterator();
087        while (itr.hasNext())
088        {
089            EntityFX fx = itr.next().getValue();
090            fx.onUpdate();
091            if (fx.isDead)
092            {
093                itr.remove();
094            }
095        }
096    }
097
098    /**
099     * Renders all current particles. Args player, partialTickTime
100     */
101    public void renderParticles(Entity par1Entity, float par2)
102    {
103        float var3 = ActiveRenderInfo.rotationX;
104        float var4 = ActiveRenderInfo.rotationZ;
105        float var5 = ActiveRenderInfo.rotationYZ;
106        float var6 = ActiveRenderInfo.rotationXY;
107        float var7 = ActiveRenderInfo.rotationXZ;
108        EntityFX.interpPosX = par1Entity.lastTickPosX + (par1Entity.posX - par1Entity.lastTickPosX) * (double)par2;
109        EntityFX.interpPosY = par1Entity.lastTickPosY + (par1Entity.posY - par1Entity.lastTickPosY) * (double)par2;
110        EntityFX.interpPosZ = par1Entity.lastTickPosZ + (par1Entity.posZ - par1Entity.lastTickPosZ) * (double)par2;
111
112        for (int var8 = 0; var8 < 3; ++var8)
113        {
114            if (!this.fxLayers[var8].isEmpty())
115            {
116                int var9 = 0;
117
118                if (var8 == 0)
119                {
120                    var9 = this.renderer.getTexture("/particles.png");
121                }
122
123                if (var8 == 1)
124                {
125                    var9 = this.renderer.getTexture("/terrain.png");
126                }
127
128                if (var8 == 2)
129                {
130                    var9 = this.renderer.getTexture("/gui/items.png");
131                }
132
133                GL11.glBindTexture(GL11.GL_TEXTURE_2D, var9);
134                Tessellator var10 = Tessellator.instance;
135                GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
136                GL11.glEnable(GL11.GL_BLEND);
137                GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
138                GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F);
139                var10.startDrawingQuads();
140
141                for (int var11 = 0; var11 < this.fxLayers[var8].size(); ++var11)
142                {
143                    EntityFX var12 = (EntityFX)this.fxLayers[var8].get(var11);
144                    if (var12 == null) continue;
145                    var10.setBrightness(var12.getBrightnessForRender(par2));
146                    var12.renderParticle(var10, par2, var3, var7, var4, var5, var6);
147                }
148
149                var10.draw();
150                GL11.glDisable(GL11.GL_BLEND);
151                GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F);
152            }
153        }
154
155        for (String key : effectList.keySet())
156        {
157            ForgeHooksClient.bindTexture(key, 0);
158            for (EntityFX entry : effectList.get(key))
159            {
160                if (entry == null) continue;
161                Tessellator tessallator = Tessellator.instance;
162                //GL11.glBindTexture(GL11.GL_TEXTURE_2D, renderer.getTexture(key));
163                tessallator.startDrawingQuads();
164
165                if (entry.getFXLayer() != 3)
166                {
167                    tessallator.setBrightness(entry.getBrightnessForRender(par2));
168                    entry.renderParticle(tessallator, par2, var3, var7, var4, var5, var6);
169                }
170
171                tessallator.draw();
172            }
173            ForgeHooksClient.unbindTexture();
174        }
175    }
176
177    public void renderLitParticles(Entity par1Entity, float par2)
178    {
179        float var4 = MathHelper.cos(par1Entity.rotationYaw * 0.017453292F);
180        float var5 = MathHelper.sin(par1Entity.rotationYaw * 0.017453292F);
181        float var6 = -var5 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F);
182        float var7 = var4 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F);
183        float var8 = MathHelper.cos(par1Entity.rotationPitch * 0.017453292F);
184        byte var9 = 3;
185
186        if (!this.fxLayers[var9].isEmpty())
187        {
188            Tessellator var10 = Tessellator.instance;
189
190            for (int var11 = 0; var11 < this.fxLayers[var9].size(); ++var11)
191            {
192                EntityFX var12 = (EntityFX)this.fxLayers[var9].get(var11);
193                if (var12 == null) continue;
194                var10.setBrightness(var12.getBrightnessForRender(par2));
195                var12.renderParticle(var10, par2, var4, var8, var5, var6, var7);
196            }
197        }
198    }
199
200    public void clearEffects(World par1World)
201    {
202        this.worldObj = par1World;
203
204        for (int var2 = 0; var2 < 4; ++var2)
205        {
206            this.fxLayers[var2].clear();
207        }
208
209        effectList.clear();
210    }
211
212    public void addBlockDestroyEffects(int par1, int par2, int par3, int par4, int par5)
213    {
214        Block var6 = Block.blocksList[par4];
215        if (var6 != null && !var6.addBlockDestroyEffects(worldObj, par1, par2, par3, par5, this))
216        {
217            byte var7 = 4;
218
219            for (int var8 = 0; var8 < var7; ++var8)
220            {
221                for (int var9 = 0; var9 < var7; ++var9)
222                {
223                    for (int var10 = 0; var10 < var7; ++var10)
224                    {
225                        double var11 = (double)par1 + ((double)var8 + 0.5D) / (double)var7;
226                        double var13 = (double)par2 + ((double)var9 + 0.5D) / (double)var7;
227                        double var15 = (double)par3 + ((double)var10 + 0.5D) / (double)var7;
228                        int var17 = this.rand.nextInt(6);
229                        this.addEffect((new EntityDiggingFX(this.worldObj, var11, var13, var15, var11 - (double)par1 - 0.5D, var13 - (double)par2 - 0.5D, var15 - (double)par3 - 0.5D, var6, var17, par5)).func_70596_a(par1, par2, par3), var6);
230                    }
231                }
232            }
233        }
234    }
235
236    /**
237     * Adds block hit particles for the specified block. Args: x, y, z, sideHit
238     */
239    public void addBlockHitEffects(int par1, int par2, int par3, int par4)
240    {
241        int var5 = this.worldObj.getBlockId(par1, par2, par3);
242
243        if (var5 != 0)
244        {
245            Block var6 = Block.blocksList[var5];
246            float var7 = 0.1F;
247            double var8 = (double)par1 + this.rand.nextDouble() * (var6.getBlockBoundsMaxX() - var6.getBlockBoundsMinX() - (double)(var7 * 2.0F)) + (double)var7 + var6.getBlockBoundsMinX();
248            double var10 = (double)par2 + this.rand.nextDouble() * (var6.getBlockBoundsMaxY() - var6.getBlockBoundsMinY() - (double)(var7 * 2.0F)) + (double)var7 + var6.getBlockBoundsMinY();
249            double var12 = (double)par3 + this.rand.nextDouble() * (var6.getBlockBoundsMaxZ() - var6.getBlockBoundsMinZ() - (double)(var7 * 2.0F)) + (double)var7 + var6.getBlockBoundsMinZ();
250
251            if (par4 == 0)
252            {
253                var10 = (double)par2 + var6.getBlockBoundsMinY() - (double)var7;
254            }
255
256            if (par4 == 1)
257            {
258                var10 = (double)par2 + var6.getBlockBoundsMaxY() + (double)var7;
259            }
260
261            if (par4 == 2)
262            {
263                var12 = (double)par3 + var6.getBlockBoundsMinZ() - (double)var7;
264            }
265
266            if (par4 == 3)
267            {
268                var12 = (double)par3 + var6.getBlockBoundsMaxZ() + (double)var7;
269            }
270
271            if (par4 == 4)
272            {
273                var8 = (double)par1 + var6.getBlockBoundsMinX() - (double)var7;
274            }
275
276            if (par4 == 5)
277            {
278                var8 = (double)par1 + var6.getBlockBoundsMaxX() + (double)var7;
279            }
280
281            this.addEffect((new EntityDiggingFX(this.worldObj, var8, var10, var12, 0.0D, 0.0D, 0.0D, var6, par4, this.worldObj.getBlockMetadata(par1, par2, par3))).func_70596_a(par1, par2, par3).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F), var6);
282        }
283    }
284
285    public String getStatistics()
286    {
287        int size = 0;
288        for (List x : fxLayers)
289        {
290            size += x.size();
291        }
292        size += effectList.size();
293        return Integer.toString(size);
294    }
295
296    public void addEffect(EntityFX effect, Object obj)
297    {
298        if (obj == null || !(obj instanceof Block || obj instanceof Item))
299        {
300            addEffect(effect);
301            return;
302        }
303
304        if (obj instanceof Item && ((Item)obj).isDefaultTexture)
305        {
306            addEffect(effect);
307            return;
308        }
309
310        if (obj instanceof Block && ((Block)obj).isDefaultTexture)
311        {
312            addEffect(effect);
313            return;
314        }
315
316        String texture = "/terrain.png";
317        if (effect.getFXLayer() == 0)
318        {
319            texture = "/particles.png";
320        }
321        else if (effect.getFXLayer() == 2)
322        {
323            texture = "/gui/items.png";
324        }
325        texture = ForgeHooks.getTexture(texture, obj);
326        effectList.put(texture, effect);
327    }
328
329    public void addBlockHitEffects(int x, int y, int z, MovingObjectPosition target)
330    {
331        Block block = Block.blocksList[worldObj.getBlockId(x, y, z)];
332        if (block != null && !block.addBlockHitEffects(worldObj, target, this))
333        {
334            addBlockHitEffects(x, y, z, target.sideHit);
335        }
336    }
337}