int gld_wipe_EndScreen(void) { qglFlush(); wipe_scr_end_tex = CaptureScreenAsTexID(); return 0; }
/* ================ DrawAllEdges ================ */ static void DrawAllEdges() { // int i; if( !dmapGlobals.drawflag ) { return; } #if 0 Draw_ClearWindow(); qglBegin( GL_LINES ); for( i = 0 ; i < numOptEdges ; i++ ) { if( optEdges[i].v1 == NULL ) { continue; } qglColor3f( 1, 0, 0 ); qglVertex3fv( optEdges[i].v1->pv.ToFloatPtr() ); qglColor3f( 0, 0, 0 ); qglVertex3fv( optEdges[i].v2->pv.ToFloatPtr() ); } qglEnd(); qglFlush(); // GLimp_SwapBuffers(); #endif }
/* ================ DrawEdges ================ */ static void DrawEdges( optIsland_t* island ) { // optEdge_t *edge; if( !dmapGlobals.drawflag ) { return; } #if 0 Draw_ClearWindow(); qglBegin( GL_LINES ); for( edge = island->edges ; edge ; edge = edge->islandLink ) { if( edge->v1 == NULL ) { continue; } qglColor3f( 1, 0, 0 ); qglVertex3fv( edge->v1->pv.ToFloatPtr() ); qglColor3f( 0, 0, 0 ); qglVertex3fv( edge->v2->pv.ToFloatPtr() ); } qglEnd(); qglFlush(); // GLimp_SwapBuffers(); #endif }
/* ==================== TryAddNewEdge ==================== */ static bool TryAddNewEdge( optVertex_t *v1, optVertex_t *v2, optIsland_t *island ) { optEdge_t *e; // if the new edge crosses any other edges, don't add it for ( e = island->edges ; e ; e = e->islandLink ) { if ( EdgesCross( e->v1, e->v2, v1, v2 ) ) { return false; } } if ( dmapGlobals.drawflag ) { qglBegin( GL_LINES ); qglColor3f( 0, ( 128 + orandom.RandomInt( 127 ) )/ 255.0, 0 ); qglVertex3fv( v1->pv.ToFloatPtr() ); qglVertex3fv( v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // add it e = AllocEdge(); e->islandLink = island->edges; island->edges = e; e->v1 = v1; e->v2 = v2; e->created = true; // link the edge to its verts LinkEdge( e ); return true; }
void GLimp_EndFrame( void ) { int width, height; width = quake2_jni_get_width(); height = quake2_jni_get_height(); qglDisable (GL_DEPTH_TEST); qglDisable (GL_CULL_FACE); qglEnable (GL_BLEND); qglDisable (GL_ALPHA_TEST); qglColor4f (1,1,1,1); switch (overlay){ case 1: Draw_StretchPic(0, 0, width, height, "/overlay1.tga"); break; case 2: Draw_StretchPic(0, 0, width, height, "/overlay2.tga"); break; } //qglFinish(); qglFlush(); // needed framecount ++; }
void idGLWidget::OnPaint() { if (!initialized) { CDC *dc = GetDC(); QEW_SetupPixelFormat(dc->m_hDC); ReleaseDC(dc); initialized = true; } CPaintDC dc(this); // device context for painting CRect rect; GetClientRect(rect); if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) { } qglViewport(0, 0, rect.Width(), rect.Height()); qglScissor(0, 0, rect.Width(), rect.Height()); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglClearColor (0.4f, 0.4f, 0.4f, 0.7f); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); qglDisable(GL_DEPTH_TEST); qglDisable(GL_BLEND); qglOrtho(0, rect.Width(), 0, rect.Height(), -256, 256); if (drawable) { drawable->draw(1, 1, rect.Width()-1, rect.Height()-1); } else { qglViewport(0, 0, rect.Width(), rect.Height()); qglScissor(0, 0, rect.Width(), rect.Height()); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglClearColor (0.4f, 0.4f, 0.4f, 0.7f); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } qwglSwapBuffers(dc); qglFlush(); qwglMakeCurrent(win32.hDC, win32.hGLRC); }
/* ==================== RenderCommandBuffers ==================== */ void idRenderSystemLocal::RenderCommandBuffers( const emptyCommand_t* const cmdHead ) { // if there isn't a draw view command, do nothing to avoid swapping a bad frame bool hasView = false; for( const emptyCommand_t* cmd = cmdHead ; cmd ; cmd = ( const emptyCommand_t* )cmd->next ) { if( cmd->commandId == RC_DRAW_VIEW_3D || cmd->commandId == RC_DRAW_VIEW_GUI ) { hasView = true; break; } } if( !hasView ) { return; } // r_skipBackEnd allows the entire time of the back end // to be removed from performance measurements, although // nothing will be drawn to the screen. If the prints // are going to a file, or r_skipBackEnd is later disabled, // usefull data can be received. // r_skipRender is usually more usefull, because it will still // draw 2D graphics if( !r_skipBackEnd.GetBool() ) { if( glConfig.timerQueryAvailable ) { if( tr.timerQueryId == 0 ) { qglGenQueriesARB( 1, & tr.timerQueryId ); } qglBeginQueryARB( GL_TIME_ELAPSED_EXT, tr.timerQueryId ); RB_ExecuteBackEndCommands( cmdHead ); qglEndQueryARB( GL_TIME_ELAPSED_EXT ); qglFlush(); } else { RB_ExecuteBackEndCommands( cmdHead ); } } // pass in null for now - we may need to do some map specific hackery in the future resolutionScale.InitForMap( NULL ); }
/* ================= DrawOriginalEdges ================= */ static void DrawOriginalEdges( int numOriginalEdges, originalEdges_t *originalEdges ) { int i; if ( !dmapGlobals.drawflag ) { return; } Draw_ClearWindow(); qglBegin( GL_LINES ); for ( i = 0 ; i < numOriginalEdges ; i++ ) { qglColor3f( 1, 0, 0 ); qglVertex3fv( originalEdges[i].v1->pv.ToFloatPtr() ); qglColor3f( 0, 0, 0 ); qglVertex3fv( originalEdges[i].v2->pv.ToFloatPtr() ); } qglEnd(); qglFlush(); }
/* ================ DrawVerts ================ */ static void DrawVerts( optIsland_t *island ) { optVertex_t *vert; if ( !dmapGlobals.drawflag ) { return; } qglEnable( GL_BLEND ); qglBlendFunc( GL_ONE, GL_ONE ); qglColor3f( 0.3f, 0.3f, 0.3f ); qglPointSize( 3 ); qglBegin( GL_POINTS ); for ( vert = island->verts ; vert ; vert = vert->islandLink ) { qglVertex3fv( vert->pv.ToFloatPtr() ); } qglEnd(); qglDisable( GL_BLEND ); qglFlush(); }
/* * R_EndOcclusionPass */ void R_EndOcclusionPass( void ) { assert( OCCLUSION_QUERIES_ENABLED( ri ) ); R_RenderOccludingSurfaces(); R_SurfIssueOcclusionQueries(); R_BackendResetPassMask(); R_BackendResetCounters(); if( r_occlusion_queries_finish->integer ) qglFinish(); else qglFlush(); qglEnable( GL_TEXTURE_2D ); }
/* ** GLimp_EndFrame ** ** Responsible for doing a swapbuffers and possibly for other stuff ** as yet to be determined. Probably better not to make this a GLimp ** function and instead do a call to GLimp_SwapBuffers. */ void GLimp_EndFrame (void) { qglFlush(); qfxMesaSwapBuffers(); }
/* =============== CreateOptTri =============== */ static void CreateOptTri( optVertex_t *first, optEdge_t *e1, optEdge_t *e2, optIsland_t *island ) { optEdge_t *opposite; optVertex_t *second, *third; optTri_t *optTri; mapTri_t *tri; if ( e1->v1 == first ) { second = e1->v2; } else if ( e1->v2 == first ) { second = e1->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); return; } if ( e2->v1 == first ) { third = e2->v2; } else if ( e2->v2 == first ) { third = e2->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); return; } if ( !IsTriangleValid( first, second, third ) ) { common->Error( "CreateOptTri: invalid" ); return; } //DrawEdges( island ); // identify the third edge if ( dmapGlobals.drawflag ) { qglColor3f(1,1,0); qglBegin( GL_LINES ); qglVertex3fv( e1->v1->pv.ToFloatPtr() ); qglVertex3fv( e1->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); qglColor3f(0,1,1); qglBegin( GL_LINES ); qglVertex3fv( e2->v1->pv.ToFloatPtr() ); qglVertex3fv( e2->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } for ( opposite = second->edges ; opposite ; ) { if ( opposite != e1 && ( opposite->v1 == third || opposite->v2 == third ) ) { break; } if ( opposite->v1 == second ) { opposite = opposite->v1link; } else if ( opposite->v2 == second ) { opposite = opposite->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); return; } } if ( !opposite ) { common->Printf( "Warning: BuildOptTriangles: couldn't locate opposite\n" ); return; } if ( dmapGlobals.drawflag ) { qglColor3f(1,0,1); qglBegin( GL_LINES ); qglVertex3fv( opposite->v1->pv.ToFloatPtr() ); qglVertex3fv( opposite->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // create new triangle optTri = (optTri_t *)Mem_Alloc( sizeof( *optTri ), TAG_DMAP ); optTri->v[0] = first; optTri->v[1] = second; optTri->v[2] = third; optTri->midpoint = ( optTri->v[0]->pv + optTri->v[1]->pv + optTri->v[2]->pv ) * ( 1.0f / 3.0f ); optTri->next = island->tris; island->tris = optTri; if ( dmapGlobals.drawflag ) { qglColor3f( 1, 1, 1 ); qglPointSize( 4 ); qglBegin( GL_POINTS ); qglVertex3fv( optTri->midpoint.ToFloatPtr() ); qglEnd(); qglFlush(); } // find the midpoint, and scan through all the original triangles to // see if it is inside any of them for ( tri = island->group->triList ; tri ; tri = tri->next ) { if ( PointInTri( optTri->midpoint, tri, island ) ) { break; } } if ( tri ) { optTri->filled = true; } else { optTri->filled = false; } if ( dmapGlobals.drawflag ) { if ( optTri->filled ) { qglColor3f( ( 128 + orandom.RandomInt( 127 ) )/ 255.0, 0, 0 ); } else { qglColor3f( 0, ( 128 + orandom.RandomInt( 127 ) ) / 255.0, 0 ); } qglBegin( GL_TRIANGLES ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINE_LOOP ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } // link the triangle to it's edges LinkTriToEdge( optTri, e1 ); LinkTriToEdge( optTri, e2 ); LinkTriToEdge( optTri, opposite ); }
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 ); }
/* ===================== SplitOriginalEdgesAtCrossings ===================== */ void SplitOriginalEdgesAtCrossings( optimizeGroup_t *opt ) { int i, j, k, l; int numOriginalVerts; edgeCrossing_t **crossings; numOriginalVerts = numOptVerts; // now split any crossing edges and create optEdges // linked to the vertexes // debug drawing bounds dmapGlobals.drawBounds = optBounds; dmapGlobals.drawBounds[0][0] -= 2; dmapGlobals.drawBounds[0][1] -= 2; dmapGlobals.drawBounds[1][0] += 2; dmapGlobals.drawBounds[1][1] += 2; // generate crossing points between all the original edges crossings = (edgeCrossing_t **)Mem_ClearedAlloc( numOriginalEdges * sizeof( *crossings ), TAG_DMAP ); for ( i = 0 ; i < numOriginalEdges ; i++ ) { if ( dmapGlobals.drawflag ) { DrawOriginalEdges( numOriginalEdges, originalEdges ); qglBegin( GL_LINES ); qglColor3f( 0, 1, 0 ); qglVertex3fv( originalEdges[i].v1->pv.ToFloatPtr() ); qglColor3f( 0, 0, 1 ); qglVertex3fv( originalEdges[i].v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); } for ( j = i+1 ; j < numOriginalEdges ; j++ ) { optVertex_t *v1, *v2, *v3, *v4; optVertex_t *newVert; edgeCrossing_t *cross; v1 = originalEdges[i].v1; v2 = originalEdges[i].v2; v3 = originalEdges[j].v1; v4 = originalEdges[j].v2; if ( !EdgesCross( v1, v2, v3, v4 ) ) { continue; } // this is the only point in optimization where // completely new points are created, and it only // happens if there is overlapping coplanar // geometry in the source triangles newVert = EdgeIntersection( v1, v2, v3, v4, opt ); if ( !newVert ) { //common->Printf( "lines %i (%i to %i) and %i (%i to %i) are colinear\n", i, v1 - optVerts, v2 - optVerts, // j, v3 - optVerts, v4 - optVerts ); // !@# // colinear, so add both verts of each edge to opposite if ( VertexBetween( v3, v1, v2 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v3; cross->next = crossings[i]; crossings[i] = cross; } if ( VertexBetween( v4, v1, v2 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v4; cross->next = crossings[i]; crossings[i] = cross; } if ( VertexBetween( v1, v3, v4 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v1; cross->next = crossings[j]; crossings[j] = cross; } if ( VertexBetween( v2, v3, v4 ) ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = v2; cross->next = crossings[j]; crossings[j] = cross; } continue; } #if 0 if ( newVert && newVert != v1 && newVert != v2 && newVert != v3 && newVert != v4 ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) cross at new point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } else if ( newVert ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) intersect at old point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } #endif if ( newVert != v1 && newVert != v2 ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = newVert; cross->next = crossings[i]; crossings[i] = cross; } if ( newVert != v3 && newVert != v4 ) { cross = (edgeCrossing_t *)Mem_ClearedAlloc( sizeof( *cross ), TAG_DMAP ); cross->ov = newVert; cross->next = crossings[j]; crossings[j] = cross; } } } // now split each edge by its crossing points // colinear edges will have duplicated edges added, but it won't hurt anything for ( i = 0 ; i < numOriginalEdges ; i++ ) { edgeCrossing_t *cross, *nextCross; int numCross; optVertex_t **sorted; numCross = 0; for ( cross = crossings[i] ; cross ; cross = cross->next ) { numCross++; } numCross += 2; // account for originals sorted = (optVertex_t **)Mem_Alloc( numCross * sizeof( *sorted ), TAG_DMAP ); sorted[0] = originalEdges[i].v1; sorted[1] = originalEdges[i].v2; j = 2; for ( cross = crossings[i] ; cross ; cross = nextCross ) { nextCross = cross->next; sorted[j] = cross->ov; Mem_Free( cross ); j++; } // add all possible fragment combinations that aren't divided // by another point for ( j = 0 ; j < numCross ; j++ ) { for ( k = j+1 ; k < numCross ; k++ ) { for ( l = 0 ; l < numCross ; l++ ) { if ( sorted[l] == sorted[j] || sorted[l] == sorted[k] ) { continue; } if ( sorted[j] == sorted[k] ) { continue; } if ( VertexBetween( sorted[l], sorted[j], sorted[k] ) ) { break; } } if ( l == numCross ) { //common->Printf( "line %i fragment from point %i to %i\n", i, sorted[j] - optVerts, sorted[k] - optVerts ); AddEdgeIfNotAlready( sorted[j], sorted[k] ); } } } Mem_Free( sorted ); } Mem_Free( crossings ); Mem_Free( originalEdges ); // check for duplicated edges for ( i = 0 ; i < numOptEdges ; i++ ) { for ( j = i+1 ; j < numOptEdges ; j++ ) { if ( ( optEdges[i].v1 == optEdges[j].v1 && optEdges[i].v2 == optEdges[j].v2 ) || ( optEdges[i].v1 == optEdges[j].v2 && optEdges[i].v2 == optEdges[j].v1 ) ) { common->Printf( "duplicated optEdge\n" ); } } } if ( dmapGlobals.verbose ) { common->Printf( "%6i original edges\n", numOriginalEdges ); common->Printf( "%6i edges after splits\n", numOptEdges ); common->Printf( "%6i original vertexes\n", numOriginalVerts ); common->Printf( "%6i vertexes after splits\n", numOptVerts ); } }
/* ==================== 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; } }
/* ============== RenderBumpTriangles ============== */ static void RenderBumpTriangles( srfTriangles_t *lowMesh, renderBump_t *rb ) { int i, j; RB_SetGL2D(); qglDisable( GL_CULL_FACE ); qglColor3f( 1, 1, 1 ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, 1, 1, 0, -1, 1 ); qglDisable( GL_BLEND ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); qglDisable( GL_DEPTH_TEST ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglColor3f( 1, 1, 1 ); // create smoothed normals for the surface, which might be // different than the normals at the vertexes if the // surface uses unsmoothedNormals, which only takes the // normal from a single triangle. We need properly smoothed // normals to make sure that the traces always go off normal // to the true surface. idVec3 *lowMeshNormals = (idVec3 *)Mem_ClearedAlloc( lowMesh->numVerts * sizeof( *lowMeshNormals ) ); R_DeriveFacePlanes( lowMesh ); R_CreateSilIndexes( lowMesh ); // recreate, merging the mirrored verts back together const idPlane *planes = lowMesh->facePlanes; for ( i = 0 ; i < lowMesh->numIndexes ; i += 3, planes++ ) { for ( j = 0 ; j < 3 ; j++ ) { int index; index = lowMesh->silIndexes[i+j]; lowMeshNormals[index] += (*planes).Normal(); } } // normalize and replicate from silIndexes to all indexes for ( i = 0 ; i < lowMesh->numIndexes ; i++ ) { lowMeshNormals[lowMesh->indexes[i]] = lowMeshNormals[lowMesh->silIndexes[i]]; lowMeshNormals[lowMesh->indexes[i]].Normalize(); } // rasterize each low poly face for ( j = 0 ; j < lowMesh->numIndexes ; j+=3 ) { // pump the event loop so the window can be dragged around Sys_GenerateEvents(); RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglRasterPos2f( 0, 1 ); qglPixelZoom( glConfig.vidWidth / (float)rb->width, glConfig.vidHeight / (float)rb->height ); qglDrawPixels( rb->width, rb->height, GL_RGBA, GL_UNSIGNED_BYTE, rb->localPic ); qglPixelZoom( 1, 1 ); qglFlush(); GLimp_SwapBuffers(); } Mem_Free( lowMeshNormals ); }
/* ============== RenderBumpFlat_f ============== */ void RenderBumpFlat_f( const idCmdArgs &args ) { int width, height; idStr source; int i; idBounds bounds; srfTriangles_t *mesh; // update the screen as we print common->SetRefreshOnPrint( true ); width = height = 256; // check options for ( i = 1 ; i < args.Argc() - 1; i++ ) { const char *s; s = args.Argv( i ); if ( s[0] == '-' ) { i++; s = args.Argv( i ); } if ( !idStr::Icmp( s, "size" ) ) { if ( i + 2 >= args.Argc() ) { i = args.Argc(); break; } width = atoi( args.Argv( i + 1 ) ); height = atoi( args.Argv( i + 2 ) ); i += 2; } else { common->Printf( "WARNING: Unknown option \"%s\"\n", s ); break; } } if ( i != ( args.Argc() - 1 ) ) { common->Error( "usage: renderBumpFlat [-size width height] asefile" ); return; } common->Printf( "Final image size: %i, %i\n", width, height ); // load the source in "fastload" mode, because we don't // need tangent and shadow information source = args.Argv( i ); idRenderModel *highPolyModel = renderModelManager->AllocModel(); highPolyModel->PartialInitFromFile( source ); if ( highPolyModel->IsDefaultModel() ) { common->Error( "failed to load %s", source.c_str() ); } // combine the high poly model into a single polyset if ( highPolyModel->NumSurfaces() != 1 ) { highPolyModel = CombineModelSurfaces( highPolyModel ); } // create normals if not present in file const modelSurface_t *surf = highPolyModel->Surface( 0 ); mesh = surf->geometry; // bound the entire file R_BoundTriSurf( mesh ); bounds = mesh->bounds; SaveWindow(); ResizeWindow( width, height ); // for small images, the viewport may be less than the minimum window qglViewport( 0, 0, width, height ); qglEnable( GL_CULL_FACE ); qglCullFace( GL_FRONT ); qglDisable( GL_STENCIL_TEST ); qglDisable( GL_SCISSOR_TEST ); qglDisable( GL_ALPHA_TEST ); qglDisable( GL_BLEND ); qglEnable( GL_DEPTH_TEST ); qglDisable( GL_TEXTURE_2D ); qglDepthMask( GL_TRUE ); qglDepthFunc( GL_LEQUAL ); qglColor3f( 1, 1, 1 ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( bounds[0][0], bounds[1][0], bounds[0][2], bounds[1][2], -( bounds[0][1] - 1 ), -( bounds[1][1] + 1 ) ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); // flat maps are automatically anti-aliased idStr filename; int j, k, c; byte *buffer; int *sumBuffer, *colorSumBuffer; bool flat; int sample; sumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 ); memset( sumBuffer, 0, width * height * 4 * 4 ); buffer = (byte *)Mem_Alloc( width * height * 4 ); colorSumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 ); memset( sumBuffer, 0, width * height * 4 * 4 ); flat = false; //flat = true; for ( sample = 0 ; sample < 16 ; sample++ ) { float xOff, yOff; xOff = ( ( sample & 3 ) / 4.0 ) * ( bounds[1][0] - bounds[0][0] ) / width; yOff = ( ( sample / 4 ) / 4.0 ) * ( bounds[1][2] - bounds[0][2] ) / height; for ( int colorPass = 0 ; colorPass < 2 ; colorPass++ ) { qglClearColor(0.5,0.5,0.5,0); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglBegin( GL_TRIANGLES ); for ( i = 0 ; i < highPolyModel->NumSurfaces() ; i++ ) { const modelSurface_t *surf = highPolyModel->Surface( i ); mesh = surf->geometry; if ( colorPass ) { // just render the surface color for artist visualization for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) { for ( k = 0 ; k < 3 ; k++ ) { int v; float *a; v = mesh->indexes[j+k]; qglColor3ubv( mesh->verts[v].color ); a = mesh->verts[v].xyz.ToFloatPtr(); qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] ); } } } else { // render as normal map // we can either flat shade from the plane, // or smooth shade from the vertex normals for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) { if ( flat ) { idPlane plane; idVec3 *a, *b, *c; int v1, v2, v3; v1 = mesh->indexes[j+0]; v2 = mesh->indexes[j+1]; v3 = mesh->indexes[j+2]; a = &mesh->verts[ v1 ].xyz; b = &mesh->verts[ v2 ].xyz; c = &mesh->verts[ v3 ].xyz; plane.FromPoints( *a, *b, *c ); // NULLNORMAL is used by the artists to force an area to reflect no // light at all if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) { qglColor3f( 0.5, 0.5, 0.5 ); } else { qglColor3f( 0.5 + 0.5*plane[0], 0.5 - 0.5*plane[2], 0.5 - 0.5*plane[1] ); } qglVertex3f( (*a)[0] + xOff, (*a)[2] + yOff, (*a)[1] ); qglVertex3f( (*b)[0] + xOff, (*b)[2] + yOff, (*b)[1] ); qglVertex3f( (*c)[0] + xOff, (*c)[2] + yOff, (*c)[1] ); } else { for ( k = 0 ; k < 3 ; k++ ) { int v; float *n; float *a; v = mesh->indexes[j+k]; n = mesh->verts[v].normal.ToFloatPtr(); // NULLNORMAL is used by the artists to force an area to reflect no // light at all if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) { qglColor3f( 0.5, 0.5, 0.5 ); } else { // we are going to flip the normal Z direction qglColor3f( 0.5 + 0.5*n[0], 0.5 - 0.5*n[2], 0.5 - 0.5*n[1] ); } a = mesh->verts[v].xyz.ToFloatPtr(); qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] ); } } } } } qglEnd(); qglFlush(); GLimp_SwapBuffers(); qglReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); c = width * height; if ( colorPass ) { // add to the sum buffer for ( i = 0 ; i < c ; i++ ) { colorSumBuffer[i*4+0] += buffer[i*4+0]; colorSumBuffer[i*4+1] += buffer[i*4+1]; colorSumBuffer[i*4+2] += buffer[i*4+2]; colorSumBuffer[i*4+3] += buffer[i*4+3]; } } else { // normalize for ( i = 0 ; i < c ; i++ ) { idVec3 v; v[0] = ( buffer[i*4+0] - 128 ) / 127.0; v[1] = ( buffer[i*4+1] - 128 ) / 127.0; v[2] = ( buffer[i*4+2] - 128 ) / 127.0; v.Normalize(); buffer[i*4+0] = 128 + 127 * v[0]; buffer[i*4+1] = 128 + 127 * v[1]; buffer[i*4+2] = 128 + 127 * v[2]; } // outline into non-drawn areas for ( i = 0 ; i < 8 ; i++ ) { OutlineNormalMap( buffer, width, height, 128, 128, 128 ); } // add to the sum buffer for ( i = 0 ; i < c ; i++ ) { sumBuffer[i*4+0] += buffer[i*4+0]; sumBuffer[i*4+1] += buffer[i*4+1]; sumBuffer[i*4+2] += buffer[i*4+2]; sumBuffer[i*4+3] += buffer[i*4+3]; } } } } c = width * height; // save out the color map for ( i = 0 ; i < c ; i++ ) { buffer[i*4+0] = colorSumBuffer[i*4+0] / 16; buffer[i*4+1] = colorSumBuffer[i*4+1] / 16; buffer[i*4+2] = colorSumBuffer[i*4+2] / 16; buffer[i*4+3] = colorSumBuffer[i*4+3] / 16; } filename = source; filename.StripFileExtension(); filename.Append( "_color.tga" ); R_VerticalFlip( buffer, width, height ); R_WriteTGA( filename, buffer, width, height ); // save out the local map // scale the sum buffer back down to the sample buffer // we allow this to denormalize for ( i = 0 ; i < c ; i++ ) { buffer[i*4+0] = sumBuffer[i*4+0] / 16; buffer[i*4+1] = sumBuffer[i*4+1] / 16; buffer[i*4+2] = sumBuffer[i*4+2] / 16; buffer[i*4+3] = sumBuffer[i*4+3] / 16; } filename = source; filename.StripFileExtension(); filename.Append( "_local.tga" ); common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height ); R_VerticalFlip( buffer, width, height ); R_WriteTGA( filename, buffer, width, height ); // free the model renderModelManager->FreeModel( highPolyModel ); // free our work buffer Mem_Free( buffer ); Mem_Free( sumBuffer ); Mem_Free( colorSumBuffer ); RestoreWindow(); // stop updating the screen as we print common->SetRefreshOnPrint( false ); common->Error( "Completed." ); }
/********* SP_DrawTexture *********/ void SP_DrawTexture(void* pixels, float width, float height, float vShift) { if (!pixels) { // Ug. We were not even able to load the error message texture. return; } // Create a texture from the buffered file GLuint texid; qglGenTextures(1, &texid); qglBindTexture(GL_TEXTURE_2D, texid); qglTexImage2D(GL_TEXTURE_2D, 0, GL_DDS1_EXT, width, height, 0, GL_DDS1_EXT, GL_UNSIGNED_BYTE, pixels); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); // Reset every GL state we've got. Who knows what state // the renderer could be in when this function gets called. qglColor3f(1.f, 1.f, 1.f); qglViewport(0, 0, 640, 480); GLboolean alpha = qglIsEnabled(GL_ALPHA_TEST); qglDisable(GL_ALPHA_TEST); GLboolean blend = qglIsEnabled(GL_BLEND); qglDisable(GL_BLEND); GLboolean cull = qglIsEnabled(GL_CULL_FACE); qglDisable(GL_CULL_FACE); GLboolean depth = qglIsEnabled(GL_DEPTH_TEST); qglDisable(GL_DEPTH_TEST); GLboolean fog = qglIsEnabled(GL_FOG); qglDisable(GL_FOG); GLboolean lighting = qglIsEnabled(GL_LIGHTING); qglDisable(GL_LIGHTING); GLboolean offset = qglIsEnabled(GL_POLYGON_OFFSET_FILL); qglDisable(GL_POLYGON_OFFSET_FILL); GLboolean scissor = qglIsEnabled(GL_SCISSOR_TEST); qglDisable(GL_SCISSOR_TEST); GLboolean stencil = qglIsEnabled(GL_STENCIL_TEST); qglDisable(GL_STENCIL_TEST); GLboolean texture = qglIsEnabled(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_2D); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglOrtho(0, 640, 0, 480, 0, 1); qglMatrixMode(GL_TEXTURE0); qglLoadIdentity(); qglMatrixMode(GL_TEXTURE1); qglLoadIdentity(); qglActiveTextureARB(GL_TEXTURE0_ARB); qglClientActiveTextureARB(GL_TEXTURE0_ARB); memset(&tess, 0, sizeof(tess)); // Draw the error message qglBeginFrame(); if (!SP_LicenseDone) { // clear the screen if we haven't done the // license yet... qglClearColor(0, 0, 0, 1); qglClear(GL_COLOR_BUFFER_BIT); } float x1 = 320 - width / 2; float x2 = 320 + width / 2; float y1 = 240 - height / 2; float y2 = 240 + height / 2; y1 += vShift; y2 += vShift; qglBeginEXT (GL_TRIANGLE_STRIP, 4, 0, 0, 4, 0); qglTexCoord2f( 0, 0 ); qglVertex2f(x1, y1); qglTexCoord2f( 1 , 0 ); qglVertex2f(x2, y1); qglTexCoord2f( 0, 1 ); qglVertex2f(x1, y2); qglTexCoord2f( 1, 1 ); qglVertex2f(x2, y2); qglEnd(); qglEndFrame(); qglFlush(); // Restore (most) of the render states we reset if (alpha) qglEnable(GL_ALPHA_TEST); else qglDisable(GL_ALPHA_TEST); if (blend) qglEnable(GL_BLEND); else qglDisable(GL_BLEND); if (cull) qglEnable(GL_CULL_FACE); else qglDisable(GL_CULL_FACE); if (depth) qglEnable(GL_DEPTH_TEST); else qglDisable(GL_DEPTH_TEST); if (fog) qglEnable(GL_FOG); else qglDisable(GL_FOG); if (lighting) qglEnable(GL_LIGHTING); else qglDisable(GL_LIGHTING); if (offset) qglEnable(GL_POLYGON_OFFSET_FILL); else qglDisable(GL_POLYGON_OFFSET_FILL); if (scissor) qglEnable(GL_SCISSOR_TEST); else qglDisable(GL_SCISSOR_TEST); if (stencil) qglEnable(GL_STENCIL_TEST); else qglDisable(GL_STENCIL_TEST); if (texture) qglEnable(GL_TEXTURE_2D); else qglDisable(GL_TEXTURE_2D); // Kill the texture qglDeleteTextures(1, &texid); }