1 //------------------------------------------------------------------------
2 //
3 //  AJ-BSP  Copyright (C) 2000-2019  Andrew Apted, et al
4 //          Copyright (C) 1994-1998  Colin Reed
5 //          Copyright (C) 1997-1998  Lee Killough
6 //
7 //  Originally based on the program 'BSP', version 2.3.
8 //
9 //  This program is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU General Public License
11 //  as published by the Free Software Foundation; either version 2
12 //  of the License, or (at your option) any later version.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //  GNU General Public License for more details.
18 //
19 //------------------------------------------------------------------------
20 
21 #include "main.h"
22 #include "bsp.h"
23 
24 #include "w_rawdef.h"
25 #include "w_wad.h"
26 
27 #include <zlib.h>
28 
29 
30 namespace ajbsp
31 {
32 
33 #define DEBUG_BLOCKMAP  0
34 #define DEBUG_REJECT    0
35 #define DEBUG_LOAD      0
36 #define DEBUG_BSP       0
37 
38 
39 static int block_x, block_y;
40 static int block_w, block_h;
41 static int block_count;
42 
43 static int block_mid_x = 0;
44 static int block_mid_y = 0;
45 
46 static u16_t ** block_lines;
47 
48 static u16_t *block_ptrs;
49 static u16_t *block_dups;
50 
51 static int block_compression;
52 static int block_overflowed;
53 
54 #define BLOCK_LIMIT  16000
55 
56 #define DUMMY_DUP  0xFFFF
57 
58 
GetBlockmapBounds(int * x,int * y,int * w,int * h)59 void GetBlockmapBounds(int *x, int *y, int *w, int *h)
60 {
61 	*x = block_x; *y = block_y;
62 	*w = block_w; *h = block_h;
63 }
64 
65 
CheckLinedefInsideBox(int xmin,int ymin,int xmax,int ymax,int x1,int y1,int x2,int y2)66 int CheckLinedefInsideBox(int xmin, int ymin, int xmax, int ymax,
67 		int x1, int y1, int x2, int y2)
68 {
69 	int count = 2;
70 	int tmp;
71 
72 	for (;;)
73 	{
74 		if (y1 > ymax)
75 		{
76 			if (y2 > ymax)
77 				return false;
78 
79 			x1 = x1 + (int) ((x2-x1) * (double)(ymax-y1) / (double)(y2-y1));
80 			y1 = ymax;
81 
82 			count = 2;
83 			continue;
84 		}
85 
86 		if (y1 < ymin)
87 		{
88 			if (y2 < ymin)
89 				return false;
90 
91 			x1 = x1 + (int) ((x2-x1) * (double)(ymin-y1) / (double)(y2-y1));
92 			y1 = ymin;
93 
94 			count = 2;
95 			continue;
96 		}
97 
98 		if (x1 > xmax)
99 		{
100 			if (x2 > xmax)
101 				return false;
102 
103 			y1 = y1 + (int) ((y2-y1) * (double)(xmax-x1) / (double)(x2-x1));
104 			x1 = xmax;
105 
106 			count = 2;
107 			continue;
108 		}
109 
110 		if (x1 < xmin)
111 		{
112 			if (x2 < xmin)
113 				return false;
114 
115 			y1 = y1 + (int) ((y2-y1) * (double)(xmin-x1) / (double)(x2-x1));
116 			x1 = xmin;
117 
118 			count = 2;
119 			continue;
120 		}
121 
122 		count--;
123 
124 		if (count == 0)
125 			break;
126 
127 		// swap end points
128 		tmp=x1;  x1=x2;  x2=tmp;
129 		tmp=y1;  y1=y2;  y2=tmp;
130 	}
131 
132 	// linedef touches block
133 	return true;
134 }
135 
136 
137 /* ----- create blockmap ------------------------------------ */
138 
139 #define BK_NUM    0
140 #define BK_MAX    1
141 #define BK_XOR    2
142 #define BK_FIRST  3
143 
144 #define BK_QUANTUM  32
145 
BlockAdd(int blk_num,int line_index)146 static void BlockAdd(int blk_num, int line_index)
147 {
148 	u16_t *cur = block_lines[blk_num];
149 
150 # if DEBUG_BLOCKMAP
151 	DebugPrintf("Block %d has line %d\n", blk_num, line_index);
152 # endif
153 
154 	if (blk_num < 0 || blk_num >= block_count)
155 		BugError("BlockAdd: bad block number %d\n", blk_num);
156 
157 	if (! cur)
158 	{
159 		// create empty block
160 		block_lines[blk_num] = cur = (u16_t *)UtilCalloc(BK_QUANTUM * sizeof(u16_t));
161 		cur[BK_NUM] = 0;
162 		cur[BK_MAX] = BK_QUANTUM;
163 		cur[BK_XOR] = 0x1234;
164 	}
165 
166 	if (BK_FIRST + cur[BK_NUM] == cur[BK_MAX])
167 	{
168 		// no more room, so allocate some more...
169 		cur[BK_MAX] += BK_QUANTUM;
170 
171 		block_lines[blk_num] = cur = (u16_t *)UtilRealloc(cur, cur[BK_MAX] * sizeof(u16_t));
172 	}
173 
174 	// compute new checksum
175 	cur[BK_XOR] = ((cur[BK_XOR] << 4) | (cur[BK_XOR] >> 12)) ^ line_index;
176 
177 	cur[BK_FIRST + cur[BK_NUM]] = LE_U16(line_index);
178 	cur[BK_NUM]++;
179 }
180 
181 
BlockAddLine(int line_index)182 static void BlockAddLine(int line_index)
183 {
184 	const LineDef *L = LineDefs[line_index];
185 
186 	int x1 = (int) L->Start()->x();
187 	int y1 = (int) L->Start()->y();
188 	int x2 = (int) L->End()->x();
189 	int y2 = (int) L->End()->y();
190 
191 	int bx1 = (MIN(x1,x2) - block_x) / 128;
192 	int by1 = (MIN(y1,y2) - block_y) / 128;
193 	int bx2 = (MAX(x1,x2) - block_x) / 128;
194 	int by2 = (MAX(y1,y2) - block_y) / 128;
195 
196 	int bx, by;
197 
198 # if DEBUG_BLOCKMAP
199 	DebugPrintf("BlockAddLine: %d (%d,%d) -> (%d,%d)\n", line_index,
200 			x1, y1, x2, y2);
201 # endif
202 
203 	// handle truncated blockmaps
204 	if (bx1 < 0) bx1 = 0;
205 	if (by1 < 0) by1 = 0;
206 	if (bx2 >= block_w) bx2 = block_w - 1;
207 	if (by2 >= block_h) by2 = block_h - 1;
208 
209 	if (bx2 < bx1 || by2 < by1)
210 		return;
211 
212 	// handle simple case #1: completely horizontal
213 	if (by1 == by2)
214 	{
215 		for (bx=bx1 ; bx <= bx2 ; bx++)
216 		{
217 			int blk_num = by1 * block_w + bx;
218 			BlockAdd(blk_num, line_index);
219 		}
220 		return;
221 	}
222 
223 	// handle simple case #2: completely vertical
224 	if (bx1 == bx2)
225 	{
226 		for (by=by1 ; by <= by2 ; by++)
227 		{
228 			int blk_num = by * block_w + bx1;
229 			BlockAdd(blk_num, line_index);
230 		}
231 		return;
232 	}
233 
234 	// handle the rest (diagonals)
235 
236 	for (by=by1 ; by <= by2 ; by++)
237 	for (bx=bx1 ; bx <= bx2 ; bx++)
238 	{
239 		int blk_num = by * block_w + bx;
240 
241 		int minx = block_x + bx * 128;
242 		int miny = block_y + by * 128;
243 		int maxx = minx + 127;
244 		int maxy = miny + 127;
245 
246 		if (CheckLinedefInsideBox(minx, miny, maxx, maxy, x1, y1, x2, y2))
247 		{
248 			BlockAdd(blk_num, line_index);
249 		}
250 	}
251 }
252 
253 
CreateBlockmap()254 static void CreateBlockmap()
255 {
256 	block_lines = (u16_t **) UtilCalloc(block_count * sizeof(u16_t *));
257 
258 	for (int i=0 ; i < NumLineDefs ; i++)
259 	{
260 		// ignore zero-length lines
261 		if (LineDefs[i]->IsZeroLength())
262 			continue;
263 
264 		BlockAddLine(i);
265 	}
266 }
267 
268 
BlockCompare(const void * p1,const void * p2)269 static int BlockCompare(const void *p1, const void *p2)
270 {
271 	int blk_num1 = ((const u16_t *) p1)[0];
272 	int blk_num2 = ((const u16_t *) p2)[0];
273 
274 	const u16_t *A = block_lines[blk_num1];
275 	const u16_t *B = block_lines[blk_num2];
276 
277 	if (A == B)
278 		return 0;
279 
280 	if (A == NULL) return -1;
281 	if (B == NULL) return +1;
282 
283 	if (A[BK_NUM] != B[BK_NUM])
284 	{
285 		return A[BK_NUM] - B[BK_NUM];
286 	}
287 
288 	if (A[BK_XOR] != B[BK_XOR])
289 	{
290 		return A[BK_XOR] - B[BK_XOR];
291 	}
292 
293 	return memcmp(A+BK_FIRST, B+BK_FIRST, A[BK_NUM] * sizeof(u16_t));
294 }
295 
296 
CompressBlockmap(void)297 static void CompressBlockmap(void)
298 {
299 	int i;
300 	int cur_offset;
301 	int dup_count=0;
302 
303 	int orig_size, new_size;
304 
305 	block_ptrs = (u16_t *)UtilCalloc(block_count * sizeof(u16_t));
306 	block_dups = (u16_t *)UtilCalloc(block_count * sizeof(u16_t));
307 
308 	// sort duplicate-detecting array.  After the sort, all duplicates
309 	// will be next to each other.  The duplicate array gives the order
310 	// of the blocklists in the BLOCKMAP lump.
311 
312 	for (i=0 ; i < block_count ; i++)
313 		block_dups[i] = i;
314 
315 	qsort(block_dups, block_count, sizeof(u16_t), BlockCompare);
316 
317 	// scan duplicate array and build up offset array
318 
319 	cur_offset = 4 + block_count + 2;
320 
321 	orig_size = 4 + block_count;
322 	new_size  = cur_offset;
323 
324 	for (i=0 ; i < block_count ; i++)
325 	{
326 		int blk_num = block_dups[i];
327 		int count;
328 
329 		// empty block ?
330 		if (block_lines[blk_num] == NULL)
331 		{
332 			block_ptrs[blk_num] = 4 + block_count;
333 			block_dups[i] = DUMMY_DUP;
334 
335 			orig_size += 2;
336 			continue;
337 		}
338 
339 		count = 2 + block_lines[blk_num][BK_NUM];
340 
341 		// duplicate ?  Only the very last one of a sequence of duplicates
342 		// will update the current offset value.
343 
344 		if (i+1 < block_count &&
345 				BlockCompare(block_dups + i, block_dups + i+1) == 0)
346 		{
347 			block_ptrs[blk_num] = cur_offset;
348 			block_dups[i] = DUMMY_DUP;
349 
350 			// free the memory of the duplicated block
351 			UtilFree(block_lines[blk_num]);
352 			block_lines[blk_num] = NULL;
353 
354 			dup_count++;
355 
356 			orig_size += count;
357 			continue;
358 		}
359 
360 		// OK, this block is either the last of a series of duplicates, or
361 		// just a singleton.
362 
363 		block_ptrs[blk_num] = cur_offset;
364 
365 		cur_offset += count;
366 
367 		orig_size += count;
368 		new_size  += count;
369 	}
370 
371 	if (cur_offset > 65535)
372 	{
373 		block_overflowed = true;
374 		return;
375 	}
376 
377 # if DEBUG_BLOCKMAP
378 	DebugPrintf("Blockmap: Last ptr = %d  duplicates = %d\n",
379 			cur_offset, dup_count);
380 # endif
381 
382 	block_compression = (orig_size - new_size) * 100 / orig_size;
383 
384 	// there's a tiny chance of new_size > orig_size
385 	if (block_compression < 0)
386 		block_compression = 0;
387 }
388 
389 
CalcBlockmapSize()390 static int CalcBlockmapSize()
391 {
392 	// compute size of final BLOCKMAP lump.
393 	// it does not need to be exact, but it *does* need to be bigger
394 	// (or equal) to the actual size of the lump.
395 
396 	// header + null_block + a bit extra
397 	int size = 20;
398 
399 	// the pointers (offsets to the line lists)
400 	size = size + block_count * 2;
401 
402 	// add size of each block
403 	for (int i=0 ; i < block_count ; i++)
404 	{
405 		int blk_num = block_dups[i];
406 
407 		// ignore duplicate or empty blocks
408 		if (blk_num == DUMMY_DUP)
409 			continue;
410 
411 		u16_t *blk = block_lines[blk_num];
412 		SYS_ASSERT(blk);
413 
414 		size += (1 + (int)(blk[BK_NUM]) + 1) * 2;
415 	}
416 
417 	return size;
418 }
419 
420 
WriteBlockmap(void)421 static void WriteBlockmap(void)
422 {
423 	int i;
424 
425 	int max_size = CalcBlockmapSize();
426 
427 	Lump_c *lump = CreateLevelLump("BLOCKMAP", max_size);
428 
429 	u16_t null_block[2] = { 0x0000, 0xFFFF };
430 	u16_t m_zero = 0x0000;
431 	u16_t m_neg1 = 0xFFFF;
432 
433 	// fill in header
434 	raw_blockmap_header_t header;
435 
436 	header.x_origin = LE_U16(block_x);
437 	header.y_origin = LE_U16(block_y);
438 	header.x_blocks = LE_U16(block_w);
439 	header.y_blocks = LE_U16(block_h);
440 
441 	lump->Write(&header, sizeof(header));
442 
443 	// handle pointers
444 	for (i=0 ; i < block_count ; i++)
445 	{
446 		u16_t ptr = LE_U16(block_ptrs[i]);
447 
448 		if (ptr == 0)
449 			BugError("WriteBlockmap: offset %d not set.\n", i);
450 
451 		lump->Write(&ptr, sizeof(u16_t));
452 	}
453 
454 	// add the null block which *all* empty blocks will use
455 	lump->Write(null_block, sizeof(null_block));
456 
457 	// handle each block list
458 	for (i=0 ; i < block_count ; i++)
459 	{
460 		int blk_num = block_dups[i];
461 
462 		// ignore duplicate or empty blocks
463 		if (blk_num == DUMMY_DUP)
464 			continue;
465 
466 		u16_t *blk = block_lines[blk_num];
467 		SYS_ASSERT(blk);
468 
469 		lump->Write(&m_zero, sizeof(u16_t));
470 		lump->Write(blk + BK_FIRST, blk[BK_NUM] * sizeof(u16_t));
471 		lump->Write(&m_neg1, sizeof(u16_t));
472 	}
473 
474 	lump->Finish();
475 }
476 
477 
FreeBlockmap(void)478 static void FreeBlockmap(void)
479 {
480 	for (int i=0 ; i < block_count ; i++)
481 	{
482 		if (block_lines[i])
483 			UtilFree(block_lines[i]);
484 	}
485 
486 	UtilFree(block_lines);
487 	UtilFree(block_ptrs);
488 	UtilFree(block_dups);
489 }
490 
491 
FindBlockmapLimits(bbox_t * bbox)492 static void FindBlockmapLimits(bbox_t *bbox)
493 {
494 	int mid_x = 0;
495 	int mid_y = 0;
496 
497 	bbox->minx = bbox->miny = SHRT_MAX;
498 	bbox->maxx = bbox->maxy = SHRT_MIN;
499 
500 	for (int i=0 ; i < NumLineDefs ; i++)
501 	{
502 		const LineDef *L = LineDefs[i];
503 
504 		if (! L->IsZeroLength())
505 		{
506 			double x1 = L->Start()->x();
507 			double y1 = L->Start()->y();
508 			double x2 = L->End()->x();
509 			double y2 = L->End()->y();
510 
511 			int lx = (int)floor(MIN(x1, x2));
512 			int ly = (int)floor(MIN(y1, y2));
513 			int hx = (int)ceil(MAX(x1, x2));
514 			int hy = (int)ceil(MAX(y1, y2));
515 
516 			if (lx < bbox->minx) bbox->minx = lx;
517 			if (ly < bbox->miny) bbox->miny = ly;
518 			if (hx > bbox->maxx) bbox->maxx = hx;
519 			if (hy > bbox->maxy) bbox->maxy = hy;
520 
521 			// compute middle of cluster (roughly, so we don't overflow)
522 			mid_x += (lx + hx) / 32;
523 			mid_y += (ly + hy) / 32;
524 		}
525 	}
526 
527 	if (NumLineDefs > 0)
528 	{
529 		block_mid_x = (mid_x / NumLineDefs) * 16;
530 		block_mid_y = (mid_y / NumLineDefs) * 16;
531 	}
532 
533 # if DEBUG_BLOCKMAP
534 	DebugPrintf("Blockmap lines centered at (%d,%d)\n", block_mid_x, block_mid_y);
535 # endif
536 }
537 
538 
InitBlockmap()539 void InitBlockmap()
540 {
541 	bbox_t map_bbox;
542 
543 	// find limits of linedefs, and store as map limits
544 	FindBlockmapLimits(&map_bbox);
545 
546 	PrintDetail("Map goes from (%d,%d) to (%d,%d)\n",
547 			map_bbox.minx, map_bbox.miny, map_bbox.maxx, map_bbox.maxy);
548 
549 	block_x = map_bbox.minx - (map_bbox.minx & 0x7);
550 	block_y = map_bbox.miny - (map_bbox.miny & 0x7);
551 
552 	block_w = ((map_bbox.maxx - block_x) / 128) + 1;
553 	block_h = ((map_bbox.maxy - block_y) / 128) + 1;
554 
555 	block_count = block_w * block_h;
556 }
557 
558 
PutBlockmap()559 void PutBlockmap()
560 {
561 	if (! cur_info->do_blockmap || NumLineDefs == 0)
562 	{
563 		// just create an empty blockmap lump
564 		CreateLevelLump("BLOCKMAP")->Finish();
565 		return;
566 	}
567 
568 	block_overflowed = false;
569 
570 	// initial phase: create internal blockmap containing the index of
571 	// all lines in each block.
572 
573 	CreateBlockmap();
574 
575 	// -AJA- second phase: compress the blockmap.  We do this by sorting
576 	//       the blocks, which is a typical way to detect duplicates in
577 	//       a large list.  This also detects BLOCKMAP overflow.
578 
579 	CompressBlockmap();
580 
581 	// final phase: write it out in the correct format
582 
583 	if (block_overflowed)
584 	{
585 		// leave an empty blockmap lump
586 		CreateLevelLump("BLOCKMAP")->Finish();
587 
588 		Warning("Blockmap overflowed (lump will be empty)\n");
589 	}
590 	else
591 	{
592 		WriteBlockmap();
593 
594 		PrintDetail("Completed blockmap, size %dx%d (compression: %d%%)\n",
595 				block_w, block_h, block_compression);
596 	}
597 
598 	FreeBlockmap();
599 }
600 
601 
602 //------------------------------------------------------------------------
603 // REJECT : Generate the reject table
604 //------------------------------------------------------------------------
605 
606 
607 static u8_t *rej_matrix;
608 static int   rej_total_size;	// in bytes
609 
610 static std::vector<int> rej_sector_groups;
611 
612 
613 //
614 // Allocate the matrix, init sectors into individual groups.
615 //
Reject_Init()616 static void Reject_Init()
617 {
618 	rej_total_size = (NumSectors * NumSectors + 7) / 8;
619 
620 	rej_matrix = new u8_t[rej_total_size];
621 	memset(rej_matrix, 0, rej_total_size);
622 
623 	rej_sector_groups.resize(NumSectors);
624 
625 	for (int i=0 ; i < NumSectors ; i++)
626 	{
627 		rej_sector_groups[i] = i;
628 	}
629 }
630 
631 
Reject_Free()632 static void Reject_Free()
633 {
634 	delete[] rej_matrix;
635 	rej_matrix = NULL;
636 
637 	rej_sector_groups.clear();
638 }
639 
640 
641 //
642 // Algorithm: Initially all sectors are in individual groups.
643 // Now we scan the linedef list.  For each two-sectored line,
644 // merge the two sector groups into one.  That's it!
645 //
Reject_GroupSectors()646 static void Reject_GroupSectors()
647 {
648 	for (int i=0 ; i < NumLineDefs ; i++)
649 	{
650 		const LineDef *L = LineDefs[i];
651 
652 		if (L->right < 0 || L->left < 0)
653 			continue;
654 
655 		int sec1 = L->Right()->sector;
656 		int sec2 = L->Left() ->sector;
657 
658 		if (sec1 < 0 || sec2 < 0 || sec1 == sec2)
659 			continue;
660 
661 		// already in the same group ?
662 		int group1 = rej_sector_groups[sec1];
663 		int group2 = rej_sector_groups[sec2];
664 
665 		if (group1 == group2)
666 			continue;
667 
668 		// prefer the group numbers to become lower
669 		if (group1 > group2)
670 			std::swap(group1, group2);
671 
672 		// merge the groups
673 		for (int s = 0 ; s < NumSectors ; s++)
674 			if (rej_sector_groups[s] == group2)
675 				rej_sector_groups[s] =  group1;
676 	}
677 }
678 
679 
680 #if DEBUG_REJECT
Reject_DebugGroups()681 static void Reject_DebugGroups()
682 {
683 	// Note: this routine is destructive to the group numbers
684 
685 	for (int i=0 ; i < NumSectors ; i++)
686 	{
687 		int group = rej_sector_groups[i];
688 		int count = 0;
689 
690 		if (group < 0)
691 			continue;
692 
693 		for (int k = i ; k < NumSectors ; k++)
694 		{
695 			if (rej_sector_groups[k] == group)
696 			{
697 				rej_sector_groups[k] = -1;
698 				count++;
699 			}
700 		}
701 
702 		DebugPrintf("Group %4d : Sectors %d\n", group, count);
703 	}
704 }
705 #endif
706 
707 
Reject_ProcessSectors()708 static void Reject_ProcessSectors()
709 {
710 	for (int view=0 ; view < NumSectors ; view++)
711 	{
712 		for (int target=0 ; target < view ; target++)
713 		{
714 			if (rej_sector_groups[view] == rej_sector_groups[target])
715 				continue;
716 
717 			int p1 = view * NumSectors + target;
718 			int p2 = target * NumSectors + view;
719 
720 			// must do both directions at same time
721 			rej_matrix[p1 >> 3] |= (1 << (p1 & 7));
722 			rej_matrix[p2 >> 3] |= (1 << (p2 & 7));
723 		}
724 	}
725 }
726 
727 
Reject_WriteLump()728 static void Reject_WriteLump()
729 {
730 	Lump_c *lump = CreateLevelLump("REJECT", rej_total_size);
731 
732 	lump->Write(rej_matrix, rej_total_size);
733 
734 	lump->Finish();
735 }
736 
737 
738 //
739 // For now we only do very basic reject processing, limited to
740 // determining all isolated groups of sectors (islands that are
741 // surrounded by void space).
742 //
PutReject()743 void PutReject()
744 {
745 	if (! cur_info->do_reject || NumSectors == 0)
746 	{
747 		// just create an empty reject lump
748 		CreateLevelLump("REJECT")->Finish();
749 		return;
750 	}
751 
752 	Reject_Init();
753 	Reject_GroupSectors();
754 	Reject_ProcessSectors();
755 
756 # if DEBUG_REJECT
757 	Reject_DebugGroups();
758 # endif
759 
760 	Reject_WriteLump();
761 	Reject_Free();
762 
763 	PrintDetail("Added simple reject lump\n");
764 }
765 
766 
767 //------------------------------------------------------------------------
768 // LEVEL : Level structure read/write functions.
769 //------------------------------------------------------------------------
770 
771 
772 // Note: ZDoom format support based on code (C) 2002,2003 Randy Heit
773 
774 
775 #define ALLOC_BLKNUM  1024
776 
777 
778 // per-level variables
779 
780 const char *lev_current_name;
781 
782 short lev_current_idx;
783 short lev_current_start;
784 
785 int lev_overflows;
786 
787 
788 std::vector<vertex_t *>  lev_vertices;
789 std::vector<seg_t *>     lev_segs;
790 std::vector<subsec_t *>  lev_subsecs;
791 std::vector<node_t *>    lev_nodes;
792 std::vector<walltip_t *> lev_walltips;
793 
794 int num_old_vert = 0;
795 int num_new_vert = 0;
796 int num_real_lines = 0;
797 
798 
799 /* ----- allocation routines ---------------------------- */
800 
NewVertex()801 vertex_t *NewVertex()
802 {
803 	vertex_t *V = (vertex_t *) UtilCalloc(sizeof(vertex_t));
804 	lev_vertices.push_back(V);
805 	return V;
806 }
807 
NewSeg()808 seg_t *NewSeg()
809 {
810 	seg_t *S = (seg_t *) UtilCalloc(sizeof(seg_t));
811 	lev_segs.push_back(S);
812 	return S;
813 }
814 
NewSubsec()815 subsec_t *NewSubsec()
816 {
817 	subsec_t *S = (subsec_t *) UtilCalloc(sizeof(subsec_t));
818 	lev_subsecs.push_back(S);
819 	return S;
820 }
821 
NewNode()822 node_t *NewNode()
823 {
824 	node_t *N = (node_t *) UtilCalloc(sizeof(node_t));
825 	lev_nodes.push_back(N);
826 	return N;
827 }
828 
NewWallTip()829 walltip_t *NewWallTip()
830 {
831 	walltip_t *WT = (walltip_t *) UtilCalloc(sizeof(walltip_t));
832 	lev_walltips.push_back(WT);
833 	return WT;
834 }
835 
836 
837 /* ----- free routines ---------------------------- */
838 
FreeVertices()839 void FreeVertices()
840 {
841 	for (unsigned int i = 0 ; i < lev_vertices.size() ; i++)
842 		UtilFree((void *) lev_vertices[i]);
843 
844 	lev_vertices.clear();
845 }
846 
FreeSegs()847 void FreeSegs()
848 {
849 	for (unsigned int i = 0 ; i < lev_segs.size() ; i++)
850 		UtilFree((void *) lev_segs[i]);
851 
852 	lev_segs.clear();
853 }
854 
FreeSubsecs()855 void FreeSubsecs()
856 {
857 	for (unsigned int i = 0 ; i < lev_subsecs.size() ; i++)
858 		UtilFree((void *) lev_subsecs[i]);
859 
860 	lev_subsecs.clear();
861 }
862 
FreeNodes()863 void FreeNodes()
864 {
865 	for (unsigned int i = 0 ; i < lev_nodes.size() ; i++)
866 		UtilFree((void *) lev_nodes[i]);
867 
868 	lev_nodes.clear();
869 }
870 
FreeWallTips()871 void FreeWallTips()
872 {
873 	for (unsigned int i = 0 ; i < lev_walltips.size() ; i++)
874 		UtilFree((void *) lev_walltips[i]);
875 
876 	lev_walltips.clear();
877 }
878 
879 
880 /* ----- reading routines ------------------------------ */
881 
GetVertices(void)882 static void GetVertices(void)
883 {
884 	for (int i = 0 ; i < NumVertices ; i++)
885 	{
886 		vertex_t *vert = NewVertex();
887 
888 		vert->x = Vertices[i]->x();
889 		vert->y = Vertices[i]->y();
890 
891 		vert->index = i;
892 	}
893 
894 	num_old_vert = num_vertices;
895 }
896 
897 
898 #if 0
899 static inline SideDef *SafeLookupSidedef(u16_t num)
900 {
901 	if (num == 0xFFFF)
902 		return NULL;
903 
904 	if ((int)num >= NumSideDefs && (s16_t)(num) < 0)
905 		return NULL;
906 
907 	return SideDefs[num];
908 }
909 #endif
910 
911 
VanillaSegDist(const seg_t * seg)912 static inline int VanillaSegDist(const seg_t *seg)
913 {
914 	const LineDef *L = LineDefs[seg->linedef];
915 
916 	double lx = seg->side ? L->End()->x() : L->Start()->x();
917 	double ly = seg->side ? L->End()->y() : L->Start()->y();
918 
919 	// use the "true" starting coord (as stored in the wad)
920 	double sx = I_ROUND(seg->start->x);
921 	double sy = I_ROUND(seg->start->y);
922 
923 	return (int) floor(hypot(sx - lx, sy - ly) + 0.5);
924 }
925 
VanillaSegAngle(const seg_t * seg)926 static inline int VanillaSegAngle(const seg_t *seg)
927 {
928 	// compute the "true" delta
929 	double dx = I_ROUND(seg->end->x) - I_ROUND(seg->start->x);
930 	double dy = I_ROUND(seg->end->y) - I_ROUND(seg->start->y);
931 
932 	double angle = UtilComputeAngle(dx, dy);
933 
934 	if (angle < 0)
935 		angle += 360.0;
936 
937 	int result = (int) floor(angle * 65536.0 / 360.0 + 0.5);
938 
939 	return (result & 0xFFFF);
940 }
941 
942 
943 /* ----- writing routines ------------------------------ */
944 
945 static const u8_t *lev_v2_magic = (u8_t *) "gNd2";
946 static const u8_t *lev_v5_magic = (u8_t *) "gNd5";
947 
948 
MarkOverflow(int flags)949 void MarkOverflow(int flags)
950 {
951 	// flags are ignored
952 
953 	lev_overflows++;
954 }
955 
956 
PutVertices(const char * name,int do_gl)957 void PutVertices(const char *name, int do_gl)
958 {
959 	int count, i;
960 
961 	// this size is worst-case scenario
962 	int size = num_vertices * (int)sizeof(raw_vertex_t);
963 
964 	Lump_c *lump = CreateLevelLump(name, size);
965 
966 	for (i=0, count=0 ; i < num_vertices ; i++)
967 	{
968 		raw_vertex_t raw;
969 
970 		vertex_t *vert = lev_vertices[i];
971 
972 		if ((do_gl ? 1 : 0) != (vert->is_new ? 1 : 0))
973 		{
974 			continue;
975 		}
976 
977 		raw.x = LE_S16(I_ROUND(vert->x));
978 		raw.y = LE_S16(I_ROUND(vert->y));
979 
980 		lump->Write(&raw, sizeof(raw));
981 
982 		count++;
983 	}
984 
985 	if (count != (do_gl ? num_new_vert : num_old_vert))
986 		BugError("PutVertices miscounted (%d != %d)\n", count,
987 				do_gl ? num_new_vert : num_old_vert);
988 
989 	if (! do_gl && count > 65534)
990 	{
991 		Failure("Number of vertices has overflowed.\n");
992 		MarkOverflow(LIMIT_VERTEXES);
993 	}
994 }
995 
996 
PutGLVertices(int do_v5)997 void PutGLVertices(int do_v5)
998 {
999 	int count, i;
1000 
1001 	// this size is worst-case scenario
1002 	int size = 4 + num_vertices * (int)sizeof(raw_v2_vertex_t);
1003 
1004 	Lump_c *lump = CreateLevelLump("GL_VERT", size);
1005 
1006 	if (do_v5)
1007 		lump->Write(lev_v5_magic, 4);
1008 	else
1009 		lump->Write(lev_v2_magic, 4);
1010 
1011 	for (i=0, count=0 ; i < num_vertices ; i++)
1012 	{
1013 		raw_v2_vertex_t raw;
1014 
1015 		vertex_t *vert = lev_vertices[i];
1016 
1017 		if (! vert->is_new)
1018 			continue;
1019 
1020 		raw.x = LE_S32((int)(vert->x * 65536.0));
1021 		raw.y = LE_S32((int)(vert->y * 65536.0));
1022 
1023 		lump->Write(&raw, sizeof(raw));
1024 
1025 		count++;
1026 	}
1027 
1028 	if (count != num_new_vert)
1029 		BugError("PutGLVertices miscounted (%d != %d)\n", count, num_new_vert);
1030 }
1031 
1032 
VertexIndex16Bit(const vertex_t * v)1033 static inline u16_t VertexIndex16Bit(const vertex_t *v)
1034 {
1035 	if (v->is_new)
1036 		return (u16_t) (v->index | 0x8000U);
1037 
1038 	return (u16_t) v->index;
1039 }
1040 
1041 
VertexIndex_V5(const vertex_t * v)1042 static inline u32_t VertexIndex_V5(const vertex_t *v)
1043 {
1044 	if (v->is_new)
1045 		return (u32_t) (v->index | 0x80000000U);
1046 
1047 	return (u32_t) v->index;
1048 }
1049 
1050 
VertexIndex_XNOD(const vertex_t * v)1051 static inline u32_t VertexIndex_XNOD(const vertex_t *v)
1052 {
1053 	if (v->is_new)
1054 		return (u32_t) (num_old_vert + v->index);
1055 
1056 	return (u32_t) v->index;
1057 }
1058 
1059 
PutSegs(void)1060 void PutSegs(void)
1061 {
1062 	int i, count;
1063 
1064 	// this size is worst-case scenario
1065 	int size = num_segs * (int)sizeof(raw_seg_t);
1066 
1067 	Lump_c *lump = CreateLevelLump("SEGS", size);
1068 
1069 	for (i=0, count=0 ; i < num_segs ; i++)
1070 	{
1071 		raw_seg_t raw;
1072 
1073 		seg_t *seg = lev_segs[i];
1074 
1075 		raw.start   = LE_U16(VertexIndex16Bit(seg->start));
1076 		raw.end     = LE_U16(VertexIndex16Bit(seg->end));
1077 		raw.angle   = LE_U16(VanillaSegAngle(seg));
1078 		raw.linedef = LE_U16(seg->linedef);
1079 		raw.flip    = LE_U16(seg->side);
1080 		raw.dist    = LE_U16(VanillaSegDist(seg));
1081 
1082 		lump->Write(&raw, sizeof(raw));
1083 
1084 		count++;
1085 
1086 #   if DEBUG_BSP
1087 		DebugPrintf("PUT SEG: %04X  Vert %04X->%04X  Line %04X %s  "
1088 				"Angle %04X  (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index,
1089 				LE_U16(raw.start), LE_U16(raw.end), LE_U16(raw.linedef),
1090 				seg->side ? "L" : "R", LE_U16(raw.angle),
1091 				seg->start->x, seg->start->y, seg->end->x, seg->end->y);
1092 #   endif
1093 	}
1094 
1095 	if (count != num_segs)
1096 		BugError("PutSegs miscounted (%d != %d)\n", count, num_segs);
1097 
1098 	if (count > 65534)
1099 	{
1100 		Failure("Number of segs has overflowed.\n");
1101 		MarkOverflow(LIMIT_SEGS);
1102 	}
1103 }
1104 
1105 
PutGLSegs(void)1106 void PutGLSegs(void)
1107 {
1108 	int i, count;
1109 
1110 	// this size is worst-case scenario
1111 	int size = num_segs * (int)sizeof(raw_gl_seg_t);
1112 
1113 	Lump_c *lump = CreateLevelLump("GL_SEGS", size);
1114 
1115 	for (i=0, count=0 ; i < num_segs ; i++)
1116 	{
1117 		raw_gl_seg_t raw;
1118 
1119 		seg_t *seg = lev_segs[i];
1120 
1121 		raw.start = LE_U16(VertexIndex16Bit(seg->start));
1122 		raw.end   = LE_U16(VertexIndex16Bit(seg->end));
1123 		raw.side  = LE_U16(seg->side);
1124 
1125 		if (seg->linedef >= 0)
1126 			raw.linedef = LE_U16(seg->linedef);
1127 		else
1128 			raw.linedef = LE_U16(0xFFFF);
1129 
1130 		if (seg->partner)
1131 			raw.partner = LE_U16(seg->partner->index);
1132 		else
1133 			raw.partner = LE_U16(0xFFFF);
1134 
1135 		lump->Write(&raw, sizeof(raw));
1136 
1137 		count++;
1138 
1139 #   if DEBUG_BSP
1140 		DebugPrintf("PUT GL SEG: %04X  Line %04X %s  Partner %04X  "
1141 				"(%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, LE_U16(raw.linedef),
1142 				seg->side ? "L" : "R", LE_U16(raw.partner),
1143 				seg->start->x, seg->start->y, seg->end->x, seg->end->y);
1144 #   endif
1145 	}
1146 
1147 	if (count != num_segs)
1148 		BugError("PutGLSegs miscounted (%d != %d)\n", count, num_segs);
1149 
1150 	if (count > 65534)
1151 		BugError("PutGLSegs with %d (> 65534) segs\n", count);
1152 }
1153 
1154 
PutGLSegs_V5()1155 void PutGLSegs_V5()
1156 {
1157 	int i, count;
1158 
1159 	// this size is worst-case scenario
1160 	int size = num_segs * (int)sizeof(raw_v5_seg_t);
1161 
1162 	Lump_c *lump = CreateLevelLump("GL_SEGS", size);
1163 
1164 	for (i=0, count=0 ; i < num_segs ; i++)
1165 	{
1166 		raw_v5_seg_t raw;
1167 
1168 		seg_t *seg = lev_segs[i];
1169 
1170 		raw.start = LE_U32(VertexIndex_V5(seg->start));
1171 		raw.end   = LE_U32(VertexIndex_V5(seg->end));
1172 
1173 		raw.side  = LE_U16(seg->side);
1174 
1175 		if (seg->linedef >= 0)
1176 			raw.linedef = LE_U16(seg->linedef);
1177 		else
1178 			raw.linedef = LE_U16(0xFFFF);
1179 
1180 		if (seg->partner)
1181 			raw.partner = LE_U32(seg->partner->index);
1182 		else
1183 			raw.partner = LE_U32(0xFFFFFFFF);
1184 
1185 		lump->Write(&raw, sizeof(raw));
1186 
1187 		count++;
1188 
1189 #   if DEBUG_BSP
1190 		DebugPrintf("PUT V3 SEG: %06X  Line %04X %s  Partner %06X  "
1191 				"(%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, LE_U16(raw.linedef),
1192 				seg->side ? "L" : "R", LE_U32(raw.partner),
1193 				seg->start->x, seg->start->y, seg->end->x, seg->end->y);
1194 #   endif
1195 	}
1196 
1197 	if (count != num_segs)
1198 		BugError("PutGLSegs miscounted (%d != %d)\n", count, num_segs);
1199 }
1200 
1201 
PutSubsecs(const char * name,int do_gl)1202 void PutSubsecs(const char *name, int do_gl)
1203 {
1204 	int i;
1205 
1206 	int size = num_subsecs * (int)sizeof(raw_subsec_t);
1207 
1208 	Lump_c * lump = CreateLevelLump(name, size);
1209 
1210 	for (i=0 ; i < num_subsecs ; i++)
1211 	{
1212 		raw_subsec_t raw;
1213 
1214 		subsec_t *sub = lev_subsecs[i];
1215 
1216 		raw.first = LE_U16(sub->seg_list->index);
1217 		raw.num   = LE_U16(sub->seg_count);
1218 
1219 		lump->Write(&raw, sizeof(raw));
1220 
1221 #   if DEBUG_BSP
1222 		DebugPrintf("PUT SUBSEC %04X  First %04X  Num %04X\n",
1223 				sub->index, LE_U16(raw.first), LE_U16(raw.num));
1224 #   endif
1225 	}
1226 
1227 	if (num_subsecs > 32767)
1228 	{
1229 		Failure("Number of %s has overflowed.\n", do_gl ? "GL subsectors" : "subsectors");
1230 		MarkOverflow(do_gl ? LIMIT_GL_SSECT : LIMIT_SSECTORS);
1231 	}
1232 }
1233 
1234 
PutGLSubsecs_V5()1235 void PutGLSubsecs_V5()
1236 {
1237 	int i;
1238 
1239 	int size = num_subsecs * (int)sizeof(raw_v5_subsec_t);
1240 
1241 	Lump_c *lump = CreateLevelLump("GL_SSECT", size);
1242 
1243 	for (i=0 ; i < num_subsecs ; i++)
1244 	{
1245 		raw_v5_subsec_t raw;
1246 
1247 		subsec_t *sub = lev_subsecs[i];
1248 
1249 		raw.first = LE_U32(sub->seg_list->index);
1250 		raw.num   = LE_U32(sub->seg_count);
1251 
1252 		lump->Write(&raw, sizeof(raw));
1253 
1254 #   if DEBUG_BSP
1255 		DebugPrintf("PUT V3 SUBSEC %06X  First %06X  Num %06X\n",
1256 					sub->index, LE_U32(raw.first), LE_U32(raw.num));
1257 #   endif
1258 	}
1259 }
1260 
1261 
1262 static int node_cur_index;
1263 
PutOneNode(node_t * node,Lump_c * lump)1264 static void PutOneNode(node_t *node, Lump_c *lump)
1265 {
1266 	raw_node_t raw;
1267 
1268 	if (node->r.node)
1269 		PutOneNode(node->r.node, lump);
1270 
1271 	if (node->l.node)
1272 		PutOneNode(node->l.node, lump);
1273 
1274 	node->index = node_cur_index++;
1275 
1276 	// Note that x/y/dx/dy are always integral in non-UDMF maps
1277 	raw.x  = LE_S16(I_ROUND(node->x));
1278 	raw.y  = LE_S16(I_ROUND(node->y));
1279 	raw.dx = LE_S16(I_ROUND(node->dx));
1280 	raw.dy = LE_S16(I_ROUND(node->dy));
1281 
1282 	raw.b1.minx = LE_S16(node->r.bounds.minx);
1283 	raw.b1.miny = LE_S16(node->r.bounds.miny);
1284 	raw.b1.maxx = LE_S16(node->r.bounds.maxx);
1285 	raw.b1.maxy = LE_S16(node->r.bounds.maxy);
1286 
1287 	raw.b2.minx = LE_S16(node->l.bounds.minx);
1288 	raw.b2.miny = LE_S16(node->l.bounds.miny);
1289 	raw.b2.maxx = LE_S16(node->l.bounds.maxx);
1290 	raw.b2.maxy = LE_S16(node->l.bounds.maxy);
1291 
1292 	if (node->r.node)
1293 		raw.right = LE_U16(node->r.node->index);
1294 	else if (node->r.subsec)
1295 		raw.right = LE_U16(node->r.subsec->index | 0x8000);
1296 	else
1297 		BugError("Bad right child in node %d\n", node->index);
1298 
1299 	if (node->l.node)
1300 		raw.left = LE_U16(node->l.node->index);
1301 	else if (node->l.subsec)
1302 		raw.left = LE_U16(node->l.subsec->index | 0x8000);
1303 	else
1304 		BugError("Bad left child in node %d\n", node->index);
1305 
1306 	lump->Write(&raw, sizeof(raw));
1307 
1308 # if DEBUG_BSP
1309 	DebugPrintf("PUT NODE %04X  Left %04X  Right %04X  "
1310 			"(%d,%d) -> (%d,%d)\n", node->index, LE_U16(raw.left),
1311 			LE_U16(raw.right), node->x, node->y,
1312 			node->x + node->dx, node->y + node->dy);
1313 # endif
1314 }
1315 
1316 
PutOneNode_V5(node_t * node,Lump_c * lump)1317 static void PutOneNode_V5(node_t *node, Lump_c *lump)
1318 {
1319 	raw_v5_node_t raw;
1320 
1321 	if (node->r.node)
1322 		PutOneNode_V5(node->r.node, lump);
1323 
1324 	if (node->l.node)
1325 		PutOneNode_V5(node->l.node, lump);
1326 
1327 	node->index = node_cur_index++;
1328 
1329 	raw.x  = LE_S16(I_ROUND(node->x));
1330 	raw.y  = LE_S16(I_ROUND(node->y));
1331 	raw.dx = LE_S16(I_ROUND(node->dx));
1332 	raw.dy = LE_S16(I_ROUND(node->dy));
1333 
1334 	raw.b1.minx = LE_S16(node->r.bounds.minx);
1335 	raw.b1.miny = LE_S16(node->r.bounds.miny);
1336 	raw.b1.maxx = LE_S16(node->r.bounds.maxx);
1337 	raw.b1.maxy = LE_S16(node->r.bounds.maxy);
1338 
1339 	raw.b2.minx = LE_S16(node->l.bounds.minx);
1340 	raw.b2.miny = LE_S16(node->l.bounds.miny);
1341 	raw.b2.maxx = LE_S16(node->l.bounds.maxx);
1342 	raw.b2.maxy = LE_S16(node->l.bounds.maxy);
1343 
1344 	if (node->r.node)
1345 		raw.right = LE_U32(node->r.node->index);
1346 	else if (node->r.subsec)
1347 		raw.right = LE_U32(node->r.subsec->index | 0x80000000U);
1348 	else
1349 		BugError("Bad right child in V5 node %d\n", node->index);
1350 
1351 	if (node->l.node)
1352 		raw.left = LE_U32(node->l.node->index);
1353 	else if (node->l.subsec)
1354 		raw.left = LE_U32(node->l.subsec->index | 0x80000000U);
1355 	else
1356 		BugError("Bad left child in V5 node %d\n", node->index);
1357 
1358 	lump->Write(&raw, sizeof(raw));
1359 
1360 # if DEBUG_BSP
1361 	DebugPrintf("PUT V5 NODE %08X  Left %08X  Right %08X  "
1362 			"(%d,%d) -> (%d,%d)\n", node->index, LE_U32(raw.left),
1363 			LE_U32(raw.right), node->x, node->y,
1364 			node->x + node->dx, node->y + node->dy);
1365 # endif
1366 }
1367 
1368 
PutNodes(const char * name,int do_v5,node_t * root)1369 void PutNodes(const char *name, int do_v5, node_t *root)
1370 {
1371 	int struct_size = do_v5 ? (int)sizeof(raw_v5_node_t) : (int)sizeof(raw_node_t);
1372 
1373 	// this can be bigger than the actual size, but never smaller
1374 	int max_size = (num_nodes + 1) * struct_size;
1375 
1376 	Lump_c *lump = CreateLevelLump(name, max_size);
1377 
1378 	node_cur_index = 0;
1379 
1380 	if (root)
1381 	{
1382 		if (do_v5)
1383 			PutOneNode_V5(root, lump);
1384 		else
1385 			PutOneNode(root, lump);
1386 	}
1387 
1388 	if (node_cur_index != num_nodes)
1389 		BugError("PutNodes miscounted (%d != %d)\n",
1390 				node_cur_index, num_nodes);
1391 
1392 	if (!do_v5 && node_cur_index > 32767)
1393 	{
1394 		Failure("Number of nodes has overflowed.\n");
1395 		MarkOverflow(LIMIT_NODES);
1396 	}
1397 }
1398 
1399 
CheckLimits(bool & force_v5,bool & force_xnod)1400 void CheckLimits(bool& force_v5, bool& force_xnod)
1401 {
1402 	if (NumSectors > 65534)
1403 	{
1404 		Failure("Map has too many sectors.\n");
1405 		MarkOverflow(LIMIT_SECTORS);
1406 	}
1407 
1408 	if (NumSideDefs > 65534)
1409 	{
1410 		Failure("Map has too many sidedefs.\n");
1411 		MarkOverflow(LIMIT_SIDEDEFS);
1412 	}
1413 
1414 	if (NumLineDefs > 65534)
1415 	{
1416 		Failure("Map has too many linedefs.\n");
1417 		MarkOverflow(LIMIT_LINEDEFS);
1418 	}
1419 
1420 	if (cur_info->gl_nodes && !cur_info->force_v5)
1421 	{
1422 		if (num_old_vert > 32767 ||
1423 			num_new_vert > 32767 ||
1424 			num_segs > 65534 ||
1425 			num_nodes > 32767)
1426 		{
1427 			Warning("Forcing V5 of GL-Nodes due to overflows.\n");
1428 			force_v5 = true;
1429 		}
1430 	}
1431 
1432 	if (! cur_info->force_xnod)
1433 	{
1434 		if (num_old_vert > 32767 ||
1435 			num_new_vert > 32767 ||
1436 			num_segs > 32767 ||
1437 			num_nodes > 32767)
1438 		{
1439 			Warning("Forcing XNOD format nodes due to overflows.\n");
1440 			force_xnod = true;
1441 		}
1442 	}
1443 }
1444 
1445 
1446 struct seg_index_CMP_pred
1447 {
operator ()ajbsp::seg_index_CMP_pred1448 	inline bool operator() (const seg_t *A, const seg_t *B) const
1449 	{
1450 		return A->index < B->index;
1451 	}
1452 };
1453 
SortSegs()1454 void SortSegs()
1455 {
1456 	// do a sanity check
1457 	for (int i = 0 ; i < num_segs ; i++)
1458 		if (lev_segs[i]->index < 0)
1459 			BugError("Seg %p never reached a subsector!\n", i);
1460 
1461 	// sort segs into ascending index
1462 	std::sort(lev_segs.begin(), lev_segs.end(), seg_index_CMP_pred());
1463 
1464 	// remove unwanted segs
1465 	while (lev_segs.size() > 0 && lev_segs.back()->index == SEG_IS_GARBAGE)
1466 	{
1467 		UtilFree((void *) lev_segs.back());
1468 		lev_segs.pop_back();
1469 	}
1470 }
1471 
1472 
1473 /* ----- ZDoom format writing --------------------------- */
1474 
1475 static const u8_t *lev_XNOD_magic = (u8_t *) "XNOD";
1476 static const u8_t *lev_XGL3_magic = (u8_t *) "XGL3";
1477 static const u8_t *lev_ZNOD_magic = (u8_t *) "ZNOD";
1478 
PutZVertices()1479 void PutZVertices()
1480 {
1481 	int count, i;
1482 
1483 	u32_t orgverts = LE_U32(num_old_vert);
1484 	u32_t newverts = LE_U32(num_new_vert);
1485 
1486 	ZLibAppendLump(&orgverts, 4);
1487 	ZLibAppendLump(&newverts, 4);
1488 
1489 	for (i=0, count=0 ; i < num_vertices ; i++)
1490 	{
1491 		raw_v2_vertex_t raw;
1492 
1493 		vertex_t *vert = lev_vertices[i];
1494 
1495 		if (! vert->is_new)
1496 			continue;
1497 
1498 		raw.x = LE_S32(I_ROUND(vert->x * 65536.0));
1499 		raw.y = LE_S32(I_ROUND(vert->y * 65536.0));
1500 
1501 		ZLibAppendLump(&raw, sizeof(raw));
1502 
1503 		count++;
1504 	}
1505 
1506 	if (count != num_new_vert)
1507 		BugError("PutZVertices miscounted (%d != %d)\n", count, num_new_vert);
1508 }
1509 
1510 
PutZSubsecs()1511 void PutZSubsecs()
1512 {
1513 	int i;
1514 	int count;
1515 	u32_t raw_num = LE_U32(num_subsecs);
1516 
1517 	int cur_seg_index = 0;
1518 
1519 	ZLibAppendLump(&raw_num, 4);
1520 
1521 	for (i=0 ; i < num_subsecs ; i++)
1522 	{
1523 		subsec_t *sub = lev_subsecs[i];
1524 		seg_t *seg;
1525 
1526 		raw_num = LE_U32(sub->seg_count);
1527 
1528 		ZLibAppendLump(&raw_num, 4);
1529 
1530 		// sanity check the seg index values
1531 		count = 0;
1532 		for (seg = sub->seg_list ; seg ; seg = seg->next, cur_seg_index++)
1533 		{
1534 			if (cur_seg_index != seg->index)
1535 				BugError("PutZSubsecs: seg index mismatch in sub %d (%d != %d)\n",
1536 						i, cur_seg_index, seg->index);
1537 
1538 			count++;
1539 		}
1540 
1541 		if (count != sub->seg_count)
1542 			BugError("PutZSubsecs: miscounted segs in sub %d (%d != %d)\n",
1543 					i, count, sub->seg_count);
1544 	}
1545 
1546 	if (cur_seg_index != num_segs)
1547 		BugError("PutZSubsecs miscounted segs (%d != %d)\n",
1548 				cur_seg_index, num_segs);
1549 }
1550 
1551 
PutZSegs()1552 void PutZSegs()
1553 {
1554 	int i, count;
1555 	u32_t raw_num = LE_U32(num_segs);
1556 
1557 	ZLibAppendLump(&raw_num, 4);
1558 
1559 	for (i=0, count=0 ; i < num_segs ; i++)
1560 	{
1561 		seg_t *seg = lev_segs[i];
1562 
1563 		if (count != seg->index)
1564 			BugError("PutZSegs: seg index mismatch (%d != %d)\n",
1565 					count, seg->index);
1566 
1567 		{
1568 			u32_t v1 = LE_U32(VertexIndex_XNOD(seg->start));
1569 			u32_t v2 = LE_U32(VertexIndex_XNOD(seg->end));
1570 
1571 			u16_t line = LE_U16(seg->linedef);
1572 			u8_t  side = seg->side;
1573 
1574 			ZLibAppendLump(&v1,   4);
1575 			ZLibAppendLump(&v2,   4);
1576 			ZLibAppendLump(&line, 2);
1577 			ZLibAppendLump(&side, 1);
1578 		}
1579 
1580 		count++;
1581 	}
1582 
1583 	if (count != num_segs)
1584 		BugError("PutZSegs miscounted (%d != %d)\n", count, num_segs);
1585 }
1586 
1587 
PutXGL3Segs()1588 void PutXGL3Segs()
1589 {
1590 	int i, count;
1591 	u32_t raw_num = LE_U32(num_segs);
1592 
1593 	ZLibAppendLump(&raw_num, 4);
1594 
1595 	for (i=0, count=0 ; i < num_segs ; i++)
1596 	{
1597 		seg_t *seg = lev_segs[i];
1598 
1599 		if (count != seg->index)
1600 			BugError("PutXGL3Segs: seg index mismatch (%d != %d)\n",
1601 					count, seg->index);
1602 
1603 		{
1604 			u32_t v1   = LE_U32(VertexIndex_XNOD(seg->start));
1605 			u32_t partner = LE_U32(seg->partner ? seg->partner->index : -1);
1606 			u32_t line = LE_U32(seg->linedef);
1607 			u8_t  side = seg->side;
1608 
1609 # if DEBUG_BSP
1610 			fprintf(stderr, "SEG[%d] v1=%d partner=%d line=%d side=%d\n", i, v1, partner, line, side);
1611 # endif
1612 
1613 			ZLibAppendLump(&v1,      4);
1614 			ZLibAppendLump(&partner, 4);
1615 			ZLibAppendLump(&line,    4);
1616 			ZLibAppendLump(&side,    1);
1617 		}
1618 
1619 		count++;
1620 	}
1621 
1622 	if (count != num_segs)
1623 		BugError("PutXGL3Segs miscounted (%d != %d)\n", count, num_segs);
1624 }
1625 
1626 
PutOneZNode(node_t * node,bool do_xgl3)1627 static void PutOneZNode(node_t *node, bool do_xgl3)
1628 {
1629 	raw_v5_node_t raw;
1630 
1631 	if (node->r.node)
1632 		PutOneZNode(node->r.node, do_xgl3);
1633 
1634 	if (node->l.node)
1635 		PutOneZNode(node->l.node, do_xgl3);
1636 
1637 	node->index = node_cur_index++;
1638 
1639 	if (do_xgl3)
1640 	{
1641 		u32_t x  = LE_S32(I_ROUND(node->x  * 65536.0));
1642 		u32_t y  = LE_S32(I_ROUND(node->y  * 65536.0));
1643 		u32_t dx = LE_S32(I_ROUND(node->dx * 65536.0));
1644 		u32_t dy = LE_S32(I_ROUND(node->dy * 65536.0));
1645 
1646 		ZLibAppendLump(&x,  4);
1647 		ZLibAppendLump(&y,  4);
1648 		ZLibAppendLump(&dx, 4);
1649 		ZLibAppendLump(&dy, 4);
1650 	}
1651 	else
1652 	{
1653 		raw.x  = LE_S16(I_ROUND(node->x));
1654 		raw.y  = LE_S16(I_ROUND(node->y));
1655 		raw.dx = LE_S16(I_ROUND(node->dx));
1656 		raw.dy = LE_S16(I_ROUND(node->dy));
1657 
1658 		ZLibAppendLump(&raw.x,  2);
1659 		ZLibAppendLump(&raw.y,  2);
1660 		ZLibAppendLump(&raw.dx, 2);
1661 		ZLibAppendLump(&raw.dy, 2);
1662 	}
1663 
1664 	raw.b1.minx = LE_S16(node->r.bounds.minx);
1665 	raw.b1.miny = LE_S16(node->r.bounds.miny);
1666 	raw.b1.maxx = LE_S16(node->r.bounds.maxx);
1667 	raw.b1.maxy = LE_S16(node->r.bounds.maxy);
1668 
1669 	raw.b2.minx = LE_S16(node->l.bounds.minx);
1670 	raw.b2.miny = LE_S16(node->l.bounds.miny);
1671 	raw.b2.maxx = LE_S16(node->l.bounds.maxx);
1672 	raw.b2.maxy = LE_S16(node->l.bounds.maxy);
1673 
1674 	ZLibAppendLump(&raw.b1, sizeof(raw.b1));
1675 	ZLibAppendLump(&raw.b2, sizeof(raw.b2));
1676 
1677 	if (node->r.node)
1678 		raw.right = LE_U32(node->r.node->index);
1679 	else if (node->r.subsec)
1680 		raw.right = LE_U32(node->r.subsec->index | 0x80000000U);
1681 	else
1682 		BugError("Bad right child in V5 node %d\n", node->index);
1683 
1684 	if (node->l.node)
1685 		raw.left = LE_U32(node->l.node->index);
1686 	else if (node->l.subsec)
1687 		raw.left = LE_U32(node->l.subsec->index | 0x80000000U);
1688 	else
1689 		BugError("Bad left child in V5 node %d\n", node->index);
1690 
1691 	ZLibAppendLump(&raw.right, 4);
1692 	ZLibAppendLump(&raw.left,  4);
1693 
1694 # if DEBUG_BSP
1695 	DebugPrintf("PUT Z NODE %08X  Left %08X  Right %08X  "
1696 			"(%d,%d) -> (%d,%d)\n", node->index, LE_U32(raw.left),
1697 			LE_U32(raw.right), node->x, node->y,
1698 			node->x + node->dx, node->y + node->dy);
1699 # endif
1700 }
1701 
1702 
PutZNodes(node_t * root,bool do_xgl3)1703 void PutZNodes(node_t *root, bool do_xgl3)
1704 {
1705 	u32_t raw_num = LE_U32(num_nodes);
1706 
1707 	ZLibAppendLump(&raw_num, 4);
1708 
1709 	node_cur_index = 0;
1710 
1711 	if (root)
1712 		PutOneZNode(root, do_xgl3);
1713 
1714 	if (node_cur_index != num_nodes)
1715 		BugError("PutZNodes miscounted (%d != %d)\n",
1716 				node_cur_index, num_nodes);
1717 }
1718 
1719 
CalcZDoomNodesSize()1720 static int CalcZDoomNodesSize()
1721 {
1722 	// compute size of the ZDoom format nodes.
1723 	// it does not need to be exact, but it *does* need to be bigger
1724 	// (or equal) to the actual size of the lump.
1725 
1726 	int size = 32;  // header + a bit extra
1727 
1728 	size += 8 + num_vertices * 8;
1729 	size += 4 + num_subsecs  * 4;
1730 	size += 4 + num_segs     * 11;
1731 	size += 4 + num_nodes    * sizeof(raw_v5_node_t);
1732 
1733 	if (cur_info->force_compress)
1734 	{
1735 		// according to RFC1951, the zlib compression worst-case
1736 		// scenario is 5 extra bytes per 32KB (0.015% increase).
1737 		// we are significantly more conservative!
1738 
1739 		size += ((size + 255) >> 5);
1740 	}
1741 
1742 	return size;
1743 }
1744 
1745 
SaveZDFormat(node_t * root_node)1746 void SaveZDFormat(node_t *root_node)
1747 {
1748 	// leave SEGS and SSECTORS empty
1749 	CreateLevelLump("SEGS")->Finish();
1750 	CreateLevelLump("SSECTORS")->Finish();
1751 
1752 	int max_size = CalcZDoomNodesSize();
1753 
1754 	Lump_c *lump = CreateLevelLump("NODES", max_size);
1755 
1756 	if (cur_info->force_compress)
1757 		lump->Write(lev_ZNOD_magic, 4);
1758 	else
1759 		lump->Write(lev_XNOD_magic, 4);
1760 
1761 	// the ZLibXXX functions do no compression for XNOD format
1762 	ZLibBeginLump(lump);
1763 
1764 	PutZVertices();
1765 	PutZSubsecs();
1766 	PutZSegs();
1767 	PutZNodes(root_node, false /* do_xgl3 */);
1768 
1769 	ZLibFinishLump();
1770 }
1771 
1772 
SaveXGL3Format(node_t * root_node)1773 void SaveXGL3Format(node_t *root_node)
1774 {
1775 	// WISH : compute a max_size
1776 
1777 	Lump_c *lump = CreateLevelLump("ZNODES", -1);
1778 
1779 	lump->Write(lev_XGL3_magic, 4);
1780 
1781 	// disable compression
1782 	cur_info->force_compress = false;
1783 
1784 	ZLibBeginLump(lump);
1785 
1786 	PutZVertices();
1787 	PutZSubsecs();
1788 	PutXGL3Segs();
1789 	PutZNodes(root_node, true /* do_xgl3 */);
1790 
1791 	ZLibFinishLump();
1792 }
1793 
1794 
1795 /* ----- whole-level routines --------------------------- */
1796 
LoadLevel()1797 void LoadLevel()
1798 {
1799 	Lump_c *LEV = edit_wad->GetLump(lev_current_start);
1800 
1801 	lev_current_name = LEV->Name();
1802 	lev_overflows = 0;
1803 
1804 	GB_PrintMsg("Building nodes on %s\n", lev_current_name);
1805 
1806 	num_new_vert = 0;
1807 	num_real_lines = 0;
1808 
1809 	GetVertices();
1810 
1811 	for (int ld = 0 ; ld < NumLineDefs ; ld++)
1812 	{
1813 		LineDef *L = LineDefs[ld];
1814 
1815 		if (L->right >= 0 || L->left >= 0)
1816 			num_real_lines++;
1817 
1818 		// init some fake flags
1819 		L->flags &= ~(MLF_IS_PRECIOUS | MLF_IS_OVERLAP);
1820 
1821 		if (L->tag >= 900 && L->tag < 1000)
1822 			L->flags |= MLF_IS_PRECIOUS;
1823 	}
1824 
1825 	PrintDetail("Loaded %d vertices, %d sectors, %d sides, %d lines, %d things\n",
1826 			NumVertices, NumSectors, NumSideDefs, NumLineDefs, NumThings);
1827 
1828 	DetectOverlappingVertices();
1829 	DetectOverlappingLines();
1830 
1831 	CalculateWallTips();
1832 
1833 	if (Level_format != MAPF_Doom)
1834 	{
1835 		// -JL- Find sectors containing polyobjs
1836 		DetectPolyobjSectors();
1837 	}
1838 }
1839 
1840 
FreeLevel(void)1841 void FreeLevel(void)
1842 {
1843 	FreeVertices();
1844 	FreeSegs();
1845 	FreeSubsecs();
1846 	FreeNodes();
1847 	FreeWallTips();
1848 }
1849 
1850 
CalcGLChecksum(void)1851 static u32_t CalcGLChecksum(void)
1852 {
1853 	u32_t crc;
1854 
1855 	Adler32_Begin(&crc);
1856 
1857 	Lump_c *lump = FindLevelLump("VERTEXES");
1858 
1859 	if (lump && lump->Length() > 0)
1860 	{
1861 		u8_t *data = new u8_t[lump->Length()];
1862 
1863 		if (! lump->Seek() ||
1864 		    ! lump->Read(data, lump->Length()))
1865 			FatalError("Error reading vertices (for checksum).\n");
1866 
1867 		Adler32_AddBlock(&crc, data, lump->Length());
1868 		delete[] data;
1869 	}
1870 
1871 	lump = FindLevelLump("LINEDEFS");
1872 
1873 	if (lump && lump->Length() > 0)
1874 	{
1875 		u8_t *data = new u8_t[lump->Length()];
1876 
1877 		if (! lump->Seek() ||
1878 		    ! lump->Read(data, lump->Length()))
1879 			FatalError("Error reading linedefs (for checksum).\n");
1880 
1881 		Adler32_AddBlock(&crc, data, lump->Length());
1882 		delete[] data;
1883 	}
1884 
1885 	Adler32_Finish(&crc);
1886 
1887 	return crc;
1888 }
1889 
1890 
CalcOptionsString()1891 static const char *CalcOptionsString()
1892 {
1893 	static char buffer[256];
1894 
1895 	snprintf(buffer, sizeof(buffer), "--cost %d%s", cur_info->factor,
1896 		cur_info->fast ? " --fast" : "");
1897 
1898 	return buffer;
1899 }
1900 
1901 
UpdateGLMarker(Lump_c * marker)1902 void UpdateGLMarker(Lump_c *marker)
1903 {
1904 	// this is very conservative, around 4 times the actual size
1905 	const int max_size = 512;
1906 
1907 	// we *must* compute the checksum BEFORE (re)creating the lump
1908 	// [ otherwise we write data into the wrong part of the file ]
1909 	u32_t crc = CalcGLChecksum();
1910 
1911 	edit_wad->RecreateLump(marker, max_size);
1912 
1913 	// when original name is long, need to specify it here
1914 	if (strlen(lev_current_name) > 5)
1915 	{
1916 		marker->Printf("LEVEL=%s\n", lev_current_name);
1917 	}
1918 
1919 	marker->Printf("BUILDER=%s\n", "Eureka " EUREKA_VERSION);
1920 	marker->Printf("OPTIONS=%s\n", CalcOptionsString());
1921 
1922 	char *time_str = UtilTimeString();
1923 
1924 	if (time_str)
1925 	{
1926 		marker->Printf("TIME=%s\n", time_str);
1927 		StringFree(time_str);
1928 	}
1929 
1930 	marker->Printf("CHECKSUM=0x%08x\n", crc);
1931 	marker->Finish();
1932 }
1933 
1934 
AddMissingLump(const char * name,const char * after)1935 static void AddMissingLump(const char *name, const char *after)
1936 {
1937 	if (edit_wad->LevelLookupLump(lev_current_idx, name) >= 0)
1938 		return;
1939 
1940 	short exist = edit_wad->LevelLookupLump(lev_current_idx, after);
1941 
1942 	// if this happens, the level structure is very broken
1943 	if (exist < 0)
1944 	{
1945 		Warning("Missing %s lump -- level structure is broken\n", after);
1946 
1947 		exist = edit_wad->LevelLastLump(lev_current_idx);
1948 	}
1949 
1950 	edit_wad->InsertPoint(exist + 1);
1951 
1952 	edit_wad->AddLump(name)->Finish();
1953 }
1954 
1955 
SaveLevel(node_t * root_node)1956 build_result_e SaveLevel(node_t *root_node)
1957 {
1958 	// Note: root_node may be NULL
1959 
1960 	edit_wad->BeginWrite();
1961 
1962 	// remove any existing GL-Nodes
1963 	edit_wad->RemoveGLNodes(lev_current_idx);
1964 
1965 	// ensure all necessary level lumps are present
1966 	AddMissingLump("SEGS",     "VERTEXES");
1967 	AddMissingLump("SSECTORS", "SEGS");
1968 	AddMissingLump("NODES",    "SSECTORS");
1969 	AddMissingLump("REJECT",   "SECTORS");
1970 	AddMissingLump("BLOCKMAP", "REJECT");
1971 
1972 	// user preferences
1973 	bool force_v5   = cur_info->force_v5;
1974 	bool force_xnod = cur_info->force_xnod;
1975 
1976 	// check for overflows...
1977 	// this sets the force_xxx vars if certain limits are breached
1978 	CheckLimits(force_v5, force_xnod);
1979 
1980 
1981 	/* --- GL Nodes --- */
1982 
1983 	Lump_c * gl_marker = NULL;
1984 
1985 	if (cur_info->gl_nodes && num_real_lines > 0)
1986 	{
1987 		SortSegs();
1988 
1989 		// create empty marker now, flesh it out later
1990 		gl_marker = CreateGLMarker();
1991 
1992 		PutGLVertices(force_v5);
1993 
1994 		if (force_v5)
1995 			PutGLSegs_V5();
1996 		else
1997 			PutGLSegs();
1998 
1999 		if (force_v5)
2000 			PutGLSubsecs_V5();
2001 		else
2002 			PutSubsecs("GL_SSECT", true);
2003 
2004 		PutNodes("GL_NODES", force_v5, root_node);
2005 
2006 		// -JL- Add empty PVS lump
2007 		CreateLevelLump("GL_PVS")->Finish();
2008 	}
2009 
2010 
2011 	/* --- Normal nodes --- */
2012 
2013 	// remove all the mini-segs from subsectors
2014 	NormaliseBspTree();
2015 
2016 	if (force_xnod && num_real_lines > 0)
2017 	{
2018 		SortSegs();
2019 
2020 		SaveZDFormat(root_node);
2021 	}
2022 	else
2023 	{
2024 		// reduce vertex precision for classic DOOM nodes.
2025 		// some segs can become "degenerate" after this, and these
2026 		// are removed from subsectors.
2027 		RoundOffBspTree();
2028 
2029 		// this also removes minisegs and degenerate segs
2030 		SortSegs();
2031 
2032 		PutVertices("VERTEXES", false);
2033 
2034 		PutSegs();
2035 		PutSubsecs("SSECTORS", false);
2036 		PutNodes("NODES", false, root_node);
2037 	}
2038 
2039 	PutBlockmap();
2040 	PutReject();
2041 
2042 	// keyword support (v5.0 of the specs).
2043 	// must be done *after* doing normal nodes (for proper checksum).
2044 	if (gl_marker)
2045 	{
2046 		UpdateGLMarker(gl_marker);
2047 	}
2048 
2049 	edit_wad->EndWrite();
2050 
2051 	if (lev_overflows > 0)
2052 	{
2053 		cur_info->total_failed_maps++;
2054 		GB_PrintMsg("FAILED with %d overflowed lumps\n", lev_overflows);
2055 
2056 		return BUILD_LumpOverflow;
2057 	}
2058 
2059 	return BUILD_OK;
2060 }
2061 
2062 
SaveUDMF(node_t * root_node)2063 build_result_e SaveUDMF(node_t *root_node)
2064 {
2065 	edit_wad->BeginWrite();
2066 
2067 	// remove any existing ZNODES lump
2068 	edit_wad->RemoveZNodes(lev_current_idx);
2069 
2070 	if (num_real_lines >= 0)
2071 	{
2072 		SortSegs();
2073 
2074 		SaveXGL3Format(root_node);
2075 	}
2076 
2077 	edit_wad->EndWrite();
2078 
2079 	if (lev_overflows > 0)
2080 	{
2081 		cur_info->total_failed_maps++;
2082 		GB_PrintMsg("FAILED with %d overflowed lumps\n", lev_overflows);
2083 
2084 		return BUILD_LumpOverflow;
2085 	}
2086 
2087 	return BUILD_OK;
2088 }
2089 
2090 
2091 //----------------------------------------------------------------------
2092 
2093 
2094 static Lump_c  *zout_lump;
2095 static z_stream zout_stream;
2096 static Bytef    zout_buffer[1024];
2097 
2098 
ZLibBeginLump(Lump_c * lump)2099 void ZLibBeginLump(Lump_c *lump)
2100 {
2101 	zout_lump = lump;
2102 
2103 	if (! cur_info->force_compress)
2104 		return;
2105 
2106 	zout_stream.zalloc = (alloc_func)0;
2107 	zout_stream.zfree  = (free_func)0;
2108 	zout_stream.opaque = (voidpf)0;
2109 
2110 	if (Z_OK != deflateInit(&zout_stream, Z_DEFAULT_COMPRESSION))
2111 		FatalError("Trouble setting up zlib compression\n");
2112 
2113 	zout_stream.next_out  = zout_buffer;
2114 	zout_stream.avail_out = sizeof(zout_buffer);
2115 }
2116 
2117 
ZLibAppendLump(const void * data,int length)2118 void ZLibAppendLump(const void *data, int length)
2119 {
2120 	// ASSERT(zout_lump)
2121 	// ASSERT(length > 0)
2122 
2123 	if (! cur_info->force_compress)
2124 	{
2125 		zout_lump->Write(data, length);
2126 		return;
2127 	}
2128 
2129 	zout_stream.next_in  = (Bytef*)data;   // const override
2130 	zout_stream.avail_in = length;
2131 
2132 	while (zout_stream.avail_in > 0)
2133 	{
2134 		int err = deflate(&zout_stream, Z_NO_FLUSH);
2135 
2136 		if (err != Z_OK)
2137 			FatalError("Trouble compressing %d bytes (zlib)\n", length);
2138 
2139 		if (zout_stream.avail_out == 0)
2140 		{
2141 			zout_lump->Write(zout_buffer, sizeof(zout_buffer));
2142 
2143 			zout_stream.next_out  = zout_buffer;
2144 			zout_stream.avail_out = sizeof(zout_buffer);
2145 		}
2146 	}
2147 }
2148 
2149 
ZLibFinishLump(void)2150 void ZLibFinishLump(void)
2151 {
2152 	if (! cur_info->force_compress)
2153 	{
2154 		zout_lump = NULL;
2155 		return;
2156 	}
2157 
2158 	int left_over;
2159 
2160 	// ASSERT(zout_stream.avail_out > 0)
2161 
2162 	zout_stream.next_in  = Z_NULL;
2163 	zout_stream.avail_in = 0;
2164 
2165 	for (;;)
2166 	{
2167 		int err = deflate(&zout_stream, Z_FINISH);
2168 
2169 		if (err == Z_STREAM_END)
2170 			break;
2171 
2172 		if (err != Z_OK)
2173 			FatalError("Trouble finishing compression (zlib)\n");
2174 
2175 		if (zout_stream.avail_out == 0)
2176 		{
2177 			zout_lump->Write(zout_buffer, sizeof(zout_buffer));
2178 
2179 			zout_stream.next_out  = zout_buffer;
2180 			zout_stream.avail_out = sizeof(zout_buffer);
2181 		}
2182 	}
2183 
2184 	left_over = sizeof(zout_buffer) - zout_stream.avail_out;
2185 
2186 	if (left_over > 0)
2187 		zout_lump->Write(zout_buffer, left_over);
2188 
2189 	deflateEnd(&zout_stream);
2190 	zout_lump = NULL;
2191 }
2192 
2193 
2194 /* ---------------------------------------------------------------- */
2195 
2196 
FindLevelLump(const char * name)2197 Lump_c * FindLevelLump(const char *name)
2198 {
2199 	short idx = edit_wad->LevelLookupLump(lev_current_idx, name);
2200 
2201 	if (idx < 0)
2202 		return NULL;
2203 
2204 	return edit_wad->GetLump(idx);
2205 }
2206 
2207 
CreateLevelLump(const char * name,int max_size)2208 Lump_c * CreateLevelLump(const char *name, int max_size)
2209 {
2210 	// look for existing one
2211 	Lump_c *lump = FindLevelLump(name);
2212 
2213 	if (lump)
2214 	{
2215 		edit_wad->RecreateLump(lump, max_size);
2216 	}
2217 	else
2218 	{
2219 		short last_idx = edit_wad->LevelLastLump(lev_current_idx);
2220 
2221 		// in UDMF maps, insert before the ENDMAP lump, otherwise insert
2222 		// after the last known lump of the level.
2223 		if (Level_format != MAPF_UDMF)
2224 			last_idx++;
2225 
2226 		edit_wad->InsertPoint(last_idx);
2227 
2228 		lump = edit_wad->AddLump(name, max_size);
2229 	}
2230 
2231 	return lump;
2232 }
2233 
2234 
CreateGLMarker()2235 Lump_c * CreateGLMarker()
2236 {
2237 	char name_buf[64];
2238 
2239 	if (strlen(lev_current_name) <= 5)
2240 	{
2241 		snprintf(name_buf, sizeof(name_buf), "GL_%s", lev_current_name);
2242 	}
2243 	else
2244 	{
2245 		// names longer than 5 chars use "GL_LEVEL" as marker name
2246 		strcpy(name_buf, "GL_LEVEL");
2247 	}
2248 
2249 	short last_idx = edit_wad->LevelLastLump(lev_current_idx);
2250 
2251 	edit_wad->InsertPoint(last_idx + 1);
2252 
2253 	Lump_c *marker = edit_wad->AddLump(name_buf);
2254 
2255 	marker->Finish();
2256 
2257 	return marker;
2258 }
2259 
2260 
2261 //------------------------------------------------------------------------
2262 // MAIN STUFF
2263 //------------------------------------------------------------------------
2264 
2265 nodebuildinfo_t * cur_info = NULL;
2266 
2267 
BuildLevel(nodebuildinfo_t * info,short lev_idx)2268 build_result_e BuildLevel(nodebuildinfo_t *info, short lev_idx)
2269 {
2270 	cur_info = info;
2271 
2272 	node_t *root_node  = NULL;
2273 	subsec_t *root_sub = NULL;
2274 	bbox_t root_bbox;
2275 
2276 	if (cur_info->cancelled)
2277 		return BUILD_Cancelled;
2278 
2279 	lev_current_idx   = lev_idx;
2280 	lev_current_start = edit_wad->LevelHeader(lev_idx);
2281 
2282 	LoadLevel();
2283 
2284 	InitBlockmap();
2285 
2286 
2287 	build_result_e ret = BUILD_OK;
2288 
2289 	if (num_real_lines > 0)
2290 	{
2291 		// create initial segs
2292 		seg_t *list = CreateSegs();
2293 
2294 		// recursively create nodes
2295 		ret = BuildNodes(list, &root_bbox, &root_node, &root_sub, 0);
2296 	}
2297 
2298 	if (ret == BUILD_OK)
2299 	{
2300 		PrintDetail("Built %d NODES, %d SSECTORS, %d SEGS, %d VERTEXES\n",
2301 					num_nodes, num_subsecs, num_segs, num_old_vert + num_new_vert);
2302 
2303 		if (root_node)
2304 		{
2305 			PrintDetail("Heights of left and right subtrees = (%d,%d)\n",
2306 					ComputeBspHeight(root_node->r.node),
2307 					ComputeBspHeight(root_node->l.node));
2308 		}
2309 
2310 		ClockwiseBspTree();
2311 
2312 		if (Level_format == MAPF_UDMF)
2313 			ret = SaveUDMF(root_node);
2314 		else
2315 			ret = SaveLevel(root_node);
2316 	}
2317 	else
2318 	{
2319 		/* build was Cancelled by the user */
2320 	}
2321 
2322 	FreeLevel();
2323 	FreeQuickAllocCuts();
2324 
2325 	// clear some fake line flags
2326 	for (int i = 0 ; i < NumLineDefs ; i++)
2327 		LineDefs[i]->flags &= ~(MLF_IS_PRECIOUS | MLF_IS_OVERLAP);
2328 
2329 	return ret;
2330 }
2331 
2332 }  // namespace ajbsp
2333 
2334 
AJBSP_BuildLevel(nodebuildinfo_t * info,short lev_idx)2335 build_result_e AJBSP_BuildLevel(nodebuildinfo_t *info, short lev_idx)
2336 {
2337 	return ajbsp::BuildLevel(info, lev_idx);
2338 }
2339 
2340 //--- editor settings ---
2341 // vi:ts=4:sw=4:noexpandtab
2342