diff --git a/src/app/core/controller.cc b/src/app/core/controller.cc index 07871b1c..a293cc80 100644 --- a/src/app/core/controller.cc +++ b/src/app/core/controller.cc @@ -2,15 +2,9 @@ #include -#include -#include - #include "absl/status/status.h" -#include "absl/strings/str_format.h" -#include "app/core/platform/file_dialog.h" -#include "app/core/platform/font_loader.h" +#include "app/core/window.h" #include "app/editor/editor_manager.h" -#include "app/gui/style.h" #include "imgui/backends/imgui_impl_sdl2.h" #include "imgui/backends/imgui_impl_sdlrenderer2.h" #include "imgui/imgui.h" @@ -18,39 +12,10 @@ namespace yaze { namespace core { -namespace { -// Helper function to draw the main window without docking enabled -// Should be followed by ImGui::End() to close the window -void DrawBasicWindow() { - constexpr ImGuiWindowFlags kMainEditorFlags = - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | - ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | - ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar; - - const ImGuiIO &io = ImGui::GetIO(); - ImGui_ImplSDLRenderer2_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); - ImGui::SetNextWindowPos(gui::kZeroPos); - ImVec2 dimensions(io.DisplaySize.x, io.DisplaySize.y); - ImGui::SetNextWindowSize(dimensions, ImGuiCond_Always); - - if (!ImGui::Begin("##YazeMain", nullptr, kMainEditorFlags)) { - ImGui::End(); - } -} -} // namespace - absl::Status Controller::OnEntry(std::string filename) { - RETURN_IF_ERROR(CreateWindow()) - RETURN_IF_ERROR(CreateRenderer()) - RETURN_IF_ERROR(CreateGuiContext()) - backend_.init_audio(); - // cast to Sdl2backend to access audio buffer and device - auto &sdl2_backend = static_cast(backend_); - editor_manager_.emulator().set_audio_buffer( - sdl2_backend.audio_buffer().get()); - editor_manager_.emulator().set_audio_device_id(sdl2_backend.audio_device()); + RETURN_IF_ERROR(CreateWindow(window_, SDL_WINDOW_RESIZABLE)); + editor_manager_.emulator().set_audio_buffer(window_.audio_buffer_.get()); + editor_manager_.emulator().set_audio_device_id(window_.audio_device_); Initialize(filename); return absl::OkStatus(); } @@ -156,96 +121,7 @@ void Controller::DoRender() const { } void Controller::OnExit() { - backend_.shutdown_audio(); - ImGui_ImplSDLRenderer2_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); - SDL_Quit(); -} - -absl::Status Controller::CreateWindow() { - auto sdl_flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; - - if (SDL_Init(sdl_flags) != 0) { - return absl::InternalError( - absl::StrFormat("SDL_Init: %s\n", SDL_GetError())); - } - - SDL_DisplayMode display_mode; - SDL_GetCurrentDisplayMode(0, &display_mode); - int screen_width = display_mode.w * 0.8; - int screen_height = display_mode.h * 0.8; - - window_ = std::unique_ptr( - SDL_CreateWindow("Yet Another Zelda3 Editor", // window title - SDL_WINDOWPOS_UNDEFINED, // initial x position - SDL_WINDOWPOS_UNDEFINED, // initial y position - screen_width, // width, in pixels - screen_height, // height, in pixels - SDL_WINDOW_RESIZABLE), - core::SDL_Deleter()); - if (window_ == nullptr) { - return absl::InternalError( - absl::StrFormat("SDL_CreateWindow: %s\n", SDL_GetError())); - } - - return absl::OkStatus(); -} - -absl::Status Controller::CreateRenderer() { - return Renderer::Get().CreateRenderer(window_.get()); -} - -absl::Status Controller::CreateGuiContext() { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - - ImGuiIO &io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - - // Initialize ImGui based on the backend - ImGui_ImplSDL2_InitForSDLRenderer(window_.get(), - Renderer::Get().renderer()); - ImGui_ImplSDLRenderer2_Init(Renderer::Get().renderer()); - - RETURN_IF_ERROR(LoadPackageFonts()); - - // Set the default style - gui::ColorsYaze(); - - // Build a new ImGui frame - backend_.new_frame(); - - return absl::OkStatus(); -} - -absl::Status Controller::LoadConfigFiles() { - // Create and load a dotfile for the application - // This will store the user's preferences and settings - std::string config_directory = GetConfigDirectory(); - - // Create the directory if it doesn't exist - if (!std::filesystem::exists(config_directory)) { - if (!std::filesystem::create_directory(config_directory)) { - return absl::InternalError(absl::StrFormat( - "Failed to create config directory %s", config_directory)); - } - } - - // Check if the config file exists - std::string config_file = config_directory + "yaze.cfg"; - if (!std::filesystem::exists(config_file)) { - // Create the file if it doesn't exist - std::ofstream file(config_file); - if (!file.is_open()) { - return absl::InternalError( - absl::StrFormat("Failed to create config file %s", config_file)); - } - file.close(); - } - - return absl::OkStatus(); + PRINT_IF_ERROR(ShutdownWindow(window_)); } } // namespace core diff --git a/src/app/core/controller.h b/src/app/core/controller.h index 3ef869a4..83513927 100644 --- a/src/app/core/controller.h +++ b/src/app/core/controller.h @@ -6,7 +6,7 @@ #include #include "absl/status/status.h" -#include "app/core/platform/backend.h" +#include "app/core/window.h" #include "app/editor/editor_manager.h" int main(int argc, char **argv); @@ -30,12 +30,7 @@ class Controller { void DoRender() const; void OnExit(); - absl::Status CreateWindow(); - absl::Status CreateRenderer(); - absl::Status CreateGuiContext(); - absl::Status LoadConfigFiles(); - - auto window() -> SDL_Window * { return window_.get(); } + auto window() -> SDL_Window * { return window_.window_.get(); } void set_active(bool active) { active_ = active; } auto active() const { return active_; } @@ -43,9 +38,8 @@ class Controller { friend int ::main(int argc, char **argv); bool active_ = false; + core::Window window_; editor::EditorManager editor_manager_; - std::shared_ptr window_; - core::PlatformBackend backend_; }; } // namespace core diff --git a/src/app/core/core.cmake b/src/app/core/core.cmake index ff2260d8..d1034361 100644 --- a/src/app/core/core.cmake +++ b/src/app/core/core.cmake @@ -3,6 +3,7 @@ set( app/core/controller.cc app/emu/emulator.cc app/core/project.cc + app/core/window.cc ) if (WIN32 OR MINGW OR UNIX AND NOT APPLE) diff --git a/src/app/core/platform/backend.h b/src/app/core/platform/backend.h deleted file mode 100644 index 25b05891..00000000 --- a/src/app/core/platform/backend.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef YAZE_APP_CORE_PLATFORM_BACKEND_H -#define YAZE_APP_CORE_PLATFORM_BACKEND_H - -#include - -#include -#include - -#include "app/core/platform/renderer.h" -#include "app/core/platform/sdl_deleter.h" -#include "imgui/backends/imgui_impl_sdl2.h" -#include "imgui/backends/imgui_impl_sdlrenderer2.h" - -namespace yaze { -namespace core { - -template -class PlatformBackend { - public: - PlatformBackend() = default; - ~PlatformBackend() = default; - - void init() { static_cast(this)->init(); } - void init_audio() { static_cast(this)->init_audio(); } - void shutdown_audio() { static_cast(this)->shutdown_audio(); } - void shutdown() { static_cast(this)->shutdown(); } - void new_frame() { static_cast(this)->new_frame(); } - void render() { static_cast(this)->render(); } -}; - -class Sdl2Backend : public PlatformBackend { - public: - Sdl2Backend() = default; - ~Sdl2Backend() = default; - - void init() { - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != - 0) { - throw std::runtime_error("Failed to initialize SDL2"); - } - - SDL_DisplayMode display_mode; - SDL_GetCurrentDisplayMode(0, &display_mode); - int screen_width = display_mode.w * 0.8; - int screen_height = display_mode.h * 0.8; - - window = std::unique_ptr( - SDL_CreateWindow("Yet Another Zelda3 Editor", // window title - SDL_WINDOWPOS_UNDEFINED, // initial x position - SDL_WINDOWPOS_UNDEFINED, // initial y position - screen_width, // width, in pixels - screen_height, // height, in pixels - SDL_WINDOW_RESIZABLE), - core::SDL_Deleter()); - if (!window) { - throw std::runtime_error("Failed to create window"); - } - - if (!Renderer::Get().CreateRenderer(window.get()).ok()) { - throw std::runtime_error("Failed to create renderer"); - } - - ImGui_ImplSDL2_InitForSDLRenderer(window.get(), - Renderer::Get().renderer()); - ImGui_ImplSDLRenderer2_Init(Renderer::Get().renderer()); - } - - void init_audio() { - const int audio_frequency = 48000; - SDL_AudioSpec want, have; - SDL_memset(&want, 0, sizeof(want)); - want.freq = audio_frequency; - want.format = AUDIO_S16; - want.channels = 2; - want.samples = 2048; - want.callback = NULL; // Uses the queue - audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); - if (audio_device_ == 0) { - throw std::runtime_error( - absl::StrFormat("Failed to open audio: %s\n", SDL_GetError())); - } - audio_buffer_ = std::make_shared(audio_frequency / 50 * 4); - SDL_PauseAudioDevice(audio_device_, 0); - } - - void shutdown_audio() { - SDL_PauseAudioDevice(audio_device_, 1); - SDL_CloseAudioDevice(audio_device_); - } - - void shutdown() { - ImGui_ImplSDL2_Shutdown(); - ImGui_ImplSDLRenderer2_Shutdown(); - SDL_DestroyRenderer(Renderer::Get().renderer()); - SDL_DestroyWindow(window.get()); - SDL_Quit(); - } - - void new_frame() { - ImGui_ImplSDLRenderer2_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - } - - void render() { - ImGui::Render(); - SDL_RenderClear(Renderer::Get().renderer()); - ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), - Renderer::Get().renderer()); - SDL_RenderPresent(Renderer::Get().renderer()); - } - - auto window_ptr() -> SDL_Window * { return window.get(); } - auto audio_device() -> SDL_AudioDeviceID { return audio_device_; } - auto audio_buffer() -> std::shared_ptr { return audio_buffer_; } - - private: - SDL_AudioDeviceID audio_device_; - std::shared_ptr audio_buffer_; - std::unique_ptr window; -}; - -} // namespace core -} // namespace yaze - -#endif // YAZE_APP_CORE_PLATFORM_BACKEND_H diff --git a/src/app/core/platform/memory_tracker.h b/src/app/core/platform/memory_tracker.h deleted file mode 100644 index 281626df..00000000 --- a/src/app/core/platform/memory_tracker.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef YAZE_APP_CORE_PLATFORM_MEMORY_TRACKER_H -#define YAZE_APP_CORE_PLATFORM_MEMORY_TRACKER_H - -#include - -#include -#include -#include -#include - -namespace yaze { -namespace core { - -class MemoryTracker { - public: - static MemoryTracker& GetInstance() { - static MemoryTracker instance; - return instance; - } - - void TrackAllocation(const void* ptr, size_t size, const char* type) { - std::lock_guard lock(mutex_); - allocations_[ptr] = {size, type}; - total_allocated_ += size; - } - - void TrackDeallocation(const void* ptr) { - std::lock_guard lock(mutex_); - auto it = allocations_.find(ptr); - if (it != allocations_.end()) { - total_allocated_ -= it->second.size; - allocations_.erase(it); - } - } - - size_t GetTotalAllocated() const { - std::lock_guard lock(mutex_); - return total_allocated_; - } - - void DumpAllocations() const { - std::lock_guard lock(mutex_); - SDL_Log("Memory allocations: %zu bytes in %zu allocations", - total_allocated_, allocations_.size()); - - std::unordered_map type_counts; - for (const auto& pair : allocations_) { - type_counts[pair.second.type] += pair.second.size; - } - - for (const auto& pair : type_counts) { - SDL_Log(" %s: %zu bytes", pair.first.c_str(), pair.second); - } - } - - // Check if the memory was freed by another reference - bool IsFreed(const void* ptr) const { - std::lock_guard lock(mutex_); - return allocations_.find(ptr) == allocations_.end(); - } - - private: - MemoryTracker() = default; - - struct AllocationInfo { - size_t size; - const char* type; - }; - - std::unordered_map allocations_; - size_t total_allocated_ = 0; - mutable std::mutex mutex_; -}; - -} // namespace core -} // namespace yaze - -#endif // YAZE_APP_CORE_PLATFORM_MEMORY_TRACKER_H diff --git a/src/app/core/window.cc b/src/app/core/window.cc new file mode 100644 index 00000000..4a30bb10 --- /dev/null +++ b/src/app/core/window.cc @@ -0,0 +1,87 @@ +#include "app/core/window.h" + +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "app/core/platform/font_loader.h" +#include "app/core/platform/sdl_deleter.h" +#include "app/gui/style.h" +#include "imgui/backends/imgui_impl_sdl2.h" +#include "imgui/backends/imgui_impl_sdlrenderer2.h" +#include "imgui/imgui.h" + +namespace yaze { +namespace core { + +absl::Status CreateWindow(Window& window, int flags) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) { + return absl::InternalError( + absl::StrFormat("SDL_Init: %s\n", SDL_GetError())); + } + + SDL_DisplayMode display_mode; + SDL_GetCurrentDisplayMode(0, &display_mode); + int screen_width = display_mode.w * 0.8; + int screen_height = display_mode.h * 0.8; + + window.window_ = std::unique_ptr( + SDL_CreateWindow("Yet Another Zelda3 Editor", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, screen_width, screen_height, + flags), + SDL_Deleter()); + if (window.window_ == nullptr) { + return absl::InternalError( + absl::StrFormat("SDL_CreateWindow: %s\n", SDL_GetError())); + } + + RETURN_IF_ERROR(Renderer::Get().CreateRenderer(window.window_.get())); + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + + ImGui_ImplSDL2_InitForSDLRenderer(window.window_.get(), + Renderer::Get().renderer()); + ImGui_ImplSDLRenderer2_Init(Renderer::Get().renderer()); + + RETURN_IF_ERROR(LoadPackageFonts()); + + gui::ColorsYaze(); + + ImGui_ImplSDLRenderer2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + + const int audio_frequency = 48000; + SDL_AudioSpec want, have; + SDL_memset(&want, 0, sizeof(want)); + want.freq = audio_frequency; + want.format = AUDIO_S16; + want.channels = 2; + want.samples = 2048; + want.callback = NULL; // Uses the queue + window.audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); + if (window.audio_device_ == 0) { + throw std::runtime_error( + absl::StrFormat("Failed to open audio: %s\n", SDL_GetError())); + } + window.audio_buffer_ = std::make_shared(audio_frequency / 50 * 4); + SDL_PauseAudioDevice(window.audio_device_, 0); + + return absl::OkStatus(); +} + +absl::Status ShutdownWindow(Window& window) { + SDL_PauseAudioDevice(window.audio_device_, 1); + SDL_CloseAudioDevice(window.audio_device_); + ImGui_ImplSDL2_Shutdown(); + ImGui_ImplSDLRenderer2_Shutdown(); + ImGui::DestroyContext(); + SDL_DestroyRenderer(Renderer::Get().renderer()); + SDL_DestroyWindow(window.window_.get()); + SDL_Quit(); + return absl::OkStatus(); +} + +} // namespace core +} // namespace yaze \ No newline at end of file diff --git a/src/app/core/platform/renderer.h b/src/app/core/window.h similarity index 86% rename from src/app/core/platform/renderer.h rename to src/app/core/window.h index 3bc438bc..08ff6629 100644 --- a/src/app/core/platform/renderer.h +++ b/src/app/core/window.h @@ -1,5 +1,5 @@ -#ifndef YAZE_APP_CORE_PLATFORM_RENDERER_H -#define YAZE_APP_CORE_PLATFORM_RENDERER_H +#ifndef YAZE_CORE_WINDOW_H_ +#define YAZE_CORE_WINDOW_H_ #include @@ -13,6 +13,16 @@ namespace yaze { namespace core { +struct Window { + std::shared_ptr window_; + SDL_AudioDeviceID audio_device_; + std::shared_ptr audio_buffer_; +}; + +absl::Status CreateWindow(Window &window, int flags); + +absl::Status ShutdownWindow(Window &window); + /** * @class Renderer * @brief The Renderer class represents the renderer for the Yaze application. @@ -76,5 +86,4 @@ class Renderer { } // namespace core } // namespace yaze - -#endif +#endif // YAZE_CORE_WINDOW_H_ \ No newline at end of file diff --git a/src/app/editor/dungeon/dungeon_editor.cc b/src/app/editor/dungeon/dungeon_editor.cc index e5a51d04..b515064f 100644 --- a/src/app/editor/dungeon/dungeon_editor.cc +++ b/src/app/editor/dungeon/dungeon_editor.cc @@ -1,7 +1,7 @@ #include "dungeon_editor.h" #include "absl/container/flat_hash_map.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/arena.h" #include "app/gfx/snes_palette.h" #include "app/gui/canvas.h" diff --git a/src/app/editor/graphics/graphics_editor.cc b/src/app/editor/graphics/graphics_editor.cc index 26da003d..f12cc359 100644 --- a/src/app/editor/graphics/graphics_editor.cc +++ b/src/app/editor/graphics/graphics_editor.cc @@ -7,7 +7,7 @@ #include "absl/strings/str_cat.h" #include "app/core/platform/clipboard.h" #include "app/core/platform/file_dialog.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/arena.h" #include "app/gfx/bitmap.h" #include "app/gfx/compression.h" diff --git a/src/app/editor/graphics/screen_editor.cc b/src/app/editor/graphics/screen_editor.cc index aa75d855..305ac0fa 100644 --- a/src/app/editor/graphics/screen_editor.cc +++ b/src/app/editor/graphics/screen_editor.cc @@ -7,7 +7,7 @@ #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "app/core/platform/file_dialog.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/arena.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" diff --git a/src/app/editor/message/message_editor.cc b/src/app/editor/message/message_editor.cc index baba2975..1206ea13 100644 --- a/src/app/editor/message/message_editor.cc +++ b/src/app/editor/message/message_editor.cc @@ -6,7 +6,7 @@ #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" diff --git a/src/app/editor/overworld/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc index bffd15ed..3393942c 100644 --- a/src/app/editor/overworld/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -9,7 +9,7 @@ #include "absl/strings/str_format.h" #include "app/core/features.h" #include "app/core/platform/clipboard.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/editor/graphics/palette_editor.h" #include "app/editor/overworld/entity.h" #include "app/gfx/arena.h" diff --git a/src/app/editor/overworld/tile16_editor.cc b/src/app/editor/overworld/tile16_editor.cc index 408fb8fd..f67c02a6 100644 --- a/src/app/editor/overworld/tile16_editor.cc +++ b/src/app/editor/overworld/tile16_editor.cc @@ -4,7 +4,7 @@ #include "absl/status/status.h" #include "app/core/platform/file_dialog.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gui/canvas.h" diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index 9e7c169c..1d521d73 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -3,7 +3,7 @@ #include #include -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/bitmap.h" #include "app/gui/color.h" #include "app/gui/input.h" diff --git a/src/app/rom.cc b/src/app/rom.cc index cbba6161..6b4270da 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -17,7 +17,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "app/core/features.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/compression.h" #include "app/gfx/snes_color.h" #include "app/gfx/snes_palette.h" diff --git a/src/app/zelda3/dungeon/room.cc b/src/app/zelda3/dungeon/room.cc index ce2973e5..921c5d51 100644 --- a/src/app/zelda3/dungeon/room.cc +++ b/src/app/zelda3/dungeon/room.cc @@ -6,7 +6,7 @@ #include #include "absl/strings/str_cat.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/arena.h" #include "app/rom.h" #include "app/snes.h" diff --git a/src/app/zelda3/screen/dungeon_map.cc b/src/app/zelda3/screen/dungeon_map.cc index 98c14b13..04b91f2c 100644 --- a/src/app/zelda3/screen/dungeon_map.cc +++ b/src/app/zelda3/screen/dungeon_map.cc @@ -4,7 +4,7 @@ #include #include "app/core/platform/file_dialog.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/gfx/tilemap.h" diff --git a/src/app/zelda3/screen/inventory.cc b/src/app/zelda3/screen/inventory.cc index 6c591ee0..f648f2c9 100644 --- a/src/app/zelda3/screen/inventory.cc +++ b/src/app/zelda3/screen/inventory.cc @@ -1,6 +1,6 @@ #include "inventory.h" -#include "app/core/platform/renderer.h" +#include "app/core/window.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h"