/** * 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.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import vazkii.botania.client.core.helper.ShaderHelper; import vazkii.botania.client.lib.LibResources; import vazkii.botania.common.core.handler.ConfigHandler; public class FXSparkle extends Particle { private static final ResourceLocation vanillaParticles = new ResourceLocation("textures/particle/particles.png"); public static final ResourceLocation particles = new ResourceLocation(LibResources.MISC_PARTICLES); private static final Queue<FXSparkle> queuedRenders = new ArrayDeque<>(); private static final Queue<FXSparkle> queuedCorruptRenders = new ArrayDeque<>(); // Queue values private float f; private float f1; private float f2; private float f3; private float f4; private float f5; public FXSparkle(World world, double x, double y, double z, float size, float red, float green, float blue, int m) { super(world, x, y, z, 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; particleMaxAge = 3 * m; multiplier = m; setSize(0.01F, 0.01F); prevPosX = posX; prevPosY = posY; prevPosZ = posZ; } public static void dispatchQueuedRenders(Tessellator tessellator) { ParticleRenderDispatcher.sparkleFxCount = 0; ParticleRenderDispatcher.fakeSparkleFxCount = 0; GlStateManager.color(1.0F, 1.0F, 1.0F, 0.75F); Minecraft.getMinecraft().renderEngine.bindTexture(ConfigHandler.matrixMode ? vanillaParticles : particles); tessellator.getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); for(FXSparkle sparkle : queuedRenders) sparkle.renderQueued(tessellator); tessellator.draw(); ShaderHelper.useShader(ShaderHelper.filmGrain); tessellator.getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); for(FXSparkle sparkle : queuedCorruptRenders) sparkle.renderQueued(tessellator); tessellator.draw(); ShaderHelper.releaseShader(); queuedRenders.clear(); queuedCorruptRenders.clear(); } private void renderQueued(Tessellator tessellator) { if(fake) ParticleRenderDispatcher.fakeSparkleFxCount++; else ParticleRenderDispatcher.sparkleFxCount++; int part = particle + particleAge/multiplier; float var8 = part % 8 / 8.0F; float var9 = var8 + 0.0624375F*2; float var10 = part / 8 / 8.0F; float var11 = var10 + 0.0624375F*2; float var12 = 0.1F * particleScale; if (shrink) var12 *= (particleMaxAge-particleAge+1)/(float)particleMaxAge; float var13 = (float)(prevPosX + (posX - prevPosX) * f - interpPosX); float var14 = (float)(prevPosY + (posY - prevPosY) * f - interpPosY); float var15 = (float)(prevPosZ + (posZ - prevPosZ) * f - interpPosZ); float var16 = 1.0F; tessellator.getBuffer().pos(var13 - f1 * var12 - f4 * var12, var14 - f2 * var12, var15 - f3 * var12 - f5 * var12).tex(var9, var11).color(particleRed * var16, particleGreen * var16, particleBlue * var16, 1).endVertex(); tessellator.getBuffer().pos(var13 - f1 * var12 + f4 * var12, var14 + f2 * var12, var15 - f3 * var12 + f5 * var12).tex(var9, var10).color(particleRed * var16, particleGreen * var16, particleBlue * var16, 1).endVertex(); tessellator.getBuffer().pos(var13 + f1 * var12 + f4 * var12, var14 + f2 * var12, var15 + f3 * var12 + f5 * var12).tex(var8, var10).color(particleRed * var16, particleGreen * var16, particleBlue * var16, 1).endVertex(); tessellator.getBuffer().pos(var13 + f1 * var12 - f4 * var12, var14 - f2 * var12, var15 + f3 * var12 - f5 * var12).tex(var8, var11).color(particleRed * var16, particleGreen * var16, particleBlue * var16, 1).endVertex(); } public void setCanCollide(boolean canCollide) { this.canCollide = canCollide; } @Override public void renderParticle(VertexBuffer worldRendererIn, 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(corrupt) queuedCorruptRenders.add(this); else queuedRenders.add(this); } @Override public void onUpdate() { prevPosX = posX; prevPosY = posY; prevPosZ = posZ; if (particleAge++ >= particleMaxAge) setExpired(); motionY -= 0.04D * particleGravity; if (canCollide && !fake) wiggleAround(posX, (getBoundingBox().minY + getBoundingBox().maxY) / 2.0D, posZ); this.move(motionX, motionY, motionZ); if (slowdown) { motionX *= 0.908000001907348633D; motionY *= 0.908000001907348633D; motionZ *= 0.908000001907348633D; if (onGround) { motionX *= 0.69999998807907104D; motionZ *= 0.69999998807907104D; } } if(fake && particleAge > 1) setExpired(); } public void setGravity(float value) { particleGravity = value; } // Copy of Entity.pushOutOfBlocks with several important changes private boolean wiggleAround(double x, double y, double z) { BlockPos blockpos = new BlockPos(x, y, z); double d0 = x - blockpos.getX(); double d1 = y - blockpos.getY(); double d2 = z - blockpos.getZ(); // Botania - change collision box list check to !airblock check if (!world.isAirBlock(blockpos)) { EnumFacing enumfacing = EnumFacing.UP; double d3 = Double.MAX_VALUE; if (!world.isBlockFullCube(blockpos.west()) && d0 < d3) { d3 = d0; enumfacing = EnumFacing.WEST; } if (!world.isBlockFullCube(blockpos.east()) && 1.0D - d0 < d3) { d3 = 1.0D - d0; enumfacing = EnumFacing.EAST; } if (!world.isBlockFullCube(blockpos.north()) && d2 < d3) { d3 = d2; enumfacing = EnumFacing.NORTH; } if (!world.isBlockFullCube(blockpos.south()) && 1.0D - d2 < d3) { d3 = 1.0D - d2; enumfacing = EnumFacing.SOUTH; } if (!world.isBlockFullCube(blockpos.up()) && 1.0D - d1 < d3) { d3 = 1.0D - d1; enumfacing = EnumFacing.UP; } float f = rand.nextFloat() * 0.05F + 0.025F; // Botania - made multiplier and add both smaller float f1 = enumfacing.getAxisDirection().getOffset(); float secondary = (rand.nextFloat() - rand.nextFloat()) * 0.1F; // Botania - Make and use a secondary movement variable below if (enumfacing.getAxis() == EnumFacing.Axis.X) { motionX = f1 * f; motionY = motionZ = secondary; } else if (enumfacing.getAxis() == EnumFacing.Axis.Y) { motionY = f1 * f; motionX = motionZ = secondary; } else if (enumfacing.getAxis() == EnumFacing.Axis.Z) { motionZ = f1 * f; motionX = motionY = secondary; } return true; } return false; } public boolean corrupt = false; public boolean fake = false; private int multiplier = 2; private final boolean shrink = true; public final int particle = 16; public boolean tinkle = false; public final boolean slowdown = true; public int currentColor = 0; }