1 /*
2 * stormbaancoureur
3 * (c) 2006,2007,2008 by Bram Stolk
4 * bram at gmail.com
5 * LICENSED ACCORDING TO THE GPLV3
6 */
7
8 #include <assert.h>
9 #include <libgen.h> // for dirname(), Is this portable?
10
11 #define GL_GLEXT_PROTOTYPES 1
12 #define GLX_GLXEXT_PROTOTYPES 1
13
14 #include <GL/glx.h>
15 #include <GL/glxext.h> // for the opengl extensions we use for hardware accelerated shadowing
16
17 #include <GL/gl.h>
18 #include <GL/glut.h>
19
20 #include <plib/ssg.h>
21 #include <plib/ul.h>
22
23 #include "ogl.h"
24 #include "staticworldobject.h"
25 #include "carobject.h"
26 #include "trackingcam.h"
27 #include "usercam.h"
28 #include "dynamicboxobject.h"
29 #include "dynamiccylobject.h"
30
31 #include "stereocontext.h"
32 #include "intro.h"
33 #include "controller.h"
34 #include "soundenginealsa.h"
35 #include "plodegui.h"
36 #include "modelmap.h"
37 #include "postscore.h"
38 #include "sturmbahn.h"
39 #include "starsky.h"
40
41 static float aspectratio=1.0;
42 static int winw=704, winh=300;
43 //static int winw=480, winh=360;
44 static ssgRoot *scene=0;
45 static ssgContext *monocontext=0;
46 static StereoContext *stereocontext=0;
47 static ssgContext *lightviewcontext=0;
48 static float fps=60.0;
49 static float gametime=0.0;
50 static float spawntime=0.0;
51 static const char *username="anonymou";
52 static float dt_hist[10]={0.016,0.016,0.016,0.016,0.016,0.016,0.016,0.016,0.016,0.016};
53 static std::string dirprefix;
54
55 static dJointGroupID contactgroup;
56 static dSpaceID bigspace;
57 static dSpaceID staticspace;
58 static dWorldID world;
59
60 static SturmBahnFull *sturmbahnfull=0;
61 static SturmBahnPractice *sturmbahnpractice=0;
62 static SturmBahnRally *sturmbahnrally=0;
63 static RespawnPoint *respawn_point_hit=0;
64
65 static ControllerPad *controller_pad=0;
66 static ControllerKey *controller_key=0;
67 static Controller *controller=0;
68 static CarObject *car=0;
69 static UserCam *trackingcam=0;
70 static int numcars=0;
71
72 static SoundEngineAlsa *sengine=0;
73 static Intro *intro=0;
74 static PlodeGUI *gui=0;
75 static bool capture=false;
76
77 static ModelMap *modelmap=0;
78 static StarSky *starsky=0;
79
80 static bool do_shadows;
81
82 static void stop_game(void);
83 static void start_game(const std::string &gametype);
84 static void restart_game(void);
85 static bool respawn(void);
86
87
88
near_callback(void * data,dGeomID o1,dGeomID o2)89 static void near_callback(void *data, dGeomID o1, dGeomID o2)
90 {
91 assert(o1);
92 assert(o2);
93
94 if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
95 {
96 // colliding a space with something
97 dSpaceCollide2(o1,o2,data,&near_callback);
98 // Note we do not want to test intersections within a space,
99 // only between spaces.
100 return;
101 }
102
103 // Two non space geoms
104
105 WorldObject *wo1 = static_cast<WorldObject*>(dGeomGetData(o1));
106 WorldObject *wo2 = static_cast<WorldObject*>(dGeomGetData(o2));
107
108 const int N = 32;
109 dContact contact[N];
110 int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact));
111
112 if (n > 0)
113 {
114 assert(wo1);
115 assert(wo2);
116
117 if (wo1->name == "respawnpoint")
118 respawn_point_hit = dynamic_cast<RespawnPoint*>(wo1);
119 if (wo2->name == "respawnpoint")
120 respawn_point_hit = dynamic_cast<RespawnPoint*>(wo2);
121
122 // This section is req'd to see if the backwheels are touching
123 // a dynamic object. If so, it could be that our car is riding
124 // on top of an object. In this case, it should be possible to
125 // engage the reverse-gear when the car is stationary relative
126 // to the ground, and yet may be moving in absolute space.
127 if (car->IsBackWheelGeometry(o1))
128 {
129 DynamicObject *dynamic_ground = dynamic_cast<DynamicObject*>(wo2);
130 if (dynamic_ground)
131 car->SetGround(dynamic_ground);
132 else
133 car->SetGround(0);
134 }
135 if (car->IsBackWheelGeometry(o2))
136 {
137 DynamicObject *dynamic_ground = dynamic_cast<DynamicObject*>(wo1);
138 if (dynamic_ground)
139 car->SetGround(dynamic_ground);
140 else
141 car->SetGround(0);
142 }
143
144 bool is_tyre=false;
145 sgVec3 wheel_dir={0,0,0};
146 float wheel_vel=0.0f;
147 if (car->IsWheelGeometry(o1,wheel_vel))
148 {
149 const dReal *m = dGeomGetRotation(o1);
150 sgSetVec3(wheel_dir, m[2],m[6],m[10]);
151 is_tyre=true;
152 }
153 if (car->IsWheelGeometry(o2,wheel_vel))
154 {
155 const dReal *m = dGeomGetRotation(o2);
156 sgSetVec3(wheel_dir, m[2],m[6],m[10]);
157 is_tyre=true;
158 }
159
160 #if 0
161 if (is_tyre)
162 fprintf(stderr,"dir %5.2f %5.2f %5.2f\n", wheel_dir[0], wheel_dir[1], wheel_dir[2]);
163 #endif
164
165 // Create constraints for all the contacts between the geometries.
166 for (int i=0; i<n; i++)
167 {
168 contact[i].surface.mu = 50.0;
169 //contact[i].surface.soft_erp = 0.985;
170 //contact[i].surface.soft_cfm = 0.020;
171 //contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1;
172 contact[i].surface.mode = dContactApprox1;
173
174 if (is_tyre)
175 {
176 contact[i].fdir1[0]=wheel_dir[0];
177 contact[i].fdir1[1]=wheel_dir[1];
178 contact[i].fdir1[2]=wheel_dir[2];
179 contact[i].surface.slip1 = 0.0250f * wheel_vel; // slip perpendicular to roll direction
180 contact[i].surface.slip2 = 0.0005f * wheel_vel; // slip in roll direction
181 contact[i].surface.mode = contact[i].surface.mode | dContactFDir1 | dContactSlip1 | dContactSlip2;
182 #if 0
183 contact[i].surface.soft_erp = 0.95;
184 contact[i].surface.soft_cfm = 0.05;
185 contact[i].surface.mode = contact[i].surface.mode | dContactSoftERP | dContactSoftCMF;
186 #endif
187 contact[i].surface.mu = 340.0;
188 contact[i].surface.mu2 = 340.0;
189 }
190
191 if ((wo1->name == "ferriswheelcart" || wo2->name == "ferriswheelcart") && is_tyre)
192 {
193 contact[i].surface.mu *= 2;
194 contact[i].surface.mu2 *= 2;
195 contact[i].surface.slip1 *= 0.01;
196 contact[i].surface.slip2 *= 0.01;
197 }
198
199 dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
200 dGeomID g1 = contact[i].geom.g1;
201 dGeomID g2 = contact[i].geom.g2;
202 dBodyID b1 = dGeomGetBody(g1);
203 dBodyID b2 = dGeomGetBody(g2);
204 assert(b1 || b2);
205 dJointAttach (c, b1, b2);
206 }
207 }
208 }
209
210
engine_noise(float dt)211 static void engine_noise(float dt)
212 {
213 float vl = car->GetWheelVelocity(2);
214 float vr = car->GetWheelVelocity(3);
215 float v = std::max(vl,vr);
216 float a = car->GetAccelerator();
217 float d = car->GetBrake();
218 float e = std::max(a,d);
219 v = v/15.0;
220 if (v>3) v=3;
221 sengine->SetModulation(1+v+e, 1+v/5+e/2);
222 sengine->SetLowPass(0.97);
223 return;
224 }
225
226
make_menu_choice(void)227 void make_menu_choice(void)
228 {
229 const std::string &choice = gui->SelectChoice();
230 if (choice == "ATTACK STORMBAAN")
231 start_game("full");
232 if (choice == "PRACTICE")
233 start_game("practice");
234 if (choice == "TEST GROUND")
235 start_game("rally");
236 }
237
238
idle(void)239 static void idle(void)
240 {
241 static ulClock clk;
242 static int frameCounter = 0;
243 clk.setMaxDelta(1.0);
244
245 float elapsed = clk.getDeltaTime();
246 clk.update();
247
248 float fractiondone=0;
249 if (sengine)
250 fractiondone=sengine->Sustain();
251 if (intro)
252 {
253 bool done=intro->Sustain(elapsed, fractiondone);
254 if (done || !gui->hasmenu)
255 {
256 delete intro;
257 intro = 0;
258 }
259 }
260
261 dt_hist[frameCounter] = elapsed;
262 frameCounter = (frameCounter+1)%10;
263
264 float dt=0;
265 int i;
266 for (i=0; i<10; i++)
267 dt += dt_hist[i];
268 dt = dt / 10;
269 assert(dt>0.0);
270 // do not update the fps every time, it is not readable when it is done each tick
271 if (frameCounter == 0)
272 fps = 1.0f / dt;
273 if (dt > 0.125) dt=0.125; // Do not accomodate systems slower than 8 fps
274
275 if (controller_pad) controller_pad->Sustain(dt);
276 if (controller_key) controller_key->Sustain(dt);
277
278 // Feed the controls into the car
279 float ste = controller->GetSteer();
280 float acc = controller->GetAccel();
281 float bra = controller->GetBrake();
282 bool act = controller->GetAction();
283 bool ebr = controller->GetEBrake();
284
285 // Steer the gui with the gamepad
286 if (gui && gui->hasmenu && controller_pad)
287 {
288 if (controller_pad->HasAnyButtonChanged(true))
289 make_menu_choice();
290 static float delta=0.0;
291 delta += controller_pad->GetAxisValue(1)*10*dt;
292 int idelta = int(delta);
293 if (idelta)
294 {
295 delta=0.0;
296 gui->ChangeChoice(idelta);
297 }
298 }
299
300 if (intro)
301 return;
302
303 if (gui && gui->hasmenu)
304 return;
305
306 car->SetSteer(ste);
307 car->SetAccelerator(acc);
308 car->SetBrake(bra);
309 car->SetAction(act);
310 car->SetEBrake(ebr);
311
312 gametime += elapsed;
313 spawntime += elapsed;
314 if (sengine)
315 engine_noise(dt);
316
317 float timestep=0.005555; // Use 5.555ms timesteps
318 static float remaining_sim_time=0;
319 remaining_sim_time += dt;
320
321 bool win=false;
322 const float SLOWMOTION=1.0f;
323 while (remaining_sim_time > timestep)
324 {
325 dSpaceCollide (bigspace, 0, &near_callback);
326 if (car) car->Sustain(SLOWMOTION*timestep);
327 if (sturmbahnpractice)
328 sturmbahnpractice->Sustain(SLOWMOTION*timestep, car->GetAction());
329 if (sturmbahnfull)
330 if (sturmbahnfull->Sustain(SLOWMOTION*timestep, car->GetAction()))
331 win=true;
332 if (sturmbahnrally)
333 sturmbahnrally->Sustain(SLOWMOTION*timestep, car->GetAction());
334 dWorldQuickStep (world, SLOWMOTION*timestep);
335 dJointGroupEmpty (contactgroup);
336 remaining_sim_time -= timestep;
337 }
338
339 if (win)
340 {
341 postscore_put(username, gametime);
342 const char *leaderboardtext = postscore_get();
343 gui->SetLeaderBoardText(leaderboardtext);
344 stop_game();
345 return;
346 }
347
348 // Check lose condition
349 sgVec3 carpos;
350 car->GetPos(carpos);
351 if (carpos[2] < -4)
352 {
353 restart_game();
354 return;
355 }
356
357 if (respawn_point_hit)
358 {
359 car->SnapShot(false);
360 gametime += 60.0f; // penalty for taking the easy way out
361 respawn_point_hit->Disable();
362 respawn_point_hit=0;
363 }
364
365 trackingcam->Update(dt);
366 sgVec3 eye, coi, up;
367 sgSetVec3(up,0,0,1);
368 trackingcam->GetCameraPos(eye);
369 trackingcam->GetTargetPos(coi);
370
371 if (monocontext)
372 monocontext->setCameraLookAt(eye, coi, up);
373
374 if (stereocontext)
375 {
376 stereocontext->SetCameraLookAt(eye, coi, up);
377 OglErrorCheck("stereocontext->SetCameraLookAt");
378 }
379
380 ssgLight *light = ssgGetLight(0);
381 if (do_shadows)
382 {
383 eye[0]= 0.0;
384 eye[1]= 40.0;
385 eye[2]= 90.0;
386 }
387 else
388 {
389 car->GetPos(coi);
390 car->GetPos(eye);
391 eye[2] += 6.5;
392 }
393
394 sgVec3 car_dir;
395 car->GetDir(car_dir);
396 sgAddVec3(coi, coi, car_dir);
397 sgVec3 light_dir;
398 sgSubVec3(light_dir, coi, eye);
399 light->setPosition(eye[0],eye[1],eye[2]);
400 light->setSpotDirection(light_dir[0],light_dir[1],light_dir[2]);
401 sgSetVec3(up,1,0,0);
402 lightviewcontext->setCameraLookAt(eye, coi, up);
403 }
404
405
redraw_single_channel(void)406 static void redraw_single_channel(void)
407 {
408 if (scene && !intro && (!gui || !gui->hasmenu))
409 {
410 if (do_shadows)
411 {
412 // 1st pass from light view
413
414 lightviewcontext->makeCurrent();
415 OglRenderShadowMap(scene);
416
417 sgMat4 mat_cam, mat_spt;
418 if (monocontext)
419 {
420 monocontext->makeCurrent();
421 monocontext->getModelviewMatrix(mat_cam);
422 }
423 if (stereocontext)
424 {
425 stereocontext->MakeCurrent("last");
426 stereocontext->getModelviewMatrix(mat_cam);
427 }
428 lightviewcontext->getModelviewMatrix(mat_spt);
429
430 OglSetupSecondPass((float*)mat_cam, (float*)mat_spt);
431 }
432
433 ssgCullAndDraw(scene);
434 OglErrorCheck("ssgCullAndDraw");
435
436 if (do_shadows)
437 {
438 glUseProgram(0);
439 // Turn off all texture units
440 glActiveTextureARB(GL_TEXTURE1_ARB);
441 glBindTexture(GL_TEXTURE_2D, 0);
442 glDisable(GL_TEXTURE_2D);
443 glActiveTextureARB(GL_TEXTURE2_ARB);
444 glBindTexture(GL_TEXTURE_2D, 0);
445 glDisable(GL_TEXTURE_2D);
446 glActiveTextureARB(GL_TEXTURE0_ARB);
447 glBindTexture(GL_TEXTURE_2D, 0);
448 glDisable(GL_TEXTURE_2D);
449 OglErrorCheck("Turn off texture units");
450 }
451 }
452
453 if (intro)
454 {
455 if (do_shadows)
456 {
457 glUseProgram(0);
458 glDisable(GL_TEXTURE_2D);
459 }
460 intro->Redraw(winw, winh);
461 OglErrorCheck("intro->Redraw");
462 }
463
464 if (gui)
465 {
466 char s[25];
467 sprintf(s, "%.02f %d FPS", gametime, (int) fps);
468 gui->Redraw(winw, winh, s);
469 OglErrorCheck("gui->Redraw");
470 }
471 }
472
473
redraw(void)474 static void redraw(void)
475 {
476 if (intro || (gui && gui->hasmenu))
477 glClearColor(0.3,0.3,0.55,1);
478 else
479 glClearColor(0.2,0.1,0.35,1);
480
481 if (stereocontext)
482 {
483 // passive stereo: clear buffers only once
484 if (!stereocontext->IsQuadBuffered())
485 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
486 stereocontext->MakeCurrent("left");
487 OglErrorCheck("MakeCurrent");
488 #if 1
489 // quad buffer stereo: clear buffers twice
490 if (stereocontext->IsQuadBuffered())
491 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
492 #endif
493 redraw_single_channel();
494 stereocontext->MakeCurrent("right");
495 OglErrorCheck("MakeCurrent");
496 #if 1
497 // quad buffer stereo: clear buffers twice
498 if (stereocontext->IsQuadBuffered())
499 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
500 #endif
501 redraw_single_channel();
502 }
503
504 if (monocontext)
505 {
506 monocontext->makeCurrent();
507 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
508 redraw_single_channel();
509 }
510
511 glutSwapBuffers () ;
512 OglErrorCheck("glutSwapBuffers");
513
514 if (capture)
515 {
516 static char *buf = new char[winw * winh * 3];
517 glMatrixMode(GL_MODELVIEW);
518 glLoadIdentity();
519 glReadBuffer(GL_BACK_LEFT);
520 glReadPixels(0,0,winw,winh,GL_RGB,GL_UNSIGNED_BYTE,(GLvoid*)(buf));
521 OglErrorCheck("glReadPixels");
522 static FILE *f=0;
523
524 if (!f)
525 {
526 f=fopen("capture.out", "wb");
527 assert(f);
528 // fprintf(f,"P6 %d %d 255\n", winw,winh);
529 }
530 unsigned char *revbuf = new unsigned char[winw*winh*3];
531 for (int y=0; y<winh; y++)
532 {
533 int chunk = 3 * winw;
534 memcpy(revbuf + y*chunk, buf + (winh - 1 - y)*chunk, chunk);
535 }
536 fwrite(revbuf,winw*winh*3,1,f);
537 fflush(f);
538 delete revbuf;
539 }
540 // We want to render the next frame immediately
541 glutPostRedisplay () ;
542 }
543
544
reshape(int w,int h)545 static void reshape(int w, int h)
546 {
547 winw=w; winh=h;
548 if (monocontext)
549 {
550 glViewport ( 0, 0, w, h ) ;
551 aspectratio = w / (float) h;
552 float fovy = 40.0 * M_PI / 180.0;
553 float nearPlaneDistance = 0.28;
554 float farPlaneDistance = 2500.0;
555 float y = tan(0.5 * fovy) * nearPlaneDistance;
556 float x = aspectratio * y;
557 monocontext->setFrustum(-x,x,-y,y,nearPlaneDistance,farPlaneDistance);
558 }
559
560 if (stereocontext)
561 stereocontext->SetWindowSize(winw, winh);
562
563 #if 1
564 int nsamples = glutGet(GLUT_WINDOW_NUM_SAMPLES);
565 #else
566 int nsamples;
567 glGetIntegerv(GL_SAMPLES, &nsamples);
568 #endif
569 fprintf(stderr,"Number of samples per pixel: %d\n", nsamples);
570 }
571
572
keyboardUp(unsigned char k,int,int)573 static void keyboardUp(unsigned char k, int, int)
574 {
575 if (controller_key) controller_key->FeedKey(k, false);
576 }
577
578
special(int k,int,int)579 static void special(int k, int, int)
580 {
581 if (k == GLUT_KEY_UP)
582 {
583 if (gui && gui->hasmenu) gui->ChangeChoice(-1);
584 if (controller_key) controller_key->FeedAction("ACCEL", true);
585 }
586 if (k == GLUT_KEY_DOWN)
587 {
588 if (gui && gui->hasmenu) gui->ChangeChoice(1);
589 if (controller_key) controller_key->FeedAction("BRAKE", true);
590 }
591 if (k == GLUT_KEY_LEFT)
592 {
593 if (controller_key) controller_key->FeedAction("LEFT", true);
594 }
595 if (k == GLUT_KEY_RIGHT)
596 {
597 if (controller_key) controller_key->FeedAction("RIGHT", true);
598 }
599 }
600
601
specialUp(int k,int,int)602 static void specialUp(int k, int, int)
603 {
604 if (k == GLUT_KEY_UP)
605 {
606 if (controller_key) controller_key->FeedAction("ACCEL", false);
607 }
608 if (k == GLUT_KEY_DOWN)
609 {
610 if (controller_key) controller_key->FeedAction("BRAKE", false);
611 }
612 if (k == GLUT_KEY_LEFT)
613 {
614 if (controller_key) controller_key->FeedAction("LEFT", false);
615 }
616 if (k == GLUT_KEY_RIGHT)
617 {
618 if (controller_key) controller_key->FeedAction("RIGHT", false);
619 }
620 }
621
622
623 static int mouse_x, mouse_y, mouse_but;
mouse(int button,int state,int x,int y)624 static void mouse(int button, int state, int x, int y)
625 {
626 mouse_x = x;
627 mouse_y = y;
628 if (state == GLUT_DOWN) mouse_but = button;
629 }
630
631
motion(int x,int y)632 static void motion(int x, int y)
633 {
634 if (!trackingcam) return;
635 float dx = (x - mouse_x) / (float) winw;
636 float dy = (y - mouse_y) / (float) winh;
637
638 if (mouse_but == GLUT_LEFT_BUTTON)
639 {
640 trackingcam->ChangeHeading(100.0 * dx);
641 trackingcam->ChangePitch(100.0 * dy);
642 }
643 if (mouse_but == GLUT_MIDDLE_BUTTON)
644 {
645 trackingcam->ChangeOffset(dx, dy);
646 }
647 if (mouse_but == GLUT_RIGHT_BUTTON)
648 {
649 trackingcam->ChangeDistance(-10.0 * dy);
650 }
651
652 mouse_x = x;
653 mouse_y = y;
654 }
655
656
start_game(const std::string & gametype)657 static void start_game(const std::string &gametype)
658 {
659 gametime = 0.0;
660 spawntime = 0.0;
661
662 // Create ODE world
663 dInitODE();
664 world = dWorldCreate();
665 bigspace = dHashSpaceCreate(0);
666 staticspace = dSimpleSpaceCreate(bigspace);
667 contactgroup = dJointGroupCreate (0);
668 #if 0
669 dWorldSetERP(world, 0.95f);
670 dWorldSetCFM(world, 0.001f);
671 #endif
672 dWorldSetGravity(world,0,0,-9.8);
673 dWorldSetAutoDisableFlag(world, true);
674 dWorldSetAutoDisableLinearThreshold(world, 0.04);
675 dWorldSetAutoDisableAngularThreshold(world, 0.04);
676 dWorldSetQuickStepNumIterations(world, 16);
677
678 // Create PLIB world
679
680 scene = new ssgRoot();
681
682 if (gametype=="practice")
683 sturmbahnpractice = new SturmBahnPractice(world, bigspace, staticspace, scene, modelmap, dirprefix);
684 if (gametype=="rally")
685 sturmbahnrally = new SturmBahnRally(world, bigspace, staticspace, scene, modelmap, dirprefix);
686 if (gametype=="full")
687 sturmbahnfull = new SturmBahnFull(world, bigspace, staticspace, scene, modelmap, dirprefix);
688
689 // Create a car
690 sgVec3 carpos;
691
692 if (sturmbahnpractice)
693 sgSetVec3(carpos, -4, 0, 1.5);
694
695 if (sturmbahnfull)
696 sgSetVec3(carpos, -17, 0, 3.0);
697 //sgSetVec3(carpos, 52, 0, 1.5); // If you wanna cheat!
698
699 if (sturmbahnrally)
700 sgSetVec3(carpos, -28, 0, 1.5);
701
702 car = new CarObject
703 (
704 modelmap->Get("frame.3ds"),
705 modelmap->Get("fivespoke.3ds"),
706 modelmap->Get("wishbone.3ds"),
707 modelmap->Get("spindle.3ds"),
708 modelmap->Get("coilspring.3ds"),
709 modelmap->Get("leafspring.3ds"),
710 modelmap->Get("rearaxle.3ds"),
711 world,
712 bigspace,
713 carpos
714 );
715 scene->addKid(car->GetEntity());
716 numcars = 1;
717
718 // Setup camera
719 trackingcam = new UserCam(0,0,0);
720 trackingcam->AddTarget(car->GetTransform());
721 trackingcam->SetPitch(16.5f);
722 trackingcam->SetDistance(4.0f);
723
724 if (sengine)
725 {
726 sengine->SetMode("engine");
727 sengine->Play(dirprefix + "/sounds/detonationnorm_s16_le.wav",0);
728 }
729 }
730
731
stop_game(void)732 static void stop_game(void)
733 {
734 delete car;
735 delete trackingcam;
736
737 if (sengine)
738 sengine->SetMode("none");
739
740 delete sturmbahnfull;
741 sturmbahnfull=0;
742 delete sturmbahnpractice;
743 sturmbahnpractice=0;
744 delete sturmbahnrally;
745 sturmbahnrally=0;
746
747 // Delete ODE stuff
748 dJointGroupDestroy(contactgroup);
749 dSpaceDestroy(staticspace);
750 dSpaceDestroy(bigspace);
751 dWorldDestroy(world);
752
753 dCloseODE();
754 }
755
756
respawn(void)757 static bool respawn(void)
758 {
759 spawntime=0.0f;
760 bool restored = car->SnapShot(true);
761 if (!restored)
762 return false;
763 return true;
764 }
765
766
restart_game(void)767 static void restart_game(void)
768 {
769 const char *gametype="";
770 if (sturmbahnpractice) gametype="practice";
771 if (sturmbahnrally) gametype="rally";
772 if (sturmbahnfull) gametype="full";
773 bool respawned = respawn();
774 if (!respawned)
775 {
776 stop_game();
777 start_game(gametype);
778 }
779 }
780
781
keyboard(unsigned char k,int,int)782 static void keyboard(unsigned char k, int, int)
783 {
784 if (k==27)
785 {
786 if (gui && gui->hasmenu)
787 {
788 if (gui->showingleaders)
789 {
790 gui->showingleaders = false;
791 return;
792 }
793 if (gui->showinghelp)
794 {
795 gui->showinghelp = false;
796 return;
797 }
798 exit(0);
799 }
800 if (spawntime>1.0f)
801 restart_game();
802 else
803 if (gui) gui->hasmenu=true;
804 }
805
806 if (gui && gui->hasmenu)
807 {
808 if (k==' ' || k==13 || k==10)
809 {
810 make_menu_choice();
811 }
812 return;
813 }
814
815 #if 0
816 if (k=='x')
817 {
818 capture=!capture;
819 return;
820 }
821 #endif
822
823 if (controller_key) controller_key->FeedKey(k, true);
824 }
825
826
827
828
829
main(int argc,char * argv[])830 int main(int argc, char *argv[])
831 {
832 std::string displaymode="monoscopic";
833
834 fprintf(stderr,"Version %s\n", VERSION_STRING(GAMEVERSION));
835 fprintf(stderr,"Stormbaan Coureur is (c)2006-2008 by Bram Stolk\n");
836 fprintf(stderr,"plib is (c) by Steve Baker\n");
837 fprintf(stderr,"OpenDE is (c) by Russel L. Smith\n");
838
839 char *bindirname = dirname(argv[0]);
840 dirprefix="/usr/local/share/stormbaancoureur";
841 if (getenv("PLODE_DATADIR"))
842 dirprefix = getenv("PLODE_DATADIR");
843 if (getenv("PLODE_DISPLAYMODE"))
844 displaymode = getenv("PLODE_DISPLAYMODE");
845 assert(displaymode == "monoscopic" || displaymode == "quadbufferstereoscopic" || displaymode == "passivestereoscopic");
846 modelmap = new ModelMap(dirprefix);
847 char *unam = getenv("USER");
848 if (unam && strlen(unam)>2)
849 {
850 username = unam;
851 if (strlen(unam)>8)
852 unam[8]=0;
853 }
854 glutInit(&argc, argv);
855 int flags = GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE;
856 if (displaymode == "quadbufferstereoscopic") flags = flags | GLUT_STEREO;
857 glutInitDisplayMode(flags);
858 glutInitWindowSize(winw, winh);
859 glutInitWindowPosition(0,0);
860 int winid=glutCreateWindow ("Stormbaan Coureur");
861 assert(winid>=1);
862 glutDisplayFunc(redraw);
863 glutReshapeFunc(reshape);
864 glutKeyboardFunc(keyboard);
865 glutKeyboardUpFunc(keyboardUp);
866 glutSpecialFunc(special);
867 glutSpecialUpFunc(specialUp);
868 glutMouseFunc(mouse);
869 glutMotionFunc(motion);
870 glutIdleFunc(idle);
871
872 #if 1
873 glutFullScreen();
874 #else
875 if (1)
876 {
877 int width = glutGameModeGet( GLUT_GAME_MODE_WIDTH );
878 int height = glutGameModeGet( GLUT_GAME_MODE_HEIGHT );
879 int pixelDepth = glutGameModeGet( GLUT_GAME_MODE_PIXEL_DEPTH );
880 int refreshRate = glutGameModeGet( GLUT_GAME_MODE_REFRESH_RATE );
881 fprintf(stderr,"%dx%d-%d@%d\n", width, height, pixelDepth, refreshRate);
882 //glutEnterGameMode();
883 }
884 #endif
885
886 do_shadows = OglCanDoShadowing();
887 fprintf
888 (
889 stderr,
890 "This platform %s all required GL extensions to do hardware accelerated shadowing.\n",
891 (do_shadows) ? "supports" : "does not support"
892 );
893
894 ssgInit();
895
896 if (do_shadows)
897 {
898 OglInitShadowing(dirprefix);
899 }
900
901 glEnable(GL_DEPTH_TEST);
902 glEnable(GL_CULL_FACE);
903
904 float amb[4]={0.0, 0.0, 0.0, 1};
905 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
906
907 starsky = new StarSky();
908 modelmap->Put("starsky", starsky->GetEntity());
909
910 controller_pad = new ControllerPad("/dev/input/js0");
911 if (controller_pad->IsWorking())
912 {
913 fprintf(stderr,"Using gamepad\n");
914 controller = controller_pad;
915 }
916 else
917 {
918 delete controller_pad;
919 controller_pad = 0;
920 char *ev = getenv("HOME");
921 controller_key = new ControllerKey(std::string((ev)?ev:"~") + "/.stormbaancoureur.keys");
922 controller = controller_key;
923 fprintf(stderr,"Using keyboard\n");
924 }
925
926
927 if (displaymode != "monoscopic")
928 {
929 stereocontext = new StereoContext(displaymode == "quadbufferstereoscopic");
930 }
931 else
932 {
933 sgVec3 eye={5.2,1.8,3.4};
934 sgVec3 coi={0,0,0};
935 sgVec3 up= {0,0,1};
936 monocontext = new ssgContext();
937 monocontext->setCameraLookAt(eye, coi, up);
938 monocontext->makeCurrent();
939 }
940 lightviewcontext = new ssgContext();
941 float fov = spot_fov * M_PI / 180.0;
942 float nearPlaneDistance = 1.0f;
943 float farPlaneDistance = 150.0f;
944 float s = tan(0.5 * fov) * nearPlaneDistance;
945 lightviewcontext->setFrustum(-s,s,-s,s, nearPlaneDistance, farPlaneDistance);
946
947 ssgLight *light=ssgGetLight(0);
948 const float ka = (do_shadows) ? 0.15f : 0.30f;
949 const float kd = (do_shadows) ? 1.00f : 2.50f;
950 const float ks = 1.0f;
951 light->setColour(GL_DIFFUSE, kd,kd,kd);
952 light->setColour(GL_AMBIENT, ka,ka,ka);
953 light->setColour(GL_SPECULAR, ks,ks,ks);
954 light->setPosition(0,0,8);
955 light->setSpotlight(true);
956 light->setSpotDirection(0,0,-1);
957 light->setSpotDiffusion(100,180);
958 light->setSpotAttenuation(1, 0.1, 0.04);
959 light->on();
960
961 sgCoord campos ;
962 sgSetCoord (&campos, 0.0f, -13.0f, 6.0f, 0.0, -34.0f, 0.0f) ;
963
964 bool nosound = getenv("PLODE_NO_SOUND");
965 if (!nosound)
966 {
967 sengine = new SoundEngineAlsa(5000);
968 if (!sengine->opened)
969 {
970 delete sengine;
971 sengine = 0;
972 }
973 }
974 if (sengine)
975 intro = new Intro(sengine, dirprefix, modelmap->Get("piston.3ds"), modelmap->Get("rod.3ds"));
976 gui = new PlodeGUI(username, controller_pad!=0);
977
978 glutMainLoop();
979 delete sengine;
980 }
981
982