1 //------------------------------------------------------------------------
2 // SEG : Choose the best Seg to use for a node line.
3 //------------------------------------------------------------------------
4 //
5 // GL-Friendly Node Builder (C) 2000-2005 Andrew Apted
6 //
7 // Based on 'BSP 2.3' by Colin Reed, Lee Killough and others.
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 // To be able to divide the nodes down, this routine must decide which
22 // is the best Seg to use as a nodeline. It does this by selecting the
23 // line with least splits and has least difference of Segs on either
24 // side of it.
25 //
26 // Credit to Raphael Quinet and DEU, this routine is a copy of the
27 // nodeline picker used in DEU5beta. I am using this method because
28 // the method I originally used was not so good.
29 //
30 // Rewritten by Lee Killough to significantly improve performance,
31 // while not affecting results one bit in >99% of cases (some tiny
32 // differences due to roundoff error may occur, but they are
33 // insignificant).
34 //
35 // Rewritten again by Andrew Apted (-AJA-), 1999-2000.
36 //
37
38 #include "system.h"
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <ctype.h>
45 #include <math.h>
46 #include <limits.h>
47 #include <assert.h>
48
49 #include "analyze.h"
50 #include "blockmap.h"
51 #include "level.h"
52 #include "node.h"
53 #include "seg.h"
54 #include "structs.h"
55 #include "util.h"
56 #include "wad.h"
57
58
59 #define PRECIOUS_MULTIPLY 100
60
61 #define SEG_REUSE_THRESHHOLD 200
62
63
64 #define DEBUG_PICKNODE 0
65 #define DEBUG_SPLIT 0
66 #define DEBUG_CUTLIST 0
67
68
69 typedef struct eval_info_s
70 {
71 int cost;
72 int splits;
73 int iffy;
74 int near_miss;
75
76 int real_left;
77 int real_right;
78 int mini_left;
79 int mini_right;
80 }
81 eval_info_t;
82
83
84 static intersection_t *quick_alloc_cuts = NULL;
85
86
87 //
88 // NewIntersection
89 //
NewIntersection(void)90 static intersection_t *NewIntersection(void)
91 {
92 intersection_t *cut;
93
94 if (quick_alloc_cuts)
95 {
96 cut = quick_alloc_cuts;
97 quick_alloc_cuts = cut->next;
98 }
99 else
100 {
101 cut = UtilCalloc(sizeof(intersection_t));
102 }
103
104 return cut;
105 }
106
107 //
108 // FreeQuickAllocCuts
109 //
FreeQuickAllocCuts(void)110 void FreeQuickAllocCuts(void)
111 {
112 while (quick_alloc_cuts)
113 {
114 intersection_t *cut = quick_alloc_cuts;
115 quick_alloc_cuts = cut->next;
116
117 UtilFree(cut);
118 }
119 }
120
121
122 //
123 // RecomputeSeg
124 //
125 // Fill in the fields 'angle', 'len', 'pdx', 'pdy', etc...
126 //
RecomputeSeg(seg_t * seg)127 void RecomputeSeg(seg_t *seg)
128 {
129 seg->psx = seg->start->x;
130 seg->psy = seg->start->y;
131 seg->pex = seg->end->x;
132 seg->pey = seg->end->y;
133 seg->pdx = seg->pex - seg->psx;
134 seg->pdy = seg->pey - seg->psy;
135
136 seg->p_length = UtilComputeDist(seg->pdx, seg->pdy);
137 seg->p_angle = UtilComputeAngle(seg->pdx, seg->pdy);
138
139 if (seg->p_length <= 0)
140 InternalError("Seg %p has zero p_length.", seg);
141
142 seg->p_perp = seg->psy * seg->pdx - seg->psx * seg->pdy;
143 seg->p_para = -seg->psx * seg->pdx - seg->psy * seg->pdy;
144 }
145
146
147 //
148 // SplitSeg
149 //
150 // -AJA- Splits the given seg at the point (x,y). The new seg is
151 // returned. The old seg is shortened (the original start
152 // vertex is unchanged), whereas the new seg becomes the cut-off
153 // tail (keeping the original end vertex).
154 //
155 // If the seg has a partner, than that partner is also split.
156 // NOTE WELL: the new piece of the partner seg is inserted into
157 // the same list as the partner seg (and after it) -- thus ALL
158 // segs (except the one we are currently splitting) must exist
159 // on a singly-linked list somewhere.
160 //
161 // Note: we must update the count values of any superblock that
162 // contains the seg (and/or partner), so that future processing
163 // is not fucked up by incorrect counts.
164 //
SplitSeg(seg_t * old_seg,float_g x,float_g y)165 static seg_t *SplitSeg(seg_t *old_seg, float_g x, float_g y)
166 {
167 seg_t *new_seg;
168 vertex_t *new_vert;
169
170 # if DEBUG_SPLIT
171 if (old_seg->linedef)
172 PrintDebug("Splitting Linedef %d (%p) at (%1.1f,%1.1f)\n",
173 old_seg->linedef->index, old_seg, x, y);
174 else
175 PrintDebug("Splitting Miniseg %p at (%1.1f,%1.1f)\n", old_seg, x, y);
176 # endif
177
178 // update superblock, if needed
179 if (old_seg->block)
180 SplitSegInSuper(old_seg->block, old_seg);
181
182 new_vert = NewVertexFromSplitSeg(old_seg, x, y);
183 new_seg = NewSeg();
184
185 // copy seg info
186 new_seg[0] = old_seg[0];
187 new_seg->next = NULL;
188
189 old_seg->end = new_vert;
190 RecomputeSeg(old_seg);
191
192 new_seg->start = new_vert;
193 RecomputeSeg(new_seg);
194
195 # if DEBUG_SPLIT
196 PrintDebug("Splitting Vertex is %04X at (%1.1f,%1.1f)\n",
197 new_vert->index, new_vert->x, new_vert->y);
198 # endif
199
200 // handle partners
201
202 if (old_seg->partner)
203 {
204 # if DEBUG_SPLIT
205 PrintDebug("Splitting Partner %p\n", old_seg->partner);
206 # endif
207
208 // update superblock, if needed
209 if (old_seg->partner->block)
210 SplitSegInSuper(old_seg->partner->block, old_seg->partner);
211
212 new_seg->partner = NewSeg();
213
214 // copy seg info
215 new_seg->partner[0] = old_seg->partner[0];
216
217 // IMPORTANT: keep partner relationship valid.
218 new_seg->partner->partner = new_seg;
219
220 old_seg->partner->start = new_vert;
221 RecomputeSeg(old_seg->partner);
222
223 new_seg->partner->end = new_vert;
224 RecomputeSeg(new_seg->partner);
225
226 // link it into list
227 old_seg->partner->next = new_seg->partner;
228 }
229
230 return new_seg;
231 }
232
233
234 //
235 // ComputeIntersection
236 //
237 // -AJA- In the quest for slime-trail annihilation :->, this routine
238 // calculates the intersection location between the current seg
239 // and the partitioning seg, and takes advantage of some common
240 // situations like horizontal/vertical lines.
241 //
ComputeIntersection(seg_t * cur,seg_t * part,float_g perp_c,float_g perp_d,float_g * x,float_g * y)242 static INLINE_G void ComputeIntersection(seg_t *cur, seg_t *part,
243 float_g perp_c, float_g perp_d, float_g *x, float_g *y)
244 {
245 double ds;
246
247 // horizontal partition against vertical seg
248 if (part->pdy == 0 && cur->pdx == 0)
249 {
250 *x = cur->psx;
251 *y = part->psy;
252 return;
253 }
254
255 // vertical partition against horizontal seg
256 if (part->pdx == 0 && cur->pdy == 0)
257 {
258 *x = part->psx;
259 *y = cur->psy;
260 return;
261 }
262
263 // 0 = start, 1 = end
264 ds = perp_c / (perp_c - perp_d);
265
266 if (cur->pdx == 0)
267 *x = cur->psx;
268 else
269 *x = cur->psx + (cur->pdx * ds);
270
271 if (cur->pdy == 0)
272 *y = cur->psy;
273 else
274 *y = cur->psy + (cur->pdy * ds);
275 }
276
277
278 //
279 // AddIntersection
280 //
AddIntersection(intersection_t ** cut_list,vertex_t * vert,seg_t * part,boolean_g self_ref)281 static void AddIntersection(intersection_t ** cut_list,
282 vertex_t *vert, seg_t *part, boolean_g self_ref)
283 {
284 intersection_t *cut;
285 intersection_t *after;
286
287 /* check if vertex already present */
288 for (cut=(*cut_list); cut; cut=cut->next)
289 {
290 if (vert == cut->vertex)
291 return;
292 }
293
294 /* create new intersection */
295 cut = NewIntersection();
296
297 cut->vertex = vert;
298 cut->along_dist = UtilParallelDist(part, vert->x, vert->y);
299 cut->self_ref = self_ref;
300
301 cut->before = VertexCheckOpen(vert, -part->pdx, -part->pdy);
302 cut->after = VertexCheckOpen(vert, part->pdx, part->pdy);
303
304 /* enqueue the new intersection into the list */
305
306 for (after=(*cut_list); after && after->next; after=after->next)
307 { }
308
309 while (after && cut->along_dist < after->along_dist)
310 after = after->prev;
311
312 /* link it in */
313 cut->next = after ? after->next : (*cut_list);
314 cut->prev = after;
315
316 if (after)
317 {
318 if (after->next)
319 after->next->prev = cut;
320
321 after->next = cut;
322 }
323 else
324 {
325 if (*cut_list)
326 (*cut_list)->prev = cut;
327
328 (*cut_list) = cut;
329 }
330 }
331
332
333 //
334 // EvalPartitionWorker
335 //
336 // Returns TRUE if a "bad seg" was found early.
337 //
EvalPartitionWorker(superblock_t * seg_list,seg_t * part,int best_cost,eval_info_t * info)338 static int EvalPartitionWorker(superblock_t *seg_list, seg_t *part,
339 int best_cost, eval_info_t *info)
340 {
341 seg_t *check;
342
343 float_g qnty;
344 float_g a, b, fa, fb;
345
346 int num;
347 int factor = cur_info->factor;
348
349 // -AJA- this is the heart of my superblock idea, it tests the
350 // _whole_ block against the partition line to quickly handle
351 // all the segs within it at once. Only when the partition
352 // line intercepts the box do we need to go deeper into it.
353
354 num = BoxOnLineSide(seg_list, part);
355
356 if (num < 0)
357 {
358 // LEFT
359
360 info->real_left += seg_list->real_num;
361 info->mini_left += seg_list->mini_num;
362
363 return FALSE;
364 }
365 else if (num > 0)
366 {
367 // RIGHT
368
369 info->real_right += seg_list->real_num;
370 info->mini_right += seg_list->mini_num;
371
372 return FALSE;
373 }
374
375 # define ADD_LEFT() \
376 do { \
377 if (check->linedef) info->real_left += 1; \
378 else info->mini_left += 1; \
379 } while (0)
380
381 # define ADD_RIGHT() \
382 do { \
383 if (check->linedef) info->real_right += 1; \
384 else info->mini_right += 1; \
385 } while (0)
386
387 /* check partition against all Segs */
388
389 for (check=seg_list->segs; check; check=check->next)
390 {
391 // This is the heart of my pruning idea - it catches
392 // bad segs early on. Killough
393
394 if (info->cost > best_cost)
395 return TRUE;
396
397 /* get state of lines' relation to each other */
398 if (check->source_line == part->source_line)
399 {
400 a = b = fa = fb = 0;
401 }
402 else
403 {
404 a = UtilPerpDist(part, check->psx, check->psy);
405 b = UtilPerpDist(part, check->pex, check->pey);
406
407 fa = fabs(a);
408 fb = fabs(b);
409 }
410
411 /* check for being on the same line */
412 if (fa <= DIST_EPSILON && fb <= DIST_EPSILON)
413 {
414 // this seg runs along the same line as the partition. Check
415 // whether it goes in the same direction or the opposite.
416
417 if (check->pdx*part->pdx + check->pdy*part->pdy < 0)
418 {
419 ADD_LEFT();
420 }
421 else
422 {
423 ADD_RIGHT();
424 }
425
426 continue;
427 }
428
429 // -AJA- check for passing through a vertex. Normally this is fine
430 // (even ideal), but the vertex could on a sector that we
431 // DONT want to split, and the normal linedef-based checks
432 // may fail to detect the sector being cut in half. Thanks
433 // to Janis Legzdinsh for spotting this obscure bug.
434
435 if (fa <= DIST_EPSILON || fb <= DIST_EPSILON)
436 {
437 if (check->linedef && check->linedef->is_precious)
438 info->cost += 40 * factor * PRECIOUS_MULTIPLY;
439 }
440
441 /* check for right side */
442 if (a > -DIST_EPSILON && b > -DIST_EPSILON)
443 {
444 ADD_RIGHT();
445
446 /* check for a near miss */
447 if ((a >= IFFY_LEN && b >= IFFY_LEN) ||
448 (a <= DIST_EPSILON && b >= IFFY_LEN) ||
449 (b <= DIST_EPSILON && a >= IFFY_LEN))
450 {
451 continue;
452 }
453
454 info->near_miss++;
455
456 // -AJA- near misses are bad, since they have the potential to
457 // cause really short minisegs to be created in future
458 // processing. Thus the closer the near miss, the higher
459 // the cost.
460
461 if (a <= DIST_EPSILON || b <= DIST_EPSILON)
462 qnty = IFFY_LEN / MAX(a, b);
463 else
464 qnty = IFFY_LEN / MIN(a, b);
465
466 info->cost += (int) (100 * factor * (qnty * qnty - 1.0));
467 continue;
468 }
469
470 /* check for left side */
471 if (a < DIST_EPSILON && b < DIST_EPSILON)
472 {
473 ADD_LEFT();
474
475 /* check for a near miss */
476 if ((a <= -IFFY_LEN && b <= -IFFY_LEN) ||
477 (a >= -DIST_EPSILON && b <= -IFFY_LEN) ||
478 (b >= -DIST_EPSILON && a <= -IFFY_LEN))
479 {
480 continue;
481 }
482
483 info->near_miss++;
484
485 // the closer the miss, the higher the cost (see note above)
486 if (a >= -DIST_EPSILON || b >= -DIST_EPSILON)
487 qnty = IFFY_LEN / -MIN(a, b);
488 else
489 qnty = IFFY_LEN / -MAX(a, b);
490
491 info->cost += (int) (70 * factor * (qnty * qnty - 1.0));
492 continue;
493 }
494
495 // When we reach here, we have a and b non-zero and opposite sign,
496 // hence this seg will be split by the partition line.
497
498 info->splits++;
499
500 // If the linedef associated with this seg has a tag >= 900, treat
501 // it as precious; i.e. don't split it unless all other options
502 // are exhausted. This is used to protect deep water and invisible
503 // lifts/stairs from being messed up accidentally by splits.
504
505 if (check->linedef && check->linedef->is_precious)
506 info->cost += 100 * factor * PRECIOUS_MULTIPLY;
507 else
508 info->cost += 100 * factor;
509
510 // -AJA- check if the split point is very close to one end, which
511 // is quite an undesirable situation (producing really short
512 // segs). This is perhaps _one_ source of those darn slime
513 // trails. Hence the name "IFFY segs", and a rather hefty
514 // surcharge :->.
515
516 if (fa < IFFY_LEN || fb < IFFY_LEN)
517 {
518 info->iffy++;
519
520 // the closer to the end, the higher the cost
521 qnty = IFFY_LEN / MIN(fa, fb);
522 info->cost += (int) (140 * factor * (qnty * qnty - 1.0));
523 }
524 }
525
526 /* handle sub-blocks recursively */
527
528 for (num=0; num < 2; num++)
529 {
530 if (! seg_list->subs[num])
531 continue;
532
533 if (EvalPartitionWorker(seg_list->subs[num], part, best_cost, info))
534 return TRUE;
535 }
536
537 /* no "bad seg" was found */
538 return FALSE;
539 }
540
541 //
542 // EvalPartition
543 //
544 // -AJA- Evaluate a partition seg & determine the cost, taking into
545 // account the number of splits, difference between left &
546 // right, and linedefs that are tagged 'precious'.
547 //
548 // Returns the computed cost, or a negative value if the seg should be
549 // skipped altogether.
550 //
EvalPartition(superblock_t * seg_list,seg_t * part,int best_cost)551 static int EvalPartition(superblock_t *seg_list, seg_t *part,
552 int best_cost)
553 {
554 eval_info_t info;
555
556 /* initialise info structure */
557 info.cost = 0;
558 info.splits = 0;
559 info.iffy = 0;
560 info.near_miss = 0;
561
562 info.real_left = 0;
563 info.real_right = 0;
564 info.mini_left = 0;
565 info.mini_right = 0;
566
567 if (EvalPartitionWorker(seg_list, part, best_cost, &info))
568 return -1;
569
570 /* make sure there is at least one real seg on each side */
571 if (!info.real_left || !info.real_right)
572 {
573 # if DEBUG_PICKNODE
574 PrintDebug("Eval : No real segs on %s%sside\n",
575 info.real_left ? "" : "left ",
576 info.real_right ? "" : "right ");
577 # endif
578
579 return -1;
580 }
581
582 /* increase cost by the difference between left & right */
583 info.cost += 100 * ABS(info.real_left - info.real_right);
584
585 // -AJA- allow miniseg counts to affect the outcome, but only to a
586 // lesser degree than real segs.
587
588 info.cost += 50 * ABS(info.mini_left - info.mini_right);
589
590 // -AJA- Another little twist, here we show a slight preference for
591 // partition lines that lie either purely horizontally or
592 // purely vertically.
593
594 if (part->pdx != 0 && part->pdy != 0)
595 info.cost += 25;
596
597 # if DEBUG_PICKNODE
598 PrintDebug("Eval %p: splits=%d iffy=%d near=%d left=%d+%d right=%d+%d "
599 "cost=%d.%02d\n", part, info.splits, info.iffy, info.near_miss,
600 info.real_left, info.mini_left, info.real_right, info.mini_right,
601 info.cost / 100, info.cost % 100);
602 # endif
603
604 return info.cost;
605 }
606
607
FindSegFromStaleNode(superblock_t * part_list,node_t * stale_nd,int * stale_opposite)608 static seg_t *FindSegFromStaleNode(superblock_t *part_list,
609 node_t *stale_nd, int *stale_opposite)
610 {
611 seg_t *part;
612 int num;
613
614 for (part=part_list->segs; part; part = part->next)
615 {
616 float_g fa, fb;
617
618 /* ignore minisegs as partition candidates */
619 if (! part->linedef)
620 continue;
621
622 fa = fabs(UtilPerpDist(part, stale_nd->x, stale_nd->y));
623 fb = fabs(UtilPerpDist(part, stale_nd->x + stale_nd->dx,
624 stale_nd->y + stale_nd->dy));
625
626 if (fa < DIST_EPSILON && fb < DIST_EPSILON)
627 {
628 /* OK found it. check if runs in same direction */
629
630 (*stale_opposite) = (stale_nd->dx * part->pdx +
631 stale_nd->dy * part->pdy < 0) ? 1 : 0;
632
633 return part;
634 }
635 }
636
637 /* handle sub-blocks recursively */
638
639 for (num=0; num < 2; num++)
640 {
641 if (! part_list->subs[num])
642 continue;
643
644 part = FindSegFromStaleNode(part_list->subs[num], stale_nd,
645 stale_opposite);
646
647 if (part)
648 return part;
649 }
650
651 return NULL;
652 }
653
654
655 /* returns FALSE if cancelled */
PickNodeWorker(superblock_t * part_list,superblock_t * seg_list,seg_t ** best,int * best_cost,int * progress,int prog_step)656 static int PickNodeWorker(superblock_t *part_list,
657 superblock_t *seg_list, seg_t ** best, int *best_cost,
658 int *progress, int prog_step)
659 {
660 seg_t *part;
661
662 int num;
663 int cost;
664
665 /* use each Seg as partition */
666 for (part=part_list->segs; part; part = part->next)
667 {
668 if (cur_comms->cancelled)
669 return FALSE;
670
671 # if DEBUG_PICKNODE
672 PrintDebug("PickNode: %sSEG %p sector=%d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n",
673 part->linedef ? "" : "MINI", part,
674 part->sector ? part->sector->index : -1,
675 part->start->x, part->start->y, part->end->x, part->end->y);
676 # endif
677
678 /* something for the user to look at */
679 (*progress) += 1;
680
681 if ((*progress % prog_step) == 0)
682 {
683 cur_comms->build_pos++;
684 DisplaySetBar(1, cur_comms->build_pos);
685 DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100);
686 }
687
688 /* ignore minisegs as partition candidates */
689 if (! part->linedef)
690 continue;
691
692 cost = EvalPartition(seg_list, part, *best_cost);
693
694 /* seg unsuitable or too costly ? */
695 if (cost < 0 || cost >= *best_cost)
696 continue;
697
698 /* we have a new better choice */
699 (*best_cost) = cost;
700
701 /* remember which Seg */
702 (*best) = part;
703 }
704
705 DisplayTicker();
706
707 /* recursively handle sub-blocks */
708
709 for (num=0; num < 2; num++)
710 {
711 if (part_list->subs[num])
712 PickNodeWorker(part_list->subs[num], seg_list, best, best_cost,
713 progress, prog_step);
714 }
715
716 return TRUE;
717 }
718
719 //
720 // PickNode
721 //
722 // Find the best seg in the seg_list to use as a partition line.
723 //
PickNode(superblock_t * seg_list,int depth,node_t ** stale_nd,int * stale_opposite)724 seg_t *PickNode(superblock_t *seg_list, int depth,
725 node_t ** stale_nd, int *stale_opposite)
726 {
727 seg_t *best=NULL;
728
729 int best_cost=INT_MAX;
730
731 int progress=0;
732 int prog_step=1<<24;
733 int build_step=0;
734
735 # if DEBUG_PICKNODE
736 PrintDebug("PickNode: BEGUN (depth %d)\n", depth);
737 # endif
738
739 /* compute info for showing progress */
740 if (depth <= 6)
741 {
742 static int depth_counts[7] = { 248, 100, 30, 10, 6, 4, 2 };
743
744 int total = seg_list->real_num + seg_list->mini_num;
745
746 build_step = depth_counts[depth];
747 prog_step = 1 + ((total - 1) / build_step);
748
749 if (total / prog_step < build_step)
750 {
751 cur_comms->build_pos += build_step - total / prog_step;
752 build_step = total / prog_step;
753
754 DisplaySetBar(1, cur_comms->build_pos);
755 DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100);
756 }
757 }
758
759 DisplayTicker();
760
761 /* -AJA- another (optional) optimisation, when building just the GL
762 * nodes. We assume that the original nodes are reasonably
763 * good choices, and re-use them as much as possible, saving
764 * *heaps* of time on really large levels.
765 */
766 if (*stale_nd && seg_list->real_num >= SEG_REUSE_THRESHHOLD)
767 {
768 best = FindSegFromStaleNode(seg_list, *stale_nd, stale_opposite);
769
770 # if DEBUG_PICKNODE
771 PrintDebug("PickNode: Trying stale node %p\n", best);
772 # endif
773
774 if (best && EvalPartition(seg_list, best, best_cost) < 0)
775 {
776 best = NULL;
777
778 # if DEBUG_PICKNODE
779 PrintDebug("PickNode: Stale node unsuitable !\n");
780 # endif
781 }
782
783 if (best)
784 {
785 /* update progress */
786 cur_comms->build_pos += build_step;
787 DisplaySetBar(1, cur_comms->build_pos);
788 DisplaySetBar(2, cur_comms->file_pos + cur_comms->build_pos / 100);
789
790 # if DEBUG_PICKNODE
791 PrintDebug("PickNode: Using Stale node (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n",
792 best->start->x, best->start->y, best->end->x, best->end->y);
793 # endif
794
795 return best;
796 }
797 }
798
799 (*stale_nd) = NULL;
800
801 if (FALSE == PickNodeWorker(seg_list, seg_list, &best, &best_cost,
802 &progress, prog_step))
803 {
804 /* hack here : BuildNodes will detect the cancellation */
805 return NULL;
806 }
807
808 # if DEBUG_PICKNODE
809 if (! best)
810 {
811 PrintDebug("PickNode: NO BEST FOUND !\n");
812 }
813 else
814 {
815 PrintDebug("PickNode: Best has score %d.%02d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n",
816 best_cost / 100, best_cost % 100, best->start->x, best->start->y,
817 best->end->x, best->end->y);
818 }
819 # endif
820
821 /* all finished, return best Seg */
822 return best;
823 }
824
825
826 //
827 // DivideOneSeg
828 //
829 // Apply the partition line to the given seg, taking the necessary
830 // action (moving it into either the left list, right list, or
831 // splitting it).
832 //
833 // -AJA- I have rewritten this routine based on the EvalPartition
834 // routine above (which I've also reworked, heavily). I think
835 // it is important that both these routines follow the exact
836 // same logic when determining which segs should go left, right
837 // or be split.
838 //
DivideOneSeg(seg_t * cur,seg_t * part,superblock_t * left_list,superblock_t * right_list,intersection_t ** cut_list)839 void DivideOneSeg(seg_t *cur, seg_t *part,
840 superblock_t *left_list, superblock_t *right_list,
841 intersection_t ** cut_list)
842 {
843 seg_t *new_seg;
844
845 float_g x, y;
846
847 /* get state of lines' relation to each other */
848 float_g a = UtilPerpDist(part, cur->psx, cur->psy);
849 float_g b = UtilPerpDist(part, cur->pex, cur->pey);
850
851 boolean_g self_ref = cur->linedef ? cur->linedef->self_ref : FALSE;
852
853 if (cur->source_line == part->source_line)
854 a = b = 0;
855
856 /* check for being on the same line */
857 if (fabs(a) <= DIST_EPSILON && fabs(b) <= DIST_EPSILON)
858 {
859 AddIntersection(cut_list, cur->start, part, self_ref);
860 AddIntersection(cut_list, cur->end, part, self_ref);
861
862 // this seg runs along the same line as the partition. check
863 // whether it goes in the same direction or the opposite.
864
865 if (cur->pdx*part->pdx + cur->pdy*part->pdy < 0)
866 {
867 AddSegToSuper(left_list, cur);
868 }
869 else
870 {
871 AddSegToSuper(right_list, cur);
872 }
873
874 return;
875 }
876
877 /* check for right side */
878 if (a > -DIST_EPSILON && b > -DIST_EPSILON)
879 {
880 if (a < DIST_EPSILON)
881 AddIntersection(cut_list, cur->start, part, self_ref);
882 else if (b < DIST_EPSILON)
883 AddIntersection(cut_list, cur->end, part, self_ref);
884
885 AddSegToSuper(right_list, cur);
886 return;
887 }
888
889 /* check for left side */
890 if (a < DIST_EPSILON && b < DIST_EPSILON)
891 {
892 if (a > -DIST_EPSILON)
893 AddIntersection(cut_list, cur->start, part, self_ref);
894 else if (b > -DIST_EPSILON)
895 AddIntersection(cut_list, cur->end, part, self_ref);
896
897 AddSegToSuper(left_list, cur);
898 return;
899 }
900
901 // when we reach here, we have a and b non-zero and opposite sign,
902 // hence this seg will be split by the partition line.
903
904 ComputeIntersection(cur, part, a, b, &x, &y);
905
906 new_seg = SplitSeg(cur, x, y);
907
908 AddIntersection(cut_list, cur->end, part, self_ref);
909
910 if (a < 0)
911 {
912 AddSegToSuper(left_list, cur);
913 AddSegToSuper(right_list, new_seg);
914 }
915 else
916 {
917 AddSegToSuper(right_list, cur);
918 AddSegToSuper(left_list, new_seg);
919 }
920 }
921
922 //
923 // SeparateSegs
924 //
SeparateSegs(superblock_t * seg_list,seg_t * part,superblock_t * lefts,superblock_t * rights,intersection_t ** cut_list)925 void SeparateSegs(superblock_t *seg_list, seg_t *part,
926 superblock_t *lefts, superblock_t *rights,
927 intersection_t ** cut_list)
928 {
929 int num;
930
931 while (seg_list->segs)
932 {
933 seg_t *cur = seg_list->segs;
934 seg_list->segs = cur->next;
935
936 cur->block = NULL;
937
938 DivideOneSeg(cur, part, lefts, rights, cut_list);
939 }
940
941 // recursively handle sub-blocks
942 for (num=0; num < 2; num++)
943 {
944 superblock_t *A = seg_list->subs[num];
945
946 if (A)
947 {
948 SeparateSegs(A, part, lefts, rights, cut_list);
949
950 if (A->real_num + A->mini_num > 0)
951 InternalError("SeparateSegs: child %d not empty !", num);
952
953 FreeSuper(A);
954 seg_list->subs[num] = NULL;
955 }
956 }
957
958 seg_list->real_num = seg_list->mini_num = 0;
959 }
960
961
FindLimitWorker(superblock_t * block,bbox_t * bbox)962 static void FindLimitWorker(superblock_t *block, bbox_t *bbox)
963 {
964 seg_t *cur;
965 int num;
966
967 for (cur=block->segs; cur; cur=cur->next)
968 {
969 float_g x1 = cur->start->x;
970 float_g y1 = cur->start->y;
971 float_g x2 = cur->end->x;
972 float_g y2 = cur->end->y;
973
974 int lx = (int) floor(MIN(x1, x2));
975 int ly = (int) floor(MIN(y1, y2));
976 int hx = (int) ceil(MAX(x1, x2));
977 int hy = (int) ceil(MAX(y1, y2));
978
979 if (lx < bbox->minx) bbox->minx = lx;
980 if (ly < bbox->miny) bbox->miny = ly;
981 if (hx > bbox->maxx) bbox->maxx = hx;
982 if (hy > bbox->maxy) bbox->maxy = hy;
983 }
984
985 // recursive handle sub-blocks
986
987 for (num=0; num < 2; num++)
988 {
989 if (block->subs[num])
990 FindLimitWorker(block->subs[num], bbox);
991 }
992 }
993
994 //
995 // FindLimits
996 //
997 // Find the limits from a list of segs, by stepping through the segs
998 // and comparing the vertices at both ends.
999 //
FindLimits(superblock_t * seg_list,bbox_t * bbox)1000 void FindLimits(superblock_t *seg_list, bbox_t *bbox)
1001 {
1002 bbox->minx = bbox->miny = SHRT_MAX;
1003 bbox->maxx = bbox->maxy = SHRT_MIN;
1004
1005 FindLimitWorker(seg_list, bbox);
1006 }
1007
1008
1009 //
1010 // AddMinisegs
1011 //
AddMinisegs(seg_t * part,superblock_t * left_list,superblock_t * right_list,intersection_t * cut_list)1012 void AddMinisegs(seg_t *part,
1013 superblock_t *left_list, superblock_t *right_list,
1014 intersection_t *cut_list)
1015 {
1016 intersection_t *cur, *next;
1017 seg_t *seg, *buddy;
1018
1019 if (! cut_list)
1020 return;
1021
1022 # if DEBUG_CUTLIST
1023 PrintDebug("CUT LIST:\n");
1024 PrintDebug("PARTITION: (%1.1f,%1.1f) += (%1.1f,%1.1f)\n",
1025 part->psx, part->psy, part->pdx, part->pdy);
1026
1027 for (cur=cut_list; cur; cur=cur->next)
1028 {
1029 PrintDebug(" Vertex %8X (%1.1f,%1.1f) Along %1.2f [%d/%d] %s\n",
1030 cur->vertex->index, cur->vertex->x, cur->vertex->y,
1031 cur->along_dist,
1032 cur->before ? cur->before->index : -1,
1033 cur->after ? cur->after->index : -1,
1034 cur->self_ref ? "SELFREF" : "");
1035 }
1036 # endif
1037
1038 // STEP 1: fix problems the intersection list...
1039
1040 cur = cut_list;
1041 next = cur->next;
1042
1043 while (cur && next)
1044 {
1045 float_g len = next->along_dist - cur->along_dist;
1046
1047 if (len < -0.1)
1048 InternalError("Bad order in intersect list: %1.3f > %1.3f\n",
1049 cur->along_dist, next->along_dist);
1050
1051 if (len > 0.2)
1052 {
1053 cur = next;
1054 next = cur->next;
1055 continue;
1056 }
1057
1058 if (len > DIST_EPSILON)
1059 {
1060 PrintMiniWarn("Skipping very short seg (len=%1.3f) near (%1.1f,%1.1f)\n",
1061 len, cur->vertex->x, cur->vertex->y);
1062 }
1063
1064 // merge the two intersections into one
1065
1066 # if DEBUG_CUTLIST
1067 PrintDebug("Merging cut (%1.0f,%1.0f) [%d/%d] with %p (%1.0f,%1.0f) [%d/%d]\n",
1068 cur->vertex->x, cur->vertex->y,
1069 cur->before ? cur->before->index : -1,
1070 cur->after ? cur->after->index : -1,
1071 next->vertex->x, next->vertex->y,
1072 next->before ? next->before->index : -1,
1073 next->after ? next->after->index : -1);
1074 # endif
1075
1076 if (cur->self_ref && !next->self_ref)
1077 {
1078 if (cur->before && next->before)
1079 cur->before = next->before;
1080
1081 if (cur->after && next->after)
1082 cur->after = next->after;
1083
1084 cur->self_ref = FALSE;
1085 }
1086
1087 if (!cur->before && next->before)
1088 cur->before = next->before;
1089
1090 if (!cur->after && next->after)
1091 cur->after = next->after;
1092
1093 # if DEBUG_CUTLIST
1094 PrintDebug("---> merged (%1.0f,%1.0f) [%d/%d] %s\n",
1095 cur->vertex->x, cur->vertex->y,
1096 cur->before ? cur->before->index : -1,
1097 cur->after ? cur->after->index : -1,
1098 cur->self_ref ? "SELFREF" : "");
1099 # endif
1100
1101 // free the unused cut
1102
1103 cur->next = next->next;
1104
1105 next->next = quick_alloc_cuts;
1106 quick_alloc_cuts = next;
1107
1108 next = cur->next;
1109 }
1110
1111 // STEP 2: find connections in the intersection list...
1112
1113 for (cur = cut_list; cur && cur->next; cur = cur->next)
1114 {
1115 next = cur->next;
1116
1117 if (!cur->after && !next->before)
1118 continue;
1119
1120 // check for some nasty OPEN/CLOSED or CLOSED/OPEN cases
1121 if (cur->after && !next->before)
1122 {
1123 if (!cur->self_ref && !cur->after->warned_unclosed)
1124 {
1125 PrintMiniWarn("Sector #%d is unclosed near (%1.1f,%1.1f)\n",
1126 cur->after->index,
1127 (cur->vertex->x + next->vertex->x) / 2.0,
1128 (cur->vertex->y + next->vertex->y) / 2.0);
1129 cur->after->warned_unclosed = 1;
1130 }
1131 continue;
1132 }
1133 else if (!cur->after && next->before)
1134 {
1135 if (!next->self_ref && !next->before->warned_unclosed)
1136 {
1137 PrintMiniWarn("Sector #%d is unclosed near (%1.1f,%1.1f)\n",
1138 next->before->index,
1139 (cur->vertex->x + next->vertex->x) / 2.0,
1140 (cur->vertex->y + next->vertex->y) / 2.0);
1141 next->before->warned_unclosed = 1;
1142 }
1143 continue;
1144 }
1145
1146 // righteo, here we have definite open space.
1147 // do a sanity check on the sectors (just for good measure).
1148
1149 if (cur->after != next->before)
1150 {
1151 if (!cur->self_ref && !next->self_ref)
1152 PrintMiniWarn("Sector mismatch: #%d (%1.1f,%1.1f) != #%d (%1.1f,%1.1f)\n",
1153 cur->after->index, next->before->index,
1154 cur->vertex->x, cur->vertex->y,
1155 next->vertex->x, next->vertex->y);
1156
1157 // choose the non-self-referencing sector when we can
1158 if (cur->self_ref && !next->self_ref)
1159 {
1160 cur->after = next->before;
1161 }
1162 }
1163
1164 // create the miniseg pair
1165 seg = NewSeg();
1166 buddy = NewSeg();
1167
1168 seg->partner = buddy;
1169 buddy->partner = seg;
1170
1171 seg->start = cur->vertex;
1172 seg->end = next->vertex;
1173
1174 buddy->start = next->vertex;
1175 buddy->end = cur->vertex;
1176
1177 // leave 'linedef' field as NULL.
1178 // leave 'side' as zero too (not needed for minisegs).
1179
1180 seg->sector = buddy->sector = cur->after;
1181
1182 seg->index = buddy->index = -1;
1183
1184 seg->source_line = buddy->source_line = part->linedef;
1185
1186 RecomputeSeg(seg);
1187 RecomputeSeg(buddy);
1188
1189 // add the new segs to the appropriate lists
1190 AddSegToSuper(right_list, seg);
1191 AddSegToSuper(left_list, buddy);
1192
1193 # if DEBUG_CUTLIST
1194 PrintDebug("AddMiniseg: %p RIGHT sector %d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n",
1195 seg, seg->sector ? seg->sector->index : -1,
1196 seg->start->x, seg->start->y, seg->end->x, seg->end->y);
1197
1198 PrintDebug("AddMiniseg: %p LEFT sector %d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n",
1199 buddy, buddy->sector ? buddy->sector->index : -1,
1200 buddy->start->x, buddy->start->y, buddy->end->x, buddy->end->y);
1201 # endif
1202 }
1203
1204 // free intersection structures into quick-alloc list
1205 while (cut_list)
1206 {
1207 cur = cut_list;
1208 cut_list = cur->next;
1209
1210 cur->next = quick_alloc_cuts;
1211 quick_alloc_cuts = cur;
1212 }
1213 }
1214
1215