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