void DrawSkyPolygon (int nump, vec3_t vecs) { int i,j; vec3_t v, av; float s, t, dv; int axis; float *vp; c_sky++; #if 0 glBegin (GL_POLYGON); for (i=0 ; i<nump ; i++, vecs+=3) { VectorAdd(vecs, r_origin, v); qglVertex3fv (v); } glEnd(); return; #endif // decide which face it maps to VectorCopy (vec3_origin, v); for (i=0, vp=vecs ; i<nump ; i++, vp+=3) { VectorAdd (vp, v, v); } av[0] = fabs(v[0]); av[1] = fabs(v[1]); av[2] = fabs(v[2]); if (av[0] > av[1] && av[0] > av[2]) { if (v[0] < 0) axis = 1; else axis = 0; } else if (av[1] > av[2] && av[1] > av[0]) { if (v[1] < 0) axis = 3; else axis = 2; } else { if (v[2] < 0) axis = 5; else axis = 4; } // project new texture coords for (i=0 ; i<nump ; i++, vecs+=3) { j = vec_to_st[axis][2]; if (j > 0) dv = vecs[j - 1]; else dv = -vecs[-j - 1]; if (dv < 0.001) continue; // don't divide by zero j = vec_to_st[axis][0]; if (j < 0) s = -vecs[-j -1] / dv; else s = vecs[j-1] / dv; j = vec_to_st[axis][1]; if (j < 0) t = -vecs[-j -1] / dv; else t = vecs[j-1] / dv; if (s < skymins[0][axis]) skymins[0][axis] = s; if (t < skymins[1][axis]) skymins[1][axis] = t; if (s > skymaxs[0][axis]) skymaxs[0][axis] = s; if (t > skymaxs[1][axis]) skymaxs[1][axis] = t; } }
void R_RenderShadowEdges( void ) { int i; #if 0 int numTris; // dumb way -- render every triangle's edges numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; if ( !facing[i] ) { continue; } i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i3 ] ); qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); qglEnd(); } #else int c, c2; int j, k; int i2; int c_edges, c_rejected; int hit[2]; #ifdef HAVE_GLES idx = 0; #endif // an edge is NOT a silhouette edge if its face doesn't face the light, // or if it has a reverse paired edge that also faces the light. // A well behaved polyhedron would have exactly two faces for each edge, // but lots of models have dangling edges or overfanned edges c_edges = 0; c_rejected = 0; for ( i = 0 ; i < tess.numVertexes ; i++ ) { c = numEdgeDefs[ i ]; for ( j = 0 ; j < c ; j++ ) { if ( !edgeDefs[ i ][ j ].facing ) { continue; } hit[0] = 0; hit[1] = 0; i2 = edgeDefs[ i ][ j ].i2; c2 = numEdgeDefs[ i2 ]; for ( k = 0 ; k < c2 ; k++ ) { if ( edgeDefs[ i2 ][ k ].i2 == i ) { hit[ edgeDefs[ i2 ][ k ].facing ]++; } } // if it doesn't share the edge with another front facing // triangle, it is a sil edge if ( hit[ 1 ] == 0 ) { #ifdef HAVE_GLES // A single drawing call is better than many. So I prefer a singe TRIANGLES call than many TRAINGLE_STRIP call // even if it seems less efficiant, it's faster on the PANDORA indexes[idx++] = i; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2; indexes[idx++] = i2; indexes[idx++] = i + tess.numVertexes; indexes[idx++] = i2 + tess.numVertexes; #else qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); #endif c_edges++; } else { c_rejected++; } } } #ifdef HAVE_GLES qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes); #endif #endif }
/* ============= GL_DrawAliasFrameLerp interpolates between two frames and origins FIXME: batch lerp all vertexes ============= */ void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp) { float l; daliasframe_t *frame, *oldframe; dtrivertx_t *v, *ov, *verts; int *order; int count; float frontlerp; float alpha; vec3_t move, delta, vectors[3]; vec3_t frontv, backv; int i; int index_xyz; float *lerp; frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = v = frame->verts; oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->oldframe * paliashdr->framesize); ov = oldframe->verts; order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); // glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]); // glScalef (frame->scale[0], frame->scale[1], frame->scale[2]); if (currententity->flags & RF_TRANSLUCENT) alpha = currententity->alpha; else alpha = 1.0; // PMM - added double shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) qglDisable( GL_TEXTURE_2D ); frontlerp = 1.0 - backlerp; // move should be the delta back to the previous frame * backlerp VectorSubtract (currententity->oldorigin, currententity->origin, delta); AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); move[0] = DotProduct (delta, vectors[0]); // forward move[1] = -DotProduct (delta, vectors[1]); // left move[2] = DotProduct (delta, vectors[2]); // up VectorAdd (move, oldframe->translate, move); for (i=0 ; i<3 ; i++) { move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; } for (i=0 ; i<3 ; i++) { frontv[i] = frontlerp*frame->scale[i]; backv[i] = backlerp*oldframe->scale[i]; } lerp = s_lerped[0]; GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv ); if ( gl_vertex_arrays->value ) { float colorArray[MAX_VERTS*4]; qglEnableClientState( GL_VERTEX_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 16, s_lerped ); // padded for SIMD // if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha ); } else { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 3, GL_FLOAT, 0, colorArray ); // // pre light everything // for ( i = 0; i < paliashdr->num_xyz; i++ ) { float l = shadedots[verts[i].lightnormalindex]; colorArray[i*3+0] = l * shadelight[0]; colorArray[i*3+1] = l * shadelight[1]; colorArray[i*3+2] = l * shadelight[2]; } } if ( qglLockArraysEXT != 0 ) qglLockArraysEXT( 0, paliashdr->num_xyz ); while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else { qglBegin (GL_TRIANGLE_STRIP); } // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { do { index_xyz = order[2]; order += 3; qglVertex3fv( s_lerped[index_xyz] ); } while (--count); } else { do { // texture coordinates come from the draw list qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; // normals and vertexes come from the frame list // l = shadedots[verts[index_xyz].lightnormalindex]; // qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); qglArrayElement( index_xyz ); } while (--count); } qglEnd (); } if ( qglUnlockArraysEXT != 0 ) qglUnlockArraysEXT(); } else { while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else { qglBegin (GL_TRIANGLE_STRIP); } if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) { do { index_xyz = order[2]; order += 3; qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha); qglVertex3fv (s_lerped[index_xyz]); } while (--count); } else { do { // texture coordinates come from the draw list qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; // normals and vertexes come from the frame list l = shadedots[verts[index_xyz].lightnormalindex]; qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); qglVertex3fv (s_lerped[index_xyz]); } while (--count); } qglEnd (); } } // if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) qglEnable( GL_TEXTURE_2D ); }
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 #ifdef _XBOX int verts = ((maxs[0]+HALF_SKY_SUBDIVISIONS) - (mins[0]+HALF_SKY_SUBDIVISIONS)) * 2 + 2; #endif for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) { #ifdef _XBOX qglBeginEXT( GL_TRIANGLE_STRIP, verts, 0, 0, verts, 0); #else #ifdef HAVE_GLES idx=0; #else qglBegin( GL_TRIANGLE_STRIP ); #endif #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 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 }
void CWind::Render(CWorldEffectsSystem *system) { vec3_t output; if (!mEnabled || !debugShowWind) { return; } qglDisable(GL_TEXTURE_2D); qglDisable(GL_CULL_FACE); GL_State(GLS_ALPHA); qglColor4f(1.0, 0.0, 0.0, 0.5); qglBegin(GL_QUADS); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, (mSize[1]/2.0), mPlanes[1], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, (mSize[1]/2.0), mPlanes[1], output); VectorMA(output, (mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); VectorMA(output, (mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); qglColor4f(0.0, 1.0, 0.0, 0.5); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); VectorMA(mPoint, (mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); VectorMA(mPoint, (mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); VectorMA(output, (mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); VectorMA(output, (mSize[2]/2.0), mPlanes[2], output); qglVertex3fv(output); qglColor4f(0.0, 0.0, 1.0, 0.5); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); qglVertex3fv(output); VectorMA(mPoint, (mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); VectorMA(output, -(mSize[1]/2.0), mPlanes[1], output); qglVertex3fv(output); VectorMA(mPoint, (mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); VectorMA(output, (mSize[1]/2.0), mPlanes[1], output); qglVertex3fv(output); VectorMA(mPoint, -(mSize[0]/2.0), mPlanes[0], output); VectorMA(output, -(mSize[2]/2.0), mPlanes[2], output); VectorMA(output, (mSize[1]/2.0), mPlanes[1], output); qglVertex3fv(output); qglEnd(); qglEnable(GL_CULL_FACE); qglEnable(GL_TEXTURE_2D); }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i; dmdl_t *paliashdr; float an; vec3_t bbox[8]; image_t *skin; if ( !( e->flags & RF_WEAPONMODEL ) ) { if ( R_CullAliasModel( bbox, e ) ) return; } if ( e->flags & RF_WEAPONMODEL ) { if ( r_lefthand->value == 2 ) return; } paliashdr = (dmdl_t *)currentmodel->extradata; // // get lighting information // // PMM - rewrote, reordered to handle new shells & mixing // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy // if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if (currententity->flags & RF_SHELL_HALF_DAM) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } if ( currententity->flags & RF_SHELL_RED ) shadelight[0] = 1.0; if ( currententity->flags & RF_SHELL_GREEN ) shadelight[1] = 1.0; if ( currententity->flags & RF_SHELL_BLUE ) shadelight[2] = 1.0; } /* // PMM -special case for godmode if ( (currententity->flags & RF_SHELL_RED) && (currententity->flags & RF_SHELL_BLUE) && (currententity->flags & RF_SHELL_GREEN) ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if ( currententity->flags & RF_SHELL_RED ) { shadelight[0] = 1.0; if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) ) shadelight[2] = 1.0; } else if ( currententity->flags & RF_SHELL_BLUE ) { if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[1] = 1.0; shadelight[2] = 1.0; } else { shadelight[2] = 1.0; } } else if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } } else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) ) { VectorClear (shadelight); // PMM - new colors if ( currententity->flags & RF_SHELL_HALF_DAM ) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_GREEN ) { shadelight[1] = 1.0; } } } //PMM - ok, now flatten these down to range from 0 to 1.0. // max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2])); // if (max_shell_val > 0) // { // for (i=0; i<3; i++) // { // shadelight[i] = shadelight[i] / max_shell_val; // } // } // pmm */ else if ( currententity->flags & RF_FULLBRIGHT ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else { R_LightPoint (currententity->origin, shadelight); // player lighting hack for communication back to server // big hack! if ( currententity->flags & RF_WEAPONMODEL ) { // pick the greatest component, which should be the same // as the mono value returned by software if (shadelight[0] > shadelight[1]) { if (shadelight[0] > shadelight[2]) r_lightlevel->value = 150*shadelight[0]; else r_lightlevel->value = 150*shadelight[2]; } else { if (shadelight[1] > shadelight[2]) r_lightlevel->value = 150*shadelight[1]; else r_lightlevel->value = 150*shadelight[2]; } } if ( gl_monolightmap->string[0] != '0' ) { float s = shadelight[0]; if ( s < shadelight[1] ) s = shadelight[1]; if ( s < shadelight[2] ) s = shadelight[2]; shadelight[0] = s; shadelight[1] = s; shadelight[2] = s; } } if ( currententity->flags & RF_MINLIGHT ) { for (i=0 ; i<3 ; i++) if (shadelight[i] > 0.1) break; if (i == 3) { shadelight[0] = 0.1; shadelight[1] = 0.1; shadelight[2] = 0.1; } } if ( currententity->flags & RF_GLOW ) { // bonus items will pulse with time float scale; float min; scale = 0.1 * sin(r_newrefdef.time*7); for (i=0 ; i<3 ; i++) { min = shadelight[i] * 0.8; shadelight[i] += scale; if (shadelight[i] < min) shadelight[i] = min; } } // ================= // PGM ir goggles color override if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) { shadelight[0] = 1.0; shadelight[1] = 0.0; shadelight[2] = 0.0; } // PGM // ================= shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; an = currententity->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // c_alias_polys += paliashdr->num_tris; // // draw all the triangles // if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); qglMatrixMode( GL_PROJECTION ); qglPushMatrix(); qglLoadIdentity(); qglScalef( -1, 1, 1 ); // jkrige - increased far plane MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 6144); //MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); // jkrige - increased far plane qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_BACK ); } qglPushMatrix (); e->angles[PITCH] = -e->angles[PITCH]; // sigh. R_RotateForEntity (e); e->angles[PITCH] = -e->angles[PITCH]; // sigh. // select skin if (currententity->skin) skin = currententity->skin; // custom player skin else { if (currententity->skinnum >= MAX_MD2SKINS) skin = currentmodel->skins[0]; else { skin = currentmodel->skins[currententity->skinnum]; if (!skin) skin = currentmodel->skins[0]; } } if (!skin) skin = r_notexture; // fallback... GL_Bind(skin->texnum); // draw it qglShadeModel (GL_SMOOTH); GL_TexEnv( GL_MODULATE ); if ( currententity->flags & RF_TRANSLUCENT ) { qglEnable (GL_BLEND); } if ( (currententity->frame >= paliashdr->num_frames) || (currententity->frame < 0) ) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame); currententity->frame = 0; currententity->oldframe = 0; } if ( (currententity->oldframe >= paliashdr->num_frames) || (currententity->oldframe < 0)) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe); currententity->frame = 0; currententity->oldframe = 0; } if ( !r_lerpmodels->value ) currententity->backlerp = 0; GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp); GL_TexEnv( GL_REPLACE ); qglShadeModel (GL_FLAT); qglPopMatrix (); #if 0 qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDisable( GL_TEXTURE_2D ); qglBegin( GL_TRIANGLE_STRIP ); for ( i = 0; i < 8; i++ ) { qglVertex3fv( bbox[i] ); } qglEnd(); qglEnable( GL_TEXTURE_2D ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglEnable( GL_CULL_FACE ); #endif if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { qglMatrixMode( GL_PROJECTION ); qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_FRONT ); } if ( currententity->flags & RF_TRANSLUCENT ) { qglDisable (GL_BLEND); } if (currententity->flags & RF_DEPTHHACK) qglDepthRange (gldepthmin, gldepthmax); // jkrige - removed alias shadows #if 0 if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL))) { qglPushMatrix (); R_RotateForEntity (e); qglDisable (GL_TEXTURE_2D); qglEnable (GL_BLEND); qglColor4f (0,0,0,0.5); GL_DrawAliasShadow (paliashdr, currententity->frame ); qglEnable (GL_TEXTURE_2D); qglDisable (GL_BLEND); qglPopMatrix (); } #endif // jkrige - removed alias shadows qglColor4f (1,1,1,1); }
/* =============== CreateOptTri =============== */ static void CreateOptTri( optVertex_t *first, optEdge_t *e1, optEdge_t *e2, optIsland_t *island ) { optEdge_t *opposite; optVertex_t *second, *third; optTri_t *optTri; mapTri_t *tri; if ( e1->v1 == first ) { second = e1->v2; } else if ( e1->v2 == first ) { second = e1->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); return; } if ( e2->v1 == first ) { third = e2->v2; } else if ( e2->v2 == first ) { third = e2->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); return; } if ( !IsTriangleValid( first, second, third ) ) { common->Error( "CreateOptTri: invalid" ); return; } //DrawEdges( island ); // identify the third edge if ( dmapGlobals.drawflag ) { qglColor3f(1,1,0); qglBegin( GL_LINES ); qglVertex3fv( e1->v1->pv.ToFloatPtr() ); qglVertex3fv( e1->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); qglColor3f(0,1,1); qglBegin( GL_LINES ); qglVertex3fv( e2->v1->pv.ToFloatPtr() ); qglVertex3fv( e2->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } for ( opposite = second->edges ; opposite ; ) { if ( opposite != e1 && ( opposite->v1 == third || opposite->v2 == third ) ) { break; } if ( opposite->v1 == second ) { opposite = opposite->v1link; } else if ( opposite->v2 == second ) { opposite = opposite->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); return; } } if ( !opposite ) { common->Printf( "Warning: BuildOptTriangles: couldn't locate opposite\n" ); return; } if ( dmapGlobals.drawflag ) { qglColor3f(1,0,1); qglBegin( GL_LINES ); qglVertex3fv( opposite->v1->pv.ToFloatPtr() ); qglVertex3fv( opposite->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // create new triangle optTri = (optTri_t *)Mem_Alloc( sizeof( *optTri ) ); optTri->v[0] = first; optTri->v[1] = second; optTri->v[2] = third; optTri->midpoint = ( optTri->v[0]->pv + optTri->v[1]->pv + optTri->v[2]->pv ) * ( 1.0f / 3.0f ); optTri->next = island->tris; island->tris = optTri; if ( dmapGlobals.drawflag ) { qglColor3f( 1, 1, 1 ); qglPointSize( 4 ); qglBegin( GL_POINTS ); qglVertex3fv( optTri->midpoint.ToFloatPtr() ); qglEnd(); qglFlush(); } // find the midpoint, and scan through all the original triangles to // see if it is inside any of them for ( tri = island->group->triList ; tri ; tri = tri->next ) { if ( PointInTri( optTri->midpoint, tri, island ) ) { break; } } if ( tri ) { optTri->filled = true; } else { optTri->filled = false; } if ( dmapGlobals.drawflag ) { if ( optTri->filled ) { qglColor3f( ( 128 + orandom.RandomInt( 127 ) )/ 255.0, 0, 0 ); } else { qglColor3f( 0, ( 128 + orandom.RandomInt( 127 ) ) / 255.0, 0 ); } qglBegin( GL_TRIANGLES ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINE_LOOP ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // link the triangle to it's edges LinkTriToEdge( optTri, e1 ); LinkTriToEdge( optTri, e2 ); LinkTriToEdge( optTri, opposite ); }
/* ==================== BuildOptTriangles Generate a new list of triangles from the optEdeges ==================== */ static void BuildOptTriangles( optIsland_t *island ) { optVertex_t *ov, *second, *third, *middle; optEdge_t *e1, *e1Next, *e2, *e2Next, *check, *checkNext; // free them FreeOptTriangles( island ); // clear the vertex emitted flags for ( ov = island->verts ; ov ; ov = ov->islandLink ) { ov->emited = false; } // clear the edge triangle links for ( check = island->edges ; check ; check = check->islandLink ) { check->frontTri = check->backTri = NULL; } // check all possible triangle made up out of the // edges coming off the vertex for ( ov = island->verts ; ov ; ov = ov->islandLink ) { if ( !ov->edges ) { continue; } #if 0 if ( dmapGlobals.drawflag && ov == (optVertex_t *)0x1845a60 ) { for ( e1 = ov->edges ; e1 ; e1 = e1Next ) { qglBegin( GL_LINES ); qglColor3f( 0,1,0 ); qglVertex3fv( e1->v1->pv.ToFloatPtr() ); qglVertex3fv( e1->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); if ( e1->v1 == ov ) { e1Next = e1->v1link; } else if ( e1->v2 == ov ) { e1Next = e1->v2link; } } } #endif for ( e1 = ov->edges ; e1 ; e1 = e1Next ) { if ( e1->v1 == ov ) { second = e1->v2; e1Next = e1->v1link; } else if ( e1->v2 == ov ) { second = e1->v1; e1Next = e1->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } // if the vertex has already been used, it can't be used again if ( second->emited ) { continue; } for ( e2 = ov->edges ; e2 ; e2 = e2Next ) { if ( e2->v1 == ov ) { third = e2->v2; e2Next = e2->v1link; } else if ( e2->v2 == ov ) { third = e2->v1; e2Next = e2->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } if ( e2 == e1 ) { continue; } // if the vertex has already been used, it can't be used again if ( third->emited ) { continue; } // if the triangle is backwards or degenerate, don't use it if ( !IsTriangleValid( ov, second, third ) ) { continue; } // see if any other edge bisects these two, which means // this triangle shouldn't be used for ( check = ov->edges ; check ; check = checkNext ) { if ( check->v1 == ov ) { middle = check->v2; checkNext = check->v1link; } else if ( check->v2 == ov ) { middle = check->v1; checkNext = check->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } if ( check == e1 || check == e2 ) { continue; } if ( IsTriangleValid( ov, second, middle ) && IsTriangleValid( ov, middle, third ) ) { break; // should use the subdivided ones } } if ( check ) { continue; // don't use it } // the triangle is valid CreateOptTri( ov, e1, e2, island ); } } // later vertexes will not emit triangles that use an // edge that this vert has already used ov->emited = true; } }
/* ============== 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((float) surface->numVerts * lodScale); } else { render_count = ROUND_INT((float) 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); #if 0 // TODO: OpenGL ES renderer 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(); #endif // 0 // connect to our parent if it's valid if (validBones[boneInfo[*boneRefs].parent]) { qglLineWidth(2); #if 0 // TODO: OpenGL ES renderer qglBegin(GL_LINES); qglColor3f(.6, .6, .6); qglVertex3fv(bonePtr->translation); qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation); qglEnd(); #endif } 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); #if 0 // TODO: OpenGL ES renderer 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(); #endif // 0 // track debug stats if (r_bonesDebug->integer == 4) { totalrv += render_count; totalrt += render_indexes / 3; totalv += surface->numVerts; totalt += surface->numTriangles; } if (r_bonesDebug->integer == 3) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles, ( float )(100.0 * render_indexes / 3) / (float) surface->numTriangles); } } } if (r_bonesDebug->integer > 1) { // dont draw the actual surface tess.numIndexes = oldIndexes; tess.numVertexes = baseVertex; return; } #ifdef DBG_PROFILE_BONES Ren_Print("\n"); #endif }
static void RemoveIfColinear( optVertex_t *ov, optIsland_t *island ) { optEdge_t *e, *e1, *e2; optVertex_t *v1, *v2, *v3; idVec3 dir1, dir2; float dist; idVec3 point; idVec3 offset; float off; v2 = ov; // we must find exactly two edges before testing for colinear e1 = NULL; e2 = NULL; for ( e = ov->edges ; e ; ) { if ( !e1 ) { e1 = e; } else if ( !e2 ) { e2 = e; } else { return; // can't remove a vertex with three edges } if ( e->v1 == v2 ) { e = e->v1link; } else if ( e->v2 == v2 ) { e = e->v2link; } else { common->Error( "RemoveIfColinear: mislinked edge" ); return; } } // can't remove if no edges if ( !e1 ) { return; } if ( !e2 ) { // this may still happen legally when a tiny triangle is // the only thing in a group common->Printf( "WARNING: vertex with only one edge\n" ); return; } if ( e1->v1 == v2 ) { v1 = e1->v2; } else if ( e1->v2 == v2 ) { v1 = e1->v1; } else { common->Error( "RemoveIfColinear: mislinked edge" ); return; } if ( e2->v1 == v2 ) { v3 = e2->v2; } else if ( e2->v2 == v2 ) { v3 = e2->v1; } else { common->Error( "RemoveIfColinear: mislinked edge" ); return; } if ( v1 == v3 ) { common->Error( "RemoveIfColinear: mislinked edge" ); return; } // they must point in opposite directions dist = ( v3->pv - v2->pv ) * ( v1->pv - v2->pv ); if ( dist >= 0 ) { return; } // see if they are colinear VectorSubtract( v3->v.xyz, v1->v.xyz, dir1 ); dir1.Normalize(); VectorSubtract( v2->v.xyz, v1->v.xyz, dir2 ); dist = DotProduct( dir2, dir1 ); VectorMA( v1->v.xyz, dist, dir1, point ); VectorSubtract( point, v2->v.xyz, offset ); off = offset.Length(); if ( off > COLINEAR_EPSILON ) { return; } if ( dmapGlobals.drawflag ) { qglBegin( GL_LINES ); qglColor3f( 1, 1, 0 ); qglVertex3fv( v1->pv.ToFloatPtr() ); qglVertex3fv( v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); qglBegin( GL_LINES ); qglColor3f( 0, 1, 1 ); qglVertex3fv( v2->pv.ToFloatPtr() ); qglVertex3fv( v3->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // replace the two edges with a single edge UnlinkEdge( e1, island ); UnlinkEdge( e2, island ); // v2 should have no edges now if ( v2->edges ) { common->Error( "RemoveIfColinear: didn't remove properly" ); return; } // if there is an existing edge that already // has these exact verts, we have just collapsed a // sliver triangle out of existance, and all the edges // can be removed for ( e = island->edges ; e ; e = e->islandLink ) { if ( ( e->v1 == v1 && e->v2 == v3 ) || ( e->v1 == v3 && e->v2 == v1 ) ) { UnlinkEdge( e, island ); RemoveIfColinear( v1, island ); RemoveIfColinear( v3, island ); return; } } // if we can't add the combined edge, link // the originals back in if ( !TryAddNewEdge( v1, v3, island ) ) { e1->islandLink = island->edges; island->edges = e1; LinkEdge( e1 ); e2->islandLink = island->edges; island->edges = e2; LinkEdge( e2 ); return; } // recursively try to combine both verts now, // because things may have changed since the last combine test RemoveIfColinear( v1, island ); RemoveIfColinear( v3, island ); }
void R_RenderShadowEdges( void ) { int i; int c; int j; int i2; #if 0 int c_edges, c_rejected; int c2, k; int hit[2]; #endif #ifdef _STENCIL_REVERSE int numTris; int o1, o2, o3; #endif // an edge is NOT a silhouette edge if its face doesn't face the light, // or if it has a reverse paired edge that also faces the light. // A well behaved polyhedron would have exactly two faces for each edge, // but lots of models have dangling edges or overfanned edges #if 0 c_edges = 0; c_rejected = 0; #endif for ( i = 0 ; i < tess.numVertexes ; i++ ) { c = numEdgeDefs[ i ]; for ( j = 0 ; j < c ; j++ ) { if ( !edgeDefs[ i ][ j ].facing ) { continue; } //with this system we can still get edges shared by more than 2 tris which //produces artifacts including seeing the shadow through walls. So for now //we are going to render all edges even though it is a tiny bit slower. -rww #if 1 i2 = edgeDefs[ i ][ j ].i2; qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); #else hit[0] = 0; hit[1] = 0; i2 = edgeDefs[ i ][ j ].i2; c2 = numEdgeDefs[ i2 ]; for ( k = 0 ; k < c2 ; k++ ) { if ( edgeDefs[ i2 ][ k ].i2 == i ) { hit[ edgeDefs[ i2 ][ k ].facing ]++; } } // if it doesn't share the edge with another front facing // triangle, it is a sil edge if (hit[1] != 1) { qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); qglEnd(); c_edges++; } else { c_rejected++; } #endif } } #ifdef _STENCIL_REVERSE //Carmack Reverse<tm> method requires that volumes //be capped properly -rww numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { if ( !facing[i] ) { continue; } o1 = tess.indexes[ i*3 + 0 ]; o2 = tess.indexes[ i*3 + 1 ]; o3 = tess.indexes[ i*3 + 2 ]; qglBegin(GL_TRIANGLES); qglVertex3fv(tess.xyz[o1]); qglVertex3fv(tess.xyz[o2]); qglVertex3fv(tess.xyz[o3]); qglEnd(); qglBegin(GL_TRIANGLES); qglVertex3fv(tess.xyz[o3 + tess.numVertexes]); qglVertex3fv(tess.xyz[o2 + tess.numVertexes]); qglVertex3fv(tess.xyz[o1 + tess.numVertexes]); qglEnd(); } #endif }
void CCamWnd::Cam_Draw() { brush_t *brush; face_t *face; float screenaspect; float yfov; double start, end; int i; /* FILE *f = fopen("g:/nardo/raduffy/editorhack.dat", "w"); if (f != NULL) { fwrite(&m_Camera.origin[0], sizeof(float), 1, f); fwrite(&m_Camera.origin[1], sizeof(float), 1, f); fwrite(&m_Camera.origin[2], sizeof(float), 1, f); fwrite(&m_Camera.angles[PITCH], sizeof(float), 1, f); fwrite(&m_Camera.angles[YAW], sizeof(float), 1, f); fclose(f); } */ if (!active_brushes.next) return; // not valid yet if (m_Camera.timing) start = Sys_DoubleTime (); // // clear // QE_CheckOpenGLForErrors(); qglViewport(0, 0, m_Camera.width, m_Camera.height); qglScissor(0, 0, m_Camera.width, m_Camera.height); qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // // set up viewpoint // vec5_t lightPos; if (g_PrefsDlg.m_bGLLighting) { qglEnable(GL_LIGHTING); //qglEnable(GL_LIGHT0); lightPos[0] = lightPos[1] = lightPos[2] = 3.5; lightPos[3] = 1.0; qglLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightPos); //qglLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); //lightPos[0] = lightPos[1] = lightPos[2] = 3.5; //qglLightfv(GL_LIGHT0, GL_AMBIENT, lightPos); } else { qglDisable(GL_LIGHTING); } qglMatrixMode(GL_PROJECTION); qglLoadIdentity (); screenaspect = (float)m_Camera.width / m_Camera.height; yfov = 2*atan((float)m_Camera.height / m_Camera.width)*180/Q_PI; qgluPerspective (yfov, screenaspect, 2, 8192); qglRotatef (-90, 1, 0, 0); // put Z going up qglRotatef (90, 0, 0, 1); // put Z going up qglRotatef (m_Camera.angles[0], 0, 1, 0); qglRotatef (-m_Camera.angles[1], 0, 0, 1); qglTranslatef (-m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]); Cam_BuildMatrix (); //if (m_Camera.draw_mode == cd_light) //{ // if (g_PrefsDlg.m_bGLLighting) // { // VectorCopy(m_Camera.origin, lightPos); // lightPos[3] = 1; // qglLightfv(GL_LIGHT0, GL_POSITION, lightPos); // } //} InitCull (); // // draw stuff // GLfloat lAmbient[] = {1.0, 1.0, 1.0, 1.0}; switch (m_Camera.draw_mode) { case cd_wire: qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_1D); qglDisable(GL_BLEND); qglDisable(GL_DEPTH_TEST); qglColor3f(1.0, 1.0, 1.0); // qglEnable (GL_LINE_SMOOTH); break; case cd_solid: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglDisable(GL_TEXTURE_2D); qglDisable(GL_BLEND); qglEnable(GL_DEPTH_TEST); qglDepthFunc (GL_LEQUAL); break; case cd_texture: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglEnable(GL_TEXTURE_2D); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglDisable(GL_BLEND); qglEnable(GL_DEPTH_TEST); qglDepthFunc (GL_LEQUAL); break; case cd_blend: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglEnable(GL_TEXTURE_2D); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglDisable(GL_DEPTH_TEST); qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; } qglMatrixMode(GL_TEXTURE); m_nNumTransBrushes = 0; for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) { //DrawLightRadius(brush); if (CullBrush (brush)) continue; if (FilterBrush (brush)) continue; if ((brush->brush_faces->texdef.flags & (SURF_TRANS33 | SURF_TRANS66)) || (brush->brush_faces->d_texture->bFromShader && brush->brush_faces->d_texture->fTrans != 1.0)) { m_TransBrushes [ m_nNumTransBrushes++ ] = brush; } else { //-- if (brush->patchBrush) //-- m_TransBrushes [ m_nNumTransBrushes++ ] = brush; //-- else Brush_Draw(brush); } } if (g_PrefsDlg.m_bGLLighting) { qglDisable (GL_LIGHTING); } // //qglDepthMask ( 0 ); // Don't write to depth buffer qglEnable ( GL_BLEND ); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for ( i = 0; i < m_nNumTransBrushes; i++ ) Brush_Draw (m_TransBrushes[i]); //qglDepthMask ( 1 ); // Ok, write now qglMatrixMode(GL_PROJECTION); // // now draw selected brushes // if (g_PrefsDlg.m_bGLLighting) { qglEnable (GL_LIGHTING); } qglTranslatef (g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]); qglMatrixMode(GL_TEXTURE); brush_t* pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; // draw normally for (brush = pList->next ; brush != pList ; brush=brush->next) { //DrawLightRadius(brush); //if (brush->patchBrush && g_qeglobals.d_select_mode == sel_curvepoint) // continue; Brush_Draw(brush); } // blend on top qglMatrixMode(GL_PROJECTION); qglDisable (GL_LIGHTING); 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); qglDisable (GL_TEXTURE_2D); for (brush = pList->next ; brush != pList ; brush=brush->next) { if ( (brush->patchBrush && g_qeglobals.d_select_mode == sel_curvepoint) || (brush->terrainBrush && g_qeglobals.d_select_mode == sel_terrainpoint) ) continue; for (face=brush->brush_faces ; face ; face=face->next) Face_Draw( face ); } int nCount = g_ptrSelectedFaces.GetSize(); if (nCount > 0) { for (int i = 0; i < nCount; i++) { face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i)); Face_Draw(selFace); } } // non-zbuffered outline qglDisable (GL_BLEND); qglDisable (GL_DEPTH_TEST); qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); qglColor3f (1, 1, 1); for (brush = pList->next ; brush != pList ; brush=brush->next) { if (g_qeglobals.dontDrawSelectedOutlines || (brush->patchBrush && g_qeglobals.d_select_mode == sel_curvepoint) || (brush->terrainBrush && g_qeglobals.d_select_mode == sel_terrainpoint)) continue; for (face=brush->brush_faces ; face ; face=face->next) Face_Draw( face ); } // edge / vertex flags if (g_qeglobals.d_select_mode == sel_vertex) { qglPointSize (4); qglColor3f (0,1,0); qglBegin (GL_POINTS); for (i=0 ; i<g_qeglobals.d_numpoints ; i++) qglVertex3fv (g_qeglobals.d_points[i]); qglEnd (); qglPointSize (1); } else if (g_qeglobals.d_select_mode == sel_edge) { float *v1, *v2; qglPointSize (4); qglColor3f (0,0,1); qglBegin (GL_POINTS); for (i=0 ; i<g_qeglobals.d_numedges ; i++) { v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1]; v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2]; qglVertex3f ( (v1[0]+v2[0])*0.5,(v1[1]+v2[1])*0.5,(v1[2]+v2[2])*0.5); } qglEnd (); qglPointSize (1); } g_splineList->draw(static_cast<qboolean>(g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint)); if (g_qeglobals.selectObject && (g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint)) { g_qeglobals.selectObject->drawSelection(); } // // draw pointfile // qglEnable(GL_DEPTH_TEST); DrawPathLines (); if (g_qeglobals.d_pointfile_display_list) { Pointfile_Draw(); // glCallList (g_qeglobals.d_pointfile_display_list); } // bind back to the default texture so that we don't have problems // elsewhere using/modifying texture maps between contexts qglBindTexture( GL_TEXTURE_2D, 0 ); #if 0 // area selection hack if (g_qeglobals.d_select_mode == sel_area) { qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglColor4f(0.0, 0.0, 1.0, 0.25); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglRectfv(g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR); qglDisable (GL_BLEND); } #endif qglFinish(); QE_CheckOpenGLForErrors(); // Sys_EndWait(); if (m_Camera.timing) { end = Sys_DoubleTime (); Sys_Printf ("Camera: %i ms\n", (int)(1000*(end-start))); } }
/* ============= EmitWaterPolys Does a water warp on the pre-fragmented glpoly_t chain NeVo - cleaned this function up ============= */ void EmitWaterPolys (msurface_t *fa) { glpoly_t *p, *bp; float *v; int i; float s, t, os, ot; float scroll; float rdt = r_newrefdef.time; if (fa->texinfo->flags & SURF_FLOWING) scroll = -64 * ( (rdt*0.5) - (int)(rdt*0.5) ); else scroll = 0; for (bp=fa->polys ; bp ; bp=bp->next) { p = bp; qglBegin (GL_TRIANGLE_FAN); for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE) { os = v[3]; ot = v[4]; #if !id386 s = os + r_turbsin[(int)((ot*0.125+rdt) * TURBSCALE) & 255]; #else s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255]; #endif s += scroll; s *= (1.0/64); #if !id386 t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255]; #else t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255]; #endif t *= (1.0/64); // --==OBSIDIAN UPDATE==-- //Adding this glColor call to lessen the alpha transparency on the water. Murky //water should not be so see through. //qglColor4f(1.0, 1.0, 1.0, 0.75); qglColor4f ( 1 - 0.3333, 1 - 0.4511, 1 - 0.5451, 0.75); // NeVo - made color match murky fog qglTexCoord2f (s, t); //=============== Water waves ============ //if (!(fa->texinfo->flags & SURF_FLOWING)) // NeVo - allow warping while flowing if (r_fluidwaves->value > 1.0) { vec3_t nv; nv[0] = v[0]; nv[1] = v[1]; nv[2] = v[2] + r_fluidwaves->value * sin( v[0] * 0.025 + rdt ) * sin( v[2] * 0.05 + rdt ) + r_fluidwaves->value *sin( v[1] * 0.025 + rdt * 2 ) *sin( v[2] * 0.05 + rdt ); qglVertex3fv (nv); } else //============= Water waves end. ============== qglVertex3fv (v); } qglEnd (); } }
void QueueDraw(){ guint32 i, k; face_t *face; winding_t *w; int j, nDrawMode = g_pParentWnd->GetCamera().draw_mode; if ( notex_faces->len ) { qglDisable( GL_TEXTURE_2D ); for ( i = 0; i < notex_faces->len; i++ ) { face = (face_t*)notex_faces->pdata[i]; w = face->face_winding; qglBegin( GL_POLYGON ); /* if (b->patchBrush) //++timo FIXME: find a use case for this?? qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); else */ qglColor4f( face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans() ); if ( g_PrefsDlg.m_bGLLighting ) { qglNormal3fv( face->plane.normal ); } for ( j = 0; j < w->numpoints; j++ ) { if ( nDrawMode == cd_texture || nDrawMode == cd_light ) { qglTexCoord2fv( &w->points[j][3] ); } qglVertex3fv( w->points[j] ); } qglEnd(); } } if ( !len ) { return; } if ( nDrawMode == cd_texture || nDrawMode == cd_light ) { qglEnable( GL_TEXTURE_2D ); } for ( k = 0; k < len; k++ ) { qglBindTexture( GL_TEXTURE_2D, sort[k].texture->texture_number ); for ( i = 0; i < sort[k].faces->len; i++ ) { face = (face_t*)sort[k].faces->pdata[i]; w = face->face_winding; qglBegin( GL_POLYGON ); /* if (b->patchBrush) //++timo FIXME: find a use case for this?? qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); else */ qglColor4f( face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans() ); if ( g_PrefsDlg.m_bGLLighting ) { qglNormal3fv( face->plane.normal ); } for ( j = 0; j < w->numpoints; j++ ) { if ( nDrawMode == cd_texture || nDrawMode == cd_light ) { qglTexCoord2fv( &w->points[j][3] ); } qglVertex3fv( w->points[j] ); } qglEnd(); } } qglBindTexture( GL_TEXTURE_2D, 0 ); }
/* ================ DrawNormals Draws vertex normals for debugging ================ */ static void DrawNormals(shaderCommands_t *input) { vec3_t temp; GL_Bind(tr.whiteImage); qglColor3f(1, 1, 1); qglDepthRange(0, 0); // never occluded GL_State(GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE); // 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); } // normals drawing else { int i; 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 R_RenderShadowEdges( void ) { int i; #if 0 int numTris; // dumb way -- render every triangle's edges numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; if ( !facing[i] ) { continue; } i1 = tess.indexes[ i * 3 + 0 ]; i2 = tess.indexes[ i * 3 + 1 ]; i3 = tess.indexes[ i * 3 + 2 ]; qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( shadowXyz[ i1 ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( shadowXyz[ i2 ] ); qglVertex3fv( tess.xyz[ i3 ] ); qglVertex3fv( shadowXyz[ i3 ] ); qglVertex3fv( tess.xyz[ i1 ] ); qglVertex3fv( shadowXyz[ i1 ] ); qglEnd(); } #else int c, c2; int j, k; int i2; int c_edges, c_rejected; int hit[2]; // an edge is NOT a silhouette edge if its face doesn't face the light, // or if it has a reverse paired edge that also faces the light. // A well behaved polyhedron would have exactly two faces for each edge, // but lots of models have dangling edges or overfanned edges c_edges = 0; c_rejected = 0; for ( i = 0 ; i < tess.numVertexes ; i++ ) { c = numEdgeDefs[ i ]; for ( j = 0 ; j < c ; j++ ) { if ( !edgeDefs[ i ][ j ].facing ) { continue; } hit[0] = 0; hit[1] = 0; i2 = edgeDefs[ i ][ j ].i2; c2 = numEdgeDefs[ i2 ]; for ( k = 0 ; k < c2 ; k++ ) { if ( edgeDefs[ i2 ][ k ].i2 == i ) { hit[ edgeDefs[ i2 ][ k ].facing ]++; } } // if it doesn't share the edge with another front facing // triangle, it is a sil edge if ( hit[ 1 ] == 0 ) { qglBegin( GL_TRIANGLE_STRIP ); qglVertex3fv( tess.xyz[ i ] ); qglVertex3fv( shadowXyz[ i ] ); qglVertex3fv( tess.xyz[ i2 ] ); qglVertex3fv( shadowXyz[ i2 ] ); qglEnd(); c_edges++; } else { c_rejected++; } } } #endif }
void GL_DrawAliasShadow (dmdl_t *paliashdr, int posenum) { dtrivertx_t *verts; int *order; vec3_t point; float height, lheight; int count; daliasframe_t *frame; lheight = currententity->origin[2] - lightspot[2]; frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = frame->verts; height = 0; order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); height = -lheight + 1.0; while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else qglBegin (GL_TRIANGLE_STRIP); do { // normals and vertexes come from the frame list //point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0]; //point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1]; //point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2]; memcpy( point, s_lerped[order[2]], sizeof( point ) ); point[0] -= shadevector[0]*(point[2]+lheight); point[1] -= shadevector[1]*(point[2]+lheight); point[2] = height; // height -= 0.001; qglVertex3fv (point); order += 3; // verts++; } while (--count); qglEnd (); } }
/* ===================== SplitOriginalEdgesAtCrossings ===================== */ void SplitOriginalEdgesAtCrossings( optimizeGroup_t *opt ) { int i, j, k, l; int numOriginalVerts; edgeCrossing_t **crossings; numOriginalVerts = numOptVerts; // now split any crossing edges and create optEdges // linked to the vertexes // debug drawing bounds dmapGlobals.drawBounds = optBounds; dmapGlobals.drawBounds[0][0] -= 2; dmapGlobals.drawBounds[0][1] -= 2; dmapGlobals.drawBounds[1][0] += 2; dmapGlobals.drawBounds[1][1] += 2; // generate crossing points between all the original edges crossings = (edgeCrossing_t **)Mem_ClearedAlloc( numOriginalEdges * sizeof( *crossings ) ); for ( i = 0 ; i < numOriginalEdges ; i++ ) { if ( dmapGlobals.drawflag ) { DrawOriginalEdges( numOriginalEdges, originalEdges ); qglBegin( GL_LINES ); qglColor3f( 0, 1, 0 ); qglVertex3fv( originalEdges[i].v1->pv.ToFloatPtr() ); qglColor3f( 0, 0, 1 ); qglVertex3fv( originalEdges[i].v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } for ( j = i+1 ; j < numOriginalEdges ; j++ ) { optVertex_t *v1, *v2, *v3, *v4; optVertex_t *newVert; edgeCrossing_t *cross; v1 = originalEdges[i].v1; v2 = originalEdges[i].v2; v3 = originalEdges[j].v1; v4 = originalEdges[j].v2; if ( !EdgesCross( v1, v2, v3, v4 ) ) { continue; } // this is the only point in optimization where // completely new points are created, and it only // happens if there is overlapping coplanar // geometry in the source triangles newVert = EdgeIntersection( v1, v2, v3, v4, opt ); if ( !newVert ) { //common->Printf( "lines %i (%i to %i) and %i (%i to %i) are colinear\n", i, v1 - optVerts, v2 - optVerts, // j, v3 - optVerts, v4 - optVerts ); // !@# // colinear, so add both verts of each edge to opposite if ( VertexBetween( v3, v1, v2 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ) ); cross->ov = v3; cross->next = crossings[i]; crossings[i] = cross; } if ( VertexBetween( v4, v1, v2 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ) ); cross->ov = v4; cross->next = crossings[i]; crossings[i] = cross; } if ( VertexBetween( v1, v3, v4 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ) ); cross->ov = v1; cross->next = crossings[j]; crossings[j] = cross; } if ( VertexBetween( v2, v3, v4 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ) ); cross->ov = v2; cross->next = crossings[j]; crossings[j] = cross; } continue; } #if 0 if ( newVert && newVert != v1 && newVert != v2 && newVert != v3 && newVert != v4 ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) cross at new point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } else if ( newVert ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) intersect at old point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } #endif if ( newVert != v1 && newVert != v2 ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ) ); cross->ov = newVert; cross->next = crossings[i]; crossings[i] = cross; } if ( newVert != v3 && newVert != v4 ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ) ); cross->ov = newVert; cross->next = crossings[j]; crossings[j] = cross; } } } // now split each edge by its crossing points // colinear edges will have duplicated edges added, but it won't hurt anything for ( i = 0 ; i < numOriginalEdges ; i++ ) { edgeCrossing_t *cross, *nextCross; int numCross; optVertex_t **sorted; numCross = 0; for ( cross = crossings[i] ; cross ; cross = cross->next ) { numCross++; } numCross += 2; // account for originals sorted = (optVertex_t **)Mem_Alloc( numCross * sizeof( *sorted ) ); sorted[0] = originalEdges[i].v1; sorted[1] = originalEdges[i].v2; j = 2; for ( cross = crossings[i] ; cross ; cross = nextCross ) { nextCross = cross->next; sorted[j] = cross->ov; Mem_Free( cross ); j++; } // add all possible fragment combinations that aren't divided // by another point for ( j = 0 ; j < numCross ; j++ ) { for ( k = j+1 ; k < numCross ; k++ ) { for ( l = 0 ; l < numCross ; l++ ) { if ( sorted[l] == sorted[j] || sorted[l] == sorted[k] ) { continue; } if ( sorted[j] == sorted[k] ) { continue; } if ( VertexBetween( sorted[l], sorted[j], sorted[k] ) ) { break; } } if ( l == numCross ) { //common->Printf( "line %i fragment from point %i to %i\n", i, sorted[j] - optVerts, sorted[k] - optVerts ); AddEdgeIfNotAlready( sorted[j], sorted[k] ); } } } Mem_Free( sorted ); } Mem_Free( crossings ); Mem_Free( originalEdges ); // check for duplicated edges for ( i = 0 ; i < numOptEdges ; i++ ) { for ( j = i+1 ; j < numOptEdges ; j++ ) { if ( ( optEdges[i].v1 == optEdges[j].v1 && optEdges[i].v2 == optEdges[j].v2 ) || ( optEdges[i].v1 == optEdges[j].v2 && optEdges[i].v2 == optEdges[j].v1 ) ) { common->Printf( "duplicated optEdge\n" ); } } } if ( dmapGlobals.verbose ) { common->Printf( "%6i original edges\n", numOriginalEdges ); common->Printf( "%6i edges after splits\n", numOptEdges ); common->Printf( "%6i original vertexes\n", numOriginalVerts ); common->Printf( "%6i vertexes after splits\n", numOptVerts ); } }
void 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 ); } } }