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 }