/* ================ DrawNormals Draws vertex normals for debugging ================ */ static void DrawNormals( shaderCommands_t *input ) { int i; vec3_t temp; GL_Bind( tr.whiteImage ); qglColor3f( 1,1,1 ); qglDepthRange( 0, 0 ); // never occluded GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); // ydnar: light direction if ( r_shownormals->integer == 2 ) { trRefEntity_t *ent = backEnd.currentEntity; vec3_t temp2; if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { VectorSubtract( ent->e.lightingOrigin, backEnd.orientation.origin, temp2 ); } else { VectorClear( temp2 ); } temp[ 0 ] = DotProduct( temp2, backEnd.orientation.axis[ 0 ] ); temp[ 1 ] = DotProduct( temp2, backEnd.orientation.axis[ 1 ] ); temp[ 2 ] = DotProduct( temp2, backEnd.orientation.axis[ 2 ] ); qglColor3f( ent->ambientLight[ 0 ] / 255, ent->ambientLight[ 1 ] / 255, ent->ambientLight[ 2 ] / 255 ); qglPointSize( 5 ); qglBegin( GL_POINTS ); qglVertex3fv( temp ); qglEnd(); qglPointSize( 1 ); if ( fabs( VectorLengthSquared( ent->lightDir ) - 1.0f ) > 0.2f ) { qglColor3f( 1, 0, 0 ); } else { qglColor3f( ent->directedLight[ 0 ] / 255, ent->directedLight[ 1 ] / 255, ent->directedLight[ 2 ] / 255 ); } qglLineWidth( 3 ); qglBegin( GL_LINES ); qglVertex3fv( temp ); VectorMA( temp, 32, ent->lightDir, temp ); qglVertex3fv( temp ); qglEnd(); qglLineWidth( 1 ); } // ydnar: normals drawing else { qglBegin( GL_LINES ); for ( i = 0 ; i < input->numVertexes ; i++ ) { qglVertex3fv( input->xyz[i].v ); VectorMA( input->xyz[i].v, r_normallength->value, input->normal[i].v, temp ); qglVertex3fv( temp ); } qglEnd(); } qglDepthRange( 0, 1 ); }
void Terrain_DrawCam( terrainMesh_t *pm ) { qglColor3f( 1,1,1 ); qglPushAttrib( GL_ALL_ATTRIB_BITS ); if ( g_bPatchWireFrame ) { if( pm->bSelected ) { qglLineWidth( 2 ); } else { qglLineWidth( 1 ); } qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDisable( GL_TEXTURE_2D ); if ( g_PrefsDlg.m_bGLLighting ) { qglDisable( GL_LIGHTING ); } DrawTerrain( pm, pm->bSelected, true ); if ( g_PrefsDlg.m_bGLLighting ) { qglEnable( GL_LIGHTING ); } qglEnable( GL_CULL_FACE ); qglLineWidth( 1 ); } else { qglEnable( GL_CULL_FACE ); qglCullFace( GL_FRONT ); // draw the textured polys DrawTerrain( pm, pm->bSelected, true ); // if selected, draw the red tint on the polys if( pm->bSelected ) { // && ( g_qeglobals.d_savedinfo.include & INCLUDE_CAMERATINT ) ) { qglColor4f( 1.0, 0.0, 0.0, 0.3 ); qglEnable( GL_BLEND ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); DrawTerrain( pm, pm->bSelected ); qglColor3f( 1, 1, 1 ); } // draw the backside poly outlines qglCullFace( GL_BACK ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDisable( GL_BLEND ); DrawTerrain( pm, pm->bSelected, true ); } qglPopAttrib(); }
void Pointfile_Draw( void ) { int i; qglColor3f( 1.0F, 0.0F, 0.0F ); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_1D); qglLineWidth (2); qglBegin(GL_LINE_STRIP); for ( i = 0; i < s_num_points; i++ ) { qglVertex3fv( s_pointvecs[i].ToFloatPtr() ); } qglEnd(); qglLineWidth( 0.5 ); }
// Draws from modelview space void GLRB_SurfaceAxis( void ) { GL_Bind( tr.whiteImage ); qglLineWidth( 3 ); qglBegin( GL_LINES ); qglColor3f( 1,0,0 ); qglVertex3f( 0,0,0 ); qglVertex3f( 16,0,0 ); qglColor3f( 0,1,0 ); qglVertex3f( 0,0,0 ); qglVertex3f( 0,16,0 ); qglColor3f( 0,0,1 ); qglVertex3f( 0,0,0 ); qglVertex3f( 0,0,16 ); qglEnd(); qglLineWidth( 1 ); }
void WINAPI Pointfile_Check (void) { char name[1024]; FILE *f; idVec3 v; strcpy (name, currentmap); StripExtension (name); strcat (name, ".lin"); f = fopen (name, "r"); if (!f) return; common->Printf ("Reading pointfile %s\n", name); if (!g_qeglobals.d_pointfile_display_list) g_qeglobals.d_pointfile_display_list = qglGenLists(1); s_num_points = 0; qglNewList (g_qeglobals.d_pointfile_display_list, GL_COMPILE); qglColor3f (1, 0, 0); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_1D); qglLineWidth (2); qglBegin(GL_LINE_STRIP); do { if (fscanf (f, "%f %f %f\n", &v[0], &v[1], &v[2]) != 3) break; if (s_num_points < MAX_POINTFILE) { VectorCopy (v, s_pointvecs[s_num_points]); s_num_points++; } qglVertex3fv( v.ToFloatPtr() ); } while (1); qglEnd(); qglLineWidth (0.5); qglEndList (); s_check_point = 0; fclose (f); //Pointfile_Next (); }
/* =================== RB_OutlinesPass Draws outlines on surfaces with shader.hasOutlines set =================== */ static void RB_OutlinesPass( void ) { int outlines; float outlinesAlpha; outlines = r_outlines->value; outlinesAlpha = r_outlinesAlpha->value; if ( !tess.shader->hasOutlines ) return; if ( !r_outlines->integer ) return; GL_Bind( tr.whiteImage ); qglColor4f( 0, 0, 0, outlinesAlpha ); GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); qglPolygonMode( GL_BACK, GL_LINE ); qglLineWidth( outlines + 1 ); qglCullFace( GL_BACK ); qglDisableClientState( GL_COLOR_ARRAY ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); qglVertexPointer (3, GL_FLOAT, 16, tess.xyz); // padded for SIMD if (qglLockArraysEXT) { qglLockArraysEXT(0, tess.numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } R_DrawElements( tess.numIndexes, tess.indexes ); if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } // FIX: Must reset these manually or renderer will b0rk! qglCullFace( GL_FRONT ); qglLineWidth( 1 ); }
/* =================== RB_SurfaceAxis Draws x/y/z lines from the origin for orientation debugging =================== */ static void RB_SurfaceAxis( void ) { // FIXME: implement this #if 0 GL_BindToTMU( tr.whiteImage, TB_COLORMAP ); GL_State( GLS_DEFAULT ); qglLineWidth( 3 ); qglBegin( GL_LINES ); qglColor3f( 1,0,0 ); qglVertex3f( 0,0,0 ); qglVertex3f( 16,0,0 ); qglColor3f( 0,1,0 ); qglVertex3f( 0,0,0 ); qglVertex3f( 0,16,0 ); qglColor3f( 0,0,1 ); qglVertex3f( 0,0,0 ); qglVertex3f( 0,0,16 ); qglEnd(); qglLineWidth( 1 ); #endif }
void Terrain_DrawXY( terrainMesh_t *pm, entity_t *owner ) { qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); if ( pm->bSelected ) { qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_SELBRUSHES ] ); } else if ( owner != world_entity && _stricmp( owner->eclass->name, "func_group" ) ) { qglColor3fv( owner->eclass->color ); } else { //FIXME qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_BRUSHES ] ); } qglLineWidth( 1 ); DrawTerrain( pm, pm->bSelected ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); }
void idGLDrawable::draw(int x, int y, int w, int h) { GL_State( GLS_DEFAULT ); qglViewport(x, y, w, h); qglScissor(x, y, w, h); qglMatrixMode(GL_PROJECTION); qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f ); qglClear(GL_COLOR_BUFFER_BIT); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); qglLineWidth(0.5); qglColor3f(1, 1, 1); globalImages->BindNull(); qglBegin(GL_LINE_LOOP); qglColor3f(1, 0, 0); qglVertex2f(x + 3, y + 3); qglColor3f(0, 1, 0); qglVertex2f(x + 3, h - 3); qglColor3f(0, 0, 1); qglVertex2f(w - 3, h - 3); qglColor3f(1, 1, 1); qglVertex2f(w - 3, y + 3); qglEnd(); }
/* ================ DrawTris Draws triangle outlines for debugging ================ */ static void DrawTris( shaderCommands_t *input ) { char *s = r_trisColor->string; vec4_t trisColor = { 1, 1, 1, 1 }; unsigned int stateBits = 0; GL_Bind( tr.whiteImage ); if ( *s == '0' && ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) { s += 2; if ( Q_IsHexColorString( s ) ) { trisColor[0] = ( (float)( gethex( *( s ) ) * 16 + gethex( *( s + 1 ) ) ) ) / 255.00; trisColor[1] = ( (float)( gethex( *( s + 2 ) ) * 16 + gethex( *( s + 3 ) ) ) ) / 255.00; trisColor[2] = ( (float)( gethex( *( s + 4 ) ) * 16 + gethex( *( s + 5 ) ) ) ) / 255.00; if ( Q_HexColorStringHasAlpha( s ) ) { trisColor[3] = ( (float)( gethex( *( s + 6 ) ) * 16 + gethex( *( s + 7 ) ) ) ) / 255.00; } } } else { int i; char *token; for ( i = 0 ; i < 4 ; i++ ) { token = COM_Parse( &s ); if ( token ) { trisColor[i] = atof( token ); } else { trisColor[i] = 1.f; } } if ( !trisColor[3] ) { trisColor[3] = 1.f; } } if ( trisColor[3] < 1.f ) { stateBits |= ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } qglColor4fv( trisColor ); // ydnar r_showtris 2 if ( r_showtris->integer == 2 ) { stateBits |= ( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); GL_State( stateBits ); qglDepthRange( 0, 0 ); } #ifdef CELSHADING_HACK else if ( r_showtris->integer == 3 ) { stateBits |= ( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); GL_State( stateBits ); qglEnable( GL_POLYGON_OFFSET_LINE ); qglPolygonOffset( 4.0, 0.5 ); qglLineWidth( 5.0 ); } #endif else { stateBits |= ( GLS_POLYMODE_LINE ); GL_State( stateBits ); qglEnable( GL_POLYGON_OFFSET_LINE ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } qglDisableClientState( GL_COLOR_ARRAY ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); // padded for SIMD if ( qglLockArraysEXT ) { qglLockArraysEXT( 0, input->numVertexes ); GLimp_LogComment( "glLockArraysEXT\n" ); } R_DrawElements( input->numIndexes, input->indexes ); if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } qglDepthRange( 0, 1 ); qglDisable( GL_POLYGON_OFFSET_LINE ); }
/* ============== 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 }
//R_DRAWCEL static void R_DrawCel( int numIndexes, const glIndex_t *indexes ) { int primitives; if( //. ignore the 2d projection. do i smell the HUD? (backEnd.projection2D == qtrue) || //. ignore general entitites that are sprites. SEE NOTE #3. (backEnd.currentEntity->e.reType == RT_SPRITE) || //. ignore these liquids. why? ever see liquid with tris on the surface? exactly. SEE NOTE #4. (tess.shader->contentFlags & (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FOG)) || //. ignore things that are two sided, meaning mostly things that have transparency. SEE NOTE #1. (tess.shader->cullType == CT_TWO_SIDED) ) { return; } primitives = r_primitives->integer; // default is to use triangles if compiled vertex arrays are present if ( primitives == 0 ) { if ( qglLockArraysEXT ) { primitives = 2; } else { primitives = 1; } } //. correction for mirrors. SEE NOTE #2. if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_FRONT); } else { qglCullFace (GL_BACK); } qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA ,GL_ONE_MINUS_SRC_ALPHA); qglColor3f (0.0f,0.0f,0.0f); qglLineWidth( (float) r_celoutline->integer ); if(primitives == 2) { qglDrawElements( GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes ); } else if(primitives == 1) { R_DrawStripElements( numIndexes, indexes, qglArrayElement ); } else if(primitives == 3) { R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); } //. correction for mirrors. SEE NOTE #2. if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_BACK); } else { qglCullFace (GL_FRONT); } qglDisable (GL_BLEND); return; /* Notes 1. this is going to be a pain in the arse. it fixes things like light `beams` from being cel'd but it also will ignore any other shader set with no culling. this usually is everything that is translucent. but this is a good hack to clean up the screen untill something more selective comes along. or who knows group desision might actually be that this is liked. if so i take back calling it a `hack`, lol. = bob. 2. mirrors display correctly because the normals of the displayed are inverted of normal space. so to continue to have them display correctly, we must invert them inversely from a normal inversion. = bob. 3. this turns off a lot of space hogging sprite cel outlines. picture if you will five people in a small room all shooting rockets. each smoke puff gets a big black square around it, each explosion gets a big black square around it, and now nobody can see eachother because everyones screen is solid black. = bob. 4. ignoring liquids means you will not get black tris lines all over the top of your liquid. i put this in after seeing the lava on q3dm7 and water on q3ctf2 that had black lines all over the top, making the liquids look solid instead of... liquid. = bob. */ }
/* ======================================================================================================================= ======================================================================================================================= */ void CNewTexWnd::OnPaint() { CPaintDC dc(this); // device context for painting int nOld = g_qeglobals.d_texturewin.m_nTotalHeight; //hdcTexture = GetDC(); if (!qwglMakeCurrent(dc.GetSafeHdc(), win32.hGLRC)) { common->Printf("ERROR: wglMakeCurrent failed..\n "); } else { const char *name; qglClearColor ( g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0], g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1], g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], 0 ); qglViewport(0, 0, rectClient.Width(), rectClient.Height()); qglScissor(0, 0, rectClient.Width(), rectClient.Height()); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); qglDisable(GL_DEPTH_TEST); qglDisable(GL_BLEND); qglOrtho(0, rectClient.Width(), origin.y - rectClient.Height(), origin.y, -100, 100); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // init stuff current.x = 8; current.y = -8; currentRow = 0; currentIndex = 0; while (1) { const idMaterial *mat = NextPos(); if (mat == NULL) { break; } int width = mat->GetEditorImage()->uploadWidth * ((float)g_PrefsDlg.m_nTextureScale / 100); int height = mat->GetEditorImage()->uploadHeight * ((float)g_PrefsDlg.m_nTextureScale / 100); // Is this texture visible? if ((draw.y - height - FONT_HEIGHT < origin.y) && (draw.y > origin.y - rectClient.Height())) { // if in use, draw a background qglLineWidth(1); qglColor3f(1, 1, 1); globalImages->BindNull(); qglBegin(GL_LINE_LOOP); qglVertex2f(draw.x - 1, draw.y + 1 - FONT_HEIGHT); qglVertex2f(draw.x - 1, draw.y - height - 1 - FONT_HEIGHT); qglVertex2f(draw.x + 1 + width, draw.y - height - 1 - FONT_HEIGHT); qglVertex2f(draw.x + 1 + width, draw.y + 1 - FONT_HEIGHT); qglEnd(); // Draw the texture float fScale = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? ((float)g_PrefsDlg.m_nTextureScale / 100) : 1.0; mat->GetEditorImage()->Bind(); QE_CheckOpenGLForErrors(); qglColor3f(1, 1, 1); qglBegin(GL_QUADS); qglTexCoord2f(0, 0); qglVertex2f(draw.x, draw.y - FONT_HEIGHT); qglTexCoord2f(1, 0); qglVertex2f(draw.x + width, draw.y - FONT_HEIGHT); qglTexCoord2f(1, 1); qglVertex2f(draw.x + width, draw.y - FONT_HEIGHT - height); qglTexCoord2f(0, 1); qglVertex2f(draw.x, draw.y - FONT_HEIGHT - height); qglEnd(); // draw the selection border if ( !idStr::Icmp(g_qeglobals.d_texturewin.texdef.name, mat->GetName()) ) { qglLineWidth(3); qglColor3f(1, 0, 0); globalImages->BindNull(); qglBegin(GL_LINE_LOOP); qglVertex2f(draw.x - 4, draw.y - FONT_HEIGHT + 4); qglVertex2f(draw.x - 4, draw.y - FONT_HEIGHT - height - 4); qglVertex2f(draw.x + 4 + width, draw.y - FONT_HEIGHT - height - 4); qglVertex2f(draw.x + 4 + width, draw.y - FONT_HEIGHT + 4); qglEnd(); qglLineWidth(1); } // draw the texture name globalImages->BindNull(); qglColor3f(1, 1, 1); qglRasterPos2f(draw.x, draw.y - FONT_HEIGHT + 2); // don't draw the directory name for (name = mat->GetName(); *name && *name != '/' && *name != '\\'; name++) { ; } if (!*name) { name = mat->GetName(); } else { name++; } qglCallLists(strlen(name), GL_UNSIGNED_BYTE, name); //qglCallLists(va("%s -- %d, %d" strlen(name), GL_UNSIGNED_BYTE, name); } } g_qeglobals.d_texturewin.m_nTotalHeight = abs(draw.y) + 100; // reset the current texture globalImages->BindNull(); qglFinish(); qwglSwapBuffers(dc.GetSafeHdc()); TRACE("Texture Paint\n"); } if (g_PrefsDlg.m_bTextureScrollbar && (m_bNeedRange || g_qeglobals.d_texturewin.m_nTotalHeight != nOld)) { m_bNeedRange = false; SetScrollRange(SB_VERT, 0, g_qeglobals.d_texturewin.m_nTotalHeight, TRUE); } //ReleaseDC(hdcTexture); }