001 package net.minecraft.client.particle;
002
003 import cpw.mods.fml.relauncher.Side;
004 import cpw.mods.fml.relauncher.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.entity.Entity;
015 import net.minecraft.item.Item;
016 import net.minecraft.util.MathHelper;
017 import net.minecraft.util.MovingObjectPosition;
018 import net.minecraft.world.World;
019 import org.lwjgl.opengl.GL11;
020
021 import net.minecraftforge.client.ForgeHooksClient;
022 import net.minecraftforge.common.ForgeHooks;
023 import com.google.common.collect.ArrayListMultimap;
024 import com.google.common.collect.Multimap;
025
026 @SideOnly(Side.CLIENT)
027 public 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 }