Logo Search packages:      
Sourcecode: vdrift version File versions

vamosworld.cc

/* vim: set noexpandtab shiftwidth=8 cino=:
 ***************************************************************************
 *                vamosworld.cc
 *
 *  Sat Mar 26 14:06:16 2005
 *  Copyright  2005  Joe Venzon
 *  joe@venzon.net
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library 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.
 */


#include "vamosworld.h"

extern void LoadingScreen(string loadtext);

extern void snap_screenshot();

VAMOSWORLD::VAMOSWORLD()
 : world(0), steerpos(0), cammode(CMChaseRigid), joyinfo(false), oldseg(0),initdone(false), shift_time(0)
{
      error_log.open("logs/vamosworld.log");
}

void VAMOSWORLD::DeInit()
{
      if (initdone)
      {
            delete world;
            initdone = false;
            track_p->ClearRoads();
            UnloadHUD();
      }
}

void VAMOSWORLD::Init (TRACK * track)
{     
      UpdateSettings();

      lastcamchange = 0.0f;

      world = new Vamos_World::World (track);

      UnloadHUD();
      LoadHUD();

      track_p = track;

      ifstream cf;
      int modenum = 0;
      settings.Get( "game.camera_mode", modenum );
      switch (modenum)
      {
            case 0:
                  SetCameraMode(CMChaseRigid);
                  break;
            case 1:
                  SetCameraMode(CMChase);
                  break;
            case 2:
                  SetCameraMode(CMOrbit);
                  break;
            case 3:
                  SetCameraMode(CMHood);
                  break;
            case 4:
                  SetCameraMode(CMFree);
                  break;
            case 5:
                  SetCameraMode(CMInCar);
                  break;
            case 6:
                  SetCameraMode(CMExternal);
                  break;
            case 7:
                  SetCameraMode(CMExtFollow);
                  break;
      }

      VERTEX initcam = track_p->GetStart().ScaleR(-1);
      initcam.y -= 6;
      cam.position = initcam;

      initdone = true;
}

extern bool verbose_output;
VAMOSWORLD::~VAMOSWORLD()
{
      if (verbose_output)
            cout << "vamosworld deinit" << endl;

      error_log.close();

      DeInit();
}

extern GLfloat LightPosition[4];

void VAMOSWORLD::DrawShadows()
{
      glPushMatrix();

      if (MP_DBGDEEP)
            cout << "car shadow start" << endl;
      draw_shadows();
      if (MP_DBGDEEP)
            cout << "car shadow done" << endl;

      glPopMatrix();
}

void VAMOSWORLD::Draw()
{
      glPushMatrix();

      QUATERNION goofyfoot;
      goofyfoot.Rotate(-3.141593/2.0, 1,0,0);
      double tempmat[16];
      goofyfoot.GetMat(tempmat);
      glMultMatrixd(tempmat);

      float lp[4];
      lp[0] = LightPosition[0];
      lp[1] = LightPosition[1];
      lp[2] = LightPosition[2];
      lp[3] = 0;
      VERTEX lpv;
      lpv.Set(lp);
      lpv = goofyfoot.ReturnConjugate().RotateVec(lpv);
      lp[0] = lpv.x;
      lp[1] = lpv.y;
      lp[2] = lpv.z;
      glLightfv( GL_LIGHT1, GL_POSITION,  lp);

      glPushMatrix();
      glEnable(GL_STENCIL_TEST);
      glMatrixMode (GL_MODELVIEW);
      glPopMatrix();

      glPopMatrix();

      lp[0] = LightPosition[0];
      lp[1] = LightPosition[1];
      lp[2] = LightPosition[2];
      lp[3] = 0;
}

void VAMOSWORLD::draw_cars(bool draw_interior, bool draw_focused_car)
{
      glMatrixMode (GL_MODELVIEW);

      for (std::vector <Vamos_World::Car_Information>::iterator it = world->m_cars.begin ();
         it != world->m_cars.end ();
         it++)
      {
            assert (it->car != 0);

            glPushAttrib(GL_ALL_ATTRIB_BITS);
            glEnable(GL_DEPTH_TEST);
            glDepthMask(1);
            glDisable(GL_CULL_FACE);
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

            it->car->SetReflectionTexture(&sphere_reflection);

            utility.SelectTU(0);
                  glPushMatrix();

                  it->car->draw (true);
                  if (draw_interior)
                  {
                        it->car->draw_interior ();
                  }
                  glPopMatrix();

            utility.SelectTU(0);
            glPopAttrib();
      }
}

void VAMOSWORLD::draw_shadows()
{
      glPushAttrib(GL_ALL_ATTRIB_BITS);
      glMatrixMode (GL_MODELVIEW);

      glDisable(GL_DEPTH_TEST);
      glDepthMask(0);
      glCullFace(GL_FRONT);
      glEnable(GL_CULL_FACE);

      int count = 0;

      std::vector <Vamos_World::Car_Information>::iterator it;
      //draw shadows, make tire sounds, create smoke
      for( it = world->m_cars.begin (); it != world->m_cars.end (); it++ )
      {
            if (MP_DBGDEEP)
                  cout << "wheel pos start" << endl;

            assert (it->car != 0);

            if (it->car->chassis().IsValid())
            {           
                  glPushMatrix();
                  VERTEX pos;
                  Vamos_Geometry::Three_Vector cp = it->car->chassis().position() + it->car->chassis().center_of_mass();
                  pos.Set(cp[0], cp[1], cp[2]);

                  VERTEX posyup;
                  posyup.Set(cp[0], cp[2], -cp[1]);

                  float x1, x2, y1, y2;
                  x1 = 3;
                  x2 = -3;
                  y1 = 3;
                  y2 = -3;

                  VERTEX wheelpos[4];

                  int i = 0;

                  double slide[4];
                  double wheelspeed[4];
                  double carspeed = GetCar(CONT_PLAYERLOCAL)->car->chassis().cm_velocity().magnitude();
                  for (i = 0; i < 4; i++)
                  {
                        Vamos_Geometry::Three_Vector tv = it->car->wheel(i)->contact_position();
                        wheelpos[i].Set(tv[0],tv[1],tv[2]);
                        slide[i] = it->car->wheel(i)->slide();
                        wheelspeed[i] = it->car->wheel(i)->rotational_speed();
                  }

                  VERTEX coord[4];
                  coord[0].Set(x1,y1,0);
                  coord[1].Set(x1,y2,0);
                  coord[2].Set(x2,y2,0);
                  coord[3].Set(x2,y1,0);

                  VERTEX shadowpos[4];

                  for (i = 0; i < 4; i++)
                        shadowpos[i] = coord[i];

                  if (MP_DBGDEEP)
                        cout << "wheel pos done" << endl;

                  size_t segidx;
                  QUATERNION rot;
                  double angle;
                  Vamos_Geometry::Three_Vector aa = it->car->chassis().axis_angle(&angle);
                  rot.SetAxisAngle(angle*(3.141593/180.0),aa[0],aa[1],aa[2]);

                  QUATERNION carorientation;
                  carorientation.SetAxisAngle(angle*(3.141593/180), -aa[0], -aa[2], aa[1]);
                  carorientation.Rotate(3.141593/2.0,0,1,0);

                  for (i = 0; i < 4; i++)
                  {
                        segidx = 0;
                        coord[i] = rot.RotateVec(coord[i]);
                  }

                  Vamos_Geometry::Three_Vector cm = it->car->chassis().center_of_mass();
                  VERTEX cmv;

                  if (MP_DBGDEEP)
                        cout << "coord adjust start" << endl;

                  cmv.Set(cm[0],cm[1],cm[2]);
                  for (i = 0; i < 4; i++)
                  {
                        coord[i].x = coord[i].x - rot.RotateVec(cmv).x;
                        coord[i].y = coord[i].y - rot.RotateVec(cmv).y;

                        VERTEX origin;
                        origin = coord[i]+pos;
                        origin.z = -origin.y;
                        origin.y = 0;
                        coord[i].z = world->p_track->Elevation(origin);
                        VERTEX c;
                        c.Set(coord[i].x+pos.x, coord[i].y+pos.y, coord[i].z);
                  }

                  VERTEX tirecoord[4], tc2[4];
                  for (i = 0; i < 4; i++)
                  {
                        tirecoord[i] = rot.RotateVec(wheelpos[i]);
                        shadowpos[i] = rot.RotateVec(shadowpos[i]);
                        tirecoord[i] = tirecoord[i] - rot.RotateVec(cmv);
                        tirecoord[i] = pos + tirecoord[i];
                        shadowpos[i] = pos + shadowpos[i];

                        float temp = tirecoord[i].z;
                        tirecoord[i].z = -tirecoord[i].y;
                        tirecoord[i].y = temp;
                        tc2[i] = tirecoord[i];

                        temp = shadowpos[i].z;
                        shadowpos[i].z = -shadowpos[i].y;
                        shadowpos[i].y = temp;
                  }

                  VERTEX tctemp = tc2[2];
                  tc2[2] = tc2[3];
                  tc2[3] = tctemp;

                  if (MP_DBGDEEP)
                        cout << "coord adjust stop" << endl;

                  if (count == 0 || multiplay.TickCar(count))
                  {

                        for (i = 0; i < 4; i++)
                        {
                              float slidemultiple = 1.0; //for venzon tire code

                              float speed_offset = -5.0;
                              float speed_gain = 0.25;
                              float attenuate = (wheelspeed[i] + speed_offset)*speed_gain;
                              if (attenuate < 0)
                                    attenuate = 0;
                              if (attenuate > 1)
                                    attenuate = 1;

                              float carfactor = (carspeed-10)*0.25;
                              if (carfactor < 0)
                                    carfactor = 0;
                              if (carfactor > 1)
                                    carfactor = 1;
                              carfactor = 1.0 - carfactor;

                              slidemultiple *= (attenuate*carfactor+1.0-carfactor);

                              float prob = 0;
                              float probmultiple = 100;
                              float maxprob = 0.1;
                              if (slide[i] > 0)
                              {
                                    float squeal = slide[i]*slidemultiple;
                                    if (squeal < 0)
                                          squeal = -squeal;
                                    float offset = 0.2;
                                    float gain = 1.0;
                                    squeal -= offset;
                                    squeal *= gain;
                                    if (squeal < 0)
                                          squeal = 0;
                                    if (squeal > 1)
                                          squeal = 1;
                                    prob = (l_timefactor / l_fps) * probmultiple;
                                    prob = prob * squeal;
                                    if (prob < 0) //not sure this is necessary
                                          prob = -prob;
                                    VERTEX dir;
                                    dir.y = 1;
                                    particle.SetParams(1.0*slide[i], 2.0*slide[i], 5.0, 14.0,
                                          0.3, 1.0, dir, 0.5, 1.0);
                                    if (prob > maxprob)
                                          prob = maxprob;
                                    particle.ProbAddParticle(tirecoord[i], prob);
                              }

                              float squeal = slide[i]*slidemultiple;
                              if (squeal < 0)   //not sure this is necessary
                                    squeal = -squeal;
                              float offset = 0.05;
                              float gain = 0.5;
                              squeal -= offset;
                              squeal *= gain;
                              if (squeal < 0)
                                    squeal = 0;
                              if (squeal > 1)
                                    squeal = 1;

                              bool snddebug = false;
                              float maxgain = 0.3;
                              gain = squeal;
                              if (gain > maxgain)
                                    gain = maxgain;
                              if (l_timefactor != 0.0f)
                                    if (!snddebug) sound.SetGain(it->car->GetTireSoundSource(i), gain);
                              float pitch = 1.0-squeal;
                              float pitchvariation = 0.4;
                              pitch *= pitchvariation;
                              pitch = pitch + (1.0-pitchvariation);
                              if (!snddebug) sound.SetPitch(it->car->GetTireSoundSource(i), pitch);

                              VERTEX tvel;
                              if (!tirecoord[i].nan() && !tvel.nan())
                                    if (!snddebug) sound.SetPosVel(it->car->GetTireSoundSource(i), tirecoord[i], tvel);

                              oldtirepos[i] = tirecoord[i];
                        }
                  }

                  if (car_shadows_enabled)
                  {
                        AABB shadowbox;
                        VERTEX minbox, maxbox;
                        bool hasmin[3];
                        bool hasmax[3];

                        VERTEX shadowquad[4];
                        for (i = 0; i < 4; i++)
                        {
                              shadowquad[i] = shadowpos[i];
                        }

                        for (i = 0; i < 3; i++) hasmin[i] = false;
                        for (i = 0; i < 3; i++) hasmax[i] = false;

                        for (i = 0; i < 4; i++)
                        {
                              if (shadowquad[i].x < minbox.x || !hasmin[0])
                              {
                                    minbox.x = shadowquad[i].x;
                                    hasmin[0] = true;
                              }
                              if (shadowquad[i].y < minbox.y || !hasmin[1])
                              {
                                    minbox.y = shadowquad[i].y;
                                    hasmin[1] = true;
                              }
                              if (-shadowquad[i].z < minbox.z || !hasmin[2])
                              {
                                    minbox.z = -shadowquad[i].z;
                                    hasmin[2] = true;
                              }

                              if (shadowquad[i].x > maxbox.x || !hasmax[0])
                              {
                                    maxbox.x = shadowquad[i].x;
                                    hasmax[0] = true;
                              }
                              if (shadowquad[i].y > maxbox.y || !hasmax[1])
                              {
                                    maxbox.y = shadowquad[i].y;
                                    hasmax[1] = true;
                              }
                              if (-shadowquad[i].z > maxbox.z || !hasmax[2])
                              {
                                    maxbox.z = -shadowquad[i].z;
                                    hasmax[2] = true;
                              }
                        }
                        maxbox.y += 5;
                        minbox.y -= 5;
                        shadowbox.SetFromCorners(minbox,maxbox);
                        list <OBJECTTRI> trilist;
                        objects.GetTrisInBBox(shadowbox, trilist);

                        utility.SelectTU(0);
                        glEnable(GL_TEXTURE_2D);
                        glEnable(GL_BLEND);
                        glDisable(GL_LIGHTING);
                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                        it->car->shadow_texture()->Activate();

                        glEnable(GL_DEPTH_TEST);
                        glDepthFunc( GL_LEQUAL );
                        glColor4f(1,1,1,1);
                        glDisable(GL_CULL_FACE);
                        glCullFace(GL_FRONT);

                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

                        VERTEX shadowdim;
                        shadowdim.x = 6;
                        shadowdim.z = 6;

                        float roadheight = world->p_track->Elevation(posyup);

                        glBegin(GL_TRIANGLES);
                              for (list <OBJECTTRI>::iterator i = trilist.begin(); i != trilist.end(); i++)
                              {
                                    i->v1.z = -i->v1.z;
                                    i->v2.z = -i->v2.z;
                                    i->v3.z = -i->v3.z;

                                    ShadowTexCoord(posyup, carorientation, shadowdim, i->v1, roadheight);
                                    glVertex3fv(i->v1.v3());
                                    ShadowTexCoord(posyup, carorientation, shadowdim, i->v2, roadheight);
                                    glVertex3fv(i->v2.v3());
                                    ShadowTexCoord(posyup, carorientation, shadowdim, i->v3, roadheight);
                                    glVertex3fv(i->v3.v3());
                              }
                        glEnd();
                  }

                  glDisable(GL_CULL_FACE);
                  glDisable(GL_BLEND);
                  glEnable(GL_LIGHTING);
                  glEnable(GL_TEXTURE_2D);
                  glPopMatrix();
            }
      }

      glEnable(GL_DEPTH_TEST);
      glDepthMask(1);
      glDisable(GL_CULL_FACE);

      utility.SelectTU(0);

      utility.SelectTU(1);
      glDisable(GL_TEXTURE_GEN_S);
      glDisable(GL_TEXTURE_GEN_T);
      glDisable(GL_TEXTURE_2D);
      utility.SelectTU(0);
      glDepthMask(1);

      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

      glPopAttrib();
}

void VAMOSWORLD::ShadowTexCoord(VERTEX &carpos, QUATERNION &carorientation, VERTEX & shadowdim, VERTEX &vert, float roadheight)
{
      VERTEX vertdiff;
      vertdiff = vert-carpos;
      vertdiff = carorientation.RotateVec(vertdiff);

      float trans = 1.0;
      float transmin = -3;
      float transbotline = -2.0;
      float transtopline = 1.5;
      float transmax = 2;
      float vertheight = vert.y - roadheight;
      if (vertheight < transmin || vertheight > transmax)
            trans = 1.0;
      else if (vertheight > transbotline && vertheight < transtopline)
            trans = 0.0;
      else if (vertheight < transbotline)
            trans = 1.0-((vertheight - transmin)*(1/(transbotline - transmin)));
      else if (vertheight > transtopline)
            trans = 1.0-((transmax - vertheight)*(1/(transmax - transtopline)));

      float opacity = 1.0f-(trans);

      glColor4f(1,1,1,opacity);

      vertdiff.x *= (1.0/shadowdim.x);
      vertdiff.z *= (1.0/shadowdim.z);

      vertdiff.x += 0.5;
      vertdiff.z += 0.5;

      float u = vertdiff.x;
      float v = vertdiff.z;

      glTexCoord2d(u,v);
}

void VAMOSWORLD::Update(float timefactor, float fps, SDL_Joystick ** js)
{     
      l_timefactor = timefactor;
      l_fps = fps;

      if (l_timefactor <= 0 || fps < 5)
      {
            sound.MuteAll();
            return;
      }

      for (std::vector <Vamos_World::Car_Information>::iterator it = world->m_cars.begin ();
      it != world->m_cars.end ();
      it++)
      {
            bool advance = false;
            int nextsector = 0;
            if (track_p->NumSectors() > 0)
            {
                  nextsector = (it->car->GetSector() + 1) % track_p->NumSectors();
                  for (int p = 0; p < 4; p++)
                  {
                        if (it->car->GetColPatch(p) == track_p->GetLapSequence(nextsector))
                        {
                              advance = true;
                        }
                  }
            }

            if (advance)
            {
                  if (nextsector == 0)
                  {
                        timer.Lap((it->car->GetSector() >= 0));
                  }

                  it->car->SetSector(nextsector);
            }
      }

      bool camswitch = false;

      ProcessControls(js, timefactor, fps);

      const int repeat = 1;
      double dt = (timefactor/fps)/(float)repeat;
      for (int loop = 0; loop < repeat; loop++)
      {
            PhysUpdate(dt);
      }
      dt = (timefactor/fps);

      if (GetCar(CONT_PLAYERLOCAL) != 0)
      {

            Vamos_Geometry::Three_Vector cm = GetCar(CONT_PLAYERLOCAL)->car->chassis().position();
            if (cammode != CMFree && cammode != CMChase && cammode != CMExternal && cammode != CMExtFollow)
            {
                  cam.position.Set(-cm[0], -cm[2], cm[1]);
            }

            double angle;
            Vamos_Geometry::Three_Vector axis = GetCar(CONT_PLAYERLOCAL)->car->chassis().axis_angle (&angle);
            Vamos_Geometry::Three_Vector vvel = GetCar(CONT_PLAYERLOCAL)->car->chassis().cm_velocity();
            VERTEX vel;
            vel.Set(vvel[0],vvel[1],vvel[2]);

            if (cammode == CMChase || cammode == CMChaseRigid || cammode == CMHood || cammode == CMInCar)
            {
                  QUATERNION carorientation;
                  carorientation.SetAxisAngle(angle*(3.141593/180), -axis[0], -axis[2], axis[1]);
                  carorientation.Rotate(3.141593/2.0,0,1,0);                  
                  if (cammode == CMChase)
                  {
                        VERTEX idealpos;
                        idealpos.Set(-cm[0], -cm[2], cm[1]);
                        VERTEX temp;
                        temp.Set(0,-2,0);
                        idealpos = idealpos + carorientation.RelativeMove(temp);
                        temp.Set(0,0,-7.5);
                        idealpos = idealpos + carorientation.RelativeMove(temp);

                        float dirblend = 1.0;
                        float posblend = 10.0*(timefactor/fps);
                        if (dirblend < 0)
                              dirblend = 0;
                        else if (dirblend > 1)
                              dirblend = 1;
                        if (posblend < 0)
                              posblend = 0;
                        else if (posblend > 1)
                              posblend = 1;
                        cam.position = cam.position.interpolatewith(idealpos, posblend);
                        cam.dir.LookAt(-cam.position.x, -cam.position.y, -cam.position.z, cm[0], cm[2]+2, -cm[1], 0,1,0);
                        cam.dir = cam.dir.ReturnConjugate();

                  }
                  else if (cammode == CMHood)
                  {
                        cam.dir = carorientation;

                        Vamos_Geometry::Three_Vector vp = GetCar(CONT_PLAYERLOCAL)->car->view_position();
                        vp = vp - GetCar(CONT_PLAYERLOCAL)->car->chassis().center_of_mass();

                        cam.dir = carorientation;
                        cam.MoveRelative(0.0, -vp[2], vp[1]+1.0);
                  }
                  else if (cammode == CMInCar)
                  {
                        Vamos_Geometry::Three_Vector vp = GetCar(CONT_PLAYERLOCAL)->car->view_position();
                        vp = vp - GetCar(CONT_PLAYERLOCAL)->car->chassis().center_of_mass();
                        cam.dir = carorientation;

                        VERTEX idealpos, viewpos;
                        viewpos.Set(-vp[0], -vp[2], vp[1]);
                        idealpos.Set(-cm[0], -cm[2], cm[1]);
                        idealpos = idealpos + carorientation.RelativeMove(viewpos);

                        if (camneedupdate)
                        {
                              cam.position = idealpos;
                              cam_lastpos = cam.position;
                              cam_lastpos2 = cam.position;
                              camneedupdate = false;
                              cam_lastvel.zero();
                              cam_lastaccel.zero();
                              cam_jerk.zero();
                        }

                        VERTEX accel;
                        VERTEX vel;
                        vel = cam.position - cam_lastpos2;
                        vel.Scale(1.0/dt);
                        accel = cam_lastvel - vel;
                        cam_lastvel = vel;
                        assert (timefactor != 0);
                        accel.Scale(1.0/dt);
                        accel = cam_lastaccel + (accel-cam_lastaccel).ScaleR(0.002);
                        cam_lastpos2 = cam.position;

                        VERTEX jerk;
                        jerk = accel - cam_lastaccel;
                        jerk.Scale(1.0/dt);
                        cam_jerk = cam_jerk + (jerk-cam_jerk).ScaleR(0.002);
                        cam_lastaccel = accel;

                        jerk = accel;
                        jerk = cam_jerk;

                        float jerkscale = 0.015;
                        float jerkmax = 0.1;

                        jerk.Scale(jerkscale);
                        if (jerk.x >= 0)
                        {
                              if (jerk.x > jerkmax)
                                    jerk.x = jerkmax;
                        }
                        else
                        {
                              if (jerk.x < -jerkmax)
                                    jerk.x = -jerkmax;
                        }
                        if (jerk.y >= 0)
                        {
                              if (jerk.y > jerkmax)
                                    jerk.y = jerkmax;
                        }
                        else
                        {
                              if (jerk.y < -jerkmax)
                                    jerk.y = -jerkmax;
                        }
                        if (jerk.z >= 0)
                        {
                              if (jerk.z > jerkmax)
                                    jerk.z = jerkmax;
                        }
                        else
                        {
                              if (jerk.z < -jerkmax)
                                    jerk.z = -jerkmax;
                        }

                        idealpos = idealpos + jerk;

                        cam.position.Set(idealpos.x, idealpos.y, idealpos.z);

                  }
                  else //CMChaseRigid
                  {
                        cam.dir = carorientation;
                        cam.MoveRelative(0,-2.0,0);
                        cam.MoveRelative(0,0,-7.75);
                  }
            }
            else if (cammode == CMOrbit)
            {
                  float mindist = 7;
                  float maxdist = 20;

                  cam.MoveRelative(0,-1.0,0);
                  cam.MoveRelative(0,0,-(mindist*(mouse.GetZoom())+maxdist*(1.0f-mouse.GetZoom())));

                  VERTEX cpos = cam.position.ScaleR(-1.0);
                  float elev = track_p->Elevation(cpos)+0.5;
                  if (cpos.y < elev)
                        cam.position.y = -elev;

                  cam.dir = mouse.GetDir();
            }
            else if (cammode == CMFree)
            {
                  cam.dir = mouse.GetDir();
            }

            if (cammode != CMFree && cammode != CMOrbit)
            {
                  mouse.InitDir(cam.dir);
            }

      }

      int count = 0;

      std::vector <Vamos_World::Car_Information>::iterator it;
      for( it = world->m_cars.begin (); it != world->m_cars.end (); it++ )
      {
            Vamos_Geometry::Three_Vector cm = it->car->chassis().position();

            int sid = it->car->GetSoundSource();
            float rpm = Vamos_Geometry::rad_s_to_rpm (it->car->engine ()->rotational_speed ());
            sound.SetPitch(sid, rpm / 7000.0f);
            count++;
            float egain = it->car->engine()->throttle();
            egain = egain*0.5+0.5;
            if (rpm < 500.0)
            {
                  egain *= (rpm / 7000.0f);
            }
            sound.SetGain(sid, egain);
            VERTEX carpos;
            carpos.x = cm[0];
            carpos.y = cm[2];
            carpos.z = -cm[1];
            VERTEX campos = cam.position;
            campos.Scale(-1);
            QUATERNION q = cam.dir;
            VERTEX at, up;
            up.y = 1.0;
            at.z = -1;

            VERTEX camvel = cam.position - cam_lastpos;
            camvel.Scale(1.0/dt);
            if (camswitch)
                  camvel.zero();
            sound.SetListener(campos, camvel, q.ReturnConjugate().RotateVec(at), q.ReturnConjugate().RotateVec(up));

            VERTEX carvel;
            carvel.x = carpos.x - it->car->car_lastpos[0];
            carvel.y = carpos.y - it->car->car_lastpos[1];
            carvel.z = carpos.z - it->car->car_lastpos[2];
            carvel.Scale(1.0/dt);
            if (!carpos.nan() && !carvel.nan())
                  sound.SetPosVel(sid, carpos, carvel);

            cam_lastpos = cam.position;
            it->car->car_lastpos[0] = cm[0];
            it->car->car_lastpos[1] = cm[2];
            it->car->car_lastpos[2] = -cm[1];
      }

      GetCar(CONT_PLAYERLOCAL)->car->GetState(replay.curstate.chassispos, 
            replay.curstate.chassisorientation,
            replay.curstate.chassisvel,
            replay.curstate.chassisangvel,
            replay.curstate.suspdisp,
            replay.curstate.suspcompvel,
            replay.curstate.whlangvel,
            replay.curstate.gear,
            replay.curstate.enginespeed,
            replay.curstate.clutchspeed,
            replay.curstate.enginedrag,
            replay.curstate.tirespeed
            );

      replay.curstate.segment = GetCar(CONT_PLAYERLOCAL)->segment_index;
      replay.curstate.time = replay.GetTime();
      multiplay.GetCurState(0)->CopyFrom(replay.curstate);
      multiplay.GetCurState(0)->time = multiplay.GetTime(0);
      replay.IncrementFrame();
      multiplay.Update(timefactor/fps);
      if (replay.Playing() != -1)
      {
            CARSTATE * cst = replay.LoadState();
            if (cst != NULL)
            {
                  Vamos_World::Car_Information * rcar = NULL;
                  if (replay.GhostCar())
                        rcar = GetCar(CONT_REPLAY);
                  else
                        rcar = GetCar(CONT_PLAYERLOCAL);
                  rcar->segment_index = cst->segment;
                  rcar->car->SetState(cst->chassispos, 
                        cst->chassisorientation,
                        cst->chassisvel,
                        cst->chassisangvel,
                        cst->suspdisp,
                        cst->suspcompvel,
                        cst->whlangvel,
                        cst->gear,
                        cst->enginespeed,
                        cst->clutchspeed,
                        cst->enginedrag,
                        cst->tirespeed
                        );
            }
      }

      if (multiplay.NumConnected() > 0)
      {
            int p;
            for (p = 0; p < multiplay.NumConnected(); p++)
            {
                  if (multiplay.StateToLoad(p+1))
                  {
                        CARSTATE * cst = multiplay.GetLoadState(p+1);
                        if (cst != NULL)
                        {
                              GetCar(CONT_PLAYERREMOTE)->segment_index = cst->segment;
                              GetCar(CONT_PLAYERREMOTE)->car->SetState(cst->chassispos,
                              cst->chassisorientation,
                              cst->chassisvel,
                              cst->chassisangvel,
                              cst->suspdisp,
                              cst->suspcompvel,
                              cst->whlangvel,
                              cst->gear,
                              cst->enginespeed,
                              cst->clutchspeed,
                              cst->enginedrag,
                              cst->tirespeed
                              );
                        }

                        multiplay.ClearStateToLoad(p+1);
                  }
            }
      }

      world->m_contact_info.clear ();
}

extern void MainPause();
extern void MainUnpause();

double dabs(double val)
{
      if (val < 0)
            return -val;
      else
            return val;
}

void VAMOSWORLD::ProcessControls(SDL_Joystick ** js, float timefactor, float fps)
{
      string dofunction = "";
      double dovalue = 0.0;
      double dotime = 0.0;
      bool held = false;

      if (GetCar(CONT_PLAYERLOCAL) != 0)
      {

            int i;

            joyinfo_js = js[0];
            joyinfo_jsarray = js;

            if (replay.Playing() != -1)
            {
                  for (i = 0; i < replay.GetNumFuncs(); i++)
                  {
                        FUNCTION_MEMORY curfunc = replay.GetFunc(i);
                        if (curfunc.active)
                        {
                              if (replay.GhostCar())
                                    DoOp(GetCar(CONT_REPLAY), curfunc.func_name, curfunc.newval, 0.0, false, timefactor, fps); 
                              else
                                    DoOp(GetCar(CONT_PLAYERLOCAL), curfunc.func_name, curfunc.newval, 0.0, false, timefactor, fps); 
                        }
                  }
            }

            if (MP_DBGDEEP)
                  cout << "multiplay tick start" << endl;
            if (multiplay.NumConnected() > 0)
            {
                  if (multiplay.TickCar(1) && !multiplay.NOOPTick(1))
                  {
                        for (i = 0; i < multiplay.NumFuncs(1); i++)
                        {
                              FUNCTION_MEMORY curfunc = multiplay.GetFuncMem(1)[i];
                              dofunction = curfunc.func_name;
                              if (curfunc.active && !(dofunction.find("view_") == 0 || dofunction == "screen_shot" || dofunction == "track_shot" || dofunction == "pause" || dofunction == "reset"))
                              {
                                    DoOp(GetCar(CONT_PLAYERREMOTE), curfunc.func_name, curfunc.newval, 0.0, false, timefactor, fps); 
                              }
                              dofunction = "";
                        }
                  }
            }
            if (MP_DBGDEEP)
                  cout << "multiplay tick done" << endl;

            for (gamecontrols.ControlIteratorReset(); gamecontrols.ControlIteratorGetControl() != NULL; gamecontrols.ControlIteratorIncrement())
            {
                  CONTROL & curctrl = *(gamecontrols.ControlIteratorGetControl());
                  dofunction = "";
                  dovalue = 0.0;
                  dotime = 0.0;
                  held = false;

                  //joystick input
                  if (curctrl.GetType() == Joy)
                  {
                        SDL_Joystick * joytouse;

                        int joynum = curctrl.GetJoyNum();

                        if (joynum >= 0 && joynum < SDL_NumJoysticks())
                        {
                              joytouse = js[joynum];

                              if (curctrl.GetJoyType() == Button)
                              {
                                    if (curctrl.GetOneTime())
                                    {
                                          if (curctrl.GetJoyPushDown())
                                          {
                                                if (!curctrl.GetJoyButtonLastState() && SDL_JoystickGetButton(joytouse, curctrl.GetJoyButton()))
                                                {
                                                      dofunction = curctrl.GetName();
                                                      dovalue = 1.0;
                                                }
                                          }
                                          else if (!curctrl.GetJoyPushDown())
                                          {
                                                if (!curctrl.GetJoyButtonLastState() && SDL_JoystickGetButton(joytouse, curctrl.GetJoyButton()))
                                                {
                                                      dofunction = curctrl.GetName();
                                                      dovalue = 0.0;
                                                }
                                          }
                                    }
                                    else
                                    {
                                          if (SDL_JoystickGetButton(joytouse, curctrl.GetJoyButton()))
                                          {
                                                dofunction = curctrl.GetName();
                                                if (curctrl.GetJoyPushDown())
                                                      dovalue = 1.0;
                                                else
                                                      dovalue = 0.0;
                                          }
                                          else
                                          {
                                                dofunction = curctrl.GetName();
                                                if (curctrl.GetJoyPushDown())
                                                      dovalue = 0.0;
                                                else
                                                      dovalue = 1.0;
                                          }

                                          held = true;
                                    }

                                    curctrl.SetJoyButtonLastState(SDL_JoystickGetButton(joytouse, curctrl.GetJoyButton()));
                              }
                              else if (curctrl.GetJoyType() == Axis)
                              {
                                    double val = SDL_JoystickGetAxis(joytouse, curctrl.GetJoyAxis());
                                    val = val / 32768.0;

                                    //apply calibration
                                    float max = gamecontrols.GetCalibration(curctrl.GetJoyNum(),curctrl.GetJoyAxis(),true);
                                    float min = gamecontrols.GetCalibration(curctrl.GetJoyNum(),curctrl.GetJoyAxis(),false);
                                    float range = max - min;
                                    float gain = 2.0 / range;
                                    float offset = 1.0 - max * gain;
                                    val = val * gain + offset;

                                    //clip
                                    if (val < -1)
                                          val = -1;
                                    if (val > 1)
                                          val = 1;

                                    //apply deadzone
                                    double deadzone = 0.0;
                                    if (gamecontrols.GetDeadzone() == "low")
                                          deadzone = 0.05;
                                    else if (gamecontrols.GetDeadzone() == "med")
                                          deadzone = 0.1;
                                    else if (gamecontrols.GetDeadzone() == "high")
                                          deadzone = 0.2;
                                    if (dabs(val) < deadzone)
                                          val = 0;
                                    else
                                    {
                                          if (val < 0)
                                                val = (val + deadzone)*(1.0/(1.0-deadzone));
                                          else
                                                val = (val - deadzone)*(1.0/(1.0-deadzone));
                                    }

                                    bool crossedover = false;
                                    switch (curctrl.GetJoyAxisType())
                                    {
                                          case Positive:
                                                if (val < 0)
                                                {
                                                      crossedover = true;
                                                      val = 0;
                                                }
                                                break;
                                          case Negative:
                                                if (val > 0)
                                                {
                                                      val = 0;
                                                      crossedover = true;
                                                }
                                                val = -val;
                                                break;
                                          case Both:
                                                val = (val + 1.0)/2.0;
                                                break;
                                    }

                                    dovalue = val;
                                    held = true;

                                    dofunction = curctrl.GetName();

                              }
                        }
                        else
                        {
                              //joystick out of range
                        }
                  }

                  //keyboard input
                  else if (curctrl.GetType() == Key)
                  {
                        //one time
                        if (curctrl.GetOneTime())
                        {
                              if (curctrl.GetKeyPushDown())
                              {
                                    if (keyman.keys[curctrl.GetKeyCode()] && !keyman.lastkeys[curctrl.GetKeyCode()])
                                    {
                                          dofunction = curctrl.GetName();
                                          dovalue = 1.0;
                                    }
                              }
                              else
                              {
                                    if (!keyman.keys[curctrl.GetKeyCode()] && keyman.lastkeys[curctrl.GetKeyCode()])
                                    {
                                          dofunction = curctrl.GetName();
                                          dovalue = 1.0;
                                    }
                              }
                        }
                        else //held
                        {
                              held = true;

                              if (curctrl.GetKeyPushDown())
                              {
                                    if (keyman.keys[curctrl.GetKeyCode()])
                                    {
                                          dofunction = curctrl.GetName();
                                          dovalue = 1.0;
                                    }
                                    else if (keyman.lastkeys[curctrl.GetKeyCode()])
                                    {
                                          dofunction = curctrl.GetName();
                                          dovalue = 0.0;
                                    }
                              }
                              else
                              {
                                    if (!keyman.keys[curctrl.GetKeyCode()])
                                    {
                                          dofunction = curctrl.GetName();
                                          dovalue = 1.0;
                                    }
                                    else if (!keyman.lastkeys[curctrl.GetKeyCode()])
                                    {
                                          dofunction = curctrl.GetName();
                                          dovalue = 0.0;
                                    }
                              }
                        }
                  }
                  else if( curctrl.GetType() == Mouse )
                  {
                        if( curctrl.GetMouseType() == MButton )
                        {
                              int mouse_button = curctrl.GetMouseButton();
                              if( curctrl.GetOneTime() )
                              {
                                    if( curctrl.GetMousePushDown() )
                                    {
                                          if( mouse.IsPressed( mouse_button ) && !curctrl.GetLastMouseState() )
                                          {
                                                dofunction = curctrl.GetName();
                                                dovalue = 1.0;
                                          }
                                    }
                                    else
                                    {
                                          if( !mouse.IsPressed( mouse_button ) && curctrl.GetLastMouseState() )
                                          {
                                                dofunction = curctrl.GetName();
                                                dovalue = 0.0;
                                          }
                                    }

                                    held = false;
                              }
                              else
                              {
                                    dofunction = curctrl.GetName();
                                    if( curctrl.GetMousePushDown() )
                                    {
                                          if( mouse.IsPressed( mouse_button ) )
                                                dovalue = 1.0;
                                          else
                                                dovalue = 0.0;
                                    }
                                    else
                                    {
                                          if( !mouse.IsPressed( mouse_button ) )
                                                dovalue = 1.0;
                                          else
                                                dovalue = 0.0;
                                    }

                                    held = true;
                              }

                              curctrl.SetLastMouseState( mouse.IsPressed( mouse_button ) );
                        }
                        else if( curctrl.GetMouseType() == Motion )
                        {
                              dofunction = curctrl.GetName();
                              MouseDirEnum mouse_direction = curctrl.GetMouseDirection();
                              float x, y;
                              bool a, b;
                              mouse.GetMouseControls( &x, &y, &a, &b );
                              switch( mouse_direction )
                              {
                              case Up:
                                    dovalue = y;
                                    break;
                              case Down:
                                    dovalue = -y;
                                    break;
                              case Left:
                                    dovalue = x;
                                    break;
                              case Right:
                                    dovalue = -x;
                                    break;
                              default:
                                    break;
                              }

                              held = true;
                        }
                  }

                  if (dofunction == "steer_left")
                  {
                        steer_set(dovalue, true);
                        dofunction = "";
                  }
                  if (dofunction == "steer_right")
                  {
                        steer_set(-dovalue, false);
                        dofunction = "";
                  }

                  if (((state.GetGameState() == STATE_PLAYING || dofunction == "gas") && (replay.Playing() == -1 || replay.GhostCar())) || dofunction.find("view_") == 0 || dofunction.find("replay_") == 0 || dofunction == "screen_shot" || dofunction == "track_shot" || dofunction == "pause")
                  {
                        if (!auto_clutch || dofunction != "engage")
                              DoOp(GetCar(CONT_PLAYERLOCAL), dofunction, dovalue, dotime, held, timefactor, fps);
                  }
            }

            if (state.GetGameState() == STATE_STAGING)
                  DoOp(GetCar(CONT_PLAYERLOCAL), "brake", 1.0, 0.0, true, timefactor, fps);
      }

      steer_commit();

      if (auto_clutch)
      {
            float autoclutch = 0.0;

            if (GetCar(CONT_PLAYERLOCAL)->car->engine()->rotational_speed() < AUTO_CLUTCH_THRESH)
            {
                  float rotspeed = GetCar(CONT_PLAYERLOCAL)->car->engine()->rotational_speed();
                  float stall = GetCar(CONT_PLAYERLOCAL)->car->engine()->stall_speed() + AUTO_CLUTCH_MARGIN;
                  float clutch = (rotspeed-stall) / (AUTO_CLUTCH_THRESH-stall);
                  if (clutch < 0)
                        clutch = 0;
                  clutch = 1.0f - clutch;
                  if (clutch > autoclutch)
                        autoclutch = clutch;
            }

            if (shift_time > 0)
            {
                  float clutch = shift_time / AUTO_CLUTCH_ENGAGE_TIME;
                  if (clutch > autoclutch)
                        autoclutch = clutch;

                  shift_time -= timefactor/fps;
            }

            if (!GetCar(CONT_PLAYERLOCAL)->car->ShiftPending())
            {
                  DoOp(GetCar(CONT_PLAYERLOCAL), "clutch", autoclutch, 0.0, true, timefactor, fps);
            }
      }
}

void VAMOSWORLD::DoOp(Vamos_World::Car_Information * c, string dofunction, float dovalue, float dotime, bool held, float timefactor, float fps)
{
      //do the requested operation
      if (dofunction != "")
      {
            if (dofunction == "reset")
                  world->reset(c);
            else if (dofunction == "brake")     c->car->brake (dovalue, dotime);
            else if (dofunction == "handbrake") c->car->handbrake (dovalue, dotime);
            else if (dofunction == "gas") c->car->gas (dovalue, dotime);
            else if (dofunction == "clutch") c->car->clutch (1.0f-dovalue, dotime);
            else if (dofunction == "steer_left" || dofunction == "steer_right") c->car->steer (dovalue, dotime);
            else if (dofunction == "disengage_shift_up") 
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift_up ();
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "disengage_shift_down") 
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift_down ();
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "engage")
            {
                  if (c->car->last_gear () == 0)
                        c->car->engage_clutch (1.0);
                  else
                        c->car->engage_clutch (0.2);
            }
            else if (dofunction == "neutral")
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(0);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "first_gear" && c->car->transmission ()->forward_gears () >= 1)
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(1);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "second_gear" && c->car->transmission ()->forward_gears () >= 2)
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(2);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "third_gear" && c->car->transmission ()->forward_gears () >= 3)
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(3);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "fourth_gear" && c->car->transmission ()->forward_gears () >= 4)
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(4);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "fifth_gear" && c->car->transmission ()->forward_gears () >= 5)
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(5);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "sixth_gear" && c->car->transmission ()->forward_gears () >= 6)
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(6);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "reverse" && c->car->transmission ()->reverse_gears () >= 1)
            {
                  c->car->disengage_clutch (0.2);
                  c->car->shift(-1);
                  if (c == GetCar(CONT_PLAYERLOCAL))
                  {
                        shift_time = AUTO_CLUTCH_ENGAGE_TIME;
                  }
            }
            else if (dofunction == "start_engine") c->car->start_engine ();

            else if (dofunction == "view_chaserigid") {mq1.AddMessage("Camera set to rigid chase mode");SetCameraMode(CMChaseRigid);}
            else if (dofunction == "view_chase") {mq1.AddMessage("Camera set to flexible chase mode");SetCameraMode(CMChase);}
            else if (dofunction == "view_orbit") {mq1.AddMessage("Camera set to mouse orbit mode");SetCameraMode(CMOrbit);}
            else if (dofunction == "view_hood") {mq1.AddMessage("Camera set to hood mounted mode");SetCameraMode(CMHood);}
            else if (dofunction == "view_free") {mq1.AddMessage("Camera set to free mode");SetCameraMode(CMFree);}
            else if (dofunction == "view_incar") {mq1.AddMessage("Camera set to in-car mode");SetCameraMode(CMInCar);}
            else if (dofunction == "view_external") {mq1.AddMessage("Camera set to external fixed mode");SetCameraMode(CMExternal);}
            else if (dofunction == "pan_left")
            {
            }
            else if (dofunction == "pan_right")
            {
            }
            else if (dofunction == "pan_up")
            {
            }
            else if (dofunction == "pan_down")
            {
            }
            else if (dofunction == "view_extfollow") {mq1.AddMessage("Camera set to external follow mode");SetCameraMode(CMExtFollow);}
            else if (dofunction == "joystick_info") joyinfo = !joyinfo;
            else if (dofunction == "proportionalsteer_toggle") propsteer = !propsteer;
            else if (dofunction == "track_shot") build_track_shot();
            else if (dofunction == "screen_shot") snap_screenshot();
            else if (dofunction == "replay_ff") replay.Jump(replay.GetTime()+10);
            else if (dofunction == "replay_rw") {double t = replay.GetTime()-10; if (t < 0) t = 0; replay.Jump(t);}
            else if (dofunction == "pause")
            {
                  if (timefactor != 0) 
                        MainPause();
            }
            else
            {
                  if (verbose_output)
                        cout << "No such function: " << dofunction << endl;
            }

            int state = 0;
            if (held)
                  state = 1;
            if (replay.Playing() == -1 && !(dofunction.find("view_") == 0 || dofunction == "screen_shot" || dofunction == "track_shot" || dofunction == "pause"))
            {
                  if (c->car->get_controller() == CONT_PLAYERLOCAL)
                        replay.AddRecord(dofunction, dovalue, state);
            }

            if (MP_DBGDEEP)
                  cout << "multiplay add record start" << endl;               
            if (multiplay.NumConnected() > 0 && !(dofunction.find("view_") == 0 || dofunction == "screen_shot" || dofunction == "track_shot" || dofunction == "pause" || dofunction == "reset"))
            {
                  if (c->car->get_controller() == CONT_PLAYERLOCAL)
                        multiplay.AddRecord(dofunction, dovalue, state);
            }
            if (MP_DBGDEEP)
                  cout << "multiplay add record done" << endl;
      }
}

void VAMOSWORLD::DrawHUD()
{
      char tempchar[32];

      float w = 0.25;
      float h = 0.333;
      float y = 0.65;
      float x = 0.05;
      utility.Draw2D(x, y, x+w, y+h, &tachbase);

      float maxrpm = Vamos_Geometry::rad_s_to_rpm (GetCar(CONT_PLAYERLOCAL)->car->engine ()->max_rotational_speed ());
      float tachspace = 0.55;
      float curtachrot = -7.0f*tachspace;
      float currpm = 11000;

      //draw RPM band
      while (currpm >= 0)
      {
            if (maxrpm > currpm+500)
                  utility.Draw2D(x, y, x+w, y+h, &tachband, curtachrot);
            curtachrot += tachspace;
            currpm -= 1000;
      }

      float nscale = 0.00055;

      //draw red band
      float redline = Vamos_Geometry::rad_s_to_rpm (GetCar(CONT_PLAYERLOCAL)->car->engine ()->peak_engine_speed ());
      redline -= 5000;
      utility.Draw2D(x, y, x+w, y+h, &tachredband, -redline*nscale);

      //draw text
      currpm = 11000;
      curtachrot = -7.0f*tachspace;
      while (currpm >= 0)
      {
            if (maxrpm >= currpm-500)
            {
                  float aspect = w / h;
                  QUATERNION rot;
                  rot.Rotate(curtachrot, 0,0,1);
                  VERTEX textoffset;
                  textoffset.Set(0,-0.125,0);
                  textoffset = rot.RotateVec(textoffset);
                  textoffset.x *= -aspect;
                  VERTEX tachcenter;
                  tachcenter.Set(x+w/2.0,y+h/2.0,0);
                  textoffset = textoffset + tachcenter;
                  VERTEX offset;
                  offset.Set(-0.01*aspect, -0.026, 0);
                  textoffset = textoffset + offset;
                  char tc[8];
                  sprintf(tc,"%i", (int)(currpm / 1000.0));
                  font.Print(textoffset.x, textoffset.y, tc, 1, 6, 0,0,0);
            }
            curtachrot += tachspace;
            currpm -= 1000;
      }

      utility.Draw2D(1.0-x-w, y, 1.0-x, y+h, &speedo);

      float rpm = Vamos_Geometry::rad_s_to_rpm (GetCar(CONT_PLAYERLOCAL)->car->engine ()->rotational_speed ());

      rpm *= nscale;
      utility.Draw2D(x, y, x+w, y+h, &needle, -rpm);

      float kph = Vamos_Geometry::m_s_to_km_h (GetCar(CONT_PLAYERLOCAL)->car->chassis().cm_velocity().magnitude());
      if (kph < 0)
            kph = -kph;

      float mph = kph * 0.621371192;
      utility.Draw2D(1.0-x-w, y, 1.0-x, y+h, &needle, -mph*0.034+0.0);

      char tchar[256];

      if( MPH )
      {
            sprintf(tchar, "%03.0f", mph);
            font.Print(1.0-x-w+0.097, y+0.25, tchar, 0, 7, 1,0,0);
            font.Print(1.0-x-w+0.103, y+0.29, "MPH", 0, 6, 0,0,0);
      }
      else
      {
            sprintf(tchar, "%03.0f", kph);
            font.Print(1.0-x-w+0.097, y+0.25, tchar, 0, 7, 1,0,0);
            font.Print(1.0-x-w+0.103, y+0.29, "km/h", 0, 6, 0,0,0);
      }

      int gear = GetCar(CONT_PLAYERLOCAL)->car->transmission ()->gear ();
      if (gear == 0)
            strcpy (tempchar, "N");
      else if (gear < 0)
            strcpy (tempchar, "R");
      else
            sprintf(tempchar, "%i", gear);
      font.Print(x+w/2.0-0.021,y+h-0.14, tempchar, 0, 9, 1,0,0);

      float pfuel = GetCar(CONT_PLAYERLOCAL)->car->fuel_tank()->fuelpercent();
      float feedback = (GetCar(CONT_PLAYERLOCAL)->car->wheel(0)->GetFeedback()+
            GetCar(CONT_PLAYERLOCAL)->car->wheel(1)->GetFeedback())*0.5;

      feedback = feedback/100.0;
      if (feedback > 0.5)
            feedback = 0.5;
      if (feedback < -0.5)
            feedback = -0.5;
      feedback += 0.5;

      pfuel = 0.1*pfuel;
      utility.Draw2D(0,0.87,0.1,1, &fgbox);
      w = .125;
      h = .1725;
      x = -.037;
      y = 0.905;
      utility.Draw2D(x,y,x+w,h+y, &needle, pfuel*20.0+2.42);

      float recspace = replay.Recording();
      if (recspace >= 0)
      {
            sprintf(tempchar, "Recording: %2.0f%% full", (recspace) * 100.0f);
            font.Print(0.4, 0.95, tempchar, 1, 6, 1, 0, 0, 1);
      }
      float playspace = replay.Playing();
      if (playspace >= 0)
      {
            sprintf(tempchar, "Playing: %2.0f%% complete", (playspace) * 100.0f);
            font.Print(0.4, 0.95, tempchar, 1, 6, 1, 0, 0, 1);
      }

      if (multiplay.NumConnected() > 0)
      {
            sprintf(tempchar, "Tx: %2.3fkb/s", multiplay.GetTxRate()/1000.0);
            font.Print(0.4, 0.92, tempchar, 1, 6, 1, 0, 0, 1);

            sprintf(tempchar, "Rx: %2.3fkb/s", multiplay.GetRxRate()/1000.0);
            font.Print(0.4, 0.95, tempchar, 1, 6, 1, 0, 0, 1);
      }

      //draw the input graph
      float mx = GetPlayerCar()->steer() / GetPlayerCar()->max_steer_angle();
      float my = GetPlayerCar()->gas() - GetPlayerCar()->brake();
      if( input_graph_enabled && ( replay.Playing() == -1 || replay.GhostCar() ) )
      {
            mx = -mx;
            float dx, dy;
            dx = 0.4;
            dy = 0.8;
            float dw = 0.2;
            float dh = 0.2;
            dh *= 1.33333;
            utility.Draw2D(dx, dy, dx+dw, dy+dh, &m_sliderh);
            float ballscale = 4.0;
            utility.Draw2D((dx+dw/2.0)-dw/(ballscale*2.0)+mx*dw/2.7, (dy+dh/2.0)-dh/(ballscale*2.0), (dx+dw/2.0)-dw/(ballscale*2.0)+mx*dw/2.7+dw/ballscale, (dy+dh/2.0)-dh/(ballscale*2.0)+dh/ballscale, &m_ballh);

            my = -my;
            dx = 0.3;
            dy = 0.87;
            dw = 0.1;
            dh = 0.1;
            dh *= 1.33333;
            ballscale = 1.0;
            utility.Draw2D(dx, dy, dx+dw, dy+dh, &m_sliderv);
            utility.Draw2D((dx+dw/2.0)-dw/(ballscale*2.0), (dy+dh/2.0)-dh/(ballscale*2.0)+my*dh/2.7, (dx+dw/2.0)-dw/(ballscale*2.0)+dw/ballscale, (dy+dh/2.0)-dh/(ballscale*2.0)+my*dh/2.7+dh/ballscale, &m_ballv);
      }
}

void VAMOSWORLD::reset()
{
      world->reset(true);
}

void VAMOSWORLD::DisplayJoyInfo()
{
      int joynum = 0;

      string joystring = "";
      char tchar[256];

      float xpos = 0.01;

      for (joynum = 0; joynum < SDL_NumJoysticks(); joynum++)
      {     
            if (SDL_NumJoysticks() > joynum)
            {
                  int i;
                  for (i = 0; i < SDL_JoystickNumAxes(joyinfo_jsarray[joynum]); i++)
                  {
                              sprintf(tchar, "Axis %i: %f\n", i, (float)SDL_JoystickGetAxis(joyinfo_jsarray[joynum], i)/32768.0f);
                              joystring = joystring + tchar;
                  }

                  for (i = 0; i < SDL_JoystickNumButtons(joyinfo_jsarray[joynum]); i++)
                  {
                              sprintf(tchar, "Button %i: %d\n", i, SDL_JoystickGetButton(joyinfo_jsarray[joynum], i));
                              joystring = joystring + tchar;
                  }

                  font.Print(xpos,0.11, joystring.c_str(), 1, 5, 1,1,1);
                  xpos += 0.2;
                  joystring = "";
            }
      }
}

void VAMOSWORLD::build_track_shot()
{
}

void VAMOSWORLD::steer_to(float val, float timefactor, float fps)
{
      bool inhibit = (gamecontrols.GetJoystickType() == "wheel");

      if (gamecontrols.GetCompensation() == "low")
      {
            if (val < 0)
                  val = -val*val;
            else
                  val = val*val;
      }
      else if (gamecontrols.GetCompensation() == "med")
      {
            val = val*val*val;
      }
      else if (gamecontrols.GetCompensation() == "high")
      {
            if (val < 0)
                  val = -val*val*val*val;
            else
                  val = val*val*val*val;
      }
      else if (gamecontrols.GetCompensation() == "900to200")
      {
            float decimate = 4.5;

            float carmph = Vamos_Geometry::m_s_to_km_h (GetCar(CONT_PLAYERLOCAL)->car->wheel (1)->speed ())*0.621371192;

            float normalat = 30;
            float transat = 15;

            if (carmph < transat)
                  decimate = 1.0;
            else if (carmph < normalat)
            {
                  float coeff = (carmph - transat)/(normalat - transat);
                  decimate = (decimate-1.0f)*coeff + 1.0f;
            }

            val = val/decimate;
      }
      else if (gamecontrols.GetCompensation() == "speed1" || gamecontrols.GetCompensation() == "speed2")
      {
            float carmph = Vamos_Geometry::m_s_to_km_h (GetCar(CONT_PLAYERLOCAL)->car->wheel (1)->speed ())*0.621371192;

            if (carmph < 0)
                  carmph = -carmph;

            float ratio = 20.0f;
            float coeff = 1.0;
            if (carmph > 1)
                  coeff = ratio/carmph;

            if (coeff > 1)
                  coeff = 1.0;
            if (gamecontrols.GetCompensation() == "speed2")
                  coeff = coeff * coeff;

            val = val*coeff;
      }

      float steerstep = 5.0*timefactor/fps;

      if (val > steerpos)
      {
            if (val - steerpos <= steerstep)
                  steerpos = val;
            else
                  steerpos += steerstep;
      }
      else
      {
            if (steerpos - val <= steerstep)
                  steerpos = val;
            else
                  steerpos -= steerstep;
      }

      if (inhibit)
            steerpos = val;

      if (steerpos > 1.0)
            steerpos = 1.0;
      if (steerpos < -1.0)
            steerpos = -1.0;
}

void VAMOSWORLD::steer_set(float val, bool left)
{
      if (left)
            steervals[0] = val;
      else
            steervals[1] = val;
}

void VAMOSWORLD::steer_commit()
{
      if (steervals[0] != 0)
      {
            steer_to(steervals[0], l_timefactor, l_fps);
      }
      else
      {
            steer_to(steervals[1], l_timefactor, l_fps);
      }

      steervals[0] = 0.0;
      steervals[1] = 0.0;

      if (replay.Playing() == -1 || replay.GhostCar())
            DoOp(GetCar(CONT_PLAYERLOCAL), "steer_left", steerpos, 0.0, true, l_timefactor, l_fps);
}

void VAMOSWORLD::SetCameraMode(CameraMode newmode)
{
      cammode = newmode;
      ofstream cf;

      settings.Set( "game.camera_mode", cammode );

      if (newmode == CMFree)
            keyman.freecam = true;
      else
            keyman.freecam = false;

      if (newmode == CMExternal || newmode == CMExtFollow)
      {
            lastcamchange = 0.0f;
            camneedupdate = true;
      }
      if (newmode == CMInCar)
      {
            cam_lastpos = cam.position;
            cam_lastpos2 = cam.position;
            cam_lastvel.zero();
            cam_lastaccel.zero();
            cam_jerk.zero();
            camneedupdate = true;
      }
}

void VAMOSWORLD::FuelPlayerCar()
{
      GetCar(CONT_PLAYERLOCAL)->car->fuel_tank()->fill();
}

void VAMOSWORLD::clear_cars()
{
      std::vector<Vamos_World::Car_Information>::iterator it;
      for( it = world->m_cars.begin (); it != world->m_cars.end (); it++ )
      {
            delete it->car;
      }
      world->m_cars.clear();
}

void VAMOSWORLD::PhysUpdate(float dt)
{
      int count = 0;
      std::vector<Vamos_World::Car_Information>::iterator it;

      for( it = world->m_cars.begin (); it != world->m_cars.end (); it++ )
      {
            if (count == 0 || multiplay.TickCar(count) || (count == 1 && replay.GhostCar()))
            {
                  it->car->propagate (dt);
                  world->interact (it->car, it->segment_index);
            }

            count++;
      }
}


Vamos_World::Car_Information * VAMOSWORLD::GetCar(CONTROLLERTYPE p)
{
      for (std::vector <Vamos_World::Car_Information>::iterator it = world->m_cars.begin ();
                     it != world->m_cars.end ();
                     it++)
      {
            if (it->car->get_controller() == p)
            {
                  return &(*it);
            }
      }

      cout << "Error -- no player car!  Get ready for a crash...." << endl;

      return NULL;
}

void VAMOSWORLD::DrawCars()
{
      glPushMatrix();

      QUATERNION goofyfoot;
      goofyfoot.Rotate(-3.141593/2.0, 1,0,0);
      double tempmat[16];
      goofyfoot.GetMat(tempmat);
      glMultMatrixd(tempmat);

      float lp[4];
      lp[0] = LightPosition[0];
      lp[1] = LightPosition[1];
      lp[2] = LightPosition[2];
      lp[3] = 0;
      VERTEX lpv;
      lpv.Set(lp);
      lpv = goofyfoot.ReturnConjugate().RotateVec(lpv);
      lp[0] = lpv.x;
      lp[1] = lpv.y;
      lp[2] = lpv.z;

      if (MP_DBGDEEP)
            cout << "draw cars start" << endl;
      draw_cars(false, true);
      if (MP_DBGDEEP)
            cout << "draw cars done" << endl;

      glPopMatrix();
}

void VAMOSWORLD::DrawTopLevel()
{
      glPushMatrix();

      glDisable(GL_STENCIL_TEST);
      particle.Draw();

      if (display_hud)
      {
            DrawHUD();
            timer.Draw();
      }

      if (joyinfo)
       DisplayJoyInfo();

      glPopMatrix();
}

void VAMOSWORLD::UpdateSettings()
{
      settings.Get( "display.show_hud", display_hud );
      settings.Get( "display.mph", MPH );
      settings.Get( "control.autoclutch", auto_clutch );
      settings.Get( "display.input_graph", input_graph_enabled );
      settings.Get( "display.car_shadows", car_shadows_enabled );
}

void VAMOSWORLD::LoadHUD()
{
      tachbase.Load("hud/tachometer.png", false);
      tachredband.Load("hud/redband.png", false);
      tachband.Load("hud/tachband.png", false);
      speedo.Load("hud/speedo.png", false);
      needle.Load("hud/needle.png", false);
      fgbox.Load("hud/fuelgaugebox.png", false);
      sphere_reflection.Load("weather/reflect.png", true);

      m_ballh.Load("hud/ball2.png", false);
      m_sliderh.Load("hud/slider2.png", false);

      m_ballv.Load("hud/accdec-marker.png", false);
      m_sliderv.Load("hud/accdec-slider.png", false);
}

void VAMOSWORLD::UnloadHUD()
{
      tachbase.Unload();
      tachredband.Unload();
      tachband.Unload();
      speedo.Unload();
      needle.Unload();
      fgbox.Unload();
      sphere_reflection.Unload();

      m_ballh.Unload();
      m_sliderh.Unload();

      m_ballv.Unload();
      m_sliderv.Unload();
}

Generated by  Doxygen 1.6.0   Back to index