Intial Commit
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package localmods.mtkviewpoint;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.FloatBuffer;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import static org.lwjgl.opengl.GL33.*;
|
||||
import viewpoint.render.FrameContext;
|
||||
import viewpoint.render.SceneData;
|
||||
import viewpoint.render.WorldRenderer;
|
||||
|
||||
/** Native Viewpoint HDR pass, before post processing, with normal scene depth testing. */
|
||||
public final class TracerRenderer {
|
||||
private static final FloatBuffer vertices=BufferUtils.createFloatBuffer(ProjectileBridge.LIMIT*6*TracerMesh.STRIDE);
|
||||
private static Field frameField,irisField;
|
||||
private static int program,vao,vbo;
|
||||
private static volatile boolean failed;
|
||||
private TracerRenderer() {}
|
||||
|
||||
public static void fail(Throwable error) {
|
||||
if (!failed) System.out.println("[MTKViewpointTurrets] 3D tracers disabled after render error: "+error);
|
||||
failed=true;
|
||||
}
|
||||
|
||||
public static void draw(SceneData scene) {
|
||||
if (failed || scene==null) return;
|
||||
var shots=ProjectileBridge.segments(scene);
|
||||
if (shots.isEmpty()) return;
|
||||
try {
|
||||
if (frameField==null) {
|
||||
frameField=WorldRenderer.class.getDeclaredField("frame"); frameField.setAccessible(true);
|
||||
irisField=WorldRenderer.class.getDeclaredField("irisDrawn"); irisField.setAccessible(true);
|
||||
}
|
||||
if (irisField.getBoolean(null)) return; // Minecraft/Iris uses separate private targets.
|
||||
FrameContext frame=(FrameContext)frameField.get(null);
|
||||
if (frame==null || frame.scene!=scene) return;
|
||||
vertices.clear();
|
||||
int count=0;
|
||||
for (var shot:shots) count+=TracerMesh.append(vertices,shot,frame.viewProjection,frame.width,frame.height);
|
||||
vertices.flip();
|
||||
if (count==0) return;
|
||||
drawBuffer(vertices,count,frame.width,frame.height,true);
|
||||
} catch (Throwable error) { fail(error); }
|
||||
}
|
||||
|
||||
// Kept separate so the same production GPU path can be checked in a tiny
|
||||
// hidden OpenGL test context without launching Project Zomboid.
|
||||
static void drawBuffer(FloatBuffer data,int count,int width,int height,boolean bindViewpointTarget) {
|
||||
int oldProgram=glGetInteger(GL_CURRENT_PROGRAM),oldVAO=glGetInteger(GL_VERTEX_ARRAY_BINDING);
|
||||
int oldVBO=glGetInteger(GL_ARRAY_BUFFER_BINDING),oldDraw=glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING);
|
||||
int oldRead=glGetInteger(GL_READ_FRAMEBUFFER_BINDING),depthFunc=glGetInteger(GL_DEPTH_FUNC);
|
||||
int[] viewport=new int[4]; glGetIntegerv(GL_VIEWPORT,viewport);
|
||||
boolean depth=glIsEnabled(GL_DEPTH_TEST),blend=glIsEnabled(GL_BLEND),cull=glIsEnabled(GL_CULL_FACE);
|
||||
boolean scissor=glIsEnabled(GL_SCISSOR_TEST),depthMask=glGetBoolean(GL_DEPTH_WRITEMASK);
|
||||
int sr=glGetInteger(GL_BLEND_SRC_RGB),dr=glGetInteger(GL_BLEND_DST_RGB);
|
||||
int sa=glGetInteger(GL_BLEND_SRC_ALPHA),da=glGetInteger(GL_BLEND_DST_ALPHA);
|
||||
int er=glGetInteger(GL_BLEND_EQUATION_RGB),ea=glGetInteger(GL_BLEND_EQUATION_ALPHA);
|
||||
try {
|
||||
if (program==0) init();
|
||||
if (bindViewpointTarget) WorldRenderer.bindTarget(); else glViewport(0,0,width,height);
|
||||
glUseProgram(program); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER,vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER,data,GL_STREAM_DRAW);
|
||||
glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glDepthMask(false);
|
||||
glDisable(GL_CULL_FACE); glDisable(GL_SCISSOR_TEST); glEnable(GL_BLEND);
|
||||
glBlendEquationSeparate(GL_FUNC_ADD,GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_ONE,GL_ONE_MINUS_SRC_ALPHA,GL_ZERO,GL_ONE);
|
||||
glDrawArrays(GL_TRIANGLES,0,count);
|
||||
} finally {
|
||||
glUseProgram(oldProgram); glBindVertexArray(oldVAO); glBindBuffer(GL_ARRAY_BUFFER,oldVBO);
|
||||
glBlendEquationSeparate(er,ea); glBlendFuncSeparate(sr,dr,sa,da);
|
||||
toggle(GL_BLEND,blend); toggle(GL_DEPTH_TEST,depth); toggle(GL_CULL_FACE,cull); toggle(GL_SCISSOR_TEST,scissor);
|
||||
glDepthFunc(depthFunc); glDepthMask(depthMask);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER,oldDraw); glBindFramebuffer(GL_READ_FRAMEBUFFER,oldRead);
|
||||
glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void toggle(int cap,boolean on) { if(on) glEnable(cap); else glDisable(cap); }
|
||||
|
||||
private static void init() {
|
||||
int vs=shader(GL_VERTEX_SHADER,"""
|
||||
#version 330 core
|
||||
layout(location=0) in vec4 clipPosition;
|
||||
layout(location=1) in vec2 uv;
|
||||
layout(location=2) in vec4 color;
|
||||
out vec2 texCoord;
|
||||
out vec4 tint;
|
||||
void main(){gl_Position=clipPosition; texCoord=uv; tint=color;}
|
||||
""");
|
||||
int fs=shader(GL_FRAGMENT_SHADER,"""
|
||||
#version 330 core
|
||||
in vec2 texCoord;
|
||||
in vec4 tint;
|
||||
out vec4 fragColor;
|
||||
void main(){
|
||||
float edge=1.0-smoothstep(0.25,1.0,abs(texCoord.y));
|
||||
float a=tint.a*edge*smoothstep(0.0,0.25,texCoord.x);
|
||||
fragColor=vec4(tint.rgb*5.0*a,a);
|
||||
}
|
||||
""");
|
||||
int linked=glCreateProgram();
|
||||
try {
|
||||
glAttachShader(linked,vs); glAttachShader(linked,fs); glLinkProgram(linked);
|
||||
if(glGetProgrami(linked,GL_LINK_STATUS)==0) throw new IllegalStateException(glGetProgramInfoLog(linked));
|
||||
} catch(RuntimeException error) {glDeleteProgram(linked); throw error;}
|
||||
finally {glDeleteShader(vs); glDeleteShader(fs);}
|
||||
vao=glGenVertexArrays(); vbo=glGenBuffers();
|
||||
glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER,vbo);
|
||||
int stride=TracerMesh.STRIDE*Float.BYTES;
|
||||
glEnableVertexAttribArray(0); glVertexAttribPointer(0,4,GL_FLOAT,false,stride,0L);
|
||||
glEnableVertexAttribArray(1); glVertexAttribPointer(1,2,GL_FLOAT,false,stride,16L);
|
||||
glEnableVertexAttribArray(2); glVertexAttribPointer(2,4,GL_FLOAT,false,stride,24L);
|
||||
program=linked;
|
||||
}
|
||||
private static int shader(int type,String source) {
|
||||
int id=glCreateShader(type); glShaderSource(id,source); glCompileShader(id);
|
||||
if(glGetShaderi(id,GL_COMPILE_STATUS)==0) {
|
||||
String error=glGetShaderInfoLog(id); glDeleteShader(id); throw new IllegalStateException(error);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user