429 lines
16 KiB
Java
Executable file
429 lines
16 KiB
Java
Executable file
package game.renderer.particle;
|
|
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Maps;
|
|
|
|
import game.block.Block;
|
|
import game.entity.Entity;
|
|
import game.material.Material;
|
|
import game.renderer.ActiveRenderInfo;
|
|
import game.renderer.DefaultVertexFormats;
|
|
import game.renderer.GlState;
|
|
import game.renderer.RenderBuffer;
|
|
import game.renderer.Tessellator;
|
|
import game.renderer.texture.TextureManager;
|
|
import game.renderer.texture.TextureMap;
|
|
import game.rng.Random;
|
|
import game.util.ExtMath;
|
|
import game.world.BlockPos;
|
|
import game.world.Facing;
|
|
import game.world.State;
|
|
import game.world.World;
|
|
|
|
public class EffectRenderer
|
|
{
|
|
public static final String particleTextures = "textures/world/particles.png";
|
|
|
|
/** Reference to the World object. */
|
|
protected World worldObj;
|
|
private List<EntityFX>[][] fxLayers = new List[4][];
|
|
private List<EntityParticleEmitter> particleEmitters = Lists.<EntityParticleEmitter>newArrayList();
|
|
private TextureManager renderer;
|
|
|
|
/** RNG. */
|
|
private Random rand = new Random();
|
|
private Map<Integer, IParticleFactory> particleTypes = Maps.<Integer, IParticleFactory>newHashMap();
|
|
|
|
public EffectRenderer(World worldIn, TextureManager rendererIn)
|
|
{
|
|
this.worldObj = worldIn;
|
|
this.renderer = rendererIn;
|
|
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
this.fxLayers[i] = new List[2];
|
|
|
|
for (int j = 0; j < 2; ++j)
|
|
{
|
|
this.fxLayers[i][j] = Lists.newArrayList();
|
|
}
|
|
}
|
|
|
|
this.registerVanillaParticles();
|
|
}
|
|
|
|
private void registerVanillaParticles()
|
|
{
|
|
this.registerParticle(ParticleType.EXPLOSION_NORMAL.getParticleID(), new EntityExplodeFX.Factory());
|
|
this.registerParticle(ParticleType.WATER_BUBBLE.getParticleID(), new EntityBubbleFX.Factory());
|
|
this.registerParticle(ParticleType.WATER_SPLASH.getParticleID(), new EntitySplashFX.Factory());
|
|
this.registerParticle(ParticleType.WATER_WAKE.getParticleID(), new EntityFishWakeFX.Factory());
|
|
this.registerParticle(ParticleType.WATER_DROP.getParticleID(), new EntityDownfallFX.RainFactory());
|
|
this.registerParticle(ParticleType.SUSPENDED.getParticleID(), new EntitySuspendFX.Factory());
|
|
this.registerParticle(ParticleType.SUSPENDED_DEPTH.getParticleID(), new EntityAuraFX.SuspendFactory());
|
|
this.registerParticle(ParticleType.CRIT.getParticleID(), new EntityCrit2FX.Factory());
|
|
this.registerParticle(ParticleType.CRIT_MAGIC.getParticleID(), new EntityCrit2FX.MagicFactory());
|
|
this.registerParticle(ParticleType.SMOKE_NORMAL.getParticleID(), new EntitySmokeFX.Factory());
|
|
this.registerParticle(ParticleType.SMOKE_LARGE.getParticleID(), new EntityCritFX.Factory());
|
|
this.registerParticle(ParticleType.SPELL.getParticleID(), new EntitySpellParticleFX.Factory());
|
|
this.registerParticle(ParticleType.SPELL_INSTANT.getParticleID(), new EntitySpellParticleFX.InstantFactory());
|
|
this.registerParticle(ParticleType.SPELL_MOB.getParticleID(), new EntitySpellParticleFX.MobFactory());
|
|
this.registerParticle(ParticleType.SPELL_MOB_AMBIENT.getParticleID(), new EntitySpellParticleFX.AmbientMobFactory());
|
|
this.registerParticle(ParticleType.SPELL_WITCH.getParticleID(), new EntitySpellParticleFX.WitchFactory());
|
|
this.registerParticle(ParticleType.DRIP_WATER.getParticleID(), new EntityDropParticleFX.WaterFactory());
|
|
this.registerParticle(ParticleType.DRIP_LAVA.getParticleID(), new EntityDropParticleFX.LavaFactory());
|
|
// this.registerParticle(EnumParticleTypes.VILLAGER_ANGRY.getParticleID(), new EntityHeartFX.AngryVillagerFactory());
|
|
this.registerParticle(ParticleType.GROW.getParticleID(), new EntityAuraFX.GrowFactory());
|
|
this.registerParticle(ParticleType.TOWN_AURA.getParticleID(), new EntityAuraFX.Factory());
|
|
this.registerParticle(ParticleType.NOTE.getParticleID(), new EntityNoteFX.Factory());
|
|
this.registerParticle(ParticleType.PORTAL.getParticleID(), new EntityPortalFX.Factory());
|
|
this.registerParticle(ParticleType.ENCHANTMENT_TABLE.getParticleID(), new EntityEnchantmentTableParticleFX.EnchantmentTable());
|
|
this.registerParticle(ParticleType.FLAME.getParticleID(), new EntityFlameFX.Factory());
|
|
this.registerParticle(ParticleType.LAVA.getParticleID(), new EntityLavaFX.Factory());
|
|
this.registerParticle(ParticleType.FOOTSTEP.getParticleID(), new EntityFootStepFX.Factory());
|
|
this.registerParticle(ParticleType.CLOUD.getParticleID(), new EntityCloudFX.Factory());
|
|
this.registerParticle(ParticleType.REDSTONE.getParticleID(), new EntityReddustFX.Factory());
|
|
this.registerParticle(ParticleType.SNOWBALL.getParticleID(), new EntityBreakingFX.SnowballFactory());
|
|
this.registerParticle(ParticleType.SNOW_SHOVEL.getParticleID(), new EntitySnowShovelFX.Factory());
|
|
this.registerParticle(ParticleType.SLIME.getParticleID(), new EntityBreakingFX.SlimeFactory());
|
|
this.registerParticle(ParticleType.HEART.getParticleID(), new EntityHeartFX.Factory());
|
|
// this.registerParticle(EnumParticleTypes.BARRIER.getParticleID(), new Barrier.Factory());
|
|
this.registerParticle(ParticleType.ITEM_CRACK.getParticleID(), new EntityBreakingFX.Factory());
|
|
this.registerParticle(ParticleType.BLOCK_CRACK.getParticleID(), new EntityDiggingFX.Factory());
|
|
this.registerParticle(ParticleType.BLOCK_DUST.getParticleID(), new EntityBlockDustFX.Factory());
|
|
this.registerParticle(ParticleType.EXPLOSION_HUGE.getParticleID(), new EntityHugeExplodeFX.Factory());
|
|
this.registerParticle(ParticleType.EXPLOSION_LARGE.getParticleID(), new EntityLargeExplodeFX.Factory());
|
|
this.registerParticle(ParticleType.FIREWORKS_SPARK.getParticleID(), new EntityFirework.Factory());
|
|
this.registerParticle(ParticleType.HAIL_CORN.getParticleID(), new EntityDownfallFX.HailFactory());
|
|
}
|
|
|
|
public void registerParticle(int id, IParticleFactory particleFactory)
|
|
{
|
|
this.particleTypes.put(Integer.valueOf(id), particleFactory);
|
|
}
|
|
|
|
public void emitParticleAtEntity(Entity entityIn, ParticleType particleTypes)
|
|
{
|
|
this.particleEmitters.add(new EntityParticleEmitter(this.worldObj, entityIn, particleTypes));
|
|
}
|
|
|
|
/**
|
|
* Spawns the relevant particle according to the particle id.
|
|
*
|
|
* @param xCoord X position of the particle
|
|
* @param yCoord Y position of the particle
|
|
* @param zCoord Z position of the particle
|
|
* @param xSpeed X speed of the particle
|
|
* @param ySpeed Y speed of the particle
|
|
* @param zSpeed Z speed of the particle
|
|
* @param parameters Parameters for the particle (color for redstone, ...)
|
|
*/
|
|
public EntityFX spawnEffectParticle(int particleId, double xCoord, double yCoord, double zCoord, double xSpeed, double ySpeed, double zSpeed, int[] parameters)
|
|
{
|
|
IParticleFactory iparticlefactory = (IParticleFactory)this.particleTypes.get(Integer.valueOf(particleId));
|
|
|
|
if (iparticlefactory != null)
|
|
{
|
|
EntityFX entityfx = iparticlefactory.getEntityFX(particleId, this.worldObj, xCoord, yCoord, zCoord, xSpeed, ySpeed, zSpeed, parameters);
|
|
|
|
if (entityfx != null)
|
|
{
|
|
this.addEffect(entityfx);
|
|
return entityfx;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void addEffect(EntityFX effect)
|
|
{
|
|
int i = effect.getFXLayer();
|
|
int j = effect.getAlpha() != 1.0F ? 0 : 1;
|
|
|
|
if (this.fxLayers[i][j].size() >= 4000)
|
|
{
|
|
this.fxLayers[i][j].remove(0);
|
|
}
|
|
|
|
this.fxLayers[i][j].add(effect);
|
|
}
|
|
|
|
public void updateEffects()
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
this.updateEffectLayer(i);
|
|
}
|
|
|
|
List<EntityParticleEmitter> list = Lists.<EntityParticleEmitter>newArrayList();
|
|
|
|
for (EntityParticleEmitter entityparticleemitter : this.particleEmitters)
|
|
{
|
|
entityparticleemitter.onUpdate();
|
|
|
|
if (entityparticleemitter.dead)
|
|
{
|
|
list.add(entityparticleemitter);
|
|
}
|
|
}
|
|
|
|
this.particleEmitters.removeAll(list);
|
|
}
|
|
|
|
private void updateEffectLayer(int layer)
|
|
{
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
this.updateEffectAlphaLayer(this.fxLayers[layer][i]);
|
|
}
|
|
}
|
|
|
|
private void updateEffectAlphaLayer(List<EntityFX> entitiesFX)
|
|
{
|
|
List<EntityFX> list = Lists.<EntityFX>newArrayList();
|
|
|
|
for (int i = 0; i < entitiesFX.size(); ++i)
|
|
{
|
|
EntityFX entityfx = (EntityFX)entitiesFX.get(i);
|
|
this.tickParticle(entityfx);
|
|
|
|
if (entityfx.dead)
|
|
{
|
|
list.add(entityfx);
|
|
}
|
|
}
|
|
|
|
entitiesFX.removeAll(list);
|
|
}
|
|
|
|
private void tickParticle(final EntityFX particle)
|
|
{
|
|
particle.onUpdate();
|
|
}
|
|
|
|
/**
|
|
* Renders all current particles. Args player, partialTickTime
|
|
*/
|
|
public void renderParticles(Entity entityIn, float partialTicks)
|
|
{
|
|
float f = ActiveRenderInfo.getRotationX();
|
|
float f1 = ActiveRenderInfo.getRotationZ();
|
|
float f2 = ActiveRenderInfo.getRotationYZ();
|
|
float f3 = ActiveRenderInfo.getRotationXY();
|
|
float f4 = ActiveRenderInfo.getRotationXZ();
|
|
EntityFX.interpPosX = entityIn.lastTickPosX + (entityIn.posX - entityIn.lastTickPosX) * (double)partialTicks;
|
|
EntityFX.interpPosY = entityIn.lastTickPosY + (entityIn.posY - entityIn.lastTickPosY) * (double)partialTicks;
|
|
EntityFX.interpPosZ = entityIn.lastTickPosZ + (entityIn.posZ - entityIn.lastTickPosZ) * (double)partialTicks;
|
|
GlState.enableBlend();
|
|
GlState.blendFunc(770, 771);
|
|
GlState.alphaFunc(516, 0.003921569F);
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
for (int j = 0; j < 2; ++j)
|
|
{
|
|
final int i_f = i;
|
|
|
|
if (!this.fxLayers[i][j].isEmpty())
|
|
{
|
|
switch (j)
|
|
{
|
|
case 0:
|
|
GlState.depthMask(false);
|
|
break;
|
|
|
|
case 1:
|
|
GlState.depthMask(true);
|
|
}
|
|
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
default:
|
|
this.renderer.bindTexture(particleTextures);
|
|
break;
|
|
|
|
case 1:
|
|
this.renderer.bindTexture(TextureMap.locationBlocksTexture);
|
|
}
|
|
|
|
GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
|
// Tessellator tessellator = Tessellator.getInstance();
|
|
RenderBuffer worldrenderer = Tessellator.getBuffer();
|
|
worldrenderer.begin(7, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
|
|
|
|
for (int k = 0; k < this.fxLayers[i][j].size(); ++k)
|
|
{
|
|
final EntityFX entityfx = (EntityFX)this.fxLayers[i][j].get(k);
|
|
|
|
entityfx.renderParticle(worldrenderer, entityIn, partialTicks, f, f4, f1, f2, f3);
|
|
}
|
|
|
|
Tessellator.draw();
|
|
}
|
|
}
|
|
}
|
|
|
|
GlState.depthMask(true);
|
|
GlState.disableBlend();
|
|
GlState.alphaFunc(516, 0.1F);
|
|
}
|
|
|
|
public void renderLitParticles(Entity entityIn, float partialTick)
|
|
{
|
|
float f = 0.017453292F;
|
|
float f1 = ExtMath.cos(entityIn.rotYaw * 0.017453292F);
|
|
float f2 = ExtMath.sin(entityIn.rotYaw * 0.017453292F);
|
|
float f3 = -f2 * ExtMath.sin(entityIn.rotPitch * 0.017453292F);
|
|
float f4 = f1 * ExtMath.sin(entityIn.rotPitch * 0.017453292F);
|
|
float f5 = ExtMath.cos(entityIn.rotPitch * 0.017453292F);
|
|
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
List<EntityFX> list = this.fxLayers[3][i];
|
|
|
|
if (!list.isEmpty())
|
|
{
|
|
// Tessellator tessellator = Tessellator.getInstance();
|
|
RenderBuffer worldrenderer = Tessellator.getBuffer();
|
|
|
|
for (int j = 0; j < list.size(); ++j)
|
|
{
|
|
EntityFX entityfx = (EntityFX)list.get(j);
|
|
entityfx.renderParticle(worldrenderer, entityIn, partialTick, f1, f5, f2, f3, f4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void clearEffects(World worldIn)
|
|
{
|
|
this.worldObj = worldIn;
|
|
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
for (int j = 0; j < 2; ++j)
|
|
{
|
|
this.fxLayers[i][j].clear();
|
|
}
|
|
}
|
|
|
|
this.particleEmitters.clear();
|
|
}
|
|
|
|
public void addBlockDestroyEffects(BlockPos pos, State state)
|
|
{
|
|
if (state.getBlock().getMaterial() != Material.air)
|
|
{
|
|
state = state.getBlock().getActualState(state, this.worldObj, pos);
|
|
int i = 4;
|
|
|
|
for (int j = 0; j < i; ++j)
|
|
{
|
|
for (int k = 0; k < i; ++k)
|
|
{
|
|
for (int l = 0; l < i; ++l)
|
|
{
|
|
double d0 = (double)pos.getX() + ((double)j + 0.5D) / (double)i;
|
|
double d1 = (double)pos.getY() + ((double)k + 0.5D) / (double)i;
|
|
double d2 = (double)pos.getZ() + ((double)l + 0.5D) / (double)i;
|
|
this.addEffect((new EntityDiggingFX(this.worldObj, d0, d1, d2, d0 - (double)pos.getX() - 0.5D, d1 - (double)pos.getY() - 0.5D, d2 - (double)pos.getZ() - 0.5D, state)).setBlockPos(pos));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds block hit particles for the specified block
|
|
*/
|
|
public void addBlockHitEffects(BlockPos pos, Facing side)
|
|
{
|
|
State iblockstate = this.worldObj.getState(pos);
|
|
Block block = iblockstate.getBlock();
|
|
|
|
if (block.getRenderType() != -1)
|
|
{
|
|
int i = pos.getX();
|
|
int j = pos.getY();
|
|
int k = pos.getZ();
|
|
float f = 0.1F;
|
|
double d0 = (double)i + this.rand.doublev() * (block.getBlockBoundsMaxX() - block.getBlockBoundsMinX() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinX();
|
|
double d1 = (double)j + this.rand.doublev() * (block.getBlockBoundsMaxY() - block.getBlockBoundsMinY() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinY();
|
|
double d2 = (double)k + this.rand.doublev() * (block.getBlockBoundsMaxZ() - block.getBlockBoundsMinZ() - (double)(f * 2.0F)) + (double)f + block.getBlockBoundsMinZ();
|
|
|
|
if (side == Facing.DOWN)
|
|
{
|
|
d1 = (double)j + block.getBlockBoundsMinY() - (double)f;
|
|
}
|
|
|
|
if (side == Facing.UP)
|
|
{
|
|
d1 = (double)j + block.getBlockBoundsMaxY() + (double)f;
|
|
}
|
|
|
|
if (side == Facing.NORTH)
|
|
{
|
|
d2 = (double)k + block.getBlockBoundsMinZ() - (double)f;
|
|
}
|
|
|
|
if (side == Facing.SOUTH)
|
|
{
|
|
d2 = (double)k + block.getBlockBoundsMaxZ() + (double)f;
|
|
}
|
|
|
|
if (side == Facing.WEST)
|
|
{
|
|
d0 = (double)i + block.getBlockBoundsMinX() - (double)f;
|
|
}
|
|
|
|
if (side == Facing.EAST)
|
|
{
|
|
d0 = (double)i + block.getBlockBoundsMaxX() + (double)f;
|
|
}
|
|
|
|
this.addEffect((new EntityDiggingFX(this.worldObj, d0, d1, d2, 0.0D, 0.0D, 0.0D, iblockstate)).setBlockPos(pos).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F));
|
|
}
|
|
}
|
|
|
|
public void moveToAlphaLayer(EntityFX effect)
|
|
{
|
|
this.moveToLayer(effect, 1, 0);
|
|
}
|
|
|
|
public void moveToNoAlphaLayer(EntityFX effect)
|
|
{
|
|
this.moveToLayer(effect, 0, 1);
|
|
}
|
|
|
|
private void moveToLayer(EntityFX effect, int layerFrom, int layerTo)
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
if (this.fxLayers[i][layerFrom].contains(effect))
|
|
{
|
|
this.fxLayers[i][layerFrom].remove(effect);
|
|
this.fxLayers[i][layerTo].add(effect);
|
|
}
|
|
}
|
|
}
|
|
|
|
public String getStatistics()
|
|
{
|
|
int i = 0;
|
|
|
|
for (int j = 0; j < 4; ++j)
|
|
{
|
|
for (int k = 0; k < 2; ++k)
|
|
{
|
|
i += this.fxLayers[j][k].size();
|
|
}
|
|
}
|
|
|
|
return "" + i;
|
|
}
|
|
}
|