/**
* This class was created by <Azanor>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [? (GMT)]
*/
package vazkii.botania.client.fx;
import java.util.ArrayDeque;
import java.util.Queue;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.client.FMLClientHandler;
import vazkii.botania.client.lib.LibResources;
import vazkii.botania.common.core.handler.ConfigHandler;
public class FXWisp extends Particle {
private static final ResourceLocation vanillaParticles = new ResourceLocation("textures/particle/particles.png");
public static final ResourceLocation particles = new ResourceLocation(LibResources.MISC_WISP_LARGE);
private static final Queue<FXWisp> queuedRenders = new ArrayDeque<>();
private static final Queue<FXWisp> queuedDepthIgnoringRenders = new ArrayDeque<>();
// Queue values
private float f;
private float f1;
private float f2;
private float f3;
private float f4;
private float f5;
public FXWisp(World world, double d, double d1, double d2, float size, float red, float green, float blue, boolean distanceLimit, boolean depthTest, float maxAgeMul) {
super(world, d, d1, d2, 0.0D, 0.0D, 0.0D);
particleRed = red;
particleGreen = green;
particleBlue = blue;
particleAlpha = 0.5F; // So MC renders us on the alpha layer, value not actually used
particleGravity = 0;
motionX = motionY = motionZ = 0;
particleScale *= size;
moteParticleScale = particleScale;
particleMaxAge = (int)(28D / (Math.random() * 0.3D + 0.7D) * maxAgeMul);
this.depthTest = depthTest;
moteHalfLife = particleMaxAge / 2;
setSize(0.01F, 0.01F);
Entity renderentity = FMLClientHandler.instance().getClient().getRenderViewEntity();
if(distanceLimit) {
int visibleDistance = 50;
if (!FMLClientHandler.instance().getClient().gameSettings.fancyGraphics)
visibleDistance = 25;
if (renderentity == null || renderentity.getDistance(posX, posY, posZ) > visibleDistance)
particleMaxAge = 0;
}
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
}
public static void dispatchQueuedRenders(Tessellator tessellator) {
ParticleRenderDispatcher.wispFxCount = 0;
ParticleRenderDispatcher.depthIgnoringWispFxCount = 0;
GlStateManager.color(1.0F, 1.0F, 1.0F, 0.75F);
Minecraft.getMinecraft().renderEngine.bindTexture(ConfigHandler.matrixMode ? vanillaParticles : particles);
if(!queuedRenders.isEmpty()) {
tessellator.getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_LMAP_COLOR);
for(FXWisp wisp : queuedRenders)
wisp.renderQueued(tessellator, true);
tessellator.draw();
}
if(!queuedDepthIgnoringRenders.isEmpty()) {
GlStateManager.disableDepth();
tessellator.getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_LMAP_COLOR);
for(FXWisp wisp : queuedDepthIgnoringRenders)
wisp.renderQueued(tessellator, false);
tessellator.draw();
GlStateManager.enableDepth();
}
queuedRenders.clear();
queuedDepthIgnoringRenders.clear();
}
private void renderQueued(Tessellator tessellator, boolean depthEnabled) {
if(depthEnabled)
ParticleRenderDispatcher.wispFxCount++;
else ParticleRenderDispatcher.depthIgnoringWispFxCount++;
float agescale = (float)particleAge / (float) moteHalfLife;
if (agescale > 1F)
agescale = 2 - agescale;
particleScale = moteParticleScale * agescale;
float f10 = 0.5F * particleScale;
float f11 = (float)(prevPosX + (posX - prevPosX) * f - interpPosX);
float f12 = (float)(prevPosY + (posY - prevPosY) * f - interpPosY);
float f13 = (float)(prevPosZ + (posZ - prevPosZ) * f - interpPosZ);
int combined = 15 << 20 | 15 << 4;
int k3 = combined >> 16 & 0xFFFF;
int l3 = combined & 0xFFFF;
tessellator.getBuffer().pos(f11 - f1 * f10 - f4 * f10, f12 - f2 * f10, f13 - f3 * f10 - f5 * f10).tex(0, 1).lightmap(k3, l3).color(particleRed, particleGreen, particleBlue, 0.5F).endVertex();
tessellator.getBuffer().pos(f11 - f1 * f10 + f4 * f10, f12 + f2 * f10, f13 - f3 * f10 + f5 * f10).tex(1, 1).lightmap(k3, l3).color(particleRed, particleGreen, particleBlue, 0.5F).endVertex();
tessellator.getBuffer().pos(f11 + f1 * f10 + f4 * f10, f12 + f2 * f10, f13 + f3 * f10 + f5 * f10).tex(1, 0).lightmap(k3, l3).color(particleRed, particleGreen, particleBlue, 0.5F).endVertex();
tessellator.getBuffer().pos(f11 + f1 * f10 - f4 * f10, f12 - f2 * f10, f13 + f3 * f10 - f5 * f10).tex(0, 0).lightmap(k3, l3).color(particleRed, particleGreen, particleBlue, 0.5F).endVertex();
}
@Override
public void renderParticle(VertexBuffer wr, Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {
this.f = f;
this.f1 = f1;
this.f2 = f2;
this.f3 = f3;
this.f4 = f4;
this.f5 = f5;
if(depthTest)
queuedRenders.add(this);
else queuedDepthIgnoringRenders.add(this);
}
// [VanillaCopy] of super, without drag when onGround is true
@Override
public void onUpdate() {
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if (this.particleAge++ >= this.particleMaxAge)
{
this.setExpired();
}
this.motionY -= 0.04D * (double)this.particleGravity;
this.move(this.motionX, this.motionY, this.motionZ);
this.motionX *= 0.9800000190734863D;
this.motionY *= 0.9800000190734863D;
this.motionZ *= 0.9800000190734863D;
}
public void setGravity(float value) {
particleGravity = value;
}
public void setSpeed(float mx, float my, float mz) {
motionX = mx;
motionY = my;
motionZ = mz;
}
private boolean depthTest = true;
public boolean distanceLimit = true;
private final float moteParticleScale;
private final int moteHalfLife;
public boolean tinkle = false;
public int blendmode = 1;
}