Exemple #1
0
int
splash_main(int argc, char **argv)
{
	osd_surface_t *surface;
	int ret = -1;
	int c, opt_index;
	char *opt_p = NULL, *opt_s = NULL;

	av_init();

	if (av_get_mode() == AV_MODE_PAL) {
		width = 720;
		height = 576;
		av_set_mode(AV_MODE_PAL);
	} else {
		width = 720;
		height = 480;
	}

	if ((surface=osd_create_surface(width, height, 0, OSD_FB)) == NULL) {
		goto err;
	}

	while ((c=getopt_long(argc, argv,
			      "blp:s:", opts, &opt_index)) != -1) {
		switch (c) {
		case 'b':
			ret = blank(surface);
			break;
#if defined(STANDALONE)
		case 'l':
			ret = draw_logo(surface);
			break;
#endif /* STANDALONE */
		case 'p':
			opt_p = strdup(optarg);
			break;
		case 's':
			opt_s = strdup(optarg);
			break;
		}
	}

	if (opt_p && opt_s) {
		ret = draw_progress(surface, atoi(opt_p), atoi(opt_s));
	}

 err:
	return ret;
}
Exemple #2
0
int parse_command(char *string, int length) {
	char *command;
	char *origstring = string;
	int parsed=0;

#ifdef DEBUG
	fprintf (logfile, "%s\n", string);
	fflush (logfile);
#endif

	parsed = strlen(string)+1;
	
	if (strcmp(string,"QUIT")==0) {
		return 1;
	}	

	command = strtok(string," ");

	if (strcmp(command,"TEXT")==0) {
		char *line = strtok(NULL,"\0");
		int length = strlen(line);		
		while (length>50) {
			draw_text(line,50);
			line+=50;
			length-=50;
		}
		draw_text(line,length);
	} else if (strcmp(command,"STATUS")==0) {
		draw_status(strtok(NULL,"\0"),0);
	} else if (strcmp(command,"SUCCESS")==0) {
		draw_status(strtok(NULL,"\0"),TEXT_FOREGROUND);
	} else if (strcmp(command,"FAILURE")==0) {
		draw_status(strtok(NULL,"\0"),RED);
	} else if (strcmp(command,"PROGRESS")==0) {
		draw_progress(atoi(strtok(NULL,"\0")));
	} else if (strcmp(command,"CLEAR")==0) {
		text_clear();
	} else if (strcmp(command,"TIMEOUT")==0) {
		timeout=(atoi(strtok(NULL,"\0")));
	} else if (strcmp(command,"QUIT")==0) {
		return 1;
	}

	return 0;
}
Exemple #3
0
void dir_draw() {
  switch(dir_ui) {
  case 0:
    if(dir_fatalerr)
      fprintf(stderr, "%s.\n", dir_fatalerr);
    break;
  case 1:
    if(dir_fatalerr)
      fprintf(stderr, "\r%s.\n", dir_fatalerr);
    else if(dir_output.size)
      fprintf(stderr, "\r%-55s %8d files /%s",
        cropstr(dir_curpath, 55), dir_output.items, formatsize(dir_output.size));
    else
      fprintf(stderr, "\r%-65s %8d files", cropstr(dir_curpath, 65), dir_output.items);
    break;
  case 2:
    browse_draw();
    if(dir_fatalerr)
      draw_error(dir_curpath, dir_fatalerr);
    else
      draw_progress();
    break;
  }
}
Exemple #4
0
void Pi::Init(const std::map<std::string,std::string> &options, bool no_gui)
{
#ifdef PIONEER_PROFILER
	Profiler::reset();
#endif

	Profiler::Timer timer;
	timer.Start();

	OS::EnableBreakpad();
	OS::NotifyLoadBegin();

	FileSystem::Init();
	FileSystem::userFiles.MakeDirectory(""); // ensure the config directory exists
#ifdef PIONEER_PROFILER
	FileSystem::userFiles.MakeDirectory("profiler");
	profilerPath = FileSystem::JoinPathBelow(FileSystem::userFiles.GetRoot(), "profiler");
#endif

	Pi::config = new GameConfig(options);

	if (config->Int("RedirectStdio"))
		OS::RedirectStdio();

	std::string version(PIONEER_VERSION);
	if (strlen(PIONEER_EXTRAVERSION)) version += " (" PIONEER_EXTRAVERSION ")";
	const char* platformName = SDL_GetPlatform();
	if(platformName)
		Output("ver %s on: %s\n\n", version.c_str(), platformName);
	else
		Output("ver %s but could not detect platform name.\n\n", version.c_str());

	Output("%s\n", OS::GetOSInfoString().c_str());

	ModManager::Init();

	Lang::Resource res(Lang::GetResource("core", config->String("Lang")));
	Lang::MakeCore(res);

	Pi::detail.planets = config->Int("DetailPlanets");
	Pi::detail.textures = config->Int("Textures");
	Pi::detail.fracmult = config->Int("FractalMultiple");
	Pi::detail.cities = config->Int("DetailCities");

	// Initialize SDL
	Uint32 sdlInitFlags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
#if defined(DEBUG) || defined(_DEBUG)
	sdlInitFlags |= SDL_INIT_NOPARACHUTE;
#endif
	if (SDL_Init(sdlInitFlags) < 0) {
		Error("SDL initialization failed: %s\n", SDL_GetError());
	}
	SDL_version ver;
	SDL_GetVersion(&ver);
	Output("SDL Version %d.%d.%d\n", ver.major, ver.minor, ver.patch);

	Graphics::RendererOGL::RegisterRenderer();

	// Do rest of SDL video initialization and create Renderer
	Graphics::Settings videoSettings = {};
	videoSettings.rendererType = Graphics::RENDERER_OPENGL;
	videoSettings.width = config->Int("ScrWidth");
	videoSettings.height = config->Int("ScrHeight");
	videoSettings.fullscreen = (config->Int("StartFullscreen") != 0);
	videoSettings.hidden = no_gui;
	videoSettings.requestedSamples = config->Int("AntiAliasingMode");
	videoSettings.vsync = (config->Int("VSync") != 0);
	videoSettings.useTextureCompression = (config->Int("UseTextureCompression") != 0);
	videoSettings.enableDebugMessages = (config->Int("EnableGLDebug") != 0);
	videoSettings.iconFile = OS::GetIconFilename();
	videoSettings.title = "Pioneer";

	Pi::renderer = Graphics::Init(videoSettings);

	Pi::CreateRenderTarget(videoSettings.width, videoSettings.height);
	Pi::rng.IncRefCount(); // so nothing tries to free it
	Pi::rng.seed(time(0));

	InitJoysticks();
	
	// we can only do bindings once joysticks are initialised.
	if (!no_gui) // This re-saves the config file. With no GUI we want to allow multiple instances in parallel.
		KeyBindings::InitBindings();

	joystickEnabled = (config->Int("EnableJoystick")) ? true : false;
	mouseYInvert = (config->Int("InvertMouseY")) ? true : false;
	compactScanner = (config->Int("CompactScanner")) ? true : false;

	navTunnelDisplayed = (config->Int("DisplayNavTunnel")) ? true : false;
	speedLinesDisplayed = (config->Int("SpeedLines")) ? true : false;
	hudTrailsDisplayed = (config->Int("HudTrails")) ? true : false;

	EnumStrings::Init();

	// get threads up
	Uint32 numThreads = config->Int("WorkerThreads");
	const int numCores = OS::GetNumCores();
	assert(numCores > 0);
	if (numThreads == 0) numThreads = std::max(Uint32(numCores) - 1, 1U);
	asyncJobQueue.reset(new AsyncJobQueue(numThreads));
	Output("started %d worker threads\n", numThreads);
	syncJobQueue.reset(new SyncJobQueue);
	
	Output("ShipType::Init()\n");
	// XXX early, Lua init needs it
	ShipType::Init();

	// XXX UI requires Lua  but Pi::ui must exist before we start loading
	// templates. so now we have crap everywhere :/
	Output("Lua::Init()\n");
	Lua::Init();

	Pi::ui.Reset(new UI::Context(Lua::manager, Pi::renderer, Graphics::GetScreenWidth(), Graphics::GetScreenHeight()));

	LuaInit();

	// Gui::Init shouldn't initialise any VBOs, since we haven't tested
	// that the capability exists. (Gui does not use VBOs so far)
	Gui::Init(renderer, Graphics::GetScreenWidth(), Graphics::GetScreenHeight(), 800, 600);

	UI::Box *box = Pi::ui->VBox(5);
	UI::Label *label = Pi::ui->Label("");
	label->SetFont(UI::Widget::FONT_HEADING_NORMAL);
	UI::Gauge *gauge = Pi::ui->Gauge();
	Pi::ui->GetTopLayer()->SetInnerWidget(
		Pi::ui->Margin(10, UI::Margin::HORIZONTAL)->SetInnerWidget(
			Pi::ui->Expand()->SetInnerWidget(
				Pi::ui->Align(UI::Align::MIDDLE)->SetInnerWidget(
					box->PackEnd(UI::WidgetSet(
						label,
						gauge
					))
				)
			)
		)
    );

	draw_progress(gauge, label, 0.0f);

	Output("GalaxyGenerator::Init()\n");
	if (config->HasEntry("GalaxyGenerator"))
		GalaxyGenerator::Init(config->String("GalaxyGenerator"),
			config->Int("GalaxyGeneratorVersion", GalaxyGenerator::LAST_VERSION));
	else
		GalaxyGenerator::Init();

	draw_progress(gauge, label, 0.1f);

	Output("FaceParts::Init()\n");
	FaceParts::Init();
	draw_progress(gauge, label, 0.2f);

	Output("new ModelCache\n");
	modelCache = new ModelCache(Pi::renderer);
	draw_progress(gauge, label, 0.3f);

	Output("Shields::Init\n");
	Shields::Init(Pi::renderer);
	draw_progress(gauge, label, 0.4f);

//unsigned int control_word;
//_clearfp();
//_controlfp_s(&control_word, _EM_INEXACT | _EM_UNDERFLOW | _EM_ZERODIVIDE, _MCW_EM);
//double fpexcept = Pi::timeAccelRates[1] / Pi::timeAccelRates[0];

	Output("BaseSphere::Init\n");
	BaseSphere::Init();
	draw_progress(gauge, label, 0.5f);

	Output("CityOnPlanet::Init\n");
	CityOnPlanet::Init();
	draw_progress(gauge, label, 0.6f);
	
	Output("SpaceStation::Init\n");
	SpaceStation::Init();
	draw_progress(gauge, label, 0.7f);
	
	Output("NavLights::Init\n");
	NavLights::Init(Pi::renderer);
	draw_progress(gauge, label, 0.75f);

	Output("Sfx::Init\n");
	Sfx::Init(Pi::renderer);
	draw_progress(gauge, label, 0.8f);

	if (!no_gui && !config->Int("DisableSound")) {
		Output("Sound::Init\n");
		Sound::Init();
		Sound::SetMasterVolume(config->Float("MasterVolume"));
		Sound::SetSfxVolume(config->Float("SfxVolume"));
		GetMusicPlayer().SetVolume(config->Float("MusicVolume"));

		Sound::Pause(0);
		if (config->Int("MasterMuted")) Sound::Pause(1);
		if (config->Int("SfxMuted")) Sound::SetSfxVolume(0.f);
		if (config->Int("MusicMuted")) GetMusicPlayer().SetEnabled(false);
	}
	draw_progress(gauge, label, 0.9f);

	OS::NotifyLoadEnd();
	draw_progress(gauge, label, 1.0f);

#if 0
	// frame test code

	Frame *root = new Frame(0, "root", 0);
	Frame *p1 = new Frame(root, "p1", Frame::FLAG_HAS_ROT);
	Frame *p1r = new Frame(p1, "p1r", Frame::FLAG_ROTATING);
	Frame *m1 = new Frame(p1, "m1", Frame::FLAG_HAS_ROT);
	Frame *m1r = new Frame(m1, "m1r", Frame::FLAG_ROTATING);
	Frame *p2 = new Frame(root, "p2", Frame::FLAG_HAS_ROT);
	Frame *p2r = new Frame(p2, "pr2", Frame::FLAG_ROTATING);

	p1->SetPosition(vector3d(1000,0,0));
	p1->SetVelocity(vector3d(0,1,0));
	p2->SetPosition(vector3d(0,2000,0));
	p2->SetVelocity(vector3d(-2,0,0));
	p1r->SetAngVelocity(vector3d(0,0,0.0001));
	p1r->SetOrient(matrix3x3d::BuildRotate(M_PI/4, vector3d(0,0,1)));
	p2r->SetAngVelocity(vector3d(0,0,-0.0004));
	p2r->SetOrient(matrix3x3d::BuildRotate(-M_PI/2, vector3d(0,0,1)));
	root->UpdateOrbitRails(0, 0);

	CargoBody *c1 = new CargoBody(Equip::Type::SLAVES);
	c1->SetFrame(p1r);
	c1->SetPosition(vector3d(0,180,0));
//	c1->SetVelocity(vector3d(1,0,0));
	CargoBody *c2 = new CargoBody(Equip::Type::SLAVES);
	c2->SetFrame(p1r);
	c2->SetPosition(vector3d(0,200,0));
//	c2->SetVelocity(vector3d(1,0,0));

	vector3d pos = c1->GetPositionRelTo(p1);
	vector3d vel = c1->GetVelocityRelTo(p1);
	double speed = vel.Length();
	vector3d pos2 = c2->GetPositionRelTo(p1);
	vector3d vel2 = c2->GetVelocityRelTo(p1);
	double speed2 = vel2.Length();

	double speed3 = c2->GetVelocityRelTo(c1).Length();
	c2->SwitchToFrame(p1);
	vector3d vel4 = c2->GetVelocityRelTo(c1);
	double speed4 = c2->GetVelocityRelTo(c1).Length();

	root->UpdateOrbitRails(0, 1.0);

	//buildrotate test

	matrix3x3d m = matrix3x3d::BuildRotate(M_PI/2, vector3d(0,0,1));
	vector3d v = m * vector3d(1,0,0);

/*	vector3d pos = p1r->GetPositionRelTo(p2r);
	vector3d vel = p1r->GetVelocityRelTo(p2r);
	matrix3x3d o1 = p1r->GetOrientRelTo(p2r);
	double speed = vel.Length();
	vector3d pos2 = p2r->GetPositionRelTo(p1r);
	vector3d vel2 = p2r->GetVelocityRelTo(p1r);
	matrix3x3d o2 = p2r->GetOrientRelTo(p1r);
	double speed2 = vel2.Length();
*/	root->UpdateOrbitRails(0, 1.0/60);

	delete p2r; delete p2; delete m1r; delete m1; delete p1r; delete p1; delete root;
	delete c1; delete c2;

#endif

#if 0
	// test code to produce list of ship stats

	FILE *pStatFile = fopen("shipstat.csv","wt");
	if (pStatFile)
	{
		fprintf(pStatFile, "name,modelname,hullmass,capacity,fakevol,rescale,xsize,ysize,zsize,facc,racc,uacc,sacc,aacc,exvel\n");
		for (auto iter : ShipType::types)
		{
			const ShipType *shipdef = &(iter.second);
			SceneGraph::Model *model = Pi::FindModel(shipdef->modelName, false);

			double hullmass = shipdef->hullMass;
			double capacity = shipdef->capacity;

			double xsize = 0.0, ysize = 0.0, zsize = 0.0, fakevol = 0.0, rescale = 0.0, brad = 0.0;
			if (model) {
				std::unique_ptr<SceneGraph::Model> inst(model->MakeInstance());
				model->CreateCollisionMesh();
				Aabb aabb = model->GetCollisionMesh()->GetAabb();
				xsize = aabb.max.x-aabb.min.x;
				ysize = aabb.max.y-aabb.min.y;
				zsize = aabb.max.z-aabb.min.z;
				fakevol = xsize*ysize*zsize;
				brad = aabb.GetRadius();
				rescale = pow(fakevol/(100 * (hullmass+capacity)), 0.3333333333);
			}

			double simass = (hullmass + capacity) * 1000.0;
			double angInertia = (2/5.0)*simass*brad*brad;
			double acc1 = shipdef->linThrust[ShipType::THRUSTER_FORWARD] / (9.81*simass);
			double acc2 = shipdef->linThrust[ShipType::THRUSTER_REVERSE] / (9.81*simass);
			double acc3 = shipdef->linThrust[ShipType::THRUSTER_UP] / (9.81*simass);
			double acc4 = shipdef->linThrust[ShipType::THRUSTER_RIGHT] / (9.81*simass);
			double acca = shipdef->angThrust/angInertia;
			double exvel = shipdef->effectiveExhaustVelocity;

			fprintf(pStatFile, "%s,%s,%.1f,%.1f,%.1f,%.3f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%f,%.1f\n",
				shipdef->name.c_str(), shipdef->modelName.c_str(), hullmass, capacity,
				fakevol, rescale, xsize, ysize, zsize, acc1, acc2, acc3, acc4, acca, exvel);
		}
		fclose(pStatFile);
	}
#endif

	luaConsole = new LuaConsole();
	KeyBindings::toggleLuaConsole.onPress.connect(sigc::mem_fun(Pi::luaConsole, &LuaConsole::Toggle));

	planner = new TransferPlanner();

	timer.Stop();
	Output("\n\nLoading took: %lf milliseconds\n", timer.millicycles());
}
Exemple #5
0
void Pi::Init()
{
	config.Load(GetPiUserDir() + "config.ini");

	Pi::detail.planets = config.Int("DetailPlanets");
	Pi::detail.cities = config.Int("DetailCities");

	int width = config.Int("ScrWidth");
	int height = config.Int("ScrHeight");
	const SDL_VideoInfo *info = NULL;
	Uint32 sdlInitFlags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
#if defined _WIN32 && defined _DEBUG
	sdlInitFlags |= SDL_INIT_NOPARACHUTE;
#endif
	if (SDL_Init(sdlInitFlags) < 0) {
		fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError());
		exit(-1);
	}

	InitJoysticks();

	// no mode set, find an ok one
	if ((width <= 0) || (height <= 0)) {
		SDL_Rect **modes = SDL_ListModes(NULL, SDL_HWSURFACE | SDL_FULLSCREEN);
		
		if (modes == 0) {
			fprintf(stderr, "It seems no video modes are available...");
		}
		if (modes == (SDL_Rect **)-1) {
			// hm. all modes available. odd. try 800x600
			width = 800; height = 600;
		} else {
			width = modes[0]->w;
			height = modes[0]->h;
		}
	}

	info = SDL_GetVideoInfo();
	printf("SDL_GetVideoInfo says %d bpp\n", info->vfmt->BitsPerPixel);
	switch (info->vfmt->BitsPerPixel) {
		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 24:
		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, "Invalid pixel depth: %d bpp\n", info->vfmt->BitsPerPixel);
	} 
	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 ((Pi::scrSurface = SDL_SetVideoMode(width, height, info->vfmt->BitsPerPixel, flags)) == 0) {
		// fall back on 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 ((Pi::scrSurface = SDL_SetVideoMode(width, height, info->vfmt->BitsPerPixel, flags)) == 0) {
			fprintf(stderr, "Failed to set video mode: %s", SDL_GetError());
		}
	}

	glewInit();
	SDL_WM_SetCaption("Pioneer","Pioneer");
	Pi::scrWidth = width;
	Pi::scrHeight = height;
	Pi::scrAspect = width / (float)height;

	Pi::rng.seed(time(NULL));

	InitOpenGL();
	GLFTInit();
	// Gui::Init shouldn't initialise any VBOs, since we haven't tested
	// that the capability exists. (Gui does not use VBOs so far)
	Gui::Init(scrWidth, scrHeight, 800, 600);
	if (!GLEW_ARB_vertex_buffer_object) {
		Error("OpenGL extension ARB_vertex_buffer_object not supported. Pioneer can not run on your graphics card.");
	}
	Render::Init(width, height);
	draw_progress(0.1f);
	Galaxy::Init();
	draw_progress(0.2f);
	NameGenerator::Init();
	if (config.Int("DisableShaders")) Render::ToggleShaders();
	if (config.Int("EnableHDR")) Render::ToggleHDR();

	draw_progress(0.3f);
	LmrModelCompilerInit();

//unsigned int control_word;
//_clearfp();
//_controlfp_s(&control_word, _EM_INEXACT | _EM_UNDERFLOW, _MCW_EM);
//double fpexcept = Pi::timeAccelRates[1] / Pi::timeAccelRates[0];


	draw_progress(0.4f);
	ShipType::Init();


	draw_progress(0.5f);
	GeoSphere::Init();
	draw_progress(0.6f);
	Space::Init();
	draw_progress(0.7f);
	Polit::Init();
	draw_progress(0.8f);
	SpaceStation::Init();
	draw_progress(0.9f);

	if (!config.Int("DisableSound")) {
		Sound::Init();
		Sound::SetGlobalVolume(config.Float("SfxVolume"));
		Sound::Pause(0);
	}
	draw_progress(1.0f);

	// test code to produce list of ship stats

	FILE *pStatFile = fopen("shipstat.csv","wt");
	if (pStatFile)
	{
		fprintf(pStatFile, "name,lmrname,hullmass,capacity,xsize,ysize,zsize,facc,racc,uacc,aacc\n");
		for (std::map<std::string, ShipType>::iterator i = ShipType::types.begin();
				i != ShipType::types.end(); ++i)
		{
			ShipType *shipdef = &(i->second);
			LmrModel *lmrModel = LmrLookupModelByName(shipdef->lmrModelName.c_str());
			LmrObjParams lmrParams; memset(&lmrParams, 0, sizeof(LmrObjParams));
			LmrCollMesh *collMesh = new LmrCollMesh(lmrModel, &lmrParams);
			Aabb aabb = collMesh->GetAabb();
		
			double hullmass = shipdef->hullMass;
			double capacity = shipdef->capacity;
			double xsize = aabb.max.x-aabb.min.x;
			double ysize = aabb.max.y-aabb.min.y;
			double zsize = aabb.max.z-aabb.min.z;
			double brad = aabb.GetBoundingRadius();
			double simass = (hullmass + capacity) * 1000.0;
			double angInertia = (2/5.0)*simass*brad*brad;
			double acc1 = shipdef->linThrust[ShipType::THRUSTER_FORWARD] / (9.81*simass);
			double acc2 = shipdef->linThrust[ShipType::THRUSTER_REVERSE] / (9.81*simass);
			double acc3 = shipdef->linThrust[ShipType::THRUSTER_UP] / (9.81*simass);
			double acca = shipdef->angThrust/angInertia;

			fprintf(pStatFile, "%s,%s,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%f\n",
				shipdef->name.c_str(), shipdef->lmrModelName.c_str(), hullmass, capacity,
				xsize, ysize, zsize, acc1, acc2, acc3, acca);
		}
		fclose(pStatFile);
	}

	gameMenuView = new GameMenuView();
	config.Save();
}
Exemple #6
0
static void
draw_func (GtkDrawingArea *da,
           cairo_t        *cr,
           int             width,
           int             height,
           gpointer        data)
{
  GtkWidget *widget = GTK_WIDGET (da);
  gint panewidth;
  gint x, y;

  panewidth = width / 2;

  cairo_rectangle (cr, 0, 0, width, height);
  cairo_set_source_rgb (cr, 0.9, 0.9, 0.9);
  cairo_fill (cr);

  x = y = 10;
  draw_horizontal_scrollbar (widget, cr, x, y, panewidth - 20, 30, GTK_STATE_FLAG_NORMAL, &height);
  y += height + 8;
  draw_horizontal_scrollbar (widget, cr, x, y, panewidth - 20, 40, GTK_STATE_FLAG_PRELIGHT, &height);
  y += height + 8;
  draw_horizontal_scrollbar (widget, cr, x, y, panewidth - 20, 50, GTK_STATE_FLAG_ACTIVE|GTK_STATE_FLAG_PRELIGHT, &height);

  y += height + 8;
  draw_text (widget, cr, x,  y, panewidth - 20, 20, "Not selected", GTK_STATE_FLAG_NORMAL);
  y += 20 + 10;
  draw_text (widget, cr, x, y, panewidth - 20, 20, "Selected", GTK_STATE_FLAG_SELECTED);

  x = 10;
  y += 20 + 10;
  draw_check (widget, cr,  x, y, GTK_STATE_FLAG_NORMAL, &width, &height);
  x += width + 10;
  draw_check (widget, cr,  x, y, GTK_STATE_FLAG_CHECKED, &width, &height);
  x += width + 10;
  draw_radio (widget, cr,  x, y, GTK_STATE_FLAG_NORMAL, &width, &height);
  x += width + 10;
  draw_radio (widget, cr, x, y, GTK_STATE_FLAG_CHECKED, &width, &height);
  x = 10;

  y += height + 10;
  draw_progress (widget, cr, x, y, panewidth - 20, 50, &height);

  y += height + 10;
  draw_scale (widget, cr, x, y, panewidth - 20, 75, &height);

  y += height + 20;
  draw_notebook (widget, cr, x, y, panewidth - 20, 160);

  /* Second column */
  x += panewidth;
  y = 10;
  draw_menu (widget, cr, x, y, panewidth - 20, &height);

  y += height + 10;
  draw_menubar (widget, cr, x, y, panewidth - 20, &height);

  y += height + 20;
  draw_spinbutton (widget, cr, x, y, panewidth - 20, &height);

  y += height + 30;
  draw_combobox (widget, cr, x, y, panewidth - 20, FALSE, &height);

  y += height + 10;
  draw_combobox (widget, cr, 10 + panewidth, y, panewidth - 20, TRUE, &height);
}
int journal_file_verify(
                JournalFile *f,
                const char *key,
                usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
                bool show_progress) {
        int r;
        Object *o;
        uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;

        uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
        sd_id128_t entry_boot_id;
        bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
        uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0, n_tags = 0;
        usec_t last_usec = 0;
        int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
        unsigned i;
        bool found_last = false;
#ifdef HAVE_GCRYPT
        uint64_t last_tag = 0;
#endif
        assert(f);

        if (key) {
#ifdef HAVE_GCRYPT
                r = journal_file_parse_verification_key(f, key);
                if (r < 0) {
                        log_error("Failed to parse seed.");
                        return r;
                }
#else
                return -ENOTSUP;
#endif
        } else if (f->seal)
                return -ENOKEY;

        data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
        if (data_fd < 0) {
                log_error_errno(errno, "Failed to create data file: %m");
                r = -errno;
                goto fail;
        }

        entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
        if (entry_fd < 0) {
                log_error_errno(errno, "Failed to create entry file: %m");
                r = -errno;
                goto fail;
        }

        entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
        if (entry_array_fd < 0) {
                log_error_errno(errno, "Failed to create entry array file: %m");
                r = -errno;
                goto fail;
        }

        if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) {
                log_error("Cannot verify file with unknown extensions.");
                r = -ENOTSUP;
                goto fail;
        }

        for (i = 0; i < sizeof(f->header->reserved); i++)
                if (f->header->reserved[i] != 0) {
                        error(offsetof(Header, reserved[i]), "Reserved field is non-zero");
                        r = -EBADMSG;
                        goto fail;
                }

        /* First iteration: we go through all objects, verify the
         * superficial structure, headers, hashes. */

        p = le64toh(f->header->header_size);
        for (;;) {
                /* Early exit if there are no objects in the file, at all */
                if (le64toh(f->header->tail_object_offset) == 0)
                        break;

                if (show_progress)
                        draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec);

                r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
                if (r < 0) {
                        error(p, "Invalid object");
                        goto fail;
                }

                if (p > le64toh(f->header->tail_object_offset)) {
                        error(offsetof(Header, tail_object_offset), "Invalid tail object pointer");
                        r = -EBADMSG;
                        goto fail;
                }

                n_objects ++;

                r = journal_file_object_verify(f, p, o);
                if (r < 0) {
                        error(p, "Invalid object contents: %s", strerror(-r));
                        goto fail;
                }

                if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
                    (o->object.flags & OBJECT_COMPRESSED_LZ4)) {
                        error(p, "Objected with double compression");
                        r = -EINVAL;
                        goto fail;
                }

                if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
                        error(p, "XZ compressed object in file without XZ compression");
                        r = -EBADMSG;
                        goto fail;
                }

                if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
                        error(p, "LZ4 compressed object in file without LZ4 compression");
                        r = -EBADMSG;
                        goto fail;
                }

                switch (o->object.type) {

                case OBJECT_DATA:
                        r = write_uint64(data_fd, p);
                        if (r < 0)
                                goto fail;

                        n_data++;
                        break;

                case OBJECT_FIELD:
                        n_fields++;
                        break;

                case OBJECT_ENTRY:
                        if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
                                error(p, "First entry before first tag");
                                r = -EBADMSG;
                                goto fail;
                        }

                        r = write_uint64(entry_fd, p);
                        if (r < 0)
                                goto fail;

                        if (le64toh(o->entry.realtime) < last_tag_realtime) {
                                error(p, "Older entry after newer tag");
                                r = -EBADMSG;
                                goto fail;
                        }

                        if (!entry_seqnum_set &&
                            le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
                                error(p, "Head entry sequence number incorrect");
                                r = -EBADMSG;
                                goto fail;
                        }

                        if (entry_seqnum_set &&
                            entry_seqnum >= le64toh(o->entry.seqnum)) {
                                error(p, "Entry sequence number out of synchronization");
                                r = -EBADMSG;
                                goto fail;
                        }

                        entry_seqnum = le64toh(o->entry.seqnum);
                        entry_seqnum_set = true;

                        if (entry_monotonic_set &&
                            sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
                            entry_monotonic > le64toh(o->entry.monotonic)) {
                                error(p, "Entry timestamp out of synchronization");
                                r = -EBADMSG;
                                goto fail;
                        }

                        entry_monotonic = le64toh(o->entry.monotonic);
                        entry_boot_id = o->entry.boot_id;
                        entry_monotonic_set = true;

                        if (!entry_realtime_set &&
                            le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
                                error(p, "Head entry realtime timestamp incorrect");
                                r = -EBADMSG;
                                goto fail;
                        }

                        entry_realtime = le64toh(o->entry.realtime);
                        entry_realtime_set = true;

                        n_entries ++;
                        break;

                case OBJECT_DATA_HASH_TABLE:
                        if (n_data_hash_tables > 1) {
                                error(p, "More than one data hash table");
                                r = -EBADMSG;
                                goto fail;
                        }

                        if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
                            le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
                                error(p, "header fields for data hash table invalid");
                                r = -EBADMSG;
                                goto fail;
                        }

                        n_data_hash_tables++;
                        break;

                case OBJECT_FIELD_HASH_TABLE:
                        if (n_field_hash_tables > 1) {
                                error(p, "More than one field hash table");
                                r = -EBADMSG;
                                goto fail;
                        }

                        if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
                            le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
                                error(p, "Header fields for field hash table invalid");
                                r = -EBADMSG;
                                goto fail;
                        }

                        n_field_hash_tables++;
                        break;

                case OBJECT_ENTRY_ARRAY:
                        r = write_uint64(entry_array_fd, p);
                        if (r < 0)
                                goto fail;

                        if (p == le64toh(f->header->entry_array_offset)) {
                                if (found_main_entry_array) {
                                        error(p, "More than one main entry array");
                                        r = -EBADMSG;
                                        goto fail;
                                }

                                found_main_entry_array = true;
                        }

                        n_entry_arrays++;
                        break;

                case OBJECT_TAG:
                        if (!JOURNAL_HEADER_SEALED(f->header)) {
                                error(p, "Tag object in file without sealing");
                                r = -EBADMSG;
                                goto fail;
                        }

                        if (le64toh(o->tag.seqnum) != n_tags + 1) {
                                error(p, "Tag sequence number out of synchronization");
                                r = -EBADMSG;
                                goto fail;
                        }

                        if (le64toh(o->tag.epoch) < last_epoch) {
                                error(p, "Epoch sequence out of synchronization");
                                r = -EBADMSG;
                                goto fail;
                        }

#ifdef HAVE_GCRYPT
                        if (f->seal) {
                                uint64_t q, rt;

                                debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));

                                rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
                                if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
                                        error(p, "tag/entry realtime timestamp out of synchronization");
                                        r = -EBADMSG;
                                        goto fail;
                                }

                                /* OK, now we know the epoch. So let's now set
                                 * it, and calculate the HMAC for everything
                                 * since the last tag. */
                                r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
                                if (r < 0)
                                        goto fail;

                                r = journal_file_hmac_start(f);
                                if (r < 0)
                                        goto fail;

                                if (last_tag == 0) {
                                        r = journal_file_hmac_put_header(f);
                                        if (r < 0)
                                                goto fail;

                                        q = le64toh(f->header->header_size);
                                } else
                                        q = last_tag;

                                while (q <= p) {
                                        r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o);
                                        if (r < 0)
                                                goto fail;

                                        r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q);
                                        if (r < 0)
                                                goto fail;

                                        q = q + ALIGN64(le64toh(o->object.size));
                                }

                                /* Position might have changed, let's reposition things */
                                r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
                                if (r < 0)
                                        goto fail;

                                if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
                                        error(p, "Tag failed verification");
                                        r = -EBADMSG;
                                        goto fail;
                                }

                                f->hmac_running = false;
                                last_tag_realtime = rt;
                                last_sealed_realtime = entry_realtime;
                        }

                        last_tag = p + ALIGN64(le64toh(o->object.size));
#endif

                        last_epoch = le64toh(o->tag.epoch);

                        n_tags ++;
                        break;

                default:
                        n_weird ++;
                }

                if (p == le64toh(f->header->tail_object_offset)) {
                        found_last = true;
                        break;
                }

                p = p + ALIGN64(le64toh(o->object.size));
        };

        if (!found_last && le64toh(f->header->tail_object_offset) != 0) {
                error(le64toh(f->header->tail_object_offset), "Tail object pointer dead");
                r = -EBADMSG;
                goto fail;
        }

        if (n_objects != le64toh(f->header->n_objects)) {
                error(offsetof(Header, n_objects), "Object number mismatch");
                r = -EBADMSG;
                goto fail;
        }

        if (n_entries != le64toh(f->header->n_entries)) {
                error(offsetof(Header, n_entries), "Entry number mismatch");
                r = -EBADMSG;
                goto fail;
        }

        if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
            n_data != le64toh(f->header->n_data)) {
                error(offsetof(Header, n_data), "Data number mismatch");
                r = -EBADMSG;
                goto fail;
        }

        if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
            n_fields != le64toh(f->header->n_fields)) {
                error(offsetof(Header, n_fields), "Field number mismatch");
                r = -EBADMSG;
                goto fail;
        }

        if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
            n_tags != le64toh(f->header->n_tags)) {
                error(offsetof(Header, n_tags), "Tag number mismatch");
                r = -EBADMSG;
                goto fail;
        }

        if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
            n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
                error(offsetof(Header, n_entry_arrays), "Entry array number mismatch");
                r = -EBADMSG;
                goto fail;
        }

        if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) {
                error(0, "Missing entry array");
                r = -EBADMSG;
                goto fail;
        }

        if (entry_seqnum_set &&
            entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
                error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum");
                r = -EBADMSG;
                goto fail;
        }

        if (entry_monotonic_set &&
            (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
             entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
                error(0, "Invalid tail monotonic timestamp");
                r = -EBADMSG;
                goto fail;
        }

        if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
                error(0, "Invalid tail realtime timestamp");
                r = -EBADMSG;
                goto fail;
        }

        /* Second iteration: we follow all objects referenced from the
         * two entry points: the object hash table and the entry
         * array. We also check that everything referenced (directly
         * or indirectly) in the data hash table also exists in the
         * entry array, and vice versa. Note that we do not care for
         * unreferenced objects. We only care that everything that is
         * referenced is consistent. */

        r = verify_entry_array(f,
                               data_fd, n_data,
                               entry_fd, n_entries,
                               entry_array_fd, n_entry_arrays,
                               &last_usec,
                               show_progress);
        if (r < 0)
                goto fail;

        r = verify_hash_table(f,
                              data_fd, n_data,
                              entry_fd, n_entries,
                              entry_array_fd, n_entry_arrays,
                              &last_usec,
                              show_progress);
        if (r < 0)
                goto fail;

        if (show_progress)
                flush_progress();

        mmap_cache_close_fd(f->mmap, data_fd);
        mmap_cache_close_fd(f->mmap, entry_fd);
        mmap_cache_close_fd(f->mmap, entry_array_fd);

        safe_close(data_fd);
        safe_close(entry_fd);
        safe_close(entry_array_fd);

        if (first_contained)
                *first_contained = le64toh(f->header->head_entry_realtime);
        if (last_validated)
                *last_validated = last_sealed_realtime;
        if (last_contained)
                *last_contained = le64toh(f->header->tail_entry_realtime);

        return 0;

fail:
        if (show_progress)
                flush_progress();

        log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
                  f->path,
                  p,
                  (unsigned long long) f->last_stat.st_size,
                  100 * p / f->last_stat.st_size);

        if (data_fd >= 0) {
                mmap_cache_close_fd(f->mmap, data_fd);
                safe_close(data_fd);
        }

        if (entry_fd >= 0) {
                mmap_cache_close_fd(f->mmap, entry_fd);
                safe_close(entry_fd);
        }

        if (entry_array_fd >= 0) {
                mmap_cache_close_fd(f->mmap, entry_array_fd);
                safe_close(entry_array_fd);
        }

        return r;
}
static int verify_entry_array(
                JournalFile *f,
                int data_fd, uint64_t n_data,
                int entry_fd, uint64_t n_entries,
                int entry_array_fd, uint64_t n_entry_arrays,
                usec_t *last_usec,
                bool show_progress) {

        uint64_t i = 0, a, n, last = 0;
        int r;

        assert(f);
        assert(data_fd >= 0);
        assert(entry_fd >= 0);
        assert(entry_array_fd >= 0);
        assert(last_usec);

        n = le64toh(f->header->n_entries);
        a = le64toh(f->header->entry_array_offset);
        while (i < n) {
                uint64_t next, m, j;
                Object *o;

                if (show_progress)
                        draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec);

                if (a == 0) {
                        error(a, "Array chain too short at %"PRIu64" of %"PRIu64, i, n);
                        return -EBADMSG;
                }

                if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
                        error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n);
                        return -EBADMSG;
                }

                r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
                if (r < 0)
                        return r;

                next = le64toh(o->entry_array.next_entry_array_offset);
                if (next != 0 && next <= a) {
                        error(a, "Array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", i, n, next);
                        return -EBADMSG;
                }

                m = journal_file_entry_array_n_items(o);
                for (j = 0; i < n && j < m; i++, j++) {
                        uint64_t p;

                        p = le64toh(o->entry_array.items[j]);
                        if (p <= last) {
                                error(a, "Entry array not sorted at %"PRIu64" of %"PRIu64, i, n);
                                return -EBADMSG;
                        }
                        last = p;

                        if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
                                error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n);
                                return -EBADMSG;
                        }

                        r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
                        if (r < 0)
                                return r;

                        r = verify_entry(f, o, p, data_fd, n_data);
                        if (r < 0)
                                return r;

                        /* Pointer might have moved, reposition */
                        r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
                        if (r < 0)
                                return r;
                }

                a = next;
        }

        return 0;
}
static int verify_hash_table(
                JournalFile *f,
                int data_fd, uint64_t n_data,
                int entry_fd, uint64_t n_entries,
                int entry_array_fd, uint64_t n_entry_arrays,
                usec_t *last_usec,
                bool show_progress) {

        uint64_t i, n;
        int r;

        assert(f);
        assert(data_fd >= 0);
        assert(entry_fd >= 0);
        assert(entry_array_fd >= 0);
        assert(last_usec);

        n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
        if (n <= 0)
                return 0;

        r = journal_file_map_data_hash_table(f);
        if (r < 0)
                return log_error_errno(r, "Failed to map data hash table: %m");

        for (i = 0; i < n; i++) {
                uint64_t last = 0, p;

                if (show_progress)
                        draw_progress(0xC000 + scale_progress(0x3FFF, i, n), last_usec);

                p = le64toh(f->data_hash_table[i].head_hash_offset);
                while (p != 0) {
                        Object *o;
                        uint64_t next;

                        if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
                                error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n);
                                return -EBADMSG;
                        }

                        r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
                        if (r < 0)
                                return r;

                        next = le64toh(o->data.next_hash_offset);
                        if (next != 0 && next <= p) {
                                error(p, "Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, i, n);
                                return -EBADMSG;
                        }

                        if (le64toh(o->data.hash) % n != i) {
                                error(p, "Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, i, n);
                                return -EBADMSG;
                        }

                        r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
                        if (r < 0)
                                return r;

                        last = p;
                        p = next;
                }

                if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
                        error(p, "Tail hash pointer mismatch in hash table");
                        return -EBADMSG;
                }
        }

        return 0;
}
Exemple #10
0
void Pi::Init()
{

	OS::NotifyLoadBegin();

	FileSystem::Init();
	FileSystem::userFiles.MakeDirectory(""); // ensure the config directory exists

	Pi::config = new GameConfig();
	KeyBindings::InitBindings();

	if (config->Int("RedirectStdio"))
		OS::RedirectStdio();

	ModManager::Init();

	if (!Lang::LoadStrings(config->String("Lang")))
		abort();

	Pi::detail.planets = config->Int("DetailPlanets");
	Pi::detail.textures = config->Int("Textures");
	Pi::detail.fracmult = config->Int("FractalMultiple");
	Pi::detail.cities = config->Int("DetailCities");

#ifdef __linux__
	// there appears to be a bug in the Linux evdev input driver that stops
	// DGA mouse grab restoring state correctly. SDL can use an alternative
	// method, but its only configurable via environment variable. Here we set
	// that environment variable (unless the user explicitly doesn't want it
	// via config).
	//
	// we also enable warp-after-grab here, as the SDL alternative method
	// doesn't restore the mouse pointer to its pre-grab position
	//
	// XXX SDL2 uses a different mechanism entirely and this environment
	// variable doesn't exist there, so we can get rid of it when we go to SDL2
	if (!config->Int("SDLUseDGAMouse")) {
		Pi::warpAfterMouseGrab = true;
		setenv("SDL_VIDEO_X11_DGAMOUSE", "0", 1);
	}
#endif

	// Initialize SDL
	Uint32 sdlInitFlags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
#if defined(DEBUG) || defined(_DEBUG)
	sdlInitFlags |= SDL_INIT_NOPARACHUTE;
#endif
	if (SDL_Init(sdlInitFlags) < 0) {
		OS::Error("SDL initialization failed: %s\n", SDL_GetError());
	}

	// needed for the UI
	SDL_EnableUNICODE(1);

	// Do rest of SDL video initialization and create Renderer
	Graphics::Settings videoSettings = {};
	videoSettings.width = config->Int("ScrWidth");
	videoSettings.height = config->Int("ScrHeight");
	videoSettings.fullscreen = (config->Int("StartFullscreen") != 0);
	videoSettings.shaders = (config->Int("DisableShaders") == 0);
	videoSettings.requestedSamples = config->Int("AntiAliasingMode");
	videoSettings.vsync = (config->Int("VSync") != 0);
	videoSettings.useTextureCompression = (config->Int("UseTextureCompression") != 0);

	Pi::renderer = Graphics::Init(videoSettings);
	{
		std::ostringstream buf;
		renderer->PrintDebugInfo(buf);

		FILE *f = FileSystem::userFiles.OpenWriteStream("opengl.txt", FileSystem::FileSourceFS::WRITE_TEXT);
		if (!f)
			fprintf(stderr, "Could not open 'opengl.txt'\n");
		const std::string &s = buf.str();
		fwrite(s.c_str(), 1, s.size(), f);
		fclose(f);
	}

	OS::LoadWindowIcon();
	SDL_WM_SetCaption("Pioneer","Pioneer");

	Pi::scrAspect = videoSettings.width / float(videoSettings.height);

	Pi::rng.seed(time(0));

	InitJoysticks();
	joystickEnabled = (config->Int("EnableJoystick")) ? true : false;
	mouseYInvert = (config->Int("InvertMouseY")) ? true : false;

	navTunnelDisplayed = (config->Int("DisplayNavTunnel")) ? true : false;

	// XXX UI requires Lua  but Pi::ui must exist before we start loading
	// templates. so now we have crap everywhere :/
	Lua::Init();

	Pi::ui.Reset(new UI::Context(Lua::manager, Pi::renderer, Graphics::GetScreenWidth(), Graphics::GetScreenHeight(), Lang::GetCurrentLanguage()));

	LuaInit();

	// Gui::Init shouldn't initialise any VBOs, since we haven't tested
	// that the capability exists. (Gui does not use VBOs so far)
	Gui::Init(renderer, Graphics::GetScreenWidth(), Graphics::GetScreenHeight(), 800, 600);

	draw_progress(0.1f);

	Galaxy::Init();
	draw_progress(0.2f);

	Faction::Init();
	draw_progress(0.3f);

	CustomSystem::Init();
	draw_progress(0.4f);

	LmrModelCompilerInit(Pi::renderer);
	modelCache = new ModelCache(Pi::renderer);
	draw_progress(0.5f);

//unsigned int control_word;
//_clearfp();
//_controlfp_s(&control_word, _EM_INEXACT | _EM_UNDERFLOW | _EM_ZERODIVIDE, _MCW_EM);
//double fpexcept = Pi::timeAccelRates[1] / Pi::timeAccelRates[0];

	ShipType::Init();
	draw_progress(0.6f);

	GeoSphere::Init();
	draw_progress(0.7f);

	CityOnPlanet::Init();
	draw_progress(0.8f);

	SpaceStation::Init();
	draw_progress(0.9f);

	Sfx::Init(Pi::renderer);
	draw_progress(0.95f);

	if (!config->Int("DisableSound")) {
		Sound::Init();
		Sound::SetMasterVolume(config->Float("MasterVolume"));
		Sound::SetSfxVolume(config->Float("SfxVolume"));
		GetMusicPlayer().SetVolume(config->Float("MusicVolume"));

		Sound::Pause(0);
		if (config->Int("MasterMuted")) Sound::Pause(1);
		if (config->Int("SfxMuted")) Sound::SetSfxVolume(0.f);
		if (config->Int("MusicMuted")) GetMusicPlayer().SetEnabled(false);
	}
	draw_progress(1.0f);

	OS::NotifyLoadEnd();

#if 0
	// frame test code

	Frame *root = new Frame(0, "root", 0);
	Frame *p1 = new Frame(root, "p1", Frame::FLAG_HAS_ROT);
	Frame *p1r = new Frame(p1, "p1r", Frame::FLAG_ROTATING);
	Frame *m1 = new Frame(p1, "m1", Frame::FLAG_HAS_ROT);
	Frame *m1r = new Frame(m1, "m1r", Frame::FLAG_ROTATING);
	Frame *p2 = new Frame(root, "p2", Frame::FLAG_HAS_ROT);
	Frame *p2r = new Frame(p2, "pr2", Frame::FLAG_ROTATING);

	p1->SetPosition(vector3d(1000,0,0));
	p1->SetVelocity(vector3d(0,1,0));
	p2->SetPosition(vector3d(0,2000,0));
	p2->SetVelocity(vector3d(-2,0,0));
	p1r->SetAngVelocity(vector3d(0,0,0.0001));
	p1r->SetOrient(matrix3x3d::BuildRotate(M_PI/4, vector3d(0,0,1)));
	p2r->SetAngVelocity(vector3d(0,0,-0.0004));
	p2r->SetOrient(matrix3x3d::BuildRotate(-M_PI/2, vector3d(0,0,1)));
	root->UpdateOrbitRails(0, 0);

	CargoBody *c1 = new CargoBody(Equip::Type::SLAVES);
	c1->SetFrame(p1r);
	c1->SetPosition(vector3d(0,180,0));
//	c1->SetVelocity(vector3d(1,0,0));
	CargoBody *c2 = new CargoBody(Equip::Type::SLAVES);
	c2->SetFrame(p1r);
	c2->SetPosition(vector3d(0,200,0));
//	c2->SetVelocity(vector3d(1,0,0));

	vector3d pos = c1->GetPositionRelTo(p1);
	vector3d vel = c1->GetVelocityRelTo(p1);
	double speed = vel.Length();
	vector3d pos2 = c2->GetPositionRelTo(p1);
	vector3d vel2 = c2->GetVelocityRelTo(p1);
	double speed2 = vel2.Length();

	double speed3 = c2->GetVelocityRelTo(c1).Length();
	c2->SwitchToFrame(p1);
	vector3d vel4 = c2->GetVelocityRelTo(c1);
	double speed4 = c2->GetVelocityRelTo(c1).Length();


	root->UpdateOrbitRails(0, 1.0);

	//buildrotate test

	matrix3x3d m = matrix3x3d::BuildRotate(M_PI/2, vector3d(0,0,1));
	vector3d v = m * vector3d(1,0,0);

/*	vector3d pos = p1r->GetPositionRelTo(p2r);
	vector3d vel = p1r->GetVelocityRelTo(p2r);
	matrix3x3d o1 = p1r->GetOrientRelTo(p2r);
	double speed = vel.Length();
	vector3d pos2 = p2r->GetPositionRelTo(p1r);
	vector3d vel2 = p2r->GetVelocityRelTo(p1r);
	matrix3x3d o2 = p2r->GetOrientRelTo(p1r);
	double speed2 = vel2.Length();
*/	root->UpdateOrbitRails(0, 1.0/60);

	delete p2r; delete p2; delete m1r; delete m1; delete p1r; delete p1; delete root;
	delete c1; delete c2;

#endif

#if 0
	// test code to produce list of ship stats

	FILE *pStatFile = fopen("shipstat.csv","wt");
	if (pStatFile)
	{
		fprintf(pStatFile, "name,lmrname,hullmass,capacity,fakevol,rescale,xsize,ysize,zsize,facc,racc,uacc,sacc,aacc,exvel\n");
		for (std::map<std::string, ShipType>::iterator i = ShipType::types.begin();
				i != ShipType::types.end(); ++i)
		{
			ShipType *shipdef = &(i->second);
			LmrModel *lmrModel = LmrLookupModelByName(shipdef->lmrModelName.c_str());
			LmrObjParams lmrParams; memset(&lmrParams, 0, sizeof(LmrObjParams));
			lmrParams.animationNamespace = "ShipAnimation";
			EquipSet equip; equip.InitSlotSizes(shipdef->id);
			lmrParams.equipment = &equip;
			LmrCollMesh *collMesh = new LmrCollMesh(lmrModel, &lmrParams);
			Aabb aabb = collMesh->GetAabb();

			double hullmass = shipdef->hullMass;
			double capacity = shipdef->capacity;
			double xsize = aabb.max.x-aabb.min.x;
			double ysize = aabb.max.y-aabb.min.y;
			double zsize = aabb.max.z-aabb.min.z;
			double fakevol = xsize*ysize*zsize;
			double rescale = pow(fakevol/(100 * (hullmass+capacity)), 0.3333333333);
			double brad = aabb.GetRadius();
			double simass = (hullmass + capacity) * 1000.0;
			double angInertia = (2/5.0)*simass*brad*brad;
			double acc1 = shipdef->linThrust[ShipType::THRUSTER_FORWARD] / (9.81*simass);
			double acc2 = shipdef->linThrust[ShipType::THRUSTER_REVERSE] / (9.81*simass);
			double acc3 = shipdef->linThrust[ShipType::THRUSTER_UP] / (9.81*simass);
			double acc4 = shipdef->linThrust[ShipType::THRUSTER_RIGHT] / (9.81*simass);
			double acca = shipdef->angThrust/angInertia;
			double exvel = shipdef->linThrust[ShipType::THRUSTER_FORWARD] /
				(shipdef->fuelTankMass * shipdef->thrusterFuelUse * 10 * 1e6);

			fprintf(pStatFile, "%s,%s,%.1f,%.1f,%.1f,%.3f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%f,%.1f\n",
				shipdef->name.c_str(), shipdef->lmrModelName.c_str(), hullmass, capacity,
				fakevol, rescale, xsize, ysize, zsize, acc1, acc2, acc3, acc4, acca, exvel);
			delete collMesh;
		}
		fclose(pStatFile);
	}
#endif

	luaConsole = new LuaConsole(10);
	KeyBindings::toggleLuaConsole.onPress.connect(sigc::ptr_fun(&Pi::ToggleLuaConsole));

	gameMenuView = new GameMenuView();
	config->Save();
}