/* * 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)< 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