/*
Copyright (C) 2007-2010 Victor Matei Petrescu

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <SDL.h>
#include <ode/ode.h>
#include <time.h>
#include "config.h"

#ifdef DREAMCAST
#include <kos.h>
#include <arch/exec.h>
#include <SDL/SDL_dreamcast.h>
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#endif

#ifdef MENU
#include "menu.h"
#endif

#if CLBITS==16
  #include "render16.h"
#elif CLBITS==24
  #include "render32.h"
#elif CLBITS==32
  #include "render32.h"
#endif

#include "defstr.h"
#include "trans.h"
#include "camera.h"
#include "readfile.h"
#include "game.h"

void play(SDL_Surface *screen, SDL_Event event);
void finish(void);
void printstats(void);

REALN tframe=0,xan=0,/*tframe-time necessary for display; xan-number of displayed images*/
      timp,dstr; /*total time, distance traveled*/
	  
int quit=0;

int main(int argc,char *argv[])
{

#ifdef DREAMCAST
printf("Starting...\n");
fs_chdir("/rd");
#endif

SDL_Event event;
SDL_Surface *screen;

/*Initialize SDL*/
#ifdef DREAMCAST
//SDL_DC_SetVideoDriver(SDL_DC_DIRECT_VIDEO);
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_JOYSTICK)<0){printf("Couldn't initialize SDL: %s\n", SDL_GetError());SDL_Quit();return 0;}
#else
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)<0){printf("Couldn't initialize SDL: %s\n", SDL_GetError());SDL_Quit();return 0;}
#endif

/*Set video mode*/
screen=SDL_SetVideoMode(SCREENWIDTH,SCREENHEIGHT,CLBITS,SDLSCREENFLAG);
if(screen == NULL){printf("Couldn't set requested video mode: %s\n",SDL_GetError());SDL_Quit();return 0;}
printf("Set %dx%dx%d\n",(screen->pitch)/(screen->format->BytesPerPixel),SCREENHEIGHT,screen->format->BitsPerPixel);

/*Set window title*/
#ifndef DREAMCAST
SDL_WM_SetCaption("Skunks-2.0.0", "Skunks-2.0.0");
#endif
/* Enable Unicode translation */
SDL_EnableUNICODE(1);
/*SDL initialized*/

/* Open Joystick (DREAMCAST) */
#ifdef DREAMCAST
SDL_Joystick *joystick;
SDL_DC_MapKey(0,SDL_DC_START,SDLK_RETURN);
SDL_DC_MapKey(0,SDL_DC_UP,SDLK_UP);
SDL_DC_MapKey(0,SDL_DC_DOWN,SDLK_DOWN);
SDL_DC_MapKey(0,SDL_DC_LEFT,SDLK_LEFT); 
SDL_DC_MapKey(0,SDL_DC_RIGHT,SDLK_RIGHT);
SDL_DC_MapKey(0,SDL_DC_A,SDLK_n);
SDL_DC_MapKey(0,SDL_DC_B,SDLK_r); //B:reverse
SDL_DC_MapKey(0,SDL_DC_Y,SDLK_m);
SDL_DC_MapKey(0,SDL_DC_X,SDLK_c);  //Y:camera
SDL_DC_MapKey(0,SDL_DC_R,SDLK_ESCAPE); //L:exits

SDL_JoystickEventState(SDL_ENABLE);
joystick = SDL_JoystickOpen(0); 	
SDL_ShowCursor(0);

//Dreamcast delay...
SDL_Delay(20);
while(SDL_PollEvent(&event))
	SDL_Delay(20);
#endif

/*ODE and World Init*/
printf("Loading ODE... ");
dInitODE();
printf("done!\n");
printf("ODE Config: %s\n", dGetConfiguration());
wglob=dWorldCreate();
/*World settings*/
dWorldSetERP(wglob,0.2);
dWorldSetCFM(wglob,1e-5);
dWorldSetGravity(wglob,GRAVITY,0,0);

#ifdef MENU
initTTF();
int end = do_menu(screen);
while (end==1){ //if a user executes this as only binary... do loop
	quit = 0; //reset exit value
	play(screen, event);
	//Reload game?
	#ifdef DREAMCAST
		printstats();
		//malloc_stats();
		void *blob;
		ssize_t length = fs_load("/cd/skunks.bin", &blob);
		if (length > 0) arch_exec(blob, length);
	#endif
	end = do_menu(screen);
}
finish();
#else
play();
printstats();
finish();
#endif

return 0;
}

void play(SDL_Surface *screen, SDL_Event event)
{

sgob *objs,camera; /*objects*/
int nob,nto,camflag=2; /*number of objects and of object types*/

char numefis[MAXWLG];
int i, t0frame; /*t0frame - moment when image starts to be displayed*/

pixcol backcol; /*culoarea fundalului*/
REALN  zfog,zmax; /*zfog,zmax - distanta de la care incepe ceatza, respectiv de la care nu se mai vede nimic*/

camflag=2; /*number of objects and of object types*/

vhc car; /*vehicle*/

tframe=0,xan=0;/*tframe-time necessary for display; xan-number of displayed images*/

/*for game*/
REALN vrx,vrxmax,vrxmr, /*rot. speed*/
      arx,arxmax,arxmr, /*rot. acceleration*/
      vrot3, /*rot. speed of level 3 objects*/
      vrotc,vrcmax,rotc, /*rot. speed and rotation of camera*/
      realstep, /*real time step (s)*/
      speed,rotspeed,
      af=0,bf=0; /*acceleration and brake factors*/
int turn, /*-1: left; 0: no turn; 1: right*/
    dmode, /*1 forward, -1 reverse*/
    nstepsf; /*number of simulation steps/frame*/
REALN volum[6]={0,0,0,0,0,0};
/*for game^*/


zfog=40;
zmax=120; /*visibility (m)*/

camera.vx[0]=0; camera.vy[0]=0; camera.vz[0]=0;
camera.vx[1]=1; camera.vy[1]=0; camera.vz[1]=0;
camera.vx[2]=0; camera.vy[2]=1; camera.vz[2]=0;
camera.vx[3]=0; camera.vy[3]=0; camera.vz[3]=1; /*set camera parameters*/

/* Get MENU or argv values!!!! */
#ifdef MENU
	sprintf(numefis, "tracks/track%i", selected_track);
	objs=readtrack(numefis,&nob,&nto,&backcol); /*read objects from file*/
	sprintf(numefis, "cars/car%i", selected_car);
	objs=readvehicle(numefis,objs,&nto,&nob,&car); /*read vehicle from file*/
#else
	if(argc<=2){printf("Error: Input files not specified\r\nExample: ./skunks cars/car1 tracks/track1\r\n");exit(1);}
	if(argc>=4){printf("Error: Too many arguments\r\n");exit(1);}
	strcpy(numefis,argv[2]);
	objs=readtrack(numefis,&nob,&nto,&backcol); /*read objects from file*/
	strcpy(numefis,argv[1]);
	objs=readvehicle(numefis,objs,&nto,&nob,&car); /*read vehicle from file*/
#endif

vrx=0; arx=0;
vrxmr=vrxmax=0.36;
arxmr=arxmax=vrxmax/1.5;
turn=0;
dmode=1;
vrot3=1.57;
vrcmax=0.79;
vrotc=0;
rotc=0;

timp=0,dstr=0; /*pornit cronometru*/
tframe=0.5; /*assuming 2 frames/second*/


while(!quit){

/*t0frame=clock();*/
t0frame=SDL_GetTicks();
xan++;

if(speed<10){vrxmr=vrxmax; arxmr=arxmax;}
else{
	vrxmr=vrxmax/(0.1*speed);
	arxmr=arxmax/(0.1*speed);
}

switch(turn){
  case 0: if(vrx>0){arx=-arxmr*1.5;}else{if(vrx<0){arx=arxmr*1.5;}else{arx=0;}}
          if(fabs(vrx)<2.25*tframe*arx){arx=0; vrx=0;}
          break;
  case -1: if(vrx>-vrxmr){arx=-arxmr; if(vrx>0){arx*=1.5;}}else{arx=0;}
           break;
  case 1: if(vrx<vrxmr){arx=arxmr; if(vrx<0){arx*=1.5;}}else{arx=0;}
          break;
  default: break;
}

vrx+=arx*tframe;
if(vrx>vrxmr){vrx=vrxmr;}
if(vrx<-vrxmr){vrx=-vrxmr;}


/*simulation*/
nstepsf=(int)(tframe/STIMESTEP)+1; /*number of simulation steps/frame*/
realstep=tframe/nstepsf; /*simulation time step*/

for(i=1;i<=nstepsf;i++){
  runsim(objs,nob,&car,realstep,vrx,af,bf);
}
/*^simulation*/


for(i=1;i<=nob;i++){
  if(objs[i].lev==3){
    rotab(&objs[i],objs[i].vx[0],objs[i].vy[0],objs[i].vz[0],objs[i].vx[3],objs[i].vy[3],objs[i].vz[3],vrot3*tframe);
  }
}

rdspeed(&car,&speed,&rotspeed);

switch(dmode){
  case 1: sprintf(textglob,"%3.0f km/h",speed*3.6);
          break;
  case -1: sprintf(textglob,"%3.0f km/h-R",speed*3.6);
          break;
  default: break;
}

volum[1]=rotspeed+100; if (volum[1]>500){volum[1]=500;}

setcamg(&camera,&car,camflag);

rotc+=vrotc*tframe; if(camflag==2){rotc=0; vrotc=0;}
if(rotc){rotatx(&camera,objs[car.oid[1]].vy[0],objs[car.oid[1]].vz[0],rotc);}

odis(screen,objs,nob,backcol,zfog,zmax,&camera); /*display image*/

dstr+=(speed*tframe);


while(SDL_PollEvent(&event)){
switch(event.type){

case SDL_KEYDOWN:
	switch(event.key.keysym.sym){
		case SDLK_q:
		case SDLK_UP: af=dmode;
		             break;
		case SDLK_a:
		case SDLK_DOWN: bf=1;
		             break;
		case SDLK_o:
		case SDLK_LEFT: turn=-1;
		             break;
		case SDLK_p:
		case SDLK_RIGHT: turn=1;
		             break;

		case SDLK_r: dmode=-dmode;
		             break;
		
		case SDLK_c: camflag++; if(camflag>2){camflag=1;}
		             rotc=0; vrotc=0;
		             break;

		case SDLK_n: vrotc=-vrcmax;
		               break;

		case SDLK_m: vrotc=vrcmax;
		               break;

		case SDLK_ESCAPE: quit=1;

		default: break;
	} break;
case SDL_KEYUP:
	switch(event.key.keysym.sym){
		case SDLK_q:
		case SDLK_UP: af=0;
		             break;
		case SDLK_a:
		case SDLK_DOWN: bf=0;
		             break;
		case SDLK_o:
		case SDLK_LEFT: if(turn==-1){turn=0;}
		             break;
		case SDLK_p:
		case SDLK_RIGHT: if(turn==1){turn=0;}
		             break;

		case SDLK_r: af=0;
		             break;

		case SDLK_n: vrotc=0;
		               break;

		case SDLK_m: vrotc=0;
		               break;

		default: break;
	} break;

case SDL_QUIT: quit=1;

default: break;
}
}
/*tframe=(REALN)(clock()-t0frame)/CLOCKS_PER_SEC;*/
tframe=(REALN)(SDL_GetTicks()-t0frame)/1000;
timp+=tframe;
}

//Free time!
for(i=1;i<=nto;i++){free(fceglob[i]);}
free(fceglob); free (refglob); free(objs);

}

void printstats(){
	printf("\r\n\r\n\r\n**********************************************\r\n");
	printf("\r\nDistance: %1.2f km\r\nTime: %1.2f seconds\r\n",dstr/1000,timp);
	printf("Average speed: %1.2f km/h\r\n",3.6*dstr/timp);
	printf("Average framerate: %1.2f f/s\r\n\r\n",xan/timp);
	printf("**********************************************\r\n\r\n");
}

void finish(){

	#ifdef MENU
	freeTTF();
	#endif

	SDL_Quit();
	
	dWorldDestroy(wglob);
	dCloseODE();
}
