C5_TRACE.C 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. /* Catacomb Armageddon Source Code
  2. * Copyright (C) 1993-2014 Flat Rock Software
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * 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. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. // C3_TRACE.C
  19. #include "DEF.H"
  20. #pragma hdrstop
  21. /*
  22. =============================================================================
  23. LOCAL CONSTANTS
  24. =============================================================================
  25. */
  26. //
  27. // TESTWALLVISABLE will set the global variable wallvisable to 1 or 0
  28. // depending on if tile.x,tile.y,wallon is visable from focal point
  29. //
  30. #define TESTWALLVISABLE { \
  31. if (tile.y<focal.y) \
  32. voffset = 0; \
  33. else if (tile.y==focal.y) \
  34. voffset = 3; \
  35. else \
  36. voffset = 6; \
  37. if (tile.x==focal.x) \
  38. voffset ++; \
  39. else if (tile.x>focal.x) \
  40. voffset += 2; \
  41. wallvisable = visable[voffset][wallon]; }
  42. /*
  43. =============================================================================
  44. GLOBAL VARIABLES
  45. =============================================================================
  46. */
  47. boolean aborttrace;
  48. /*
  49. =============================================================================
  50. LOCAL VARIABLES
  51. =============================================================================
  52. */
  53. unsigned wallvisable,voffset;
  54. fixed edgex,edgey;
  55. int wallon;
  56. int basecolor;
  57. walltype *oldwall;
  58. //
  59. // offsets from upper left corner of a tile to the left and right edges of
  60. // a given wall (NORTH-WEST)
  61. //
  62. fixed point1x[4] = {GLOBAL1,GLOBAL1,0 ,0 };
  63. fixed point1y[4] = {0 ,GLOBAL1,GLOBAL1,0 };
  64. fixed point2x[4] = {0 ,GLOBAL1,GLOBAL1,0 };
  65. fixed point2y[4] = {0 ,0 ,GLOBAL1 ,GLOBAL1};
  66. //
  67. // offset from tile.x,tile.y of the tile that shares wallon side
  68. // (side is not visable if it is shared)
  69. //
  70. int sharex[4] = { 0, 1, 0,-1};
  71. int sharey[4] = {-1, 0, 1, 0};
  72. //
  73. // amount to move tile.x,tile.y to follow wallon to another tile
  74. //
  75. int followx[4] = {-1, 0, 1, 0};
  76. int followy[4] = { 0,-1, 0, 1};
  77. //
  78. // cornerwall gives the wall on the same tile to start following when the
  79. // wall ends at an empty tile (go around an edge on same tile)
  80. // turnwall gives the wall on tile.x+sharex,tile.y+sharey to start following
  81. // when the wall hits another tile (right angle corner)
  82. //
  83. int cornerwall[4] = {WEST,NORTH,EAST,SOUTH};
  84. int turnwall[4] = {EAST,SOUTH,WEST,NORTH};
  85. //
  86. // wall visabilities in reletive locations
  87. // -,- 0,- +,-
  88. // -,0 0,0 +,0
  89. // -,+ 0,+ +,+
  90. //
  91. int visable[9][4] =
  92. {
  93. {0,1,1,0}, {0,0,1,0}, {0,0,1,1},
  94. {0,1,0,0}, {0,0,0,0}, {0,0,0,1},
  95. {1,1,0,0}, {1,0,0,0}, {1,0,0,1}
  96. };
  97. int startwall[9] = {2,2,3, 1,0,3, 1,0,0};
  98. int backupwall[9] = {3,3,0, 2,0,0, 2,1,1};
  99. int walllength;
  100. /*
  101. =============================================================================
  102. FUNCTIONS
  103. =============================================================================
  104. */
  105. /*
  106. ========================
  107. =
  108. = FollowTrace
  109. =
  110. ========================
  111. */
  112. int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max)
  113. {
  114. int tx,ty,otx,oty;
  115. long absdx,absdy,xstep,ystep;
  116. tx = tracex>>TILESHIFT;
  117. ty = tracey>>TILESHIFT;
  118. spotvis[tx][ty] = true;
  119. absdx=LABS(deltax);
  120. absdy=LABS(deltay);
  121. if (absdx>absdy)
  122. {
  123. ystep = (deltay<<8)/(absdx>>8);
  124. if (!ystep)
  125. ystep = deltay>0 ? 1 : -1;
  126. oty = (tracey+ystep)>>TILESHIFT;
  127. if (deltax>0)
  128. {
  129. //###############
  130. //
  131. // step x by +1
  132. //
  133. //###############
  134. do
  135. {
  136. tx++;
  137. spotvis[tx][ty] = true;
  138. tracey+=ystep;
  139. ty = tracey>>TILESHIFT;
  140. if (ty!=oty)
  141. {
  142. if (tilemap[tx-1][ty])
  143. {
  144. tile.x = tx-1;
  145. tile.y = ty;
  146. return 1;
  147. }
  148. oty = ty;
  149. }
  150. if (tilemap[tx][ty])
  151. {
  152. tile.x = tx;
  153. tile.y = ty;
  154. return 1;
  155. }
  156. } while (--max);
  157. return 0;
  158. }
  159. else
  160. {
  161. //###############
  162. //
  163. // step x by -1
  164. //
  165. //###############
  166. do
  167. {
  168. tx--;
  169. spotvis[tx][ty] = true;
  170. tracey+=ystep;
  171. ty = tracey>>TILESHIFT;
  172. if (ty!=oty)
  173. {
  174. if (tilemap[tx][oty])
  175. {
  176. tile.x = tx;
  177. tile.y = oty;
  178. return 1;
  179. }
  180. oty = ty;
  181. }
  182. if (tilemap[tx][ty])
  183. {
  184. tile.x = tx;
  185. tile.y = ty;
  186. return 1;
  187. }
  188. } while (--max);
  189. return 0;
  190. }
  191. }
  192. else
  193. {
  194. xstep = (deltax<<8)/(absdy>>8);
  195. if (!xstep)
  196. xstep = deltax>0 ? 1 : -1;
  197. otx = (tracex+xstep)>>TILESHIFT;
  198. if (deltay>0)
  199. {
  200. //###############
  201. //
  202. // step y by +1
  203. //
  204. //###############
  205. do
  206. {
  207. ty++;
  208. spotvis[tx][ty] = true;
  209. tracex+=xstep;
  210. tx = tracex>>TILESHIFT;
  211. if (tx!=otx)
  212. {
  213. if (tilemap[tx][ty-1])
  214. {
  215. tile.x = tx;
  216. tile.y = ty-1;
  217. return 1;
  218. }
  219. otx = tx;
  220. }
  221. if (tilemap[tx][ty])
  222. {
  223. tile.x = tx;
  224. tile.y = ty;
  225. return 1;
  226. }
  227. } while (--max);
  228. return 0;
  229. }
  230. else
  231. {
  232. //###############
  233. //
  234. // step y by -1
  235. //
  236. //###############
  237. do
  238. {
  239. ty--;
  240. spotvis[tx][ty] = true;
  241. tracex+=xstep;
  242. tx = tracex>>TILESHIFT;
  243. if (tx!=otx)
  244. {
  245. if (tilemap[otx][ty])
  246. {
  247. tile.x = otx;
  248. tile.y = ty;
  249. return 1;
  250. }
  251. otx = tx;
  252. }
  253. if (tilemap[tx][ty])
  254. {
  255. tile.x = tx;
  256. tile.y = ty;
  257. return 1;
  258. }
  259. } while (--max);
  260. return 0;
  261. }
  262. }
  263. }
  264. //===========================================================================
  265. /*
  266. =================
  267. =
  268. = BackTrace
  269. =
  270. = Traces backwards from edgex,edgey to viewx,viewy to see if a closer
  271. = tile obscures the given point. If it does, it finishes the wall and
  272. = starts a new one.
  273. = Returns true if a tile is hit.
  274. = Call with a 1 to have it automatically finish the current wall
  275. =
  276. =================
  277. */
  278. int BackTrace (int finish)
  279. {
  280. fixed tracex,tracey;
  281. long deltax,deltay,absdx,absdy;
  282. int steps,otx,oty,testx,testheight,offset,wall;
  283. deltax = viewx-edgex;
  284. deltay = viewy-edgey;
  285. absdx = LABS(deltax);
  286. absdy = LABS(deltay);
  287. if (absdx>absdy)
  288. steps = ABS(focal.x-(edgex>>TILESHIFT))-1;
  289. else
  290. steps = ABS(focal.y-(edgey>>TILESHIFT))-1;
  291. if (steps<=0)
  292. return 0;
  293. otx = tile.x;
  294. oty = tile.y;
  295. if (!FollowTrace(edgex,edgey,deltax,deltay,steps))
  296. return 0;
  297. //
  298. // if the start wall is behind the focal point, the trace went too far back
  299. //
  300. if (ABS(tile.x-focal.x)<2 && ABS(tile.y-focal.y)<2) // too close
  301. {
  302. if (tile.x == focal.x && tile.y == focal.y)
  303. {
  304. tile.x = otx;
  305. tile.y = oty;
  306. return 0;
  307. }
  308. if (tile.x<focal.x)
  309. {
  310. if (tile.y<focal.y)
  311. wall = SOUTH;
  312. else
  313. wall = EAST;
  314. }
  315. else if (tile.x==focal.x)
  316. {
  317. if (tile.y<focal.y)
  318. wall = SOUTH;
  319. else
  320. wall = NORTH;
  321. }
  322. else
  323. {
  324. if (tile.y<=focal.y)
  325. wall = WEST;
  326. else
  327. wall = NORTH;
  328. }
  329. //
  330. // rotate the X value to see if it is behind the view plane
  331. //
  332. if (TransformX (((long)tile.x<<16)+point1x[wall],
  333. ((long)tile.y<<16)+point1y[wall]) < FOCALLENGTH)
  334. {
  335. tile.x = otx;
  336. tile.y = oty;
  337. return 0;
  338. }
  339. }
  340. //
  341. // if the old wall is still behind a closer wall, ignore the back trace
  342. // and continue on (dealing with limited precision...)
  343. //
  344. if (finish && !FinishWall ()) // the wall is still behind a forward wall
  345. {
  346. tile.x = otx;
  347. tile.y = oty;
  348. rightwall->x1 = oldwall->x2; // common edge with last wall
  349. rightwall->height1 = oldwall->height2;
  350. return 0;
  351. }
  352. //
  353. // back up along the intersecting face to find the rightmost wall
  354. //
  355. if (tile.y<focal.y)
  356. offset = 0;
  357. else if (tile.y==focal.y)
  358. offset = 3;
  359. else
  360. offset = 6;
  361. if (tile.x==focal.x)
  362. offset ++;
  363. else if (tile.x>focal.x)
  364. offset += 2;
  365. wallon = backupwall[offset];
  366. while (tilemap[tile.x][tile.y])
  367. {
  368. tile.x += followx[wallon];
  369. tile.y += followy[wallon];
  370. };
  371. tile.x -= followx[wallon];
  372. tile.y -= followy[wallon];
  373. wallon = cornerwall[wallon]; // turn to first visable face
  374. edgex = ((long)tile.x<<16);
  375. edgey = ((long)tile.y<<16);
  376. TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],
  377. &rightwall->x1,&rightwall->height1);
  378. basecolor = tilemap[tile.x][tile.y];
  379. return 1;
  380. }
  381. //===========================================================================
  382. /*
  383. =================
  384. =
  385. = ForwardTrace
  386. =
  387. = Traces forwards from edgex,edgey along the line from viewx,viewy until
  388. = a solid tile is hit. Sets tile.x,tile.y
  389. =
  390. =================
  391. */
  392. void ForwardTrace (void)
  393. {
  394. int offset;
  395. fixed tracex,tracey;
  396. long deltax,deltay;
  397. deltax = edgex-viewx;
  398. deltay = edgey-viewy;
  399. FollowTrace(edgex,edgey,deltax,deltay,0);
  400. if (tile.y<focal.y)
  401. offset = 0;
  402. else if (tile.y==focal.y)
  403. offset = 3;
  404. else
  405. offset = 6;
  406. if (tile.x==focal.x)
  407. offset ++;
  408. else if (tile.x>focal.x)
  409. offset += 2;
  410. wallon = startwall[offset];
  411. //
  412. // start the new wall
  413. //
  414. edgex = ((long)tile.x<<16);
  415. edgey = ((long)tile.y<<16);
  416. //
  417. // if entire first wall is invisable, corner
  418. //
  419. TransformPoint (edgex+point2x[wallon],edgey+point2y[wallon],
  420. &rightwall->x2,&rightwall->height2);
  421. if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]]
  422. || rightwall->x2 < (rightwall-1)->x2 )
  423. wallon = cornerwall [wallon];
  424. //
  425. // transform first point
  426. //
  427. TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],
  428. &rightwall->x1,&rightwall->height1);
  429. basecolor = tilemap[tile.x][tile.y];
  430. }
  431. //===========================================================================
  432. /*
  433. =================
  434. =
  435. = FinishWall
  436. =
  437. = Transforms edgex,edgey as the next point of the current wall
  438. = and sticks it in the wall list
  439. =
  440. =================
  441. */
  442. int FinishWall (void)
  443. {
  444. char num[20];
  445. oldwall = rightwall;
  446. rightwall->color = basecolor;
  447. TransformPoint (edgex,edgey,&rightwall->x2,&rightwall->height2);
  448. if (rightwall->x2 <= (rightwall-1)->x2+2
  449. && rightwall->height2 < (rightwall-1)->height2 )
  450. return 0;
  451. rightwall->walllength = walllength;
  452. switch (wallon)
  453. {
  454. case north:
  455. case south:
  456. rightwall->side = 0;
  457. rightwall->planecoord = edgey;
  458. break;
  459. case west:
  460. case east:
  461. rightwall->side = 1;
  462. rightwall->planecoord = edgex;
  463. break;
  464. }
  465. walllength = 1;
  466. rightwall++;
  467. return 1;
  468. }
  469. //===========================================================================
  470. /*
  471. =================
  472. =
  473. = InsideCorner
  474. =
  475. =================
  476. */
  477. void InsideCorner (void)
  478. {
  479. int offset;
  480. //
  481. // the wall turned -90 degrees, so draw what we have, move to the new tile,
  482. // change wallon, change color, and continue following.
  483. //
  484. FinishWall ();
  485. tile.x += sharex[wallon];
  486. tile.y += sharey[wallon];
  487. wallon = turnwall[wallon];
  488. //
  489. // if the new wall is visable, continue following it. Otherwise
  490. // follow it backwards until it turns
  491. //
  492. TESTWALLVISABLE;
  493. if (wallvisable)
  494. {
  495. //
  496. // just turn to the next wall and continue
  497. //
  498. rightwall->x1 = oldwall->x2; // common edge with last wall
  499. rightwall->height1 = oldwall->height2;
  500. basecolor = tilemap[tile.x][tile.y];
  501. return; // continue from here
  502. }
  503. //
  504. // back follow the invisable wall until it turns, then follow that
  505. //
  506. do
  507. {
  508. tile.x += followx[wallon];
  509. tile.y += followy[wallon];
  510. } while (tilemap[tile.x][tile.y]);
  511. tile.x -= followx[wallon];
  512. tile.y -= followy[wallon];
  513. wallon = cornerwall[wallon]; // turn to first visable face
  514. edgex = ((long)tile.x<<16)+point1x[wallon];
  515. edgey = ((long)tile.y<<16)+point1y[wallon];
  516. if (!BackTrace(0)) // backtrace without finishing a wall
  517. {
  518. TransformPoint (edgex,edgey,&rightwall->x1,&rightwall->height1);
  519. basecolor = tilemap[tile.x][tile.y];
  520. }
  521. }
  522. //===========================================================================
  523. /*
  524. =================
  525. =
  526. = OutsideCorner
  527. =
  528. =================
  529. */
  530. void OutsideCorner (void)
  531. {
  532. int offset;
  533. //
  534. // edge is the outside edge of a corner, so draw the current wall and
  535. // turn the corner (+90 degrees)
  536. //
  537. FinishWall ();
  538. tile.x -= followx[wallon]; // backup to the real tile
  539. tile.y -= followy[wallon];
  540. wallon = cornerwall[wallon];
  541. //
  542. // if the new wall is visable, continue following it. Otherwise
  543. // trace a ray from the corner to find a wall in the distance to
  544. // follow
  545. //
  546. TESTWALLVISABLE;
  547. if (wallvisable)
  548. {
  549. //
  550. // the new wall is visable, so just continue on
  551. //
  552. rightwall->x1 = oldwall->x2; // common edge with last wall
  553. rightwall->height1 = oldwall->height2;
  554. return; // still on same tile, so color is ok
  555. }
  556. //
  557. // start from a new tile further away
  558. //
  559. ForwardTrace(); // find the next wall further back
  560. }
  561. //===========================================================================
  562. /*
  563. =================
  564. =
  565. = FollowWalls
  566. =
  567. = Starts a wall edge at the leftmost edge of tile.x,tile.y and follows it
  568. = until something else is seen or the entire view area is covered
  569. =
  570. =================
  571. */
  572. void FollowWalls (void)
  573. {
  574. int height,newcolor,offset,wall;
  575. //####################
  576. //
  577. // figure leftmost wall of new tile
  578. //
  579. //####################
  580. restart:
  581. walllength = 1;
  582. if (tile.y<focal.y)
  583. offset = 0;
  584. else if (tile.y==focal.y)
  585. offset = 3;
  586. else
  587. offset = 6;
  588. if (tile.x==focal.x)
  589. offset ++;
  590. else if (tile.x>focal.x)
  591. offset += 2;
  592. wallon = startwall[offset];
  593. //
  594. // if the start wall is inside a block, skip it by cornering to the second wall
  595. //
  596. if ( tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])
  597. wallon = cornerwall [wallon];
  598. //
  599. // transform first edge to screen coordinates
  600. //
  601. edgex = ((long)tile.x<<16);
  602. edgey = ((long)tile.y<<16);
  603. TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],
  604. &rightwall->x1,&rightwall->height1);
  605. basecolor = tilemap[tile.x][tile.y];
  606. //##################
  607. //
  608. // follow the wall as long as possible
  609. //
  610. //##################
  611. advance:
  612. do // while ( tile.x != right.x || tile.y != right.y)
  613. {
  614. //
  615. // check for conditions that shouldn't happed...
  616. //
  617. if (rightwall->x1 > VIEWXH) // somehow missed right tile...
  618. return;
  619. if (rightwall == &walls[DANGERHIGH])
  620. {
  621. //
  622. // somethiing got messed up! Correct by thrusting ahead...
  623. //
  624. // VW_ColorBorder(6);
  625. bordertime = 60;
  626. Thrust(player->angle,TILEGLOBAL/4);
  627. player->angle+=5;
  628. if (player->angle>ANGLES)
  629. player->angle-=ANGLES;
  630. aborttrace = true;
  631. return;
  632. #if 0
  633. strcpy (str,"Wall list overflow at LE:");
  634. itoa(mapon+1,str2,10);
  635. strcat (str,str2);
  636. strcat (str," X:");
  637. ltoa(objlist[0].x,str2,10);
  638. strcat (str,str2);
  639. strcat (str," Y:");
  640. ltoa(objlist[0].y,str2,10);
  641. strcat (str,str2);
  642. strcat (str," AN:");
  643. itoa(objlist[0].angle,str2,10);
  644. strcat (str,str2);
  645. Quit (str);
  646. #endif
  647. }
  648. //
  649. // proceed along wall
  650. //
  651. edgex = ((long)tile.x<<16)+point2x[wallon];
  652. edgey = ((long)tile.y<<16)+point2y[wallon];
  653. if (BackTrace(1)) // went behind a closer wall
  654. continue;
  655. //
  656. // advance to next tile along wall
  657. //
  658. tile.x += followx[wallon];
  659. tile.y += followy[wallon];
  660. if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])
  661. {
  662. InsideCorner (); // turn at a corner
  663. continue;
  664. }
  665. newcolor = tilemap[tile.x][tile.y];
  666. if (!newcolor) // turn around an edge
  667. {
  668. OutsideCorner ();
  669. continue;
  670. }
  671. if (newcolor != basecolor)
  672. {
  673. //
  674. // wall changed color, so draw what we have and continue following
  675. //
  676. FinishWall ();
  677. rightwall->x1 = oldwall->x2; // new wall shares this edge
  678. rightwall->height1 = oldwall->height2;
  679. basecolor = newcolor;
  680. continue;
  681. }
  682. walllength++;
  683. } while (tile.x != right.x || tile.y != right.y);
  684. //######################
  685. //
  686. // draw the last tile
  687. //
  688. //######################
  689. edgex = ((long)tile.x<<16)+point2x[wallon];
  690. edgey = ((long)tile.y<<16)+point2y[wallon];
  691. FinishWall();
  692. wallon = cornerwall[wallon];
  693. //
  694. // if the corner wall is visable, draw it
  695. //
  696. TESTWALLVISABLE;
  697. if (wallvisable)
  698. {
  699. rightwall->x1 = oldwall->x2; // common edge with last wall
  700. rightwall->height1 = oldwall->height2;
  701. edgex = ((long)tile.x<<16)+point2x[wallon];
  702. edgey = ((long)tile.y<<16)+point2y[wallon];
  703. FinishWall();
  704. }
  705. }
  706. //===========================================================================