Experimenting...
This commit is contained in:
parent
a63c6e683e
commit
5a13579849
6 changed files with 346 additions and 6833 deletions
6732
Data/sandbox-log.txt
6732
Data/sandbox-log.txt
File diff suppressed because it is too large
Load diff
|
@ -251,7 +251,7 @@ bool clip2tri::triangulateComplex(vector<Point> &outputTriangles, const Path &ou
|
|||
F64(S64(steiner_points->at(j).x * CLIPPER_SCALE_FACT)),
|
||||
F64(S64(steiner_points->at(j).y * CLIPPER_SCALE_FACT)),
|
||||
});
|
||||
cdt->AddPoint(steiners[j]);
|
||||
//cdt->AddPoint(steiners[j]);
|
||||
}
|
||||
}
|
||||
// end: steiner points
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "KP3D_Log.h"
|
||||
|
||||
namespace {
|
||||
const float EPSILON = 0.0001f;
|
||||
const float EPSILON = 1.0f / 128.0f;
|
||||
}
|
||||
|
||||
namespace kp3d {
|
||||
|
@ -50,14 +50,102 @@ std::vector<std::vector<Vec2>> SplitComplexPolygon(std::vector<Vec2> polygon)
|
|||
output.push_back(polygon_excerpt);
|
||||
}
|
||||
|
||||
if (output.size() > 1)
|
||||
{
|
||||
KP3D_LOG_INFO("Split: ");
|
||||
for (int i = 0; i < output.size(); i++)
|
||||
KP3D_LOG_INFO("{} size: {}", i, output[i].size());
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::vector<std::vector<Vec2>> ClipPolygonHoles(std::vector<Vec2> polygon, std::vector<std::vector<Vec2>> holes)
|
||||
{
|
||||
if (holes.empty())
|
||||
{
|
||||
return { polygon };
|
||||
}
|
||||
|
||||
for (std::vector<Vec2>& hole : holes)
|
||||
{
|
||||
polygon.push_back(polygon[0]);
|
||||
for (Vec2 point: hole)
|
||||
polygon.push_back(point);
|
||||
polygon.push_back(hole[0]);
|
||||
}
|
||||
//polygon.push_back(polygon[0]);
|
||||
|
||||
//polygon.erase(std::unique(polygon.begin(), polygon.end()), polygon.end());
|
||||
|
||||
return SplitComplexPolygon(polygon);
|
||||
|
||||
#if 0
|
||||
using namespace Clipper2Lib;
|
||||
|
||||
if (holes.empty())
|
||||
{
|
||||
return {polygon};
|
||||
}
|
||||
if (holes.size() > 1)
|
||||
holes.pop_back();
|
||||
|
||||
//ClipperD c;
|
||||
PathsD solution;
|
||||
|
||||
// PolyPathD tree;
|
||||
PathD complex_polygon;
|
||||
for (const Vec2& v: polygon)
|
||||
{
|
||||
complex_polygon.push_back({v.x, v.y});
|
||||
}
|
||||
// PolyTreeD cp(&tree, complex_polygon);
|
||||
PathsD subjects;
|
||||
subjects.push_back(complex_polygon);
|
||||
PathsD clips;
|
||||
KP3D_LOG_INFO("# holes: {}", holes.size());
|
||||
for (const auto& vl: holes)
|
||||
{
|
||||
PathD clip;
|
||||
for (const Vec2& v : vl) {
|
||||
clip.push_back({ v.x, v.y });
|
||||
//complex_polygon.push_back({v.x, v.y});
|
||||
}
|
||||
clips.push_back(clip);
|
||||
// cp.AddChild(clip);
|
||||
//tree.AddChild(clip);
|
||||
|
||||
}
|
||||
|
||||
// tree.AddChild(complex_polygon); ?
|
||||
//c.AddSubject({complex_polygon});
|
||||
//c.AddSubject(clips);
|
||||
//c.AddClip(clips);
|
||||
//c.AddClip(clips);
|
||||
// PolyTreeD clipper_output;
|
||||
//PathsD clipper_output;
|
||||
//c.Execute(ClipType::Difference, FillRule::NonZero, clipper_output);
|
||||
PathsD clipper_output = Difference(subjects, clips, FillRule::EvenOdd);
|
||||
|
||||
std::vector<std::vector<Vec2>> output;
|
||||
|
||||
for (auto& o: clipper_output)
|
||||
{
|
||||
std::vector<Vec2> polygon_excerpt;
|
||||
for (const auto& point: o)
|
||||
polygon_excerpt.push_back({(float) point.x, (float) point.y});
|
||||
output.push_back(polygon_excerpt);
|
||||
}
|
||||
|
||||
if (output.size() > 0)
|
||||
{
|
||||
KP3D_LOG_INFO("Split ({}):", output.size());
|
||||
for (int i = 0; i < output.size(); i++)
|
||||
KP3D_LOG_INFO("{} size: {}", i, output[i].size());
|
||||
}
|
||||
|
||||
if (output.empty())
|
||||
{
|
||||
return { polygon };
|
||||
}
|
||||
|
||||
return output;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} // namespace kp3d
|
||||
|
|
|
@ -54,5 +54,7 @@ bool PointInLine(XYf point, XYf line_start, XYf line_end);
|
|||
float Distance(XYf a, XYf b);
|
||||
|
||||
std::vector<std::vector<Vec2>> SplitComplexPolygon(std::vector<Vec2> polygon);
|
||||
std::vector<std::vector<Vec2>> ClipPolygonHoles(std::vector<Vec2> polygon, std::vector<std::vector<Vec2>> holes);
|
||||
|
||||
|
||||
} // namespace kp3d
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <clip2tri/clip2tri.h>
|
||||
#include <clipper/clipper.hpp>
|
||||
#include <clipper2/clipper.h>
|
||||
#include <poly2tri/poly2tri.h>
|
||||
|
||||
#include "KP3D_Renderer3D.h"
|
||||
|
@ -13,9 +14,49 @@
|
|||
|
||||
namespace {
|
||||
|
||||
bool SectorContains(const kp3d::Sector& outer, const kp3d::Sector& inner) {
|
||||
|
||||
using namespace Clipper2Lib;
|
||||
using namespace kp3d;
|
||||
|
||||
} // namespace
|
||||
PathD outer_path;
|
||||
for (const Wall& l: outer.walls)
|
||||
outer_path.push_back({l.start.x, l.start.y});
|
||||
|
||||
PathD inner_path;
|
||||
for (const Wall& l: inner.walls)
|
||||
inner_path.push_back({l.start.x, l.start.y});
|
||||
|
||||
|
||||
bool completely_inside = false;
|
||||
bool partially_inside = false;
|
||||
int count = 0;
|
||||
int partial_count = 0;
|
||||
for (auto& p : inner_path)
|
||||
{
|
||||
PointInPolygonResult status = Clipper2Lib::PointInPolygon(p, outer_path);
|
||||
if (status == PointInPolygonResult::IsInside)
|
||||
count++;
|
||||
if (status == PointInPolygonResult::IsOn)
|
||||
partial_count++;
|
||||
}
|
||||
if (count == inner_path.size())
|
||||
completely_inside = true;
|
||||
if (partial_count > 0 && count > 0)
|
||||
partially_inside = true;
|
||||
|
||||
// KP3D_LOG_INFO("COMPLETE: {}, PARTIAL: {} / {}", count, partial_count, child_path.size());
|
||||
if (completely_inside)
|
||||
{
|
||||
|
||||
//s.children.push_back(&s2);
|
||||
//s2.parents.push_back(s.id);
|
||||
}
|
||||
|
||||
return completely_inside || (count > 0 && partial_count < 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace kp3d {
|
||||
|
||||
|
@ -29,13 +70,11 @@ Map::~Map()
|
|||
|
||||
ErrCode Map::LoadFromFile(const std::string& path)
|
||||
{
|
||||
// TODO: ...
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
ErrCode Map::SaveToFile(const std::string& path)
|
||||
{
|
||||
// TODO: ...
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -44,7 +83,7 @@ ErrCode Map::SaveToFile(const std::string& path)
|
|||
*/
|
||||
void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
|
||||
{
|
||||
const float e = 0.001f;
|
||||
const float e = 1.0f / 128.0f;
|
||||
|
||||
if (sector.inverted)
|
||||
invert ^= 1;
|
||||
|
@ -53,53 +92,57 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
|
|||
for (const auto& st: flat.steiner_points)
|
||||
steiner_points.emplace_back(st.x, st.z);
|
||||
|
||||
std::vector<std::vector<c2t::Point>> subsector_polygons; // unused for now
|
||||
|
||||
std::vector<Sector*> secs_inside;
|
||||
for (Sector* sp : sector.children)
|
||||
std::vector<std::vector<c2t::Point>> subsector_polygons;
|
||||
for (Sector* s: sector.children)
|
||||
{
|
||||
std::vector<c2t::Point> ss;
|
||||
Sector& s = *sp;
|
||||
if (!s.children.empty())
|
||||
continue;
|
||||
for (Wall& l : s.walls)
|
||||
float area = 0.0f;
|
||||
for (Wall& l : s->walls)
|
||||
{
|
||||
if (PointInPolygon(sector.walls, l.start))
|
||||
if (s->inverted)
|
||||
{
|
||||
ss.push_back({ l.start.x, l.start.y });
|
||||
}
|
||||
}
|
||||
for (Wall& l : s.walls)
|
||||
{
|
||||
if (s.inverted)
|
||||
{
|
||||
if (!FloatCmp(s.floor.base_height, sector.floor.base_height))
|
||||
s.floor.texture = nullptr;
|
||||
if (!FloatCmp(s.ceiling.base_height, sector.ceiling.base_height))
|
||||
s.ceiling.texture = nullptr;
|
||||
//if (s.ceiling.base_height <= sector.ceiling.base_height + 0.000001f)
|
||||
// s.ceiling.texture = nullptr;
|
||||
continue;
|
||||
if (FloatCmp(s->floor.base_height, sector.floor.base_height, e))
|
||||
s->floor.texture = nullptr;
|
||||
if (FloatCmp(s->ceiling.base_height, sector.ceiling.base_height, e))
|
||||
s->ceiling.texture = nullptr;
|
||||
//continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
l.textures[TEX_FRONT] = nullptr;
|
||||
l.flags = Wall::FLAG_OPENING;
|
||||
l.portal = §or;
|
||||
}
|
||||
ss.push_back({l.start.x, l.start.y});
|
||||
|
||||
area += l.start.x * l.end.y;
|
||||
area -= l.end.x * l.start.y;
|
||||
}
|
||||
|
||||
//if (area > 0)//<= 0.0f)
|
||||
// std::reverse(ss.begin(), ss.end());
|
||||
|
||||
subsector_polygons.push_back(ss);
|
||||
}
|
||||
|
||||
std::vector<c2t::Point> sector_polygons;
|
||||
std::vector<c2t::Point> flat_polygons;
|
||||
for (Wall& l: sector.walls)
|
||||
sector_polygons.emplace_back(l.start.x, l.start.y);
|
||||
flat_polygons.emplace_back(l.start.x, l.start.y);
|
||||
KP3D_LOG_INFO("TRIANGULATING SECTOR: {}", sector.id);
|
||||
//std::vector<std::vector<Vec2>> polygons = ClipPolygonHoles(flat_polygons, subsector_polygons);
|
||||
//for (const std::vector<Vec2>& polygon: polygons)
|
||||
//const auto& polygon = polygons[1 % polygons.size()];
|
||||
{
|
||||
|
||||
//std::vector<c2t::Point> sector_polygons;
|
||||
//for (const Vec2& l: sector.walls)
|
||||
// sector_polygons.push_back({l.x, l.y});
|
||||
|
||||
// Triangulate the sector floors and ceilings and send the result to the mesh. To do this we're using version of the Clipper
|
||||
// library merged with poly2tri, called clip2tri, which I've since modified to support Steiner points.
|
||||
c2t::clip2tri clipper;
|
||||
std::vector<c2t::Point> clipper_out;
|
||||
clipper.triangulate(subsector_polygons, clipper_out, sector_polygons, &steiner_points);
|
||||
clipper.triangulate(subsector_polygons, clipper_out, flat_polygons, &steiner_points);
|
||||
|
||||
const float MAX = 1000000.0f;
|
||||
float min_height = MAX;
|
||||
|
@ -116,7 +159,6 @@ void Map::BuildFlat(Sector& sector, Flat& flat, bool invert)
|
|||
float cu = c.x * 0.5f, cv = c.y * 0.5f;
|
||||
|
||||
// Build mesh data for floor
|
||||
{
|
||||
Vec3 fva = Vec3(a.x, flat.base_height, a.y);
|
||||
Vec3 fvb = Vec3(b.x, flat.base_height, b.y);
|
||||
Vec3 fvc = Vec3(c.x, flat.base_height, c.y);
|
||||
|
@ -166,47 +208,27 @@ void Map::BuildQuad(Sector& sector, Flat& flat_top, Flat& flat_bottom, const Tex
|
|||
if (sector.inverted)
|
||||
flip ^= 1;
|
||||
|
||||
Vec3 p1 = Vec3(pos_a.x, pos_a.y, pos_a.z);
|
||||
Vec3 p2 = Vec3(pos_a.x, pos_b.y, pos_a.z);
|
||||
Vec3 p3 = Vec3(pos_b.x, pos_a.y, pos_b.z);
|
||||
Vec3 p4 = Vec3(pos_b.x, pos_b.y, pos_b.z);
|
||||
|
||||
std::vector<Vec2> points;
|
||||
points.emplace_back(0.0f);
|
||||
for (const Vertex3D& v: flat_bottom.triangulated_data)
|
||||
{
|
||||
if (!PointInLine({v.position.x, v.position.z}, {pos_a.x, pos_a.z}, {pos_b.x, pos_b.z}))
|
||||
continue;
|
||||
|
||||
// Project 3D point into 2D
|
||||
Vec2 mpos = {Distance({v.position.x, v.position.z}, {p1.x, p1.z}), v.position.y};
|
||||
|
||||
// Overwrite the start point if we've landed on it
|
||||
if (FloatCmp(v.position.x, p1.x, 0.0001f) && FloatCmp(v.position.z, p1.z, 0.0001f))
|
||||
points[0] = mpos;
|
||||
|
||||
Vec2 mpos = {Distance({v.position.x, v.position.z}, {pos_a.x, pos_a.z}), v.position.y};
|
||||
points.push_back(mpos);
|
||||
}
|
||||
std::vector<Vec2> top_points;
|
||||
top_points.emplace_back(Distance({ p4.x, p4.z }, { p1.x, p1.z }), p4.y); // This may be re-enabled, BUT
|
||||
for (const Vertex3D& v: flat_top.triangulated_data)
|
||||
{
|
||||
if (!PointInLine({v.position.x, v.position.z}, {pos_a.x, pos_a.z}, {pos_b.x, pos_b.z}))
|
||||
continue;
|
||||
|
||||
// Project 3D point into 2D
|
||||
Vec2 mpos = {Distance({v.position.x, v.position.z}, {p1.x, p1.z}), v.position.y};
|
||||
|
||||
if (FloatCmp(v.position.x, p4.x, 0.0001f) && FloatCmp(v.position.z, p4.z, 0.0001f))
|
||||
top_points[0] = mpos;
|
||||
|
||||
Vec2 mpos = {Distance({v.position.x, v.position.z}, {pos_a.x, pos_a.z}), v.position.y};
|
||||
top_points.push_back(mpos);
|
||||
}
|
||||
std::sort(points.begin() + 1, points.end(), [&](Vec2 a, Vec2 b) { return a.x < b.x; });
|
||||
std::sort(top_points.begin() + 1 , top_points.end(), [&](Vec2 a, Vec2 b) { return a.x > b.x; }); // ^^^^ If you do, add +1 to begin()
|
||||
std::sort(points.begin(), points.end(), [&](Vec2 a, Vec2 b) { return a.x < b.x; });
|
||||
std::sort(top_points.begin(), top_points.end(), [&](Vec2 a, Vec2 b) { return a.x > b.x; });
|
||||
points.insert(points.end(), top_points.begin(), top_points.end());
|
||||
|
||||
float angle = atan2({p4.z - p1.z}, {p4.x - p1.x});
|
||||
float angle = atan2({pos_b.z - pos_a.z}, {pos_b.x - pos_a.x});
|
||||
|
||||
points.erase(unique(points.begin(), points.end()), points.end());
|
||||
|
||||
|
@ -215,53 +237,29 @@ void Map::BuildQuad(Sector& sector, Flat& flat_top, Flat& flat_bottom, const Tex
|
|||
// There's a chance we may have ended up with a complex polygon, which poly2tri isn't able to handle. So our solution is to
|
||||
// break them up.
|
||||
std::vector<std::vector<Vec2>> polygons = SplitComplexPolygon(points);
|
||||
|
||||
|
||||
//auto& polygon = polygons.front();
|
||||
for (const std::vector<Vec2>& polygon: polygons)
|
||||
{
|
||||
std::vector<std::vector<c2t::Point>> holes; // unused for now
|
||||
std::vector<c2t::Point> wall_polygon;
|
||||
for (Vec2 p: polygon)
|
||||
wall_polygon.emplace_back(p.x, p.y);
|
||||
|
||||
c2t::clip2tri clipper;
|
||||
std::vector<c2t::Point> clipper_out;
|
||||
clipper.triangulate(holes, clipper_out, wall_polygon);
|
||||
p2t::CDT cdt();
|
||||
|
||||
clipper.triangulate({}, clipper_out, wall_polygon);
|
||||
for (int i = 0; i < clipper_out.size(); i += 3)
|
||||
{
|
||||
c2t::Point a = clipper_out.at(i + 0);
|
||||
c2t::Point b = clipper_out.at(i + 1);
|
||||
c2t::Point c = clipper_out.at(i + 2);
|
||||
|
||||
// Safety clamp
|
||||
if (a.x < 0) a.x = 0;
|
||||
if (b.x < 0) b.x = 0;
|
||||
if (c.x < 0) c.x = 0;
|
||||
if (a.x > top_points[0].x)
|
||||
a.x = top_points[0].x;
|
||||
if (b.x > top_points[0].x)
|
||||
b.x = top_points[0].x;
|
||||
if (c.x > top_points[0].x)
|
||||
c.x = top_points[0].x;
|
||||
|
||||
//if (flip)
|
||||
// std::swap(b, c);
|
||||
|
||||
float au = a.x * 0.5f, av = a.y * 0.5f;
|
||||
float bu = b.x * 0.5f, bv = b.y * 0.5f;
|
||||
float cu = c.x * 0.5f, cv = c.y * 0.5f;
|
||||
|
||||
// Build mesh data for wall
|
||||
Vec3 fva = Vec3(a.x, a.y, 0.0f).Rotated({ 0, 1, 0 }, -ToDegrees(angle)); fva.x += p1.x; fva.z += p1.z;
|
||||
Vec3 fvb = Vec3(b.x, b.y, 0.0f).Rotated({ 0, 1, 0 }, -ToDegrees(angle)); fvb.x += p1.x; fvb.z += p1.z;
|
||||
Vec3 fvc = Vec3(c.x, c.y, 0.0f).Rotated({ 0, 1, 0 }, -ToDegrees(angle)); fvc.x += p1.x; fvc.z += p1.z;
|
||||
|
||||
bool iba = PointInLine({ fva.x, fva.z }, { pos_a.x, pos_a.z }, { pos_b.x, pos_b.z });
|
||||
bool ibb = PointInLine({ fvb.x, fvb.z }, { pos_a.x, pos_a.z }, { pos_b.x, pos_b.z });
|
||||
bool ibc = PointInLine({ fvc.x, fvc.z }, { pos_a.x, pos_a.z }, { pos_b.x, pos_b.z });
|
||||
Vec3 fva = Vec3(a.x, a.y, 0.0f).Rotated({0, 1, 0}, -ToDegrees(angle)); fva.x += pos_a.x; fva.z += pos_a.z;
|
||||
Vec3 fvb = Vec3(b.x, b.y, 0.0f).Rotated({0, 1, 0}, -ToDegrees(angle)); fvb.x += pos_a.x; fvb.z += pos_a.z;
|
||||
Vec3 fvc = Vec3(c.x, c.y, 0.0f).Rotated({0, 1, 0}, -ToDegrees(angle)); fvc.x += pos_a.x; fvc.z += pos_a.z;
|
||||
|
||||
// Fix up the UVs so they keep the right scale
|
||||
float tw = texture ? texture_scale / texture->GetWidth() : 0.0f;
|
||||
|
@ -281,20 +279,11 @@ void Map::BuildWall(Sector& sector, Wall& wall)
|
|||
Vec3 b = {wall.end.x, 0.0f, wall.end.y};
|
||||
BuildQuad(sector, sector.floor, sector.ceiling, wall.textures[TEX_FRONT], a, b, false, false, false, wall.uv_offset[TEX_FRONT]);
|
||||
|
||||
if (wall.flags & Wall::OPENING)
|
||||
if (wall.flags & Wall::FLAG_OPENING)
|
||||
{
|
||||
Flat& ft = sector.floor;
|
||||
Flat& fb = wall.portal->floor;
|
||||
a.y = ft.base_height;
|
||||
b.y = fb.base_height;
|
||||
|
||||
BuildQuad(sector, ft, fb, wall.textures[TEX_LOWER], a, b, false, false, false, wall.uv_offset[TEX_LOWER]);
|
||||
|
||||
Flat& ct = sector.ceiling;
|
||||
Flat& cb = wall.portal->ceiling;
|
||||
a.y = ct.base_height;
|
||||
b.y = cb.base_height;
|
||||
BuildQuad(sector, ct, cb, wall.textures[TEX_UPPER], a, b, true, false, false, wall.uv_offset[TEX_UPPER]);
|
||||
// Build upper and lower walls for sectors connected to other sectors
|
||||
BuildQuad(sector, sector.floor, wall.portal->floor, wall.textures[TEX_LOWER], a, b, false, false, false, wall.uv_offset[TEX_LOWER]);
|
||||
BuildQuad(sector, sector.ceiling, wall.portal->ceiling, wall.textures[TEX_UPPER], a, b, true, false, false, wall.uv_offset[TEX_UPPER]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,8 +323,8 @@ void Map::JoinSectors(Sector& sector)
|
|||
w1.end.x = l.start.x;
|
||||
w1.end.y = l.start.y;
|
||||
w1.textures[TEX_FRONT] = nullptr;
|
||||
w1.flags = Wall::FLAG_OPENING;
|
||||
w1.portal = &s;
|
||||
w1.flags = Wall::OPENING;
|
||||
Wall w2 = ld;
|
||||
w2.start.x = w1.end.x;
|
||||
w2.start.y = w1.end.y;
|
||||
|
@ -345,10 +334,10 @@ void Map::JoinSectors(Sector& sector)
|
|||
InsertLine(sector.walls, i + 1, w1);
|
||||
InsertLine(sector.walls, i + 2, w2);
|
||||
|
||||
l.textures[TEX_FRONT] = nullptr;
|
||||
// Mark the other one as an opening
|
||||
// This really shouldn't be necessary I think, but whatever
|
||||
l.flags = Wall::OPENING;
|
||||
l.textures[TEX_FRONT] = nullptr;
|
||||
l.flags = Wall::FLAG_OPENING;
|
||||
l.portal = §or;
|
||||
}
|
||||
}
|
||||
|
@ -427,25 +416,79 @@ void Map::Init()
|
|||
//build_sector(&tex3, &tex, &tex2, -1.2f, 3.0f, 5, points5, std::size(points5));
|
||||
build_sector(&tex3, &tex, &tex2, test_u, test_l, 5, points5, std::size(points5), false);
|
||||
|
||||
// Build tree
|
||||
for (Sector& sp: sectors)
|
||||
{
|
||||
// Correct sectors with counter-clockwise linedef order using the shoelace formula,
|
||||
// also while we're at it grab the sector areas (will be useful later) and reset old data.
|
||||
std::unordered_map<int, float> sector_areas;
|
||||
int i = 0;
|
||||
for (Sector& s: sectors)
|
||||
{
|
||||
if (s.id == sp.id)
|
||||
continue;
|
||||
// Since we're regenerating the map, we don't want to re-use this data, it may be old.
|
||||
s.parents.clear();
|
||||
s.flags = Sector::NO_FLAGS;
|
||||
s.parent_id = 0;
|
||||
s.id = ++i;
|
||||
|
||||
// Now perform the swap + save the area
|
||||
float area = 0.0f;
|
||||
|
||||
int cnt = 0;
|
||||
for (Wall& l: s.walls)
|
||||
{
|
||||
if (PointInPolygon(sp.walls, l.start))
|
||||
bool touched = l.flags & Wall::FLAG_TOUCHED;
|
||||
bool no_collisions = l.flags & Wall::FLAG_NO_COLLISION;
|
||||
l.flags = Wall::NO_FLAGS;
|
||||
if (touched)
|
||||
l.flags |= Wall::FLAG_TOUCHED;
|
||||
if (no_collisions)
|
||||
l.flags |= Wall::FLAG_NO_COLLISION;
|
||||
|
||||
area += l.start.x * l.end.y;
|
||||
area -= l.end.x * l.start.y;
|
||||
}
|
||||
|
||||
area *= 0.5f;
|
||||
sector_areas.emplace(s.id, fabsf(area));
|
||||
|
||||
if (area <= 0.0f)
|
||||
{
|
||||
cnt++;
|
||||
std::reverse(s.walls.begin(), s.walls.end());
|
||||
for (Wall& l: s.walls)
|
||||
std::swap(l.start, l.end);
|
||||
}
|
||||
|
||||
s.area = fabsf(area);
|
||||
}
|
||||
|
||||
std::sort(sectors.begin(), sectors.end(), [](const Sector& a, const Sector& b) {
|
||||
return a.area < b.area;
|
||||
});
|
||||
for (auto& sector: sectors) {
|
||||
for (auto& potentialParent: sectors) {
|
||||
if (sector.id == potentialParent.id)
|
||||
continue;
|
||||
if (SectorContains(potentialParent, sector)) {
|
||||
potentialParent.children.push_back(§or);
|
||||
sector.parent_id = potentialParent.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cnt == s.walls.size())
|
||||
sp.children.push_back(&s);
|
||||
}
|
||||
|
||||
|
||||
KP3D_LOG_INFO("SECTOR HIERARCHY");
|
||||
for (Sector& s: sectors)
|
||||
{
|
||||
KP3D_LOG_INFO("Sector {} (area: {})", s.id, s.area);
|
||||
KP3D_LOG_INFO(" Parent: ");
|
||||
KP3D_LOG_INFO(" - {}", s.parent_id ? std::to_string(s.parent_id) : "[NO PARENT]");
|
||||
KP3D_LOG_INFO(" Children: ");
|
||||
for (Sector* c: s.children)
|
||||
{
|
||||
KP3D_LOG_INFO(" - {}", c->id);
|
||||
|
||||
}
|
||||
if (s.children.empty())
|
||||
KP3D_LOG_INFO(" - [NO CHILDREN]");
|
||||
KP3D_LOG_INFO("-----");
|
||||
}
|
||||
|
||||
// Preproc
|
||||
|
@ -456,7 +499,7 @@ void Map::Init()
|
|||
// Build up "steiner points" for terrain only
|
||||
// We'll do this along a grid for now; it should be noted that this will be expected to be part of the sector data later
|
||||
int num_steiners_along_xy = 50;
|
||||
float steiner_size = 1.0f;
|
||||
float steiner_size = 1.1f;
|
||||
for (int i = 0; i < num_steiners_along_xy; i++)
|
||||
{
|
||||
for (int j = 0; j < num_steiners_along_xy; j++)
|
||||
|
@ -489,12 +532,14 @@ void Map::Init()
|
|||
}
|
||||
|
||||
JoinSectors(s);
|
||||
}
|
||||
|
||||
for (Sector& s : sectors)
|
||||
{
|
||||
// Build level geometry
|
||||
BuildFlat(s, s.floor, false);
|
||||
BuildFlat(s, s.ceiling, true);
|
||||
}
|
||||
|
||||
for (Sector& s : sectors)
|
||||
for (Wall& ld : s.walls)
|
||||
BuildWall(s, ld);
|
||||
|
|
|
@ -23,8 +23,10 @@ struct Wall
|
|||
enum Flags: byte
|
||||
{
|
||||
NO_FLAGS,
|
||||
OPENING
|
||||
// ...
|
||||
FLAG_OPENING = 1 << 0,
|
||||
FLAG_DELETE = 1 << 1,
|
||||
FLAG_NO_COLLISION = 1 << 2,
|
||||
FLAG_TOUCHED = 1 << 3
|
||||
};
|
||||
|
||||
const Texture* textures[3];
|
||||
|
@ -54,8 +56,13 @@ struct Sector
|
|||
{
|
||||
enum Flags: byte
|
||||
{
|
||||
NO_FLAGS
|
||||
// ...
|
||||
NO_FLAGS,
|
||||
FLAG_SUBSECTOR = 1 << 0,
|
||||
FLAG_HAS_SUBSECTOR = 1 << 1,
|
||||
FLAG_FLIP_SSECTOR_UL_WALLS = 1 << 2,
|
||||
FLAG_SUBSECTOR_CONNECTED_TO_SOMETHING = 1 << 3,
|
||||
FLAG_SUBSECTOR_EXEMPT = 1 << 4,
|
||||
FLAG_DELETE = 1 << 5
|
||||
};
|
||||
|
||||
uint id;
|
||||
|
@ -74,6 +81,9 @@ struct Sector
|
|||
bool inverted = false;
|
||||
|
||||
std::vector<Sector*> children;
|
||||
std::vector<int> parents;
|
||||
|
||||
float area = 0.0f;
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue