mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-27 20:20:40 +00:00
- added GZDoom's clipper.
This commit is contained in:
parent
a484e39e05
commit
c6f83fa8bd
3 changed files with 562 additions and 0 deletions
|
@ -638,6 +638,8 @@ file( GLOB HEADER_FILES
|
|||
core/music/*.h
|
||||
core/menu/*.h
|
||||
core/input/*.h
|
||||
core/rendering/*.h
|
||||
core/rendering/scene/*.h
|
||||
|
||||
common/audio/sound/thirdparty/*.h
|
||||
common/audio/sound/*.h
|
||||
|
@ -1069,6 +1071,8 @@ set (PCH_SOURCES
|
|||
core/statusbar2.cpp
|
||||
core/gi.cpp
|
||||
|
||||
core/rendering/scene/hw_clipper.cpp
|
||||
|
||||
core/console/c_notifybuffer.cpp
|
||||
core/console/d_event.cpp
|
||||
|
||||
|
@ -1361,6 +1365,8 @@ include_directories(
|
|||
core/dobject
|
||||
core/menu
|
||||
core/input
|
||||
core/rendering
|
||||
core/rendering/scene
|
||||
platform
|
||||
common/audio/sound
|
||||
common/audio/music
|
||||
|
|
397
source/core/rendering/scene/hw_clipper.cpp
Normal file
397
source/core/rendering/scene/hw_clipper.cpp
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
*
|
||||
** gl_clipper.cpp
|
||||
**
|
||||
** Handles visibility checks.
|
||||
** Loosely based on the JDoom clipper.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2003 Tim Stump
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "hw_clipper.h"
|
||||
#include "basics.h"
|
||||
|
||||
unsigned Clipper::starttime;
|
||||
|
||||
Clipper::Clipper()
|
||||
{
|
||||
starttime++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveRange(ClipNode * range)
|
||||
{
|
||||
if (range == cliphead)
|
||||
{
|
||||
cliphead = cliphead->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (range->prev) range->prev->next = range->next;
|
||||
if (range->next) range->next->prev = range->prev;
|
||||
}
|
||||
|
||||
Free(range);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Clear
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::Clear()
|
||||
{
|
||||
ClipNode *node = cliphead;
|
||||
ClipNode *temp;
|
||||
|
||||
blocked = false;
|
||||
while (node != NULL)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
Free(temp);
|
||||
}
|
||||
node = silhouette;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
Free(temp);
|
||||
}
|
||||
|
||||
cliphead = NULL;
|
||||
silhouette = NULL;
|
||||
starttime++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetSilhouette
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::SetSilhouette()
|
||||
{
|
||||
ClipNode *node = cliphead;
|
||||
ClipNode *last = NULL;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
ClipNode *snode = NewRange(node->start, node->end);
|
||||
if (silhouette == NULL) silhouette = snode;
|
||||
snode->prev = last;
|
||||
if (last != NULL) last->next = snode;
|
||||
last = snode;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// IsRangeVisible
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool Clipper::IsRangeVisible(angle_t startAngle, angle_t endAngle)
|
||||
{
|
||||
ClipNode *ci;
|
||||
ci = cliphead;
|
||||
|
||||
if (endAngle==0 && ci && ci->start==0) return false;
|
||||
|
||||
while (ci != NULL && ci->start < endAngle)
|
||||
{
|
||||
if (startAngle >= ci->start && endAngle <= ci->end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ci = ci->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// AddClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::AddClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node, *temp, *prevNode;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else if (node->start<=start && node->end>=end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start <= end)
|
||||
{
|
||||
if (node->end >= start)
|
||||
{
|
||||
// we found the first overlapping node
|
||||
if (node->start > start)
|
||||
{
|
||||
// the new range overlaps with this node's start point
|
||||
node->start = start;
|
||||
}
|
||||
|
||||
if (node->end < end)
|
||||
{
|
||||
node->end = end;
|
||||
}
|
||||
|
||||
ClipNode *node2 = node->next;
|
||||
while (node2 && node2->start <= node->end)
|
||||
{
|
||||
if (node2->end > node->end) node->end = node2->end;
|
||||
ClipNode *delnode = node2;
|
||||
node2 = node2->next;
|
||||
RemoveRange(delnode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
//just add range
|
||||
node = cliphead;
|
||||
prevNode = NULL;
|
||||
temp = NewRange(start, end);
|
||||
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
prevNode = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
temp->next = node;
|
||||
if (node == NULL)
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
if (prevNode) prevNode->next = temp;
|
||||
if (!cliphead) cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node == cliphead)
|
||||
{
|
||||
cliphead->prev = temp;
|
||||
cliphead = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp->prev = prevNode;
|
||||
prevNode->next = temp;
|
||||
node->prev = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = NewRange(start, end);
|
||||
cliphead = temp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveClipRange
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::RemoveClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node;
|
||||
|
||||
if (silhouette)
|
||||
{
|
||||
node = silhouette;
|
||||
while (node != NULL && node->end <= start)
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
if (node != NULL && node->start <= start)
|
||||
{
|
||||
if (node->end >= end) return;
|
||||
start = node->end;
|
||||
node = node->next;
|
||||
}
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
DoRemoveClipRange(start, node->start);
|
||||
start = node->end;
|
||||
node = node->next;
|
||||
}
|
||||
if (start >= end) return;
|
||||
}
|
||||
DoRemoveClipRange(start, end);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// RemoveClipRange worker function
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Clipper::DoRemoveClipRange(angle_t start, angle_t end)
|
||||
{
|
||||
ClipNode *node, *temp;
|
||||
|
||||
if (cliphead)
|
||||
{
|
||||
//check to see if range contains any old ranges
|
||||
node = cliphead;
|
||||
while (node != NULL && node->start < end)
|
||||
{
|
||||
if (node->start >= start && node->end <= end)
|
||||
{
|
||||
temp = node;
|
||||
node = node->next;
|
||||
RemoveRange(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
//check to see if range overlaps a range (or possibly 2)
|
||||
node = cliphead;
|
||||
while (node != NULL)
|
||||
{
|
||||
if (node->start >= start && node->start <= end)
|
||||
{
|
||||
node->start = end;
|
||||
break;
|
||||
}
|
||||
else if (node->end >= start && node->end <= end)
|
||||
{
|
||||
node->end=start;
|
||||
}
|
||||
else if (node->start < start && node->end > end)
|
||||
{
|
||||
temp = NewRange(end, node->end);
|
||||
node->end=start;
|
||||
temp->next=node->next;
|
||||
temp->prev=node;
|
||||
node->next=temp;
|
||||
if (temp->next) temp->next->prev=temp;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t Clipper::AngleToPseudo(angle_t ang)
|
||||
{
|
||||
double vecx = cos(ang * M_PI / ANGLE_180);
|
||||
double vecy = sin(ang * M_PI / ANGLE_180);
|
||||
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2.f - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
||||
// line from p1 to p2. The pseudoangle has the property that the ordering of
|
||||
// points by true angle around p1 and ordering of points by pseudoangle are the
|
||||
// same.
|
||||
//
|
||||
// For clipping exact angles are not needed. Only the ordering matters.
|
||||
// This is about as fast as the fixed point R_PointToAngle2 but without
|
||||
// the precision issues associated with that function.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t Clipper::PointToPseudoAngle(double x, double y)
|
||||
{
|
||||
double vecx = x - viewpoint.X;
|
||||
double vecy = y - viewpoint.Y;
|
||||
|
||||
if (vecx == 0 && vecy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2. - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
159
source/core/rendering/scene/hw_clipper.h
Normal file
159
source/core/rendering/scene/hw_clipper.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
#ifndef __GL_CLIPPER
|
||||
#define __GL_CLIPPER
|
||||
|
||||
#include "xs_Float.h"
|
||||
#include "memarena.h"
|
||||
#include "basics.h"
|
||||
#include "vectors.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
|
||||
DVector2 viewpoint;
|
||||
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 DVector2 &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 DVector2& v1, const DVector2& v2)
|
||||
{
|
||||
angle_t a2 = PointToPseudoAngle(v1.X, v1.Y);
|
||||
angle_t a1 = PointToPseudoAngle(v2.X, v2.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);
|
||||
|
||||
inline angle_t GetClipAngle(const DVector2& v)
|
||||
{
|
||||
return PointToPseudoAngle(v.X, v.Y);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue