lerp.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. #pragma warning(disable:4018) //amckern - 64bit - '<' Singed/Unsigned Mismatch
  2. #include "qrad.h"
  3. int g_lerp_enabled = DEFAULT_LERP_ENABLED;
  4. // =====================================================================================
  5. // TestWallIntersectTri
  6. // Returns true if wall polygon intersects patch polygon
  7. // =====================================================================================
  8. static bool TestWallIntersectTri(const lerpTriangulation_t* const trian, const vec3_t p1, const vec3_t p2, const vec3_t p3)
  9. {
  10. int x;
  11. const lerpWall_t* wall = trian->walls;
  12. dplane_t plane;
  13. #ifdef HLRAD_FASTMATH
  14. PlaneFromPoints(p1,p2,p3,&plane);
  15. #else
  16. plane_from_points(p1, p2, p3, &plane);
  17. #endif
  18. // Try first 'vertical' side
  19. // Since we test each of the 3 segments from patch against wall, only one side of wall needs testing inside
  20. // patch (since they either dont intersect at all at this point, or both line segments intersect inside)
  21. for (x = 0; x < trian->numwalls; x++, wall++)
  22. {
  23. vec3_t point;
  24. // Try side A
  25. #ifdef HLRAD_FASTMATH
  26. if(LineSegmentIntersectsPlane(plane,wall->vertex[0],wall->vertex[3],point))
  27. {
  28. if(PointInTri(point,&plane,p1,p2,p3))
  29. {
  30. #else
  31. if (intersect_linesegment_plane(&plane, wall->vertex[0], wall->vertex[3], point))
  32. {
  33. if (point_in_tri(point, &plane, p1, p2, p3))
  34. {
  35. #endif
  36. #if 0
  37. Verbose
  38. ("Wall side A point @ (%4.3f %4.3f %4.3f) inside patch (%4.3f %4.3f %4.3f) (%4.3f %4.3f %4.3f) (%4.3f %4.3f %4.3f)\n",
  39. point[0], point[1], point[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], p3[0], p3[1], p3[2]);
  40. #endif
  41. return true;
  42. }
  43. }
  44. }
  45. return false;
  46. }
  47. // =====================================================================================
  48. // TestLineSegmentIntersectWall
  49. // Returns true if line would hit the 'wall' (to fix light streaking)
  50. // =====================================================================================
  51. static bool TestLineSegmentIntersectWall(const lerpTriangulation_t* const trian, const vec3_t p1, const vec3_t p2)
  52. {
  53. int x;
  54. const lerpWall_t* wall = trian->walls;
  55. for (x = 0; x < trian->numwalls; x++, wall++)
  56. {
  57. vec3_t point;
  58. #ifdef HLRAD_FASTMATH
  59. if(LineSegmentIntersectsPlane(wall->plane,p1,p2,point))
  60. {
  61. if(PointInWall(wall,point))
  62. {
  63. #else
  64. if (intersect_linesegment_plane(&wall->plane, p1, p2, point))
  65. {
  66. if (point_in_wall(wall, point))
  67. {
  68. #endif
  69. #if 0
  70. Verbose
  71. ("Tested point @ (%4.3f %4.3f %4.3f) blocks segment from (%4.3f %4.3f %4.3f) to (%4.3f %4.3f %4.3f) intersects wall\n",
  72. point[0], point[1], point[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]);
  73. #endif
  74. return true;
  75. }
  76. }
  77. }
  78. return false;
  79. }
  80. // =====================================================================================
  81. // TestTriIntersectWall
  82. // Returns true if line would hit the 'wall' (to fix light streaking)
  83. // =====================================================================================
  84. static bool TestTriIntersectWall(const lerpTriangulation_t* trian, const vec3_t p1, const vec3_t p2,
  85. const vec3_t p3)
  86. {
  87. if (TestLineSegmentIntersectWall(trian, p1, p2) || TestLineSegmentIntersectWall(trian, p1, p3)
  88. || TestLineSegmentIntersectWall(trian, p2, p3))
  89. {
  90. return true;
  91. }
  92. return false;
  93. }
  94. // =====================================================================================
  95. // LerpTriangle
  96. // pt1 must be closest point
  97. // =====================================================================================
  98. #ifdef ZHLT_TEXLIGHT
  99. static void LerpTriangle(const lerpTriangulation_t* const trian, const vec3_t point, vec3_t result, const unsigned pt1, const unsigned pt2, const unsigned pt3, int style) //LRC
  100. #else
  101. static void LerpTriangle(const lerpTriangulation_t* const trian, const vec3_t point, vec3_t result, const unsigned pt1, const unsigned pt2, const unsigned pt3)
  102. #endif
  103. {
  104. patch_t* p1;
  105. patch_t* p2;
  106. patch_t* p3;
  107. vec3_t base;
  108. vec3_t d1;
  109. vec3_t d2;
  110. vec_t x;
  111. vec_t y;
  112. vec_t y1;
  113. vec_t x2;
  114. vec3_t v;
  115. dplane_t ep1;
  116. dplane_t ep2;
  117. p1 = trian->points[pt1];
  118. p2 = trian->points[pt2];
  119. p3 = trian->points[pt3];
  120. #ifdef ZHLT_TEXLIGHT
  121. VectorCopy(*GetTotalLight(p1, style), base); //LRC
  122. VectorSubtract(*GetTotalLight(p2, style), base, d1); //LRC
  123. VectorSubtract(*GetTotalLight(p3, style), base, d2); //LRC
  124. #else
  125. VectorCopy(p1->totallight, base);
  126. VectorSubtract(p2->totallight, base, d1);
  127. VectorSubtract(p3->totallight, base, d2);
  128. #endif
  129. // Get edge normals
  130. VectorSubtract(p1->origin, p2->origin, v);
  131. VectorNormalize(v);
  132. CrossProduct(v, trian->plane->normal, ep1.normal);
  133. ep1.dist = DotProduct(p1->origin, ep1.normal);
  134. VectorSubtract(p1->origin, p3->origin, v);
  135. VectorNormalize(v);
  136. CrossProduct(v, trian->plane->normal, ep2.normal);
  137. ep2.dist = DotProduct(p1->origin, ep2.normal);
  138. x = DotProduct(point, ep1.normal) - ep1.dist;
  139. y = DotProduct(point, ep2.normal) - ep2.dist;
  140. y1 = DotProduct(p2->origin, ep2.normal) - ep2.dist;
  141. x2 = DotProduct(p3->origin, ep1.normal) - ep1.dist;
  142. VectorCopy(base, result);
  143. if (fabs(x2) >= ON_EPSILON)
  144. {
  145. int i;
  146. for (i = 0; i < 3; i++)
  147. {
  148. result[i] += x * d2[i] / x2;
  149. }
  150. }
  151. if (fabs(y1) >= ON_EPSILON)
  152. {
  153. int i;
  154. for (i = 0; i < 3; i++)
  155. {
  156. result[i] += y * d1[i] / y1;
  157. }
  158. }
  159. }
  160. // =====================================================================================
  161. // LerpNearest
  162. // =====================================================================================
  163. #ifdef ZHLT_TEXLIGHT
  164. static void LerpNearest(const lerpTriangulation_t* const trian, vec3_t result, int style) //LRC
  165. #else
  166. static void LerpNearest(const lerpTriangulation_t* const trian, vec3_t result)
  167. #endif
  168. {
  169. unsigned x;
  170. unsigned numpoints = trian->numpoints;
  171. patch_t* patch;
  172. // Find nearest in original face
  173. for (x = 0; x < numpoints; x++)
  174. {
  175. patch = trian->points[trian->dists[x].patch];
  176. if (patch->faceNumber == trian->facenum)
  177. {
  178. #ifdef ZHLT_TEXLIGHT
  179. VectorCopy(*GetTotalLight(patch, style), result); //LRC
  180. #else
  181. VectorCopy(patch->totallight, result);
  182. #endif
  183. return;
  184. }
  185. }
  186. // If none in nearest face, settle for nearest
  187. if (numpoints)
  188. {
  189. #ifdef ZHLT_TEXLIGHT
  190. VectorCopy(*GetTotalLight(trian->points[trian->dists[0].patch], style), result); //LRC
  191. #else
  192. VectorCopy(trian->points[trian->dists[0].patch]->totallight, result);
  193. #endif
  194. }
  195. else
  196. {
  197. VectorClear(result);
  198. }
  199. }
  200. // =====================================================================================
  201. // LerpEdge
  202. // =====================================================================================
  203. #ifdef ZHLT_TEXLIGHT
  204. static bool LerpEdge(const lerpTriangulation_t* const trian, const vec3_t point, vec3_t result, int style) //LRC
  205. #else
  206. static bool LerpEdge(const lerpTriangulation_t* const trian, const vec3_t point, vec3_t result)
  207. #endif
  208. {
  209. patch_t* p1;
  210. patch_t* p2;
  211. patch_t* p3;
  212. vec3_t v1;
  213. vec3_t v2;
  214. vec_t d;
  215. p1 = trian->points[trian->dists[0].patch];
  216. p2 = trian->points[trian->dists[1].patch];
  217. p3 = trian->points[trian->dists[2].patch];
  218. VectorSubtract(point, p1->origin, v2);
  219. VectorNormalize(v2);
  220. // Try nearest and 2
  221. if (!TestLineSegmentIntersectWall(trian, p1->origin, p2->origin))
  222. {
  223. VectorSubtract(p2->origin, p1->origin, v1);
  224. VectorNormalize(v1);
  225. d = DotProduct(v2, v1);
  226. if (d >= ON_EPSILON)
  227. {
  228. int i;
  229. vec_t length1;
  230. vec_t length2;
  231. vec3_t segment;
  232. vec_t total_length;
  233. VectorSubtract(point, p1->origin, segment);
  234. length1 = VectorLength(segment);
  235. VectorSubtract(point, p2->origin, segment);
  236. length2 = VectorLength(segment);
  237. total_length = length1 + length2;
  238. for (i = 0; i < 3; i++)
  239. {
  240. #ifdef ZHLT_TEXLIGHT
  241. result[i] = (((*GetTotalLight(p1, style))[i] * length2) + ((*GetTotalLight(p1, style))[i] * length1)) / total_length; //LRC
  242. #else
  243. result[i] = ((p1->totallight[i] * length2) + (p2->totallight[i] * length1)) / total_length;
  244. #endif
  245. }
  246. return true;
  247. }
  248. }
  249. // Try nearest and 3
  250. if (!TestLineSegmentIntersectWall(trian, p1->origin, p3->origin))
  251. {
  252. VectorSubtract(p3->origin, p1->origin, v1);
  253. VectorNormalize(v1);
  254. d = DotProduct(v2, v1);
  255. if (d >= ON_EPSILON)
  256. {
  257. int i;
  258. vec_t length1;
  259. vec_t length2;
  260. vec3_t segment;
  261. vec_t total_length;
  262. VectorSubtract(point, p1->origin, segment);
  263. length1 = VectorLength(segment);
  264. VectorSubtract(point, p3->origin, segment);
  265. length2 = VectorLength(segment);
  266. total_length = length1 + length2;
  267. for (i = 0; i < 3; i++)
  268. {
  269. #ifdef ZHLT_TEXLIGHT
  270. result[i] = (((*GetTotalLight(p1, style))[i] * length2) + ((*GetTotalLight(p3, style))[i] * length1)) / total_length; //LRC
  271. #else
  272. result[i] = ((p1->totallight[i] * length2) + (p3->totallight[i] * length1)) / total_length;
  273. #endif
  274. }
  275. return true;
  276. }
  277. }
  278. return false;
  279. }
  280. // =====================================================================================
  281. //
  282. // SampleTriangulation
  283. //
  284. // =====================================================================================
  285. // =====================================================================================
  286. // dist_sorter
  287. // =====================================================================================
  288. static int CDECL dist_sorter(const void* p1, const void* p2)
  289. {
  290. lerpDist_t* dist1 = (lerpDist_t*) p1;
  291. lerpDist_t* dist2 = (lerpDist_t*) p2;
  292. if (dist1->dist < dist2->dist)
  293. {
  294. return -1;
  295. }
  296. else if (dist1->dist > dist2->dist)
  297. {
  298. return 1;
  299. }
  300. else
  301. {
  302. return 0;
  303. }
  304. }
  305. // =====================================================================================
  306. // FindDists
  307. // =====================================================================================
  308. static void FindDists(const lerpTriangulation_t* const trian, const vec3_t point)
  309. {
  310. unsigned x;
  311. unsigned numpoints = trian->numpoints;
  312. patch_t** patch = trian->points;
  313. lerpDist_t* dists = trian->dists;
  314. vec3_t delta;
  315. for (x = 0; x < numpoints; x++, patch++, dists++)
  316. {
  317. VectorSubtract((*patch)->origin, point, delta);
  318. dists->dist = VectorLength(delta);
  319. dists->patch = x;
  320. }
  321. qsort((void*)trian->dists, (size_t) numpoints, sizeof(lerpDist_t), dist_sorter);
  322. }
  323. // =====================================================================================
  324. // SampleTriangulation
  325. // =====================================================================================
  326. #ifdef ZHLT_TEXLIGHT
  327. void SampleTriangulation(const lerpTriangulation_t* const trian, vec3_t point, vec3_t result, int style) //LRC
  328. #else
  329. void SampleTriangulation(const lerpTriangulation_t* const trian, vec3_t point, vec3_t result)
  330. #endif
  331. {
  332. FindDists(trian, point);
  333. if ((trian->numpoints > 3) && (g_lerp_enabled))
  334. {
  335. unsigned pt1;
  336. unsigned pt2;
  337. unsigned pt3;
  338. vec_t* p1;
  339. vec_t* p2;
  340. vec_t* p3;
  341. dplane_t plane;
  342. pt1 = trian->dists[0].patch;
  343. pt2 = trian->dists[1].patch;
  344. pt3 = trian->dists[2].patch;
  345. p1 = trian->points[pt1]->origin;
  346. p2 = trian->points[pt2]->origin;
  347. p3 = trian->points[pt3]->origin;
  348. #ifdef HLRAD_FASTMATH // KGP
  349. PlaneFromPoints(p1,p2,p3,&plane);
  350. SnapToPlane(&plane,point,0.0);
  351. if(PointInTri(point,&plane,p1,p2,p3))
  352. {
  353. #else
  354. plane_from_points(p1, p2, p3, &plane);
  355. SnapToPlane(&plane, point, 0.0);
  356. if (point_in_tri(point, &plane, p1, p2, p3))
  357. { // TODO check edges/tri for blocking by wall
  358. #endif
  359. if (!TestWallIntersectTri(trian, p1, p2, p3) && !TestTriIntersectWall(trian, p1, p2, p3))
  360. {
  361. #ifdef ZHLT_TEXLIGHT
  362. LerpTriangle(trian, point, result, pt1, pt2, pt3, style); //LRC
  363. #else
  364. LerpTriangle(trian, point, result, pt1, pt2, pt3);
  365. #endif
  366. return;
  367. }
  368. }
  369. else
  370. {
  371. #ifdef ZHLT_TEXLIGHT
  372. if (LerpEdge(trian, point, result, style)) //LRC
  373. #else
  374. if (LerpEdge(trian, point, result))
  375. #endif
  376. {
  377. return;
  378. }
  379. }
  380. }
  381. #ifdef ZHLT_TEXLIGHT
  382. LerpNearest(trian, result, style); //LRC
  383. #else
  384. LerpNearest(trian, result);
  385. #endif
  386. }
  387. // =====================================================================================
  388. // AddPatchToTriangulation
  389. // =====================================================================================
  390. static void AddPatchToTriangulation(lerpTriangulation_t* trian, patch_t* patch)
  391. {
  392. if (!(patch->flags & ePatchFlagOutside))
  393. {
  394. int pnum = trian->numpoints;
  395. if (pnum >= trian->maxpoints)
  396. {
  397. trian->points = (patch_t**)realloc(trian->points, sizeof(patch_t*) * (trian->maxpoints + DEFAULT_MAX_LERP_POINTS));
  398. hlassume(trian->points != NULL, assume_NoMemory);
  399. memset(trian->points + trian->maxpoints, 0, sizeof(patch_t*) * DEFAULT_MAX_LERP_POINTS); // clear the new block
  400. trian->maxpoints += DEFAULT_MAX_LERP_POINTS;
  401. }
  402. trian->points[pnum] = patch;
  403. trian->numpoints++;
  404. }
  405. }
  406. // =====================================================================================
  407. // CreateWalls
  408. // =====================================================================================
  409. static void CreateWalls(lerpTriangulation_t* trian, const dface_t* const face)
  410. {
  411. const dplane_t* p = getPlaneFromFace(face);
  412. int facenum = face - g_dfaces;
  413. int x;
  414. for (x = 0; x < face->numedges; x++)
  415. {
  416. edgeshare_t* es;
  417. dface_t* f2;
  418. int edgenum = g_dsurfedges[face->firstedge + x];
  419. if (edgenum > 0)
  420. {
  421. es = &g_edgeshare[edgenum];
  422. f2 = es->faces[1];
  423. }
  424. else
  425. {
  426. es = &g_edgeshare[-edgenum];
  427. f2 = es->faces[0];
  428. }
  429. // Build Wall for non-coplanar neighbhors
  430. if (f2 && !es->coplanar && VectorCompare(vec3_origin, es->interface_normal))
  431. {
  432. const dplane_t* plane = getPlaneFromFace(f2);
  433. // if plane isn't facing us, ignore it
  434. if (DotProduct(plane->normal, g_face_centroids[facenum]) < plane->dist)
  435. {
  436. continue;
  437. }
  438. {
  439. vec3_t delta;
  440. vec3_t p0;
  441. vec3_t p1;
  442. lerpWall_t* wall;
  443. if (trian->numwalls >= trian->maxwalls)
  444. {
  445. trian->walls =
  446. (lerpWall_t*)realloc(trian->walls, sizeof(lerpWall_t) * (trian->maxwalls + DEFAULT_MAX_LERP_WALLS));
  447. hlassume(trian->walls != NULL, assume_NoMemory);
  448. memset(trian->walls + trian->maxwalls, 0, sizeof(lerpWall_t) * DEFAULT_MAX_LERP_WALLS); // clear the new block
  449. trian->maxwalls += DEFAULT_MAX_LERP_WALLS;
  450. }
  451. wall = &trian->walls[trian->numwalls];
  452. trian->numwalls++;
  453. VectorScale(p->normal, 10000.0, delta);
  454. VectorCopy(g_dvertexes[g_dedges[abs(edgenum)].v[0]].point, p0);
  455. VectorCopy(g_dvertexes[g_dedges[abs(edgenum)].v[1]].point, p1);
  456. // Adjust for origin-based models
  457. // technically we should use the other faces g_face_offset entries
  458. // If they are nonzero, it has to be from the same model with
  459. // the same offset, so we are cool
  460. VectorAdd(p0, g_face_offset[facenum], p0);
  461. VectorAdd(p1, g_face_offset[facenum], p1);
  462. VectorAdd(p0, delta, wall->vertex[0]);
  463. VectorAdd(p1, delta, wall->vertex[1]);
  464. VectorSubtract(p1, delta, wall->vertex[2]);
  465. VectorSubtract(p0, delta, wall->vertex[3]);
  466. {
  467. vec3_t delta1;
  468. vec3_t delta2;
  469. vec3_t normal;
  470. vec_t dist;
  471. VectorSubtract(wall->vertex[2], wall->vertex[1], delta1);
  472. VectorSubtract(wall->vertex[0], wall->vertex[1], delta2);
  473. CrossProduct(delta1, delta2, normal);
  474. VectorNormalize(normal);
  475. dist = DotProduct(normal, p0);
  476. VectorCopy(normal, wall->plane.normal);
  477. wall->plane.dist = dist;
  478. }
  479. }
  480. }
  481. }
  482. }
  483. // =====================================================================================
  484. // AllocTriangulation
  485. // =====================================================================================
  486. static lerpTriangulation_t* AllocTriangulation()
  487. {
  488. lerpTriangulation_t* trian = (lerpTriangulation_t*)calloc(1, sizeof(lerpTriangulation_t));
  489. trian->maxpoints = DEFAULT_MAX_LERP_POINTS;
  490. trian->maxwalls = DEFAULT_MAX_LERP_WALLS;
  491. trian->points = (patch_t**)calloc(DEFAULT_MAX_LERP_POINTS, sizeof(patch_t*));
  492. trian->walls = (lerpWall_t*)calloc(DEFAULT_MAX_LERP_WALLS, sizeof(lerpWall_t));
  493. hlassume(trian->points != NULL, assume_NoMemory);
  494. hlassume(trian->walls != NULL, assume_NoMemory);
  495. return trian;
  496. }
  497. // =====================================================================================
  498. // FreeTriangulation
  499. // =====================================================================================
  500. void FreeTriangulation(lerpTriangulation_t* trian)
  501. {
  502. free(trian->dists);
  503. free(trian->points);
  504. free(trian->walls);
  505. free(trian);
  506. }
  507. // =====================================================================================
  508. // CreateTriangulation
  509. // =====================================================================================
  510. lerpTriangulation_t* CreateTriangulation(const unsigned int facenum)
  511. {
  512. const dface_t* f = g_dfaces + facenum;
  513. const dplane_t* p = getPlaneFromFace(f);
  514. lerpTriangulation_t* trian = AllocTriangulation();
  515. patch_t* patch;
  516. unsigned int j;
  517. dface_t* f2;
  518. trian->facenum = facenum;
  519. trian->plane = p;
  520. trian->face = f;
  521. for (patch = g_face_patches[facenum]; patch; patch = patch->next)
  522. {
  523. AddPatchToTriangulation(trian, patch);
  524. }
  525. CreateWalls(trian, f);
  526. for (j = 0; j < f->numedges; j++)
  527. {
  528. edgeshare_t* es;
  529. int edgenum = g_dsurfedges[f->firstedge + j];
  530. if (edgenum > 0)
  531. {
  532. es = &g_edgeshare[edgenum];
  533. f2 = es->faces[1];
  534. }
  535. else
  536. {
  537. es = &g_edgeshare[-edgenum];
  538. f2 = es->faces[0];
  539. }
  540. if (!es->coplanar && VectorCompare(vec3_origin, es->interface_normal))
  541. {
  542. continue;
  543. }
  544. for (patch = g_face_patches[f2 - g_dfaces]; patch; patch = patch->next)
  545. {
  546. AddPatchToTriangulation(trian, patch);
  547. }
  548. }
  549. trian->dists = (lerpDist_t*)calloc(trian->numpoints, sizeof(lerpDist_t));
  550. #ifdef HLRAD_HULLU
  551. //Get rid off error that seems to happen with some opaque faces (when opaque face have all edges 'out' of map)
  552. if(trian->numpoints != 0)
  553. #endif
  554. hlassume(trian->dists != NULL, assume_NoMemory);
  555. return trian;
  556. }