mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-27 04:35:52 +01:00
415 lines
9.8 KiB
C++
Executable File
415 lines
9.8 KiB
C++
Executable File
#ifndef SE_INCL_CLIPPING_INL
|
|
#define SE_INCL_CLIPPING_INL
|
|
#ifdef PRAGMA_ONCE
|
|
#pragma once
|
|
#endif
|
|
|
|
/*
|
|
* Line clipping flags
|
|
*/
|
|
#define LCF_REMOVED (0x00L) // the entire edge is invisible
|
|
#define LCF_UNCLIPPED (0x80L) // this point remains unclipped
|
|
#define LCF_NEAR (0x01L) // this point is clipped at near plane
|
|
#define LCF_FAR (0x02L) // this point is clipped at far plane
|
|
#define LCF_LEFT (0x04L) // this point is clipped at left plane
|
|
#define LCF_RIGHT (0x08L) // this point is clipped at right plane
|
|
#define LCF_TOP (0x10L) // this point is clipped at top plane
|
|
#define LCF_BOTTOM (0x20L) // this point is clipped at bottom plane
|
|
|
|
#define LCF_EDGEREMOVED (0x0000L) // used for testing if entire edge is removed
|
|
// shifts used for clip flags for start/end vertex
|
|
#define LCS_VERTEX0 (0)
|
|
#define LCS_VERTEX1 (8)
|
|
// masks used for clip flags for start/end vertex
|
|
#define LCM_VERTEX0 (0x00FFL)
|
|
#define LCM_VERTEX1 (0xFF00L)
|
|
// creating line clip flags for start/end vertex
|
|
#define LCFVERTEX0(lcf) ((lcf)<<LCS_VERTEX0)
|
|
#define LCFVERTEX1(lcf) ((lcf)<<LCS_VERTEX1)
|
|
|
|
// asm shortcuts
|
|
#define O offset
|
|
#define Q qword ptr
|
|
#define D dword ptr
|
|
#define W word ptr
|
|
#define B byte ptr
|
|
|
|
/*
|
|
* Intersecting object (works on edges)
|
|
*/
|
|
class ENGINE_API CIntersector {
|
|
private:
|
|
FLOAT ci_fX0; // relative coordinates of point
|
|
FLOAT ci_fY0;
|
|
INDEX ci_ct;
|
|
public:
|
|
// constructor
|
|
inline CIntersector(FLOAT fX0=0.0f, FLOAT fY0=0.0f)
|
|
: ci_fX0(fX0), ci_fY0(fY0), ci_ct(0) {};
|
|
|
|
inline void Clear(void) { ci_ct = 0;}; // Clears intersection count
|
|
inline void AddEdge( FLOAT fedgx1, FLOAT fedgy1, FLOAT fedgx2, FLOAT fedgy2); // Checks for intersection
|
|
inline BOOL IsIntersecting() { return (ci_ct % 2) != 0; }; // Do we have intersection?
|
|
};
|
|
|
|
// inline functions implementation
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// CIntersector
|
|
/////////////////////////////////////////////////////////////////////
|
|
/*
|
|
* Checks for intersection of edge with +x axis
|
|
*/
|
|
ENGINE_API inline void CIntersector::AddEdge( FLOAT fedgx1, FLOAT fedgy1, FLOAT fedgx2, FLOAT fedgy2)
|
|
{
|
|
// transform edge relative to the origin
|
|
fedgx1-=ci_fX0; fedgy1-=ci_fY0;
|
|
fedgx2-=ci_fX0; fedgy2-=ci_fY0;
|
|
|
|
if( fedgy1 > 0)
|
|
{
|
|
if( fedgy2 > 0) return;
|
|
|
|
if( fedgx1 <= 0)
|
|
{
|
|
if( fedgx2 <= 0) return;
|
|
}
|
|
else if( fedgx2 > 0)
|
|
{
|
|
ci_ct ++;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( fedgy2 <= 0) return;
|
|
|
|
if( fedgx1 <= 0)
|
|
{
|
|
if( fedgx2 <= 0) return;
|
|
}
|
|
else if( fedgx2 > 0)
|
|
{
|
|
ci_ct ++;
|
|
return;
|
|
}
|
|
}
|
|
// here we calculate x coordinate of edge and +x axis intersection point
|
|
FLOAT a, b;
|
|
a = (fedgy2 - fedgy1)/(fedgx2 - fedgx1);
|
|
b = fedgy1 - a*fedgx1;
|
|
if( -b/a < 0) return; // no intersection, intersection coordinate x is left from 0
|
|
ci_ct ++;
|
|
}
|
|
|
|
/* rcg10042001 !!! FIXME */
|
|
#ifdef _MSC_VER
|
|
#define ASMOPT 1
|
|
#endif
|
|
|
|
// how much are the clip planes offset inside frustum
|
|
#define CLIPPLANE_EPSILON (1E-3f)
|
|
|
|
/*
|
|
* Clip a line by a single plane -- helper function.
|
|
*/
|
|
inline BOOL ClipLineByNearPlane(FLOAT3D &v0, FLOAT3D &v1, FLOAT fPlaneDistance,
|
|
ULONG &ulCode0, ULONG &ulCode1, ULONG ulCodeClip)
|
|
{
|
|
#if ASMOPT
|
|
static FLOAT f1=1;
|
|
static FLOAT fDistance0, fDistance1;
|
|
__asm {
|
|
mov esi,D [v0]
|
|
mov edi,D [v1]
|
|
|
|
fld D [fPlaneDistance]
|
|
fchs
|
|
|
|
fld D [esi+ 8]
|
|
fsubr st(0),st(1)
|
|
fld D [edi+ 8]
|
|
fsubp st(2),st(0)
|
|
fstp D [fDistance0]
|
|
fst D [fDistance1]
|
|
|
|
fsubr D [fDistance0]
|
|
fdivr D [f1]
|
|
|
|
cmp D [fDistance0],0
|
|
jg firstFront
|
|
|
|
|
|
;firstBack:
|
|
cmp D [fDistance1],0
|
|
jle falseRet
|
|
|
|
;secondFront:
|
|
mov eax,D [fPlaneDistance]
|
|
mov ebx,D [ulCode0]
|
|
xor eax,80000000h
|
|
mov edx,D [ulCodeClip]
|
|
mov D [esi+ 8],eax
|
|
mov D [ebx],edx
|
|
|
|
fmul D [fDistance0]
|
|
;//st0=fFactor
|
|
fld D [esi+ 0]
|
|
fsub D [edi+ 0]
|
|
fld D [esi+ 4]
|
|
fsub D [edi+ 4]
|
|
;//st0=v0(2)-v1(2), st1=v0(1)-v1(1), st2=fFactor
|
|
fxch st(1)
|
|
fmul st(0),st(2)
|
|
fxch st(1)
|
|
fmulp st(2),st(0)
|
|
;//st0=(v0(1)-v1(1))*fFactor, st1=(v0(2)-v1(2))*fFactor
|
|
fsubr D [esi+ 0]
|
|
fxch st(1)
|
|
fsubr D [esi+ 4]
|
|
fxch st(1)
|
|
fstp D [esi+ 0]
|
|
fst D [esi+ 4]
|
|
jmp trueRet
|
|
|
|
firstFront:
|
|
cmp D [fDistance1],0
|
|
jg trueRet
|
|
|
|
;secondBack:
|
|
mov eax,D [fPlaneDistance]
|
|
mov ebx,D [ulCode1]
|
|
mov edx,D [ulCodeClip]
|
|
xor eax,80000000h
|
|
shl edx,8
|
|
mov D [edi+ 8],eax
|
|
mov D [ebx],edx
|
|
|
|
fmul D [fDistance1]
|
|
;//st0=fFactor
|
|
fld D [esi+ 0]
|
|
fsub D [edi+ 0]
|
|
fld D [esi+ 4]
|
|
fsub D [edi+ 4]
|
|
;//st0=v0(2)-v1(2), st1=v0(1)-v1(1), st2=fFactor
|
|
fxch st(1)
|
|
fmul st(0),st(2)
|
|
fxch st(1)
|
|
fmulp st(2),st(0)
|
|
;//st0=(v0(1)-v1(1))*fFactor, st1=(v0(2)-v1(2))*fFactor
|
|
fsubr D [edi+ 0]
|
|
fxch st(1)
|
|
fsubr D [edi+ 4]
|
|
fxch st(1)
|
|
fstp D [edi+ 0]
|
|
fst D [edi+ 4]
|
|
}
|
|
trueRet:
|
|
_asm fstp st(0)
|
|
return TRUE;
|
|
falseRet:
|
|
_asm fstp st(0)
|
|
return FALSE;
|
|
#else
|
|
// calculate point distances from clip plane
|
|
FLOAT fDistance0 = -fPlaneDistance-v0(3);
|
|
FLOAT fDistance1 = -fPlaneDistance-v1(3);
|
|
if (fDistance0<=0) {
|
|
// if both are back
|
|
if (fDistance1<=0) {
|
|
// no line remains
|
|
return FALSE;
|
|
// if first is back, second front
|
|
} else {
|
|
// clip first
|
|
FLOAT fDivisor = 1.0f/(fDistance0-fDistance1);
|
|
FLOAT fFactor = fDistance0*fDivisor;
|
|
v0(1) = v0(1)-(v0(1)-v1(1))*fFactor;
|
|
v0(2) = v0(2)-(v0(2)-v1(2))*fFactor;
|
|
v0(3) = -fPlaneDistance;
|
|
// mark that first was clipped
|
|
ulCode0 = LCFVERTEX0(ulCodeClip);
|
|
// line remains
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
// if first is front, second back
|
|
if (fDistance1<=0) {
|
|
// clip second
|
|
FLOAT fDivisor = 1.0f/(fDistance0-fDistance1);
|
|
FLOAT fFactor = fDistance1*fDivisor;
|
|
v1(1) = v1(1)-(v0(1)-v1(1))*fFactor;
|
|
v1(2) = v1(2)-(v0(2)-v1(2))*fFactor;
|
|
v1(3) = -fPlaneDistance;
|
|
// mark that second was clipped
|
|
ulCode1 = LCFVERTEX1(ulCodeClip);
|
|
// line remains
|
|
return TRUE;
|
|
// if both are front
|
|
} else {
|
|
// line remains unclipped
|
|
return TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Clip a line by a single plane -- helper function.
|
|
*/
|
|
inline BOOL ClipLineByFarPlane(FLOAT3D &v0, FLOAT3D &v1, FLOAT fPlaneDistance,
|
|
ULONG &ulCode0, ULONG &ulCode1, ULONG ulCodeClip)
|
|
{
|
|
#if ASMOPT
|
|
static FLOAT f1=1;
|
|
static FLOAT fDistance0, fDistance1;
|
|
__asm {
|
|
mov esi,D [v0]
|
|
mov edi,D [v1]
|
|
|
|
fld D [fPlaneDistance]
|
|
fadd D [esi+ 8]
|
|
fld D [fPlaneDistance]
|
|
fadd D [edi+ 8]
|
|
fxch st(1)
|
|
fstp D [fDistance0]
|
|
fst D [fDistance1]
|
|
|
|
fsubr D [fDistance0]
|
|
fdivr D [f1]
|
|
|
|
cmp D [fDistance0],0
|
|
jg firstFront
|
|
|
|
|
|
;firstBack:
|
|
cmp D [fDistance1],0
|
|
jle falseRet
|
|
|
|
;secondFront:
|
|
mov eax,D [fPlaneDistance]
|
|
mov ebx,D [ulCode0]
|
|
xor eax,80000000h
|
|
mov edx,D [ulCodeClip]
|
|
mov D [esi+ 8],eax
|
|
mov D [ebx],edx
|
|
|
|
fmul D [fDistance0]
|
|
;//st0=fFactor
|
|
fld D [esi+ 0]
|
|
fsub D [edi+ 0]
|
|
fld D [esi+ 4]
|
|
fsub D [edi+ 4]
|
|
;//st0=v0(2)-v1(2), st1=v0(1)-v1(1), st2=fFactor
|
|
fxch st(1)
|
|
fmul st(0),st(2)
|
|
fxch st(1)
|
|
fmulp st(2),st(0)
|
|
;//st0=(v0(1)-v1(1))*fFactor, st1=(v0(2)-v1(2))*fFactor
|
|
fsubr D [esi+ 0]
|
|
fxch st(1)
|
|
fsubr D [esi+ 4]
|
|
fxch st(1)
|
|
fstp D [esi+ 0]
|
|
fst D [esi+ 4]
|
|
jmp trueRet
|
|
|
|
firstFront:
|
|
cmp D [fDistance1],0
|
|
jg trueRet
|
|
|
|
;secondBack:
|
|
mov eax,D [fPlaneDistance]
|
|
mov ebx,D [ulCode1]
|
|
mov edx,D [ulCodeClip]
|
|
xor eax,80000000h
|
|
shl edx,8
|
|
mov D [edi+8],eax
|
|
mov D [ebx],edx
|
|
|
|
fmul D [fDistance1]
|
|
;//st0=fFactor
|
|
fld D [esi+ 0]
|
|
fsub D [edi+ 0]
|
|
fld D [esi+ 4]
|
|
fsub D [edi+ 4]
|
|
;//st0=v0(2)-v1(2), st1=v0(1)-v1(1), st2=fFactor
|
|
fxch st(1)
|
|
fmul st(0),st(2)
|
|
fxch st(1)
|
|
fmulp st(2),st(0)
|
|
;//st0=(v0(1)-v1(1))*fFactor, st1=(v0(2)-v1(2))*fFactor
|
|
fsubr D [edi+ 0]
|
|
fxch st(1)
|
|
fsubr D [edi+ 4]
|
|
fxch st(1)
|
|
fstp D [edi+ 0]
|
|
fst D [edi+ 4]
|
|
}
|
|
trueRet:
|
|
_asm fstp st(0)
|
|
return TRUE;
|
|
falseRet:
|
|
_asm fstp st(0)
|
|
return FALSE;
|
|
#else
|
|
// calculate point distances from clip plane
|
|
FLOAT fDistance0 = fPlaneDistance+v0(3);
|
|
FLOAT fDistance1 = fPlaneDistance+v1(3);
|
|
if (fDistance0<=0) {
|
|
// if both are back
|
|
if (fDistance1<=0) {
|
|
// no line remains
|
|
return FALSE;
|
|
// if first is back, second front
|
|
} else {
|
|
// clip first
|
|
FLOAT fDivisor = 1.0f/(fDistance0-fDistance1);
|
|
FLOAT fFactor = fDistance0*fDivisor;
|
|
v0(1) = v0(1)-(v0(1)-v1(1))*fFactor;
|
|
v0(2) = v0(2)-(v0(2)-v1(2))*fFactor;
|
|
v0(3) = -fPlaneDistance;
|
|
// mark that first was clipped
|
|
ulCode0 = LCFVERTEX0(ulCodeClip);
|
|
// line remains
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
// if first is front, second back
|
|
if (fDistance1<=0) {
|
|
// clip second
|
|
FLOAT fDivisor = 1.0f/(fDistance0-fDistance1);
|
|
FLOAT fFactor = fDistance1*fDivisor;
|
|
v1(1) = v1(1)-(v0(1)-v1(1))*fFactor;
|
|
v1(2) = v1(2)-(v0(2)-v1(2))*fFactor;
|
|
v1(3) = -fPlaneDistance;
|
|
// mark that second was clipped
|
|
ulCode1 = LCFVERTEX1(ulCodeClip);
|
|
// line remains
|
|
return TRUE;
|
|
// if both are front
|
|
} else {
|
|
// line remains unclipped
|
|
return TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static inline void MakeClipPlane(const FLOAT3D &vN, FLOAT fD, FLOATplane3D &pl)
|
|
{
|
|
FLOAT fOoL = 1.0f/vN.Length();
|
|
pl = FLOATplane3D(vN*fOoL, fD*fOoL);
|
|
}
|
|
|
|
#undef ASMOPT
|
|
|
|
#undef O
|
|
#undef Q
|
|
#undef D
|
|
#undef W
|
|
#undef B
|
|
|
|
#endif /* include-once blocker. */
|
|
|