Initial sauer
[SauerbratenRemote.git] / src / engine / main.cpp
blobfdddc43f65b107ebcda9ba6271658eeb9fe2b319
1 // main.cpp: initialisation & main loop
3 #include "pch.h"
4 #include "engine.h"
6 void cleanup()
8 cleangl();
9 cleanupserver();
10 SDL_ShowCursor(1);
11 freeocta(worldroot);
12 extern void clear_command(); clear_command();
13 extern void clear_console(); clear_console();
14 extern void clear_mdls(); clear_mdls();
15 extern void clear_sound(); clear_sound();
16 SDL_Quit();
19 void quit() // normal exit
21 extern void writeinitcfg();
22 writeinitcfg();
23 writeservercfg();
24 abortconnect();
25 disconnect(1);
26 writecfg();
27 cleanup();
28 exit(EXIT_SUCCESS);
31 void fatal(const char *s, ...) // failure exit
33 SDL_ShowCursor(1);
34 s_sprintfdlv(msg,s,s);
35 puts(msg);
36 #ifdef WIN32
37 MessageBox(NULL, msg, "sauerbraten fatal error", MB_OK|MB_SYSTEMMODAL);
38 #endif
39 SDL_Quit();
40 exit(EXIT_FAILURE);
43 double getaccurateticks()
45 #ifdef WIN32
46 LARGE_INTEGER count, freq;
47 QueryPerformanceCounter(&count);
48 QueryPerformanceFrequency(&freq);
49 return double(count.QuadPart)/double(freq.QuadPart)*1000;
50 #else
51 return SDL_GetTicks(); // FIXME: do something equally good on linux etc
52 #endif
55 SDL_Surface *screen = NULL;
57 int curtime;
58 int totalmillis = 0, lastmillis = 0;
60 dynent *player = NULL;
62 static bool initing = false, restoredinits = false;
63 bool initwarning()
65 if(!initing)
67 if(restoredinits) conoutf("Please restart Sauerbraten for this setting to take effect.");
68 else conoutf("Please restart Sauerbraten with the -r command-line option for this setting to take effect.");
70 return !initing;
73 VARF(scr_w, 320, 1024, 10000, initwarning());
74 VARF(scr_h, 200, 768, 10000, initwarning());
75 VARF(colorbits, 0, 0, 32, initwarning());
76 VARF(depthbits, 0, 0, 32, initwarning());
77 VARF(stencilbits, 0, 1, 32, initwarning());
78 VARF(fsaa, 0, 0, 16, initwarning());
79 VARF(vsync, -1, -1, 1, initwarning());
81 void writeinitcfg()
83 FILE *f = openfile("init.cfg", "w");
84 if(!f) return;
85 fprintf(f, "// automatically written on exit, DO NOT MODIFY\n// modify settings in game\n");
86 fprintf(f, "scr_w %d\n", scr_w);
87 fprintf(f, "scr_h %d\n", scr_h);
88 fprintf(f, "colorbits %d\n", colorbits);
89 fprintf(f, "depthbits %d\n", depthbits);
90 fprintf(f, "stencilbits %d\n", stencilbits);
91 fprintf(f, "fsaa %d\n", fsaa);
92 fprintf(f, "vsync %d\n", vsync);
93 extern int useshaders, shaderprecision;
94 fprintf(f, "shaders %d\n", useshaders);
95 fprintf(f, "shaderprecision %d\n", shaderprecision);
96 extern int soundchans, soundfreq, soundbufferlen;
97 fprintf(f, "soundchans %d\n", soundchans);
98 fprintf(f, "soundfreq %d\n", soundfreq);
99 fprintf(f, "soundbufferlen %d\n", soundbufferlen);
100 fclose(f);
103 void screenshot(char *filename)
105 SDL_Surface *image = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
106 if(!image) return;
107 uchar *tmp = new uchar[screen->w*screen->h*3];
108 glPixelStorei(GL_PACK_ALIGNMENT, 1);
109 glReadPixels(0, 0, screen->w, screen->h, GL_RGB, GL_UNSIGNED_BYTE, tmp);
110 uchar *dst = (uchar *)image->pixels;
111 loopi(screen->h)
113 memcpy(dst, &tmp[3*screen->w*(screen->h-i-1)], 3*screen->w);
114 endianswap(dst, 3, screen->w);
115 dst += image->pitch;
117 delete[] tmp;
118 if(!filename[0])
120 static string buf;
121 s_sprintf(buf)("screenshot_%d.bmp", lastmillis);
122 filename = buf;
124 else path(filename);
125 SDL_SaveBMP(image, findfile(filename, "wb"));
126 SDL_FreeSurface(image);
129 COMMAND(screenshot, "s");
130 COMMAND(quit, "");
132 void computescreen(const char *text, Texture *t)
134 int w = screen->w, h = screen->h;
135 gettextres(w, h);
136 glMatrixMode(GL_MODELVIEW);
137 glLoadIdentity();
138 glEnable(GL_BLEND);
139 glEnable(GL_TEXTURE_2D);
140 glDisable(GL_DEPTH_TEST);
141 glDisable(GL_CULL_FACE);
142 glClearColor(0.15f, 0.15f, 0.15f, 1);
143 glColor3f(1, 1, 1);
144 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
145 glMatrixMode(GL_PROJECTION);
146 loopi(2)
148 glLoadIdentity();
149 glOrtho(0, w*3, h*3, 0, -1, 1);
150 glClear(GL_COLOR_BUFFER_BIT);
151 draw_text(text, 70, 2*FONTH + FONTH/2);
152 glLoadIdentity();
153 glOrtho(0, w, h, 0, -1, 1);
154 if(t)
156 glDisable(GL_BLEND);
157 glBindTexture(GL_TEXTURE_2D, t->gl);
158 #if 0
159 int x = (w-640)/2, y = (h-320)/2;
160 glBegin(GL_TRIANGLE_FAN);
161 glTexCoord2f(0.5f, 0.5f); glVertex2f(x+640/2.0f, y+320/2.0f);
162 loopj(64+1)
164 float c = 0.5f+0.5f*cosf(2*M_PI*j/64.0f), s = 0.5f+0.5f*sinf(2*M_PI*j/64.0f);
165 glTexCoord2f(c, 320.0f/640.0f*(s-0.5f)+0.5f);
166 glVertex2f(x+640*c, y+320*s);
168 #else
169 int sz = 256, x = (w-sz)/2, y = min(384, h-256);
170 glBegin(GL_QUADS);
171 glTexCoord2f(0, 0); glVertex2i(x, y);
172 glTexCoord2f(1, 0); glVertex2i(x+sz, y);
173 glTexCoord2f(1, 1); glVertex2i(x+sz, y+sz);
174 glTexCoord2f(0, 1); glVertex2i(x, y+sz);
175 #endif
176 glEnd();
177 glEnable(GL_BLEND);
179 int x = (w-512)/2, y = 128;
180 settexture("data/sauer_logo_512_256a.png");
181 glBegin(GL_QUADS);
182 glTexCoord2f(0, 0); glVertex2i(x, y);
183 glTexCoord2f(1, 0); glVertex2i(x+512, y);
184 glTexCoord2f(1, 1); glVertex2i(x+512, y+256);
185 glTexCoord2f(0, 1); glVertex2i(x, y+256);
186 glEnd();
187 SDL_GL_SwapBuffers();
189 glMatrixMode(GL_MODELVIEW);
190 glDisable(GL_BLEND);
191 glDisable(GL_TEXTURE_2D);
192 glEnable(GL_DEPTH_TEST);
193 glEnable(GL_CULL_FACE);
196 static void bar(float bar, int w, int o, float r, float g, float b)
198 int side = 2*FONTH;
199 float x1 = side, x2 = bar*(w*3-2*side)+side;
200 float y1 = o*FONTH;
201 glColor3f(r, g, b);
202 glBegin(GL_TRIANGLE_STRIP);
203 loopk(10)
205 float c = cosf(M_PI/2 + k/9.0f*M_PI), s = 1 + sinf(M_PI/2 + k/9.0f*M_PI);
206 glVertex2f(x2 - c*FONTH, y1 + s*FONTH);
207 glVertex2f(x1 + c*FONTH, y1 + s*FONTH);
209 glEnd();
211 #if 0
212 glColor3f(0.3f, 0.3f, 0.3f);
213 glBegin(GL_LINE_LOOP);
214 loopk(10)
216 float c = cosf(M_PI/2 + k/9.0f*M_PI), s = 1 + sinf(M_PI/2 + k/9.0f*M_PI);
217 glVertex2f(x1 + c*FONTH, y1 + s*FONTH);
219 loopk(10)
221 float c = cosf(M_PI/2 + k/9.0f*M_PI), s = 1 - sinf(M_PI/2 + k/9.0f*M_PI);
222 glVertex2f(x2 - c*FONTH, y1 + s*FONTH);
224 glEnd();
225 #endif
228 void show_out_of_renderloop_progress(float bar1, const char *text1, float bar2, const char *text2, GLuint tex) // also used during loading
230 if(!inbetweenframes) return;
232 clientkeepalive(); // make sure our connection doesn't time out while loading maps etc.
234 int w = screen->w, h = screen->h;
235 gettextres(w, h);
237 glDisable(GL_DEPTH_TEST);
238 glMatrixMode(GL_MODELVIEW);
239 glPushMatrix();
240 glLoadIdentity();
241 glMatrixMode(GL_PROJECTION);
242 glPushMatrix();
243 glLoadIdentity();
244 glOrtho(0, w*3, h*3, 0, -1, 1);
245 notextureshader->set();
247 glLineWidth(3);
249 if(text1)
251 bar(1, w, 4, 0, 0, 0.8f);
252 if(bar1>0) bar(bar1, w, 4, 0, 0.5f, 1);
255 if(bar2>0)
257 bar(1, w, 6, 0.5f, 0, 0);
258 bar(bar2, w, 6, 0.75f, 0, 0);
261 glLineWidth(1);
263 glEnable(GL_BLEND);
264 glEnable(GL_TEXTURE_2D);
265 defaultshader->set();
267 if(text1) draw_text(text1, 2*FONTH, 4*FONTH + FONTH/2);
268 if(bar2>0) draw_text(text2, 2*FONTH, 6*FONTH + FONTH/2);
270 glDisable(GL_BLEND);
272 if(tex)
274 glBindTexture(GL_TEXTURE_2D, tex);
275 int sz = 256, x = (w-sz)/2, y = min(384, h-256);
276 sz *= 3;
277 x *= 3;
278 y *= 3;
279 glBegin(GL_QUADS);
280 glTexCoord2f(0, 0); glVertex2i(x, y);
281 glTexCoord2f(1, 0); glVertex2i(x+sz, y);
282 glTexCoord2f(1, 1); glVertex2i(x+sz, y+sz);
283 glTexCoord2f(0, 1); glVertex2i(x, y+sz);
284 glEnd();
287 glDisable(GL_TEXTURE_2D);
289 glPopMatrix();
290 glMatrixMode(GL_MODELVIEW);
291 glPopMatrix();
292 glEnable(GL_DEPTH_TEST);
293 SDL_GL_SwapBuffers();
296 void setfullscreen(bool enable)
298 if(enable == !(screen->flags&SDL_FULLSCREEN))
300 #if defined(WIN32) || defined(__APPLE__)
301 conoutf("\"fullscreen\" variable not supported on this platform. Use the -t command-line option.");
302 extern int fullscreen;
303 fullscreen = !enable;
304 #else
305 SDL_WM_ToggleFullScreen(screen);
306 SDL_WM_GrabInput((screen->flags&SDL_FULLSCREEN) ? SDL_GRAB_ON : SDL_GRAB_OFF);
307 #endif
311 void screenres(int *w, int *h)
313 #if !defined(WIN32) && !defined(__APPLE__)
314 if(initing)
316 #endif
317 scr_w = *w;
318 scr_h = *h;
319 #if defined(WIN32) || defined(__APPLE__)
320 initwarning();
321 #else
322 return;
324 SDL_Surface *surf = SDL_SetVideoMode(*w, *h, 0, SDL_OPENGL|SDL_RESIZABLE|(screen->flags&SDL_FULLSCREEN));
325 if(!surf) return;
326 screen = surf;
327 scr_w = screen->w;
328 scr_h = screen->h;
329 glViewport(0, 0, scr_w, scr_h);
330 #endif
333 VARF(fullscreen, 0, 0, 1, setfullscreen(fullscreen!=0));
335 COMMAND(screenres, "ii");
337 VARFP(gamma, 30, 100, 300,
339 float f = gamma/100.0f;
340 if(SDL_SetGamma(f,f,f)==-1)
342 conoutf("Could not set gamma (card/driver doesn't support it?)");
343 conoutf("sdl: %s", SDL_GetError());
347 void keyrepeat(bool on)
349 SDL_EnableKeyRepeat(on ? SDL_DEFAULT_REPEAT_DELAY : 0,
350 SDL_DEFAULT_REPEAT_INTERVAL);
353 VARF(gamespeed, 10, 100, 1000, if(multiplayer()) gamespeed = 100);
355 VARF(paused, 0, 0, 1, if(multiplayer()) paused = 0);
357 VAR(maxfps, 5, 200, 500);
359 void limitfps(int &millis, int curmillis)
361 static int fpserror = 0;
362 int delay = 1000/maxfps - (millis-curmillis);
363 if(delay < 0) fpserror = 0;
364 else
366 fpserror += 1000%maxfps;
367 if(fpserror >= maxfps)
369 ++delay;
370 fpserror -= maxfps;
372 if(delay > 0)
374 SDL_Delay(delay);
375 millis += delay;
380 #if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__)
381 void stackdumper(unsigned int type, EXCEPTION_POINTERS *ep)
383 if(!ep) fatal("unknown type");
384 EXCEPTION_RECORD *er = ep->ExceptionRecord;
385 CONTEXT *context = ep->ContextRecord;
386 string out, t;
387 s_sprintf(out)("Sauerbraten Win32 Exception: 0x%x [0x%x]\n\n", er->ExceptionCode, er->ExceptionCode==EXCEPTION_ACCESS_VIOLATION ? er->ExceptionInformation[1] : -1);
388 STACKFRAME sf = {{context->Eip, 0, AddrModeFlat}, {}, {context->Ebp, 0, AddrModeFlat}, {context->Esp, 0, AddrModeFlat}, 0};
389 SymInitialize(GetCurrentProcess(), NULL, TRUE);
391 while(::StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &sf, context, NULL, ::SymFunctionTableAccess, ::SymGetModuleBase, NULL))
393 struct { IMAGEHLP_SYMBOL sym; string n; } si = { { sizeof( IMAGEHLP_SYMBOL ), 0, 0, 0, sizeof(string) } };
394 IMAGEHLP_LINE li = { sizeof( IMAGEHLP_LINE ) };
395 DWORD off;
396 if(SymGetSymFromAddr(GetCurrentProcess(), (DWORD)sf.AddrPC.Offset, &off, &si.sym) && SymGetLineFromAddr(GetCurrentProcess(), (DWORD)sf.AddrPC.Offset, &off, &li))
398 char *del = strrchr(li.FileName, '\\');
399 s_sprintf(t)("%s - %s [%d]\n", si.sym.Name, del ? del + 1 : li.FileName, li.LineNumber);
400 s_strcat(out, t);
403 fatal(out);
405 #endif
407 #define MAXFPSHISTORY 60
409 int fpspos = 0, fpshistory[MAXFPSHISTORY];
411 void resetfpshistory()
413 loopi(MAXFPSHISTORY) fpshistory[i] = 1;
414 fpspos = 0;
417 void updatefpshistory(int millis)
419 fpshistory[fpspos++] = max(1, min(1000, millis));
420 if(fpspos>=MAXFPSHISTORY) fpspos = 0;
423 void getfps(int &fps, int &bestdiff, int &worstdiff)
425 int total = fpshistory[MAXFPSHISTORY-1], best = total, worst = total;
426 loopi(MAXFPSHISTORY-1)
428 int millis = fpshistory[i];
429 total += millis;
430 if(millis < best) best = millis;
431 if(millis > worst) worst = millis;
434 fps = (1000*MAXFPSHISTORY)/total;
435 bestdiff = 1000/best-fps;
436 worstdiff = fps-1000/worst;
439 bool inbetweenframes = false;
441 static bool findarg(int argc, char **argv, const char *str)
443 for(int i = 1; i<argc; i++) if(strstr(argv[i], str)==argv[i]) return true;
444 return false;
447 static int clockrealbase = 0, clockvirtbase = 0;
448 static void clockreset() { clockrealbase = SDL_GetTicks(); clockvirtbase = totalmillis; }
449 VARFP(clockerror, 990000, 1000000, 1010000, clockreset());
450 VARFP(clockfix, 0, 0, 1, clockreset());
452 int main(int argc, char **argv)
454 #ifdef WIN32
455 //atexit((void (__cdecl *)(void))_CrtDumpMemoryLeaks);
456 #ifndef _DEBUG
457 #ifndef __GNUC__
458 __try {
459 #endif
460 #endif
461 #endif
463 bool dedicated = false;
464 int fs = SDL_FULLSCREEN, par = 0;
465 char *load = NULL, *initscript = NULL;
467 #define log(s) puts("init: " s)
469 initing = true;
470 for(int i = 1; i<argc; i++)
472 if(argv[i][0]=='-') switch(argv[i][1])
474 case 'q': printf("Using home directory: %s\n", &argv[i][2]); sethomedir(&argv[i][2]); break;
475 case 'k': printf("Adding package directory: %s\n", &argv[i][2]); addpackagedir(&argv[i][2]); break;
476 case 'r': execfile(argv[i][2] ? &argv[i][2] : (char *)"init.cfg"); restoredinits = true; break;
477 case 'd': dedicated = true; break;
478 case 'w': scr_w = atoi(&argv[i][2]); if(scr_w<320) scr_w = 320; if(!findarg(argc, argv, "-h")) scr_h = (scr_w*3)/4; break;
479 case 'h': scr_h = atoi(&argv[i][2]); if(scr_h<200) scr_h = 200; if(!findarg(argc, argv, "-w")) scr_w = (scr_h*4)/3; break;
480 case 'z': depthbits = atoi(&argv[i][2]); break;
481 case 'b': colorbits = atoi(&argv[i][2]); break;
482 case 'a': fsaa = atoi(&argv[i][2]); break;
483 case 'v': vsync = atoi(&argv[i][2]); break;
484 case 't': fs = 0; break;
485 case 's': stencilbits = atoi(&argv[i][2]); break;
486 case 'f':
488 extern int useshaders, shaderprecision;
489 int n = atoi(&argv[i][2]);
490 useshaders = n ? 1 : 0;
491 shaderprecision = min(max(n - 1, 0), 3);
492 break;
494 case 'l':
496 char pkgdir[] = "packages/";
497 load = strstr(path(&argv[i][2]), path(pkgdir));
498 if(load) load += sizeof(pkgdir)-1;
499 else load = &argv[i][2];
500 break;
502 case 'x': initscript = &argv[i][2]; break;
503 default: if(!serveroption(argv[i])) gameargs.add(argv[i]); break;
505 else gameargs.add(argv[i]);
507 initing = false;
509 log("sdl");
511 #ifdef _DEBUG
512 par = SDL_INIT_NOPARACHUTE;
513 fs = 0;
514 #ifdef WIN32
515 SetEnvironmentVariable("SDL_DEBUG", "1");
516 #endif
517 #endif
519 //#ifdef WIN32
520 //SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
521 //#endif
523 if(SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO|SDL_INIT_AUDIO|par)<0) fatal("Unable to initialize SDL: %s", SDL_GetError());
525 log("enet");
526 if(enet_initialize()<0) fatal("Unable to initialise network module");
528 initserver(dedicated); // never returns if dedicated
530 log("video: mode");
531 int resize = SDL_RESIZABLE;
532 #if defined(WIN32) || defined(__APPLE__)
533 resize = 0;
534 #endif
535 SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL|resize|fs);
536 if(modes && modes!=(SDL_Rect **)-1)
538 bool hasmode = false;
539 for(int i = 0; modes[i]; i++)
541 if(scr_w <= modes[i]->w && scr_h <= modes[i]->h) { hasmode = true; break; }
543 if(!hasmode) { scr_w = modes[0]->w; scr_h = modes[0]->h; }
545 bool hasbpp = true;
546 if(colorbits && modes)
547 hasbpp = SDL_VideoModeOK(modes!=(SDL_Rect **)-1 ? modes[0]->w : scr_w, modes!=(SDL_Rect **)-1 ? modes[0]->h : scr_h, colorbits, SDL_OPENGL|resize|fs)==colorbits;
549 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
550 #if SDL_VERSION_ATLEAST(1, 2, 11)
551 if(vsync>=0) SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vsync);
552 #endif
553 static int configs[] =
555 0x7, /* try everything */
556 0x6, 0x5, 0x3, /* try disabling one at a time */
557 0x4, 0x2, 0x1, /* try disabling two at a time */
558 0 /* try disabling everything */
560 int config = 0;
561 loopi(sizeof(configs)/sizeof(configs[0]))
563 config = configs[i];
564 if(!depthbits && config&1) continue;
565 if(!stencilbits && config&2) continue;
566 if(!fsaa && config&4) continue;
567 if(depthbits) SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, config&1 ? depthbits : 0);
568 if(stencilbits)
570 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, config&2 ? 1 : 0);
571 hasstencil = (config&2)!=0;
573 if(fsaa)
575 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, config&4 ? 1 : 0);
576 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config&4 ? fsaa : 0);
578 screen = SDL_SetVideoMode(scr_w, scr_h, hasbpp ? colorbits : 0, SDL_OPENGL|resize|fs);
579 if(screen) break;
581 if(!screen) fatal("Unable to create OpenGL screen: %s", SDL_GetError());
582 else
584 if(!hasbpp) conoutf("%d bit color buffer not supported - disabling", colorbits);
585 if(depthbits && (config&1)==0) conoutf("%d bit z-buffer not supported - disabling", depthbits);
586 if(stencilbits && (config&2)==0) conoutf("Stencil buffer not supported - disabling");
587 if(fsaa && (config&4)==0) conoutf("%dx anti-aliasing not supported - disabling", fsaa);
590 scr_w = screen->w;
591 scr_h = screen->h;
593 fullscreen = fs!=0;
595 log("video: misc");
596 SDL_WM_SetCaption("sauerbraten engine", NULL);
597 #ifndef WIN32
598 if(fs)
599 #endif
600 SDL_WM_GrabInput(SDL_GRAB_ON);
601 keyrepeat(false);
602 SDL_ShowCursor(0);
604 log("gl");
605 gl_init(scr_w, scr_h, hasbpp ? colorbits : 0, config&1 ? depthbits : 0, config&4 ? fsaa : 0);
606 notexture = textureload("data/notexture.png");
607 if(!notexture) fatal("could not find core textures");
609 log("console");
610 persistidents = false;
611 if(!execfile("data/stdlib.cfg")) fatal("cannot find data files (you are running from the wrong folder, try .bat file in the main folder)"); // this is the first file we load.
612 if(!execfile("data/font.cfg")) fatal("cannot find font definitions");
613 if(!setfont("default")) fatal("no default font specified");
615 computescreen("initializing...");
616 inbetweenframes = true;
618 log("gl: effects");
619 loadshaders();
620 particleinit();
622 log("world");
623 camera1 = player = cl->iterdynents(0);
624 emptymap(0, true);
626 log("sound");
627 initsound();
629 log("cfg");
630 exec("data/keymap.cfg");
631 exec("data/stdedit.cfg");
632 exec("data/menus.cfg");
633 exec("data/sounds.cfg");
634 exec("data/brush.cfg");
635 execfile("mybrushes.cfg");
636 if(cl->savedservers()) execfile(cl->savedservers());
638 persistidents = true;
640 if(!execfile(cl->savedconfig())) exec(cl->defaultconfig());
641 execfile(cl->autoexec());
643 persistidents = false;
645 string gamecfgname;
646 s_strcpy(gamecfgname, "data/game_");
647 s_strcat(gamecfgname, cl->gameident());
648 s_strcat(gamecfgname, ".cfg");
649 exec(gamecfgname);
651 persistidents = true;
653 log("localconnect");
654 localconnect();
655 cc->gameconnect(false);
656 cc->changemap(load ? load : cl->defaultmap());
658 if(initscript) execute(initscript);
660 log("mainloop");
662 resetfpshistory();
664 int ignore = 5, grabmouse = 0;
665 for(;;)
667 static int frames = 0;
668 int millis = SDL_GetTicks() - clockrealbase;
669 if(clockfix) millis = int(millis*(double(clockerror)/1000000));
670 millis += clockvirtbase;
671 if(millis<totalmillis) millis = totalmillis;
672 limitfps(millis, totalmillis);
673 int elapsed = millis-totalmillis;
674 if(multiplayer(false)) curtime = elapsed;
675 else
677 static int timeerr = 0;
678 int scaledtime = elapsed*gamespeed + timeerr;
679 curtime = scaledtime/100;
680 timeerr = scaledtime%100;
681 if(curtime>200) curtime = 200;
682 if(paused) curtime = 0;
685 if(lastmillis) cl->updateworld(worldpos, curtime, lastmillis);
687 menuprocess();
689 lastmillis += curtime;
690 totalmillis = millis;
692 checksleep(lastmillis);
694 serverslice(0);
696 if(frames) updatefpshistory(elapsed);
697 frames++;
699 // miscellaneous general game effects
700 findorientation();
701 entity_particles();
702 updatevol();
703 checkmapsounds();
705 inbetweenframes = false;
706 SDL_GL_SwapBuffers();
707 if(frames>2) gl_drawframe(screen->w, screen->h);
708 inbetweenframes = true;
710 SDL_Event event;
711 int lasttype = 0, lastbut = 0;
712 while(SDL_PollEvent(&event))
714 switch(event.type)
716 case SDL_QUIT:
717 quit();
718 break;
720 #if !defined(WIN32) && !defined(__APPLE__)
721 case SDL_VIDEORESIZE:
722 screenres(&event.resize.w, &event.resize.h);
723 break;
724 #endif
726 case SDL_KEYDOWN:
727 case SDL_KEYUP:
728 keypress(event.key.keysym.sym, event.key.state==SDL_PRESSED, event.key.keysym.unicode);
729 break;
731 case SDL_ACTIVEEVENT:
732 if(event.active.state & SDL_APPINPUTFOCUS)
733 grabmouse = event.active.gain;
734 else
735 if(event.active.gain)
736 grabmouse = 1;
737 break;
739 case SDL_MOUSEMOTION:
740 if(ignore) { ignore--; break; }
741 #ifndef WIN32
742 if(!(screen->flags&SDL_FULLSCREEN) && grabmouse)
744 #ifdef __APPLE__
745 if(event.motion.y == 0) break; //let mac users drag windows via the title bar
746 #endif
747 if(event.motion.x == screen->w / 2 && event.motion.y == screen->h / 2) break;
748 SDL_WarpMouse(screen->w / 2, screen->h / 2);
750 if((screen->flags&SDL_FULLSCREEN) || grabmouse)
751 #endif
752 if(!g3d_movecursor(event.motion.xrel, event.motion.yrel))
753 mousemove(event.motion.xrel, event.motion.yrel);
754 break;
756 case SDL_MOUSEBUTTONDOWN:
757 case SDL_MOUSEBUTTONUP:
758 if(lasttype==event.type && lastbut==event.button.button) break; // why?? get event twice without it
759 keypress(-event.button.button, event.button.state!=0, 0);
760 lasttype = event.type;
761 lastbut = event.button.button;
762 break;
767 ASSERT(0);
768 return EXIT_FAILURE;
770 #if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__)
771 } __except(stackdumper(0, GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) { return 0; }
772 #endif