void idSplineList::draw(bool editMode) { int i; vec4_t 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 glBox(idVec3_t &color, idVec3_t &point, float size) { idVec3_t mins(point); idVec3_t maxs(point); mins[0] -= size; mins[1] += size; mins[2] -= size; maxs[0] += size; maxs[1] -= size; maxs[2] += size; qglColor3fv(color); qglBegin(GL_LINE_LOOP); qglVertex3f(mins[0],mins[1],mins[2]); qglVertex3f(maxs[0],mins[1],mins[2]); qglVertex3f(maxs[0],maxs[1],mins[2]); qglVertex3f(mins[0],maxs[1],mins[2]); qglEnd(); qglBegin(GL_LINE_LOOP); qglVertex3f(mins[0],mins[1],maxs[2]); qglVertex3f(maxs[0],mins[1],maxs[2]); qglVertex3f(maxs[0],maxs[1],maxs[2]); qglVertex3f(mins[0],maxs[1],maxs[2]); qglEnd(); qglBegin(GL_LINES); qglVertex3f(mins[0],mins[1],mins[2]); qglVertex3f(mins[0],mins[1],maxs[2]); qglVertex3f(mins[0],maxs[1],maxs[2]); qglVertex3f(mins[0],maxs[1],mins[2]); qglVertex3f(maxs[0],mins[1],mins[2]); qglVertex3f(maxs[0],mins[1],maxs[2]); qglVertex3f(maxs[0],maxs[1],maxs[2]); qglVertex3f(maxs[0],maxs[1],mins[2]); qglEnd(); }
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 SetColor(face_t* f, float fColor[3]) { return; if (g_bCamPaint) { fColor[0] = f->d_color[0]; fColor[1] = f->d_color[1]; fColor[2] = f->d_color[2]; qglColor3fv(fColor); } }
/* ================ glLabeledPoint ================ */ void glLabeledPoint(idVec4 &color, idVec3 &point, float size, const char *label) { qglColor3fv( color.ToFloatPtr() ); qglPointSize( size ); qglBegin( GL_POINTS ); qglVertex3fv( point.ToFloatPtr() ); qglEnd(); idVec3 v = point; v.x += 1; v.y += 1; v.z += 1; qglRasterPos3fv( v.ToFloatPtr() ); qglCallLists( strlen(label), GL_UNSIGNED_BYTE, label ); }
void DecColor(float fColor[3]) { return; if (g_bCamPaint) { fColor[0] -= fDec; fColor[1] -= fDec ; fColor[2] -= fDec; for (int i = 0; i < 3; i++) { if (fColor[i] <= fLowerLimit) fColor[i] = fFullBright; } qglColor3fv(fColor); } }
void GLRB_DrawBeam( const image_t* image, const float* color, const vec3_t startPoints[], const vec3_t endPoints[], int segs ) { int i; GL_Bind( image ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); qglColor3fv( color ); qglBegin( GL_TRIANGLE_STRIP ); for ( i = 0; i <= segs; i++ ) { qglVertex3fv( startPoints[ i % segs] ); qglVertex3fv( endPoints[ i % segs] ); } qglEnd(); }
/* ================ glBox ================ */ void glBox(idVec4 &color, idVec3 &point, float size) { idVec3 mins(point); idVec3 maxs(point); mins[0] -= size; mins[1] += size; mins[2] -= size; maxs[0] += size; maxs[1] -= size; maxs[2] += size; idVec4 saveColor; qglGetFloatv(GL_CURRENT_COLOR, saveColor.ToFloatPtr()); qglColor3fv( color.ToFloatPtr() ); qglBegin(GL_LINE_LOOP); qglVertex3f(mins[0],mins[1],mins[2]); qglVertex3f(maxs[0],mins[1],mins[2]); qglVertex3f(maxs[0],maxs[1],mins[2]); qglVertex3f(mins[0],maxs[1],mins[2]); qglEnd(); qglBegin(GL_LINE_LOOP); qglVertex3f(mins[0],mins[1],maxs[2]); qglVertex3f(maxs[0],mins[1],maxs[2]); qglVertex3f(maxs[0],maxs[1],maxs[2]); qglVertex3f(mins[0],maxs[1],maxs[2]); qglEnd(); qglBegin(GL_LINES); qglVertex3f(mins[0],mins[1],mins[2]); qglVertex3f(mins[0],mins[1],maxs[2]); qglVertex3f(mins[0],maxs[1],maxs[2]); qglVertex3f(mins[0],maxs[1],mins[2]); qglVertex3f(maxs[0],mins[1],mins[2]); qglVertex3f(maxs[0],mins[1],maxs[2]); qglVertex3f(maxs[0],maxs[1],maxs[2]); qglVertex3f(maxs[0],maxs[1],mins[2]); qglEnd(); qglColor4fv(saveColor.ToFloatPtr()); }
void GLRB_DrawSkyBox( const skyboxDrawInfo_t* skybox, const float* eye_origin, const float* colorTint ) { int i, j, k; qglColor3fv( colorTint ); qglPushMatrix (); GL_State( 0 ); qglTranslatef( eye_origin[0], eye_origin[1], eye_origin[2] ); for ( i = 0; i < 6; ++i ) { const skyboxSideDrawInfo_t* side = &skybox->sides[i]; if ( !side->image ) continue; GL_Bind( side->image ); for ( j = 0; j < side->stripCount; ++j ) { int start = side->stripInfo[j].offset; int end = side->stripInfo[j].length + start; qglBegin( GL_TRIANGLE_STRIP ); for ( k = start; k < end; ++k ) { qglTexCoord2fv( skybox->tbuffer + 2 * k ); qglVertex3fv( skybox->vbuffer + 3 * k ); } qglEnd(); } } qglPopMatrix(); }
/* ============== Z_Draw ============== */ void Z_Draw (void) { brush_t *brush; float w, h; double start, end; qtexture_t *q; float top, bottom; vec3_t org_top, org_bottom, dir_up, dir_down; int xCam = z.width/3; if (!active_brushes.next) return; // not valid yet if (z.timing) start = Sys_DoubleTime (); // // clear // qglViewport(0, 0, z.width, z.height); qglClearColor ( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2], 0); /* GL Bug */ /* When not using hw acceleration, gl will fault if we clear the depth buffer bit on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT only after Z_Draw() has been called once. Yeah, right. */ qglClear(glbitClear); glbitClear |= GL_DEPTH_BUFFER_BIT; qglMatrixMode(GL_PROJECTION); qglLoadIdentity (); w = z.width/2 / z.scale; h = z.height/2 / z.scale; qglOrtho (-w, w, z.origin[2]-h, z.origin[2]+h, -8, 8); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_1D); qglDisable(GL_DEPTH_TEST); qglDisable(GL_BLEND); // // now draw the grid // Z_DrawGrid (); // // draw stuff // qglDisable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglDisable(GL_TEXTURE_2D); qglDisable(GL_BLEND); qglDisable(GL_DEPTH_TEST); // draw filled interiors and edges dir_up[0] = 0 ; dir_up[1] = 0; dir_up[2] = 1; dir_down[0] = 0 ; dir_down[1] = 0; dir_down[2] = -1; VectorCopy (z.origin, org_top); org_top[2] = MAX_WORLD_COORD;//4096; // MAX_WORLD_COORD ? (John said this didn't work, Hmmmmmm) // !suspect! VectorCopy (z.origin, org_bottom); org_bottom[2] = MIN_WORLD_COORD;//-4096; // MIN_WORLD_COORD? " " !suspect! for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) { if (brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1]) continue; if (!Brush_Ray (org_top, dir_down, brush, &top)) continue; top = org_top[2] - top; if (!Brush_Ray (org_bottom, dir_up, brush, &bottom)) continue; bottom = org_bottom[2] + bottom; q = Texture_ForName (brush->brush_faces->texdef.name); qglColor3f (q->color[0], q->color[1], q->color[2]); qglBegin (GL_QUADS); qglVertex2f (-xCam, bottom); qglVertex2f (xCam, bottom); qglVertex2f (xCam, top); qglVertex2f (-xCam, top); qglEnd (); qglColor3f (1,1,1); qglBegin (GL_LINE_LOOP); qglVertex2f (-xCam, bottom); qglVertex2f (xCam, bottom); qglVertex2f (xCam, top); qglVertex2f (-xCam, top); qglEnd (); } // // now draw selected brushes // for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) { if ( !(brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1]) ) { if (Brush_Ray (org_top, dir_down, brush, &top)) { top = org_top[2] - top; if (Brush_Ray (org_bottom, dir_up, brush, &bottom)) { bottom = org_bottom[2] + bottom; q = Texture_ForName (brush->brush_faces->texdef.name); qglColor3f (q->color[0], q->color[1], q->color[2]); qglBegin (GL_QUADS); qglVertex2f (-xCam, bottom); qglVertex2f (xCam, bottom); qglVertex2f (xCam, top); qglVertex2f (-xCam, top); qglEnd (); } } } qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); qglBegin (GL_LINE_LOOP); qglVertex2f (-xCam, brush->mins[2]); qglVertex2f (xCam, brush->mins[2]); qglVertex2f (xCam, brush->maxs[2]); qglVertex2f (-xCam, brush->maxs[2]); qglEnd (); } ZDrawCameraIcon (); ZDrawZClip(); qglFinish(); QE_CheckOpenGLForErrors(); if (z.timing) { end = Sys_DoubleTime (); Sys_Printf ("z: %i ms\n", (int)(1000*(end-start))); } }
/* ============== Z_DrawGrid ============== */ void Z_DrawGrid (void) { float zz, zb, ze; int w, h; char text[32]; w = z.width/2 / z.scale; h = z.height/2 / z.scale; zb = z.origin[2] - h; if (zb < region_mins[2]) zb = region_mins[2]; zb = 64 * floor (zb/64); ze = z.origin[2] + h; if (ze > region_maxs[2]) ze = region_maxs[2]; ze = 64 * ceil (ze/64); // draw major blocks qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); qglBegin (GL_LINES); qglVertex2f (0, zb); qglVertex2f (0, ze); for (zz=zb ; zz<ze ; zz+=64) { qglVertex2f (-w, zz); qglVertex2f (w, zz); } qglEnd (); // draw minor blocks if (g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*z.scale >= 4 && g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR] != g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK]) { qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); qglBegin (GL_LINES); for (zz=zb ; zz<ze ; zz+=g_qeglobals.d_gridsize) { if ( ! ((int)zz & 63) ) continue; qglVertex2f (-w, zz); qglVertex2f (w, zz); } qglEnd (); } // draw coordinate text if needed qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT]); for (zz=zb ; zz<ze ; zz+=64) { qglRasterPos2f (-w+1, zz); sprintf (text, "%i",(int)zz); qglCallLists (strlen(text), GL_UNSIGNED_BYTE, text); } }
/* ============== Z_DrawGrid ============== */ void Z_DrawGrid (void) { float zz, zb, ze; float w, h; char text[32]; w = (z.width/2 / z.scale); h = (z.height/2 / z.scale); zb = z.origin[2] - h; if (zb < region_mins[2]) zb = region_mins[2]; zb = 64 * floor (zb/64); ze = z.origin[2] + h; if (ze > region_maxs[2]) ze = region_maxs[2]; ze = 64 * ceil (ze/64); // draw major blocks qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); if ( g_qeglobals.d_showgrid ) { if (g_qeglobals.d_gridsize < 128) { qglBegin (GL_LINES); qglVertex2f (0, zb); qglVertex2f (0, ze); for (zz=zb ; zz<ze ; zz+=64) { qglVertex2f (-w, zz); qglVertex2f (w, zz); } qglEnd (); } else { qglBegin (GL_LINES); qglVertex2f (0, zb); qglVertex2f (0, ze); for (zz=zb ; zz<ze ; zz+=64) { // d_gridsize >= 128 .. it's an int for sure if ( ((int)zz & ((int)g_qeglobals.d_gridsize-1)) != 0 ) continue; qglVertex2f (-w, zz); qglVertex2f (w, zz); } qglEnd (); } } // draw minor blocks if (g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*z.scale >= 4 && g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR] != g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK]) { qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); qglBegin (GL_LINES); for (zz=zb ; zz<ze ; zz+=g_qeglobals.d_gridsize) { if ( ! ((int)zz & 63) ) continue; qglVertex2f (-w, zz); qglVertex2f (w, zz); } qglEnd (); } // draw coordinate text if needed if ( g_qeglobals.d_savedinfo.show_coordinates) { qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT]); int step = (int)(g_qeglobals.d_gridsize > 64 ? g_qeglobals.d_gridsize : 64); zb = z.origin[2] - h; if (zb < region_mins[2]) zb = region_mins[2]; zb = step * floor (zb/step); for (zz=zb ; zz<ze ; zz+=step) { qglRasterPos2f (-w+(1/z.scale), zz); sprintf (text, "%i",(int)zz); gtk_glwidget_print_string(text); } } }
/* ================== RB_FogPass ================== */ static void RB_FogPass( const drawSurf_t *drawSurfs, const drawSurf_t *drawSurfs2 ) { const srfTriangles_t*frustumTris; drawSurf_t ds; const idMaterial *lightShader; const shaderStage_t *stage; const float *regs; // create a surface for the light frustom triangles, which are oriented drawn side out frustumTris = backEnd.vLight->frustumTris; // if we ran out of vertex cache memory, skip it if ( !frustumTris->ambientCache ) { return; } memset( &ds, 0, sizeof( ds ) ); ds.space = &backEnd.viewDef->worldSpace; ds.geo = frustumTris; ds.scissorRect = backEnd.viewDef->scissor; // find the current color and density of the fog lightShader = backEnd.vLight->lightShader; regs = backEnd.vLight->shaderRegisters; // assume fog shaders have only a single stage stage = lightShader->GetStage(0); backEnd.lightColor[0] = regs[ stage->color.registers[0] ]; backEnd.lightColor[1] = regs[ stage->color.registers[1] ]; backEnd.lightColor[2] = regs[ stage->color.registers[2] ]; backEnd.lightColor[3] = regs[ stage->color.registers[3] ]; qglColor3fv( backEnd.lightColor ); // calculate the falloff planes float a; // if they left the default value on, set a fog distance of 500 if ( backEnd.lightColor[3] <= 1.0 ) { a = -0.5f / DEFAULT_FOG_DISTANCE; } else { // otherwise, distance = alpha color a = -0.5f / backEnd.lightColor[3]; } GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); // texture 0 is the falloff image GL_SelectTexture( 0 ); globalImages->fogImage->Bind(); //GL_Bind( tr.whiteImage ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnable( GL_TEXTURE_GEN_S ); qglEnable( GL_TEXTURE_GEN_T ); qglTexCoord2f( 0.5f, 0.5f ); // make sure Q is set fogPlanes[0][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[2]; fogPlanes[0][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[6]; fogPlanes[0][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[10]; fogPlanes[0][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[14]; fogPlanes[1][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[0]; fogPlanes[1][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[4]; fogPlanes[1][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[8]; fogPlanes[1][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[12]; // texture 1 is the entering plane fade correction GL_SelectTexture( 1 ); globalImages->fogEnterImage->Bind(); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnable( GL_TEXTURE_GEN_S ); qglEnable( GL_TEXTURE_GEN_T ); // T will get a texgen for the fade plane, which is always the "top" plane on unrotated lights fogPlanes[2][0] = 0.001f * backEnd.vLight->fogPlane[0]; fogPlanes[2][1] = 0.001f * backEnd.vLight->fogPlane[1]; fogPlanes[2][2] = 0.001f * backEnd.vLight->fogPlane[2]; fogPlanes[2][3] = 0.001f * backEnd.vLight->fogPlane[3]; // S is based on the view origin float s = backEnd.viewDef->renderView.vieworg * fogPlanes[2].Normal() + fogPlanes[2][3]; fogPlanes[3][0] = 0; fogPlanes[3][1] = 0; fogPlanes[3][2] = 0; fogPlanes[3][3] = FOG_ENTER + s; qglTexCoord2f( FOG_ENTER + s, FOG_ENTER ); // draw it RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_BasicFog ); RB_RenderDrawSurfChainWithFunction( drawSurfs2, RB_T_BasicFog ); // the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead // of depthfunc_equal GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS ); GL_Cull( CT_BACK_SIDED ); RB_RenderDrawSurfChainWithFunction( &ds, RB_T_BasicFog ); GL_Cull( CT_FRONT_SIDED ); GL_SelectTexture( 1 ); qglDisable( GL_TEXTURE_GEN_S ); qglDisable( GL_TEXTURE_GEN_T ); globalImages->BindNull(); GL_SelectTexture( 0 ); qglDisable( GL_TEXTURE_GEN_S ); qglDisable( GL_TEXTURE_GEN_T ); }
/* ============== 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 }
/* ============== CZWnd::Z_Draw ============== */ void CZWnd::Z_Draw( void ) { brush_t *brush; float w, h; float top, bottom; idVec3 org_top, org_bottom, dir_up, dir_down; int xCam = z.width / 3 / z.scale; // sikk - Keep brush widths proportional to window if ( !active_brushes.next ) { return; // not valid yet } // clear qglViewport( 0, 0, z.width, z.height ); qglScissor( 0, 0, z.width, z.height ); qglClearColor( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2], 0 ); /* * GL Bug £ * When not using hw acceleration, gl will fault if we clear the depth buffer bit * on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT only after * Z_Draw() has been called once. Yeah, right. £ * qglClear(glbitClear); */ qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // // glbitClear |= GL_DEPTH_BUFFER_BIT; // qglClear(GL_DEPTH_BUFFER_BIT); // qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); w = z.width / 2 / z.scale; h = z.height / 2 / z.scale; qglOrtho( -w, w, z.origin[2] - h, z.origin[2] + h, -8, 8 ); globalImages->BindNull(); qglDisable( GL_DEPTH_TEST ); qglDisable( GL_BLEND ); // now draw the grid Z_DrawGrid(); // draw stuff qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); globalImages->BindNull(); // draw filled interiors and edges dir_up[0] = 0; dir_up[1] = 0; dir_up[2] = 1; dir_down[0] = 0; dir_down[1] = 0; dir_down[2] = -1; VectorCopy( z.origin, org_top ); org_top[2] = 4096; VectorCopy( z.origin, org_bottom ); org_bottom[2] = -4096; for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) { if ( brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1] ) { continue; } if ( !Brush_Ray( org_top, dir_down, brush, &top ) ) { continue; } top = org_top[2] - top; if ( !Brush_Ray( org_bottom, dir_up, brush, &bottom ) ) { continue; } bottom = org_bottom[2] + bottom; //q = declManager->FindMaterial( brush->brush_faces->texdef.name ); qglColor3f( brush->owner->eclass->color.x, brush->owner->eclass->color.y, brush->owner->eclass->color.z ); qglBegin( GL_QUADS ); qglVertex2f( -xCam, bottom ); qglVertex2f( xCam, bottom ); qglVertex2f( xCam, top ); qglVertex2f( -xCam, top ); qglEnd(); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINE_LOOP ); qglVertex2f( -xCam, bottom ); qglVertex2f( xCam, bottom ); qglVertex2f( xCam, top ); qglVertex2f( -xCam, top ); qglEnd(); } // now draw selected brushes for ( brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next ) { if ( !( brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1] ) ) { if ( Brush_Ray( org_top, dir_down, brush, &top ) ) { top = org_top[2] - top; if ( Brush_Ray( org_bottom, dir_up, brush, &bottom ) ) { bottom = org_bottom[2] + bottom; //q = declManager->FindMaterial( brush->brush_faces->texdef.name ); qglColor3f( brush->owner->eclass->color.x, brush->owner->eclass->color.y, brush->owner->eclass->color.z ); qglBegin( GL_QUADS ); qglVertex2f( -xCam, bottom ); qglVertex2f( xCam, bottom ); qglVertex2f( xCam, top ); qglVertex2f( -xCam, top ); qglEnd(); } } } qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() ); qglBegin( GL_LINE_LOOP ); qglVertex2f( -xCam, brush->mins[2] ); qglVertex2f( xCam, brush->mins[2] ); qglVertex2f( xCam, brush->maxs[2] ); qglVertex2f( -xCam, brush->maxs[2] ); qglEnd(); } Z_DrawCameraIcon(); Z_DrawZClip(); qglFinish(); QE_CheckOpenGLForErrors(); }
/* ============== CZWnd::Z_DrawGrid ============== */ void CZWnd::Z_DrawGrid( void ) { float zz, zb, ze; int w, h; char text[ 32 ]; w = z.width / 2 / z.scale; h = z.height / 2 / z.scale; // ---> sikk - Fixed Grid // int nSize = 1.0f / g_qeglobals.d_gridsize * 256; float fScale = 1.0f / g_qeglobals.d_gridsize * 8; int stepSize = g_qeglobals.d_gridsize * 8 * fScale / 2 / z.scale; if ( stepSize < g_qeglobals.d_gridsize * 8 ) { stepSize = g_qeglobals.d_gridsize * 8; } else { int i; for ( i = 1; i < stepSize; i <<= 1 ) {} stepSize = i; } // int stepSize = max( 64, g_qeglobals.d_gridsize ); // sikk - Larger Grid Sizes - Added // <--- sikk - Fixed Grid zb = z.origin[2] - h; if ( zb < region_mins[ 2 ] ) { zb = region_mins[ 2 ]; } zb = stepSize * floor( zb / stepSize ); // sikk - Larger Grid Sizes - was 64 ze = z.origin[2] + h; if ( ze > region_maxs[ 2 ] ) { ze = region_maxs[ 2 ]; } ze = stepSize * ceil( ze / stepSize ); // sikk - Larger Grid Sizes - was 64 // draw minor blocks if ( //z.scale > fScale && // sikk - Fixed grid g_qeglobals.d_showgrid && //g_qeglobals.d_gridsize * z.scale >= 4 && !g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMINOR ].Compare( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDBACK ] ) ) { qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMINOR ].ToFloatPtr() ); qglBegin( GL_LINES ); for ( zz = zb; zz < ze; zz += stepSize / 8 ) { // ---> sikk - Fixed grid //if ( !( (int)zz & 63 ) ) { // continue; //} //<--- sikk - Fixed grid qglVertex2f( -w, zz ); qglVertex2f( w, zz ); } qglEnd(); } // draw major blocks qglBegin( GL_LINES ); qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMAJOR ].ToFloatPtr() ); qglVertex2f( 0, zb ); qglVertex2f( 0, ze ); for ( zz = zb; zz < ze; zz += stepSize ) { // sikk - Larger Grid Sizes - was 64 if ( zz == 0 ) { qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDTEXT ].ToFloatPtr() ); } else { qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDMAJOR ].ToFloatPtr() ); } qglVertex2f( -w, zz ); qglVertex2f( w, zz ); } qglEnd(); // draw coordinate text if needed qglColor3fv( g_qeglobals.d_savedinfo.colors[ COLOR_GRIDTEXT ].ToFloatPtr() ); for ( zz = zb; zz < ze; zz += stepSize ) { qglRasterPos2f( -w + 1, zz ); sprintf( text, "%i", (int)zz ); qglCallLists( strlen( text ), GL_UNSIGNED_BYTE, text ); } }