wolf_raycast.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. Copyright (C) 2004 Michael Liebscher
  3. Copyright (C) 2000-2002 by DarkOne the Hacker
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. /*
  17. * wolf_raycast.c: Wolfenstein3-D ray-casting.
  18. *
  19. * Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
  20. * Date: 2004
  21. *
  22. * Acknowledgement:
  23. * This code was derived from NewWolf, and was originally
  24. * written by DarkOne the Hacker.
  25. *
  26. */
  27. #include "../wolfiphone.h"
  28. W8 tile_visible[ 64 ][ 64 ]; // can player see this tile?
  29. /*
  30. -----------------------------------------------------------------------------
  31. Function: R_RayCast() -Ray cast viewport.
  32. Parameters: viewport -[in] Position of camera.
  33. lvl -[in] Pointer to valid LevelData_t structure.
  34. Returns: Nothing.
  35. Notes: Marks all visible tiles in tile_visible[] array.
  36. -----------------------------------------------------------------------------
  37. */
  38. PUBLIC void R_RayCast( placeonplane_t viewport, LevelData_t *lvl )
  39. {
  40. int n, x, y, angle, vx, vy;
  41. r_trace_t trace;
  42. memset( tile_visible, 0, sizeof( tile_visible ) ); // clear tile visible flags
  43. // viewport tile coordinates
  44. x = viewport.origin[ 0 ];
  45. y = viewport.origin[ 1 ];
  46. angle = viewport.angle;
  47. vx = POS2TILE( viewport.origin[ 0 ] );
  48. vy = POS2TILE( viewport.origin[ 1 ] );
  49. trace.tile_vis = tile_visible;
  50. trace.flags = TRACE_SIGHT | TRACE_MARK_MAP;
  51. //
  52. // Ray casting
  53. //
  54. // FIXME: control ray count and make angle init
  55. for( n = 0 ; n < 640 ; ++n )
  56. {
  57. trace.x = x;
  58. trace.y = y;
  59. trace.a = NormalizeAngle( angle + ColumnAngle[ n ] );
  60. R_Trace( &trace, lvl );
  61. }
  62. //
  63. // Rendering
  64. //
  65. for( x = 0 ; x < 64; ++x )
  66. for( y = 0 ; y < 64; ++y )
  67. if( tile_visible[ x ][ y ] )
  68. {
  69. lvl->tileEverVisible[x][y] = 1; // for automap
  70. if( lvl->tilemap[ x ][ y ] & DOOR_TILE )
  71. {
  72. /* door */
  73. if( lvl->Doors.DoorMap[ x ][ y ].action != dr_open )
  74. {
  75. _boolean backside = false;
  76. if( lvl->Doors.DoorMap[ x ][ y ].vertical )
  77. {
  78. if( x < vx )
  79. backside = true;
  80. }
  81. else
  82. {
  83. if( y < vy )
  84. backside = true;
  85. }
  86. R_Draw_Door( x, y, LOWERZCOORD, UPPERZCOORD,
  87. lvl->Doors.DoorMap[ x ][ y ].vertical,
  88. backside,
  89. lvl->Doors.DoorMap[ x ][ y ].texture,
  90. Door_Opened( &lvl->Doors, x, y ) );
  91. }
  92. /* door sides */
  93. if( lvl->Doors.DoorMap[ x ][ y ].vertical )
  94. {
  95. if( y <= vy )
  96. R_Draw_Wall( (float)x, (float)(y-1), LOWERZCOORD, UPPERZCOORD, dir4_north, TEX_PLATE );
  97. if( y >= vy )
  98. R_Draw_Wall( (float)x, (float)(y+1), LOWERZCOORD, UPPERZCOORD, dir4_south, TEX_PLATE );
  99. if( x <= vx && lvl->tilemap[ x - 1 ][ y ] & WALL_TILE )
  100. R_Draw_Wall( (float)(x-1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_east, lvl->wall_tex_x[ x - 1 ][ y ] );
  101. if( x >= vx && lvl->tilemap[ x + 1 ][ y ] & WALL_TILE )
  102. R_Draw_Wall( (float)(x+1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_west, lvl->wall_tex_x[ x + 1 ][ y ] );
  103. }
  104. else
  105. {
  106. if( x <= vx )
  107. R_Draw_Wall((float)(x-1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_east, TEX_PLATE+1);
  108. if( x >= vx )
  109. R_Draw_Wall((float)(x+1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_west, TEX_PLATE+1);
  110. if( y <= vy && lvl->tilemap[ x ][ y - 1 ] & WALL_TILE )
  111. R_Draw_Wall( (float)x, (float)(y-1), LOWERZCOORD, UPPERZCOORD, dir4_north, lvl->wall_tex_y[x][y-1]);
  112. if( y >= vy && lvl->tilemap[ x ][ y + 1 ] & WALL_TILE )
  113. R_Draw_Wall( (float)x, (float)(y+1), LOWERZCOORD, UPPERZCOORD, dir4_south, lvl->wall_tex_y[x][y+1]);
  114. }
  115. }
  116. else
  117. {
  118. /* Push-Wall */
  119. if( (r_world->tilemap[ x ][ y ] & PUSHWALL_TILE) )
  120. {
  121. float dx, dy;
  122. dx = PWall.dx * PWall.PWpointsmoved / 128.0f;
  123. dy = PWall.dy * PWall.PWpointsmoved / 128.0f;
  124. if( PWall.x <= vx )
  125. R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_east, PWall.tex_x );
  126. if( PWall.x >= vx )
  127. R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_west, PWall.tex_x );
  128. if( PWall.y <= vy )
  129. R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_north, PWall.tex_y );
  130. if( PWall.y >= vy )
  131. R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_south, PWall.tex_y );
  132. }
  133. /* x-wall */
  134. if( x <= vx && r_world->tilemap[ x - 1 ][ y ] & WALL_TILE )
  135. R_Draw_Wall( (float)(x-1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_east, r_world->wall_tex_x[x-1][y]);
  136. if( x >= vx && r_world->tilemap[ x + 1 ][ y ] & WALL_TILE )
  137. R_Draw_Wall( (float)(x+1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_west, r_world->wall_tex_x[x+1][y]);
  138. /* y-wall */
  139. if( y <= vy && r_world->tilemap[ x ][ y - 1 ] & WALL_TILE )
  140. R_Draw_Wall( (float)x, (float)(y-1), LOWERZCOORD, UPPERZCOORD, dir4_north, r_world->wall_tex_y[x][y-1]);
  141. if( y >= vy && r_world->tilemap[ x ][ y + 1 ] & WALL_TILE )
  142. R_Draw_Wall( (float)x, (float)(y+1), LOWERZCOORD, UPPERZCOORD, dir4_south, r_world->wall_tex_y[x][y+1]);
  143. }
  144. }
  145. // back to full brightness in case the last draw was a dim wall
  146. pfglColor3f( 1, 1, 1 );
  147. }
  148. int x_tile_step[ 4 ] = { 1, -1, -1, 1 };
  149. int y_tile_step[ 4 ] = { 1, 1, -1, -1 };
  150. /*
  151. -----------------------------------------------------------------------------
  152. Function: R_TraceCheck() -Trace ray check.
  153. Parameters:
  154. lvl -[in] Pointer to valid LevelData_t structure.
  155. x, y -[in] In tiles.
  156. Returns: true to stop tracing, false otherwise.
  157. Notes: Tells ray casting if we hit a wall or door and to stop tracing.
  158. -----------------------------------------------------------------------------
  159. */
  160. PRIVATE _boolean R_TraceCheck( LevelData_t *lvl, int x, int y, int frac, int dfrac, _boolean vert, _boolean flip, r_trace_t *trace )
  161. {
  162. if( lvl->tilemap[ x ][ y ] & WALL_TILE )
  163. {
  164. if( vert )
  165. {
  166. trace->x = (x << TILESHIFT) + (flip ? TILEGLOBAL : 0);
  167. trace->y = (y << TILESHIFT) + frac;
  168. trace->flags |= TRACE_HIT_VERT;
  169. }
  170. else
  171. {
  172. trace->x = (x << TILESHIFT) + frac;
  173. trace->y = (y << TILESHIFT) + (flip ? TILEGLOBAL : 0);
  174. trace->flags &= ~TRACE_HIT_VERT;
  175. }
  176. return true; // wall, stop tracing
  177. }
  178. if( trace->tile_vis )
  179. {
  180. trace->tile_vis[ x ][ y ] = true; // this tile is visible
  181. }
  182. if( lvl->tilemap[ x ][ y ] & DOOR_TILE &&
  183. lvl->Doors.DoorMap[ x ][ y ].action != dr_open )
  184. {
  185. frac += dfrac >> 1;
  186. if( POS2TILE( frac ) )
  187. return false;
  188. if( vert )
  189. {
  190. if( lvl->Doors.DoorMap[ x ][ y ].action != dr_closed &&
  191. (frac >> 10) > DOOR_FULLOPEN - Door_Opened( &lvl->Doors, x, y ) )
  192. {
  193. return false; // opened enough
  194. }
  195. trace->x = TILE2POS( x );
  196. trace->y = (y << TILESHIFT) + frac;
  197. trace->flags |= TRACE_HIT_VERT;
  198. }
  199. else
  200. {
  201. if( lvl->Doors.DoorMap[ x ][ y ].action != dr_closed &&
  202. (frac >> 10) < Door_Opened( &lvl->Doors, x, y ) )
  203. {
  204. return false; // opened enough
  205. }
  206. trace->y = TILE2POS( y );
  207. trace->x = (x << TILESHIFT) + frac;
  208. trace->flags &= ~TRACE_HIT_VERT;
  209. }
  210. trace->flags |= TRACE_HIT_DOOR;
  211. return true; // closed door, stop tracing
  212. }
  213. return false; // no intersection, go on!
  214. }
  215. /*
  216. -----------------------------------------------------------------------------
  217. Function: R_Trace() -Trace ray.
  218. Parameters:
  219. trace -[in] Pointer to valid r_trace_t structure.
  220. lvl -[in] Pointer to valid LevelData_t structure.
  221. Returns: Nothing.
  222. Notes:
  223. -----------------------------------------------------------------------------
  224. */
  225. PUBLIC void R_Trace( r_trace_t *trace, LevelData_t *lvl )
  226. {
  227. int xtilestep, ytilestep;
  228. int xstep, ystep;
  229. int xtile, ytile;
  230. int xintercept, yintercept;
  231. int YmapPos, XmapPos;
  232. quadrant q;
  233. // Setup for ray casting
  234. q = GetQuadrant( FINE2RAD( trace->a ) );
  235. xtilestep = x_tile_step[ q ];
  236. ytilestep = y_tile_step[ q ];
  237. xtile = POS2TILE( trace->x ) + xtilestep;
  238. ytile = POS2TILE( trace->y ) + ytilestep;
  239. xstep = ytilestep * XnextTable[ trace->a ];
  240. ystep = xtilestep * YnextTable[ trace->a ];
  241. xintercept = (int)( ( ((ytilestep == -1 ? ytile+1 : ytile) << TILESHIFT) - trace->y ) / TanTable[ trace->a ]) + trace->x;
  242. yintercept = (int)( ( ((xtilestep == -1 ? xtile+1 : xtile) << TILESHIFT) - trace->x ) * TanTable[ trace->a ]) + trace->y;
  243. YmapPos = yintercept >> TILESHIFT; // toXray
  244. XmapPos = xintercept >> TILESHIFT; // toYray
  245. if( trace->tile_vis )
  246. {
  247. // this tile is visible
  248. trace->tile_vis[ POS2TILE( trace->x ) ][ POS2TILE( trace->y ) ] = true;
  249. }
  250. //
  251. // Start of ray-casting
  252. //
  253. while( 1 )
  254. {
  255. //
  256. // Vertical loop // an anologue for X-Ray
  257. //
  258. while( ! (ytilestep == -1 && YmapPos <= ytile) && ! (ytilestep == 1 && YmapPos >= ytile) )
  259. {
  260. if( xtile < 0 || xtile >= 64 || YmapPos < 0 || YmapPos >= 64 )
  261. {
  262. return;
  263. }
  264. if( R_TraceCheck( lvl, xtile, YmapPos, yintercept % TILEGLOBAL, ystep, true, (_boolean)(xtilestep == -1), trace ) )
  265. {
  266. return;
  267. }
  268. // prepare for next step
  269. xtile += xtilestep;
  270. yintercept += ystep;
  271. YmapPos = yintercept >> TILESHIFT;
  272. }
  273. //
  274. // Horizontal loop // an anologue for Y-Ray
  275. //
  276. while( ! (xtilestep == -1 && XmapPos <= xtile) && ! (xtilestep == 1 && XmapPos >= xtile) )
  277. {
  278. if( ytile < 0 || ytile >= 64 || XmapPos < 0 || XmapPos >= 64 )
  279. {
  280. return;
  281. }
  282. if( R_TraceCheck( lvl, XmapPos, ytile, xintercept % TILEGLOBAL, xstep, false, (_boolean)(ytilestep == -1), trace ) )
  283. {
  284. return;
  285. }
  286. // prepare for next step
  287. ytile += ytilestep;
  288. xintercept += xstep;
  289. XmapPos = xintercept >> TILESHIFT;
  290. }
  291. } // end of while( 1 )
  292. }