[GL renderer] Implement clipping planes

This commit is contained in:
wheremyfoodat 2023-07-04 20:33:14 +03:00
parent f7ad66c708
commit aa27389473

View file

@ -30,6 +30,8 @@ const char* vertexShader = R"(
flat out vec4 v_textureEnvColor[6];
flat out vec4 v_textureEnvBufferColor;
out float gl_ClipDistance[2];
// TEV uniforms
uniform uint u_textureEnvColor[6];
uniform uint u_textureEnvBufferColor;
@ -50,12 +52,32 @@ const char* vertexShader = R"(
float(abgr >> 24)
);
}
vec3 rotateVec3ByQuaternion(vec3 v, vec4 q){
vec3 u = q.xyz;
float s = q.w;
return 2.0 * dot(u, v) * u + (s * s - dot(u, u))* v + 2.0 * s * cross(u, v);
}
// Convert an arbitrary-width floating point literal to an f32
float decodeFP(uint hex, uint E, uint M){
uint width = M + E + 1u;
uint bias = 128u - (1u << (E - 1u));
uint exponent = (hex >> M) & ((1u << E) - 1u);
uint mantissa = hex & ((1u << M) - 1u);
uint sign = (hex >> (E + M)) << 31u;
if ((hex & ((1u << (width - 1u)) - 1u)) != 0) {
if (exponent == (1u << E) - 1u) exponent = 255u;
else exponent += bias;
hex = sign | (mantissa << (23u - M)) | (exponent << 23u);
} else {
hex = sign;
}
return uintBitsToFloat(hex);
}
void main() {
gl_Position = a_coords;
v_colour = a_vertexColour;
@ -75,6 +97,21 @@ const char* vertexShader = R"(
}
v_textureEnvBufferColor = abgr8888ToVec4(u_textureEnvBufferColor);
// Parse clipping plane registers
// The plane registers describe a clipping plane in the form of Ax + By + Cz + D = 0
// With n = (A, B, C) being the normal vector and D being the origin point distance
// Therefore, for the second clipping plane, we can just pass the dot product of the clip vector and the input coordinates to gl_ClipDistance[1]
vec4 clipData = vec4(
decodeFP(readPicaReg(0x48) & 0xffffffu, 7, 16),
decodeFP(readPicaReg(0x49) & 0xffffffu, 7, 16),
decodeFP(readPicaReg(0x4A) & 0xffffffu, 7, 16),
decodeFP(readPicaReg(0x4B) & 0xffffffu, 7, 16)
);
// There's also another, always-on clipping plane based on vertex z
gl_ClipDistance[0] = -a_coords.z;
gl_ClipDistance[1] = dot(clipData, a_coords);
}
)";
@ -235,7 +272,7 @@ const char* fragmentShader = R"(
if (lut >= FR_LUT && lut <= RR_LUT)
lut -= 1;
if (lut==SP_LUT)
lut=8+light;
lut = light + 8;
return texture(u_tex_lighting_lut, vec2(value, lut)).r;
}
@ -828,6 +865,11 @@ void Renderer::drawVertices(PICA::PrimType primType, std::span<const PicaVertex>
glUniform1ui(alphaControlLoc, alphaControl);
}
OpenGL::enableClipPlane(0); // Clipping plane 0 is always enabled
if (regs[PICA::InternalRegs::ClipEnable] & 1) {
OpenGL::enableClipPlane(1);
}
setupBlending();
OpenGL::Framebuffer poop = getColourFBO();
poop.bind(OpenGL::DrawAndReadFramebuffer);
@ -904,7 +946,6 @@ void Renderer::drawVertices(PICA::PrimType primType, std::span<const PicaVertex>
constexpr u32 topScreenBuffer = 0x1f000000;
constexpr u32 bottomScreenBuffer = 0x1f05dc00;
// Quick hack to display top screen for now
void Renderer::display() {
OpenGL::disableScissor();
@ -1000,6 +1041,8 @@ void Renderer::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32
OpenGL::disableBlend();
OpenGL::disableDepth();
OpenGL::disableScissor();
OpenGL::disableClipPlane(0);
OpenGL::disableClipPlane(1);
displayProgram.use();
// Hack: Detect whether we are writing to the top or bottom screen by checking output gap and drawing to the proper part of the output texture