/* =================== OptimizeGroupList This will also fix tjunctions =================== */ void OptimizeGroupList( optimizeGroup_t *groupList ) { int c_in, c_edge, c_tjunc2; optimizeGroup_t *group; if ( !groupList ) { return; } c_in = CountGroupListTris( groupList ); // optimize and remove colinear edges, which will // re-introduce some t junctions for ( group = groupList ; group ; group = group->nextGroup ) { OptimizeOptList( group ); } c_edge = CountGroupListTris( groupList ); // fix t junctions again FixAreaGroupsTjunctions( groupList ); FreeTJunctionHash(); c_tjunc2 = CountGroupListTris( groupList ); SetGroupTriPlaneNums( groupList ); common->Printf( "----- OptimizeAreaGroups Results -----\n" ); common->Printf( "%6i tris in\n", c_in ); common->Printf( "%6i tris after edge removal optimization\n", c_edge ); common->Printf( "%6i tris after final t junction fixing\n", c_tjunc2 ); }
/* ==================== OptimizeOptList ==================== */ static void OptimizeOptList( optimizeGroup_t *opt ) { optimizeGroup_t *oldNext; // fix the t junctions among this single list // so we can match edges // can we avoid doing this if colinear vertexes break edges? oldNext = opt->nextGroup; opt->nextGroup = NULL; FixAreaGroupsTjunctions( opt ); opt->nextGroup = oldNext; // create the 2D vectors dmapGlobals.mapPlanes[opt->planeNum].Normal().NormalVectors( opt->axis[0], opt->axis[1] ); AddOriginalEdges( opt ); SplitOriginalEdgesAtCrossings( opt ); #if 0 // seperate any discontinuous areas for individual optimization // to reduce the scope of the problem SeparateIslands( opt ); #else DontSeparateIslands( opt ); #endif // now free the hash verts FreeTJunctionHash(); // free the original list and use the new one FreeTriList( opt->triList ); opt->triList = opt->regeneratedTris; opt->regeneratedTris = NULL; }
/* ================== FixEntityTjunctions ================== */ void FixEntityTjunctions( uEntity_t *e ) { int i; for ( i = 0 ; i < e->numAreas ; i++ ) { FixAreaGroupsTjunctions( e->areas[i].groups ); FreeTJunctionHash(); } }
/* ================== FixGlobalTjunctions ================== */ void FixGlobalTjunctions( uEntity_t *e ) { mapTri_t *a; int vert; int i; optimizeGroup_t *group; int areaNum; common->Printf( "----- FixGlobalTjunctions -----\n" ); // clear the hash tables memset( hashVerts, 0, sizeof( hashVerts ) ); numHashVerts = 0; numTotalVerts = 0; // bound all the triangles to determine the bucket size hashBounds.Clear(); for ( areaNum = 0 ; areaNum < e->numAreas ; areaNum++ ) { for ( group = e->areas[areaNum].groups ; group ; group = group->nextGroup ) { for ( a = group->triList ; a ; a = a->next ) { hashBounds.AddPoint( a->v[0].xyz ); hashBounds.AddPoint( a->v[1].xyz ); hashBounds.AddPoint( a->v[2].xyz ); } } } // spread the bounds so it will never have a zero size for ( i = 0 ; i < 3 ; i++ ) { hashBounds[0][i] = floor( hashBounds[0][i] - 1 ); hashBounds[1][i] = ceil( hashBounds[1][i] + 1 ); hashIntMins[i] = hashBounds[0][i] * SNAP_FRACTIONS; hashScale[i] = ( hashBounds[1][i] - hashBounds[0][i] ) / HASH_BINS; hashIntScale[i] = hashScale[i] * SNAP_FRACTIONS; if ( hashIntScale[i] < 1 ) { hashIntScale[i] = 1; } } // add all the points to the hash buckets for ( areaNum = 0 ; areaNum < e->numAreas ; areaNum++ ) { for ( group = e->areas[areaNum].groups ; group ; group = group->nextGroup ) { // don't touch discrete surfaces if ( group->material != NULL && group->material->IsDiscrete() ) { continue; } for ( a = group->triList ; a ; a = a->next ) { for ( vert = 0 ; vert < 3 ; vert++ ) { a->hashVert[vert] = GetHashVert( a->v[vert].xyz ); } } } } // add all the func_static model vertexes to the hash buckets // optionally inline some of the func_static models if ( dmapGlobals.entityNum == 0 ) { for ( int eNum = 1 ; eNum < dmapGlobals.num_entities ; eNum++ ) { uEntity_t *entity = &dmapGlobals.uEntities[eNum]; const char *className = entity->mapEntity->epairs.GetString( "classname" ); if ( idStr::Icmp( className, "func_static" ) ) { continue; } const char *modelName = entity->mapEntity->epairs.GetString( "model" ); if ( !modelName ) { continue; } if ( !strstr( modelName, ".lwo" ) && !strstr( modelName, ".ase" ) && !strstr( modelName, ".ma" ) ) { continue; } idRenderModel *model = renderModelManager->FindModel( modelName ); // common->Printf( "adding T junction verts for %s.\n", entity->mapEntity->epairs.GetString( "name" ) ); idMat3 axis; // get the rotation matrix in either full form, or single angle form if ( !entity->mapEntity->epairs.GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", axis ) ) { float angle = entity->mapEntity->epairs.GetFloat( "angle" ); if ( angle != 0.0f ) { axis = idAngles( 0.0f, angle, 0.0f ).ToMat3(); } else { axis.Identity(); } } idVec3 origin = entity->mapEntity->epairs.GetVector( "origin" ); for ( i = 0 ; i < model->NumSurfaces() ; i++ ) { const modelSurface_t *surface = model->Surface( i ); const srfTriangles_t *tri = surface->geometry; mapTri_t mapTri; memset( &mapTri, 0, sizeof( mapTri ) ); mapTri.material = surface->shader; // don't let discretes (autosprites, etc) merge together if ( mapTri.material->IsDiscrete() ) { mapTri.mergeGroup = (void *)surface; } for ( int j = 0 ; j < tri->numVerts ; j += 3 ) { idVec3 v = tri->verts[j].xyz * axis + origin; GetHashVert( v ); } } } } // now fix each area for ( areaNum = 0 ; areaNum < e->numAreas ; areaNum++ ) { for ( group = e->areas[areaNum].groups ; group ; group = group->nextGroup ) { // don't touch discrete surfaces if ( group->material != NULL && group->material->IsDiscrete() ) { continue; } mapTri_t *newList = NULL; for ( mapTri_t *tri = group->triList ; tri ; tri = tri->next ) { mapTri_t *fixed = FixTriangleAgainstHash( tri ); newList = MergeTriLists( newList, fixed ); } FreeTriList( group->triList ); group->triList = newList; } } // done FreeTJunctionHash(); }