forked from Ports/perfect_dark
Fix 3
This commit is contained in:
1 parent
b20abed21e
commit
0fd290c8c3
1 file changed
+31
-5
@@ -34,7 +34,9 @@ struct ShaderProgram {
|
||||
GLint noise_scale_location;
|
||||
GLint three_point_filter_locations[2];
|
||||
GLint decal_mode_location;
|
||||
GLint decal_scale_location;
|
||||
int decal_mode;
|
||||
float decal_scale;
|
||||
};
|
||||
|
||||
struct Framebuffer {
|
||||
@@ -64,8 +66,10 @@ static MipmapFilteringMode current_mipmap_filter_mode = MIPMAP_LINEAR;
|
||||
static bool current_textures_linear_filter[2] = {false, false};
|
||||
static struct ShaderProgram* current_shader_program;
|
||||
|
||||
// Decals are clipped to the geometry they lie on, using a copy of the depth buffer
|
||||
// N64 decal depth mode: pixels only pass when close to the stored depth, using a copy of the depth buffer
|
||||
#define DECAL_DEPTH_TEXTURE_UNIT 2
|
||||
// Height of the N64 frame; the RDP's depth slope tolerance is measured in N64 pixels
|
||||
#define DECAL_N64_SCREEN_HEIGHT 240.0f
|
||||
static bool depth_copy_supported;
|
||||
static bool depth_copy_dirty = true;
|
||||
static size_t depth_copy_source;
|
||||
@@ -399,6 +403,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
append_line(fs_buf, &fs_len, "uniform int frame_count;");
|
||||
append_line(fs_buf, &fs_len, "uniform float noise_scale;");
|
||||
append_line(fs_buf, &fs_len, "uniform int uDecalMode;");
|
||||
append_line(fs_buf, &fs_len, "uniform highp float uDecalPixelScale;");
|
||||
append_line(fs_buf, &fs_len, "uniform highp sampler2D uDepthTex;");
|
||||
|
||||
append_line(fs_buf, &fs_len, "float random(in vec3 value) {");
|
||||
@@ -460,12 +465,13 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
|
||||
append_line(fs_buf, &fs_len, "void main() {");
|
||||
|
||||
// Discard decal pixels hanging past an edge, i.e. where the stored surface is clearly further away than the decal.
|
||||
// (1 - z) is roughly proportional to 1 / distance, so this allows a gap of about 3% of the distance, plus slope.
|
||||
// RDP decal Z mode: pass only if |z - stored z| <= dz (the per-pixel depth slope), and never over cleared depth.
|
||||
// The slope is computed before anything can discard, since derivatives are undefined after a neighbor discards.
|
||||
append_line(fs_buf, &fs_len, " highp float decalSlope = fwidth(gl_FragCoord.z);");
|
||||
append_line(fs_buf, &fs_len, " if (uDecalMode != 0) {");
|
||||
append_line(fs_buf, &fs_len, " highp float storedZ = texelFetch(uDepthTex, ivec2(gl_FragCoord.xy), 0).r;");
|
||||
append_line(fs_buf, &fs_len, " if (storedZ - gl_FragCoord.z > 0.03 * (1.0 - gl_FragCoord.z) + 3.0 * decalSlope) discard;");
|
||||
append_line(fs_buf, &fs_len, " highp float dz = max(decalSlope * uDecalPixelScale, 1.0 / 262144.0);");
|
||||
append_line(fs_buf, &fs_len, " if (storedZ >= 1.0 || abs(gl_FragCoord.z - storedZ) > dz) discard;");
|
||||
append_line(fs_buf, &fs_len, " }");
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@@ -679,7 +685,9 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
prg->three_point_filter_locations[0] = glGetUniformLocation(shader_program, "three_point_filter0");
|
||||
prg->three_point_filter_locations[1] = glGetUniformLocation(shader_program, "three_point_filter1");
|
||||
prg->decal_mode_location = glGetUniformLocation(shader_program, "uDecalMode");
|
||||
prg->decal_scale_location = glGetUniformLocation(shader_program, "uDecalPixelScale");
|
||||
prg->decal_mode = 0;
|
||||
prg->decal_scale = 0.0f;
|
||||
if (prg->decal_mode_location >= 0) {
|
||||
glUniform1i(prg->decal_mode_location, 0);
|
||||
glUniform1i(glGetUniformLocation(shader_program, "uDepthTex"), DECAL_DEPTH_TEXTURE_UNIT);
|
||||
@@ -926,11 +934,29 @@ static void gfx_opengl_set_decal_uniforms(struct ShaderProgram* prg, bool enable
|
||||
glUniform1i(prg->decal_mode_location, mode);
|
||||
prg->decal_mode = mode;
|
||||
}
|
||||
|
||||
const float scale = framebuffers[current_framebuffer].height / DECAL_N64_SCREEN_HEIGHT;
|
||||
if (enabled && prg->decal_scale != scale) {
|
||||
glUniform1f(prg->decal_scale_location, scale);
|
||||
prg->decal_scale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) {
|
||||
// printf("flushing %d tris\n", buf_vbo_num_tris);
|
||||
gfx_opengl_set_decal_uniforms(current_shader_program, current_depth_decal && gfx_opengl_update_depth_copy());
|
||||
if (current_depth_decal) {
|
||||
// The shader replaces the depth test like the RDP does; fall back to polygon offset if depth can't be copied
|
||||
const bool decal = gfx_opengl_update_depth_copy();
|
||||
glDepthFunc(decal ? GL_ALWAYS : GL_LEQUAL);
|
||||
if (decal) {
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
} else {
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
gfx_opengl_set_decal_uniforms(current_shader_program, decal);
|
||||
} else {
|
||||
gfx_opengl_set_decal_uniforms(current_shader_program, false);
|
||||
}
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris);
|
||||
|
||||
Reference in new issue
Block a user