summaryrefslogtreecommitdiff
path: root/player.c
diff options
context:
space:
mode:
Diffstat (limited to 'player.c')
-rw-r--r--player.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/player.c b/player.c
new file mode 100644
index 0000000..e844a5a
--- /dev/null
+++ b/player.c
@@ -0,0 +1,384 @@
+/*
+=======================================================================
+This file is part of Redman's RT.
+
+Redman's RT 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 3 of the License, or
+(at your option) any later version.
+
+Redman's RT 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 Redman's RT. If not, see <http://www.gnu.org/licenses/>.
+=======================================================================
+*/
+
+#include "common.h"
+
+W_blockdata_t G_RemoveBlock( W_world_t *world, vec3_t vieworg, vec3_t viewdir, size_t targetDepth )
+{
+ ray_t ray;
+ rtres_t rtres;
+ W_otnode_t *target, *node;
+ W_blockdata_t block;
+ size_t i, depth;
+
+ U_BuildRay( vieworg, viewdir, INFINITY, &ray, &rtres );
+
+new_target:
+
+ target = W_Trace( world, NULL, &ray, &rtres );
+
+ if( !target )
+ return BLOCK_NONE;
+
+ for( depth = 0, node = target; node != world->otroot; node = node->p, depth++ );
+
+ if( depth < targetDepth )
+ {
+ for( i = 0; i < 8; i++ )
+ {
+ target->n[ i ] = W_NewOTNode( target, i );
+ memcpy( &target->n[ i ]->data, &target->data, sizeof( W_blockdata_t ) );
+ }
+ memset( &target->data, 0, sizeof( W_blockdata_t ) );
+ goto new_target;
+ }
+ else if( depth == targetDepth )
+ block = target->data;
+ else
+ block = BLOCK_NONE;
+
+ W_DeleteOTNode( target );
+ return block;
+}
+
+bool_t G_PlaceBlock( W_world_t *world, vec3_t vieworg, vec3_t viewdir, W_blockdata_t blockdata, size_t targetDepth )
+{
+ ray_t ray;
+ rtres_t rtres;
+ W_otnode_t *target, *node;
+ vec3_t point;
+ size_t depth;
+
+ U_BuildRay( vieworg, viewdir, INFINITY, &ray, &rtres );
+
+ if( !W_Trace( world, NULL, &ray, &rtres ) )
+ return false;
+
+ V3MA2( point, ray.org, rtres.dist, ray.dir, 1.0e-2, rtres.normal );
+
+ target = W_Point( world->otroot, point );
+
+ if( !target )
+ return false;
+
+ if( target->data )
+ return false;
+
+ for( depth = 0, node = target; node != world->otroot; node = node->p, depth++ );
+
+ while( depth < targetDepth )
+ {
+ int index, ix, iy, iz;
+ vec3_t center;
+
+ V3Lerp( center, 0.5, target->aabb[ 0 ], target->aabb[ 1 ] );
+
+ ix = ( point[ 0 ] > center[ 0 ] );
+ iy = ( point[ 1 ] >= center[ 1 ] );
+ iz = ( point[ 2 ] >= center[ 2 ] );
+
+ index = ix | ( iy << 1 ) | ( iz << 2 );
+ if( target->n[ index ] )
+ printf( "wtf???\n" );
+
+ memset( &target->data, 0, sizeof( W_blockdata_t ) );
+ target = target->n[ index ] = W_NewOTNode( target, index );
+
+ depth++;
+ }
+
+ if( depth > targetDepth )
+ return false; //no space
+
+ target->data = blockdata;
+
+ return true;
+}
+
+void G_RecolorBlock( W_world_t *world, vec3_t vieworg, vec3_t viewdir )
+{
+ W_otnode_t *node;
+ ray_t ray;
+ rtres_t rtres;
+
+ U_BuildRay( vieworg, viewdir, INFINITY, &ray, &rtres );
+
+ node = W_Trace( world, NULL, &ray, &rtres );
+
+ if( node )
+ {
+ node->data++;
+ node->data %= _Material_count;
+ if( node->data == 0 )
+ node->data = 1;
+ }
+}
+
+bool_t G_ExactTraceAABB( const vec3_t const *aabb, const ray_t *ray, rtres_t *rt )
+{
+ vec_t tn, tp, tyn, typ, tzn, tzp;
+
+ tn = ( aabb[ ray->dinvsign[ 0 ] ][ 0 ] - ray->org[ 0 ] ) * ray->dinv[ 0 ];
+ tp = ( aabb[ 1 - ray->dinvsign[ 0 ] ][ 0 ] - ray->org[ 0 ] ) * ray->dinv[ 0 ];
+
+ tyn = ( aabb[ ray->dinvsign[ 1 ] ][ 1 ] - ray->org[ 1 ] ) * ray->dinv[ 1 ];
+ typ = ( aabb[ 1 - ray->dinvsign[ 1 ] ][ 1 ] - ray->org[ 1 ] ) * ray->dinv[ 1 ];
+
+ V3Set( rt->normal, ray->dsign2[ 0 ], 0, 0 );
+
+ V3MA( rt->hit, ray->org, tn, ray->dir );
+ rt->hit[ 0 ] = aabb[ ray->dinvsign[ 0 ] ][ 0 ];
+
+ if( ( tn > typ ) || ( tyn > tp ) )
+ return false;
+
+ if( tyn > tn )
+ {
+ tn = tyn;
+ V3Set( rt->normal, 0, ray->dsign2[ 1 ], 0 );
+
+ V3MA( rt->hit, ray->org, tn, ray->dir );
+ rt->hit[ 1 ] = aabb[ ray->dinvsign[ 1 ] ][ 1 ];
+ }
+
+ if( typ < tp )
+ tp = typ;
+
+ tzn = ( aabb[ ray->dinvsign[ 2 ] ][ 2 ] - ray->org[ 2 ] ) * ray->dinv[ 2 ];
+ tzp = ( aabb[ 1 - ray->dinvsign[ 2 ] ][ 2 ] - ray->org[ 2 ] ) * ray->dinv[ 2 ];
+
+ if( ( tn > tzp ) || ( tzn > tp ) )
+ return false;
+
+ if( tzn > tn )
+ {
+ tn = tzn;
+ V3Set( rt->normal, 0, 0, ray->dsign2[ 2 ] );
+ V3MA( rt->hit, ray->org, tn, ray->dir );
+ rt->hit[ 2 ] = aabb[ ray->dinvsign[ 2 ] ][ 2 ];
+ }
+
+ if( tzp < tp )
+ tp = tzp;
+
+ rt->dist = tn;
+
+ return tn >= 0;
+}
+
+static void G_BoxTrace_R( W_otnode_t *node, W_otnode_t **node_best, rtres_t *rt_best, const ray_t *ray, const vec3_t *delta )
+{
+ size_t i;
+ bool_t intersects;
+ vec3_t aabb[ 2 ];
+ rtres_t rt;
+
+ V3Add( aabb[ 0 ], node->aabb[ 0 ], delta[ 0 ] );
+ V3Add( aabb[ 1 ], node->aabb[ 1 ], delta[ 1 ] );
+
+ if( U_PointInAABB2( ray->org, (const vec3_t *)aabb ) )
+ {
+ if( node->data )
+ return;
+ intersects = true;
+ }
+ else
+ intersects = G_ExactTraceAABB( (const vec3_t*)aabb, ray, &rt );
+
+ if( !intersects )
+ return;
+
+ if( node->data )
+ {
+ if( rt_best->dist >= rt.dist )
+ {
+ (*node_best) = node;
+ memcpy( rt_best, &rt, sizeof( rtres_t ) );
+ rt_best->data = node->data;
+ }
+ }
+ else
+ for( i = 0; i < 8; i++ )
+ if( node->n[ i ] )
+ G_BoxTrace_R( node->n[ i ], node_best, rt_best, ray, delta );
+}
+
+W_otnode_t *G_BoxTrace( W_world_t *world, rtres_t *rt_best, const ray_t *ray, const vec3_t *aabb )
+{
+ W_otnode_t *out_node = NULL;
+
+ memset( rt_best, 0, sizeof( rtres_t ) );
+ rt_best->dist = INFINITY;
+
+ if( !world->otroot )
+ return NULL;
+
+ G_BoxTrace_R( world->otroot, &out_node, rt_best, ray, aabb );
+
+ if( rt_best->dist > ray->limit )
+ return NULL;
+
+ return out_node;
+}
+
+void G_ClipVelocity( vec3_t out, vec3_t in, vec3_t normal )
+{
+ vec_t dot;
+
+ dot = V3Dot( in, normal );
+ V3Mul2( out, in, 1, normal, -dot );
+}
+
+
+
+//FIXME: G_BoxTrace gets stuck on edges
+void G_MovePlayer( W_world_t *world, G_player_t *p, vec_t delta )
+{
+ ray_t ray;
+ rtres_t rtres;
+ vec_t disp, speed;
+ bool_t clip;
+
+ while( delta > 1e-3 )
+ {
+ V3Copy( ray.dir, p->velocity );
+ speed = V3Normalize( ray.dir );
+ disp = speed * delta;
+
+ U_BuildRay( p->origin, p->velocity, disp, &ray, &rtres );
+
+ clip = ( G_BoxTrace( world, &rtres, &ray, (const vec3_t*)p->aabb ) != NULL );
+
+ if( clip )
+ {
+ V3Copy( p->origin, rtres.hit );
+ delta -= rtres.dist / V3Length( p->velocity );
+
+ V3Reflect( p->velocity, p->velocity, rtres.normal );
+
+ //G_ClipVelocity( p->velocity, p->velocity, rtres.normal );
+ }
+ else
+ {
+ V3MA( p->origin, p->origin, disp, ray.dir );
+ break;
+ }
+ }
+}
+
+/*
+void G_RunPlayer( W_world_t *world, G_player_t *p )
+{
+ G_time_t frametime;
+ vec_t delta;
+ frametime = U_Clock( );
+
+ V3AnglesToMatrix( p->matrix, p->angles );
+ M3RotZ( p->flatMatrix, p->angles[ 2 ] );
+
+ #define TIMESTEP 10
+
+ while( p->lastPhysicsTime + TIMESTEP < frametime )
+ {
+ vec3_t wishvel;
+
+ delta = 1.0e-3 * TIMESTEP;
+
+ if( p->cmd_noclip )
+ {
+ vec_t mod;
+
+ mod = delta * ( p->cmd_sprint ? 20 : 6 );
+
+ V3MA2( p->origin, p->origin, p->cmd_move[ 0 ] * mod, p->matrix + 3, p->cmd_move[ 1 ] * mod, p->matrix );
+ if( p->cmd_jump )
+ V3MA( p->origin, p->origin, -mod, p->matrix + 6 );
+
+ V3Set( p->velocity, 0, 0, 0 );
+
+ p->lastPhysicsTime += TIMESTEP;
+ continue;
+ }
+
+ {
+ ray_t ray;
+ rtres_t rtres;
+
+ V3Copy( ray.org, p->origin );
+ V3Set( ray.dir, 0, 0, 1 );
+ U_BuildRay( NULL, NULL, 0.01, &ray, &rtres );
+ p->onGround = ( G_BoxTrace( world, &rtres, &ray, (const vec3_t*)p->aabb ) != NULL );
+ }
+
+ if( p->onGround && p->cmd_jump )
+ p->velocity[ 2 ] = -2.6;
+
+ V3Mul2( wishvel, p->flatMatrix + 3, p->cmd_move[ 0 ],
+ p->flatMatrix, p->cmd_move[ 1 ] );
+ wishvel[ 2 ] = 0.0;
+ V2Normalize( wishvel );
+
+ V2Mul( wishvel, wishvel, 2 );
+ if( p->cmd_sprint )
+ V2Mul( wishvel, wishvel, 2 );
+
+
+ V2Lerp( p->velocity, 0.1, p->velocity, wishvel );
+ p->velocity[ 2 ] += 5.81 * delta;
+
+ G_MovePlayer( world, p, delta );
+
+ p->lastPhysicsTime += TIMESTEP;
+ }
+}*/
+
+void G_RunPlayer( W_world_t *world, G_player_t *p )
+{
+ G_time_t frametime;
+ vec_t delta;
+ frametime = U_Clock( );
+
+ V3AnglesToMatrix( p->matrix, p->angles );
+
+ #define TIMESTEP 10
+
+ while( p->lastPhysicsTime + TIMESTEP < frametime )
+ {
+ size_t i;
+ vec_t mod;
+ vec3_t target;
+
+ delta = 1.0e-3 * TIMESTEP;
+
+ mod = ( p->cmd_sprint ? 20 : 6 );
+
+ for( i = 0; i < 3; i++ )
+ target[ i ] = p->cmd_move[ 0 ] * p->matrix[ i + 3 ] +
+ p->cmd_move[ 1 ] * p->matrix[ i ] +
+ ( p->cmd_jump ? -p->matrix[ i + 6 ] : 0 ) +
+ ( p->cmd_down ? p->matrix[ i + 6 ] : 0 );
+ V3Mul( target, target, mod );
+
+ V3Lerp( p->velocity, 0.1, p->velocity, target );
+
+ V3MA( p->origin, p->origin, delta, p->velocity );
+
+ p->lastPhysicsTime += TIMESTEP;
+ }
+}