/* ================ RB_DrawElementsWithCounters ================ */ void RB_DrawElementsWithCounters( const srfTriangles_t *tri ) { backEnd.pc.c_drawElements++; backEnd.pc.c_drawIndexes += tri->numIndexes; backEnd.pc.c_drawVertexes += tri->numVerts; if ( tri->ambientSurface != NULL ) { if ( tri->indexes == tri->ambientSurface->indexes ) { backEnd.pc.c_drawRefIndexes += tri->numIndexes; } if ( tri->verts == tri->ambientSurface->verts ) { backEnd.pc.c_drawRefVertexes += tri->numVerts; } } if ( tri->indexCache && r_useIndexBuffers.GetBool() ) { qglDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : tri->numIndexes, GL_INDEX_TYPE, (int *)vertexCache.Position( tri->indexCache ) ); backEnd.pc.c_vboIndexes += tri->numIndexes; } else { if ( r_useIndexBuffers.GetBool() ) { vertexCache.UnbindIndex(); } qglDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : tri->numIndexes, GL_INDEX_TYPE, tri->indexes ); } }
/* ================== R_DrawElements Optionally performs our own glDrawElements that looks for strip conditions instead of using the single glDrawElements call that may be inefficient without compiled vertex arrays. ================== */ static void R_DrawElements(int numIndexes, const glIndex_t *indexes) { switch (r_primitives->integer) { case 0: // default is to use triangles if compiled vertex arrays are present if (qglLockArraysEXT) { qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes); } else { R_DrawStripElements(numIndexes, indexes, R_ArrayElement); } return; case 1: R_DrawStripElements(numIndexes, indexes, R_ArrayElement); return; case 2: qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes); return; case 3: R_DrawStripElements(numIndexes, indexes, R_ArrayElementDiscrete); return; default: // anything else will cause no drawing return; } }
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) { int s, t, i = 0; int size; glIndex_t *indicies; size = (maxs[1] - mins[1]) * (maxs[0] - mins[0] + 1); indicies = ri.Hunk_AllocateTempMemory(sizeof(glIndex_t) * size); GL_Bind( image ); 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++ ) { indicies[i++] = t * (SKY_SUBDIVISIONS + 1) + s; indicies[i++] = (t + 1) * (SKY_SUBDIVISIONS + 1) + s; } } qglDisableClientState(GL_COLOR_ARRAY); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 0, s_skyTexCoords); qglVertexPointer(3, GL_FLOAT, 0, s_skyPoints); qglDrawElements(GL_TRIANGLE_STRIP, i, GL_INDEX_TYPE, indicies); Hunk_FreeTempMemory(indicies); }
static void R_DrawMultiElementsVBO( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex, GLsizei *multiDrawNumIndexes, glIndex_t **multiDrawFirstIndex) { if (glRefConfig.multiDrawArrays) { qglMultiDrawElementsEXT(GL_TRIANGLES, multiDrawNumIndexes, GL_INDEX_TYPE, (const GLvoid **)multiDrawFirstIndex, multiDrawPrimitives); } else { int i; if (glRefConfig.drawRangeElements) { for (i = 0; i < multiDrawPrimitives; i++) { qglDrawRangeElementsEXT(GL_TRIANGLES, multiDrawMinIndex[i], multiDrawMaxIndex[i], multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); } } else { for (i = 0; i < multiDrawPrimitives; i++) { qglDrawElements(GL_TRIANGLES, multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); } } } }
/* ================== R_DrawElements Optionally performs our own glDrawElements that looks for strip conditions instead of using the single glDrawElements call that may be inefficient without compiled vertex arrays. ================== */ static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) { int primitives; primitives = r_primitives->integer; // default is to use triangles if compiled vertex arrays are present if ( primitives == 0 ) { if ( qglLockArraysEXT ) { primitives = 2; } else { primitives = 1; } } if ( primitives == 2 ) { qglDrawElements( GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes ); return; } if ( primitives == 1 ) { R_DrawStripElements( numIndexes, indexes, qglArrayElement ); return; } if ( primitives == 3 ) { R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); return; } // anything else will cause no drawing }
/* ============= R_DrawShadowVolume ============= */ void R_DrawShadowVolume (void) { if (gl_config.drawRangeElements) qglDrawRangeElementsEXT(GL_TRIANGLES, 0, shadow_va, shadow_index, GL_UNSIGNED_INT, indexArray); else qglDrawElements(GL_TRIANGLES, shadow_index, GL_UNSIGNED_INT, indexArray); }
/* ================ DrawTris Draws triangle outlines for debugging ================ */ static void DrawTris (shaderCommands_t *input) { GL_Bind( tr.whiteImage ); qglColor3f (1,1,1); GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); qglDepthRange( 0, 0 ); qglDisableClientState (GL_COLOR_ARRAY); qglDisableClientState (GL_TEXTURE_COORD_ARRAY); qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD if (qglLockArraysEXT) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } #ifdef HAVE_GLES qglDrawElements( GL_LINE_STRIP, input->numIndexes, GL_INDEX_TYPE, input->indexes ); #else R_DrawElements( input->numIndexes, input->indexes ); #endif if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } qglDepthRange( 0, 1 ); }
static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) { #ifdef GL_VERSION_ES_CM_1_0 int i; //Com_Printf("R_DrawElements(): r_primitives %d numIndexes %d\n", r_primitives->integer, numIndexes); if ( r_primitives->integer != 2 && r_primitives->integer != 0 ) { Com_Printf("Error: R_DrawElements() not implemented on GLES for r_primitives != 2 (r_primitives %d)\n", r_primitives->integer); return; } // GLES does not support GL_UNSIGNED_INT for glDrawElements, so we'll convert values on the fly - this is SLOW, as you may imagine. for (i = 0; i < numIndexes; i++) indexes_short[i] = indexes[i]; qglDrawElements(GL_TRIANGLES, numIndexes, GL_UNSIGNED_SHORT, indexes_short); #else int primitives; primitives = r_primitives->integer; // default is to use triangles if compiled vertex arrays are present if ( primitives == 0 ) { if ( qglLockArraysEXT ) { primitives = 2; } else { primitives = 1; } } if ( primitives == 2 ) { qglDrawElements( GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes ); return; } if ( primitives == 1 ) { R_DrawStripElements( numIndexes, indexes, qglArrayElement ); return; } if ( primitives == 3 ) { R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); return; } #endif // anything else will cause no drawing }
void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) { if (glRefConfig.drawRangeElements) qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(GL_INDEX_TYPE))); else qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(GL_INDEX_TYPE))); }
/* ================ RB_DrawShadowElementsWithCounters May not use all the indexes in the surface if caps are skipped ================ */ void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexes ) { backEnd.pc.c_shadowElements++; backEnd.pc.c_shadowIndexes += numIndexes; backEnd.pc.c_shadowVertexes += tri->numVerts; if ( tri->indexCache && r_useIndexBuffers.GetBool() ) { qglDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : numIndexes, GL_INDEX_TYPE, (int *)vertexCache.Position( tri->indexCache ) ); backEnd.pc.c_vboIndexes += numIndexes; } else { if ( r_useIndexBuffers.GetBool() ) { vertexCache.UnbindIndex(); } qglDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : numIndexes, GL_INDEX_TYPE, tri->indexes ); } }
/* ================= RB_DrawArrays ================= */ void RB_DrawArrays (void) { if (rb_vertex == 0 || rb_index == 0) // nothing to render return; GL_LockArrays (rb_vertex); if (glConfig.drawRangeElements) qglDrawRangeElementsEXT(GL_TRIANGLES, 0, rb_vertex, rb_index, GL_UNSIGNED_INT, indexArray); else qglDrawElements(GL_TRIANGLES, rb_index, GL_UNSIGNED_INT, indexArray); GL_UnlockArrays (); }
/* ================= RB_DrawArrays ================= */ void RB_DrawArrays (GLenum polyMode) { if (rb_vertex == 0 || rb_index == 0) // nothing to render return; GL_LockArrays (rb_vertex); if (gl_config.drawRangeElements) qglDrawRangeElementsEXT(polyMode, 0, rb_vertex, rb_index, GL_UNSIGNED_INT, indexArray); else qglDrawElements(polyMode, rb_index, GL_UNSIGNED_INT, indexArray); GL_UnlockArrays (); }
void CMistyFog2::Render(CWorldEffectsSystem *system) { if (mFadeAlpha <= 0.0) { return; } qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity (); MYgluPerspective (80.0, 1.0, 4, 2048.0); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglLoadIdentity (); qglRotatef (-90, 1, 0, 0); // put Z going up qglRotatef (90, 0, 0, 1); // put Z going up qglRotatef (0, 1, 0, 0); qglRotatef (-90, 0, 1, 0); qglRotatef (-90, 0, 0, 1); qglDisable(GL_TEXTURE_2D); GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_ONE); qglShadeModel (GL_SMOOTH); qglColorPointer(4, GL_FLOAT, 0, mColors); qglEnableClientState(GL_COLOR_ARRAY); qglVertexPointer( 3, GL_FLOAT, 0, mVerts ); qglEnableClientState(GL_VERTEX_ARRAY); if (qglLockArraysEXT) { qglLockArraysEXT(0, MISTYFOG_HEIGHT*MISTYFOG_WIDTH); } qglDrawElements(GL_QUADS, (MISTYFOG_HEIGHT-1)*(MISTYFOG_WIDTH-1)*4, GL_UNSIGNED_INT, mIndexes); if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); } qglDisableClientState(GL_COLOR_ARRAY); // qglDisableClientState(GL_VERTEX_ARRAY); backend doesn't ever re=enable this properly qglPopMatrix(); qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); // bug somewhere in the backend which requires this }
/* ================= RB_ShadowFinish Darken everything that is is a shadow volume. We have to delay this until everything has been shadowed, because otherwise shadows from different body parts would overlap and double darken. ================= */ void RB_ShadowFinish( void ) { vec3_t quad[4] = { {-100.0f, 100.0f, -10.0f}, { 100.0f, 100.0f, -10.0f}, { 100.0f, -100.0f, -10.0f}, {-100.0f, -100.0f, -10.0f} }; glIndex_t indicies[6] = { 0, 1, 2, 0, 3, 2 }; if ( r_shadows->integer != 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_NOTEQUAL, 0, 255 ); qglDisable (GL_CLIP_PLANE0); qglDisable (GL_CULL_FACE); GL_Bind( tr.whiteImage ); qglLoadIdentity (); glColor4f( 0.6f, 0.6f, 0.6f, 1.0f ); GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); // glColor4f( 1, 0, 0, 1 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglVertexPointer(3, GL_FLOAT, 0, quad); qglDrawElements(GL_TRIANGLE_STRIP, 6, GL_INDEX_TYPE, indicies); glColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); }
/* =============== RB_ShowImages Draw all the images to the screen, on top of whatever was there. This is used to test for texture thrashing. Also called by RE_EndRegistration =============== */ void RB_ShowImages( void ) { int i; image_t *image; float x, y, w, h; int start, end; #ifdef VCMODS_OPENGLES vec2_t texcoords[4] = { {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} }; vec2_t verts[4]; glIndex_t indicies[6] = { 0, 1, 2, 0, 3, 2}; #endif if ( !backEnd.projection2D ) { RB_SetGL2D(); } qglClear( GL_COLOR_BUFFER_BIT ); qglFinish(); start = ri.Milliseconds(); #ifdef VCMODS_OPENGLES qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); #endif for ( i=0 ; i<tr.numImages ; i++ ) { image = tr.images[i]; w = glConfig.vidWidth / 20; h = glConfig.vidHeight / 15; x = i % 20 * w; y = i / 20 * h; // show in proportional size in mode 2 if ( r_showImages->integer == 2 ) { w *= image->uploadWidth / 512.0f; h *= image->uploadHeight / 512.0f; } #ifdef VCMODS_OPENGLES verts[0][0] = x; verts[0][1] = y; verts[1][0] = x+w; verts[1][1] = y; verts[2][0] = x+w; verts[2][1] = y+h; verts[3][0] = x; verts[3][1] = y+h; qglTexCoordPointer( 2, GL_FLOAT, 0, texcoords ); qglVertexPointer ( 2, GL_FLOAT, 0, verts ); qglDrawElements( GL_TRIANGLE_STRIP, 6, GL_INDEX_TYPE, indicies ); #else 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(); #endif } #ifdef VCMODS_OPENGLES qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #endif qglFinish(); end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); }
void R_RenderShadowEdges( void ) { int i; int c; int j; int i2; #if 0 int c_edges, c_rejected; int c2, k; int hit[2]; #endif #ifdef _STENCIL_REVERSE int numTris; int o1, o2, o3; #endif // 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, // but lots of models have dangling edges or overfanned edges #if 0 c_edges = 0; c_rejected = 0; #endif #ifdef HAVE_GLES idx = 0; #endif for ( i = 0 ; i < tess.numVertexes ; i++ ) { c = numEdgeDefs[ i ]; for ( j = 0 ; j < c ; j++ ) { if ( !edgeDefs[ i ][ j ].facing ) { continue; } //with this system we can still get edges shared by more than 2 tris which //produces artifacts including seeing the shadow through walls. So for now //we are going to render all edges even though it is a tiny bit slower. -rww #if 1 i2 = edgeDefs[ i ][ j ].i2; #ifdef HAVE_GLES // A single drawing call is better than many. So I prefer a singe TRIANGLES call than many TRIANGLE_STRIP call // even if it seems less efficiant, it's faster on the PANDORA indexes[idx++] = i; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2; indexes[idx++] = i2; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2 + tess.numVertexes; #else qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); #endif #else hit[0] = 0; hit[1] = 0; i2 = edgeDefs[ i ][ j ].i2; c2 = numEdgeDefs[ i2 ]; for ( k = 0 ; k < c2 ; k++ ) { if ( edgeDefs[ i2 ][ k ].i2 == i ) { hit[ edgeDefs[ i2 ][ k ].facing ]++; } } // if it doesn't share the edge with another front facing // triangle, it is a sil edge if (hit[1] != 1) { qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); c_edges++; } else { c_rejected++; } #endif } } #ifdef _STENCIL_REVERSE //Carmack Reverse<tm> method requires that volumes //be capped properly -rww numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { if ( !facing[i] ) { continue; } o1 = tess.indexes[ i*3 + 0 ]; o2 = tess.indexes[ i*3 + 1 ]; o3 = tess.indexes[ i*3 + 2 ]; #ifdef HAVE_GLES indexes[idx++]=o1; indexes[idx++]=o2; indexes[idx++]=o3; indexes[idx++]=o3 + tess.numVertexes; indexes[idx++]=o2 + tess.numVertexes; indexes[idx++]=o1 + tess.numVertexes; #else qglBegin(GL_TRIANGLES); qglVertex3fv(tess.xyz[o1]); qglVertex3fv(tess.xyz[o2]); qglVertex3fv(tess.xyz[o3]); qglEnd(); qglBegin(GL_TRIANGLES); qglVertex3fv(tess.xyz[o3 + tess.numVertexes]); qglVertex3fv(tess.xyz[o2 + tess.numVertexes]); qglVertex3fv(tess.xyz[o1 + tess.numVertexes]); qglEnd(); #endif } #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #endif #endif }
void R_RenderShadowEdges( void ) { int i; #if 0 int numTris; // dumb way -- render every triangle's edges numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; if ( !facing[i] ) { continue; } i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i3 ] ); qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglEnd(); } #else int c, c2; int j, k; int i2; int c_edges, c_rejected; int hit[2]; // 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, // but lots of models have dangling edges or overfanned edges c_edges = 0; c_rejected = 0; unsigned short indicies[4]; for ( i = 0 ; i < tess.numVertexes ; i++ ) { c = numEdgeDefs[ i ]; for ( j = 0 ; j < c ; j++ ) { if ( !edgeDefs[ i ][ j ].facing ) { continue; } hit[0] = 0; hit[1] = 0; i2 = edgeDefs[ i ][ j ].i2; c2 = numEdgeDefs[ i2 ]; for ( k = 0 ; k < c2 ; k++ ) { if ( edgeDefs[ i2 ][ k ].i2 == i ) { hit[ edgeDefs[ i2 ][ k ].facing ]++; } } // if it doesn't share the edge with another front facing // triangle, it is a sil edge if ( hit[ 1 ] == 0 ) { indicies[0] = i; indicies[1] = i + tess.numVertexes; indicies[2] = i2; indicies[3] = i2 + tess.numVertexes; qglVertexPointer(3, GL_FLOAT, 16, tess.xyz); qglDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indicies); c_edges++; } else { c_rejected++; } } } #endif }
/* * RB_DrawElementsReal */ void RB_DrawElementsReal( rbDrawElements_t *de ) { int firstVert, numVerts, firstElem, numElems; int numInstances; if( ! ( r_drawelements->integer || rb.currentEntity == &rb.nullEnt ) || !de ) return; RB_ApplyScissor(); numVerts = de->numVerts; numElems = de->numElems; firstVert = de->firstVert; firstElem = de->firstElem; numInstances = de->numInstances; if( numInstances ) { if( glConfig.ext.instanced_arrays ) { // the instance data is contained in vertex attributes qglDrawElementsInstancedARB( rb.primitive, numElems, GL_UNSIGNED_SHORT, (GLvoid *)(firstElem * sizeof( elem_t )), numInstances ); rb.stats.c_totalDraws++; } else if( glConfig.ext.draw_instanced ) { int i, numUInstances = 0; // manually update uniform values for instances for currently bound program, // respecting the MAX_GLSL_UNIFORM_INSTANCES limit for( i = 0; i < numInstances; i += numUInstances ) { numUInstances = min( numInstances - i, MAX_GLSL_UNIFORM_INSTANCES ); RB_SetInstanceData( numUInstances, rb.drawInstances + i ); qglDrawElementsInstancedARB( rb.primitive, numElems, GL_UNSIGNED_SHORT, (GLvoid *)(firstElem * sizeof( elem_t )), numUInstances ); rb.stats.c_totalDraws++; } } else { int i; // manually update uniform values for instances for currently bound program, // one by one for( i = 0; i < numInstances; i++ ) { RB_SetInstanceData( 1, rb.drawInstances + i ); if( glConfig.ext.draw_range_elements ) { qglDrawRangeElementsEXT( rb.primitive, firstVert, firstVert + numVerts - 1, numElems, GL_UNSIGNED_SHORT, (GLvoid *)(firstElem * sizeof( elem_t )) ); } else { qglDrawElements( rb.primitive, numElems, GL_UNSIGNED_SHORT, (GLvoid *)(firstElem * sizeof( elem_t )) ); } rb.stats.c_totalDraws++; } } } else { numInstances = 1; if( glConfig.ext.draw_range_elements ) { qglDrawRangeElementsEXT( rb.primitive, firstVert, firstVert + numVerts - 1, numElems, GL_UNSIGNED_SHORT, (GLvoid *)(firstElem * sizeof( elem_t )) ); } else { qglDrawElements( rb.primitive, numElems, GL_UNSIGNED_SHORT, (GLvoid *)(firstElem * sizeof( elem_t )) ); } rb.stats.c_totalDraws++; } rb.stats.c_totalVerts += numVerts * numInstances; if( rb.primitive == GL_TRIANGLES ) { rb.stats.c_totalTris += numElems * numInstances / 3; } }
void RB_DoShadowTessEnd( vec3_t lightPos ) { int i; int numTris; vec3_t lightDir; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #if 1 //controlled method - try to keep shadows in range so they don't show through so much -rww vec3_t worldxyz; vec3_t entLight; float groundDist; VectorCopy( backEnd.currentEntity->lightDir, entLight ); entLight[2] = 0.0f; VectorNormalize(entLight); //Oh well, just cast them straight down no matter what onto the ground plane. //This presets no chance of screwups and still looks better than a stupid //shader blob. VectorSet(lightDir, entLight[0]*0.3f, entLight[1]*0.3f, 1.0f); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { //add or.origin to vert xyz to end up with world oriented coord, then figure //out the ground pos for the vert to project the shadow volume to VectorAdd(tess.xyz[i], backEnd.ori.origin, worldxyz); groundDist = worldxyz[2] - backEnd.currentEntity->e.shadowPlane; groundDist += 16.0f; //fudge factor VectorMA( tess.xyz[i], -groundDist, lightDir, tess.xyz[i+tess.numVertexes] ); } #else if (lightPos) { for ( i = 0 ; i < tess.numVertexes ; i++ ) { tess.xyz[i+tess.numVertexes][0] = tess.xyz[i][0]+(( tess.xyz[i][0]-lightPos[0] )*128.0f); tess.xyz[i+tess.numVertexes][1] = tess.xyz[i][1]+(( tess.xyz[i][1]-lightPos[1] )*128.0f); tess.xyz[i+tess.numVertexes][2] = tess.xyz[i][2]+(( tess.xyz[i][2]-lightPos[2] )*128.0f); } } else { VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } } #endif // decide which triangles face the light memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; if (!lightPos) { VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); } else { float planeEq[4]; planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]); planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]); planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]); planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) + v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) + v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) ); d = planeEq[0]*lightPos[0]+ planeEq[1]*lightPos[1]+ planeEq[2]*lightPos[2]+ planeEq[3]; } if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } GL_Bind( tr.whiteImage ); //qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); #ifndef _DEBUG_STENCIL_SHADOWS qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); #else qglColor3f( 1.0f, 0.0f, 0.0f ); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //qglDisable(GL_DEPTH_TEST); #endif #ifdef HAVE_GLES GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglDisableClientState( GL_COLOR_ARRAY ); qglVertexPointer (3, GL_FLOAT, 16, tess.xyz); #endif #ifdef _STENCIL_REVERSE qglDepthFunc(GL_LESS); //now using the Carmack Reverse<tm> -rww if ( backEnd.viewParms.isMirror ) { //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } else { //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } qglDepthFunc(GL_LEQUAL); #else // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } #endif // reenable writing to the color buffer qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); #ifdef HAVE_GLES if (text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState( GL_COLOR_ARRAY ); #endif #ifdef _DEBUG_STENCIL_SHADOWS qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif }
void R_RenderShadowEdges( void ) { int i; #if 0 int numTris; // dumb way -- render every triangle's edges numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; if ( !facing[i] ) { continue; } i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i3 ] ); qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglEnd(); } #else int c, c2; int j, k; int i2; int c_edges, c_rejected; int hit[2]; #ifdef HAVE_GLES idx = 0; #endif // 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, // but lots of models have dangling edges or overfanned edges c_edges = 0; c_rejected = 0; for ( i = 0 ; i < tess.numVertexes ; i++ ) { c = numEdgeDefs[ i ]; for ( j = 0 ; j < c ; j++ ) { if ( !edgeDefs[ i ][ j ].facing ) { continue; } hit[0] = 0; hit[1] = 0; i2 = edgeDefs[ i ][ j ].i2; c2 = numEdgeDefs[ i2 ]; for ( k = 0 ; k < c2 ; k++ ) { if ( edgeDefs[ i2 ][ k ].i2 == i ) { hit[ edgeDefs[ i2 ][ k ].facing ]++; } } // if it doesn't share the edge with another front facing // triangle, it is a sil edge if ( hit[ 1 ] == 0 ) { #ifdef HAVE_GLES // A single drawing call is better than many. So I prefer a singe TRIANGLES call than many TRAINGLE_STRIP call // even if it seems less efficiant, it's faster on the PANDORA indexes[idx++] = i; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2; indexes[idx++] = i2; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2 + tess.numVertexes; #else qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); #endif c_edges++; } else { c_rejected++; } } } #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #endif #endif }
/* * RE_StretchRaw * * FIXME: not exactly backend * Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. * Used for cinematics. */ void RE_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qbool dirty) { int i, j; int start, end; shaderProgram_t *sp = &tr.textureColorShader; Vec4 color; if(!tr.registered){ return; } R_SyncRenderThread(); /* we definately want to sync every frame for the cinematics */ qglFinish(); start = 0; if(r_speeds->integer){ start = ri.Milliseconds(); } /* make sure rows and cols are powers of 2 */ for(i = 0; (1 << i) < cols; i++){ } for(j = 0; (1 << j) < rows; j++){ } if((1 << i) != cols || (1 << j) != rows){ ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } GL_Bind(tr.scratchImage[client]); /* if the scratchImage isn't in the format we want, specify it as a new texture */ if(cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height){ tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); }else{ if(dirty){ /* otherwise, just subimage upload it so that drivers can tell we are going to be changing * it and don't try and do a texture compression */ qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data); } } if(r_speeds->integer){ end = ri.Milliseconds(); ri.Printf(PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start); } /* FIXME: HUGE hack */ if(glRefConfig.framebufferObject && !glState.currentFBO){ if(backEnd.framePostProcessed){ FBO_Bind(tr.screenScratchFbo); }else{ FBO_Bind(tr.renderFbo); } } RB_SetGL2D(); tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; tess.xyz[tess.numVertexes][0] = x; tess.xyz[tess.numVertexes][1] = y; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x + w; tess.xyz[tess.numVertexes][1] = y; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x + w; tess.xyz[tess.numVertexes][1] = y + h; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x; tess.xyz[tess.numVertexes][1] = y + h; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; /* FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function */ RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); sp = &tr.textureColorShader; GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); setv34(color, 1, 1, 1, 1); GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); qglDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(0)); /* R_BindNullVBO(); * R_BindNullIBO(); */ tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; }
//R_DRAWCEL static void R_DrawCel( int numIndexes, const glIndex_t *indexes ) { int primitives; if( //. ignore the 2d projection. do i smell the HUD? (backEnd.projection2D == qtrue) || //. ignore general entitites that are sprites. SEE NOTE #3. (backEnd.currentEntity->e.reType == RT_SPRITE) || //. ignore these liquids. why? ever see liquid with tris on the surface? exactly. SEE NOTE #4. (tess.shader->contentFlags & (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FOG)) || //. ignore things that are two sided, meaning mostly things that have transparency. SEE NOTE #1. (tess.shader->cullType == CT_TWO_SIDED) ) { return; } primitives = r_primitives->integer; // default is to use triangles if compiled vertex arrays are present if ( primitives == 0 ) { if ( qglLockArraysEXT ) { primitives = 2; } else { primitives = 1; } } //. correction for mirrors. SEE NOTE #2. if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_FRONT); } else { qglCullFace (GL_BACK); } qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA ,GL_ONE_MINUS_SRC_ALPHA); qglColor3f (0.0f,0.0f,0.0f); qglLineWidth( (float) r_celoutline->integer ); if(primitives == 2) { qglDrawElements( GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes ); } else if(primitives == 1) { R_DrawStripElements( numIndexes, indexes, qglArrayElement ); } else if(primitives == 3) { R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); } //. correction for mirrors. SEE NOTE #2. if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_BACK); } else { qglCullFace (GL_FRONT); } qglDisable (GL_BLEND); return; /* Notes 1. this is going to be a pain in the arse. it fixes things like light `beams` from being cel'd but it also will ignore any other shader set with no culling. this usually is everything that is translucent. but this is a good hack to clean up the screen untill something more selective comes along. or who knows group desision might actually be that this is liked. if so i take back calling it a `hack`, lol. = bob. 2. mirrors display correctly because the normals of the displayed are inverted of normal space. so to continue to have them display correctly, we must invert them inversely from a normal inversion. = bob. 3. this turns off a lot of space hogging sprite cel outlines. picture if you will five people in a small room all shooting rockets. each smoke puff gets a big black square around it, each explosion gets a big black square around it, and now nobody can see eachother because everyones screen is solid black. = bob. 4. ignoring liquids means you will not get black tris lines all over the top of your liquid. i put this in after seeing the lava on q3dm7 and water on q3ctf2 that had black lines all over the top, making the liquids look solid instead of... liquid. = bob. */ }
void R_RenderShadowEdges(void) { int i; int c, c2; int j, k; int i2; int c_edges, c_rejected; int hit[2]; // 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, // but lots of models have dangling edges or overfanned edges c_edges = 0; c_rejected = 0; idx = 0; for (i = 0 ; i < tess.numVertexes ; i++) { c = numEdgeDefs[i]; for (j = 0 ; j < c ; j++) { if (!edgeDefs[i][j].facing) { continue; } hit[0] = 0; hit[1] = 0; i2 = edgeDefs[i][j].i2; c2 = numEdgeDefs[i2]; for (k = 0 ; k < c2 ; k++) { if (edgeDefs[i2][k].i2 == i) { hit[edgeDefs[i2][k].facing]++; } } // if it doesn't share the edge with another front facing // triangle, it is a sil edge if (hit[1] == 0) { // A single drawing call is better than many. So I prefer a singe TRIANGLES call than many TRAINGLE_STRIP call // even if it seems less efficiant, it's faster on the PANDORA indexes[idx++] = i; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2; indexes[idx++] = i2; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2 + tess.numVertexes; c_edges++; } else { c_rejected++; } } } qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); }
/* ================= RB_ShadowTessEnd triangleFromEdge[ v1 ][ v2 ] set triangle from edge( v1, v2, tri ) if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { } ================= */ void RB_ShadowTessEnd(void) { int i; int numTris; vec3_t lightDir; // we can only do this if we have enough space in the vertex buffers if (tess.numVertexes >= tess.maxShaderVerts / 2) { return; } if (glConfig.stencilBits < 4) { return; } VectorCopy(backEnd.currentEntity->lightDir, lightDir); // project vertexes away from light direction for (i = 0 ; i < tess.numVertexes ; i++) { VectorMA(tess.xyz[i].v, -512, lightDir, tess.xyz[i + tess.numVertexes].v); } // decide which triangles face the light memset(numEdgeDefs, 0, 4 * tess.numVertexes); numTris = tess.numIndexes / 3; { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; for (i = 0 ; i < numTris ; i++) { i1 = tess.indexes[i * 3 + 0]; i2 = tess.indexes[i * 3 + 1]; i3 = tess.indexes[i * 3 + 2]; v1 = tess.xyz[i1].v; v2 = tess.xyz[i2].v; v3 = tess.xyz[i3].v; VectorSubtract(v2, v1, d1); VectorSubtract(v3, v1, d2); CrossProduct(d1, d2, normal); d = DotProduct(normal, lightDir); if (d > 0) { facing[i] = 1; } else { facing[i] = 0; } // create the edges R_AddEdgeDef(i1, i2, facing[i]); R_AddEdgeDef(i2, i3, facing[i]); R_AddEdgeDef(i3, i1, facing[i]); } } // draw the silhouette edges GL_Bind(tr.whiteImage); qglEnable(GL_CULL_FACE); GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO); qglColor3f(0.2f, 0.2f, 0.2f); // don't write to the color buffer qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 1, 255); qglVertexPointer(3, GL_FLOAT, 16, tess.xyz); GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (text) { qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } if (glcol) { qglDisableClientState(GL_COLOR_ARRAY); } // mirrors have the culling order reversed if (backEnd.viewParms.isMirror) { qglCullFace(GL_FRONT); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); R_RenderShadowEdges(); qglCullFace(GL_BACK); qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR); qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); } else { qglCullFace(GL_BACK); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); R_RenderShadowEdges(); qglCullFace(GL_FRONT); qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR); qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); } if (text) { qglEnableClientState(GL_TEXTURE_COORD_ARRAY); } if (glcol) { qglEnableClientState(GL_COLOR_ARRAY); } // reenable writing to the color buffer qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); }
void R_DrawSkyBox (void) { int i; float skyM[16]; vec_t *v, *st; if (skyrotate) { // check for no sky at all for (i = 0; i < 6; i++) { if (skymins[0][i] < skymaxs[0][i] && skymins[1][i] < skymaxs[1][i]) break; } if (i == 6) return; // nothing visible R_RotateMatrix(skyM, r_WorldViewMatrix, r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); } else { skyM[0] = r_WorldViewMatrix[0]; skyM[1] = r_WorldViewMatrix[1]; skyM[2] = r_WorldViewMatrix[2]; skyM[4] = r_WorldViewMatrix[4]; skyM[5] = r_WorldViewMatrix[5]; skyM[6] = r_WorldViewMatrix[6]; skyM[8] = r_WorldViewMatrix[8]; skyM[9] = r_WorldViewMatrix[9]; skyM[10] = r_WorldViewMatrix[10]; skyM[3] = skyM[7] = skyM[11] = skyM[12] = skyM[13] = skyM[14] = 0.0f; skyM[15] = 1.0f; } qglLoadMatrixf( skyM ); qglTexCoordPointer( 2, GL_FLOAT, 0, r_arrays.tcoords ); for (i = 0; i < 6; i++) { if (skyrotate) { // hack, forces full sky to draw when rotating skymins[0][i] = skymins[1][i] = -1; skymaxs[0][i] = skymaxs[1][i] = 1; } else if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]) continue; GL_Bind (sky_images[skytexorder[i]]->texnum); st = r_arrays.tcoords[0]; v = r_arrays.vertices; MakeSkyVec (skymins[0][i], skymins[1][i], i, v, st); MakeSkyVec (skymins[0][i], skymaxs[1][i], i, v+=3, st+=2); MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i, v+=3, st+=2); MakeSkyVec (skymaxs[0][i], skymins[1][i], i, v+=3, st+=2); if(gl_state.compiledVertexArray) { qglLockArraysEXT( 0, 4 ); qglDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, r_arrays.indices ); qglUnlockArraysEXT (); } else { qglDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, r_arrays.indices ); } } qglLoadMatrixf(r_WorldViewMatrix); }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. 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; #ifdef VCMODS_OPENGLES vec2_t texcoords[4]; vec2_t verts[4]; glIndex_t indicies[6] = {0, 1, 2, 0, 3, 2}; #endif if ( !tr.registered ) { return; } R_SyncRenderThread(); // we definately want to sync every frame for the cinematics qglFinish(); start = end = 0; if ( r_speeds->integer ) { start = ri.Milliseconds(); } // make sure rows and cols are powers of 2 for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { } for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { } if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; #ifdef VCMODS_OPENGLES //don't do qglTexImage2D as this may end up doing a compressed image //on which we are not allowed to do further sub images glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #else qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #endif qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } else { if (dirty) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } RB_SetGL2D(); #ifdef VCMODS_OPENGLES qglColor4f( tr.identityLight, tr.identityLight, tr.identityLight, 1.0f ); verts[0][0] = x; verts[0][1] = y; verts[1][0] = x+w; verts[1][1] = y; verts[2][0] = x+w; verts[2][1] = y+h; verts[3][0] = x; verts[3][1] = y+h; texcoords[0][0] = 0.5f/cols; texcoords[0][1] = 0.5f/rows; texcoords[1][0] = (cols-0.5f)/cols; texcoords[1][1] = 0.5f/rows; texcoords[2][0] = (cols-0.5f)/cols; texcoords[2][1] = (rows-0.5f)/rows; texcoords[3][0] = 0.5f/cols; texcoords[3][1] = (rows-0.5f)/rows; qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texcoords ); qglVertexPointer ( 2, GL_FLOAT, 0, verts ); qglDrawElements( GL_TRIANGLE_STRIP, 6, GL_INDEX_TYPE, indicies ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #else 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 (); #endif }