OutRun/src/main.cc

694 lines
25 KiB
C++

#include <gint/display.h>
#include <gint/drivers/r61524.h>
#include <gint/keyboard.h>
#include <gint/gint.h>
#include <gint/defs/types.h>
#include <fxlibc/printf.h>
#include <libprof.h>
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <math.h>
#include <vector>
#include "parameters.h"
#include "colors.h"
#include "include/camera.h"
#include "include/segment.h"
#include "include/circuit.h"
#include "include/drawstuff.h"
#include "include/clouds.h"
#include "include/cars.h"
#include "include/menus.h"
//extern bopti_image_t car1, car2, car3, car4, car5, car6, car7, car8;
//extern bopti_image_t tree1, tree2, tree3, tree4, tree5, tree6;
//extern bopti_image_t leftturn, rightturn, uphill, downhill;
//extern bopti_image_t checkpoint, startlights, stoplights, waitlights;
extern bopti_image_t player;
//extern bopti_image_t sky1, sky2, sky3;
//extern bopti_image_t mountain, treeline;
//extern bopti_image_t mainscreen;
extern font_t speedfont;
extern bopti_image_t speedhud;
int CurrentCircuitBiome = PLAINS;
std::vector<Segment*> circuit;
int MAX_SEGMENT=0;
camera *cam;
std::vector<Clouds*> nuages;
std::vector<Cars*> traffic;
bool stop = false;
bool record = false;
bool screenshot = false;
bool ShowDebug1 = false;
bool ShowDebug2 = false;
bool ShowDebug3 = false;
bool BDrawDeco = true;
bool BDrawClds = true;
bool BDrawCars = true;
bool BDrawRoad = true;
uint16_t currentcurve=0;
uint8_t shiftcolor=0;
float speed = 0.0;
float maxspeedforward = 5.0;
float maxspeedbackward = 2.0;
int direction = 1;
bool speedcontrol = false;
uint8_t minYRoad = 224; // We will track the upper Y (in fact the minimum Y during the RoadDrawing to optimize the rendering of the Sky
int8_t viewside = 0;
int deltaFarbackground = 0;
int deltaNearbackground = 0;
int lastindex=0;
int CC=0; // current curve
int CS=0;
static void get_inputs( float dt, int index )
{
CC = circuit[index]->Curve;
CS = circuit[index]->Slope;
key_event_t ev;
while((ev = pollevent()).type != KEYEV_NONE)
{
}
speedcontrol = false;
viewside=0;
if (CC<0)
{
viewside=-1;
cam->decX( CC*dt*speed/100 );
}
else if (CC>0)
{
viewside=+1;
cam->decX( CC*dt*speed/100 );
}
if(keydown(KEY_LEFT))
{
cam->decX(25.0);
viewside=-1;
if (CC<0) viewside=-2; // We are in a curve and turning
if (CC>0) viewside=0;
}
if(keydown(KEY_RIGHT))
{
cam->incX(25.0);
viewside=1;
if (CC>0) viewside=+2;
if (CC<0) viewside=0;
}
if(keydown(KEY_SHIFT))
{
if (direction==-1 && speed > 0)
{
direction = -1;
speed -= 0.5;
if (speed<0) speed=0;
cam->decZ(speed*dt);
}
else
{
direction = 1;
speed+=0.05;
if (speed>maxspeedforward) speed=maxspeedforward;
cam->incZ(speed*dt);
}
speedcontrol = true;
}
if(keydown(KEY_ALPHA))
{
if (direction==1 && speed > 0)
{
direction = 1;
speed -= 0.5;
if (speed<0) speed=0;
cam->incZ(speed*dt);
}
else
{
direction = -1;
speed+=0.025;
if (speed>maxspeedbackward) speed=maxspeedbackward;
cam->decZ(speed*dt);
}
speedcontrol = true;
}
if(keydown(KEY_EXIT)) stop = true;
#if IS_FXLIB==1
if(keydown(KEY_XOT))
{
ShowDebug1 = false;
ShowDebug2 = false;
ShowDebug3 = false;
}
if(keydown(KEY_LOG))
{
ShowDebug1 = true;
ShowDebug2 = false;
ShowDebug3 = false;
}
if(keydown(KEY_LN))
{
ShowDebug1 = false;
ShowDebug2 = true;
ShowDebug3 = false;
}
if(keydown(KEY_SIN))
{
ShowDebug1 = false;
ShowDebug2 = false;
ShowDebug3 = true;
}
if(keydown(KEY_F1)) BDrawDeco = !BDrawDeco;
if(keydown(KEY_F2)) BDrawClds = !BDrawClds;
if(keydown(KEY_F3)) BDrawCars = !BDrawCars;
if(keydown(KEY_F4)) BDrawRoad = !BDrawRoad;
if(keydown(KEY_F5)) screenshot = true;
if(keydown(KEY_F6)) record = !record;
#endif // IS_FXLIB
if (speedcontrol==false)
{
speed-=0.3;
if (speed<0) speed=0;
if (direction==1)
cam->incZ(speed*dt);
else
cam->decZ(speed*dt);
}
/* Adjust position of the background */
if (lastindex!=index)
{
deltaFarbackground -= CC*speed*dt/250;
deltaNearbackground -= CC*speed*dt/100;
}
lastindex = index;
/* adjust speed if we drive on the side of the road */
if (fround(cam->cX)<-1*ROAD_WIDTH && speed>2.0) speed=2.0;
if (fround(cam->cX)>ROAD_WIDTH && speed>2.0) speed=2.0;
if (fround(cam->cX)<-1.35*ROAD_WIDTH && speed>0.0)
{
speed=0.0;
cam->cX=fix(-0.75*ROAD_WIDTH);
}
if (fround(cam->cX)>1.35*ROAD_WIDTH && speed>0.0)
{
speed=0.0;
cam->cX=fix(0.75*ROAD_WIDTH);
}
}
int main(void)
{
__printf_enable_fp();
__printf_enable_fixed();
#if IS_FXLIB==1
usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL };
usb_open(interfaces, GINT_CALL_NULL);
#endif
prof_t perf_update, perf_create, perf_project, perf_render;
int32_t start_time = 99000000;
uint32_t score=99999;
uint8_t stage=0;
uint8_t selectedCircuit=0;
uint32_t time_update=0, time_create=0, time_project=0, time_render=0;
prof_init();
drawStartTitle();
bool exitflag = false;
do
{
exitflag = false;
stage = drawMainMenu();
if (stage==0 || stage==1)
{
selectedCircuit = drawMenuCircuitSelect();
if (selectedCircuit != -1) exitflag=true;
}
else if (stage==3)
{
drawCredit();
}
}
while (!exitflag);
stage = selectedCircuit;
if (selectedCircuit==0) CurrentCircuitBiome = PLAINS;
else if (selectedCircuit==1) CurrentCircuitBiome = DESERT;
else if (selectedCircuit==2) CurrentCircuitBiome = USA;
else if (selectedCircuit==3) CurrentCircuitBiome = FINLAND;
else if (selectedCircuit==4) CurrentCircuitBiome = AFRICA;
else if (selectedCircuit==5) CurrentCircuitBiome = PLAINS;
else if (selectedCircuit==6) CurrentCircuitBiome = DESERT;
else if (selectedCircuit==7) CurrentCircuitBiome = USA;
else if (selectedCircuit==8) CurrentCircuitBiome = FINLAND;
else if (selectedCircuit==9) CurrentCircuitBiome = AFRICA;
else CurrentCircuitBiome = PLAINS;
int nbInterestingSegments = (MAX_RENDER_DISTANCE / SEGMENT_LENGTH); // the number of segments to be projected considering the rendering distance
perf_create = prof_make();
prof_enter(perf_create);
initData( ); // Positioning of the Camera
createCircuit(); // Creates the circuit
putBillBoards();
createClouds(); // Creates the Sky and Clouds
createTraffic(); // Creates the cas
prepareDecoration( CurrentCircuitBiome ); // Prepares the multiple variations of Decoration (image scaling)
prepareTraffic(); // Prepares the multiple variations of Cars (image scaling)
prof_leave(perf_create);
time_create = prof_time(perf_create);
//--------------
MAX_SEGMENT = circuit.size();
int indexstart = 0;
int indexend = 0;
uint32_t maxDistance = (MAX_SEGMENT-nbInterestingSegments-5)*SEGMENT_LENGTH;
uint32_t dt=0;
uint16_t l=0;
uint32_t remaining_time;
while (!stop)
{
perf_update = prof_make();
prof_enter(perf_update);
get_inputs( dt, indexstart );
dt = ((float) (time_update+time_render+time_project) / 1000.0);
start_time -= (time_update+time_render+time_project);
if (start_time<0) start_time=0;
remaining_time = ((float) (start_time) / 1000000.0);
//--------------
if (fround(cam->cZ)<=0) cam->cZ=fixdouble(0.0);
if (fround(cam->cZ)>=maxDistance) cam->cZ=fixdouble(maxDistance);
indexstart = fround(cam->cZ) / SEGMENT_LENGTH;
if (indexstart<0) indexstart=0;
indexend = indexstart+nbInterestingSegments+1;
if (indexstart>MAX_SEGMENT-nbInterestingSegments-2) indexstart=MAX_SEGMENT-nbInterestingSegments-2;
prof_leave(perf_update);
time_update = prof_time(perf_update);
//--------------
perf_project = prof_make();
prof_enter(perf_project);
if (BDrawCars)
{
updateTraffic( dt, maxDistance );
for (int k=0; k<traffic.size(); k++) // Need to project 1 more segment than actual drawing
{
uint16_t CarSegment = traffic[k]->wZ / SEGMENT_LENGTH;
if (CarSegment>=indexstart && CarSegment<indexend)
{
//traffic[k]->visible = true;
circuit[CarSegment]->CarList.push_back(k);
}
//else
//traffic[k]->visible = false;
}
}
minYRoad = SCREEN_HEIGHT;
float roadpart = f2float(cam->cX)/(float) ROAD_WIDTH;
// Update car positions : car with higher speed change line not to collide with player
if (BDrawCars)
for( int l=0; l<circuit[indexstart]->CarList.size(); l++ ) // For all cars inside that road segment
{
uint8_t indexCar = circuit[indexstart]->CarList[l];
if (traffic[indexCar]->wX>(roadpart-0.25f) && traffic[indexCar]->wX<(roadpart+0.25f) && traffic[indexCar]->Speed>speed)
{
if (traffic[indexCar]->wX>-0.25) traffic[indexCar]->wX-=0.5; // if we are on one of the most right lanes, we overtake by the left
else traffic[indexCar]->wX=-0.25; // else we change to the lane on the right
}
}
if (BDrawCars)
for( int l=0; l<circuit[indexstart+1]->CarList.size(); l++ ) // For all cars inside that road segment
{
uint8_t indexCar = circuit[indexstart+1]->CarList[l];
if (traffic[indexCar]->wX>(roadpart-0.15f) && traffic[indexCar]->wX<(roadpart+0.15f) && traffic[indexCar]->Speed<speed)
{
speed = 2.0;
}
}
uint16_t cumulCurve=0;
for (int k=indexstart; k<=indexend; k++) // Need to project 1 more segment than actual drawing
{
projectCircuitFP( k ); // We project the current segment
if (circuit[k]->Y < minYRoad) // This is a trick to save precious time while drawing the Sky
minYRoad = circuit[k]->Y;
circuit[k]->CumulatedCurve = cumulCurve; // This is the curve accumulated when we are drawing curves
cumulCurve += circuit[k]->Curve;
if (BDrawCars)
for( int l=0; l<circuit[k]->CarList.size(); l++ ) // For all cars inside that road segment
{
uint8_t indexCar = circuit[k]->CarList[l];
traffic[indexCar]->Project3DFP( cam, k );
}
}
prof_leave(perf_project);
time_project = prof_time(perf_project);
//--------------
perf_render = prof_make();
prof_enter(perf_render);
drawSky( DAY_BLUE_SKY );
if (BDrawClds)
drawClouds( l % 396 );
drawFarBackground( deltaFarbackground );
drawNearBackground( deltaNearbackground );
cam->cY = fix( 300+2*CS ) + interpolatePositionY(fround(cam->cZ) );
for( int k=indexend-1; k>=indexstart; k--)
{
currentcurve = circuit[k]->CumulatedCurve;
if (BDrawRoad)
drawCircuitSegment( k );
if (BDrawDeco)
drawDecoration( k );
if (BDrawCars)
for( int l=0; l<circuit[k]->CarList.size(); l++ ) // For all cars inside that road segment
{
uint8_t indexCar = circuit[k]->CarList[l];
drawTraffic( indexCar );
}
circuit[k]->CarList.clear();
}
int mod_base=20;
int mod_comp=10;
if (abs(speed)<1.0) mod_base = 30, mod_comp = 15;
else if (abs(speed)<2.0) mod_base = 20, mod_comp = 10;
else if (abs(speed)<3.0) mod_base = 16, mod_comp = 8;
else if (abs(speed)<4.0) mod_base = 12, mod_comp = 6;
else if (abs(speed)<5.0) mod_base = 8, mod_comp = 4;
else mod_base = 4, mod_comp = 2;
if ((speed==0) || (l%mod_base<=mod_comp)) // the small rick to have the speed impression on wheels and to have the correct view of the car during turns
{
if (viewside==-2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 99,1,80,46, DIMAGE_NONE);
else if (viewside==-1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 181,1,74,46, DIMAGE_NONE);
else if (viewside==0) dsubimage( SCREEN_CX-36, SCREEN_HEIGHT-46, &player, 257,1,72,46, DIMAGE_NONE);
else if (viewside==1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 331,1,74,46, DIMAGE_NONE);
else if (viewside==2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 407,1,80,46, DIMAGE_NONE);
}
else
{
if (viewside==-2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 99,49,80,46, DIMAGE_NONE);
else if (viewside==-1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 181,49,74,46, DIMAGE_NONE);
else if (viewside==0) dsubimage( SCREEN_CX-36, SCREEN_HEIGHT-46, &player, 257,49,72,46, DIMAGE_NONE);
else if (viewside==1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 331,49,74,46, DIMAGE_NONE);
else if (viewside==2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 407,49,80,46, DIMAGE_NONE);
}
score = fround(cam->cZ)/100;
//dprint( 1, 1, C_BLACK, "Crt=%.3D ms", time_create );
//dprint( 1, 15, C_RED, "Prj=%.3D ms", time_project );
//dprint( 1, 30, C_RED, "Rdr=%.3D ms", time_render );
//dprint( 1, 45, C_RED, "Upd=%.3D ms", time_update );
//dprint( 1, 1, C_BLACK, "Dt=%.3D ms", dt );
float drawspeed = (float) (speed*5.0f);
dsubimage( 5, 5, &speedhud, 0, 117, 37, 13, DIMAGE_NONE); // speed logo
dsubimage( 135, 5, &speedhud, 0, 130, 37, 13, DIMAGE_NONE); // timer logo
dsubimage( 245, 5, &speedhud, 37, 117, 38, 13, DIMAGE_NONE); // speed logo
dsubimage( 245, 25, &speedhud, 37, 130, 38, 13, DIMAGE_NONE); // timer logo
dfont(&speedfont);
if (drawspeed==0.0)
{
dprint_opt(122,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "0 :", drawspeed );
dprint_opt(120,1, C_RGB(255,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "0 :", drawspeed );
}
else
{
dprint_opt(122,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.1f :", drawspeed );
dprint_opt(120,1, C_RGB(255,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.1f :", drawspeed ); //the ':' char corresponds to "Km/h"
}
dprint_opt(233,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", remaining_time );
dprint_opt(230,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", remaining_time ); // the ';' char corresponds to "s"
dprint_opt(390,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", score );
dprint_opt(388,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", score ); // the ';' char corresponds to "s"
dprint_opt(390,23, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", stage );
dprint_opt(388,21, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", stage ); // the ';' char corresponds to "s"
if (drawspeed==0.0) dsubimage( 48, 25, &speedhud, 0, 0, 76, 13, DIMAGE_NONE);
else if (drawspeed<3.30) dsubimage( 48, 25, &speedhud, 0, 13, 76, 13, DIMAGE_NONE);
else if (drawspeed<6.70) dsubimage( 48, 25, &speedhud, 0, 26, 76, 13, DIMAGE_NONE);
else if (drawspeed<10.0) dsubimage( 48, 25, &speedhud, 0, 39, 76, 13, DIMAGE_NONE);
else if (drawspeed<13.3) dsubimage( 48, 25, &speedhud, 0, 52, 76, 13, DIMAGE_NONE);
else if (drawspeed<16.7) dsubimage( 48, 25, &speedhud, 0, 65, 76, 13, DIMAGE_NONE);
else if (drawspeed<20.0) dsubimage( 48, 25, &speedhud, 0, 78, 76, 13, DIMAGE_NONE);
else if (drawspeed<23.3) dsubimage( 48, 25, &speedhud, 0, 91, 76, 13, DIMAGE_NONE);
else dsubimage( 48, 25, &speedhud, 0, 104, 76, 13, DIMAGE_NONE);
//dprint( 1, 1, C_BLACK, "FPS=%.3D ms", 1000/dt );
/*
#if 0
dprint( 1, 210, C_WHITE, "Decs: %c", BDrawDeco==true?'Y':'N' ); // Key F1
dprint( 67, 210, C_WHITE, "Clds: %c", BDrawClds==true?'Y':'N' ); // Key F2
dprint( 133, 210, C_WHITE, "Cars: %c", BDrawCars==true?'Y':'N' ); // Key F3
dprint( 199, 210, C_WHITE, "DtR: %.1f", ((float) (time_render) / 1000.0) ); // Key F4
dprint( 265, 210, C_WHITE, "ScrSht" ); // Key F5
dprint( 331, 210, C_WHITE, "RecVid" ); // Key F6
#endif // 1
#if 0
if (ShowDebug1)
{
Segment* currentSeg = circuit[indexstart];
dprint( 1, 1, C_RED, "Crt=%.3D ms", time_create );
dprint( 1, 15, C_RED, "Prj=%.3D ms", time_project );
dprint( 1, 29, C_RED, "Rdr=%.3D ms", time_render );
dprint( 1, 55, C_WHITE, "It=%d", l);
dprint( 1, 69, C_GREEN, "St=%d ", indexstart );
dprint( 1, 83, C_GREEN, "En=%d", indexend );
dprint( 1, 97, C_RED, "Sz= %d", circuit.size() );
dprint( 100, 55, C_WHITE, "SzSgmt=%d bytes", sizeof(Segment) );
dprint( 100, 69, C_WHITE, ">XYZc=(%d,%d,%.0lf,%d)", circuit[indexstart]->wX, circuit[indexstart]->wY, circuit[indexstart]->wZ, circuit[indexstart]->Curve );
dprint( 100, 83, C_WHITE, ">XYZc=(%d,%d,%.0lf,%d)", circuit[indexend]->wX, circuit[indexend]->wY, circuit[indexend]->wZ, circuit[indexstart]->Curve );
dprint( 100, 97, C_WHITE, "C[i]Adr= %p", &currentSeg),
dprint( 320, 1, C_WHITE, "CamX=%d", fround( cam->cX ) );
dprint( 320, 15, C_WHITE, "CamY=%d", fround( cam->cY ) );
dprint( 320, 29, C_WHITE, "CamZ=%d", fround( cam->cZ ) );
dprint( 320, 55, C_WHITE, "Dir=%d", direction );
dprint( 320, 69, C_WHITE, "Spd=%.1f", speed );
dprint( 320, 83, C_WHITE, "Dz =%.1f", speed*dt );
dprint( 320, 97, C_WHITE, "dt =%.3D ms", dt );
}
if (ShowDebug2)
{
#if 0
dprint( 1, 1, C_RED, "Crt=%.3D ms", time_create );
dprint( 1, 15, C_RED, "Prj=%.3D ms", time_project );
dprint( 1, 29, C_RED, "Rdr=%.3D ms", time_render );
dprint( 1, 50, C_BLACK, "ISt_Z=%.1lf", circuit[indexstart]->wZ);
dprint( 1, 65, C_BLACK, "IEd_Z=%.1lf", circuit[indexend]->wZ);
for( int k=indexend-1; k>=indexstart; k--)
{
dprint( 100, 1+10*k-indexstart, C_WHITE, "S[%d]=%d", k, circuit[k]->DScale );
}
for( int k=0; k<nuages.size(); k++)
{
dprint( 250, 1+10*k, C_WHITE, "Cl[%d]=(%d,%d,%d)", k, nuages[k]->X, nuages[k]->Y, nuages[k]->type );
}
#endif // 0
for( int k=0; k<traffic.size(); k++)
{
if (traffic[k]->visible == true) dprint( 1, 1+10*k, C_GREEN, "Car %d Sc=%d wZ=%.0lf / Seg=%d X=%d Y=%d", k, traffic[k]->DScale, traffic[k]->wZ, traffic[k]->segnum, traffic[k]->X, traffic[k]->Y, traffic[k]->S );
else dprint( 1, 1+10*k, C_RED, "Car %d Sc=%d wZ=%.0lf / Seg=%d X=%d Y=%d", k, traffic[k]->DScale, traffic[k]->wZ, traffic[k]->segnum, traffic[k]->X, traffic[k]->Y, traffic[k]->S );
}
}
if (ShowDebug3)
{
dprint( 1, 1, C_BLACK, "S");
for( int k=0; k<=indexend-indexstart; k++)
{
int nbCars=circuit[indexstart+k]->CarList.size();
dprint( 25+k*25, 1, C_BLACK, "%d", indexstart+k );
dprint( 25+k*25, 11, C_RED, "%d", nbCars );
for( int l=0; l<nbCars; l++ ) // For all cars inside that road segment
{
dprint( 1, 33+10*l, C_BLACK, "C" );
dprint( 25+k*25, 33+10*l, C_BLACK, "%d", circuit[indexstart+k]->CarList[l]);
}
}
}
#endif
*/
/*
for( int k=indexend-1; k>=indexstart; k--)
{
circuit[k]->CarList.clear();
}
*/
//dupdate();
r61524_display(gint_vram, 0, DHEIGHT, R61524_DMA_WAIT);
prof_leave(perf_render);
time_render = prof_time(perf_render);
#if IS_FXLIB==1
if (screenshot && usb_is_open())
{
usb_fxlink_screenshot(false);
screenshot = false;
}
if(record && usb_is_open())
{
usb_fxlink_videocapture(false);
}
#endif
l++;
}
prof_quit();
#if IS_FXLIB==1
usb_close();
#endif
circuit.clear();
nuages.clear();
delete cam;
freeDecoration();
freeTraffic();
return 1;
}