Example #1
0
int main(int argc, char* argv[]) {
	// Initialize logger
	logFile.open("engine_test.log");
	logFilePath = std::experimental::filesystem::current_path();
	logFilePath /= "engine_test.log";
	cout << "Log files can be found at:\n   ";
	cout << "   " << logFilePath << endl;

	if (logFile.is_open()) {
		logger.OpenStream(&logFile);
	}
	else {
		logger.OpenStream(&std::cout);
	}

	// Set exception terminate handler
	std::set_terminate(OnTerminate);


	// Create the window itself
	Window window;
	window.SetTitle("QC Simulator");
	window.SetSize({ 960, 640 });


	// Create GraphicsEngine
	systemLogStream.Event("Initializing Graphics Engine...");

	std::unique_ptr<IGxapiManager> gxapiMgr;
	std::unique_ptr<IGraphicsApi, ReportDeleter> gxapi;
	std::unique_ptr<GraphicsEngine> engine;
	std::unique_ptr<QCWorld> qcWorld;
	std::unique_ptr<InputHandler> inputHandler;
	std::unique_ptr<Input> joyInput;
	std::unique_ptr<Input> keyboardInput;

	try {
		// Create manager
		systemLogStream.Event("Creating GxApi Manager...");
		gxapiMgr.reset(new GxapiManager());
		auto adapters = gxapiMgr->EnumerateAdapters();
		std::string cardList;
		for (auto adapter : adapters) {
			cardList += "\n";
			cardList += adapter.name;
		}
		systemLogStream.Event("Available graphics cards:" + cardList);


		// Create graphics api
		int device = 0;
		if (argc == 3 && argv[1] == std::string("--device") && isdigit(argv[2][0])) {
			device = argv[2][0] - '0'; // works for single digits, good enough, lol
		}
		systemLogStream.Event("Creating GraphicsApi...");
		gxapi.reset(gxapiMgr->CreateGraphicsApi(adapters[device].adapterId));
		std::stringstream ss;
		ss << "Using graphics card: " << adapters[device].name;
		systemLogStream.Event(ss.str());


		// Create graphics engine
		systemLogStream.Event("Creating Graphics Engine...");

		GraphicsEngineDesc desc;
		desc.fullScreen = false;
		desc.graphicsApi = gxapi.get();
		desc.gxapiManager = gxapiMgr.get();
		desc.width = window.GetClientSize().x;
		desc.height = window.GetClientSize().y;
		desc.targetWindow = window.GetNativeHandle();
		desc.logger = &logger;

		engine.reset(new GraphicsEngine(desc));

		// Load graphics pipeline
		std::string pipelineFileName = SelectPipeline(gxapi.get());
		std::string exeDir = System::GetExecutableDir();
		std::ifstream pipelineFile(INL_PIPELINE_DIRECTORY "\\" + pipelineFileName);
		if (!pipelineFile.is_open()) {
			throw FileNotFoundException("Failed to open pipeline JSON.");
		}
		std::string pipelineDesc((std::istreambuf_iterator<char>(pipelineFile)), std::istreambuf_iterator<char>());
		engine->LoadPipeline(pipelineDesc);


		// Create mini world
		qcWorld.reset(new QCWorld(engine.get()));
		

		// Create input handling
		inputHandler = std::make_unique<InputHandler>(qcWorld.get());

		window.OnResize += Delegate<void(ResizeEvent)>{ &InputHandler::OnResize, inputHandler.get() };

		auto joysticks = Input::GetDeviceList(eInputSourceType::JOYSTICK);
		if (!joysticks.empty()) {
			joyInput = std::make_unique<Input>(joysticks.front().id);
			joyInput->SetQueueMode(eInputQueueMode::QUEUED);
			joyInput->OnJoystickMove += Delegate<void(JoystickMoveEvent)>{ &InputHandler::OnJoystickMove, inputHandler.get() };
		}
		auto keyboards = Input::GetDeviceList(eInputSourceType::KEYBOARD);
		if (!keyboards.empty()) {
			keyboardInput = std::make_unique<Input>(keyboards.front().id);
			keyboardInput->SetQueueMode(eInputQueueMode::QUEUED);
			keyboardInput->OnKeyboard += Delegate<void(KeyboardEvent)>{ &InputHandler::OnKey, inputHandler.get() };
		}

		window.OnResize += [&engine, &qcWorld](ResizeEvent evt) {
			engine->SetScreenSize(evt.clientSize.x, evt.clientSize.y);
			qcWorld->ScreenSizeChanged(evt.clientSize.x, evt.clientSize.y);
		};

		logger.Flush();
	}
	catch (Exception& ex) {
		errorMessage = std::string("Error creating GraphicsEngine: ") + ex.what() + "\n" + ex.StackTraceStr();
		systemLogStream.Event(errorMessage);
		logger.Flush();
	}
	catch (std::exception& ex) {
		errorMessage = std::string("Error creating GraphicsEngine: ") + ex.what();
		systemLogStream.Event(errorMessage);
		logger.Flush();
	}

	if (!qcWorld) {
		return 0;
	}


	// Main rendering loop
	Timer timer;
	timer.Start();
	double frameTime = 0.05, frameRateUpdate = 0;
	std::vector<double> frameTimeHistory;
	float avgFps = 0;

	auto CaptionHandler = [&window](Vec2i cursorPos) {
		Vec2i size = window.GetSize();
		RectI rc;
		rc.top = 5;
		rc.bottom = 50;
		rc.right = size.x - 5;
		rc.left = size.x - 50;
		if (rc.IsPointInside(cursorPos))
			return eWindowCaptionButton::CLOSE;
		rc.Move({ -50, 0 });
		if (rc.IsPointInside(cursorPos))
			return eWindowCaptionButton::MAXIMIZE;
		rc.Move({ -50, 0 });
		if (rc.IsPointInside(cursorPos))
			return eWindowCaptionButton::MINIMIZE;
		if (cursorPos.y < 55) {
			return eWindowCaptionButton::BAR;
		}
		return eWindowCaptionButton::NONE;
	};
	//window.SetBorderless(true);
	//window.SetCaptionButtonHandler(CaptionHandler);

	while (!window.IsClosed()) {
		inputHandler->SetFocused(window.IsFocused());
		window.CallEvents();
		if (joyInput) {
			joyInput->CallEvents();
		}
		if (keyboardInput) {
			keyboardInput->CallEvents();
		}

		try {
			// Update world
			qcWorld->UpdateWorld(frameTime);
			qcWorld->RenderWorld(frameTime);

			// Calculate elapsed time for frame.
			frameTime = timer.Elapsed();
			timer.Reset();

			// Calculate average framerate
			frameRateUpdate += frameTime;
			if (frameRateUpdate > 0.5) {
				frameRateUpdate = 0;

				double avgFrameTime = 0.0;
				for (auto v : frameTimeHistory) {
					avgFrameTime += v;
				}
				avgFrameTime /= frameTimeHistory.size();
				avgFps = 1 / avgFrameTime;

				frameTimeHistory.clear();
			}
			frameTimeHistory.push_back(frameTime);

			// Set info text as window title
			unsigned width, height;
			engine->GetScreenSize(width, height);
			std::string title = "Graphics Engine Test | " + std::to_string(width) + "x" + std::to_string(height) + " | FPS=" + std::to_string((int)avgFps);
			window.SetTitle(title);
		}
		catch (Exception& ex) {
			std::stringstream trace;
			trace << "Graphics engine error:" << ex.what() << "\n";
			ex.PrintStackTrace(trace);
			systemLogStream.Event(trace.str());
			PostQuitMessage(0);
		}
		catch (std::exception& ex) {
			systemLogStream.Event(std::string("Graphics engine error: ") + ex.what());
			logger.Flush();
			PostQuitMessage(0);
		}
	}

	cout << "Shutting down." << endl;
	return 0;
}