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