Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

bg_slidemove.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 // bg_slidemove.c -- part of bg_pmove functionality
00024 
00025 #include "q_shared.h"
00026 #include "bg_public.h"
00027 #include "bg_local.h"
00028 
00029 /*
00030 
00031 input: origin, velocity, bounds, groundPlane, trace function
00032 
00033 output: origin, velocity, impacts, stairup boolean
00034 
00035 */
00036 
00037 /*
00038 ==================
00039 PM_SlideMove
00040 
00041 Returns qtrue if the velocity was clipped in some way
00042 ==================
00043 */
00044 #define MAX_CLIP_PLANES 5
00045 qboolean    PM_SlideMove( qboolean gravity ) {
00046     int         bumpcount, numbumps;
00047     vec3_t      dir;
00048     float       d;
00049     int         numplanes;
00050     vec3_t      planes[MAX_CLIP_PLANES];
00051     vec3_t      primal_velocity;
00052     vec3_t      clipVelocity;
00053     int         i, j, k;
00054     trace_t trace;
00055     vec3_t      end;
00056     float       time_left;
00057     float       into;
00058     vec3_t      endVelocity;
00059     vec3_t      endClipVelocity;
00060     
00061     numbumps = 4;
00062 
00063     VectorCopy (pm->ps->velocity, primal_velocity);
00064 
00065     if ( gravity ) {
00066         VectorCopy( pm->ps->velocity, endVelocity );
00067         endVelocity[2] -= pm->ps->gravity * pml.frametime;
00068         pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
00069         primal_velocity[2] = endVelocity[2];
00070         if ( pml.groundPlane ) {
00071             // slide along the ground plane
00072             PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
00073                 pm->ps->velocity, OVERCLIP );
00074         }
00075     }
00076 
00077     time_left = pml.frametime;
00078 
00079     // never turn against the ground plane
00080     if ( pml.groundPlane ) {
00081         numplanes = 1;
00082         VectorCopy( pml.groundTrace.plane.normal, planes[0] );
00083     } else {
00084         numplanes = 0;
00085     }
00086 
00087     // never turn against original velocity
00088     VectorNormalize2( pm->ps->velocity, planes[numplanes] );
00089     numplanes++;
00090 
00091     for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
00092 
00093         // calculate position we are trying to move to
00094         VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
00095 
00096         // see if we can make it there
00097         pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
00098 
00099         if (trace.allsolid) {
00100             // entity is completely trapped in another solid
00101             pm->ps->velocity[2] = 0;    // don't build up falling damage, but allow sideways acceleration
00102             return qtrue;
00103         }
00104 
00105         if (trace.fraction > 0) {
00106             // actually covered some distance
00107             VectorCopy (trace.endpos, pm->ps->origin);
00108         }
00109 
00110         if (trace.fraction == 1) {
00111              break;     // moved the entire distance
00112         }
00113 
00114         // save entity for contact
00115         PM_AddTouchEnt( trace.entityNum );
00116 
00117         time_left -= time_left * trace.fraction;
00118 
00119         if (numplanes >= MAX_CLIP_PLANES) {
00120             // this shouldn't really happen
00121             VectorClear( pm->ps->velocity );
00122             return qtrue;
00123         }
00124 
00125         //
00126         // if this is the same plane we hit before, nudge velocity
00127         // out along it, which fixes some epsilon issues with
00128         // non-axial planes
00129         //
00130         for ( i = 0 ; i < numplanes ; i++ ) {
00131             if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
00132                 VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
00133                 break;
00134             }
00135         }
00136         if ( i < numplanes ) {
00137             continue;
00138         }
00139         VectorCopy (trace.plane.normal, planes[numplanes]);
00140         numplanes++;
00141 
00142         //
00143         // modify velocity so it parallels all of the clip planes
00144         //
00145 
00146         // find a plane that it enters
00147         for ( i = 0 ; i < numplanes ; i++ ) {
00148             into = DotProduct( pm->ps->velocity, planes[i] );
00149             if ( into >= 0.1 ) {
00150                 continue;       // move doesn't interact with the plane
00151             }
00152 
00153             // see how hard we are hitting things
00154             if ( -into > pml.impactSpeed ) {
00155                 pml.impactSpeed = -into;
00156             }
00157 
00158             // slide along the plane
00159             PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
00160 
00161             // slide along the plane
00162             PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
00163 
00164             // see if there is a second plane that the new move enters
00165             for ( j = 0 ; j < numplanes ; j++ ) {
00166                 if ( j == i ) {
00167                     continue;
00168                 }
00169                 if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
00170                     continue;       // move doesn't interact with the plane
00171                 }
00172 
00173                 // try clipping the move to the plane
00174                 PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
00175                 PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
00176 
00177                 // see if it goes back into the first clip plane
00178                 if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
00179                     continue;
00180                 }
00181 
00182                 // slide the original velocity along the crease
00183                 CrossProduct (planes[i], planes[j], dir);
00184                 VectorNormalize( dir );
00185                 d = DotProduct( dir, pm->ps->velocity );
00186                 VectorScale( dir, d, clipVelocity );
00187 
00188                 CrossProduct (planes[i], planes[j], dir);
00189                 VectorNormalize( dir );
00190                 d = DotProduct( dir, endVelocity );
00191                 VectorScale( dir, d, endClipVelocity );
00192 
00193                 // see if there is a third plane the the new move enters
00194                 for ( k = 0 ; k < numplanes ; k++ ) {
00195                     if ( k == i || k == j ) {
00196                         continue;
00197                     }
00198                     if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
00199                         continue;       // move doesn't interact with the plane
00200                     }
00201 
00202                     // stop dead at a tripple plane interaction
00203                     VectorClear( pm->ps->velocity );
00204                     return qtrue;
00205                 }
00206             }
00207 
00208             // if we have fixed all interactions, try another move
00209             VectorCopy( clipVelocity, pm->ps->velocity );
00210             VectorCopy( endClipVelocity, endVelocity );
00211             break;
00212         }
00213     }
00214 
00215     if ( gravity ) {
00216         VectorCopy( endVelocity, pm->ps->velocity );
00217     }
00218 
00219     // don't change velocity if in a timer (FIXME: is this correct?)
00220     if ( pm->ps->pm_time ) {
00221         VectorCopy( primal_velocity, pm->ps->velocity );
00222     }
00223 
00224     return ( bumpcount != 0 );
00225 }
00226 
00227 /*
00228 ==================
00229 PM_StepSlideMove
00230 
00231 ==================
00232 */
00233 void PM_StepSlideMove( qboolean gravity ) {
00234     vec3_t      start_o, start_v;
00235     vec3_t      down_o, down_v;
00236     trace_t     trace;
00237 //  float       down_dist, up_dist;
00238 //  vec3_t      delta, delta2;
00239     vec3_t      up, down;
00240     float       stepSize;
00241 
00242     VectorCopy (pm->ps->origin, start_o);
00243     VectorCopy (pm->ps->velocity, start_v);
00244 
00245     if ( PM_SlideMove( gravity ) == 0 ) {
00246         return;     // we got exactly where we wanted to go first try   
00247     }
00248 
00249     VectorCopy(start_o, down);
00250     down[2] -= STEPSIZE;
00251     pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
00252     VectorSet(up, 0, 0, 1);
00253     // never step up when you still have up velocity
00254     if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
00255                                         DotProduct(trace.plane.normal, up) < 0.7)) {
00256         return;
00257     }
00258 
00259     VectorCopy (pm->ps->origin, down_o);
00260     VectorCopy (pm->ps->velocity, down_v);
00261 
00262     VectorCopy (start_o, up);
00263     up[2] += STEPSIZE;
00264 
00265     // test the player position if they were a stepheight higher
00266     pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
00267     if ( trace.allsolid ) {
00268         if ( pm->debugLevel ) {
00269             Com_Printf("%i:bend can't step\n", c_pmove);
00270         }
00271         return;     // can't step up
00272     }
00273 
00274     stepSize = trace.endpos[2] - start_o[2];
00275     // try slidemove from this position
00276     VectorCopy (trace.endpos, pm->ps->origin);
00277     VectorCopy (start_v, pm->ps->velocity);
00278 
00279     PM_SlideMove( gravity );
00280 
00281     // push down the final amount
00282     VectorCopy (pm->ps->origin, down);
00283     down[2] -= stepSize;
00284     pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
00285     if ( !trace.allsolid ) {
00286         VectorCopy (trace.endpos, pm->ps->origin);
00287     }
00288     if ( trace.fraction < 1.0 ) {
00289         PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
00290     }
00291 
00292 #if 0
00293     // if the down trace can trace back to the original position directly, don't step
00294     pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
00295     if ( trace.fraction == 1.0 ) {
00296         // use the original move
00297         VectorCopy (down_o, pm->ps->origin);
00298         VectorCopy (down_v, pm->ps->velocity);
00299         if ( pm->debugLevel ) {
00300             Com_Printf("%i:bend\n", c_pmove);
00301         }
00302     } else 
00303 #endif
00304     {
00305         // use the step move
00306         float   delta;
00307 
00308         delta = pm->ps->origin[2] - start_o[2];
00309         if ( delta > 2 ) {
00310             if ( delta < 7 ) {
00311                 PM_AddEvent( EV_STEP_4 );
00312             } else if ( delta < 11 ) {
00313                 PM_AddEvent( EV_STEP_8 );
00314             } else if ( delta < 15 ) {
00315                 PM_AddEvent( EV_STEP_12 );
00316             } else {
00317                 PM_AddEvent( EV_STEP_16 );
00318             }
00319         }
00320         if ( pm->debugLevel ) {
00321             Com_Printf("%i:stepped\n", c_pmove);
00322         }
00323     }
00324 }
00325 

Generated on Thu Aug 25 12:37:30 2005 for Quake III Arena by  doxygen 1.3.9.1