001package net.minecraft.client.particle; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.ArrayList; 006import java.util.List; 007import java.util.Random; 008import net.minecraft.block.Block; 009import net.minecraft.client.renderer.ActiveRenderInfo; 010import net.minecraft.client.renderer.RenderEngine; 011import net.minecraft.client.renderer.Tessellator; 012import net.minecraft.entity.Entity; 013import net.minecraft.util.MathHelper; 014import net.minecraft.util.MovingObjectPosition; 015import net.minecraft.world.World; 016import org.lwjgl.opengl.GL11; 017 018@SideOnly(Side.CLIENT) 019public class EffectRenderer 020{ 021 /** Reference to the World object. */ 022 protected World worldObj; 023 private List[] fxLayers = new List[4]; 024 private RenderEngine renderer; 025 026 /** RNG. */ 027 private Random rand = new Random(); 028 029 public EffectRenderer(World par1World, RenderEngine par2RenderEngine) 030 { 031 if (par1World != null) 032 { 033 this.worldObj = par1World; 034 } 035 036 this.renderer = par2RenderEngine; 037 038 for (int i = 0; i < 4; ++i) 039 { 040 this.fxLayers[i] = new ArrayList(); 041 } 042 } 043 044 public void addEffect(EntityFX par1EntityFX) 045 { 046 int i = par1EntityFX.getFXLayer(); 047 048 if (this.fxLayers[i].size() >= 4000) 049 { 050 this.fxLayers[i].remove(0); 051 } 052 053 this.fxLayers[i].add(par1EntityFX); 054 } 055 056 public void updateEffects() 057 { 058 for (int i = 0; i < 4; ++i) 059 { 060 for (int j = 0; j < this.fxLayers[i].size(); ++j) 061 { 062 EntityFX entityfx = (EntityFX)this.fxLayers[i].get(j); 063 064 if (entityfx != null) 065 { 066 entityfx.onUpdate(); 067 } 068 069 if (entityfx == null || entityfx.isDead) 070 { 071 this.fxLayers[i].remove(j--); 072 } 073 } 074 } 075 } 076 077 /** 078 * Renders all current particles. Args player, partialTickTime 079 */ 080 public void renderParticles(Entity par1Entity, float par2) 081 { 082 float f1 = ActiveRenderInfo.rotationX; 083 float f2 = ActiveRenderInfo.rotationZ; 084 float f3 = ActiveRenderInfo.rotationYZ; 085 float f4 = ActiveRenderInfo.rotationXY; 086 float f5 = ActiveRenderInfo.rotationXZ; 087 EntityFX.interpPosX = par1Entity.lastTickPosX + (par1Entity.posX - par1Entity.lastTickPosX) * (double)par2; 088 EntityFX.interpPosY = par1Entity.lastTickPosY + (par1Entity.posY - par1Entity.lastTickPosY) * (double)par2; 089 EntityFX.interpPosZ = par1Entity.lastTickPosZ + (par1Entity.posZ - par1Entity.lastTickPosZ) * (double)par2; 090 091 for (int i = 0; i < 3; ++i) 092 { 093 if (!this.fxLayers[i].isEmpty()) 094 { 095 switch (i) 096 { 097 case 0: 098 default: 099 this.renderer.bindTexture("/particles.png"); 100 break; 101 case 1: 102 this.renderer.bindTexture("/terrain.png"); 103 break; 104 case 2: 105 this.renderer.bindTexture("/gui/items.png"); 106 } 107 108 Tessellator tessellator = Tessellator.instance; 109 GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); 110 GL11.glDepthMask(false); 111 GL11.glEnable(GL11.GL_BLEND); 112 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); 113 GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F); 114 tessellator.startDrawingQuads(); 115 116 for (int j = 0; j < this.fxLayers[i].size(); ++j) 117 { 118 EntityFX entityfx = (EntityFX)this.fxLayers[i].get(j); 119 if (entityfx == null) continue; 120 tessellator.setBrightness(entityfx.getBrightnessForRender(par2)); 121 entityfx.renderParticle(tessellator, par2, f1, f5, f2, f3, f4); 122 } 123 124 tessellator.draw(); 125 GL11.glDisable(GL11.GL_BLEND); 126 GL11.glDepthMask(true); 127 GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); 128 } 129 } 130 } 131 132 public void renderLitParticles(Entity par1Entity, float par2) 133 { 134 float f1 = MathHelper.cos(par1Entity.rotationYaw * 0.017453292F); 135 float f2 = MathHelper.sin(par1Entity.rotationYaw * 0.017453292F); 136 float f3 = -f2 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F); 137 float f4 = f1 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F); 138 float f5 = MathHelper.cos(par1Entity.rotationPitch * 0.017453292F); 139 byte b0 = 3; 140 141 if (!this.fxLayers[b0].isEmpty()) 142 { 143 Tessellator tessellator = Tessellator.instance; 144 145 for (int i = 0; i < this.fxLayers[b0].size(); ++i) 146 { 147 EntityFX entityfx = (EntityFX)this.fxLayers[b0].get(i); 148 if (entityfx == null) continue; 149 tessellator.setBrightness(entityfx.getBrightnessForRender(par2)); 150 entityfx.renderParticle(tessellator, par2, f1, f5, f2, f3, f4); 151 } 152 } 153 } 154 155 public void clearEffects(World par1World) 156 { 157 this.worldObj = par1World; 158 159 for (int i = 0; i < 4; ++i) 160 { 161 this.fxLayers[i].clear(); 162 } 163 } 164 165 public void addBlockDestroyEffects(int par1, int par2, int par3, int par4, int par5) 166 { 167 Block block = Block.blocksList[par4]; 168 if (block != null && !block.addBlockDestroyEffects(worldObj, par1, par2, par3, par5, this)) 169 { 170 byte b0 = 4; 171 172 for (int j1 = 0; j1 < b0; ++j1) 173 { 174 for (int k1 = 0; k1 < b0; ++k1) 175 { 176 for (int l1 = 0; l1 < b0; ++l1) 177 { 178 double d0 = (double)par1 + ((double)j1 + 0.5D) / (double)b0; 179 double d1 = (double)par2 + ((double)k1 + 0.5D) / (double)b0; 180 double d2 = (double)par3 + ((double)l1 + 0.5D) / (double)b0; 181 int i2 = this.rand.nextInt(6); 182 this.addEffect((new EntityDiggingFX(this.worldObj, d0, d1, d2, d0 - (double)par1 - 0.5D, d1 - (double)par2 - 0.5D, d2 - (double)par3 - 0.5D, block, i2, par5, this.renderer)).func_70596_a(par1, par2, par3)); 183 } 184 } 185 } 186 } 187 } 188 189 /** 190 * Adds block hit particles for the specified block. Args: x, y, z, sideHit 191 */ 192 public void addBlockHitEffects(int par1, int par2, int par3, int par4) 193 { 194 int i1 = this.worldObj.getBlockId(par1, par2, par3); 195 196 if (i1 != 0) 197 { 198 Block block = Block.blocksList[i1]; 199 float f = 0.1F; 200 double d0 = (double)par1 + this.rand.nextDouble() * (block.getBlockBoundsMaxX() - block.getBlockBoundsMinX() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinX(); 201 double d1 = (double)par2 + this.rand.nextDouble() * (block.getBlockBoundsMaxY() - block.getBlockBoundsMinY() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinY(); 202 double d2 = (double)par3 + this.rand.nextDouble() * (block.getBlockBoundsMaxZ() - block.getBlockBoundsMinZ() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinZ(); 203 204 if (par4 == 0) 205 { 206 d1 = (double)par2 + block.getBlockBoundsMinY() - (double)f; 207 } 208 209 if (par4 == 1) 210 { 211 d1 = (double)par2 + block.getBlockBoundsMaxY() + (double)f; 212 } 213 214 if (par4 == 2) 215 { 216 d2 = (double)par3 + block.getBlockBoundsMinZ() - (double)f; 217 } 218 219 if (par4 == 3) 220 { 221 d2 = (double)par3 + block.getBlockBoundsMaxZ() + (double)f; 222 } 223 224 if (par4 == 4) 225 { 226 d0 = (double)par1 + block.getBlockBoundsMinX() - (double)f; 227 } 228 229 if (par4 == 5) 230 { 231 d0 = (double)par1 + block.getBlockBoundsMaxX() + (double)f; 232 } 233 234 this.addEffect((new EntityDiggingFX(this.worldObj, d0, d1, d2, 0.0D, 0.0D, 0.0D, block, par4, this.worldObj.getBlockMetadata(par1, par2, par3), this.renderer)).func_70596_a(par1, par2, par3).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F)); 235 } 236 } 237 238 public String getStatistics() 239 { 240 return "" + (this.fxLayers[0].size() + this.fxLayers[1].size() + this.fxLayers[2].size()); 241 } 242 243 public void addBlockHitEffects(int x, int y, int z, MovingObjectPosition target) 244 { 245 Block block = Block.blocksList[worldObj.getBlockId(x, y, z)]; 246 if (block != null && !block.addBlockHitEffects(worldObj, target, this)) 247 { 248 addBlockHitEffects(x, y, z, target.sideHit); 249 } 250 } 251}