Artifact fe88d055bb879cf686588777fb4840c8322d7bf64f0cc8cfd8017a1b84df1659:
- File
src/Cube.mm
— part of check-in
[489124a92f]
at
2025-03-16 10:11:39
on branch trunk
— Use one autorelease pool per frame
This way, nowhere else autorelease pools need to be managed. (user: js, size: 9526) [annotate] [blame] [check-ins using]
// main.cpp: initialisation & main loop #include "cube.h" #import "DynamicEntity.h" OF_APPLICATION_DELEGATE(Cube) VARF(gamespeed, 10, 100, 1000, if (multiplayer()) gamespeed = 100); VARP(minmillis, 0, 5, 1000); @implementation Cube { int _width, _height; } + (Cube *)sharedInstance { return (Cube *)OFApplication.sharedApplication.delegate; } - (void)applicationDidFinishLaunching:(OFNotification *)notification { @autoreleasepool { bool dedicated, windowed; int par = 0, uprate = 0, maxcl = 4; OFString *__autoreleasing sdesc, *__autoreleasing ip; OFString *__autoreleasing master, *__autoreleasing passwd; processInitQueue(); #define log(s) conoutf(@"init: %@", s) log(@"sdl"); const OFOptionsParserOption options[] = { { 'd', @"dedicated", 0, &dedicated, NULL }, { 't', @"window", 0, &windowed, NULL }, { 'w', @"width", 1, NULL, NULL }, { 'h', @"height", 1, NULL, NULL }, { 'u', @"upload-rate", 1, NULL, NULL }, { 'n', @"server-desc", 1, NULL, &sdesc }, { 'i', @"ip", 1, NULL, &ip }, { 'm', @"master", 1, NULL, &master }, { 'p', @"password", 1, NULL, &passwd }, { 'c', @"max-clients", 1, NULL, NULL }, { '\0', nil, 0, NULL, NULL } }; OFOptionsParser *optionsParser = [OFOptionsParser parserWithOptions:options]; OFUnichar option; while ((option = [optionsParser nextOption]) != '\0') { switch (option) { case 'w': _width = optionsParser.argument.intValue; break; case 'h': _height = optionsParser.argument.intValue; break; case 'u': uprate = optionsParser.argument.intValue; break; case 'c': maxcl = optionsParser.argument.intValue; break; case ':': case '=': case '?': conoutf(@"unknown commandline option"); [OFApplication terminateWithStatus:1]; } } if (sdesc == nil) sdesc = @""; if (ip == nil) ip = @""; if (passwd == nil) passwd = @""; _gameDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; _userDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; [OFFileManager.defaultManager createDirectoryAtIRI: [_userDataIRI IRIByAppendingPathComponent:@"demos"] createParents:true]; [OFFileManager.defaultManager createDirectoryAtIRI: [_userDataIRI IRIByAppendingPathComponent:@"savegames"] createParents:true]; if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | par) < 0) fatal(@"Unable to initialize SDL"); initPlayers(); log(@"net"); if (enet_initialize() < 0) fatal(@"Unable to initialise network module"); initclient(); // never returns if dedicated initserver(dedicated, uprate, sdesc, ip, master, passwd, maxcl); log(@"world"); empty_world(7, true); log(@"video: sdl"); if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) fatal(@"Unable to initialize SDL Video"); if (_width == 0 || _height == 0) { SDL_DisplayMode mode; if (SDL_GetDesktopDisplayMode(0, &mode) == 0) { _width = mode.w; _height = mode.h; } else { _width = 1920; _height = 1080; } } log(@"video: mode"); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); if ((_window = SDL_CreateWindow("cube engine", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _width, _height, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | (!windowed ? SDL_WINDOW_FULLSCREEN : 0))) == NULL || SDL_GL_CreateContext(_window) == NULL) fatal(@"Unable to create OpenGL screen"); log(@"video: misc"); SDL_SetWindowGrab(_window, SDL_TRUE); SDL_SetRelativeMouseMode(SDL_TRUE); SDL_ShowCursor(0); log(@"gl"); gl_init(_width, _height); log(@"basetex"); int xs, ys; if (!installtex(2, [_gameDataIRI IRIByAppendingPathComponent:@"data/newchars.png"], &xs, &ys, false) || !installtex(3, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/base.png"], &xs, &ys, false) || !installtex(6, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/ball1.png"], &xs, &ys, false) || !installtex(7, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/smoke.png"], &xs, &ys, false) || !installtex(8, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/ball2.png"], &xs, &ys, false) || !installtex(9, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/ball3.png"], &xs, &ys, false) || !installtex(4, [_gameDataIRI IRIByAppendingPathComponent:@"data/explosion.jpg"], &xs, &ys, false) || !installtex(5, [_gameDataIRI IRIByAppendingPathComponent:@"data/items.png"], &xs, &ys, false) || !installtex(1, [_gameDataIRI IRIByAppendingPathComponent:@"data/crosshair.png"], &xs, &ys, false)) fatal(@"could not find core textures (hint: run cube " @"from the parent of the bin directory)"); log(@"sound"); initsound(); log(@"cfg"); newmenu(@"frags\tpj\tping\tteam\tname"); newmenu(@"ping\tplr\tserver"); exec(@"data/keymap.cfg"); exec(@"data/menus.cfg"); exec(@"data/prefabs.cfg"); exec(@"data/sounds.cfg"); exec(@"servers.cfg"); if (!execfile([_userDataIRI IRIByAppendingPathComponent:@"config.cfg"])) execfile([_gameDataIRI IRIByAppendingPathComponent:@"data/defaults.cfg"]); exec(@"autoexec.cfg"); log(@"localconnect"); localconnect(); // if this map is changed, also change depthcorrect() changemap(@"metl3"); log(@"mainloop"); } OFDate *past = [OFDate date]; int ignore = 5; for (;;) { @autoreleasepool { [OFRunLoop.mainRunLoop runUntilDate:past]; int millis = SDL_GetTicks() * gamespeed / 100; if (millis - lastmillis > 200) lastmillis = millis - 200; else if (millis - lastmillis < 1) lastmillis = millis - 1; if (millis - lastmillis < minmillis) SDL_Delay(minmillis - (millis - lastmillis)); cleardlights(); updateworld(millis); if (!demoplayback) serverslice((int)time(NULL), 0); static float fps = 30.0f; fps = (1000.0f / curtime + fps * 50) / 51; computeraytable(player1.o.x, player1.o.y); readdepth(_width, _height); SDL_GL_SwapWindow(_window); extern void updatevol(); updatevol(); // cheap hack to get rid of initial sparklies, even when // triple buffering etc. if (_framesInMap++ < 5) { player1.yaw += 5; gl_drawframe(_width, _height, fps); player1.yaw -= 5; } gl_drawframe(_width, _height, fps); SDL_Event event; int lasttype = 0, lastbut = 0; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: [self quit]; break; case SDL_KEYDOWN: case SDL_KEYUP: if (_repeatsKeys || event.key.repeat == 0) keypress(event.key.keysym.sym, event.key.state == SDL_PRESSED); break; case SDL_TEXTINPUT: input(@(event.text.text)); break; case SDL_MOUSEMOTION: if (ignore) { ignore--; break; } mousemove(event.motion.xrel, event.motion.yrel); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: if (lasttype == event.type && lastbut == event.button.button) // why?? get event twice without // it break; keypress(-event.button.button, event.button.state != 0); lasttype = event.type; lastbut = event.button.button; break; } } } } } - (void)applicationWillTerminate:(OFNotification *)notification { stop(); disconnect(true); writecfg(); cleangl(); cleansound(); cleanupserver(); SDL_ShowCursor(1); SDL_Quit(); } - (void)showMessage:(OFString *)msg { #ifdef _WIN32 MessageBoxW( NULL, msg.UTF16String, L"cube fatal error", MB_OK | MB_SYSTEMMODAL); #else [OFStdOut writeString:msg]; #endif } - (void)screenshot { SDL_Surface *image; SDL_Surface *temp; if ((image = SDL_CreateRGBSurface(SDL_SWSURFACE, _width, _height, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0)) != NULL) { if ((temp = SDL_CreateRGBSurface(SDL_SWSURFACE, _width, _height, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0)) != NULL) { glReadPixels(0, 0, _width, _height, GL_RGB, GL_UNSIGNED_BYTE, image->pixels); for (int idx = 0; idx < _height; idx++) { char *dest = (char *)temp->pixels + 3 * _width * idx; memcpy(dest, (char *)image->pixels + 3 * _width * (_height - 1 - idx), 3 * _width); endianswap(dest, 3, _width); } OFString *path = [OFString stringWithFormat:@"screenshots/screenshot_%d.bmp", lastmillis]; SDL_SaveBMP(temp, [_userDataIRI IRIByAppendingPathComponent:path] .fileSystemRepresentation.UTF8String); SDL_FreeSurface(temp); } SDL_FreeSurface(image); } } - (void)quit { writeservercfg(); [OFApplication terminateWithStatus:0]; } @end void fatal(OFString *s, OFString *o) // failure exit { OFString *msg = [OFString stringWithFormat:@"%@%@ (%s)\n", s, o, SDL_GetError()]; [Cube.sharedInstance showMessage:msg]; [OFApplication terminateWithStatus:1]; } void quit() // normal exit { [Cube.sharedInstance quit]; } COMMAND(quit, ARG_NONE) void screenshot() { [Cube.sharedInstance screenshot]; } COMMAND(screenshot, ARG_NONE)