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 implements eu.crushedpixel.replaymod.video.capturer.WorldRenderer { 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 list = (List) 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 list = (List) 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); } }