From 1c19c4440079eb1297761d0b520438d77d124f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Thu, 11 Apr 2024 00:19:08 +0200 Subject: [PATCH] wip: renderstate impl --- bind/v4k.lua | 34 ++++ demos/99-renderstate.c | 71 ++++++++ engine/joint/v4k.h | 338 +++++++++++++++++++++++++++++------- engine/split/v4k_font.c | 45 +++-- engine/split/v4k_render.c | 176 ++++++++++++++++++- engine/split/v4k_render.h | 61 +++++++ engine/split/v4k_renderdd.c | 19 +- engine/split/v4k_window.c | 37 ++-- engine/v4k.c | 277 ++++++++++++++++++++++------- engine/v4k.h | 61 +++++++ 10 files changed, 924 insertions(+), 195 deletions(-) create mode 100644 demos/99-renderstate.c diff --git a/bind/v4k.lua b/bind/v4k.lua index a547c01..f0e82e4 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -1032,6 +1032,38 @@ typedef struct reflect_t { const char* symbol_naked(const char *s); int ui_reflect(const char *mask); typedef unsigned handle; +typedef struct renderstate_t { + int viewportX; + int viewportY; + int viewportWidth; + int viewportHeight; + float clearColor[4]; + double clearDepth; + bool depthTestEnabled; + unsigned depthFunc; + bool blendEnabled; + unsigned blendFunc; + unsigned blendSrc; + unsigned blendDst; + bool cullFaceEnabled; + unsigned cullFaceMode; + bool stencilTestEnabled; + unsigned stencilFunc; + int stencilRef; + unsigned stencilMask; + unsigned frontFace; + bool smoothLineEnabled; + float lineWidth; + bool pointSizeEnabled; + float pointSize; + unsigned polygonModeFace; + unsigned polygonModeMode; + bool scissorTestEnabled; + int scissorBox[4]; +} renderstate_t; + renderstate_t renderstate(); + bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB); + void renderstate_apply(const renderstate_t *state); unsigned rgba( uint8_t r, uint8_t g, uint8_t b, uint8_t a ); unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a ); unsigned rgbaf( float r, float g, float b, float a ); @@ -1148,6 +1180,7 @@ typedef struct shadowmap_t { unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); unsigned shader_bind(unsigned program); + int shader_uniform(const char *name); void shader_bool(const char *uniform, bool i ); void shader_int(const char *uniform, int i); void shader_uint(const char *uniform, unsigned i ); @@ -1362,6 +1395,7 @@ typedef struct model_t { float *instanced_matrices; unsigned num_instances; int stored_flags; + renderstate_t rs; } model_t; enum BILLBOARD_MODE { BILLBOARD_X = 0x1, diff --git a/demos/99-renderstate.c b/demos/99-renderstate.c new file mode 100644 index 0000000..8b4d19a --- /dev/null +++ b/demos/99-renderstate.c @@ -0,0 +1,71 @@ +#include + +int main() { + window_create(40, WINDOW_SQUARE | WINDOW_MSAA8); + window_title(__FILE__); + + // set up pipeline + renderstate_t state = renderstate(); + state.clearColor[0] = 0.2f; + state.clearColor[1] = 0.2f; + state.clearColor[2] = 0.2f; + state.clearColor[3] = 1.0f; + state.depthTestEnabled = GL_TRUE; + state.depthFunc = GL_LEQUAL; + state.blendEnabled = GL_FALSE; + state.cullFaceEnabled = GL_TRUE; + + // prepare triangle buffer + float vertices[] = { + -0.5f, -0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, + 0.0f, 0.5f, 0.0f + }; + + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + // basic shader + const char *vertex_shader_src = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main() {\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; + + const char *fragment_shader_src = "#version 330 core\n" + "out vec4 FragColor;\n" + "void main() {\n" + " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\0"; + + handle program = shader(vertex_shader_src, fragment_shader_src, "aPos", "FragColor", ""); + + // app loop + while( window_swap() ) { + // input controls + if( input(KEY_ESC) ) break; + + // bind pipeline + renderstate_apply(&state); + + // clear screen + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // draw triangle + glUseProgram(program); + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES, 0, 3); + } +} diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index d52ee16..5376090 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -17030,6 +17030,65 @@ API int ui_reflect(const char *mask); // *, model* or NULL typedef unsigned handle; // GLuint +// ----------------------------------------------------------------------------- +// renderstate +typedef struct renderstate_t { + // Viewport parameters + int viewportX; + int viewportY; + int viewportWidth; + int viewportHeight; + + // Clear color + float clearColor[4]; + + // Clear depth + double clearDepth; + + // Depth test + bool depthTestEnabled; + unsigned depthFunc; + + // Blending + bool blendEnabled; + unsigned blendFunc; + unsigned blendSrc; + unsigned blendDst; + + // Culling + bool cullFaceEnabled; + unsigned cullFaceMode; + + // Stencil test + bool stencilTestEnabled; + unsigned stencilFunc; + int stencilRef; + unsigned stencilMask; + + // Face culling direction + unsigned frontFace; // GL_CW or GL_CCW + + // Line width + bool smoothLineEnabled; + float lineWidth; + + // Point size + bool pointSizeEnabled; + float pointSize; + + // Polygon mode + unsigned polygonModeFace; + unsigned polygonModeMode; + + // Scissor test + bool scissorTestEnabled; + int scissorBox[4]; +} renderstate_t; + +API renderstate_t renderstate(); +API bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB); +API void renderstate_apply(const renderstate_t *state); + // ----------------------------------------------------------------------------- // colors @@ -17250,6 +17309,7 @@ API void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float botto API unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_bind(unsigned program); +API int shader_uniform(const char *name); API void shader_bool(const char *uniform, bool i ); API void shader_int(const char *uniform, int i); API void shader_uint(const char *uniform, unsigned i ); @@ -17599,6 +17659,7 @@ typedef struct model_t { unsigned num_instances; int stored_flags; + renderstate_t rs; } model_t; enum BILLBOARD_MODE { @@ -363103,6 +363164,9 @@ typedef struct font_t { // vbos GLuint vbo_quad; // vec2: simply just a regular [0,1]x[0,1] quad GLuint vbo_instances; // vec4: (char_pos_x, char_pos_y, char_index, color_index) + + // render state + renderstate_t rs; } font_t; enum { FONTS_MAX = 10 }; @@ -363441,6 +363505,16 @@ void font_face_from_mem(const char *tag, const void *ttf_data, unsigned ttf_len, glUniform2f(glGetUniformLocation(f->program, "res_meta"), f->num_glyphs, 2); glUniform1f(glGetUniformLocation(f->program, "num_colors"), FONT_MAX_COLORS); (void)flags; + + // set up pipeline + f->rs = renderstate(); + f->rs.blendEnabled = 1; + f->rs.blendFunc = GL_FUNC_ADD; + f->rs.blendSrc = GL_SRC_ALPHA; + f->rs.blendDst = GL_ONE_MINUS_SRC_ALPHA; + f->rs.scissorTestEnabled = 1; + f->rs.depthTestEnabled = 0; + f->rs.cullFaceEnabled = 0; } void font_face(const char *tag, const char *filename_ttf, float font_size, unsigned flags) { @@ -363471,25 +363545,10 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glActiveTexture(GL_TEXTURE2); glGetIntegerv(GL_TEXTURE_BINDING_1D, &last_texture2); - glGetIntegerv(GL_BLEND_SRC, &last_blend_src); - glGetIntegerv(GL_BLEND_DST, &last_blend_dst); - glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); - glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); - - GLboolean last_enable_blend = glIsEnabled(GL_BLEND); - GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); - GLboolean last_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - - // Setup render state: alpha-blending enabled, no depth testing, enable clipping and bind textures - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // @fixme: store existing scissor test setup - glEnable(GL_SCISSOR_TEST); - glScissor(rect.x, window_height() - (rect.y+rect.w), rect.z, rect.w); - - glDisable(GL_DEPTH_TEST); + f->rs.scissorBox[0] = rect.x; + f->rs.scissorBox[1] = window_height() - (rect.y+rect.w); + f->rs.scissorBox[2] = rect.z; + f->rs.scissorBox[3] = rect.w; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, f->texture_fontdata); @@ -363515,6 +363574,9 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glBindBuffer(GL_ARRAY_BUFFER, f->vbo_instances); glBufferSubData(GL_ARRAY_BUFFER, 0, 4*4*glyph_idx, glyph_data); + // setup pipeline + renderstate_apply(&f->rs); + // actual drawing glDrawArraysInstanced(GL_TRIANGLES, 0, 6, glyph_idx); @@ -363528,13 +363590,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_1D, last_texture2); - glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); glBindVertexArray(last_vertex_array); - glBlendFunc(last_blend_src, last_blend_dst); - - (last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); - (last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND)); - (last_scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST)); } // 1. call font_face() if it's the first time it's called. @@ -370069,6 +370125,154 @@ void glCopyBackbufferToTexture( texture_t *tex ) { // unused glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 0, 0, window_width(), window_height(), 0 ); } +// ---------------------------------------------------------------------------- +// renderstate + +renderstate_t renderstate() { + renderstate_t state = {0}; + + // Set default viewport parameters + state.viewportX = 0; + state.viewportY = 0; + state.viewportWidth = window_width(); + state.viewportHeight = window_height(); + + // Set default clear color to black + state.clearColor[0] = 0.0f; // Red + state.clearColor[1] = 0.0f; // Green + state.clearColor[2] = 0.0f; // Blue + state.clearColor[3] = 1.0f; // Alpha + + // Set default clear depth to maximum distance + state.clearDepth = 1.0; + + // Enable depth test by default with less or equal function + state.depthTestEnabled = GL_TRUE; + state.depthFunc = GL_LEQUAL; + + // Disable blending by default + state.blendEnabled = GL_FALSE; + state.blendFunc = GL_FUNC_ADD; + state.blendSrc = GL_ONE; + state.blendDst = GL_ZERO; + + // Enable culling by default and cull back faces + state.cullFaceEnabled = GL_TRUE; + state.cullFaceMode = GL_BACK; + + // Disable stencil test by default + state.stencilTestEnabled = GL_FALSE; + state.stencilFunc = GL_ALWAYS; + state.stencilRef = 0; + state.stencilMask = 0xFFFFFFFF; + + // Set default front face to counter-clockwise + state.frontFace = GL_CCW; + + // Set default line width + state.smoothLineEnabled = GL_FALSE; + state.lineWidth = 1.0f; + + // Set default point size + state.pointSizeEnabled = GL_FALSE; + state.pointSize = 1.0f; + + // Set default polygon mode to fill + state.polygonModeFace = GL_FRONT_AND_BACK; + state.polygonModeMode = GL_FILL; + + // Disable scissor test by default + state.scissorTestEnabled = GL_FALSE; + state.scissorBox[0] = 0; + state.scissorBox[1] = 0; + state.scissorBox[2] = window_width(); + state.scissorBox[3] = window_height(); + + return state; +} + +bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB) { + return memcmp(stateA, stateB, sizeof(renderstate_t)) == 0; +} + +void renderstate_apply(const renderstate_t *state) { + if (state != NULL) { + // Apply viewport parameters + glViewport(state->viewportX, state->viewportY, state->viewportWidth, state->viewportHeight); + + // Apply clear color + glClearColor(state->clearColor[0], state->clearColor[1], state->clearColor[2], state->clearColor[3]); + + // Apply clear depth + glClearDepth(state->clearDepth); + + // Apply depth test + if (state->depthTestEnabled) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(state->depthFunc); + } else { + glDisable(GL_DEPTH_TEST); + } + + // Apply blending + if (state->blendEnabled) { + glEnable(GL_BLEND); + glBlendEquation(state->blendFunc); + glBlendFunc(state->blendSrc, state->blendDst); + } else { + glDisable(GL_BLEND); + } + + // Apply culling @fixme + // if (state->cullFaceEnabled) { + // glEnable(GL_CULL_FACE); + // glCullFace(state->cullFaceMode); + // } else { + // glDisable(GL_CULL_FACE); + // } + + // Apply stencil test + if (state->stencilTestEnabled) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(state->stencilFunc, state->stencilRef, state->stencilMask); + } else { + glDisable(GL_STENCIL_TEST); + } + + // Apply front face direction @fixme + // glFrontFace(state->frontFace); + + // Apply line width + glLineWidth(state->lineWidth); + + // apply smooth lines + if (state->smoothLineEnabled) { + glEnable(GL_LINE_SMOOTH); + } else { + glDisable(GL_LINE_SMOOTH); + } + + // Apply point size + if (state->pointSizeEnabled) { + glEnable(GL_PROGRAM_POINT_SIZE); + glPointSize(state->pointSize); + } else { + glDisable(GL_PROGRAM_POINT_SIZE); + } + + // Apply polygon mode + glPolygonMode(state->polygonModeFace, state->polygonModeMode); + + // Apply scissor test + if (state->scissorTestEnabled) { + glEnable(GL_SCISSOR_TEST); + glScissor(state->scissorBox[0], state->scissorBox[1], state->scissorBox[2], state->scissorBox[3]); + } else { + glDisable(GL_SCISSOR_TEST); + } + } +} + // ---------------------------------------------------------------------------- // shaders @@ -370543,7 +370747,7 @@ typedef map(unsigned,int) uniform_binding; static __thread unsigned last_shader = -1; static __thread quarks_db uniform_names; static __thread map(handle, uniform_binding) uniforms; -static + int shader_uniform(const char *name) { do_once map_init(uniforms, less_int, hash_int); if (!map_find(uniforms, last_shader)) { @@ -371873,17 +372077,21 @@ void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength) { API vec4 window_getcolor_(); // internal use, not public +static renderstate_t skybox_rs; + int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) { last_cubemap = &sky->cubemap; - //glClear(GL_DEPTH_BUFFER_BIT); - //glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - //glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); + do_once { + skybox_rs = renderstate(); + } // we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise - vec4 bgcolor = window_getcolor_(); glClearColor(bgcolor.r, bgcolor.g, bgcolor.b, 1); // @transparent + vec4 bgcolor = window_getcolor_(); + skybox_rs.clearColor[0] = bgcolor.r; + skybox_rs.clearColor[1] = bgcolor.g; + skybox_rs.clearColor[2] = bgcolor.b; + skybox_rs.clearColor[3] = 1; // @transparent mat44 mvp; multiply44x2(mvp, proj, view); @@ -371893,6 +372101,8 @@ int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) { if( sky->flags ) { shader_cubemap("u_cubemap", sky->cubemap.id); } + + renderstate_apply(&skybox_rs); return 0; // @fixme: return sortable hash here? } int skybox_pop_state() { @@ -371903,7 +372113,6 @@ int skybox_pop_state() { } int skybox_render(skybox_t *sky, mat44 proj, mat44 view) { skybox_push_state(sky, proj, view); - glEnable(GL_DEPTH_TEST); mesh_render(&sky->geometry); skybox_pop_state(); return 0; @@ -373562,6 +373771,11 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model, model_t model_from_mem(const void *mem, int len, int flags) { model_t m = {0}; + { + m.rs = renderstate(); + m.rs.blendEnabled = 1; + } + m.stored_flags = flags; m.shading = SHADING_PHONG; @@ -373845,6 +374059,8 @@ void model_draw_call(model_t m, int shader) { handle old_shader = last_shader; shader_bind(shader); + renderstate_apply(&m.rs); + glBindVertexArray( q->vao ); struct iqmtriangle *tris = NULL; @@ -374143,6 +374359,7 @@ typedef struct text2d_cmd { float sca; } text2d_cmd; +static renderstate_t dd_rs; static uint32_t dd_color = ~0u; static GLuint dd_program = -1; static int dd_u_color = -1; @@ -374176,7 +374393,9 @@ void ddraw_flush() { } void ddraw_flush_projview(mat44 proj, mat44 view) { - glEnable(GL_DEPTH_TEST); + do_once dd_rs = renderstate(); + + dd_rs.depthTestEnabled = 1; glActiveTexture(GL_TEXTURE0); mat44 mvp; @@ -374191,16 +374410,16 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { glEnableVertexAttribArray(0); - glDepthFunc(GL_LEQUAL); - glEnable(GL_PROGRAM_POINT_SIZE); // for GL_POINTS - glEnable(GL_LINE_SMOOTH); // for GL_LINES (thin) + dd_rs.pointSizeEnabled = 1; + dd_rs.smoothLineEnabled = 1; for( int i = 0; i < 3; ++i ) { // [0] thin, [1] thick, [2] points GLenum mode = i < 2 ? GL_LINES : GL_POINTS; - glLineWidth(i == 1 ? 1 : 0.3); // 0.625); + dd_rs.lineWidth = (i == 1 ? 1 : 0.3); // 0.625); for each_map(dd_lists[dd_ontop][i], unsigned, rgb, array(vec3), list) { int count = array_count(list); if(!count) continue; + renderstate_apply(&dd_rs); // color vec3 rgbf = {((rgb>>0)&255)/255.f,((rgb>>8)&255)/255.f,((rgb>>16)&255)/255.f}; glUniform3fv(dd_u_color, GL_TRUE, &rgbf.x); @@ -374229,10 +374448,11 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { glUniformMatrix4fv(glGetUniformLocation(dd_program, "u_MVP"), 1, GL_FALSE, mvp); for( int i = 0; i < 3; ++i ) { // [0] thin, [1] thick, [2] points GLenum mode = i < 2 ? GL_LINES : GL_POINTS; - glLineWidth(i == 1 ? 1 : 0.3); // 0.625); + dd_rs.lineWidth = (i == 1 ? 1 : 0.3); // 0.625); for each_map(dd_lists[dd_ontop][i], unsigned, rgb, array(vec3), list) { int count = array_count(list); if(!count) continue; + renderstate_apply(&dd_rs); // color vec3 rgbf = {((rgb>>0)&255)/255.f,((rgb>>8)&255)/255.f,((rgb>>16)&255)/255.f}; glUniform3fv(dd_u_color, GL_TRUE, &rgbf.x); @@ -374251,9 +374471,6 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { array_resize(dd_text2d, 0); } - glDisable(GL_LINE_SMOOTH); - glDisable(GL_PROGRAM_POINT_SIZE); - glBindVertexArray(0); ddraw_color(WHITE); // reset color for next drawcall @@ -379529,7 +379746,20 @@ struct nk_glfw *window_handle_nkglfw() { return g->nk_glfw; } +static renderstate_t window_rs; + void glNewFrame() { + do_once { + window_rs = renderstate(); + window_rs.blendEnabled = 1; + window_rs.depthTestEnabled = 1; + } + + window_rs.clearColor[0] = winbgcolor.r; + window_rs.clearColor[1] = winbgcolor.g; + window_rs.clearColor[2] = winbgcolor.b; + window_rs.clearColor[3] = window_has_transparent() ? 0 : winbgcolor.a; + // @transparent debug // if( input_down(KEY_F1) ) window_transparent(window_has_transparent()^1); // if( input_down(KEY_F2) ) window_maximize(window_has_maximize()^1); @@ -379550,30 +379780,8 @@ void glNewFrame() { g->width = w; g->height = h; - // blending defaults - glEnable(GL_BLEND); + renderstate_apply(&window_rs); - // culling defaults -// glEnable(GL_CULL_FACE); -// glCullFace(GL_BACK); -// glFrontFace(GL_CCW); - - // depth-testing defaults - glEnable(GL_DEPTH_TEST); -// glDepthFunc(GL_LESS); - - // depth-writing defaults -// glDepthMask(GL_TRUE); - - // seamless cubemaps -// glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - - glViewport(0, 0, window_width(), window_height()); - - // GLfloat bgColor[4]; glGetFloatv(GL_COLOR_CLEAR_VALUE, bgColor); - glClearColor(winbgcolor.r, winbgcolor.g, winbgcolor.b, window_has_transparent() ? 0 : winbgcolor.a); // @transparent - //glClearColor(0.15,0.15,0.15,1); - //glClearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); } diff --git a/engine/split/v4k_font.c b/engine/split/v4k_font.c index ab16ccc..8539975 100644 --- a/engine/split/v4k_font.c +++ b/engine/split/v4k_font.c @@ -1554,6 +1554,9 @@ typedef struct font_t { // vbos GLuint vbo_quad; // vec2: simply just a regular [0,1]x[0,1] quad GLuint vbo_instances; // vec4: (char_pos_x, char_pos_y, char_index, color_index) + + // render state + renderstate_t rs; } font_t; enum { FONTS_MAX = 10 }; @@ -1892,6 +1895,16 @@ void font_face_from_mem(const char *tag, const void *ttf_data, unsigned ttf_len, glUniform2f(glGetUniformLocation(f->program, "res_meta"), f->num_glyphs, 2); glUniform1f(glGetUniformLocation(f->program, "num_colors"), FONT_MAX_COLORS); (void)flags; + + // set up pipeline + f->rs = renderstate(); + f->rs.blendEnabled = 1; + f->rs.blendFunc = GL_FUNC_ADD; + f->rs.blendSrc = GL_SRC_ALPHA; + f->rs.blendDst = GL_ONE_MINUS_SRC_ALPHA; + f->rs.scissorTestEnabled = 1; + f->rs.depthTestEnabled = 0; + f->rs.cullFaceEnabled = 0; } void font_face(const char *tag, const char *filename_ttf, float font_size, unsigned flags) { @@ -1922,25 +1935,10 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glActiveTexture(GL_TEXTURE2); glGetIntegerv(GL_TEXTURE_BINDING_1D, &last_texture2); - glGetIntegerv(GL_BLEND_SRC, &last_blend_src); - glGetIntegerv(GL_BLEND_DST, &last_blend_dst); - glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); - glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); - - GLboolean last_enable_blend = glIsEnabled(GL_BLEND); - GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); - GLboolean last_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - - // Setup render state: alpha-blending enabled, no depth testing, enable clipping and bind textures - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // @fixme: store existing scissor test setup - glEnable(GL_SCISSOR_TEST); - glScissor(rect.x, window_height() - (rect.y+rect.w), rect.z, rect.w); - - glDisable(GL_DEPTH_TEST); + f->rs.scissorBox[0] = rect.x; + f->rs.scissorBox[1] = window_height() - (rect.y+rect.w); + f->rs.scissorBox[2] = rect.z; + f->rs.scissorBox[3] = rect.w; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, f->texture_fontdata); @@ -1966,6 +1964,9 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glBindBuffer(GL_ARRAY_BUFFER, f->vbo_instances); glBufferSubData(GL_ARRAY_BUFFER, 0, 4*4*glyph_idx, glyph_data); + // setup pipeline + renderstate_apply(&f->rs); + // actual drawing glDrawArraysInstanced(GL_TRIANGLES, 0, 6, glyph_idx); @@ -1979,13 +1980,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_1D, last_texture2); - glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); glBindVertexArray(last_vertex_array); - glBlendFunc(last_blend_src, last_blend_dst); - - (last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); - (last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND)); - (last_scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST)); } // 1. call font_face() if it's the first time it's called. diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index ec39cc3..697fd71 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -50,6 +50,154 @@ void glCopyBackbufferToTexture( texture_t *tex ) { // unused glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 0, 0, window_width(), window_height(), 0 ); } +// ---------------------------------------------------------------------------- +// renderstate + +renderstate_t renderstate() { + renderstate_t state = {0}; + + // Set default viewport parameters + state.viewportX = 0; + state.viewportY = 0; + state.viewportWidth = window_width(); + state.viewportHeight = window_height(); + + // Set default clear color to black + state.clearColor[0] = 0.0f; // Red + state.clearColor[1] = 0.0f; // Green + state.clearColor[2] = 0.0f; // Blue + state.clearColor[3] = 1.0f; // Alpha + + // Set default clear depth to maximum distance + state.clearDepth = 1.0; + + // Enable depth test by default with less or equal function + state.depthTestEnabled = GL_TRUE; + state.depthFunc = GL_LEQUAL; + + // Disable blending by default + state.blendEnabled = GL_FALSE; + state.blendFunc = GL_FUNC_ADD; + state.blendSrc = GL_ONE; + state.blendDst = GL_ZERO; + + // Enable culling by default and cull back faces + state.cullFaceEnabled = GL_TRUE; + state.cullFaceMode = GL_BACK; + + // Disable stencil test by default + state.stencilTestEnabled = GL_FALSE; + state.stencilFunc = GL_ALWAYS; + state.stencilRef = 0; + state.stencilMask = 0xFFFFFFFF; + + // Set default front face to counter-clockwise + state.frontFace = GL_CCW; + + // Set default line width + state.smoothLineEnabled = GL_FALSE; + state.lineWidth = 1.0f; + + // Set default point size + state.pointSizeEnabled = GL_FALSE; + state.pointSize = 1.0f; + + // Set default polygon mode to fill + state.polygonModeFace = GL_FRONT_AND_BACK; + state.polygonModeMode = GL_FILL; + + // Disable scissor test by default + state.scissorTestEnabled = GL_FALSE; + state.scissorBox[0] = 0; + state.scissorBox[1] = 0; + state.scissorBox[2] = window_width(); + state.scissorBox[3] = window_height(); + + return state; +} + +bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB) { + return memcmp(stateA, stateB, sizeof(renderstate_t)) == 0; +} + +void renderstate_apply(const renderstate_t *state) { + if (state != NULL) { + // Apply viewport parameters + glViewport(state->viewportX, state->viewportY, state->viewportWidth, state->viewportHeight); + + // Apply clear color + glClearColor(state->clearColor[0], state->clearColor[1], state->clearColor[2], state->clearColor[3]); + + // Apply clear depth + glClearDepth(state->clearDepth); + + // Apply depth test + if (state->depthTestEnabled) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(state->depthFunc); + } else { + glDisable(GL_DEPTH_TEST); + } + + // Apply blending + if (state->blendEnabled) { + glEnable(GL_BLEND); + glBlendEquation(state->blendFunc); + glBlendFunc(state->blendSrc, state->blendDst); + } else { + glDisable(GL_BLEND); + } + + // Apply culling @fixme + // if (state->cullFaceEnabled) { + // glEnable(GL_CULL_FACE); + // glCullFace(state->cullFaceMode); + // } else { + // glDisable(GL_CULL_FACE); + // } + + // Apply stencil test + if (state->stencilTestEnabled) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(state->stencilFunc, state->stencilRef, state->stencilMask); + } else { + glDisable(GL_STENCIL_TEST); + } + + // Apply front face direction @fixme + // glFrontFace(state->frontFace); + + // Apply line width + glLineWidth(state->lineWidth); + + // apply smooth lines + if (state->smoothLineEnabled) { + glEnable(GL_LINE_SMOOTH); + } else { + glDisable(GL_LINE_SMOOTH); + } + + // Apply point size + if (state->pointSizeEnabled) { + glEnable(GL_PROGRAM_POINT_SIZE); + glPointSize(state->pointSize); + } else { + glDisable(GL_PROGRAM_POINT_SIZE); + } + + // Apply polygon mode + glPolygonMode(state->polygonModeFace, state->polygonModeMode); + + // Apply scissor test + if (state->scissorTestEnabled) { + glEnable(GL_SCISSOR_TEST); + glScissor(state->scissorBox[0], state->scissorBox[1], state->scissorBox[2], state->scissorBox[3]); + } else { + glDisable(GL_SCISSOR_TEST); + } + } +} + // ---------------------------------------------------------------------------- // shaders @@ -524,7 +672,7 @@ typedef map(unsigned,int) uniform_binding; static __thread unsigned last_shader = -1; static __thread quarks_db uniform_names; static __thread map(handle, uniform_binding) uniforms; -static + int shader_uniform(const char *name) { do_once map_init(uniforms, less_int, hash_int); if (!map_find(uniforms, last_shader)) { @@ -1854,17 +2002,21 @@ void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength) { API vec4 window_getcolor_(); // internal use, not public +static renderstate_t skybox_rs; + int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) { last_cubemap = &sky->cubemap; - //glClear(GL_DEPTH_BUFFER_BIT); - //glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - //glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); + do_once { + skybox_rs = renderstate(); + } // we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise - vec4 bgcolor = window_getcolor_(); glClearColor(bgcolor.r, bgcolor.g, bgcolor.b, 1); // @transparent + vec4 bgcolor = window_getcolor_(); + skybox_rs.clearColor[0] = bgcolor.r; + skybox_rs.clearColor[1] = bgcolor.g; + skybox_rs.clearColor[2] = bgcolor.b; + skybox_rs.clearColor[3] = 1; // @transparent mat44 mvp; multiply44x2(mvp, proj, view); @@ -1874,6 +2026,8 @@ int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) { if( sky->flags ) { shader_cubemap("u_cubemap", sky->cubemap.id); } + + renderstate_apply(&skybox_rs); return 0; // @fixme: return sortable hash here? } int skybox_pop_state() { @@ -1884,7 +2038,6 @@ int skybox_pop_state() { } int skybox_render(skybox_t *sky, mat44 proj, mat44 view) { skybox_push_state(sky, proj, view); - glEnable(GL_DEPTH_TEST); mesh_render(&sky->geometry); skybox_pop_state(); return 0; @@ -3543,6 +3696,11 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model, model_t model_from_mem(const void *mem, int len, int flags) { model_t m = {0}; + { + m.rs = renderstate(); + m.rs.blendEnabled = 1; + } + m.stored_flags = flags; m.shading = SHADING_PHONG; @@ -3826,6 +3984,8 @@ void model_draw_call(model_t m, int shader) { handle old_shader = last_shader; shader_bind(shader); + renderstate_apply(&m.rs); + glBindVertexArray( q->vao ); struct iqmtriangle *tris = NULL; diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index 5611b37..cd6a25d 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -8,6 +8,65 @@ typedef unsigned handle; // GLuint +// ----------------------------------------------------------------------------- +// renderstate +typedef struct renderstate_t { + // Viewport parameters + int viewportX; + int viewportY; + int viewportWidth; + int viewportHeight; + + // Clear color + float clearColor[4]; + + // Clear depth + double clearDepth; + + // Depth test + bool depthTestEnabled; + unsigned depthFunc; + + // Blending + bool blendEnabled; + unsigned blendFunc; + unsigned blendSrc; + unsigned blendDst; + + // Culling + bool cullFaceEnabled; + unsigned cullFaceMode; + + // Stencil test + bool stencilTestEnabled; + unsigned stencilFunc; + int stencilRef; + unsigned stencilMask; + + // Face culling direction + unsigned frontFace; // GL_CW or GL_CCW + + // Line width + bool smoothLineEnabled; + float lineWidth; + + // Point size + bool pointSizeEnabled; + float pointSize; + + // Polygon mode + unsigned polygonModeFace; + unsigned polygonModeMode; + + // Scissor test + bool scissorTestEnabled; + int scissorBox[4]; +} renderstate_t; + +API renderstate_t renderstate(); +API bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB); +API void renderstate_apply(const renderstate_t *state); + // ----------------------------------------------------------------------------- // colors @@ -228,6 +287,7 @@ API void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float botto API unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_bind(unsigned program); +API int shader_uniform(const char *name); API void shader_bool(const char *uniform, bool i ); API void shader_int(const char *uniform, int i); API void shader_uint(const char *uniform, unsigned i ); @@ -577,6 +637,7 @@ typedef struct model_t { unsigned num_instances; int stored_flags; + renderstate_t rs; } model_t; enum BILLBOARD_MODE { diff --git a/engine/split/v4k_renderdd.c b/engine/split/v4k_renderdd.c index 179c734..942fd3b 100644 --- a/engine/split/v4k_renderdd.c +++ b/engine/split/v4k_renderdd.c @@ -33,6 +33,7 @@ typedef struct text2d_cmd { float sca; } text2d_cmd; +static renderstate_t dd_rs; static uint32_t dd_color = ~0u; static GLuint dd_program = -1; static int dd_u_color = -1; @@ -66,7 +67,9 @@ void ddraw_flush() { } void ddraw_flush_projview(mat44 proj, mat44 view) { - glEnable(GL_DEPTH_TEST); + do_once dd_rs = renderstate(); + + dd_rs.depthTestEnabled = 1; glActiveTexture(GL_TEXTURE0); mat44 mvp; @@ -81,16 +84,16 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { glEnableVertexAttribArray(0); - glDepthFunc(GL_LEQUAL); - glEnable(GL_PROGRAM_POINT_SIZE); // for GL_POINTS - glEnable(GL_LINE_SMOOTH); // for GL_LINES (thin) + dd_rs.pointSizeEnabled = 1; + dd_rs.smoothLineEnabled = 1; for( int i = 0; i < 3; ++i ) { // [0] thin, [1] thick, [2] points GLenum mode = i < 2 ? GL_LINES : GL_POINTS; - glLineWidth(i == 1 ? 1 : 0.3); // 0.625); + dd_rs.lineWidth = (i == 1 ? 1 : 0.3); // 0.625); for each_map(dd_lists[dd_ontop][i], unsigned, rgb, array(vec3), list) { int count = array_count(list); if(!count) continue; + renderstate_apply(&dd_rs); // color vec3 rgbf = {((rgb>>0)&255)/255.f,((rgb>>8)&255)/255.f,((rgb>>16)&255)/255.f}; glUniform3fv(dd_u_color, GL_TRUE, &rgbf.x); @@ -119,10 +122,11 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { glUniformMatrix4fv(glGetUniformLocation(dd_program, "u_MVP"), 1, GL_FALSE, mvp); for( int i = 0; i < 3; ++i ) { // [0] thin, [1] thick, [2] points GLenum mode = i < 2 ? GL_LINES : GL_POINTS; - glLineWidth(i == 1 ? 1 : 0.3); // 0.625); + dd_rs.lineWidth = (i == 1 ? 1 : 0.3); // 0.625); for each_map(dd_lists[dd_ontop][i], unsigned, rgb, array(vec3), list) { int count = array_count(list); if(!count) continue; + renderstate_apply(&dd_rs); // color vec3 rgbf = {((rgb>>0)&255)/255.f,((rgb>>8)&255)/255.f,((rgb>>16)&255)/255.f}; glUniform3fv(dd_u_color, GL_TRUE, &rgbf.x); @@ -141,9 +145,6 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { array_resize(dd_text2d, 0); } - glDisable(GL_LINE_SMOOTH); - glDisable(GL_PROGRAM_POINT_SIZE); - glBindVertexArray(0); ddraw_color(WHITE); // reset color for next drawcall diff --git a/engine/split/v4k_window.c b/engine/split/v4k_window.c index 4b59b6a..dab5a1c 100644 --- a/engine/split/v4k_window.c +++ b/engine/split/v4k_window.c @@ -221,7 +221,20 @@ struct nk_glfw *window_handle_nkglfw() { return g->nk_glfw; } +static renderstate_t window_rs; + void glNewFrame() { + do_once { + window_rs = renderstate(); + window_rs.blendEnabled = 1; + window_rs.depthTestEnabled = 1; + } + + window_rs.clearColor[0] = winbgcolor.r; + window_rs.clearColor[1] = winbgcolor.g; + window_rs.clearColor[2] = winbgcolor.b; + window_rs.clearColor[3] = window_has_transparent() ? 0 : winbgcolor.a; + // @transparent debug // if( input_down(KEY_F1) ) window_transparent(window_has_transparent()^1); // if( input_down(KEY_F2) ) window_maximize(window_has_maximize()^1); @@ -242,30 +255,8 @@ void glNewFrame() { g->width = w; g->height = h; - // blending defaults - glEnable(GL_BLEND); + renderstate_apply(&window_rs); - // culling defaults -// glEnable(GL_CULL_FACE); -// glCullFace(GL_BACK); -// glFrontFace(GL_CCW); - - // depth-testing defaults - glEnable(GL_DEPTH_TEST); -// glDepthFunc(GL_LESS); - - // depth-writing defaults -// glDepthMask(GL_TRUE); - - // seamless cubemaps -// glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - - glViewport(0, 0, window_width(), window_height()); - - // GLfloat bgColor[4]; glGetFloatv(GL_COLOR_CLEAR_VALUE, bgColor); - glClearColor(winbgcolor.r, winbgcolor.g, winbgcolor.b, window_has_transparent() ? 0 : winbgcolor.a); // @transparent - //glClearColor(0.15,0.15,0.15,1); - //glClearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); } diff --git a/engine/v4k.c b/engine/v4k.c index cba9396..6ddd5b7 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -10256,6 +10256,9 @@ typedef struct font_t { // vbos GLuint vbo_quad; // vec2: simply just a regular [0,1]x[0,1] quad GLuint vbo_instances; // vec4: (char_pos_x, char_pos_y, char_index, color_index) + + // render state + renderstate_t rs; } font_t; enum { FONTS_MAX = 10 }; @@ -10594,6 +10597,16 @@ void font_face_from_mem(const char *tag, const void *ttf_data, unsigned ttf_len, glUniform2f(glGetUniformLocation(f->program, "res_meta"), f->num_glyphs, 2); glUniform1f(glGetUniformLocation(f->program, "num_colors"), FONT_MAX_COLORS); (void)flags; + + // set up pipeline + f->rs = renderstate(); + f->rs.blendEnabled = 1; + f->rs.blendFunc = GL_FUNC_ADD; + f->rs.blendSrc = GL_SRC_ALPHA; + f->rs.blendDst = GL_ONE_MINUS_SRC_ALPHA; + f->rs.scissorTestEnabled = 1; + f->rs.depthTestEnabled = 0; + f->rs.cullFaceEnabled = 0; } void font_face(const char *tag, const char *filename_ttf, float font_size, unsigned flags) { @@ -10624,25 +10637,10 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glActiveTexture(GL_TEXTURE2); glGetIntegerv(GL_TEXTURE_BINDING_1D, &last_texture2); - glGetIntegerv(GL_BLEND_SRC, &last_blend_src); - glGetIntegerv(GL_BLEND_DST, &last_blend_dst); - glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); - glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); - - GLboolean last_enable_blend = glIsEnabled(GL_BLEND); - GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); - GLboolean last_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - - // Setup render state: alpha-blending enabled, no depth testing, enable clipping and bind textures - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // @fixme: store existing scissor test setup - glEnable(GL_SCISSOR_TEST); - glScissor(rect.x, window_height() - (rect.y+rect.w), rect.z, rect.w); - - glDisable(GL_DEPTH_TEST); + f->rs.scissorBox[0] = rect.x; + f->rs.scissorBox[1] = window_height() - (rect.y+rect.w); + f->rs.scissorBox[2] = rect.z; + f->rs.scissorBox[3] = rect.w; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, f->texture_fontdata); @@ -10668,6 +10666,9 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glBindBuffer(GL_ARRAY_BUFFER, f->vbo_instances); glBufferSubData(GL_ARRAY_BUFFER, 0, 4*4*glyph_idx, glyph_data); + // setup pipeline + renderstate_apply(&f->rs); + // actual drawing glDrawArraysInstanced(GL_TRIANGLES, 0, 6, glyph_idx); @@ -10681,13 +10682,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_1D, last_texture2); - glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); glBindVertexArray(last_vertex_array); - glBlendFunc(last_blend_src, last_blend_dst); - - (last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); - (last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND)); - (last_scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST)); } // 1. call font_face() if it's the first time it's called. @@ -17222,6 +17217,154 @@ void glCopyBackbufferToTexture( texture_t *tex ) { // unused glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 0, 0, window_width(), window_height(), 0 ); } +// ---------------------------------------------------------------------------- +// renderstate + +renderstate_t renderstate() { + renderstate_t state = {0}; + + // Set default viewport parameters + state.viewportX = 0; + state.viewportY = 0; + state.viewportWidth = window_width(); + state.viewportHeight = window_height(); + + // Set default clear color to black + state.clearColor[0] = 0.0f; // Red + state.clearColor[1] = 0.0f; // Green + state.clearColor[2] = 0.0f; // Blue + state.clearColor[3] = 1.0f; // Alpha + + // Set default clear depth to maximum distance + state.clearDepth = 1.0; + + // Enable depth test by default with less or equal function + state.depthTestEnabled = GL_TRUE; + state.depthFunc = GL_LEQUAL; + + // Disable blending by default + state.blendEnabled = GL_FALSE; + state.blendFunc = GL_FUNC_ADD; + state.blendSrc = GL_ONE; + state.blendDst = GL_ZERO; + + // Enable culling by default and cull back faces + state.cullFaceEnabled = GL_TRUE; + state.cullFaceMode = GL_BACK; + + // Disable stencil test by default + state.stencilTestEnabled = GL_FALSE; + state.stencilFunc = GL_ALWAYS; + state.stencilRef = 0; + state.stencilMask = 0xFFFFFFFF; + + // Set default front face to counter-clockwise + state.frontFace = GL_CCW; + + // Set default line width + state.smoothLineEnabled = GL_FALSE; + state.lineWidth = 1.0f; + + // Set default point size + state.pointSizeEnabled = GL_FALSE; + state.pointSize = 1.0f; + + // Set default polygon mode to fill + state.polygonModeFace = GL_FRONT_AND_BACK; + state.polygonModeMode = GL_FILL; + + // Disable scissor test by default + state.scissorTestEnabled = GL_FALSE; + state.scissorBox[0] = 0; + state.scissorBox[1] = 0; + state.scissorBox[2] = window_width(); + state.scissorBox[3] = window_height(); + + return state; +} + +bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB) { + return memcmp(stateA, stateB, sizeof(renderstate_t)) == 0; +} + +void renderstate_apply(const renderstate_t *state) { + if (state != NULL) { + // Apply viewport parameters + glViewport(state->viewportX, state->viewportY, state->viewportWidth, state->viewportHeight); + + // Apply clear color + glClearColor(state->clearColor[0], state->clearColor[1], state->clearColor[2], state->clearColor[3]); + + // Apply clear depth + glClearDepth(state->clearDepth); + + // Apply depth test + if (state->depthTestEnabled) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(state->depthFunc); + } else { + glDisable(GL_DEPTH_TEST); + } + + // Apply blending + if (state->blendEnabled) { + glEnable(GL_BLEND); + glBlendEquation(state->blendFunc); + glBlendFunc(state->blendSrc, state->blendDst); + } else { + glDisable(GL_BLEND); + } + + // Apply culling @fixme + // if (state->cullFaceEnabled) { + // glEnable(GL_CULL_FACE); + // glCullFace(state->cullFaceMode); + // } else { + // glDisable(GL_CULL_FACE); + // } + + // Apply stencil test + if (state->stencilTestEnabled) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(state->stencilFunc, state->stencilRef, state->stencilMask); + } else { + glDisable(GL_STENCIL_TEST); + } + + // Apply front face direction @fixme + // glFrontFace(state->frontFace); + + // Apply line width + glLineWidth(state->lineWidth); + + // apply smooth lines + if (state->smoothLineEnabled) { + glEnable(GL_LINE_SMOOTH); + } else { + glDisable(GL_LINE_SMOOTH); + } + + // Apply point size + if (state->pointSizeEnabled) { + glEnable(GL_PROGRAM_POINT_SIZE); + glPointSize(state->pointSize); + } else { + glDisable(GL_PROGRAM_POINT_SIZE); + } + + // Apply polygon mode + glPolygonMode(state->polygonModeFace, state->polygonModeMode); + + // Apply scissor test + if (state->scissorTestEnabled) { + glEnable(GL_SCISSOR_TEST); + glScissor(state->scissorBox[0], state->scissorBox[1], state->scissorBox[2], state->scissorBox[3]); + } else { + glDisable(GL_SCISSOR_TEST); + } + } +} + // ---------------------------------------------------------------------------- // shaders @@ -17696,7 +17839,7 @@ typedef map(unsigned,int) uniform_binding; static __thread unsigned last_shader = -1; static __thread quarks_db uniform_names; static __thread map(handle, uniform_binding) uniforms; -static + int shader_uniform(const char *name) { do_once map_init(uniforms, less_int, hash_int); if (!map_find(uniforms, last_shader)) { @@ -19026,17 +19169,21 @@ void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength) { API vec4 window_getcolor_(); // internal use, not public +static renderstate_t skybox_rs; + int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) { last_cubemap = &sky->cubemap; - //glClear(GL_DEPTH_BUFFER_BIT); - //glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - //glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); + do_once { + skybox_rs = renderstate(); + } // we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise - vec4 bgcolor = window_getcolor_(); glClearColor(bgcolor.r, bgcolor.g, bgcolor.b, 1); // @transparent + vec4 bgcolor = window_getcolor_(); + skybox_rs.clearColor[0] = bgcolor.r; + skybox_rs.clearColor[1] = bgcolor.g; + skybox_rs.clearColor[2] = bgcolor.b; + skybox_rs.clearColor[3] = 1; // @transparent mat44 mvp; multiply44x2(mvp, proj, view); @@ -19046,6 +19193,8 @@ int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) { if( sky->flags ) { shader_cubemap("u_cubemap", sky->cubemap.id); } + + renderstate_apply(&skybox_rs); return 0; // @fixme: return sortable hash here? } int skybox_pop_state() { @@ -19056,7 +19205,6 @@ int skybox_pop_state() { } int skybox_render(skybox_t *sky, mat44 proj, mat44 view) { skybox_push_state(sky, proj, view); - glEnable(GL_DEPTH_TEST); mesh_render(&sky->geometry); skybox_pop_state(); return 0; @@ -20715,6 +20863,11 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model, model_t model_from_mem(const void *mem, int len, int flags) { model_t m = {0}; + { + m.rs = renderstate(); + m.rs.blendEnabled = 1; + } + m.stored_flags = flags; m.shading = SHADING_PHONG; @@ -20998,6 +21151,8 @@ void model_draw_call(model_t m, int shader) { handle old_shader = last_shader; shader_bind(shader); + renderstate_apply(&m.rs); + glBindVertexArray( q->vao ); struct iqmtriangle *tris = NULL; @@ -21296,6 +21451,7 @@ typedef struct text2d_cmd { float sca; } text2d_cmd; +static renderstate_t dd_rs; static uint32_t dd_color = ~0u; static GLuint dd_program = -1; static int dd_u_color = -1; @@ -21329,7 +21485,9 @@ void ddraw_flush() { } void ddraw_flush_projview(mat44 proj, mat44 view) { - glEnable(GL_DEPTH_TEST); + do_once dd_rs = renderstate(); + + dd_rs.depthTestEnabled = 1; glActiveTexture(GL_TEXTURE0); mat44 mvp; @@ -21344,16 +21502,16 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { glEnableVertexAttribArray(0); - glDepthFunc(GL_LEQUAL); - glEnable(GL_PROGRAM_POINT_SIZE); // for GL_POINTS - glEnable(GL_LINE_SMOOTH); // for GL_LINES (thin) + dd_rs.pointSizeEnabled = 1; + dd_rs.smoothLineEnabled = 1; for( int i = 0; i < 3; ++i ) { // [0] thin, [1] thick, [2] points GLenum mode = i < 2 ? GL_LINES : GL_POINTS; - glLineWidth(i == 1 ? 1 : 0.3); // 0.625); + dd_rs.lineWidth = (i == 1 ? 1 : 0.3); // 0.625); for each_map(dd_lists[dd_ontop][i], unsigned, rgb, array(vec3), list) { int count = array_count(list); if(!count) continue; + renderstate_apply(&dd_rs); // color vec3 rgbf = {((rgb>>0)&255)/255.f,((rgb>>8)&255)/255.f,((rgb>>16)&255)/255.f}; glUniform3fv(dd_u_color, GL_TRUE, &rgbf.x); @@ -21382,10 +21540,11 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { glUniformMatrix4fv(glGetUniformLocation(dd_program, "u_MVP"), 1, GL_FALSE, mvp); for( int i = 0; i < 3; ++i ) { // [0] thin, [1] thick, [2] points GLenum mode = i < 2 ? GL_LINES : GL_POINTS; - glLineWidth(i == 1 ? 1 : 0.3); // 0.625); + dd_rs.lineWidth = (i == 1 ? 1 : 0.3); // 0.625); for each_map(dd_lists[dd_ontop][i], unsigned, rgb, array(vec3), list) { int count = array_count(list); if(!count) continue; + renderstate_apply(&dd_rs); // color vec3 rgbf = {((rgb>>0)&255)/255.f,((rgb>>8)&255)/255.f,((rgb>>16)&255)/255.f}; glUniform3fv(dd_u_color, GL_TRUE, &rgbf.x); @@ -21404,9 +21563,6 @@ void ddraw_flush_projview(mat44 proj, mat44 view) { array_resize(dd_text2d, 0); } - glDisable(GL_LINE_SMOOTH); - glDisable(GL_PROGRAM_POINT_SIZE); - glBindVertexArray(0); ddraw_color(WHITE); // reset color for next drawcall @@ -26682,7 +26838,20 @@ struct nk_glfw *window_handle_nkglfw() { return g->nk_glfw; } +static renderstate_t window_rs; + void glNewFrame() { + do_once { + window_rs = renderstate(); + window_rs.blendEnabled = 1; + window_rs.depthTestEnabled = 1; + } + + window_rs.clearColor[0] = winbgcolor.r; + window_rs.clearColor[1] = winbgcolor.g; + window_rs.clearColor[2] = winbgcolor.b; + window_rs.clearColor[3] = window_has_transparent() ? 0 : winbgcolor.a; + // @transparent debug // if( input_down(KEY_F1) ) window_transparent(window_has_transparent()^1); // if( input_down(KEY_F2) ) window_maximize(window_has_maximize()^1); @@ -26703,30 +26872,8 @@ void glNewFrame() { g->width = w; g->height = h; - // blending defaults - glEnable(GL_BLEND); + renderstate_apply(&window_rs); - // culling defaults -// glEnable(GL_CULL_FACE); -// glCullFace(GL_BACK); -// glFrontFace(GL_CCW); - - // depth-testing defaults - glEnable(GL_DEPTH_TEST); -// glDepthFunc(GL_LESS); - - // depth-writing defaults -// glDepthMask(GL_TRUE); - - // seamless cubemaps -// glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - - glViewport(0, 0, window_width(), window_height()); - - // GLfloat bgColor[4]; glGetFloatv(GL_COLOR_CLEAR_VALUE, bgColor); - glClearColor(winbgcolor.r, winbgcolor.g, winbgcolor.b, window_has_transparent() ? 0 : winbgcolor.a); // @transparent - //glClearColor(0.15,0.15,0.15,1); - //glClearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); } diff --git a/engine/v4k.h b/engine/v4k.h index 3519545..cb2dd03 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -3097,6 +3097,65 @@ API int ui_reflect(const char *mask); // *, model* or NULL typedef unsigned handle; // GLuint +// ----------------------------------------------------------------------------- +// renderstate +typedef struct renderstate_t { + // Viewport parameters + int viewportX; + int viewportY; + int viewportWidth; + int viewportHeight; + + // Clear color + float clearColor[4]; + + // Clear depth + double clearDepth; + + // Depth test + bool depthTestEnabled; + unsigned depthFunc; + + // Blending + bool blendEnabled; + unsigned blendFunc; + unsigned blendSrc; + unsigned blendDst; + + // Culling + bool cullFaceEnabled; + unsigned cullFaceMode; + + // Stencil test + bool stencilTestEnabled; + unsigned stencilFunc; + int stencilRef; + unsigned stencilMask; + + // Face culling direction + unsigned frontFace; // GL_CW or GL_CCW + + // Line width + bool smoothLineEnabled; + float lineWidth; + + // Point size + bool pointSizeEnabled; + float pointSize; + + // Polygon mode + unsigned polygonModeFace; + unsigned polygonModeMode; + + // Scissor test + bool scissorTestEnabled; + int scissorBox[4]; +} renderstate_t; + +API renderstate_t renderstate(); +API bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB); +API void renderstate_apply(const renderstate_t *state); + // ----------------------------------------------------------------------------- // colors @@ -3317,6 +3376,7 @@ API void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float botto API unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); API unsigned shader_bind(unsigned program); +API int shader_uniform(const char *name); API void shader_bool(const char *uniform, bool i ); API void shader_int(const char *uniform, int i); API void shader_uint(const char *uniform, unsigned i ); @@ -3666,6 +3726,7 @@ typedef struct model_t { unsigned num_instances; int stored_flags; + renderstate_t rs; } model_t; enum BILLBOARD_MODE {