/* * ProcessSubModel */ static void ProcessSubModel(void){ entity_t *e; int start, end; tree_t *tree; bsp_brush_t *list; vec3_t mins, maxs; e = &entities[entity_num]; start = e->first_brush; end = start + e->num_brushes; mins[0] = mins[1] = mins[2] = -MAX_WORLD_WIDTH; maxs[0] = maxs[1] = maxs[2] = MAX_WORLD_WIDTH; list = MakeBspBrushList(start, end, mins, maxs); if(!nocsg) list = ChopBrushes(list); tree = BrushBSP(list, mins, maxs); MakeTreePortals(tree); MarkVisibleSides(tree, start, end); MakeFaces(tree->head_node); FixTjuncs(tree->head_node); WriteBSP(tree->head_node); FreeTree(tree); }
/* ============ ProcessSubModel ============ */ void ProcessSubModel( ) { entity_t *e; int start, end; tree_t *tree; bspbrush_t *list; Vector mins, maxs; e = &entities[entity_num]; start = e->firstbrush; end = start + e->numbrushes; mins[0] = mins[1] = mins[2] = MIN_COORD_INTEGER; maxs[0] = maxs[1] = maxs[2] = MAX_COORD_INTEGER; list = MakeBspBrushList (start, end, mins, maxs, FULL_DETAIL); if (!nocsg) list = ChopBrushes (list); tree = BrushBSP (list, mins, maxs); // This would wind up crashing the engine because we'd have a negative leaf index in dmodel_t::headnode. if ( tree->headnode->planenum == PLANENUM_LEAF ) { const char *pClassName = ValueForKey( e, "classname" ); const char *pTargetName = ValueForKey( e, "targetname" ); Error( "bmodel %d has no head node (class '%s', targetname '%s')", entity_num, pClassName, pTargetName ); } MakeTreePortals (tree); #if DEBUG_BRUSHMODEL if ( entity_num == DEBUG_BRUSHMODEL ) WriteGLView( tree, "tree_all" ); #endif MarkVisibleSides (tree, start, end, FULL_DETAIL); MakeFaces (tree->headnode); FixTjuncs( tree->headnode, NULL ); WriteBSP( tree->headnode, NULL ); #if DEBUG_BRUSHMODEL if ( entity_num == DEBUG_BRUSHMODEL ) { WriteGLView( tree, "tree_vis" ); WriteGLViewFaces( tree, "tree_faces" ); } #endif FreeTree (tree); }
//----------------------------------------------------------------------------- // Clips all occluder brushes against each other //----------------------------------------------------------------------------- static tree_t *ClipOccluderBrushes( ) { // Create a list of all occluder brushes in the level CUtlVector< mapbrush_t * > mapBrushes( 1024, 1024 ); for ( entity_num=0; entity_num < g_MainMap->num_entities; ++entity_num ) { if (!IsFuncOccluder(entity_num)) continue; entity_t *e = &entities[entity_num]; int end = e->firstbrush + e->numbrushes; int i; for ( i = e->firstbrush; i < end; ++i ) { mapBrushes.AddToTail( &g_MainMap->mapbrushes[i] ); } } int nBrushCount = mapBrushes.Count(); if ( nBrushCount == 0 ) return NULL; Vector mins, maxs; mins[0] = mins[1] = mins[2] = MIN_COORD_INTEGER; maxs[0] = maxs[1] = maxs[2] = MAX_COORD_INTEGER; bspbrush_t *list = MakeBspBrushList( mapBrushes.Base(), nBrushCount, mins, maxs ); if (!nocsg) list = ChopBrushes (list); tree_t *tree = BrushBSP (list, mins, maxs); MakeTreePortals (tree); MarkVisibleSides (tree, mapBrushes.Base(), nBrushCount); MakeFaces( tree->headnode ); // NOTE: This will output the occluder face vertices + planes FixTjuncs( tree->headnode, NULL ); return tree; }
/** * @sa ProcessModels */ static void ProcessSubModel (int entityNum) { const entity_t* e; int start, end; tree_t* tree; bspbrush_t* list; AABB aabb; BeginModel(entityNum); e = &entities[entityNum]; #if 0 Com_Printf("Processing entity: %i into model %i (%s:%s)\n", entityNum, curTile->nummodels, e->epairs->key, e->epairs->value); #endif start = e->firstbrush; end = start + e->numbrushes; aabb.reset(); aabb.expand(MAX_WORLD_WIDTH); /* every level (-1) */ list = MakeBspBrushList(start, end, -1, aabb); if (!config.nocsg) list = ChopBrushes(list); tree = BuildTree(list, aabb.mins, aabb.maxs); assert(tree); assert(tree->headnode); if (tree->headnode->planenum == PLANENUM_LEAF) Sys_Error("No head node bmodel of %s (%i)\n", ValueForKey(e, "classname"), entityNum); MakeTreePortals(tree); MarkVisibleSides(tree, start, end); MakeFaces(tree->headnode); FixTjuncs(tree->headnode); curTile->models[curTile->nummodels].headnode = WriteBSP(tree->headnode); FreeTree(tree); EndModel(); }
/* * 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); }
/* ============ 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 ); }
/** * @sa ProcessLevel * @return The node num */ static int32_t ConstructLevelNodes_r (const int levelnum, const vec3_t cmins, const vec3_t cmaxs, int entityNum) { bspbrush_t *list; tree_t *tree; vec3_t diff, bmins, bmaxs; int32_t nn[3]; node_t *node; /* calculate bounds, stop if no brushes are available */ if (!MapBrushesBounds(brush_start, brush_end, levelnum, cmins, cmaxs, bmins, bmaxs)) return LEAFNODE; Verb_Printf(VERB_DUMP, "ConstructLevelNodes_r: lv=%i (%f %f %f) (%f %f %f)\n", levelnum, cmins[0], cmins[1], cmins[2], cmaxs[0], cmaxs[1], cmaxs[2]); VectorSubtract(bmaxs, bmins, diff); /* Com_Printf("(%i): %i %i: (%i %i) (%i %i) -> (%i %i) (%i %i)\n", levelnum, (int)diff[0], (int)diff[1], (int)cmins[0], (int)cmins[1], (int)cmaxs[0], (int)cmaxs[1], (int)bmins[0], (int)bmins[1], (int)bmaxs[0], (int)bmaxs[1]); */ if (diff[0] > SPLIT_BRUSH_SIZE || diff[1] > SPLIT_BRUSH_SIZE) { /* continue subdivision */ /* split the remaining hull at the middle of the longer axis */ vec3_t nmins, nmaxs; int n; if (diff[1] > diff[0]) n = 1; else n = 0; VectorCopy(bmins, nmins); VectorCopy(bmaxs, nmaxs); nmaxs[n] -= diff[n] / 2; /* Com_Printf(" (%i %i) (%i %i)\n", (int)nmins[0], (int)nmins[1], (int)nmaxs[0], (int)nmaxs[1]); */ nn[0] = ConstructLevelNodes_r(levelnum, nmins, nmaxs, entityNum); nmins[n] += diff[n] / 2; nmaxs[n] += diff[n] / 2; /* Com_Printf(" (%i %i) (%i %i)\n", (int)nmins[0], (int)nmins[1], (int)nmaxs[0], (int)nmaxs[1]); */ nn[1] = ConstructLevelNodes_r(levelnum, nmins, nmaxs, entityNum); } else { /* no children */ nn[0] = LEAFNODE; nn[1] = LEAFNODE; } /* add v_epsilon to avoid clipping errors */ VectorSubtract(bmins, v_epsilon, bmins); VectorAdd(bmaxs, v_epsilon, bmaxs); /* Call BeginModel only to initialize brush pointers */ BeginModel(entityNum); list = MakeBspBrushList(brush_start, brush_end, levelnum, bmins, bmaxs); if (!list) { nn[2] = LEAFNODE; return BuildNodeChildren(nn); } if (!config.nocsg) list = ChopBrushes(list); /* begin model creation now */ tree = BuildTree(list, bmins, bmaxs); MakeTreePortals(tree); MarkVisibleSides(tree, brush_start, brush_end); MakeFaces(tree->headnode); FixTjuncs(tree->headnode); if (!config.noprune) PruneNodes(tree->headnode); /* correct bounds */ node = tree->headnode; VectorAdd(bmins, v_epsilon, node->mins); VectorSubtract(bmaxs, v_epsilon, node->maxs); /* finish model */ nn[2] = WriteBSP(tree->headnode); FreeTree(tree); /* Store created nodes */ return BuildNodeChildren(nn); }