engine: reject mbf21 and shit24 wads. there is no way to know if it is safe to ignore...
[k8vavoom.git] / source / maploader / mapload_nodes_aj.cpp
blob637738bf720c928bf99575212f25d9860ad054c3
1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
12 //**
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
16 //**
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
21 //**
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
24 //**
25 //**************************************************************************
26 //**
27 //** Build nodes using ajbsp.
28 //**
29 //**************************************************************************
30 #include "../gamedefs.h"
31 #include "../text.h"
32 #include "../bsp/ajbsp/bsp.h"
34 //#define VV_AJBSP_USE_VERTEX_ROUNDOFF
37 static VCvarB ajbsp_roundoff_tree("ajbsp_roundoff_tree", false, "Roundoff vertices in AJBSP?", CVAR_PreInit|CVAR_Hidden|CVAR_NoShadow);
39 static VCvarB nodes_show_warnings("nodes_show_warnings", true, "Show various node builder warnings?", CVAR_Archive|CVAR_NoShadow);
40 static VCvarB nodes_fast_mode("nodes_fast_mode", false, "Do faster rebuild, but generate worser BSP tree?", CVAR_Archive|CVAR_NoShadow);
43 namespace ajbsp {
44 //extern bool lev_doing_hexen;
45 extern int num_old_vert;
46 extern int num_new_vert;
47 extern int num_complete_seg;
48 extern int num_real_lines;
49 extern int num_vertices;
50 extern int num_linedefs;
51 extern int num_sidedefs;
52 extern int num_sectors;
53 extern int num_things;
54 extern int num_segs;
55 extern int num_subsecs;
56 extern int num_nodes;
60 //==========================================================================
62 // ajRoundOffVertexI32
64 // round vertex coordinates to 16.16 fixed point
65 // used in all modes to create fixed point BSP info (see below)
67 //==========================================================================
68 static inline vint32 ajRoundoffVertexI32 (const double v) {
69 return (vint32)(v*65536.0);
73 #ifdef VV_AJBSP_USE_VERTEX_ROUNDOFF
74 //==========================================================================
76 // ajRoundOffVertex
78 // round vertex coordinates using 16.16 fixed point as base value
80 //==========================================================================
81 static inline float ajRoundoffVertex (const double v) {
82 vint32 iv = ajRoundoffVertexI32(v);
83 return (float)(((double)iv)/65536.0);
85 #endif
88 //==========================================================================
90 // stripNL
92 //==========================================================================
93 static void stripNL (char *str) {
94 if (!str) return;
95 auto slen = strlen(str);
96 while (slen > 0 && (str[slen-1] == '\n' || str[slen-1] == '\r')) str[--slen] = '\0';
100 //==========================================================================
102 // ajbsp_FatalError
104 //==========================================================================
105 __attribute__((noreturn)) __attribute__((format(printf,1,2))) void ajbsp_FatalError (const char *fmt, ...) {
106 va_list ap;
107 va_start(ap, fmt);
108 char *res = vavarg(fmt, ap);
109 va_end(ap);
110 stripNL(res);
111 Sys_Error("AJBSP: %s", res);
115 //==========================================================================
117 // ajbsp_PrintMsg
119 //==========================================================================
120 __attribute__((format(printf,1,2))) void ajbsp_PrintMsg (const char *fmt, ...) {
121 va_list ap;
122 va_start(ap, fmt);
123 char *res = vavarg(fmt, ap);
124 va_end(ap);
125 stripNL(res);
126 GCon->Logf("AJBSP: %s", res);
130 //==========================================================================
132 // ajbsp_PrintVerbose
134 //==========================================================================
135 __attribute__((format(printf,1,2))) void ajbsp_PrintVerbose (const char *fmt, ...) {
136 if (!nodes_show_warnings) return;
137 va_list ap;
138 va_start(ap, fmt);
139 char *res = vavarg(fmt, ap);
140 va_end(ap);
141 stripNL(res);
142 GCon->Logf("AJBSP: %s", res);
146 //==========================================================================
148 // ajbsp_PrintDetail
150 //==========================================================================
151 __attribute__((format(printf,1,2))) void ajbsp_PrintDetail (const char *fmt, ...) {
152 if (!nodes_show_warnings) return;
153 va_list ap;
154 va_start(ap, fmt);
155 char *res = vavarg(fmt, ap);
156 va_end(ap);
157 stripNL(res);
158 GCon->Logf("AJBSP: %s", res);
162 //==========================================================================
164 // ajbsp_DebugPrintf
166 //==========================================================================
167 __attribute__((format(printf,1,2))) void ajbsp_DebugPrintf (const char * /*fmt*/, ...) {
171 //==========================================================================
173 // ajbsp_PrintMapName
175 //==========================================================================
176 void ajbsp_PrintMapName (const char * /*name*/) {
180 //==========================================================================
182 // ajbsp_Progress
184 //==========================================================================
185 void ajbsp_Progress (int curr, int total) {
186 #ifdef CLIENT
187 if (total <= 0) {
188 R_PBarUpdate("BSP", 42, 42, true); // final update
189 } else {
190 R_PBarUpdate("BSP", curr, total);
192 //if (cl && cl->Net) GCon->Logf(NAME_Debug, "!!!! **** !!!! curr=%d; total=%d; time=%g", curr, total, Sys_Time());
193 #endif
197 //==========================================================================
199 // UploadSectors
201 //==========================================================================
202 static void UploadSectors (VLevel *Level) {
203 const sector_t *pSrc = Level->Sectors;
204 for (int i = 0; i < Level->NumSectors; ++i, ++pSrc) {
205 ajbsp::sector_t *sector = ajbsp::NewSector();
206 memset(sector, 0, sizeof(*sector));
207 sector->coalesce = (pSrc->sectorTag >= 900 && pSrc->sectorTag < 1000 ? 1 : 0);
208 if (!sector->coalesce) {
209 for (int f = 0; f < pSrc->moreTags.length(); ++f) {
210 if (pSrc->moreTags[f] >= 900 && pSrc->moreTags[f] < 1000) {
211 sector->coalesce = 1;
212 break;
216 // sector indices never change
217 sector->index = i;
218 sector->warned_facing = -1;
223 //==========================================================================
225 // UploadSidedefs
227 //==========================================================================
228 static void UploadSidedefs (VLevel *Level) {
229 const side_t *pSrc = Level->Sides;
230 for (int i = 0; i < Level->NumSides; ++i, ++pSrc) {
231 ajbsp::sidedef_t *side = ajbsp::NewSidedef();
232 memset(side, 0, sizeof(*side));
233 side->sector = (!pSrc->Sector ? nullptr : ajbsp::LookupSector((int)(ptrdiff_t)(pSrc->Sector-Level->Sectors)));
234 if (side->sector) side->sector->is_used = 1;
235 // sidedef indices never change
236 side->index = i;
241 // ////////////////////////////////////////////////////////////////////////// //
242 #ifdef VV_AJBSP_USE_VERTEX_ROUNDOFF
243 struct __attribute__((packed)) VertexInfoRounded {
244 private:
245 vint32 xy[2];
246 int index; // vertex index in AJBSP
248 public:
249 inline VertexInfo () noexcept {}
250 inline VertexInfo (const TVec &v, int aindex) noexcept { xy[0] = ajRoundoffVertexI32(v.x); xy[1] = ajRoundoffVertexI32(v.y); index = aindex; }
252 inline bool operator == (const VertexInfo &vi) const noexcept { return (memcmp(&xy[0], &vi.xy[0], sizeof(xy)) == 0); }
253 inline bool operator != (const VertexInfo &vi) const noexcept { return (memcmp(&xy[0], &vi.xy[0], sizeof(xy)) != 0); }
255 inline int getIndex () const noexcept { return index; }
256 inline float getX () const noexcept { return (float)(((double)xy[0])/65536.0); }
257 inline float getY () const noexcept { return (float)(((double)xy[1])/65536.0); }
258 inline const void *getHashData () const noexcept { return (const void *)(&xy[0]); }
259 inline size_t getHashDataSize () const noexcept { return sizeof(xy); }
261 static_assert(sizeof(VertexInfo) == sizeof(vint32)*2+sizeof(int), "oops");
262 inline uint32_t GetTypeHash (const VertexInfo &vi) noexcept { return joaatHashBuf(vi.getHashData(), vi.getHashDataSize()); }
263 #define Vertex2DInfo VertexInfoRounded
264 #endif
267 //==========================================================================
269 // ajUploadVertex
271 // this deals with duplicate vertices
273 //==========================================================================
274 static int ajUploadVertex (TMap<Vertex2DInfo, int> &vmap, VLevel *Level, const TVec *v) {
275 Vertex2DInfo vi(*v, ajbsp::num_vertices);
276 auto pp = vmap.get(vi);
277 if (pp) return *pp;
278 vassert(vi.getIndex() == ajbsp::num_vertices);
279 vmap.put(vi, vi.getIndex());
280 ajbsp::vertex_t *vert = ajbsp::NewVertex();
281 memset(vert, 0, sizeof(*vert));
282 vert->x = vi.getX();
283 vert->y = vi.getY();
284 vert->index = (int)(ptrdiff_t)(v-Level->Vertexes);
285 vert->is_new = 0;
286 vert->is_used = 1;
287 return vi.getIndex();
291 //==========================================================================
293 // UploadLinedefs
295 // ...and vertices
297 //==========================================================================
298 static void UploadLinedefs (VLevel *Level) {
299 TMap<Vertex2DInfo, int> vmap;
300 const line_t *pSrc = Level->Lines;
301 for (int i = 0; i < Level->NumLines; ++i, ++pSrc) {
302 ajbsp::linedef_t *line = ajbsp::NewLinedef();
303 memset(line, 0, sizeof(*line));
304 //if (line == nullptr) Sys_Error("AJBSP: out of memory!");
305 if (!pSrc->v1 || !pSrc->v2) Sys_Error("linedef without vertexes");
306 line->start = ajbsp::LookupVertex(ajUploadVertex(vmap, Level, pSrc->v1));
307 line->end = ajbsp::LookupVertex(ajUploadVertex(vmap, Level, pSrc->v2));
308 line->start->is_used = 1;
309 line->end->is_used = 1;
310 line->zero_len = (fabs(line->start->x-line->end->x) < DIST_EPSILON) && (fabs(line->start->y-line->end->y) < DIST_EPSILON);
311 line->flags = pSrc->flags;
312 line->type = pSrc->special;
313 line->two_sided = (pSrc->flags&ML_TWOSIDED ? 1 : 0);
314 line->is_precious = (pSrc->arg1 >= 900 && pSrc->arg1 < 1000 ? 1 : 0); // arg1 is tag
315 line->right = (pSrc->sidenum[0] < 0 ? nullptr : ajbsp::LookupSidedef(pSrc->sidenum[0]));
316 line->left = (pSrc->sidenum[1] < 0 ? nullptr : ajbsp::LookupSidedef(pSrc->sidenum[1]));
317 if (line->right) {
318 line->right->is_used = 1;
319 line->right->on_special |= (line->type > 0 ? 1 : 0);
321 if (line->left) {
322 line->left->is_used = 1;
323 line->left->on_special |= (line->type > 0 ? 1 : 0);
325 if (line->right || line->left) ++ajbsp::num_real_lines;
326 line->self_ref = (line->left && line->right && line->left->sector == line->right->sector);
327 line->index = i;
329 ajbsp::num_old_vert = ajbsp::num_vertices;
333 //==========================================================================
335 // UploadThings
337 //==========================================================================
338 static void UploadThings (VLevel *Level) {
339 const mthing_t *pSrc = Level->Things;
340 for (int i = 0; i < Level->NumThings; ++i, ++pSrc) {
341 ajbsp::thing_t *Thing = ajbsp::NewThing();
342 memset(Thing, 0, sizeof(*Thing));
343 Thing->x = (int)pSrc->x;
344 Thing->y = (int)pSrc->y;
345 Thing->type = pSrc->type;
346 Thing->options = pSrc->options;
347 Thing->index = i;
352 // ////////////////////////////////////////////////////////////////////////// //
353 struct CopyInfo {
354 TMap<const void *, int> ajvidx; // for `AJVertexIndex()`, created in `CopyGLVerts()`
358 //==========================================================================
360 // AJVertexIndex
362 //==========================================================================
363 static inline int AJVertexIndex (CopyInfo &nfo, const ajbsp::vertex_t *v) {
364 vassert(v != nullptr);
365 auto ip = nfo.ajvidx.get(v);
366 if (!ip) Sys_Error("AJBSP: found unknown vertex");
367 return *ip;
371 //==========================================================================
373 // CopyGLVerts
375 //==========================================================================
376 static void CopyGLVerts (VLevel *Level, CopyInfo &nfo) {
377 const int oldvnum = Level->NumVertexes;
378 delete[] Level->Vertexes;
379 nfo.ajvidx.reset();
381 Level->Vertexes = new TVec[ajbsp::num_vertices];
382 Level->NumVertexes = ajbsp::num_vertices;
383 memset((void *)Level->Vertexes, 0, sizeof(TVec)*ajbsp::num_vertices);
385 for (int i = 0; i < ajbsp::num_vertices; ++i) {
386 ajbsp::vertex_t *vert = ajbsp::LookupVertex(i);
387 nfo.ajvidx.put(vert, i); // for `AJVertexIndex()`
388 TVec *pDst = &Level->Vertexes[i];
389 #ifdef VV_AJBSP_USE_VERTEX_ROUNDOFF
390 *pDst = TVec(ajRoundoffVertex(vert->x), ajRoundoffVertex(vert->y), 0);
391 #else
392 *pDst = TVec(vert->x, vert->y, 0);
393 #endif
396 // fix lines
397 for (int i = 0; i < Level->NumLines; ++i) {
398 auto ajline = ajbsp::LookupLinedef(i);
399 line_t *ld = &Level->Lines[i];
401 int v1idx = AJVertexIndex(nfo, ajline->start);
402 if (v1idx < 0 || v1idx >= ajbsp::num_vertices) Sys_Error("AJBSP: invalid line #%d v1 index", i);
403 ld->v1 = &Level->Vertexes[v1idx];
405 int v2idx = AJVertexIndex(nfo, ajline->end);
406 if (v2idx < 0 || v2idx >= ajbsp::num_vertices) Sys_Error("AJBSP: invalid line #%d v1 index", i);
407 ld->v2 = &Level->Vertexes[v2idx];
410 GCon->Logf("AJBSP: copied %d vertices (old number is %d)", Level->NumVertexes, oldvnum);
414 //==========================================================================
416 // CopySegs
418 //==========================================================================
419 static void CopySegs (VLevel *Level, CopyInfo &nfo) {
420 Level->NumSegs = 0;
421 delete[] Level->Segs;
422 Level->NumSegs = ajbsp::num_segs;
423 Level->Segs = new seg_t[ajbsp::num_segs+Level->NumLines*2+1]; //k8: this may overallocate, but i don't care
424 memset((void *)Level->Segs, 0, sizeof(seg_t)*(ajbsp::num_segs+Level->NumLines*2+1));
426 for (int i = 0; i < ajbsp::num_segs; ++i) {
427 ajbsp::seg_t *srcseg = ajbsp::LookupSeg(i);
428 if (srcseg->is_degenerate) Sys_Error("AJBSP: seg #%d is degenerate (the thing that should not be!)", i);
429 if (srcseg->index != i) Host_Error("AJBSP: seg #%d has invalid index %d", i, srcseg->index);
431 seg_t *destseg = &Level->Segs[i];
433 destseg->partner = (srcseg->partner ? &Level->Segs[srcseg->partner->index] : nullptr);
434 destseg->frontsub = nullptr;
436 auto v1mp = AJVertexIndex(nfo, srcseg->start);
437 auto v2mp = AJVertexIndex(nfo, srcseg->end);
438 if (v1mp < 0 || v2mp < 0) Sys_Error("AJBSP: vertex not found for seg #%d", i);
439 if (v1mp == v2mp) GCon->Logf(NAME_Error, "AJBSP: seg #%d has same start and end vertex (%d:%d) (%d:%d)", i, v1mp, srcseg->start->index, v2mp, srcseg->end->index);
440 if (v1mp >= Level->NumVertexes || v2mp >= Level->NumVertexes) Sys_Error("AJBSP: invalid vertices not found for seg #%d", i);
441 destseg->v1 = &Level->Vertexes[v1mp];
442 destseg->v2 = &Level->Vertexes[v2mp];
444 if (srcseg->side != 0 && srcseg->side != 1) Sys_Error("AJBSP: invalid seg #%d side (%d)", i, srcseg->side);
445 destseg->side = srcseg->side;
447 if (srcseg->linedef) {
448 if (srcseg->linedef->index < 0 || srcseg->linedef->index >= Level->NumLines) Sys_Error("AJBSP: invalid seg #%d linedef (%d), max is %d", i, srcseg->linedef->index, Level->NumLines-1);
449 destseg->linedef = &Level->Lines[srcseg->linedef->index];
452 GCon->Logf("AJBSP: copied %d segs", Level->NumSegs);
456 //==========================================================================
458 // CopySubsectors
460 //==========================================================================
461 static void CopySubsectors (VLevel *Level, CopyInfo &/*nfo*/) {
462 Level->NumSubsectors = ajbsp::num_subsecs;
463 delete[] Level->Subsectors;
464 Level->Subsectors = new subsector_t[Level->NumSubsectors];
465 memset((void *)Level->Subsectors, 0, sizeof(subsector_t)*Level->NumSubsectors);
466 for (int i = 0; i < Level->NumSubsectors; ++i) {
467 ajbsp::subsec_t *srcss = ajbsp::LookupSubsec(i);
468 const int ajfsegidx = srcss->seg_list->index; // exactly the same as k8vavoom index
470 subsector_t *destss = &Level->Subsectors[i];
471 destss->numlines = srcss->seg_count;
473 if (destss->numlines < 0) Sys_Error("AJBSP: invalid subsector #%d data (numlines)", i);
474 if (destss->numlines == 0) {
475 destss->firstline = 0; // doesn't matter
476 } else {
477 destss->firstline = ajfsegidx;
478 // check segments
479 for (int j = 0; j < destss->numlines; ++j) {
480 const ajbsp::seg_t *xseg = ajbsp::LookupSeg(ajfsegidx+j);
481 if (xseg->index != ajfsegidx+j) Host_Error("AJBSP: subsector #%d contains non-sequential segs (expected %d, got %d)", i, ajfsegidx+j, xseg->index);
485 GCon->Logf("AJBSP: copied %d subsectors", Level->NumSubsectors);
489 //==========================================================================
491 // CopyNode
493 //==========================================================================
494 static void CopyNode (VLevel *Level, int &NodeIndex, ajbsp::node_t *SrcNode, node_t *Nodes) {
495 if (SrcNode->r.node) CopyNode(Level, NodeIndex, SrcNode->r.node, Nodes);
496 if (SrcNode->l.node) CopyNode(Level, NodeIndex, SrcNode->l.node, Nodes);
498 if (NodeIndex >= ajbsp::num_nodes) Host_Error("AJBSP: invalid total number of nodes (0)");
500 SrcNode->index = NodeIndex;
501 node_t *Node = &Nodes[NodeIndex];
502 ++NodeIndex;
504 const TVec org = TVec(SrcNode->xs, SrcNode->ys);
505 TVec dir = TVec(SrcNode->xe-SrcNode->xs, SrcNode->ye-SrcNode->ys);
506 //k8: this seems to be unnecessary
507 // check if `Length()` and `SetPointDirXY()` are happy
508 if (dir.isZero2D()) {
509 //Host_Error("AJBSP: invalid BSP node (zero direction)");
510 GCon->Logf("AJBSP: invalid BSP node (zero direction%s)", (SrcNode->too_long ? "; overlong node" : ""));
511 dir.x = 0.001f;
513 Node->SetPointDirXY(org, dir);
515 // those things are used to emulate buggy vanilla "point in subsector" code
516 // they aren't used for anything else, so precision loss doesn't really matter
517 // they are in 16.16 fixed point format
518 Node->sx = ajRoundoffVertexI32(SrcNode->xs);
519 Node->sy = ajRoundoffVertexI32(SrcNode->ys);
520 if (!SrcNode->too_long) {
521 Node->dx = ajRoundoffVertexI32(SrcNode->xe)-Node->sx;
522 Node->dy = ajRoundoffVertexI32(SrcNode->ye)-Node->sy;
523 } else {
524 Node->dx = (vint32)(((vint64)ajRoundoffVertexI32(SrcNode->xe)-(vint64)Node->sx)/2);
525 Node->dy = (vint32)(((vint64)ajRoundoffVertexI32(SrcNode->ye)-(vint64)Node->sy)/2);
528 //TODO: check if i should convert AJBSP bounding boxes to floats
529 Node->bbox[0][0] = SrcNode->r.bounds.minx;
530 Node->bbox[0][1] = SrcNode->r.bounds.miny;
531 Node->bbox[0][2] = -32768.0f;
532 Node->bbox[0][3] = SrcNode->r.bounds.maxx;
533 Node->bbox[0][4] = SrcNode->r.bounds.maxy;
534 Node->bbox[0][5] = 32768.0f;
536 Node->bbox[1][0] = SrcNode->l.bounds.minx;
537 Node->bbox[1][1] = SrcNode->l.bounds.miny;
538 Node->bbox[1][2] = -32768.0f;
539 Node->bbox[1][3] = SrcNode->l.bounds.maxx;
540 Node->bbox[1][4] = SrcNode->l.bounds.maxy;
541 Node->bbox[1][5] = 32768.0f;
543 #if 0
544 if (SrcNode->ldefidx >= 0 && SrcNode->ldefidx < Level->NumLines) {
545 Node->splitldef = &Level->Lines[SrcNode->ldefidx];
546 } else {
547 if (SrcNode->ldefidx >= 0) Host_Error("AJBSP: invalid splitting linedef index in BSP");
548 Node->splitldef = nullptr;
550 #endif
552 if (SrcNode->r.node) Node->children[0] = SrcNode->r.node->index;
553 else if (SrcNode->r.subsec) Node->children[0] = SrcNode->r.subsec->index|NF_SUBSECTOR;
554 else Host_Error("AJBSP: bad left child in BSP");
555 // fuck you, gshitcc
556 if (SrcNode->l.node) Node->children[1] = SrcNode->l.node->index;
557 else if (SrcNode->l.subsec) Node->children[1] = SrcNode->l.subsec->index|NF_SUBSECTOR;
558 else Host_Error("AJBSP: bad right child in BSP");
562 //==========================================================================
564 // CopyNodes
566 //==========================================================================
567 static void CopyNodes (VLevel *Level, ajbsp::node_t *root_node) {
568 Level->NumNodes = ajbsp::num_nodes;
569 delete[] Level->Nodes;
570 Level->Nodes = new node_t[Level->NumNodes+1];
571 memset((void *)Level->Nodes, 0, sizeof(node_t)*(Level->NumNodes+1));
572 if (root_node) {
573 int NodeIndex = 0;
574 CopyNode(Level, NodeIndex, root_node, Level->Nodes);
575 if (NodeIndex != ajbsp::num_nodes) Host_Error("AJBSP: invalid total number of nodes (1)");
577 GCon->Logf("AJBSP: copied %d nodes", Level->NumNodes);
581 //==========================================================================
583 // VLevel::BuildNodesAJ
585 //==========================================================================
586 void VLevel::BuildNodesAJ () {
587 // set up glBSP build globals
588 nodebuildinfo_t nb_info;
589 nb_info.fast = nodes_fast_mode;
590 nb_info.warnings = true; // not currently used, but meh
591 nb_info.do_blockmap = true;
592 nb_info.do_reject = true;
594 ajbsp::cur_info = &nb_info;
596 //lev_doing_normal = false;
597 //!bool lev_doing_hexen = !!(LevelFlags&(LF_Extended|LF_TextMap));
599 ajbsp::num_vertices = 0;
600 ajbsp::num_linedefs = 0;
601 ajbsp::num_sidedefs = 0;
602 ajbsp::num_sectors = 0;
603 ajbsp::num_things = 0;
604 ajbsp::num_segs = 0;
605 ajbsp::num_subsecs = 0;
606 ajbsp::num_nodes = 0;
608 ajbsp::num_old_vert = 0;
609 ajbsp::num_new_vert = 0;
610 ajbsp::num_complete_seg = 0;
611 ajbsp::num_real_lines = 0;
613 // set up map data from loaded data
614 // vertices will be uploaded with linedefs
615 UploadSectors(this);
616 UploadSidedefs(this);
617 UploadLinedefs(this);
618 UploadThings(this);
620 // other data initialisation
621 // no need to prune vertices, 'cause our vertex uploader will upload only used vertices
622 //ajbsp::PruneVerticesAtEnd();
623 GCon->Logf("AJBSP: copied %d original vertexes out of %d", ajbsp::num_vertices, NumVertexes);
624 GCon->Logf("AJBSP: building nodes (%s mode)", (nodes_fast_mode ? "fast" : "normal"));
626 GCon->Logf("AJBSP: detecting overlapped vertices");
627 ajbsp::DetectOverlappingVertices();
628 GCon->Logf("AJBSP: detecting overlapped linedefs");
629 ajbsp::DetectOverlappingLines();
630 GCon->Logf("AJBSP: caclulating wall tips");
631 ajbsp::CalculateWallTips();
633 //k8: always try polyobjects, why not?
634 GCon->Logf("AJBSP: detecting polyobjects");
635 /*if (lev_doing_hexen)*/ ajbsp::DetectPolyobjSectors(); // -JL- Find sectors containing polyobjs
637 //if (cur_info->window_fx) ajbsp::DetectWindowEffects();
638 //GCon->Logf("AJBSP: building blockmap");
639 ajbsp::InitBlockmap();
641 GCon->Logf("AJBSP: creating initial segs");
642 // create initial segs
643 ajbsp::superblock_t *seg_list = ajbsp::CreateSegs();
644 ajbsp::node_t *root_node;
645 ajbsp::subsec_t *root_sub;
646 ajbsp::bbox_t seg_bbox;
647 GCon->Logf("AJBSP: calculating total limits");
648 ajbsp::FindLimits(seg_list, &seg_bbox);
649 GCon->Logf("AJBSP: building nodes");
650 build_result_e ret = ajbsp::BuildNodes(seg_list, &root_node, &root_sub, 0, &seg_bbox);
651 ajbsp::FreeSuper(seg_list);
653 if (ret == build_result_e::BUILD_OK) {
654 GCon->Log("AJBSP: finalising the tree");
655 ajbsp::ClockwiseBspTree();
656 ajbsp::CheckLimits();
657 //k8: this seems to be unnecessary for GL nodes
658 //ajbsp::NormaliseBspTree(); // remove all the mini-segs
659 if (ajbsp_roundoff_tree) {
660 GCon->Log("AJBSP: rounding off bsp tree");
661 ajbsp::RoundOffBspTree();
663 ajbsp::SortSegs();
664 ajbsp_Progress(-1, -1);
666 GCon->Logf("AJBSP: built with %d nodes, %d subsectors, %d segs, %d vertexes", ajbsp::num_nodes, ajbsp::num_subsecs, ajbsp::num_segs, ajbsp::num_vertices);
667 if (root_node && root_node->r.node && root_node->l.node) GCon->Logf("AJBSP: heights of subtrees: %d/%d", ajbsp::ComputeBspHeight(root_node->r.node), ajbsp::ComputeBspHeight(root_node->l.node));
669 GCon->Logf("AJBSP: copying built data");
670 // copy nodes into internal structures
671 CopyInfo nfo;
672 CopyGLVerts(this, nfo);
673 CopySegs(this, nfo);
674 CopySubsectors(this, nfo);
675 CopyNodes(this, root_node);
677 // reject
678 if (ajbsp::cur_info->do_reject) {
679 VMemoryStream *xms = new VMemoryStream();
680 xms->BeginWrite();
681 ajbsp::PutReject(*xms);
683 delete[] RejectMatrix;
684 RejectMatrix = nullptr;
686 RejectMatrixSize = xms->TotalSize();
687 if (RejectMatrixSize) {
688 TArrayNC<vuint8> &arr = xms->GetArray();
689 RejectMatrix = new vuint8[RejectMatrixSize];
690 if (RejectMatrixSize) memcpy(RejectMatrix, arr.ptr(), RejectMatrixSize);
691 // check if it's an all-zeroes lump, in which case it's useless and can be discarded
692 // k8: don't do it, or k8vavoom will try to rebuild/reload it
694 delete xms;
697 // blockmap
698 // k8: ajbsp blockmap builder (or reader) seems to not work on switch; don't use it at all
699 delete[] BlockMapLump;
700 BlockMapLump = nullptr;
701 BlockMapLumpSize = 0;
704 // free any memory used by AJBSP
705 ajbsp::FreeLevel();
706 ajbsp::FreeQuickAllocCuts();
707 ajbsp::FreeQuickAllocSupers();
709 ajbsp::cur_info = nullptr;
711 if (ret != build_result_e::BUILD_OK) Host_Error("Node build failed");