diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 86d9ac47c3..4b6d80f2a5 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -576,6 +576,11 @@ typedef struct { #define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) #define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) #define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) + +#define Vector2Set(v, x, y) ((v)[0]=(x), (v)[1]=(y)) +#define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) + +#define Vector4Set(v, x, y, z, w) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z), (v)[3]=(w)) #define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) #define Byte4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) diff --git a/code/renderergl1/tr_backend.c b/code/renderergl1/tr_backend.c index 56cf37d12b..c7f73f8ee3 100644 --- a/code/renderergl1/tr_backend.c +++ b/code/renderergl1/tr_backend.c @@ -719,6 +719,45 @@ void RB_SetGL2D (void) { backEnd.refdef.floatTime = backEnd.refdef.time * 0.001; } +/* +================ +RB_InstantQuad2 +================ +*/ +void RB_InstantQuad2( vec4_t quadVerts[4], vec2_t texCoords[2] ) { + glIndex_t indexes[6]; + + qglDisableClientState( GL_COLOR_ARRAY ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + qglTexCoordPointer( 2, GL_FLOAT, 0, texCoords ); + qglVertexPointer( 3, GL_FLOAT, 16, quadVerts ); + + indexes[0] = 0; + indexes[1] = 1; + indexes[2] = 2; + indexes[3] = 0; + indexes[4] = 2; + indexes[5] = 3; + + R_DrawElements( 6, indexes ); +} + +/* +================ +RB_InstantQuad +===============- +*/ +void RB_InstantQuad( vec4_t quadVerts[4] ) { + vec2_t texCoords[4] = { + { 0, 0 }, + { 1, 0 }, + { 1, 1 }, + { 0, 1 } + }; + + RB_InstantQuad2( quadVerts, texCoords ); +} /* ============= @@ -732,6 +771,8 @@ Used for cinematics. void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { int i, j; int start, end; + vec4_t quadVerts[4]; + vec2_t texCoords[4]; if ( !tr.registered ) { return; @@ -771,16 +812,17 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); - qglBegin (GL_QUADS); - qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); - qglVertex2f (x, y); - qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); - qglVertex2f (x+w, y); - qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); - qglVertex2f (x+w, y+h); - qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); - qglVertex2f (x, y+h); - qglEnd (); + Vector4Set( quadVerts[0], x, y, 0.0f, 1.0f ); + Vector4Set( quadVerts[1], x + w, y, 0.0f, 1.0f ); + Vector4Set( quadVerts[2], x + w, y + h, 0.0f, 1.0f ); + Vector4Set( quadVerts[3], x, y + h, 0.0f, 1.0f ); + + Vector2Set( texCoords[0], 0.5f / cols, 0.5f / rows ); + Vector2Set( texCoords[1], (cols - 0.5f) / cols, 0.5f / rows ); + Vector2Set( texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows ); + Vector2Set( texCoords[3], 0.5f / cols, (rows - 0.5f) / rows ); + + RB_InstantQuad2( quadVerts, texCoords ); } void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { @@ -963,6 +1005,7 @@ void RB_ShowImages( void ) { image_t *image; float x, y, w, h; int start, end; + vec4_t quadVerts[4]; if ( !backEnd.projection2D ) { RB_SetGL2D(); @@ -989,16 +1032,13 @@ void RB_ShowImages( void ) { } GL_Bind( image ); - qglBegin (GL_QUADS); - qglTexCoord2f( 0, 0 ); - qglVertex2f( x, y ); - qglTexCoord2f( 1, 0 ); - qglVertex2f( x + w, y ); - qglTexCoord2f( 1, 1 ); - qglVertex2f( x + w, y + h ); - qglTexCoord2f( 0, 1 ); - qglVertex2f( x, y + h ); - qglEnd(); + + Vector4Set( quadVerts[0], x, y, 0, 1 ); + Vector4Set( quadVerts[1], x + w, y, 0, 1 ); + Vector4Set( quadVerts[2], x + w, y + h, 0, 1 ); + Vector4Set( quadVerts[3], x, y + h, 0, 1 ); + + RB_InstantQuad( quadVerts ); } qglFinish(); diff --git a/code/renderergl1/tr_local.h b/code/renderergl1/tr_local.h index e07f575bb6..8aac61fc17 100644 --- a/code/renderergl1/tr_local.h +++ b/code/renderergl1/tr_local.h @@ -1224,10 +1224,12 @@ typedef struct stageVars } stageVars_t; +// xyz index SHADER_MAX_VERTEXES-1 is used to check for overflow +// xyz index >= SHADER_MAX_VERTEXES are used for DrawNormals() and RB_ShadowTessEnd() typedef struct shaderCommands_s { glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); - vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); + vec4_t xyz[SHADER_MAX_VERTEXES*2] QALIGN(16); vec4_t normal[SHADER_MAX_VERTEXES] QALIGN(16); vec2_t texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16); color4ub_t vertexColors[SHADER_MAX_VERTEXES] QALIGN(16); @@ -1266,6 +1268,8 @@ void RB_StageIteratorLightmappedMultitexture( void ); void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ); void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ); +void RB_InstantQuad( vec4_t quadVerts[4] ); +void RB_InstantQuad2( vec4_t quadVerts[4], vec2_t texCoords[4] ); void RB_ShowImages( void ); diff --git a/code/renderergl1/tr_main.c b/code/renderergl1/tr_main.c index 09559a2e71..61e264a1f4 100644 --- a/code/renderergl1/tr_main.c +++ b/code/renderergl1/tr_main.c @@ -1299,29 +1299,36 @@ R_DebugPolygon ================ */ void R_DebugPolygon( int color, int numPoints, float *points ) { - int i; + if ( numPoints < 3 ) { + ri.Printf( PRINT_WARNING, "Debug polygon with color 0x%08X only has %d points (must have at least 3)\n", color, numPoints ); + return; + } GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); + qglDisableClientState( GL_COLOR_ARRAY ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - // draw solid shade + qglVertexPointer( 3, GL_FLOAT, 0, points ); - qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); + if (qglLockArraysEXT) { + qglLockArraysEXT(0, numPoints); + GLimp_LogComment( "glLockArraysEXT\n" ); } - qglEnd(); + + // draw solid shade + qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); + qglDrawArrays( GL_TRIANGLE_FAN, 0, numPoints ); // draw wireframe outline - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); qglDepthRange( 0, 0 ); qglColor3f( 1, 1, 1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); + qglDrawArrays( GL_LINE_LOOP, 0, numPoints ); qglDepthRange( 0, 1 ); + + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } } /* diff --git a/code/renderergl1/tr_shade.c b/code/renderergl1/tr_shade.c index 7ea78d1302..2e78320fe6 100644 --- a/code/renderergl1/tr_shade.c +++ b/code/renderergl1/tr_shade.c @@ -254,15 +254,31 @@ Draws triangle outlines for debugging ================ */ static void DrawTris (shaderCommands_t *input) { + glIndex_t lineIndexes[SHADER_MAX_INDEXES*2]; + int i, numTris; + GL_Bind( tr.whiteImage ); qglColor3f (1,1,1); - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); + GL_State( GLS_DEPTHMASK_TRUE ); qglDepthRange( 0, 0 ); qglDisableClientState (GL_COLOR_ARRAY); qglDisableClientState (GL_TEXTURE_COORD_ARRAY); + // convert triangles to lines + numTris = tess.numIndexes / 3; + for (i = 0 ; i < numTris; i++) { + lineIndexes[i*6+0] = input->indexes[i*3+0]; + lineIndexes[i*6+1] = input->indexes[i*3+1]; + + lineIndexes[i*6+2] = input->indexes[i*3+1]; + lineIndexes[i*6+3] = input->indexes[i*3+2]; + + lineIndexes[i*6+4] = input->indexes[i*3+2]; + lineIndexes[i*6+5] = input->indexes[i*3+0]; + } + qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD if (qglLockArraysEXT) { @@ -270,7 +286,7 @@ static void DrawTris (shaderCommands_t *input) { GLimp_LogComment( "glLockArraysEXT\n" ); } - R_DrawElements( input->numIndexes, input->indexes ); + qglDrawElements( GL_LINES, numTris*6, GL_INDEX_TYPE, lineIndexes ); if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); @@ -288,23 +304,41 @@ Draws vertex normals for debugging ================ */ static void DrawNormals (shaderCommands_t *input) { + glIndex_t lineIndexes[SHADER_MAX_INDEXES*2]; int i; - vec3_t temp; GL_Bind( tr.whiteImage ); qglColor3f (1,1,1); qglDepthRange( 0, 0 ); // never occluded - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); + GL_State( GLS_DEPTHMASK_TRUE ); + + qglDisableClientState (GL_COLOR_ARRAY); + qglDisableClientState (GL_TEXTURE_COORD_ARRAY); - qglBegin (GL_LINES); for (i = 0 ; i < input->numVertexes ; i++) { - qglVertex3fv (input->xyz[i]); - VectorMA (input->xyz[i], 2, input->normal[i], temp); - qglVertex3fv (temp); + VectorMA( input->xyz[i], 2, input->normal[i], input->xyz[i + input->numVertexes] ); + + lineIndexes[i*2] = i; + lineIndexes[i*2+1] = i + input->numVertexes; + } + + qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD + + if (qglLockArraysEXT) { + qglLockArraysEXT(0, input->numVertexes * 2); + GLimp_LogComment( "glLockArraysEXT\n" ); } - qglEnd (); + qglDrawElements( GL_LINES, input->numVertexes * 2, GL_INDEX_TYPE, lineIndexes ); + + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } qglDepthRange( 0, 1 ); + + // FIXME: kind of ugly to have to clear this to avoid overflow detection. + memset( input->xyz[SHADER_MAX_VERTEXES-1], 0, sizeof ( input->xyz[0] ) ); } /* diff --git a/code/renderergl1/tr_shadows.c b/code/renderergl1/tr_shadows.c index 13fbfdf74e..89426d9a1b 100644 --- a/code/renderergl1/tr_shadows.c +++ b/code/renderergl1/tr_shadows.c @@ -44,7 +44,8 @@ typedef struct { static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; static int numEdgeDefs[SHADER_MAX_VERTEXES]; static int facing[SHADER_MAX_INDEXES/3]; -static vec3_t shadowXyz[SHADER_MAX_VERTEXES]; +static glIndex_t shadowIndexes[SHADER_MAX_VERTEXES*MAX_EDGE_DEFS*6]; +static int numShadowIndexes; void R_AddEdgeDef( int i1, int i2, int facing ) { int c; @@ -59,7 +60,7 @@ void R_AddEdgeDef( int i1, int i2, int facing ) { numEdgeDefs[ i1 ]++; } -void R_RenderShadowEdges( void ) { +void R_CalculateShadowEdges( void ) { int i; #if 0 @@ -68,6 +69,8 @@ void R_RenderShadowEdges( void ) { // dumb way -- render every triangle's edges numTris = tess.numIndexes / 3; + numShadowIndexes = 0; + for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; @@ -79,15 +82,16 @@ void R_RenderShadowEdges( void ) { i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; + // FIXME: Convert to using shadowIndexes qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( shadowXyz[ i1 ] ); + qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( shadowXyz[ i2 ] ); + qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i3 ] ); - qglVertex3fv( shadowXyz[ i3 ] ); + qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( shadowXyz[ i1 ] ); + qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglEnd(); } #else @@ -97,6 +101,8 @@ void R_RenderShadowEdges( void ) { int c_edges, c_rejected; int hit[2]; + numShadowIndexes = 0; + // an edge is NOT a silhouette edge if its face doesn't face the light, // or if it has a reverse paired edge that also faces the light. // A well behaved polyhedron would have exactly two faces for each edge, @@ -123,14 +129,23 @@ void R_RenderShadowEdges( void ) { } // if it doesn't share the edge with another front facing - // triangle, it is a sil edge + // triangle, it is a silhouette edge if ( hit[ 1 ] == 0 ) { +/* qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); - qglVertex3fv( shadowXyz[ i ] ); + qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( shadowXyz[ i2 ] ); + qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); +*/ + shadowIndexes[numShadowIndexes++] = i; + shadowIndexes[numShadowIndexes++] = i + tess.numVertexes; + shadowIndexes[numShadowIndexes++] = i2; + + shadowIndexes[numShadowIndexes++] = i2; + shadowIndexes[numShadowIndexes++] = i + tess.numVertexes; + shadowIndexes[numShadowIndexes++] = i2 + tess.numVertexes; c_edges++; } else { c_rejected++; @@ -166,7 +181,7 @@ void RB_ShadowTessEnd( void ) { // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { - VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] ); + VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i + tess.numVertexes] ); } // decide which triangles face the light @@ -204,12 +219,24 @@ void RB_ShadowTessEnd( void ) { R_AddEdgeDef( i3, i1, facing[ i ] ); } + R_CalculateShadowEdges(); + // draw the silhouette edges GL_Bind( tr.whiteImage ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor3f( 0.2f, 0.2f, 0.2f ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisableClientState( GL_COLOR_ARRAY ); + + qglVertexPointer( 3, GL_FLOAT, 16, tess.xyz ); // padded for SIMD + + if (qglLockArraysEXT) { + qglLockArraysEXT(0, tess.numVertexes*2); + GLimp_LogComment( "glLockArraysEXT\n" ); + } + // don't write to the color buffer qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); @@ -220,16 +247,23 @@ void RB_ShadowTessEnd( void ) { GL_Cull( CT_BACK_SIDED ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - R_RenderShadowEdges(); + R_DrawElements( numShadowIndexes, shadowIndexes ); GL_Cull( CT_FRONT_SIDED ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - R_RenderShadowEdges(); + R_DrawElements( numShadowIndexes, shadowIndexes ); + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } // reenable writing to the color buffer qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); + + // FIXME: kind of ugly to have to clear this to avoid overflow detection. + memset( tess.xyz[SHADER_MAX_VERTEXES-1], 0, sizeof ( tess.xyz[0] ) ); } @@ -244,6 +278,8 @@ overlap and double darken. ================= */ void RB_ShadowFinish( void ) { + vec4_t quadVerts[4]; + if ( r_shadows->integer != 2 ) { return; } @@ -266,12 +302,12 @@ void RB_ShadowFinish( void ) { // qglColor3f( 1, 0, 0 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - qglBegin( GL_QUADS ); - qglVertex3f( -100, 100, -10 ); - qglVertex3f( 100, 100, -10 ); - qglVertex3f( 100, -100, -10 ); - qglVertex3f( -100, -100, -10 ); - qglEnd (); + Vector4Set( quadVerts[0], -100, 100, -10, 0 ); + Vector4Set( quadVerts[1], 100, 100, -10, 0 ); + Vector4Set( quadVerts[2], 100, -100, -10, 0 ); + Vector4Set( quadVerts[3], -100, -100, -10, 0 ); + + RB_InstantQuad( quadVerts ); qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); diff --git a/code/renderergl1/tr_sky.c b/code/renderergl1/tr_sky.c index 1d12e924ec..63e6ce61fe 100644 --- a/code/renderergl1/tr_sky.c +++ b/code/renderergl1/tr_sky.c @@ -361,27 +361,82 @@ static int sky_texorder[6] = {0,2,1,3,4,5}; static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; +// NOTE: This reuses the tess structure out of convience but it doesn't use the shader system. static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) { int s, t; + int vertexStart = tess.numVertexes; + int indexStart = tess.numIndexes; + int tHeight, sWidth; + + tHeight = maxs[1] - mins[1] + 1; + sWidth = maxs[0] - mins[0] + 1; GL_Bind( image ); - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) + for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) { - qglBegin( GL_TRIANGLE_STRIP ); - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) { - qglTexCoord2fv( s_skyTexCoords[t][s] ); - qglVertex3fv( s_skyPoints[t][s] ); + VectorCopy( s_skyPoints[t][s], tess.xyz[tess.numVertexes] ); + + tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; + tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; + + tess.numVertexes++; + + if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) + { + ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySide()" ); + } + } + } + + for ( t = 0; t < tHeight-1; t++ ) + { + for ( s = 0; s < sWidth-1; s++ ) + { + if ( tess.numIndexes + 6 >= SHADER_MAX_INDEXES ) + { + ri.Error( ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySide()" ); + } - qglTexCoord2fv( s_skyTexCoords[t+1][s] ); - qglVertex3fv( s_skyPoints[t+1][s] ); + tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); + tess.numIndexes++; + + tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); + tess.numIndexes++; } + } + + qglDisableClientState( GL_COLOR_ARRAY ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnd(); + qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); + qglVertexPointer( 3, GL_FLOAT, 16, tess.xyz ); + + if (qglLockArraysEXT) { + qglLockArraysEXT(0, tess.numIndexes); + GLimp_LogComment( "glLockArraysEXT\n" ); } + + R_DrawElements( tess.numIndexes - indexStart, tess.indexes + indexStart ); + + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } + + tess.numVertexes = vertexStart; + tess.numIndexes = indexStart; } static void DrawSkyBox( shader_t *shader ) diff --git a/code/renderergl1/tr_surface.c b/code/renderergl1/tr_surface.c index 41e72738d8..61bf9d033e 100644 --- a/code/renderergl1/tr_surface.c +++ b/code/renderergl1/tr_surface.c @@ -288,7 +288,8 @@ static void RB_SurfaceBeam( void ) int i; vec3_t perpvec; vec3_t direction, normalized_direction; - vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; + vec4_t vertexes[(NUM_BEAM_SEGS+1)*2] QALIGN(16); + float *start_point, *end_point; // pointers to vec4_t vec3_t oldorigin, origin; e = &backEnd.currentEntity->e; @@ -314,23 +315,40 @@ static void RB_SurfaceBeam( void ) for ( i = 0; i < NUM_BEAM_SEGS ; i++ ) { - RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); -// VectorAdd( start_points[i], origin, start_points[i] ); - VectorAdd( start_points[i], direction, end_points[i] ); + start_point = vertexes[i*2]; + end_point = vertexes[i*2+1]; + + RotatePointAroundVector( start_point, normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); +// VectorAdd( start_point, origin, start_point ); + VectorAdd( start_point, direction, end_point ); } + // duplicate first start/end points + VectorCopy( vertexes[0], vertexes[NUM_BEAM_SEGS*2] ); + VectorCopy( vertexes[1], vertexes[NUM_BEAM_SEGS*2+1] ); + GL_Bind( tr.whiteImage ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); qglColor3f( 1, 0, 0 ); - qglBegin( GL_TRIANGLE_STRIP ); - for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) { - qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] ); - qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisableClientState( GL_COLOR_ARRAY ); + + qglVertexPointer( 3, GL_FLOAT, 16, vertexes ); // padded for SIMD + + if (qglLockArraysEXT) { + qglLockArraysEXT(0, ARRAY_LEN(vertexes)); + GLimp_LogComment( "glLockArraysEXT\n" ); + } + + qglDrawArrays( GL_TRIANGLE_STRIP, 0, ARRAY_LEN(vertexes) ); + + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); } - qglEnd(); } //================================================================================ @@ -1026,20 +1044,35 @@ Draws x/y/z lines from the origin for orientation debugging =================== */ static void RB_SurfaceAxis( void ) { + vec4_t colors[6] = { + { 1,0,0,1 }, + { 1,0,0,1 }, + { 0,1,0,1 }, + { 0,1,0,1 }, + { 0,0,1,1 }, + { 0,0,1,1 } + }; + vec4_t vertexes[6] = { + { 0, 0, 0, 0 }, + { 16, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 16, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 16, 0 } + }; + GL_Bind( tr.whiteImage ); GL_State( GLS_DEFAULT ); qglLineWidth( 3 ); - qglBegin( GL_LINES ); - qglColor3f( 1,0,0 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 16,0,0 ); - qglColor3f( 0,1,0 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 0,16,0 ); - qglColor3f( 0,0,1 ); - qglVertex3f( 0,0,0 ); - qglVertex3f( 0,0,16 ); - qglEnd(); + + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglEnableClientState( GL_COLOR_ARRAY ); + + qglColorPointer( 4, GL_FLOAT, 0, colors ); + qglVertexPointer( 3, GL_FLOAT, 16, vertexes ); // padded for SIMD + + qglDrawArrays( GL_LINES, 0, 6 ); + qglLineWidth( 1 ); } diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c index df54528b01..9ca32633aa 100644 --- a/code/renderergl2/tr_backend.c +++ b/code/renderergl2/tr_backend.c @@ -671,8 +671,8 @@ Used for cinematics. void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { int i, j; int start, end; - vec4_t quadVerts[4]; - vec2_t texCoords[4]; + vec4_t quadVerts[4]; + vec2_t texCoords[4]; if ( !tr.registered ) { return; @@ -716,22 +716,22 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * RB_SetGL2D(); - VectorSet4(quadVerts[0], x, y, 0.0f, 1.0f); - VectorSet4(quadVerts[1], x + w, y, 0.0f, 1.0f); - VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f); - VectorSet4(quadVerts[3], x, y + h, 0.0f, 1.0f); + Vector4Set( quadVerts[0], x, y, 0.0f, 1.0f ); + Vector4Set( quadVerts[1], x + w, y, 0.0f, 1.0f ); + Vector4Set( quadVerts[2], x + w, y + h, 0.0f, 1.0f ); + Vector4Set( quadVerts[3], x, y + h, 0.0f, 1.0f ); - VectorSet2(texCoords[0], 0.5f / cols, 0.5f / rows); - VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows); - VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows); - VectorSet2(texCoords[3], 0.5f / cols, (rows - 0.5f) / rows); + Vector2Set( texCoords[0], 0.5f / cols, 0.5f / rows ); + Vector2Set( texCoords[1], (cols - 0.5f) / cols, 0.5f / rows ); + Vector2Set( texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows ); + Vector2Set( texCoords[3], 0.5f / cols, (rows - 0.5f) / rows ); GLSL_BindProgram(&tr.textureColorShader); GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); - RB_InstantQuad2(quadVerts, texCoords); + RB_InstantQuad2( quadVerts, texCoords ); } void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { @@ -1221,6 +1221,7 @@ void RB_ShowImages( void ) { image_t *image; float x, y, w, h; int start, end; + vec4_t quadVerts[4]; RB_SetGL2D(); @@ -1244,18 +1245,14 @@ void RB_ShowImages( void ) { h *= image->uploadHeight / 512.0f; } - { - vec4_t quadVerts[4]; - - GL_BindToTMU(image, TB_COLORMAP); + GL_BindToTMU( image, TB_COLORMAP ); - VectorSet4(quadVerts[0], x, y, 0, 1); - VectorSet4(quadVerts[1], x + w, y, 0, 1); - VectorSet4(quadVerts[2], x + w, y + h, 0, 1); - VectorSet4(quadVerts[3], x, y + h, 0, 1); + Vector4Set( quadVerts[0], x, y, 0, 1 ); + Vector4Set( quadVerts[1], x + w, y, 0, 1 ); + Vector4Set( quadVerts[2], x + w, y + h, 0, 1 ); + Vector4Set( quadVerts[3], x, y + h, 0, 1 ); - RB_InstantQuad(quadVerts); - } + RB_InstantQuad( quadVerts ); } qglFinish(); diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h index 39f6f7a2ba..0cf1f85ca3 100644 --- a/code/renderergl2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -2020,10 +2020,12 @@ typedef struct stageVars vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES]; } stageVars_t; +// xyz index SHADER_MAX_VERTEXES-1 is used to check for overflow +// xyz index >= SHADER_MAX_VERTEXES are used for DrawNormals() and RB_ShadowTessEnd() typedef struct shaderCommands_s { glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); - vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); + vec4_t xyz[SHADER_MAX_VERTEXES*2] QALIGN(16); int16_t normal[SHADER_MAX_VERTEXES][4] QALIGN(16); int16_t tangent[SHADER_MAX_VERTEXES][4] QALIGN(16); vec2_t texCoords[SHADER_MAX_VERTEXES] QALIGN(16); diff --git a/code/renderergl2/tr_main.c b/code/renderergl2/tr_main.c index 02f7d489fb..c0467d839c 100644 --- a/code/renderergl2/tr_main.c +++ b/code/renderergl2/tr_main.c @@ -1681,29 +1681,36 @@ R_DebugPolygon void R_DebugPolygon( int color, int numPoints, float *points ) { // FIXME: implement this #if 0 - int i; + if ( numPoints < 3 ) { + ri.Printf( PRINT_WARNING, "Debug polygon with color 0x%08X only has %d points (must have at least 3)\n", color, numPoints ); + return; + } GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); + qglDisableClientState( GL_COLOR_ARRAY ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - // draw solid shade + qglVertexPointer( 3, GL_FLOAT, 0, points ); - qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); + if (qglLockArraysEXT) { + qglLockArraysEXT(0, numPoints); + GLimp_LogComment( "glLockArraysEXT\n" ); } - qglEnd(); + + // draw solid shade + qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); + qglDrawArrays( GL_TRIANGLE_FAN, 0, numPoints ); // draw wireframe outline - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); qglDepthRange( 0, 0 ); qglColor3f( 1, 1, 1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); + qglDrawArrays( GL_LINE_LOOP, 0, numPoints ); qglDepthRange( 0, 1 ); + + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } #endif } diff --git a/code/renderergl2/tr_shadows.c b/code/renderergl2/tr_shadows.c index 697800c137..0ec0acef98 100644 --- a/code/renderergl2/tr_shadows.c +++ b/code/renderergl2/tr_shadows.c @@ -44,7 +44,8 @@ typedef struct { static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; static int numEdgeDefs[SHADER_MAX_VERTEXES]; //static int facing[SHADER_MAX_INDEXES/3]; -//static vec3_t shadowXyz[SHADER_MAX_VERTEXES]; +static glIndex_t shadowIndexes[SHADER_MAX_VERTEXES*MAX_EDGE_DEFS*6]; +static int numShadowIndexes; void R_AddEdgeDef( int i1, int i2, int facing ) { int c; @@ -59,9 +60,7 @@ void R_AddEdgeDef( int i1, int i2, int facing ) { numEdgeDefs[ i1 ]++; } -void R_RenderShadowEdges( void ) { - // FIXME: implement this -#if 0 +void R_CalculateShadowEdges( void ) { int i; #if 0 @@ -70,6 +69,8 @@ void R_RenderShadowEdges( void ) { // dumb way -- render every triangle's edges numTris = tess.numIndexes / 3; + numShadowIndexes = 0; + for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; @@ -81,15 +82,16 @@ void R_RenderShadowEdges( void ) { i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; + // FIXME: Convert to using shadowIndexes qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( shadowXyz[ i1 ] ); + qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( shadowXyz[ i2 ] ); + qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i3 ] ); - qglVertex3fv( shadowXyz[ i3 ] ); + qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( shadowXyz[ i1 ] ); + qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglEnd(); } #else @@ -99,6 +101,8 @@ void R_RenderShadowEdges( void ) { int c_edges, c_rejected; int hit[2]; + numShadowIndexes = 0; + // an edge is NOT a silhouette edge if its face doesn't face the light, // or if it has a reverse paired edge that also faces the light. // A well behaved polyhedron would have exactly two faces for each edge, @@ -125,14 +129,23 @@ void R_RenderShadowEdges( void ) { } // if it doesn't share the edge with another front facing - // triangle, it is a sil edge + // triangle, it is a silhouette edge if ( hit[ 1 ] == 0 ) { +/* qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); - qglVertex3fv( shadowXyz[ i ] ); + qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( shadowXyz[ i2 ] ); + qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); +*/ + shadowIndexes[numShadowIndexes++] = i; + shadowIndexes[numShadowIndexes++] = i + tess.numVertexes; + shadowIndexes[numShadowIndexes++] = i2; + + shadowIndexes[numShadowIndexes++] = i2; + shadowIndexes[numShadowIndexes++] = i + tess.numVertexes; + shadowIndexes[numShadowIndexes++] = i2 + tess.numVertexes; c_edges++; } else { c_rejected++; @@ -140,7 +153,6 @@ void R_RenderShadowEdges( void ) { } } #endif -#endif } /* @@ -171,7 +183,7 @@ void RB_ShadowTessEnd( void ) { // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { - VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] ); + VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i + tess.numVertexes] ); } // decide which triangles face the light @@ -209,12 +221,24 @@ void RB_ShadowTessEnd( void ) { R_AddEdgeDef( i3, i1, facing[ i ] ); } + R_CalculateShadowEdges(); + // draw the silhouette edges GL_BindToTMU( tr.whiteImage, TB_COLORMAP ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor3f( 0.2f, 0.2f, 0.2f ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisableClientState( GL_COLOR_ARRAY ); + + qglVertexPointer( 3, GL_FLOAT, 16, tess.xyz ); // padded for SIMD + + if (qglLockArraysEXT) { + qglLockArraysEXT(0, tess.numVertexes*2); + GLimp_LogComment( "glLockArraysEXT\n" ); + } + // don't write to the color buffer qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); @@ -225,16 +249,23 @@ void RB_ShadowTessEnd( void ) { GL_Cull( CT_BACK_SIDED ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - R_RenderShadowEdges(); + R_DrawElements( numShadowIndexes, shadowIndexes ); GL_Cull( CT_FRONT_SIDED ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - R_RenderShadowEdges(); + R_DrawElements( numShadowIndexes, shadowIndexes ); + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + GLimp_LogComment( "glUnlockArraysEXT\n" ); + } // reenable writing to the color buffer qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); + + // FIXME: kind of ugly to have to clear this to avoid overflow detection. + memset( tess.xyz[SHADER_MAX_VERTEXES-1], 0, sizeof ( tess.xyz[0] ) ); #endif } @@ -252,6 +283,8 @@ overlap and double darken. void RB_ShadowFinish( void ) { // FIXME: implement this #if 0 + vec4_t quadVerts[4]; + if ( r_shadows->integer != 2 ) { return; } @@ -273,12 +306,12 @@ void RB_ShadowFinish( void ) { // qglColor3f( 1, 0, 0 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - qglBegin( GL_QUADS ); - qglVertex3f( -100, 100, -10 ); - qglVertex3f( 100, 100, -10 ); - qglVertex3f( 100, -100, -10 ); - qglVertex3f( -100, -100, -10 ); - qglEnd (); + Vector4Set( quadVerts[0], -100, 100, -10, 0 ); + Vector4Set( quadVerts[1], 100, 100, -10, 0 ); + Vector4Set( quadVerts[2], 100, -100, -10, 0 ); + Vector4Set( quadVerts[3], -100, -100, -10, 0 ); + + RB_InstantQuad( quadVerts ); qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c index 94f68d26e6..c66400f0fc 100644 --- a/code/renderergl2/tr_sky.c +++ b/code/renderergl2/tr_sky.c @@ -361,57 +361,57 @@ static int sky_texorder[6] = {0,2,1,3,4,5}; static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; +// NOTE: This reuses the tess structure out of convience but it doesn't use the shader system. static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) { int s, t; int firstVertex = tess.numVertexes; //int firstIndex = tess.numIndexes; - vec4_t color; + int tHeight, sWidth; + + tHeight = maxs[1] - mins[1] + 1; + sWidth = maxs[0] - mins[0] + 1; //tess.numVertexes = 0; //tess.numIndexes = 0; tess.firstIndex = tess.numIndexes; GL_BindToTMU( image, TB_COLORMAP ); - GL_Cull( CT_TWO_SIDED ); for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) { for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) { - tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0]; - tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1]; - tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2]; - tess.xyz[tess.numVertexes][3] = 1.0; + VectorCopy( s_skyPoints[t][s], tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0]; tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1]; tess.numVertexes++; - if(tess.numVertexes >= SHADER_MAX_VERTEXES) + if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) { - ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()"); + ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySide()" ); } } } - for ( t = 0; t < maxs[1] - mins[1]; t++ ) + for ( t = 0; t < tHeight-1; t++ ) { - for ( s = 0; s < maxs[0] - mins[0]; s++ ) + for ( s = 0; s < sWidth-1; s++ ) { - if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES) + if ( tess.numIndexes + 6 >= SHADER_MAX_INDEXES ) { - ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()"); + ri.Error( ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySide()" ); } - tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; + tess.indexes[tess.numIndexes++] = s + t * sWidth + firstVertex; + tess.indexes[tess.numIndexes++] = s + (t + 1) * sWidth + firstVertex; + tess.indexes[tess.numIndexes++] = (s + 1) + t * sWidth + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; + tess.indexes[tess.numIndexes++] = (s + 1) + t * sWidth + firstVertex; + tess.indexes[tess.numIndexes++] = s + (t + 1) * sWidth + firstVertex; + tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * sWidth + firstVertex; } } @@ -420,6 +420,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max /* { shaderProgram_t *sp = &tr.textureColorShader; + vec4_t color; GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); @@ -435,7 +436,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max */ { shaderProgram_t *sp = &tr.lightallShader[0]; - vec4_t vector; + vec4_t color, vector; GLSL_BindProgram(sp);