diff options
| author | Tim Angus <tim@ngus.net> | 2001-01-04 08:38:28 +0000 | 
|---|---|---|
| committer | Tim Angus <tim@ngus.net> | 2001-01-04 08:38:28 +0000 | 
| commit | eb4e4d240dab282addb4fda26ddf77a1d01f22cc (patch) | |
| tree | ade26acba87efb786c100aea2d9b214623851c52 | |
| parent | ae51d659752ca314460b1e7f1bd4d4d58f2f7afc (diff) | |
added q_*.. d'oh
| -rw-r--r-- | src/game/bg_pmove.c | 15 | ||||
| -rw-r--r-- | src/game/q_math.c | 1355 | ||||
| -rw-r--r-- | src/game/q_shared.c | 1229 | ||||
| -rw-r--r-- | src/game/q_shared.h | 1206 | 
4 files changed, 3802 insertions, 3 deletions
diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c index 5d17b0be..a0c3c150 100644 --- a/src/game/bg_pmove.c +++ b/src/game/bg_pmove.c @@ -1486,10 +1486,19 @@ static void PM_GroundClimbTrace( void )          if( !VectorCompare( trace.plane.normal, refNormal ) && !VectorCompare( surfNormal, refNormal ) &&              !VectorCompare( trace.plane.normal, ceilingNormal ) && !VectorCompare( surfNormal, ceilingNormal ) )          { +          int dAngle;            vectoangles( trace.plane.normal, toAngles );            vectoangles( surfNormal, surfAngles ); -          pm->ps->delta_angles[1] -= ANGLE2SHORT( surfAngles[1] - toAngles[1] ); +          //pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( surfAngles[ YAW ] - toAngles[ YAW ] ); +          dAngle = ANGLE2SHORT( RAD2DEG( arccos( DotProduct( trace.plane.normal, surfNormal ) ) ) ); +          if( dAngle < 0 ) +            dAngle = -dAngle; + +          pm->ps->delta_angles[ YAW ] += dAngle; +           +          Com_Printf( "%1.0f ", surfAngles[ YAW ] - toAngles[ YAW ] ); +          Com_Printf( "%1.0f\n", RAD2DEG( arccos( DotProduct( trace.plane.normal, surfNormal ) ) ) );          }          //transition from wall to ceiling @@ -2501,8 +2510,8 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {      //-abs( rotAngle ).. sorta      if( rotAngle > 0 ) -      rotAngle -= rotAngle*2; - +      rotAngle = -rotAngle; +            //hmmm could get away with only one rotation and some clever stuff later... but i'm lazy      RotatePointAroundVector( rotaxis[0], xNormal, axis[0], rotAngle );      RotatePointAroundVector( rotaxis[1], xNormal, axis[1], rotAngle ); diff --git a/src/game/q_math.c b/src/game/q_math.c new file mode 100644 index 00000000..324418e5 --- /dev/null +++ b/src/game/q_math.c @@ -0,0 +1,1355 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// +// q_math.c -- stateless support routines that are included in each code module + +/* + *  Portions Copyright (C) 2000-2001 Tim Angus + * + *  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, 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. + */ + +/*  To assertain which portions are licensed under the GPL and which are + *  licensed by Id Software, Inc. please run a diff between the equivalent + *  versions of the "Tremulous" modification and the unmodified "Quake3" + *  game source code. + */ +                     +#include "q_shared.h" + + +vec3_t  vec3_origin = {0,0,0}; +vec3_t  axisDefault[3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + + +vec4_t    colorBlack  = {0, 0, 0, 1}; +vec4_t    colorRed  = {1, 0, 0, 1}; +vec4_t    colorGreen  = {0, 1, 0, 1}; +vec4_t    colorBlue = {0, 0, 1, 1}; +vec4_t    colorYellow = {1, 1, 0, 1}; +vec4_t    colorMagenta= {1, 0, 1, 1}; +vec4_t    colorCyan = {0, 1, 1, 1}; +vec4_t    colorWhite  = {1, 1, 1, 1}; +vec4_t    colorLtGrey = {0.75, 0.75, 0.75, 1}; +vec4_t    colorMdGrey = {0.5, 0.5, 0.5, 1}; +vec4_t    colorDkGrey = {0.25, 0.25, 0.25, 1}; + +vec4_t  g_color_table[8] = +  { +  {0.0, 0.0, 0.0, 1.0}, +  {1.0, 0.0, 0.0, 1.0}, +  {0.0, 1.0, 0.0, 1.0}, +  {1.0, 1.0, 0.0, 1.0}, +  {0.0, 0.0, 1.0, 1.0}, +  {0.0, 1.0, 1.0, 1.0}, +  {1.0, 0.0, 1.0, 1.0}, +  {1.0, 1.0, 1.0, 1.0}, +  }; + + +vec3_t  bytedirs[NUMVERTEXNORMALS] = +{ +{-0.525731f, 0.000000f, 0.850651f}, {-0.442863f, 0.238856f, 0.864188f},  +{-0.295242f, 0.000000f, 0.955423f}, {-0.309017f, 0.500000f, 0.809017f},  +{-0.162460f, 0.262866f, 0.951056f}, {0.000000f, 0.000000f, 1.000000f},  +{0.000000f, 0.850651f, 0.525731f}, {-0.147621f, 0.716567f, 0.681718f},  +{0.147621f, 0.716567f, 0.681718f}, {0.000000f, 0.525731f, 0.850651f},  +{0.309017f, 0.500000f, 0.809017f}, {0.525731f, 0.000000f, 0.850651f},  +{0.295242f, 0.000000f, 0.955423f}, {0.442863f, 0.238856f, 0.864188f},  +{0.162460f, 0.262866f, 0.951056f}, {-0.681718f, 0.147621f, 0.716567f},  +{-0.809017f, 0.309017f, 0.500000f},{-0.587785f, 0.425325f, 0.688191f},  +{-0.850651f, 0.525731f, 0.000000f},{-0.864188f, 0.442863f, 0.238856f},  +{-0.716567f, 0.681718f, 0.147621f},{-0.688191f, 0.587785f, 0.425325f},  +{-0.500000f, 0.809017f, 0.309017f}, {-0.238856f, 0.864188f, 0.442863f},  +{-0.425325f, 0.688191f, 0.587785f}, {-0.716567f, 0.681718f, -0.147621f},  +{-0.500000f, 0.809017f, -0.309017f}, {-0.525731f, 0.850651f, 0.000000f},  +{0.000000f, 0.850651f, -0.525731f}, {-0.238856f, 0.864188f, -0.442863f},  +{0.000000f, 0.955423f, -0.295242f}, {-0.262866f, 0.951056f, -0.162460f},  +{0.000000f, 1.000000f, 0.000000f}, {0.000000f, 0.955423f, 0.295242f},  +{-0.262866f, 0.951056f, 0.162460f}, {0.238856f, 0.864188f, 0.442863f},  +{0.262866f, 0.951056f, 0.162460f}, {0.500000f, 0.809017f, 0.309017f},  +{0.238856f, 0.864188f, -0.442863f},{0.262866f, 0.951056f, -0.162460f},  +{0.500000f, 0.809017f, -0.309017f},{0.850651f, 0.525731f, 0.000000f},  +{0.716567f, 0.681718f, 0.147621f}, {0.716567f, 0.681718f, -0.147621f},  +{0.525731f, 0.850651f, 0.000000f}, {0.425325f, 0.688191f, 0.587785f},  +{0.864188f, 0.442863f, 0.238856f}, {0.688191f, 0.587785f, 0.425325f},  +{0.809017f, 0.309017f, 0.500000f}, {0.681718f, 0.147621f, 0.716567f},  +{0.587785f, 0.425325f, 0.688191f}, {0.955423f, 0.295242f, 0.000000f},  +{1.000000f, 0.000000f, 0.000000f}, {0.951056f, 0.162460f, 0.262866f},  +{0.850651f, -0.525731f, 0.000000f},{0.955423f, -0.295242f, 0.000000f},  +{0.864188f, -0.442863f, 0.238856f}, {0.951056f, -0.162460f, 0.262866f},  +{0.809017f, -0.309017f, 0.500000f}, {0.681718f, -0.147621f, 0.716567f},  +{0.850651f, 0.000000f, 0.525731f}, {0.864188f, 0.442863f, -0.238856f},  +{0.809017f, 0.309017f, -0.500000f}, {0.951056f, 0.162460f, -0.262866f},  +{0.525731f, 0.000000f, -0.850651f}, {0.681718f, 0.147621f, -0.716567f}, +{0.681718f, -0.147621f, -0.716567f},{0.850651f, 0.000000f, -0.525731f},  +{0.809017f, -0.309017f, -0.500000f}, {0.864188f, -0.442863f, -0.238856f},  +{0.951056f, -0.162460f, -0.262866f}, {0.147621f, 0.716567f, -0.681718f},  +{0.309017f, 0.500000f, -0.809017f}, {0.425325f, 0.688191f, -0.587785f},  +{0.442863f, 0.238856f, -0.864188f}, {0.587785f, 0.425325f, -0.688191f},  +{0.688191f, 0.587785f, -0.425325f}, {-0.147621f, 0.716567f, -0.681718f},  +{-0.309017f, 0.500000f, -0.809017f}, {0.000000f, 0.525731f, -0.850651f},  +{-0.525731f, 0.000000f, -0.850651f}, {-0.442863f, 0.238856f, -0.864188f},  +{-0.295242f, 0.000000f, -0.955423f}, {-0.162460f, 0.262866f, -0.951056f},  +{0.000000f, 0.000000f, -1.000000f}, {0.295242f, 0.000000f, -0.955423f},  +{0.162460f, 0.262866f, -0.951056f}, {-0.442863f, -0.238856f, -0.864188f},  +{-0.309017f, -0.500000f, -0.809017f}, {-0.162460f, -0.262866f, -0.951056f},  +{0.000000f, -0.850651f, -0.525731f}, {-0.147621f, -0.716567f, -0.681718f},  +{0.147621f, -0.716567f, -0.681718f}, {0.000000f, -0.525731f, -0.850651f},  +{0.309017f, -0.500000f, -0.809017f}, {0.442863f, -0.238856f, -0.864188f},  +{0.162460f, -0.262866f, -0.951056f}, {0.238856f, -0.864188f, -0.442863f},  +{0.500000f, -0.809017f, -0.309017f}, {0.425325f, -0.688191f, -0.587785f},  +{0.716567f, -0.681718f, -0.147621f}, {0.688191f, -0.587785f, -0.425325f},  +{0.587785f, -0.425325f, -0.688191f}, {0.000000f, -0.955423f, -0.295242f},  +{0.000000f, -1.000000f, 0.000000f}, {0.262866f, -0.951056f, -0.162460f},  +{0.000000f, -0.850651f, 0.525731f}, {0.000000f, -0.955423f, 0.295242f},  +{0.238856f, -0.864188f, 0.442863f}, {0.262866f, -0.951056f, 0.162460f},  +{0.500000f, -0.809017f, 0.309017f}, {0.716567f, -0.681718f, 0.147621f},  +{0.525731f, -0.850651f, 0.000000f}, {-0.238856f, -0.864188f, -0.442863f},  +{-0.500000f, -0.809017f, -0.309017f}, {-0.262866f, -0.951056f, -0.162460f},  +{-0.850651f, -0.525731f, 0.000000f}, {-0.716567f, -0.681718f, -0.147621f},  +{-0.716567f, -0.681718f, 0.147621f}, {-0.525731f, -0.850651f, 0.000000f},  +{-0.500000f, -0.809017f, 0.309017f}, {-0.238856f, -0.864188f, 0.442863f},  +{-0.262866f, -0.951056f, 0.162460f}, {-0.864188f, -0.442863f, 0.238856f},  +{-0.809017f, -0.309017f, 0.500000f}, {-0.688191f, -0.587785f, 0.425325f},  +{-0.681718f, -0.147621f, 0.716567f}, {-0.442863f, -0.238856f, 0.864188f},  +{-0.587785f, -0.425325f, 0.688191f}, {-0.309017f, -0.500000f, 0.809017f},  +{-0.147621f, -0.716567f, 0.681718f}, {-0.425325f, -0.688191f, 0.587785f},  +{-0.162460f, -0.262866f, 0.951056f}, {0.442863f, -0.238856f, 0.864188f},  +{0.162460f, -0.262866f, 0.951056f}, {0.309017f, -0.500000f, 0.809017f},  +{0.147621f, -0.716567f, 0.681718f}, {0.000000f, -0.525731f, 0.850651f},  +{0.425325f, -0.688191f, 0.587785f}, {0.587785f, -0.425325f, 0.688191f},  +{0.688191f, -0.587785f, 0.425325f}, {-0.955423f, 0.295242f, 0.000000f},  +{-0.951056f, 0.162460f, 0.262866f}, {-1.000000f, 0.000000f, 0.000000f},  +{-0.850651f, 0.000000f, 0.525731f}, {-0.955423f, -0.295242f, 0.000000f},  +{-0.951056f, -0.162460f, 0.262866f}, {-0.864188f, 0.442863f, -0.238856f},  +{-0.951056f, 0.162460f, -0.262866f}, {-0.809017f, 0.309017f, -0.500000f},  +{-0.864188f, -0.442863f, -0.238856f}, {-0.951056f, -0.162460f, -0.262866f},  +{-0.809017f, -0.309017f, -0.500000f}, {-0.681718f, 0.147621f, -0.716567f},  +{-0.681718f, -0.147621f, -0.716567f}, {-0.850651f, 0.000000f, -0.525731f},  +{-0.688191f, 0.587785f, -0.425325f}, {-0.587785f, 0.425325f, -0.688191f},  +{-0.425325f, 0.688191f, -0.587785f}, {-0.425325f, -0.688191f, -0.587785f},  +{-0.587785f, -0.425325f, -0.688191f}, {-0.688191f, -0.587785f, -0.425325f} +}; + +//============================================================== + +int   Q_rand( int *seed ) { +  *seed = (69069 * *seed + 1); +  return *seed; +} + +float Q_random( int *seed ) { +  return ( Q_rand( seed ) & 0xffff ) / (float)0x10000; +} + +float Q_crandom( int *seed ) { +  return 2.0 * ( Q_random( seed ) - 0.5 ); +} + + +//======================================================= + +signed char ClampChar( int i ) { +  if ( i < -128 ) { +    return -128; +  } +  if ( i > 127 ) { +    return 127; +  } +  return i; +} + +signed short ClampShort( int i ) { +  if ( i < -32768 ) { +    return -32768; +  } +  if ( i > 0x7fff ) { +    return 0x7fff; +  } +  return i; +} + + +// this isn't a real cheap function to call! +int DirToByte( vec3_t dir ) { +  int   i, best; +  float d, bestd; + +  if ( !dir ) { +    return 0; +  } + +  bestd = 0; +  best = 0; +  for (i=0 ; i<NUMVERTEXNORMALS ; i++) +  { +    d = DotProduct (dir, bytedirs[i]); +    if (d > bestd) +    { +      bestd = d; +      best = i; +    } +  } + +  return best; +} + +void ByteToDir( int b, vec3_t dir ) { +  if ( b < 0 || b >= NUMVERTEXNORMALS ) { +    VectorCopy( vec3_origin, dir ); +    return; +  } +  VectorCopy (bytedirs[b], dir); +} + + +unsigned ColorBytes3 (float r, float g, float b) { +  unsigned  i; + +  ( (byte *)&i )[0] = r * 255; +  ( (byte *)&i )[1] = g * 255; +  ( (byte *)&i )[2] = b * 255; + +  return i; +} + +unsigned ColorBytes4 (float r, float g, float b, float a) { +  unsigned  i; + +  ( (byte *)&i )[0] = r * 255; +  ( (byte *)&i )[1] = g * 255; +  ( (byte *)&i )[2] = b * 255; +  ( (byte *)&i )[3] = a * 255; + +  return i; +} + +float NormalizeColor( const vec3_t in, vec3_t out ) { +  float max; + +  max = in[0]; +  if ( in[1] > max ) { +    max = in[1]; +  } +  if ( in[2] > max ) { +    max = in[2]; +  } + +  if ( !max ) { +    VectorClear( out ); +  } else { +    out[0] = in[0] / max; +    out[1] = in[1] / max; +    out[2] = in[2] / max; +  } +  return max; +} + + +/* +===================== +PlaneFromPoints + +Returns false if the triangle is degenrate. +The normal will point out of the clock for clockwise ordered points +===================== +*/ +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) { +  vec3_t  d1, d2; + +  VectorSubtract( b, a, d1 ); +  VectorSubtract( c, a, d2 ); +  CrossProduct( d2, d1, plane ); +  if ( VectorNormalize( plane ) == 0 ) { +    return qfalse; +  } + +  plane[3] = DotProduct( a, plane ); +  return qtrue; +} + + +/// These optimised and much cleaner implementations of the Vector Rotation +/// functions were provided by Riv of planetquake (riviera@planetquake.com) +/// ...Cheers Riv... +/* +=============== +RotatePointAroundVector + +This is not implemented very well... +=============== +*/ +void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees) +{ +  float sin_a; +  float cos_a; +  float cos_ia; +  float i_i_ia; +  float j_j_ia; +  float k_k_ia; +  float i_j_ia; +  float i_k_ia; +  float j_k_ia; +  float a_sin; +  float b_sin; +  float c_sin; +  float rot[3][3]; + +  cos_ia = DEG2RAD(degrees); +  sin_a = sin(cos_ia); +  cos_a = cos(cos_ia); +  cos_ia = 1.0F - cos_a; + +  i_i_ia = dir[0] * dir[0] * cos_ia; +  j_j_ia = dir[1] * dir[1] * cos_ia; +  k_k_ia = dir[2] * dir[2] * cos_ia; +  i_j_ia = dir[0] * dir[1] * cos_ia; +  i_k_ia = dir[0] * dir[2] * cos_ia; +  j_k_ia = dir[1] * dir[2] * cos_ia; + +  a_sin = dir[0] * sin_a; +  b_sin = dir[1] * sin_a; +  c_sin = dir[2] * sin_a; + +  rot[0][0] = i_i_ia + cos_a; +  rot[0][1] = i_j_ia - c_sin; +  rot[0][2] = i_k_ia + b_sin; +  rot[1][0] = i_j_ia + c_sin; +  rot[1][1] = j_j_ia + cos_a; +  rot[1][2] = j_k_ia - a_sin; + +  rot[2][0] = i_k_ia - b_sin; +  rot[2][1] = j_k_ia + a_sin; +  rot[2][2] = k_k_ia + cos_a; + +  dst[0] = point[0] * rot[0][0] + point[1] * rot[0][1] + point[2] * rot[0][2]; +  dst[1] = point[0] * rot[1][0] + point[1] * rot[1][1] + point[2] * rot[1][2]; +  dst[2] = point[0] * rot[2][0] + point[1] * rot[2][1] + point[2] * rot[2][2]; +} + + +/* +=============== +RotateAroundDirection +=============== +*/ +void RotateAroundDirection(vec3_t axis[3], vec_t angle) +{ +  vec_t scale; + +  angle = DEG2RAD(angle); + +  // create an arbitrary axis[1]  +  PerpendicularVector(axis[1], axis[0]); + +  // cross to get axis[2] +  CrossProduct(axis[0], axis[1], axis[2]); + +  // rotate +  scale = cos(angle); +  VectorScale(axis[1], scale, axis[1]); + +  scale = sin(angle); +  VectorMA(axis[1], scale, axis[2], axis[1]); + +  // recalculate axis[2] +  CrossProduct(axis[0], axis[1], axis[2]); +} + + +void vectoangles( const vec3_t value1, vec3_t angles ) { +  float forward; +  float yaw, pitch; + +  if ( value1[1] == 0 && value1[0] == 0 ) { +    yaw = 0; +    if ( value1[2] > 0 ) { +      pitch = 90; +    } +    else { +      pitch = 270; +    } +  } +  else { +    if ( value1[0] ) { +      yaw = ( atan2 ( value1[1], value1[0] ) * 180 / M_PI ); +    } +    else if ( value1[1] > 0 ) { +      yaw = 90; +    } +    else { +      yaw = 270; +    } +    if ( yaw < 0 ) { +      yaw += 360; +    } + +    forward = sqrt ( value1[0]*value1[0] + value1[1]*value1[1] ); +    pitch = ( atan2(value1[2], forward) * 180 / M_PI ); +    if ( pitch < 0 ) { +      pitch += 360; +    } +  } + +  angles[PITCH] = -pitch; +  angles[YAW] = yaw; +  angles[ROLL] = 0; +} + + +/* +================= +AxisToAngles +TA: takes an axis (forward + right + up) +    and returns angles -- including a roll +================= +*/ +void AxisToAngles( vec3_t axis[3], vec3_t angles ) { +  float length1; +  float yaw, pitch, roll; + +  if ( axis[0][1] == 0 && axis[0][0] == 0 ) { +    yaw = 0; +    if ( axis[0][2] > 0 ) { +      pitch = 90; +    } +    else { +      pitch = 270; +    } +  } +  else { +    if ( axis[0][0] ) { +      yaw = ( atan2 ( axis[0][1], axis[0][0] ) * 180 / M_PI ); +    } +    else if ( axis[0][1] > 0 ) { +      yaw = 90; +    } +    else { +      yaw = 270; +    } +    if ( yaw < 0 ) { +      yaw += 360; +    } + +    length1 = sqrt ( axis[0][0]*axis[0][0] + axis[0][1]*axis[0][1] ); +    pitch = ( atan2(axis[0][2], length1) * 180 / M_PI ); +    if ( pitch < 0 ) { +      pitch += 360; +    } + +    roll = ( atan2( axis[1][2], axis[2][2] ) * 180 / M_PI ); +    if ( roll < 0 ) { +      roll += 360; +    } +  } + +  angles[PITCH] = -pitch; +  angles[YAW] = yaw; +  angles[ROLL] = roll; +} + +/* +================= +AnglesToAxis +================= +*/ +void AnglesToAxis( const vec3_t angles, vec3_t axis[3] ) { +  vec3_t  right; + +  // angle vectors returns "right" instead of "y axis" +  AngleVectors( angles, axis[0], right, axis[2] ); +  VectorSubtract( vec3_origin, right, axis[1] ); +} + +void AxisClear( vec3_t axis[3] ) { +  axis[0][0] = 1; +  axis[0][1] = 0; +  axis[0][2] = 0; +  axis[1][0] = 0; +  axis[1][1] = 1; +  axis[1][2] = 0; +  axis[2][0] = 0; +  axis[2][1] = 0; +  axis[2][2] = 1; +} + +void AxisCopy( vec3_t in[3], vec3_t out[3] ) { +  VectorCopy( in[0], out[0] ); +  VectorCopy( in[1], out[1] ); +  VectorCopy( in[2], out[2] ); +} + +void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) +{ +  float d; +  vec3_t n; +  float inv_denom; + +  inv_denom = 1.0F / DotProduct( normal, normal ); + +  d = DotProduct( normal, p ) * inv_denom; + +  n[0] = normal[0] * inv_denom; +  n[1] = normal[1] * inv_denom; +  n[2] = normal[2] * inv_denom; + +  dst[0] = p[0] - d * n[0]; +  dst[1] = p[1] - d * n[1]; +  dst[2] = p[2] - d * n[2]; +} + +/* +================ +MakeNormalVectors + +Given a normalized forward vector, create two +other perpendicular vectors +================ +*/ +void MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up) { +  float   d; + +  // this rotate and negate guarantees a vector +  // not colinear with the original +  right[1] = -forward[0]; +  right[2] = forward[1]; +  right[0] = forward[2]; + +  d = DotProduct (right, forward); +  VectorMA (right, -d, forward, right); +  VectorNormalize (right); +  CrossProduct (right, forward, up); +} + + +void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out ) +{ +  out[0] = DotProduct( in, matrix[0] ); +  out[1] = DotProduct( in, matrix[1] ); +  out[2] = DotProduct( in, matrix[2] ); +} + +//============================================================================ + +/* +** float q_rsqrt( float number ) +*/ +float Q_rsqrt( float number ) +{ +  long i; +  float x2, y; +  const float threehalfs = 1.5F; + +  x2 = number * 0.5F; +  y  = number; +  i  = * ( long * ) &y;           // evil floating point bit level hacking +  i  = 0x5f3759df - ( i >> 1 );               // what the fuck? +  y  = * ( float * ) &i; +  y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration +//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed + +  return y; +} + +float Q_fabs( float f ) { +  int tmp = * ( int * ) &f; +  tmp &= 0x7FFFFFFF; +  return * ( float * ) &tmp; +} + +//============================================================ + +/* +=============== +LerpAngle + +=============== +*/ +float LerpAngle (float from, float to, float frac) { +  float a; + +  if ( to - from > 180 ) { +    to -= 360; +  } +  if ( to - from < -180 ) { +    to += 360; +  } +  a = from + frac * (to - from); + +  return a; +} + + +/* +================= +AngleSubtract + +Always returns a value from -180 to 180 +================= +*/ +float AngleSubtract( float a1, float a2 ) { +  float a; + +  a = a1 - a2; +  while ( a > 180 ) { +    a -= 360; +  } +  while ( a < -180 ) { +    a += 360; +  } +  return a; +} + + +void AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 ) { +  v3[0] = AngleSubtract( v1[0], v2[0] ); +  v3[1] = AngleSubtract( v1[1], v2[1] ); +  v3[2] = AngleSubtract( v1[2], v2[2] ); +} + + +float AngleMod(float a) { +  a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); +  return a; +} + + +/* +================= +AngleNormalize360 + +returns angle normalized to the range [0 <= angle < 360] +================= +*/ +float AngleNormalize360 ( float angle ) { +  return (360.0 / 65536) * ((int)(angle * (65536 / 360.0)) & 65535); +} + + +/* +================= +AngleNormalize180 + +returns angle normalized to the range [-180 < angle <= 180] +================= +*/ +float AngleNormalize180 ( float angle ) { +  angle = AngleNormalize360( angle ); +  if ( angle > 180.0 ) { +    angle -= 360.0; +  } +  return angle; +} + + +/* +================= +AngleDelta + +returns the normalized delta from angle1 to angle2 +================= +*/ +float AngleDelta ( float angle1, float angle2 ) { +  return AngleNormalize180( angle1 - angle2 ); +} + + +//============================================================ + + +/* +================= +SetPlaneSignbits +================= +*/ +void SetPlaneSignbits (cplane_t *out) { +  int bits, j; + +  // for fast box on planeside test +  bits = 0; +  for (j=0 ; j<3 ; j++) { +    if (out->normal[j] < 0) { +      bits |= 1<<j; +    } +  } +  out->signbits = bits; +} + + +/* +================== +BoxOnPlaneSide + +Returns 1, 2, or 1 + 2 + +// this is the slow, general version +int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p) +{ +  int   i; +  float dist1, dist2; +  int   sides; +  vec3_t  corners[2]; + +  for (i=0 ; i<3 ; i++) +  { +    if (p->normal[i] < 0) +    { +      corners[0][i] = emins[i]; +      corners[1][i] = emaxs[i]; +    } +    else +    { +      corners[1][i] = emins[i]; +      corners[0][i] = emaxs[i]; +    } +  } +  dist1 = DotProduct (p->normal, corners[0]) - p->dist; +  dist2 = DotProduct (p->normal, corners[1]) - p->dist; +  sides = 0; +  if (dist1 >= 0) +    sides = 1; +  if (dist2 < 0) +    sides |= 2; + +  return sides; +} + +================== +*/ +#if !(defined __linux__ && defined __i386__ && !defined C_ONLY) +#if defined __LCC__ || defined C_ONLY || !id386 + +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p) +{ +  float dist1, dist2; +  int   sides; + +// fast axial cases +  if (p->type < 3) +  { +    if (p->dist <= emins[p->type]) +      return 1; +    if (p->dist >= emaxs[p->type]) +      return 2; +    return 3; +  } + +// general case +  switch (p->signbits) +  { +  case 0: +    dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +    dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +    break; +  case 1: +    dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +    dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +    break; +  case 2: +    dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +    dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +    break; +  case 3: +    dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +    dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +    break; +  case 4: +    dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +    dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +    break; +  case 5: +    dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +    dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +    break; +  case 6: +    dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +    dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +    break; +  case 7: +    dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +    dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +    break; +  default: +    dist1 = dist2 = 0;    // shut up compiler +    break; +  } + +  sides = 0; +  if (dist1 >= p->dist) +    sides = 1; +  if (dist2 < p->dist) +    sides |= 2; + +  return sides; +} +#else +#pragma warning( disable: 4035 ) + +__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p) +{ +  static int bops_initialized; +  static int Ljmptab[8]; + +  __asm { + +    push ebx + +    cmp bops_initialized, 1 +    je  initialized +    mov bops_initialized, 1 + +    mov Ljmptab[0*4], offset Lcase0 +    mov Ljmptab[1*4], offset Lcase1 +    mov Ljmptab[2*4], offset Lcase2 +    mov Ljmptab[3*4], offset Lcase3 +    mov Ljmptab[4*4], offset Lcase4 +    mov Ljmptab[5*4], offset Lcase5 +    mov Ljmptab[6*4], offset Lcase6 +    mov Ljmptab[7*4], offset Lcase7 + +initialized: + +    mov edx,dword ptr[4+12+esp] +    mov ecx,dword ptr[4+4+esp] +    xor eax,eax +    mov ebx,dword ptr[4+8+esp] +    mov al,byte ptr[17+edx] +    cmp al,8 +    jge Lerror +    fld dword ptr[0+edx] +    fld st(0) +    jmp dword ptr[Ljmptab+eax*4] +Lcase0: +    fmul dword ptr[ebx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ebx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ebx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ecx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +    jmp LSetSides +Lcase1: +    fmul dword ptr[ecx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ebx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ebx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ecx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +    jmp LSetSides +Lcase2: +    fmul dword ptr[ebx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ecx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ebx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ecx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +    jmp LSetSides +Lcase3: +    fmul dword ptr[ecx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ecx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ebx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ecx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +    jmp LSetSides +Lcase4: +    fmul dword ptr[ebx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ebx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ecx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ebx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +    jmp LSetSides +Lcase5: +    fmul dword ptr[ecx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ebx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ecx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ebx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +    jmp LSetSides +Lcase6: +    fmul dword ptr[ebx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ecx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ecx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ecx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ebx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +    jmp LSetSides +Lcase7: +    fmul dword ptr[ecx] +    fld dword ptr[0+4+edx] +    fxch st(2) +    fmul dword ptr[ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[4+ecx] +    fld dword ptr[0+8+edx] +    fxch st(2) +    fmul dword ptr[4+ebx] +    fxch st(2) +    fld st(0) +    fmul dword ptr[8+ecx] +    fxch st(5) +    faddp st(3),st(0) +    fmul dword ptr[8+ebx] +    fxch st(1) +    faddp st(3),st(0) +    fxch st(3) +    faddp st(2),st(0) +LSetSides: +    faddp st(2),st(0) +    fcomp dword ptr[12+edx] +    xor ecx,ecx +    fnstsw ax +    fcomp dword ptr[12+edx] +    and ah,1 +    xor ah,1 +    add cl,ah +    fnstsw ax +    and ah,1 +    add ah,ah +    add cl,ah +    pop ebx +    mov eax,ecx +    ret +Lerror: +    int 3 +  } +} +#pragma warning( default: 4035 ) + +#endif +#endif + +/* +================= +RadiusFromBounds +================= +*/ +float RadiusFromBounds( const vec3_t mins, const vec3_t maxs ) { +  int   i; +  vec3_t  corner; +  float a, b; + +  for (i=0 ; i<3 ; i++) { +    a = fabs( mins[i] ); +    b = fabs( maxs[i] ); +    corner[i] = a > b ? a : b; +  } + +  return VectorLength (corner); +} + + +void ClearBounds( vec3_t mins, vec3_t maxs ) { +  mins[0] = mins[1] = mins[2] = 99999; +  maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ) { +  if ( v[0] < mins[0] ) { +    mins[0] = v[0]; +  } +  if ( v[0] > maxs[0]) { +    maxs[0] = v[0]; +  } + +  if ( v[1] < mins[1] ) { +    mins[1] = v[1]; +  } +  if ( v[1] > maxs[1]) { +    maxs[1] = v[1]; +  } + +  if ( v[2] < mins[2] ) { +    mins[2] = v[2]; +  } +  if ( v[2] > maxs[2]) { +    maxs[2] = v[2]; +  } +} + + +int VectorCompare( const vec3_t v1, const vec3_t v2 ) { +  if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2]) { +    return 0; +  } + +  return 1; +} + + +vec_t VectorNormalize( vec3_t v ) { +  float length, ilength; + +  length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +  length = sqrt (length); + +  if ( length ) { +    ilength = 1/length; +    v[0] *= ilength; +    v[1] *= ilength; +    v[2] *= ilength; +  } + +  return length; +} + +// +// fast vector normalize routine that does not check to make sure +// that length != 0, nor does it return length +// +void VectorNormalizeFast( vec3_t v ) +{ +  float ilength; + +  ilength = Q_rsqrt( DotProduct( v, v ) ); + +  v[0] *= ilength; +  v[1] *= ilength; +  v[2] *= ilength; +} + +vec_t VectorNormalize2( const vec3_t v, vec3_t out) { +  float length, ilength; + +  length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +  length = sqrt (length); + +  if (length) +  { +    ilength = 1/length; +    out[0] = v[0]*ilength; +    out[1] = v[1]*ilength; +    out[2] = v[2]*ilength; +  } else { +    VectorClear( out ); +  } + +  return length; + +} + +void _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc) { +  vecc[0] = veca[0] + scale*vecb[0]; +  vecc[1] = veca[1] + scale*vecb[1]; +  vecc[2] = veca[2] + scale*vecb[2]; +} + + +vec_t _DotProduct( const vec3_t v1, const vec3_t v2 ) { +  return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out ) { +  out[0] = veca[0]-vecb[0]; +  out[1] = veca[1]-vecb[1]; +  out[2] = veca[2]-vecb[2]; +} + +void _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out ) { +  out[0] = veca[0]+vecb[0]; +  out[1] = veca[1]+vecb[1]; +  out[2] = veca[2]+vecb[2]; +} + +void _VectorCopy( const vec3_t in, vec3_t out ) { +  out[0] = in[0]; +  out[1] = in[1]; +  out[2] = in[2]; +} + +void _VectorScale( const vec3_t in, vec_t scale, vec3_t out ) { +  out[0] = in[0]*scale; +  out[1] = in[1]*scale; +  out[2] = in[2]*scale; +} + +void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) { +  cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; +  cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; +  cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t VectorLength( const vec3_t v ) { +  return sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); +} + + +vec_t VectorLengthSquared( const vec3_t v ) { +    return (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); +} + + +vec_t Distance( const vec3_t p1, const vec3_t p2 ) { +  vec3_t  v; + +  VectorSubtract (p2, p1, v); +  return VectorLength( v ); +} + +vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 ) { +  vec3_t  v; + +  VectorSubtract (p2, p1, v); +  return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +} + + +void VectorInverse( vec3_t v ){ +  v[0] = -v[0]; +  v[1] = -v[1]; +  v[2] = -v[2]; +} + +void Vector4Scale( const vec4_t in, vec_t scale, vec4_t out ) { +  out[0] = in[0]*scale; +  out[1] = in[1]*scale; +  out[2] = in[2]*scale; +  out[3] = in[3]*scale; +} + + +int Q_log2( int val ) { +  int answer; + +  answer = 0; +  while ( ( val>>=1 ) != 0 ) { +    answer++; +  } +  return answer; +} + + + +/* +================= +PlaneTypeForNormal +================= +*/ +/* +int PlaneTypeForNormal (vec3_t normal) { +  if ( normal[0] == 1.0 ) +    return PLANE_X; +  if ( normal[1] == 1.0 ) +    return PLANE_Y; +  if ( normal[2] == 1.0 ) +    return PLANE_Z; + +  return PLANE_NON_AXIAL; +} +*/ + + +/* +================ +MatrixMultiply +================ +*/ +void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) { +  out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + +        in1[0][2] * in2[2][0]; +  out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + +        in1[0][2] * in2[2][1]; +  out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + +        in1[0][2] * in2[2][2]; +  out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + +        in1[1][2] * in2[2][0]; +  out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + +        in1[1][2] * in2[2][1]; +  out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + +        in1[1][2] * in2[2][2]; +  out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + +        in1[2][2] * in2[2][0]; +  out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + +        in1[2][2] * in2[2][1]; +  out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + +        in1[2][2] * in2[2][2]; +} + + +void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) { +  float   angle; +  static float    sr, sp, sy, cr, cp, cy; +  // static to help MS compiler fp bugs + +  angle = angles[YAW] * (M_PI*2 / 360); +  sy = sin(angle); +  cy = cos(angle); +  angle = angles[PITCH] * (M_PI*2 / 360); +  sp = sin(angle); +  cp = cos(angle); +  angle = angles[ROLL] * (M_PI*2 / 360); +  sr = sin(angle); +  cr = cos(angle); + +  if (forward) +  { +    forward[0] = cp*cy; +    forward[1] = cp*sy; +    forward[2] = -sp; +  } +  if (right) +  { +    right[0] = (-1*sr*sp*cy+-1*cr*-sy); +    right[1] = (-1*sr*sp*sy+-1*cr*cy); +    right[2] = -1*sr*cp; +  } +  if (up) +  { +    up[0] = (cr*sp*cy+-sr*-sy); +    up[1] = (cr*sp*sy+-sr*cy); +    up[2] = cr*cp; +  } +} + +/* +** assumes "src" is normalized +*/ +void PerpendicularVector( vec3_t dst, const vec3_t src ) +{ +  int pos; +  int i; +  float minelem = 1.0F; +  vec3_t tempvec; + +  /* +  ** find the smallest magnitude axially aligned vector +  */ +  for ( pos = 0, i = 0; i < 3; i++ ) +  { +    if ( fabs( src[i] ) < minelem ) +    { +      pos = i; +      minelem = fabs( src[i] ); +    } +  } +  tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; +  tempvec[pos] = 1.0F; + +  /* +  ** project the point onto the plane defined by src +  */ +  ProjectPointOnPlane( dst, tempvec, src ); + +  /* +  ** normalize the result +  */ +  VectorNormalize( dst ); +} + +float arccos( float x ) +{ +  return atan2( sqrt( 1.0 - x * x ) / x, x ); +} + diff --git a/src/game/q_shared.c b/src/game/q_shared.c new file mode 100644 index 00000000..3477de84 --- /dev/null +++ b/src/game/q_shared.c @@ -0,0 +1,1229 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// +// q_shared.c -- stateless support routines that are included in each code dll + +/* + *  Portions Copyright (C) 2000-2001 Tim Angus + * + *  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, 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. + */ + +/*  To assertain which portions are licensed under the GPL and which are + *  licensed by Id Software, Inc. please run a diff between the equivalent + *  versions of the "Tremulous" modification and the unmodified "Quake3" + *  game source code. + */ +                     +#include "q_shared.h" + +float Com_Clamp( float min, float max, float value ) { +  if ( value < min ) { +    return min; +  } +  if ( value > max ) { +    return max; +  } +  return value; +} + + +/* +============ +COM_SkipPath +============ +*/ +char *COM_SkipPath (char *pathname) +{ +  char  *last; + +  last = pathname; +  while (*pathname) +  { +    if (*pathname=='/') +      last = pathname+1; +    pathname++; +  } +  return last; +} + +/* +============ +COM_StripExtension +============ +*/ +void COM_StripExtension( const char *in, char *out ) { +  while ( *in && *in != '.' ) { +    *out++ = *in++; +  } +  *out = 0; +} + + +/* +================== +COM_DefaultExtension +================== +*/ +void COM_DefaultExtension (char *path, int maxSize, const char *extension ) { +  char  oldPath[MAX_QPATH]; +  char    *src; + +// +// if path doesn't have a .EXT, append extension +// (extension should include the .) +// +  src = path + strlen(path) - 1; + +  while (*src != '/' && src != path) { +    if ( *src == '.' ) { +      return;                 // it has an extension +    } +    src--; +  } + +  Q_strncpyz( oldPath, path, sizeof( oldPath ) ); +  Com_sprintf( path, maxSize, "%s%s", oldPath, extension ); +} + +/* +============================================================================ + +          BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +// can't just use function pointers, or dll linkage can +// mess up when qcommon is included in multiple places +static short  (*_BigShort) (short l); +static short  (*_LittleShort) (short l); +static int    (*_BigLong) (int l); +static int    (*_LittleLong) (int l); +static qint64 (*_BigLong64) (qint64 l); +static qint64 (*_LittleLong64) (qint64 l); +static float  (*_BigFloat) (float l); +static float  (*_LittleFloat) (float l); + +short BigShort(short l){return _BigShort(l);} +short LittleShort(short l) {return _LittleShort(l);} +int   BigLong (int l) {return _BigLong(l);} +int   LittleLong (int l) {return _LittleLong(l);} +qint64  BigLong64 (qint64 l) {return _BigLong64(l);} +qint64  LittleLong64 (qint64 l) {return _LittleLong64(l);} +float BigFloat (float l) {return _BigFloat(l);} +float LittleFloat (float l) {return _LittleFloat(l);} + +short   ShortSwap (short l) +{ +  byte    b1,b2; + +  b1 = l&255; +  b2 = (l>>8)&255; + +  return (b1<<8) + b2; +} + +short ShortNoSwap (short l) +{ +  return l; +} + +int    LongSwap (int l) +{ +  byte    b1,b2,b3,b4; + +  b1 = l&255; +  b2 = (l>>8)&255; +  b3 = (l>>16)&255; +  b4 = (l>>24)&255; + +  return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LongNoSwap (int l) +{ +  return l; +} + +qint64 Long64Swap (qint64 ll) +{ +  qint64  result; + +  result.b0 = ll.b7; +  result.b1 = ll.b6; +  result.b2 = ll.b5; +  result.b3 = ll.b4; +  result.b4 = ll.b3; +  result.b5 = ll.b2; +  result.b6 = ll.b1; +  result.b7 = ll.b0; + +  return result; +} + +qint64 Long64NoSwap (qint64 ll) +{ +  return ll; +} + + +float FloatSwap (float f) +{ +  union +  { +    float f; +    byte  b[4]; +  } dat1, dat2; + + +  dat1.f = f; +  dat2.b[0] = dat1.b[3]; +  dat2.b[1] = dat1.b[2]; +  dat2.b[2] = dat1.b[1]; +  dat2.b[3] = dat1.b[0]; +  return dat2.f; +} + +float FloatNoSwap (float f) +{ +  return f; +} + +/* +================ +Swap_Init +================ +*/ +void Swap_Init (void) +{ +  byte  swaptest[2] = {1,0}; + +// set the byte swapping variables in a portable manner +  if ( *(short *)swaptest == 1) +  { +    _BigShort = ShortSwap; +    _LittleShort = ShortNoSwap; +    _BigLong = LongSwap; +    _LittleLong = LongNoSwap; +    _BigLong64 = Long64Swap; +    _LittleLong64 = Long64NoSwap; +    _BigFloat = FloatSwap; +    _LittleFloat = FloatNoSwap; +  } +  else +  { +    _BigShort = ShortNoSwap; +    _LittleShort = ShortSwap; +    _BigLong = LongNoSwap; +    _LittleLong = LongSwap; +    _BigLong64 = Long64NoSwap; +    _LittleLong64 = Long64Swap; +    _BigFloat = FloatNoSwap; +    _LittleFloat = FloatSwap; +  } + +} + + +/* +============================================================================ + +PARSING + +============================================================================ +*/ + +static  char  com_token[MAX_TOKEN_CHARS]; +static  char  com_parsename[MAX_TOKEN_CHARS]; +static  int   com_lines; + +void COM_BeginParseSession( const char *name ) +{ +  com_lines = 0; +  Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name); +} + +int COM_GetCurrentParseLine( void ) +{ +  return com_lines; +} + +char *COM_Parse( char **data_p ) +{ +  return COM_ParseExt( data_p, qtrue ); +} + + +void COM_ParseError( char *format, ... ) +{ +  va_list argptr; +  static char string[4096]; + +  va_start (argptr, format); +  vsprintf (string, format, argptr); +  va_end (argptr); + +  Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string); +} + +void COM_ParseWarning( char *format, ... ) +{ +  va_list argptr; +  static char string[4096]; + +  va_start (argptr, format); +  vsprintf (string, format, argptr); +  va_end (argptr); + +  Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string); +} + + +/* +============== +COM_Parse + +Parse a token out of a string +Will never return NULL, just empty strings + +If "allowLineBreaks" is qtrue then an empty +string will be returned if the next token is +a newline. +============== +*/ +static char *SkipWhitespace( char *data, qboolean *hasNewLines ) { +  int c; + +  while( (c = *data) <= ' ') { +    if( !c ) { +      return NULL; +    } +    if( c == '\n' ) { +      com_lines++; +      *hasNewLines = qtrue; +    } +    data++; +  } + +  return data; +} + + +int COM_Compress( char *data_p ) { +  char *datai, *datao; +  int c, pc, size; +  qboolean ws = qfalse; + +  size = 0; +  pc = 0; +  datai = datao = data_p; +  if (datai) { +    while ((c = *datai) != 0) { +      if (c == 13 || c == 10) { +        *datao = c; +        datao++; +        ws = qfalse; +        pc = c; +        datai++; +        size++; +      // skip double slash comments +      } else if ( c == '/' && datai[1] == '/' ) { +        while (*datai && *datai != '\n') { +          datai++; +        } +        ws = qfalse; +      // skip /* */ comments +      } else if ( c=='/' && datai[1] == '*' ) { +        while ( *datai && ( *datai != '*' || datai[1] != '/' ) )  +        { +          datai++; +        } +        if ( *datai )  +        { +          datai += 2; +        } +        ws = qfalse; +      } else { +        if (ws) { +          *datao = ' '; +          datao++; +        } +        *datao = c; +        datao++; +        datai++; +        ws = qfalse; +        pc = c; +        size++; +      } +    } +  } +  *datao = 0; +  return size; +} + + +char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) +{ +  int c = 0, len; +  qboolean hasNewLines = qfalse; +  char *data; + +  data = *data_p; +  len = 0; +  com_token[0] = 0; + +  // make sure incoming data is valid +  if ( !data ) +  { +    *data_p = NULL; +    return com_token; +  } + +  while ( 1 ) +  { +    // skip whitespace +    data = SkipWhitespace( data, &hasNewLines ); +    if ( !data ) +    { +      *data_p = NULL; +      return com_token; +    } +    if ( hasNewLines && !allowLineBreaks ) +    { +      *data_p = data; +      return com_token; +    } + +    c = *data; + +    // skip double slash comments +    if ( c == '/' && data[1] == '/' ) +    { +      data += 2; +      while (*data && *data != '\n') { +        data++; +      } +    } +    // skip /* */ comments +    else if ( c=='/' && data[1] == '*' ) +    { +      data += 2; +      while ( *data && ( *data != '*' || data[1] != '/' ) ) +      { +        data++; +      } +      if ( *data ) +      { +        data += 2; +      } +    } +    else +    { +      break; +    } +  } + +  // handle quoted strings +  if (c == '\"') +  { +    data++; +    while (1) +    { +      c = *data++; +      if (c=='\"' || !c) +      { +        com_token[len] = 0; +        *data_p = ( char * ) data; +        return com_token; +      } +      if (len < MAX_TOKEN_CHARS) +      { +        com_token[len] = c; +        len++; +      } +    } +  } + +  // parse a regular word +  do +  { +    if (len < MAX_TOKEN_CHARS) +    { +      com_token[len] = c; +      len++; +    } +    data++; +    c = *data; +    if ( c == '\n' ) +      com_lines++; +  } while (c>32); + +  if (len == MAX_TOKEN_CHARS) +  { +//    Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS); +    len = 0; +  } +  com_token[len] = 0; + +  *data_p = ( char * ) data; +  return com_token; +} + + +#if 0 +// no longer used +/* +=============== +COM_ParseInfos +=============== +*/ +int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) { +  char  *token; +  int   count; +  char  key[MAX_TOKEN_CHARS]; + +  count = 0; + +  while ( 1 ) { +    token = COM_Parse( &buf ); +    if ( !token[0] ) { +      break; +    } +    if ( strcmp( token, "{" ) ) { +      Com_Printf( "Missing { in info file\n" ); +      break; +    } + +    if ( count == max ) { +      Com_Printf( "Max infos exceeded\n" ); +      break; +    } + +    infos[count][0] = 0; +    while ( 1 ) { +      token = COM_ParseExt( &buf, qtrue ); +      if ( !token[0] ) { +        Com_Printf( "Unexpected end of info file\n" ); +        break; +      } +      if ( !strcmp( token, "}" ) ) { +        break; +      } +      Q_strncpyz( key, token, sizeof( key ) ); + +      token = COM_ParseExt( &buf, qfalse ); +      if ( !token[0] ) { +        strcpy( token, "<NULL>" ); +      } +      Info_SetValueForKey( infos[count], key, token ); +    } +    count++; +  } + +  return count; +} +#endif + + +/* +================== +COM_MatchToken +================== +*/ +void COM_MatchToken( char **buf_p, char *match ) { +  char  *token; + +  token = COM_Parse( buf_p ); +  if ( strcmp( token, match ) ) { +    Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match ); +  } +} + + +/* +================= +SkipBracedSection + +The next token should be an open brace. +Skips until a matching close brace is found. +Internal brace depths are properly skipped. +================= +*/ +void SkipBracedSection (char **program) { +  char      *token; +  int       depth; + +  depth = 0; +  do { +    token = COM_ParseExt( program, qtrue ); +    if( token[1] == 0 ) { +      if( token[0] == '{' ) { +        depth++; +      } +      else if( token[0] == '}' ) { +        depth--; +      } +    } +  } while( depth && *program ); +} + +/* +================= +SkipRestOfLine +================= +*/ +void SkipRestOfLine ( char **data ) { +  char  *p; +  int   c; + +  p = *data; +  while ( (c = *p++) != 0 ) { +    if ( c == '\n' ) { +      com_lines++; +      break; +    } +  } + +  *data = p; +} + + +void Parse1DMatrix (char **buf_p, int x, float *m) { +  char  *token; +  int   i; + +  COM_MatchToken( buf_p, "(" ); + +  for (i = 0 ; i < x ; i++) { +    token = COM_Parse(buf_p); +    m[i] = atof(token); +  } + +  COM_MatchToken( buf_p, ")" ); +} + +void Parse2DMatrix (char **buf_p, int y, int x, float *m) { +  int   i; + +  COM_MatchToken( buf_p, "(" ); + +  for (i = 0 ; i < y ; i++) { +    Parse1DMatrix (buf_p, x, m + i * x); +  } + +  COM_MatchToken( buf_p, ")" ); +} + +void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) { +  int   i; + +  COM_MatchToken( buf_p, "(" ); + +  for (i = 0 ; i < z ; i++) { +    Parse2DMatrix (buf_p, y, x, m + i * x*y); +  } + +  COM_MatchToken( buf_p, ")" ); +} + + +/* +============================================================================ + +          LIBRARY REPLACEMENT FUNCTIONS + +============================================================================ +*/ + +int Q_isprint( int c ) +{ +  if ( c >= 0x20 && c <= 0x7E ) +    return ( 1 ); +  return ( 0 ); +} + +int Q_islower( int c ) +{ +  if (c >= 'a' && c <= 'z') +    return ( 1 ); +  return ( 0 ); +} + +int Q_isupper( int c ) +{ +  if (c >= 'A' && c <= 'Z') +    return ( 1 ); +  return ( 0 ); +} + +int Q_isalpha( int c ) +{ +  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) +    return ( 1 ); +  return ( 0 ); +} + +char* Q_strrchr( const char* string, int c ) +{ +  char cc = c; +  char *s; +  char *sp=(char *)0; + +  s = (char*)string; + +  while (*s) +  { +    if (*s == cc) +      sp = s; +    s++; +  } +  if (cc == 0) +    sp = s; + +  return sp; +} + +/* +============= +Q_strncpyz + +Safe strncpy that ensures a trailing zero +============= +*/ +void Q_strncpyz( char *dest, const char *src, int destsize ) { +  if ( !src ) { +    Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" ); +  } +  if ( destsize < 1 ) { +    Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); +  } + +  strncpy( dest, src, destsize-1 ); +    dest[destsize-1] = 0; +} + +int Q_stricmpn (const char *s1, const char *s2, int n) { +  int   c1, c2; + +  do { +    c1 = *s1++; +    c2 = *s2++; + +    if (!n--) { +      return 0;   // strings are equal until end point +    } + +    if (c1 != c2) { +      if (c1 >= 'a' && c1 <= 'z') { +        c1 -= ('a' - 'A'); +      } +      if (c2 >= 'a' && c2 <= 'z') { +        c2 -= ('a' - 'A'); +      } +      if (c1 != c2) { +        return c1 < c2 ? -1 : 1; +      } +    } +  } while (c1); + +  return 0;   // strings are equal +} + +int Q_strncmp (const char *s1, const char *s2, int n) { +  int   c1, c2; + +  do { +    c1 = *s1++; +    c2 = *s2++; + +    if (!n--) { +      return 0;   // strings are equal until end point +    } + +    if (c1 != c2) { +      return c1 < c2 ? -1 : 1; +    } +  } while (c1); + +  return 0;   // strings are equal +} + +int Q_stricmp (const char *s1, const char *s2) { +  return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1; +} + + +char *Q_strlwr( char *s1 ) { +    char  *s; + +    s = s1; +  while ( *s ) { +    *s = tolower(*s); +    s++; +  } +    return s1; +} + +char *Q_strupr( char *s1 ) { +    char  *s; + +    s = s1; +  while ( *s ) { +    *s = toupper(*s); +    s++; +  } +    return s1; +} + + +// never goes past bounds or leaves without a terminating 0 +void Q_strcat( char *dest, int size, const char *src ) { +  int   l1; + +  l1 = strlen( dest ); +  if ( l1 >= size ) { +    Com_Error( ERR_FATAL, "Q_strcat: already overflowed" ); +  } +  Q_strncpyz( dest + l1, src, size - l1 ); +} + + +int Q_PrintStrlen( const char *string ) { +  int     len; +  const char  *p; + +  if( !string ) { +    return 0; +  } + +  len = 0; +  p = string; +  while( *p ) { +    if( Q_IsColorString( p ) ) { +      p += 2; +      continue; +    } +    p++; +    len++; +  } + +  return len; +} + + +char *Q_CleanStr( char *string ) { +  char* d; +  char* s; +  int   c; + +  s = string; +  d = string; +  while ((c = *s) != 0 ) { +    if ( Q_IsColorString( s ) ) { +      s++; +    } +    else if ( c >= 0x20 && c <= 0x7E ) { +      *d++ = c; +    } +    s++; +  } +  *d = '\0'; + +  return string; +} + + +void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { +  int   len; +  va_list   argptr; +  char  bigbuffer[32000]; // big, but small enough to fit in PPC stack + +  va_start (argptr,fmt); +  len = vsprintf (bigbuffer,fmt,argptr); +  va_end (argptr); +  if ( len >= sizeof( bigbuffer ) ) { +    Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); +  } +  if (len >= size) { +    Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); +  } +  Q_strncpyz (dest, bigbuffer, size ); +} + + +/* +============ +va + +does a varargs printf into a temp buffer, so I don't need to have +varargs versions of all text functions. +FIXME: make this buffer size safe someday +============ +*/ +char  * QDECL va( char *format, ... ) { +  va_list   argptr; +  static char   string[2][32000]; // in case va is called by nested functions +  static int    index = 0; +  char  *buf; + +  buf = string[index & 1]; +  index++; + +  va_start (argptr, format); +  vsprintf (buf, format,argptr); +  va_end (argptr); + +  return buf; +} + + +/* +===================================================================== + +  INFO STRINGS + +===================================================================== +*/ + +/* +=============== +Info_ValueForKey + +Searches the string for the given +key and returns the associated value, or an empty string. +FIXME: overflow check? +=============== +*/ +char *Info_ValueForKey( const char *s, const char *key ) { +  char  pkey[BIG_INFO_KEY]; +  static  char value[2][BIG_INFO_VALUE];  // use two buffers so compares +                      // work without stomping on each other +  static  int valueindex = 0; +  char  *o; + +  if ( !s || !key ) { +    return ""; +  } + +  if ( strlen( s ) >= BIG_INFO_STRING ) { +    Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" ); +  } + +  valueindex ^= 1; +  if (*s == '\\') +    s++; +  while (1) +  { +    o = pkey; +    while (*s != '\\') +    { +      if (!*s) +        return ""; +      *o++ = *s++; +    } +    *o = 0; +    s++; + +    o = value[valueindex]; + +    while (*s != '\\' && *s) +    { +      *o++ = *s++; +    } +    *o = 0; + +    if (!Q_stricmp (key, pkey) ) +      return value[valueindex]; + +    if (!*s) +      break; +    s++; +  } + +  return ""; +} + + +/* +=================== +Info_NextPair + +Used to itterate through all the key/value pairs in an info string +=================== +*/ +void Info_NextPair( const char **head, char *key, char *value ) { +  char  *o; +  const char  *s; + +  s = *head; + +  if ( *s == '\\' ) { +    s++; +  } +  key[0] = 0; +  value[0] = 0; + +  o = key; +  while ( *s != '\\' ) { +    if ( !*s ) { +      *o = 0; +      *head = s; +      return; +    } +    *o++ = *s++; +  } +  *o = 0; +  s++; + +  o = value; +  while ( *s != '\\' && *s ) { +    *o++ = *s++; +  } +  *o = 0; + +  *head = s; +} + + +/* +=================== +Info_RemoveKey +=================== +*/ +void Info_RemoveKey( char *s, const char *key ) { +  char  *start; +  char  pkey[MAX_INFO_KEY]; +  char  value[MAX_INFO_VALUE]; +  char  *o; + +  if ( strlen( s ) >= MAX_INFO_STRING ) { +    Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" ); +  } + +  if (strchr (key, '\\')) { +    return; +  } + +  while (1) +  { +    start = s; +    if (*s == '\\') +      s++; +    o = pkey; +    while (*s != '\\') +    { +      if (!*s) +        return; +      *o++ = *s++; +    } +    *o = 0; +    s++; + +    o = value; +    while (*s != '\\' && *s) +    { +      if (!*s) +        return; +      *o++ = *s++; +    } +    *o = 0; + +    if (!strcmp (key, pkey) ) +    { +      strcpy (start, s);  // remove this part +      return; +    } + +    if (!*s) +      return; +  } + +} + + +/* +=================== +Info_RemoveKey_Big +=================== +*/ +void Info_RemoveKey_Big( char *s, const char *key ) { +  char  *start; +  char  pkey[BIG_INFO_KEY]; +  char  value[BIG_INFO_VALUE]; +  char  *o; + +  if ( strlen( s ) >= BIG_INFO_STRING ) { +    Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" ); +  } + +  if (strchr (key, '\\')) { +    return; +  } + +  while (1) +  { +    start = s; +    if (*s == '\\') +      s++; +    o = pkey; +    while (*s != '\\') +    { +      if (!*s) +        return; +      *o++ = *s++; +    } +    *o = 0; +    s++; + +    o = value; +    while (*s != '\\' && *s) +    { +      if (!*s) +        return; +      *o++ = *s++; +    } +    *o = 0; + +    if (!strcmp (key, pkey) ) +    { +      strcpy (start, s);  // remove this part +      return; +    } + +    if (!*s) +      return; +  } + +} + + +/* +================== +Info_Validate + +Some characters are illegal in info strings because they +can mess up the server's parsing +================== +*/ +qboolean Info_Validate( const char *s ) { +  if ( strchr( s, '\"' ) ) { +    return qfalse; +  } +  if ( strchr( s, ';' ) ) { +    return qfalse; +  } +  return qtrue; +} + +/* +================== +Info_SetValueForKey + +Changes or adds a key/value pair +================== +*/ +void Info_SetValueForKey( char *s, const char *key, const char *value ) { +  char  newi[MAX_INFO_STRING]; + +  if ( strlen( s ) >= MAX_INFO_STRING ) { +    Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" ); +  } + +  if (strchr (key, '\\') || strchr (value, '\\')) +  { +    Com_Printf ("Can't use keys or values with a \\\n"); +    return; +  } + +  if (strchr (key, ';') || strchr (value, ';')) +  { +    Com_Printf ("Can't use keys or values with a semicolon\n"); +    return; +  } + +  if (strchr (key, '\"') || strchr (value, '\"')) +  { +    Com_Printf ("Can't use keys or values with a \"\n"); +    return; +  } + +  Info_RemoveKey (s, key); +  if (!value || !strlen(value)) +    return; + +  Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); + +  if (strlen(newi) + strlen(s) > MAX_INFO_STRING) +  { +    Com_Printf ("Info string length exceeded\n"); +    return; +  } + +  strcat (s, newi); +} + +//==================================================================== + + +/* +================== +Info_SetValueForKey_Big + +Changes or adds a key/value pair +================== +*/ +void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) { +  char  newi[BIG_INFO_STRING]; + +  if ( strlen( s ) >= BIG_INFO_STRING ) { +    Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" ); +  } + +  if (strchr (key, '\\') || strchr (value, '\\')) +  { +    Com_Printf ("Can't use keys or values with a \\\n"); +    return; +  } + +  if (strchr (key, ';') || strchr (value, ';')) +  { +    Com_Printf ("Can't use keys or values with a semicolon\n"); +    return; +  } + +  if (strchr (key, '\"') || strchr (value, '\"')) +  { +    Com_Printf ("Can't use keys or values with a \"\n"); +    return; +  } + +  Info_RemoveKey_Big (s, key); +  if (!value || !strlen(value)) +    return; + +  Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); + +  if (strlen(newi) + strlen(s) > BIG_INFO_STRING) +  { +    Com_Printf ("BIG Info string length exceeded\n"); +    return; +  } + +  strcat (s, newi); +} + + + +//==================================================================== diff --git a/src/game/q_shared.h b/src/game/q_shared.h new file mode 100644 index 00000000..b4bc4f23 --- /dev/null +++ b/src/game/q_shared.h @@ -0,0 +1,1206 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// + +/* + *  Portions Copyright (C) 2000-2001 Tim Angus + * + *  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, 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. + */ + +/*  To assertain which portions are licensed under the GPL and which are + *  licensed by Id Software, Inc. please run a diff between the equivalent + *  versions of the "Tremulous" modification and the unmodified "Quake3" + *  game source code. + */ + +#ifndef __Q_SHARED_H +#define __Q_SHARED_H + +// q_shared.h -- included first by ALL program modules. +// A user mod should never modify this file + +#define Q3_VERSION    "Q3 1.27g" + + +#define NEW_ANIMS +#define MAX_TEAMNAME 32 + +#ifdef _WIN32 + +#pragma warning(disable : 4018)     // signed/unsigned mismatch +#pragma warning(disable : 4032) +#pragma warning(disable : 4051) +#pragma warning(disable : 4057)   // slightly different base types +#pragma warning(disable : 4100)   // unreferenced formal parameter +#pragma warning(disable : 4115) +#pragma warning(disable : 4125)   // decimal digit terminates octal escape sequence +#pragma warning(disable : 4127)   // conditional expression is constant +#pragma warning(disable : 4136) +#pragma warning(disable : 4152)   // nonstandard extension, function/data pointer conversion in expression +//#pragma warning(disable : 4201) +//#pragma warning(disable : 4214) +#pragma warning(disable : 4244) +#pragma warning(disable : 4142)   // benign redefinition +//#pragma warning(disable : 4305)   // truncation from const double to float +//#pragma warning(disable : 4310)   // cast truncates constant value +//#pragma warning(disable:  4505)   // unreferenced local function has been removed +#pragma warning(disable : 4514) +#pragma warning(disable : 4702)   // unreachable code +#pragma warning(disable : 4711)   // selected for automatic inline expansion +#pragma warning(disable : 4220)   // varargs matches remaining parameters +#endif + +#if defined(ppc) || defined(__ppc) || defined(__ppc__) || defined(__POWERPC__) +#define idppc 1 +#endif + +/********************************************************************** +  VM Considerations + +  The VM can not use the standard system headers because we aren't really +  using the compiler they were meant for.  We use bg_lib.h which contains +  prototypes for the functions we define for our own use in bg_lib.c. + +  When writing mods, please add needed headers HERE, do not start including +  stuff like <stdio.h> in the various .c files that make up each of the VMs +  since you will be including system headers files can will have issues. + +  Remember, if you use a C library function that is not defined in bg_lib.c, +  you will have to add your own version for support in the VM. + + **********************************************************************/ + +#ifdef Q3_VM + +#include "bg_lib.h" + +#else + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <ctype.h> +#include <limits.h> + +#endif + +#ifdef _WIN32 + +//#pragma intrinsic( memset, memcpy ) + +#endif + + +// this is the define for determining if we have an asm version of a C function +#if (defined _M_IX86 || defined __i386__) && !defined __sun__  && !defined __LCC__ +#define id386 1 +#else +#define id386 0 +#endif + +// for windows fastcall option + +#define QDECL + +//======================= WIN32 DEFINES ================================= + +#ifdef WIN32 + +#define MAC_STATIC + +#undef QDECL +#define QDECL __cdecl + +// buildstring will be incorporated into the version string +#ifdef NDEBUG +#ifdef _M_IX86 +#define CPUSTRING "win-x86" +#elif defined _M_ALPHA +#define CPUSTRING "win-AXP" +#endif +#else +#ifdef _M_IX86 +#define CPUSTRING "win-x86-debug" +#elif defined _M_ALPHA +#define CPUSTRING "win-AXP-debug" +#endif +#endif + + +#define PATH_SEP '\\' + +#endif + +//======================= MAC OS X SERVER DEFINES ===================== + +#if defined(__MACH__) && defined(__APPLE__) + +#define MAC_STATIC + +#ifdef __ppc__ +#define CPUSTRING "MacOSXS-ppc" +#elif defined __i386__ +#define CPUSTRING "MacOSXS-i386" +#else +#define CPUSTRING "MacOSXS-other" +#endif + +#define PATH_SEP  '/' + +#define GAME_HARD_LINKED +#define CGAME_HARD_LINKED +#define UI_HARD_LINKED +#define BOTLIB_HARD_LINKED + +#endif + +//======================= MAC DEFINES ================================= + +#ifdef __MACOS__ + +#include <MacTypes.h> + +#define MAC_STATIC  static + +#define CPUSTRING "MacOS-PPC" + +#define PATH_SEP ':' + +#define GAME_HARD_LINKED +#define CGAME_HARD_LINKED +#define UI_HARD_LINKED +#define BOTLIB_HARD_LINKED + +void Sys_PumpEvents( void ); + +#endif + +//======================= LINUX DEFINES ================================= + +// the mac compiler can't handle >32k of locals, so we +// just waste space and make big arrays static... +#ifdef __linux__ + +#define MAC_STATIC + +#ifdef __i386__ +#define CPUSTRING "linux-i386" +#elif defined __axp__ +#define CPUSTRING "linux-alpha" +#else +#define CPUSTRING "linux-other" +#endif + +#define PATH_SEP '/' + +#endif + +//============================================================= + + +typedef unsigned char     byte; + +typedef enum {qfalse, qtrue}  qboolean; + +typedef int   qhandle_t; +typedef int   sfxHandle_t; +typedef int   fileHandle_t; +typedef int   clipHandle_t; + + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define MAX_QINT      0x7fffffff +#define MIN_QINT      (-MAX_QINT-1) + + +// angle indexes +#define PITCH       0   // up / down +#define YAW         1   // left / right +#define ROLL        2   // fall over + +// the game guarantees that no string from the network will ever +// exceed MAX_STRING_CHARS +#define MAX_STRING_CHARS  1024  // max length of a string passed to Cmd_TokenizeString +#define MAX_STRING_TOKENS 256   // max tokens resulting from Cmd_TokenizeString +#define MAX_TOKEN_CHARS   1024  // max length of an individual token + +#define MAX_INFO_STRING   1024 +#define MAX_INFO_KEY    1024 +#define MAX_INFO_VALUE    1024 + +#define BIG_INFO_STRING   8192  // used for system info key only +#define BIG_INFO_KEY      8192 +#define BIG_INFO_VALUE    8192 + +#define MAX_QPATH     64    // max length of a quake game pathname +#define MAX_OSPATH      256   // max length of a filesystem pathname + +#define MAX_NAME_LENGTH   32    // max length of a client name + +#define MAX_SAY_TEXT  150 + +// paramters for command buffer stuffing +typedef enum { +  EXEC_NOW,     // don't return until completed, a VM should NEVER use this, +            // because some commands might cause the VM to be unloaded... +  EXEC_INSERT,    // insert at current position, but don't run yet +  EXEC_APPEND     // add to end of the command buffer (normal case) +} cbufExec_t; + + +// +// these aren't needed by any of the VMs.  put in another header? +// +#define MAX_MAP_AREA_BYTES    32    // bit vector of area visibility + + +// print levels from renderer (FIXME: set up for game / cgame?) +typedef enum { +  PRINT_ALL, +  PRINT_DEVELOPER,    // only print when "developer 1" +  PRINT_WARNING, +  PRINT_ERROR +} printParm_t; + +#ifdef ERR_FATAL +#undef ERR_FATAL      // this is be defined in malloc.h +#endif + +// parameters to the main Error routine +typedef enum { +  ERR_FATAL,          // exit the entire game with a popup window +  ERR_DROP,         // print to console and disconnect from game +  ERR_SERVERDISCONNECT,   // don't kill server +  ERR_DISCONNECT,       // client disconnected from the server +  ERR_NEED_CD         // pop up the need-cd dialog +} errorParm_t; + + +// font rendering values used by ui and cgame + +#define PROP_GAP_WIDTH      3 +#define PROP_SPACE_WIDTH    8 +#define PROP_HEIGHT       27 +#define PROP_SMALL_SIZE_SCALE 0.75 + +#define BLINK_DIVISOR     200 +#define PULSE_DIVISOR     75 + +#define UI_LEFT     0x00000000  // default +#define UI_CENTER   0x00000001 +#define UI_RIGHT    0x00000002 +#define UI_FORMATMASK 0x00000007 +#define UI_SMALLFONT  0x00000010 +#define UI_BIGFONT    0x00000020  // default +#define UI_GIANTFONT  0x00000040 +#define UI_DROPSHADOW 0x00000800 +#define UI_BLINK    0x00001000 +#define UI_INVERSE    0x00002000 +#define UI_PULSE    0x00004000 + +#if defined(_DEBUG) && !defined(BSPC) +  #define HUNK_DEBUG +#endif + +typedef enum { +  h_high, +  h_low, +  h_dontcare +} ha_pref; + +#ifdef HUNK_DEBUG +#define Hunk_Alloc( size, preference )        Hunk_AllocDebug(size, preference, #size, __FILE__, __LINE__) +void *Hunk_AllocDebug( int size, ha_pref preference, char *label, char *file, int line ); +#else +void *Hunk_Alloc( int size, ha_pref preference ); +#endif + +void Com_Memset (void* dest, const int val, const size_t count); +void Com_Memcpy (void* dest, const void* src, const size_t count); + +#define CIN_system  1 +#define CIN_loop  2 +#define CIN_hold  4 +#define CIN_silent  8 +#define CIN_shader  16 + +/* +============================================================== + +MATHLIB + +============================================================== +*/ + + +typedef float vec_t; +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; +typedef vec_t vec5_t[5]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; + +#ifndef M_PI +#define M_PI    3.14159265358979323846f  // matches value in gcc v2 math.h +#endif + +#define NUMVERTEXNORMALS  162 +extern  vec3_t  bytedirs[NUMVERTEXNORMALS]; + +// all drawing is done to a 640*480 virtual screen size +// and will be automatically scaled to the real resolution +#define SCREEN_WIDTH    640 +#define SCREEN_HEIGHT   480 + +#define TINYCHAR_WIDTH    (SMALLCHAR_WIDTH) +#define TINYCHAR_HEIGHT   (SMALLCHAR_HEIGHT/2) + +#define SMALLCHAR_WIDTH   8 +#define SMALLCHAR_HEIGHT  16 + +#define BIGCHAR_WIDTH   16 +#define BIGCHAR_HEIGHT    16 + +#define GIANTCHAR_WIDTH   32 +#define GIANTCHAR_HEIGHT  48 + +extern  vec4_t    colorBlack; +extern  vec4_t    colorRed; +extern  vec4_t    colorGreen; +extern  vec4_t    colorBlue; +extern  vec4_t    colorYellow; +extern  vec4_t    colorMagenta; +extern  vec4_t    colorCyan; +extern  vec4_t    colorWhite; +extern  vec4_t    colorLtGrey; +extern  vec4_t    colorMdGrey; +extern  vec4_t    colorDkGrey; + +#define Q_COLOR_ESCAPE  '^' +#define Q_IsColorString(p)  ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE ) + +#define COLOR_BLACK   '0' +#define COLOR_RED   '1' +#define COLOR_GREEN   '2' +#define COLOR_YELLOW  '3' +#define COLOR_BLUE    '4' +#define COLOR_CYAN    '5' +#define COLOR_MAGENTA '6' +#define COLOR_WHITE   '7' +#define ColorIndex(c) ( ( (c) - '0' ) & 7 ) + +#define S_COLOR_BLACK "^0" +#define S_COLOR_RED   "^1" +#define S_COLOR_GREEN "^2" +#define S_COLOR_YELLOW  "^3" +#define S_COLOR_BLUE  "^4" +#define S_COLOR_CYAN  "^5" +#define S_COLOR_MAGENTA "^6" +#define S_COLOR_WHITE "^7" + +extern vec4_t g_color_table[8]; + +#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b +#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a + +#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F ) +#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI ) + +struct cplane_s; + +extern  vec3_t  vec3_origin; +extern  vec3_t  axisDefault[3]; + +#define nanmask (255<<23) + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +float Q_fabs( float f ); +float Q_rsqrt( float f );   // reciprocal square root + +#define SQRTFAST( x ) ( 1.0f / Q_rsqrt( x ) ) + +signed char ClampChar( int i ); +signed short ClampShort( int i ); + +// this isn't a real cheap function to call! +int DirToByte( vec3_t dir ); +void ByteToDir( int b, vec3_t dir ); + +#if 1 + +#define DotProduct(x,y)     ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c)    ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorCopy(a,b)     ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) +#define VectorScale(v, s, o)  ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) +#define VectorMA(v, s, b, o)  ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) + +#else + +#define DotProduct(x,y)     _DotProduct(x,y) +#define VectorSubtract(a,b,c) _VectorSubtract(a,b,c) +#define VectorAdd(a,b,c)    _VectorAdd(a,b,c) +#define VectorCopy(a,b)     _VectorCopy(a,b) +#define VectorScale(v, s, o)  _VectorScale(v,s,o) +#define VectorMA(v, s, b, o)  _VectorMA(v,s,b,o) + +#endif + +#ifdef __LCC__ +#ifdef VectorCopy +#undef VectorCopy +// this is a little hack to get more efficient copies in our interpreter +typedef struct { +  float v[3]; +} vec3struct_t; +#define VectorCopy(a,b) *(vec3struct_t *)b=*(vec3struct_t *)a; +#endif +#endif + +#define VectorClear(a)      ((a)[0]=(a)[1]=(a)[2]=0) +#define VectorNegate(a,b)   ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) +#define Vector4Copy(a,b)    ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) + +#define SnapVector(v) {v[0]=((int)(v[0]));v[1]=((int)(v[1]));v[2]=((int)(v[2]));} + +// just in case you do't want to use the macros +vec_t _DotProduct( const vec3_t v1, const vec3_t v2 ); +void _VectorSubtract( const vec3_t veca, const vec3_t vecb, vec3_t out ); +void _VectorAdd( const vec3_t veca, const vec3_t vecb, vec3_t out ); +void _VectorCopy( const vec3_t in, vec3_t out ); +void _VectorScale( const vec3_t in, float scale, vec3_t out ); +void _VectorMA( const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc ); + +unsigned ColorBytes3 (float r, float g, float b); +unsigned ColorBytes4 (float r, float g, float b, float a); + +float NormalizeColor( const vec3_t in, vec3_t out ); + +float RadiusFromBounds( const vec3_t mins, const vec3_t maxs ); +void ClearBounds( vec3_t mins, vec3_t maxs ); +void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ); +int VectorCompare( const vec3_t v1, const vec3_t v2 ); +vec_t VectorLength( const vec3_t v ); +vec_t VectorLengthSquared( const vec3_t v ); +vec_t Distance( const vec3_t p1, const vec3_t p2 ); +vec_t DistanceSquared( const vec3_t p1, const vec3_t p2 ); +void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ); +vec_t VectorNormalize (vec3_t v);   // returns vector length +void VectorNormalizeFast(vec3_t v);   // does NOT return vector length, uses rsqrt approximation +vec_t VectorNormalize2( const vec3_t v, vec3_t out ); +void VectorInverse (vec3_t v); +void Vector4Scale( const vec4_t in, vec_t scale, vec4_t out ); +void VectorRotate( vec3_t in, vec3_t matrix[3], vec3_t out ); +int Q_log2(int val); + +float Q_acos(float c); + +int   Q_rand( int *seed ); +float Q_random( int *seed ); +float Q_crandom( int *seed ); + +#define random()  ((rand () & 0x7fff) / ((float)0x7fff)) +#define crandom() (2.0 * (random() - 0.5)) + +void vectoangles( const vec3_t value1, vec3_t angles); +void AnglesToAxis( const vec3_t angles, vec3_t axis[3] ); + +void AxisClear( vec3_t axis[3] ); +void AxisCopy( vec3_t in[3], vec3_t out[3] ); + +void SetPlaneSignbits( struct cplane_s *out ); +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane); + +float AngleMod(float a); +float LerpAngle (float from, float to, float frac); +float AngleSubtract( float a1, float a2 ); +void  AnglesSubtract( vec3_t v1, vec3_t v2, vec3_t v3 ); + +float AngleNormalize360 ( float angle ); +float AngleNormalize180 ( float angle ); +float AngleDelta ( float angle1, float angle2 ); + +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ); +void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ); +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); +void RotateAroundDirection( vec3_t axis[3], float yaw ); +void MakeNormalVectors( const vec3_t forward, vec3_t right, vec3_t up ); +// perpendicular vector could be replaced by this + +//int PlaneTypeForNormal (vec3_t normal); + +void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]); +void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void PerpendicularVector( vec3_t dst, const vec3_t src ); + +//============================================= + +float Com_Clamp( float min, float max, float value ); + +char  *COM_SkipPath( char *pathname ); +void  COM_StripExtension( const char *in, char *out ); +void  COM_DefaultExtension( char *path, int maxSize, const char *extension ); + +void  COM_BeginParseSession( const char *name ); +int   COM_GetCurrentParseLine( void ); +char  *COM_Parse( char **data_p ); +char  *COM_ParseExt( char **data_p, qboolean allowLineBreak ); +int   COM_Compress( char *data_p ); +void  COM_ParseError( char *format, ... ); +void  COM_ParseWarning( char *format, ... ); +//int   COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ); + +#define MAX_TOKENLENGTH   1024 + +#ifndef TT_STRING +//token types +#define TT_STRING         1     // string +#define TT_LITERAL          2     // literal +#define TT_NUMBER         3     // number +#define TT_NAME           4     // name +#define TT_PUNCTUATION        5     // punctuation +#endif + +typedef struct pc_token_s +{ +  int type; +  int subtype; +  int intvalue; +  float floatvalue; +  char string[MAX_TOKENLENGTH]; +} pc_token_t; + +// data is an in/out parm, returns a parsed out token + +void  COM_MatchToken( char**buf_p, char *match ); + +void SkipBracedSection (char **program); +void SkipRestOfLine ( char **data ); + +void Parse1DMatrix (char **buf_p, int x, float *m); +void Parse2DMatrix (char **buf_p, int y, int x, float *m); +void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m); + +void  QDECL Com_sprintf (char *dest, int size, const char *fmt, ...); + + +// mode parm for FS_FOpenFile +typedef enum { +  FS_READ, +  FS_WRITE, +  FS_APPEND, +  FS_APPEND_SYNC +} fsMode_t; + +typedef enum { +  FS_SEEK_CUR, +  FS_SEEK_END, +  FS_SEEK_SET +} fsOrigin_t; + +//============================================= + +int Q_isprint( int c ); +int Q_islower( int c ); +int Q_isupper( int c ); +int Q_isalpha( int c ); + +// portable case insensitive compare +int   Q_stricmp (const char *s1, const char *s2); +int   Q_strncmp (const char *s1, const char *s2, int n); +int   Q_stricmpn (const char *s1, const char *s2, int n); +char  *Q_strlwr( char *s1 ); +char  *Q_strupr( char *s1 ); +char  *Q_strrchr( const char* string, int c ); + +// buffer size safe library replacements +void  Q_strncpyz( char *dest, const char *src, int destsize ); +void  Q_strcat( char *dest, int size, const char *src ); + +// strlen that discounts Quake color sequences +int Q_PrintStrlen( const char *string ); +// removes color sequences from string +char *Q_CleanStr( char *string ); + +//============================================= + +// 64-bit integers for global rankings interface +// implemented as a struct for qvm compatibility +typedef struct +{ +  byte  b0; +  byte  b1; +  byte  b2; +  byte  b3; +  byte  b4; +  byte  b5; +  byte  b6; +  byte  b7; +} qint64; + +//============================================= + +short BigShort(short l); +short LittleShort(short l); +int   BigLong (int l); +int   LittleLong (int l); +qint64  BigLong64 (qint64 l); +qint64  LittleLong64 (qint64 l); +float BigFloat (float l); +float LittleFloat (float l); + +void  Swap_Init (void); +char  * QDECL va(char *format, ...); + +//============================================= + +// +// key / value info strings +// +char *Info_ValueForKey( const char *s, const char *key ); +void Info_RemoveKey( char *s, const char *key ); +void Info_RemoveKey_big( char *s, const char *key ); +void Info_SetValueForKey( char *s, const char *key, const char *value ); +void Info_SetValueForKey_Big( char *s, const char *key, const char *value ); +qboolean Info_Validate( const char *s ); +void Info_NextPair( const char **s, char *key, char *value ); + +// this is only here so the functions in q_shared.c and bg_*.c can link +void  QDECL Com_Error( int level, const char *error, ... ); +void  QDECL Com_Printf( const char *msg, ... ); + + +/* +========================================================== + +CVARS (console variables) + +Many variables can be used for cheating purposes, so when +cheats is zero, force all unspecified variables to their +default values. +========================================================== +*/ + +#define CVAR_ARCHIVE    1 // set to cause it to be saved to vars.rc +                // used for system variables, not for player +                // specific configurations +#define CVAR_USERINFO   2 // sent to server on connect or change +#define CVAR_SERVERINFO   4 // sent in response to front end requests +#define CVAR_SYSTEMINFO   8 // these cvars will be duplicated on all clients +#define CVAR_INIT     16  // don't allow change from console at all, +                // but can be set from the command line +#define CVAR_LATCH      32  // will only change when C code next does +                // a Cvar_Get(), so it can't be changed +                // without proper initialization.  modified +                // will be set, even though the value hasn't +                // changed yet +#define CVAR_ROM      64  // display only, cannot be set by user at all +#define CVAR_USER_CREATED 128 // created by a set command +#define CVAR_TEMP     256 // can be set even when cheats are disabled, but is not archived +#define CVAR_CHEAT      512 // can not be changed if cheats are disabled +#define CVAR_NORESTART    1024  // do not clear when a cvar_restart is issued + +// nothing outside the Cvar_*() functions should modify these fields! +typedef struct cvar_s { +  char    *name; +  char    *string; +  char    *resetString;   // cvar_restart will reset to this value +  char    *latchedString;   // for CVAR_LATCH vars +  int     flags; +  qboolean  modified;     // set each time the cvar is changed +  int     modificationCount;  // incremented each time the cvar is changed +  float   value;        // atof( string ) +  int     integer;      // atoi( string ) +  struct cvar_s *next; +  struct cvar_s *hashNext; +} cvar_t; + +#define MAX_CVAR_VALUE_STRING 256 + +typedef int cvarHandle_t; + +// the modules that run in the virtual machine can't access the cvar_t directly, +// so they must ask for structured updates +typedef struct { +  cvarHandle_t  handle; +  int     modificationCount; +  float   value; +  int     integer; +  char    string[MAX_CVAR_VALUE_STRING]; +} vmCvar_t; + +/* +============================================================== + +COLLISION DETECTION + +============================================================== +*/ + +#include "surfaceflags.h"     // shared with the q3map utility + +// plane types are used to speed some tests +// 0-2 are axial planes +#define PLANE_X     0 +#define PLANE_Y     1 +#define PLANE_Z     2 +#define PLANE_NON_AXIAL 3 + +/* +================= +PlaneTypeForNormal +================= +*/ + +#define PlaneTypeForNormal(x) (x[0] == 1.0 ? PLANE_X : (x[1] == 1.0 ? PLANE_Y : (x[2] == 1.0 ? PLANE_Z : PLANE_NON_AXIAL) ) ) + +// plane_t structure +// !!! if this is changed, it must be changed in asm code too !!! +typedef struct cplane_s { +  vec3_t  normal; +  float dist; +  byte  type;     // for fast side tests: 0,1,2 = axial, 3 = nonaxial +  byte  signbits;   // signx + (signy<<1) + (signz<<2), used as lookup during collision +  byte  pad[2]; +} cplane_t; + + +// a trace is returned when a box is swept through the world +typedef struct { +  qboolean  allsolid; // if true, plane is not valid +  qboolean  startsolid; // if true, the initial point was in a solid area +  float   fraction; // time completed, 1.0 = didn't hit anything +  vec3_t    endpos;   // final position +  cplane_t  plane;    // surface normal at impact, transformed to world space +  int     surfaceFlags; // surface hit +  int     contents; // contents on other side of surface hit +  int     entityNum;  // entity the contacted sirface is a part of +} trace_t; + +// trace->entityNum can also be 0 to (MAX_GENTITIES-1) +// or ENTITYNUM_NONE, ENTITYNUM_WORLD + + +// markfragments are returned by CM_MarkFragments() +typedef struct { +  int   firstPoint; +  int   numPoints; +} markFragment_t; + + + +typedef struct { +  vec3_t    origin; +  vec3_t    axis[3]; +} orientation_t; + +//===================================================================== + + +// in order from highest priority to lowest +// if none of the catchers are active, bound key strings will be executed +#define KEYCATCH_CONSOLE    0x0001 +#define KEYCATCH_UI         0x0002 +#define KEYCATCH_MESSAGE    0x0004 +#define KEYCATCH_CGAME      0x0008 + +// sound channels +// channel 0 never willingly overrides +// other channels will allways override a playing sound on that channel +typedef enum { +  CHAN_AUTO, +  CHAN_LOCAL,   // menu sounds, etc +  CHAN_WEAPON, +  CHAN_VOICE, +  CHAN_ITEM, +  CHAN_BODY, +  CHAN_LOCAL_SOUND, // chat messages, etc +  CHAN_ANNOUNCER    // announcer voices, etc +} soundChannel_t; + + +/* +======================================================================== + +  ELEMENTS COMMUNICATED ACROSS THE NET + +======================================================================== +*/ + +#define ANGLE2SHORT(x)  ((int)((x)*65536/360) & 65535) +#define SHORT2ANGLE(x)  ((x)*(360.0/65536)) + +#define SNAPFLAG_RATE_DELAYED 1 +#define SNAPFLAG_NOT_ACTIVE   2 // snapshot used during connection and for zombies +#define SNAPFLAG_SERVERCOUNT  4 // toggled every map_restart so transitions can be detected + +// +// per-level limits +// +#define MAX_CLIENTS     64   // absolute limit +#define MAX_LOCATIONS   64 + +#define GENTITYNUM_BITS   10    // don't need to send any more +#define MAX_GENTITIES   (1<<GENTITYNUM_BITS) + +// entitynums are communicated with GENTITY_BITS, so any reserved +// values thatare going to be communcated over the net need to +// also be in this range +#define ENTITYNUM_NONE    (MAX_GENTITIES-1) +#define ENTITYNUM_WORLD   (MAX_GENTITIES-2) +#define ENTITYNUM_MAX_NORMAL  (MAX_GENTITIES-2) + + +#define MAX_MODELS      256   // these are sent over the net as 8 bits +#define MAX_SOUNDS      256   // so they cannot be blindly increased + + +#define MAX_CONFIGSTRINGS 1024 + +// these are the only configstrings that the system reserves, all the +// other ones are strictly for servergame to clientgame communication +#define CS_SERVERINFO   0   // an info string with all the serverinfo cvars +#define CS_SYSTEMINFO   1   // an info string for server system to client system configuration (timescale, etc) + +#define RESERVED_CONFIGSTRINGS  2 // game can't modify below this, only the system can + +#define MAX_GAMESTATE_CHARS 16000 +typedef struct { +  int     stringOffsets[MAX_CONFIGSTRINGS]; +  char    stringData[MAX_GAMESTATE_CHARS]; +  int     dataCount; +} gameState_t; + +//========================================================= + +// bit field limits +#define MAX_STATS         16 +#define MAX_PERSISTANT    16 +#define MAX_POWERUPS      16  +#define MAX_WEAPONS       16 + +#define MAX_PS_EVENTS     2 + +#define PS_PMOVEFRAMECOUNTBITS  6 + +// playerState_t is the information needed by both the client and server +// to predict player motion and actions +// nothing outside of pmove should modify these, or some degree of prediction error +// will occur + +// you can't add anything to this without modifying the code in msg.c + +// playerState_t is a full superset of entityState_t as it is used by players, +// so if a playerState_t is transmitted, the entityState_t can be fully derived +// from it. +typedef struct playerState_s { +  int     commandTime;  // cmd->serverTime of last executed command +  int     pm_type; +  int     bobCycle;   // for view bobbing and footstep generation +  int     pm_flags;   // ducked, jump_held, etc +  int     pm_time; + +  vec3_t    origin; +  vec3_t    velocity; +  int     weaponTime; +  int     gravity; +  int     speed; +  int     delta_angles[3];  // add to command angles to get view direction +                  // changed by spawns, rotating objects, and teleporters + +  int     groundEntityNum;// ENTITYNUM_NONE = in air + +  int     legsTimer;    // don't change low priority animations until this runs out +  int     legsAnim;   // mask off ANIM_TOGGLEBIT + +  int     torsoTimer;   // don't change low priority animations until this runs out +  int     torsoAnim;    // mask off ANIM_TOGGLEBIT + +  int     movementDir;  // a number 0 to 7 that represents the reletive angle +                // of movement to the view angle (axial and diagonals) +                // when at rest, the value will remain unchanged +                // used to twist the legs during strafing + +  //TA: this is also used by wall climbing classes As I can't add anything to the +  //    playerState_t struct.This means wall climbing classes won't ever be able to use +  //    a grapple hook. Does this matter? +  vec3_t    grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL + +  int     eFlags;     // copied to entityState_t->eFlags + +  int     eventSequence;  // pmove generated events +  int     events[MAX_PS_EVENTS]; +  int     eventParms[MAX_PS_EVENTS]; + +  int     externalEvent;  // events set on player from another source +  int     externalEventParm; +  int     externalEventTime; + +  int     clientNum;    // ranges from 0 to MAX_CLIENTS-1 +  int     weapon;     // copied to entityState_t->weapon +  int     weaponstate; + +  vec3_t    viewangles;   // for fixed views +  int     viewheight; + +  // damage feedback +  int     damageEvent;  // when it changes, latch the other parms +  int     damageYaw; +  int     damagePitch; +  int     damageCount; + +  int     stats[MAX_STATS]; +  int     persistant[MAX_PERSISTANT]; // stats that aren't cleared on death +  int     powerups[MAX_POWERUPS]; // level.time that the powerup runs out +  int     ammo[MAX_WEAPONS]; + +  int     generic1; +  int     loopSound; +  int     jumppad_ent;  // jumppad entity hit this frame +   +  // not communicated over the net at all +  int     ping;     // server to game info for scoreboard +  int     pmove_framecount; // FIXME: don't transmit over the network +  int     jumppad_frame; +  int     entityEventSequence; +} playerState_t; + + +//==================================================================== + + +// +// usercmd_t->button bits, many of which are generated by the client system, +// so they aren't game/cgame only definitions +// +#define BUTTON_ATTACK   1 +#define BUTTON_TALK     2     // displays talk balloon and disables actions +#define BUTTON_USE_HOLDABLE 4 +#define BUTTON_GESTURE    8 +#define BUTTON_WALKING    16      // walking can't just be infered from MOVE_RUN +                    // because a key pressed late in the frame will +                    // only generate a small move value for that frame +                    // walking will use different animations and +                    // won't generate footsteps +#define BUTTON_AFFIRMATIVE  32 +#define BUTTON_NEGATIVE   64 + +#define BUTTON_GETFLAG    128 +#define BUTTON_GUARDBASE  256 +#define BUTTON_PATROL   512 +#define BUTTON_FOLLOWME   1024 + +#define BUTTON_ANY      2048      // any key whatsoever + +#define MOVE_RUN      120     // if forwardmove or rightmove are >= MOVE_RUN, +                    // then BUTTON_WALKING should be set + + +// usercmd_t is sent to the server each client frame +typedef struct usercmd_s { +  int   serverTime; +  int   angles[3]; +  int   buttons; +  byte  weapon; //weapon +  signed char forwardmove, rightmove, upmove; +} usercmd_t; + +//=================================================================== + +// if entityState->solid == SOLID_BMODEL, modelindex is an inline model number +#define SOLID_BMODEL  0xffffff + +typedef enum { +  TR_STATIONARY, +  TR_INTERPOLATE,       // non-parametric, but interpolate between snapshots +  TR_LINEAR, +  TR_LINEAR_STOP, +  TR_SINE,          // value = base + sin( time / duration ) * delta +  TR_GRAVITY +} trType_t; + +typedef struct { +  trType_t  trType; +  int   trTime; +  int   trDuration;     // if non 0, trTime + trDuration = stop time +  vec3_t  trBase; +  vec3_t  trDelta;      // velocity, etc +} trajectory_t; + +// entityState_t is the information conveyed from the server +// in an update message about entities that the client will +// need to render in some way +// Different eTypes may use the information in different ways +// The messages are delta compressed, so it doesn't really matter if +// the structure size is fairly large + +typedef struct entityState_s { +  int   number;     // entity index +  int   eType;      // entityType_t +  int   eFlags; + +  trajectory_t  pos;  // for calculating position +  trajectory_t  apos; // for calculating angles + +  int   time; +  int   time2; + +  vec3_t  origin; +  vec3_t  origin2; + +  vec3_t  angles; +  vec3_t  angles2; + +  int   otherEntityNum; // shotgun sources, etc +  int   otherEntityNum2; + +  int   groundEntityNum;  // -1 = in air + +  int   constantLight;  // r + (g<<8) + (b<<16) + (intensity<<24) +  int   loopSound;    // constantly loop this sound + +  int   modelindex; +  int   modelindex2; +  int   clientNum;    // 0 to (MAX_CLIENTS - 1), for players and corpses +  int   frame; + +  int   solid;      // for client side prediction, trap_linkentity sets this properly + +  int   event;      // impulse events -- muzzle flashes, footsteps, etc +  int   eventParm; + +  // for players +  int   powerups;   // bit flags +  int   weapon;     // determines weapon and flash model, etc +  int   legsAnim;   // mask off ANIM_TOGGLEBIT +  int   torsoAnim;    // mask off ANIM_TOGGLEBIT + +  int   generic1; +} entityState_t; + +typedef enum { +  CA_UNINITIALIZED, +  CA_DISCONNECTED,  // not talking to a server +  CA_AUTHORIZING,   // not used any more, was checking cd key +  CA_CONNECTING,    // sending request packets to the server +  CA_CHALLENGING,   // sending challenge packets to the server +  CA_CONNECTED,   // netchan_t established, getting gamestate +  CA_LOADING,     // only during cgame initialization, never during main loop +  CA_PRIMED,      // got gamestate, waiting for first frame +  CA_ACTIVE,      // game views should be displayed +  CA_CINEMATIC    // playing a cinematic or a static pic, not connected to a server +} connstate_t; + +// font support  + +#define GLYPH_START 0 +#define GLYPH_END 255 +#define GLYPH_CHARSTART 32 +#define GLYPH_CHAREND 127 +#define GLYPHS_PER_FONT GLYPH_END - GLYPH_START + 1 +typedef struct { +  int height;       // number of scan lines +  int top;          // top of glyph in buffer +  int bottom;       // bottom of glyph in buffer +  int pitch;        // width for copying +  int xSkip;        // x adjustment +  int imageWidth;   // width of actual image +  int imageHeight;  // height of actual image +  float s;          // x offset in image where glyph starts +  float t;          // y offset in image where glyph starts +  float s2; +  float t2; +  qhandle_t glyph;  // handle to the shader with the glyph +  char shaderName[32]; +} glyphInfo_t; + +typedef struct { +  glyphInfo_t glyphs [GLYPHS_PER_FONT]; +  float glyphScale; +  char name[MAX_QPATH]; +} fontInfo_t; + +#define Square(x) ((x)*(x)) + +// real time +//============================================= + + +typedef struct qtime_s { +  int tm_sec;     /* seconds after the minute - [0,59] */ +  int tm_min;     /* minutes after the hour - [0,59] */ +  int tm_hour;    /* hours since midnight - [0,23] */ +  int tm_mday;    /* day of the month - [1,31] */ +  int tm_mon;     /* months since January - [0,11] */ +  int tm_year;    /* years since 1900 */ +  int tm_wday;    /* days since Sunday - [0,6] */ +  int tm_yday;    /* days since January 1 - [0,365] */ +  int tm_isdst;   /* daylight savings time flag */ +} qtime_t; + + +// server browser sources +#define AS_LOCAL      0 +#define AS_MPLAYER    1 +#define AS_GLOBAL     2 +#define AS_FAVORITES  3 + + +// cinematic states +typedef enum { +  FMV_IDLE, +  FMV_PLAY,   // play +  FMV_EOF,    // all other conditions, i.e. stop/EOF/abort +  FMV_ID_BLT, +  FMV_ID_IDLE, +  FMV_LOOPED, +  FMV_ID_WAIT +} e_status; + +typedef enum _flag_status { +  FLAG_ATBASE = 0, +  FLAG_TAKEN,     // CTF +  FLAG_TAKEN_RED,   // One Flag CTF +  FLAG_TAKEN_BLUE,  // One Flag CTF +  FLAG_DROPPED +} flagStatus_t; + + + +#define MAX_GLOBAL_SERVERS      2048 +#define MAX_OTHER_SERVERS     128 +#define MAX_PINGREQUESTS      16 +#define MAX_SERVERSTATUSREQUESTS  16 + +#define SAY_ALL   0 +#define SAY_TEAM  1 +#define SAY_TELL  2 + +#define CDKEY_LEN 16 +#define CDCHKSUM_LEN 2 + +#endif  // __Q_SHARED_H  | 
