2021-03-15 18:05:08 +00:00
|
|
|
#ifndef __GL_CLIPPER
|
|
|
|
#define __GL_CLIPPER
|
|
|
|
|
|
|
|
#include "xs_Float.h"
|
|
|
|
#include "memarena.h"
|
|
|
|
#include "basics.h"
|
|
|
|
#include "vectors.h"
|
2021-03-22 22:40:25 +00:00
|
|
|
#include "binaryangle.h"
|
|
|
|
#include "intvec.h"
|
2021-03-15 18:05:08 +00:00
|
|
|
|
2021-12-12 22:52:56 +00:00
|
|
|
class ClipWindow
|
|
|
|
{
|
|
|
|
FVector2 left, right; // left and right edge of the window in 2D
|
|
|
|
FAngle leftang, rightang; // view angles of the window edges
|
|
|
|
Plane planes[2]; // top and bottom plane of the window
|
|
|
|
|
|
|
|
// The inside is behind the plane defined by p1 - p4, the sides are defined by p0, pn and pn+1 respectively.
|
|
|
|
// p1 is lower left, p2 upper left, p3 upper right and p4 lower right.
|
|
|
|
void build(const FVector3& p0, const FVector3& p1, const FVector3& p2, const FVector3& p3, const FVector3& p4, DAngle la, DAngle ra)
|
|
|
|
{
|
|
|
|
left = p1.XY();
|
|
|
|
right = p4.XY();
|
|
|
|
planes[0].Init(p0, p2, p3); // top plane - must point inside.
|
|
|
|
planes[1].Init(p0, p4, p1); // bottom plane - must point inside.
|
|
|
|
}
|
|
|
|
|
|
|
|
bool polyInWindow(const TArrayView<FVector3>& points)
|
|
|
|
{
|
|
|
|
for (auto& plane : planes)
|
|
|
|
{
|
|
|
|
for (auto& point : points)
|
|
|
|
{
|
|
|
|
if (!plane.PointOnSide(point)) goto nextplane; // Too bad that C++ still has no option to continue an outer loop from here...
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
nextplane:;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-03-15 18:05:08 +00:00
|
|
|
class ClipNode
|
|
|
|
{
|
|
|
|
friend class Clipper;
|
|
|
|
|
|
|
|
ClipNode *prev, *next;
|
2021-04-24 10:08:38 +00:00
|
|
|
int start, end;
|
2021-03-15 18:05:08 +00:00
|
|
|
|
|
|
|
bool operator== (const ClipNode &other)
|
|
|
|
{
|
|
|
|
return other.start == start && other.end == end;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Clipper
|
|
|
|
{
|
|
|
|
FMemArena nodearena;
|
|
|
|
ClipNode * freelist = nullptr;
|
|
|
|
|
|
|
|
ClipNode * clipnodes = nullptr;
|
|
|
|
ClipNode * cliphead = nullptr;
|
2021-03-22 22:40:25 +00:00
|
|
|
vec2_t viewpoint;
|
2021-04-24 10:08:38 +00:00
|
|
|
void RemoveRange(ClipNode* cn);
|
|
|
|
binangle visibleStart, visibleEnd;
|
2021-03-15 18:05:08 +00:00
|
|
|
|
|
|
|
public:
|
2021-04-24 10:08:38 +00:00
|
|
|
bool IsRangeVisible(int startangle, int endangle);
|
|
|
|
void AddClipRange(int startangle, int endangle);
|
|
|
|
void RemoveClipRange(int startangle, int endangle);
|
2021-03-15 18:05:08 +00:00
|
|
|
|
2021-04-24 10:08:38 +00:00
|
|
|
public:
|
2021-03-15 18:05:08 +00:00
|
|
|
|
2021-04-24 10:08:38 +00:00
|
|
|
void Clear(binangle rangestart);
|
2021-03-15 18:05:08 +00:00
|
|
|
|
|
|
|
void Free(ClipNode *node)
|
|
|
|
{
|
|
|
|
node->next = freelist;
|
|
|
|
freelist = node;
|
|
|
|
}
|
|
|
|
|
2021-03-22 22:40:25 +00:00
|
|
|
private:
|
2021-03-15 18:05:08 +00:00
|
|
|
ClipNode * GetNew()
|
|
|
|
{
|
|
|
|
if (freelist)
|
|
|
|
{
|
|
|
|
ClipNode * p = freelist;
|
|
|
|
freelist = p->next;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
else return (ClipNode*)nodearena.Alloc(sizeof(ClipNode));
|
|
|
|
}
|
|
|
|
|
2021-04-24 10:08:38 +00:00
|
|
|
ClipNode * NewRange(int start, int end)
|
2021-03-15 18:05:08 +00:00
|
|
|
{
|
|
|
|
ClipNode * c = GetNew();
|
|
|
|
|
|
|
|
c->start = start;
|
|
|
|
c->end = end;
|
|
|
|
c->next = c->prev = NULL;
|
|
|
|
return c;
|
|
|
|
}
|
2021-03-22 22:40:25 +00:00
|
|
|
|
|
|
|
public:
|
2021-03-15 18:05:08 +00:00
|
|
|
|
2021-03-22 22:40:25 +00:00
|
|
|
void SetViewpoint(const vec2_t &vp)
|
2021-03-15 18:05:08 +00:00
|
|
|
{
|
|
|
|
viewpoint = vp;
|
|
|
|
}
|
|
|
|
|
2021-04-24 10:08:38 +00:00
|
|
|
void SetVisibleRange(angle_t a1, angle_t a2)
|
2021-03-15 18:05:08 +00:00
|
|
|
{
|
2021-04-24 10:08:38 +00:00
|
|
|
if (a2 != 0xffffffff)
|
2021-03-15 18:05:08 +00:00
|
|
|
{
|
2021-04-24 10:08:38 +00:00
|
|
|
visibleStart = bamang(a1 - a2);
|
|
|
|
visibleEnd = bamang(a1 + a2);
|
2021-03-15 18:05:08 +00:00
|
|
|
}
|
2021-04-24 10:08:38 +00:00
|
|
|
else visibleStart = visibleEnd = bamang(0);
|
2021-03-15 18:05:08 +00:00
|
|
|
}
|
|
|
|
|
2021-04-24 10:08:38 +00:00
|
|
|
void RestrictVisibleRange(binangle a1, binangle a2)
|
2021-03-15 18:05:08 +00:00
|
|
|
{
|
2021-04-24 10:08:38 +00:00
|
|
|
if (visibleStart == visibleEnd)
|
2021-03-15 18:05:08 +00:00
|
|
|
{
|
2021-04-24 10:08:38 +00:00
|
|
|
visibleStart = a1;
|
|
|
|
visibleEnd = a2;
|
2021-03-15 18:05:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-24 10:08:38 +00:00
|
|
|
if (a1.asbam() - visibleStart.asbam() < visibleEnd.asbam() - visibleStart.asbam()) visibleStart = a1;
|
|
|
|
if (a2.asbam() - visibleStart.asbam() < visibleEnd.asbam() - visibleStart.asbam()) visibleStart = a2;
|
2021-03-15 18:05:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-23 20:23:49 +00:00
|
|
|
void DumpClipper();
|
2021-03-15 18:05:08 +00:00
|
|
|
|
2021-04-10 08:56:11 +00:00
|
|
|
binangle PointToAngle(const vec2_t& pos)
|
|
|
|
{
|
|
|
|
vec2_t vec = pos - viewpoint;
|
|
|
|
return bvectangbam(vec.x, vec.y);
|
|
|
|
}
|
|
|
|
|
2021-03-15 18:05:08 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|