#include #include "libs.h" #include "l3d.h" #include "gui.h" #include "glfreetype.h" #include "player.h" #include "space.h" #include "planet.h" #include "star.h" #include "frame.h" #include "ship_cpanel.h" #include "sector_view.h" #include "system_view.h" #include "system_info_view.h" #include "world_view.h" #include "object_viewer_view.h" #include "star_system.h" #include "space_station.h" #include "space_station_view.h" #include "info_view.h" #include "serializer.h" float L3D::timeAccel = 1.0f; int L3D::scrWidth; int L3D::scrHeight; float L3D::scrAspect; SDL_Surface* L3D::scrSurface; sigc::signal L3D::onKeyPress; sigc::signal L3D::onKeyRelease; sigc::signal L3D::onMouseButtonUp; sigc::signal L3D::onMouseButtonDown; char L3D::keyState[SDLK_LAST]; char L3D::mouseButton[5]; int L3D::mouseMotion[2]; enum L3D::MapView L3D::mapView; Player* L3D::player; View* L3D::currentView; WorldView* L3D::worldView; ObjectViewerView* L3D::objectViewerView; SpaceStationView* L3D::spaceStationView; InfoView* L3D::infoView; SectorView* L3D::sectorView; SystemView* L3D::systemView; SystemInfoView* L3D::systemInfoView; ShipCpanel* L3D::cpan; StarSystem* L3D::selectedSystem; StarSystem* L3D::currentSystem; MTRand L3D::rng; double L3D::gameTime; float L3D::frameTime; GLUquadric* L3D::gluQuadric; bool L3D::showDebugInfo; void L3D::Init(IniConfig& config) { int width = config.Int("ScrWidth"); int height = config.Int("ScrHeight"); const SDL_VideoInfo* info = NULL; if(SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError()); exit(-1); } info = SDL_GetVideoInfo(); switch(config.Int("ScrDepth")) { case 16: SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); break; case 32: SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); break; default: fprintf(stderr, "Fatal error: Invalid screen depth in config.ini.\n"); L3D::Quit(); } SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); Uint32 flags = SDL_OPENGL; if(config.Int("StartFullscreen")) flags |= SDL_FULLSCREEN; if((L3D::scrSurface = SDL_SetVideoMode(width, height, info->vfmt->BitsPerPixel, flags)) == 0) { /* Fall back to 16-bit depth buffer.. */ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); fprintf(stderr,"Failed to set video mode. (%s). Re-trying with 16 bit depth buffer.\n",SDL_GetError()); if((L3D::scrSurface = SDL_SetVideoMode(width, height, info->vfmt->BitsPerPixel, flags)) == 0) { fprintf(stderr, "video mode set failed: %s\n", SDL_GetError()); exit(-1); } } L3D::scrWidth = width; L3D::scrHeight = height; L3D::scrAspect = width / (float)height; L3D::rng.seed(time(NULL)); InitOpenGL(); dInitODE(); GLFTInit(); Space::Init(); Gui::Init(scrWidth, scrHeight, 800, 600); } void L3D::InitOpenGL() { glShadeModel(GL_SMOOTH); glCullFace(GL_BACK); glFrontFace(GL_CCW); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0, 0, 0, 0); glViewport(0, 0, scrWidth, scrHeight); gluQuadric = gluNewQuadric(); } void L3D::Quit(void) { SDL_Quit(); exit(0); } void L3D::SetTimeAccel(float s) { /* We don't want player spinning like crazy when hitting time accel. */ if(s > 10) { player->SetAngVelocity(vector3d(0,0,0)); dBodySetTorque(player->m_body, 0, 0, 0); player->SetAngThrusterState(0, 0.0f); player->SetAngThrusterState(1, 0.0f); player->SetAngThrusterState(2, 0.0f); } timeAccel = s; } void L3D::SetMapView(enum MapView v) { mapView = v; if(v == MAP_SECTOR) SetView(sectorView); else SetView(systemView); } void L3D::SetView(View* v) { if(currentView) currentView->HideAll(); currentView = v; currentView->ShowAll(); } void L3D::HandleEvents(void) { SDL_Event event; L3D::mouseMotion[0] = L3D::mouseMotion[1] = 0; while(SDL_PollEvent(&event)) { Gui::HandleSDLEvent(&event); switch(event.type) { case SDL_KEYDOWN: if(KeyState(SDLK_LCTRL) && (event.key.keysym.sym == SDLK_q)) L3D::Quit(); if(event.key.keysym.sym == SDLK_i) L3D::showDebugInfo = !L3D::showDebugInfo; #ifdef DEBUG if(event.key.keysym.sym == SDLK_F12) { /* Add test object. */ Ship* body = new Ship(ShipType::LADYBIRD); body->SetLabel("A friend"); body->SetFrame(L3D::player->GetFrame()); body->SetPosition(L3D::player->GetPosition()+vector3d(0,0,-1000)); Space::AddBody(body); } #endif if(event.key.keysym.sym == SDLK_F11) SDL_WM_ToggleFullScreen(L3D::scrSurface); if(event.key.keysym.sym == SDLK_F10) L3D::SetView(L3D::objectViewerView); if(event.key.keysym.sym == SDLK_F9) Serializer::Write::Game("quicksave.sav"); L3D::keyState[event.key.keysym.sym] = 1; L3D::onKeyPress.emit(&event.key.keysym); break; case SDL_KEYUP: L3D::keyState[event.key.keysym.sym] = 0; L3D::onKeyRelease.emit(&event.key.keysym); break; case SDL_MOUSEBUTTONDOWN: L3D::mouseButton[event.button.button] = 1; L3D::onMouseButtonDown.emit(event.button.button, event.button.x, event.button.y); break; case SDL_MOUSEBUTTONUP: L3D::mouseButton[event.button.button] = 1; L3D::onMouseButtonUp.emit(event.button.button, event.button.x, event.button.y); break; case SDL_MOUSEMOTION: L3D::mouseMotion[0] += event.motion.xrel; L3D::mouseMotion[1] += event.motion.yrel; //SDL_GetRelativeMouseState(&L3D::mouseMotion[0], &L3D::mouseMotion[1]); break; case SDL_QUIT: L3D::Quit(); break; } } } static void draw_intro(float _time) { static float lightCol[4] = { 1, 1, 1, 0 }; static float lightDir[4] = { 0, 1, 0, 0 }; static ObjParams params = { { 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0.0f, 0.0f, 0.1f}, { 0.0f, 0.0f, 0.0f }, /* pColor[3] */ { { { 1.0f, 1.0f, 1.0f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }, { { 0.8f, 0.6f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }, { { 0.5f, 0.5f, 0.5f }, { 0, 0, 0 }, { 0, 0, 0 }, 0 }, }, { "LEPHISTO" }, }; glRotatef(_time*10, 1, 0, 0); L3D::worldView->DrawBgStars(); glPushAttrib(GL_ALL_ATTRIB_BITS); sbreSetViewport(L3D::GetScrWidth(), L3D::GetScrHeight(), L3D::GetScrWidth()*0.5, 1.0f, 1000.0f, 0.0f, 1.0f); sbreSetDirLight(lightCol, lightDir); matrix4x4d rot = matrix4x4d::RotateYMatrix(_time) * matrix4x4d::RotateZMatrix(0.6*_time) * matrix4x4d::RotateXMatrix(_time*.7); Matrix m; Vector p; m.x1 = rot[0]; m.x2 = rot[4]; m.x3 = rot[ 8]; m.y1 = rot[1]; m.y2 = rot[5]; m.y3 = rot[ 9]; m.z1 = rot[2]; m.z2 = rot[6]; m.z3 = rot[10]; p.x = 0; p.y = 0; p.z = 80; sbreRenderModel(&p, &m, 61, ¶ms); glPopAttrib(); } void L3D::Start(void) { player = new Player(ShipType::SLEEK); player->SetLabel("Me"); Space::AddBody(player); cpan = new ShipCpanel(); sectorView = new SectorView(); systemView = new SystemView(); systemInfoView = new SystemInfoView(); worldView = new WorldView(); objectViewerView = new ObjectViewerView(); spaceStationView = new SpaceStationView(); infoView = new InfoView(); Gui::Fixed* splash = new Gui::Fixed(Gui::Screen::GetWidth(), Gui::Screen::GetHeight()); Gui::Screen::AddBaseWidget(splash, 0, 0); splash->SetTransparency(true); const float w = Gui::Screen::GetWidth() / 2; const float h = Gui::Screen::GetHeight() / 2; const int OPTS = 4; Gui::ToggleButton* opts[OPTS]; opts[0] = new Gui::ToggleButton(); opts[0]->SetShortcut(SDLK_1, KMOD_NONE); opts[1] = new Gui::ToggleButton(); opts[1]->SetShortcut(SDLK_2, KMOD_NONE); opts[2] = new Gui::ToggleButton(); opts[2]->SetShortcut(SDLK_3, KMOD_NONE); opts[3] = new Gui::ToggleButton(); opts[3]->SetShortcut(SDLK_4, KMOD_NONE); splash->Add(opts[0], w, h+64); splash->Add(new Gui::Label("New game starting on Earth"), w+32, h+64); splash->Add(opts[1], w, h+32); splash->Add(new Gui::Label("New game starting on debug point"), w+32, h+32); splash->Add(opts[2], w, h); splash->Add(new Gui::Label("Load quicksave"), w+32, h); splash->Add(opts[3], w, h-32); splash->Add(new Gui::Label("Quit"), w+32, h-32); splash->ShowAll(); int choice = 0; Uint32 last_time = SDL_GetTicks(); float _time = 0; do { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); L3D::HandleEvents(); SDL_ShowCursor(1); SDL_WM_GrabInput(SDL_GRAB_OFF); draw_intro(_time); Gui::Draw(); glFlush(); SDL_GL_SwapBuffers(); L3D::frameTime = 0.001*(SDL_GetTicks() - last_time); _time += L3D::frameTime; last_time = SDL_GetTicks(); /* Poll ui instead of using callbacks. :D */ for(int i = 0; i < OPTS; i++) if(opts[i]->GetPressed()) choice = i+1; } while(!choice); splash->HideAll(); if(choice == 1) { /* Earth start point. */ StarSystem s(0,0,0); HyperspaceTo(&s); //Frame* pframe = *(++(++(Space::rootFrame->m_children.begin()))); //player->SetFrame(pframe); /* TODO: There isn't a sensible way to find stations for a planet. */ SpaceStation* station = 0; for(Space::bodiesIter_t i = Space::bodies.begin(); i!=Space::bodies.end(); i++) { if((*i)->IsType(Object::SPACESTATION)) { station = (SpaceStation*)*i; break; } } assert(station); player->SetFrame(station->GetFrame()); player->SetDockedWith(station, 0); MainLoop(); } else if(choice == 2) { /* Debug start point. */ StarSystem s(0,0,1); HyperspaceTo(&s); Frame* pframe = *(Space::rootFrame->m_children.begin()); player->SetFrame(pframe); player->SetPosition(vector3d(0,0,EARTH_RADIUS)); MainLoop(); } else if(choice == 3) { /* Load quicksave. */ Serializer::Read::Game("quicksave.sav"); } } void L3D::MainLoop(void) { cpan->ShowAll(); SetView(worldView); Uint32 last_stats = SDL_GetTicks(); int frame_stat = 0; int phys_stat = 0; char fps_readout[32]; Uint32 time_before_frame = SDL_GetTicks(); Uint32 last_phys_update = time_before_frame; for(;;) { frame_stat++; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); currentView->Draw3D(); /* * TODO: HandleEvents at the moment must be after view->Draw3D and before * Gui::Draw so that labels drawn to screen can have mouse events correctly * detected. Gui::Draw wipes memory of label positions. */ L3D::HandleEvents(); /* Hide cursor for ship control. */ if(L3D::MouseButtonState(3)) { SDL_ShowCursor(0); SDL_WM_GrabInput(SDL_GRAB_ON); } else { SDL_ShowCursor(1); SDL_WM_GrabInput(SDL_GRAB_OFF); } Gui::Draw(); #ifdef DEBUG if(L3D::showDebugInfo) { Gui::Screen::EnterOrtho(); glColor3f(1, 1, 1); glTranslatef(0, Gui::Screen::GetHeight()-20, 0); Gui::Screen::RenderString(fps_readout); Gui::Screen::LeaveOrtho(); } #endif glFlush(); SDL_GL_SwapBuffers(); //if(glGetError()) printf("GL: %s\n", gluErrorString(glGetError())); L3D::frameTime = 0.001*(SDL_GetTicks() - time_before_frame); time_before_frame = SDL_GetTicks(); /* Fixed 62.5hz physics. */ while(time_before_frame - last_phys_update > 16) { last_phys_update += 16; const float step = L3D::GetTimeStep(); if(step) Space::TimeStep(step); gameTime += step; phys_stat++; } currentView->Update(); if(SDL_GetTicks() - last_stats > 1000) { snprintf(fps_readout, sizeof(fps_readout), "%d fps, %d phys updates", frame_stat, phys_stat); frame_stat = 0; phys_stat = 0; last_stats += 1000; } } } StarSystem* L3D::GetSelectedSystem(void) { int sector_x, sector_y, system_idx; L3D::sectorView->GetSelectedSystem(§or_x, §or_y, &system_idx); if(system_idx == -1) { selectedSystem = 0; return NULL; } if(selectedSystem) { if(!selectedSystem->IsSystem(sector_x, sector_y, system_idx)) { delete selectedSystem; selectedSystem = 0; } } if(!selectedSystem) { selectedSystem = new StarSystem(sector_x, sector_y, system_idx); } return selectedSystem; } void L3D::HyperspaceTo(StarSystem* dest) { int sec_x, sec_y, sys_idx; dest->GetPos(&sec_x, &sec_y, &sys_idx); if(currentSystem) delete currentSystem; currentSystem = new StarSystem(sec_x, sec_y, sys_idx); Space::Clear(); Space::BuildSystem(); float ang = rng.Double(M_PI); L3D::player->SetPosition(vector3d(sin(ang)*AU, cos(ang)*AU,0)); L3D::player->SetVelocity(vector3d(0.0)); } void L3D::Serialize(void) { using namespace Serializer::Write; StarSystem::Serialize(selectedSystem); wr_double(gameTime); StarSystem::Serialize(currentSystem); Space::Serialize(); sectorView->Save(); worldView->Save(); } void L3D::Unserialize(void) { using namespace Serializer::Read; selectedSystem = StarSystem::Unserialize(); gameTime = rd_double(); currentSystem = StarSystem::Unserialize(); Space::Clear(); if(L3D::player) { L3D::player->MarkDead(); Space::bodies.remove(L3D::player); delete L3D::player; L3D::player = 0; } Space::Unserialize(); sectorView->Load(); worldView->Load(); } IniConfig::IniConfig(const char* filename) { FILE* f = fopen(filename, "r"); if(!f) { fprintf(stderr, "Could not open '%s'.\n", filename); L3D::Quit(); } char buf[1024]; while(fgets(buf, sizeof(buf), f)) { if(buf[0] == '#') continue; char* sep = strchr(buf, '='); char* kend = sep; if(!sep) continue; *sep = 0; /* Strip whitespace. */ while(isspace(*(--kend))) *kend = 0; while(isspace(*(++sep))) *sep = 0; /* Snip \r, \n. */ char* vend = sep; while(*(++vend)) if((*vend == '\r') || (*vend == '\n')) { *vend = 0; break; } std::string key = std::string(buf); std::string val = std::string(sep); (*this)[key] = val; } fclose(f); } void sigsegv_handler(int signum) { if(signum == SIGSEGV) { printf("Segfault! All is lost! Abondon ship\n"); SDL_Quit(); abort(); } } int main(int argc, char** argv) { printf("Lephisto3D's super high tech demo!\n"); signal(SIGSEGV, sigsegv_handler); IniConfig cfg("config.ini"); L3D::Init(cfg); L3D::Start(); L3D::Quit(); return 0; }