/* * ProcessWorldModel */ static void ProcessWorldModel(void){ entity_t *e; tree_t *tree; boolean_t leaked; boolean_t optimize; e = &entities[entity_num]; brush_start = e->first_brush; brush_end = brush_start + e->num_brushes; leaked = false; // perform per-block operations if(block_xh * 1024 > map_maxs[0]) block_xh = floor(map_maxs[0] / 1024.0); if((block_xl + 1) * 1024 < map_mins[0]) block_xl = floor(map_mins[0] / 1024.0); if(block_yh * 1024 > map_maxs[1]) block_yh = floor(map_maxs[1] / 1024.0); if((block_yl + 1) * 1024 < map_mins[1]) block_yl = floor(map_mins[1] / 1024.0); if(block_xl < -4) block_xl = -4; if(block_yl < -4) block_yl = -4; if(block_xh > 3) block_xh = 3; if(block_yh > 3) block_yh = 3; for(optimize = false; optimize <= true; optimize++){ Com_Verbose("--------------------------------------------\n"); RunThreadsOn((block_xh - block_xl + 1) * (block_yh - block_yl + 1), !verbose, ProcessBlock_Thread); // build the division tree // oversizing the blocks guarantees that all the boundaries // will also get nodes. Com_Verbose("--------------------------------------------\n"); tree = AllocTree(); tree->head_node = BlockTree(block_xl - 1, block_yl - 1, block_xh + 1, block_yh + 1); tree->mins[0] = (block_xl) * 1024; tree->mins[1] = (block_yl) * 1024; tree->mins[2] = map_mins[2] - 8; tree->maxs[0] = (block_xh + 1) * 1024; tree->maxs[1] = (block_yh + 1) * 1024; tree->maxs[2] = map_maxs[2] + 8; // perform the global operations MakeTreePortals(tree); if(FloodEntities(tree)) FillOutside(tree->head_node); else { leaked = true; LeakFile(tree); if(leaktest){ Com_Error(ERR_FATAL, "--- MAP LEAKED, ABORTING LEAKTEST ---\n"); } Com_Verbose("**** leaked ****\n"); } MarkVisibleSides(tree, brush_start, brush_end); if(noopt || leaked) break; if(!optimize){ FreeTree(tree); } } FloodAreas(tree); MakeFaces(tree->head_node); FixTjuncs(tree->head_node); if(!noprune) PruneNodes(tree->head_node); WriteBSP(tree->head_node); if(!leaked) WritePortalFile(tree); FreeTree(tree); }
//=========================================================================== // creates an .AAS file with the given name // a MAP should be loaded before calling this // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_Create(char *aasfile) { entity_t *e; tree_t *tree; double start_time; //for a possible leak file strcpy(source, aasfile); StripExtension(source); //the time started start_time = I_FloatTime(); //set the default number of threads (depends on number of processors) ThreadSetDefault(); //set the global entity number to the world model entity_num = 0; //the world entity e = &entities[entity_num]; //process the whole world tree = ProcessWorldBrushes(e->firstbrush, e->firstbrush + e->numbrushes); //if the conversion is cancelled if (cancelconversion) { Tree_Free(tree); return; } //end if //display BSP tree creation time Log_Print("BSP tree created in %5.0f seconds\n", I_FloatTime() - start_time); //prune the bsp tree Tree_PruneNodes(tree->headnode); //if the conversion is cancelled if (cancelconversion) { Tree_Free(tree); return; } //end if //create the tree portals MakeTreePortals(tree); //if the conversion is cancelled if (cancelconversion) { Tree_Free(tree); return; } //end if //Marks all nodes that can be reached by entites if (FloodEntities(tree)) { //fill out nodes that can't be reached FillOutside(tree->headnode); } //end if else { LeakFile(tree); Error("**** leaked ****\n"); return; } //end else //create AAS from the BSP tree //========================================== //initialize tmp aas AAS_InitTmpAAS(); //create the convex areas from the leaves AAS_CreateAreas(tree->headnode); //free the BSP tree because it isn't used anymore if (freetree) Tree_Free(tree); //try to merge area faces AAS_MergeAreaFaces(); //do gravitational subdivision AAS_GravitationalSubdivision(); //merge faces if possible AAS_MergeAreaFaces(); AAS_RemoveAreaFaceColinearPoints(); //merge areas if possible AAS_MergeAreas(); //NOTE: prune nodes directly after area merging AAS_PruneNodes(); //flip shared faces so they are all facing to the same area AAS_FlipSharedFaces(); AAS_RemoveAreaFaceColinearPoints(); //merge faces if possible AAS_MergeAreaFaces(); //merge area faces in the same plane AAS_MergeAreaPlaneFaces(); //do ladder subdivision AAS_LadderSubdivision(); //FIXME: melting is buggy AAS_MeltAreaFaceWindings(); //remove tiny faces AAS_RemoveTinyFaces(); //create area settings AAS_CreateAreaSettings(); //check if the winding plane is equal to the face plane //AAS_CheckAreaWindingPlanes(); // //AAS_CheckSharedFaces(); //========================================== //if the conversion is cancelled if (cancelconversion) { Tree_Free(tree); AAS_FreeTmpAAS(); return; } //end if //store the created AAS stuff in the AAS file format and write the file AAS_StoreFile(aasfile); //free the temporary AAS memory AAS_FreeTmpAAS(); //display creation time Log_Print("\nAAS created in %5.0f seconds\n", I_FloatTime() - start_time); } //end of the function AAS_Create
void ProcessWorldModel( void ) { int i, s; entity_t *e; tree_t *tree; face_t *faces; qboolean ignoreLeaks, leaked; xmlNodePtr polyline, leaknode; char level[ 2 ], shader[ 1024 ]; const char *value; /* sets integer blockSize from worldspawn "_blocksize" key if it exists */ value = ValueForKey( &entities[ 0 ], "_blocksize" ); if( value[ 0 ] == '\0' ) value = ValueForKey( &entities[ 0 ], "blocksize" ); if( value[ 0 ] == '\0' ) value = ValueForKey( &entities[ 0 ], "chopsize" ); /* sof2 */ if( value[ 0 ] != '\0' ) { /* scan 3 numbers */ s = sscanf( value, "%d %d %d", &blockSize[ 0 ], &blockSize[ 1 ], &blockSize[ 2 ] ); /* handle legacy case */ if( s == 1 ) { blockSize[ 1 ] = blockSize[ 0 ]; blockSize[ 2 ] = blockSize[ 0 ]; } } Sys_Printf( "block size = { %d %d %d }\n", blockSize[ 0 ], blockSize[ 1 ], blockSize[ 2 ] ); /* sof2: ignore leaks? */ value = ValueForKey( &entities[ 0 ], "_ignoreleaks" ); /* ydnar */ if( value[ 0 ] == '\0' ) value = ValueForKey( &entities[ 0 ], "ignoreleaks" ); if( value[ 0 ] == '1' ) ignoreLeaks = qtrue; else ignoreLeaks = qfalse; /* begin worldspawn model */ BeginModel(); e = &entities[ 0 ]; e->firstDrawSurf = 0; /* ydnar: gs mods */ ClearMetaTriangles(); /* check for patches with adjacent edges that need to lod together */ PatchMapDrawSurfs( e ); /* build an initial bsp tree using all of the sides of all of the structural brushes */ faces = MakeStructuralBSPFaceList( entities[ 0 ].brushes ); tree = FaceBSP( faces ); MakeTreePortals( tree ); FilterStructuralBrushesIntoTree( e, tree ); /* see if the bsp is completely enclosed */ if( FloodEntities( tree ) || ignoreLeaks ) { /* rebuild a better bsp tree using only the sides that are visible from the inside */ FillOutside( tree->headnode ); /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */ ClipSidesIntoTree( e, tree ); /* build a visible face tree */ faces = MakeVisibleBSPFaceList( entities[ 0 ].brushes ); FreeTree( tree ); tree = FaceBSP( faces ); MakeTreePortals( tree ); FilterStructuralBrushesIntoTree( e, tree ); leaked = qfalse; /* ydnar: flood again for skybox */ if( skyboxPresent ) FloodEntities( tree ); } else { Sys_FPrintf( SYS_NOXML, "**********************\n" ); Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" ); Sys_FPrintf( SYS_NOXML, "**********************\n" ); polyline = LeakFile( tree ); leaknode = xmlNewNode( NULL, "message" ); xmlNodeSetContent( leaknode, "MAP LEAKED\n" ); xmlAddChild( leaknode, polyline ); level[0] = (int) '0' + SYS_ERR; level[1] = 0; xmlSetProp( leaknode, "level", (char*) &level ); xml_SendNode( leaknode ); if( leaktest ) { Sys_Printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n"); exit( 0 ); } leaked = qtrue; /* chop the sides to the convex hull of their visible fragments, giving us the smallest polygons */ ClipSidesIntoTree( e, tree ); } /* save out information for visibility processing */ NumberClusters( tree ); if( !leaked ) WritePortalFile( tree ); /* flood from entities */ FloodAreas( tree ); /* create drawsurfs for triangle models */ AddTriangleModels( e ); /* create drawsurfs for surface models */ AddEntitySurfaceModels( e ); /* generate bsp brushes from map brushes */ EmitBrushes( e->brushes, &e->firstBrush, &e->numBrushes ); /* add references to the detail brushes */ FilterDetailBrushesIntoTree( e, tree ); /* drawsurfs that cross fog boundaries will need to be split along the fog boundary */ if( !nofog ) FogDrawSurfaces( e ); /* subdivide each drawsurf as required by shader tesselation */ if( !nosubdivide ) SubdivideFaceSurfaces( e, tree ); /* add in any vertexes required to fix t-junctions */ if( !notjunc ) FixTJunctions( e ); /* ydnar: classify the surfaces */ ClassifyEntitySurfaces( e ); /* ydnar: project decals */ MakeEntityDecals( e ); /* ydnar: meta surfaces */ MakeEntityMetaTriangles( e ); SmoothMetaTriangles(); FixMetaTJunctions(); MergeMetaTriangles(); /* ydnar: debug portals */ if( debugPortals ) MakeDebugPortalSurfs( tree ); /* ydnar: fog hull */ value = ValueForKey( &entities[ 0 ], "_foghull" ); if( value[ 0 ] != '\0' ) { sprintf( shader, "textures/%s", value ); MakeFogHullSurfs( e, tree, shader ); } /* ydnar: bug 645: do flares for lights */ for( i = 0; i < numEntities && emitFlares; i++ ) { entity_t *light, *target; const char *value, *flareShader; vec3_t origin, targetOrigin, normal, color; int lightStyle; /* get light */ light = &entities[ i ]; value = ValueForKey( light, "classname" ); if( !strcmp( value, "light" ) ) { /* get flare shader */ flareShader = ValueForKey( light, "_flareshader" ); value = ValueForKey( light, "_flare" ); if( flareShader[ 0 ] != '\0' || value[ 0 ] != '\0' ) { /* get specifics */ GetVectorForKey( light, "origin", origin ); GetVectorForKey( light, "_color", color ); lightStyle = IntForKey( light, "_style" ); if( lightStyle == 0 ) lightStyle = IntForKey( light, "style" ); /* handle directional spotlights */ value = ValueForKey( light, "target" ); if( value[ 0 ] != '\0' ) { /* get target light */ target = FindTargetEntity( value ); if( target != NULL ) { GetVectorForKey( target, "origin", targetOrigin ); VectorSubtract( targetOrigin, origin, normal ); VectorNormalize( normal, normal ); } } else //% VectorClear( normal ); VectorSet( normal, 0, 0, -1 ); /* create the flare surface (note shader defaults automatically) */ DrawSurfaceForFlare( mapEntityNum, origin, normal, color, (char*) flareShader, lightStyle ); } } } /* add references to the final drawsurfs in the apropriate clusters */ FilterDrawsurfsIntoTree( e, tree ); /* match drawsurfaces back to original brushsides (sof2) */ FixBrushSides( e ); /* finish */ EndModel( e, tree->headnode ); FreeTree( tree ); }
/* ============ ProcessModel ============ */ bool ProcessModel( uEntity_t *e, bool floodFill ) { bspface_t *faces; // build a bsp tree using all of the sides // of all of the structural brushes faces = MakeStructuralBspFaceList ( e->primitives ); e->tree = FaceBSP( faces ); // create portals at every leaf intersection // to allow flood filling MakeTreePortals( e->tree ); // classify the leafs as opaque or areaportal FilterBrushesIntoTree( e ); // see if the bsp is completely enclosed if ( floodFill && !dmapGlobals.noFlood ) { if ( FloodEntities( e->tree ) ) { // set the outside leafs to opaque FillOutside( e ); } else { common->Printf ( "**********************\n" ); common->Warning( "******* leaked *******" ); common->Printf ( "**********************\n" ); LeakFile( e->tree ); // bail out here. If someone really wants to // process a map that leaks, they should use // -noFlood return false; } } // get minimum convex hulls for each visible side // this must be done before creating area portals, // because the visible hull is used as the portal ClipSidesByTree( e ); // determine areas before clipping tris into the // tree, so tris will never cross area boundaries FloodAreas( e ); // we now have a BSP tree with solid and non-solid leafs marked with areas // all primitives will now be clipped into this, throwing away // fragments in the solid areas PutPrimitivesInAreas( e ); // now build shadow volumes for the lights and split // the optimize lists by the light beam trees // so there won't be unneeded overdraw in the static // case Prelight( e ); // optimizing is a superset of fixing tjunctions if ( !dmapGlobals.noOptimize ) { OptimizeEntity( e ); } else if ( !dmapGlobals.noTJunc ) { FixEntityTjunctions( e ); } // now fix t junctions across areas FixGlobalTjunctions( e ); return true; }
/* ============ ProcessWorldModel ============ */ void ProcessWorldModel (void) { entity_t *e; tree_t *tree; qboolean leaked; qboolean optimize; e = &entities[entity_num]; brush_start = e->firstbrush; brush_end = brush_start + e->numbrushes; leaked = false; // // perform per-block operations // if (block_xh * 1024 > map_maxs[0]) block_xh = floor(map_maxs[0]/1024.0); if ( (block_xl+1) * 1024 < map_mins[0]) block_xl = floor(map_mins[0]/1024.0); if (block_yh * 1024 > map_maxs[1]) block_yh = floor(map_maxs[1]/1024.0); if ( (block_yl+1) * 1024 < map_mins[1]) block_yl = floor(map_mins[1]/1024.0); if (block_xl <-4) block_xl = -4; if (block_yl <-4) block_yl = -4; if (block_xh > 3) block_xh = 3; if (block_yh > 3) block_yh = 3; for (optimize = false ; optimize <= true ; optimize++) { qprintf ("--------------------------------------------\n"); RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1), !verbose, ProcessBlock_Thread); // // build the division tree // oversizing the blocks guarantees that all the boundaries // will also get nodes. // qprintf ("--------------------------------------------\n"); tree = AllocTree (); tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1); tree->mins[0] = (block_xl)*1024; tree->mins[1] = (block_yl)*1024; tree->mins[2] = map_mins[2] - 8; tree->maxs[0] = (block_xh+1)*1024; tree->maxs[1] = (block_yh+1)*1024; tree->maxs[2] = map_maxs[2] + 8; // // perform the global operations // MakeTreePortals (tree); if (FloodEntities (tree)) FillOutside (tree->headnode); else { printf ("**** leaked ****\n"); leaked = true; LeakFile (tree); if (leaktest) { printf ("--- MAP LEAKED ---\n"); exit (0); } } MarkVisibleSides (tree, brush_start, brush_end); if (noopt || leaked) break; if (!optimize) { FreeTree (tree); } } FloodAreas (tree); if (glview) WriteGLView (tree, source); MakeFaces (tree->headnode); FixTjuncs (tree->headnode); if (!noprune) PruneNodes (tree->headnode); WriteBSP (tree->headnode); if (!leaked) WritePortalFile (tree); FreeTree (tree); }
void ProcessWorldModel (void) { entity_t *e; tree_t *tree = NULL; qboolean leaked; int optimize; int start; e = &entities[entity_num]; brush_start = e->firstbrush; brush_end = brush_start + e->numbrushes; leaked = false; // // perform per-block operations // if (block_xh * BLOCKS_SIZE > g_MainMap->map_maxs[0]) { block_xh = floor(g_MainMap->map_maxs[0]/BLOCKS_SIZE); } if ( (block_xl+1) * BLOCKS_SIZE < g_MainMap->map_mins[0]) { block_xl = floor(g_MainMap->map_mins[0]/BLOCKS_SIZE); } if (block_yh * BLOCKS_SIZE > g_MainMap->map_maxs[1]) { block_yh = floor(g_MainMap->map_maxs[1]/BLOCKS_SIZE); } if ( (block_yl+1) * BLOCKS_SIZE < g_MainMap->map_mins[1]) { block_yl = floor(g_MainMap->map_mins[1]/BLOCKS_SIZE); } // HLTOOLS: updated to +/- MAX_COORD_INTEGER ( new world size limits / worldsize.h ) if (block_xl < BLOCKS_MIN) { block_xl = BLOCKS_MIN; } if (block_yl < BLOCKS_MIN) { block_yl = BLOCKS_MIN; } if (block_xh > BLOCKS_MAX) { block_xh = BLOCKS_MAX; } if (block_yh > BLOCKS_MAX) { block_yh = BLOCKS_MAX; } for (optimize = 0 ; optimize <= 1 ; optimize++) { qprintf ("--------------------------------------------\n"); RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1), !verbose, ProcessBlock_Thread); // // build the division tree // oversizing the blocks guarantees that all the boundaries // will also get nodes. // qprintf ("--------------------------------------------\n"); tree = AllocTree (); tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1); tree->mins[0] = (block_xl)*BLOCKS_SIZE; tree->mins[1] = (block_yl)*BLOCKS_SIZE; tree->mins[2] = g_MainMap->map_mins[2] - 8; tree->maxs[0] = (block_xh+1)*BLOCKS_SIZE; tree->maxs[1] = (block_yh+1)*BLOCKS_SIZE; tree->maxs[2] = g_MainMap->map_maxs[2] + 8; // // perform the global operations // // make the portals/faces by traversing down to each empty leaf MakeTreePortals (tree); if (FloodEntities (tree)) { // turns everthing outside into solid FillOutside (tree->headnode); } else { Warning( ("**** leaked ****\n") ); leaked = true; LeakFile (tree); if (leaktest) { Warning( ("--- MAP LEAKED ---\n") ); exit (0); } } // mark the brush sides that actually turned into faces MarkVisibleSides (tree, brush_start, brush_end, NO_DETAIL); if (noopt || leaked) break; if (!optimize) { // If we are optimizing, free the tree. Next time we will construct it again, but // we'll use the information in MarkVisibleSides() so we'll only split with planes that // actually contribute renderable geometry FreeTree (tree); } } FloodAreas (tree); RemoveAreaPortalBrushes_R( tree->headnode ); start = Plat_FloatTime(); Msg("Building Faces..."); // this turns portals with one solid side into faces // it also subdivides each face if necessary to fit max lightmap dimensions MakeFaces (tree->headnode); Msg("done (%d)\n", (int)(Plat_FloatTime() - start) ); if (glview) { WriteGLView (tree, source); } AssignOccluderAreas( tree ); Compute3DSkyboxAreas( tree->headnode, g_SkyAreas ); face_t *pLeafFaceList = NULL; if ( !nodetail ) { pLeafFaceList = MergeDetailTree( tree, brush_start, brush_end ); } start = Plat_FloatTime(); Msg("FixTjuncs...\n"); // This unifies the vertex list for all edges (splits collinear edges to remove t-junctions) // It also welds the list of vertices out of each winding/portal and rounds nearly integer verts to integer pLeafFaceList = FixTjuncs (tree->headnode, pLeafFaceList); // this merges all of the solid nodes that have separating planes if (!noprune) { Msg("PruneNodes...\n"); PruneNodes (tree->headnode); } // Msg( "SplitSubdividedFaces...\n" ); // SplitSubdividedFaces( tree->headnode ); Msg("WriteBSP...\n"); WriteBSP (tree->headnode, pLeafFaceList); Msg("done (%d)\n", (int)(Plat_FloatTime() - start) ); if (!leaked) { WritePortalFile (tree); } FreeTree( tree ); FreeLeafFaces( pLeafFaceList ); }
/* =============== ProcessEntity =============== */ void ProcessEntity (int entnum) { entity_t *ent; char mod[80]; surface_t *surfs; node_t *nodes; brushset_t *bs; ent = &entities[entnum]; if (!ent->brushes) return; // non-bmodel entity if (entnum > 0) { worldmodel = false; if (entnum == 1) qprintf ("--- Internal Entities ---\n"); sprintf (mod, "*%i", nummodels); if (verbose) PrintEntity (ent); if (hullnum == 0) printf ("MODEL: %s\n", mod); SetKeyValue (ent, "model", mod); } else worldmodel = true; // // take the brush_ts and clip off all overlapping and contained faces, // leaving a perfect skin of the model with no hidden faces // bs = Brush_LoadEntity (ent, hullnum); if (!bs->brushes) { PrintEntity (ent); Error ("Entity with no valid brushes"); } brushset = bs; surfs = CSGFaces (bs); if (hullnum != 0) { nodes = SolidBSP (surfs, true); if (entnum == 0 && !nofill) // assume non-world bmodels are simple { PortalizeWorld (nodes); if (FillOutside (nodes)) { surfs = GatherNodeFaces (nodes); nodes = SolidBSP (surfs, false); // make a really good tree with proper heuristic splitting plane selection } FreeAllPortals (nodes); } WriteNodePlanes (nodes); WriteClipNodes (nodes); BumpModel (hullnum); } else { // // SolidBSP generates a node tree // // if not the world, make a good tree first // the world is just going to make a bad tree // because the outside filling will force a regeneration later nodes = SolidBSP (surfs, entnum == 0); // // build all the portals in the bsp tree // some portals are solid polygons, and some are paths to other leafs // if (entnum == 0 && !nofill) // assume non-world bmodels are simple { PortalizeWorld (nodes); if (FillOutside (nodes)) { FreeAllPortals (nodes); // get the remaining faces together into surfaces again surfs = GatherNodeFaces (nodes); // merge polygons MergeAll (surfs); // make a really good tree nodes = SolidBSP (surfs, false); // make the real portals for vis tracing PortalizeWorld (nodes); // save portal file for vis tracing WritePortalfile (nodes); // fix tjunctions tjunc (nodes); } FreeAllPortals (nodes); } WriteNodePlanes (nodes); MakeFaceEdges (nodes); WriteDrawNodes (nodes); } }
/* ============ ProcessWorldModel ============ */ void ProcessWorldModel( void ) { entity_t *e; tree_t *tree; bspface_t *faces; qboolean leaked; BeginModel(); e = &entities[0]; e->firstDrawSurf = 0;//numMapDrawSurfs; // check for patches with adjacent edges that need to LOD together PatchMapDrawSurfs( e ); // build an initial bsp tree using all of the sides // of all of the structural brushes faces = MakeStructuralBspFaceList ( entities[0].brushes ); tree = FaceBSP( faces ); MakeTreePortals (tree); FilterStructuralBrushesIntoTree( e, tree ); // see if the bsp is completely enclosed if ( FloodEntities (tree) ) { // rebuild a better bsp tree using only the // sides that are visible from the inside FillOutside (tree->headnode); // chop the sides to the convex hull of // their visible fragments, giving us the smallest // polygons ClipSidesIntoTree( e, tree ); faces = MakeVisibleBspFaceList( entities[0].brushes ); FreeTree (tree); tree = FaceBSP( faces ); MakeTreePortals( tree ); FilterStructuralBrushesIntoTree( e, tree ); leaked = qfalse; } else { _printf ("**********************\n"); _printf ("******* leaked *******\n"); _printf ("**********************\n"); LeakFile (tree); if ( leaktest ) { _printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n"); exit (0); } leaked = qtrue; // chop the sides to the convex hull of // their visible fragments, giving us the smallest // polygons ClipSidesIntoTree( e, tree ); } // save out information for visibility processing NumberClusters( tree ); if ( !leaked ) { WritePortalFile( tree ); } if ( glview ) { // dump the portals for debugging WriteGLView( tree, source ); } FloodAreas (tree); // add references to the detail brushes FilterDetailBrushesIntoTree( e, tree ); // create drawsurfs for triangle models AddTriangleModels( tree ); // drawsurfs that cross fog boundaries will need to // be split along the bound if ( !nofog ) { FogDrawSurfs(); // may fragment drawsurfs } // subdivide each drawsurf as required by shader tesselation if ( !nosubdivide ) { SubdivideDrawSurfs( e, tree ); } // merge together all common shaders on the same plane and remove // all colinear points, so extra tjunctions won't be generated if ( !nomerge ) { MergeSides( e, tree ); // !@# testing } // add in any vertexes required to fix tjunctions if ( !notjunc ) { FixTJunctions( e ); } // allocate lightmaps for faces and patches AllocateLightmaps( e ); // add references to the final drawsurfs in the apropriate clusters FilterDrawsurfsIntoTree( e, tree ); EndModel( tree->headnode ); FreeTree (tree); }
/* ============ ProcessWorldModel ============ */ void ProcessWorldModel(void) { int s; entity_t *e; tree_t *tree; bspFace_t *faces; qboolean leaked; xmlNodePtr polyline, leaknode; char level[2]; const char *value; e = &entities[0]; e->firstDrawSurf = 0; //numMapDrawSurfs; // sets integer blockSize from worldspawn "_blocksize" key if it exists value = ValueForKey(e, "_blocksize"); if(value[0] == '\0') value = ValueForKey(e, "blocksize"); if(value[0] == '\0') value = ValueForKey(e, "chopsize"); // sof2 if(value[0] != '\0') { // scan 3 numbers s = sscanf(value, "%d %d %d", &blockSize[0], &blockSize[1], &blockSize[2]); // handle legacy case if(s == 1) { blockSize[1] = blockSize[0]; blockSize[2] = blockSize[0]; } } Sys_Printf("block size = { %d %d %d }\n", blockSize[0], blockSize[1], blockSize[2]); BeginModel(e); // check for patches with adjacent edges that need to LOD together PatchMapDrawSurfs(e); // build an initial bsp tree using all of the sides // of all of the structural brushes faces = MakeStructuralBspFaceList(entities[0].brushes); tree = FaceBSP(faces); MakeTreePortals(tree); FilterStructuralBrushesIntoTree(e, tree); if(drawFlag) { // draw unoptimized portals in new window drawTree = tree; Draw_Scene(DrawTree); } // see if the bsp is completely enclosed if(FloodEntities(tree)) { // rebuild a better bsp tree using only the // sides that are visible from the inside FillOutside(tree->headnode); // chop the sides to the convex hull of // their visible fragments, giving us the smallest // polygons ClipSidesIntoTree(e, tree); faces = MakeVisibleBspFaceList(entities[0].brushes); FreeTree(tree); tree = FaceBSP(faces); MakeTreePortals(tree); FilterStructuralBrushesIntoTree(e, tree); leaked = qfalse; } else { Sys_FPrintf(SYS_NOXML, "**********************\n"); Sys_FPrintf(SYS_NOXML, "******* leaked *******\n"); Sys_FPrintf(SYS_NOXML, "**********************\n"); polyline = LeakFile(tree); leaknode = xmlNewNode(NULL, "message"); xmlNodeSetContent(leaknode, "MAP LEAKED\n"); xmlAddChild(leaknode, polyline); level[0] = (int)'0' + SYS_ERR; level[1] = 0; xmlSetProp(leaknode, "level", (char *)&level); xml_SendNode(leaknode); if(leaktest) { Sys_Printf("--- MAP LEAKED, ABORTING LEAKTEST ---\n"); exit(0); } leaked = qtrue; // chop the sides to the convex hull of // their visible fragments, giving us the smallest // polygons ClipSidesIntoTree(e, tree); } // save out information for visibility processing NumberClusters(tree); if(!leaked) { WritePortalFile(tree); } if(glview) { // dump the portals for debugging WriteGLView(tree, source); } FloodAreas(tree); if(drawFlag) { // draw optimized portals in new window drawTree = tree; Draw_Scene(DrawTree); } // add references to the detail brushes FilterDetailBrushesIntoTree(e, tree); // create drawsurfs for triangle models AddTriangleModels(); // drawsurfs that cross fog boundaries will need to // be split along the bound if(!nofog) { FogDrawSurfs(); // may fragment drawsurfs } // subdivide each drawsurf as required by shader tesselation if(!nosubdivide) { SubdivideDrawSurfs(e, tree); } // merge together all common shaders on the same plane and remove // all colinear points, so extra tjunctions won't be generated if(!nomerge) { MergeSides(e, tree); // !@# testing } // add in any vertexes required to fix tjunctions if(!notjunc) { FixTJunctions(e); } // allocate lightmaps for faces and patches AllocateLightmaps(e); // add references to the final drawsurfs in the apropriate clusters FilterDrawsurfsIntoTree(e, tree); EndModel(e, tree->headnode); FreeTree(tree); }