Last active
November 29, 2019 23:09
-
-
Save cplir-c/b526fb55aa97f526567d829a50ca1b0b to your computer and use it in GitHub Desktop.
Translated badly from https://raw.githubusercontent.com/therealfarfetchd/illuminate/6435404fc7b11cd4be402fabf49aaca36a7ba187/src/main/kotlin/client/render/PostProcess.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package therealfarfetchd.illuminate.client.render; | |
import com.mojang.blaze3d.platform.GLX.GL_TEXTURE0; | |
import com.mojang.blaze3d.platform.GLX.GL_TEXTURE2; | |
import static com.mojang.blaze3d.platform.GLX.glBindFramebuffer; | |
import com.mojang.blaze3d.platform.GlStateManager; | |
import static com.mojang.blaze3d.platform.GlStateManager.activeTexture; | |
import static com.mojang.blaze3d.platform.GlStateManager.bindTexture; | |
import static com.mojang.blaze3d.platform.GlStateManager.clear; | |
import static com.mojang.blaze3d.platform.GlStateManager.colorMask; | |
import static com.mojang.blaze3d.platform.GlStateManager.depthMask; | |
import static com.mojang.blaze3d.platform.GlStateManager.disableCull; | |
import static com.mojang.blaze3d.platform.GlStateManager.disableTexture; | |
import static com.mojang.blaze3d.platform.GlStateManager.enableTexture; | |
import static com.mojang.blaze3d.platform.GlStateManager.popMatrix; | |
import static com.mojang.blaze3d.platform.GlStateManager.pushMatrix; | |
import static com.mojang.blaze3d.platform.GlStateManager.translated; | |
import net.minecraft.client.MinecraftClient; | |
static import net.minecraft.client.gl.GlFramebuffer; | |
import net.minecraft.client.render.Tessellator; | |
import net.minecraft.client.render.VertexFormats; | |
import net.minecraft.util.Identifier; | |
import org.lwjgl.BufferUtils; | |
import org.lwjgl.opengl.GL11; | |
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; | |
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; | |
import static org.lwjgl.opengl.GL11.GL_NEAREST; | |
import static org.lwjgl.opengl.GL11.GL_QUADS; | |
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; | |
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; | |
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; | |
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; | |
import static org.lwjgl.opengl.GL11.glClear; | |
import static org.lwjgl.opengl.GL11.glDrawBuffer; | |
import static org.lwjgl.opengl.GL11.glGetFloatv; | |
import static org.lwjgl.opengl.GL11.glMatrixMode; | |
import static org.lwjgl.opengl.GL11.glViewport; | |
import static org.lwjgl.opengl.GL12.GL_CLAMP_TO_EDGE; | |
import static org.lwjgl.opengl.GL13.GL_TEXTURE3; | |
import static org.lwjgl.opengl.GL13.GL_TEXTURE4; | |
import static org.lwjgl.opengl.GL14; | |
import static org.lwjgl.opengl.GL20.glUniform1i; | |
import static org.lwjgl.opengl.GL20.glUniform3f; | |
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; | |
import static org.lwjgl.opengl.GL30.GL_DEPTH_ATTACHMENT; | |
import static org.lwjgl.opengl.GL30.GL_DRAW_FRAMEBUFFER; | |
import static org.lwjgl.opengl.GL30.GL_READ_FRAMEBUFFER; | |
import static org.lwjgl.opengl.GL30.glBlitFramebuffer; | |
import static therealfarfetchd.illuminate.ModID; | |
import therealfarfetchd.illuminate.client.api.Light; | |
import therealfarfetchd.illuminate.client.glwrap.WGlFramebuffer; | |
import therealfarfetchd.illuminate.client.glwrap.WGlShader; | |
import therealfarfetchd.illuminate.client.glwrap.WGlTexture2D; | |
import static therealfarfetchd.illuminate.client.setFramebuffer; | |
import static therealfarfetchd.illuminate.common.util.ext.minus; | |
import static therealfarfetchd.illuminate.common.util.ext.ortho; | |
import static therealfarfetchd.illuminate.common.util.ext.times; | |
import therealfarfetchd.qcommon.croco.Mat4; | |
import therealfarfetchd.qcommon.croco.Vec3; | |
import java.io.IOException; | |
private FloatBuffer matBuf = BufferUtils.createFloatBuffer(16) | |
@Suppress("PrivatePropertyName") | |
class PostProcess { | |
private MinecraftClient mc; | |
private GlFramebuffer = mc.framebuffer; | |
private int width = target.viewWidth; | |
private int height = target.viewHeight; | |
private WGlShader shader; | |
private int uMvp = 0; | |
private int uCamInv = 0; | |
private int uWidth = 0; | |
private int uHeight = 0; | |
private int uWorld = 0; | |
private int uDepth = 0; | |
private int[] uLightTex = new int[10]; | |
private int[] uLightDepth = new int[10]; | |
private int[] uLightCam = new int[10]; | |
private int[] uLightPos = new int[10]; | |
private int uLightCount = 0; | |
private GlFramebuffer offscreenFb = new GlFramebuffer(width, height, true, MinecraftClient.IS_SYSTEM_MAC); | |
private LightFramebuffer lightDepthFb = new LightFramebuffer(1024, 1024, false); | |
private WGlFramebuffer blitFb = WGlFramebuffer.create(); | |
WGlTexture2D playerCamDepth = WGlTexture2D.create() | |
Map<Light, LightContainer> lights = new HashMap<>(); | |
Set<LightContainer> activeLights = java.util.Collections.emptySet(); | |
/* private set */ | |
/* What's this? */ | |
{ | |
playerCamDepth.texParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
playerCamDepth.texParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
playerCamDepth.texParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
playerCamDepth.texParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
try { | |
val vshs = mc.resourceManager.getResource(Identifier(ModID, "shaders/lighting.vert")).use(() -> { it.inputStream.bufferedReader().readText() }); | |
val fshs = mc.resourceManager.getResource(Identifier(ModID, "shaders/lighting.frag")).use(() -> { it.inputStream.bufferedReader().readText() }); | |
shader = mkShader(vshs, fshs); | |
} catch (IOException e) { | |
shader = WGlShader.None; | |
} | |
if (shader.isValid) { | |
shader.enable(); | |
uMvp = shader.getUniformLocation("mvp"); | |
uCamInv = shader.getUniformLocation("camInv"); | |
uWidth = shader.getUniformLocation("width"); | |
uHeight = shader.getUniformLocation("height"); | |
uWorld = shader.getUniformLocation("world"); | |
uDepth = shader.getUniformLocation("depth"); | |
for (int i = 0; i < 10; ++i) { | |
uLightTex[it] = shader.getUniformLocation("lightTex[$it]"); | |
uLightDepth[it] = shader.getUniformLocation("lightDepth[$it]"); | |
uLightCam[it] = shader.getUniformLocation("lightCam[$it]"); | |
uLightPos[it] = shader.getUniformLocation("lightPos[$it]"); | |
} | |
uLightCount = shader.getUniformLocation("lightCount"); | |
shader.disable(); | |
} | |
blitFb.bind(); | |
glDrawBuffer(GL11.GL_NONE); | |
mc.getFramebuffer.beginWrite(false); | |
} | |
/** | |
* Determine which lights should be rendered from the player's position | |
*/ | |
void setupLights(float delta) { | |
if (lights.size() < 10) | |
activeLights = lights.values.toSet(); | |
else { | |
Vec3 camPos = Vec3.from((mc.cameraEntity != null ? mc.cameraEntity : mc.player).getCameraPosVec(delta)); | |
activeLights = lights.values.asSequence().sortedBy(it -> { (it.light.pos - camPos).lengthSq }).take(10).toSet(); | |
} | |
} | |
/** | |
* Resize the framebuffers and textures to the specified size. | |
*/ | |
public void resize(int width, int height) { | |
offscreenFb.resize(width, height, MinecraftClient.IS_SYSTEM_MAC); | |
} | |
/** | |
* Draws the world from each light's perspective and saves the depth buffer for later use. | |
*/ | |
public void renderLightDepths(float delta, long nanoTime) { | |
if (activeLights.isEmpty()) return; | |
boolean oldHudHidden = mc.options.hudHidden; | |
CameraEntity oldCam = mc.cameraEntity; | |
mc.options.hudHidden = true; | |
GlFramebuffer window = mc.framebuffer; | |
for (int i = 0; i < activeLights.size(); ++i){ | |
Light lc = activeLights.get(i); | |
lightDepthFb.beginWrite(true); | |
glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT); | |
mc.setFramebuffer(lightDepthFb); | |
glMatrixMode(GL11.GL_PROJECTION); | |
pushMatrix(); | |
glMatrixMode(GL11.GL_MODELVIEW); | |
pushMatrix(); | |
lc.getLight.prepare(delta); | |
setupCamera(lc); | |
val lightSource = new LightSource(mc.world, lc.light); | |
mc.cameraEntity = lightSource; | |
disableCull(); | |
renderWorld(mc.gameRenderer, delta, nanoTime, i); | |
blitDepthToTex(lightDepthFb, lc.depth); | |
glMatrixMode(GL11.GL_PROJECTION); | |
popMatrix(); | |
glMatrixMode(GL11.GL_MODELVIEW); | |
popMatrix(); | |
} | |
mc.setFramebuffer(window); | |
window.beginWrite(true); | |
mc.cameraEntity = oldCam; | |
mc.options.hudHidden = oldHudHidden; | |
} | |
/** | |
* Applies the shader onto the target framebuffer | |
*/ | |
public void paintSurfaces(float delta){ | |
if (activeLights.isEmpty()) return; | |
if (!shader.isValid) return; // something is fucked | |
CameraEntity ce = mc.cameraEntity!! | |
Camera camera = mc.gameRenderer.camera | |
Vec3 cameraPosVec = camera.pos | |
translated(-cameraPosVec.x, -cameraPosVec.y, -cameraPosVec.z); | |
blitDepthToTex(target, playerCamDepth); | |
clear(GL_DEPTH_BUFFER_BIT, MinecraftClient.IS_SYSTEM_MAC); | |
paintSurfaces(target, offscreenFb); | |
blit(offscreenFb, target); | |
target.beginWrite(true); | |
} | |
/** | |
* Apply the shader onto the source framebuffer and draw into the target framebuffer | |
*/ | |
private fun paintSurfaces(GlFramebuffer from, GlFramebuffer into) { | |
val sourceW = from.texWidth; | |
val sourceH = from.texHeight; | |
val targetH = into.texHeight; | |
val targetW = into.texWidth; | |
from.endWrite(); | |
shader.enable(); | |
glUniform1i(uWidth, sourceW); | |
glUniform1i(uHeight, sourceH); | |
enableTexture(); | |
from.beginRead(); | |
glUniform1i(uWorld, 0); | |
activeTexture(GL_TEXTURE2); | |
enableTexture(); | |
playerCamDepth.bind(); | |
glUniform1i(uDepth, 2); | |
activeTexture(GL_TEXTURE0); | |
for (int i = 0; i < activeLights.size(); ++i){ | |
Light l = activeLights.get(i); | |
loadLight(i, l); | |
} | |
glUniform1i(uLightCount, activeLights.size); | |
matBuf.clear(); | |
ortho(0f, targetW.toFloat(), targetH.toFloat(), 0f, -1f, 1f).intoBuffer(matBuf); | |
matBuf.rewind(); | |
glUniformMatrix4fv(uMvp, false, matBuf); | |
matBuf.clear(); | |
glGetFloatv(GL11.GL_MODELVIEW_MATRIX, matBuf); | |
Mat4 mv = Mat4.fromBuffer(matBuf); | |
matBuf.clear(); | |
glGetFloatv(GL11.GL_PROJECTION_MATRIX, matBuf); | |
Mat4 p = Mat4.fromBuffer(matBuf); | |
matBuf.clear(); | |
(p.multiply(mv)).invert().intoBuffer(matBuf); | |
matBuf.rewind(); | |
glUniformMatrix4fv(uCamInv, false, matBuf); | |
glViewport(0, 0, targetW, targetH); | |
into.clear(MinecraftClient.IS_SYSTEM_MAC); | |
into.beginWrite(false); | |
depthMask(true); | |
colorMask(true, true, true, true); | |
Tesselator t = Tessellator.getInstance(); | |
BufferBuilder buf = t.bufferBuilder; | |
buf.begin(GL_QUADS, VertexFormats.POSITION); | |
buf.vertex(0.0, 0.0, 0.0).next(); | |
buf.vertex(0.0, targetH.toDouble(), 0.0).next(); | |
buf.vertex(targetW.toDouble(), targetH.toDouble(), 0.0).next(); | |
buf.vertex(targetW.toDouble(), 0.0, 0.0).next(); | |
t.draw(); | |
into.endWrite(); | |
shader.disable(); | |
from.endRead(); | |
for (i = 2; i <l 3 + activeLights.size() * 2; ++i) { | |
activeTexture(GL_TEXTURE0 + i); | |
disableTexture(); | |
} | |
activeTexture(GL_TEXTURE0); | |
} | |
private void loadLight(int i, LightContainer l) { | |
activeTexture(GL_TEXTURE3 + 2 * i); | |
enableTexture(); | |
bindTexture(l.getLight().getTex()); | |
activeTexture(GL_TEXTURE4 + 2 * i); | |
enableTexture(); | |
l.getDepth().bind(); | |
glUniform1i(uLightTex[i], 3 + 2 * i); | |
glUniform1i(uLightDepth[i], 4 + 2 * i); | |
matBuf.clear(); | |
l.mvp.intoBuffer(matBuf); | |
matBuf.rewind(); | |
glUniformMatrix4fv(uLightCam[i], false, matBuf); | |
glUniform3f(uLightPos[i], l.light.pos.x, l.light.pos.y, l.light.pos.z); | |
} | |
/** | |
* Sets up GL's modelview and projection matrices according to the information from the passed [Light] | |
*/ | |
private void setupCamera(LightContainer light) { | |
Buffer<Mat4> matBuf = matBuf; | |
matBuf.clear(); | |
light.getP().intoBuffer(matBuf); | |
matBuf.rewind(); | |
GlStateManager.matrixMode(GL11.GL_PROJECTION); | |
GlStateManager.loadIdentity(); | |
GlStateManager.multMatrix(matBuf); | |
matBuf.clear(); | |
light.getMv().intoBuffer(matBuf); | |
matBuf.rewind(); | |
GlStateManager.matrixMode(GL11.GL_MODELVIEW); | |
GlStateManager.loadIdentity(); | |
GlStateManager.multMatrix(matBuf); | |
} | |
/** | |
* Copies the contents of a [GlFramebuffer] into another [GlFramebuffer]. | |
*/ | |
private void blit(GlFramebuffer from, GlFramebuffer into) { | |
glBindFramebuffer(GL_READ_FRAMEBUFFER, from.fbo); | |
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, into.fbo); | |
glBlitFramebuffer(0, 0, from.texWidth, from.texHeight, 0, into.texHeight, into.texWidth, 0, GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT, GL_NEAREST); | |
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | |
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | |
} | |
/** | |
* Copies depth buffer from a [GlFramebuffer] into a [WGlTexture2D]. | |
* Needed because MC stores depth information in a renderbuffer which can't be directly accessed. | |
*/ | |
private void blitDepthToTex(GlFramebuffer from, WGlTexture2D into) { | |
into.texImage(GL14.GL_DEPTH_COMPONENT24, from.texWidth, from.texHeight, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, 0); | |
blitFb.bind(GL_DRAW_FRAMEBUFFER); | |
into.bind(); | |
blitFb.attachTexture(GL_DEPTH_ATTACHMENT, into, GL_DRAW_FRAMEBUFFER); | |
/* GL_DRAW_FRAMEBUFFER should be assigned to target in this call */ | |
glBindFramebuffer(GL_READ_FRAMEBUFFER, from.fbo); | |
glBlitFramebuffer(0, 0, from.texWidth, from.texHeight, 0, 0, from.texWidth, from.texHeight, GL_DEPTH_BUFFER_BIT, GL_NEAREST); | |
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | |
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | |
from.beginWrite(true); | |
} | |
/** | |
* Destroy the native resources this [PostProcess] object occupies. It will be unusable after this operation | |
*/ | |
public void destroy() { | |
shader.destroy(); | |
playerCamDepth.destroy(); | |
offscreenFb.delete(); | |
lightDepthFb.delete(); | |
blitFb.destroy(); | |
lights.getValues().forEach(LightContainer::destroy); | |
lights.clear(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment