123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../precompiled.h"
- /*
- =================
- UpdateVertexIndex
- =================
- */
- ID_INLINE int UpdateVertexIndex( int vertexIndexNum[2], int *vertexRemap, int *vertexCopyIndex, int vertNum ) {
- int s = INT32_SIGNBITSET( vertexRemap[vertNum] );
- vertexIndexNum[0] = vertexRemap[vertNum];
- vertexRemap[vertNum] = vertexIndexNum[s];
- vertexIndexNum[1] += s;
- vertexCopyIndex[vertexRemap[vertNum]] = vertNum;
- return vertexRemap[vertNum];
- }
- /*
- =================
- idSurface::Split
- =================
- */
- int idSurface::Split( const idPlane &plane, const float epsilon, idSurface **front, idSurface **back, int *frontOnPlaneEdges, int *backOnPlaneEdges ) const {
- float * dists;
- float f;
- byte * sides;
- int counts[3];
- int * edgeSplitVertex;
- int numEdgeSplitVertexes;
- int * vertexRemap[2];
- int vertexIndexNum[2][2];
- int * vertexCopyIndex[2];
- int * indexPtr[2];
- int indexNum[2];
- int * index;
- int * onPlaneEdges[2];
- int numOnPlaneEdges[2];
- int maxOnPlaneEdges;
- int i;
- idSurface * surface[2];
- idDrawVert v;
- dists = (float *) _alloca( verts.Num() * sizeof( float ) );
- sides = (byte *) _alloca( verts.Num() * sizeof( byte ) );
- counts[0] = counts[1] = counts[2] = 0;
- // determine side for each vertex
- for ( i = 0; i < verts.Num(); i++ ) {
- dists[i] = f = plane.Distance( verts[i].xyz );
- if ( f > epsilon ) {
- sides[i] = SIDE_FRONT;
- } else if ( f < -epsilon ) {
- sides[i] = SIDE_BACK;
- } else {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- *front = *back = NULL;
- // if coplanar, put on the front side if the normals match
- if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
- f = ( verts[indexes[1]].xyz - verts[indexes[0]].xyz ).Cross( verts[indexes[0]].xyz - verts[indexes[2]].xyz ) * plane.Normal();
- if ( IEEE_FLT_SIGNBITSET( f ) ) {
- *back = new (TAG_IDLIB_SURFACE) idSurface( *this );
- return SIDE_BACK;
- } else {
- *front = new (TAG_IDLIB_SURFACE) idSurface( *this );
- return SIDE_FRONT;
- }
- }
- // if nothing at the front of the clipping plane
- if ( !counts[SIDE_FRONT] ) {
- *back = new (TAG_IDLIB_SURFACE) idSurface( *this );
- return SIDE_BACK;
- }
- // if nothing at the back of the clipping plane
- if ( !counts[SIDE_BACK] ) {
- *front = new (TAG_IDLIB_SURFACE) idSurface( *this );
- return SIDE_FRONT;
- }
- // allocate front and back surface
- *front = surface[0] = new (TAG_IDLIB_SURFACE) idSurface();
- *back = surface[1] = new (TAG_IDLIB_SURFACE) idSurface();
- edgeSplitVertex = (int *) _alloca( edges.Num() * sizeof( int ) );
- numEdgeSplitVertexes = 0;
- maxOnPlaneEdges = 4 * counts[SIDE_ON];
- counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
- // split edges
- for ( i = 0; i < edges.Num(); i++ ) {
- int v0 = edges[i].verts[0];
- int v1 = edges[i].verts[1];
- int sidesOr = ( sides[v0] | sides[v1] );
- // if both vertexes are on the same side or one is on the clipping plane
- if ( !( sides[v0] ^ sides[v1] ) || ( sidesOr & SIDE_ON ) ) {
- edgeSplitVertex[i] = -1;
- counts[sidesOr & SIDE_BACK]++;
- counts[SIDE_ON] += ( sidesOr & SIDE_ON ) >> 1;
- } else {
- f = dists[v0] / ( dists[v0] - dists[v1] );
- v.LerpAll( verts[v0], verts[v1], f );
- edgeSplitVertex[i] = numEdgeSplitVertexes++;
- surface[0]->verts.Append( v );
- surface[1]->verts.Append( v );
- }
- }
- // each edge is shared by at most two triangles, as such there can never be more indexes than twice the number of edges
- surface[0]->indexes.Resize( ( ( counts[SIDE_FRONT] + counts[SIDE_ON] ) * 2 ) + ( numEdgeSplitVertexes * 4 ) );
- surface[1]->indexes.Resize( ( ( counts[SIDE_BACK] + counts[SIDE_ON] ) * 2 ) + ( numEdgeSplitVertexes * 4 ) );
- // allocate indexes to construct the triangle indexes for the front and back surface
- vertexRemap[0] = (int *) _alloca( verts.Num() * sizeof( int ) );
- memset( vertexRemap[0], -1, verts.Num() * sizeof( int ) );
- vertexRemap[1] = (int *) _alloca( verts.Num() * sizeof( int ) );
- memset( vertexRemap[1], -1, verts.Num() * sizeof( int ) );
- vertexCopyIndex[0] = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
- vertexCopyIndex[1] = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
- vertexIndexNum[0][0] = vertexIndexNum[1][0] = 0;
- vertexIndexNum[0][1] = vertexIndexNum[1][1] = numEdgeSplitVertexes;
- indexPtr[0] = surface[0]->indexes.Ptr();
- indexPtr[1] = surface[1]->indexes.Ptr();
- indexNum[0] = surface[0]->indexes.Num();
- indexNum[1] = surface[1]->indexes.Num();
- maxOnPlaneEdges += 4 * numEdgeSplitVertexes;
- // allocate one more in case no triangles are actually split which may happen for a disconnected surface
- onPlaneEdges[0] = (int *) _alloca( ( maxOnPlaneEdges + 1 ) * sizeof( int ) );
- onPlaneEdges[1] = (int *) _alloca( ( maxOnPlaneEdges + 1 ) * sizeof( int ) );
- numOnPlaneEdges[0] = numOnPlaneEdges[1] = 0;
- // split surface triangles
- for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
- int e0, e1, e2, v0, v1, v2, s, n;
- e0 = abs( edgeIndexes[i+0] );
- e1 = abs( edgeIndexes[i+1] );
- e2 = abs( edgeIndexes[i+2] );
- v0 = indexes[i+0];
- v1 = indexes[i+1];
- v2 = indexes[i+2];
- switch( ( INT32_SIGNBITSET( edgeSplitVertex[e0] ) | ( INT32_SIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INT32_SIGNBITSET( edgeSplitVertex[e2] ) << 2 ) ) ^ 7 ) {
- case 0: { // no edges split
- if ( ( sides[v0] & sides[v1] & sides[v2] ) & SIDE_ON ) {
- // coplanar
- f = ( verts[v1].xyz - verts[v0].xyz ).Cross( verts[v0].xyz - verts[v2].xyz ) * plane.Normal();
- s = IEEE_FLT_SIGNBITSET( f );
- } else {
- s = ( sides[v0] | sides[v1] | sides[v2] ) & SIDE_BACK;
- }
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]] = n;
- numOnPlaneEdges[s] += ( sides[v0] & sides[v1] ) >> 1;
- onPlaneEdges[s][numOnPlaneEdges[s]] = n+1;
- numOnPlaneEdges[s] += ( sides[v1] & sides[v2] ) >> 1;
- onPlaneEdges[s][numOnPlaneEdges[s]] = n+2;
- numOnPlaneEdges[s] += ( sides[v2] & sides[v0] ) >> 1;
- index = indexPtr[s];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- indexNum[s] = n;
- break;
- }
- case 1: { // first edge split
- s = sides[v0] & SIDE_BACK;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e0];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- indexNum[s] = n;
- s ^= 1;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- index[n++] = edgeSplitVertex[e0];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- indexNum[s] = n;
- break;
- }
- case 2: { // second edge split
- s = sides[v1] & SIDE_BACK;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e1];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- indexNum[s] = n;
- s ^= 1;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- index[n++] = edgeSplitVertex[e1];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- indexNum[s] = n;
- break;
- }
- case 3: { // first and second edge split
- s = sides[v1] & SIDE_BACK;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e1];
- index[n++] = edgeSplitVertex[e0];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- indexNum[s] = n;
- s ^= 1;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e0];
- index[n++] = edgeSplitVertex[e1];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- index[n++] = edgeSplitVertex[e1];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- indexNum[s] = n;
- break;
- }
- case 4: { // third edge split
- s = sides[v2] & SIDE_BACK;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e2];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- indexNum[s] = n;
- s ^= 1;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- index[n++] = edgeSplitVertex[e2];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- indexNum[s] = n;
- break;
- }
- case 5: { // first and third edge split
- s = sides[v0] & SIDE_BACK;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e0];
- index[n++] = edgeSplitVertex[e2];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- indexNum[s] = n;
- s ^= 1;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e2];
- index[n++] = edgeSplitVertex[e0];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- index[n++] = edgeSplitVertex[e2];
- indexNum[s] = n;
- break;
- }
- case 6: { // second and third edge split
- s = sides[v2] & SIDE_BACK;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e2];
- index[n++] = edgeSplitVertex[e1];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v2 );
- indexNum[s] = n;
- s ^= 1;
- n = indexNum[s];
- onPlaneEdges[s][numOnPlaneEdges[s]++] = n;
- index = indexPtr[s];
- index[n++] = edgeSplitVertex[e1];
- index[n++] = edgeSplitVertex[e2];
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v0 );
- index[n++] = UpdateVertexIndex( vertexIndexNum[s], vertexRemap[s], vertexCopyIndex[s], v1 );
- index[n++] = edgeSplitVertex[e2];
- indexNum[s] = n;
- break;
- }
- }
- }
- surface[0]->indexes.SetNum( indexNum[0] );
- surface[1]->indexes.SetNum( indexNum[1] );
- // copy vertexes
- surface[0]->verts.SetNum( vertexIndexNum[0][1] );
- index = vertexCopyIndex[0];
- for ( i = numEdgeSplitVertexes; i < surface[0]->verts.Num(); i++ ) {
- surface[0]->verts[i] = verts[index[i]];
- }
- surface[1]->verts.SetNum( vertexIndexNum[1][1] );
- index = vertexCopyIndex[1];
- for ( i = numEdgeSplitVertexes; i < surface[1]->verts.Num(); i++ ) {
- surface[1]->verts[i] = verts[index[i]];
- }
- // generate edge indexes
- surface[0]->GenerateEdgeIndexes();
- surface[1]->GenerateEdgeIndexes();
- if ( frontOnPlaneEdges ) {
- memcpy( frontOnPlaneEdges, onPlaneEdges[0], numOnPlaneEdges[0] * sizeof( int ) );
- frontOnPlaneEdges[numOnPlaneEdges[0]] = -1;
- }
- if ( backOnPlaneEdges ) {
- memcpy( backOnPlaneEdges, onPlaneEdges[1], numOnPlaneEdges[1] * sizeof( int ) );
- backOnPlaneEdges[numOnPlaneEdges[1]] = -1;
- }
- return SIDE_CROSS;
- }
- /*
- =================
- idSurface::ClipInPlace
- =================
- */
- bool idSurface::ClipInPlace( const idPlane &plane, const float epsilon, const bool keepOn ) {
- float * dists;
- float f;
- byte * sides;
- int counts[3];
- int i;
- int * edgeSplitVertex;
- int * vertexRemap;
- int vertexIndexNum[2];
- int * vertexCopyIndex;
- int * indexPtr;
- int indexNum;
- int numEdgeSplitVertexes;
- idDrawVert v;
- idList<idDrawVert, TAG_IDLIB_LIST_SURFACE> newVerts;
- idList<int, TAG_IDLIB_LIST_SURFACE> newIndexes;
- dists = (float *) _alloca( verts.Num() * sizeof( float ) );
- sides = (byte *) _alloca( verts.Num() * sizeof( byte ) );
- counts[0] = counts[1] = counts[2] = 0;
- // determine side for each vertex
- for ( i = 0; i < verts.Num(); i++ ) {
- dists[i] = f = plane.Distance( verts[i].xyz );
- if ( f > epsilon ) {
- sides[i] = SIDE_FRONT;
- } else if ( f < -epsilon ) {
- sides[i] = SIDE_BACK;
- } else {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- // if coplanar, put on the front side if the normals match
- if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
- f = ( verts[indexes[1]].xyz - verts[indexes[0]].xyz ).Cross( verts[indexes[0]].xyz - verts[indexes[2]].xyz ) * plane.Normal();
- if ( IEEE_FLT_SIGNBITSET( f ) ) {
- Clear();
- return false;
- } else {
- return true;
- }
- }
- // if nothing at the front of the clipping plane
- if ( !counts[SIDE_FRONT] ) {
- Clear();
- return false;
- }
- // if nothing at the back of the clipping plane
- if ( !counts[SIDE_BACK] ) {
- return true;
- }
- edgeSplitVertex = (int *) _alloca( edges.Num() * sizeof( int ) );
- numEdgeSplitVertexes = 0;
- counts[SIDE_FRONT] = counts[SIDE_BACK] = 0;
- // split edges
- for ( i = 0; i < edges.Num(); i++ ) {
- int v0 = edges[i].verts[0];
- int v1 = edges[i].verts[1];
- // if both vertexes are on the same side or one is on the clipping plane
- if ( !( sides[v0] ^ sides[v1] ) || ( ( sides[v0] | sides[v1] ) & SIDE_ON ) ) {
- edgeSplitVertex[i] = -1;
- counts[(sides[v0]|sides[v1]) & SIDE_BACK]++;
- } else {
- f = dists[v0] / ( dists[v0] - dists[v1] );
- v.LerpAll( verts[v0], verts[v1], f );
- edgeSplitVertex[i] = numEdgeSplitVertexes++;
- newVerts.Append( v );
- }
- }
- // each edge is shared by at most two triangles, as such there can never be
- // more indexes than twice the number of edges
- newIndexes.Resize( ( counts[SIDE_FRONT] << 1 ) + ( numEdgeSplitVertexes << 2 ) );
- // allocate indexes to construct the triangle indexes for the front and back surface
- vertexRemap = (int *) _alloca( verts.Num() * sizeof( int ) );
- memset( vertexRemap, -1, verts.Num() * sizeof( int ) );
- vertexCopyIndex = (int *) _alloca( ( numEdgeSplitVertexes + verts.Num() ) * sizeof( int ) );
- vertexIndexNum[0] = 0;
- vertexIndexNum[1] = numEdgeSplitVertexes;
- indexPtr = newIndexes.Ptr();
- indexNum = newIndexes.Num();
- // split surface triangles
- for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
- int e0, e1, e2, v0, v1, v2;
- e0 = abs( edgeIndexes[i+0] );
- e1 = abs( edgeIndexes[i+1] );
- e2 = abs( edgeIndexes[i+2] );
- v0 = indexes[i+0];
- v1 = indexes[i+1];
- v2 = indexes[i+2];
- switch( ( INT32_SIGNBITSET( edgeSplitVertex[e0] ) | ( INT32_SIGNBITSET( edgeSplitVertex[e1] ) << 1 ) | ( INT32_SIGNBITSET( edgeSplitVertex[e2] ) << 2 ) ) ^ 7 ) {
- case 0: { // no edges split
- if ( ( sides[v0] | sides[v1] | sides[v2] ) & SIDE_BACK ) {
- break;
- }
- if ( ( sides[v0] & sides[v1] & sides[v2] ) & SIDE_ON ) {
- // coplanar
- if ( !keepOn ) {
- break;
- }
- f = ( verts[v1].xyz - verts[v0].xyz ).Cross( verts[v0].xyz - verts[v2].xyz ) * plane.Normal();
- if ( IEEE_FLT_SIGNBITSET( f ) ) {
- break;
- }
- }
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- break;
- }
- case 1: { // first edge split
- if ( !( sides[v0] & SIDE_BACK ) ) {
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- indexPtr[indexNum++] = edgeSplitVertex[e0];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- } else {
- indexPtr[indexNum++] = edgeSplitVertex[e0];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- }
- break;
- }
- case 2: { // second edge split
- if ( !( sides[v1] & SIDE_BACK ) ) {
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = edgeSplitVertex[e1];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- } else {
- indexPtr[indexNum++] = edgeSplitVertex[e1];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- }
- break;
- }
- case 3: { // first and second edge split
- if ( !( sides[v1] & SIDE_BACK ) ) {
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = edgeSplitVertex[e1];
- indexPtr[indexNum++] = edgeSplitVertex[e0];
- } else {
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- indexPtr[indexNum++] = edgeSplitVertex[e0];
- indexPtr[indexNum++] = edgeSplitVertex[e1];
- indexPtr[indexNum++] = edgeSplitVertex[e1];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- }
- break;
- }
- case 4: { // third edge split
- if ( !( sides[v2] & SIDE_BACK ) ) {
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- } else {
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- }
- break;
- }
- case 5: { // first and third edge split
- if ( !( sides[v0] & SIDE_BACK ) ) {
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- indexPtr[indexNum++] = edgeSplitVertex[e0];
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- } else {
- indexPtr[indexNum++] = edgeSplitVertex[e0];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- }
- break;
- }
- case 6: { // second and third edge split
- if ( !( sides[v2] & SIDE_BACK ) ) {
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v2 );
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- indexPtr[indexNum++] = edgeSplitVertex[e1];
- } else {
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = edgeSplitVertex[e1];
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v0 );
- indexPtr[indexNum++] = UpdateVertexIndex( vertexIndexNum, vertexRemap, vertexCopyIndex, v1 );
- indexPtr[indexNum++] = edgeSplitVertex[e2];
- }
- break;
- }
- }
- }
- newIndexes.SetNum( indexNum );
- // copy vertexes
- newVerts.SetNum( vertexIndexNum[1] );
- for ( i = numEdgeSplitVertexes; i < newVerts.Num(); i++ ) {
- newVerts[i] = verts[vertexCopyIndex[i]];
- }
- // copy back to this surface
- indexes = newIndexes;
- verts = newVerts;
- GenerateEdgeIndexes();
- return true;
- }
- /*
- =============
- idSurface::IsConnected
- =============
- */
- bool idSurface::IsConnected() const {
- int i, j, numIslands, numTris;
- int queueStart, queueEnd;
- int *queue, *islandNum;
- int curTri, nextTri, edgeNum;
- const int *index;
- numIslands = 0;
- numTris = indexes.Num() / 3;
- islandNum = (int *) _alloca16( numTris * sizeof( int ) );
- memset( islandNum, -1, numTris * sizeof( int ) );
- queue = (int *) _alloca16( numTris * sizeof( int ) );
- for ( i = 0; i < numTris; i++ ) {
- if ( islandNum[i] != -1 ) {
- continue;
- }
- queueStart = 0;
- queueEnd = 1;
- queue[0] = i;
- islandNum[i] = numIslands;
- for ( curTri = queue[queueStart]; queueStart < queueEnd; curTri = queue[++queueStart] ) {
- index = &edgeIndexes[curTri * 3];
- for ( j = 0; j < 3; j++ ) {
- edgeNum = index[j];
- nextTri = edges[abs(edgeNum)].tris[INT32_SIGNBITNOTSET(edgeNum)];
- if ( nextTri == -1 ) {
- continue;
- }
- nextTri /= 3;
- if ( islandNum[nextTri] != -1 ) {
- continue;
- }
- queue[queueEnd++] = nextTri;
- islandNum[nextTri] = numIslands;
- }
- }
- numIslands++;
- }
- return ( numIslands == 1 );
- }
- /*
- =================
- idSurface::IsClosed
- =================
- */
- bool idSurface::IsClosed() const {
- for ( int i = 0; i < edges.Num(); i++ ) {
- if ( edges[i].tris[0] < 0 || edges[i].tris[1] < 0 ) {
- return false;
- }
- }
- return true;
- }
- /*
- =============
- idSurface::IsPolytope
- =============
- */
- bool idSurface::IsPolytope( const float epsilon ) const {
- int i, j;
- idPlane plane;
- if ( !IsClosed() ) {
- return false;
- }
- for ( i = 0; i < indexes.Num(); i += 3 ) {
- plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
- for ( j = 0; j < verts.Num(); j++ ) {
- if ( plane.Side( verts[j].xyz, epsilon ) == SIDE_FRONT ) {
- return false;
- }
- }
- }
- return true;
- }
- /*
- =============
- idSurface::PlaneDistance
- =============
- */
- float idSurface::PlaneDistance( const idPlane &plane ) const {
- int i;
- float d, min, max;
- min = idMath::INFINITY;
- max = -min;
- for ( i = 0; i < verts.Num(); i++ ) {
- d = plane.Distance( verts[i].xyz );
- if ( d < min ) {
- min = d;
- if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
- return 0.0f;
- }
- }
- if ( d > max ) {
- max = d;
- if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
- return 0.0f;
- }
- }
- }
- if ( IEEE_FLT_SIGNBITNOTSET( min ) ) {
- return min;
- }
- if ( IEEE_FLT_SIGNBITSET( max ) ) {
- return max;
- }
- return 0.0f;
- }
- /*
- =============
- idSurface::PlaneSide
- =============
- */
- int idSurface::PlaneSide( const idPlane &plane, const float epsilon ) const {
- bool front, back;
- int i;
- float d;
- front = false;
- back = false;
- for ( i = 0; i < verts.Num(); i++ ) {
- d = plane.Distance( verts[i].xyz );
- if ( d < -epsilon ) {
- if ( front ) {
- return SIDE_CROSS;
- }
- back = true;
- continue;
- }
- else if ( d > epsilon ) {
- if ( back ) {
- return SIDE_CROSS;
- }
- front = true;
- continue;
- }
- }
- if ( back ) {
- return SIDE_BACK;
- }
- if ( front ) {
- return SIDE_FRONT;
- }
- return SIDE_ON;
- }
- /*
- =================
- idSurface::LineIntersection
- =================
- */
- bool idSurface::LineIntersection( const idVec3 &start, const idVec3 &end, bool backFaceCull ) const {
- float scale;
- RayIntersection( start, end - start, scale, false );
- return ( scale >= 0.0f && scale <= 1.0f );
- }
- /*
- =================
- idSurface::RayIntersection
- =================
- */
- bool idSurface::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull ) const {
- int i, i0, i1, i2, s0, s1, s2;
- float d, s;
- byte *sidedness;
- idPluecker rayPl, pl;
- idPlane plane;
- sidedness = (byte *)_alloca( edges.Num() * sizeof(byte) );
- scale = idMath::INFINITY;
- rayPl.FromRay( start, dir );
- // ray sidedness for edges
- for ( i = 0; i < edges.Num(); i++ ) {
- pl.FromLine( verts[ edges[i].verts[1] ].xyz, verts[ edges[i].verts[0] ].xyz );
- d = pl.PermutedInnerProduct( rayPl );
- sidedness[ i ] = IEEE_FLT_SIGNBITSET( d );
- }
- // test triangles
- for ( i = 0; i < edgeIndexes.Num(); i += 3 ) {
- i0 = edgeIndexes[i+0];
- i1 = edgeIndexes[i+1];
- i2 = edgeIndexes[i+2];
- s0 = sidedness[abs(i0)] ^ INT32_SIGNBITSET( i0 );
- s1 = sidedness[abs(i1)] ^ INT32_SIGNBITSET( i1 );
- s2 = sidedness[abs(i2)] ^ INT32_SIGNBITSET( i2 );
- if ( s0 & s1 & s2 ) {
- plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
- plane.RayIntersection( start, dir, s );
- if ( idMath::Fabs( s ) < idMath::Fabs( scale ) ) {
- scale = s;
- }
- } else if ( !backFaceCull && !(s0 | s1 | s2) ) {
- plane.FromPoints( verts[indexes[i+0]].xyz, verts[indexes[i+1]].xyz, verts[indexes[i+2]].xyz );
- plane.RayIntersection( start, dir, s );
- if ( idMath::Fabs( s ) < idMath::Fabs( scale ) ) {
- scale = s;
- }
- }
- }
- if ( idMath::Fabs( scale ) < idMath::INFINITY ) {
- return true;
- }
- return false;
- }
- /*
- =================
- idSurface::GenerateEdgeIndexes
- Assumes each edge is shared by at most two triangles.
- =================
- */
- void idSurface::GenerateEdgeIndexes() {
- int i, j, i0, i1, i2, s, v0, v1, edgeNum;
- int *index, *vertexEdges, *edgeChain;
- surfaceEdge_t e[3];
- vertexEdges = (int *) _alloca16( verts.Num() * sizeof( int ) );
- memset( vertexEdges, -1, verts.Num() * sizeof( int ) );
- edgeChain = (int *) _alloca16( indexes.Num() * sizeof( int ) );
- edgeIndexes.SetNum( indexes.Num() );
- edges.Clear();
- // the first edge is a dummy
- e[0].verts[0] = e[0].verts[1] = e[0].tris[0] = e[0].tris[1] = 0;
- edges.Append( e[0] );
- for ( i = 0; i < indexes.Num(); i += 3 ) {
- index = indexes.Ptr() + i;
- // vertex numbers
- i0 = index[0];
- i1 = index[1];
- i2 = index[2];
- // setup edges each with smallest vertex number first
- s = INT32_SIGNBITSET(i1 - i0);
- e[0].verts[0] = index[s];
- e[0].verts[1] = index[s^1];
- s = INT32_SIGNBITSET(i2 - i1) + 1;
- e[1].verts[0] = index[s];
- e[1].verts[1] = index[s^3];
- s = INT32_SIGNBITSET(i2 - i0) << 1;
- e[2].verts[0] = index[s];
- e[2].verts[1] = index[s^2];
- // get edges
- for ( j = 0; j < 3; j++ ) {
- v0 = e[j].verts[0];
- v1 = e[j].verts[1];
- for ( edgeNum = vertexEdges[v0]; edgeNum >= 0; edgeNum = edgeChain[edgeNum] ) {
- if ( edges[edgeNum].verts[1] == v1 ) {
- break;
- }
- }
- // if the edge does not yet exist
- if ( edgeNum < 0 ) {
- e[j].tris[0] = e[j].tris[1] = -1;
- edgeNum = edges.Append( e[j] );
- edgeChain[edgeNum] = vertexEdges[v0];
- vertexEdges[v0] = edgeNum;
- }
- // update edge index and edge tri references
- if ( index[j] == v0 ) {
- assert( edges[edgeNum].tris[0] == -1 ); // edge may not be shared by more than two triangles
- edges[edgeNum].tris[0] = i;
- edgeIndexes[i+j] = edgeNum;
- } else {
- assert( edges[edgeNum].tris[1] == -1 ); // edge may not be shared by more than two triangles
- edges[edgeNum].tris[1] = i;
- edgeIndexes[i+j] = -edgeNum;
- }
- }
- }
- }
- /*
- =================
- idSurface::FindEdge
- =================
- */
- int idSurface::FindEdge( int v1, int v2 ) const {
- int i, firstVert, secondVert;
- if ( v1 < v2 ) {
- firstVert = v1;
- secondVert = v2;
- } else {
- firstVert = v2;
- secondVert = v1;
- }
- for ( i = 1; i < edges.Num(); i++ ) {
- if ( edges[i].verts[0] == firstVert ) {
- if ( edges[i].verts[1] == secondVert ) {
- break;
- }
- }
- }
- if ( i < edges.Num() ) {
- return v1 < v2 ? i : -i;
- }
- return 0;
- }
|