tr_marks.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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. // tr_marks.c -- polygon projection on the world polygons
  19. #include "tr_local.h"
  20. //#include "assert.h"
  21. #define MAX_VERTS_ON_POLY 64
  22. #define MARKER_OFFSET 0 // 1
  23. /*
  24. =============
  25. R_ChopPolyBehindPlane
  26. Out must have space for two more vertexes than in
  27. =============
  28. */
  29. #define SIDE_FRONT 0
  30. #define SIDE_BACK 1
  31. #define SIDE_ON 2
  32. static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
  33. int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
  34. vec3_t normal, vec_t dist, vec_t epsilon) {
  35. float dists[MAX_VERTS_ON_POLY+4];
  36. int sides[MAX_VERTS_ON_POLY+4];
  37. int counts[3];
  38. float dot;
  39. int i, j;
  40. float *p1, *p2, *clip;
  41. float d;
  42. // don't clip if it might overflow
  43. if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
  44. *numOutPoints = 0;
  45. return;
  46. }
  47. counts[0] = counts[1] = counts[2] = 0;
  48. // determine sides for each point
  49. for ( i = 0 ; i < numInPoints ; i++ ) {
  50. dot = DotProduct( inPoints[i], normal );
  51. dot -= dist;
  52. dists[i] = dot;
  53. if ( dot > epsilon ) {
  54. sides[i] = SIDE_FRONT;
  55. } else if ( dot < -epsilon ) {
  56. sides[i] = SIDE_BACK;
  57. } else {
  58. sides[i] = SIDE_ON;
  59. }
  60. counts[sides[i]]++;
  61. }
  62. sides[i] = sides[0];
  63. dists[i] = dists[0];
  64. *numOutPoints = 0;
  65. if ( !counts[0] ) {
  66. return;
  67. }
  68. if ( !counts[1] ) {
  69. *numOutPoints = numInPoints;
  70. Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
  71. return;
  72. }
  73. for ( i = 0 ; i < numInPoints ; i++ ) {
  74. p1 = inPoints[i];
  75. clip = outPoints[ *numOutPoints ];
  76. if ( sides[i] == SIDE_ON ) {
  77. VectorCopy( p1, clip );
  78. (*numOutPoints)++;
  79. continue;
  80. }
  81. if ( sides[i] == SIDE_FRONT ) {
  82. VectorCopy( p1, clip );
  83. (*numOutPoints)++;
  84. clip = outPoints[ *numOutPoints ];
  85. }
  86. if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
  87. continue;
  88. }
  89. // generate a split point
  90. p2 = inPoints[ (i+1) % numInPoints ];
  91. d = dists[i] - dists[i+1];
  92. if ( d == 0 ) {
  93. dot = 0;
  94. } else {
  95. dot = dists[i] / d;
  96. }
  97. // clip xyz
  98. for (j=0 ; j<3 ; j++) {
  99. clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
  100. }
  101. (*numOutPoints)++;
  102. }
  103. }
  104. /*
  105. =================
  106. R_BoxSurfaces_r
  107. =================
  108. */
  109. void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
  110. int s, c;
  111. msurface_t *surf, **mark;
  112. // do the tail recursion in a loop
  113. while ( node->contents == -1 ) {
  114. s = BoxOnPlaneSide( mins, maxs, node->plane );
  115. if (s == 1) {
  116. node = node->children[0];
  117. } else if (s == 2) {
  118. node = node->children[1];
  119. } else {
  120. R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
  121. node = node->children[1];
  122. }
  123. }
  124. // add the individual surfaces
  125. mark = node->firstmarksurface;
  126. c = node->nummarksurfaces;
  127. while (c--) {
  128. //
  129. if (*listlength >= listsize) break;
  130. //
  131. surf = *mark;
  132. // check if the surface has NOIMPACT or NOMARKS set
  133. if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
  134. || ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
  135. surf->viewCount = tr.viewCount;
  136. }
  137. // extra check for surfaces to avoid list overflows
  138. else if (*(surf->data) == SF_FACE) {
  139. // the face plane should go through the box
  140. s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );
  141. if (s == 1 || s == 2) {
  142. surf->viewCount = tr.viewCount;
  143. } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {
  144. // don't add faces that make sharp angles with the projection direction
  145. surf->viewCount = tr.viewCount;
  146. }
  147. }
  148. else if (*(surfaceType_t *) (surf->data) != SF_GRID) surf->viewCount = tr.viewCount;
  149. // check the viewCount because the surface may have
  150. // already been added if it spans multiple leafs
  151. if (surf->viewCount != tr.viewCount) {
  152. surf->viewCount = tr.viewCount;
  153. list[*listlength] = (surfaceType_t *) surf->data;
  154. (*listlength)++;
  155. }
  156. mark++;
  157. }
  158. }
  159. /*
  160. =================
  161. R_AddMarkFragments
  162. =================
  163. */
  164. void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
  165. int numPlanes, vec3_t *normals, float *dists,
  166. int maxPoints, vec3_t pointBuffer,
  167. int maxFragments, markFragment_t *fragmentBuffer,
  168. int *returnedPoints, int *returnedFragments,
  169. vec3_t mins, vec3_t maxs) {
  170. int pingPong, i;
  171. markFragment_t *mf;
  172. // chop the surface by all the bounding planes of the to be projected polygon
  173. pingPong = 0;
  174. for ( i = 0 ; i < numPlanes ; i++ ) {
  175. R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
  176. &numClipPoints, clipPoints[!pingPong],
  177. normals[i], dists[i], 0.5 );
  178. pingPong ^= 1;
  179. if ( numClipPoints == 0 ) {
  180. break;
  181. }
  182. }
  183. // completely clipped away?
  184. if ( numClipPoints == 0 ) {
  185. return;
  186. }
  187. // add this fragment to the returned list
  188. if ( numClipPoints + (*returnedPoints) > maxPoints ) {
  189. return; // not enough space for this polygon
  190. }
  191. /*
  192. // all the clip points should be within the bounding box
  193. for ( i = 0 ; i < numClipPoints ; i++ ) {
  194. int j;
  195. for ( j = 0 ; j < 3 ; j++ ) {
  196. if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
  197. if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
  198. }
  199. if (j < 3) break;
  200. }
  201. if (i < numClipPoints) return;
  202. */
  203. mf = fragmentBuffer + (*returnedFragments);
  204. mf->firstPoint = (*returnedPoints);
  205. mf->numPoints = numClipPoints;
  206. Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
  207. (*returnedPoints) += numClipPoints;
  208. (*returnedFragments)++;
  209. }
  210. /*
  211. =================
  212. R_MarkFragments
  213. =================
  214. */
  215. int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
  216. int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
  217. int numsurfaces, numPlanes;
  218. int i, j, k, m, n;
  219. surfaceType_t *surfaces[64];
  220. vec3_t mins, maxs;
  221. int returnedFragments;
  222. int returnedPoints;
  223. vec3_t normals[MAX_VERTS_ON_POLY+2];
  224. float dists[MAX_VERTS_ON_POLY+2];
  225. vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
  226. int numClipPoints;
  227. float *v;
  228. srfSurfaceFace_t *surf;
  229. srfGridMesh_t *cv;
  230. drawVert_t *dv;
  231. vec3_t normal;
  232. vec3_t projectionDir;
  233. vec3_t v1, v2;
  234. int *indexes;
  235. //increment view count for double check prevention
  236. tr.viewCount++;
  237. //
  238. VectorNormalize2( projection, projectionDir );
  239. // find all the brushes that are to be considered
  240. ClearBounds( mins, maxs );
  241. for ( i = 0 ; i < numPoints ; i++ ) {
  242. vec3_t temp;
  243. AddPointToBounds( points[i], mins, maxs );
  244. VectorAdd( points[i], projection, temp );
  245. AddPointToBounds( temp, mins, maxs );
  246. // make sure we get all the leafs (also the one(s) in front of the hit surface)
  247. VectorMA( points[i], -20, projectionDir, temp );
  248. AddPointToBounds( temp, mins, maxs );
  249. }
  250. if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
  251. // create the bounding planes for the to be projected polygon
  252. for ( i = 0 ; i < numPoints ; i++ ) {
  253. VectorSubtract(points[(i+1)%numPoints], points[i], v1);
  254. VectorAdd(points[i], projection, v2);
  255. VectorSubtract(points[i], v2, v2);
  256. CrossProduct(v1, v2, normals[i]);
  257. VectorNormalizeFast(normals[i]);
  258. dists[i] = DotProduct(normals[i], points[i]);
  259. }
  260. // add near and far clipping planes for projection
  261. VectorCopy(projectionDir, normals[numPoints]);
  262. dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
  263. VectorCopy(projectionDir, normals[numPoints+1]);
  264. VectorInverse(normals[numPoints+1]);
  265. dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
  266. numPlanes = numPoints + 2;
  267. numsurfaces = 0;
  268. R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
  269. //assert(numsurfaces <= 64);
  270. //assert(numsurfaces != 64);
  271. returnedPoints = 0;
  272. returnedFragments = 0;
  273. for ( i = 0 ; i < numsurfaces ; i++ ) {
  274. if (*surfaces[i] == SF_GRID) {
  275. cv = (srfGridMesh_t *) surfaces[i];
  276. for ( m = 0 ; m < cv->height - 1 ; m++ ) {
  277. for ( n = 0 ; n < cv->width - 1 ; n++ ) {
  278. // We triangulate the grid and chop all triangles within
  279. // the bounding planes of the to be projected polygon.
  280. // LOD is not taken into account, not such a big deal though.
  281. //
  282. // It's probably much nicer to chop the grid itself and deal
  283. // with this grid as a normal SF_GRID surface so LOD will
  284. // be applied. However the LOD of that chopped grid must
  285. // be synced with the LOD of the original curve.
  286. // One way to do this; the chopped grid shares vertices with
  287. // the original curve. When LOD is applied to the original
  288. // curve the unused vertices are flagged. Now the chopped curve
  289. // should skip the flagged vertices. This still leaves the
  290. // problems with the vertices at the chopped grid edges.
  291. //
  292. // To avoid issues when LOD applied to "hollow curves" (like
  293. // the ones around many jump pads) we now just add a 2 unit
  294. // offset to the triangle vertices.
  295. // The offset is added in the vertex normal vector direction
  296. // so all triangles will still fit together.
  297. // The 2 unit offset should avoid pretty much all LOD problems.
  298. numClipPoints = 3;
  299. dv = cv->verts + m * cv->width + n;
  300. VectorCopy(dv[0].xyz, clipPoints[0][0]);
  301. VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
  302. VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
  303. VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
  304. VectorCopy(dv[1].xyz, clipPoints[0][2]);
  305. VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
  306. // check the normal of this triangle
  307. VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
  308. VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
  309. CrossProduct(v1, v2, normal);
  310. VectorNormalizeFast(normal);
  311. if (DotProduct(normal, projectionDir) < -0.1) {
  312. // add the fragments of this triangle
  313. R_AddMarkFragments(numClipPoints, clipPoints,
  314. numPlanes, normals, dists,
  315. maxPoints, pointBuffer,
  316. maxFragments, fragmentBuffer,
  317. &returnedPoints, &returnedFragments, mins, maxs);
  318. if ( returnedFragments == maxFragments ) {
  319. return returnedFragments; // not enough space for more fragments
  320. }
  321. }
  322. VectorCopy(dv[1].xyz, clipPoints[0][0]);
  323. VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
  324. VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
  325. VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
  326. VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
  327. VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
  328. // check the normal of this triangle
  329. VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
  330. VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
  331. CrossProduct(v1, v2, normal);
  332. VectorNormalizeFast(normal);
  333. if (DotProduct(normal, projectionDir) < -0.05) {
  334. // add the fragments of this triangle
  335. R_AddMarkFragments(numClipPoints, clipPoints,
  336. numPlanes, normals, dists,
  337. maxPoints, pointBuffer,
  338. maxFragments, fragmentBuffer,
  339. &returnedPoints, &returnedFragments, mins, maxs);
  340. if ( returnedFragments == maxFragments ) {
  341. return returnedFragments; // not enough space for more fragments
  342. }
  343. }
  344. }
  345. }
  346. }
  347. else if (*surfaces[i] == SF_FACE) {
  348. surf = ( srfSurfaceFace_t * ) surfaces[i];
  349. // check the normal of this face
  350. if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
  351. continue;
  352. }
  353. /*
  354. VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
  355. VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
  356. CrossProduct(v1, v2, normal);
  357. VectorNormalize(normal);
  358. if (DotProduct(normal, projectionDir) > -0.5) continue;
  359. */
  360. indexes = (int *)( (byte *)surf + surf->ofsIndices );
  361. for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
  362. for ( j = 0 ; j < 3 ; j++ ) {
  363. v = surf->points[0] + VERTEXSIZE * indexes[k+j];;
  364. VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
  365. }
  366. // add the fragments of this face
  367. R_AddMarkFragments( 3 , clipPoints,
  368. numPlanes, normals, dists,
  369. maxPoints, pointBuffer,
  370. maxFragments, fragmentBuffer,
  371. &returnedPoints, &returnedFragments, mins, maxs);
  372. if ( returnedFragments == maxFragments ) {
  373. return returnedFragments; // not enough space for more fragments
  374. }
  375. }
  376. continue;
  377. }
  378. else {
  379. // ignore all other world surfaces
  380. // might be cool to also project polygons on a triangle soup
  381. // however this will probably create huge amounts of extra polys
  382. // even more than the projection onto curves
  383. continue;
  384. }
  385. }
  386. return returnedFragments;
  387. }