123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- /*
- Copyright (C) 2004 Michael Liebscher
- Copyright (C) 2000-2002 by DarkOne the Hacker
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- /*
- * wolf_raycast.c: Wolfenstein3-D ray-casting.
- *
- * Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
- * Date: 2004
- *
- * Acknowledgement:
- * This code was derived from NewWolf, and was originally
- * written by DarkOne the Hacker.
- *
- */
- #include "../wolfiphone.h"
- W8 tile_visible[ 64 ][ 64 ]; // can player see this tile?
- /*
- -----------------------------------------------------------------------------
- Function: R_RayCast() -Ray cast viewport.
-
- Parameters: viewport -[in] Position of camera.
- lvl -[in] Pointer to valid LevelData_t structure.
-
- Returns: Nothing.
-
- Notes: Marks all visible tiles in tile_visible[] array.
- -----------------------------------------------------------------------------
- */
- PUBLIC void R_RayCast( placeonplane_t viewport, LevelData_t *lvl )
- {
- int n, x, y, angle, vx, vy;
- r_trace_t trace;
- memset( tile_visible, 0, sizeof( tile_visible ) ); // clear tile visible flags
- // viewport tile coordinates
- x = viewport.origin[ 0 ];
- y = viewport.origin[ 1 ];
- angle = viewport.angle;
- vx = POS2TILE( viewport.origin[ 0 ] );
- vy = POS2TILE( viewport.origin[ 1 ] );
- trace.tile_vis = tile_visible;
- trace.flags = TRACE_SIGHT | TRACE_MARK_MAP;
- //
- // Ray casting
- //
- // FIXME: control ray count and make angle init
- for( n = 0 ; n < 640 ; ++n )
- {
- trace.x = x;
- trace.y = y;
- trace.a = NormalizeAngle( angle + ColumnAngle[ n ] );
- R_Trace( &trace, lvl );
- }
- //
- // Rendering
- //
- for( x = 0 ; x < 64; ++x )
- for( y = 0 ; y < 64; ++y )
- if( tile_visible[ x ][ y ] )
- {
- lvl->tileEverVisible[x][y] = 1; // for automap
- if( lvl->tilemap[ x ][ y ] & DOOR_TILE )
- {
- /* door */
- if( lvl->Doors.DoorMap[ x ][ y ].action != dr_open )
- {
- _boolean backside = false;
- if( lvl->Doors.DoorMap[ x ][ y ].vertical )
- {
- if( x < vx )
- backside = true;
- }
- else
- {
- if( y < vy )
- backside = true;
- }
- R_Draw_Door( x, y, LOWERZCOORD, UPPERZCOORD,
- lvl->Doors.DoorMap[ x ][ y ].vertical,
- backside,
- lvl->Doors.DoorMap[ x ][ y ].texture,
- Door_Opened( &lvl->Doors, x, y ) );
- }
- /* door sides */
- if( lvl->Doors.DoorMap[ x ][ y ].vertical )
- {
- if( y <= vy )
- R_Draw_Wall( (float)x, (float)(y-1), LOWERZCOORD, UPPERZCOORD, dir4_north, TEX_PLATE );
- if( y >= vy )
- R_Draw_Wall( (float)x, (float)(y+1), LOWERZCOORD, UPPERZCOORD, dir4_south, TEX_PLATE );
- if( x <= vx && lvl->tilemap[ x - 1 ][ y ] & WALL_TILE )
- R_Draw_Wall( (float)(x-1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_east, lvl->wall_tex_x[ x - 1 ][ y ] );
-
- if( x >= vx && lvl->tilemap[ x + 1 ][ y ] & WALL_TILE )
- R_Draw_Wall( (float)(x+1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_west, lvl->wall_tex_x[ x + 1 ][ y ] );
- }
- else
- {
- if( x <= vx )
- R_Draw_Wall((float)(x-1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_east, TEX_PLATE+1);
- if( x >= vx )
- R_Draw_Wall((float)(x+1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_west, TEX_PLATE+1);
- if( y <= vy && lvl->tilemap[ x ][ y - 1 ] & WALL_TILE )
- R_Draw_Wall( (float)x, (float)(y-1), LOWERZCOORD, UPPERZCOORD, dir4_north, lvl->wall_tex_y[x][y-1]);
-
- if( y >= vy && lvl->tilemap[ x ][ y + 1 ] & WALL_TILE )
- R_Draw_Wall( (float)x, (float)(y+1), LOWERZCOORD, UPPERZCOORD, dir4_south, lvl->wall_tex_y[x][y+1]);
- }
- }
- else
- {
- /* Push-Wall */
- if( (r_world->tilemap[ x ][ y ] & PUSHWALL_TILE) )
- {
- float dx, dy;
- dx = PWall.dx * PWall.PWpointsmoved / 128.0f;
- dy = PWall.dy * PWall.PWpointsmoved / 128.0f;
- if( PWall.x <= vx )
- R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_east, PWall.tex_x );
- if( PWall.x >= vx )
- R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_west, PWall.tex_x );
- if( PWall.y <= vy )
- R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_north, PWall.tex_y );
- if( PWall.y >= vy )
- R_Draw_Wall( (float)PWall.x + dx, (float)PWall.y + dy, LOWERZCOORD, UPPERZCOORD, dir4_south, PWall.tex_y );
- }
- /* x-wall */
- if( x <= vx && r_world->tilemap[ x - 1 ][ y ] & WALL_TILE )
- R_Draw_Wall( (float)(x-1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_east, r_world->wall_tex_x[x-1][y]);
-
- if( x >= vx && r_world->tilemap[ x + 1 ][ y ] & WALL_TILE )
- R_Draw_Wall( (float)(x+1), (float)y, LOWERZCOORD, UPPERZCOORD, dir4_west, r_world->wall_tex_x[x+1][y]);
-
- /* y-wall */
- if( y <= vy && r_world->tilemap[ x ][ y - 1 ] & WALL_TILE )
- R_Draw_Wall( (float)x, (float)(y-1), LOWERZCOORD, UPPERZCOORD, dir4_north, r_world->wall_tex_y[x][y-1]);
-
- if( y >= vy && r_world->tilemap[ x ][ y + 1 ] & WALL_TILE )
- R_Draw_Wall( (float)x, (float)(y+1), LOWERZCOORD, UPPERZCOORD, dir4_south, r_world->wall_tex_y[x][y+1]);
- }
- }
- // back to full brightness in case the last draw was a dim wall
- pfglColor3f( 1, 1, 1 );
- }
- int x_tile_step[ 4 ] = { 1, -1, -1, 1 };
- int y_tile_step[ 4 ] = { 1, 1, -1, -1 };
- /*
- -----------------------------------------------------------------------------
- Function: R_TraceCheck() -Trace ray check.
-
- Parameters:
- lvl -[in] Pointer to valid LevelData_t structure.
- x, y -[in] In tiles.
-
- Returns: true to stop tracing, false otherwise.
-
- Notes: Tells ray casting if we hit a wall or door and to stop tracing.
- -----------------------------------------------------------------------------
- */
- PRIVATE _boolean R_TraceCheck( LevelData_t *lvl, int x, int y, int frac, int dfrac, _boolean vert, _boolean flip, r_trace_t *trace )
- {
- if( lvl->tilemap[ x ][ y ] & WALL_TILE )
- {
- if( vert )
- {
- trace->x = (x << TILESHIFT) + (flip ? TILEGLOBAL : 0);
- trace->y = (y << TILESHIFT) + frac;
- trace->flags |= TRACE_HIT_VERT;
- }
- else
- {
- trace->x = (x << TILESHIFT) + frac;
- trace->y = (y << TILESHIFT) + (flip ? TILEGLOBAL : 0);
- trace->flags &= ~TRACE_HIT_VERT;
- }
- return true; // wall, stop tracing
- }
- if( trace->tile_vis )
- {
- trace->tile_vis[ x ][ y ] = true; // this tile is visible
- }
- if( lvl->tilemap[ x ][ y ] & DOOR_TILE &&
- lvl->Doors.DoorMap[ x ][ y ].action != dr_open )
- {
- frac += dfrac >> 1;
- if( POS2TILE( frac ) )
- return false;
- if( vert )
- {
- if( lvl->Doors.DoorMap[ x ][ y ].action != dr_closed &&
- (frac >> 10) > DOOR_FULLOPEN - Door_Opened( &lvl->Doors, x, y ) )
- {
- return false; // opened enough
- }
- trace->x = TILE2POS( x );
- trace->y = (y << TILESHIFT) + frac;
- trace->flags |= TRACE_HIT_VERT;
- }
- else
- {
- if( lvl->Doors.DoorMap[ x ][ y ].action != dr_closed &&
- (frac >> 10) < Door_Opened( &lvl->Doors, x, y ) )
- {
- return false; // opened enough
- }
- trace->y = TILE2POS( y );
- trace->x = (x << TILESHIFT) + frac;
- trace->flags &= ~TRACE_HIT_VERT;
- }
- trace->flags |= TRACE_HIT_DOOR;
- return true; // closed door, stop tracing
- }
- return false; // no intersection, go on!
- }
- /*
- -----------------------------------------------------------------------------
- Function: R_Trace() -Trace ray.
-
- Parameters:
- trace -[in] Pointer to valid r_trace_t structure.
- lvl -[in] Pointer to valid LevelData_t structure.
-
- Returns: Nothing.
-
- Notes:
- -----------------------------------------------------------------------------
- */
- PUBLIC void R_Trace( r_trace_t *trace, LevelData_t *lvl )
- {
- int xtilestep, ytilestep;
- int xstep, ystep;
- int xtile, ytile;
- int xintercept, yintercept;
- int YmapPos, XmapPos;
- quadrant q;
- // Setup for ray casting
- q = GetQuadrant( FINE2RAD( trace->a ) );
- xtilestep = x_tile_step[ q ];
- ytilestep = y_tile_step[ q ];
- xtile = POS2TILE( trace->x ) + xtilestep;
- ytile = POS2TILE( trace->y ) + ytilestep;
- xstep = ytilestep * XnextTable[ trace->a ];
- ystep = xtilestep * YnextTable[ trace->a ];
- xintercept = (int)( ( ((ytilestep == -1 ? ytile+1 : ytile) << TILESHIFT) - trace->y ) / TanTable[ trace->a ]) + trace->x;
- yintercept = (int)( ( ((xtilestep == -1 ? xtile+1 : xtile) << TILESHIFT) - trace->x ) * TanTable[ trace->a ]) + trace->y;
- YmapPos = yintercept >> TILESHIFT; // toXray
- XmapPos = xintercept >> TILESHIFT; // toYray
- if( trace->tile_vis )
- {
- // this tile is visible
- trace->tile_vis[ POS2TILE( trace->x ) ][ POS2TILE( trace->y ) ] = true;
- }
-
- //
- // Start of ray-casting
- //
- while( 1 )
- {
- //
- // Vertical loop // an anologue for X-Ray
- //
- while( ! (ytilestep == -1 && YmapPos <= ytile) && ! (ytilestep == 1 && YmapPos >= ytile) )
- {
- if( xtile < 0 || xtile >= 64 || YmapPos < 0 || YmapPos >= 64 )
- {
- return;
- }
- if( R_TraceCheck( lvl, xtile, YmapPos, yintercept % TILEGLOBAL, ystep, true, (_boolean)(xtilestep == -1), trace ) )
- {
- return;
- }
- // prepare for next step
- xtile += xtilestep;
- yintercept += ystep;
- YmapPos = yintercept >> TILESHIFT;
- }
- //
- // Horizontal loop // an anologue for Y-Ray
- //
- while( ! (xtilestep == -1 && XmapPos <= xtile) && ! (xtilestep == 1 && XmapPos >= xtile) )
- {
- if( ytile < 0 || ytile >= 64 || XmapPos < 0 || XmapPos >= 64 )
- {
- return;
- }
- if( R_TraceCheck( lvl, XmapPos, ytile, xintercept % TILEGLOBAL, xstep, false, (_boolean)(ytilestep == -1), trace ) )
- {
- return;
- }
- // prepare for next step
- ytile += ytilestep;
- xintercept += xstep;
- XmapPos = xintercept >> TILESHIFT;
- }
- } // end of while( 1 )
- }
|