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