Logo Search packages:      
Sourcecode: vdrift version File versions

main.cpp

 // vim: set noet sw=8 cino=:
#define GL_GLEXT_PROTOTYPES

#include <fenv.h>

#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
#include <SDL/SDL.h>
#include <math.h>
#include <string>
#include <vector>

using namespace std;

#include "font.h"
#include "utility.h"
#include "textures.h"
#include "backdrop.h"
#include "camera.h"
#include "weather.h"
#include "keyman.h"
#include "mouse.h"
#include "messageq.h"
#include "particles.h"
/*#include "mesh.h"                 // Header File For The MESH Class
#include "entity.h"                 // ...etc
#include "meshlist.h"
#include "entitylist.h"
#include "water.h"
#include "model.h"
#include "gamedb.h"
#include "ships.h"*/
#include "settings.h"
#include "sound.h"
/* #include "menu.h" */
#include "timer.h"
#include "controls.h"
#include "vamosworld.h"
#include "replay.h"
//#include "trees.h"
#include "logo.h"
#include "gamestate.h"
#include "objects.h"
#include "multiplay.h"
#include "net.h"
#include "configfile.h"
#include "bezier.h"
#include "track.h"
#include "textures.h"
#include "exception.h"
#include "cardinfo.h"

using namespace VDrift;

#include <vamos/body/Gl_Car.h>
#include <vamos/geometry/Texture_Image.h>
#include <vamos/geometry/Three_Vector.h>
//#include <vamos/track/Strip_Track.h>
#include <vamos/body/Car.h>
#include <vamos/body/Fuel_Tank.h>
#include <vamos/body/Wheel.h>
#include <vamos/geometry/Conversions.h>
//#include <vamos/track/Track.h>
#include <vamos/world/World.h>

#include "gui/gui.h"

#ifdef _WIN32
//#define GL_GLEXT_PROTOTYPES
#include <GL/glext.h>
//#include <GL/wglext.h>
//#include <GL/glprocs.h>
#endif

//#define PERFORMANCE_PROFILE

//fps less than below will not tick the simulation
//#define MIN_FPS 5.0

#ifdef PERFORMANCE_PROFILE
#include <sys/time.h>
suseconds_t GetMicroSeconds()
{
      struct timeval tv;
      struct timezone tz;
            
      tz.tz_minuteswest = 0;
      tz.tz_dsttime = 0;
      
      gettimeofday(&tv, &tz);
      
      return tv.tv_usec;
}
#endif


// Set up some booleans
#define TRUE  1
#define FALSE 0

// screen width, height, and bit depth
//const int SCREEN_WIDTH = 1024;
//const int SCREEN_HEIGHT = 768;
//const int SCREEN_BPP = 32;

int SCREEN_WIDTH = 1024;
int SCREEN_HEIGHT = 768;
int SCREEN_BPP = 32;

//#define PATCH_DEBUG

bool verbose_output = false;

//bool in_menu = false;
//bool menu_display = false;

/*const int SCREEN_WIDTH = 1280;
const int SCREEN_HEIGHT = 1024;
const int SCREEN_BPP = 32;*/

// This is our SDL surface
SDL_Surface *surface;

// Ambient Light Values ( NEW )
//GLfloat LightAmbient[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightAmbient[]  = { 0.15f, 0.15f, 0.15f, 1.0f };
// Diffuse Light Values ( NEW )
//GLfloat LightDiffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightDiffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightSpecular[]  = { 0.0f, 0.0f, 0.0f, 0.0f };
// Light Position ( NEW )
GLfloat LightPosition[4];

/*
ENTITYLIST entities;
MESHLIST meshes;
TERRAIN terrain;
TREES foliage;
WATER water;
GAMEDB gamedb;
SHIPS ships;*/
KEYMAN keyman;
GAMECONTROLS gamecontrols;
SETTINGS settings;
TEXTURES textures;
CAMERA cam;
FONT font;
UTILITY utility;
BACKDROP backdrop;
WEATHER weathersystem;
MOUSE mouse;
MESSAGEQ mq1;
//TERRAIN terrain;
PARTICLE particle;
SOUNDMANAGER sound;
/* MENU menu; */
TIMER timer;
REPLAY replay;
//TREES trees;
LOGO logo;
GAMESTATE state;
OBJECTS objects;
NET net;
MULTIPLAY multiplay;
VGUI::Gui gui;
TRACK track;
CARDINFO gfxcard;

VAMOSWORLD world;
//Vamos_Track::Strip_Track *road;

ofstream error_log;

#define CAR_Y_OFFSET 1.0

double day_time;
double abs_time;

//for game timing and FPS stuff
static GLint T0;
static GLint Frames;
static GLfloat fps;

bool showfps;

static int frameno;

float timefactor = 1.0f;

//#define AVERAGEFRAMES 30
#define AVERAGEFRAMES 5

float pfps;
float lfps[AVERAGEFRAMES];
int lfpspos = 0;
bool lfpsfull = false;

//#define FRAME_TIME 0.002
#define FRAME_TIME 0.004
double execution_time = 0.0;

bool pauserequest = false;
bool unpauserequest = false;
bool esc_pressed = false;

float view_dist = 10000.0;

//int screenshots = 0;
string cur_tex_size = "";
int cur_screen_w = 0;
int cur_screen_h = 0;
int cur_screen_bpp = 0;
bool cur_fullscreen = false;
string tree_detail = "";

float FrameTime()
{
      return FRAME_TIME;
}

int Screenshot(char *filename)
{
      SDL_Surface *screen;
      SDL_Surface *temp = NULL;
      unsigned char *pixels;
      int i;
      
      screen = surface;
      
      if (!(screen->flags & SDL_OPENGL))
      {
            SDL_SaveBMP(temp, filename);
            return 0;
      }
      
      temp = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, 16,
      #if SDL_BYTEORDER == SDL_LIL_ENDIAN
      0x000000FF, 0x0000FF00, 0x00FF0000, 0
      #else
      0x00FF0000, 0x0000FF00, 0x000000FF, 0
      #endif
      );
      if (temp == NULL)
            return -1;
      
      pixels = (unsigned char *) malloc(3 * screen->w * screen->h);
      if (pixels == NULL)
      {
            SDL_FreeSurface(temp);
            return -1;
      }
      
      glReadPixels(0, 0, screen->w, screen->h, GL_RGB, GL_UNSIGNED_BYTE, pixels);
      
      for (i=0; i<screen->h; i++)
            memcpy(((char *) temp->pixels) + temp->pitch * i, pixels + 3*screen->w * (screen->h-i-1), screen->w*3);
      free(pixels);
      
      SDL_SaveBMP(temp, filename);
      SDL_FreeSurface(temp);
      return 0;
}

void ResetWorld(bool fullreset);

/** Cleaup and exit.
 * @param returnCode the exit code
 *
 * This function cleans up the game state and restores the desktop environment
 * to it's previous state.
 */
void Quit(int returnCode)
{
      state.SetGameState(STATE_EXIT);

      if (replay.Recording() != -1)
            replay.Stop();

      gamecontrols.WriteControlFile();

      if (verbose_output)
            cout << "Quit called" << endl;

      error_log.close();

      /* clean up the window */
      SDL_Quit( );

      if (verbose_output)
            cout << "SDL_Quit finished" << endl;

      exit(returnCode);
}

// function to reset our viewport after a window resize
int resizeWindow( int width, int height )
{
      // Height / width ration
      GLfloat ratio;
 
      // Protect against a divide by zero
      if ( height == 0 )
            height = 1;

      ratio = ( GLfloat )width / ( GLfloat )height;

      // Setup our viewport.
      glViewport( 0, 0, ( GLint )width, ( GLint )height );

      // change to the projection matrix and set our viewing volume.
      glMatrixMode( GL_PROJECTION );
      glLoadIdentity( );

      // Set our perspective
      gluPerspective( 45.0f, ratio, 0.1f, 10000.0f );

      // Make sure we're chaning the model view and not the projection
      glMatrixMode( GL_MODELVIEW );

      // Reset The View
      glLoadIdentity( );

      return( TRUE );
}

void LoadingScreen(string loadtext);

void ChangeDisplay(int w, int h, int bpp, bool fullscreen, bool reloadtextures)
{
      SCREEN_WIDTH = w;
      SCREEN_HEIGHT = h;
      SCREEN_BPP = bpp;
      
      // the flags to pass to SDL_SetVideoMode
      int videoFlags = SDL_OPENGL;       // Enable OpenGL in SDL
      videoFlags |= SDL_GL_DOUBLEBUFFER; // Enable double buffering
      videoFlags |= SDL_HWPALETTE;       // Store the palette in hardware
      videoFlags |= SDL_RESIZABLE;       // Enable window resizing

      // This checks to see if surfaces can be stored in memory
      /*if ( videoInfo->hw_available )
            videoFlags |= SDL_HWSURFACE;
      else
            videoFlags |= SDL_SWSURFACE;

      if ( videoInfo->blit_hw )
            videoFlags |= SDL_HWACCEL;*/

      if (fullscreen)
      {
            videoFlags |= SDL_HWSURFACE|SDL_ANYFORMAT|SDL_FULLSCREEN;  
      }     
      else
      {
            videoFlags |= SDL_SWSURFACE|SDL_ANYFORMAT;
      }

      // get a SDL surface
      if (surface != NULL)
      {
            SDL_FreeSurface(surface);
            surface = NULL;
      }
      surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags );

      resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );

      if (reloadtextures)
      {
            if( gui.GetEnabled() ) gui.SetEnabled( false );
            LoadingScreen("Loading...\nReloading textures");
            //textures.DeleteAll();
            textures.ReloadAll();
            LoadingScreen("Loading...\nFont");
            font.Load();
            LoadingScreen("Loading...\nBackdrop");
            backdrop.Init();
            //menu.Load();
            LoadingScreen("Loading...\nGame Controls");
            gamecontrols.LoadControls();
            LoadingScreen("Loading...\nParticles");
            particle.Load();
            LoadingScreen("Loading...\nTimer");
            timer.Load();
            LoadingScreen("Loading...\nHUD");
            world.UnloadHUD();
            world.LoadHUD();
            LoadingScreen("Loading...\nUser interface");
            //gui.DeInit();
            gui.ReInit();
            //menu.MainMenu();
            //gui.ChangePage( "Main" );
            //gui.SetEnabled( true );
      }

      gui.UpdateScreenSize();
}

void ReloadDisplay()
{
      string tex_size;
      int w, h, bpp;
      bool fullscreen, show_fps, reload_tex;

      settings.Get( "display.width", w );
      settings.Get( "display.height", h );
      settings.Get( "display.depth", bpp );
      settings.Get( "display.fullscreen", fullscreen );
      settings.Get( "display.show_fps", show_fps );
      settings.Get( "display.texture_size", tex_size );
      settings.Get( "display.view_distance", view_dist );
      settings.Get( "display.tree_detail", tree_detail );

      reload_tex = ( tex_size == cur_tex_size ) &&
                   ( w == cur_screen_w ) &&
                   ( h == cur_screen_h ) &&
                   ( fullscreen == cur_fullscreen ) &&
                   ( bpp == cur_screen_bpp ) ? false : true;
      reload_tex = true;

      showfps = show_fps;
      world.UpdateSettings();
      objects.UpdateSettings();
      //trees.UpdateSettings();
      //terrain.UpdateSettings();
      ChangeDisplay( w, h, bpp, fullscreen, reload_tex );
      cur_tex_size = tex_size;
      cur_screen_w = w;
      cur_screen_h = h;
      cur_screen_bpp = bpp;
      cur_fullscreen = fullscreen;
}

void Update()
{
      //cam.position.DebugPrint();

      if (MP_DBGDEEP)
            cout << "main update start" << endl;

      bool mainloop = false;

      //if unpaused and getting a reasonable framerate
      //if (fps > MIN_FPS && timefactor != 0.0f)
      if (fps > 0.0f && timefactor != 0.0f && state.GetGameState() != STATE_INITIALMENU)
      {
            /*VERTEX campos = cam.position;
            campos.Scale(-1.0);
            cout << campos.x << "," << campos.z << ": " << track.Elevation(campos) << endl;*/
            
            
            execution_time += timefactor / fps;
            int num_updates = (int) (execution_time / FRAME_TIME);
            double this_frame = (double) num_updates * FRAME_TIME;

            mouse.Update(cam, SCREEN_WIDTH, SCREEN_HEIGHT, timefactor, fps);
            weathersystem.Update(abs_time);

            while (execution_time > FRAME_TIME)
            {
                  #ifdef PERFORMANCE_PROFILE
                  suseconds_t t1, t2;
                  t1 = GetMicroSeconds();
                  t1 = GetMicroSeconds();
                  #endif

                  //multiplay.Update(FRAME_TIME);
                  
                  //weather tick

                  #ifdef PERFORMANCE_PROFILE
                  t2 = GetMicroSeconds();
                  cout << "multiplay.Update() ticks: " << t2-t1 << endl;
                  t1 = GetMicroSeconds();
                  #endif

                  //timer tick
                  //timer.TickTimer(timefactor,fps);
                  timer.TickTimer(1.0, 1.0/FRAME_TIME);

                  cam.Update();

                  //handle input
                  //keyman.DoHeldKeys(timefactor, fps, cam);
                  keyman.DoHeldKeys(1.0, 1.0/FRAME_TIME, cam);

                  #ifdef PERFORMANCE_PROFILE
                  t1 = GetMicroSeconds();
                  t1 = GetMicroSeconds();
                  #endif

                  //world.Update(timefactor, fps, js);
                  world.Update(1.0, 1.0/FRAME_TIME, gamecontrols.Get_js());

                  #ifdef PERFORMANCE_PROFILE
                  t2 = GetMicroSeconds();
                  cout << "world update ticks: " << t2-t1 << endl;
                  t1 = GetMicroSeconds();
                  #endif

                  keyman.DoOneTimeKeys(cam);

                  //particle.Update(timefactor, fps);
                  //particle.Update(1.0, 1.0/FRAME_TIME);

                  cam.ExtractFrustum();

                  LightPosition[0] = cos(backdrop.sunpos_lat);
                  LightPosition[1] = sin(backdrop.sunpos_lat);
                  if (LightPosition[1] < 0)
                        LightPosition[1] *= 10.0f; //to simulate sun disappearing behind horizon
                  LightPosition[2] = 0.0f;//tan(backdrop.sunpos_lng);

                  float dusktime = 0.5;
                  float dawntime = 0.0;
                  float transtime = 0.05;

                  float diffuse = 1.0f;
                  if (day_time >= dusktime || day_time <= dawntime)
                  {
                        diffuse = 0.0;
                  }

                  if (day_time > dawntime && day_time < transtime)
                  {
                        diffuse = day_time / (transtime);
                  }

                  if (day_time > dusktime - transtime && day_time < dusktime)
                  {
                        diffuse = (day_time - dusktime - transtime) / transtime;
                  }

                  diffuse = diffuse*0.9+0.1;

                  VERTEX ld;
                  ld.Set(LightDiffuse[0], LightDiffuse[1], LightDiffuse[2]);
                  ld.Scale(diffuse);
                  glLightfv( GL_LIGHT1, GL_DIFFUSE, ld.v3() );

                  //float timepassed = (timefactor/fps)/86400.0;
                  float timepassed = (FRAME_TIME)/86400.0;
                  /*if (keyman.keys[keyman.GetKey("AccelTimeVFast")])
                        timefactor = 10000.0;
                  else if (keyman.keys[keyman.GetKey("AccelTimeFast")])
                        timefactor = 1000.0;
                  else
                        timefactor = 1.0;*/
                  //float timepassed = (timefactor/fps)/60.0;
                  //float timepassed = (timefactor/fps)/10.0;
                  abs_time += timepassed;
                  day_time += timepassed;
                  if (day_time > 1.0f)
                        day_time -= 1.0f;

                  #ifdef PERFORMANCE_PROFILE
                  t2 = GetMicroSeconds();
                  cout << "Time increment ticks: " << t2-t1 << endl;
                  t1 = GetMicroSeconds();
                  #endif

                  multiplay.Send(FRAME_TIME);

                  mainloop = true;

                  //terrain.Update(cam, timefactor, fps, day_time);
                  //terrain.Update(cam, 1.0, 1.0/FRAME_TIME, day_time);

                  execution_time -= FRAME_TIME;
                  num_updates++;

                  //replay.IncrementFrame();
            }
            particle.Update(1.0, 1.0/this_frame);
//          terrain.Update(cam, 1.0, 1.0/this_frame, day_time);
      }
      else
      {
            //print "paused"
            if (state.GetGameState() != STATE_INITIALMENU)
                  world.Update(timefactor, fps, gamecontrols.Get_js());
      }

      if (pauserequest)
      {
            if (timefactor != 0.0f)
                  timefactor = 0.0f;
            pauserequest = false;
      }
      if (unpauserequest)
      {
            if (timefactor == 0.0f)
                  timefactor = 1.0f;
            unpauserequest = false;
      }

      sound.Update();
      /*if (!mainloop)
            multiplay.Update(0);*/ //don't need this anymore because we're stopping things from being paused in multiplayer mode

      if (MP_DBGDEEP)
            cout << "main update done" << endl;
}

void snap_screenshot()
{
      char scrname[64];
      int num_shots;
      settings.Get( "game.num_shots", num_shots );
      sprintf(scrname, "%s/screenshots/shot%03d.bmp", (settings.GetSettingsDir()).c_str(), num_shots );
      Screenshot(scrname);
      settings.Set( "game.num_shots", num_shots + 1 );
}

void MainPause()
{
      //if (!menu.InMenu() && !multiplay.NumConnected() > 0)
      //if (state.GetGameState() == STATE_PLAYING)
      if( !gui.GetEnabled() && !multiplay.NumConnected() > 0 )
            pauserequest = true;
      /*bool mouse_enabled;
      settings.Get( "mouse.enabled", mouse_enabled );
      if( mouse_enabled )
      {
            gui.MouseReturn();
      }*/
      gui.ProcessAction( "Pause" );
}

void MainUnpause()
{
      unpauserequest = true;
}

// function to handle key press events
void handleKeyPress( SDL_keysym *keysym )
{
      //Vamos_Geometry::Three_Vector tvec1(44.464,-126.8737,0);
      //VERTEX tvec2;
      //QUATERNION trot;

      //if (state.GetGameState() == STATE_MENU)
      //if (menu.InMenu())
      //    menu.MenuKey(keysym->sym);
      //else if (timefactor == 0 && !menu.InMenu()) timefactor = 0;
            //          else timefactor = 1.0;
      if( !gui.GetEnabled() )
      {
            switch ( keysym->sym )
            {
            case SDLK_ESCAPE:
                  // ESC key was pressed
                  //Quit(0);
                  //gui.ChangePage( "InGameMenu" );
                  //menu.MainMenu();
                  esc_pressed = true;
                  break;
            /*case SDLK_F7:
                  
                  tvec1 = tvec1.rotate(0,0,6.21652);
                  cout << tvec1[0] << "," << tvec1[1] << endl;
            
                  
                  tvec2.Set(44.464,-126.8737,0);
                  
                  trot.Rotate(6.21652, 0, 0, 1);
                  tvec2 = trot.RotateVec(tvec2);
                  tvec2.DebugPrint();
                  break;*/
            /*case SDLK_F7:
                  if (timefactor != 100.0f)
                        timefactor = 100.0f;
                  else
                        timefactor = 1.0f;
                  break;*/
            /*case SDLK_PAGEUP:
                  //tmpvert = cam.GetVelocity();
                  cam.MoveRelative(0.0f, 0.0f, -2.0f);
                  //cam.Update();
                  //cam.LoadVelocityIdentity();
                  break;
            case SDLK_PAGEDOWN:
                  //tmpvert = cam.GetVelocity();
                  cam.MoveRelative(0.0f, 0.0f, 2.0f);
                  //cam.Update();
                  //cam.LoadVelocityIdentity();
                  break;*/
            
            //case SDLK_F11:
                  //SDL_WM_ToggleFullScreen( surface );
                  //ChangeDisplay(1280,1024,32,true);
                  //menu.DisplayMenu();//DisplaySelect();
                  //break;
            
            //case SDLK_F12:
                  //menu.MainMenu();
                  //break;

            default:
                  /*if (timefactor == 0.0f)
                        MainUnpause();
                  else
                        keyman.OneTime(keysym->sym);*/
                  break;
            }
      }

      return;
}

void handleKeyRelease( SDL_keysym *keysym )
{
      if( !gui.GetEnabled() )
      {
            switch ( keysym->sym )
            {
            case SDLK_ESCAPE:
                  // ESC key was released
                  if( esc_pressed )
                  {
                        esc_pressed = false;
                        MainPause();
                  }
                  break;
            default:
                  /*if (timefactor == 0.0f)
                        MainUnpause();
                  else*/
                        keyman.OneTime(keysym->sym);
                  break;
            }
      }

      return;
}

void glSetup()
{
      // Enable Texture Mapping ( NEW )
      glEnable( GL_TEXTURE_2D );
      // Enable smooth shading
      glShadeModel( GL_SMOOTH );
      // Set the background black
      //glClearColor( 0.53f, 0.74f, 0.91f, 0.0f );
      glClearColor(0,0,0,0);
      // Depth buffer setup
      glClearDepth( 1.0f );
      // Enables Depth Testing
      glEnable( GL_DEPTH_TEST );
      // The Type Of Depth Test To Do
      glDepthFunc( GL_LEQUAL );
      // Really Nice Perspective Calculations
      glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
      // Enable Lighting
      glEnable( GL_LIGHTING );

      //set the clipping planes
      //glFrustum(1000,1000,1000,1000,1,1000);

      //utility.Tex2D(3, false);
      //utility.Tex2D(2, false);
      //utility.Tex2D(1, false);
      //utility.Tex2D(0, true);
}

//string otrack_file;
//string car_file;
string data_dir;
//int car_paint;

//int number_of_opponents;
//int focused_car;

void SelectCar(string cfile, bool trim)
{     
      //if (clearold)
      world.clear_cars();
      //string car_name;
      //settings.Get( "game.selected_car", car_name );
      //int car_paint;
      //settings.Get( "game.car_paint", car_paint );
      //car_file = cfile;
      state.SetCarName(0, cfile);

      Vamos_Body::Gl_Car* car = 0;
/*    try
      {
*/          car = new Vamos_Body::Gl_Car (Vamos_Geometry::Three_Vector (11.0, 0.0, 0.6));
            car->read (data_dir, cfile);
            car->SetPaint(state.GetCarPaint(0));
            car->chassis ().translate (Vamos_Geometry::Three_Vector(track.GetStart().x, -track.GetStart().z, track.GetStart().y));
            car->chassis ().translate (Vamos_Geometry::Three_Vector (10.0*multiplay.MyNum(), 0.0, 
                                                                     -car->chassis ().lowest_contact_position () + CAR_Y_OFFSET));
            car->start_engine ();
            car->set_controller(1);
            world.add_car (car);

            /*for (int i = 0; i < number_of_opponents; i++)
            {
                  car = new Vamos_Body::Gl_Car (Vamos_Geometry::Three_Vector (11.0, 0.0, 0.6));
                  car->read (data_dir, cfile);
                  car->chassis ().translate (Vamos_Geometry::Three_Vector (10.0 * (i + 1), 0.0, 
                        -car->chassis ().lowest_contact_position () + CAR_Y_OFFSET));
                  car->start_engine ();
                  car->set_controller(-1);
                  world.add_car (car);
            }*/

            int i;
            //if (!multiplay.Server()) //the client re-loads the world, the server doesn't (NOT TRUE ANYMORE)
            {
                  for (i = 0; i < multiplay.NumConnected()+1; i++)
                  {
                        if (i != multiplay.MyNum())
                        {
                              int idx = i;
                              if (idx == 0)
                                    idx = 1;
                              car = new Vamos_Body::Gl_Car (Vamos_Geometry::Three_Vector (11.0, 0.0, 0.6));
                              car->read (data_dir, state.GetCarName(idx));
                              car->SetPaint(state.GetCarPaint(idx));
                              car->chassis ().translate (Vamos_Geometry::Three_Vector(track.GetStart().x, -track.GetStart().z, track.GetStart().y));
                              car->chassis ().translate (Vamos_Geometry::Three_Vector (10.0*i, 0.0, 
                                    -car->chassis ().lowest_contact_position () + CAR_Y_OFFSET));
                              car->start_engine ();
                              car->set_controller(2);
                              world.add_car (car);
                        }
                  }
            }

            if (replay.GhostCar())
            {
                  car = new Vamos_Body::Gl_Car (Vamos_Geometry::Three_Vector (11.0, 0.0, 0.6));
                  car->read (data_dir, replay.ReplayCar());
                  car->SetPaint(replay.ReplayPaint());
                  car->chassis ().translate (Vamos_Geometry::Three_Vector (10.0*multiplay.MyNum(), 0.0, 
                        -car->chassis ().lowest_contact_position () + CAR_Y_OFFSET));
                  car->start_engine ();
                  car->set_controller(3);
                  world.add_car (car);
            }

            world.reset();
/*    }
      catch (Vamos_Geometry::XML_Exception& error)
      {
            std::cerr << error.message () << std::endl;
            std::exit (EXIT_FAILURE);
      }
*/
      if (trim)
            ResetWorld(false);
}

bool UnloadWorld()
{
      //these should have error catching such that if they're called before
      // init, it's OK
      //textures.DeleteAll();
      backdrop.DeInit();
//    terrain.DeInit();
      world.DeInit();
      sound.Unload();
      
      return true;
}

#ifdef PATCH_DEBUG
BEZIER * thepatch;
#endif

bool LoadWorld()
{
      UnloadWorld();

      //begin loading world
      timefactor = 1.0;
      
      //reset best lap time
      timer.ResetBest();
      timer.ResetLast();

      LoadingScreen("Loading...\nConfiguration files");

      //state.SetCarName( 0, "" );
      //state.SetCarPaint( 0, 0 );
      //state.SetTrackName( "" );

      string selected_car = "";
      string track_name;
      int car_paint = 0;

      settings.Get( "game.selected_car", selected_car );
      settings.Get( "game.car_paint", car_paint );
      settings.Get( "game.track", track_name );

      //cout << "selected " << track_name << " " << selected_car << endl;
      state.SetCarName( 0, selected_car );
      state.SetCarPaint( 0, car_paint );
      state.SetTrackName( track_name );

      if (state.GetCarName(0) == "")
            state.SetCarName(0, "CS");

      //if (track_name == "")
      //    state.SetTrackName( "ruudskogen" );

      //string world_file = "default-world";
      //string controls_file = "default-controls";
      //number_of_opponents = 0;
      //focused_car = 0;
      //string track_file = "tracks/" + state.GetTrackName() + "/" + state.GetTrackName() + ".xml";
      //world_file = "worlds/" + world_file + ".xml";
      //controls_file = settings.GetSettingsDir() + "/controls/" + controls_file + ".xml";
      data_dir = settings.GetDataDir() + "/";

      /*LoadingScreen("Loading...\nLoading terrain");
      //terrain.Init(2000,200,2000,"outermap3.raw","outermap1-detail.bmp","outermap2-test.png");
      //terrain.Init(2000,200,2000,"shaw4.raw","outermap1-detail.bmp","shawtestmap2.png", REFLECT_RES);
      //terrain.Init(2000,200,2000,"shawlike.raw","detail-lowfreq.bmp","shawlike.png", REFLECT_RES_X, REFLECT_RES_Y);
      //terrain.Init(2000,200,2000,"outermap4.raw","outermap1-detail.bmp","outermap4v1.png");
      string terrainfile;
      string trackpath = settings.GetDataDir() + "/tracks/" + state.GetTrackName() + "/";
      terrainfile = trackpath + "parameters.txt";

      ifstream tf(terrainfile.c_str());
      int numparam, i;
      numparam = 7;
      float param[numparam];
      if (tf)
      {
            for (i = 0; i < numparam; i++)
                  param[i] = utility.fGetParam(tf);
            terrain.Init((int)param[0],(int)param[1],(int)param[2], trackpath+"terrain.png", trackpath+"mask.png", trackpath+"texture.png", trackpath+"detail.png", trackpath+"detail2.png", trackpath+"parametric.png", param[3], param[4], param[5], param[6]);
      }
      else
      {
            cout << "Couldn't find track terrain parameter file " << terrainfile << endl;
            //terrain.Init(3000,300,3000, otrack_file+".png", otrack_file+"-mask.png", otrack_file+".png", otrack_file+"-detail.png", otrack_file+"-detail2.png", otrack_file+"-parametric.png", -1500, -2000, 150, 100);
            param[0] = 3000; param[1] = 300; param[2] = 3000;
            param[3] = -1500;
            param[4] = -2000;
            param[5] = 150;
            param[6] = 100;
            terrain.Init((int)param[0],(int)param[1],(int)param[2], trackpath+"terrain.png", trackpath+"mask.png", trackpath+"texture.png", trackpath+"detail.png", trackpath+"detail2.png", trackpath+"parametric.png", param[3], param[4], param[5], param[6]);
      }

      LoadingScreen("Loading...\nTrack");
      try
      {
            road = new Vamos_Track::Strip_Track;
            road->read (data_dir, track_file);
      }
      catch (Vamos_Geometry::XML_Exception& error)
      {
            std::cerr << error.message () << std::endl;
            std::exit (EXIT_FAILURE);
      }*/

      LoadingScreen("Loading...\nTrack");
      track.Load(state.GetTrackName());
      
      LoadingScreen("Loading...\nLoading backdrop");
      backdrop.Init();
      
      LoadingScreen("Loading...\nLoading scenery objects");
      string objectpath = settings.GetDataDir() + "/tracks/" + state.GetTrackName() + "/objects";
      objects.LoadObjectsFromFolder(objectpath);

      #ifdef COLLISION_TESTING
      if (0)
      {
            bool col = false;
            VERTEX origin, dir, colpt, normal;
            bool closest = true;
            origin.Set(496.334,1000,-1.11335);
            dir.Set(0,-1,0);
            BEZIER * colpatch;
            ROADSTRIP * colstrip;
            ofstream deb;
            deb.open("debug.log");
            deb << "Debug log start" << endl;
            deb.close();
            
            col = track.CollideRoads(origin, dir, colpt, closest, colstrip, colpatch, normal);
            deb.open("debug.log", ofstream::out | ofstream::app);
            deb << "col: " << col << endl;
            deb << "origin: "; origin.DebugPrint(deb);
            deb << "dir: "; dir.DebugPrint(deb);
            deb << "colpt: "; colpt.DebugPrint(deb);
            deb << "closest: " << closest << endl;
            deb << "normal: "; normal.DebugPrint(deb);
            deb << "seglen: " << 10000.0f << endl;
            deb << "-------------" << endl;
            deb.close();
            
            col = objects.Collide(origin, dir, colpt, closest, normal, 10000.0f);
            deb.open("debug.log", ofstream::out | ofstream::app);
            deb << "col: " << col << endl;
            deb << "origin: "; origin.DebugPrint(deb);
            deb << "dir: "; dir.DebugPrint(deb);
            deb << "colpt: "; colpt.DebugPrint(deb);
            deb << "closest: " << closest << endl;
            deb << "normal: "; normal.DebugPrint(deb);
            deb << "seglen: " << 10000.0f << endl;
            deb << "-------------" << endl;
            deb.close();
      }
      #endif
      
      //Quit(0);
      
      LoadingScreen("Loading...\nLoading sound");
      //sound.Deinit();
      //sound.Init();
      sound.Reload();

      LoadingScreen("Loading...\nWorld");
      world.Init(&track);

      LoadingScreen("Loading...\nCar");
      SelectCar(state.GetCarName(0), true);
      //world.GetPlayerCar()->SetPaint(car_paint); <-done in selectcar instead.

      //LoadingScreen("Loading...\nLoading Trees");
      //trees.ReadFromFile(settings.GetFullDataPath("tracks/" + state.GetTrackName() + "/treemap.png"), settings.GetFullDataPath("tracks/" + state.GetTrackName() + "/foliagemap.png"));
      /*trees.DeleteAll();
      int numtrees = 200;
      for (i = 0; i < numtrees/2; i++)
      {
            VERTEX tp;
            tp.x = ((float) rand()/RAND_MAX)*(param[0]/2.0)+param[0]/4.0;
            tp.z = ((float) rand()/RAND_MAX)*(param[2]/2.0)+param[2]/4.0;
            tp.x += param[3];
            tp.z += param[4];
            tp.y = terrain.GetHeight(tp.x, tp.z);
            trees.Add(tp, 40.0, 0, 5);
      }

      for (i = 0; i < numtrees/2; i++)
      {
            VERTEX tp;
            tp.x = ((float) rand()/RAND_MAX)*(param[0]/2.0)+param[0]/4.0;
            tp.z = ((float) rand()/RAND_MAX)*(param[2]/2.0)+param[2]/4.0;
            tp.x += param[3];
            tp.z += param[4];
            tp.y = terrain.GetHeight(tp.x, tp.z);
            trees.Add(tp, 60.0, 1, 5);
      }*/

      timer.Reset();
      particle.Clear();

      LoadingScreen("Loading...\nDone");

      mq1.AddMessage("Simulation start");

      #ifdef PATCH_DEBUG
      {
            VERTEX v[4];
            /*v[0].Set(-2045.29,604.818,-566.924);
            v[1].Set(-2040.08,605.083,-572.898);
            v[2].Set(-2026.6,602.961,-550.628);
            v[3].Set(-2020.85,602.961,-557.449);*/
            v[0].Set(-2148.81,583.537,-1395.68);
            v[1].Set(-2151.04,583.525,-1396.96);
            v[2].Set(-2145.45,583.378,-1401.53);
            v[3].Set(-2147.67,583.341,-1402.81);

            thepatch = track.GetPatch(v);
            if (thepatch != NULL)
            {
                  cout << "Got patch" << endl;
            
                  VERTEX p1,p2;
                  /*p1.Set(-2032.96,603.927,-562.198);
                  p2.Set(-2033,603.931,-562.227);*/
                  p1 = (v[0] + v[1]).ScaleR(0.5);
                  p2 = (v[2] + v[3]).ScaleR(0.5);
                  VERTEX dir;
                  dir = p2-p1;
                  dir = dir.normalize();
                  dir.Scale(7.0);
                  p1 = p1 - dir.ScaleR(0.5);
                  int steps = 100;
                  /*cout << "c(";
                  for (int i = 0; i < steps; i++)
                  {
                        VERTEX p;
                        p = p1 + dir.ScaleR((float)i/(float)steps);
                        cout << track.Elevation(p) << ",";
                        //cout << track.Elevation(p1) << endl;
                        //cout << track.Elevation(p2) << endl;
                  }
                  cout << ")" << endl;*/
                  
                  cout << "c(";
                  for (int i = 0; i < steps; i++)
                  {
                        VERTEX p;
                        p = p1 + dir.ScaleR((float)i/(float)steps);
                        VERTEX dir;
                        dir.y = -1000;
                        p.y += 1000;
                        VERTEX tvert, tnorm;
                        bool col = thepatch->CollideSubDivQuadSimpleNorm(p, dir, tvert, tnorm);
                        if (col)
                              cout << tvert.y << ",";
                        else
                              cout << 600 << ",";
                        //cout << track.Elevation(p) << ",";
                        //cout << track.Elevation(p1) << endl;
                        //cout << track.Elevation(p2) << endl;
                  }
                  cout << ")" << endl;
            }
            else
                  cout << "couldn't find patch" << endl;
      }
      #endif
      
      //triangle-triangle collision testing
      /*if (0)
      {
            VERTEX tri1[3];
            VERTEX tri2[3];
            tri1[0].Set(0,0,0);
            tri1[1].Set(1,0,0);
            tri1[2].Set(1,0,1);
            
            tri2[0].Set(0,1,0);
            tri2[1].Set(1,1,0);
            tri2[2].Set(1,-1,1);
            
            VERTEX colpt, colseg;
            int whichtri;
            
            bool col = utility.BruteForceTriangleIntersectionF(tri1, tri2, colpt, 
                        colseg, whichtri);
            if (col)
            {
                  colpt.DebugPrint();
                  colseg.DebugPrint();
                  cout << whichtri << endl;
            }
            else
                  cout << "No col" << endl;
      }
      
      if (0)
      {
            VERTEX tri1[3];
            VERTEX tri2[3];
            tri1[0].Set(132.422,-1.18925,1.84825);
            tri1[1].Set(131.82,-0.16846,-0.154412);
            tri1[2].Set(131.803,-0.173352,1.84551);
            
            tri2[0].Set(220.398,220.398,-3.08942e-06);
            tri2[1].Set(-220.398,220.398,1.19984e-05);
            tri2[2].Set(220.398,-220.398,-2.23572e-05);
            
            VERTEX colpt, colseg;
            int whichtri;
            
            bool col = utility.BruteForceTriangleIntersectionF(tri1, tri2, colpt, 
                        colseg, whichtri);
            if (col)
            {
                  colpt.DebugPrint();
                  colseg.DebugPrint();
                  cout << whichtri << endl;
            }
            else
                  cout << "No col" << endl;
      }*/
      
      return true;
}

void InitGameData()
{
      //LoadingScreen("Loading...\nInitializing utilities");
      utility.Init();

      state.SetGameState(STATE_LOGO);
      logo.run();

      //state.SetGameState(STATE_PLAYING);
      state.SetGameState(STATE_INITIALMENU);
      LoadingScreen("Loading...\nSetting time");
      LightPosition[0] = 2.0f;
      LightPosition[1] = 2.0f;
      LightPosition[2] = 2.0f;
      LightPosition[3] = 0.0f;

      day_time = abs_time = 0.1;
      //day_time = abs_time = 0.03;
      //day_time = abs_time = 0.48;
      //day_time = abs_time = 0.75;

      //LoadingScreen("Loading...\nUser interface");
      //menu.Load();
      //gui.Init();

      LoadingScreen("Loading...\nInitializing weather");
      weathersystem.Init();
      weathersystem.Update(abs_time);

      LoadingScreen("Loading...\nSetting camera position");

      // Set the initial camera position
      //cam.Move(-200,-200,-200);
      //cam.Move(-596.513,-30.9295,-250.623);

      cam.Move(0,-5,0);
      cam.Update();
      cam.LoadVelocityIdentity();
      //cam.Rotate(180.0,0,1,0);
      /*
      LoadingScreen("Loading...\nLoading Meshes");
      //load scene objects
      string listval;
      listval = settings.GetSettingsDir() + "/meshlist.txt";
      int ret;
      ret = meshes.LoadList(listval);
      if (!ret)
      {
            error_log << "Fatal error:  could not load mesh list\n";
            return FALSE;
      }

      //LoadingScreen("Loading...\nLoading game database");
      //gamedb.LoadAll();

      LoadingScreen("Loading...\nLoading new game state");
      */

      LoadingScreen("Loading...\nStarting message queue");
      mq1.SetPersist(5.0f);
      mq1.SetDepth(1);
      mq1.SetPos(0.01,0.09,5,1);
      mq1.SetBuildUp(true);
      //mq1.SetTimePrint(true);

      /*
      //LoadingScreen("Loading...\nLoading sound");
      //sound.Load(&cam);

      //LoadingScreen("Loading...\nLoading HUD");
      //playerhud.Load();

      LoadingScreen("Loading...\nLoading water");
      water.initWater(64,64,1,3.0f);
      //water.initWater(32,32,16,100.0f);
      //water.initWater(64,64,8,10.0f);
*/

      LoadingScreen("Loading...\nGame control config");
      keyman.Load();
      gamecontrols.LoadControls();

//    LoadingScreen("Loading...\nLoading Trees");
//    trees.Load();

      LoadingScreen("Loading...\nInitializing particle engine");
      particle.Load();
      VERTEX wind;
      wind.x = 0.3;
      wind.z = 0.1;
      particle.SetWind(wind);

      LoadingScreen("Loading...\nLoading Timer");
      timer.Load();

      LoadingScreen("Loading...\nInitializing Network");
      net.Init();

      string track;
      settings.Get( "game.track", track );
      state.SetTrackName( track );
      if( state.GetTrackName() == "" )
            state.SetTrackName("ruudskogen");

      ifstream csfile;
      //car_file = "";
      //state.SetCarName(0, "");
      //csfile.open("carsettings/selected_car");
      //car_paint = 0;
      //state.SetCarPaint(0, 0);
/*    if (csfile)
      {
            state.SetCarName(0, utility.sGetLine(csfile));
            state.SetCarPaint(0, utility.iGetParam(csfile));
            csfile.close();
      }
*/
      string car_name;
      int car_paint;
      settings.Get( "game.selected_car", car_name );
      settings.Get( "game.car_paint", car_paint );

      state.SetCarName( 0, car_name );
      state.SetCarPaint( 0, car_paint );
      // XXX use a better way to pick the default car
      if (state.GetCarName(0) == "")
      {
            state.SetCarName(0, "MI");
            //cout << "no car selected, picking default" << endl;
      }
      
      LoadingScreen("Loading...\nInitializing sound");
      sound.Init();
      float sound_volume = 0.5;
      settings.Get( "sound.volume", sound_volume );
      sound.SetMasterVolume( sound_volume );
}

// general OpenGL initialization function
void InitGL( GLvoid )
{
      //warning:  this must be done BEFORE anything important
      //or else it will override it
      font.Load();
      
      // Enable Texture Mapping ( NEW )
      glEnable( GL_TEXTURE_2D );

      // Enable smooth shading
      glShadeModel( GL_SMOOTH );

      // Set the background black
      //glClearColor( 0.46f, 0.54f, 0.64f, 0.0f );
      glClearColor(0,0,0,0);

      // Depth buffer setup
      glClearDepth( 1.0f );

      // Enables Depth Testing
      glEnable( GL_DEPTH_TEST );

      // The Type Of Depth Test To Do
      glDepthFunc( GL_LEQUAL );

      // Really Nice Perspective Calculations
      glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

      // Position The Light
      glLightfv( GL_LIGHT1, GL_POSITION, LightPosition );
      
      // Setup The Diffuse Light
      glLightfv( GL_LIGHT1, GL_DIFFUSE, LightDiffuse );
      glLightfv( GL_LIGHT1, GL_SPECULAR, LightSpecular );
      
      // Setup The Ambient Light
      glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient );

      // Enable Light One
      glEnable( GL_LIGHT1 );
      
      // Enable Lighting
      glEnable( GL_LIGHTING );
      
      //our perspective matrix
      glMatrixMode( GL_PROJECTION );
      glLoadIdentity( );
      gluPerspective( 45.0f, (float)SCREEN_WIDTH/SCREEN_HEIGHT, 0.1f, 10000.0f );
      glMatrixMode( GL_MODELVIEW );
      
      // Enable front face culling, since that's what Quake3 does
      //glCullFace(GL_FRONT);
      //glEnable(GL_CULL_FACE);
}

void LoadingScreen(string loadtext)
{
      if (verbose_output)
      cout << loadtext << endl;

      glPushAttrib(GL_ALL_ATTRIB_BITS);
      glPushMatrix();
      
      utility.Tex2D(3, false);
      utility.Tex2D(2, false);
      utility.Tex2D(1, false);
      utility.Tex2D(0, true);
      
      glSetup();
      
      glEnable(GL_TEXTURE_2D);
      
      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer

      Frames++;

      font.Print(0,0,loadtext.c_str(),1,6,1,1,1);
      
      // Draw it to the screen
      SDL_GL_SwapBuffers( );

      GLint t = SDL_GetTicks();
      //if (t - T0 >= 50) 
      {
            GLfloat seconds = (t - T0) / 1000.0;
            fps = 1 / seconds;
            //printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
            T0 = t;
            //Frames = 0;
      }
      
      glPopMatrix();
      glPopAttrib();
}

/*int RenderReflectedScene(bool underwater, float waterheight)
{
      backdrop.SetFogStrength(weathersystem.GetFogDensity());
      backdrop.RefreshFog();
      
      int sizex, sizey;
      sizex = REFLECT_RES_X;
      sizey = REFLECT_RES_Y;
      glViewport(0, 0, sizex, sizey);
      
      glMatrixMode( GL_PROJECTION );
      glLoadIdentity( );
      gluPerspective( 70.0f, (float)SCREEN_WIDTH/SCREEN_HEIGHT, 0.1f, 10000.0f );
      glMatrixMode( GL_MODELVIEW );
      
      
      
      //backdrop.SetFogStrength(0.05f);
      
      backdrop.RefreshFog();
      
      #ifdef _WIN32
      //fix multitexturing state
      pglActiveTexture(GL_TEXTURE0_ARB);
      #else
       //fix multitexturing state
      glActiveTexture(GL_TEXTURE0_ARB);
      #endif
      
      glSetup();
      
      //glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
      float clearcolor[4];
      backdrop.GetHorizonColor(clearcolor);
      clearcolor[3] = 0.0f;
      glClearColor( clearcolor[0], clearcolor[1], clearcolor[2], clearcolor[3] );
      
      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer
      
      GLdouble temp_matrix[16];
      
      
      
      //QUATERNION oldcamdir = cam.dir;
      //cam.Rotate(3.141593f, 0, 0, 1);
      
      
      
      cam.PutTransformInto(temp_matrix);
      glLoadMatrixd(temp_matrix);
      
      //cam.dir = oldcamdir;
      

      
      
      glPushMatrix();
      //glTranslatef(0, -5, 0);
      glScalef(1.0f,-1.0f,1.0f);
      backdrop.SetCloudTexture(terrain.GetCloudTexture());
      backdrop.DrawSky(true, day_time, 1.0f, underwater);
      glClear (GL_DEPTH_BUFFER_BIT);
      glPopMatrix();
      
      glTranslatef(cam.GetPosition().x,cam.GetPosition().y,cam.GetPosition().z);
      
      glTranslatef(0, waterheight*2, 0);
      
      glScalef(1.0f,-1.0f,1.0f);
      
      
      //reset sun position so it's in the correct frame
      float lp[4];
      lp[0] = LightPosition[0];
      lp[1] = LightPosition[1];
      lp[2] = LightPosition[2];
      lp[3] = 0;
      glLightfv( GL_LIGHT1, GL_POSITION, lp );

      //adjust light color to be dimmer for reflection
      float lc[4];
      float light_atten = 0.0f;
      if (underwater)
            light_atten = 1.0f;
      else
            light_atten = 0.1f;
      lc[0] = LightDiffuse[0]*light_atten;
      lc[1] = LightDiffuse[1]*light_atten;
      lc[2] = LightDiffuse[2]*light_atten;
      lc[3] = LightDiffuse[3]*light_atten;
      glLightfv( GL_LIGHT1, GL_DIFFUSE, lc );
      if (underwater)
            light_atten = 0.0f;
      else
            light_atten = 0.0f;
      lc[0] = LightDiffuse[0]*light_atten;
      lc[1] = LightDiffuse[1]*light_atten;
      lc[2] = LightDiffuse[2]*light_atten;
      lc[3] = LightDiffuse[3]*light_atten;
      glLightfv( GL_LIGHT1, GL_AMBIENT, lc );

      //put a clipping plane at the water level.
      //using a simple plane as below may not be good enough; the world is 
      // curved, so the plane should have the same normal as the spherical normal
      GLdouble equation[4];
      VERTEX temp;
      VERTEX earthnormal = temp - cam.position;
      earthnormal.y += EARTH_RADIUS;
      earthnormal = earthnormal.normalize();
      equation[0] = earthnormal.x;
      equation[1] = earthnormal.y;
      equation[2] = -earthnormal.z;
      equation[3] = -(waterheight);
      glClipPlane(GL_CLIP_PLANE1, equation);
      glEnable(GL_CLIP_PLANE1);
      
      terrain.SetFrustum(cam);
      
      terrain.Draw(cam, 10.0f, true, true, false, true, timefactor, fps, day_time);
      
      //terrain doubling to try to eliminate reflection artifacts...
      // introduces artifacts of its own
      //maybe only do this if underwater?
      glPushMatrix();
      glTranslatef(0, waterheight*2, 0);
      glScalef(1.0f, -1.0f, 1.0f);
      glClipPlane(GL_CLIP_PLANE1, equation);
      glLightfv( GL_LIGHT1, GL_POSITION, lp );
      terrain.Draw(cam, 10.0f, true, true, false, false, timefactor, fps, day_time);
      glPopMatrix();
      
      //restore light color
      glLightfv( GL_LIGHT1, GL_DIFFUSE, LightDiffuse );
      glLightfv( GL_LIGHT1, GL_SPECULAR, LightSpecular );
      glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient );

      //draw trees
      foliage.Draw(terrain, cam);
      
      equation[0] = earthnormal.x;
      equation[1] = earthnormal.y;
      equation[2] = -earthnormal.z;
      equation[3] = -(waterheight);
      glClipPlane(GL_CLIP_PLANE1, equation);
      
      
      //glDisable(GL_CLIP_PLANE1);
      //glScalef(1,-1,1);
      
      if (underwater)
      {
            glPushMatrix();
            glTranslatef(0, waterheight*2, 0);
            glScalef(1.0f, -1.0f, 1.0f);
            glClipPlane(GL_CLIP_PLANE1, equation);
            glLightfv( GL_LIGHT1, GL_POSITION, lp );
            ships.Draw(true);
            glPopMatrix();
      }
      else
      {
            glClipPlane(GL_CLIP_PLANE1, equation);
            ships.Draw(true);
      }
      
      
      
      
      
      glDisable(GL_CLIP_PLANE1);
      
      
      //redraw sky so that land reflections appear washed out
      if (!underwater)
      {
            float skytrans = 0.8f;
            cam.PutTransformInto(temp_matrix);
            glLoadMatrixd(temp_matrix);
            glScalef(1.0f,-1.0f,1.0f);
            backdrop.DrawSky(true, day_time, skytrans, underwater);
      }
      
      
      //add a brightness/contrast adjustment
      glClear (GL_DEPTH_BUFFER_BIT);
      glLoadIdentity();
      glPushAttrib(GL_ALL_ATTRIB_BITS);
      glDisable(GL_TEXTURE_2D);
      glEnable(GL_BLEND);
      glDisable(GL_FOG);
      glDisable(GL_LIGHTING);
      glTranslatef(0,0,-40.0f);
      glBlendFunc(GL_ONE, GL_SRC_ALPHA);
      
      float scale = 0.8f;
      float bias = 0.0f;
      
      glColor4f(bias, bias, bias, scale);
      float x1, y1, x2, y2;
      x1 = -80;
      y1 = -80;
      x2 = 80;
      y2 = 80;
      
      if (scale > 1.0) 
      {
            float remainingScale;
            
            remainingScale = scale;
            glBlendFunc(GL_DST_COLOR, GL_ONE);
            if (remainingScale > 2.0) 
            {
                  glColor4f(1, 1, 1, 1);
                  while (remainingScale > 2.0) 
                  {
                        glRectf(x1,y1,x2,y2);
                        remainingScale /= 2.0;
                  }
            }
            glColor4f(remainingScale - 1,
                  remainingScale - 1, remainingScale - 1, 1);
            glRectf(x1,y1,x2,y2);
            glBlendFunc(GL_ONE, GL_ONE);
            if (bias != 0)
            {
                  if (bias > 0) 
                  {
                        glColor4f(bias, bias, bias, 0.0);
                  }
                  else 
                  {
                        glColor4f(-bias, -bias, -bias, 0.0);
                        //can't do bias < 0
                  }
                  glRectf(x1,y1,x2,y2);
            }
      }
      else 
      {
            if (bias > 0) 
            {
                  glColor4f(bias, bias, bias, scale);
            }
            else 
            {
                  glColor4f(-bias, -bias, -bias, scale);
                  //can't do bias < 0
            }
            glBlendFunc(GL_ONE, GL_SRC_ALPHA);
            glRectf(x1,y1,x2,y2);
      }
      
      glPopAttrib();

      
      

      // Before we copy the screen to a texture, we need to specify the current
      // texture to draw to by calling glBindTexture() with the appropriate texture 
      glBindTexture(GL_TEXTURE_2D, terrain.reflection_texture);                

      // Now comes the moment we have all been waiting for, we render the screen
      // to the texture.  We pass in the texture type, detail level (0), pixel format,
      // the x and y position to start from, the width and height to grab, and a border.
      // If you only want a part of the screen, this works great for that.
      glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, sizex, sizey, 0);

      // Here we clear the screen and depth bits of the small viewport
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            

      // Set our viewport back to it's normal size
      glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);    

      
    
      //glPopMatrix();
      
      return true;
}
*/

// Here goes our drawing code
int drawGLScene( GLvoid )
{
      #ifdef PERFORMANCE_PROFILE
      suseconds_t t1, t2;
      t1 = GetMicroSeconds();
      t1 = GetMicroSeconds();
      #endif
      
      //glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      if (state.GetGameState() != STATE_INITIALMENU)
      {                 
            backdrop.SetFogStrength(weathersystem.GetFogDensity());
            backdrop.RefreshFog();
      }
      
      #ifdef PERFORMANCE_PROFILE
      t2 = GetMicroSeconds();
      cout << "RenderReflectedScene() ticks: " << t2-t1 << endl;
      t1 = GetMicroSeconds();
      #endif
      
      glMatrixMode( GL_PROJECTION );
      glLoadIdentity( );

      gluPerspective( 45.0f, (float)SCREEN_WIDTH/SCREEN_HEIGHT, 0.1f, view_dist );
      glMatrixMode( GL_MODELVIEW );
      
      glSetup();
      
      glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); 
      //glClearColor( 255.0f, 0.0f, 0.0f, 0.0f ); 
      
      #ifdef PERFORMANCE_PROFILE
      t2 = GetMicroSeconds();
      cout << "glSetup() ticks: " << t2-t1 << endl;
      t1 = GetMicroSeconds();
      #endif
      
      utility.Tex2D(3, false);
      utility.Tex2D(2, false);
      utility.Tex2D(1, false);
      utility.Tex2D(0, true);
      
      glStencilMask(~0);
      glClearStencil(0);
      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);        // Clear Screen And Depth Buffer
      
      glEnable(GL_STENCIL_TEST);
      glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
      glStencilFunc(GL_ALWAYS, 1, ~0);
      glDisable(GL_STENCIL_TEST);

      
      GLdouble temp_matrix[16];
      cam.PutTransformInto(temp_matrix);
      glLoadMatrixd(temp_matrix);
      
      //reset sun position so it's in the correct frame
      float lp[4];
      lp[0] = LightPosition[0];
      lp[1] = LightPosition[1];
      lp[2] = LightPosition[2];
      lp[3] = 0;
      glLightfv( GL_LIGHT1, GL_POSITION, lp );
      
      #ifdef PERFORMANCE_PROFILE
      t2 = GetMicroSeconds();
      cout << "Matrix setup and light setup ticks: " << t2-t1 << endl;
      t1 = GetMicroSeconds();
      #endif
      
      if (state.GetGameState() != STATE_INITIALMENU)
      {
            
            bool normal = true;           if (normal)
                  backdrop.DrawSky(day_time, 1.0f);
            glClear (GL_DEPTH_BUFFER_BIT);
            
            #ifdef PERFORMANCE_PROFILE
            t2 = GetMicroSeconds();
            cout << "DrawSky() ticks: " << t2-t1 << endl;
            t1 = GetMicroSeconds();
            #endif
            
            glTranslatef(cam.GetPosition().x,cam.GetPosition().y,cam.GetPosition().z);
      
      
            
            if (MP_DBGDEEP)
                  cout << "normal draw start" << endl;
            
//          terrain.SetFrustum(cam);
            
            #ifdef PERFORMANCE_PROFILE
            t2 = GetMicroSeconds();
            cout << "terrain.SetFrustum() ticks: " << t2-t1 << endl;
            t1 = GetMicroSeconds();
            #endif
            
            //glPolygonOffset(1.0,1.0);
            glPolygonOffset(0.0,10.0);
            glEnable(GL_POLYGON_OFFSET_FILL);
      
            if (normal)
            {
                  //GLfloat LightAmbient2[]  = { 0.3f, 0.3f, 0.3f, 1.0f };
                  //glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient2 );
                  glDisable(GL_STENCIL_TEST);
                  
            /*    if (utility.numTUs() > 3 && state.GetTreeDetail() != "Off" && state.GetTreeDetail() != "FoliageOnly")
                  {
                        utility.SelectTU(3);
                        glEnable(GL_TEXTURE_2D);
                        glBindTexture(GL_TEXTURE_2D, trees.GetCompositeShadow());
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
                        glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_MODULATE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);
                        utility.SelectTU(0);
                  }*/

//                terrain.Draw(cam, 1.0f, timefactor, fps, day_time);

                  #ifdef PERFORMANCE_PROFILE
                  t2 = GetMicroSeconds();
                  cout << "terrain.Draw() ticks: " << t2-t1 << endl;
                  t1 = GetMicroSeconds();
                  #endif

                  utility.SelectTU(3);
                  glDisable(GL_TEXTURE_2D);
                  utility.SelectTU(0);
                  glEnable(GL_TEXTURE_2D);

                  glEnable(GL_STENCIL_TEST);
//                trees.Draw();
                  #ifdef PERFORMANCE_PROFILE
                  t2 = GetMicroSeconds();
                  cout << "trees.Draw() ticks: " << t2-t1 << endl;
                  t1 = GetMicroSeconds();
                  #endif
                  objects.Draw(track.GetCullFaces());
                  
                  #ifdef PATCH_DEBUG
                  track.VisualizeRoads(true, false, NULL);
                  #endif
                  
                  #ifdef PERFORMANCE_PROFILE
                  t2 = GetMicroSeconds();
                  cout << "objects.Draw() ticks: " << t2-t1 << endl;
                  t1 = GetMicroSeconds();
                  #endif

                  //glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient );
            }

            if (MP_DBGDEEP)
                  cout << "normal draw done" << endl;

            glDisable(GL_POLYGON_OFFSET_FILL);

            //glClear (GL_DEPTH_BUFFER_BIT);

            #ifdef PERFORMANCE_PROFILE
            t2 = GetMicroSeconds();
            cout << "normal draw done" << t2-t1 << endl;
            t1 = GetMicroSeconds();
            #endif


            //glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glEnable(GL_STENCIL_TEST);
            if (MP_DBGDEEP)
                  cout << "world draw start" << endl;
            world.Draw();
            if (MP_DBGDEEP)
                  cout << "world draw done" << endl;

            if (MP_DBGDEEP)
                  cout << "shadow draw start" << endl;

            /*glEnable(GL_STENCIL_TEST);
            glStencilFunc(GL_EQUAL, 0, ~0);
            glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);*/
            world.DrawShadows();
            glDisable(GL_STENCIL_TEST);

            if (MP_DBGDEEP)
                  cout << "shadow draw done" << endl;

            world.DrawCars();
            
            world.DrawTopLevel();

            #ifdef PATCH_DEBUG
            VERTEX c;
            c.Set(0,1,0);
            if (thepatch != NULL)
                  thepatch->Visualize(true,true,c);
            #endif
            
            //image in the framebuffer is now complete.

            /*//add a brightness/contrast adjustment
            glClear (GL_DEPTH_BUFFER_BIT);
            glLoadIdentity();
            glPushAttrib(GL_ALL_ATTRIB_BITS);
            glDisable(GL_TEXTURE_2D);
            glEnable(GL_BLEND);
            glDisable(GL_FOG);
            glDisable(GL_LIGHTING);
            glTranslatef(0,0,-40.0f);
            glBlendFunc(GL_ONE, GL_SRC_ALPHA);

            float rd = (float) weathersystem.GetRainDrops();

            float rainscale = 0.7f;
            float clearscale = 1.1f;
            float rainbias = 0.035f;
            float clearbias = 0.0f;
            float rainmax = 50.0f;

            float rainfactor = (rd/rainmax);
            if (rainfactor > 1.0f)
                  rainfactor = 1.0f;

            float scale = rainfactor*rainscale+(1.0f-rainfactor)*clearscale;
            float bias = rainfactor*rainbias+(1.0f-rainfactor)*clearbias;

            glColor4f(bias, bias, bias, scale);
            float x1, y1, x2, y2;
            x1 = -30;
            y1 = -30;
            x2 = 30;
            y2 = 30;

            if (scale > 1.0) 
            {
                  float remainingScale;
                  
                  remainingScale = scale;
                  glBlendFunc(GL_DST_COLOR, GL_ONE);
                  if (remainingScale > 2.0) 
                  {
                        glColor4f(1, 1, 1, 1);
                        while (remainingScale > 2.0) 
                        {
                              glRectf(x1,y1,x2,y2);
                              remainingScale /= 2.0;
                        }
                  }
                  glColor4f(remainingScale - 1,
                        remainingScale - 1, remainingScale - 1, 1);
                  glRectf(x1,y1,x2,y2);
                  glBlendFunc(GL_ONE, GL_ONE);
                  if (bias != 0)
                  {
                        if (bias > 0) 
                        {
                              glColor4f(bias, bias, bias, 0.0);
                        } 
                        else 
                        {
                              glColor4f(-bias, -bias, -bias, 0.0);
                              //can't do bias < 0
                        }
                        glRectf(x1,y1,x2,y2);
                  }
            }
            else 
            {
                  if (bias > 0) 
                  {
                        glColor4f(bias, bias, bias, scale);
                  }
                  else 
                  {
                        glColor4f(-bias, -bias, -bias, scale);
                        //can't do bias < 0
                  }
                  glBlendFunc(GL_ONE, GL_SRC_ALPHA);
                  glRectf(x1,y1,x2,y2);
            }

            glPopAttrib();*/

            //timer.Draw();
      }

      if (MP_DBGDEEP)
            cout << "menu draw start" << endl;

      glDisable(GL_STENCIL_TEST);

      if (fps > 0.0f)
            mq1.Draw(timefactor, fps, font);


      if( gui.GetEnabled() )
            gui.Draw();

      #ifdef PERFORMANCE_PROFILE
      t2 = GetMicroSeconds();
      cout << "Brightness/contrast adjustment ticks: " << t2-t1 << endl;
      t1 = GetMicroSeconds();
      #endif

      Frames++;
      frameno++;
      if (frameno >= 30011)
            frameno -= 30011;
      lfps[lfpspos] = pfps;
      lfpspos++;
      if (lfpspos >= AVERAGEFRAMES)
      {
            lfpspos = lfpspos % AVERAGEFRAMES;
            lfpsfull = true;
      }

      int i;

      float tfps = 0.0f;
      int tnum = 0;
      for (i = 0; i < AVERAGEFRAMES; i++)
      {
            if (!(!lfpsfull && i >= lfpspos))
            {
                  tfps += lfps[i];
                  tnum++;
            }
      }
      fps = tfps / (float) tnum;

      /*lfps += pfps;
      {
            //const int freq = (int) MIN_FPS;
            const int freq = 60;
            if (Frames >= freq)
            {
                  fps = lfps / freq;
                  Frames = 0;
                  lfps = 0;
            }
      }*/

      char tempchar[1024];
      sprintf(tempchar, "Frames per second:  %f\n", 
            fps);

      //font.Print(0.5,0,tempchar,0,0,1,1,0);
      if (showfps)
            font.Print( 0.75, 0.0, tempchar, 1, 5, 1.0 );

      #ifdef PERFORMANCE_PROFILE
      t2 = GetMicroSeconds();
      cout << "font.Print() ticks: " << t2-t1 << endl;
      t1 = GetMicroSeconds();
      #endif

      // Draw it to the screen
      SDL_GL_SwapBuffers( );

      GLint t = SDL_GetTicks();
      //if (t - T0 >= 50) 
      {
            GLfloat seconds = (t - T0) / 1000.0;
            pfps = 1 / seconds;
            //printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
            T0 = t;
            //Frames = 0;
      }

      #ifdef PERFORMANCE_PROFILE
      t2 = GetMicroSeconds();
      cout << "SwapBuffers() ticks: " << t2-t1 << endl;
      t1 = GetMicroSeconds();
      cout << endl;
      #endif

      if (MP_DBGDEEP)
            cout << "menu draw done" << endl;

      return( TRUE );
}

// This function returns true if the extension is there.
bool isExtensionSupported(string extstring)
{
      char * temp = (char *) glGetString(GL_EXTENSIONS);
      if (temp == 0)
      {
            cout << "Error getting extensions.  Continuing anyway, errors may follow!" << endl;
            return true;
      }

      string s = temp;
      string::size_type temppos = s.find(extstring);

      bool hasext = (temppos <= s.length());

      if (!hasext)
      {
            cout << "Extension not supported: " << extstring << endl;
      }

      //cout << s << endl;

      return hasext;
}

void ResetWorld(bool fullreset)
{
      if (fullreset)
      {
            SelectCar(state.GetCarName(0), true);
            
            timer.Reset();
      }

      world.reset();
}

int main( int argc, char **argv )
{
      const vector<string> args(argv, argv + argc);
// catch fpe exceptions.
//    feenableexcept(FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW);

      // Flags to pass to SDL_SetVideoMode
      int videoFlags = 0;
      // main loop variable
      int done = FALSE;
      // used to collect events
      SDL_Event event;
      // this holds some info about our display
      const SDL_VideoInfo *videoInfo;
      // whether or not the window is active
      int isActive = TRUE;
      // should we run a benchmark test and then quit?
      bool benchmode = false;

      surface = NULL;

      //load error log
      error_log.open((settings.GetSettingsDir() + "/logs/main.log").c_str());

      //create trig lookups
      //CreateLookupTable();
      
      for (vector<string>::const_iterator i = args.begin(); i != args.end(); ++i)
      {
            if (*i == "-verbose")
                  verbose_output = true;
            if( *i == "-benchmark")
                  benchmode = true;
      }
      
       #ifdef ENABLE_NLS
            
            if (verbose_output)
                  cout << settings.GetLocaleDir () << std::endl;
            
            setlocale (LC_MESSAGES, ""); // only LC_MESSAGES, LC_ALL breaks menus
            bindtextdomain (PACKAGE, (settings.GetLocaleDir ()).c_str ());
            textdomain (PACKAGE);
      #endif

      // parse options file
      settings.ParseOptionFile();

      float sound_volume = 0.5;
      settings.Get( "sound.volume", sound_volume );
      sound.SetMasterVolume( sound_volume );

      mouse.UpdateSettings();
      world.UpdateSettings();
      multiplay.UpdateSettings();
      state.UpdateSettings();
      objects.UpdateSettings();

      for (vector<string>::const_iterator i = args.begin(); i != args.end(); ++i)
      {
            if (*i == "-nosound")
                  sound.DisableAllSound();
      }

/*
      bool setdir = false;
      for (vector<string>::const_iterator i = args.begin(); i != args.end(); ++i)
      {
            if (*i == "-datadir")
                  setdir = true;
            else
            {
                  if (setdir)
                  {
                        string new_data_dir = *i;
                        cout << "Changing data directory to \"" + new_data_dir + "\"..." << endl;
                        settings.SetDefaultDataDir(new_data_dir);
                        cout << "Done. Now re-run vdrift normally." << endl;
                        setdir = false;
                        Quit(0);
                  }
            }
      }
      if( setdir )
      {
            cout << "You must specify a path with the -datadir and option!" << endl;
            Quit(1);
      }

      for (vector<string>::const_iterator i = args.begin(); i != args.end(); ++i)
      {
            if (*i == "-defaultdatadir")
                  setdir = true;
            else
            {
                  if (setdir)
                  {
                        string new_data_dir = *i;
                        cout << "Changing default data directory to \"" + new_data_dir + "\"..." << endl;
                        settings.SetDataDir(new_data_dir);
                        cout << "Done. Now delete your \"~/.vdrift/VDrift.config\" and re-run vdrift normally." << endl;
                        setdir = false;
                        Quit(0);
                  }
            }
      }
      if( setdir )
      {
            cout << "You must specify a path with the -defaultdatadir option!" << endl;
            Quit(1);
      }
*/
      //set frame stats to zero
      Frames = 0;
      T0 = 0;
      fps = 0;
      frameno = 0;

        try
        {

            // initialize SDL
#ifdef DEBUG
            if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0 )
#else
            if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0 )
#endif
            {
                  throw INIT_ERROR(string("SDL initilization failed (") + SDL_GetError() + ")");
            }

            /*
            cout << _c("Run with -verbose for troubleshooting.") << endl;
            cout << _c("Run with -nosound to disable sound.") << endl;
            cout << _c("Run with -datadir /path/to/vdrift/data to change the data directory in your local settings.") << endl;
            cout << _c("Run with -defaultdatadir /path/to/vdrift/data (as root) to change the data directory system-wide.") << endl;
            cout << _c("Note: after running \"vdrift -defaultdatadir ...\" as root, delete your ~/.vdrift/VDrift.config file.") << endl;
            */

            printf("%i joystick(s) found:\n", SDL_NumJoysticks() );
            for(int i=0; i < SDL_NumJoysticks(); i++ ) 
            {
                  printf("    %i. %s\n", i, SDL_JoystickName(i));
            }
            /*SDL_Joystick *joystick;
            SDL_JoystickEventState(SDL_ENABLE);
            joystick = SDL_JoystickOpen(0);
            printf("Joystick 0 opened.\n\n");*/

            SDL_JoystickEventState(SDL_ENABLE);

            gamecontrols.InitJoy();

            SDL_WM_SetCaption(_c("VDrift - open source drift racing simulation - powered by Vamos"), NULL);
            SDL_WM_SetIcon(IMG_Load(settings.GetFullDataPath("textures/small/icons/vdrift-32x32.png").c_str()), NULL);
            SDL_ShowCursor(SDL_DISABLE);

            // Fetch the video info
            videoInfo = SDL_GetVideoInfo( );

            if ( !videoInfo )
            {
                  throw INIT_ERROR(string("Video query failed (") + SDL_GetError() + ")");
            }

            // the flags to pass to SDL_SetVideoMode
            videoFlags  = SDL_OPENGL;          // Enable OpenGL in SDL
            videoFlags |= SDL_GL_DOUBLEBUFFER; // Enable double buffering
            videoFlags |= SDL_HWPALETTE;       // Store the palette in hardware
            videoFlags |= SDL_RESIZABLE;       // Enable window resizing

            // This checks to see if surfaces can be stored in memory
            if ( videoInfo->hw_available )
                  videoFlags |= SDL_HWSURFACE;
            else
                  videoFlags |= SDL_SWSURFACE;

            // This checks if hardware blits can be done
            if( videoInfo->blit_hw )
                  videoFlags |= SDL_HWACCEL;

            // Sets up OpenGL double buffering
            SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
          
            //set up the depth buffer to be 16 bits, this is enough
            SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );

            // set up our screen
            settings.Get( "display.width", cur_screen_w );
            settings.Get( "display.height", cur_screen_h );
            settings.Get( "display.depth", cur_screen_bpp );
            settings.Get( "display.texture_size", cur_tex_size );
            settings.Get( "display.fullscreen", cur_fullscreen );

            if( SDL_VideoModeOK( cur_screen_w, cur_screen_h, cur_screen_bpp, videoFlags ) != 0 )
            {
                  ChangeDisplay( cur_screen_w, cur_screen_h, cur_screen_bpp, cur_fullscreen, true );
            }
            else
            {
                  surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags );
            }

            // Verify there is a surface
            if( !surface )
            {
                  throw INIT_ERROR("Surface creation failed.");
            }

            // initialize OpenGL
            LoadingScreen( "Loading...\nInitializing OpenGL" );
            InitGL();
            LoadingScreen( "Loading...\nInitializing Game Data" );
            InitGameData();

            // resize the initial window
            resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );
            
            gfxcard.BuildCardInfo();
            gfxcard.PrintCardInfo(cout);

            if( !( isExtensionSupported( "GL_ARB_multitexture" ) ) )
            {
                  throw INIT_ERROR("Required OpenGL extensions not present.");
            }
      }
      catch (const INIT_ERROR& e)
      {
            cerr << "Error initilizing VDrift: " << e.what() << "\n";
            Quit(1);
      }

      if( benchmode )
      {
            //run a benchmark and quit
            if( !replay.PlayStart("benchmark") )
            {
                  cout << "Can't find the benchmark replay file (benchmark.vdr)!" << endl;
            }
            
            Quit( 1 );
      }

      // now we have set up a window etc. - we can get video modes now so it's ok to parse the option file
      LoadingScreen( "Loading...\nParsing Dynamic Options" );
      settings.ParseDynamicOptions();

      LoadingScreen( "Loading...\nUser Interface" );
      gui.Init();
      gui.ChangePage( "Main" );

      // enable the user interface
      LoadingScreen( "Loading...\nDone" );
      gui.SetEnabled( true );

      // see if the framerate counter is on
      settings.Get( "display.show_fps", showfps );

      timefactor = 1.0f;
      
      // wait for events
      while( !done )
      {
            // handle the events in the queue

            while( SDL_PollEvent( &event ) )
            {
                  float v;
                  
                  switch( event.type )
                  {
                  case SDL_ACTIVEEVENT:
                        // Something's happend with our focus
                        // If we lost focus or we are iconified, we
                        // shouldn't draw the screen

                        if ( event.active.gain == 0 )
                              isActive = FALSE;
                        else
                              isActive = TRUE;
                        break;                      
                  case SDL_VIDEORESIZE:
                        // handle resize event
                        surface = SDL_SetVideoMode( event.resize.w,
                                          event.resize.h,
                                          16, videoFlags );
                        if ( !surface )
                        {
                              fprintf( stderr, "Could not get a surface after resize: %s\n", SDL_GetError( ) );
                              Quit(1);
                        }
                        resizeWindow( event.resize.w, event.resize.h );
                        break;
                  case SDL_KEYDOWN:
                        // handle key presses
                        if( gui.GetEnabled() )
                              gui.KeyPress( event.key.keysym.sym );
                        handleKeyPress( &event.key.keysym );
                        keyman.KeyDown(event.key.keysym.sym);
                        break;
                  case SDL_KEYUP:
                        if( gui.GetEnabled() )
                              gui.KeyRelease( event.key.keysym.sym );
                        handleKeyRelease( &event.key.keysym );
                        keyman.KeyUp(event.key.keysym.sym);
                        break;
                  case SDL_QUIT:
                        // handle quit requests
                        done = 1;
                        break;
                  case SDL_MOUSEBUTTONDOWN:
                        if( gui.GetEnabled() )
                              gui.MousePress();
                        break;
                  case SDL_MOUSEBUTTONUP:
                        if( gui.GetEnabled() )
                              gui.MouseRelease();
                        break;
                  case SDL_JOYBUTTONDOWN:
                        if( gui.GetEnabled() )
                              gui.JoyPress( event.jbutton.which, event.jbutton.button );
                        //if (timefactor == 0.0f && !menu.InMenu())
                        //if (timefactor == 0.0f && state.GetGameState() != STATE_MENU)
                        if (timefactor == 0.0f && !gui.GetEnabled())
                              MainUnpause();
                        // TODO: replace this functionality in Gui
                        //menu.AssignJoyButton(event.jbutton.which, event.jbutton.button);
                        break;
                  case SDL_JOYBUTTONUP:
                        if( gui.GetEnabled() )
                              gui.JoyRelease( event.jbutton.which, event.jbutton.button );
                        break;
                  case SDL_JOYAXISMOTION:
                        v = event.jaxis.value / 32768.0f;
                        if( /*( v > 0.1 || v < -0.1 ) &&*/ gui.GetEnabled() )
                              gui.JoyMove( event.jaxis.which, event.jaxis.axis, v );
                        // TODO: replace this functionality in Gui
                              //menu.AssignJoyAxis(event.jaxis.which, event.jaxis.axis, v);
                        break;
                  default:
                        break;
                  }
            }

            if( gui.GetEnabled() )
                  gui.JoyUpdate();

            // do the game logic & draw the screen
            //if ( isActive )
            {
                  Update();
                  if (MP_DBGDEEP)
                        cout << "main draw start" << endl;
                  drawGLScene( );
                  if (MP_DBGDEEP)
                        cout << "main draw done" << endl;
            }
      }
      
      gamecontrols.DeinitJoy();
      
      Quit(0);
      return 0; // never executed
}

Generated by  Doxygen 1.6.0   Back to index