// // DivideOneSeg // // Apply the partition line to the given seg, taking the necessary // action (moving it into either the left list, right list, or // splitting it). // // -AJA- I have rewritten this routine based on the EvalPartition // routine above (which I've also reworked, heavily). I think // it is important that both these routines follow the exact // same logic when determining which segs should go left, right // or be split. // void DivideOneSeg(seg_t *cur, seg_t *part, superblock_t *left_list, superblock_t *right_list, intersection_t ** cut_list) { seg_t *new_seg; float_g x, y; /* get state of lines' relation to each other */ float_g a = UtilPerpDist(part, cur->psx, cur->psy); float_g b = UtilPerpDist(part, cur->pex, cur->pey); boolean_g self_ref = cur->linedef ? cur->linedef->self_ref : FALSE; if (cur->source_line == part->source_line) a = b = 0; /* check for being on the same line */ if (fabs(a) <= DIST_EPSILON && fabs(b) <= DIST_EPSILON) { AddIntersection(cut_list, cur->start, part, self_ref); AddIntersection(cut_list, cur->end, part, self_ref); // this seg runs along the same line as the partition. check // whether it goes in the same direction or the opposite. if (cur->pdx*part->pdx + cur->pdy*part->pdy < 0) { AddSegToSuper(left_list, cur); } else { AddSegToSuper(right_list, cur); } return; } /* check for right side */ if (a > -DIST_EPSILON && b > -DIST_EPSILON) { if (a < DIST_EPSILON) AddIntersection(cut_list, cur->start, part, self_ref); else if (b < DIST_EPSILON) AddIntersection(cut_list, cur->end, part, self_ref); AddSegToSuper(right_list, cur); return; } /* check for left side */ if (a < DIST_EPSILON && b < DIST_EPSILON) { if (a > -DIST_EPSILON) AddIntersection(cut_list, cur->start, part, self_ref); else if (b > -DIST_EPSILON) AddIntersection(cut_list, cur->end, part, self_ref); AddSegToSuper(left_list, cur); return; } // when we reach here, we have a and b non-zero and opposite sign, // hence this seg will be split by the partition line. ComputeIntersection(cur, part, a, b, &x, &y); new_seg = SplitSeg(cur, x, y); AddIntersection(cut_list, cur->end, part, self_ref); if (a < 0) { AddSegToSuper(left_list, cur); AddSegToSuper(right_list, new_seg); } else { AddSegToSuper(right_list, cur); AddSegToSuper(left_list, new_seg); } }
// If there are any segs on the splitter that span more than two events, they // must be split. Alien Vendetta is one example wad that is quite bad about // having overlapping lines. If we skip this step, these segs will still be // split later, but minisegs will erroneously be added for them, and partner // seg information will be messed up in the generated tree. void FNodeBuilder::FixSplitSharers () { D(printf("events:\n")); D(Events.PrintTree()); for (unsigned int i = 0; i < SplitSharers.Size(); ++i) { DWORD seg = SplitSharers[i].Seg; int v2 = Segs[seg].v2; FEvent *event = Events.FindEvent (SplitSharers[i].Distance); FEvent *next; if (event == NULL) { // Should not happen continue; } D(printf("Considering events on seg %d(%d[%d,%d]->%d[%d,%d]) [%g:%g]\n", seg, Segs[seg].v1, Vertices[Segs[seg].v1].x>>16, Vertices[Segs[seg].v1].y>>16, Segs[seg].v2, Vertices[Segs[seg].v2].x>>16, Vertices[Segs[seg].v2].y>>16, SplitSharers[i].Distance, event->Distance)); if (SplitSharers[i].Forward) { event = Events.GetSuccessor (event); if (event == NULL) { continue; } next = Events.GetSuccessor (event); } else { event = Events.GetPredecessor (event); if (event == NULL) { continue; } next = Events.GetPredecessor (event); } while (event != NULL && next != NULL && event->Info.Vertex != v2) { D(printf("Forced split of seg %d(%d[%d,%d]->%d[%d,%d]) at %d(%d,%d):%g\n", seg, Segs[seg].v1, Vertices[Segs[seg].v1].x>>16, Vertices[Segs[seg].v1].y>>16, Segs[seg].v2, Vertices[Segs[seg].v2].x>>16, Vertices[Segs[seg].v2].y>>16, event->Info.Vertex, Vertices[event->Info.Vertex].x>>16, Vertices[event->Info.Vertex].y>>16, event->Distance)); DWORD newseg = SplitSeg (seg, event->Info.Vertex, 1); Segs[newseg].next = Segs[seg].next; Segs[seg].next = newseg; DWORD partner = Segs[seg].partner; if (partner != DWORD_MAX) { int endpartner = SplitSeg (partner, event->Info.Vertex, 1); Segs[endpartner].next = Segs[partner].next; Segs[partner].next = endpartner; Segs[seg].partner = endpartner; //Segs[endpartner].partner = seg; Segs[partner].partner = newseg; assert (Segs[Segs[seg].partner].partner == seg); assert (Segs[Segs[newseg].partner].partner == newseg); assert (Segs[seg].v1 == Segs[endpartner].v2); assert (Segs[seg].v2 == Segs[endpartner].v1); assert (Segs[partner].v1 == Segs[newseg].v2); assert (Segs[partner].v2 == Segs[newseg].v1); } seg = newseg; if (SplitSharers[i].Forward) { event = next; next = Events.GetSuccessor (next); } else { event = next; next = Events.GetPredecessor (next); } } } }
// If there are any segs on the splitter that span more than two events, they // must be split. Alien Vendetta is one example wad that is quite bad about // having overlapping lines. If we skip this step, these segs will still be // split later, but minisegs will erroneously be added for them, and partner // seg information will be messed up in the generated tree. void FNodeBuilder::FixSplitSharers (const node_t &node) { D(Printf(PRINT_LOG, "events:\n")); D(Events.PrintTree()); for (unsigned int i = 0; i < SplitSharers.Size(); ++i) { DWORD seg = SplitSharers[i].Seg; int v2 = Segs[seg].v2; FEvent *event = Events.FindEvent (SplitSharers[i].Distance); FEvent *next; if (event == NULL) { // Should not happen continue; } // Use the CRT's printf so the formatting matches ZDBSP's D(char buff[200]); D(sprintf(buff, "Considering events on seg %d(%d[%d,%d]->%d[%d,%d]) [%g:%g]\n", seg, Segs[seg].v1, Vertices[Segs[seg].v1].x>>16, Vertices[Segs[seg].v1].y>>16, Segs[seg].v2, Vertices[Segs[seg].v2].x>>16, Vertices[Segs[seg].v2].y>>16, SplitSharers[i].Distance, event->Distance)); D(Printf(PRINT_LOG, "%s", buff)); if (SplitSharers[i].Forward) { event = Events.GetSuccessor (event); if (event == NULL) { continue; } next = Events.GetSuccessor (event); } else { event = Events.GetPredecessor (event); if (event == NULL) { continue; } next = Events.GetPredecessor (event); } while (event != NULL && next != NULL && event->Info.Vertex != v2) { D(Printf(PRINT_LOG, "Forced split of seg %d(%d->%d) at %d(%d,%d)\n", seg, Segs[seg].v1, Segs[seg].v2, event->Info.Vertex, Vertices[event->Info.Vertex].x>>16, Vertices[event->Info.Vertex].y>>16)); DWORD newseg = SplitSeg (seg, event->Info.Vertex, 1); Segs[newseg].next = Segs[seg].next; Segs[seg].next = newseg; DWORD partner = Segs[seg].partner; if (partner != DWORD_MAX) { int endpartner = SplitSeg (partner, event->Info.Vertex, 1); Segs[endpartner].next = Segs[partner].next; Segs[partner].next = endpartner; Segs[seg].partner = endpartner; Segs[partner].partner = newseg; } seg = newseg; if (SplitSharers[i].Forward) { event = next; next = Events.GetSuccessor (next); } else { event = next; next = Events.GetPredecessor (next); } } } }
// If there are any segs on the splitter that span more than two events, they // must be split. Alien Vendetta is one example wad that is quite bad about // having overlapping lines. If we skip this step, these segs will still be // split later, but minisegs will erroneously be added for them, and partner // seg information will be messed up in the generated tree. void FNodeBuilder::FixSplitSharers (const node_t &node) { for (unsigned int i = 0; i < SplitSharers.Size(); ++i) { DWORD seg = SplitSharers[i].Seg; int v2 = Segs[seg].v2; FEvent *event = Events.FindEvent (SplitSharers[i].Distance); FEvent *next; if (event == NULL) { // Should not happen continue; } if (SplitSharers[i].Forward) { event = Events.GetSuccessor (event); if (event == NULL) { continue; } next = Events.GetSuccessor (event); } else { event = Events.GetPredecessor (event); if (event == NULL) { continue; } next = Events.GetPredecessor (event); } while (event != NULL && next != NULL && event->Info.Vertex != v2) { D(Printf(PRINT_LOG, "Forced split of seg %d(%d->%d) at %d(%d,%d)\n", seg, Segs[seg].v1, Segs[seg].v2, event->Info.Vertex, Vertices[event->Info.Vertex].x>>16, Vertices[event->Info.Vertex].y>>16)); DWORD newseg = SplitSeg (seg, event->Info.Vertex, 1); Segs[newseg].next = Segs[seg].next; Segs[seg].next = newseg; DWORD partner = Segs[seg].partner; if (partner != DWORD_MAX) { int endpartner = SplitSeg (partner, event->Info.Vertex, 1); Segs[endpartner].next = Segs[partner].next; Segs[partner].next = endpartner; Segs[seg].partner = endpartner; Segs[partner].partner = newseg; } seg = newseg; if (SplitSharers[i].Forward) { event = next; next = Events.GetSuccessor (next); } else { event = next; next = Events.GetPredecessor (next); } } } }