Files
ReplayModCinematic/src/main/java/eu/crushedpixel/replaymod/video/entity/CustomEntityRenderer.java

466 lines
18 KiB
Java

package eu.crushedpixel.replaymod.video.entity;
import eu.crushedpixel.replaymod.coremod.asm_Hooks;
import eu.crushedpixel.replaymod.renderer.SpectatorRenderer;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.settings.RenderOptions;
import eu.crushedpixel.replaymod.video.capturer.CaptureData;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.EffectRenderer;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.culling.ClippingHelperImpl;
import net.minecraft.client.renderer.culling.ICamera;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.EnumWorldBlockLayer;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.glu.Project;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import static net.minecraft.client.renderer.GlStateManager.*;
import static org.lwjgl.opengl.GL11.*;
public class CustomEntityRenderer<D extends CaptureData> implements eu.crushedpixel.replaymod.video.capturer.WorldRenderer<D> {
public final Minecraft mc = Minecraft.getMinecraft();
public final EntityRenderer proxied = mc.entityRenderer;
protected final SpectatorRenderer spectatorRenderer = new SpectatorRenderer(){
@Override
protected void gluPerspective(float fovY, float aspect, float zNear, float zFar) {
CustomEntityRenderer.this.gluPerspective(fovY, aspect, zNear, zFar);
}
};
public GluPerspectiveHook gluPerspectiveHook;
public LoadShaderHook loadShaderHook;
protected int frameCount;
protected D data;
protected final RenderOptions options;
public CustomEntityRenderer(RenderOptions options) {
this.options = options;
// Install entity renderer hooks
try {
Field hookField = EntityRenderer.class.getField("hook");
hookField.set(proxied, this);
} catch (NoSuchFieldException e) {
throw new Error(e);
} catch (IllegalAccessException e) {
throw new Error(e);
}
if (options.isHideNameTags()) {
asm_Hooks.DO_NOT_RENDER_NAME_TAGS = true;
}
}
@SuppressWarnings("unused") // Method called by ASM hook
public void loadShader(ResourceLocation resourceLocation) {
if (loadShaderHook != null) {
loadShaderHook.loadShader(resourceLocation);
} else {
original_loadShader(resourceLocation);
}
}
@SuppressWarnings("unused")
protected final void original_loadShader(ResourceLocation resourceLocation) {
// Method body generated by ASM
}
protected void gluPerspective(float fovY, float aspect, float zNear, float zFar) {
if (gluPerspectiveHook == null) {
Project.gluPerspective(fovY, aspect, zNear, zFar);
} else {
gluPerspectiveHook.gluPerspective(fovY, aspect, zNear, zFar);
}
}
public void withDisplaySize(int displayWidth, int displayHeight, Runnable runnable) {
final int prevWidth = mc.displayWidth;
final int prevHeight = mc.displayHeight;
mc.displayWidth = displayWidth;
mc.displayHeight = displayHeight;
runnable.run();
mc.displayWidth = prevWidth;
mc.displayHeight = prevHeight;
}
public void renderWorld(float partialTicks, long finishTimeNano) {
proxied.updateLightmap(partialTicks);
enableDepth();
enableAlpha();
alphaFunc(516, 0.5F);
renderWorldPass(partialTicks, finishTimeNano, 2);
}
protected void renderWorldPass(float partialTicks, long finishTimeNano, int renderPass) {
RenderGlobal renderglobal = mc.renderGlobal;
Entity entity = mc.getRenderViewEntity();
enableCull();
viewport(0, 0, mc.displayWidth, mc.displayHeight);
proxied.updateFogColor(partialTicks);
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
setupCameraTransform(partialTicks);
ActiveRenderInfo.updateRenderInfo(mc.thePlayer, mc.gameSettings.thirdPersonView == 2);
ClippingHelperImpl.getInstance();
ICamera camera = new NoCullingCamera();
if (this.mc.gameSettings.renderDistanceChunks >= 4 || !options.isDefaultSky() ) {
setupFog(-1, partialTicks);
matrixMode(GL_PROJECTION);
loadIdentity();
gluPerspective(proxied.getFOVModifier(partialTicks, true), (float) mc.displayWidth / mc.displayHeight, 0.05F, proxied.farPlaneDistance * 2.0F);
matrixMode(GL_MODELVIEW);
if (options.isDefaultSky()) {
renderglobal.renderSky(partialTicks, renderPass);
} else {
int c = options.getSkyColor();
clearColor((c >> 16 & 0xff) / (float) 0xff, (c >> 8 & 0xff) / (float) 0xff, (c & 0xff) / (float) 0xff, 1);
clear(GL_COLOR_BUFFER_BIT);
}
matrixMode(GL_PROJECTION);
loadIdentity();
gluPerspective(proxied.getFOVModifier(partialTicks, true), (float) mc.displayWidth / mc.displayHeight, 0.05F, proxied.farPlaneDistance * MathHelper.SQRT_2);
matrixMode(GL_MODELVIEW);
}
setupFog(0, partialTicks);
shadeModel(GL_SMOOTH);
if (entity.posY + entity.getEyeHeight() < 128) {
renderCloudsCheck(renderglobal, partialTicks, renderPass);
}
setupFog(0, partialTicks);
mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
RenderHelper.disableStandardItemLighting();
renderglobal.setupTerrain(entity, partialTicks, camera, frameCount++, mc.thePlayer.isSpectator());
renderglobal.updateChunks(finishTimeNano);
matrixMode(GL_MODELVIEW);
pushMatrix();
disableAlpha();
renderglobal.renderBlockLayer(EnumWorldBlockLayer.SOLID, partialTicks, renderPass, entity);
enableAlpha();
renderglobal.renderBlockLayer(EnumWorldBlockLayer.CUTOUT_MIPPED, partialTicks, renderPass, entity);
mc.getTextureManager().getTexture(TextureMap.locationBlocksTexture).setBlurMipmap(false, false);
renderglobal.renderBlockLayer(EnumWorldBlockLayer.CUTOUT, partialTicks, renderPass, entity);
mc.getTextureManager().getTexture(TextureMap.locationBlocksTexture).restoreLastBlurMipmap();
shadeModel(GL_FLAT);
alphaFunc(516, 0.1F);
matrixMode(GL_MODELVIEW);
popMatrix();
pushMatrix();
RenderHelper.enableStandardItemLighting();
net.minecraftforge.client.ForgeHooksClient.setRenderPass(0);
renderglobal.renderEntities(entity, camera, partialTicks);
net.minecraftforge.client.ForgeHooksClient.setRenderPass(0);
RenderHelper.disableStandardItemLighting();
proxied.disableLightmap();
matrixMode(GL_MODELVIEW);
popMatrix();
enableBlend();
tryBlendFuncSeparate(770, 1, 1, 0);
renderglobal.drawBlockDamageTexture(Tessellator.getInstance(), Tessellator.getInstance().getWorldRenderer(), entity, partialTicks);
disableBlend();
renderParticles(entity, partialTicks);
depthMask(false);
enableCull();
proxied.renderRainSnow(partialTicks);
depthMask(true);
renderglobal.renderWorldBorder(entity, partialTicks);
disableBlend();
enableCull();
tryBlendFuncSeparate(770, 771, 1, 0);
alphaFunc(516, 0.1F);
setupFog(0, partialTicks);
enableBlend();
depthMask(false);
mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
shadeModel(GL_SMOOTH);
if (mc.gameSettings.fancyGraphics) {
enableBlend();
tryBlendFuncSeparate(770, 771, 1, 0);
renderglobal.renderBlockLayer(EnumWorldBlockLayer.TRANSLUCENT, partialTicks, renderPass, entity);
disableBlend();
} else {
renderglobal.renderBlockLayer(EnumWorldBlockLayer.TRANSLUCENT, partialTicks, renderPass, entity);
}
RenderHelper.enableStandardItemLighting();
net.minecraftforge.client.ForgeHooksClient.setRenderPass(1);
renderglobal.renderEntities(entity, camera, partialTicks);
net.minecraftforge.client.ForgeHooksClient.setRenderPass(-1);
RenderHelper.disableStandardItemLighting();
shadeModel(GL_FLAT);
depthMask(true);
enableCull();
disableBlend();
disableFog();
if (entity.posY + entity.getEyeHeight() >= 128) {
renderCloudsCheck(renderglobal, partialTicks, renderPass);
}
net.minecraftforge.client.ForgeHooksClient.dispatchRenderLast(renderglobal, partialTicks);
renderSpectatorHand(partialTicks, renderPass);
}
protected void renderParticles(Entity entity, float partialTicks) {
proxied.enableLightmap();
renderLitParticles(entity, partialTicks);
RenderHelper.disableStandardItemLighting();
setupFog(0, partialTicks);
renderNormalParticles(entity, partialTicks);
proxied.disableLightmap();
}
protected void renderLitParticles(Entity entity, float partialTicks) {
EffectRenderer effectRenderer = mc.effectRenderer;
Tessellator tessellator = Tessellator.getInstance();
WorldRenderer worldrenderer = tessellator.getWorldRenderer();
double yaw = Math.toRadians(entity.rotationYaw);
double pitch = Math.toRadians(entity.rotationPitch);
float rotX = (float) Math.cos(yaw);
float rotZ = (float) Math.sin(yaw);
float rotXZ = (float) Math.cos(pitch);
float rotYZ = (float) (-rotZ * Math.sin(pitch));
float rotXY = (float) (rotX * Math.sin(pitch));
for (int i = 0; i < 2; i++) {
@SuppressWarnings("unchecked")
List<EntityFX> list = (List<EntityFX>) effectRenderer.fxLayers[3][i];
for (EntityFX fx : list) {
worldrenderer.setBrightness(fx.getBrightnessForRender(partialTicks));
renderParticle(fx, worldrenderer, entity, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY);
}
}
}
protected void renderNormalParticles(Entity entity, float partialTicks) {
EffectRenderer effectRenderer = mc.effectRenderer;
TextureManager textureManager = mc.getTextureManager();
Tessellator tessellator = Tessellator.getInstance();
WorldRenderer worldRenderer = tessellator.getWorldRenderer();
double yaw = Math.toRadians(entity.rotationYaw);
double pitch = Math.toRadians(entity.rotationPitch);
float rotX = (float) Math.cos(yaw);
float rotZ = (float) Math.sin(yaw);
float rotXZ = (float) Math.cos(pitch);
float rotYZ = (float) (-rotZ * Math.sin(pitch));
float rotXY = (float) (rotX * Math.sin(pitch));
EntityFX.interpPosX = entity.posX;
EntityFX.interpPosY = entity.posY;
EntityFX.interpPosZ = entity.posZ;
enableBlend();
blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
alphaFunc(GL_GREATER, 0.003921569F);
for (int texture = 0; texture < 3; texture++) {
for (int depthMask = 0; depthMask < 2; depthMask++) {
if (effectRenderer.fxLayers[texture][depthMask].isEmpty()) {
continue;
}
if (depthMask == 0) {
GlStateManager.depthMask(false);
} else {
GlStateManager.depthMask(true);
}
if (texture == 1) {
textureManager.bindTexture(TextureMap.locationBlocksTexture);
} else {
textureManager.bindTexture(EffectRenderer.particleTextures);
}
color(1, 1, 1, 1);
worldRenderer.startDrawingQuads();
@SuppressWarnings("unchecked")
List<EntityFX> list = (List<EntityFX>) effectRenderer.fxLayers[texture][depthMask];
for (final EntityFX fx : list) {
worldRenderer.setBrightness(fx.getBrightnessForRender(partialTicks));
renderParticle(fx, worldRenderer, entity, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY);
}
tessellator.draw();
}
}
depthMask(true);
disableBlend();
alphaFunc(516, 0.1F);
}
protected void renderParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks,
float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) {
fx.func_180434_a(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY);
}
protected void renderSpectatorHand(float partialTicks, int renderPass) {
Entity currentEntity = ReplayHandler.getCurrentEntity();
if(!ReplayHandler.isCamera() && currentEntity instanceof EntityPlayer) {
spectatorRenderer.renderSpectatorHand((EntityPlayer) currentEntity, partialTicks, renderPass);
}
}
protected void setupCameraTransform(float partialTicks) {
Entity entity = mc.getRenderViewEntity();
float orgYaw = entity.rotationYaw;
float orgPitch = entity.rotationPitch;
float orgPrevYaw = entity.prevRotationYaw;
float orgPrevPitch = entity.prevRotationPitch;
float orgRoll = ReplayHandler.getCameraTilt();
proxied.farPlaneDistance = (float)(this.mc.gameSettings.renderDistanceChunks * 16);
matrixMode(GL_PROJECTION);
loadIdentity();
gluPerspective(proxied.getFOVModifier(partialTicks, true), (float) this.mc.displayWidth / (float) this.mc.displayHeight, 0.05F, proxied.farPlaneDistance * MathHelper.SQRT_2);
matrixMode(GL_MODELVIEW);
loadIdentity();
orientCamera(partialTicks);
entity.rotationYaw = orgYaw;
entity.rotationPitch = orgPitch;
entity.prevRotationYaw = orgPrevYaw;
entity.prevRotationPitch = orgPrevPitch;
ReplayHandler.setCameraTilt(orgRoll);
}
protected void setupFog(int fogDistanceFlag, float partialTicks) {
if (options.isDefaultSky()) {
proxied.setupFog(fogDistanceFlag, partialTicks);
}
}
protected void orientCamera(float partialTicks) {
Entity entity = mc.getRenderViewEntity();
if (options.getIgnoreCameraRotation()[0]) {
entity.prevRotationYaw = entity.rotationYaw = 0;
}
if (options.getIgnoreCameraRotation()[1]) {
entity.prevRotationPitch = entity.rotationPitch = 0;
}
if (options.getIgnoreCameraRotation()[2]) {
ReplayHandler.setCameraTilt(0);
}
proxied.orientCamera(partialTicks);
}
protected void renderCloudsCheck(RenderGlobal renderglobal, float partialTicks, int renderPass) {
if (this.mc.gameSettings.shouldRenderClouds()) {
matrixMode(GL_PROJECTION);
loadIdentity();
gluPerspective(proxied.getFOVModifier(partialTicks, true), (float) this.mc.displayWidth / (float) this.mc.displayHeight, 0.05F, proxied.farPlaneDistance * 4.0F);
matrixMode(GL_MODELVIEW);
pushMatrix();
setupFog(0, partialTicks);
renderglobal.renderClouds(partialTicks, renderPass);
disableFog();
popMatrix();
matrixMode(GL_PROJECTION);
loadIdentity();
gluPerspective(proxied.getFOVModifier(partialTicks, true), (float)this.mc.displayWidth / (float)this.mc.displayHeight, 0.05F, proxied.farPlaneDistance * MathHelper.SQRT_2);
matrixMode(GL_MODELVIEW);
}
}
@Override
public void close() throws IOException {
try {
Field hookField = EntityRenderer.class.getField("hook");
hookField.set(proxied, null);
} catch (NoSuchFieldException e) {
throw new Error(e);
} catch (IllegalAccessException e) {
throw new Error(e);
}
asm_Hooks.DO_NOT_RENDER_NAME_TAGS = false;
spectatorRenderer.cleanup();
}
@Override
public void renderWorld(ReadableDimension displaySize, final float partialTicks, D data) {
this.data = data;
withDisplaySize(displaySize.getWidth(), displaySize.getHeight(), new Runnable() {
@Override
public void run() {
renderWorld(partialTicks, 0);
if (OpenGlHelper.shadersSupported) {
if (proxied.theShaderGroup != null && proxied.useShader) {
matrixMode(GL_TEXTURE);
pushMatrix();
loadIdentity();
proxied.theShaderGroup.loadShaderGroup(partialTicks);
popMatrix();
}
}
}
});
}
public static final class NoCullingCamera implements ICamera {
@Override
public boolean isBoundingBoxInFrustum(AxisAlignedBB p_78546_1_) {
return true;
}
@Override
public void setPosition(double p_78547_1_, double p_78547_3_, double p_78547_5_) {
}
}
public interface GluPerspectiveHook {
void gluPerspective(float fovY, float aspect, float zNear, float zFar);
}
public interface LoadShaderHook {
void loadShader(ResourceLocation resourceLocation);
}
}