mirror of
https://github.com/HbmMods/Hbm-s-Nuclear-Tech-GIT.git
synced 2026-01-25 10:32:49 +00:00
380 lines
14 KiB
Java
380 lines
14 KiB
Java
package com.hbm.render.entity.effect;
|
|
|
|
import java.util.Random;
|
|
|
|
import org.lwjgl.opengl.GL11;
|
|
|
|
import com.hbm.entity.effect.EntityNukeCloudSmall;
|
|
import com.hbm.entity.effect.EntityNukeCloudSmall.Cloudlet;
|
|
import com.hbm.lib.RefStrings;
|
|
import com.hbm.main.ResourceManager;
|
|
import com.hbm.render.loader.HFRWavefrontObject;
|
|
|
|
import net.minecraft.client.renderer.ActiveRenderInfo;
|
|
import net.minecraft.client.renderer.OpenGlHelper;
|
|
import net.minecraft.client.renderer.RenderHelper;
|
|
import net.minecraft.client.renderer.Tessellator;
|
|
import net.minecraft.client.renderer.entity.Render;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.util.MathHelper;
|
|
import net.minecraft.util.ResourceLocation;
|
|
import net.minecraftforge.client.model.IModelCustom;
|
|
|
|
public class RenderSmallNukeMK4 extends Render {
|
|
|
|
public static final IModelCustom mush = new HFRWavefrontObject(new ResourceLocation(RefStrings.MODID, "models/effect/mush.obj"));
|
|
public static final IModelCustom shockwave = new HFRWavefrontObject(new ResourceLocation(RefStrings.MODID, "models/effect/ring_roller.obj"));
|
|
public static final IModelCustom thinring = new HFRWavefrontObject(new ResourceLocation(RefStrings.MODID, "models/effect/ring_thin.obj"));
|
|
private static final ResourceLocation cloudlet = new ResourceLocation(RefStrings.MODID + ":textures/particle/particle_base.png");
|
|
|
|
/*
|
|
* // // ////// ////// // //
|
|
* //// //// // // // //// //
|
|
* // // // ////// // // ////
|
|
* // // // // // // //
|
|
* // // // // ////// // //
|
|
*/
|
|
|
|
/**
|
|
* Look how nice and clean this is!
|
|
*/
|
|
@Override
|
|
public void doRender(Entity entity, double x, double y, double z, float f0, float interp) {
|
|
|
|
GL11.glPushMatrix();
|
|
GL11.glTranslated(x, y, z);
|
|
|
|
EntityNukeCloudSmall cloud = (EntityNukeCloudSmall)entity;
|
|
|
|
mushWrapper(cloud, interp);
|
|
cloudletWrapper(cloud, interp);
|
|
flashWrapper(cloud, interp);
|
|
|
|
GL11.glPopMatrix();
|
|
}
|
|
|
|
@Override
|
|
protected ResourceLocation getEntityTexture(Entity entity) {
|
|
return null;
|
|
}
|
|
|
|
/*
|
|
* // // ////// ////// ////// ////// ////// ////// //////
|
|
* // // // // // // // // // // // // // //
|
|
* // // // //// ////// ////// ////// //// //// //////
|
|
* //// //// // // // // // // // // // //
|
|
* // // // // // // // // ////// // // //////
|
|
*/
|
|
|
|
/**
|
|
* Wrapper for the initial flash
|
|
* Caps the rendering at 60 ticks and sets the alpha function
|
|
* @param cloud
|
|
* @param interp
|
|
*/
|
|
private void flashWrapper(EntityNukeCloudSmall cloud, float interp) {
|
|
|
|
if(cloud.age < 60) {
|
|
|
|
GL11.glPushMatrix();
|
|
//Function [0, 1] that determines the scale and intensity (inverse!) of the flash
|
|
double scale = (cloud.ticksExisted + interp) / 60D;
|
|
GL11.glAlphaFunc(GL11.GL_GEQUAL, 0.0F);
|
|
|
|
//Euler function to slow down the scale as it progresses
|
|
//Makes it start fast and the fade-out is nice and smooth
|
|
scale = scale * Math.pow(Math.E, -scale) * 2.717391304D;
|
|
|
|
renderFlash(scale);
|
|
GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
|
GL11.glPopMatrix();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrapper for the entire mush (head + stem)
|
|
* Renders the entire thing twice to allow for smooth color gradients
|
|
* @param cloud
|
|
* @param interp
|
|
*/
|
|
private void mushWrapper(EntityNukeCloudSmall cloud, float interp) {
|
|
|
|
float size = cloud.getDataWatcher().getWatchableObjectFloat(18) * 5;
|
|
|
|
GL11.glPushMatrix();
|
|
|
|
GL11.glScalef(size, size, size);
|
|
|
|
boolean balefire = cloud.getDataWatcher().getWatchableObjectByte(19) == 1;
|
|
|
|
if(balefire)
|
|
bindTexture(ResourceManager.balefire);
|
|
else
|
|
bindTexture(ResourceManager.fireball);
|
|
|
|
GL11.glDisable(GL11.GL_CULL_FACE);
|
|
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
|
GL11.glDisable(GL11.GL_LIGHTING);
|
|
|
|
//Float [0, 1] for the initial solid-colored layer fade-in
|
|
float func = MathHelper.clamp_float((cloud.ticksExisted + interp) * 0.0075F, 0, 1);
|
|
//Function that determines how high the cloud has risen. The values are the results of trial and error and i forgot what they mean
|
|
double height = Math.max(20 - 30 * 20 / ((((cloud.ticksExisted + interp) * 0.5) - 60 * 0.1) + 1), 0);
|
|
|
|
if(balefire)
|
|
GL11.glColor4f(1.0F - (1.0F - 0.64F) * func, 1.0F, 1.0F - (1.0F - 0.5F) * func, 1F);
|
|
else
|
|
GL11.glColor4f(1.0F, 1.0F - (1.0F - 0.7F) * func, 1.0F - (1.0F - 0.48F) * func, 1F);
|
|
|
|
renderMushHead(cloud.ticksExisted + interp, height);
|
|
renderMushStem(cloud.ticksExisted + interp, height);
|
|
GL11.glEnable(GL11.GL_LIGHTING);
|
|
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
|
|
|
//Float [0.75, 0] That determines the occupancy of the texture layer
|
|
float texAlpha = func * 0.875F;
|
|
|
|
GL11.glColor4f(1F, 1F, 1F, texAlpha);
|
|
//Sets blend to "how you'd expect it" mode
|
|
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
|
|
GL11.glEnable(GL11.GL_BLEND);
|
|
|
|
//And now we fuck with texture transformations
|
|
GL11.glMatrixMode(GL11.GL_TEXTURE);
|
|
GL11.glLoadIdentity();
|
|
|
|
GL11.glTranslated(0, -(cloud.ticksExisted + interp) * 0.035, 0);
|
|
|
|
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
|
|
|
GL11.glPushMatrix();
|
|
//It's the thing that makes glow-in-the-dark work
|
|
GL11.glPushAttrib(GL11.GL_LIGHTING_BIT);
|
|
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240F, 240F);
|
|
renderMushHead(cloud.ticksExisted + interp, height);
|
|
renderMushStem(cloud.ticksExisted + interp, height);
|
|
GL11.glEnable(GL11.GL_LIGHTING);
|
|
GL11.glPopAttrib();
|
|
GL11.glPopMatrix();
|
|
|
|
//Clean this up otherwise the game becomes one-dimensional
|
|
GL11.glMatrixMode(GL11.GL_TEXTURE);
|
|
GL11.glLoadIdentity();
|
|
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
|
|
|
GL11.glDisable(GL11.GL_BLEND);
|
|
GL11.glEnable(GL11.GL_CULL_FACE);
|
|
|
|
GL11.glPopMatrix();
|
|
}
|
|
|
|
/**
|
|
* Adds all cloudlets to the tessellator and then draws them
|
|
* @param cloud
|
|
* @param interp
|
|
*/
|
|
private void cloudletWrapper(EntityNukeCloudSmall cloud, float interp) {
|
|
|
|
GL11.glPushMatrix();
|
|
GL11.glEnable(GL11.GL_BLEND);
|
|
//To prevent particles cutting off before fully fading out
|
|
GL11.glAlphaFunc(GL11.GL_GEQUAL, 0.01F);
|
|
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
|
|
RenderHelper.disableStandardItemLighting();
|
|
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
|
GL11.glDepthMask(false);
|
|
|
|
bindTexture(cloudlet);
|
|
|
|
Tessellator tess = Tessellator.instance;
|
|
tess.startDrawingQuads();
|
|
|
|
for(Cloudlet cloudlet : cloud.cloudlets) {
|
|
float scale = cloud.age + interp - cloudlet.age;
|
|
tessellateCloudlet(tess, cloudlet.posX, cloudlet.posY - cloud.posY + 2, cloudlet.posZ, scale, cloud.getDataWatcher().getWatchableObjectByte(19));
|
|
}
|
|
|
|
/*Random rand = new Random(cloud.getEntityId());
|
|
float size = cloud.getDataWatcher().getWatchableObjectFloat(18);
|
|
|
|
for(int i = 0; i < 300 * size; i++) {
|
|
|
|
float scale = size * 10;
|
|
Vec3 vec = Vec3.createVectorHelper(rand.nextGaussian() * scale, 0, rand.nextGaussian() * scale);
|
|
|
|
tessellateCloudlet(tess, vec.xCoord, (scale - vec.lengthVector()) * rand.nextDouble() * 0.5, vec.zCoord - 10, (float)(cloud.age * cloud.cloudletLife) / cloud.maxAge, cloud.getDataWatcher().getWatchableObjectByte(19));
|
|
}*/
|
|
|
|
tess.draw();
|
|
|
|
GL11.glDepthMask(true);
|
|
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
|
RenderHelper.enableStandardItemLighting();
|
|
GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
|
GL11.glDisable(GL11.GL_BLEND);
|
|
GL11.glPopMatrix();
|
|
}
|
|
|
|
/*
|
|
* ////// ////// // // //// ////// ////// ////// ////// //////
|
|
* // // // //// // // // // // // // // // //
|
|
* //// //// // //// // // //// //// //// //// //////
|
|
* // // // // // // // // // // // // // //
|
|
* // // ////// // // //// ////// // // ////// // // //////
|
|
*/
|
|
|
|
/**
|
|
* Once again the recycled ender dragon death animation
|
|
* It worked so well the last 14 times, let's go for 15
|
|
* @param intensity Double [0, 1] that determines scale and alpha
|
|
*/
|
|
private void renderFlash(double intensity) {
|
|
|
|
GL11.glScalef(0.2F, 0.2F, 0.2F);
|
|
|
|
double inverse = 1.0D - intensity;
|
|
|
|
Tessellator tessellator = Tessellator.instance;
|
|
RenderHelper.disableStandardItemLighting();
|
|
|
|
Random random = new Random(432L);
|
|
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
|
GL11.glShadeModel(GL11.GL_SMOOTH);
|
|
GL11.glEnable(GL11.GL_BLEND);
|
|
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
|
|
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
|
GL11.glEnable(GL11.GL_CULL_FACE);
|
|
GL11.glDepthMask(false);
|
|
|
|
GL11.glPushMatrix();
|
|
|
|
float scale = 100;
|
|
|
|
for(int i = 0; i < 300; i++) {
|
|
|
|
GL11.glRotatef(random.nextFloat() * 360.0F, 1.0F, 0.0F, 0.0F);
|
|
GL11.glRotatef(random.nextFloat() * 360.0F, 0.0F, 1.0F, 0.0F);
|
|
GL11.glRotatef(random.nextFloat() * 360.0F, 0.0F, 0.0F, 1.0F);
|
|
GL11.glRotatef(random.nextFloat() * 360.0F, 1.0F, 0.0F, 0.0F);
|
|
GL11.glRotatef(random.nextFloat() * 360.0F, 0.0F, 1.0F, 0.0F);
|
|
|
|
float vert1 = (random.nextFloat() * 20.0F + 5.0F + 1 * 10.0F) * (float)(intensity * scale);
|
|
float vert2 = (random.nextFloat() * 2.0F + 1.0F + 1 * 2.0F) * (float)(intensity * scale);
|
|
|
|
tessellator.startDrawing(6);
|
|
|
|
tessellator.setColorRGBA_F(1.0F, 1.0F, 1.0F, (float) inverse);
|
|
tessellator.addVertex(0.0D, 0.0D, 0.0D);
|
|
tessellator.setColorRGBA_F(1.0F, 1.0F, 1.0F, 0.0F);
|
|
tessellator.addVertex(-0.866D * vert2, vert1, -0.5F * vert2);
|
|
tessellator.addVertex(0.866D * vert2, vert1, -0.5F * vert2);
|
|
tessellator.addVertex(0.0D, vert1, 1.0F * vert2);
|
|
tessellator.addVertex(-0.866D * vert2, vert1, -0.5F * vert2);
|
|
tessellator.draw();
|
|
}
|
|
|
|
GL11.glPopMatrix();
|
|
|
|
GL11.glDepthMask(true);
|
|
GL11.glDisable(GL11.GL_CULL_FACE);
|
|
GL11.glDisable(GL11.GL_BLEND);
|
|
GL11.glShadeModel(GL11.GL_FLAT);
|
|
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
|
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
|
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
|
RenderHelper.enableStandardItemLighting();
|
|
}
|
|
|
|
/**
|
|
* Render call for the mush head model
|
|
* Includes offset and smoothing
|
|
* Also scales the fireball along XZ
|
|
* @param progress Lifetime + interpolation number
|
|
* @param height The current animation offset
|
|
*/
|
|
private void renderMushHead(float progress, double height) {
|
|
|
|
GL11.glPushMatrix();
|
|
|
|
double expansion = 100;
|
|
double width = Math.min(progress, expansion) / expansion * 0.3 + 0.7;
|
|
|
|
GL11.glTranslated(0, -26 + height, 0);
|
|
GL11.glScaled(width, 1, width);
|
|
|
|
GL11.glShadeModel(GL11.GL_SMOOTH);
|
|
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
|
mush.renderPart("Ball");
|
|
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
|
GL11.glShadeModel(GL11.GL_FLAT);
|
|
|
|
GL11.glPopMatrix();
|
|
}
|
|
|
|
/**
|
|
* Render call for the mush stem model
|
|
* Includes offset and smoothing
|
|
* @param progress Lifetime + interpolation number
|
|
* @param height The current animation offset
|
|
*/
|
|
private void renderMushStem(float progress, double height) {
|
|
|
|
GL11.glPushMatrix();
|
|
|
|
GL11.glTranslated(0, -26 + height, 0);
|
|
|
|
GL11.glShadeModel(GL11.GL_SMOOTH);
|
|
GL11.glDisable(GL11.GL_ALPHA_TEST);
|
|
mush.renderPart("Stem");
|
|
GL11.glEnable(GL11.GL_ALPHA_TEST);
|
|
GL11.glShadeModel(GL11.GL_FLAT);
|
|
|
|
GL11.glPopMatrix();
|
|
}
|
|
|
|
/**
|
|
* Adds one cloudlet (one face) to the tessellator.
|
|
* Rotation is done using ActiveRenderInfo, which I'd assume runs on magic
|
|
* But hey, if it works for particles, why not here too?
|
|
* @param tess
|
|
* @param posX
|
|
* @param posY
|
|
* @param posZ
|
|
* @param age The mush' age when the cloudlet was created
|
|
* @param type DataWatcher byte #19 which differentiates between different mush types
|
|
*/
|
|
private void tessellateCloudlet(Tessellator tess, double posX, double posY, double posZ, float age, int type) {
|
|
|
|
float alpha = 1F - Math.max(age / (float)(EntityNukeCloudSmall.cloudletLife), 0F);
|
|
float alphaorig = alpha;
|
|
|
|
float scale = 5F * (alpha * 0.5F + 0.5F);
|
|
|
|
if(age < 3)
|
|
alpha = age * 0.333F;
|
|
|
|
float f1 = ActiveRenderInfo.rotationX;
|
|
float f2 = ActiveRenderInfo.rotationZ;
|
|
float f3 = ActiveRenderInfo.rotationYZ;
|
|
float f4 = ActiveRenderInfo.rotationXY;
|
|
float f5 = ActiveRenderInfo.rotationXZ;
|
|
|
|
Random rand = new Random((long) ((posX * 5 + posY * 25 + posZ * 125) * 1000D));
|
|
|
|
float brightness = rand.nextFloat() * 0.25F + 0.25F;
|
|
|
|
if(type == 1) {
|
|
tess.setColorRGBA_F(0.25F * alphaorig, alphaorig - brightness * 0.5F, 0.25F * alphaorig, alpha);
|
|
} else {
|
|
|
|
tess.setColorRGBA_F(brightness, brightness, brightness, alpha);
|
|
}
|
|
|
|
tess.addVertexWithUV((double)(posX - f1 * scale - f3 * scale), (double)(posY - f5 * scale), (double)(posZ - f2 * scale - f4 * scale), 1, 1);
|
|
tess.addVertexWithUV((double)(posX - f1 * scale + f3 * scale), (double)(posY + f5 * scale), (double)(posZ - f2 * scale + f4 * scale), 1, 0);
|
|
tess.addVertexWithUV((double)(posX + f1 * scale + f3 * scale), (double)(posY + f5 * scale), (double)(posZ + f2 * scale + f4 * scale), 0, 0);
|
|
tess.addVertexWithUV((double)(posX + f1 * scale - f3 * scale), (double)(posY - f5 * scale), (double)(posZ + f2 * scale - f4 * scale), 0, 1);
|
|
|
|
}
|
|
}
|