/* ============= GL_DrawAliasFrameLerp interpolates between two frames and origins FIXME: batch lerp all vertexes ============= */ void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp) { float l; daliasframe_t *frame, *oldframe; dtrivertx_t *v, *ov, *verts; int *order; int count; float frontlerp; float alpha; vec3_t move, delta, vectors[3]; vec3_t frontv, backv; int i; int index_xyz; float *lerp; frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = v = frame->verts; oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->oldframe * paliashdr->framesize); ov = oldframe->verts; order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); // glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]); // glScalef (frame->scale[0], frame->scale[1], frame->scale[2]); if (currententity->flags & RF_TRANSLUCENT) alpha = currententity->alpha; else alpha = 1.0; // PMM - added double shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) qglDisable( GL_TEXTURE_2D ); frontlerp = 1.0 - backlerp; // move should be the delta back to the previous frame * backlerp VectorSubtract (currententity->oldorigin, currententity->origin, delta); AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); move[0] = DotProduct (delta, vectors[0]); // forward move[1] = -DotProduct (delta, vectors[1]); // left move[2] = DotProduct (delta, vectors[2]); // up VectorAdd (move, oldframe->translate, move); for (i=0 ; i<3 ; i++) { move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; } for (i=0 ; i<3 ; i++) { frontv[i] = frontlerp*frame->scale[i]; backv[i] = backlerp*oldframe->scale[i]; } lerp = s_lerped[0]; GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv ); if ( gl_vertex_arrays->value ) { float colorArray[MAX_VERTS*4]; qglEnableClientState( GL_VERTEX_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 16, s_lerped ); // padded for SIMD // if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha ); } else { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 3, GL_FLOAT, 0, colorArray ); // // pre light everything // for ( i = 0; i < paliashdr->num_xyz; i++ ) { float l = shadedots[verts[i].lightnormalindex]; colorArray[i*3+0] = l * shadelight[0]; colorArray[i*3+1] = l * shadelight[1]; colorArray[i*3+2] = l * shadelight[2]; } } if ( qglLockArraysEXT != 0 ) qglLockArraysEXT( 0, paliashdr->num_xyz ); while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else { qglBegin (GL_TRIANGLE_STRIP); } // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { do { index_xyz = order[2]; order += 3; qglVertex3fv( s_lerped[index_xyz] ); } while (--count); } else { do { // texture coordinates come from the draw list qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; // normals and vertexes come from the frame list // l = shadedots[verts[index_xyz].lightnormalindex]; // qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); qglArrayElement( index_xyz ); } while (--count); } qglEnd (); } if ( qglUnlockArraysEXT != 0 ) qglUnlockArraysEXT(); } else { while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else { qglBegin (GL_TRIANGLE_STRIP); } if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) { do { index_xyz = order[2]; order += 3; qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha); qglVertex3fv (s_lerped[index_xyz]); } while (--count); } else { do { // texture coordinates come from the draw list qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; // normals and vertexes come from the frame list l = shadedots[verts[index_xyz].lightnormalindex]; qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); qglVertex3fv (s_lerped[index_xyz]); } while (--count); } qglEnd (); } } // if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) qglEnable( GL_TEXTURE_2D ); }
/* ================= 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 ) { if ( r_shadows->integer != 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #ifdef _DEBUG_STENCIL_SHADOWS return; #endif qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_NOTEQUAL, 0, 255 ); qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); bool planeZeroBack = false; if (qglIsEnabled(GL_CLIP_PLANE0)) { planeZeroBack = true; qglDisable (GL_CLIP_PLANE0); } GL_Cull(CT_TWO_SIDED); //qglDisable (GL_CULL_FACE); GL_Bind( tr.whiteImage ); qglPushMatrix(); qglLoadIdentity (); // qglColor3f( 0.6f, 0.6f, 0.6f ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); // qglColor3f( 1, 0, 0 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor4f( 0.0f, 0.0f, 0.0f, 0.5f ); //GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); #ifdef HAVE_GLES static GLfloat vtx[] = { -100.0f, 100.0f, -10.0f, 100.0f, 100.0f, -10.0f, 100.0f, -100.0f, -10.0f, -100.0f, -100.0f, -10.0f }; 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, 0, vtx); qglDrawArrays(GL_TRIANGLE_FAN, 0, 4); if (text) qglEnableClientState(GL_TEXTURE_COORD_ARRAY); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); #else qglBegin( GL_QUADS ); qglVertex3f( -100.0f, 100.0f, -10.0f); qglVertex3f( 100.0f, 100.0f, -10.0f); qglVertex3f( 100.0f, -100.0f, -10.0f); qglVertex3f( -100.0f, -100.0f, -10.0f); qglEnd(); #endif qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); if (planeZeroBack) { qglEnable (GL_CLIP_PLANE0); } qglPopMatrix(); }
void RB_DistortionFill(void) { float alpha = tr_distortionAlpha; float spost = 0.0f; float spost2 = 0.0f; if ( glConfig.stencilBits < 4 ) { return; } //ok, cap the stupid thing now I guess if (!tr_distortionPrePost) { RB_CaptureScreenImage(); } qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); //reset the view matrices and go into ortho mode qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglOrtho(0, glConfig.vidWidth, glConfig.vidHeight, 32, -1, 1); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglLoadIdentity(); if (tr_distortionStretch) { //override spost = tr_distortionStretch; spost2 = tr_distortionStretch; } else { //do slow stretchy effect spost = sin(tr.refdef.time * 0.0005 + tr.refdef.timeFraction * 0.0005); if (spost < 0.0f) { spost = -spost; } spost *= 0.2f; spost2 = sin(tr.refdef.time * 0.0005 + tr.refdef.timeFraction * 0.0005); if (spost2 < 0.0f) { spost2 = -spost2; } spost2 *= 0.08f; } if (alpha != 1.0f) { //blend GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA); } else { //be sure to reset the draw state GL_State(0); } #ifdef HAVE_GLES qglColor4f(1.0f, 1.0f, 1.0f, alpha); GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (!text) qglEnableClientState(GL_TEXTURE_COORD_ARRAY); if (glcol) qglDisableClientState(GL_COLOR_ARRAY); GLfloat tex[] = { 0 + spost2, 1 - spost, 0 + spost2, 0 + spost, 1 - spost2, 0 + spost, 1 - spost2, 1 - spost }; GLfloat vtx[] = { 0, 0, 0, glConfig.vidHeight, glConfig.vidWidth, glConfig.vidHeight, glConfig.vidWidth, 0 }; qglTexCoordPointer(2, GL_FLOAT, 0, tex); qglVertexPointer(2, GL_FLOAT, 0, vtx); qglDrawArrays(GL_TRIANGLE_FAN, 0, 4); /* if (glcol) qglEnableClientState( GL_COLOR_ARRAY ); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY );*/ #else qglBegin(GL_QUADS); qglColor4f(1.0f, 1.0f, 1.0f, alpha); qglTexCoord2f(0+spost2, 1-spost); qglVertex2f(0, 0); qglTexCoord2f(0+spost2, 0+spost); qglVertex2f(0, glConfig.vidHeight); qglTexCoord2f(1-spost2, 0+spost); qglVertex2f(glConfig.vidWidth, glConfig.vidHeight); qglTexCoord2f(1-spost2, 1-spost); qglVertex2f(glConfig.vidWidth, 0); qglEnd(); #endif if (tr_distortionAlpha == 1.0f && tr_distortionStretch == 0.0f) { //no overrides if (tr_distortionNegate) { //probably the crazy alternate saber trail alpha = 0.8f; GL_State(GLS_SRCBLEND_ZERO|GLS_DSTBLEND_ONE_MINUS_SRC_COLOR); } else { alpha = 0.5f; GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA); } spost = sin(tr.refdef.time * 0.0008 + tr.refdef.timeFraction * 0.0008); if (spost < 0.0f) { spost = -spost; } spost *= 0.08f; spost2 = sin(tr.refdef.time * 0.0008 + tr.refdef.timeFraction * 0.0008); if (spost2 < 0.0f) { spost2 = -spost2; } spost2 *= 0.2f; #ifdef HAVE_GLES qglColor4f(1.0f, 1.0f, 1.0f, alpha); /* GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglDisableClientState( GL_COLOR_ARRAY );*/ GLfloat tex[] = { 0 + spost2, 1 - spost, 0 + spost2, 0 + spost, 1 - spost2, 0 + spost, 1 - spost2, 1 - spost }; GLfloat vtx[] = { 0, 0, 0, glConfig.vidHeight, glConfig.vidWidth, glConfig.vidHeight, glConfig.vidWidth, 0 }; qglTexCoordPointer(2, GL_FLOAT, 0, tex); qglVertexPointer(2, GL_FLOAT, 0, vtx); qglDrawArrays(GL_TRIANGLE_FAN, 0, 4); #else qglBegin(GL_QUADS); qglColor4f(1.0f, 1.0f, 1.0f, alpha); qglTexCoord2f(0+spost2, 1-spost); qglVertex2f(0, 0); qglTexCoord2f(0+spost2, 0+spost); qglVertex2f(0, glConfig.vidHeight); qglTexCoord2f(1-spost2, 0+spost); qglVertex2f(glConfig.vidWidth, glConfig.vidHeight); qglTexCoord2f(1-spost2, 1-spost); qglVertex2f(glConfig.vidWidth, 0); qglEnd(); #endif } #ifdef HAVE_GLES if (glcol) qglEnableClientState(GL_COLOR_ARRAY); if (!text) qglDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif //pop the view matrices back qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglPopMatrix(); qglDisable( GL_STENCIL_TEST ); }
void idSplineList::draw(bool editMode) { int i; idVec4 yellow(1, 1, 0, 1); if(controlPoints.Num() == 0) { return; } if(dirty) { buildSpline(); } qglColor3fv(controlColor); qglPointSize(5); qglBegin(GL_POINTS); for(i = 0; i < controlPoints.Num(); i++) { qglVertex3fv(*controlPoints[i]); } qglEnd(); if(editMode) { for(i = 0; i < controlPoints.Num(); i++) { glBox(activeColor, *controlPoints[i], 4); } } //Draw the curve qglColor3fv(pathColor); qglBegin(GL_LINE_STRIP); int count = splinePoints.Num(); for(i = 0; i < count; i++) { qglVertex3fv(*splinePoints[i]); } qglEnd(); if(editMode) { qglColor3fv(segmentColor); qglPointSize(3); qglBegin(GL_POINTS); for(i = 0; i < count; i++) { qglVertex3fv(*splinePoints[i]); } qglEnd(); } if(count > 0) { //assert(activeSegment >=0 && activeSegment < count); if(activeSegment >= 0 && activeSegment < count) { glBox(activeColor, *splinePoints[activeSegment], 6); glBox(yellow, *splinePoints[activeSegment], 8); } } }
void R_DrawAliasShadow ( dmdl_t *paliashdr, int posenum ) { #if defined(VERTEX_ARRAYS) uint16_t total; GLenum type; #endif int *order; vec3_t point; float height, lheight; int count; lheight = currententity->origin [ 2 ] - lightspot [ 2 ]; height = 0; order = (int *) ( (byte *) paliashdr + paliashdr->ofs_glcmds ); height = -lheight + 0.1f; /* stencilbuffer shadows */ if ( have_stencil && gl_stencilshadow->value ) { qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_EQUAL, 1, 2 ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); } while ( 1 ) { /* get the vertex count and primitive type */ count = *order++; if ( !count ) { break; /* done */ } if ( count < 0 ) { count = -count; #if defined(VERTEX_ARRAYS) type = GL_TRIANGLE_FAN; #else qglBegin( GL_TRIANGLE_FAN ); #endif } else { #if defined(VERTEX_ARRAYS) type = GL_TRIANGLE_STRIP; #else qglBegin( GL_TRIANGLE_STRIP ); #endif } #if defined(VERTEX_ARRAYS) total = count; GLfloat vtx[3*total]; uint32_t index_vtx = 0; #endif do { /* normals and vertexes come from the frame list */ memcpy( point, s_lerped [ order [ 2 ] ], sizeof ( point ) ); point [ 0 ] -= shadevector [ 0 ] * ( point [ 2 ] + lheight ); point [ 1 ] -= shadevector [ 1 ] * ( point [ 2 ] + lheight ); point [ 2 ] = height; #if defined(VERTEX_ARRAYS) vtx[index_vtx++] = point [ 0 ]; vtx[index_vtx++] = point [ 1 ]; vtx[index_vtx++] = point [ 2 ]; #else qglVertex3fv( point ); #endif order += 3; } while ( --count ); #if defined(VERTEX_ARRAYS) qglEnableClientState( GL_VERTEX_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 0, vtx ); qglDrawArrays( type, 0, total ); qglDisableClientState( GL_VERTEX_ARRAY ); #else qglEnd(); #endif } /* stencilbuffer shadows */ if ( have_stencil && gl_stencilshadow->value ) { qglDisable( GL_STENCIL_TEST ); } }
/* ============= 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 }
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; 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 ) { 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 }
void R_DrawSkyBox (void) { int i; #if 0 qglEnable (GL_BLEND); GL_TexEnv( GL_MODULATE ); qglColor4f (1,1,1,0.5); qglDisable (GL_DEPTH_TEST); #endif // jkrige - skybox qglDisable (GL_DEPTH_TEST); /*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 }*/ // jkrige - skybox qglPushMatrix (); qglTranslatef (r_origin[0], r_origin[1], r_origin[2]); qglRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); for (i=0 ; i<6 ; i++) { // jkrige - skybox /*if (skyrotate) { // hack, forces full sky to draw when rotating skymins[0][i] = -1; skymins[1][i] = -1; skymaxs[0][i] = 1; skymaxs[1][i] = 1; } if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]) continue;*/ // jkrige - skybox GL_Bind (sky_images[skytexorder[i]]->texnum); qglBegin (GL_QUADS); // jkrige - skybox MakeSkyVec (-1, -1, i); MakeSkyVec (-1, 1, i); MakeSkyVec (1, 1, i); MakeSkyVec (1, -1, i); //MakeSkyVec (skymins[0][i], skymins[1][i], i); //MakeSkyVec (skymins[0][i], skymaxs[1][i], i); //MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i); //MakeSkyVec (skymaxs[0][i], skymins[1][i], i); // jkrige - skybox qglEnd (); } qglPopMatrix (); #if 0 glDisable (GL_BLEND); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor4f (1,1,1,0.5); glEnable (GL_DEPTH_TEST); #endif // jkrige - skybox qglEnable (GL_DEPTH_TEST); // jkrige - skybox }
/* ============= 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; if ( !tr.registered ) { return; } R_SyncRenderThread(); #ifdef FRAMEBUFFER_AND_GLSL_SUPPORT // Needed here to support cinematics R_FrameBuffer_EndFrame(); #endif // 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; 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 ); } RB_SetGL2D(); 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 (); }
/* =============== DrawRuledSurface =============== */ void DrawRuledSurface (face_t *cf, float ctrl[2][3][5] ) { int j, k, l; vec5_t curve[2][CBLOCK_SUBDIVISIONS+1]; //float u; float *v; if (curveFile) { fprintf (curveFile, "RULED {\n"); fprintf (curveFile, "textures/%s\n", cf->texdef.name); Write3DMatrix (curveFile, 2, 3, 5, (float *)ctrl); fprintf (curveFile, "}\n"); return; } for (j = 0 ; j < 2 ; j++) { for (l = 0 ; l < 5 ; l++) { float a, b, c; float qA, qB, qC; float f; int k; a = ctrl[j][0][l]; b = ctrl[j][1][l]; c = ctrl[j][2][l]; qA = a - 2 * b + c; qB = 2 * b - 2 * a; qC = a; for (k = 0 ; k <= CBLOCK_SUBDIVISIONS ; k++) { f = (float)k / CBLOCK_SUBDIVISIONS; curve[j][k][l] = qA*f*f + qB*f + qC; } } } if ( bevelBrush ) { face_t *f; for (k = 0 ; k < CBLOCK_SUBDIVISIONS ; k++) { f = Face_Clone( bevelBrush->brush_faces ); f->texdef.flags |= SURF_CURVE_FAKE; f->next = bevelBrush->brush_faces; bevelBrush->brush_faces = f; VectorCopy( curve[0][k], f->planepts[0] ); VectorCopy( curve[1][k], f->planepts[1] ); VectorCopy( curve[0][k+1], f->planepts[2] ); Brush_MakeFacePlane( f ); } return; } qglBindTexture (GL_TEXTURE_2D, cf->d_texture->texture_number); float fColor[3]; SetColor(cf, fColor); qglBegin (GL_QUAD_STRIP); for (k = 0 ; k <= CBLOCK_SUBDIVISIONS ; k++) { v = curve[0][k]; qglTexCoord2fv( v + 3 ); qglVertex3fv( v ); v = curve[1][k]; qglTexCoord2fv( v + 3 ); qglVertex3fv( v ); } qglEnd (); }
/* =================== DrawPatch =================== */ void DrawPatch (face_t *cf, float ctrl[3][3][5]) { int i, j; float u, v; vec5_t verts[CBLOCK_SUBDIVISIONS+1][CBLOCK_SUBDIVISIONS+1]; if (curveFile) { fprintf (curveFile, "PATCH {\n"); fprintf (curveFile, "textures/%s\n", cf->texdef.name); Write3DMatrix (curveFile, 3, 3, 5, (float *)ctrl); fprintf (curveFile, "}\n"); return; } for (i = 0 ; i <= CBLOCK_SUBDIVISIONS ; i++) { for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) { u = (float)i / CBLOCK_SUBDIVISIONS; v = (float)j / CBLOCK_SUBDIVISIONS; SamplePatch (ctrl, u, v, verts[i][j]); } } if ( bevelBrush ) { face_t *f; vec3_t v0, v1, v2; vec3_t d1, d2, cross; for (i = 0 ; i < CBLOCK_SUBDIVISIONS ; i++) { for (j = 0 ; j < CBLOCK_SUBDIVISIONS ; j++) { VectorCopy( verts[i][j], v0 ); VectorCopy( verts[i][j+1], v1 ); VectorCopy( verts[i+1][j], v2 ); VectorSubtract( v0, v1, d1 ); VectorSubtract( v2, v1, d2 ); CrossProduct( d1, d2, cross ); if ( VectorLength( cross ) == 0 ) { continue; // degenerate } f = Face_Clone( bevelBrush->brush_faces ); f->texdef.flags |= SURF_CURVE_FAKE; VectorCopy( v0, f->planepts[0] ); VectorCopy( v1, f->planepts[1] ); VectorCopy( v2, f->planepts[2] ); Brush_MakeFacePlane( f ); f->next = bevelBrush->brush_faces; bevelBrush->brush_faces = f; } } return; } qglBindTexture (GL_TEXTURE_2D, cf->d_texture->texture_number); float fColor[3]; SetColor(cf, fColor); for (i = 0 ; i < CBLOCK_SUBDIVISIONS ; i++) { qglBegin (GL_QUAD_STRIP); for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) { qglTexCoord2fv( verts[i+1][j] + 3 ); qglVertex3fv( verts[i+1][j] ); qglTexCoord2fv( verts[i][j] + 3 ); qglVertex3fv( verts[i][j] ); DecColor(fColor); } qglEnd (); } }
/* =============== DrawCurveFan Draws a curve as part of a flat surface =============== */ void DrawCurveFan (face_t *cf, vec5_t opposite, vec5_t prev, vec5_t peak, vec5_t next) { int i, k, l; float coef[5][3]; // write it out if (curveFile) { vec5_t vecs[4]; for ( i = 0 ; i < 5 ; i++ ) { vecs[0][i] = opposite[i]; vecs[1][i] = prev[i]; vecs[2][i] = peak[i]; vecs[3][i] = next[i]; } fprintf (curveFile, "CURVEFAN {\n"); fprintf (curveFile, "textures/%s\n", cf->texdef.name); Write2DMatrix (curveFile, 4, 5, (float *)vecs); fprintf (curveFile, "}\n"); return; } // calculate the coefficients for (l = 0 ; l < 5 ; l++) { float a, b, c; a = prev[l]; b = peak[l]; c = next[l]; coef[l][0] = a; coef[l][1] = 2 * b - 2 * a; coef[l][2] = a - 2 * b + c; } // draw it qglBindTexture (GL_TEXTURE_2D, cf->d_texture->texture_number); float fColor[3]; SetColor(cf, fColor); qglBegin (GL_TRIANGLE_FAN); qglTexCoord2fv( opposite + 3 ); qglVertex3fv( opposite ); for ( k = 0 ; k <= CBLOCK_SUBDIVISIONS ; k++ ) { vec5_t curve; float f; f = (float)k / CBLOCK_SUBDIVISIONS; for ( l = 0 ; l < 5 ; l++ ) { curve[l] = coef[l][2]*f*f + coef[l][1]*f + coef[l][0]; } qglTexCoord2fv( curve + 3 ); qglVertex3fv( curve ); DecColor(fColor); } qglEnd (); }
void RB_ColorCorrect( void ) { GLint loc; GLenum target; int width, height; int shift; float mul; if ( !r_enablePostProcess->integer || !r_enableColorCorrect->integer || !glsl ) { return; } GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = glConfig.vidWidth; height = glConfig.vidHeight; qglBindTexture(target, tr.backBufferTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); RB_SetGL2D(); GL_State( GLS_DEPTHTEST_DISABLE ); qglUseProgramObjectARB(tr.colorCorrectSp); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_gammaRecip"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_gammaRecip", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)(1.0 / r_gamma->value)); //mul = r_overBrightBitsValue->value; mul = r_overBrightBits->value; if (mul < 0.0) { mul = 0.0; } shift = tr.overbrightBits; loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_overbright"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_overbright", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)((float)(1 << shift) * mul)); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_contrast"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_contrast", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_contrast->value); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); qglBegin(GL_QUADS); qglTexCoord2i(0, 0); qglVertex2i(0, height); qglTexCoord2i(width, 0); qglVertex2i(width, height); qglTexCoord2i(width, height); qglVertex2i(width, 0); qglTexCoord2i(0, height); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
static void RB_BloomCombine( void ) { GLenum target; int width, height; GLint loc; GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = tr.bloomWidth; height = tr.bloomHeight; qglBindTexture(target, tr.bloomTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, glConfig.vidHeight - height, width, height); qglUseProgramObjectARB(tr.combineSp); qglBindTexture(target, tr.backBufferTexture); loc = qglGetUniformLocationARB(tr.combineSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); GL_SelectTexture(1); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); qglBindTexture(target, tr.bloomTexture); loc = qglGetUniformLocationARB(tr.combineSp, "bloomTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get bloomTex", __FUNCTION__); } qglUniform1iARB(loc, 1); loc = qglGetUniformLocationARB(tr.combineSp, "p_bloomsaturation"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_bloomsaturation", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSaturation->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_scenesaturation"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_scenesaturation", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSceneSaturation->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_bloomintensity"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_bloomintensity", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomIntensity->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_sceneintensity"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_sceneintensity", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSceneIntensity->value); width = glConfig.vidWidth; height = glConfig.vidHeight; qglBegin(GL_QUADS); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, 0); qglVertex2i(0, height); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, tr.bloomWidth, 0); qglVertex2i(width, height); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, tr.bloomWidth, tr.bloomHeight); qglVertex2i(width, 0); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, tr.bloomHeight); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); GL_SelectTexture(1); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
/* =============== CreateOptTri =============== */ static void CreateOptTri( optVertex_t *first, optEdge_t *e1, optEdge_t *e2, optIsland_t *island ) { optEdge_t *opposite; optVertex_t *second, *third; optTri_t *optTri; mapTri_t *tri; if ( e1->v1 == first ) { second = e1->v2; } else if ( e1->v2 == first ) { second = e1->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); return; } if ( e2->v1 == first ) { third = e2->v2; } else if ( e2->v2 == first ) { third = e2->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); return; } if ( !IsTriangleValid( first, second, third ) ) { common->Error( "CreateOptTri: invalid" ); return; } //DrawEdges( island ); // identify the third edge if ( dmapGlobals.drawflag ) { qglColor3f(1,1,0); qglBegin( GL_LINES ); qglVertex3fv( e1->v1->pv.ToFloatPtr() ); qglVertex3fv( e1->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); qglColor3f(0,1,1); qglBegin( GL_LINES ); qglVertex3fv( e2->v1->pv.ToFloatPtr() ); qglVertex3fv( e2->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } for ( opposite = second->edges ; opposite ; ) { if ( opposite != e1 && ( opposite->v1 == third || opposite->v2 == third ) ) { break; } if ( opposite->v1 == second ) { opposite = opposite->v1link; } else if ( opposite->v2 == second ) { opposite = opposite->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); return; } } if ( !opposite ) { common->Printf( "Warning: BuildOptTriangles: couldn't locate opposite\n" ); return; } if ( dmapGlobals.drawflag ) { qglColor3f(1,0,1); qglBegin( GL_LINES ); qglVertex3fv( opposite->v1->pv.ToFloatPtr() ); qglVertex3fv( opposite->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // create new triangle optTri = (optTri_t *)Mem_Alloc( sizeof( *optTri ), TAG_DMAP ); optTri->v[0] = first; optTri->v[1] = second; optTri->v[2] = third; optTri->midpoint = ( optTri->v[0]->pv + optTri->v[1]->pv + optTri->v[2]->pv ) * ( 1.0f / 3.0f ); optTri->next = island->tris; island->tris = optTri; if ( dmapGlobals.drawflag ) { qglColor3f( 1, 1, 1 ); qglPointSize( 4 ); qglBegin( GL_POINTS ); qglVertex3fv( optTri->midpoint.ToFloatPtr() ); qglEnd(); qglFlush(); } // find the midpoint, and scan through all the original triangles to // see if it is inside any of them for ( tri = island->group->triList ; tri ; tri = tri->next ) { if ( PointInTri( optTri->midpoint, tri, island ) ) { break; } } if ( tri ) { optTri->filled = true; } else { optTri->filled = false; } if ( dmapGlobals.drawflag ) { if ( optTri->filled ) { qglColor3f( ( 128 + orandom.RandomInt( 127 ) )/ 255.0, 0, 0 ); } else { qglColor3f( 0, ( 128 + orandom.RandomInt( 127 ) ) / 255.0, 0 ); } qglBegin( GL_TRIANGLES ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINE_LOOP ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // link the triangle to it's edges LinkTriToEdge( optTri, e1 ); LinkTriToEdge( optTri, e2 ); LinkTriToEdge( optTri, opposite ); }
/* =============== 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; if ( !backEnd.projection2D ) { RB_SetGL2D(); } qglClear( GL_COLOR_BUFFER_BIT ); qglFinish(); start = ri.Milliseconds(); for ( i = 0 ; i < tr.numImages ; i++ ) { image = tr.images[i]; w = glConfig.vidWidth / 40; h = glConfig.vidHeight / 30; x = i % 40 * w; y = i / 30 * h; // show in proportional size in mode 2 if ( r_showImages->integer == 2 ) { w *= image->uploadWidth / 512.0f; h *= image->uploadHeight / 512.0f; } #ifdef USE_OPENGLES GLfloat tex[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; GLfloat vtx[] = { x, y, x + w, y, x + w, y + h, x, y + h }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (glcol) qglDisableClientState(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #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 } qglFinish(); end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); }
/* =============== 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 ); }
/* ============= 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; if ( !tr.registered ) { return; } R_IssuePendingRenderCommands(); if ( tess.numIndexes ) { RB_EndSurface(); } // 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; #ifdef USE_OPENGLES qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #else qglTexImage2D( GL_TEXTURE_2D, 0, 3, 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(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); #ifdef USE_OPENGLES GLfloat tex[] = { 0.5f / cols, 0.5f / rows, ( cols - 0.5f ) / cols , 0.5f / rows, ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows, 0.5f / cols, ( rows - 0.5f ) / rows }; GLfloat vtx[] = { x, y, x+w, y, x+w, y+h, x, y+h }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (glcol) qglDisableClientState(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); #else 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 }
/* ============== R_CalcBones The list of bones[] should only be built and modified from within here ============== */ void R_CalcBones(mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones) { int i; int *boneRefs; float torsoWeight; // if the entity has changed since the last time the bones were built, reset them if (memcmp(&lastBoneEntity, refent, sizeof(refEntity_t))) { // different, cached bones are not valid memset(validBones, 0, header->numBones); lastBoneEntity = *refent; // (SA) also reset these counter statics //----(SA) print stats for the complete model (not per-surface) if (r_bonesDebug->integer == 4 && totalrt) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, totalrv, totalv, totalrt, totalt, ( float )(100.0 * totalrt) / (float) totalt); } totalrv = totalrt = totalv = totalt = 0; } memset(newBones, 0, header->numBones); if (refent->oldframe == refent->frame) { backlerp = 0; frontlerp = 1; } else { backlerp = refent->backlerp; frontlerp = 1.0f - backlerp; } if (refent->oldTorsoFrame == refent->torsoFrame) { torsoBacklerp = 0; torsoFrontlerp = 1; } else { torsoBacklerp = refent->torsoBacklerp; torsoFrontlerp = 1.0f - torsoBacklerp; } frameSize = (int) (sizeof(mdsFrame_t) + (header->numBones - 1) * sizeof(mdsBoneFrameCompressed_t)); frame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->frame * frameSize); torsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->torsoFrame * frameSize); oldFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldframe * frameSize); oldTorsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldTorsoFrame * frameSize); // lerp all the needed bones (torsoParent is always the first bone in the list) cBoneList = frame->bones; cBoneListTorso = torsoFrame->bones; boneInfo = ( mdsBoneInfo_t * )((byte *)header + header->ofsBones); boneRefs = boneList; // Matrix3Transpose(refent->torsoAxis, torsoAxis); #ifdef HIGH_PRECISION_BONES if (qtrue) { #else if (!backlerp && !torsoBacklerp) { #endif for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBone(header, refent, boneInfo[*boneRefs].parent); } R_CalcBone(header, refent, *boneRefs); } } else // interpolated { cOldBoneList = oldFrame->bones; cOldBoneListTorso = oldTorsoFrame->bones; for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBoneLerp(header, refent, boneInfo[*boneRefs].parent); } R_CalcBoneLerp(header, refent, *boneRefs); } } // adjust for torso rotations torsoWeight = 0; boneRefs = boneList; for (i = 0; i < numBones; i++, boneRefs++) { thisBoneInfo = &boneInfo[*boneRefs]; bonePtr = &bones[*boneRefs]; // add torso rotation if (thisBoneInfo->torsoWeight > 0) { if (!newBones[*boneRefs]) { // just copy it back from the previous calc bones[*boneRefs] = oldBones[*boneRefs]; continue; } if (!(thisBoneInfo->flags & BONEFLAG_TAG)) { // 1st multiply with the bone->matrix // 2nd translation for rotation relative to bone around torso parent offset VectorSubtract(bonePtr->translation, torsoParentOffset, t); Matrix4FromAxisPlusTranslation(bonePtr->matrix, t, m1); // 3rd scaled rotation // 4th translate back to torso parent offset // use previously created matrix if available for the same weight if (torsoWeight != thisBoneInfo->torsoWeight) { Matrix4FromScaledAxisPlusTranslation(torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2); torsoWeight = thisBoneInfo->torsoWeight; } // multiply matrices to create one matrix to do all calculations Matrix4MultiplyInto3x3AndTranslation(m2, m1, bonePtr->matrix, bonePtr->translation); } else // tag's require special handling { // rotate each of the axis by the torsoAngles LocalScaledMatrixTransformVector(bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0]); LocalScaledMatrixTransformVector(bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1]); LocalScaledMatrixTransformVector(bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2]); memcpy(bonePtr->matrix, tmpAxis, sizeof(tmpAxis)); // rotate the translation around the torsoParent VectorSubtract(bonePtr->translation, torsoParentOffset, t); LocalScaledMatrixTransformVector(t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation); VectorAdd(bonePtr->translation, torsoParentOffset, bonePtr->translation); } } } // backup the final bones memcpy(oldBones, bones, sizeof(bones[0]) * header->numBones); } #ifdef DBG_PROFILE_BONES #define DBG_SHOWTIME Ren_Print("%i: %i, ", di++, (dt = ri.Milliseconds()) - ldt); ldt = dt; #else #define DBG_SHOWTIME ; #endif /* ============== RB_SurfaceAnim ============== */ void RB_SurfaceAnim(mdsSurface_t *surface) { int j, k; refEntity_t *refent; int *boneList; mdsHeader_t *header; #ifdef DBG_PROFILE_BONES int di = 0, dt, ldt; dt = ri.Milliseconds(); ldt = dt; #endif refent = &backEnd.currentEntity->e; boneList = ( int * )((byte *)surface + surface->ofsBoneReferences); header = ( mdsHeader_t * )((byte *)surface + surface->ofsHeader); R_CalcBones(header, (const refEntity_t *)refent, boneList, surface->numBoneReferences); DBG_SHOWTIME // calculate LOD // TODO: lerp the radius and origin VectorAdd(refent->origin, frame->localOrigin, vec); lodRadius = frame->radius; lodScale = RB_CalcMDSLod(refent, vec, lodRadius, header->lodBias, header->lodScale); //DBG_SHOWTIME // modification to allow dead skeletal bodies to go below minlod (experiment) if (refent->reFlags & REFLAG_DEAD_LOD) { if (lodScale < 0.35) // allow dead to lod down to 35% (even if below surf->minLod) (%35 is arbitrary and probably not good generally. worked for the blackguard/infantry as a test though) { lodScale = 0.35; } render_count = ROUND_INT(surface->numVerts * lodScale); } else { render_count = ROUND_INT(surface->numVerts * lodScale); if (render_count < surface->minLod) { if (!(refent->reFlags & REFLAG_DEAD_LOD)) { render_count = surface->minLod; } } } if (render_count > surface->numVerts) { render_count = surface->numVerts; } RB_CheckOverflow(render_count, surface->numTriangles); //DBG_SHOWTIME // setup triangle list RB_CheckOverflow(surface->numVerts, surface->numTriangles * 3); //DBG_SHOWTIME collapse_map = ( int * )(( byte * )surface + surface->ofsCollapseMap); triangles = ( int * )((byte *)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; oldIndexes = baseIndex; tess.numVertexes += render_count; pIndexes = &tess.indexes[baseIndex]; //DBG_SHOWTIME if (render_count == surface->numVerts) { memcpy(pIndexes, triangles, sizeof(triangles[0]) * indexes); if (baseVertex) { glIndex_t *indexesEnd; for (indexesEnd = pIndexes + indexes ; pIndexes < indexesEnd ; pIndexes++) { *pIndexes += baseVertex; } } tess.numIndexes += indexes; } else { int *collapseEnd; pCollapse = collapse; for (j = 0; j < render_count; pCollapse++, j++) { *pCollapse = j; } pCollapseMap = &collapse_map[render_count]; for (collapseEnd = collapse + surface->numVerts ; pCollapse < collapseEnd; pCollapse++, pCollapseMap++) { *pCollapse = collapse[*pCollapseMap]; } for (j = 0 ; j < indexes ; j += 3) { p0 = collapse[*(triangles++)]; p1 = collapse[*(triangles++)]; p2 = collapse[*(triangles++)]; // FIXME // note: serious optimization opportunity here, // by sorting the triangles the following "continue" // could have been made into a "break" statement. if (p0 == p1 || p1 == p2 || p2 == p0) { continue; } *(pIndexes++) = baseVertex + p0; *(pIndexes++) = baseVertex + p1; *(pIndexes++) = baseVertex + p2; tess.numIndexes += 3; } baseIndex = tess.numIndexes; } //DBG_SHOWTIME // deform the vertexes by the lerped bones numVerts = surface->numVerts; v = ( mdsVertex_t * )((byte *)surface + surface->ofsVerts); tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); for (j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4) { mdsWeight_t *w; VectorClear(tempVert); w = v->weights; for (k = 0 ; k < v->numWeights ; k++, w++) { bone = &bones[w->boneIndex]; LocalAddScaledMatrixTransformVectorTranslate(w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert); } LocalMatrixTransformVector(v->normal, bones[v->weights[0].boneIndex].matrix, tempNormal); tess.texCoords0[baseVertex + j].v[0] = v->texCoords[0]; tess.texCoords0[baseVertex + j].v[1] = v->texCoords[1]; v = (mdsVertex_t *)&v->weights[v->numWeights]; } DBG_SHOWTIME if (r_bonesDebug->integer) { if (r_bonesDebug->integer < 3) { int i; // DEBUG: show the bones as a stick figure with axis at each bone boneRefs = ( int * )((byte *)surface + surface->ofsBoneReferences); for (i = 0; i < surface->numBoneReferences; i++, boneRefs++) { bonePtr = &bones[*boneRefs]; GL_Bind(tr.whiteImage); qglLineWidth(1); qglBegin(GL_LINES); for (j = 0; j < 3; j++) { VectorClear(vec); vec[j] = 1; qglColor3fv(vec); qglVertex3fv(bonePtr->translation); VectorMA(bonePtr->translation, 5, bonePtr->matrix[j], vec); qglVertex3fv(vec); } qglEnd(); // connect to our parent if it's valid if (validBones[boneInfo[*boneRefs].parent]) { qglLineWidth(2); qglBegin(GL_LINES); qglColor3f(.6, .6, .6); qglVertex3fv(bonePtr->translation); qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation); qglEnd(); } qglLineWidth(1); } } if (r_bonesDebug->integer == 3 || r_bonesDebug->integer == 4) { int render_indexes = (tess.numIndexes - oldIndexes); // show mesh edges tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); GL_Bind(tr.whiteImage); qglLineWidth(1); qglBegin(GL_LINES); qglColor3f(.0, .0, .8); pIndexes = &tess.indexes[oldIndexes]; for (j = 0; j < render_indexes / 3; j++, pIndexes += 3) { qglVertex3fv(tempVert + 4 * pIndexes[0]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[0]); } qglEnd(); // track debug stats if (r_bonesDebug->integer == 4) { totalrv += render_count; totalrt += render_indexes / 3; totalv += surface->numVerts; totalt += surface->numTriangles; } if (r_bonesDebug->integer == 3) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles, ( float )(100.0 * render_indexes / 3) / (float) surface->numTriangles); } } } if (r_bonesDebug->integer > 1) { // dont draw the actual surface tess.numIndexes = oldIndexes; tess.numVertexes = baseVertex; return; } #ifdef DBG_PROFILE_BONES Ren_Print("\n"); #endif }
static inline void RB_BlurGlowTexture() { qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); // Go into orthographic 2d mode. qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglOrtho(0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight, 0, -1, 1); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglLoadIdentity(); GL_State(GLS_DEPTHTEST_DISABLE); ///////////////////////////////////////////////////////// // Setup vertex and pixel programs. ///////////////////////////////////////////////////////// // NOTE: The 0.25 is because we're blending 4 textures (so = 1.0) and we want a relatively normalized pixel // intensity distribution, but this won't happen anyways if intensity is higher than 1.0. float fBlurDistribution = r_DynamicGlowIntensity->value * 0.25f; float fBlurWeight[4] = { fBlurDistribution, fBlurDistribution, fBlurDistribution, 1.0f }; // Enable and set the Vertex Program. qglEnable( GL_VERTEX_PROGRAM_ARB ); qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, tr.glowVShader ); // Apply Pixel Shaders. if ( qglCombinerParameterfvNV ) { BeginPixelShader( GL_REGISTER_COMBINERS_NV, tr.glowPShader ); // Pass the blur weight to the regcom. qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, (float*)&fBlurWeight ); } else if ( qglProgramEnvParameter4fARB ) { BeginPixelShader( GL_FRAGMENT_PROGRAM_ARB, tr.glowPShader ); // Pass the blur weight to the Fragment Program. qglProgramEnvParameter4fARB( GL_FRAGMENT_PROGRAM_ARB, 0, fBlurWeight[0], fBlurWeight[1], fBlurWeight[2], fBlurWeight[3] ); } ///////////////////////////////////////////////////////// // Set the blur texture to the 4 texture stages. ///////////////////////////////////////////////////////// // How much to offset each texel by. float fTexelWidthOffset = 0.1f, fTexelHeightOffset = 0.1f; GLuint uiTex = tr.screenGlow; qglActiveTextureARB( GL_TEXTURE3_ARB ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE2_ARB ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE1_ARB ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB(GL_TEXTURE0_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); ///////////////////////////////////////////////////////// // Draw the blur passes (each pass blurs it more, increasing the blur radius ). ///////////////////////////////////////////////////////// //int iTexWidth = backEnd.viewParms.viewportWidth, iTexHeight = backEnd.viewParms.viewportHeight; int iTexWidth = glConfig.vidWidth, iTexHeight = glConfig.vidHeight; for ( int iNumBlurPasses = 0; iNumBlurPasses < r_DynamicGlowPasses->integer; iNumBlurPasses++ ) { // Load the Texel Offsets into the Vertex Program. qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 0, -fTexelWidthOffset, -fTexelWidthOffset, 0.0f, 0.0f ); qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 1, -fTexelWidthOffset, fTexelWidthOffset, 0.0f, 0.0f ); qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 2, fTexelWidthOffset, -fTexelWidthOffset, 0.0f, 0.0f ); qglProgramEnvParameter4fARB( GL_VERTEX_PROGRAM_ARB, 3, fTexelWidthOffset, fTexelWidthOffset, 0.0f, 0.0f ); // After first pass put the tex coords to the viewport size. if ( iNumBlurPasses == 1 ) { if ( !g_bTextureRectangleHack ) { iTexWidth = backEnd.viewParms.viewportWidth; iTexHeight = backEnd.viewParms.viewportHeight; } uiTex = tr.blurImage; qglActiveTextureARB( GL_TEXTURE3_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE2_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB( GL_TEXTURE1_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglActiveTextureARB(GL_TEXTURE0_ARB ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); // Copy the current image over. qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, uiTex ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); } // Draw the fullscreen quad. qglBegin( GL_QUADS ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0, iTexHeight ); qglVertex2f( 0, 0 ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0, 0 ); qglVertex2f( 0, backEnd.viewParms.viewportHeight ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, iTexWidth, 0 ); qglVertex2f( backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglMultiTexCoord2fARB( GL_TEXTURE0_ARB, iTexWidth, iTexHeight ); qglVertex2f( backEnd.viewParms.viewportWidth, 0 ); qglEnd(); qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.blurImage ); qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); // Increase the texel offsets. // NOTE: This is possibly the most important input to the effect. Even by using an exponential function I've been able to // make it look better (at a much higher cost of course). This is cheap though and still looks pretty great. In the future // I might want to use an actual gaussian equation to correctly calculate the pixel coefficients and attenuates, texel // offsets, gaussian amplitude and radius... fTexelWidthOffset += r_DynamicGlowDelta->value; fTexelHeightOffset += r_DynamicGlowDelta->value; } // Disable multi-texturing. qglActiveTextureARB( GL_TEXTURE3_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglActiveTextureARB( GL_TEXTURE2_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglActiveTextureARB( GL_TEXTURE1_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglActiveTextureARB(GL_TEXTURE0_ARB ); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); qglDisable( GL_VERTEX_PROGRAM_ARB ); EndPixelShader(); qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglPopMatrix(); qglDisable( GL_BLEND ); glState.currenttmu = 0; //this matches the last one we activated }
/** * @brief Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. * Used for cinematics. * * @param[in] x * @param[in] y * @param[in] w * @param[in] h * @param[in] cols * @param[in] rows * @param[in] data * @param[in] client * @param[in] dirty * * @todo FIXME: not exactly backend */ 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; if (!tr.registered) { return; } R_IssuePendingRenderCommands(); // we definately want to sync every frame for the cinematics qglFinish(); start = 0; if (r_speeds->integer) { start = ri.Milliseconds(); } if (!GL_ARB_texture_non_power_of_two) { // 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) { Ren_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, 3, 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) { int end = ri.Milliseconds(); Ren_Print("qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start); } RB_SetGL2D(); 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(); }
// Draw the glow blur over the screen additively. static inline void RB_DrawGlowOverlay() { qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); // Go into orthographic 2d mode. qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglOrtho(0, glConfig.vidWidth, glConfig.vidHeight, 0, -1, 1); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglLoadIdentity(); GL_State(GLS_DEPTHTEST_DISABLE); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_EXT ); // For debug purposes. if ( r_DynamicGlow->integer != 2 ) { // Render the normal scene texture. qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.sceneImage ); qglBegin(GL_QUADS); qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); qglTexCoord2f( 0, glConfig.vidHeight ); qglVertex2f( 0, 0 ); qglTexCoord2f( 0, 0 ); qglVertex2f( 0, glConfig.vidHeight ); qglTexCoord2f( glConfig.vidWidth, 0 ); qglVertex2f( glConfig.vidWidth, glConfig.vidHeight ); qglTexCoord2f( glConfig.vidWidth, glConfig.vidHeight ); qglVertex2f( glConfig.vidWidth, 0 ); qglEnd(); } // One and Inverse Src Color give a very soft addition, while one one is a bit stronger. With one one we can // use additive blending through multitexture though. if ( r_DynamicGlowSoft->integer ) { qglBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR ); } else { qglBlendFunc( GL_ONE, GL_ONE ); } qglEnable( GL_BLEND ); // Now additively render the glow texture. qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.blurImage ); qglBegin(GL_QUADS); qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); qglTexCoord2f( 0, r_DynamicGlowHeight->integer ); qglVertex2f( 0, 0 ); qglTexCoord2f( 0, 0 ); qglVertex2f( 0, glConfig.vidHeight ); qglTexCoord2f( r_DynamicGlowWidth->integer, 0 ); qglVertex2f( glConfig.vidWidth, glConfig.vidHeight ); qglTexCoord2f( r_DynamicGlowWidth->integer, r_DynamicGlowHeight->integer ); qglVertex2f( glConfig.vidWidth, 0 ); qglEnd(); qglDisable( GL_TEXTURE_RECTANGLE_EXT ); qglEnable( GL_TEXTURE_2D ); qglBlendFunc( GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR ); qglDisable( GL_BLEND ); qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglPopMatrix(); }
/* ================== RB_STD_LightScale Perform extra blending passes to multiply the entire buffer by a floating point value ================== */ void RB_STD_LightScale(void) { float v, f; if (backEnd.overBright == 1.0f) { return; } if (r_skipLightScale.GetBool()) { return; } RB_LogComment("---------- RB_STD_LightScale ----------\n"); // the scissor may be smaller than the viewport for subviews if (r_useScissor.GetBool()) { qglScissor(backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1, backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1, backEnd.viewDef->scissor.x2 - backEnd.viewDef->scissor.x1 + 1, backEnd.viewDef->scissor.y2 - backEnd.viewDef->scissor.y1 + 1); backEnd.currentScissor = backEnd.viewDef->scissor; } // full screen blends qglLoadIdentity(); qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglOrtho(0, 1, 0, 1, -1, 1); GL_State(GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR); GL_Cull(CT_TWO_SIDED); // so mirror views also get it globalImages->BindNull(); qglDisable(GL_DEPTH_TEST); qglDisable(GL_STENCIL_TEST); v = 1; while (idMath::Fabs(v - backEnd.overBright) > 0.01) { // a little extra slop f = backEnd.overBright / v; f /= 2; if (f > 1) { f = 1; } qglColor3f(f, f, f); v = v * f * 2; qglBegin(GL_QUADS); qglVertex2f(0,0); qglVertex2f(0,1); qglVertex2f(1,1); qglVertex2f(1,0); qglEnd(); } qglPopMatrix(); qglEnable(GL_DEPTH_TEST); qglMatrixMode(GL_MODELVIEW); GL_Cull(CT_FRONT_SIDED); }
/* ==================== BuildOptTriangles Generate a new list of triangles from the optEdeges ==================== */ static void BuildOptTriangles( optIsland_t *island ) { optVertex_t *ov, *second, *third, *middle; optEdge_t *e1, *e1Next, *e2, *e2Next, *check, *checkNext; // free them FreeOptTriangles( island ); // clear the vertex emitted flags for ( ov = island->verts ; ov ; ov = ov->islandLink ) { ov->emited = false; } // clear the edge triangle links for ( check = island->edges ; check ; check = check->islandLink ) { check->frontTri = check->backTri = NULL; } // check all possible triangle made up out of the // edges coming off the vertex for ( ov = island->verts ; ov ; ov = ov->islandLink ) { if ( !ov->edges ) { continue; } #if 0 if ( dmapGlobals.drawflag && ov == (optVertex_t *)0x1845a60 ) { for ( e1 = ov->edges ; e1 ; e1 = e1Next ) { qglBegin( GL_LINES ); qglColor3f( 0,1,0 ); qglVertex3fv( e1->v1->pv.ToFloatPtr() ); qglVertex3fv( e1->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); if ( e1->v1 == ov ) { e1Next = e1->v1link; } else if ( e1->v2 == ov ) { e1Next = e1->v2link; } } } #endif for ( e1 = ov->edges ; e1 ; e1 = e1Next ) { if ( e1->v1 == ov ) { second = e1->v2; e1Next = e1->v1link; } else if ( e1->v2 == ov ) { second = e1->v1; e1Next = e1->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } // if the vertex has already been used, it can't be used again if ( second->emited ) { continue; } for ( e2 = ov->edges ; e2 ; e2 = e2Next ) { if ( e2->v1 == ov ) { third = e2->v2; e2Next = e2->v1link; } else if ( e2->v2 == ov ) { third = e2->v1; e2Next = e2->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } if ( e2 == e1 ) { continue; } // if the vertex has already been used, it can't be used again if ( third->emited ) { continue; } // if the triangle is backwards or degenerate, don't use it if ( !IsTriangleValid( ov, second, third ) ) { continue; } // see if any other edge bisects these two, which means // this triangle shouldn't be used for ( check = ov->edges ; check ; check = checkNext ) { if ( check->v1 == ov ) { middle = check->v2; checkNext = check->v1link; } else if ( check->v2 == ov ) { middle = check->v1; checkNext = check->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } if ( check == e1 || check == e2 ) { continue; } if ( IsTriangleValid( ov, second, middle ) && IsTriangleValid( ov, middle, third ) ) { break; // should use the subdivided ones } } if ( check ) { continue; // don't use it } // the triangle is valid CreateOptTri( ov, e1, e2, island ); } } // later vertexes will not emit triangles that use an // edge that this vert has already used ov->emited = true; } }
/* * Interpolates between two frames and origins */ void R_DrawAliasFrameLerp ( dmdl_t *paliashdr, float backlerp ) { #if defined(VERTEX_ARRAYS) uint16_t total; GLenum type; #endif float l; daliasframe_t *frame, *oldframe; dtrivertx_t *v, *ov, *verts; int *order; int count; float frontlerp; float alpha; vec3_t move, delta, vectors [ 3 ]; vec3_t frontv, backv; int i; int index_xyz; float *lerp; frame = (daliasframe_t *) ( (byte *) paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize ); verts = v = frame->verts; oldframe = (daliasframe_t *) ( (byte *) paliashdr + paliashdr->ofs_frames + currententity->oldframe * paliashdr->framesize ); ov = oldframe->verts; order = (int *) ( (byte *) paliashdr + paliashdr->ofs_glcmds ); if ( currententity->flags & RF_TRANSLUCENT ) { alpha = currententity->alpha; } else { alpha = 1.0; } if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM ) ) { qglDisable( GL_TEXTURE_2D ); } frontlerp = 1.0 - backlerp; /* move should be the delta back to the previous frame * backlerp */ VectorSubtract( currententity->oldorigin, currententity->origin, delta ); AngleVectors( currententity->angles, vectors [ 0 ], vectors [ 1 ], vectors [ 2 ] ); move [ 0 ] = DotProduct( delta, vectors [ 0 ] ); /* forward */ move [ 1 ] = -DotProduct( delta, vectors [ 1 ] ); /* left */ move [ 2 ] = DotProduct( delta, vectors [ 2 ] ); /* up */ VectorAdd( move, oldframe->translate, move ); for ( i = 0; i < 3; i++ ) { move [ i ] = backlerp * move [ i ] + frontlerp * frame->translate [ i ]; } for ( i = 0; i < 3; i++ ) { frontv [ i ] = frontlerp * frame->scale [ i ]; backv [ i ] = backlerp * oldframe->scale [ i ]; } lerp = s_lerped [ 0 ]; R_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv ); if ( gl_vertex_arrays->value ) { float colorArray [ MAX_VERTS * 4 ]; qglEnableClientState( GL_VERTEX_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 16, s_lerped ); if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM ) ) { qglColor4f( shadelight [ 0 ], shadelight [ 1 ], shadelight [ 2 ], alpha ); } else { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 3, GL_FLOAT, 0, colorArray ); /* pre light everything */ for ( i = 0; i < paliashdr->num_xyz; i++ ) { float l = shadedots [ verts [ i ].lightnormalindex ]; colorArray [ i * 3 + 0 ] = l * shadelight [ 0 ]; colorArray [ i * 3 + 1 ] = l * shadelight [ 1 ]; colorArray [ i * 3 + 2 ] = l * shadelight [ 2 ]; } } #if !defined(VERTEX_ARRAYS) if ( qglLockArraysEXT != 0 ) { qglLockArraysEXT( 0, paliashdr->num_xyz ); } #endif while ( 1 ) { /* get the vertex count and primitive type */ count = *order++; if ( !count ) { break; /* done */ } if ( count < 0 ) { count = -count; #if defined(VERTEX_ARRAYS) type = GL_TRIANGLE_FAN; #else qglBegin( GL_TRIANGLE_FAN ); #endif } else { #if defined(VERTEX_ARRAYS) type = GL_TRIANGLE_STRIP; #else qglBegin( GL_TRIANGLE_STRIP ); #endif } #if defined(VERTEX_ARRAYS) total = count; GLfloat vtx[3*total]; GLfloat tex[2*total]; uint32_t index_vtx = 0; uint32_t index_tex = 0; #endif if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM ) ) { do { index_xyz = order [ 2 ]; order += 3; #if defined(VERTEX_ARRAYS) vtx[index_vtx++] = s_lerped [ index_xyz ][0]; vtx[index_vtx++] = s_lerped [ index_xyz ][1]; vtx[index_vtx++] = s_lerped [ index_xyz ][2]; #else qglVertex3fv( s_lerped [ index_xyz ] ); #endif } while ( --count ); } else { do { #if defined(VERTEX_ARRAYS) tex[index_tex++] = ( (float *) order ) [ 0 ]; tex[index_tex++] = ( (float *) order ) [ 1 ]; index_xyz = order [ 2 ]; order += 3; #else /* texture coordinates come from the draw list */ qglTexCoord2f( ( (float *) order ) [ 0 ], ( (float *) order ) [ 1 ] ); index_xyz = order [ 2 ]; order += 3; qglArrayElement( index_xyz ); #endif } while ( --count ); } #if defined(VERTEX_ARRAYS) qglEnableClientState( GL_VERTEX_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 0, vtx ); qglDrawArrays( type, 0, total ); qglDisableClientState( GL_VERTEX_ARRAY ); #else qglEnd(); #endif } #if !defined(VERTEX_ARRAYS) if ( qglUnlockArraysEXT != 0 ) { qglUnlockArraysEXT(); } #endif } else { while ( 1 ) { /* get the vertex count and primitive type */ count = *order++; if ( !count ) { break; /* done */ } if ( count < 0 ) { count = -count; #if defined(VERTEX_ARRAYS) type = GL_TRIANGLE_FAN; #else qglBegin( GL_TRIANGLE_FAN ); #endif } else { #if defined(VERTEX_ARRAYS) type = GL_TRIANGLE_STRIP; #else qglBegin( GL_TRIANGLE_STRIP ); #endif } #if defined(VERTEX_ARRAYS) total = count; GLfloat vtx[3*total]; GLfloat tex[2*total]; GLfloat clr[4*total]; uint32_t index_vtx = 0; uint32_t index_tex = 0; uint32_t index_clr = 0; #endif if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) { do { index_xyz = order [ 2 ]; order += 3; #if defined(VERTEX_ARRAYS) clr[index_clr++] = shadelight [ 0 ]; clr[index_clr++] = shadelight [ 1 ]; clr[index_clr++] = shadelight [ 2 ]; clr[index_clr++] = alpha; vtx[index_vtx++] = s_lerped [ index_xyz ][ 0 ]; vtx[index_vtx++] = s_lerped [ index_xyz ][ 1 ]; vtx[index_vtx++] = s_lerped [ index_xyz ][ 2 ]; #else qglColor4f( shadelight [ 0 ], shadelight [ 1 ], shadelight [ 2 ], alpha ); qglVertex3fv( s_lerped [ index_xyz ] ); #endif } while ( --count ); } else { do { /* texture coordinates come from the draw list */ #if defined(VERTEX_ARRAYS) tex[index_tex++] = ( (float *) order ) [ 0 ]; tex[index_tex++] = ( (float *) order ) [ 1 ]; #else qglTexCoord2f( ( (float *) order ) [ 0 ], ( (float *) order ) [ 1 ] ); #endif index_xyz = order [ 2 ]; order += 3; /* normals and vertexes come from the frame list */ l = shadedots [ verts [ index_xyz ].lightnormalindex ]; #if defined(VERTEX_ARRAYS) clr[index_clr++] = l * shadelight [ 0 ]; clr[index_clr++] = l * shadelight [ 1 ]; clr[index_clr++] = l * shadelight [ 2 ]; clr[index_clr++] = alpha; vtx[index_vtx++] = s_lerped [ index_xyz ][ 0 ]; vtx[index_vtx++] = s_lerped [ index_xyz ][ 1 ]; vtx[index_vtx++] = s_lerped [ index_xyz ][ 2 ]; #else qglColor4f( l * shadelight [ 0 ], l * shadelight [ 1 ], l * shadelight [ 2 ], alpha ); qglVertex3fv( s_lerped [ index_xyz ] ); #endif } while ( --count ); } #if defined(VERTEX_ARRAYS) qglEnableClientState( GL_VERTEX_ARRAY ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnableClientState( GL_COLOR_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 0, vtx ); qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglColorPointer( 4, GL_FLOAT, 0, clr ); qglDrawArrays( type, 0, total ); qglDisableClientState( GL_VERTEX_ARRAY ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); qglDisableClientState( GL_COLOR_ARRAY ); #else qglEnd(); #endif } } if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM ) ) { qglEnable( GL_TEXTURE_2D ); } }
/* ===================== SplitOriginalEdgesAtCrossings ===================== */ void SplitOriginalEdgesAtCrossings( optimizeGroup_t *opt ) { int i, j, k, l; int numOriginalVerts; edgeCrossing_t **crossings; numOriginalVerts = numOptVerts; // now split any crossing edges and create optEdges // linked to the vertexes // debug drawing bounds dmapGlobals.drawBounds = optBounds; dmapGlobals.drawBounds[0][0] -= 2; dmapGlobals.drawBounds[0][1] -= 2; dmapGlobals.drawBounds[1][0] += 2; dmapGlobals.drawBounds[1][1] += 2; // generate crossing points between all the original edges crossings = (edgeCrossing_t **)Mem_ClearedAlloc( numOriginalEdges * sizeof( *crossings ), TAG_DMAP ); for ( i = 0 ; i < numOriginalEdges ; i++ ) { if ( dmapGlobals.drawflag ) { DrawOriginalEdges( numOriginalEdges, originalEdges ); qglBegin( GL_LINES ); qglColor3f( 0, 1, 0 ); qglVertex3fv( originalEdges[i].v1->pv.ToFloatPtr() ); qglColor3f( 0, 0, 1 ); qglVertex3fv( originalEdges[i].v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } for ( j = i+1 ; j < numOriginalEdges ; j++ ) { optVertex_t *v1, *v2, *v3, *v4; optVertex_t *newVert; edgeCrossing_t *cross; v1 = originalEdges[i].v1; v2 = originalEdges[i].v2; v3 = originalEdges[j].v1; v4 = originalEdges[j].v2; if ( !EdgesCross( v1, v2, v3, v4 ) ) { continue; } // this is the only point in optimization where // completely new points are created, and it only // happens if there is overlapping coplanar // geometry in the source triangles newVert = EdgeIntersection( v1, v2, v3, v4, opt ); if ( !newVert ) { //common->Printf( "lines %i (%i to %i) and %i (%i to %i) are colinear\n", i, v1 - optVerts, v2 - optVerts, // j, v3 - optVerts, v4 - optVerts ); // !@# // colinear, so add both verts of each edge to opposite if ( VertexBetween( v3, v1, v2 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v3; cross->next = crossings[i]; crossings[i] = cross; } if ( VertexBetween( v4, v1, v2 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v4; cross->next = crossings[i]; crossings[i] = cross; } if ( VertexBetween( v1, v3, v4 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v1; cross->next = crossings[j]; crossings[j] = cross; } if ( VertexBetween( v2, v3, v4 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v2; cross->next = crossings[j]; crossings[j] = cross; } continue; } #if 0 if ( newVert && newVert != v1 && newVert != v2 && newVert != v3 && newVert != v4 ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) cross at new point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } else if ( newVert ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) intersect at old point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } #endif if ( newVert != v1 && newVert != v2 ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = newVert; cross->next = crossings[i]; crossings[i] = cross; } if ( newVert != v3 && newVert != v4 ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = newVert; cross->next = crossings[j]; crossings[j] = cross; } } } // now split each edge by its crossing points // colinear edges will have duplicated edges added, but it won't hurt anything for ( i = 0 ; i < numOriginalEdges ; i++ ) { edgeCrossing_t *cross, *nextCross; int numCross; optVertex_t **sorted; numCross = 0; for ( cross = crossings[i] ; cross ; cross = cross->next ) { numCross++; } numCross += 2; // account for originals sorted = (optVertex_t **)Mem_Alloc( numCross * sizeof( *sorted ), TAG_DMAP ); sorted[0] = originalEdges[i].v1; sorted[1] = originalEdges[i].v2; j = 2; for ( cross = crossings[i] ; cross ; cross = nextCross ) { nextCross = cross->next; sorted[j] = cross->ov; Mem_Free( cross ); j++; } // add all possible fragment combinations that aren't divided // by another point for ( j = 0 ; j < numCross ; j++ ) { for ( k = j+1 ; k < numCross ; k++ ) { for ( l = 0 ; l < numCross ; l++ ) { if ( sorted[l] == sorted[j] || sorted[l] == sorted[k] ) { continue; } if ( sorted[j] == sorted[k] ) { continue; } if ( VertexBetween( sorted[l], sorted[j], sorted[k] ) ) { break; } } if ( l == numCross ) { //common->Printf( "line %i fragment from point %i to %i\n", i, sorted[j] - optVerts, sorted[k] - optVerts ); AddEdgeIfNotAlready( sorted[j], sorted[k] ); } } } Mem_Free( sorted ); } Mem_Free( crossings ); Mem_Free( originalEdges ); // check for duplicated edges for ( i = 0 ; i < numOptEdges ; i++ ) { for ( j = i+1 ; j < numOptEdges ; j++ ) { if ( ( optEdges[i].v1 == optEdges[j].v1 && optEdges[i].v2 == optEdges[j].v2 ) || ( optEdges[i].v1 == optEdges[j].v2 && optEdges[i].v2 == optEdges[j].v1 ) ) { common->Printf( "duplicated optEdge\n" ); } } } if ( dmapGlobals.verbose ) { common->Printf( "%6i original edges\n", numOriginalEdges ); common->Printf( "%6i edges after splits\n", numOptEdges ); common->Printf( "%6i original vertexes\n", numOriginalVerts ); common->Printf( "%6i vertexes after splits\n", numOptVerts ); } }
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 }
static void RemoveIfColinear( optVertex_t *ov, optIsland_t *island ) { optEdge_t *e, *e1, *e2; optVertex_t *v1, *v2, *v3; idVec3 dir1, dir2; float dist; idVec3 point; idVec3 offset; float off; v2 = ov; // we must find exactly two edges before testing for colinear e1 = NULL; e2 = NULL; for ( e = ov->edges ; e ; ) { if ( !e1 ) { e1 = e; } else if ( !e2 ) { e2 = e; } else { return; // can't remove a vertex with three edges } if ( e->v1 == v2 ) { e = e->v1link; } else if ( e->v2 == v2 ) { e = e->v2link; } else { common->Error( "RemoveIfColinear: mislinked edge" ); return; } } // can't remove if no edges if ( !e1 ) { return; } if ( !e2 ) { // this may still happen legally when a tiny triangle is // the only thing in a group common->Printf( "WARNING: vertex with only one edge\n" ); return; } if ( e1->v1 == v2 ) { v1 = e1->v2; } else if ( e1->v2 == v2 ) { v1 = e1->v1; } else { common->Error( "RemoveIfColinear: mislinked edge" ); return; } if ( e2->v1 == v2 ) { v3 = e2->v2; } else if ( e2->v2 == v2 ) { v3 = e2->v1; } else { common->Error( "RemoveIfColinear: mislinked edge" ); return; } if ( v1 == v3 ) { common->Error( "RemoveIfColinear: mislinked edge" ); return; } // they must point in opposite directions dist = ( v3->pv - v2->pv ) * ( v1->pv - v2->pv ); if ( dist >= 0 ) { return; } // see if they are colinear VectorSubtract( v3->v.xyz, v1->v.xyz, dir1 ); dir1.Normalize(); VectorSubtract( v2->v.xyz, v1->v.xyz, dir2 ); dist = DotProduct( dir2, dir1 ); VectorMA( v1->v.xyz, dist, dir1, point ); VectorSubtract( point, v2->v.xyz, offset ); off = offset.Length(); if ( off > COLINEAR_EPSILON ) { return; } if ( dmapGlobals.drawflag ) { qglBegin( GL_LINES ); qglColor3f( 1, 1, 0 ); qglVertex3fv( v1->pv.ToFloatPtr() ); qglVertex3fv( v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); qglBegin( GL_LINES ); qglColor3f( 0, 1, 1 ); qglVertex3fv( v2->pv.ToFloatPtr() ); qglVertex3fv( v3->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // replace the two edges with a single edge UnlinkEdge( e1, island ); UnlinkEdge( e2, island ); // v2 should have no edges now if ( v2->edges ) { common->Error( "RemoveIfColinear: didn't remove properly" ); return; } // if there is an existing edge that already // has these exact verts, we have just collapsed a // sliver triangle out of existance, and all the edges // can be removed for ( e = island->edges ; e ; e = e->islandLink ) { if ( ( e->v1 == v1 && e->v2 == v3 ) || ( e->v1 == v3 && e->v2 == v1 ) ) { UnlinkEdge( e, island ); RemoveIfColinear( v1, island ); RemoveIfColinear( v3, island ); return; } } // if we can't add the combined edge, link // the originals back in if ( !TryAddNewEdge( v1, v3, island ) ) { e1->islandLink = island->edges; island->edges = e1; LinkEdge( e1 ); e2->islandLink = island->edges; island->edges = e2; LinkEdge( e2 ); return; } // recursively try to combine both verts now, // because things may have changed since the last combine test RemoveIfColinear( v1, island ); RemoveIfColinear( v3, island ); }
static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) { int i; int last[3] = { -1, -1, -1 }; qboolean even; c_begins++; if ( numIndexes <= 0 ) { return; } qglBegin( GL_TRIANGLE_STRIP ); // prime the strip element( indexes[0] ); element( indexes[1] ); element( indexes[2] ); c_vertexes += 3; last[0] = indexes[0]; last[1] = indexes[1]; last[2] = indexes[2]; even = qfalse; for ( i = 3; i < numIndexes; i += 3 ) { // odd numbered triangle in potential strip if ( !even ) { // check previous triangle to see if we're continuing a strip if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) ) { element( indexes[i+2] ); c_vertexes++; assert( indexes[i+2] < tess.numVertexes ); even = qtrue; } // otherwise we're done with this strip so finish it and start // a new one else { qglEnd(); qglBegin( GL_TRIANGLE_STRIP ); c_begins++; element( indexes[i+0] ); element( indexes[i+1] ); element( indexes[i+2] ); c_vertexes += 3; even = qfalse; } } else { // check previous triangle to see if we're continuing a strip if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) ) { element( indexes[i+2] ); c_vertexes++; even = qfalse; } // otherwise we're done with this strip so finish it and start // a new one else { qglEnd(); qglBegin( GL_TRIANGLE_STRIP ); c_begins++; element( indexes[i+0] ); element( indexes[i+1] ); element( indexes[i+2] ); c_vertexes += 3; even = qfalse; } } // cache the last three vertices last[0] = indexes[i+0]; last[1] = indexes[i+1]; last[2] = indexes[i+2]; } qglEnd(); }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i; dmdl_t *paliashdr; float an; vec3_t bbox[8]; image_t *skin; if ( !( e->flags & RF_WEAPONMODEL ) ) { if ( R_CullAliasModel( bbox, e ) ) return; } if ( e->flags & RF_WEAPONMODEL ) { if ( r_lefthand->value == 2 ) return; } paliashdr = (dmdl_t *)currentmodel->extradata; // // get lighting information // // PMM - rewrote, reordered to handle new shells & mixing // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy // if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if (currententity->flags & RF_SHELL_HALF_DAM) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } if ( currententity->flags & RF_SHELL_RED ) shadelight[0] = 1.0; if ( currententity->flags & RF_SHELL_GREEN ) shadelight[1] = 1.0; if ( currententity->flags & RF_SHELL_BLUE ) shadelight[2] = 1.0; } /* // PMM -special case for godmode if ( (currententity->flags & RF_SHELL_RED) && (currententity->flags & RF_SHELL_BLUE) && (currententity->flags & RF_SHELL_GREEN) ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if ( currententity->flags & RF_SHELL_RED ) { shadelight[0] = 1.0; if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) ) shadelight[2] = 1.0; } else if ( currententity->flags & RF_SHELL_BLUE ) { if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[1] = 1.0; shadelight[2] = 1.0; } else { shadelight[2] = 1.0; } } else if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } } else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) ) { VectorClear (shadelight); // PMM - new colors if ( currententity->flags & RF_SHELL_HALF_DAM ) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_GREEN ) { shadelight[1] = 1.0; } } } //PMM - ok, now flatten these down to range from 0 to 1.0. // max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2])); // if (max_shell_val > 0) // { // for (i=0; i<3; i++) // { // shadelight[i] = shadelight[i] / max_shell_val; // } // } // pmm */ else if ( currententity->flags & RF_FULLBRIGHT ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else { R_LightPoint (currententity->origin, shadelight); // player lighting hack for communication back to server // big hack! if ( currententity->flags & RF_WEAPONMODEL ) { // pick the greatest component, which should be the same // as the mono value returned by software if (shadelight[0] > shadelight[1]) { if (shadelight[0] > shadelight[2]) r_lightlevel->value = 150*shadelight[0]; else r_lightlevel->value = 150*shadelight[2]; } else { if (shadelight[1] > shadelight[2]) r_lightlevel->value = 150*shadelight[1]; else r_lightlevel->value = 150*shadelight[2]; } } if ( gl_monolightmap->string[0] != '0' ) { float s = shadelight[0]; if ( s < shadelight[1] ) s = shadelight[1]; if ( s < shadelight[2] ) s = shadelight[2]; shadelight[0] = s; shadelight[1] = s; shadelight[2] = s; } } if ( currententity->flags & RF_MINLIGHT ) { for (i=0 ; i<3 ; i++) if (shadelight[i] > 0.1) break; if (i == 3) { shadelight[0] = 0.1; shadelight[1] = 0.1; shadelight[2] = 0.1; } } if ( currententity->flags & RF_GLOW ) { // bonus items will pulse with time float scale; float min; scale = 0.1 * sin(r_newrefdef.time*7); for (i=0 ; i<3 ; i++) { min = shadelight[i] * 0.8; shadelight[i] += scale; if (shadelight[i] < min) shadelight[i] = min; } } // ================= // PGM ir goggles color override if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) { shadelight[0] = 1.0; shadelight[1] = 0.0; shadelight[2] = 0.0; } // PGM // ================= shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; an = currententity->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // c_alias_polys += paliashdr->num_tris; // // draw all the triangles // if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); qglMatrixMode( GL_PROJECTION ); qglPushMatrix(); qglLoadIdentity(); qglScalef( -1, 1, 1 ); MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_BACK ); } qglPushMatrix (); e->angles[PITCH] = -e->angles[PITCH]; // sigh. e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // Knightmare- roll is backwards R_RotateForEntity (e, true); e->angles[PITCH] = -e->angles[PITCH]; // sigh. e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // Knightmare- roll is backwards // select skin if (currententity->skin) skin = currententity->skin; // custom player skin else { if (currententity->skinnum >= MAX_MD2SKINS) skin = currentmodel->skins[0]; else { skin = currentmodel->skins[currententity->skinnum]; if (!skin) skin = currentmodel->skins[0]; } } if (!skin) skin = r_notexture; // fallback... GL_Bind(skin->texnum); // draw it qglShadeModel (GL_SMOOTH); GL_TexEnv( GL_MODULATE ); if ( currententity->flags & RF_TRANSLUCENT ) { qglEnable (GL_BLEND); } if ( (currententity->frame >= paliashdr->num_frames) || (currententity->frame < 0) ) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame); currententity->frame = 0; currententity->oldframe = 0; } if ( (currententity->oldframe >= paliashdr->num_frames) || (currententity->oldframe < 0)) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe); currententity->frame = 0; currententity->oldframe = 0; } if ( !r_lerpmodels->value ) currententity->backlerp = 0; GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp); GL_TexEnv( GL_REPLACE ); qglShadeModel (GL_FLAT); qglPopMatrix (); //#if 1 if (gl_showbbox->value) // Knightmare- show bbox option { qglColor4f (1.0f, 1.0f, 1.0f, 1.0f); qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDisable( GL_TEXTURE_2D ); /* qglBegin( GL_TRIANGLE_STRIP ); for ( i = 0; i < 8; i++ ) { qglVertex3fv( bbox[i] ); } qglEnd();*/ qglBegin( GL_QUADS ); qglVertex3fv( bbox[0] ); qglVertex3fv( bbox[1] ); qglVertex3fv( bbox[3] ); qglVertex3fv( bbox[2] ); qglVertex3fv( bbox[4] ); qglVertex3fv( bbox[5] ); qglVertex3fv( bbox[7] ); qglVertex3fv( bbox[6] ); qglVertex3fv( bbox[0] ); qglVertex3fv( bbox[1] ); qglVertex3fv( bbox[5] ); qglVertex3fv( bbox[4] ); qglVertex3fv( bbox[2] ); qglVertex3fv( bbox[3] ); qglVertex3fv( bbox[7] ); qglVertex3fv( bbox[6] ); qglEnd(); qglEnable( GL_TEXTURE_2D ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglEnable( GL_CULL_FACE ); } //#endif if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { qglMatrixMode( GL_PROJECTION ); qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_FRONT ); } if ( currententity->flags & RF_TRANSLUCENT ) { qglDisable (GL_BLEND); } if (currententity->flags & RF_DEPTHHACK) qglDepthRange (gldepthmin, gldepthmax); if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL))) { // qglPushMatrix (); // R_RotateForEntity (e, false); // qglDisable (GL_TEXTURE_2D); // qglEnable (GL_BLEND); // qglColor4f (0, 0, 0, gl_shadowalpha->value); // was 0.5 GL_DrawAliasShadow (e, paliashdr, currententity->frame ); // qglEnable (GL_TEXTURE_2D); // qglDisable (GL_BLEND); // qglPopMatrix (); } qglColor4f (1,1,1,1); }