From 4461128255ab24735d7110cb7fe99ac2479cef04 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Mon, 15 Jul 2024 08:23:43 -0400 Subject: [PATCH] GL1 unified draw calls, cont. Batching procedure from previous commit, applied this time to GLPoly / single texture surfaces; alpha and liquid included. --- src/client/refresh/gl1/gl1_buffer.c | 116 ++++++++++++++++++++- src/client/refresh/gl1/gl1_surf.c | 145 +++++++------------------- src/client/refresh/gl1/gl1_warp.c | 45 ++------ src/client/refresh/gl1/header/local.h | 7 +- 4 files changed, 166 insertions(+), 147 deletions(-) diff --git a/src/client/refresh/gl1/gl1_buffer.c b/src/client/refresh/gl1/gl1_buffer.c index 3e591e5e..cbcbb5df 100644 --- a/src/client/refresh/gl1/gl1_buffer.c +++ b/src/client/refresh/gl1/gl1_buffer.c @@ -61,16 +61,17 @@ R_ApplyGLBuffer(void) { // Properties of batched draws here GLint vtx_size; - qboolean texture; + qboolean texture, alpha, texenv_set; if (gl_buf.vtx_ptr == 0 || gl_buf.idx_ptr == 0) { return; } - // defaults for drawing + // defaults for drawing (mostly buf_singletex features) vtx_size = 3; texture = true; + alpha = texenv_set = false; // choosing features by type switch (gl_buf.type) @@ -78,10 +79,52 @@ R_ApplyGLBuffer(void) case buf_2d: vtx_size = 2; break; + case buf_alpha: + alpha = true; + break; default: break; } + if (alpha) + { + // the textures are prescaled up for a better + // lighting range, so scale it back down + glColor4f(gl_state.inverse_intensity, gl_state.inverse_intensity, + gl_state.inverse_intensity, gl_buf.alpha); + + } + else if (gl_buf.flags & SURF_DRAWTURB) + { + texenv_set = true; + + // This is a hack ontop of a hack. Warping surfaces like those generated + // by R_EmitWaterPolys() don't have a lightmap. Original Quake II therefore + // negated the global intensity on those surfaces, because otherwise they + // would show up much too bright. When we implemented overbright bits this + // hack modified the global GL state in an incompatible way. So implement + // a new hack, based on overbright bits... Depending on the value set to + // gl1_overbrightbits the result is different: + + // 0: Old behaviour. + // 1: No overbright bits on the global scene but correct lighting on + // warping surfaces. + // 2,4: Overbright bits on the global scene but not on warping surfaces. + // They oversaturate otherwise. + + if (gl1_overbrightbits->value) + { + R_TexEnv(GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1); + } + else + { + R_TexEnv(GL_MODULATE); + glColor4f(gl_state.inverse_intensity, gl_state.inverse_intensity, + gl_state.inverse_intensity, 1.0f); + } + } + glEnableClientState( GL_VERTEX_ARRAY ); glVertexPointer (vtx_size, GL_FLOAT, 0, gl_buf.vtx); @@ -104,13 +147,20 @@ R_ApplyGLBuffer(void) glDisableClientState( GL_VERTEX_ARRAY ); + if (texenv_set) + { + R_TexEnv(GL_REPLACE); + } + gl_buf.vtx_ptr = gl_buf.idx_ptr = 0; } void R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha) { - if ( gl_buf.type != type || gl_buf.texture[0] != colortex ) + if ( gl_buf.type != type || gl_buf.texture[0] != colortex || + (type == buf_singletex && gl_buf.flags != flags) || + (type == buf_alpha && gl_buf.alpha != alpha)) { R_ApplyGLBuffer(); @@ -169,3 +219,63 @@ R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy, gl_buf.vtx_ptr += 4; } + +/* + * Set up indices with the proper shape for the next buffered vertices + */ +void +R_SetBufferIndices(GLenum type, GLuint vertices_num) +{ + int i; + + if ( gl_buf.vtx_ptr + vertices_num >= MAX_VERTICES || + gl_buf.idx_ptr + ( (vertices_num - 2) * 3 ) >= MAX_INDICES ) + { + R_ApplyGLBuffer(); + } + + switch (type) + { + case GL_TRIANGLE_FAN: + for (i = 0; i < vertices_num-2; i++) + { + gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr; + gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+1; + gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+2; + } + break; + default: + R_Printf(PRINT_DEVELOPER, "R_SetBufferIndices: no such type %d\n", type); + return; + } + + // These affect the functions that follow in this file + vt = gl_buf.vtx_ptr * 3; // vertex index + tx = gl_buf.vtx_ptr * 2; // texcoord index + cl = gl_buf.vtx_ptr * 4; // color index + + // R_BufferVertex() must be called as many times as vertices_num + gl_buf.vtx_ptr += vertices_num; +} + +/* + * Adds a single vertex to buffer + */ +void +R_BufferVertex(GLfloat x, GLfloat y, GLfloat z) +{ + gl_buf.vtx[vt++] = x; + gl_buf.vtx[vt++] = y; + gl_buf.vtx[vt++] = z; +} + +/* + * Adds texture coordinates for color texture (no lightmap coords) + */ +void +R_BufferSingleTex(GLfloat s, GLfloat t) +{ + // tx should be set before this is called, by R_SetBufferIndices + gl_buf.tex[0][tx++] = s; + gl_buf.tex[0][tx++] = t; +} diff --git a/src/client/refresh/gl1/gl1_surf.c b/src/client/refresh/gl1/gl1_surf.c index 5848756f..d63d0ac9 100644 --- a/src/client/refresh/gl1/gl1_surf.c +++ b/src/client/refresh/gl1/gl1_surf.c @@ -43,63 +43,35 @@ void R_SetCacheState(msurface_t *surf); void R_BuildLightMap(msurface_t *surf, byte *dest, int stride); static void -R_DrawGLPoly(glpoly_t *p) +R_DrawGLPoly(msurface_t *fa) { - float *v; + int i, nv; + float *v, scroll; - v = p->verts[0]; + v = fa->polys->verts[0]; + nv = fa->polys->numverts; - glEnableClientState( GL_VERTEX_ARRAY ); - glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - glVertexPointer( 3, GL_FLOAT, VERTEXSIZE*sizeof(GLfloat), v ); - glTexCoordPointer( 2, GL_FLOAT, VERTEXSIZE*sizeof(GLfloat), v+3 ); - glDrawArrays( GL_TRIANGLE_FAN, 0, p->numverts ); - - glDisableClientState( GL_VERTEX_ARRAY ); - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); -} - -static void -R_DrawGLFlowingPoly(msurface_t *fa) -{ - int i; - float *v; - glpoly_t *p; - float scroll; - - p = fa->polys; - - scroll = -64 * ((r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0)); - - if (scroll == 0.0) + if (fa->texinfo->flags & SURF_FLOWING) { - scroll = -64.0; + scroll = -64 * ((r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0)); + + if (scroll == 0.0) + { + scroll = -64.0; + } + } + else + { + scroll = 0.0; } - YQ2_VLA(GLfloat, tex, 2*p->numverts); - unsigned int index_tex = 0; + R_SetBufferIndices(GL_TRIANGLE_FAN, nv); - v = p->verts [ 0 ]; - - for ( i = 0; i < p->numverts; i++, v += VERTEXSIZE ) - { - tex[index_tex++] = v [ 3 ] + scroll; - tex[index_tex++] = v [ 4 ]; - } - v = p->verts [ 0 ]; - - glEnableClientState( GL_VERTEX_ARRAY ); - glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - glVertexPointer( 3, GL_FLOAT, VERTEXSIZE*sizeof(GLfloat), v ); - glTexCoordPointer( 2, GL_FLOAT, 0, tex ); - glDrawArrays( GL_TRIANGLE_FAN, 0, p->numverts ); - - glDisableClientState( GL_VERTEX_ARRAY ); - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); - - YQ2_VLAFREE(tex); + for ( i = 0; i < nv; i++, v += VERTEXSIZE ) + { + R_BufferVertex(v[0], v[1], v[2]); + R_BufferSingleTex(v[3] + scroll, v[4]); + } } static void @@ -419,47 +391,11 @@ R_RenderBrushPoly(entity_t *currententity, msurface_t *fa) if (fa->flags & SURF_DRAWTURB) { - /* This is a hack ontop of a hack. Warping surfaces like those generated - by R_EmitWaterPolys() don't have a lightmap. Original Quake II therefore - negated the global intensity on those surfaces, because otherwise they - would show up much too bright. When we implemented overbright bits this - hack modified the global GL state in an incompatible way. So implement - a new hack, based on overbright bits... Depending on the value set to - gl1_overbrightbits the result is different: - - 0: Old behaviour. - 1: No overbright bits on the global scene but correct lighting on - warping surfaces. - 2: Overbright bits on the global scene but not on warping surfaces. - They oversaturate otherwise. */ - if (gl1_overbrightbits->value) - { - R_TexEnv(GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1); - } - else - { - R_TexEnv(GL_MODULATE); - glColor4f(gl_state.inverse_intensity, gl_state.inverse_intensity, - gl_state.inverse_intensity, 1.0f); - } - R_EmitWaterPolys(fa); - R_TexEnv(GL_REPLACE); - return; } - R_TexEnv(GL_REPLACE); - - if (fa->texinfo->flags & SURF_FLOWING) - { - R_DrawGLFlowingPoly(fa); - } - else - { - R_DrawGLPoly(fa->polys); - } + R_DrawGLPoly(fa); if (gl_config.multitexture) { @@ -538,7 +474,7 @@ void R_DrawAlphaSurfaces(void) { msurface_t *s; - float intens; + float alpha; /* go back to the world matrix */ glLoadMatrixf(r_world_matrix); @@ -546,41 +482,35 @@ R_DrawAlphaSurfaces(void) glEnable(GL_BLEND); R_TexEnv(GL_MODULATE); - /* the textures are prescaled up for a better - lighting range, so scale it back down */ - intens = gl_state.inverse_intensity; - for (s = r_alpha_surfaces; s; s = s->texturechain) { - R_Bind(s->texinfo->image->texnum); c_brush_polys++; if (s->texinfo->flags & SURF_TRANS33) { - glColor4f(intens, intens, intens, 0.33); + alpha = 0.33f; } else if (s->texinfo->flags & SURF_TRANS66) { - glColor4f(intens, intens, intens, 0.66); + alpha = 0.66f; } else { - glColor4f(intens, intens, intens, 1); + alpha = 1.0f; } + R_UpdateGLBuffer(buf_alpha, s->texinfo->image->texnum, 0, 0, alpha); + if (s->flags & SURF_DRAWTURB) { R_EmitWaterPolys(s); } - else if (s->texinfo->flags & SURF_FLOWING) - { - R_DrawGLFlowingPoly(s); - } else { - R_DrawGLPoly(s->polys); + R_DrawGLPoly(s); } } + R_ApplyGLBuffer(); // Flush the last batched array R_TexEnv(GL_REPLACE); glColor4f(1, 1, 1, 1); @@ -842,12 +772,13 @@ R_DrawTextureChains(entity_t *currententity) for ( ; s; s = s->texturechain) { - R_Bind(image->texnum); // may reset because of dynamic lighting in R_RenderBrushPoly + R_UpdateGLBuffer(buf_singletex, image->texnum, 0, s->flags, 1); R_RenderBrushPoly(currententity, s); } image->texturechain = NULL; } + R_ApplyGLBuffer(); // Flush the last batched array } else // multitexture { @@ -872,7 +803,7 @@ R_DrawTextureChains(entity_t *currententity) } } - R_EnableMultitexture(false); + R_EnableMultitexture(false); // force disabling, SURF_DRAWTURB surfaces may not exist for (i = 0, image = gltextures; i < numgltextures; i++, image++) { @@ -885,13 +816,14 @@ R_DrawTextureChains(entity_t *currententity) { if (s->flags & SURF_DRAWTURB) { - R_Bind(image->texnum); + R_UpdateGLBuffer(buf_singletex, image->texnum, 0, s->flags, 1); R_RenderBrushPoly(currententity, s); } } image->texturechain = NULL; } + R_ApplyGLBuffer(); } } @@ -958,13 +890,14 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel) } else { - R_EnableMultitexture(false); - R_Bind(image->texnum); + R_UpdateGLBuffer(buf_singletex, image->texnum, 0, psurf->flags, 1); R_RenderBrushPoly(currententity, psurf); } } } } + R_EnableMultitexture(false); + R_ApplyGLBuffer(); if (!(currententity->flags & RF_TRANSLUCENT)) { diff --git a/src/client/refresh/gl1/gl1_warp.c b/src/client/refresh/gl1/gl1_warp.c index ba96a4a3..d0ca9f7a 100644 --- a/src/client/refresh/gl1/gl1_warp.c +++ b/src/client/refresh/gl1/gl1_warp.c @@ -282,7 +282,7 @@ R_EmitWaterPolys(msurface_t *fa) { glpoly_t *p, *bp; float *v; - int i; + int i, nv; float s, t, os, ot; float scroll; float rdt = r_newrefdef.time; @@ -296,53 +296,24 @@ R_EmitWaterPolys(msurface_t *fa) scroll = 0; } - // workaround for lack of VLAs (=> our workaround uses alloca() which is bad in loops) -#ifdef _MSC_VER - int maxNumVerts = 0; - for ( glpoly_t* tmp = fa->polys; tmp; tmp = tmp->next ) - { - if (tmp->numverts > maxNumVerts) - maxNumVerts = tmp->numverts; - } - - YQ2_VLA( GLfloat, tex, 2 * maxNumVerts ); -#endif - for (bp = fa->polys; bp; bp = bp->next) { p = bp; -#ifndef _MSC_VER // we have real VLAs, so it's safe to use one in this loop - YQ2_VLA(GLfloat, tex, 2*p->numverts); -#endif - unsigned int index_tex = 0; + nv = p->numverts; + R_SetBufferIndices(GL_TRIANGLE_FAN, nv); - for ( i = 0, v = p->verts [ 0 ]; i < p->numverts; i++, v += VERTEXSIZE ) + for ( i = 0, v = p->verts [ 0 ]; i < nv; i++, v += VERTEXSIZE ) { os = v [ 3 ]; ot = v [ 4 ]; - s = os + r_turbsin [ (int) ( ( ot * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ]; - s += scroll; - tex[index_tex++] = s * ( 1.0 / 64 ); - + s = os + r_turbsin [ (int) ( ( ot * 0.125 + rdt ) * TURBSCALE ) & 255 ] + scroll; t = ot + r_turbsin [ (int) ( ( os * 0.125 + rdt ) * TURBSCALE ) & 255 ]; - tex[index_tex++] = t * ( 1.0 / 64 ); + + R_BufferVertex( v[0], v[1], v[2] ); + R_BufferSingleTex( s * ( 1.0 / 64 ), t * ( 1.0 / 64 ) ); } - - v = p->verts [ 0 ]; - - glEnableClientState( GL_VERTEX_ARRAY ); - glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - glVertexPointer( 3, GL_FLOAT, VERTEXSIZE*sizeof(GLfloat), v ); - glTexCoordPointer( 2, GL_FLOAT, 0, tex ); - glDrawArrays( GL_TRIANGLE_FAN, 0, p->numverts ); - - glDisableClientState( GL_VERTEX_ARRAY ); - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); } - - YQ2_VLAFREE( tex ); } void diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index 554b3b4a..b6a24e9b 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -109,7 +109,9 @@ typedef enum typedef enum { - buf_2d + buf_2d, + buf_singletex, + buf_alpha } buffered_draw_t; #include "model.h" @@ -290,6 +292,9 @@ void R_ApplyGLBuffer(void); void R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha); void R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy, GLfloat ul_tx, GLfloat ul_ty, GLfloat dr_tx, GLfloat dr_ty); +void R_SetBufferIndices(GLenum type, GLuint vertices_num); +void R_BufferVertex(GLfloat x, GLfloat y, GLfloat z); +void R_BufferSingleTex(GLfloat s, GLfloat t); #ifdef DEBUG void glCheckError_(const char *file, const char *function, int line);