/* * main.c * * Where it all begins * * Copyright (c) 2008 Thomas White * * This file is part of Thrust3D - a silly game * * Thrust3D 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. * * Thrust3D 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 Thrust3D. If not, see . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "types.h" #include "model.h" #include "game.h" #include "render.h" #include "physics.h" #include "utils.h" typedef enum { RES_640, RES_800, RES_1024, RES_1280, RES_1280W, RES_1330, RES_1440, RES_1680 } ScreenResolution; static void main_version() { printf("Thrust3D version "PACKAGE_VERSION", (c) 2008 Thomas White \n"); } static void main_help(const char *n) { printf("Syntax: %s [options]\n\n", n); printf("Post-apocalyptic Jet Set Willy, set in a 3D nuclear power station.\n\n"); printf(" -h, --help Display this help message and exit.\n"); printf(" -v, --version Display version number and exit.\n"); printf(" -r, --resolution Set display resolution. See below for possible values for .\n"); printf(" -f, --fullscreen Use the full screen.\n"); printf(" -n, --no-music Don't play any background music.\n"); printf("\nAdvanced options:\n\n"); printf(" --disable-vbos Disable the use of vertex buffer objects.\n"); printf(" --disable-fbos Disable the use of framebuffer objects.\n"); printf(" --disable-shaders Disable the use of shaders.\n"); printf(" --audio-debug Print audio debugging messages to stdout.\n"); printf(" --game-debug Print game control debugging messages to stdout.\n"); printf(" --no-framerate-limit Do not wait between frames.\n"); printf(" --status-line Show game status on the terminal.\n"); printf("\n"); printf("Allowable values for are as follows:\n\n"); printf(" Width Height\n"); printf(" 640 - 640 x 480\n"); printf(" 800 - 800 x 600 (this is the default)\n"); printf(" 1024 - 1024 x 768\n"); printf(" 1280 - 1280 x 1024\n"); printf(" 1280W - 1280 x 768 (widescreen)\n"); printf(" 1330 - 1330 x 900 (widescreen)\n"); printf(" 1440 - 1440 x 900 (widescreen)\n"); printf(" 1680 - 1680 x 1050 (widescreen)\n"); printf("\n"); main_version(); } int main_event_filter(const SDL_Event *event) { if ( event->type == SDL_MOUSEMOTION ) return 0; return 1; } int main(int argc, char *argv[]) { SDL_Event event; int finished; SDL_Surface *screen; int width, height; int c; Uint32 video_flags; ScreenResolution res; GameOptions gameopts; Uint16 cx, cy; double vyaw_scale, vang_scale; gameopts.disable_vbos = 0; gameopts.disable_fbos = 0; gameopts.disable_shaders = 0; gameopts.audio_debug = 0; gameopts.game_debug = 0; gameopts.no_music = 0; gameopts.no_framerate_limit = 0; gameopts.status_line = 0; const struct option longopts[] = { {"fullscreen", 0, NULL, 'f'}, {"resolution", 1, NULL, 'r'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'v'}, {"disable-vbos", 0, &gameopts.disable_vbos, 1}, {"disable-fbos", 0, &gameopts.disable_fbos, 1}, {"disable-shaders", 0, &gameopts.disable_shaders, 1}, {"audio-debug", 0, &gameopts.audio_debug, 1}, {"game-debug", 0, &gameopts.game_debug, 1}, {"no-framerate-limit", 0, &gameopts.no_framerate_limit, 1}, {"status-line", 0, &gameopts.status_line, 1}, {"no-music", 0, NULL, 'n'}, {0, 0, NULL, 0} }; res = RES_800; width = 800; height = 600; video_flags = SDL_OPENGL; while ((c = getopt_long(argc, argv, "hvr:fn", longopts, NULL)) != -1) { switch ( c ) { case 'r' : { if ( strcasecmp(optarg, "640") == 0 ) res = RES_640; else if ( strcasecmp(optarg, "800") == 0 ) res = RES_800; else if ( strcasecmp(optarg, "1024") == 0 ) res = RES_1024; else if ( strcasecmp(optarg, "1280") == 0 ) res = RES_1280; else if ( strcasecmp(optarg, "1280W") == 0 ) res = RES_1280W; else if ( strcasecmp(optarg, "1330") == 0 ) res = RES_1330; else if ( strcasecmp(optarg, "1440") == 0 ) res = RES_1440; else if ( strcasecmp(optarg, "1680") == 0 ) res = RES_1680; else { fprintf(stderr, "Unrecognised resolution '%s'\n", optarg); exit(1); } break; } case 'f' : { video_flags = video_flags | SDL_FULLSCREEN; break; } case 'v' : { main_version(); return 0; } case 'n' : { gameopts.no_music = 1; break; } case 'h' : { main_help(argv[0]); return 0; } case 0 : { break; } default : { return 1; } } } /* SDL initial setup */ if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "Couldn't initialise SDL: %s\n", SDL_GetError()); return 1; } atexit(SDL_Quit); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); switch ( res ) { case RES_640 : { width = 640; height = 480; break; } case RES_800 : { width = 800; height = 600; break; } case RES_1024 : { width = 1024; height = 768; break; } case RES_1280W : { width = 1280; height = 768; break; } case RES_1280 : { width = 1280; height = 1024; break; } case RES_1330 : { width = 1330; height = 900; break; } case RES_1440 : { width = 1440; height = 900; break; } case RES_1680 : { width = 1680; height = 1050; break; } default : { assert(this_point_not_reached); break; } } screen = SDL_SetVideoMode(width, height, 16, video_flags); if ( screen == NULL ) { fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError()); SDL_Quit(); return 1; } SDL_WM_SetCaption("Thrust3D", "Thrust3D"); SDL_ShowCursor(SDL_DISABLE); //SDL_WM_GrabInput(SDL_GRAB_ON); SDL_SetEventFilter(main_event_filter); cx = width/2; cy = height/2; SDL_WarpMouse(cx, cy); vyaw_scale = (2*M_PI/width); vang_scale = (2*M_PI/height); /* World setup */ Game *game; game = game_new(width, height, gameopts); /* Main loop */ finished = 0; game->time = 0.0; game->tlast = utils_highresms(); game->t_fps = game->time; while ( !finished ) { int mx, my; Uint8 buttons; int mouse_thrust = 0; double us, dt; /* Tick size is measured, ... */ us = utils_highresms(); dt = us - game->tlast; game->tlast = us; /* ... but timer advances only when game is not paused */ if ( !game->paused ) { game->time += dt; } SDL_PollEvent(&event); switch ( event.type ) { case SDL_KEYDOWN : if ( !game->paused ) { if ( event.key.keysym.sym == SDLK_SPACE ) game->thrusting = 1; if ( event.key.keysym.sym == SDLK_LEFT ) game->turn_left = 1; if ( event.key.keysym.sym == SDLK_RIGHT ) game->turn_right = 1; if ( event.key.keysym.sym == SDLK_UP ) game->forward = 1; if ( event.key.keysym.sym == SDLK_DOWN ) game->reverse = 1; if ( event.key.keysym.sym == SDLK_w ) render_set_wireframe(1); if ( event.key.keysym.sym == SDLK_e ) render_set_wireframe(0); } if ( event.key.keysym.sym == SDLK_p ) game_pause(game); if ( event.key.keysym.sym == SDLK_q ) finished = 1; if ( event.key.keysym.sym == SDLK_ESCAPE ) finished = 1; if ( event.key.keysym.sym == SDLK_r ) SDL_WarpMouse(cx, cy); break; case SDL_KEYUP : /* Process key releases even when paused */ if ( event.key.keysym.sym == SDLK_SPACE ) game->thrusting = 0; if ( event.key.keysym.sym == SDLK_LEFT ) game->turn_left = 0; if ( event.key.keysym.sym == SDLK_RIGHT ) game->turn_right = 0; if ( event.key.keysym.sym == SDLK_UP ) game->forward = 0; if ( event.key.keysym.sym == SDLK_DOWN ) game->reverse = 0; if ( event.key.keysym.sym == SDLK_p ) game->pause_rel = 1; break; case SDL_QUIT : finished = 1; break; } buttons = SDL_GetMouseState(&mx, &my); game->view_yaw = -(mx-cx)*vyaw_scale; game->view_angle = deg2rad(-20.0) + (my-cy)*vang_scale; if ( game->view_angle > deg2rad(89.0) ) game->view_angle = deg2rad(89.0); if ( game->view_angle < deg2rad(-89.0) ) game->view_angle = deg2rad(-89.0); if ( !game->thrusting && ((buttons & SDL_BUTTON(1)) || (buttons & SDL_BUTTON(3))) ) { game->thrusting = 1; mouse_thrust = 1; } /* Physics steps only happen when game is not paused */ if ( !game->paused ) { physics_step(game, dt); } /* Draw in any case */ render_draw(game); if ( mouse_thrust ) game->thrusting = 0; if ( gameopts.status_line ) { printf("%+13.3f %+5.3f %+7.5f %+7.5f %+7.5f %2i %2i %2i %3i fps (r:%6lli p:%6lli) \r", game->time, dt, game->lander->vx, game->lander->vy, game->lander->vz, game->cur_room_x, game->cur_room_y, game->cur_room_z, game->fps, game->time_render, game->time_physics); fflush(stdout); } /* Calculate FPS every half a second */ game->frames++; if ( game->time - game->t_fps > 500.0 ) { game->fps = (500*game->frames) / (game->time - game->t_fps); game->t_fps = game->time; game->frames = 0; } /* Wait for how long it takes the graphics card to catch up, at the most recent measurement. */ if ( !gameopts.no_framerate_limit && (game->time_physics < game->time_render) ) { usleep(game->time_render-game->time_physics); } } game_shutdown(game); SDL_Quit(); if ( gameopts.status_line ) printf("\n"); return 0; }