Program Listing for File main.cpp¶
↰ Return to documentation for file (blam\main.cpp
)
// Blamite Engine - Entry point for Blamite engine //
// (c) Elaztek Studios 2016-2018 //
#include "core.h"
// External includes
#include <thread>
#include <Uxtheme.h>
// Internal includes
#include "components/content/fonts/fonts.h"
#include "components/core/blam_ui/blam_ui.h"
#include "components/core/cache/cache.h"
#include "components/core/config/config.h"
#include "components/core/debug_ui/debug_colors.h"
#include "components/core/debug_ui/debug_ui.h"
#include "components/core/dialogs/dialogs.h"
#include "components/core/engine_definitions/engine_definitions.h"
#include "components/core/error/error.h"
#include "components/core/logger/logger.h"
#include "components/core/placeholders/placeholders.h"
#include "components/core/utils/converters/converters.h"
#include "components/core/utils/io/io.h"
#include "components/core/utils/res/res.h"
#include "components/core/utils/utilities.h"
#include "components/discord/m_discord.h"
#include "components/haloscript/haloscript.h"
#include "components/input/keyboard.h"
#include "components/networking/messages.h"
#include "components/networking/socket.h"
#include "components/rendering/directx11/render_stack/render_stack.h"
#include "components/rendering/directx11/render_stack/stack_types/blam_ui/console.hpp"
#include "components/rendering/directx11/render_stack/stack_types/blam_ui/debug_menu.hpp"
#include "components/rendering/directx11/render_stack/stack_types/blam_ui/fpscounter.hpp"
#include "components/rendering/rendering.h"
#include "version_data.h"
#include "components/3rdparty/imgui/formats/imgui_impl_win32.h"
#include "components/3rdparty/imgui/formats/dx11/imgui_impl_dx11.h"
//extern "C" int __cdecl myPuts(const char* message);
// ImGUI data
BlamRendering::RenderStack::ImGUIObject* imgui;
bool imgui_initialized = false;
// Blam UI data
BlamRendering::RenderStack::ConsoleUI* console;
// Window data
WNDCLASSEX wc;
HWND hwndGoto = NULL;
HWND main_hwnd = NULL;
HINSTANCE hInst;
HCURSOR cursor;
const wchar_t* window_name;
// Socket data
UINT8* socketBuffer;
Blam::Network::Socket sock;
Blam::LinearAllocator allocator;
UINT32 bytesReceived;
Blam::Endpoint from;
extern bool isConnected;
// Threading data
std::thread render_thread;
bool use_separate_render_thread = false;
// Forward declarations
INT_PTR CALLBACK FirstbootDialog(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
void cleanup_resources(LPCWSTR ver_conv, WNDCLASSEX wc);
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI MainWindowProcedure(HWND window_handle, UINT message, WPARAM wParam, LPARAM lParam)
{
//handle imgui input
if (ImGui_ImplWin32_WndProcHandler(window_handle, message, wParam, lParam))
{
return true;
}
//if imgui doesnt handle input, then its our job to do so
switch (message)
{
case WM_QUIT:
{
cleanup_resources(window_name, wc);
return 0;
}
case WM_SIZE:
{
//resize Direct3D render target upon window resize
if (BlamRendering::DirectX::GetD3DDevice() != NULL && wParam != SIZE_MINIMIZED)
{
BlamRendering::DirectX::HandleWindowResize(lParam);
}
return 0;
}
case WM_KEYDOWN:
{
return Blam::Input::HandleKeyPress(wParam);
}
case WM_CHAR:
{
return Blam::Input::HandleCharacterInput(wParam);
}
case WM_KEYUP:
{
//key released
return 0;
}
case WM_SYSCOMMAND:
{
// Disable ALT application menu
if ((wParam & 0xfff0) == SC_KEYMENU)
{
return 0;
}
break;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case ID_HELP_CREDITS:
{
if (!IsWindow(hwndGoto))
{
hwndGoto = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROPPAGE_MEDIUM), window_handle, NULL);
ShowWindow(hwndGoto, SW_SHOW);
}
break;
}
case ID_HELP_ABOUT:
{
Blam::Dialogs::AboutDialogProcedure(hInst, window_handle);
break;
}
case ID_TEST_SHOW_FIRSTBOOT:
{
Blam::Dialogs::FirstbootDialogProcedure(hInst, window_handle);
break;
}
case ID_TEST_ERROR:
{
Blam::Dialogs::ErrorDialogProcedure(hInst, window_handle, "This is a test error.");
break;
}
case ID_TEST_FONTTEST:
{
Blam::Dialogs::FontTestDialogProcedure(hInst, window_handle);
break;
}
case ID_TEST_IDD:
{
Blam::Dialogs::ErrorDialogProcedure(hInst, window_handle, "this shit was literally fucking garbage (tell halo to replace with IDD_PROPPAGE_MEDIUM thing just to finally put it in it's place)");
break;
}
case ID_TEST_RESTOREIMGUI:
{
if (!BlamRendering::RenderStack::ContainsImGUIObject())
{
BlamRendering::RenderStack::ImGUIObject* imgui_obj = new BlamRendering::RenderStack::ImGUIObject();
BlamRendering::RenderStack::AddToStack("imgui", imgui_obj);
}
else
{
Blam::DebugUI::ShowErrorDialog("imgui already present", "imgui is already present in the render stack");
}
break;
}
case ID_FILE_EXIT:
{
DestroyWindow(window_handle);
break;
}
default:
{
return DefWindowProc(window_handle, message, wParam, lParam);
}
}
return 0L;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(window_handle, message, wParam, lParam);
}
int main(int args_count, char *args[])
{
//assign hInstance
hInst = GetModuleHandle(NULL);
//int e = myPuts("are we connected");
Blam::Config::LoadConfig();
//load console color configuration
{
if (Blam::Config::GetConfig()->GetString("console_color_set") == "classic")
{
Blam::Utils::IO::CreateFileFromResource(CONFIG_COLOR_NAME, IDR_CON_COL_BUNGIE, "CFG", false);
}
else if (Blam::Config::GetConfig()->GetString("console_color_set") == "new")
{
Blam::Utils::IO::CreateFileFromResource(CONFIG_COLOR_NAME, IDR_CON_COL_NEW, "CFG", false);
}
else
{
if (!Blam::Utils::IO::file_exists(CONFIG_COLOR_NAME))
{
Blam::Utils::IO::CreateFileFromResource(CONFIG_COLOR_NAME, IDR_CON_COL_NEW, "CFG", false);
}
}
Blam::Config::LoadConfig(CONFIG_COLOR_NAME);
}
// Start logger
{
//Load configuration placeholders
Blam::Placeholders::LoadPlaceholders();
//Initialize logger
InternalUI::Colors::RegisterDefaultColors();
Blam::Logger::PrepareLogger();
Blam::Logger::PrintStartupHeader();
Blam::Logger::Queue::Flush();
Blam::LogEvent("Engine root set to '" + Blam::Config::GetConfig()->GetString("game_data_root") + "'");
Blam::LogEvent("User data root set to '" + Blam::Config::GetConfig()->GetString("user_data_root") + "'");
Blam::Logger::LogEvent("color log test", true, WSV_NONE, 255, 76, 255);
}
// Create gvars.xml then load it
{
Blam::Utils::IO::CreateFileFromResource(Blam::Config::GetConfig()->GetString("game_data_root") + GVARS_FILE, IDR_GVARS_XML, "XML", false);
BlamScript::Globals::LoadGlobalsFromFile();
}
// Initialize debug menu
{
std::string debug_menu_path = Blam::Config::GetConfig()->GetString("game_data_root") + "" + "./" + DEBUG_MENU_FILE + ".xml";
if (!Blam::Utils::IO::file_exists(debug_menu_path))
{
if (Blam::Config::GetConfig()->GetBoolean("autoGenerateNewDebugMenuFile"))
{
Blam::Utils::IO::CreateFileFromResource(debug_menu_path, IDR_DEBUG_MENU_INIT_XML, "XML", false);
}
else
{
Blam::Logger::LogEvent("### WARNING unable to find debug_menu_init.xml, and automatic generation is disabled in config! this may result in the debug menu not being functional.", WSV_WARNING);
}
}
Blam::DebugMenu::InitializeDebugMenu();
}
// Check whether to show firstboot dialog
if (Blam::Config::GetConfig()->GetBoolean("show_firstboot") == true)
{
//show firstboot dialog
}
// Create application window
{
std::wstring version = Blam::Converters::ConvertStringToWstring(Blam::EngineDefs::GetVersion());
window_name = version.c_str();
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_CLASSDC;
wc.lpfnWndProc = MainWindowProcedure;
wc.cbClsExtra = 0L;
wc.cbWndExtra = 0L;
wc.hInstance = hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = window_name;
wc.hIconSm = NULL;
//check whether or not to enable windows menubar
if (Blam::Config::GetConfig()->GetBoolean("show_windows_menubar") == true)
{
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
}
//check whether or not to use a custom cursor
if (Blam::Config::GetConfig()->GetBoolean("use_custom_cursor"))
{
cursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_POINTER));
if (cursor)
{
wc.hCursor = cursor;
SetCursor(cursor);
}
else
{
Blam::LogEvent("### WARNING failed to load cursor resource");
BL_LOGEVT_RGB("", true, WSV_WARNING, 255, 255, 0);
Blam::Error::ShowLastErrorInfo("LoadCursorW", Blam::Error::ErrorDisplayType::Log);
}
}
RegisterClassEx(&wc);
main_hwnd = CreateWindow(window_name, window_name, WS_OVERLAPPEDWINDOW, 0, 0, 1920, 1040, NULL, NULL, wc.hInstance, NULL);
if (Blam::Config::GetConfig()->GetBoolean("use_themed_windows") == false)
{
SetWindowTheme(main_hwnd, L" ", L" ");
}
}
//initialize netcode if enabled
if (Blam::Config::GetConfig()->GetBoolean("use_netcode") == true)
{
Blam::linearAllocCreate(&allocator, 16 * 1024 * 1024);
Blam::LogEvent("### WARNING netcode is experimental!");
if (Blam::Network::Init())
{
Blam::Network::Start(&sock, &allocator);
Blam::LogEvent("Blam::Network - Initialized!");
socketBuffer = Blam::linearAlloc(&allocator, 2048);
Blam::Endpoint endpoint = {};
endpoint.address = (127 << 24) | (0 << 16) | (0 << 8) | 1;
endpoint.port = 6536;
UINT32 ClientHelloSize = Blam::Network::ClientHelloMessage(socketBuffer);
if (Blam::Network::Send(&sock, socketBuffer, ClientHelloSize, &endpoint))
{
Blam::LogEvent("Successfully sent message!");
isConnected = true;
}
}
}
// Initialize DirectX
{
HRESULT hr = BlamRendering::DirectX::Initialize(main_hwnd);
if (FAILED(hr))
{
Blam::Logger::LogEvent("### ERROR failed to initialize DirectX! details: '" + std::string(Blam::Error::GetStringFromHResult(hr)) + "'", WSV_CRITICAL);
cleanup_resources(window_name, wc);
return -45;
}
}
//Show application window
ShowWindow(main_hwnd, SW_MAXIMIZE);
UpdateWindow(main_hwnd);
//Setup ImGUI
{
IMGUI_CHECKVERSION();
// Setup ImGui binding
ImGui::CreateContext();
Blam::LogEvent("Getting I/O for ImGUI");
// Load Fonts
// (there is a default font, this is only if you want to change it. see extra_fonts/README.txt for more details)
ImGuiIO& io = ImGui::GetIO(); //(void)io;
ImGui_ImplWin32_Init(main_hwnd);
imgui_initialized = ImGui_ImplDX11_Init(BlamRendering::DirectX::GetD3DDevice(), BlamRendering::DirectX::GetD3DContext());
if (Blam::Config::GetConfig()->GetBoolean("enable_imgui_gamepad_nav"))
{
Blam::LogEvent("imgui gamepad navigation enabled");
io.ConfigFlags += ImGuiConfigFlags_NavEnableGamepad;
}
//load font for imgui
{
float font_size = Blam::Config::GetConfig()->GetFloat("sys_font_size");
std::string font_path_str = "./maps/fonts/" + Blam::Config::GetConfig()->GetString("sys_font");
if (Blam::Config::GetConfig()->GetBoolean("sys_font_force_extension") == true)
{
font_path_str = font_path_str + ".bin";
}
const char* font_path = font_path_str.c_str();
Blam::Logger::LogEvent("Loading standard front from " + font_path_str);
ImFont* font0 = io.Fonts->AddFontFromFileTTF(font_path_str.c_str(), font_size);
}
Blam::LogEvent("Setting UI theme: Elaztek");
InternalUI::load_elaztek_styles();
if (BlamRendering::DirectX::RenderTargetClearing() == false)
{
Blam::LogEvent("############################################");
Blam::LogEvent("# Render target clearing is DISABLED! #");
Blam::LogEvent("# You will notice some visual distortion #");
Blam::LogEvent("# and other visual errors! #");
Blam::LogEvent("############################################");
}
BlamRendering::SetClearColor(ImColor(114, 144, 154));
imgui = new BlamRendering::RenderStack::ImGUIObject();
BlamRendering::RenderStack::AddToStack("imgui", imgui);
InternalUI::Initialize();
}
Blam::LogEvent("ENGINE_VERSION: " + std::string(Blam::EngineDefs::GetVersion()));
Blam::LogEvent("UI_VERSION: " + std::string(InternalUI::GetVersion()));
Blam::LogEvent("IMGUI_VERSION: " + std::string(ImGui::GetVersion()));
//Blam::LogEvent("Beginning init");
//Load blamscript (this shit really sucks and is useless)
{
Blam::Logger::LogEvent("Initializing blamscript (TODO: rewrite all this shit)");
BlamScript::InitCSC();
BlamScript::InitHSC();
}
//load content
{
//Blam::Content::Fonts::LoadFont("./maps/fonts/" + Blam::Config::GetConfig()->GetString("ui_default_font"));
//Blam::Content::Fonts::LoadFont("./maps/fonts/conduit");
//Blam::Content::Fonts::LoadFont("./maps/fonts/arial-12");
//Blam::Content::Fonts::LoadFont("./maps/fonts/denmark-80");
Blam::Content::Fonts::LoadAllFonts();
}
//Initialize Discord Rich Presence
{
Blam::DiscordRPC::InitDiscord();
Blam::DiscordRPC::UpdatePresence(ENGINE_VERSION, "Using the Blamite Engine");
}
bool debug = Blam::Config::GetConfig()->GetBoolean("debugMode");
use_separate_render_thread = Blam::Config::GetConfig()->GetBoolean("use_separate_render_thread");
if (use_separate_render_thread)
{
Blam::Logger::LogEvent("### NOTICE rendering is being handled on a separate thread!");
render_thread = std::thread(BlamRendering::DirectX::RenderThread, debug);
render_thread.detach();
}
// Load built-in console commands
Blam::Console::RegisterBuiltinCommands();
// Create custom ui elements (console, fps counter)
{
BlamRendering::RenderStack::FPSCounter* fpscounter = new BlamRendering::RenderStack::FPSCounter();
BlamRendering::RenderStack::AddToStack("fps_counter", fpscounter);
console = new BlamRendering::RenderStack::ConsoleUI();
BlamRendering::RenderStack::AddToStack("console", console);
BlamRendering::RenderStack::DebugMenu* debug_menu = new BlamRendering::RenderStack::DebugMenu();
BlamRendering::RenderStack::AddToStack("debug_menu", debug_menu);
}
// Run any startup commands in init.txt
{
if (Blam::Utils::IO::file_exists("./init.txt"))
{
std::vector<std::string> startup_commands = Blam::Utils::IO::GetFileContentsAsLines("./init.txt");
for (int i = 0; i < startup_commands.size(); i++)
{
Blam::Console::RunCommandLine(startup_commands.at(i));
}
}
}
// Main application loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{
Blam::Tick::tick();
if (cursor)
{
//SetCursor(cursor);
}
if (debug == true)
{
//Blam::DebugUIKeyListener();
}
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (!use_separate_render_thread)
{
BlamRendering::DirectX::RenderLoop(debug);
BlamRendering::DirectX::GetDXGISwapChain()->Present(1, 0);
}
Blam::Network::HandleReceive(&sock, socketBuffer, 2048, &bytesReceived, &from);
Blam::Logger::Queue::Flush();
}
cleanup_resources(window_name, wc);
return 0;
}
void cleanup_resources(LPCWSTR ver_conv, WNDCLASSEX wc)
{
if (use_separate_render_thread)
{
Blam::Logger::LogEvent("stopping render thread");
BlamRendering::DirectX::ShutdownRenderThread();
while (BlamRendering::DirectX::HasRenderThreadStopped() == false)
{
//wait for render thread to stop
}
}
BlamRendering::RenderStack::Cleanup();
Blam::LogEvent("Shutting down discord");
Blam::DiscordRPC::ShutdownDiscord();
if (imgui_initialized)
{
Blam::LogEvent("Shutting down ImGUI and cleaning up D3D device");
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
}
else
{
Blam::LogEvent("### INFO engine shutting down before imgui init");
}
InternalUI::Shutdown();
//delete imgui;
//delete console;
Blam::Console::Cleanup();
Blam::Content::Fonts::Cleanup();
Blam::Cache::ClearCachedFiles();
BlamRendering::DirectX::Cleanup();
Blam::Logger::Queue::Flush();
DestroyWindow(main_hwnd);
UnregisterClass(ver_conv, wc.hInstance);
}
HWND Blam::GetMainWindowHandle()
{
return main_hwnd;
}