GL1 unified draw calls, cont.

Batching procedure from previous commit, applied this time to GLPoly
/ single texture surfaces; alpha and liquid included.
This commit is contained in:
Jaime Moreira 2024-07-15 08:23:43 -04:00
parent 50aebd2de4
commit 4461128255
4 changed files with 166 additions and 147 deletions

View file

@ -61,16 +61,17 @@ R_ApplyGLBuffer(void)
{ {
// Properties of batched draws here // Properties of batched draws here
GLint vtx_size; GLint vtx_size;
qboolean texture; qboolean texture, alpha, texenv_set;
if (gl_buf.vtx_ptr == 0 || gl_buf.idx_ptr == 0) if (gl_buf.vtx_ptr == 0 || gl_buf.idx_ptr == 0)
{ {
return; return;
} }
// defaults for drawing // defaults for drawing (mostly buf_singletex features)
vtx_size = 3; vtx_size = 3;
texture = true; texture = true;
alpha = texenv_set = false;
// choosing features by type // choosing features by type
switch (gl_buf.type) switch (gl_buf.type)
@ -78,10 +79,52 @@ R_ApplyGLBuffer(void)
case buf_2d: case buf_2d:
vtx_size = 2; vtx_size = 2;
break; break;
case buf_alpha:
alpha = true;
break;
default: default:
break; 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 ); glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer (vtx_size, GL_FLOAT, 0, gl_buf.vtx); glVertexPointer (vtx_size, GL_FLOAT, 0, gl_buf.vtx);
@ -104,13 +147,20 @@ R_ApplyGLBuffer(void)
glDisableClientState( GL_VERTEX_ARRAY ); glDisableClientState( GL_VERTEX_ARRAY );
if (texenv_set)
{
R_TexEnv(GL_REPLACE);
}
gl_buf.vtx_ptr = gl_buf.idx_ptr = 0; gl_buf.vtx_ptr = gl_buf.idx_ptr = 0;
} }
void void
R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha) 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(); 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; 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;
}

View file

@ -43,63 +43,35 @@ void R_SetCacheState(msurface_t *surf);
void R_BuildLightMap(msurface_t *surf, byte *dest, int stride); void R_BuildLightMap(msurface_t *surf, byte *dest, int stride);
static void 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 ); if (fa->texinfo->flags & SURF_FLOWING)
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)
{ {
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); R_SetBufferIndices(GL_TRIANGLE_FAN, nv);
unsigned int index_tex = 0;
v = p->verts [ 0 ]; for ( i = 0; i < nv; i++, v += VERTEXSIZE )
{
for ( i = 0; i < p->numverts; i++, v += VERTEXSIZE ) R_BufferVertex(v[0], v[1], v[2]);
{ R_BufferSingleTex(v[3] + scroll, v[4]);
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);
} }
static void static void
@ -419,47 +391,11 @@ R_RenderBrushPoly(entity_t *currententity, msurface_t *fa)
if (fa->flags & SURF_DRAWTURB) 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_EmitWaterPolys(fa);
R_TexEnv(GL_REPLACE);
return; return;
} }
R_TexEnv(GL_REPLACE); R_DrawGLPoly(fa);
if (fa->texinfo->flags & SURF_FLOWING)
{
R_DrawGLFlowingPoly(fa);
}
else
{
R_DrawGLPoly(fa->polys);
}
if (gl_config.multitexture) if (gl_config.multitexture)
{ {
@ -538,7 +474,7 @@ void
R_DrawAlphaSurfaces(void) R_DrawAlphaSurfaces(void)
{ {
msurface_t *s; msurface_t *s;
float intens; float alpha;
/* go back to the world matrix */ /* go back to the world matrix */
glLoadMatrixf(r_world_matrix); glLoadMatrixf(r_world_matrix);
@ -546,41 +482,35 @@ R_DrawAlphaSurfaces(void)
glEnable(GL_BLEND); glEnable(GL_BLEND);
R_TexEnv(GL_MODULATE); 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) for (s = r_alpha_surfaces; s; s = s->texturechain)
{ {
R_Bind(s->texinfo->image->texnum);
c_brush_polys++; c_brush_polys++;
if (s->texinfo->flags & SURF_TRANS33) if (s->texinfo->flags & SURF_TRANS33)
{ {
glColor4f(intens, intens, intens, 0.33); alpha = 0.33f;
} }
else if (s->texinfo->flags & SURF_TRANS66) else if (s->texinfo->flags & SURF_TRANS66)
{ {
glColor4f(intens, intens, intens, 0.66); alpha = 0.66f;
} }
else 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) if (s->flags & SURF_DRAWTURB)
{ {
R_EmitWaterPolys(s); R_EmitWaterPolys(s);
} }
else if (s->texinfo->flags & SURF_FLOWING)
{
R_DrawGLFlowingPoly(s);
}
else else
{ {
R_DrawGLPoly(s->polys); R_DrawGLPoly(s);
} }
} }
R_ApplyGLBuffer(); // Flush the last batched array
R_TexEnv(GL_REPLACE); R_TexEnv(GL_REPLACE);
glColor4f(1, 1, 1, 1); glColor4f(1, 1, 1, 1);
@ -842,12 +772,13 @@ R_DrawTextureChains(entity_t *currententity)
for ( ; s; s = s->texturechain) 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); R_RenderBrushPoly(currententity, s);
} }
image->texturechain = NULL; image->texturechain = NULL;
} }
R_ApplyGLBuffer(); // Flush the last batched array
} }
else // multitexture 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++) for (i = 0, image = gltextures; i < numgltextures; i++, image++)
{ {
@ -885,13 +816,14 @@ R_DrawTextureChains(entity_t *currententity)
{ {
if (s->flags & SURF_DRAWTURB) if (s->flags & SURF_DRAWTURB)
{ {
R_Bind(image->texnum); R_UpdateGLBuffer(buf_singletex, image->texnum, 0, s->flags, 1);
R_RenderBrushPoly(currententity, s); R_RenderBrushPoly(currententity, s);
} }
} }
image->texturechain = NULL; image->texturechain = NULL;
} }
R_ApplyGLBuffer();
} }
} }
@ -958,13 +890,14 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel)
} }
else else
{ {
R_EnableMultitexture(false); R_UpdateGLBuffer(buf_singletex, image->texnum, 0, psurf->flags, 1);
R_Bind(image->texnum);
R_RenderBrushPoly(currententity, psurf); R_RenderBrushPoly(currententity, psurf);
} }
} }
} }
} }
R_EnableMultitexture(false);
R_ApplyGLBuffer();
if (!(currententity->flags & RF_TRANSLUCENT)) if (!(currententity->flags & RF_TRANSLUCENT))
{ {

View file

@ -282,7 +282,7 @@ R_EmitWaterPolys(msurface_t *fa)
{ {
glpoly_t *p, *bp; glpoly_t *p, *bp;
float *v; float *v;
int i; int i, nv;
float s, t, os, ot; float s, t, os, ot;
float scroll; float scroll;
float rdt = r_newrefdef.time; float rdt = r_newrefdef.time;
@ -296,53 +296,24 @@ R_EmitWaterPolys(msurface_t *fa)
scroll = 0; 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) for (bp = fa->polys; bp; bp = bp->next)
{ {
p = bp; p = bp;
#ifndef _MSC_VER // we have real VLAs, so it's safe to use one in this loop nv = p->numverts;
YQ2_VLA(GLfloat, tex, 2*p->numverts); R_SetBufferIndices(GL_TRIANGLE_FAN, nv);
#endif
unsigned int index_tex = 0;
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 ]; os = v [ 3 ];
ot = v [ 4 ]; ot = v [ 4 ];
s = os + r_turbsin [ (int) ( ( ot * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ]; s = os + r_turbsin [ (int) ( ( ot * 0.125 + rdt ) * TURBSCALE ) & 255 ] + scroll;
s += scroll;
tex[index_tex++] = s * ( 1.0 / 64 );
t = ot + r_turbsin [ (int) ( ( os * 0.125 + rdt ) * TURBSCALE ) & 255 ]; 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 void

View file

@ -109,7 +109,9 @@ typedef enum
typedef enum typedef enum
{ {
buf_2d buf_2d,
buf_singletex,
buf_alpha
} buffered_draw_t; } buffered_draw_t;
#include "model.h" #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_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, 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); 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 #ifdef DEBUG
void glCheckError_(const char *file, const char *function, int line); void glCheckError_(const char *file, const char *function, int line);