int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts) { FPrivSeg *seg, *prev; angle_t prevAngle; double accumx, accumy; fixed_t midx, midy; int firstVert; DWORD first, max, count, i, j; first = Subsectors[subsector].firstline; max = first + Subsectors[subsector].numlines; count = 0; accumx = accumy = 0.0; for (i = first; i < max; ++i) { seg = &Segs[SegList[i].SegNum]; accumx += double(Vertices[seg->v1].x) + double(Vertices[seg->v2].x); accumy += double(Vertices[seg->v1].y) + double(Vertices[seg->v2].y); } midx = fixed_t(accumx / (max - first) / 2); midy = fixed_t(accumy / (max - first) / 2); seg = &Segs[SegList[first].SegNum]; prevAngle = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); seg->storedseg = PushGLSeg (segs, seg, outVerts); count = 1; prev = seg; firstVert = seg->v1; for (i = first + 1; i < max; ++i) { angle_t bestdiff = ANGLE_MAX; FPrivSeg *bestseg = NULL; DWORD bestj = DWORD_MAX; j = first; do { seg = &Segs[SegList[j].SegNum]; angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); angle_t diff = prevAngle - ang; if (seg->v1 == prev->v2) { bestdiff = diff; bestseg = seg; bestj = j; break; } if (diff < bestdiff && diff > 0) { bestdiff = diff; bestseg = seg; bestj = j; } } while (++j < max); // Is a NULL bestseg actually okay? if (bestseg != NULL) { seg = bestseg; } if (prev->v2 != seg->v1) { // Add a new miniseg to connect the two segs PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[seg->v1]); count++; } prevAngle -= bestdiff; seg->storedseg = PushGLSeg (segs, seg, outVerts); count++; prev = seg; if (seg->v2 == firstVert) { prev = seg; break; } } if (prev->v2 != firstVert) { PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[firstVert]); count++; } return count; }
int FNodeBuilder::CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts) { FPrivSeg *seg, *prev; angle_t prevAngle; double accumx, accumy; fixed_t midx, midy; int firstVert; uint32_t first, max, count, i, j; bool diffplanes; int firstplane; first = (uint32_t)(size_t)Subsectors[subsector].firstline; max = first + Subsectors[subsector].numlines; count = 0; accumx = accumy = 0.0; diffplanes = false; firstplane = Segs[SegList[first].SegNum].planenum; // Calculate the midpoint of the subsector and also check for degenerate subsectors. // A subsector is degenerate if it exists in only one dimension, which can be // detected when all the segs lie in the same plane. This can happen if you have // outward-facing lines in the void that don't point toward any sector. (Some of the // polyobjects in Hexen are constructed like this.) for (i = first; i < max; ++i) { seg = &Segs[SegList[i].SegNum]; accumx += double(Vertices[seg->v1].x) + double(Vertices[seg->v2].x); accumy += double(Vertices[seg->v1].y) + double(Vertices[seg->v2].y); if (firstplane != seg->planenum) { diffplanes = true; } } midx = fixed_t(accumx / (max - first) / 2); midy = fixed_t(accumy / (max - first) / 2); seg = &Segs[SegList[first].SegNum]; prevAngle = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); seg->storedseg = PushGLSeg (segs, seg, outVerts); count = 1; prev = seg; firstVert = seg->v1; #ifdef DD Printf(PRINT_LOG, "--%d--\n", subsector); for (j = first; j < max; ++j) { seg = &Segs[SegList[j].SegNum]; angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); Printf(PRINT_LOG, "%d%c %5d(%5d,%5d)->%5d(%5d,%5d) - %3.5f %d,%d [%08x,%08x]-[%08x,%08x]\n", j, seg->linedef == -1 ? '+' : ':', seg->v1, Vertices[seg->v1].x>>16, Vertices[seg->v1].y>>16, seg->v2, Vertices[seg->v2].x>>16, Vertices[seg->v2].y>>16, double(ang/2)*180/(1<<30), seg->planenum, seg->planefront, Vertices[seg->v1].x, Vertices[seg->v1].y, Vertices[seg->v2].x, Vertices[seg->v2].y); } #endif if (diffplanes) { // A well-behaved subsector. Output the segs sorted by the angle formed by connecting // the subsector's center to their first vertex. D(Printf(PRINT_LOG, "Well behaved subsector\n")); for (i = first + 1; i < max; ++i) { angle_t bestdiff = ANGLE_MAX; FPrivSeg *bestseg = NULL; uint32_t bestj = DWORD_MAX; j = first; do { seg = &Segs[SegList[j].SegNum]; angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); angle_t diff = prevAngle - ang; if (seg->v1 == prev->v2) { bestdiff = diff; bestseg = seg; bestj = j; break; } if (diff < bestdiff && diff > 0) { bestdiff = diff; bestseg = seg; bestj = j; } } while (++j < max); // Is a NULL bestseg actually okay? if (bestseg != NULL) { seg = bestseg; } if (prev->v2 != seg->v1) { // Add a new miniseg to connect the two segs PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[seg->v1]); count++; } #ifdef DD Printf(PRINT_LOG, "+%d\n", bestj); #endif prevAngle -= bestdiff; seg->storedseg = PushGLSeg (segs, seg, outVerts); count++; prev = seg; if (seg->v2 == firstVert) { prev = seg; break; } } #ifdef DD Printf(PRINT_LOG, "\n"); #endif } else { // A degenerate subsector. These are handled in three stages: // Stage 1. Proceed in the same direction as the start seg until we // hit the seg furthest from it. // Stage 2. Reverse direction and proceed until we hit the seg // furthest from the start seg. // Stage 3. Reverse direction again and insert segs until we get // to the start seg. // A dot product serves to determine distance from the start seg. D(Printf(PRINT_LOG, "degenerate subsector\n")); // Stage 1. Go forward. count += OutputDegenerateSubsector (segs, subsector, true, 0, prev, outVerts); // Stage 2. Go backward. count += OutputDegenerateSubsector (segs, subsector, false, DBL_MAX, prev, outVerts); // Stage 3. Go forward again. count += OutputDegenerateSubsector (segs, subsector, true, -DBL_MAX, prev, outVerts); } if (prev->v2 != firstVert) { PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[firstVert]); count++; } #ifdef DD Printf(PRINT_LOG, "Output GL subsector %d:\n", subsector); for (i = segs.Size() - count; i < (int)segs.Size(); ++i) { Printf(PRINT_LOG, " Seg %5d%c(%5d,%5d)-(%5d,%5d) [%08x,%08x]-[%08x,%08x]\n", i, segs[i].linedef == NULL ? '+' : ' ', segs[i].v1->fixX()>>16, segs[i].v1->fixY()>>16, segs[i].v2->fixX()>>16, segs[i].v2->fixY()>>16, segs[i].v1->fixX(), segs[i].v1->fixY(), segs[i].v2->fixX(), segs[i].v2->fixY()); } #endif return count; }
int FNodeBuilder::OutputDegenerateSubsector (TArray<glseg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts) { static const double bestinit[2] = { -DBL_MAX, DBL_MAX }; FPrivSeg *seg; int i, j, first, max, count; double dot, x1, y1, dx, dy, dx2, dy2; bool wantside; first = (uint32_t)(size_t)Subsectors[subsector].firstline; max = first + Subsectors[subsector].numlines; count = 0; seg = &Segs[SegList[first].SegNum]; x1 = Vertices[seg->v1].x; y1 = Vertices[seg->v1].y; dx = Vertices[seg->v2].x - x1; dy = Vertices[seg->v2].y - y1; wantside = seg->planefront ^ !bForward; for (i = first + 1; i < max; ++i) { double bestdot = bestinit[bForward]; FPrivSeg *bestseg = NULL; for (j = first + 1; j < max; ++j) { seg = &Segs[SegList[j].SegNum]; if (seg->planefront != wantside) { continue; } dx2 = Vertices[seg->v1].x - x1; dy2 = Vertices[seg->v1].y - y1; dot = dx*dx2 + dy*dy2; if (bForward) { if (dot < bestdot && dot > lastdot) { bestdot = dot; bestseg = seg; } } else { if (dot > bestdot && dot < lastdot) { bestdot = dot; bestseg = seg; } } } if (bestseg != NULL) { if (prev->v2 != bestseg->v1) { PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[bestseg->v1]); count++; } seg->storedseg = PushGLSeg (segs, bestseg, outVerts); count++; prev = bestseg; lastdot = bestdot; } } return count; }
int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts) { FPrivSeg *seg, *prev; angle_t prevAngle; double accumx, accumy; fixed_t midx, midy; int firstVert; DWORD first, max, count, i, j; bool diffplanes; int firstplane; first = Subsectors[subsector].firstline; max = first + Subsectors[subsector].numlines; count = 0; accumx = accumy = 0.0; diffplanes = false; firstplane = Segs[SegList[first].SegNum].planenum; // Calculate the midpoint of the subsector and also check for degenerate subsectors. // A subsector is degenerate if it exists in only one dimension, which can be // detected when all the segs lie in the same plane. This can happen if you have // outward-facing lines in the void that don't point toward any sector. (Some of the // polyobjects in Hexen are constructed like this.) for (i = first; i < max; ++i) { seg = &Segs[SegList[i].SegNum]; accumx += double(Vertices[seg->v1].x) + double(Vertices[seg->v2].x); accumy += double(Vertices[seg->v1].y) + double(Vertices[seg->v2].y); if (firstplane != seg->planenum) { diffplanes = true; } } midx = fixed_t(accumx / (max - first) / 2); midy = fixed_t(accumy / (max - first) / 2); seg = &Segs[SegList[first].SegNum]; prevAngle = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); seg->storedseg = PushGLSeg (segs, seg, outVerts); count = 1; prev = seg; firstVert = seg->v1; if (diffplanes) { // A well-behaved subsector. Output the segs sorted by the angle formed by connecting // the subsector's center to their first vertex. for (i = first + 1; i < max; ++i) { angle_t bestdiff = ANGLE_MAX; FPrivSeg *bestseg = NULL; DWORD bestj = DWORD_MAX; j = first; do { seg = &Segs[SegList[j].SegNum]; angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy); angle_t diff = prevAngle - ang; if (seg->v1 == prev->v2) { bestdiff = diff; bestseg = seg; bestj = j; break; } if (diff < bestdiff && diff > 0) { bestdiff = diff; bestseg = seg; bestj = j; } } while (++j < max); // Is a NULL bestseg actually okay? if (bestseg != NULL) { seg = bestseg; } if (prev->v2 != seg->v1) { // Add a new miniseg to connect the two segs PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[seg->v1]); count++; } prevAngle -= bestdiff; seg->storedseg = PushGLSeg (segs, seg, outVerts); count++; prev = seg; if (seg->v2 == firstVert) { prev = seg; break; } } } else { // A degenerate subsector. These are handled in three stages: // Stage 1. Proceed in the same direction as the start seg until we // hit the seg furthest from it. // Stage 2. Reverse direction and proceed until we hit the seg // furthest from the start seg. // Stage 3. Reverse direction again and insert segs until we get // to the start seg. // A dot product serves to determine distance from the start seg. // Stage 1. Go forward. count += OutputDegenerateSubsector (segs, subsector, true, 0, prev, outVerts); // Stage 2. Go backward. count += OutputDegenerateSubsector (segs, subsector, false, DBL_MAX, prev, outVerts); // Stage 3. Go forward again. count += OutputDegenerateSubsector (segs, subsector, true, -DBL_MAX, prev, outVerts); } if (prev->v2 != firstVert) { PushConnectingGLSeg (subsector, segs, &outVerts[prev->v2], &outVerts[firstVert]); count++; } return count; }