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 }