/* ================== CalcPortalVis ================== */ void CalcPortalVis( void ){ #ifdef MREDEBUG Sys_Printf( "%6d portals out of %d", 0, numportals * 2 ); //get rid of the counter RunThreadsOnIndividual( numportals * 2, qfalse, PortalFlow ); #else RunThreadsOnIndividual( numportals * 2, qtrue, PortalFlow ); #endif }
/* ============= RadWorld ============= */ void RadWorld (void) { int i; MakeBackplanes (); MakeParents (0, -1); MakeTnodes (&dmodels[0]); // turn each face into a single patch MakePatches (); PairEdges (); // subdivide patches to a maximum dimension SubdividePatches (); do { // create directlights out of patches and lights CreateDirectLights (); // build initial facelights RunThreadsOnIndividual (numfaces, true, BuildFacelights); // free up the direct lights now that we have facelights DeleteDirectLights (); } while( numbounce != 0 && ProgressiveRefinement() ); if (numbounce > 0) { // build transfer lists MakeAllScales (); // invert the transfers for gather vs scatter RunThreadsOnIndividual (num_patches, true, SwapTransfersTask); // spread light around BounceLight (); for( i=0; i < num_patches; i++ ) if ( !VectorCompare( patches[i].directlight, vec3_origin ) ) VectorSubtract( patches[i].totallight, patches[i].directlight, patches[i].totallight ); } // blend bounced light into direct light and save PrecompLightmapOffsets(); RunThreadsOnIndividual (numfaces, true, FinalLightFace); }
void RadCreateDiffuseLights( void ){ /* startup */ Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" ); numDiffuseSurfaces = 0; numDiffuseLights = 0; numBrushDiffuseLights = 0; numTriangleDiffuseLights = 0; numPatchDiffuseLights = 0; numAreaLights = 0; /* hit every surface (threaded) */ RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight ); /* dump the lights generated to a file */ if ( dump ) { char dumpName[ 1024 ], ext[ 64 ]; FILE *file; light_t *light; strcpy( dumpName, source ); StripExtension( dumpName ); sprintf( ext, "_bounce_%03d.map", iterations ); strcat( dumpName, ext ); file = fopen( dumpName, "wb" ); Sys_Printf( "Writing %s...\n", dumpName ); if ( file ) { for ( light = lights; light; light = light->next ) { fprintf( file, "{\n" "\"classname\" \"light\"\n" "\"light\" \"%d\"\n" "\"origin\" \"%.0f %.0f %.0f\"\n" "\"_color\" \"%.3f %.3f %.3f\"\n" "}\n", (int) light->add, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ], light->color[ 0 ], light->color[ 1 ], light->color[ 2 ] ); } fclose( file ); } } /* increment */ iterations++; /* print counts */ Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces ); Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights ); Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights ); Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights ); Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights ); }
/* ================== CalcPortalVis ================== */ void CalcPortalVis (void) { int i; // fastvis just uses mightsee for a very loose bound if( fastvis ) { for (i=0 ; i<g_numportals*2 ; i++) { portals[i].portalvis = portals[i].portalflood; portals[i].status = stat_done; } return; } if (g_bUseMPI) { RunMPIPortalFlow(); } else { RunThreadsOnIndividual (g_numportals*2, true, PortalFlow); } }
/* ================== CalcPassagePortalVis ================== */ void CalcPassagePortalVis( void ){ PassageMemory(); #ifdef MREDEBUG Sys_Printf( "%6d portals out of %d", 0, numportals * 2 ); RunThreadsOnIndividual( numportals * 2, qfalse, CreatePassages ); Sys_Printf( "\n" ); Sys_Printf( "%6d portals out of %d", 0, numportals * 2 ); RunThreadsOnIndividual( numportals * 2, qfalse, PassagePortalFlow ); Sys_Printf( "\n" ); #else Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 ); RunThreadsOnIndividual( numportals * 2, qtrue, CreatePassages ); Sys_Printf( "\n--- PassagePortalFlow (%d) ---\n", numportals * 2 ); RunThreadsOnIndividual( numportals * 2, qtrue, PassagePortalFlow ); #endif }
/* ================== CalcVis ================== */ void CalcVis( void ){ int i; const char *value; /* ydnar: rr2do2's farplane code */ farPlaneDist = 0.0f; value = ValueForKey( &entities[ 0 ], "_farplanedist" ); /* proper '_' prefixed key */ if ( value[ 0 ] == '\0' ) { value = ValueForKey( &entities[ 0 ], "fogclip" ); /* wolf compatibility */ } if ( value[ 0 ] == '\0' ) { value = ValueForKey( &entities[ 0 ], "distancecull" ); /* sof2 compatibility */ } if ( value[ 0 ] != '\0' ) { farPlaneDist = atof( value ); if ( farPlaneDist > 0.0f ) { Sys_Printf( "farplane distance = %.1f\n", farPlaneDist ); } else{ farPlaneDist = 0.0f; } } Sys_Printf( "\n--- BasePortalVis (%d) ---\n", numportals * 2 ); RunThreadsOnIndividual( numportals * 2, qtrue, BasePortalVis ); // RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis); SortPortals(); if ( fastvis ) { CalcFastVis(); } else if ( noPassageVis ) { CalcPortalVis(); } else if ( passageVisOnly ) { CalcPassageVis(); } else { CalcPassagePortalVis(); } // // assemble the leaf vis lists by oring and compressing the portal lists // Sys_Printf( "creating leaf vis...\n" ); for ( i = 0 ; i < portalclusters ; i++ ) ClusterMerge( i ); Sys_Printf( "Total visible clusters: %i\n", totalvis ); Sys_Printf( "Average clusters visible: %i\n", totalvis / portalclusters ); }
void ProcessModels (void) { int i, j, type; int placed; int first, contents; brush_t temp; vec3_t origin; for (i=0 ; i<num_entities ; i++) { if (!entities[i].numbrushes) continue; // // sort the contents down so stone bites water, etc // first = entities[i].firstbrush; placed = 0; for (type=0 ; type<4 ; type++) { contents = typecontents[type]; for (j=placed+1 ; j< entities[i].numbrushes ; j++) { if (mapbrushes[first+j].contents == contents) { temp = mapbrushes[first+placed]; mapbrushes[first+placed] = mapbrushes[j]; mapbrushes[j] = temp; placed++; } } } // // csg them in order // if (i == 0) { RunThreadsOnIndividual (entities[i].numbrushes, 1 , CSGBrush); } else { for (j=0 ; j<entities[i].numbrushes ; j++) CSGBrush (first + j); } // write end of model marker if (!glview) { for (j=0 ; j<NUM_HULLS ; j++) fprintf (out[j], "-1 -1 -1 -1\n"); } } }
/* ============= LightWorld ============= */ void LightWorld (void) { filebase = file_p = dlightdata; file_end = filebase + MAX_MAP_LIGHTING; RunThreadsOnIndividual (numfaces, true, LightFace); lightdatasize = file_p - filebase; printf ("lightdatasize: %i\n", lightdatasize); }
/* ================== CalcVis ================== */ void CalcVis( void ){ int i; RunThreadsOnIndividual( numportals * 2, true, BasePortalVis ); // RunThreadsOnIndividual (numportals*2, true, BetterPortalVis); SortPortals(); CalcPortalVis(); // // assemble the leaf vis lists by oring and compressing the portal lists // for ( i = 0 ; i < portalclusters ; i++ ) ClusterMerge( i ); Sys_Printf( "Average clusters visible: %i\n", totalvis / portalclusters ); }
/* ================== CalcVis ================== */ void CalcVis (void) { int i; if (g_bUseMPI) { RunMPIBasePortalVis(); } else { RunThreadsOnIndividual (g_numportals*2, true, BasePortalVis); } SortPortals (); CalcPortalVis (); // // assemble the leaf vis lists by oring the portal lists // for ( i = 0; i < portalclusters; i++ ) { ClusterMerge( i ); } int count = 0; // Now crosscheck each leaf's vis and compress for ( i = 0; i < portalclusters; i++ ) { count += CompressAndCrosscheckClusterVis( i ); } Msg ("Optimized: %d visible clusters (%.2f%%)\n", count, totalvis, count*100/totalvis); Msg ("Total clusters visible: %i\n", totalvis); Msg ("Average clusters visible: %i\n", totalvis / portalclusters); }
/* ================== CalcVis ================== */ void CalcVis(void) { int i, minvis, maxvis; const char *value; double mu, sigma, totalvis, totalvis2; /* ydnar: rr2do2's farplane code */ farPlaneDist = 0.0f; value = ValueForKey(&entities[0], "_farplanedist"); /* proper '_' prefixed key */ if(value[0] == '\0') value = ValueForKey(&entities[0], "fogclip"); /* wolf compatibility */ if(value[0] == '\0') value = ValueForKey(&entities[0], "distancecull"); /* sof2 compatibility */ if(value[0] != '\0') { farPlaneDist = atof(value); if(farPlaneDist > 0.0f) Sys_Printf("farplane distance = %.1f\n", farPlaneDist); else farPlaneDist = 0.0f; } Sys_Printf("\n--- BasePortalVis (%d) ---\n", numportals * 2); RunThreadsOnIndividual(numportals * 2, qtrue, BasePortalVis); // RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis); SortPortals(); if(fastvis) { CalcFastVis(); } else if(noPassageVis) { CalcPortalVis(); } else if(passageVisOnly) { CalcPassageVis(); } else { CalcPassagePortalVis(); } // // assemble the leaf vis lists by oring and compressing the portal lists // Sys_Printf("creating leaf vis...\n"); for(i = 0; i < portalclusters; i++) ClusterMerge(i); totalvis = 0; totalvis2 = 0; minvis = -1; maxvis = -1; for(i = 0; i < MAX_MAP_LEAFS; ++i) if(clustersizehistogram[i]) { if(debugCluster) Sys_FPrintf(SYS_VRB, "%4i clusters have exactly %4i visible clusters\n", clustersizehistogram[i], i); /* cast is to prevent integer overflow */ totalvis += ((double)i) * ((double)clustersizehistogram[i]); totalvis2 += ((double)i) * ((double)i) * ((double)clustersizehistogram[i]); if(minvis < 0) minvis = i; maxvis = i; } mu = totalvis / portalclusters; sigma = sqrt(totalvis2 / portalclusters - mu * mu); Sys_Printf("Total clusters: %i\n", portalclusters); Sys_Printf("Total visible clusters: %.0f\n", totalvis); Sys_Printf("Average clusters visible: %.2f (%.3f%%/total)\n", mu, mu / portalclusters * 100.0); Sys_Printf(" Standard deviation: %.2f (%.3f%%/total, %.3f%%/avg)\n", sigma, sigma / portalclusters * 100.0, sigma / mu * 100.0); Sys_Printf(" Minimum: %i (%.3f%%/total, %.3f%%/avg)\n", minvis, minvis / (double)portalclusters * 100.0, minvis / mu * 100.0); Sys_Printf(" Maximum: %i (%.3f%%/total, %.3f%%/avg)\n", maxvis, maxvis / (double)portalclusters * 100.0, maxvis / mu * 100.0); }
/* ============ 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 ); }
int main (int argc, char **argv) { int i, j; int hull; entity_t *ent; char source[1024]; char name[1024]; double start, end; printf( "qcsg.exe v2.8 (%s)\n", __DATE__ ); printf ("---- qcsg ----\n" ); for (i=1 ; i<argc ; i++) { if (!strcmp(argv[i],"-threads")) { numthreads = atoi (argv[i+1]); i++; } else if (!strcmp(argv[i],"-glview")) { glview = true; } else if (!strcmp(argv[i], "-v")) { printf ("verbose = true\n"); verbose = true; } else if (!strcmp(argv[i], "-draw")) { printf ("drawflag = true\n"); drawflag = true; } else if (!strcmp(argv[i], "-noclip")) { printf ("noclip = true\n"); noclip = true; } else if (!strcmp(argv[i], "-onlyents")) { printf ("onlyents = true\n"); onlyents = true; } else if (!strcmp(argv[i], "-nowadtextures")) { printf ("wadtextures = false\n"); wadtextures = false; } else if (!strcmp(argv[i], "-wadinclude")) { pszWadInclude[nWadInclude++] = strdup( argv[i + 1] ); i++; } else if( !strcmp( argv[ i ], "-proj" ) ) { strcpy( qproject, argv[ i + 1 ] ); i++; } else if (!strcmp(argv[i], "-hullfile")) { hullfile = true; strcpy( qhullfile, argv[i + 1] ); i++; } else if (argv[i][0] == '-') Error ("Unknown option \"%s\"", argv[i]); else break; } if (i != argc - 1) Error ("usage: qcsg [-nowadtextures] [-wadinclude <name>] [-draw] [-glview] [-noclip] [-onlyents] [-proj <name>] [-threads #] [-v] [-hullfile <name>] mapfile"); SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL); start = I_FloatTime (); CheckHullFile( hullfile, qhullfile ); ThreadSetDefault (); SetQdirFromPath (argv[i]); strcpy (source, ExpandArg (argv[i])); COM_FixSlashes(source); StripExtension (source); strcpy (name, ExpandArg (argv[i])); DefaultExtension (name, ".map"); // might be .reg // // if onlyents, just grab the entites and resave // if (onlyents && !glview) { char out[1024]; int old_entities; sprintf (out, "%s.bsp", source); LoadBSPFile (out); // Get the new entity data from the map file LoadMapFile (name); // Write it all back out again. WriteBSP (source); end = I_FloatTime (); printf ("%5.0f seconds elapsed\n", end-start); return 0; } // // start from scratch // LoadMapFile (name); RunThreadsOnIndividual (nummapbrushes, true, CreateBrush); BoundWorld (); qprintf ("%5i map planes\n", nummapplanes); for (i=0 ; i<NUM_HULLS ; i++) { char name[1024]; if (glview) sprintf (name, "%s.gl%i",source, i); else sprintf (name, "%s.p%i",source, i); out[i] = fopen (name, "w"); if (!out[i]) Error ("Couldn't open %s",name); } ProcessModels (); qprintf ("%5i csg faces\n", c_csgfaces); qprintf ("%5i used faces\n", c_outfaces); qprintf ("%5i tiny faces\n", c_tiny); qprintf ("%5i tiny clips\n", c_tiny_clip); for (i=0 ; i<NUM_HULLS ; i++) fclose (out[i]); if (!glview) { EmitPlanes (); WriteBSP (source); } end = I_FloatTime (); printf ("%5.0f seconds elapsed\n", end-start); return 0; }