static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) { int s, t; GL_Bind( image ); #ifdef HAVE_GLES GLfloat vtx[3*1024]; // arbitrary sized GLfloat tex[2*1024]; int idx; 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 ); #endif for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) { #ifdef HAVE_GLES idx=0; #else qglBegin( GL_TRIANGLE_STRIP ); #endif for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) { #ifdef HAVE_GLES memcpy(tex+idx*2, s_skyTexCoords[t][s], sizeof(GLfloat)*2); memcpy(vtx+idx*3, s_skyPoints[t][s], sizeof(GLfloat)*3); idx++; memcpy(tex+idx*2, s_skyTexCoords[t+1][s], sizeof(GLfloat)*2); memcpy(vtx+idx*3, s_skyPoints[t+1][s], sizeof(GLfloat)*3); idx++; #else qglTexCoord2fv( s_skyTexCoords[t][s] ); qglVertex3fv( s_skyPoints[t][s] ); qglTexCoord2fv( s_skyTexCoords[t+1][s] ); qglVertex3fv( s_skyPoints[t+1][s] ); #endif } #ifdef HAVE_GLES //*TODO* Try to switch from many DrawArrays of GL_TRIANGLE_STRIP to a single DrawArrays of TRIANGLES to see if it perform better qglVertexPointer (3, GL_FLOAT, 0, vtx); qglTexCoordPointer(2, GL_FLOAT, 0, tex); qglDrawArrays(GL_TRIANGLE_STRIP, 0, idx); #else qglEnd(); #endif } #ifdef HAVE_GLES if (glcol) qglEnableClientState(GL_COLOR_ARRAY); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #endif }
/* ================= 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; } qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_NOTEQUAL, 0, 255); qglDisable(GL_CLIP_PLANE0); qglDisable(GL_CULL_FACE); GL_Bind(tr.whiteImage); qglLoadIdentity(); qglColor3f(0.6f, 0.6f, 0.6f); GL_State(GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); 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); } GLfloat vtx[] = { -100, 100, -10, 100, 100, -10, 100, -100, -10, -100, -100, -10 }; 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); } qglColor4f(1, 1, 1, 1); qglDisable(GL_STENCIL_TEST); }
/* ================= 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 defined(VV_LIGHTING) && defined(_XBOX) StencilShadower.FinishShadows(); #else 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 ); qglBegin( GL_QUADS ); qglVertex3f( -100, 100, -10 ); qglVertex3f( 100, 100, -10 ); qglVertex3f( 100, -100, -10 ); qglVertex3f( -100, -100, -10 ); qglEnd (); qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); if (planeZeroBack) { qglEnable (GL_CLIP_PLANE0); } qglPopMatrix(); #endif // VV_LIGHTING && _XBOX }
static void DrawSkySideInner(struct image_s *image, const int mins[2], const int maxs[2]) { int s, t; GL_Bind(image); GLfloat vtx[3 * 1024]; // arbitrary sized GLfloat tex[2 * 1024]; int idx; 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); } //qglDisable (GL_BLEND); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); for (t = mins[1] + HALF_SKY_SUBDIVISIONS; t < maxs[1] + HALF_SKY_SUBDIVISIONS; t++) { idx = 0; for (s = mins[0] + HALF_SKY_SUBDIVISIONS; s <= maxs[0] + HALF_SKY_SUBDIVISIONS; s++) { memcpy(tex + idx * 2, s_skyTexCoords[t][s], sizeof(GLfloat) * 2); memcpy(vtx + idx * 3, s_skyPoints[t][s], sizeof(GLfloat) * 3); idx++; memcpy(tex + idx * 2, s_skyTexCoords[t + 1][s], sizeof(GLfloat) * 2); memcpy(vtx + idx * 3, s_skyPoints[t + 1][s], sizeof(GLfloat) * 3); idx++; } qglVertexPointer(3, GL_FLOAT, 0, vtx); qglTexCoordPointer(2, GL_FLOAT, 0, tex); qglDrawArrays(GL_TRIANGLE_STRIP, 0, idx); } qglDisable(GL_BLEND); }
/* ================= 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 GLfloat vtx[] = { -100, 100, -10, 100, 100, -10, 100, -100, -10, -100, -100, -10 }; 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, 100, -10 ); qglVertex3f( 100, 100, -10 ); qglVertex3f( 100, -100, -10 ); qglVertex3f( -100, -100, -10 ); qglEnd (); #endif qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); if (planeZeroBack) { qglEnable (GL_CLIP_PLANE0); } qglPopMatrix(); }
void RB_DoShadowTessEnd( vec3_t lightPos ) { int i; int numTris; vec3_t lightDir; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #if 1 //controlled method - try to keep shadows in range so they don't show through so much -rww vec3_t worldxyz; vec3_t entLight; float groundDist; VectorCopy( backEnd.currentEntity->lightDir, entLight ); entLight[2] = 0.0f; VectorNormalize(entLight); //Oh well, just cast them straight down no matter what onto the ground plane. //This presets no chance of screwups and still looks better than a stupid //shader blob. VectorSet(lightDir, entLight[0]*0.3f, entLight[1]*0.3f, 1.0f); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { //add or.origin to vert xyz to end up with world oriented coord, then figure //out the ground pos for the vert to project the shadow volume to VectorAdd(tess.xyz[i], backEnd.ori.origin, worldxyz); groundDist = worldxyz[2] - backEnd.currentEntity->e.shadowPlane; groundDist += 16.0f; //fudge factor VectorMA( tess.xyz[i], -groundDist, lightDir, tess.xyz[i+tess.numVertexes] ); } #else if (lightPos) { for ( i = 0 ; i < tess.numVertexes ; i++ ) { tess.xyz[i+tess.numVertexes][0] = tess.xyz[i][0]+(( tess.xyz[i][0]-lightPos[0] )*128.0f); tess.xyz[i+tess.numVertexes][1] = tess.xyz[i][1]+(( tess.xyz[i][1]-lightPos[1] )*128.0f); tess.xyz[i+tess.numVertexes][2] = tess.xyz[i][2]+(( tess.xyz[i][2]-lightPos[2] )*128.0f); } } else { VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } } #endif // decide which triangles face the light memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; if (!lightPos) { VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); } else { float planeEq[4]; planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]); planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]); planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]); planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) + v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) + v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) ); d = planeEq[0]*lightPos[0]+ planeEq[1]*lightPos[1]+ planeEq[2]*lightPos[2]+ planeEq[3]; } if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } GL_Bind( tr.whiteImage ); //qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); #ifndef _DEBUG_STENCIL_SHADOWS qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); #else qglColor3f( 1.0f, 0.0f, 0.0f ); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //qglDisable(GL_DEPTH_TEST); #endif #ifdef HAVE_GLES GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglDisableClientState( GL_COLOR_ARRAY ); qglVertexPointer (3, GL_FLOAT, 16, tess.xyz); #endif #ifdef _STENCIL_REVERSE qglDepthFunc(GL_LESS); //now using the Carmack Reverse<tm> -rww if ( backEnd.viewParms.isMirror ) { //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } else { //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } qglDepthFunc(GL_LEQUAL); #else // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #else R_RenderShadowEdges(); #endif } #endif // reenable writing to the color buffer qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); #ifdef HAVE_GLES if (text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState( GL_COLOR_ARRAY ); #endif #ifdef _DEBUG_STENCIL_SHADOWS qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif }
static void ProjectDlightTexture( void ) { int i, l; vec3_t origin; float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; int fogging; vec3_t floatColor; shaderStage_t *dStage; if ( !backEnd.refdef.num_dlights ) { return; } for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { vec3_t dist; int clip; float modulate; backEnd.pc.c_dlightVertexes++; VectorSubtract( origin, tess.xyz[i], dist ); int l = 1; int bestIndex = 0; float greatest = tess.normal[i][0]; if (greatest < 0.0f) { greatest = -greatest; } if (VectorCompare(tess.normal[i], vec3_origin)) { //damn you terrain! bestIndex = 2; } else { while (l < 3) { if ((tess.normal[i][l] > greatest && tess.normal[i][l] > 0.0f) || (tess.normal[i][l] < -greatest && tess.normal[i][l] < 0.0f)) { greatest = tess.normal[i][l]; if (greatest < 0.0f) { greatest = -greatest; } bestIndex = l; } l++; } } float dUse = 0.0f; const float maxScale = 1.5f; const float maxGroundScale = 1.4f; const float lightScaleTolerance = 0.1f; if (bestIndex == 2) { dUse = origin[2]-tess.xyz[i][2]; if (dUse < 0.0f) { dUse = -dUse; } dUse = (radius*0.5f)/dUse; if (dUse > maxGroundScale) { dUse = maxGroundScale; } else if (dUse < 0.1f) { dUse = 0.1f; } if (VectorCompare(tess.normal[i], vec3_origin) || tess.normal[i][0] > lightScaleTolerance || tess.normal[i][0] < -lightScaleTolerance || tess.normal[i][1] > lightScaleTolerance || tess.normal[i][1] < -lightScaleTolerance) { //if not perfectly flat, we must use a constant dist scale = 1.0f / radius; } else { scale = 1.0f / (radius*dUse); } texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; } else if (bestIndex == 1) { dUse = origin[1]-tess.xyz[i][1]; if (dUse < 0.0f) { dUse = -dUse; } dUse = (radius*0.5f)/dUse; if (dUse > maxScale) { dUse = maxScale; } else if (dUse < 0.1f) { dUse = 0.1f; } if (tess.normal[i][0] > lightScaleTolerance || tess.normal[i][0] < -lightScaleTolerance || tess.normal[i][2] > lightScaleTolerance || tess.normal[i][2] < -lightScaleTolerance) { //if not perfectly flat, we must use a constant dist scale = 1.0f / radius; } else { scale = 1.0f / (radius*dUse); } texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[2] * scale; } else { dUse = origin[0]-tess.xyz[i][0]; if (dUse < 0.0f) { dUse = -dUse; } dUse = (radius*0.5f)/dUse; if (dUse > maxScale) { dUse = maxScale; } else if (dUse < 0.1f) { dUse = 0.1f; } if (tess.normal[i][2] > lightScaleTolerance || tess.normal[i][2] < -lightScaleTolerance || tess.normal[i][1] > lightScaleTolerance || tess.normal[i][1] < -lightScaleTolerance) { //if not perfectly flat, we must use a constant dist scale = 1.0f / radius; } else { scale = 1.0f / (radius*dUse); } texCoords[0] = 0.5f + dist[1] * scale; texCoords[1] = 0.5f + dist[2] * scale; } clip = 0; if ( texCoords[0] < 0.0f ) { clip |= 1; } else if ( texCoords[0] > 1.0f ) { clip |= 2; } if ( texCoords[1] < 0.0f ) { clip |= 4; } else if ( texCoords[1] > 1.0f ) { clip |= 8; } // modulate the strength based on the height and color if ( dist[bestIndex] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[bestIndex] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[bestIndex] = Q_fabs(dist[bestIndex]); if ( dist[bestIndex] < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist[bestIndex]) * scale; } } clipBits[i] = clip; colors[0] = Q_ftol(floatColor[0] * modulate); colors[1] = Q_ftol(floatColor[1] * modulate); colors[2] = Q_ftol(floatColor[2] * modulate); colors[3] = 255; } // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } hitIndexes[numIndexes] = a; hitIndexes[numIndexes+1] = b; hitIndexes[numIndexes+2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } //don't have fog enabled when we redraw with alpha test, or it will double over //and screw the tri up -rww if (r_drawfog->value == 2 && tr.world && (tess.fogNum == tr.world->globalFog || tess.fogNum == tr.world->numfogs)) { fogging = qglIsEnabled(GL_FOG); if (fogging) { qglDisable(GL_FOG); } } else { fogging = 0; } dStage = NULL; if (tess.shader && qglActiveTextureARB) { int i = 0; while (i < tess.shader->numUnfoggedPasses) { const int blendBits = (GLS_SRCBLEND_BITS+GLS_DSTBLEND_BITS); if (((tess.shader->stages[i].bundle[0].image && !tess.shader->stages[i].bundle[0].isLightmap && !tess.shader->stages[i].bundle[0].numTexMods) || (tess.shader->stages[i].bundle[1].image && !tess.shader->stages[i].bundle[1].isLightmap && !tess.shader->stages[i].bundle[1].numTexMods)) && (tess.shader->stages[i].stateBits & blendBits) == 0 ) { //only use non-lightmap opaque stages dStage = &tess.shader->stages[i]; break; } i++; } } if (dStage) { GL_SelectTexture( 0 ); GL_State(0); qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); if (dStage->bundle[0].image && !dStage->bundle[0].isLightmap && !dStage->bundle[0].numTexMods) { R_BindAnimatedImage( &dStage->bundle[0] ); } else { R_BindAnimatedImage( &dStage->bundle[1] ); } GL_SelectTexture( 1 ); qglEnable( GL_TEXTURE_2D ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); GL_TexEnv( GL_MODULATE ); GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);// | GLS_ATEST_GT_0); R_DrawElements( numIndexes, hitIndexes ); qglDisable( GL_TEXTURE_2D ); GL_SelectTexture(0); } else { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->additive ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); } if (fogging) { qglEnable(GL_FOG); } backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } }
/* =================== ProjectDlightTexture Perform dynamic lighting with another rendering pass =================== */ static void ProjectDlightTexture2( void ) { int i, l; vec3_t origin; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; float oldTexCoordsArray[SHADER_MAX_VERTEXES][2]; float vertCoordsArray[SHADER_MAX_VERTEXES][4]; unsigned int colorArray[SHADER_MAX_VERTEXES]; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float radius; int fogging; shaderStage_t *dStage; vec3_t posa; vec3_t posb; vec3_t posc; vec3_t dist; vec3_t e1; vec3_t e2; vec3_t normal; float fac,modulate; vec3_t floatColor; byte colorTemp[4]; int needResetVerts=0; if ( !backEnd.refdef.num_dlights ) { return; } for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; int clipall = 63; for ( i = 0 ; i < tess.numVertexes ; i++) { int clip; VectorSubtract( origin, tess.xyz[i], dist ); clip = 0; if ( dist[0] < -radius ) { clip |= 1; } else if ( dist[0] > radius ) { clip |= 2; } if ( dist[1] < -radius ) { clip |= 4; } else if ( dist[1] > radius ) { clip |= 8; } if ( dist[2] < -radius ) { clip |= 16; } else if ( dist[2] > radius ) { clip |= 32; } clipBits[i] = clip; clipall &= clip; } if ( clipall ) { continue; // this surface doesn't have any of this light } floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } // copy the vertex positions VectorCopy(tess.xyz[a],posa); VectorCopy(tess.xyz[b],posb); VectorCopy(tess.xyz[c],posc); VectorSubtract( posa, posb,e1); VectorSubtract( posc, posb,e2); CrossProduct(e1,e2,normal); // rjr - removed for hacking if ( (!r_dlightBacks->integer && DotProduct(normal,origin)-DotProduct(normal,posa) <= 0.0f) || // backface if ( DotProduct(normal,origin)-DotProduct(normal,posa) <= 0.0f || // backface DotProduct(normal,normal) < 1E-8f) // junk triangle { continue; } VectorNormalize(normal); fac=DotProduct(normal,origin)-DotProduct(normal,posa); if (fac >= radius) // out of range { continue; } modulate = 1.0f-((fac*fac) / (radius*radius)); fac = 0.5f/sqrtf(radius*radius - fac*fac); // save the verts VectorCopy(posa,vertCoordsArray[numIndexes]); VectorCopy(posb,vertCoordsArray[numIndexes+1]); VectorCopy(posc,vertCoordsArray[numIndexes+2]); // now we need e1 and e2 to be an orthonormal basis if (DotProduct(e1,e1) > DotProduct(e2,e2)) { VectorNormalize(e1); CrossProduct(e1,normal,e2); } else { VectorNormalize(e2); CrossProduct(normal,e2,e1); } VectorScale(e1,fac,e1); VectorScale(e2,fac,e2); VectorSubtract( posa, origin,dist); texCoordsArray[numIndexes][0]=DotProduct(dist,e1)+0.5f; texCoordsArray[numIndexes][1]=DotProduct(dist,e2)+0.5f; VectorSubtract( posb, origin,dist); texCoordsArray[numIndexes+1][0]=DotProduct(dist,e1)+0.5f; texCoordsArray[numIndexes+1][1]=DotProduct(dist,e2)+0.5f; VectorSubtract( posc, origin,dist); texCoordsArray[numIndexes+2][0]=DotProduct(dist,e1)+0.5f; texCoordsArray[numIndexes+2][1]=DotProduct(dist,e2)+0.5f; if ((texCoordsArray[numIndexes][0] < 0.0f && texCoordsArray[numIndexes+1][0] < 0.0f && texCoordsArray[numIndexes+2][0] < 0.0f) || (texCoordsArray[numIndexes][0] > 1.0f && texCoordsArray[numIndexes+1][0] > 1.0f && texCoordsArray[numIndexes+2][0] > 1.0f) || (texCoordsArray[numIndexes][1] < 0.0f && texCoordsArray[numIndexes+1][1] < 0.0f && texCoordsArray[numIndexes+2][1] < 0.0f) || (texCoordsArray[numIndexes][1] > 1.0f && texCoordsArray[numIndexes+1][1] > 1.0f && texCoordsArray[numIndexes+2][1] > 1.0f) ) { continue; // didn't end up hitting this tri } /* old code, get from the svars = wrong oldTexCoordsArray[numIndexes][0]=tess.svars.texcoords[0][a][0]; oldTexCoordsArray[numIndexes][1]=tess.svars.texcoords[0][a][1]; oldTexCoordsArray[numIndexes+1][0]=tess.svars.texcoords[0][b][0]; oldTexCoordsArray[numIndexes+1][1]=tess.svars.texcoords[0][b][1]; oldTexCoordsArray[numIndexes+2][0]=tess.svars.texcoords[0][c][0]; oldTexCoordsArray[numIndexes+2][1]=tess.svars.texcoords[0][c][1]; */ oldTexCoordsArray[numIndexes][0]=tess.texCoords[a][0][0]; oldTexCoordsArray[numIndexes][1]=tess.texCoords[a][0][1]; oldTexCoordsArray[numIndexes+1][0]=tess.texCoords[b][0][0]; oldTexCoordsArray[numIndexes+1][1]=tess.texCoords[b][0][1]; oldTexCoordsArray[numIndexes+2][0]=tess.texCoords[c][0][0]; oldTexCoordsArray[numIndexes+2][1]=tess.texCoords[c][0][1]; colorTemp[0] = Q_ftol(floatColor[0] * modulate); colorTemp[1] = Q_ftol(floatColor[1] * modulate); colorTemp[2] = Q_ftol(floatColor[2] * modulate); colorTemp[3] = 255; byteAlias_t *ba = (byteAlias_t *)&colorTemp; colorArray[numIndexes + 0] = ba->ui; colorArray[numIndexes + 1] = ba->ui; colorArray[numIndexes + 2] = ba->ui; hitIndexes[numIndexes] = numIndexes; hitIndexes[numIndexes+1] = numIndexes+1; hitIndexes[numIndexes+2] = numIndexes+2; numIndexes += 3; if (numIndexes>=SHADER_MAX_VERTEXES-3) { break; // we are out of space, so we are done :) } } if ( !numIndexes ) { continue; } //don't have fog enabled when we redraw with alpha test, or it will double over //and screw the tri up -rww if (r_drawfog->value == 2 && tr.world && (tess.fogNum == tr.world->globalFog || tess.fogNum == tr.world->numfogs)) { fogging = qglIsEnabled(GL_FOG); if (fogging) { qglDisable(GL_FOG); } } else { fogging = 0; } dStage = NULL; if (tess.shader && qglActiveTextureARB) { int i = 0; while (i < tess.shader->numUnfoggedPasses) { const int blendBits = (GLS_SRCBLEND_BITS+GLS_DSTBLEND_BITS); if (((tess.shader->stages[i].bundle[0].image && !tess.shader->stages[i].bundle[0].isLightmap && !tess.shader->stages[i].bundle[0].numTexMods && tess.shader->stages[i].bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[i].bundle[0].tcGen != TCGEN_FOG) || (tess.shader->stages[i].bundle[1].image && !tess.shader->stages[i].bundle[1].isLightmap && !tess.shader->stages[i].bundle[1].numTexMods && tess.shader->stages[i].bundle[1].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[i].bundle[1].tcGen != TCGEN_FOG)) && (tess.shader->stages[i].stateBits & blendBits) == 0 ) { //only use non-lightmap opaque stages dStage = &tess.shader->stages[i]; break; } i++; } } if (!needResetVerts) { needResetVerts=1; if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } } qglVertexPointer (3, GL_FLOAT, 16, vertCoordsArray); // padded for SIMD if (dStage) { GL_SelectTexture( 0 ); GL_State(0); qglTexCoordPointer( 2, GL_FLOAT, 0, oldTexCoordsArray[0] ); if (dStage->bundle[0].image && !dStage->bundle[0].isLightmap && !dStage->bundle[0].numTexMods && dStage->bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && dStage->bundle[0].tcGen != TCGEN_FOG) { R_BindAnimatedImage( &dStage->bundle[0] ); } else { R_BindAnimatedImage( &dStage->bundle[1] ); } GL_SelectTexture( 1 ); qglEnable( GL_TEXTURE_2D ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); GL_TexEnv( GL_MODULATE ); GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);// | GLS_ATEST_GT_0); R_DrawElements( numIndexes, hitIndexes ); qglDisable( GL_TEXTURE_2D ); GL_SelectTexture(0); } else { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->additive ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); } if (fogging) { qglEnable(GL_FOG); } backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } if (needResetVerts) { qglVertexPointer (3, GL_FLOAT, 16, tess.xyz); // padded for SIMD if (qglLockArraysEXT) { qglLockArraysEXT(0, tess.numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } } }
/* ================= RB_ShadowTessEnd triangleFromEdge[ v1 ][ v2 ] set triangle from edge( v1, v2, tri ) if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { } ================= */ void RB_ShadowTessEnd(void) { int i; int numTris; vec3_t lightDir; // we can only do this if we have enough space in the vertex buffers if (tess.numVertexes >= tess.maxShaderVerts / 2) { return; } if (glConfig.stencilBits < 4) { return; } VectorCopy(backEnd.currentEntity->lightDir, lightDir); // project vertexes away from light direction for (i = 0 ; i < tess.numVertexes ; i++) { VectorMA(tess.xyz[i].v, -512, lightDir, tess.xyz[i + tess.numVertexes].v); } // decide which triangles face the light memset(numEdgeDefs, 0, 4 * tess.numVertexes); numTris = tess.numIndexes / 3; { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; for (i = 0 ; i < numTris ; i++) { i1 = tess.indexes[i * 3 + 0]; i2 = tess.indexes[i * 3 + 1]; i3 = tess.indexes[i * 3 + 2]; v1 = tess.xyz[i1].v; v2 = tess.xyz[i2].v; v3 = tess.xyz[i3].v; VectorSubtract(v2, v1, d1); VectorSubtract(v3, v1, d2); CrossProduct(d1, d2, normal); d = DotProduct(normal, lightDir); if (d > 0) { facing[i] = 1; } else { facing[i] = 0; } // create the edges R_AddEdgeDef(i1, i2, facing[i]); R_AddEdgeDef(i2, i3, facing[i]); R_AddEdgeDef(i3, i1, facing[i]); } } // draw the silhouette edges GL_Bind(tr.whiteImage); qglEnable(GL_CULL_FACE); GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO); qglColor3f(0.2f, 0.2f, 0.2f); // don't write to the color buffer qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 1, 255); qglVertexPointer(3, GL_FLOAT, 16, tess.xyz); GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (text) { qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } if (glcol) { qglDisableClientState(GL_COLOR_ARRAY); } // mirrors have the culling order reversed if (backEnd.viewParms.isMirror) { qglCullFace(GL_FRONT); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); R_RenderShadowEdges(); qglCullFace(GL_BACK); qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR); qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); } else { qglCullFace(GL_BACK); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); R_RenderShadowEdges(); qglCullFace(GL_FRONT); qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR); qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); } if (text) { qglEnableClientState(GL_TEXTURE_COORD_ARRAY); } if (glcol) { qglEnableClientState(GL_COLOR_ARRAY); } // reenable writing to the color buffer qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); }
/* =============== 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 ); }
// Renders the input text at the current location with the current color. // The X position of the current location is used to place the left edge of the text image, // where the text image bounds are defined as the logical extents of the line of text. // The Y position of the current location is used to place the bottom of the text image. // You should offset the Y position by the amount returned by gtk_glwidget_font_descent() // if you want to place the baseline of the text image at the current Y position. // Note: A problem with this function is that if the lower left corner of the text falls // just a hair outside of the viewport (meaning the current raster position is invalid), // then no text will be rendered. The solution to this is a very hacky one. You can search // Google for "glDrawPixels clipping". void gtk_glwidget_print_string( const char *s ){ // The idea for this code initially came from the font-pangoft2.c example that comes with GtkGLExt. PangoLayout *layout; PangoRectangle log_rect; FT_Bitmap bitmap; unsigned char *begin_bitmap_buffer; GLfloat color[4]; GLint previous_unpack_alignment; GLboolean previous_blend_enabled; GLint previous_blend_func_src; GLint previous_blend_func_dst; GLfloat previous_red_bias; GLfloat previous_green_bias; GLfloat previous_blue_bias; GLfloat previous_alpha_scale; if ( !_debug_font_created ) { Error( "Programming error: gtk_glwidget_print_string() called but font does not exist; " "you should have called gtk_glwidget_create_font() first" ); } layout = pango_layout_new( ft2_context ); pango_layout_set_width( layout, -1 ); // -1 no wrapping. All text on one line. pango_layout_set_text( layout, s, -1 ); // -1 null-terminated string. pango_layout_get_extents( layout, NULL, &log_rect ); if ( log_rect.width > 0 && log_rect.height > 0 ) { bitmap.rows = font_ascent + font_descent; bitmap.width = PANGO_PIXELS_CEIL( log_rect.width ); bitmap.pitch = -bitmap.width; // Rendering it "upside down" for OpenGL. begin_bitmap_buffer = (unsigned char *) g_malloc( bitmap.rows * bitmap.width ); memset( begin_bitmap_buffer, 0, bitmap.rows * bitmap.width ); bitmap.buffer = begin_bitmap_buffer + ( bitmap.rows - 1 ) * bitmap.width; // See pitch above. bitmap.num_grays = 0xff; bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; pango_ft2_render_layout_subpixel( &bitmap, layout, -log_rect.x, y_offset_bitmap_render_pango_units ); qglGetFloatv( GL_CURRENT_COLOR, color ); // Save state. I didn't see any OpenGL push/pop operations for these. // Question: Is saving/restoring this state necessary? Being safe. qglGetIntegerv( GL_UNPACK_ALIGNMENT, &previous_unpack_alignment ); previous_blend_enabled = qglIsEnabled( GL_BLEND ); qglGetIntegerv( GL_BLEND_SRC, &previous_blend_func_src ); qglGetIntegerv( GL_BLEND_DST, &previous_blend_func_dst ); qglGetFloatv( GL_RED_BIAS, &previous_red_bias ); qglGetFloatv( GL_GREEN_BIAS, &previous_green_bias ); qglGetFloatv( GL_BLUE_BIAS, &previous_blue_bias ); qglGetFloatv( GL_ALPHA_SCALE, &previous_alpha_scale ); qglPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); qglEnable( GL_BLEND ); qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); qglPixelTransferf( GL_RED_BIAS, color[0] ); qglPixelTransferf( GL_GREEN_BIAS, color[1] ); qglPixelTransferf( GL_BLUE_BIAS, color[2] ); qglPixelTransferf( GL_ALPHA_SCALE, color[3] ); qglDrawPixels( bitmap.width, bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, begin_bitmap_buffer ); g_free( begin_bitmap_buffer ); // Restore state in reverse order of how we set it. qglPixelTransferf( GL_ALPHA_SCALE, previous_alpha_scale ); qglPixelTransferf( GL_BLUE_BIAS, previous_blue_bias ); qglPixelTransferf( GL_GREEN_BIAS, previous_green_bias ); qglPixelTransferf( GL_RED_BIAS, previous_red_bias ); qglBlendFunc( previous_blend_func_src, previous_blend_func_dst ); if ( !previous_blend_enabled ) { qglDisable( GL_BLEND ); } qglPixelStorei( GL_UNPACK_ALIGNMENT, previous_unpack_alignment ); } g_object_unref( G_OBJECT( layout ) ); }
/** * @note Unused. */ void RB_DrawBounds(vec3_t mins, vec3_t maxs) { vec3_t center; GL_Bind(tr.whiteImage); GL_State(GLS_POLYMODE_LINE); // box corners GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (glcol) { qglDisableClientState(GL_COLOR_ARRAY); } if (text) { qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } GLfloat vtx1[] = { mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2], mins[0], mins[1], mins[2], mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2], mins[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2], maxs[0], maxs[1], maxs[2], maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2], maxs[0], maxs[1], mins[2] }; qglColor3f(1, 1, 1); qglVertexPointer(3, GL_FLOAT, 0, vtx1); qglDrawArrays(GL_LINES, 0, 12); center[0] = (mins[0] + maxs[0]) * 0.5; center[1] = (mins[1] + maxs[1]) * 0.5; center[2] = (mins[2] + maxs[2]) * 0.5; // center axis GLfloat vtx2[] = { mins[0], center[1], center[2], maxs[0], center[1], center[2], center[0], mins[1], center[2], center[0], maxs[1], center[2], center[0], center[1], mins[2], center[0], center[1], maxs[2] }; qglColor3f(1, 0.85, 0); qglVertexPointer(3, GL_FLOAT, 0, vtx2); qglDrawArrays(GL_LINES, 0, 6); if (glcol) { qglEnableClientState(GL_COLOR_ARRAY); } if (text) { qglEnableClientState(GL_TEXTURE_COORD_ARRAY); } }
/********* SP_DrawTexture *********/ void SP_DrawTexture(void* pixels, float width, float height, float vShift) { if (!pixels) { // Ug. We were not even able to load the error message texture. return; } // Create a texture from the buffered file GLuint texid; qglGenTextures(1, &texid); qglBindTexture(GL_TEXTURE_2D, texid); qglTexImage2D(GL_TEXTURE_2D, 0, GL_DDS1_EXT, width, height, 0, GL_DDS1_EXT, GL_UNSIGNED_BYTE, pixels); 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 ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); // Reset every GL state we've got. Who knows what state // the renderer could be in when this function gets called. qglColor3f(1.f, 1.f, 1.f); qglViewport(0, 0, 640, 480); GLboolean alpha = qglIsEnabled(GL_ALPHA_TEST); qglDisable(GL_ALPHA_TEST); GLboolean blend = qglIsEnabled(GL_BLEND); qglDisable(GL_BLEND); GLboolean cull = qglIsEnabled(GL_CULL_FACE); qglDisable(GL_CULL_FACE); GLboolean depth = qglIsEnabled(GL_DEPTH_TEST); qglDisable(GL_DEPTH_TEST); GLboolean fog = qglIsEnabled(GL_FOG); qglDisable(GL_FOG); GLboolean lighting = qglIsEnabled(GL_LIGHTING); qglDisable(GL_LIGHTING); GLboolean offset = qglIsEnabled(GL_POLYGON_OFFSET_FILL); qglDisable(GL_POLYGON_OFFSET_FILL); GLboolean scissor = qglIsEnabled(GL_SCISSOR_TEST); qglDisable(GL_SCISSOR_TEST); GLboolean stencil = qglIsEnabled(GL_STENCIL_TEST); qglDisable(GL_STENCIL_TEST); GLboolean texture = qglIsEnabled(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_2D); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglOrtho(0, 640, 0, 480, 0, 1); qglMatrixMode(GL_TEXTURE0); qglLoadIdentity(); qglMatrixMode(GL_TEXTURE1); qglLoadIdentity(); qglActiveTextureARB(GL_TEXTURE0_ARB); qglClientActiveTextureARB(GL_TEXTURE0_ARB); memset(&tess, 0, sizeof(tess)); // Draw the error message qglBeginFrame(); if (!SP_LicenseDone) { // clear the screen if we haven't done the // license yet... qglClearColor(0, 0, 0, 1); qglClear(GL_COLOR_BUFFER_BIT); } float x1 = 320 - width / 2; float x2 = 320 + width / 2; float y1 = 240 - height / 2; float y2 = 240 + height / 2; y1 += vShift; y2 += vShift; qglBeginEXT (GL_TRIANGLE_STRIP, 4, 0, 0, 4, 0); qglTexCoord2f( 0, 0 ); qglVertex2f(x1, y1); qglTexCoord2f( 1 , 0 ); qglVertex2f(x2, y1); qglTexCoord2f( 0, 1 ); qglVertex2f(x1, y2); qglTexCoord2f( 1, 1 ); qglVertex2f(x2, y2); qglEnd(); qglEndFrame(); qglFlush(); // Restore (most) of the render states we reset if (alpha) qglEnable(GL_ALPHA_TEST); else qglDisable(GL_ALPHA_TEST); if (blend) qglEnable(GL_BLEND); else qglDisable(GL_BLEND); if (cull) qglEnable(GL_CULL_FACE); else qglDisable(GL_CULL_FACE); if (depth) qglEnable(GL_DEPTH_TEST); else qglDisable(GL_DEPTH_TEST); if (fog) qglEnable(GL_FOG); else qglDisable(GL_FOG); if (lighting) qglEnable(GL_LIGHTING); else qglDisable(GL_LIGHTING); if (offset) qglEnable(GL_POLYGON_OFFSET_FILL); else qglDisable(GL_POLYGON_OFFSET_FILL); if (scissor) qglEnable(GL_SCISSOR_TEST); else qglDisable(GL_SCISSOR_TEST); if (stencil) qglEnable(GL_STENCIL_TEST); else qglDisable(GL_STENCIL_TEST); if (texture) qglEnable(GL_TEXTURE_2D); else qglDisable(GL_TEXTURE_2D); // Kill the texture qglDeleteTextures(1, &texid); }
/* ============= 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 qbyte *data, int client, qboolean dirty) { int i, j; int start, end; 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 IPHONE qglTexImage2D( 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 // IPHONE 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 ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); } 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 ); Com_DPrintf("blend = %d, lighting = %d\n", qglIsEnabled(GL_BLEND), qglIsEnabled(GL_LIGHTING)); } } 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 (); }
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.0005f); if (spost < 0.0f) { spost = -spost; } spost *= 0.2f; spost2 = sin(tr.refdef.time*0.0005f); 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.0008f); if (spost < 0.0f) { spost = -spost; } spost *= 0.08f; spost2 = sin(tr.refdef.time*0.0008f); 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 ); }
/* ============= 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 }
void DrawTerrain( terrainMesh_t *pm, bool bPoints, bool bShade ) { int i; int w; int h; int x; int y; //int n; //float x1; //float y1; float scale_x; float scale_y; //vec3_t pSelectedPoints[ MAX_TERRA_POINTS ]; //int nIndex; terravert_t a0; terravert_t a1; terravert_t a2; terravert_t b0; terravert_t b1; terravert_t b2; terrainVert_t *vert; qtexture_t *texture; h = pm->height - 1; w = pm->width - 1; scale_x = pm->scale_x; scale_y = pm->scale_y; qglShadeModel (GL_SMOOTH); if ( bShade ) { for( i = 0; i < pm->numtextures; i++ ) { texture = pm->textures[ i ]; qglBindTexture( GL_TEXTURE_2D, texture->texture_number ); vert = pm->heightmap; for( y = 0; y < h; y++ ) { qglBegin( GL_TRIANGLES ); for( x = 0; x < w; x++, vert++ ) { Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture ); // first tri if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) { qglColor4fv( a0.rgba ); qglTexCoord2fv( a0.tc ); qglVertex3fv( a0.xyz ); qglColor4fv( a1.rgba ); qglTexCoord2fv( a1.tc ); qglVertex3fv( a1.xyz ); qglColor4fv( a2.rgba ); qglTexCoord2fv( a2.tc ); qglVertex3fv( a2.xyz ); } // second tri if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) { qglColor4fv( b0.rgba ); qglTexCoord2fv( b0.tc ); qglVertex3fv( b0.xyz ); qglColor4fv( b1.rgba ); qglTexCoord2fv( b1.tc ); qglVertex3fv( b1.xyz ); qglColor4fv( b2.rgba ); qglTexCoord2fv( b2.tc ); qglVertex3fv( b2.xyz ); } } qglEnd (); } } } else { for( i = 0; i < pm->numtextures; i++ ) { texture = pm->textures[ i ]; qglBindTexture( GL_TEXTURE_2D, texture->texture_number ); vert = pm->heightmap; for( y = 0; y < h; y++ ) { qglBegin( GL_TRIANGLES ); for( x = 0; x < w; x++, vert++ ) { Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture ); // first tri if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) { qglColor4fv( a0.rgba ); qglTexCoord2fv( a0.tc ); qglVertex3fv( a0.xyz ); qglColor4fv( a1.rgba ); qglTexCoord2fv( a1.tc ); qglVertex3fv( a1.xyz ); qglColor4fv( a2.rgba ); qglTexCoord2fv( a2.tc ); qglVertex3fv( a2.xyz ); } // second tri if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) { qglColor4fv( b0.rgba ); qglTexCoord2fv( b0.tc ); qglVertex3fv( b0.xyz ); qglColor4fv( b1.rgba ); qglTexCoord2fv( b1.tc ); qglVertex3fv( b1.xyz ); qglColor4fv( b2.rgba ); qglTexCoord2fv( b2.tc ); qglVertex3fv( b2.xyz ); } } qglEnd (); } } } qglPushAttrib( GL_CURRENT_BIT ); bool bDisabledLighting = qglIsEnabled( GL_LIGHTING ); if ( bDisabledLighting ) { qglDisable( GL_LIGHTING ); } #if 0 terrainVert_t *currentrow; terrainVert_t *nextrow; float x2; float y2; // Draw normals qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINES ); y2 = pm->origin[ 1 ]; nextrow = pm->heightmap; for( y = 0; y < h; y++ ) { y1 = y2; y2 += scale_y; x2 = pm->origin[ 0 ]; currentrow = nextrow; nextrow = currentrow + pm->width; for( x = 0; x < w; x++ ) { x1 = x2; x2 += scale_x; // normals qglVertex3f( x1, y1, pm->origin[ 2 ] + currentrow[ x ].height ); qglVertex3f( x1 + currentrow[ x ].normal[ 0 ] * 16.0f, y1 + currentrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x ].height + currentrow[ x ].normal[ 2 ] * 16.0f ); qglVertex3f( x2, y1, pm->origin[ 2 ] + currentrow[ x + 1 ].height ); qglVertex3f( x2 + currentrow[ x + 1 ].normal[ 0 ] * 16.0f, y1 + currentrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x + 1 ].height + currentrow[ x + 1 ].normal[ 2 ] * 16.0f ); qglVertex3f( x1, y2, pm->origin[ 2 ] + nextrow[ x ].height ); qglVertex3f( x1 + nextrow[ x ].normal[ 0 ] * 16.0f, y2 + nextrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x ].height + nextrow[ x ].normal[ 2 ] * 16.0f ); qglVertex3f( x2, y2, pm->origin[ 2 ] + nextrow[ x + 1 ].height ); qglVertex3f( x2 + nextrow[ x + 1 ].normal[ 0 ] * 16.0f, y2 + nextrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x + 1 ].height + nextrow[ x + 1 ].normal[ 2 ] * 16.0f ); } } qglEnd (); qglEnable( GL_TEXTURE_2D ); #endif #if 0 if ( bPoints && ( g_qeglobals.d_select_mode == sel_terrainpoint || g_qeglobals.d_select_mode == sel_area ) ) { qglPointSize( 6 ); qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglBegin( GL_POINTS ); nIndex = 0; qglColor4f( 1, 0, 1, 1 ); y1 = pm->origin[ 1 ]; for ( y = 0; y < pm->height; y++, y1 += pm->scale_y ) { x1 = pm->origin[ 0 ]; for( x = 0; x < pm->width; x++, x1 += pm->scale_x ) { // FIXME: need to not do loop lookups inside here n = Terrain_PointInMoveList( &pm->heightmap[ x + y * pm->width ] ); if ( n >= 0 ) { VectorSet( pSelectedPoints[ nIndex ], x1, y1, pm->heightmap[ x + y * pm->width ].height + pm->origin[ 2 ] ); nIndex++; } else { qglVertex3f( x1, y1, pm->origin[ 2 ] + pm->heightmap[ x + y * pm->width ].height ); } } } qglEnd(); qglEnable( GL_TEXTURE_2D ); if ( nIndex > 0 ) { qglBegin( GL_POINTS ); qglColor4f( 0, 0, 1, 1 ); while( nIndex-- > 0 ) { qglVertex3fv( pSelectedPoints[ nIndex ] ); } qglEnd(); } } #endif if ( g_qeglobals.d_numterrapoints && ( ( g_qeglobals.d_select_mode == sel_terrainpoint ) || ( g_qeglobals.d_select_mode == sel_terraintexture ) ) ) { #if 0 qglPointSize( 6 ); qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglBegin( GL_POINTS ); qglColor4f( 1, 0, 1, 1 ); for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) { qglVertex3fv( g_qeglobals.d_terrapoints[ i ]->xyz ); } qglEnd(); qglEnable( GL_TEXTURE_2D ); #endif brush_t *pb; terrainMesh_t *pm; pm = NULL; for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) { if ( pb->terrainBrush ) { pm = pb->pTerrain; break; } } if ( pm ) { qglDisable( GL_TEXTURE_2D ); qglBegin( GL_TRIANGLES ); qglEnable( GL_BLEND ); qglColor4f( 0.25, 0.5, 1, 0.35 ); for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) { terravert_t a0; terravert_t a1; terravert_t a2; qglColor4f( 0.25, 0.5, 1, g_qeglobals.d_terrapoints[ i ]->scale * 0.75 + 0.25 ); Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2, &a0, &a1, &a2 ); qglVertex3fv( a0.xyz ); qglVertex3fv( a1.xyz ); qglVertex3fv( a2.xyz ); Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2 + 1, &a0, &a1, &a2 ); qglVertex3fv( a0.xyz ); qglVertex3fv( a1.xyz ); qglVertex3fv( a2.xyz ); } qglEnd(); qglDisable( GL_BLEND ); qglEnable( GL_TEXTURE_2D ); } } }