|
|
|
|
/******************************************************************************
|
|
|
|
|
* File - core.cpp
|
|
|
|
|
* Author - Joey Pollack
|
|
|
|
|
* Date - 2021/08/30 (y/m/d)
|
|
|
|
|
* Mod Date - 2021/08/30 (y/m/d)
|
|
|
|
|
* Description - The Core Engine Class. Manages the engine components.
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "core.h"
|
|
|
|
|
#include "version.h"
|
|
|
|
|
|
|
|
|
|
#include "core_console.h"
|
|
|
|
|
|
|
|
|
|
#include <dearimgui/imgui.h>
|
|
|
|
|
#include <LunariumConfig.h>
|
|
|
|
|
|
|
|
|
|
#include <platform/terminal.h>
|
|
|
|
|
|
|
|
|
|
// Run modes
|
|
|
|
|
#include <run_modes/testbed/testbed.h>
|
|
|
|
|
#include <run_modes/editor/editor.h>
|
|
|
|
|
|
|
|
|
|
// Sub Systems
|
|
|
|
|
#include <platform/window.h>
|
|
|
|
|
#include <input/input_manager.h>
|
|
|
|
|
#include <graphics/opengl/glGraphics.h>
|
|
|
|
|
#include <gui/gui.h>
|
|
|
|
|
// #include <gui/logGui.h>
|
|
|
|
|
// #include <gui/luaConsole.h>
|
|
|
|
|
#include <scripting/script_manager.h>
|
|
|
|
|
#include <scripting/coreAPI.h>
|
|
|
|
|
|
|
|
|
|
namespace lunarium
|
|
|
|
|
{
|
|
|
|
|
Core* Core::mpInstance = nullptr;
|
|
|
|
|
Core::Core()
|
|
|
|
|
: mbIsInit(false), mpArgs(nullptr), mpWindow(nullptr), mpGraphics(nullptr), mpInput(nullptr),
|
|
|
|
|
mGUI(GUI::GetInstance()), mbMidRender(false), mbMidTextureRender(false), mpRunMode(nullptr), mbShowGuiDemo(false)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Core& Core::GetInstance()
|
|
|
|
|
{
|
|
|
|
|
if (!mpInstance)
|
|
|
|
|
{
|
|
|
|
|
mpInstance = new Core;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *mpInstance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// SHUTDOWN
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
void Core::Shutdown()
|
|
|
|
|
{
|
|
|
|
|
if (!mpInstance)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Logger::Info(LogCategory::CORE, "Lunarium is shutting down!");
|
|
|
|
|
|
|
|
|
|
int x, y;
|
|
|
|
|
mpInstance->MainWindow().GetPosition(&x, &y);
|
|
|
|
|
mpInstance->mState.Display.WindowStartPosition.X = x;
|
|
|
|
|
mpInstance->mState.Display.WindowStartPosition.Y = y;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mpInstance->mpWindow->GetFramebufferSize(&mpInstance->mState.Display.WindowedSize.Width,
|
|
|
|
|
&mpInstance->mState.Display.WindowedSize.Height);
|
|
|
|
|
|
|
|
|
|
mpInstance->mpWindow->GetPosition(&mpInstance->mState.Display.WindowStartPosition.X,
|
|
|
|
|
&mpInstance->mState.Display.WindowStartPosition.Y);
|
|
|
|
|
|
|
|
|
|
mpInstance->mState.SaveToFile();
|
|
|
|
|
|
|
|
|
|
// Run Mode shuts down first
|
|
|
|
|
mpInstance->mpRunMode->Shutdown();
|
|
|
|
|
delete mpInstance->mpRunMode;
|
|
|
|
|
mpInstance->mpRunMode = nullptr;
|
|
|
|
|
|
|
|
|
|
// Shutdown subsystems
|
|
|
|
|
CoreAPI::FreeInstance();
|
|
|
|
|
ScriptManager::FreeInstance();
|
|
|
|
|
|
|
|
|
|
//LuaConsole::FreeInstance();
|
|
|
|
|
//LogGui::FreeInstance();
|
|
|
|
|
GUI::GetInstance().Shutdown();
|
|
|
|
|
GUI::FreeInstance();
|
|
|
|
|
|
|
|
|
|
mpInstance->mpInput->Shutdown();
|
|
|
|
|
delete mpInstance->mpInput;
|
|
|
|
|
mpInstance->mpInput = nullptr;
|
|
|
|
|
|
|
|
|
|
mpInstance->mpGraphics->Shutdown();
|
|
|
|
|
delete mpInstance->mpGraphics;
|
|
|
|
|
mpInstance->mpGraphics = nullptr;
|
|
|
|
|
|
|
|
|
|
mpInstance->mpWindow->Shutdown();
|
|
|
|
|
delete mpInstance->mpWindow;
|
|
|
|
|
mpInstance->mpWindow = nullptr;
|
|
|
|
|
|
|
|
|
|
delete mpInstance->mpArgs;
|
|
|
|
|
mpInstance->mpArgs = nullptr;
|
|
|
|
|
|
|
|
|
|
mpInstance->mbIsInit = false;
|
|
|
|
|
delete mpInstance;
|
|
|
|
|
mpInstance = nullptr;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// INITIALIZATION
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
void Core::Initialize(int argc, char** argv)
|
|
|
|
|
{
|
|
|
|
|
if (mbIsInit)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Setup the log system
|
|
|
|
|
mMasterLogFile.open("Lunarium_Master.log", std::ios_base::app);
|
|
|
|
|
mMasterLogFile << "\n\n";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mErrorLogFile.open("Lunarium_Errors.log", std::ios_base::app);
|
|
|
|
|
|
|
|
|
|
mGraphicsLogFile.open("Lunarium_Graphics.log", std::ios_base::app);
|
|
|
|
|
mErrorLogFile << "\n\n";
|
|
|
|
|
|
|
|
|
|
if (mMasterLogFile.is_open())
|
|
|
|
|
Logger::GetInstance()->AddListener(new FileListener(mMasterLogFile));
|
|
|
|
|
|
|
|
|
|
if (mErrorLogFile.is_open())
|
|
|
|
|
Logger::GetInstance()->AddListener(new FileListener(mErrorLogFile, LogLevel::ERROR | LogLevel::FATAL_ERROR));
|
|
|
|
|
|
|
|
|
|
if (mGraphicsLogFile.is_open())
|
|
|
|
|
Logger::GetInstance()->AddListener(new FileListener(mGraphicsLogFile, LogLevel::GRAPHICS_INTERNAL_DEBUG | LogLevel::GRAPHICS_INTERNAL_ERROR));
|
|
|
|
|
|
|
|
|
|
Logger::GetInstance()->SetAllowRepeats(true);
|
|
|
|
|
|
|
|
|
|
// Init the Debug log window
|
|
|
|
|
OpRes result;
|
|
|
|
|
mPanelIDs.CoreConsole = AddPanel(new CoreConsole);
|
|
|
|
|
|
|
|
|
|
Logger::Info(LogCategory::CORE, "Running Lunarium version %s", Version::GetVersion().ToString().c_str());
|
|
|
|
|
|
|
|
|
|
// Attempt to load the engine state file. This file should be placed in the same directory as the lunarium program.
|
|
|
|
|
if (Failed(State::CreateFromFile("engine_state.xml", mState)))
|
|
|
|
|
{
|
|
|
|
|
Logger::Warn(LogCategory::CORE, "Unable to load state file: engine_state.xml. Loading default state.");
|
|
|
|
|
mState = State::CreateDefault();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger::Info(LogCategory::CORE, "Loaded state file: engine_state.xml");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse command line args -- None right now
|
|
|
|
|
std::vector<Args::SwitchDesc> sd;
|
|
|
|
|
mpArgs = new Args(argc, argv, '-', sd);
|
|
|
|
|
|
|
|
|
|
// Init Graphics/Window system
|
|
|
|
|
mpWindow = new Window;
|
|
|
|
|
result = mpWindow->Initialize(mState);
|
|
|
|
|
if (Failed(result))
|
|
|
|
|
{
|
|
|
|
|
Logger::Fatal(LogCategory::CORE,
|
|
|
|
|
"Could not initialize the Window system: %s", result.Description.c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RenderSystem::OPENGL == mState.Display.Renderer)
|
|
|
|
|
{
|
|
|
|
|
mpGraphics = new OglGraphics;
|
|
|
|
|
}
|
|
|
|
|
else if (RenderSystem::VULKAN == mState.Display.Renderer)
|
|
|
|
|
{
|
|
|
|
|
Logger::Fatal(LogCategory::CORE,
|
|
|
|
|
"Can not create Vulkan graphics system because it is not yet implemented. Must use OpenGL instead.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger::Fatal(LogCategory::CORE,
|
|
|
|
|
"Could not create graphics system: Unknown render framework specified.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: This should probably be based on a state setting instead
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
result = mpGraphics->Initialize(mpWindow);
|
|
|
|
|
#else
|
|
|
|
|
result = mpGraphics->Initialize(mpWindow, false);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (Failed(result))
|
|
|
|
|
{
|
|
|
|
|
Logger::Fatal(LogCategory::CORE,
|
|
|
|
|
"Could not initialized the graphics system: %s", result.Description);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mpGraphics->SetClearColor(Color(0.5f, 0.5f, 0.75f, 1.0f));
|
|
|
|
|
|
|
|
|
|
// INPUT
|
|
|
|
|
mpInput = new InputManager;
|
|
|
|
|
mpInput->Initialize(mpWindow);
|
|
|
|
|
|
|
|
|
|
// GUI
|
|
|
|
|
result = mGUI.Initialize(mpWindow->GetWindow());
|
|
|
|
|
if (Failed(result))
|
|
|
|
|
{
|
|
|
|
|
Logger::Warn(LogCategory::CORE,
|
|
|
|
|
"Could not initialized the main GUI system: %s", result.Description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SCRIPTING
|
|
|
|
|
ScriptManager& scriptMan = ScriptManager::GetInstance();
|
|
|
|
|
result = scriptMan.Initialize();
|
|
|
|
|
if (Failed(result))
|
|
|
|
|
{
|
|
|
|
|
Logger::Warn(LogCategory::CORE,
|
|
|
|
|
"Could not initialized the LUA script manager: %s", result.Description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CoreAPI& capi = CoreAPI::GetInstance();
|
|
|
|
|
result = capi.Initialize(scriptMan);
|
|
|
|
|
if (Failed(result))
|
|
|
|
|
{
|
|
|
|
|
Logger::Warn(LogCategory::CORE,
|
|
|
|
|
"Could not initialized the LUA Core API: %s", result.Description);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RUN MODE
|
|
|
|
|
const char* types[] = { "game", "editor", "test" };
|
|
|
|
|
Logger::Info(LogCategory::CORE, "Running in mode: %s", types[mState.Mode]);
|
|
|
|
|
if (RunMode::MODE_TEST == mState.Mode)
|
|
|
|
|
{
|
|
|
|
|
mpRunMode = new TestBed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (RunMode::MODE_EDITOR == mState.Mode)
|
|
|
|
|
{
|
|
|
|
|
#if BUILD_NO_EDITOR
|
|
|
|
|
Logger::Fatal(LogCategory::CORE, "The Editor is not available with this build");
|
|
|
|
|
return;
|
|
|
|
|
#else
|
|
|
|
|
mpRunMode = new editor::Editor;
|
|
|
|
|
FreePanel(mPanelIDs.CoreConsole); // Editor uses it's own console
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize the Run Mode
|
|
|
|
|
if (Failed(mpRunMode->Initialize()))
|
|
|
|
|
{
|
|
|
|
|
Logger::Fatal(LogCategory::CORE,
|
|
|
|
|
"Could not initialize the Run Mode: %s", result.Description.c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
mbIsInit = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Core::IsInit() const
|
|
|
|
|
{
|
|
|
|
|
return mbIsInit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const State& Core::GetState() const
|
|
|
|
|
{
|
|
|
|
|
return mState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Core::SignalShutdown()
|
|
|
|
|
{
|
|
|
|
|
mpWindow->SetShouldCloseFlag(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// GAME LOOP
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
void Core::RunGameLoop()
|
|
|
|
|
{
|
|
|
|
|
mFrameCounter.Reset();
|
|
|
|
|
|
|
|
|
|
// TODO: Init frame counter
|
|
|
|
|
while (!mpWindow->ShouldWindowClose())
|
|
|
|
|
{
|
|
|
|
|
mFrameCounter.NewFrame();
|
|
|
|
|
|
|
|
|
|
// Display FPS in window title for now
|
|
|
|
|
std::string title = "Lunarium - FPS: ";
|
|
|
|
|
title += std::to_string(mFrameCounter.GetFrameData().CurrentFPS);
|
|
|
|
|
glfwSetWindowTitle(mpWindow->GetWindow(), title.c_str());
|
|
|
|
|
|
|
|
|
|
// Get pointers to gui panels
|
|
|
|
|
CoreConsole* con = (CoreConsole*)mPanels[mPanelIDs.CoreConsole];
|
|
|
|
|
|
|
|
|
|
// Poll input
|
|
|
|
|
Window::PollEvents();
|
|
|
|
|
auto keyEvents = mpInput->PollKeys();
|
|
|
|
|
|
|
|
|
|
if (!ImGui::GetIO().WantCaptureKeyboard)
|
|
|
|
|
{
|
|
|
|
|
// Send key events
|
|
|
|
|
for (int i = 0; i < keyEvents.KeysPressed.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
mpRunMode->OnKeyPress(keyEvents.KeysPressed[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < keyEvents.KeysReleased.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
mpRunMode->OnKeyRelease(keyEvents.KeysReleased[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Check if there is a new LUA command
|
|
|
|
|
std::string command;
|
|
|
|
|
if (con && con->GetNewCommand(command))
|
|
|
|
|
{
|
|
|
|
|
// Logger::Debug(LogCategory::SCRIPTING, "New LUA command: %s", command.c_str());
|
|
|
|
|
OpRes result = ScriptManager::RunScript(command.c_str());
|
|
|
|
|
if (Failed(result))
|
|
|
|
|
{
|
|
|
|
|
Logger::Error(LogCategory::SCRIPTING, result.Description.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// UPDATE game state
|
|
|
|
|
mpRunMode->OnTick(mFrameCounter.GetFrameData().LastFrameTime);
|
|
|
|
|
|
|
|
|
|
// DEBUG PANELS
|
|
|
|
|
if (Core::Input().IsKeyPressed(KeyCode::F2, true) && con)
|
|
|
|
|
{
|
|
|
|
|
con->SetOpen(!con->IsOpen());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Core::Input().IsKeyPressed(KeyCode::F3, true))
|
|
|
|
|
{
|
|
|
|
|
mbShowGuiDemo = !mbShowGuiDemo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RENDER
|
|
|
|
|
if (mbMidTextureRender)
|
|
|
|
|
{
|
|
|
|
|
Logger::Warn(LogCategory::CORE, "Render to texture was not ended!");
|
|
|
|
|
EndRenderToTexture();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mGUI.NewFrame();
|
|
|
|
|
mpGraphics->BeginDraw();
|
|
|
|
|
mbMidRender = true;
|
|
|
|
|
|
|
|
|
|
// Gui windows
|
|
|
|
|
if (con)
|
|
|
|
|
{
|
|
|
|
|
con->DoFrame();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mbShowGuiDemo)
|
|
|
|
|
{
|
|
|
|
|
mGUI.ShowDemoWindow(mbShowGuiDemo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run mode
|
|
|
|
|
mpRunMode->OnRender(mpGraphics);
|
|
|
|
|
|
|
|
|
|
// END RENDER
|
|
|
|
|
mGUI.EndFrame();
|
|
|
|
|
mpGraphics->EndDraw();
|
|
|
|
|
mbMidRender = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OpRes Core::BeginRenderToTexture(int id)
|
|
|
|
|
{
|
|
|
|
|
if (mbMidRender)
|
|
|
|
|
{
|
|
|
|
|
return OpRes::Fail("Can not switch render targets in the middle of rendering");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mbMidTextureRender = true;
|
|
|
|
|
mpGraphics->BeginDraw(id);
|
|
|
|
|
return OpRes::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Image* Core::EndRenderToTexture()
|
|
|
|
|
{
|
|
|
|
|
if (!mbMidTextureRender)
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mbMidTextureRender = false;
|
|
|
|
|
return mpGraphics->EndDraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// STATIC INTERFACE
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
Window& Core::MainWindow()
|
|
|
|
|
{
|
|
|
|
|
return *mpInstance->mpWindow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IGraphics& Core::Graphics()
|
|
|
|
|
{
|
|
|
|
|
return *mpInstance->mpGraphics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InputManager& Core::Input()
|
|
|
|
|
{
|
|
|
|
|
return *mpInstance->mpInput;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// HELPERS
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
uint32_t Core::AddPanel(gui::Panel* p)
|
|
|
|
|
{
|
|
|
|
|
mPanels.push_back(p);
|
|
|
|
|
return mPanels.size() - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Core::FreePanel(uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
delete mPanels[id];
|
|
|
|
|
mPanels[id] = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CoreLogListener::CoreLogListener(uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
|
|
|
|
: LogListener(acceptedLogLevels, acceptedLogCategories, myName)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CoreLogListener::Log(LogMessage& message)
|
|
|
|
|
{
|
|
|
|
|
if (!LevelIsSet(message.LogLevel) ||
|
|
|
|
|
!CategoryIsSet(message.LogCategory))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
|
|
switch (message.LogLevel)
|
|
|
|
|
{
|
|
|
|
|
case LogLevel::GRAPHICS_INTERNAL_ERROR:
|
|
|
|
|
case LogLevel::FATAL_ERROR:
|
|
|
|
|
case LogLevel::ERROR:
|
|
|
|
|
std::cout << Terminal::Color(TermColor::TC_RED); break;
|
|
|
|
|
case LogLevel::WARNING: std::cout << Terminal::Color(TermColor::TC_YELLOW); break;
|
|
|
|
|
case LogLevel::INFO: std::cout << Terminal::Color(TermColor::TC_GREEN); break;
|
|
|
|
|
case LogLevel::DEBUG: std::cout << Terminal::Color(TermColor::TC_BLUE); break;
|
|
|
|
|
case LogLevel::TRACE: std::cout << Terminal::Color(TermColor::TC_CYAN); break;
|
|
|
|
|
case LogLevel::GRAPHICS_INTERNAL_DEBUG: break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::cout << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
|
|
|
|
|
<< Logger::GetLevelName(message.LogLevel) << message.Message << Terminal::Color(TermColor::TC_DEFAULT) << std::flush;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|