#ifdef SYSTEM_WIN32 #pragma warning(disable:4996) #endif #pragma warning(disable:4018) // '<' : signed/unsigned mismatch #include "bsp5.h" node_t g_outside_node; // portals outside the world face this //============================================================================= /* * ============= * AddPortalToNodes * ============= */ void AddPortalToNodes(portal_t* p, node_t* front, node_t* back) { if (p->nodes[0] || p->nodes[1]) { Error("AddPortalToNode: allready included"); } p->nodes[0] = front; p->next[0] = front->portals; front->portals = p; p->nodes[1] = back; p->next[1] = back->portals; back->portals = p; } /* * ============= * RemovePortalFromNode * ============= */ void RemovePortalFromNode(portal_t* portal, node_t* l) { portal_t** pp; portal_t* t; // remove reference to the current portal pp = &l->portals; while (1) { t = *pp; if (!t) { Error("RemovePortalFromNode: portal not in leaf"); } if (t == portal) { break; } if (t->nodes[0] == l) { pp = &t->next[0]; } else if (t->nodes[1] == l) { pp = &t->next[1]; } else { Error("RemovePortalFromNode: portal not bounding leaf"); } } if (portal->nodes[0] == l) { *pp = portal->next[0]; portal->nodes[0] = NULL; } else if (portal->nodes[1] == l) { *pp = portal->next[1]; portal->nodes[1] = NULL; } } //============================================================================ /* * ================ * MakeHeadnodePortals * * The created portals will face the global g_outside_node * ================ */ void MakeHeadnodePortals(node_t* node, const vec3_t mins, const vec3_t maxs) { vec3_t bounds[2]; int i, j, n; portal_t* p; portal_t* portals[6]; dplane_t bplanes[6]; dplane_t* pl; // pad with some space so there will never be null volume leafs for (i = 0; i < 3; i++) { bounds[0][i] = mins[i] - SIDESPACE; bounds[1][i] = maxs[i] + SIDESPACE; } g_outside_node.contents = CONTENTS_SOLID; g_outside_node.portals = NULL; for (i = 0; i < 3; i++) { for (j = 0; j < 2; j++) { n = j * 3 + i; p = AllocPortal(); portals[n] = p; pl = &bplanes[n]; memset(pl, 0, sizeof(*pl)); if (j) { pl->normal[i] = -1; pl->dist = -bounds[j][i]; } else { pl->normal[i] = 1; pl->dist = bounds[j][i]; } p->plane = *pl; p->winding = new Winding(*pl); AddPortalToNodes(p, node, &g_outside_node); } } // clip the basewindings by all the other planes for (i = 0; i < 6; i++) { for (j = 0; j < 6; j++) { if (j == i) { continue; } portals[i]->winding->Clip(bplanes[j], true); } } } /* * ============================================================================== * * PORTAL FILE GENERATION * * ============================================================================== */ static FILE* pf; static int num_visleafs; // leafs the player can be in static int num_visportals; static void WritePortalFile_r(const node_t* const node) { int i; portal_t* p; Winding* w; dplane_t plane2; if (!node->contents) { WritePortalFile_r(node->children[0]); WritePortalFile_r(node->children[1]); return; } if (node->contents == CONTENTS_SOLID) { return; } for (p = node->portals; p;) { w = p->winding; if (w && p->nodes[0] == node) { if (p->nodes[0]->contents == p->nodes[1]->contents) { // write out to the file // sometimes planes get turned around when they are very near // the changeover point between different axis. interpret the // plane the same way vis will, and flip the side orders if needed w->getPlane(plane2); if (DotProduct(p->plane.normal, plane2.normal) < 1.0 - ON_EPSILON) { // backwards... fprintf(pf, "%u %i %i ", w->m_NumPoints, p->nodes[1]->visleafnum, p->nodes[0]->visleafnum); } else { fprintf(pf, "%u %i %i ", w->m_NumPoints, p->nodes[0]->visleafnum, p->nodes[1]->visleafnum); } for (i = 0; i < w->m_NumPoints; i++) { fprintf(pf, "(%f %f %f) ", w->m_Points[i][0], w->m_Points[i][1], w->m_Points[i][2]); } fprintf(pf, "\n"); } } if (p->nodes[0] == node) { p = p->next[0]; } else { p = p->next[1]; } } } /* * ================ * NumberLeafs_r * ================ */ static void NumberLeafs_r(node_t* node) { portal_t* p; if (!node->contents) { // decision node node->visleafnum = -99; NumberLeafs_r(node->children[0]); NumberLeafs_r(node->children[1]); return; } if (node->contents == CONTENTS_SOLID) { // solid block, viewpoint never inside node->visleafnum = -1; return; } node->visleafnum = num_visleafs++; for (p = node->portals; p;) { if (p->nodes[0] == node) // only write out from first leaf { if (p->nodes[0]->contents == p->nodes[1]->contents) { num_visportals++; } p = p->next[0]; } else { p = p->next[1]; } } } /* * ================ * WritePortalfile * ================ */ void WritePortalfile(node_t* headnode) { // set the visleafnum field in every leaf and count the total number of portals num_visleafs = 0; num_visportals = 0; NumberLeafs_r(headnode); // write the file pf = fopen(g_portfilename, "w"); if (!pf) { Error("Error writing portal file %s", g_portfilename); } fprintf(pf, "%i\n", num_visleafs); fprintf(pf, "%i\n", num_visportals); WritePortalFile_r(headnode); fclose(pf); Log("BSP generation successful, writing portal file '%s'\n", g_portfilename); } //=================================================== void FreePortals(node_t* node) { portal_t* p; portal_t* nextp; if (node->planenum != -1) { FreePortals(node->children[0]); FreePortals(node->children[1]); return; } for (p = node->portals; p; p = nextp) { if (p->nodes[0] == node) { nextp = p->next[0]; } else { nextp = p->next[1]; } RemovePortalFromNode(p, p->nodes[0]); RemovePortalFromNode(p, p->nodes[1]); delete p->winding; FreePortal(p); } }