1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
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.
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.
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/>.
25 //**************************************************************************
27 //** Build nodes using ajbsp.
29 //**************************************************************************
30 #include "../gamedefs.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
);
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
;
55 extern int num_subsecs
;
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 //==========================================================================
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);
88 //==========================================================================
92 //==========================================================================
93 static void stripNL (char *str
) {
95 auto slen
= strlen(str
);
96 while (slen
> 0 && (str
[slen
-1] == '\n' || str
[slen
-1] == '\r')) str
[--slen
] = '\0';
100 //==========================================================================
104 //==========================================================================
105 __attribute__((noreturn
)) __attribute__((format(printf
,1,2))) void ajbsp_FatalError (const char *fmt
, ...) {
108 char *res
= vavarg(fmt
, ap
);
111 Sys_Error("AJBSP: %s", res
);
115 //==========================================================================
119 //==========================================================================
120 __attribute__((format(printf
,1,2))) void ajbsp_PrintMsg (const char *fmt
, ...) {
123 char *res
= vavarg(fmt
, ap
);
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;
139 char *res
= vavarg(fmt
, ap
);
142 GCon
->Logf("AJBSP: %s", res
);
146 //==========================================================================
150 //==========================================================================
151 __attribute__((format(printf
,1,2))) void ajbsp_PrintDetail (const char *fmt
, ...) {
152 if (!nodes_show_warnings
) return;
155 char *res
= vavarg(fmt
, ap
);
158 GCon
->Logf("AJBSP: %s", res
);
162 //==========================================================================
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 //==========================================================================
184 //==========================================================================
185 void ajbsp_Progress (int curr
, int total
) {
188 R_PBarUpdate("BSP", 42, 42, true); // final update
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());
197 //==========================================================================
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;
216 // sector indices never change
218 sector
->warned_facing
= -1;
223 //==========================================================================
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
241 // ////////////////////////////////////////////////////////////////////////// //
242 #ifdef VV_AJBSP_USE_VERTEX_ROUNDOFF
243 struct __attribute__((packed
)) VertexInfoRounded
{
246 int index
; // vertex index in AJBSP
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
267 //==========================================================================
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
);
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
));
284 vert
->index
= (int)(ptrdiff_t)(v
-Level
->Vertexes
);
287 return vi
.getIndex();
291 //==========================================================================
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]));
318 line
->right
->is_used
= 1;
319 line
->right
->on_special
|= (line
->type
> 0 ? 1 : 0);
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
);
329 ajbsp::num_old_vert
= ajbsp::num_vertices
;
333 //==========================================================================
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
;
352 // ////////////////////////////////////////////////////////////////////////// //
354 TMap
<const void *, int> ajvidx
; // for `AJVertexIndex()`, created in `CopyGLVerts()`
358 //==========================================================================
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");
371 //==========================================================================
375 //==========================================================================
376 static void CopyGLVerts (VLevel
*Level
, CopyInfo
&nfo
) {
377 const int oldvnum
= Level
->NumVertexes
;
378 delete[] Level
->Vertexes
;
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);
392 *pDst
= TVec(vert
->x
, vert
->y
, 0);
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 //==========================================================================
418 //==========================================================================
419 static void CopySegs (VLevel
*Level
, CopyInfo
&nfo
) {
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 //==========================================================================
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
477 destss
->firstline
= ajfsegidx
;
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 //==========================================================================
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
];
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" : ""));
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
;
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
;
544 if (SrcNode
->ldefidx
>= 0 && SrcNode
->ldefidx
< Level
->NumLines
) {
545 Node
->splitldef
= &Level
->Lines
[SrcNode
->ldefidx
];
547 if (SrcNode
->ldefidx
>= 0) Host_Error("AJBSP: invalid splitting linedef index in BSP");
548 Node
->splitldef
= nullptr;
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");
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 //==========================================================================
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));
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;
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
616 UploadSidedefs(this);
617 UploadLinedefs(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();
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
672 CopyGLVerts(this, nfo
);
674 CopySubsectors(this, nfo
);
675 CopyNodes(this, root_node
);
678 if (ajbsp::cur_info
->do_reject
) {
679 VMemoryStream
*xms
= new VMemoryStream();
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
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
706 ajbsp::FreeQuickAllocCuts();
707 ajbsp::FreeQuickAllocSupers();
709 ajbsp::cur_info
= nullptr;
711 if (ret
!= build_result_e::BUILD_OK
) Host_Error("Node build failed");