Add new files for the particle refactoring

This commit is contained in:
Electroblob
2018-05-02 13:17:04 +01:00
parent 8a53cc6150
commit df14912693
7 changed files with 752 additions and 0 deletions
@@ -0,0 +1,136 @@
package electroblob.wizardry.client.particle;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleBuff extends ParticleEntityLinked {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png");
private final boolean mirror;
public ParticleBuff(World world, Entity entity, float r, float g, float b, boolean mirror){
super(world, entity);
this.setRBGColorF(r, g, b);
this.mirror = mirror;
}
public ParticleBuff(World world, Entity entity, int maxAge, float r, float g, float b, boolean mirror){
super(world, entity, maxAge);
this.setRBGColorF(r, g, b);
this.mirror = mirror;
}
@Override
public void init(){
this.particleGravity = 0;
this.posY += 1;
}
@Override
public void onUpdate(){
super.onUpdate();
this.setPosition(this.entity.posX, this.entity.posY + 1 + 4f * this.particleAge/this.particleMaxAge, this.entity.posZ);
if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge;
}
@Override
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ,
float rotationYZ, float rotationXY, float rotationXZ){
GlStateManager.pushMatrix();
GlStateManager.pushAttrib();
float scale = 0.6f;
GlStateManager.scale(scale, scale, scale);
if(mirror) GlStateManager.scale(-1, 1, 1);
GlStateManager.enableBlend();
GlStateManager.disableAlpha();
GlStateManager.disableCull();
GlStateManager.disableLighting();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE);
// Makes the particle colour add to the colour of the texture pixels, rather than the default multiplying
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_ADD);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
// Does the texture translation wrapping thing (the cool stuff)
GlStateManager.matrixMode(GL11.GL_TEXTURE);
GlStateManager.loadIdentity();
GlStateManager.translate((this.particleAge + partialTicks)/(float)this.particleMaxAge * -2, 0, 0);
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
RenderHelper.disableStandardItemLighting();
Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
// I'm pretty sure these were always static.
Particle.interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks;
Particle.interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks;
Particle.interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks;
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
// Increases from 0 to 1 in steps of 0.125 evenly throughout the particle's lifetime
float f = 0.875f - 0.125f * MathHelper.floor((float)this.particleAge/(float)this.particleMaxAge * 8 - 0.000001f);
float g = f + 0.125f;
float hrepeat = 1;
float yScale = 0.7f;
buffer.pos(x-1, y-yScale, z-1).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x-1, y+yScale, z-1).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x+1, y-yScale, z-1).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x+1, y+yScale, z-1).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x+1, y-yScale, z+1).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x+1, y+yScale, z+1).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x-1, y-yScale, z+1).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x-1, y+yScale, z+1).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x-1, y-yScale, z-1).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
buffer.pos(x-1, y+yScale, z-1).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
Tessellator.getInstance().draw();
// Undoes the texture transformations
GlStateManager.matrixMode(GL11.GL_TEXTURE);
GlStateManager.loadIdentity();
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
GlStateManager.disableBlend();
GlStateManager.enableAlpha();
GlStateManager.enableCull();
GlStateManager.enableLighting();
// Reverses the colour addition change from before
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GlStateManager.popAttrib();
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,61 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/**
* Abstract superclass for particles that are linked to entities, i.e. move with a given entity. This is generally used
* for visual effects in spell casting.
*
* @author Electroblob
* @since Wizardry 4.2
*/
@SideOnly(Side.CLIENT)
public abstract class ParticleEntityLinked extends Particle {
/** True if the particle always renders at full brightness. Defaults to false. */
protected boolean fullBrightness = false;
/** The entity this particle is linked to. The particle will move with this entity. */
protected Entity entity;
public ParticleEntityLinked(World world, Entity entity){
super(world, entity.posX, entity.posY, entity.posZ, entity.motionX, entity.motionY, entity.motionZ);
this.entity = entity;
this.init();
}
public ParticleEntityLinked(World world, Entity entity, int maxAge){
this(world, entity);
this.particleMaxAge = maxAge;
}
/**
* Called from both constructors to set constants, avoiding duplicate code. Common fields to set here include:
* particleScale, particleGravity, canCollide, fullBrightness and setting the texture index.
*/
public abstract void init();
/* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png
* to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the
* render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine
* for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was
* presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning
* you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten
* anyway since they bind their own textures. It is of course important to bind the texture every time you render a
* custom particle, but I don't see how you could do it any other way, since you don't have access to
* EffectRenderer. */
@Override
public int getFXLayer(){
// This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer.
return 3;
}
@Override
public int getBrightnessForRender(float partialTick){
return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick);
}
}
@@ -0,0 +1,44 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
/**
* Copied from ParticleFirework.Overlay; for some reason that class has no public constructors, plus I want to change the
* scale and a few other things
* @author Electroblob
* @since Wizardry 4.2.0
*/
public class ParticleFlash extends ParticleWizardry {
public ParticleFlash(World world, double x, double y, double z){
super(world, x, y, z);
this.setRBGColorF(1, 1, 1);
this.particleScale = 7.1f; // 7.1f is the value used in fireworks
this.particleMaxAge = 4;
}
@Override
public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F) * 0.25F * (float)Math.PI);
this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F) * 0.25F * 0.5F);
float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
int i = this.getBrightnessForRender(partialTicks);
int j = i >> 16 & 65535;
int k = i & 65535;
buffer.pos((double)(f5 - rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 - rotationYZ * f4 - rotationXZ * f4)).tex(0.5D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
buffer.pos((double)(f5 - rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 - rotationYZ * f4 + rotationXZ * f4)).tex(0.5D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
buffer.pos((double)(f5 + rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 + rotationYZ * f4 + rotationXZ * f4)).tex(0.25D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
buffer.pos((double)(f5 + rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 + rotationYZ * f4 - rotationXZ * f4)).tex(0.25D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
}
@Override
public int getBrightnessForRender(float partialTicks){
return 15728880;
}
}
@@ -0,0 +1,39 @@
package electroblob.wizardry.client.particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class ParticleMagicBubble extends ParticleWizardry {
public ParticleMagicBubble(World world, double x, double y, double z){
super(world, x, y, z);
this.particleRed = 1.0F;
this.particleGreen = 1.0F;
this.particleBlue = 1.0F;
this.setParticleTextureIndex(32);
this.setSize(0.02F, 0.02F);
this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F;
// this.motionX = par8 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
// this.motionY = par10 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
// this.motionZ = par12 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D));
}
@Override
public void onUpdate(){
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
this.motionY += 0.002D;
this.move(this.motionX, this.motionY, this.motionZ);
this.motionX *= 0.8500000238418579D;
this.motionY *= 0.8500000238418579D;
this.motionZ *= 0.8500000238418579D;
if(this.particleMaxAge-- <= 0){
this.setExpired();
}
}
}
@@ -0,0 +1,94 @@
package electroblob.wizardry.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/**
* Abstract superclass for all of wizardry's particles. This replaces {@code ParticleCustomTexture} (the functionality of
* which is no longer necessary since wizardry now uses {@code TextureAtlasSprite}s to do the rendering), and fits into
* {@code ParticleBuilder} by exposing all the necessary variables through getters, allowing them to be set on the fly
* rather than needing to be passed into the constructor.
* <p>
* The new system is as follows:
* <p>
* - All particle classes have a single constructor which takes a world and a position only.<br>
* - Each particle class defines any relevant default values in its constructor, including velocity.<br>
* - The particle builder then overwrites any other values that were set during building.
* <p>
* This beauty of this system is that there are never any redundant parameters when spawning particles. For example,
* snow particles nearly always fall at the same speed, which can now be defined in the particle class and no longer
* needs to be defined when spawning the particle - but importantly, it can still be overridden if desired.
*
* @author Electroblob
* @since Wizardry 4.2.0
* @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder
*/
@SideOnly(Side.CLIENT)
public abstract class ParticleWizardry extends Particle {
/** True if the particle is shaded, false if the particle always renders at full brightness. Defaults to false. */
protected boolean shaded = false;
protected float fadeRed = 1;
protected float fadeGreen = 1;
protected float fadeBlue = 0;
public ParticleWizardry(World world, double x, double y, double z){
super(world, x, y, z);
}
/** Sets whether the particle should render at full brightness or not. True if the particle is shaded, false if
* the particle always renders at full brightness. Defaults to false.*/
public void setShaded(boolean shaded){
this.shaded = shaded;
}
/** Sets this particle's gravity. True to enable gravity, false to disable. Defaults to false.*/
public void setGravity(boolean gravity){
this.particleGravity = gravity ? 1 : 0;
}
/** Sets this particle's lifetime in ticks.*/
public void setLifetime(int lifetime){
this.particleMaxAge = lifetime;
}
/**
* Sets the velocity of the particle.
* @param vx The x velocity
* @param vy The y velocity
* @param vz The z velocity
*/
public void setVelocity(double vx, double vy, double vz){
this.motionX = vx;
this.motionY = vy;
this.motionZ = vz;
}
/**
* Sets the fade colour of the particle.
* @param r The red colour component
* @param g The green colour component
* @param g The blue colour component
*/
public void setFadeColour(float r, float g, float b){
this.fadeRed = r;
this.fadeGreen = g;
this.fadeBlue = b;
}
@Override
public int getBrightnessForRender(float partialTick){
return shaded ? super.getBrightnessForRender(partialTick) : 15728880;
}
/** Simple particle factory interface which takes a world and a position and returns a particle. Used (via lambda
* expressions) in the client proxy to link particle enum types to actual particle classes. */
@SideOnly(Side.CLIENT)
@FunctionalInterface
public interface IWizardryParticleFactory {
ParticleWizardry createParticle(World world, double x, double y, double z);
}
}