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 ); }
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 ); }
/* 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 ); }