514 lines
15 KiB
C++
514 lines
15 KiB
C++
#include <signal.h>
|
|
#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<void, SDL_keysym*> L3D::onKeyPress;
|
|
sigc::signal<void, SDL_keysym*> L3D::onKeyRelease;
|
|
sigc::signal<void, int, int, int> L3D::onMouseButtonUp;
|
|
sigc::signal<void, int, int, int> 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;
|
|
}
|
|
|