#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TODO : Replace with message box from framework + call main and not winmain + subsystem // TODO : Think how to do the draw pipeline. // Ex: Expose a Draw method ? // Store a graphics context ? // For now. Put everything in Update down below. // Should split update from draw, update should have a != timestep than graphics (60fps or more) // TODO : Remove main.h. Useless // May be remove that Application class, useless too. using namespace Juliet; namespace { using GameInit_t = void (*)(void); using GameShutdown_t = void (*)(void); using GameUpdate_t = void (*)(float deltaTime); struct GameFunctionTable { GameInit_t Init = nullptr; GameShutdown_t Shutdown = nullptr; GameUpdate_t Update = nullptr; } Game; const char* GameFunctionTable[] = { "GameInit", "GameShutdown", "GameUpdate" }; } // namespace void JulietApplication::Init() { Log(LogLevel::Message, LogCategory::Editor, "Initializing Juliet Application..."); Log(LogLevel::Message, LogCategory::Editor, "%s", GetBasePath()); GraphicsConfig config; GraphicsDevice = CreateGraphicsDevice(config); MainWindow = CreatePlatformWindow("Juliet Editor", 1280, 720); Running = MainWindow != nullptr && GraphicsDevice != nullptr; if (Running) { AttachToWindow(GraphicsDevice, MainWindow); // Game = LoadDynamicLibrary("Game.dll"); GameCode.Functions = reinterpret_cast(&Game); GameCode.FunctionCount = ArraySize(GameFunctionTable); GameCode.FunctionNames = GameFunctionTable; InitHotReloadCode(GameCode, StringBufferParam("Game.dll"), StringBufferParam("Game_Temp.dll"), StringBufferParam("lock.tmp")); if ((Running = GameCode.IsValid)) { Game.Init(); } } } void JulietApplication::Shutdown() { Log(LogLevel::Message, LogCategory::Editor, "Shutting down Juliet Application..."); Game.Shutdown(); ShutdownHotReloadCode(GameCode); if (MainWindow && GraphicsDevice) { DetachFromWindow(GraphicsDevice, MainWindow); } if (MainWindow) { DestroyPlatformWindow(MainWindow); } if (GraphicsDevice) { DestroyGraphicsDevice(GraphicsDevice); } Log(LogLevel::Message, LogCategory::Editor, "Juliet App shutdown Completed"); } void JulietApplication::Update() { SystemEvent evt; while (GetEvent(evt)) { if (evt.Type == EventType::Window_Close_Request) { if (evt.Data.Window.AssociatedWindowID == GetWindowID(MainWindow)) { Running = false; } } } Game.Update(0.0f); if (ShouldReloadCode(GameCode)) { ReloadCode(GameCode); } // Draw here for now // 1) Acquire a Command Buffer CommandList* cmdList = AcquireCommandList(GraphicsDevice, QueueType::Graphics); if (cmdList == nullptr) { Log(LogLevel::Error, LogCategory::Editor, "Failed to acquire command list."); Running = false; return; } Texture* swapChainTexture = nullptr; if (!AcquireSwapChainTexture(cmdList, MainWindow, &swapChainTexture)) { Log(LogLevel::Error, LogCategory::Editor, "Failed to acquire swapchain texture."); Running = false; return; } if (swapChainTexture) { ColorTargetInfo colorTargetInfo = {}; colorTargetInfo.TargetTexture = swapChainTexture; colorTargetInfo.ClearColor = { .R = .5f, .G = .8f, .B = .0f, .A = 1.f }; colorTargetInfo.LoadOperation = LoadOperation::Clear; colorTargetInfo.StoreOperation = StoreOperation::Store; RenderPass* renderPass = BeginRenderPass(cmdList, colorTargetInfo); EndRenderPass(renderPass); } // Submit Commands SubmitCommandLists(cmdList); } bool JulietApplication::IsRunning() { return Running; } namespace { JulietApplication EditorApplication; } JulietApplication& GetEditorApplication() { return EditorApplication; } int main(int argc, char** argv) { CreateMutex(0, false, L"Local\\Juliet.App"); if (GetLastError() == ERROR_ALREADY_EXISTS) { MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION); return EXIT_FAILURE; } StartApplication(EditorApplication, JulietInit_Flags::Display); // Pause here to not close the console window immediatly on stop system("PAUSE"); return EXIT_SUCCESS; }