diff --git a/engine/client/gl_studio.c b/engine/client/gl_studio.c index ed0ceff4..814a3ad0 100644 --- a/engine/client/gl_studio.c +++ b/engine/client/gl_studio.c @@ -102,13 +102,22 @@ typedef struct vec4_t lightpos[MAXSTUDIOVERTS][MAX_LOCALLIGHTS]; vec3_t lightbonepos[MAXSTUDIOBONES][MAX_LOCALLIGHTS]; float locallightR2[MAX_LOCALLIGHTS]; + + // drawelements renderer + vec3_t arrayverts[MAXSTUDIOVERTS]; + vec2_t arraycoord[MAXSTUDIOVERTS]; + unsigned short arrayelems[MAXSTUDIOVERTS*6]; + GLubyte arraycolor[MAXSTUDIOVERTS][4]; + uint numverts; + uint numelems; } studio_draw_state_t; // studio-related cvars -convar_t *r_studio_sort_textures; -convar_t *r_drawviewmodel; +static convar_t *r_studio_sort_textures; +static convar_t *r_drawviewmodel; convar_t *cl_righthand = NULL; -convar_t *cl_himodels; +static convar_t *cl_himodels; +static convar_t *r_studio_drawelements; static r_studio_interface_t *pStudioDraw; static studio_draw_state_t g_studio; // global studio state @@ -135,6 +144,7 @@ void R_StudioInit( void ) cl_himodels = Cvar_Get( "cl_himodels", "1", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" ); r_studio_sort_textures = Cvar_Get( "r_studio_sort_textures", "0", FCVAR_ARCHIVE, "change draw order for additive meshes" ); r_drawviewmodel = Cvar_Get( "r_drawviewmodel", "1", 0, "draw firstperson weapon model" ); + r_studio_drawelements = Cvar_Get( "r_studio_drawelements", "1", FCVAR_ARCHIVE, "use glDrawElements for studiomodels" ); Matrix3x4_LoadIdentity( g_studio.rotationmatrix ); Cvar_RegisterVariable( &r_glowshellfreq ); @@ -1723,7 +1733,7 @@ R_LightLambert ==================== */ -void R_LightLambert( vec4_t light[MAX_LOCALLIGHTS], vec3_t normal, vec3_t color ) +void R_LightLambert( vec4_t light[MAX_LOCALLIGHTS], vec3_t normal, vec3_t color, byte *out ) { vec3_t finalLight; vec3_t localLight; @@ -1761,7 +1771,53 @@ void R_LightLambert( vec4_t light[MAX_LOCALLIGHTS], vec3_t normal, vec3_t color } } - pglColor4f( finalLight[0], finalLight[1], finalLight[2], tr.blend ); + out[0] = finalLight[0] * 255; + out[1] = finalLight[1] * 255; + out[2] = finalLight[2] * 255; +} + +static void R_StudioSetColorBegin(short *ptricmds, vec3_t *pstudionorms ) +{ + float *lv = (float *)g_studio.lightvalues[ptricmds[1]]; + rgba_t color; + + if( g_studio.numlocallights ) + { + color[3] = tr.blend * 255; + R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv, color ); + pglColor4ubv( color ); + } + else + { + if( RI.currententity->curstate.rendermode == kRenderTransColor ) + { + color[3] = tr.blend * 255; + VectorCopy( (byte*)&RI.currententity->curstate.rendercolor, color ); + pglColor4ubv( color ); + } + else pglColor4f( lv[0], lv[1], lv[2], tr.blend ); + } +} + +static void R_StudioSetColorArray(short *ptricmds, vec3_t *pstudionorms, byte *color ) +{ + float *lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + color[3] = tr.blend * 255; + + if( g_studio.numlocallights ) + R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv, color ); + else + { + if( RI.currententity->curstate.rendermode == kRenderTransColor ) + VectorCopy( (byte*)&RI.currententity->curstate.rendercolor, color ); + else + { + color[0] = lv[0] * 255; + color[1] = lv[1] * 255; + color[2] = lv[2] * 255; + } + } } /* @@ -1934,11 +1990,8 @@ _inline void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, floa for( ; i > 0; i--, ptricmds += 4 ) { - lv = (float *)g_studio.lightvalues[ptricmds[1]]; + R_StudioSetColorBegin( ptricmds, pstudionorms ); - if( g_studio.numlocallights ) - R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv ); - else pglColor4f( lv[0], lv[1], lv[2], tr.blend ); pglTexCoord2f( ptricmds[2] * s, ptricmds[3] * t ); pglVertex3fv( g_studio.verts[ptricmds[0]] ); } @@ -1970,10 +2023,7 @@ _inline void R_StudioDrawFloatMesh( short *ptricmds, vec3_t *pstudionorms ) for( ; i > 0; i--, ptricmds += 4 ) { - lv = (float *)g_studio.lightvalues[ptricmds[1]]; - if( g_studio.numlocallights ) - R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv ); - else pglColor4f( lv[0], lv[1], lv[2], tr.blend ); + R_StudioSetColorBegin( ptricmds, pstudionorms ); pglTexCoord2f( HalfToFloat( ptricmds[2] ), HalfToFloat( ptricmds[3] )); pglVertex3fv( g_studio.verts[ptricmds[0]] ); } @@ -2009,10 +2059,13 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa { if( glowShell ) { + color24 *clr = &RI.currententity->curstate.rendercolor; + idx = g_studio.normaltable[ptricmds[0]]; av = g_studio.verts[ptricmds[0]]; lv = g_studio.norms[ptricmds[0]]; VectorMA( av, scale, lv, vert ); + pglColor4ub( clr->r, clr->g, clr->b, 255 ); pglTexCoord2f( g_studio.chrome[idx][0] * s, g_studio.chrome[idx][1] * t ); pglVertex3fv( vert ); } @@ -2020,9 +2073,7 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa { idx = ptricmds[1]; lv = (float *)g_studio.lightvalues[ptricmds[1]]; - if( g_studio.numlocallights ) - R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv ); - else pglColor4f( lv[0], lv[1], lv[2], tr.blend ); + R_StudioSetColorBegin( ptricmds, pstudionorms ); pglTexCoord2f( g_studio.chrome[idx][0] * s, g_studio.chrome[idx][1] * t ); pglVertex3fv( g_studio.verts[ptricmds[0]] ); } @@ -2032,6 +2083,220 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa } } + +_inline int R_StudioBuildIndices( qboolean tri_strip, int vertexState ) +{ + // build in indices + if( vertexState++ < 3 ) + { + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + else if( tri_strip ) + { + // flip triangles between clockwise and counter clockwise + if( vertexState & 1 ) + { + // draw triangle [n-2 n-1 n] + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 2; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + else + { + // draw triangle [n-1 n-2 n] + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 2; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + } + else + { + // draw triangle fan [0 n-1 n] + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - ( vertexState - 1 ); + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1; + g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts; + } + + return vertexState; +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioBuildArrayNormalMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t ) +{ + float *lv; + int i; + float alpha = tr.blend; + + while( i = *( ptricmds++ )) + { + int vertexState = 0; + qboolean tri_strip = true; + + if( i < 0 ) + { + tri_strip = false; + i = -i; + } + + for( ; i > 0; i--, ptricmds += 4 ) + { + GLubyte *cl; + cl = g_studio.arraycolor[g_studio.numverts]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + g_studio.arraycoord[g_studio.numverts][0] = ptricmds[2] * s; + g_studio.arraycoord[g_studio.numverts][1] = ptricmds[3] * t; + + VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] ); + g_studio.numverts++; + } + } +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioBuildArrayFloatMesh( short *ptricmds, vec3_t *pstudionorms ) +{ + float *lv; + int i; + float alpha = tr.blend; + + while( i = *( ptricmds++ )) + { + int vertexState = 0; + qboolean tri_strip = true; + + if( i < 0 ) + { + tri_strip = false; + i = -i; + } + + for( ; i > 0; i--, ptricmds += 4 ) + { + GLubyte *cl; + cl = g_studio.arraycolor[g_studio.numverts]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + g_studio.arraycoord[g_studio.numverts][0] = HalfToFloat( ptricmds[2] ); + g_studio.arraycoord[g_studio.numverts][1] = HalfToFloat( ptricmds[3] ); + + VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] ); + g_studio.numverts++; + } + } +} + +/* +=============== +R_StudioDrawNormalMesh + +generic path +=============== +*/ +_inline void R_StudioBuildArrayChromeMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t, float scale ) +{ + float *lv, *av; + int i, idx; + qboolean glowShell = (scale > 0.0f) ? true : false; + vec3_t vert; + float alpha = tr.blend; + + while( i = *( ptricmds++ )) + { + int vertexState = 0; + qboolean tri_strip = true; + + if( i < 0 ) + { + tri_strip = false; + i = -i; + } + + for( ; i > 0; i--, ptricmds += 4 ) + { + GLubyte *cl; + cl = g_studio.arraycolor[g_studio.numverts]; + lv = (float *)g_studio.lightvalues[ptricmds[1]]; + + vertexState = R_StudioBuildIndices( tri_strip, vertexState ); + + if( glowShell ) + { + idx = g_studio.normaltable[ptricmds[0]]; + av = g_studio.verts[ptricmds[0]]; + lv = g_studio.norms[ptricmds[0]]; + + cl[0] = RI.currententity->curstate.rendercolor.r; + cl[1] = RI.currententity->curstate.rendercolor.g; + cl[2] = RI.currententity->curstate.rendercolor.b; + cl[3] = 255; + + VectorMA( av, scale, lv, vert ); + VectorCopy( vert, g_studio.arrayverts[g_studio.numverts] ); + } + else + { + idx = ptricmds[1]; + R_StudioSetColorArray( ptricmds, pstudionorms, cl ); + + VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] ); + } + + g_studio.arraycoord[g_studio.numverts][0] = g_studio.chrome[idx][0] * s; + g_studio.arraycoord[g_studio.numverts][1] = g_studio.chrome[idx][1] * t; + + g_studio.numverts++; + } + } +} + +_inline void R_StudioDrawArrays( uint startverts, uint startelems ) +{ + pglEnableClientState( GL_VERTEX_ARRAY ); + pglVertexPointer( 3, GL_FLOAT, 12, g_studio.arrayverts ); + + pglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + pglTexCoordPointer( 2, GL_FLOAT, 0, g_studio.arraycoord ); + + if( !( g_nForceFaceFlags & STUDIO_NF_CHROME ) ) + { + pglEnableClientState( GL_COLOR_ARRAY ); + pglColorPointer( 4, GL_UNSIGNED_BYTE, 0, g_studio.arraycolor ); + } + +#if !defined XASH_NANOGL || defined XASH_WES && defined __EMSCRIPTEN__ // WebGL need to know array sizes + if( pglDrawRangeElements ) + pglDrawRangeElements( GL_TRIANGLES, startverts, g_studio.numverts, + g_studio.numelems - startelems, GL_UNSIGNED_SHORT, &g_studio.arrayelems[startelems] ); + else +#endif + pglDrawElements( GL_TRIANGLES, g_studio.numelems - startelems, GL_UNSIGNED_SHORT, &g_studio.arrayelems[startelems] ); + pglDisableClientState( GL_VERTEX_ARRAY ); + pglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + if( !( g_nForceFaceFlags & STUDIO_NF_CHROME ) ) + pglDisableClientState( GL_COLOR_ARRAY ); +} + /* =============== R_StudioDrawPoints @@ -2054,6 +2319,9 @@ static void R_StudioDrawPoints( void ) if( !m_pStudioHeader ) return; + + g_studio.numverts = g_studio.numelems = 0; + // safety bounding the skinnum m_skinnum = bound( 0, RI.currententity->curstate.skin, ( m_pStudioHeader->numskinfamilies - 1 )); ptexture = (mstudiotexture_t *)((byte *)m_pStudioHeader + m_pStudioHeader->textureindex); @@ -2151,6 +2419,8 @@ static void R_StudioDrawPoints( void ) for( j = 0; j < m_pSubModel->nummesh; j++ ) { float oldblend = tr.blend; + uint startArrayVerts = g_studio.numverts; + uint startArrayElems = g_studio.numelems; short *ptricmds; float s, t; @@ -2184,11 +2454,24 @@ static void R_StudioDrawPoints( void ) R_StudioSetupSkin( m_pStudioHeader, pskinref[pmesh->skinref] ); - if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) - R_StudioDrawChromeMesh( ptricmds, pstudionorms, s, t, shellscale ); - else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS )) - R_StudioDrawFloatMesh( ptricmds, pstudionorms ); - else R_StudioDrawNormalMesh( ptricmds, pstudionorms, s, t ); + if( CVAR_TO_BOOL(r_studio_drawelements) ) + { + if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) + R_StudioBuildArrayChromeMesh( ptricmds, pstudionorms, s, t, shellscale ); + else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS )) + R_StudioBuildArrayFloatMesh( ptricmds, pstudionorms ); + else R_StudioBuildArrayNormalMesh( ptricmds, pstudionorms, s, t ); + + R_StudioDrawArrays( startArrayVerts, startArrayElems ); + } + else + { + if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME )) + R_StudioDrawChromeMesh( ptricmds, pstudionorms, s, t, shellscale ); + else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS )) + R_StudioDrawFloatMesh( ptricmds, pstudionorms ); + else R_StudioDrawNormalMesh( ptricmds, pstudionorms, s, t ); + } if( FBitSet( g_nFaceFlags, STUDIO_NF_MASKED )) {