qzdoom/src/hwrenderer/scene/hw_clipper.h
Christoph Oelckers 74d8c929cc Give the clipper a reference to the current viewpoint
This is both for efficiency and encapsulation. At last on MSVC in 64 bit, accessing global variables is very inefficient and the clipper was doing it repeatedly in its worker functions.

It is also one less place where the global viewpoint gets checked.
2018-06-19 09:37:49 +02:00

162 lines
3.3 KiB
C++

#ifndef __GL_CLIPPER
#define __GL_CLIPPER
#include "doomtype.h"
#include "xs_Float.h"
#include "r_utility.h"
#include "memarena.h"
class ClipNode
{
friend class Clipper;
ClipNode *prev, *next;
angle_t start, end;
bool operator== (const ClipNode &other)
{
return other.start == start && other.end == end;
}
};
class Clipper
{
static unsigned starttime;
FMemArena nodearena;
ClipNode * freelist = nullptr;
ClipNode * clipnodes = nullptr;
ClipNode * cliphead = nullptr;
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
const FRenderViewpoint *viewpoint = nullptr;
bool blocked = false;
static angle_t AngleToPseudo(angle_t ang);
bool IsRangeVisible(angle_t startangle, angle_t endangle);
void RemoveRange(ClipNode * cn);
void AddClipRange(angle_t startangle, angle_t endangle);
void RemoveClipRange(angle_t startangle, angle_t endangle);
void DoRemoveClipRange(angle_t start, angle_t end);
public:
Clipper();
void Clear();
void Free(ClipNode *node)
{
node->next = freelist;
freelist = node;
}
ClipNode * GetNew()
{
if (freelist)
{
ClipNode * p = freelist;
freelist = p->next;
return p;
}
else return (ClipNode*)nodearena.Alloc(sizeof(ClipNode));
}
ClipNode * NewRange(angle_t start, angle_t end)
{
ClipNode * c = GetNew();
c->start = start;
c->end = end;
c->next = c->prev = NULL;
return c;
}
void SetViewpoint(const FRenderViewpoint &vp)
{
viewpoint = &vp;
}
void SetSilhouette();
bool SafeCheckRange(angle_t startAngle, angle_t endAngle)
{
if(startAngle > endAngle)
{
return (IsRangeVisible(startAngle, ANGLE_MAX) || IsRangeVisible(0, endAngle));
}
return IsRangeVisible(startAngle, endAngle);
}
void SafeAddClipRange(angle_t startangle, angle_t endangle)
{
if(startangle > endangle)
{
// The range has to added in two parts.
AddClipRange(startangle, ANGLE_MAX);
AddClipRange(0, endangle);
}
else
{
// Add the range as usual.
AddClipRange(startangle, endangle);
}
}
void SafeAddClipRange(const vertex_t *v1, const vertex_t *v2)
{
angle_t a2 = PointToPseudoAngle(v1->p.X, v1->p.Y);
angle_t a1 = PointToPseudoAngle(v2->p.X, v2->p.Y);
SafeAddClipRange(a1,a2);
}
void SafeAddClipRangeRealAngles(angle_t startangle, angle_t endangle)
{
SafeAddClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
}
void SafeRemoveClipRange(angle_t startangle, angle_t endangle)
{
if(startangle > endangle)
{
// The range has to added in two parts.
RemoveClipRange(startangle, ANGLE_MAX);
RemoveClipRange(0, endangle);
}
else
{
// Add the range as usual.
RemoveClipRange(startangle, endangle);
}
}
void SafeRemoveClipRangeRealAngles(angle_t startangle, angle_t endangle)
{
SafeRemoveClipRange(AngleToPseudo(startangle), AngleToPseudo(endangle));
}
void SetBlocked(bool on)
{
blocked = on;
}
bool IsBlocked() const
{
return blocked;
}
angle_t PointToPseudoAngle(double x, double y);
bool CheckBox(const float *bspcoord);
// Used to speed up angle calculations during clipping
inline angle_t GetClipAngle(vertex_t *v)
{
return unsigned(v->angletime) == starttime ? v->viewangle : (v->angletime = starttime, v->viewangle = PointToPseudoAngle(v->p.X, v->p.Y));
}
};
#endif