Skip to content

Instantly share code, notes, and snippets.

@Galaxtone
Created July 18, 2018 01:18
Show Gist options
  • Save Galaxtone/390060cf0099730d7583c45305d654b4 to your computer and use it in GitHub Desktop.
Save Galaxtone/390060cf0099730d7583c45305d654b4 to your computer and use it in GitHub Desktop.
package com.galaxtone.noneuclideanportals.graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.Project;
import com.galaxtone.noneuclideanportals.Portal;
import com.galaxtone.noneuclideanportals.utils.Selection;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.culling.ClippingHelperImpl;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.client.renderer.culling.ICamera;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing.Axis;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RenderHandler {
/* List of client list portal ordered by maximum axis-aligned distance across the X and Z axis */
public static List<Portal> orderedPortalList = new ArrayList<Portal>();
/* Useful for rendering */
private static final Tessellator tessellator = Tessellator.getInstance();
private static final VertexBuffer buffer = tessellator.getBuffer();
/* Used for interpolation for smooth motion */
public static float partialTicks;
/* Entity that the player is spectating or the player themselves if their not, and the interpolation for smooth rendering */
public static Entity entity;
public static Vec3d offset;
/* Used to skip the Render event when redrawing the world */
public static boolean skipEvent = false;
/* Used for interpolating things */
private static double interpolate(double oldValue, double newValue) {
return oldValue + (newValue - oldValue) * partialTicks;
}
private static Vec3d interpolate(double oldX, double oldY, double oldZ, double newX, double newY, double newZ) {
return new Vec3d(
interpolate(oldX, newX),
interpolate(oldY, newY),
interpolate(oldZ, newZ));
}
/* Called every frame to update everything for rendering the current frame */
public static void update(float newPartialTicks) {
partialTicks = newPartialTicks;
entity = Minecraft.getMinecraft().getRenderViewEntity();
offset = interpolate(entity.prevPosX, entity.prevPosY, entity.prevPosZ, entity.posX, entity.posY, entity.posZ);
Map<Portal, Double> distance = new HashMap<Portal, Double>(Portal.clientList.size());
for (Portal portal : Portal.clientList)
distance.put(portal, Math.max(portal.position.getX() + 0.5D - entity.posX, portal.position.getY() + 0.5D - entity.posZ));
List<Entry<Portal, Double>> entries = new ArrayList<Entry<Portal, Double>>(distance.entrySet());
entries.sort(Entry.comparingByValue());
int length = 0;
for (Entry<Portal, Double> entry : entries)
if (entity.worldObj.isBlockLoaded(entry.getKey().position))
length++;
else
break;
orderedPortalList = new ArrayList<Portal>(Portal.clientList.size());
int index = 0;
for (Entry<Portal, Double> entry : entries) {
if (++index > length)
break;
orderedPortalList.add(entry.getKey());
}
}
/* Draws a square */
private static void drawQuad(Axis axis, AxisAlignedBB plane) {
plane = plane.offset(-offset.xCoord, -offset.yCoord, -offset.zCoord);
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
switch (axis) {
case X:
buffer.pos(plane.minX, plane.minY, plane.minZ).endVertex();
buffer.pos(plane.minX, plane.minY, plane.maxZ).endVertex();
buffer.pos(plane.minX, plane.maxY, plane.maxZ).endVertex();
buffer.pos(plane.minX, plane.maxY, plane.minZ).endVertex();
break;
case Z:
buffer.pos(plane.minX, plane.minY, plane.minZ).endVertex();
buffer.pos(plane.maxX, plane.minY, plane.minZ).endVertex();
buffer.pos(plane.maxX, plane.maxY, plane.minZ).endVertex();
buffer.pos(plane.minX, plane.maxY, plane.minZ).endVertex();
break;
case Y:
buffer.pos(plane.minX, plane.minY, plane.minZ).endVertex();
buffer.pos(plane.maxX, plane.minY, plane.minZ).endVertex();
buffer.pos(plane.maxX, plane.minY, plane.maxZ).endVertex();
buffer.pos(plane.minX, plane.minY, plane.maxZ).endVertex();
break;
}
tessellator.draw();
}
/* Draws a square centered within the blocks */
private static void drawCenteredQuad(Axis axis, AxisAlignedBB plane) {
switch (axis) {
case X:
plane = plane.offset(0.5, 0, 0);
break;
case Z:
plane = plane.offset(0, 0, 0.5);
break;
case Y:
plane = plane.offset(0, 0.5, 0);
break;
}
drawQuad(axis, plane);
}
/* Draws an outline of an area */
private static void drawBoxOutline(AxisAlignedBB box) {
box = box.offset(-offset.xCoord, -offset.yCoord, -offset.zCoord);
buffer.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION);
buffer.pos(box.minX, box.minY, box.minZ).endVertex();
buffer.pos(box.maxX, box.minY, box.minZ).endVertex();
buffer.pos(box.maxX, box.minY, box.maxZ).endVertex();
buffer.pos(box.minX, box.minY, box.maxZ).endVertex();
buffer.pos(box.minX, box.minY, box.minZ).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION);
buffer.pos(box.minX, box.minY, box.minZ).endVertex();
buffer.pos(box.minX, box.maxY, box.minZ).endVertex();
buffer.pos(box.maxX, box.minY, box.minZ).endVertex();
buffer.pos(box.maxX, box.maxY, box.minZ).endVertex();
buffer.pos(box.maxX, box.minY, box.maxZ).endVertex();
buffer.pos(box.maxX, box.maxY, box.maxZ).endVertex();
buffer.pos(box.minX, box.minY, box.maxZ).endVertex();
buffer.pos(box.minX, box.maxY, box.maxZ).endVertex();
tessellator.draw();
buffer.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION);
buffer.pos(box.minX, box.maxY, box.minZ).endVertex();
buffer.pos(box.maxX, box.maxY, box.minZ).endVertex();
buffer.pos(box.maxX, box.maxY, box.maxZ).endVertex();
buffer.pos(box.minX, box.maxY, box.maxZ).endVertex();
buffer.pos(box.minX, box.maxY, box.minZ).endVertex();
tessellator.draw();
}
/* Renders current selection area for new portal creation */
public static void renderSelection() {
GlStateManager.enableBlend();
GlStateManager.disableDepth();
GlStateManager.disableCull();
GlStateManager.disableTexture2D();
GlStateManager.color(0.8F, 0.0F, 0.8F, 0.3F);
drawCenteredQuad(Selection.axis, Selection.plane);
drawBoxOutline(Selection.plane);
GlStateManager.disableBlend();
GlStateManager.enableDepth();
GlStateManager.enableCull();
GlStateManager.enableTexture2D();
}
/* Renders all the portals */
public static void renderPortals() {
Vec3d position = ActiveRenderInfo.projectViewFromEntity(entity, partialTicks);
for (Portal portal : orderedPortalList) {
Portal.Side side = portal.getSide(position);
BlockPos min = new BlockPos(side.plane.minX, side.plane.minY, side.plane.minZ);
BlockPos max = new BlockPos(side.plane.maxX, side.plane.maxY, side.plane.maxZ);
if (entity.worldObj.isAreaLoaded(min, max)) continue;
GlStateManager.disableCull();
GlStateManager.disableTexture2D();
GlStateManager.enableCull();
GlStateManager.enableTexture2D();
/*GlStateManager.colorMask(false, false, false, false);
GlStateManager.depthMask(false);
GlStateManager.disableDepth();
GL11.glEnable(GL11.GL_STENCIL);
GL11.glStencilOp(GL11.GL_INCR, zfail, zpass);
GL11.glStencilFunc(GL11.GL_NEVER, ref, mask);
drawQuad(side.portal.axis, side.plane);*/
}/*
GL11.glStencilFunc(GL11.GL_NOTEQUAL, recursionLevel, mask);
GL11.glStencilOp(GL11.GL_INCR, GL11.GL_KEEP, GL11.GL_KEEP);
GL11.glStencilMask(0xFF);
GlStateManager.getFloat(GL11.GL_PROJECTION_MATRIX, projectionMatrixBuffer);
Matrix4f projMat = (Matrix4f) new Matrix4f().load(projectionMatrixBuffer.asReadOnlyBuffer());
Quaternion clip = new Quaternion();
Quaternion quat = new Quaternion();
quat.x = (Math.signum(clip.x) + projMat.m20) / projMat.m00;
quat.y = (Math.signum(clip.y) + projMat.m21) / projMat.m11;
quat.z = -1.0F;
quat.w = (1.0F + projMat.m22) / projMat.m23;
float dot = 2f / Quaternion.dot(clip, quat);
projMat.m02 = clip.x * dot;
projMat.m12 = clip.y * dot;
projMat.m22 = clip.z * dot + 1F;
projMat.m32 = 1f;
projMat.store(projectionMatrixBuffer);
GlStateManager.matrixMode(GL11.GL_PROJECTION);
GL11.glLoadMatrix(projectionMatrixBuffer.asReadOnlyBuffer());
// TODO https://cdn.discordapp.com/attachments/294069306608582656/436437528728567809/unknown.png
// Draw 5 quads based on portal plane, axis and portal side direction.
}
*/
}
public static void renderWorldPass() {
Minecraft minecraft = Minecraft.getMinecraft();
int pass = 2;
if (minecraft.gameSettings.anaglyph)
pass = EntityRenderer.anaglyphField;
GlStateManager.enableCull();
minecraft.mcProfiler.endStartSection("camera");
minecraft.entityRenderer.setupCameraTransform(partialTicks, pass);
ActiveRenderInfo.updateRenderInfo(minecraft.thePlayer, minecraft.gameSettings.thirdPersonView == 2);
GlStateManager.translate(0.0f, 10.0f, 0.0f);
minecraft.mcProfiler.endStartSection("frustum");
ClippingHelperImpl.getInstance();
minecraft.mcProfiler.endStartSection("culling");
ICamera icamera = new Frustum();
Entity entity = minecraft.getRenderViewEntity();
Vec3d position = interpolate(entity.lastTickPosX, entity.lastTickPosY, entity.lastTickPosZ, entity.posX, entity.posY, entity.posZ);
icamera.setPosition(position.xCoord, position.yCoord, position.zCoord);
if (minecraft.gameSettings.renderDistanceChunks >= 4) {
minecraft.entityRenderer.setupFog(-1, partialTicks);
minecraft.mcProfiler.endStartSection("sky");
GlStateManager.matrixMode(GL11.GL_PROJECTION);
GlStateManager.loadIdentity();
Project.gluPerspective(minecraft.entityRenderer.getFOVModifier(partialTicks, true), minecraft.displayWidth / minecraft.displayHeight, 0.05F, minecraft.entityRenderer.farPlaneDistance * 2.0F);
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
minecraft.renderGlobal.renderSky(partialTicks, pass);
GlStateManager.matrixMode(GL11.GL_PROJECTION);
GlStateManager.loadIdentity();
Project.gluPerspective(minecraft.entityRenderer.getFOVModifier(partialTicks, true), minecraft.displayWidth / minecraft.displayHeight, 0.05F, minecraft.entityRenderer.farPlaneDistance * MathHelper.SQRT_2);
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
}
minecraft.entityRenderer.setupFog(0, partialTicks);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
if (entity.posY + entity.getEyeHeight() < 128.0D)
minecraft.entityRenderer.renderCloudsCheck(minecraft.renderGlobal, partialTicks, pass);
minecraft.mcProfiler.endStartSection("prepareterrain");
minecraft.entityRenderer.setupFog(0, partialTicks);
TextureManager textureManager = minecraft.getTextureManager();
textureManager.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
RenderHelper.disableStandardItemLighting();
minecraft.mcProfiler.endStartSection("terrain_setup");
minecraft.renderGlobal.setupTerrain(entity, partialTicks, icamera, minecraft.entityRenderer.frameCount++, minecraft.thePlayer.isSpectator());
if (pass != 1) {
minecraft.mcProfiler.endStartSection("updatechunks");
minecraft.renderGlobal.updateChunks(Long.MAX_VALUE);
}
minecraft.mcProfiler.endStartSection("terrain");
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
GlStateManager.pushMatrix();
GlStateManager.disableAlpha();
minecraft.renderGlobal.renderBlockLayer(BlockRenderLayer.SOLID, partialTicks, pass, entity);
GlStateManager.enableAlpha();
minecraft.renderGlobal.renderBlockLayer(BlockRenderLayer.CUTOUT_MIPPED, partialTicks, pass, entity);
textureManager.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).setBlurMipmap(false, false);
minecraft.renderGlobal.renderBlockLayer(BlockRenderLayer.CUTOUT, partialTicks, pass, entity);
textureManager.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).restoreLastBlurMipmap();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.alphaFunc(GL11.GL_GREATER, 0.1F);
if (!minecraft.entityRenderer.debugView) {
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
GlStateManager.popMatrix();
GlStateManager.pushMatrix();
RenderHelper.enableStandardItemLighting();
minecraft.mcProfiler.endStartSection("entities");
net.minecraftforge.client.ForgeHooksClient.setRenderPass(0);
minecraft.renderGlobal.renderEntities(entity, icamera, partialTicks);
net.minecraftforge.client.ForgeHooksClient.setRenderPass(0);
RenderHelper.disableStandardItemLighting();
minecraft.entityRenderer.disableLightmap();
}
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
GlStateManager.popMatrix();
if (minecraft.entityRenderer.isDrawBlockOutline() && minecraft.objectMouseOver != null && !entity.isInsideOfMaterial(Material.WATER)) {
EntityPlayer entityplayer = (EntityPlayer) entity;
GlStateManager.disableAlpha();
minecraft.mcProfiler.endStartSection("outline");
if (!net.minecraftforge.client.ForgeHooksClient.onDrawBlockHighlight(minecraft.renderGlobal, entityplayer, minecraft.objectMouseOver, 0, partialTicks))
minecraft.renderGlobal.drawSelectionBox(entityplayer, minecraft.objectMouseOver, 0, partialTicks);
GlStateManager.enableAlpha();
}
if (minecraft.debugRenderer.shouldRender())
minecraft.debugRenderer.renderDebug(partialTicks, Long.MAX_VALUE);
minecraft.mcProfiler.endStartSection("destroyProgress");
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
textureManager.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).setBlurMipmap(false, false);
minecraft.renderGlobal.drawBlockDamageTexture(Tessellator.getInstance(), Tessellator.getInstance().getBuffer(), entity, partialTicks);
textureManager.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).restoreLastBlurMipmap();
GlStateManager.disableBlend();
if (!minecraft.entityRenderer.debugView) {
minecraft.entityRenderer.enableLightmap();
minecraft.mcProfiler.endStartSection("litParticles");
minecraft.effectRenderer.renderLitParticles(entity, partialTicks);
RenderHelper.disableStandardItemLighting();
minecraft.entityRenderer.setupFog(0, partialTicks);
minecraft.mcProfiler.endStartSection("particles");
minecraft.effectRenderer.renderParticles(entity, partialTicks);
minecraft.entityRenderer.disableLightmap();
}
GlStateManager.depthMask(false);
GlStateManager.enableCull();
minecraft.mcProfiler.endStartSection("weather");
minecraft.entityRenderer.renderRainSnow(partialTicks);
GlStateManager.depthMask(true);
minecraft.renderGlobal.renderWorldBorder(entity, partialTicks);
GlStateManager.disableBlend();
GlStateManager.enableCull();
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
GlStateManager.alphaFunc(GL11.GL_GREATER, 0.1F);
minecraft.entityRenderer.setupFog(0, partialTicks);
GlStateManager.enableBlend();
GlStateManager.depthMask(false);
textureManager.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
GlStateManager.shadeModel(GL11.GL_SMOOTH);
minecraft.mcProfiler.endStartSection("translucent");
minecraft.renderGlobal.renderBlockLayer(BlockRenderLayer.TRANSLUCENT, partialTicks, pass, entity);
if (!minecraft.entityRenderer.debugView) {
RenderHelper.enableStandardItemLighting();
minecraft.mcProfiler.endStartSection("entities");
net.minecraftforge.client.ForgeHooksClient.setRenderPass(1);
minecraft.renderGlobal.renderEntities(entity, icamera, partialTicks);
GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
net.minecraftforge.client.ForgeHooksClient.setRenderPass(-1);
RenderHelper.disableStandardItemLighting();
}
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.depthMask(true);
GlStateManager.enableCull();
GlStateManager.disableBlend();
GlStateManager.disableFog();
if (entity.posY + entity.getEyeHeight() >= 128.0D) {
minecraft.mcProfiler.endStartSection("aboveClouds");
minecraft.entityRenderer.renderCloudsCheck(minecraft.renderGlobal, partialTicks, pass);
}
RenderHandler.skipEvent = true;
minecraft.mcProfiler.endStartSection("forge_render_last");
net.minecraftforge.client.ForgeHooksClient.dispatchRenderLast(minecraft.renderGlobal, partialTicks);
RenderHandler.skipEvent = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment