From c140a7bb646ed86c0371af5471a64165e6c1afcc Mon Sep 17 00:00:00 2001 From: korenkonder Date: Wed, 25 Sep 2024 01:06:52 +0300 Subject: [PATCH] Reflect: Added stencil test --- src/CRE/gl_state.cpp | 32 +++++++++++ src/CRE/gl_state.hpp | 8 +++ src/CRE/render_manager.cpp | 107 ++++++++++++++++++++++++++++++++++++- 3 files changed, 146 insertions(+), 1 deletion(-) diff --git a/src/CRE/gl_state.cpp b/src/CRE/gl_state.cpp index 1b69433a..e5d65735 100644 --- a/src/CRE/gl_state.cpp +++ b/src/CRE/gl_state.cpp @@ -422,6 +422,12 @@ void gl_state_get() { glGetIntegerv(GL_SCISSOR_BOX, (GLint*)&gl_state.scissor_box); glGetBooleanv(GL_SCISSOR_TEST, &gl_state.scissor_test); glGetBooleanv(GL_STENCIL_TEST, &gl_state.stencil_test); + glGetIntegerv(GL_STENCIL_FUNC, (GLint*)&gl_state.stencil_func); + glGetIntegerv(GL_STENCIL_VALUE_MASK, (GLint*)&gl_state.stencil_value_mask); + glGetIntegerv(GL_STENCIL_FAIL, (GLint*)&gl_state.stencil_fail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, (GLint*)&gl_state.stencil_dpfail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, (GLint*)&gl_state.stencil_dppass); + glGetIntegerv(GL_STENCIL_REF, &gl_state.stencil_ref); glGetIntegerv(GL_STENCIL_WRITEMASK, (GLint*)&gl_state.stencil_mask); glGetIntegerv(GL_VIEWPORT, (GLint*)&gl_state.viewport); @@ -642,6 +648,19 @@ void gl_state_set_scissor(GLint x, GLint y, GLsizei width, GLsizei height, bool } } +void gl_state_set_stencil_func(GLenum func, GLint ref, GLuint mask, bool force) { + if (force || gl_state.stencil_func != func + || gl_state.stencil_ref != ref || gl_state.stencil_value_mask != mask) { +#ifdef USE_OPENGL + if (!Vulkan::use) + glStencilFunc(func, ref, mask); +#endif + gl_state.stencil_func = func; + gl_state.stencil_ref = ref; + gl_state.stencil_value_mask = mask; + } +} + void gl_state_set_stencil_mask(GLuint mask, bool force) { if (force || gl_state.stencil_mask != mask) { #ifdef USE_OPENGL @@ -652,6 +671,19 @@ void gl_state_set_stencil_mask(GLuint mask, bool force) { } } +void gl_state_set_stencil_op(GLenum sfail, GLenum dpfail, GLenum dppass, bool force) { + if (force || gl_state.stencil_fail != sfail + || gl_state.stencil_dpfail != dpfail || gl_state.stencil_dppass != dppass) { +#ifdef USE_OPENGL + if (!Vulkan::use) + glStencilOp(sfail, dpfail, dppass); +#endif + gl_state.stencil_fail = sfail; + gl_state.stencil_dpfail = dpfail; + gl_state.stencil_dppass = dppass; + } +} + void gl_state_set_viewport(const gl_state_rect& rect, bool force) { if (force || gl_state.viewport.x != rect.x || gl_state.viewport.y != rect.y || gl_state.viewport.width != rect.width || gl_state.viewport.height != rect.height) { diff --git a/src/CRE/gl_state.hpp b/src/CRE/gl_state.hpp index 81acbade..0bccb359 100644 --- a/src/CRE/gl_state.hpp +++ b/src/CRE/gl_state.hpp @@ -57,7 +57,13 @@ struct gl_state_struct { gl_state_rect scissor_box; GLboolean scissor_test; GLboolean stencil_test; + GLenum stencil_func; + GLenum stencil_fail; + GLenum stencil_dpfail; + GLenum stencil_dppass; GLuint stencil_mask; + GLint stencil_ref; + GLuint stencil_value_mask; gl_state_rect viewport; }; @@ -128,7 +134,9 @@ extern void gl_state_set_polygon_mode(GLenum face, GLenum mode, bool force = fal extern void gl_state_set_primitive_restart_index(GLuint index, bool force = false); extern void gl_state_set_scissor(const gl_state_rect& rect, bool force = false); extern void gl_state_set_scissor(GLint x, GLint y, GLsizei width, GLsizei height, bool force = false); +extern void gl_state_set_stencil_func(GLenum func, GLint ref, GLuint mask, bool force = false); extern void gl_state_set_stencil_mask(GLuint mask, bool force = false); +extern void gl_state_set_stencil_op(GLenum sfail, GLenum dpfail, GLenum dppass, bool force = false); extern void gl_state_set_viewport(const gl_state_rect& rect, bool force = false); extern void gl_state_set_viewport(GLint x, GLint y, GLsizei width, GLsizei height, bool force = false); extern void gl_state_use_program(GLuint program, bool force = false); diff --git a/src/CRE/render_manager.cpp b/src/CRE/render_manager.cpp index 713d1ba3..7902325b 100644 --- a/src/CRE/render_manager.cpp +++ b/src/CRE/render_manager.cpp @@ -8,6 +8,7 @@ #include "Glitter/glitter.hpp" #include "light_param/fog.hpp" #include "light_param/light.hpp" +#include "mdl/draw_object.hpp" #include "rob/rob.hpp" #include "Vulkan/gl_wrap.hpp" #include "config.hpp" @@ -41,6 +42,7 @@ static int32_t draw_pass_3d_translucent_count_layers(render_context* rctx, int32_t* alpha_array, mdl::ObjType opaque, mdl::ObjType transparent, mdl::ObjType translucent); static void draw_pass_3d_translucent_has_objects(render_context* rctx, bool* arr, mdl::ObjType type); +static void draw_pass_reflect_stencil(render_context* rctx, mdl::ObjType type); static void blur_filter_apply(render_context* rctx, RenderTexture* dst, RenderTexture* src, blur_filter_mode filter, const vec2 res_scale, const vec4 scale, const vec4 offset); @@ -67,7 +69,7 @@ namespace rndr { static const RenderTextureData render_manager_render_texture_data_array[] = { { GL_TEXTURE_2D, 0x200, 0x100, 0, GL_RGBA8 , GL_DEPTH_COMPONENT24 }, - { GL_TEXTURE_2D, 0x200, 0x100, 0, GL_RGBA16F, GL_DEPTH_COMPONENT24 }, + { GL_TEXTURE_2D, 0x200, 0x100, 0, GL_RGBA16F, GL_DEPTH24_STENCIL8 }, { GL_TEXTURE_2D, 0x400, 0x400, 0, GL_RGBA8 , GL_ZERO }, { GL_TEXTURE_2D, 0x400, 0x400, 0, GL_RGBA8 , GL_ZERO }, { GL_TEXTURE_2D, 0x400, 0x400, 0, GL_RGBA8 , GL_ZERO }, @@ -682,6 +684,35 @@ namespace rndr { else glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (sv_better_reflect) { + gl_state_set_stencil_mask(0xFF); + + glClearStencil(0x00); + glClear(GL_STENCIL_BUFFER_BIT); + + rctx->draw_state->shader_index = SHADER_FT_SIL; + + gl_state_disable_depth_test(); + gl_state_set_depth_func(GL_LEQUAL); + gl_state_set_depth_mask(GL_TRUE); + + gl_state_enable_stencil_test(); + gl_state_set_stencil_op(GL_KEEP, GL_KEEP, GL_REPLACE); + gl_state_set_stencil_func(GL_ALWAYS, 0x01, 0xFF); + + gl_state_set_color_mask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + draw_pass_reflect_stencil(rctx, mdl::OBJ_TYPE_OPAQUE); + draw_pass_reflect_stencil(rctx, mdl::OBJ_TYPE_TRANSLUCENT); + draw_pass_reflect_stencil(rctx, mdl::OBJ_TYPE_TRANSLUCENT_SORT_BY_RADIUS); + draw_pass_reflect_stencil(rctx, mdl::OBJ_TYPE_TRANSPARENT); + gl_state_set_color_mask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + gl_state_set_stencil_op(GL_KEEP, GL_KEEP, GL_KEEP); + gl_state_set_stencil_func(GL_EQUAL, 0x01, 0x01); + + gl_state_set_stencil_mask(0x00); + } + rctx->draw_state->shader_index = SHADER_FT_S_REFL; light_set* set = &rctx->light_set[LIGHT_SET_MAIN]; @@ -778,6 +809,9 @@ namespace rndr { uniform_value[U_REFLECT] = 0; rctx->draw_state->shader_index = -1; + if (sv_better_reflect) + gl_state_disable_stencil_test(); + for (int32_t i = reflect_blur_num, j = 0; i > 0; i--, j++) { blur_filter_apply(rctx, &refl_buf_tex, &refl_tex, reflect_blur_filter, 1.0f, 1.0f, 0.0f); @@ -1976,6 +2010,77 @@ static void draw_pass_3d_translucent_has_objects(render_context* rctx, bool* arr } } +static void draw_pass_reflect_stencil(render_context* rctx, mdl::ObjType type) { + if (type < 0 || type >= mdl::OBJ_TYPE_MAX || rctx->disp_manager->get_obj_count(type) < 1) + return; + + int32_t alpha_test = 0; + float_t min_alpha = 1.0f; + float_t alpha_threshold = 0.0f; + + for (int32_t i = 0; i < 5; i++) + gl_state_active_bind_texture_2d(i, rctx->empty_texture_2d->glid); + gl_state_active_bind_texture_cube_map(5, rctx->empty_texture_cube_map->glid); + gl_state_active_texture(0); + gl_state_set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + uniform_value_reset(); + gl_state_get(); + + switch (type) { + case mdl::OBJ_TYPE_TRANSLUCENT: + case mdl::OBJ_TYPE_TRANSLUCENT_SORT_BY_RADIUS: + alpha_test = 1; + min_alpha = 0.0f; + alpha_threshold = 0.0f; + break; + case mdl::OBJ_TYPE_TRANSPARENT: + alpha_test = 1; + min_alpha = 0.1f; + alpha_threshold = 0.5f; + break; + default: + break; + } + rctx->set_batch_alpha_threshold(alpha_threshold); + rctx->set_batch_min_alpha(min_alpha); + uniform_value[U_ALPHA_TEST] = alpha_test; + + for (mdl::ObjData*& i : rctx->disp_manager->obj[type]) { + switch (i->kind) { + case mdl::OBJ_KIND_NORMAL: { + switch (i->args.sub_mesh.material->material.shader.index) { + case SHADER_FT_WATER01: + case SHADER_FT_FLOOR: + case SHADER_FT_PUDDLE: + mat4 mat; + mat4_scale_rot(&i->mat, 1.1f, &mat); + draw_sub_mesh(rctx, &i->args.sub_mesh, &mat, mdl::draw_sub_mesh_default); + break; + } + } break; + case mdl::OBJ_KIND_TRANSLUCENT: { + for (int32_t j = 0; j < i->args.translucent.count; j++) + switch (i->args.translucent.sub_mesh[j]->material->material.shader.index) { + case SHADER_FT_WATER01: + case SHADER_FT_FLOOR: + case SHADER_FT_PUDDLE: + mat4 mat; + mat4_scale_rot(&i->mat, 1.1f, &mat); + draw_sub_mesh(rctx, i->args.translucent.sub_mesh[j], &mat, mdl::draw_sub_mesh_default); + break; + } + } break; + } + } + + uniform_value_reset(); + gl_state_bind_vertex_array(0); + shader::unbind(); + gl_state_set_blend_func(GL_ONE, GL_ZERO); + for (int32_t i = 0; i < 5; i++) + gl_state_bind_sampler(i, 0); +} + static void blur_filter_apply(render_context* rctx, RenderTexture* dst, RenderTexture* src, blur_filter_mode filter, const vec2 res_scale, const vec4 scale, const vec4 offset) { if (!dst || !src)