29 #include "../../../idlib/precompiled.h"
52 #define MAX_OPT_VERTEXES 0x10000
56 #define MAX_OPT_EDGES 0x40000
57 static int numOptEdges;
70 static void ValidateEdgeCounts(
optIsland_t *island ) {
77 for ( e = vert->
edges ; e ; ) {
79 if ( e->
v1 == vert ) {
81 }
else if ( e->
v2 == vert ) {
87 if ( c != 2 && c != 0 ) {
106 e = &optEdges[ numOptEdges ];
108 memset( e, 0,
sizeof( *e ) );
129 if ( e1->
v1 == vert ) {
131 }
else if ( e1->
v2 == vert ) {
134 common->
Error(
"RemoveEdgeFromVert: vert not found" );
139 if ( e->
v1 == vert ) {
141 }
else if ( e->
v2 == vert ) {
144 common->
Error(
"RemoveEdgeFromVert: vert not found" );
157 RemoveEdgeFromVert( e, e->
v1 );
158 RemoveEdgeFromVert( e, e->
v2 );
167 common->
Error(
"RemoveEdgeFromIsland: couldn't free edge" );
206 if ( optVerts[i].pv[0] == x && optVerts[i].pv[1] == y ) {
219 memset( vert, 0,
sizeof( *vert ) );
237 static void DrawAllEdges(
void ) {
247 for ( i = 0 ; i < numOptEdges ; i++ ) {
248 if ( optEdges[i].
v1 ==
NULL ) {
328 d1 = p1->
pv - v1->
pv;
329 d2 = p1->
pv - v2->
pv;
352 idVec3 dir1, dir2, cross1, cross2;
354 dir1 = p1->
pv - l1->
pv;
355 dir2 = p1->
pv - l2->
pv;
356 cross1 = dir1.
Cross( dir2 );
358 dir1 = p2->
pv - l1->
pv;
359 dir2 = p2->
pv - l2->
pv;
360 cross2 = dir1.
Cross( dir2 );
362 if ( cross1[2] - cross2[2] == 0 ) {
366 f = cross1[2] / ( cross1[2] - cross2[2] );
370 memset( v, 0,
sizeof( *v ) );
375 v->
st[0] = p1->
v.
st[0] * ( 1.0 -
f ) + p2->
v.
st[0] * f;
376 v->
st[1] = p1->
v.
st[1] * ( 1.0 - f ) + p2->
v.
st[1] *
f;
392 t1 = IsTriangleDegenerate( l1, l2, p1 );
393 t2 = IsTriangleDegenerate( l1, l2, p2 );
396 float s1, s2, s3, s4;
397 bool positive, negative;
399 s1 = ( p1->
pv - l1->
pv ) * ( l2->
pv - l1->
pv );
400 s2 = ( p2->
pv - l1->
pv ) * ( l2->
pv - l1->
pv );
401 s3 = ( p1->
pv - l2->
pv ) * ( l2->
pv - l1->
pv );
402 s4 = ( p2->
pv - l2->
pv ) * ( l2->
pv - l1->
pv );
404 if ( s1 > 0 || s2 > 0 || s3 > 0 || s4 > 0 ) {
409 if ( s1 < 0 || s2 < 0 || s3 < 0 || s4 < 0 ) {
415 if ( positive && negative ) {
419 }
else if ( p1 != l1 && p1 != l2 && p2 != l1 && p2 != l2 ) {
421 t1 = IsTriangleValid( l1, l2, p1 );
422 t2 = IsTriangleValid( l1, l2, p2 );
427 t1 = IsTriangleValid( l1, p1, l2 );
428 t2 = IsTriangleValid( l1, p2, l2 );
448 if ( a1 == b1 && a2 == b2 ) {
451 if ( a1 == b2 && a2 == b1 ) {
459 if ( !PointsStraddleLine( a1, a2, b1, b2 ) ) {
462 if ( !PointsStraddleLine( b1, b2, a1, a2 ) ) {
480 if ( EdgesCross( e->
v1, e->
v2, v1, v2 ) ) {
515 static int LengthSort(
const void *
a,
const void *
b ) {
536 static void AddInteriorEdges(
optIsland_t *island ) {
549 if ( !vert->
edges ) {
559 if ( !vert->
edges ) {
565 if ( !vert2->
edges ) {
568 lengths[numLengths].
v1 = vert;
569 lengths[numLengths].
v2 = vert2;
570 dir = ( vert->
pv - vert2->
pv ) ;
578 qsort( lengths, numLengths,
sizeof( lengths[0] ), LengthSort );
582 for ( i = 0 ; i < numLengths ; i++ ) {
583 if ( TryAddNewEdge( lengths[i].v1, lengths[i].v2, island ) ) {
590 common->
Printf(
"%6i added interior edges\n", c_addedEdges );
606 #define COLINEAR_EPSILON 0.1
621 for ( e = ov->
edges ; e ; ) {
631 }
else if ( e->
v2 == v2 ) {
634 common->
Error(
"RemoveIfColinear: mislinked edge" );
646 common->
Printf(
"WARNING: vertex with only one edge\n" );
650 if ( e1->
v1 == v2 ) {
652 }
else if ( e1->
v2 == v2 ) {
655 common->
Error(
"RemoveIfColinear: mislinked edge" );
657 if ( e2->
v1 == v2 ) {
659 }
else if ( e2->
v2 == v2 ) {
662 common->
Error(
"RemoveIfColinear: mislinked edge" );
666 common->
Error(
"RemoveIfColinear: mislinked edge" );
670 dist = ( v3->
pv - v2->
pv ) * ( v1->
pv - v2->
pv );
704 UnlinkEdge( e1, island );
705 UnlinkEdge( e2, island );
709 common->
Error(
"RemoveIfColinear: didn't remove properly" );
718 if ( ( e->
v1 == v1 && e->
v2 == v3 )
719 || ( e->
v1 == v3 && e->
v2 == v1 ) ) {
720 UnlinkEdge( e, island );
721 RemoveIfColinear( v1, island );
722 RemoveIfColinear( v3, island );
729 if ( !TryAddNewEdge( v1, v3, island ) ) {
742 RemoveIfColinear( v1, island );
743 RemoveIfColinear( v3, island );
751 static void CombineColinearEdges(
optIsland_t *island ) {
761 common->
Printf(
"%6i original exterior edges\n", c_edges );
765 RemoveIfColinear( ov, island );
773 common->
Printf(
"%6i optimized exterior edges\n", c_edges );
786 static void FreeOptTriangles(
optIsland_t *island ) {
789 for ( opt = island->
tris ; opt ; opt = next ) {
811 d1 = v2->
pv - v1->
pv;
812 d2 = v3->
pv - v1->
pv;
813 normal = d1.
Cross( d2 );
814 if ( normal[2] <= 0 ) {
818 d1 = v3->
pv - v2->
pv;
819 d2 = v1->
pv - v2->
pv;
820 normal = d1.
Cross( d2 );
821 if ( normal[2] <= 0 ) {
825 d1 = v1->
pv - v3->
pv;
826 d2 = v2->
pv - v3->
pv;
827 normal = d1.
Cross( d2 );
828 if ( normal[2] <= 0 ) {
847 d1 = v2->
pv - v1->
pv;
848 d2 = v3->
pv - v1->
pv;
849 normal = d1.
Cross( d2 );
850 if ( normal[2] == 0 ) {
855 return (
bool)!IsTriangleValid( v1, v2, v3 );
875 normal = d1.
Cross( d2 );
876 if ( normal[2] < 0 ) {
882 normal = d1.
Cross( d2 );
883 if ( normal[2] < 0 ) {
889 normal = d1.
Cross( d2 );
890 if ( normal[2] < 0 ) {
905 if ( ( edge->
v1 == optTri->
v[0] && edge->
v2 == optTri->
v[1] )
906 || ( edge->
v1 == optTri->
v[1] && edge->
v2 == optTri->
v[2] )
907 || ( edge->
v1 == optTri->
v[2] && edge->
v2 == optTri->
v[0] ) ) {
909 common->
Printf(
"Warning: LinkTriToEdge: already in use\n" );
915 if ( ( edge->
v1 == optTri->
v[1] && edge->
v2 == optTri->
v[0] )
916 || ( edge->
v1 == optTri->
v[2] && edge->
v2 == optTri->
v[1] )
917 || ( edge->
v1 == optTri->
v[0] && edge->
v2 == optTri->
v[2] ) ) {
919 common->
Printf(
"Warning: LinkTriToEdge: already in use\n" );
925 common->
Error(
"LinkTriToEdge: edge not found on tri" );
939 if ( e1->
v1 == first ) {
941 }
else if ( e1->
v2 == first ) {
947 if ( e2->
v1 == first ) {
949 }
else if ( e2->
v2 == first ) {
955 if ( !IsTriangleValid( first, second, third ) ) {
977 for ( opposite = second->
edges ; opposite ; ) {
978 if ( opposite != e1 && ( opposite->
v1 == third || opposite->
v2 == third ) ) {
981 if ( opposite->
v1 == second ) {
982 opposite = opposite->
v1link;
983 }
else if ( opposite->
v2 == second ) {
984 opposite = opposite->
v2link;
986 common->
Error(
"BuildOptTriangles: mislinked edge" );
991 common->
Printf(
"Warning: BuildOptTriangles: couldn't locate opposite\n" );
1007 optTri->
v[1] = second;
1008 optTri->
v[2] = third;
1009 optTri->
midpoint = ( optTri->
v[0]->
pv + optTri->
v[1]->
pv + optTri->
v[2]->
pv ) * ( 1.0f / 3.0f );
1011 island->
tris = optTri;
1025 if ( PointInTri( optTri->
midpoint, tri, island ) ) {
1055 LinkTriToEdge( optTri, e1 );
1056 LinkTriToEdge( optTri, e2 );
1057 LinkTriToEdge( optTri, opposite );
1072 vec = ov->
pv - v->
pv;
1088 static void BuildOptTriangles(
optIsland_t *island ) {
1090 optEdge_t *e1, *e1Next, *e2, *e2Next, *check, *checkNext;
1093 FreeOptTriangles( island );
1114 for ( e1 = ov->
edges ; e1 ; e1 = e1Next ) {
1121 if ( e1->
v1 == ov ) {
1123 }
else if ( e1->
v2 == ov ) {
1129 for ( e1 = ov->
edges ; e1 ; e1 = e1Next ) {
1130 if ( e1->
v1 == ov ) {
1133 }
else if ( e1->
v2 == ov ) {
1137 common->
Error(
"BuildOptTriangles: mislinked edge" );
1145 for ( e2 = ov->
edges ; e2 ; e2 = e2Next ) {
1146 if ( e2->
v1 == ov ) {
1149 }
else if ( e2->
v2 == ov ) {
1153 common->
Error(
"BuildOptTriangles: mislinked edge" );
1165 if ( !IsTriangleValid( ov, second, third ) ) {
1171 for ( check = ov->
edges ; check ; check = checkNext ) {
1172 if ( check->
v1 == ov ) {
1174 checkNext = check->
v1link;
1175 }
else if ( check->
v2 == ov ) {
1177 checkNext = check->
v2link;
1179 common->
Error(
"BuildOptTriangles: mislinked edge" );
1182 if ( check == e1 || check == e2 ) {
1186 if ( IsTriangleValid( ov, second, middle )
1187 && IsTriangleValid( ov, middle, third ) ) {
1197 CreateOptTri( ov, e1, e2, island );
1216 static void RegenerateTriangles(
optIsland_t *island ) {
1223 for ( optTri = island->
tris ; optTri ; optTri = optTri->
next ) {
1234 tri->
v[0] = optTri->
v[0]->
v;
1235 tri->
v[1] = optTri->
v[1]->
v;
1236 tri->
v[2] = optTri->
v[2]->
v;
1243 common->
Printf(
"WARNING: backwards triangle generated!\n" );
1254 FreeOptTriangles( island );
1271 static void RemoveInteriorEdges(
optIsland_t *island ) {
1272 int c_interiorEdges;
1273 int c_exteriorEdges;
1277 c_exteriorEdges = 0;
1278 c_interiorEdges = 0;
1279 for ( e = island->
edges ; e ; e = next ) {
1294 if ( front == back ) {
1296 UnlinkEdge( e, island );
1305 common->
Printf(
"%6i original interior edges\n", c_interiorEdges );
1306 common->
Printf(
"%6i original exterior edges\n", c_exteriorEdges );
1325 for ( e = v1->
edges ; e ; ) {
1326 if ( ( e->
v1 == v1 && e->
v2 == v2 ) || ( e->
v1 == v2 && e->
v2 == v1 ) ) {
1329 if ( e->
v1 == v1 ) {
1331 }
else if ( e->
v2 == v1 ) {
1334 common->
Error(
"SplitEdgeByList: bad edge link" );
1356 static void DrawOriginalEdges(
int numOriginalEdges,
originalEdges_t *originalEdges ) {
1365 for ( i = 0 ; i < numOriginalEdges ; i++ ) {
1382 static int numOriginalEdges;
1389 static void AddOriginalTriangle(
optVertex_t *v[3] ) {
1394 if ( !IsTriangleValid( v[0], v[1], v[2] ) ) {
1395 common->
Printf(
"WARNING: backwards triangle in input!\n" );
1399 for (
int i = 0 ; i < 3 ; i++ ) {
1410 for ( j = 0 ; j < numOriginalEdges ; j++ ) {
1411 if ( originalEdges[j].v1 == v1 && originalEdges[j].v2 == v2 ) {
1414 if ( originalEdges[j].v2 == v1 && originalEdges[j].v1 == v2 ) {
1419 if ( j == numOriginalEdges ) {
1421 originalEdges[
j].
v1 =
v1;
1422 originalEdges[
j].
v2 =
v2;
1448 numOriginalEdges = 0;
1453 for ( tri = opt->
triList ; tri ; tri = tri->
next ) {
1458 AddOriginalTriangle( v );
1469 int numOriginalVerts;
1487 for ( i = 0 ; i < numOriginalEdges ; i++ ) {
1489 DrawOriginalEdges( numOriginalEdges, originalEdges );
1498 for ( j = i+1 ; j < numOriginalEdges ; j++ ) {
1503 v1 = originalEdges[
i].
v1;
1504 v2 = originalEdges[
i].
v2;
1505 v3 = originalEdges[
j].
v1;
1506 v4 = originalEdges[
j].
v2;
1508 if ( !EdgesCross( v1, v2, v3, v4 ) ) {
1516 newVert = EdgeIntersection( v1, v2, v3, v4, opt );
1522 if ( VertexBetween( v3, v1, v2 ) ) {
1525 cross->
next = crossings[
i];
1529 if ( VertexBetween( v4, v1, v2 ) ) {
1532 cross->
next = crossings[
i];
1536 if ( VertexBetween( v1, v3, v4 ) ) {
1539 cross->
next = crossings[
j];
1543 if ( VertexBetween( v2, v3, v4 ) ) {
1546 cross->
next = crossings[
j];
1553 if ( newVert && newVert != v1 && newVert != v2 && newVert != v3 && newVert != v4 ) {
1554 common->
Printf(
"lines %i (%i to %i) and %i (%i to %i) cross at new point %i\n", i, v1 - optVerts, v2 - optVerts,
1555 j, v3 - optVerts, v4 - optVerts, newVert - optVerts );
1556 }
else if ( newVert ) {
1557 common->
Printf(
"lines %i (%i to %i) and %i (%i to %i) intersect at old point %i\n", i, v1 - optVerts, v2 - optVerts,
1558 j, v3 - optVerts, v4 - optVerts, newVert - optVerts );
1561 if ( newVert != v1 && newVert != v2 ) {
1563 cross->
ov = newVert;
1564 cross->
next = crossings[
i];
1568 if ( newVert != v3 && newVert != v4 ) {
1570 cross->
ov = newVert;
1571 cross->
next = crossings[
j];
1581 for ( i = 0 ; i < numOriginalEdges ; i++ ) {
1587 for ( cross = crossings[i] ;
cross ; cross = cross->
next ) {
1592 sorted[0] = originalEdges[
i].
v1;
1593 sorted[1] = originalEdges[
i].
v2;
1595 for ( cross = crossings[i] ;
cross ; cross = nextCross ) {
1596 nextCross = cross->
next;
1597 sorted[
j] = cross->
ov;
1604 for ( j = 0 ; j < numCross ; j++ ) {
1605 for ( k = j+1 ; k < numCross ; k++ ) {
1606 for ( l = 0 ; l < numCross ; l++ ) {
1607 if ( sorted[l] == sorted[j] || sorted[l] == sorted[k] ) {
1610 if ( sorted[j] == sorted[k] ) {
1613 if ( VertexBetween( sorted[l], sorted[j], sorted[k] ) ) {
1617 if ( l == numCross ) {
1632 for ( i = 0 ; i < numOptEdges ; i++ ) {
1633 for ( j = i+1 ; j < numOptEdges ; j++ ) {
1634 if ( ( optEdges[i].v1 == optEdges[j].v1 && optEdges[i].v2 == optEdges[j].v2 )
1635 || ( optEdges[i].v1 == optEdges[j].v2 && optEdges[i].v2 == optEdges[j].v1 ) ) {
1642 common->
Printf(
"%6i original edges\n", numOriginalEdges );
1643 common->
Printf(
"%6i edges after splits\n", numOptEdges );
1644 common->
Printf(
"%6i original vertexes\n", numOriginalVerts );
1645 common->
Printf(
"%6i vertexes after splits\n", numOptVerts );
1660 static void CullUnusedVerts(
optIsland_t *island ) {
1668 for ( prev = &island->
verts ; *prev ; ) {
1671 if ( !vert->
edges ) {
1677 if ( ( edge->
v1 == vert && !edge->
v1link )
1678 || ( edge->
v2 == vert && !edge->
v2link ) ) {
1682 UnlinkEdge( edge, island );
1712 static void OptimizeIsland(
optIsland_t *island ) {
1715 AddInteriorEdges( island );
1716 DrawEdges( island );
1720 BuildOptTriangles( island );
1724 RemoveInteriorEdges( island );
1725 DrawEdges( island );
1727 ValidateEdgeCounts( island );
1730 CombineColinearEdges( island );
1731 CullUnusedVerts( island );
1732 DrawEdges( island );
1736 AddInteriorEdges( island );
1737 DrawEdges( island );
1741 BuildOptTriangles( island );
1744 RegenerateTriangles( island );
1762 island->
verts = vert;
1764 for ( e = vert->
edges ; e ; ) {
1772 if ( e->
v1 == vert ) {
1773 AddVertexToIsland_r( e->
v2, island );
1777 if ( e->
v2 == vert ) {
1778 AddVertexToIsland_r( e->
v1, island );
1782 common->
Error(
"AddVertexToIsland_r: mislinked vert" );
1810 if ( optVerts[i].addedToIsland ) {
1814 memset( &island, 0,
sizeof( island ) );
1816 AddVertexToIsland_r( &optVerts[i], &island );
1817 OptimizeIsland( &island );
1830 memset( &island, 0,
sizeof( island ) );
1836 island.
verts = &optVerts[
i];
1839 for ( i = 0 ; i < numOptEdges ; i++ ) {
1841 island.
edges = &optEdges[
i];
1844 OptimizeIsland( &island );
1855 static bool PointInSourceTris(
float x,
float y,
float z,
optimizeGroup_t *opt ) {
1867 for ( tri = opt->
triList ; tri ; tri = tri->
next ) {
1899 AddOriginalEdges( opt );
1905 SeparateIslands( opt );
1907 DontSeparateIslands( opt );
1931 for ( group = groups ; group ; group = group->
nextGroup ) {
1932 for ( tri = group->
triList ; tri ; tri = tri->
next ) {
1948 int c_in, c_edge, c_tjunc2;
1959 for ( group = groupList ; group ; group = group->
nextGroup ) {
1960 OptimizeOptList( group );
1971 common->
Printf(
"----- OptimizeAreaGroups Results -----\n" );
1973 common->
Printf(
"%6i tris after edge removal optimization\n", c_edge );
1974 common->
Printf(
"%6i tris after final t junction fixing\n", c_tjunc2 );
1987 for ( i = 0 ; i < e->
numAreas ; i++ ) {
void cross(float a[], float b[], float c[])
void AddEdgeIfNotAlready(optVertex_t *v1, optVertex_t *v2)
const idVec3 & Normal(void) const
const float * ToFloatPtr(void) const
#define VectorSubtract(a, b, c)
optVertex_t * FindOptVertex(idDrawVert *v, optimizeGroup_t *opt)
struct optVertex_s * islandLink
void FreeTri(mapTri_t *tri)
idVec3 Cross(const idVec3 &a) const
void SetGroupTriPlaneNums(optimizeGroup_t *groups)
struct optTri_s * backTri
void FreeTriList(mapTri_t *a)
void Draw_ClearWindow(void)
struct optimizeGroup_s * groups
struct optTri_s * frontTri
bool AddPoint(const idVec3 &v)
void OptimizeEntity(uEntity_t *e)
GLfloat GLfloat GLfloat v2
mapTri_t * regeneratedTris
void PlaneForTri(const mapTri_t *tri, idPlane &plane)
struct edgeCrossing_s edgeCrossing_t
struct optEdge_s * v1link
struct optVertex_s * optVert[3]
void FixAreaGroupsTjunctions(optimizeGroup_t *groupList)
GLubyte GLubyte GLubyte a
virtual void Printf(const char *fmt,...) id_attribute((format(printf
mapTri_t * AllocTri(void)
struct edgeCrossing_s * next
GLfloat GLfloat GLfloat GLfloat v3
int CountGroupListTris(const optimizeGroup_t *groupList)
struct optEdge_s * islandLink
void FreeTJunctionHash(void)
const idMaterial * material
void SplitOriginalEdgesAtCrossings(optimizeGroup_t *opt)
int CountTriList(const mapTri_t *list)
struct optimizeGroup_s * nextGroup
void * Mem_ClearedAlloc(const int size)
optVertex_t optVerts[MAX_OPT_VERTEXES]
const idMaterial * material
void * Mem_Alloc(const int size)
#define VectorMA(v, s, b, o)
dmapGlobals_t dmapGlobals
virtual void Error(const char *fmt,...) id_attribute((format(printf
bool ContainsPoint(const idVec3 &p) const
struct optEdge_s * v2link
void OptimizeGroupList(optimizeGroup_t *groupList)