/* ================== PortalizeWorld Builds the exact polyhedrons for the nodes and leafs ================== */ void PortalizeWorld(node_t *headnode) { Message(msgProgress, "Portalize"); iNodesDone = 0; MakeHeadnodePortals(headnode); CutNodePortals_r(headnode); if (hullnum) return; // save portal file for vis tracing WritePortalfile(headnode); Message(msgStat, "%5i vis leafs", num_visleafs); Message(msgStat, "%5i vis portals", num_visportals); }
/* =========== FillOutside =========== */ node_t *FillOutside (node_t *node, qboolean leakfile) { int s; vec_t *v; int i; qboolean inside; qboolean ret; vec3_t origin; char *cl; qprintf ("----- FillOutside ----\n"); if (nofill) { printf ("skipped\n"); return node; } // // place markers for all entities so // we know if we leak inside // inside = false; for (i=1 ; i<num_entities ; i++) { GetVectorForKey (&entities[i], "origin", origin); if (!VectorCompare(origin, vec3_origin)) { cl = ValueForKey (&entities[i], "classname"); origin[2] += 1; // so objects on floor are ok // nudge playerstart around if needed so clipping hulls allways // have a vlaid point if (!strcmp (cl, "info_player_start")) { int x, y; for (x=-16 ; x<=16 ; x += 16) { for (y=-16 ; y<=16 ; y += 16) { origin[0] += x; origin[1] += y; if (PlaceOccupant (i, origin, node)) { inside = true; goto gotit; } origin[0] -= x; origin[1] -= y; } } gotit: ; } else { if (PlaceOccupant (i, origin, node)) inside = true; } } } if (!inside) { printf ("Hullnum %i: No entities in empty space -- no filling performed\n", hullnum); return node; } s = !(outside_node.portals->nodes[1] == &outside_node); // first check to see if an occupied leaf is hit outleafs = 0; valid++; prevleaknode = NULL; if (leakfile) { pointfile = fopen (pointfilename, "w"); if (!pointfile) Error ("Couldn't open %s\n", pointfilename); StripExtension (pointfilename); strcat (pointfilename, ".lin"); linefile = fopen (pointfilename, "w"); if (!linefile) Error ("Couldn't open %s\n", pointfilename); } ret = RecursiveFillOutside (outside_node.portals->nodes[s], false); if (leakfile) { fclose (pointfile); fclose (linefile); } if (ret) { printf("LEAK LEAK LEAK\n"); GetVectorForKey (&entities[hit_occupied], "origin", origin); qprintf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); qprintf ("reached occupant at: (%4.0f,%4.0f,%4.0f)\n" , origin[0], origin[1], origin[2]); qprintf ("no filling performed\n"); qprintf ("point file and line file generated\n"); qprintf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); if (leakonly) Error ("Stopped by leak."); return node; } // now go back and fill things in valid++; RecursiveFillOutside (outside_node.portals->nodes[s], true); // remove faces and nodes from filled in leafs c_falsenodes = 0; c_free_faces = 0; c_keep_faces = 0; node = ClearOutFaces_r (node); qprintf ("%5i outleafs\n", outleafs); qprintf ("%5i freed faces\n", c_free_faces); qprintf ("%5i keep faces\n", c_keep_faces); qprintf ("%5i falsenodes\n", c_falsenodes); // save portal file for vis tracing if (leakfile) WritePortalfile (node); return node; }
/* =============== 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); } }