/* ============ EndBSPFile ============ */ void EndBSPFile( void ){ char path[1024]; #if 0 int len; byte *buf; #endif EmitBrushes(); EmitPlanes(); UnparseEntities(); // load the pop #if 0 sprintf( path, "%s/pics/pop.lmp", gamedir ); len = LoadFile( path, &buf ); memcpy( dpop, buf, sizeof( dpop ) ); free( buf ); #endif // write the map sprintf( path, "%s.bsp", source ); Sys_Printf( "Writing %s\n", path ); WriteBSPFile( path ); }
/** * @brief Finishes a new bsp and writes to disk * @sa BeginBSPFile */ void EndBSPFile (const char* filename) { EmitBrushes(); EmitPlanes(); UnparseEntities(); /* write the map */ Verb_Printf(VERB_LESS, "Writing %s\n", filename); WriteBSPFile(filename); }
/* ============ EndBSPFile ============ */ void EndBSPFile (void) { // Mark noshadow faces. MarkNoShadowFaces(); EmitBrushes (); EmitPlanes (); // stick flat normals at the verts SaveVertexNormals(); // Figure out lightmap extents for all faces. UpdateAllFaceLightmapExtents(); // Generate geometry and lightmap alpha for displacements. EmitDispLMAlphaAndNeighbors(); // Emit overlay data. Overlay_EmitOverlayFaces(); OverlayTransition_EmitOverlayFaces(); // phys collision needs dispinfo to operate (needs to generate phys collision for displacement surfs) EmitPhysCollision(); // We can't calculate this properly until vvis (since we need vis to do this), so we set // to zero everywhere by default. ClearDistToClosestWater(); // Emit static props found in the .vmf file EmitStaticProps(); // Place detail props found in .vmf and based on material properties EmitDetailObjects(); // Compute bounds after creating disp info because we need to reference it ComputeBoundsNoSkybox(); // Make sure that we have a water lod control eneity if we have water in the map. EnsurePresenceOfWaterLODControlEntity(); // Doing this here because stuff about may filter out entities UnparseEntities (); // remove unused texinfos CompactTexinfos(); // Figure out which faces want macro textures. DiscoverMacroTextures(); char fileName[1024]; V_strncpy( fileName, source, sizeof( fileName ) ); V_DefaultExtension( fileName, ".bsp", sizeof( fileName ) ); Msg ("Writing %s\n", fileName); WriteBSPFile (fileName); }
/* ============ EndBSPFile ============ */ void EndBSPFile (void) { char path[1024]; EmitBrushes (); EmitPlanes (); UnparseEntities (); // write the map sprintf (path, "%s.bsp", source); Con_Print ("Writing %s\n", path); WriteBSPFile (path); }
/* * @brief */ void EndBSPFile(void) { EmitBrushes(); EmitPlanes(); EmitAreaPortals(); UnparseEntities(); // now that the verts have been resolved, align the normals count d_bsp.num_normals = d_bsp.num_vertexes; // write the map Com_Verbose("Writing %s\n", bsp_name); WriteBSPFile(bsp_name); }
/* ============ EndBSPFile ============ */ void EndBSPFile( void ) { #if 0 char path[1024]; int len; byte *buf; #endif EmitBrushes(); EmitPlanes(); Q2_UnparseEntities(); // load the pop #if 0 sprintf( path, "%s/pics/pop.lmp", gamedir ); len = LoadFile( path, &buf ); memcpy( dpop, buf, sizeof( dpop ) ); FreeMemory( buf ); #endif }
/* ================== BeginModel ================== */ void BeginModel( void ) { dmodel_t *mod; bspbrush_t *b; entity_t *e; vec3_t mins, maxs; parseMesh_t *p; int i; if ( nummodels == MAX_MAP_MODELS ) { Error( "MAX_MAP_MODELS" ); } mod = &dmodels[nummodels]; // // bound the brushes // e = &entities[entity_num]; ClearBounds (mins, maxs); for ( b = e->brushes ; b ; b = b->next ) { if ( !b->numsides ) { continue; // not a real brush (origin brush, etc) } AddPointToBounds (b->mins, mins, maxs); AddPointToBounds (b->maxs, mins, maxs); } for ( p = e->patches ; p ; p = p->next ) { for ( i = 0 ; i < p->mesh.width * p->mesh.height ; i++ ) { AddPointToBounds( p->mesh.verts[i].xyz, mins, maxs ); } } VectorCopy (mins, mod->mins); VectorCopy (maxs, mod->maxs); mod->firstSurface = numDrawSurfaces; mod->firstBrush = numbrushes; EmitBrushes( e->brushes ); }
void ProcessSubModel( void ) { entity_t *e; tree_t *tree; brush_t *b, *bc; node_t *node; /* start a brush model */ BeginModel(); e = &entities[ mapEntityNum ]; e->firstDrawSurf = numMapDrawSurfs; /* ydnar: gs mods */ ClearMetaTriangles(); /* check for patches with adjacent edges that need to lod together */ PatchMapDrawSurfs( e ); /* allocate a tree */ node = AllocNode(); node->planenum = PLANENUM_LEAF; tree = AllocTree(); tree->headnode = node; /* add the sides to the tree */ ClipSidesIntoTree( e, tree ); /* ydnar: 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 ); /* just put all the brushes in headnode */ for( b = e->brushes; b; b = b->next ) { bc = CopyBrush( b ); bc->next = node->brushlist; node->brushlist = bc; } /* 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 and project lightmaps */ ClassifyEntitySurfaces( e ); /* ydnar: project decals */ MakeEntityDecals( e ); /* ydnar: meta surfaces */ MakeEntityMetaTriangles( e ); SmoothMetaTriangles(); FixMetaTJunctions(); MergeMetaTriangles(); /* 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, node ); FreeTree( tree ); }
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 ); }
/** * @brief Calculates the routing of a map * @sa CheckUnit * @sa CheckConnections * @sa ProcessWorldModel */ void DoRouting (void) { int i; byte* data; vec3_t mins, maxs; pos3_t pos; /* Turn on trace debugging if requested. */ if (config.generateDebugTrace) debugTrace = true; /* Record the current mapTiles[0] state so we can remove all CLIPS when done. */ PushInfo(); /* build tracing structure */ EmitBrushes(); EmitPlanes(); /** This is needed for tracing to work!!! */ /** @note LEVEL_TRACING is not an actual level */ MakeTracingNodes(LEVEL_ACTORCLIP + 1); /* Reset the whole block of map data to 0 */ Nmap.init(); /* get world bounds for optimizing */ RT_GetMapSize(&mapTiles, mins, maxs); /* Com_Printf("Vectors: (%f, %f, %f) to (%f, %f, %f)\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); */ VecToPos(mins, wpMins); VecToPos(maxs, wpMaxs); /* Verify the world extents are not lopsided. */ assert(wpMins[0] <= wpMaxs[0]); assert(wpMins[1] <= wpMaxs[1]); assert(wpMins[2] <= wpMaxs[2]); /* scan area heights */ RunSingleThreadOn(CheckUnitThread, PATHFINDING_WIDTH * PATHFINDING_WIDTH * ACTOR_MAX_SIZE, config.verbosity >= VERB_NORMAL, "UNITCHECK"); /* scan connections */ RunSingleThreadOn(CheckConnectionsThread, PATHFINDING_WIDTH * PATHFINDING_WIDTH * (CORE_DIRECTIONS / (1 + RT_IS_BIDIRECTIONAL)) * (ACTOR_MAX_SIZE), config.verbosity >= VERB_NORMAL, "CONNCHECK"); /* Try to shrink the world bounds along the x and y coordinates */ for (i = 0; i < 2; i++) { /* for x and y, but not z */ int j = i ^ 1; /* if i points to x, j points to y and vice versa */ /* Increase the mins */ while (wpMaxs[j] > wpMins[j]) { VectorSet(pos, wpMins[0], wpMins[1], wpMaxs[2]); for (pos[i] = wpMins[i]; pos[i] <= wpMaxs[i]; pos[i]++) { /* for all cells in an x or y row */ if (Nmap.getFloor(1, pos[0], pos[1], wpMaxs[2]) + wpMaxs[2] * CELL_HEIGHT != -1) /* no floor ? */ break; } if (pos[i] <= wpMaxs[i]) /* found a floor before the end of the row ? */ break; /* break while */ wpMins[j]++; /* if it was an x-row, increase y-value of mins and vice versa */ } /* Decrease the maxs */ while (wpMaxs[j] > wpMins[j]) { VectorCopy(wpMaxs, pos); for (pos[i] = wpMins[i]; pos[i] <= wpMaxs[i]; pos[i]++) { if (Nmap.getFloor(1, pos[0], pos[1], wpMaxs[2]) + wpMaxs[2] * CELL_HEIGHT != -1) break; } if (pos[i] <= wpMaxs[i]) break; wpMaxs[j]--; } } /* Output the floor trace file if set */ if (config.generateTraceFile) { RT_WriteCSVFiles(Nmap, baseFilename, wpMins, wpMaxs); } /* store the data */ data = curTile->routedata; for (i = 0; i < 3; i++) wpMins[i] = LittleLong(wpMins[i]); data = CompressRouting((byte*)wpMins, data, sizeof(wpMins)); for (i = 0; i < 3; i++) wpMaxs[i] = LittleLong(wpMaxs[i]); data = CompressRouting((byte*)wpMaxs, data, sizeof(wpMaxs)); data = CompressRouting((byte*)&Nmap, data, sizeof(Nmap)); curTile->routedatasize = data - curTile->routedata; /* Ensure that we did not exceed our allotment of memory for this data. */ assert(curTile->routedatasize <= MAX_MAP_ROUTING); /* Remove the CLIPS fom the tracing structure by resetting it. */ PopInfo(); }
/* PseudoCompileBSP() a stripped down ProcessModels */ void PseudoCompileBSP( qboolean need_tree, const char *BSPFilePath, const char *surfaceFilePath ){ int models; char modelValue[10]; entity_t *entity; face_t *faces; tree_t *tree; node_t *node; brush_t *brush; side_t *side; int i; SetDrawSurfacesBuffer(); mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS ); memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS ); numMapDrawSurfs = 0; BeginBSPFile(); models = 1; for ( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ ) { /* get entity */ entity = &entities[ mapEntityNum ]; if ( entity->brushes == NULL && entity->patches == NULL ) { continue; } if ( mapEntityNum != 0 ) { sprintf( modelValue, "*%d", models++ ); SetKeyValue( entity, "model", modelValue ); } /* process the model */ Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels ); BeginModel(); entity->firstDrawSurf = numMapDrawSurfs; ClearMetaTriangles(); PatchMapDrawSurfs( entity ); if ( mapEntityNum == 0 && need_tree ) { faces = MakeStructuralBSPFaceList( entities[0].brushes ); tree = FaceBSP( faces ); node = tree->headnode; } else { node = AllocNode(); node->planenum = PLANENUM_LEAF; tree = AllocTree(); tree->headnode = node; } /* a minimized ClipSidesIntoTree */ for ( brush = entity->brushes; brush; brush = brush->next ) { /* walk the brush sides */ for ( i = 0; i < brush->numsides; i++ ) { /* get side */ side = &brush->sides[ i ]; if ( side->winding == NULL ) { continue; } /* shader? */ if ( side->shaderInfo == NULL ) { continue; } /* save this winding as a visible surface */ DrawSurfaceForSide( entity, brush, side, side->winding ); } } if ( meta ) { ClassifyEntitySurfaces( entity ); MakeEntityDecals( entity ); MakeEntityMetaTriangles( entity ); SmoothMetaTriangles(); MergeMetaTriangles(); } FilterDrawsurfsIntoTree( entity, tree ); FilterStructuralBrushesIntoTree( entity, tree ); FilterDetailBrushesIntoTree( entity, tree ); EmitBrushes( entity->brushes, &entity->firstBrush, &entity->numBrushes ); EndModel( entity, node ); } EndBSPFile( qfalse, BSPFilePath, surfaceFilePath ); }