Module: rscene.cpp

class RScene
.h

constructorRScene()
destructor~RScene()
Resetvoid Reset()

Prepare for filling information into this scene

RemoveCarsvoid RemoveCars()
AddCarbool AddCar(RCar *newCar)
SetTrackvoid SetTrack(RTrack *trk)

Set a track (mostly a derived class of RTrack)

SetViewvoid SetView(int x,int y,int wid,int hgt)

Set scene viewport (in the current graphics context)

SetDefaultStatevoid SetDefaultState()

Set some OpenGL state variable that we like to use as a default

Clearvoid Clear()

Do a default clear of the view
Note this may be skipped if you know you're going to paint all over the viewport

Paintvoid Paint()

Paint track & cars

TimeLineCrossedvoid TimeLineCrossed(RCar *car)

A car has crossed its current timeline (checkpoint).
Adjust statistics for this car.

GetCurrentLapTimeint GetCurrentLapTime(RCar *car)

Returns live current lap time for the car
This is updated as the car is driving the lap

GetBestLapTimeint GetBestLapTime(RCar *car)

Returns best lap time for the car, or 0 for none.



/*
 * RScene - a scene contains the track and vehicles
 * 05-10-00: Created!
 * BUGS:
 * - Doesn't keep a bound for the #laps (lapTime[])
 * (c) Dolphinity/Ruud van Gaal
 */

#include <racer/racer.h>
#include <qlib/debug.h>
#pragma hdrstop
DEBUG_ENABLE

#undef  DBG_CLASS
#define DBG_CLASS "RScene"

RScene::RScene()
{
  DBG_C("ctor")

  int i;

  env=0;
  track=0;
  cars=0;
}

RScene::~RScene()
{
  DBG_C("dtor")

  int i;

  // Track is deleted by RMGR, don't delete here
  if(env)delete env;
  //if(track)delete track;
  RemoveCars();
}

/********
* Reset *
********/
void RScene::Reset()
// Prepare for filling information into this scene
{
  int i,j;
  
  RemoveCars();
  // Reset timing statistics
  for(i=0;i<MAX_CAR;i++)
  {
    curTimeLine[i]=0;
    bestLapTime[i]=0;
    for(j=0;j<MAX_LAP;j++)
    {
      lapTime[i][j]=0;
    }
    for(j=0;j<RTrackVRML::MAX_TIMELINE;j++)
    {
      tlTime[i][j]=0;
    }
    // No lap started yet
    curLap[i]=-1;
  }
}

/*******
* CARS *
*******/
void RScene::RemoveCars()
{
  int i;
  for(i=0;i<cars;i++)
    if(car[i])
    { delete car[i];
      car[i]=0;
    }
  cars=0;
}
bool RScene::AddCar(RCar *newCar)
{
  DBG_C("AddCar")
  DBG_ARG_P(newCar)

  if(cars==MAX_CAR)
  { qwarn("Too many cars in scene");
    return FALSE;
  }
  car[cars]=newCar;
  // Make sure the car knows its place in the scene
  car[cars]->SetIndex(cars);
  cars++;
  return TRUE;
}

/********
* TRACK *
********/
void RScene::SetTrack(RTrack *trk)
// Set a track (mostly a derived class of RTrack)
{
  DBG_C("SetTrack")
  DBG_ARG_P(trk)

  track=trk;
}

/***********
* Painting *
***********/
void RScene::SetView(int x,int y,int wid,int hgt)
// Set scene viewport (in the current graphics context)
{
  DBG_C("SetView")
  DBG_ARG_I(x)
  DBG_ARG_I(y)
  DBG_ARG_I(wid)
  DBG_ARG_I(hgt)

  glViewport(x,y,wid,hgt);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(65.0,(GLfloat)wid/(GLfloat)hgt,1.0,1000.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void RScene::SetDefaultState()
// Set some OpenGL state variable that we like to use as a default
{
  glClearColor(.2,.3,.4,0);
  glEnable(GL_CULL_FACE);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_DEPTH_TEST);
  glShadeModel(GL_FLAT);
}

void RScene::Clear()
// Do a default clear of the view
// Note this may be skipped if you know you're going to paint all over the viewport
{
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
}
void RScene::Paint()
// Paint track & cars
{
  DBG_C("Paint")

  int i;

#ifdef OBS
  {
    static int roll;
    glRotatef(roll,0,1,0);
    roll++;
  }
#endif

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  
  if(track)
    track->Paint();
  for(i=0;i<MAX_CAR;i++)
  {
    if(car[i])
      car[i]->Paint();
  }
}

/********************
* Timing statistics *
********************/
void RScene::TimeLineCrossed(RCar *car)
// A car has crossed its current timeline (checkpoint).
// Adjust statistics for this car.
{
  int i,n=car->GetIndex();
  int lap;
  
  // Check for bad tracks
  if(!track->GetTimeLines())return;
  
  // Store intermediate time
  if(curTimeLine[n]==0)
  {
    // Start/finish!
    if(curLap[n]==-1)
    {
      // Just starting the first lap
      curLap[n]++;
      // Store lap start time in lap time variable
      lapTime[n][0]=RMGR->time->GetSimTime();
    } else
    {
      // Finished a lap
      lap=curLap[n];
      // The start time of this lap was stored in curLapTime[...]
      lapTime[n][lap]=RMGR->time->GetSimTime()-lapTime[n][lap];
      if(bestLapTime[n]==0||lapTime[n][lap]<bestLapTime[n])
      {
        // You've got a best lap!
        bestLapTime[n]=lapTime[n][lap];
      }
      // Store start time of next lap
      lapTime[n][lap+1]=RMGR->time->GetSimTime();
      // Reset intermediate times
      for(i=0;i<RTrack::MAX_TIMELINE;i++)
      {
        tlTime[n][i]=0;
      }
      curLap[n]++;
    }
  }
  
  // Switch to next checkpoint timeline
  curTimeLine[n]=(curTimeLine[n]+1)%track->GetTimeLines();
}
int RScene::GetCurrentLapTime(RCar *car)
// Returns live current lap time for the car
// This is updated as the car is driving the lap
{
  int n=car->GetIndex();
  
  // Doing a lap already?
  if(curLap[n]==-1)return 0;
  // Calculate the time the car is busy in the current lap
  return RMGR->time->GetSimTime()-lapTime[n][curLap[n]];
}
int RScene::GetBestLapTime(RCar *car)
// Returns best lap time for the car, or 0 for none.
{
  return bestLapTime[car->GetIndex()];
}