tjunction.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "qbsp.h"
  19. typedef struct edgePoint_s {
  20. float intercept;
  21. vec3_t xyz;
  22. struct edgePoint_s *prev, *next;
  23. } edgePoint_t;
  24. typedef struct edgeLine_s {
  25. vec3_t normal1;
  26. float dist1;
  27. vec3_t normal2;
  28. float dist2;
  29. vec3_t origin;
  30. vec3_t dir;
  31. edgePoint_t chain; // unused element of doubly linked list
  32. } edgeLine_t;
  33. typedef struct {
  34. float length;
  35. drawVert_t *dv[2];
  36. } originalEdge_t;
  37. #define MAX_ORIGINAL_EDGES 0x10000
  38. originalEdge_t originalEdges[MAX_ORIGINAL_EDGES];
  39. int numOriginalEdges;
  40. #define MAX_EDGE_LINES 0x10000
  41. edgeLine_t edgeLines[MAX_EDGE_LINES];
  42. int numEdgeLines;
  43. int c_degenerateEdges;
  44. int c_addedVerts;
  45. int c_totalVerts;
  46. int c_natural, c_rotate, c_cant;
  47. // these should be whatever epsilon we actually expect,
  48. // plus SNAP_INT_TO_FLOAT
  49. #define LINE_POSITION_EPSILON 0.25
  50. #define POINT_ON_LINE_EPSILON 0.25
  51. /*
  52. ====================
  53. InsertPointOnEdge
  54. ====================
  55. */
  56. void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) {
  57. vec3_t delta;
  58. float d;
  59. edgePoint_t *p, *scan;
  60. VectorSubtract( v, e->origin, delta );
  61. d = DotProduct( delta, e->dir );
  62. p = malloc( sizeof(edgePoint_t) );
  63. p->intercept = d;
  64. VectorCopy( v, p->xyz );
  65. if ( e->chain.next == &e->chain ) {
  66. e->chain.next = e->chain.prev = p;
  67. p->next = p->prev = &e->chain;
  68. return;
  69. }
  70. scan = e->chain.next;
  71. for ( ; scan != &e->chain ; scan = scan->next ) {
  72. d = p->intercept - scan->intercept;
  73. if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {
  74. free( p );
  75. return; // the point is already set
  76. }
  77. if ( p->intercept < scan->intercept ) {
  78. // insert here
  79. p->prev = scan->prev;
  80. p->next = scan;
  81. scan->prev->next = p;
  82. scan->prev = p;
  83. return;
  84. }
  85. }
  86. // add at the end
  87. p->prev = scan->prev;
  88. p->next = scan;
  89. scan->prev->next = p;
  90. scan->prev = p;
  91. }
  92. /*
  93. ====================
  94. AddEdge
  95. ====================
  96. */
  97. int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) {
  98. int i;
  99. edgeLine_t *e;
  100. float d;
  101. vec3_t dir;
  102. VectorSubtract( v2, v1, dir );
  103. d = VectorNormalize( dir, dir );
  104. if ( d < 0.1 ) {
  105. // if we added a 0 length vector, it would make degenerate planes
  106. c_degenerateEdges++;
  107. return -1;
  108. }
  109. if ( !createNonAxial ) {
  110. if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {
  111. if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {
  112. Error( "MAX_ORIGINAL_EDGES" );
  113. }
  114. originalEdges[ numOriginalEdges ].dv[0] = (drawVert_t *)v1;
  115. originalEdges[ numOriginalEdges ].dv[1] = (drawVert_t *)v2;
  116. originalEdges[ numOriginalEdges ].length = d;
  117. numOriginalEdges++;
  118. return -1;
  119. }
  120. }
  121. for ( i = 0 ; i < numEdgeLines ; i++ ) {
  122. e = &edgeLines[i];
  123. d = DotProduct( v1, e->normal1 ) - e->dist1;
  124. if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
  125. continue;
  126. }
  127. d = DotProduct( v1, e->normal2 ) - e->dist2;
  128. if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
  129. continue;
  130. }
  131. d = DotProduct( v2, e->normal1 ) - e->dist1;
  132. if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
  133. continue;
  134. }
  135. d = DotProduct( v2, e->normal2 ) - e->dist2;
  136. if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
  137. continue;
  138. }
  139. // this is the edge
  140. InsertPointOnEdge( v1, e );
  141. InsertPointOnEdge( v2, e );
  142. return i;
  143. }
  144. // create a new edge
  145. if ( numEdgeLines >= MAX_EDGE_LINES ) {
  146. Error( "MAX_EDGE_LINES" );
  147. }
  148. e = &edgeLines[ numEdgeLines ];
  149. numEdgeLines++;
  150. e->chain.next = e->chain.prev = &e->chain;
  151. VectorCopy( v1, e->origin );
  152. VectorCopy( dir, e->dir );
  153. MakeNormalVectors( e->dir, e->normal1, e->normal2 );
  154. e->dist1 = DotProduct( e->origin, e->normal1 );
  155. e->dist2 = DotProduct( e->origin, e->normal2 );
  156. InsertPointOnEdge( v1, e );
  157. InsertPointOnEdge( v2, e );
  158. return numEdgeLines - 1;
  159. }
  160. /*
  161. ====================
  162. AddSurfaceEdges
  163. ====================
  164. */
  165. void AddSurfaceEdges( mapDrawSurface_t *ds ) {
  166. int i;
  167. for ( i = 0 ; i < ds->numVerts ; i++ ) {
  168. // save the edge number in the lightmap field
  169. // so we don't need to look it up again
  170. ds->verts[i].lightmap[0] =
  171. AddEdge( ds->verts[i].xyz, ds->verts[(i+1) % ds->numVerts].xyz, qfalse );
  172. }
  173. }
  174. /*
  175. ================
  176. ColinearEdge
  177. ================
  178. */
  179. qboolean ColinearEdge( vec3_t v1, vec3_t v2, vec3_t v3 ) {
  180. vec3_t midpoint, dir, offset, on;
  181. float d;
  182. VectorSubtract( v2, v1, midpoint );
  183. VectorSubtract( v3, v1, dir );
  184. d = VectorNormalize( dir, dir );
  185. if ( d == 0 ) {
  186. return qfalse; // degenerate
  187. }
  188. d = DotProduct( midpoint, dir );
  189. VectorScale( dir, d, on );
  190. VectorSubtract( midpoint, on, offset );
  191. d = VectorLength ( offset );
  192. if ( d < 0.1 ) {
  193. return qtrue;
  194. }
  195. return qfalse;
  196. }
  197. /*
  198. ====================
  199. AddPatchEdges
  200. Add colinear border edges, which will fix some classes of patch to
  201. brush tjunctions
  202. ====================
  203. */
  204. void AddPatchEdges( mapDrawSurface_t *ds ) {
  205. int i;
  206. float *v1, *v2, *v3;
  207. for ( i = 0 ; i < ds->patchWidth - 2; i+=2 ) {
  208. v1 = ds->verts[ i ].xyz;
  209. v2 = ds->verts[ i + 1 ].xyz;
  210. v3 = ds->verts[ i + 2 ].xyz;
  211. // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
  212. if ( ColinearEdge( v1, v2, v3 ) ) {
  213. AddEdge( v1, v3, qfalse );
  214. }
  215. v1 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i ].xyz;
  216. v2 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 1 ].xyz;
  217. v3 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 2 ].xyz;
  218. // if v2 is on the v1 to v3 line, add an edge from v1 to v3
  219. if ( ColinearEdge( v1, v2, v3 ) ) {
  220. AddEdge( v1, v3, qfalse );
  221. }
  222. }
  223. for ( i = 0 ; i < ds->patchHeight - 2 ; i+=2 ) {
  224. v1 = ds->verts[ i * ds->patchWidth ].xyz;
  225. v2 = ds->verts[ ( i + 1 ) * ds->patchWidth ].xyz;
  226. v3 = ds->verts[ ( i + 2 ) * ds->patchWidth ].xyz;
  227. // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
  228. if ( ColinearEdge( v1, v2, v3 ) ) {
  229. AddEdge( v1, v3, qfalse );
  230. }
  231. v1 = ds->verts[ ( ds->patchWidth - 1 ) + i * ds->patchWidth ].xyz;
  232. v2 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 1 ) * ds->patchWidth ].xyz;
  233. v3 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 2 ) * ds->patchWidth ].xyz;
  234. // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
  235. if ( ColinearEdge( v1, v2, v3 ) ) {
  236. AddEdge( v1, v3, qfalse );
  237. }
  238. }
  239. }
  240. /*
  241. ====================
  242. FixSurfaceJunctions
  243. ====================
  244. */
  245. #define MAX_SURFACE_VERTS 256
  246. void FixSurfaceJunctions( mapDrawSurface_t *ds ) {
  247. int i, j, k;
  248. edgeLine_t *e;
  249. edgePoint_t *p;
  250. int originalVerts;
  251. int counts[MAX_SURFACE_VERTS];
  252. int originals[MAX_SURFACE_VERTS];
  253. int firstVert[MAX_SURFACE_VERTS];
  254. drawVert_t verts[MAX_SURFACE_VERTS], *v1, *v2;
  255. int numVerts;
  256. float start, end, frac;
  257. vec3_t delta;
  258. originalVerts = ds->numVerts;
  259. numVerts = 0;
  260. for ( i = 0 ; i < ds->numVerts ; i++ ) {
  261. counts[i] = 0;
  262. firstVert[i] = numVerts;
  263. // copy first vert
  264. if ( numVerts == MAX_SURFACE_VERTS ) {
  265. Error( "MAX_SURFACE_VERTS" );
  266. }
  267. verts[numVerts] = ds->verts[i];
  268. originals[numVerts] = i;
  269. numVerts++;
  270. // check to see if there are any t junctions before the next vert
  271. v1 = &ds->verts[i];
  272. v2 = &ds->verts[ (i+1) % ds->numVerts ];
  273. j = (int)ds->verts[i].lightmap[0];
  274. if ( j == -1 ) {
  275. continue; // degenerate edge
  276. }
  277. e = &edgeLines[ j ];
  278. VectorSubtract( v1->xyz, e->origin, delta );
  279. start = DotProduct( delta, e->dir );
  280. VectorSubtract( v2->xyz, e->origin, delta );
  281. end = DotProduct( delta, e->dir );
  282. if ( start < end ) {
  283. p = e->chain.next;
  284. } else {
  285. p = e->chain.prev;
  286. }
  287. for ( ; p != &e->chain ; ) {
  288. if ( start < end ) {
  289. if ( p->intercept > end - ON_EPSILON ) {
  290. break;
  291. }
  292. } else {
  293. if ( p->intercept < end + ON_EPSILON ) {
  294. break;
  295. }
  296. }
  297. if (
  298. ( start < end && p->intercept > start + ON_EPSILON ) ||
  299. ( start > end && p->intercept < start - ON_EPSILON ) ) {
  300. // insert this point
  301. if ( numVerts == MAX_SURFACE_VERTS ) {
  302. Error( "MAX_SURFACE_VERTS" );
  303. }
  304. // take the exact intercept point
  305. VectorCopy( p->xyz, verts[ numVerts ].xyz );
  306. // copy the normal
  307. VectorCopy( v1->normal, verts[ numVerts ].normal );
  308. // interpolate the texture coordinates
  309. frac = ( p->intercept - start ) / ( end - start );
  310. for ( j = 0 ; j < 2 ; j++ ) {
  311. verts[ numVerts ].st[j] = v1->st[j] +
  312. frac * ( v2->st[j] - v1->st[j] );
  313. }
  314. originals[numVerts] = i;
  315. numVerts++;
  316. counts[i]++;
  317. }
  318. if ( start < end ) {
  319. p = p->next;
  320. } else {
  321. p = p->prev;
  322. }
  323. }
  324. }
  325. c_addedVerts += numVerts - ds->numVerts;
  326. c_totalVerts += numVerts;
  327. // FIXME: check to see if the entire surface degenerated
  328. // after snapping
  329. // rotate the points so that the initial vertex is between
  330. // two non-subdivided edges
  331. for ( i = 0 ; i < numVerts ; i++ ) {
  332. if ( originals[ (i+1) % numVerts ] == originals[ i ] ) {
  333. continue;
  334. }
  335. j = (i + numVerts - 1 ) % numVerts;
  336. k = (i + numVerts - 2 ) % numVerts;
  337. if ( originals[ j ] == originals[ k ] ) {
  338. continue;
  339. }
  340. break;
  341. }
  342. if ( i == 0 ) {
  343. // fine the way it is
  344. c_natural++;
  345. ds->numVerts = numVerts;
  346. ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
  347. memcpy( ds->verts, verts, numVerts * sizeof( *ds->verts ) );
  348. return;
  349. }
  350. if ( i == numVerts ) {
  351. // create a vertex in the middle to start the fan
  352. c_cant++;
  353. /*
  354. memset ( &verts[numVerts], 0, sizeof( verts[numVerts] ) );
  355. for ( i = 0 ; i < numVerts ; i++ ) {
  356. for ( j = 0 ; j < 10 ; j++ ) {
  357. verts[numVerts].xyz[j] += verts[i].xyz[j];
  358. }
  359. }
  360. for ( j = 0 ; j < 10 ; j++ ) {
  361. verts[numVerts].xyz[j] /= numVerts;
  362. }
  363. i = numVerts;
  364. numVerts++;
  365. */
  366. } else {
  367. // just rotate the vertexes
  368. c_rotate++;
  369. }
  370. ds->numVerts = numVerts;
  371. ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
  372. for ( j = 0 ; j < ds->numVerts ; j++ ) {
  373. ds->verts[j] = verts[ ( j + i ) % ds->numVerts ];
  374. }
  375. }
  376. /*
  377. ================
  378. EdgeCompare
  379. ================
  380. */
  381. int EdgeCompare( const void *elem1, const void *elem2 ) {
  382. float d1, d2;
  383. d1 = ((originalEdge_t *)elem1)->length;
  384. d2 = ((originalEdge_t *)elem2)->length;
  385. if ( d1 < d2 ) {
  386. return -1;
  387. }
  388. if ( d2 > d1 ) {
  389. return 1;
  390. }
  391. return 0;
  392. }
  393. /*
  394. ================
  395. FixTJunctions
  396. Call after the surface list has been pruned, but before lightmap allocation
  397. ================
  398. */
  399. void FixTJunctions( entity_t *ent ) {
  400. int i;
  401. mapDrawSurface_t *ds;
  402. int axialEdgeLines;
  403. originalEdge_t *e;
  404. qprintf("----- FixTJunctions -----\n");
  405. numEdgeLines = 0;
  406. numOriginalEdges = 0;
  407. // add all the edges
  408. // this actually creates axial edges, but it
  409. // only creates originalEdge_t structures
  410. // for non-axial edges
  411. for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
  412. ds = &mapDrawSurfs[i];
  413. if ( ds->patch ) {
  414. AddPatchEdges( ds );
  415. } else if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
  416. // miscModels don't add tjunctions
  417. } else {
  418. AddSurfaceEdges( ds );
  419. }
  420. }
  421. axialEdgeLines = numEdgeLines;
  422. // sort the non-axial edges by length
  423. qsort( originalEdges, numOriginalEdges, sizeof(originalEdges[0]), EdgeCompare );
  424. // add the non-axial edges, longest first
  425. // this gives the most accurate edge description
  426. for ( i = 0 ; i < numOriginalEdges ; i++ ) {
  427. e = &originalEdges[i];
  428. e->dv[0]->lightmap[0] = AddEdge( e->dv[0]->xyz, e->dv[1]->xyz, qtrue );
  429. }
  430. qprintf( "%6i axial edge lines\n", axialEdgeLines );
  431. qprintf( "%6i non-axial edge lines\n", numEdgeLines - axialEdgeLines );
  432. qprintf( "%6i degenerate edges\n", c_degenerateEdges );
  433. // insert any needed vertexes
  434. for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
  435. ds = &mapDrawSurfs[i];
  436. if ( ds->patch ) {
  437. continue;
  438. }
  439. if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
  440. continue;
  441. }
  442. FixSurfaceJunctions( ds );
  443. }
  444. qprintf( "%6i verts added for tjunctions\n", c_addedVerts );
  445. qprintf( "%6i total verts\n", c_totalVerts );
  446. qprintf( "%6i naturally ordered\n", c_natural );
  447. qprintf( "%6i rotated orders\n", c_rotate );
  448. qprintf( "%6i can't order\n", c_cant );
  449. }