1 // main.cpp
2 
3 #include "main.h"
4 
5 
6 cGame cMain::game;
7 
8 unsigned int* gInstantfont = NULL;
9 
cGame()10 cGame::cGame()
11 : pad1(NULL),
12 map1(map_zedwise),
13 
14 camera(NULL),
15 
16 world(NULL),
17 
18 mission(0),
19 bgm("/usr/local/share/linwarrior/planet/ambient/ambient.wav"),
20 
21 paused(false),
22 fullscreen(DEFAULT_FULLSCREEN),
23 wireframe(false),
24 nightvision(false),
25 
26 printpad(false),
27 fps(DEFAULT_FPS),
28 width(DEFAULT_XRES),
29 height(DEFAULT_YRES),
30 depth(DEFAULT_BPP),
31 fov(DEFAULT_FOV) {
32 }
33 
printHelp()34 void cGame::printHelp() {
35     std::cout << std::endl
36             << "LinWarrior" << std::endl
37             << "  by Benjamin Pickhardt (benjamin.pickhardt*udo.edu)" << std::endl
38             << std::endl
39             << "Build:" << std::endl
40             << "  " << __DATE__ << std::endl
41             << "  " << __TIME__ << std::endl
42             << std::endl
43             << "Options:" << std::endl
44             << std::endl
45             << "  --help          prints this help screen" << std::endl
46             << "  --resolution    followed by resolution WIDTH or WIDTHxHEIGHT" << std::endl
47             << "  --window        start in windowed mode" << std::endl
48             << "  --joypad        followed by a (default) or b." << std::endl
49             << "                  The a-Type Gamepad is noticeable by zedwise" << std::endl
50             << "                  ordered buttons and b-Type by clockwise buttons" << std::endl
51             //<< "  --mission       followed by mission name (todo)" << std::endl
52             << "  --bgm           play background music wav file" << std::endl
53             << std::endl
54             << "  All options can be abbreviated by their first letter:" << std::endl
55             << "    --help is the same as -h" << std::endl
56             << std::endl
57             << std::endl;
58 }
59 
parseArgs(int argc,char ** args)60 int cGame::parseArgs(int argc, char** args) {
61     // Walk through arguments until all consumed or an error occured.
62 
63     loopi(argc) {
64         if (arg_i("--help")) {
65             return 1;
66         } else if (arg_i("--resolution")) {
67             advance_i();
68             std::string s = args[i];
69             int x0 = s.find('x', 0);
70             int x1 = s.find('x', x0 + 1);
71             // Is it WIDTHxHEIGHT? or else just Width?
72             if (x0 > 0) {
73                 // Width
74                 std::string w = s.substr(0, x0 - 0);
75                 this->width = atoi(w.c_str());
76                 // Height
77                 std::string h = s.substr(x0 + 1, x1 - (x0 + 1));
78                 this->height = atoi(h.c_str());
79                 // Depth
80                 if (x1 > 0) {
81                     std::string d = s.substr(x1 + 1);
82                     this->depth = atoi(d.c_str());
83                     // unused value
84                 }
85             } else {
86                 // Just take the width and find a fitting height.
87                 this->width = atoi(s.c_str());
88                 double aspect = 4.0f / 3.0f;
89                 if (this->width > 1024) aspect = 16.0f / 9.0f;
90                 this->height = (int) (this->width / aspect);
91                 this->height += (this->height % 2); // make even just in case.
92             }
93             std::cout << "Resolution: " << this->width << " x " << this->height << std::endl;
94         } else if (arg_i("--joypad")) {
95             advance_i();
96             std::string s = args[i];
97             if (s.compare("a")) {
98                 this->map1 = map_zedwise;
99             } else if (s.compare("b")) {
100                 this->map1 = map_clockwise;
101             } else {
102                 printHelp();
103             }
104         } else if (arg_i("--window")) {
105             this->fullscreen = false;
106         } else if (arg_i("--mission")) {
107             advance_i();
108             std::string s = args[i];
109             this->mission = atoi(s.c_str());
110         } else if (arg_i("--bgm")) {
111             advance_i();
112             std::string s = args[i];
113             this->bgm = s;
114         }
115     }
116     return 0;
117 }
118 
initMission()119 void cGame::initMission() {
120     this->world = new cWorld();
121     assert(this->world != NULL);
122     if (this->mission == 1) {
123         this->world->mMission = new cEmptyMission();
124         assert(this->world->mMission != NULL);
125         this->camera = this->world->mMission->init(this->world);
126         this->pad1 = this->camera->entity->pad;
127     } else {
128         this->world->mMission = new cTestMission();
129         assert(this->world->mMission != NULL);
130         this->camera = this->world->mMission->init(this->world);
131         this->pad1 = this->camera->entity->pad;
132     }
133     assert(this->camera != NULL);
134     assert(this->pad1 != NULL);
135 }
136 
initGL(int width,int height)137 void cMain::initGL(int width, int height) {
138     cout << "Initialising initial OpenGL settings.\n";
139 
140 #ifdef __WIN32
141     glTexImage3D = SDL_GL_GetProcAddress("glTexImage3D");
142     assert(glTexImage3D != NULL);
143 #endif
144 
145     if (true) {
146         std::string glinfo;
147         glinfo = (const char*) glGetString(GL_RENDERER);
148         std::cout << glinfo << std::endl << std::endl;
149         glinfo = (const char*) glGetString(GL_VENDOR);
150         std::cout << glinfo << std::endl << std::endl;
151         glinfo = (const char*) glGetString(GL_VERSION);
152         std::cout << glinfo << std::endl << std::endl;
153         glinfo = (const char*) glGetString(GL_EXTENSIONS);
154         std::cout << glinfo << std::endl << std::endl;
155         if (glinfo.find("GL_EXT_texture3D", 0) == std::string::npos) {
156             cObject::ENABLE_TEXTURE_3D = 0;
157         }
158     }
159 
160     glViewport(0, 0, width, height);
161 
162     float fogColor[4] = {1.0, 1.0, 1.0, 1.0};
163     float fogDensity = 0.003;
164 
165     glEnable(GL_BLEND);
166     glEnable(GL_DEPTH_TEST);
167 
168     glClearAccum(0.0, 0.0, 0.0, 0.0);
169     glClearColor(0.0, 0.125, 0.0, 0.0);
170     //glClearDepth(1.0);
171     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
172 
173     glShadeModel(GL_SMOOTH);
174     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
175     //glDepthMask(GL_TRUE);
176     //glDepthFunc(GL_LEQUAL);
177 
178     glFogi(GL_FOG_MODE, GL_EXP);
179     glFogfv(GL_FOG_COLOR, fogColor);
180     glFogf(GL_FOG_DENSITY, fogDensity);
181 
182     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
183 
184     // Lighting
185     {
186         glEnable(GL_LIGHTING);
187         float p[] = {0, 500, 0, 1};
188         float a[] = {0.5, 0.5, 0.5, 1};
189         glLightfv(GL_LIGHT0, GL_POSITION, p);
190         glLightfv(GL_LIGHT0, GL_AMBIENT, a);
191         glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0);
192         glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.001);
193         glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.00001);
194         glEnable(GL_COLOR_MATERIAL);
195         glEnable(GL_NORMALIZE);
196     }
197 
198     // Init instant console font.
199     glUploadFont();
200 }
201 
drawFrame(int elapsed_msec)202 void cMain::drawFrame(int elapsed_msec) {
203     //std::cout << "elapsed: " << (elapsed_msec / 1000.0f) << std::endl;
204     //if (hurlmotion) elapsed = int(elapsed * 1.0f);
205 
206     if (!game.paused) {
207         // Re-Cluster spatial index.
208         game.world->clusterObjects();
209 
210         int subframes = 1;
211 
212         loopi(subframes) {
213             // calculate the time that the last frame took.
214             game.world->advanceTime(elapsed_msec / subframes);
215 
216             // Deliver overdue messages to objects and groups of objects.
217             game.world->dispatchMessages();
218 
219             // Calculate new animation state and the like (if not paused).
220             game.world->animateObjects();
221 
222             // Calculate positions through transformations.
223             glPushMatrix();
224             {
225                 glLoadIdentity();
226                 game.world->transformObjects();
227             }
228             glPopMatrix();
229         }
230     } else {
231         // Delete Fragged Objects of previous frames.
232         game.world->bagFragged();
233     }
234 
235     // Draw fewer frames?
236     //static int cnt = 0;
237     //cnt++;
238     //if (cnt % 2 == 0) return;
239 
240     // SOLID / WIREFRAME drawing scheme.
241     if (!game.wireframe) {
242         glClearColor(0.2, 0.2, 0.2, 1.0);
243         glEnable(GL_FOG);
244         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
245         glEnable(GL_CULL_FACE);
246         glEnable(GL_LIGHTING);
247         glEnable(GL_LIGHT0);
248         glClear(GL_DEPTH_BUFFER_BIT); // With Background.
249     } else {
250         glClearColor(0.2, 0.2, 0.2, 1.0);
251         glEnable(GL_FOG);
252         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
253         //glDisable(GL_CULL_FACE);
254         glDisable(GL_LIGHTING);
255         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // W/o background.
256     }
257 
258 
259     glPushPerspectiveProjection(game.fov);
260     {
261 
262         // Setup camera.
263         glLoadIdentity();
264         if (game.camera) {
265             game.camera->multEyeMatrix();
266             game.camera->setAsAudioListener();
267         }
268 
269         // Find objects in visible range.
270         float* origin = game.camera->traceable->pos.data();
271         float maxrange = game.world->mViewdistance;
272         float min[] = {origin[0] - maxrange, origin[2] - maxrange};
273         float max[] = {origin[0] + maxrange, origin[2] + maxrange};
274         std::list<cObject*>* objects = game.world->mCluster->findUsersetInterval(min, max);
275         assert(objects != NULL);
276         //cout << "vis:" << objects->size() << " vs " << mObjects.size() << endl;
277 
278         // Draw the surounding Sky- and Ground-Dome/Box
279         game.world->drawBack();
280 
281         // Draw the Objects themselves.
282         game.world->drawSolid(game.camera, objects);
283 
284         // Draw the Object's translucent effects.
285         game.world->drawEffect(game.camera, objects);
286 
287         // Delete list of visible objects.
288         delete objects;
289 
290         // Draw the Head-Up-Display of the currently spectating Object.
291         game.camera->drawHUD();
292 
293     }
294     glPopProjection();
295 
296     glFlush();
297 
298     if (game.nightvision) {
299         glAccumBlurInverse(0.83);
300     }
301 }
302 
updateKey(Uint8 keysym)303 void cMain::updateKey(Uint8 keysym) {
304     if (keysym == _TEXTURE_KEY) {
305         cObject::ENABLE_TEXTURE_3D = !cObject::ENABLE_TEXTURE_3D;
306     } else if (keysym == _WIREFRAME_KEY) {
307         game.wireframe = !game.wireframe;
308     } else if (keysym == _NIGHTVISION_KEY) {
309         game.nightvision = !game.nightvision;
310     } else if (keysym == _PAUSE_KEY) {
311         game.paused = !game.paused;
312     } else {
313         if (keysym == SDLK_1) cWorld::instance->mViewdistance = 100;
314         else if (keysym == SDLK_2) cWorld::instance->mViewdistance = 150;
315         else if (keysym == SDLK_3) cWorld::instance->mViewdistance = 200;
316         else if (keysym == SDLK_4) cWorld::instance->mViewdistance = 250;
317         else if (keysym == SDLK_5) cWorld::instance->mViewdistance = 300;
318         else if (keysym == SDLK_6) cWorld::instance->mViewdistance = 350;
319         else if (keysym == SDLK_7) cWorld::instance->mViewdistance = 400;
320         else if (keysym == SDLK_8) cWorld::instance->mViewdistance = 450;
321         else if (keysym == SDLK_9) cWorld::instance->mViewdistance = 500;
322         else if (keysym == SDLK_0) cWorld::instance->mViewdistance = 5000;
323     }
324 }
325 
updatePad(cPad * pad,SDL_Joystick * joy,int * mapping)326 void cMain::updatePad(cPad* pad, SDL_Joystick* joy, int* mapping) {
327     if (pad == NULL) return;
328 
329     int default_mapping[] = {
330         0, 1, 2, 3,
331         4, 5, 6, 7,
332         8, 9, 10, 11,
333         12, 13, 14, 15,
334         16, 17, 18, 19,
335         20, 21, 22, 23,
336         24, 25, 26, 27,
337         28, 29, 30, 31
338     };
339     int* map = default_mapping;
340     if (mapping != NULL) map = mapping;
341 
342     pad->reset();
343     if (joy != NULL) {
344 
345         loopi(4) {
346             pad->setAxis((cPad::Axes) i, SDL_JoystickGetAxis(joy, i) / 32000.0f);
347         }
348 
349         loopi(32) {
350             if (SDL_JoystickGetButton(joy, map[i])) pad->setButton((cPad::Buttons)i, true);
351         }
352         //pad->print();
353     }
354 
355     Uint8 *keystate = SDL_GetKeyState(NULL);
356     if (keystate == NULL) return;
357     // First Analogue Control Stick
358     if (keystate[SDLK_LEFT] == 1) pad->setAxis(cPad::AX_LR1, -1.0f);
359     if (keystate[SDLK_RIGHT] == 1) pad->setAxis(cPad::AX_LR1, +1.0f);
360     if (keystate[SDLK_UP] == 1) pad->setAxis(cPad::AX_UD1, -1.0f);
361     if (keystate[SDLK_DOWN] == 1) pad->setAxis(cPad::AX_UD1, +1.0f);
362     // Start and Select
363     if (keystate[SDLK_RETURN] == 1) pad->setButton(cPad::BT_START, true);
364     if (keystate[SDLK_BACKSPACE] == 1) pad->setButton(cPad::BT_SELECT, true);
365     // Lx and Rx Buttons
366     if (keystate[SDLK_w] == 1) pad->setButton(cPad::BT_L1, true);
367     if (keystate[SDLK_a] == 1) pad->setButton(cPad::BT_L2, true);
368     if (keystate[SDLK_r] == 1) pad->setButton(cPad::BT_R1, true);
369     if (keystate[SDLK_g] == 1) pad->setButton(cPad::BT_R2, true);
370     // Primary Buttons
371     if (keystate[SDLK_s] == 1) pad->setButton(cPad::BT_SQUARE, true);
372     if (keystate[SDLK_e] == 1) pad->setButton(cPad::BT_DELTA, true);
373     if (keystate[SDLK_d] == 1) pad->setButton(cPad::BT_CROSS, true);
374     if (keystate[SDLK_f] == 1) pad->setButton(cPad::BT_CIRCLE, true);
375     // Second Analogue Stick or Coolie-Hat:
376     if (keystate[SDLK_LALT] == 0) {
377         if (keystate[SDLK_j]) pad->setAxis(cPad::AX_LR2, -1.0f);
378         if (keystate[SDLK_l]) pad->setAxis(cPad::AX_LR2, +1.0f);
379         if (keystate[SDLK_i]) pad->setAxis(cPad::AX_UD2, -1.0f);
380         if (keystate[SDLK_k]) pad->setAxis(cPad::AX_UD2, +1.0f);
381     } else {
382         if (keystate[SDLK_j]) pad->setButton(cPad::BT_HL, true);
383         if (keystate[SDLK_l]) pad->setButton(cPad::BT_HR, true);
384         if (keystate[SDLK_i]) pad->setButton(cPad::BT_HU, true);
385         if (keystate[SDLK_k]) pad->setButton(cPad::BT_HD, true);
386     };
387     // Stick Buttons
388     if (keystate[SDLK_PERIOD]) pad->setButton(cPad::BT_J1B, true);
389     if (keystate[SDLK_COMMA]) pad->setButton(cPad::BT_J2B, true);
390 }
391 
alEnableSystem(bool en)392 int alEnableSystem(bool en) {
393     static ALCdevice *dev = NULL;
394     static ALCcontext *ctx = NULL;
395     static bool isenabled = false;
396 
397     if (en && !isenabled) {
398         cout << "Enabling OpenAL\n";
399         dev = alcOpenDevice(NULL);
400         if (!dev) {
401             //fprintf(stderr, "Could not open OpenAL device.\n");
402             cout << "Could not open OpenAL device.\n";
403             return 1;
404         }
405         ctx = alcCreateContext(dev, NULL);
406         alcMakeContextCurrent(ctx);
407         if (!ctx) {
408             //fprintf(stderr, "Could not make OpenAL context current.\n");
409             cout << "Could not make OpenAL context current.\n";
410             return 1;
411         }
412         isenabled = true;
413         return 0;
414     } else if (!en && isenabled) {
415         cout << "Disabling OpenAL\n";
416         alcMakeContextCurrent(NULL);
417         alcDestroyContext(ctx);
418         alcCloseDevice(dev);
419         isenabled = false;
420         return 0;
421     } else {
422         return 1;
423     }
424 }
425 
cleanup()426 void cleanup() {
427     SDL_Quit();
428     alutExit();
429     alEnableSystem(false);
430 }
431 
sdlmain(int argc,char ** args)432 int cMain::sdlmain(int argc, char** args) {
433     std::cout << "LinWarrior 3D  (Build " __DATE__ ") by hackcraft.de" << std::endl << std::endl;
434 
435     if (game.parseArgs(argc, args)) {
436         game.printHelp();
437         return 1;
438     }
439 
440     double spf = 1.0 / (double) game.fps;
441 
442     // Initialize SDL video and input
443     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
444         std::cout << "Unable to init SDL: " << SDL_GetError() << std::endl;
445         return 1;
446     }
447 
448     // Init Video-Mode
449     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
450     SDL_Surface* screen = NULL;
451     if (game.fullscreen) screen = SDL_SetVideoMode(game.width, game.height, 0, SDL_OPENGLBLIT | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN);
452     else screen = SDL_SetVideoMode(game.width, game.height, 0, SDL_OPENGLBLIT | SDL_HWSURFACE | SDL_DOUBLEBUF);
453     if (!screen) {
454         std::cout << "Unable to set " << game.width << " x " << game.height << "video: " << SDL_GetError() << std::endl;
455         return 1;
456     }
457 
458     // Set custom window-title.
459     char* title;
460     char* icon;
461     SDL_WM_GetCaption(&title, &icon);
462     SDL_WM_SetCaption("LinWarrior 3D  (Build " __DATE__ ") by hackcraft.de", icon);
463 
464     cout << "Trying to open audio.\n";
465 
466     if (alEnableSystem(true)) {
467         cout << "Could not enable OpenAL.\n";
468     }
469 
470     //if (!alutInit(&argc, args)) {
471     if (!alutInitWithoutContext(NULL, NULL)) {
472         std::cout << "Unable to init ALUT: " << alGetError() << std::endl;
473         // Maybe just let it run without sound? Hope for no followup errors.
474         //return 1;
475     }
476     cout << "\nALUT supported file formats:\n" << alutGetMIMETypes(ALUT_LOADER_BUFFER) << "\n\n";
477     cout << "\nALUT supported memory formats:\n" << alutGetMIMETypes(ALUT_LOADER_MEMORY) << "\n\n";
478     alGetError();
479     //alDopplerFactor(2.0);
480     //alSpeedOfSound(343.3*0.1);
481 
482     // Ambient noise loop.
483     if (1) {
484         cout << "Loading Background Music.\n";
485         try {
486             ALuint buffer;
487             ALuint source;
488 
489             //buffer = alutCreateBufferHelloWorld();
490             buffer = alutCreateBufferFromFile(game.bgm.c_str());
491             if (buffer == AL_NONE) throw "Could not create buffer from file for background music.";
492             alGenSources(1, &source);
493             if (alGetError() != AL_NO_ERROR) throw "Could not generate background music source.";
494             alSourcei(source, AL_BUFFER, buffer);
495             alSourcef(source, AL_PITCH, 1.0f);
496             alSourcef(source, AL_GAIN, 1.0f);
497 
498             float zero[] = {0.0f, 0.0f, 0.0f};
499             alSourcefv(source, AL_POSITION, zero);
500             alSourcefv(source, AL_VELOCITY, zero);
501             alSourcei(source, AL_LOOPING, AL_TRUE);
502             alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
503             alSourcePlay(source);
504         } catch (const char* s) {
505             cout << "Sorry no bgm possible.\n" << s << "\n";
506         }
507     }
508 
509     initGL(screen->w, screen->h);
510     game.initMission();
511 
512     cout << "back in sdl main.\n";
513 
514     SDL_ShowCursor(SDL_DISABLE);
515     SDL_Joystick* joy0 = SDL_JoystickOpen(0);
516 
517     // Cleanup afterwards.
518     atexit(cleanup);
519 
520     // program main loop
521     bool done = false;
522     unsigned long start_ms = SDL_GetTicks();
523     while (!done) {
524         //cout << "loop\n";
525 
526         // message processing loop
527         SDL_Event event;
528         while (SDL_PollEvent(&event)) {
529             // check for messages
530             switch (event.type) {
531                     // exit if the window is closed
532                 case SDL_QUIT:
533                 {
534                     done = true;
535                     break;
536                 }
537                     // check for keypresses
538                 case SDL_KEYDOWN:
539                 {
540                     // Keymapping for virtual gamepad.
541                     updateKey(event.key.keysym.sym);
542                     // exit if ESCAPE is pressed
543                     if (event.key.keysym.sym == SDLK_ESCAPE) done = true;
544                     break;
545                 }
546             } // switch
547         } // while poll event
548 
549         // Possibly print out info on pushed buttons.
550         if (game.printpad) loopi(32) {
551             if (SDL_JoystickGetButton(joy0, i)) std::cout << "Button" << i << std::endl;
552         }
553         // Transfer real Joystick-/Gamepad-Input into the virtual gamepad
554         // of the player by using a (re-)mapping.
555         updatePad(game.pad1, joy0, game.map1);
556         // After securing Matrix: update world and draw frame.
557         //glPushMatrix();
558         {
559             //cout << "[\n";
560             drawFrame(spf * 1000.0f);
561             //cout << "]\n";
562         }
563         //glPopMatrix();
564 
565         // Lock framerate and give back idle time to the os,
566         // other processes or threads.
567         {
568             spf = (1.0f / game.fps);
569             // msec since frame started (end of last frame).
570             long delta_ms = SDL_GetTicks() - start_ms;
571             // Necessary delay to lock frame to that frame rate.
572             const unsigned long frame_ms = (long) (spf * 1000);
573             long delay_ms = frame_ms - delta_ms;
574             if (delay_ms > 0) {
575                 // Wake me up *before* time is up
576                 const long min_delay_ms = 3;
577                 if (delay_ms >= min_delay_ms) { // Some can only sleep >= x ms.
578                     long os_delay_ms = delay_ms - min_delay_ms;
579                     alutSleep(os_delay_ms * 0.001);
580                     //SDL_Delay(os_delay_ms);
581                     //std::cout << os_delay_ms << std::endl;
582                 }
583                 // debug timing
584                 //std::cout << "framebudget " << frame_ms << "ms of which " << frame_ms - delay_ms << "ms were used, remaining to waste " << delay_ms << "ms." << std::endl;
585                 //std::cout << "framebudget " << frame_ms << "ms - " << frame_ms - delay_ms << "ms = " << delay_ms << "ms" << std::endl;
586                 // Syncing in the last msecs by hand:
587                 int c = 0;
588                 while (true) {
589                     if (SDL_GetTicks() - start_ms >= frame_ms) break;
590                     c++;
591                 }
592             }
593         }
594         start_ms = SDL_GetTicks();
595 
596         SDL_GL_SwapBuffers();
597 
598     } // end main loop
599 
600     std::cout << "Thank you for playing." << std::endl;
601     return 0;
602 }
603 
604 
605 //
606 // GOD begins below!
607 //
608 
609 #ifdef n_WIN32
610 
WinMain(void * hInstance,void * hPrevInstance,char * lpCmdLine,int nCmdShow)611 extern "C" int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int nCmdShow) {
612     int argc = 2;
613     char *args[] = {"Nothing", "Nothing", "Nothing"};
614 #else
615 
616 int main(int argc, char **args) {
617 #endif
618     try {
619         return cMain::sdlmain(argc, args);
620     } catch (char* s) {
621         cout << "Fatal exception caught:\n" << s << endl;
622     }
623 }
624 
625