123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- /////////////////////////////////////////////////////////////////////
- // Clipping functions
- // check if a polygon is to be visible
- __forceinline ULONG CRenderer::GetPolygonVisibility(const CBrushPolygon &bpo)
- {
- // get transformed polygon's plane
- CWorkingPlane *pwplPolygonPlane = bpo.bpo_pbplPlane->bpl_pwplWorking;
- CWorkingPlane wplReverse;
- BOOL bInvertPolygon = FALSE;
- // if the polygon should be inverted or double sided
- if((re_bRenderingShadows
- &&!re_bDirectionalShadows
- &&re_ubLightIllumination!=0
- &&bpo.bpo_bppProperties.bpp_ubIlluminationType==re_ubLightIllumination)
- || (re_pbrCurrent->br_pfsFieldSettings!=NULL && !pwplPolygonPlane->wpl_bVisible)
- ) {
- bInvertPolygon = TRUE;
- }
- if (bInvertPolygon) {
- // make temporary inverted polygon plane
- pwplPolygonPlane = &wplReverse;
- pwplPolygonPlane->wpl_plView = -bpo.bpo_pbplPlane->bpl_pwplWorking->wpl_plView;
- pwplPolygonPlane->wpl_bVisible =
- re_pbrCurrent->br_prProjection->IsViewerPlaneVisible(pwplPolygonPlane->wpl_plView);
- }
- // if the poly is double-sided and detail
- if( !re_bRenderingShadows && (bpo.bpo_ulFlags&BPOF_DOUBLESIDED) && (bpo.bpo_ulFlags&BPOF_DETAILPOLYGON)) {
- // it's definately visible
- return PDF_POLYGONVISIBLE;
- }
- // if the plane is invisible
- if (!pwplPolygonPlane->wpl_bVisible) {
- // polygon is invisible
- return 0;
- }
- // if the polygon is invisible
- if ((bpo.bpo_ulFlags&BPOF_INVISIBLE)
- ||(re_bRenderingShadows && (bpo.bpo_ulFlags&BPOF_DOESNOTCASTSHADOW))) {
- // skip it
- return 0;
- }
- ULONG ulDirection = PDF_POLYGONVISIBLE;
- BOOL bProjectionInverted = re_prProjection->pr_bInverted;
- if (bProjectionInverted && !bInvertPolygon) {
- ulDirection |= PDF_FLIPEDGESPRE;
- } else if (!bProjectionInverted && bInvertPolygon){
- ulDirection |= PDF_FLIPEDGESPOST;
- }
- // else, polygon is visible
- return ulDirection;
- }
- // check if polygon is outside viewfrustum
- __forceinline BOOL CRenderer::IsPolygonCulled(const CBrushPolygon &bpo)
- {
- CBrushSector &bsc = *bpo.bpo_pbscSector;
- // setup initial mask
- ULONG ulMask = 0xFFFFFFFF;
- // for each vertex
- INDEX ctVtx = bpo.bpo_apbvxTriangleVertices.Count();
- {for(INDEX i=0; i<ctVtx; i++) {
- CBrushVertex *pbvx = bpo.bpo_apbvxTriangleVertices[i];
- INDEX ivx = bsc.bsc_abvxVertices.Index(pbvx);
- // get the outcodes for that vertex
- ULONG ulCode = re_avvxViewVertices[bsc.bsc_ivvx0+ivx].vvx_ulOutcode;
- // and them to the mask
- ulMask &= ulCode;
- }}
- // if any bit in the mask is still set, it means that all points are out
- // wtr to that plane
- return ulMask;
- }
- // find which portals should be rendered as portals or as pretenders
- void CRenderer::FindPretenders(void)
- {
- re_pbscCurrent->bsc_ispo0 = re_aspoScreenPolygons.Count();
- // for all polygons in sector
- FOREACHINSTATICARRAY(re_pbscCurrent->bsc_abpoPolygons, CBrushPolygon, itpo) {
- CBrushPolygon &bpo = *itpo;
- // initially not rendered as portal
- bpo.bpo_ulFlags&=~BPOF_RENDERASPORTAL;
- // if it is portal,
- if (bpo.bpo_ulFlags&BPOF_PORTAL) {
- // initially rendered as portal
- bpo.bpo_ulFlags|=BPOF_RENDERASPORTAL;
- // if could be a pretender
- if (bpo.bpo_bppProperties.bpp_uwPretenderDistance!=0) {
- // get distance at which it is a pretender
- FLOAT fPretenderDistance = bpo.bpo_bppProperties.bpp_uwPretenderDistance;
- // for each vertex in the polygon
- INDEX ctVtx = bpo.bpo_apbvxTriangleVertices.Count();
- CBrushSector &bsc = *bpo.bpo_pbscSector;
- {for(INDEX i=0; i<ctVtx; i++) {
- CBrushVertex *pbvx = bpo.bpo_apbvxTriangleVertices[i];
- INDEX ivx = bsc.bsc_abvxVertices.Index(pbvx);
- // get distance of the vertex from the view plane
- FLOAT fx = re_avvxViewVertices[bsc.bsc_ivvx0+ivx].vvx_vView(1);
- FLOAT fy = re_avvxViewVertices[bsc.bsc_ivvx0+ivx].vvx_vView(2);
- FLOAT fz = re_avvxViewVertices[bsc.bsc_ivvx0+ivx].vvx_vView(3);
- FLOAT fD = fx*fx+fy*fy+fz*fz;
- // if nearer than allowed pretender distance
- if (fD<fPretenderDistance*fPretenderDistance) {
- // this polygon is not a pretender
- goto nextpolygon;
- }
- }}
- // if all vertices passed the check, mark as pretender
- bpo.bpo_ulFlags&=~BPOF_RENDERASPORTAL;
- }
- }
- nextpolygon:;
- }
- }
- // make screen polygons for nondetail polygons in current sector
- void CRenderer::MakeNonDetailScreenPolygons(void)
- {
- _pfRenderProfile.StartTimer(CRenderProfile::PTI_MAKENONDETAILSCREENPOLYGONS);
- re_pbscCurrent->bsc_ispo0 = re_aspoScreenPolygons.Count();
- // detail polygons are not skipped if rendering shadows
- const ULONG ulDetailMask = re_bRenderingShadows ? 0 : BPOF_DETAILPOLYGON;
- // for all polygons in sector
- FOREACHINSTATICARRAY(re_pbscCurrent->bsc_abpoPolygons, CBrushPolygon, itpo) {
- CBrushPolygon &bpo = *itpo;
- // if polygon does not contribute to the visibility determination
- if ( (bpo.bpo_ulFlags&ulDetailMask)
- &&!(bpo.bpo_ulFlags&BPOF_RENDERASPORTAL)) {
- // skip it
- continue;
- }
- // no screen polygon by default
- bpo.bpo_pspoScreenPolygon = NULL;
- // skip if the polygon is not visible
- ASSERT( !IsPolygonCulled(bpo)); // cannot be culled yet!
- const ULONG ulVisible = GetPolygonVisibility(bpo);
- if( ulVisible==0) continue;
- _sfStats.IncrementCounter(CStatForm::SCI_POLYGONS);
- _pfRenderProfile.IncrementCounter(CRenderProfile::PCI_NONDETAILPOLYGONS);
- // make screen polygon for the polygon
- CScreenPolygon &spo = *MakeScreenPolygon(bpo);
- // add its edges
- MakeInitialPolygonEdges(bpo, spo, ulVisible);
- }
- // remember number of polygons in sector
- re_pbscCurrent->bsc_ctspo = re_aspoScreenPolygons.Count()-re_pbscCurrent->bsc_ispo0;
- _pfRenderProfile.StopTimer(CRenderProfile::PTI_MAKENONDETAILSCREENPOLYGONS);
- }
- // make screen polygons for detail polygons in current sector
- void CRenderer::MakeDetailScreenPolygons(void)
- {
- // if rendering shadows or not rendering detail polygons
- if (re_bRenderingShadows
- ||!wld_bRenderDetailPolygons) {
- // do nothing
- return;
- }
- _pfRenderProfile.StartTimer(CRenderProfile::PTI_MAKEDETAILSCREENPOLYGONS);
- // for all polygons in sector
- FOREACHINSTATICARRAY(re_pbscCurrent->bsc_abpoPolygons, CBrushPolygon, itpo) {
- CBrushPolygon &bpo = *itpo;
- // if polygon is not detail
- if (!(bpo.bpo_ulFlags&BPOF_DETAILPOLYGON)
- || (bpo.bpo_ulFlags&BPOF_RENDERASPORTAL)) {
- // skip it
- continue;
- }
- // no screen polygon by default
- bpo.bpo_pspoScreenPolygon = NULL;
- // skip if the polygon is not visible
- if( GetPolygonVisibility(bpo)==0) continue;
- // skip if outside the frustum
- if( (re_pbscCurrent->bsc_ulFlags&BSCF_NEEDSCLIPPING) && IsPolygonCulled(bpo)) continue;
- _sfStats.IncrementCounter(CStatForm::SCI_DETAILPOLYGONS);
- _pfRenderProfile.IncrementCounter(CRenderProfile::PCI_DETAILPOLYGONS);
- // make screen polygon for the polygon
- CScreenPolygon &spo = *MakeScreenPolygon(bpo);
- // if it is portal
- if (spo.IsPortal()) {
- // pass it immediately
- PassPortal(spo);
- } else {
- // add polygon to scene polygons for rendering
- AddPolygonToScene(&spo);
- }
- }
- _pfRenderProfile.StopTimer(CRenderProfile::PTI_MAKEDETAILSCREENPOLYGONS);
- }
- // make initial edges for a polygon
- void CRenderer::MakeInitialPolygonEdges(CBrushPolygon &bpo, CScreenPolygon &spo, BOOL ulDirection)
- {
- // get number of edges
- INDEX ctEdges = bpo.bpo_abpePolygonEdges.Count();
- spo.spo_ubDirectionFlags = ulDirection&PDF_FLIPEDGESPOST;
- BOOL bInvert = (ulDirection&PDF_FLIPEDGESPRE)!=0;
-
- // remember edge vertex start and count
- spo.spo_ctEdgeVx = ctEdges*2;
- spo.spo_iEdgeVx0 = re_aiEdgeVxClipSrc.Count();
- // create edge vertices
- INDEX *ai = re_aiEdgeVxClipSrc.Push(ctEdges*2);
- // for each edge
- for (INDEX iEdge=0; iEdge<ctEdges; iEdge++) {
- // set the two vertices
- CBrushPolygonEdge &bpe = bpo.bpo_abpePolygonEdges[iEdge];
- CWorkingEdge &wed = *bpe.bpe_pbedEdge->bed_pwedWorking;
- if (bpe.bpe_bReverse^bInvert) {
- ai[iEdge*2+0] = wed.wed_iwvx1+re_iViewVx0;
- ai[iEdge*2+1] = wed.wed_iwvx0+re_iViewVx0;
- } else {
- ai[iEdge*2+0] = wed.wed_iwvx0+re_iViewVx0;
- ai[iEdge*2+1] = wed.wed_iwvx1+re_iViewVx0;
- }
- }
- }
- // make final edges for all polygons in current sector
- void CRenderer::MakeFinalPolygonEdges(void)
- {
- _pfRenderProfile.StartTimer(CRenderProfile::PTI_MAKEFINALPOLYGONEDGES);
- // for each polygon
- INDEX ispo0 = re_pbscCurrent->bsc_ispo0;
- INDEX ispoTop = re_pbscCurrent->bsc_ispo0+re_pbscCurrent->bsc_ctspo;
- for(INDEX ispo = ispo0; ispo<ispoTop; ispo++) {
- CScreenPolygon &spo = re_aspoScreenPolygons[ispo];
- // if polygon has no edges
- if (spo.spo_ctEdgeVx==0) {
- // skip it
- continue;
- }
- INDEX iEdgeVx0New = re_aiEdgeVxMain.Count();
- INDEX *piVertices = re_aiEdgeVxMain.Push(spo.spo_ctEdgeVx);
- // for each vertex
- INDEX ivxTop = spo.spo_iEdgeVx0+spo.spo_ctEdgeVx;
- for(INDEX ivx=spo.spo_iEdgeVx0; ivx<ivxTop; ivx++) {
- // copy to final array
- *piVertices++ = re_aiEdgeVxClipSrc[ivx];
- }
- // remember new edge vertex positions
- spo.spo_iEdgeVx0 = iEdgeVx0New;
- }
- // clear temporary arrays
- re_aiEdgeVxClipSrc.PopAll();
- re_aiEdgeVxClipDst.PopAll();
- _pfRenderProfile.StopTimer(CRenderProfile::PTI_MAKEFINALPOLYGONEDGES);
- }
- // clip all polygons to one clip plane
- void CRenderer::ClipToOnePlane(const FLOATplane3D &plView)
- {
- // remember clip plane
- re_plClip = plView;
- // no need for clipping if no vertices are outside
- ASSERT( re_pbscCurrent->bsc_ulFlags&BSCF_NEEDSCLIPPING);
- if( !MakeOutcodes()) return;
- // for each polygon
- INDEX ispo0 = re_pbscCurrent->bsc_ispo0;
- INDEX ispoTop = re_pbscCurrent->bsc_ispo0+re_pbscCurrent->bsc_ctspo;
- for(INDEX ispo = ispo0; ispo<ispoTop; ispo++) {
- // clip to the plane
- ClipOnePolygon(re_aspoScreenPolygons[ispo]);
- }
- // swap edge buffers
- Swap(re_aiEdgeVxClipSrc.sa_Count , re_aiEdgeVxClipDst.sa_Count );
- Swap(re_aiEdgeVxClipSrc.sa_Array , re_aiEdgeVxClipDst.sa_Array );
- Swap(re_aiEdgeVxClipSrc.sa_UsedCount, re_aiEdgeVxClipDst.sa_UsedCount);
- re_aiEdgeVxClipDst.PopAll();
- }
- // clip all polygons to all clip planes of a projection
- void CRenderer::ClipToAllPlanes(CAnyProjection3D &pr)
- {
- _pfRenderProfile.StartTimer(CRenderProfile::PTI_CLIPTOALLPLANES);
- // clip to up/down/left/right clip planes
- FLOATplane3D pl;
- pl = pr->pr_plClipU; pl.Offset(-0.001f); ClipToOnePlane(pl);
- pl = pr->pr_plClipD; pl.Offset(-0.001f); ClipToOnePlane(pl);
- pl = pr->pr_plClipL; pl.Offset(-0.001f); ClipToOnePlane(pl);
- pl = pr->pr_plClipR; pl.Offset(-0.001f); ClipToOnePlane(pl);
- // clip to near clip plane
- ClipToOnePlane(FLOATplane3D(FLOAT3D(0,0,-1), pr->pr_NearClipDistance));
- // clip to far clip plane if existing
- if (pr->pr_FarClipDistance>0) {
- ClipToOnePlane(FLOATplane3D(FLOAT3D(0,0,1), -pr->pr_FarClipDistance));
- }
- // if projection is mirrored or warped
- if (pr->pr_bMirror||pr->pr_bWarp) {
- // clip to mirror plane
- ClipToOnePlane(pr->pr_plMirrorView);
- }
- _pfRenderProfile.StopTimer(CRenderProfile::PTI_CLIPTOALLPLANES);
- }
- // make outcodes for current clip plane for all active vertices
- __forceinline BOOL CRenderer::MakeOutcodes(void)
- {
- SLONG slMask = 0;
- // for each active view vertex
- INDEX iVxTop = re_avvxViewVertices.Count();
- for(INDEX ivx = re_iViewVx0; ivx<iVxTop; ivx++) {
- CViewVertex &vvx = re_avvxViewVertices[ivx];
- // calculate the distance
- vvx.vvx_fD = re_plClip.PointDistance(vvx.vvx_vView);
- // calculate the outcode
- const ULONG ulOutCode = (*(SLONG*)&vvx.vvx_fD) & 0x80000000;
- // add to the outcode of the vertex
- vvx.vvx_ulOutcode = (vvx.vvx_ulOutcode>>1)|ulOutCode;
- // add to mask
- slMask|=ulOutCode;
- }
- // if any was negative, return true -- needs clipping
- return slMask;
- }
- // clip one polygon to current clip plane
- void CRenderer::ClipOnePolygon(CScreenPolygon &spo)
- {
- //
- // NOTE: There is one ugly problem with this loop.
- // I don't know any better way to fix it, so I have commented it.
- // If the vertex references (vvx0 and vvx1) are taken _before_ pushing the vvxNew,
- // it can cause access violation, because pushing can move array in memory.
- // Therefore, it is important to take the references _after_ the Push() call.
-
- INDEX iEdgeVx0New = re_aiEdgeVxClipDst.Count();
- // for each edge
- INDEX ivxTop = spo.spo_iEdgeVx0+spo.spo_ctEdgeVx;
- for(INDEX ivx=spo.spo_iEdgeVx0; ivx<ivxTop; ivx+=2) {
- INDEX ivx0 = re_aiEdgeVxClipSrc[ivx+0];
- INDEX ivx1 = re_aiEdgeVxClipSrc[ivx+1];
- // get vertices
- FLOAT fD0 = re_avvxViewVertices[ivx0].vvx_fD;
- FLOAT fD1 = re_avvxViewVertices[ivx1].vvx_fD;
- if (fD0<=0) {
- // if both are back
- if (fD1<=0) {
- // no screen edge remains
- continue;
- // if first is back, second front
- } else {
- // make new vertex
- INDEX ivxNew = re_avvxViewVertices.Count();
- CViewVertex &vvxNew = re_avvxViewVertices.Push();
- CViewVertex &vvx0 = re_avvxViewVertices[ivx0]; // must do this after push, see note above!
- CViewVertex &vvx1 = re_avvxViewVertices[ivx1]; // must do this after push, see note above!
- // clip first
- FLOAT fDivisor = 1.0f/(fD0-fD1);
- FLOAT fFactor = fD0*fDivisor;
- vvxNew.vvx_vView(1) = vvx0.vvx_vView(1)-(vvx0.vvx_vView(1)-vvx1.vvx_vView(1))*fFactor;
- vvxNew.vvx_vView(2) = vvx0.vvx_vView(2)-(vvx0.vvx_vView(2)-vvx1.vvx_vView(2))*fFactor;
- vvxNew.vvx_vView(3) = vvx0.vvx_vView(3)-(vvx0.vvx_vView(3)-vvx1.vvx_vView(3))*fFactor;
- // remember new edge
- re_aiEdgeVxClipDst.Push() = ivxNew;
- re_aiEdgeVxClipDst.Push() = ivx1;
- // add new vertex to clip buffer
- re_aiClipBuffer.Push() = ivxNew;
- }
- } else {
- // if first is front, second back
- if ((SLONG&)fD1<=0) {
- // make new vertex
- INDEX ivxNew = re_avvxViewVertices.Count();
- CViewVertex &vvxNew = re_avvxViewVertices.Push();
- CViewVertex &vvx0 = re_avvxViewVertices[ivx0]; // must do this after push, see note above!
- CViewVertex &vvx1 = re_avvxViewVertices[ivx1]; // must do this after push, see note above!
- // clip second
- FLOAT fDivisor = 1.0f/(fD0-fD1);
- FLOAT fFactor = fD1*fDivisor;
- vvxNew.vvx_vView(1) = vvx1.vvx_vView(1)-(vvx0.vvx_vView(1)-vvx1.vvx_vView(1))*fFactor;
- vvxNew.vvx_vView(2) = vvx1.vvx_vView(2)-(vvx0.vvx_vView(2)-vvx1.vvx_vView(2))*fFactor;
- vvxNew.vvx_vView(3) = vvx1.vvx_vView(3)-(vvx0.vvx_vView(3)-vvx1.vvx_vView(3))*fFactor;
- // remember new edge
- re_aiEdgeVxClipDst.Push() = ivx0;
- re_aiEdgeVxClipDst.Push() = ivxNew;
- // add new vertex to clip buffer
- re_aiClipBuffer.Push() = ivxNew;
- // if both are front
- } else {
- // just copy the edge
- re_aiEdgeVxClipDst.Push() = ivx0;
- re_aiEdgeVxClipDst.Push() = ivx1;
- }
- }
- }
- // if there is anything in clip buffer
- if (re_aiClipBuffer.Count()>0) {
- // generate clip edges
- GenerateClipEdges(spo);
- }
- // remember new edge vertex positions
- spo.spo_ctEdgeVx = re_aiEdgeVxClipDst.Count()-iEdgeVx0New;
- spo.spo_iEdgeVx0 = iEdgeVx0New;
- }
- /*
- * Compare two vertices for quick-sort.
- */
- static UBYTE *_aVertices=NULL;
- static int qsort_CompareVertices_plus( const void *ppvVertex0, const void *ppvVertex1)
- {
- INDEX ivx0 = *(const INDEX*)ppvVertex0;
- INDEX ivx1 = *(const INDEX*)ppvVertex1;
- FLOAT f0 = *(FLOAT*)(_aVertices+ivx0*sizeof(CViewVertex));
- FLOAT f1 = *(FLOAT*)(_aVertices+ivx1*sizeof(CViewVertex));
- if (f0<f1) return -1;
- else if (f0>f1) return +1;
- else return 0;
- }
- static int qsort_CompareVertices_minus( const void *ppvVertex0, const void *ppvVertex1)
- {
- INDEX ivx0 = *(const INDEX*)ppvVertex0;
- INDEX ivx1 = *(const INDEX*)ppvVertex1;
- FLOAT f0 = *(FLOAT*)(_aVertices+ivx0*sizeof(CViewVertex));
- FLOAT f1 = *(FLOAT*)(_aVertices+ivx1*sizeof(CViewVertex));
- if (f0<f1) return +1;
- else if (f0>f1) return -1;
- else return 0;
- }
- // generate clip edges for one polygon
- void CRenderer::GenerateClipEdges(CScreenPolygon &spo)
- {
- ASSERT(re_aiClipBuffer.Count()>0);
- FLOATplane3D &plPolygonPlane = spo.spo_pbpoBrushPolygon->bpo_pbplPlane->bpl_pwplWorking->wpl_plView;
- // calculate the clip buffer direction in 3d as:
- // clip_normal_vector x polygon_normal_vector
- FLOAT3D vClipDir = ((FLOAT3D &)re_plClip)*((FLOAT3D &)plPolygonPlane);
- // get max axis
- INDEX iMaxAxis = 1;
- FLOAT fMaxAbs = Abs(vClipDir(1));
- if (Abs(vClipDir(2))>fMaxAbs) {
- iMaxAxis = 2;
- fMaxAbs = Abs(vClipDir(2));
- }
- if (Abs(vClipDir(3))>fMaxAbs) {
- iMaxAxis = 3;
- fMaxAbs = Abs(vClipDir(3));
- }
- _aVertices = (UBYTE*) &re_avvxViewVertices[0].vvx_vView(iMaxAxis);
- INDEX *aIndices = &re_aiClipBuffer[0];
- INDEX ctIndices = re_aiClipBuffer.Count();
- // there must be even number of vertices in the buffer
- ASSERT(ctIndices%2 == 0);
- // if the sign of axis is negative
- if (vClipDir(iMaxAxis)<0) {
- // sort them inversely
- qsort(aIndices, ctIndices, sizeof(INDEX), qsort_CompareVertices_minus);
- // if it is negative
- } else {
- // sort them normally
- qsort(aIndices, ctIndices, sizeof(INDEX), qsort_CompareVertices_plus);
- }
- // for each two vertices
- for(INDEX iClippedVertex=0; iClippedVertex<ctIndices; iClippedVertex+=2) {
- // add the edge
- re_aiEdgeVxClipDst.Push() = aIndices[iClippedVertex+0];
- re_aiEdgeVxClipDst.Push() = aIndices[iClippedVertex+1];
- }
- // clear the clip buffer
- re_aiClipBuffer.PopAll();
- }
|