backend-infra-engineer: Release v0.3.3 snapshot
This commit is contained in:
@@ -15,25 +15,25 @@
|
||||
UIDocumentPickerDelegate,
|
||||
UITabBarControllerDelegate,
|
||||
PKCanvasViewDelegate>
|
||||
@property(strong, nonatomic) UIWindow *window;
|
||||
@property(strong, nonatomic) UIWindow* window;
|
||||
|
||||
@property UIDocumentPickerViewController *documentPicker;
|
||||
@property(nonatomic, copy) void (^completionHandler)(NSString *selectedFile);
|
||||
@property UIDocumentPickerViewController* documentPicker;
|
||||
@property(nonatomic, copy) void (^completionHandler)(NSString* selectedFile);
|
||||
- (void)PresentDocumentPickerWithCompletionHandler:
|
||||
(void (^)(NSString *selectedFile))completionHandler;
|
||||
(void (^)(NSString* selectedFile))completionHandler;
|
||||
|
||||
// TODO: Setup a tab bar controller for multiple yaze instances
|
||||
@property(nonatomic) UITabBarController *tabBarController;
|
||||
@property(nonatomic) UITabBarController* tabBarController;
|
||||
|
||||
// TODO: Setup a font picker for the text editor and display settings
|
||||
@property(nonatomic) UIFontPickerViewController *fontPicker;
|
||||
@property(nonatomic) UIFontPickerViewController* fontPicker;
|
||||
|
||||
// TODO: Setup the pencil kit for drawing
|
||||
@property PKToolPicker *toolPicker;
|
||||
@property PKCanvasView *canvasView;
|
||||
@property PKToolPicker* toolPicker;
|
||||
@property PKCanvasView* canvasView;
|
||||
|
||||
// TODO: Setup the file manager for file operations
|
||||
@property NSFileManager *fileManager;
|
||||
@property NSFileManager* fileManager;
|
||||
|
||||
@end
|
||||
|
||||
@@ -51,7 +51,7 @@ void yaze_initialize_cocoa();
|
||||
/**
|
||||
* @brief Run the Cocoa application delegate.
|
||||
*/
|
||||
int yaze_run_cocoa_app_delegate(const char *filename);
|
||||
int yaze_run_cocoa_app_delegate(const char* filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
@@ -8,81 +8,90 @@
|
||||
|
||||
namespace yaze {
|
||||
|
||||
|
||||
std::vector<std::filesystem::path> AssetLoader::GetSearchPaths(const std::string& relative_path) {
|
||||
std::vector<std::filesystem::path> AssetLoader::GetSearchPaths(
|
||||
const std::string& relative_path) {
|
||||
std::vector<std::filesystem::path> search_paths;
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
// macOS bundle resource paths
|
||||
std::string bundle_root = yaze::util::GetBundleResourcePath();
|
||||
|
||||
|
||||
// Try Contents/Resources first (standard bundle location)
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / "Contents" / "Resources" / relative_path);
|
||||
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / "Contents" /
|
||||
"Resources" / relative_path);
|
||||
|
||||
// Try without Contents (if app is at root)
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / "Resources" / relative_path);
|
||||
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / "Resources" /
|
||||
relative_path);
|
||||
|
||||
// Development paths (when running from build dir)
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / ".." / ".." / ".." / "assets" / relative_path);
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / ".." / ".." / ".." / ".." / "assets" / relative_path);
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / ".." / ".." /
|
||||
".." / "assets" / relative_path);
|
||||
search_paths.push_back(std::filesystem::path(bundle_root) / ".." / ".." /
|
||||
".." / ".." / "assets" / relative_path);
|
||||
#endif
|
||||
|
||||
|
||||
// Standard relative paths (works for all platforms)
|
||||
search_paths.push_back(std::filesystem::path("assets") / relative_path);
|
||||
search_paths.push_back(std::filesystem::path("../assets") / relative_path);
|
||||
search_paths.push_back(std::filesystem::path("../../assets") / relative_path);
|
||||
search_paths.push_back(std::filesystem::path("../../../assets") / relative_path);
|
||||
search_paths.push_back(std::filesystem::path("../../../../assets") / relative_path);
|
||||
|
||||
search_paths.push_back(std::filesystem::path("../../../assets") /
|
||||
relative_path);
|
||||
search_paths.push_back(std::filesystem::path("../../../../assets") /
|
||||
relative_path);
|
||||
|
||||
// Build directory paths
|
||||
search_paths.push_back(std::filesystem::path("build/assets") / relative_path);
|
||||
search_paths.push_back(std::filesystem::path("../build/assets") / relative_path);
|
||||
|
||||
search_paths.push_back(std::filesystem::path("../build/assets") /
|
||||
relative_path);
|
||||
|
||||
return search_paths;
|
||||
}
|
||||
|
||||
absl::StatusOr<std::filesystem::path> AssetLoader::FindAssetFile(const std::string& relative_path) {
|
||||
absl::StatusOr<std::filesystem::path> AssetLoader::FindAssetFile(
|
||||
const std::string& relative_path) {
|
||||
auto search_paths = GetSearchPaths(relative_path);
|
||||
|
||||
|
||||
for (const auto& path : search_paths) {
|
||||
if (std::filesystem::exists(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Debug: Print searched paths
|
||||
std::string searched_paths;
|
||||
for (const auto& path : search_paths) {
|
||||
searched_paths += "\n - " + path.string();
|
||||
}
|
||||
|
||||
|
||||
return absl::NotFoundError(
|
||||
absl::StrFormat("Asset file not found: %s\nSearched paths:%s",
|
||||
absl::StrFormat("Asset file not found: %s\nSearched paths:%s",
|
||||
relative_path, searched_paths));
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> AssetLoader::LoadTextFile(const std::string& relative_path) {
|
||||
absl::StatusOr<std::string> AssetLoader::LoadTextFile(
|
||||
const std::string& relative_path) {
|
||||
auto path_result = FindAssetFile(relative_path);
|
||||
if (!path_result.ok()) {
|
||||
return path_result.status();
|
||||
}
|
||||
|
||||
|
||||
const auto& path = *path_result;
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to open file: %s", path.string()));
|
||||
}
|
||||
|
||||
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
std::string content = buffer.str();
|
||||
|
||||
|
||||
if (content.empty()) {
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("File is empty: %s", path.string()));
|
||||
}
|
||||
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -90,5 +99,4 @@ bool AssetLoader::AssetExists(const std::string& relative_path) {
|
||||
return FindAssetFile(relative_path).ok();
|
||||
}
|
||||
|
||||
|
||||
} // namespace yaze
|
||||
|
||||
@@ -9,11 +9,10 @@
|
||||
|
||||
namespace yaze {
|
||||
|
||||
|
||||
/**
|
||||
* @class AssetLoader
|
||||
* @brief Cross-platform asset file loading utility
|
||||
*
|
||||
*
|
||||
* Handles platform-specific paths for loading assets from:
|
||||
* - macOS bundle resources
|
||||
* - Windows relative paths
|
||||
@@ -24,25 +23,29 @@ class AssetLoader {
|
||||
public:
|
||||
/**
|
||||
* Load a text file from the assets directory
|
||||
* @param relative_path Path relative to assets/ (e.g., "agent/system_prompt.txt")
|
||||
* @param relative_path Path relative to assets/ (e.g.,
|
||||
* "agent/system_prompt.txt")
|
||||
* @return File contents or error
|
||||
*/
|
||||
static absl::StatusOr<std::string> LoadTextFile(const std::string& relative_path);
|
||||
|
||||
static absl::StatusOr<std::string> LoadTextFile(
|
||||
const std::string& relative_path);
|
||||
|
||||
/**
|
||||
* Find an asset file by trying multiple platform-specific paths
|
||||
* @param relative_path Path relative to assets/
|
||||
* @return Full path to file or error
|
||||
*/
|
||||
static absl::StatusOr<std::filesystem::path> FindAssetFile(const std::string& relative_path);
|
||||
|
||||
static absl::StatusOr<std::filesystem::path> FindAssetFile(
|
||||
const std::string& relative_path);
|
||||
|
||||
/**
|
||||
* Get list of search paths for a given asset
|
||||
* @param relative_path Path relative to assets/
|
||||
* @return Vector of paths to try in order
|
||||
*/
|
||||
static std::vector<std::filesystem::path> GetSearchPaths(const std::string& relative_path);
|
||||
|
||||
static std::vector<std::filesystem::path> GetSearchPaths(
|
||||
const std::string& relative_path);
|
||||
|
||||
/**
|
||||
* Check if an asset file exists
|
||||
* @param relative_path Path relative to assets/
|
||||
@@ -51,7 +54,6 @@ class AssetLoader {
|
||||
static bool AssetExists(const std::string& relative_path);
|
||||
};
|
||||
|
||||
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_PLATFORM_ASSET_LOADER_H_
|
||||
|
||||
@@ -1,66 +1,68 @@
|
||||
// Windows and Linux implementation of FileDialogWrapper using nativefiledialog-extended
|
||||
#include "util/file_util.h"
|
||||
|
||||
// Windows and Linux implementation of FileDialogWrapper using
|
||||
// nativefiledialog-extended
|
||||
#include <nfd.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "util/file_util.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace util {
|
||||
|
||||
std::string FileDialogWrapper::ShowOpenFileDialog() {
|
||||
nfdchar_t* outPath = nullptr;
|
||||
nfdfilteritem_t filterItem[2] = {{"ROM Files", "sfc,smc"}, {"All Files", "*"}};
|
||||
nfdfilteritem_t filterItem[2] = {{"ROM Files", "sfc,smc"},
|
||||
{"All Files", "*"}};
|
||||
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 2, nullptr);
|
||||
|
||||
|
||||
if (result == NFD_OKAY) {
|
||||
std::string path(outPath);
|
||||
NFD_FreePath(outPath);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string FileDialogWrapper::ShowOpenFolderDialog() {
|
||||
nfdchar_t* outPath = nullptr;
|
||||
nfdresult_t result = NFD_PickFolder(&outPath, nullptr);
|
||||
|
||||
|
||||
if (result == NFD_OKAY) {
|
||||
std::string path(outPath);
|
||||
NFD_FreePath(outPath);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string FileDialogWrapper::ShowSaveFileDialog(const std::string& default_name,
|
||||
const std::string& default_extension) {
|
||||
std::string FileDialogWrapper::ShowSaveFileDialog(
|
||||
const std::string& default_name, const std::string& default_extension) {
|
||||
nfdchar_t* outPath = nullptr;
|
||||
nfdfilteritem_t filterItem[1] = {{default_extension.empty() ? "All Files" : default_extension.c_str(),
|
||||
default_extension.empty() ? "*" : default_extension.c_str()}};
|
||||
|
||||
nfdresult_t result = NFD_SaveDialog(&outPath,
|
||||
default_extension.empty() ? nullptr : filterItem,
|
||||
default_extension.empty() ? 0 : 1,
|
||||
nullptr,
|
||||
default_name.c_str());
|
||||
|
||||
nfdfilteritem_t filterItem[1] = {
|
||||
{default_extension.empty() ? "All Files" : default_extension.c_str(),
|
||||
default_extension.empty() ? "*" : default_extension.c_str()}};
|
||||
|
||||
nfdresult_t result = NFD_SaveDialog(
|
||||
&outPath, default_extension.empty() ? nullptr : filterItem,
|
||||
default_extension.empty() ? 0 : 1, nullptr, default_name.c_str());
|
||||
|
||||
if (result == NFD_OKAY) {
|
||||
std::string path(outPath);
|
||||
NFD_FreePath(outPath);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> FileDialogWrapper::GetSubdirectoriesInFolder(
|
||||
const std::string& folder_path) {
|
||||
std::vector<std::string> subdirs;
|
||||
|
||||
|
||||
try {
|
||||
for (const auto& entry : std::filesystem::directory_iterator(folder_path)) {
|
||||
if (entry.is_directory()) {
|
||||
@@ -70,14 +72,14 @@ std::vector<std::string> FileDialogWrapper::GetSubdirectoriesInFolder(
|
||||
} catch (...) {
|
||||
// Return empty vector on error
|
||||
}
|
||||
|
||||
|
||||
return subdirs;
|
||||
}
|
||||
|
||||
std::vector<std::string> FileDialogWrapper::GetFilesInFolder(
|
||||
const std::string& folder_path) {
|
||||
std::vector<std::string> files;
|
||||
|
||||
|
||||
try {
|
||||
for (const auto& entry : std::filesystem::directory_iterator(folder_path)) {
|
||||
if (entry.is_regular_file()) {
|
||||
@@ -87,7 +89,7 @@ std::vector<std::string> FileDialogWrapper::GetFilesInFolder(
|
||||
} catch (...) {
|
||||
// Return empty vector on error
|
||||
}
|
||||
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
@@ -100,13 +102,13 @@ std::string FileDialogWrapper::ShowOpenFileDialogBespoke() {
|
||||
return ShowOpenFileDialog();
|
||||
}
|
||||
|
||||
std::string FileDialogWrapper::ShowSaveFileDialogNFD(const std::string& default_name,
|
||||
const std::string& default_extension) {
|
||||
std::string FileDialogWrapper::ShowSaveFileDialogNFD(
|
||||
const std::string& default_name, const std::string& default_extension) {
|
||||
return ShowSaveFileDialog(default_name, default_extension);
|
||||
}
|
||||
|
||||
std::string FileDialogWrapper::ShowSaveFileDialogBespoke(const std::string& default_name,
|
||||
const std::string& default_extension) {
|
||||
std::string FileDialogWrapper::ShowSaveFileDialogBespoke(
|
||||
const std::string& default_name, const std::string& default_extension) {
|
||||
return ShowSaveFileDialog(default_name, default_extension);
|
||||
}
|
||||
|
||||
@@ -120,4 +122,3 @@ std::string FileDialogWrapper::ShowOpenFolderDialogBespoke() {
|
||||
|
||||
} // namespace util
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
#include "app/platform/font_loader.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "util/file_util.h"
|
||||
#include "app/gui/core/icons.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "util/file_util.h"
|
||||
#include "util/macro.h"
|
||||
|
||||
namespace yaze {
|
||||
@@ -54,7 +53,7 @@ absl::Status LoadFont(const FontConfig& font_config) {
|
||||
}
|
||||
|
||||
if (!imgui_io.Fonts->AddFontFromFileTTF(actual_font_path.data(),
|
||||
font_config.font_size)) {
|
||||
font_config.font_size)) {
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to load font from %s", actual_font_path));
|
||||
}
|
||||
@@ -70,8 +69,9 @@ absl::Status AddIconFont(const FontConfig& /*config*/) {
|
||||
icons_config.PixelSnapH = true;
|
||||
std::string icon_font_path = SetFontPath(FONT_ICON_FILE_NAME_MD);
|
||||
ImGuiIO& imgui_io = ImGui::GetIO();
|
||||
if (!imgui_io.Fonts->AddFontFromFileTTF(icon_font_path.c_str(), ICON_FONT_SIZE,
|
||||
&icons_config, icons_ranges)) {
|
||||
if (!imgui_io.Fonts->AddFontFromFileTTF(icon_font_path.c_str(),
|
||||
ICON_FONT_SIZE, &icons_config,
|
||||
icons_ranges)) {
|
||||
return absl::InternalError("Failed to add icon fonts");
|
||||
}
|
||||
return absl::OkStatus();
|
||||
@@ -85,9 +85,9 @@ absl::Status AddJapaneseFont(const FontConfig& /*config*/) {
|
||||
japanese_font_config.PixelSnapH = true;
|
||||
std::string japanese_font_path = SetFontPath(NOTO_SANS_JP);
|
||||
ImGuiIO& imgui_io = ImGui::GetIO();
|
||||
if (!imgui_io.Fonts->AddFontFromFileTTF(japanese_font_path.data(), ICON_FONT_SIZE,
|
||||
&japanese_font_config,
|
||||
imgui_io.Fonts->GetGlyphRangesJapanese())) {
|
||||
if (!imgui_io.Fonts->AddFontFromFileTTF(
|
||||
japanese_font_path.data(), ICON_FONT_SIZE, &japanese_font_config,
|
||||
imgui_io.Fonts->GetGlyphRangesJapanese())) {
|
||||
return absl::InternalError("Failed to add Japanese fonts");
|
||||
}
|
||||
return absl::OkStatus();
|
||||
@@ -97,7 +97,8 @@ absl::Status AddJapaneseFont(const FontConfig& /*config*/) {
|
||||
|
||||
absl::Status LoadPackageFonts() {
|
||||
if (font_registry.fonts.empty()) {
|
||||
// Initialize the font names and sizes with proper ImFontConfig initialization
|
||||
// Initialize the font names and sizes with proper ImFontConfig
|
||||
// initialization
|
||||
font_registry.fonts = {
|
||||
FontConfig{KARLA_REGULAR, FONT_SIZE_DEFAULT, {}, {}},
|
||||
FontConfig{ROBOTO_MEDIUM, FONT_SIZE_DEFAULT, {}, {}},
|
||||
@@ -120,7 +121,7 @@ absl::Status ReloadPackageFont(const FontConfig& config) {
|
||||
ImGuiIO& imgui_io = ImGui::GetIO();
|
||||
std::string actual_font_path = SetFontPath(config.font_path);
|
||||
if (!imgui_io.Fonts->AddFontFromFileTTF(actual_font_path.data(),
|
||||
config.font_size)) {
|
||||
config.font_size)) {
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to load font from %s", actual_font_path));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
namespace yaze {
|
||||
|
||||
|
||||
struct FontConfig {
|
||||
const char* font_path;
|
||||
float font_size;
|
||||
@@ -28,7 +27,6 @@ absl::Status ReloadPackageFont(const FontConfig& config);
|
||||
|
||||
void LoadSystemFonts();
|
||||
|
||||
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_PLATFORM_FONTLOADER_H
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define YAZE_APP_CORE_TIMING_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace yaze {
|
||||
@@ -9,7 +10,7 @@ namespace yaze {
|
||||
/**
|
||||
* @class TimingManager
|
||||
* @brief Provides accurate timing for animations and frame pacing
|
||||
*
|
||||
*
|
||||
* This class solves the issue where ImGui::GetIO().DeltaTime only updates
|
||||
* when events are processed (mouse movement, etc). It uses SDL's performance
|
||||
* counter to provide accurate timing regardless of input events.
|
||||
@@ -28,18 +29,18 @@ class TimingManager {
|
||||
float Update() {
|
||||
uint64_t current_time = SDL_GetPerformanceCounter();
|
||||
float delta_time = 0.0f;
|
||||
|
||||
|
||||
if (last_time_ > 0) {
|
||||
delta_time = (current_time - last_time_) / static_cast<float>(frequency_);
|
||||
|
||||
|
||||
// Clamp delta time to prevent huge jumps (e.g., when debugging)
|
||||
if (delta_time > 0.1f) {
|
||||
delta_time = 0.1f;
|
||||
}
|
||||
|
||||
|
||||
accumulated_time_ += delta_time;
|
||||
frame_count_++;
|
||||
|
||||
|
||||
// Update FPS counter once per second
|
||||
if (accumulated_time_ >= 1.0f) {
|
||||
fps_ = static_cast<float>(frame_count_) / accumulated_time_;
|
||||
@@ -47,35 +48,32 @@ class TimingManager {
|
||||
accumulated_time_ = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
last_time_ = current_time;
|
||||
last_delta_time_ = delta_time;
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the last frame's delta time in seconds
|
||||
*/
|
||||
float GetDeltaTime() const {
|
||||
return last_delta_time_;
|
||||
}
|
||||
|
||||
float GetDeltaTime() const { return last_delta_time_; }
|
||||
|
||||
/**
|
||||
* @brief Get current FPS
|
||||
*/
|
||||
float GetFPS() const {
|
||||
return fps_;
|
||||
}
|
||||
|
||||
float GetFPS() const { return fps_; }
|
||||
|
||||
/**
|
||||
* @brief Get total elapsed time since first update
|
||||
*/
|
||||
float GetElapsedTime() const {
|
||||
if (last_time_ == 0) return 0.0f;
|
||||
if (last_time_ == 0)
|
||||
return 0.0f;
|
||||
uint64_t current_time = SDL_GetPerformanceCounter();
|
||||
return (current_time - first_time_) / static_cast<float>(frequency_);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reset the timing state
|
||||
*/
|
||||
@@ -114,4 +112,3 @@ class TimingManager {
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_CORE_TIMING_H
|
||||
|
||||
|
||||
@@ -4,45 +4,47 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/platform/font_loader.h"
|
||||
#include "util/sdl_deleter.h"
|
||||
#include "util/log.h"
|
||||
#include "app/gfx/resource/arena.h"
|
||||
#include "app/gui/core/style.h"
|
||||
#include "app/platform/font_loader.h"
|
||||
#include "imgui/backends/imgui_impl_sdl2.h"
|
||||
#include "imgui/backends/imgui_impl_sdlrenderer2.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "util/log.h"
|
||||
#include "util/sdl_deleter.h"
|
||||
|
||||
namespace {
|
||||
// Custom ImGui assertion handler to prevent crashes
|
||||
void ImGuiAssertionHandler(const char* expr, const char* file, int line,
|
||||
const char* msg) {
|
||||
// Log the assertion instead of crashing
|
||||
LOG_ERROR("ImGui", "Assertion failed: %s\nFile: %s:%d\nMessage: %s",
|
||||
expr, file, line, msg ? msg : "");
|
||||
|
||||
LOG_ERROR("ImGui", "Assertion failed: %s\nFile: %s:%d\nMessage: %s", expr,
|
||||
file, line, msg ? msg : "");
|
||||
|
||||
// Try to recover by resetting ImGui state
|
||||
static int error_count = 0;
|
||||
error_count++;
|
||||
|
||||
|
||||
if (error_count > 5) {
|
||||
LOG_ERROR("ImGui", "Too many assertions, resetting workspace settings...");
|
||||
|
||||
|
||||
// Backup and reset imgui.ini
|
||||
try {
|
||||
if (std::filesystem::exists("imgui.ini")) {
|
||||
std::filesystem::copy("imgui.ini", "imgui.ini.backup",
|
||||
std::filesystem::copy_options::overwrite_existing);
|
||||
std::filesystem::copy(
|
||||
"imgui.ini", "imgui.ini.backup",
|
||||
std::filesystem::copy_options::overwrite_existing);
|
||||
std::filesystem::remove("imgui.ini");
|
||||
LOG_INFO("ImGui", "Workspace settings reset. Backup saved to imgui.ini.backup");
|
||||
LOG_INFO("ImGui",
|
||||
"Workspace settings reset. Backup saved to imgui.ini.backup");
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR("ImGui", "Failed to reset workspace: %s", e.what());
|
||||
}
|
||||
|
||||
|
||||
error_count = 0; // Reset counter
|
||||
}
|
||||
|
||||
|
||||
// Don't abort - let the program continue
|
||||
// The assertion is logged and workspace can be reset if needed
|
||||
}
|
||||
@@ -87,7 +89,7 @@ absl::Status CreateWindow(Window& window, gfx::IRenderer* renderer, int flags) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
|
||||
|
||||
// Set custom assertion handler to prevent crashes
|
||||
#ifdef IMGUI_DISABLE_DEFAULT_ASSERT_HANDLER
|
||||
ImGui::SetAssertHandler(ImGuiAssertionHandler);
|
||||
@@ -103,7 +105,8 @@ absl::Status CreateWindow(Window& window, gfx::IRenderer* renderer, int flags) {
|
||||
|
||||
// Initialize ImGui backends if renderer is provided
|
||||
if (renderer) {
|
||||
SDL_Renderer* sdl_renderer = static_cast<SDL_Renderer*>(renderer->GetBackendRenderer());
|
||||
SDL_Renderer* sdl_renderer =
|
||||
static_cast<SDL_Renderer*>(renderer->GetBackendRenderer());
|
||||
ImGui_ImplSDL2_InitForSDLRenderer(window.window_.get(), sdl_renderer);
|
||||
ImGui_ImplSDLRenderer2_Init(sdl_renderer);
|
||||
}
|
||||
@@ -112,23 +115,25 @@ absl::Status CreateWindow(Window& window, gfx::IRenderer* renderer, int flags) {
|
||||
|
||||
// Apply original YAZE colors as fallback, then try to load theme system
|
||||
gui::ColorsYaze();
|
||||
|
||||
|
||||
// Audio is now handled by IAudioBackend in Emulator class
|
||||
// Keep legacy buffer allocation for backwards compatibility
|
||||
if (window.audio_device_ == 0) {
|
||||
const int audio_frequency = 48000;
|
||||
const size_t buffer_size = (audio_frequency / 50) * 2; // 1920 int16_t for stereo PAL
|
||||
|
||||
const size_t buffer_size =
|
||||
(audio_frequency / 50) * 2; // 1920 int16_t for stereo PAL
|
||||
|
||||
// CRITICAL FIX: Allocate buffer as ARRAY, not single value
|
||||
// Use new[] with shared_ptr custom deleter for proper array allocation
|
||||
window.audio_buffer_ = std::shared_ptr<int16_t>(
|
||||
new int16_t[buffer_size],
|
||||
std::default_delete<int16_t[]>());
|
||||
|
||||
new int16_t[buffer_size], std::default_delete<int16_t[]>());
|
||||
|
||||
// Note: Actual audio device is created by Emulator's IAudioBackend
|
||||
// This maintains compatibility with existing code paths
|
||||
LOG_INFO("Window", "Audio buffer allocated: %zu int16_t samples (backend in Emulator)",
|
||||
buffer_size);
|
||||
LOG_INFO(
|
||||
"Window",
|
||||
"Audio buffer allocated: %zu int16_t samples (backend in Emulator)",
|
||||
buffer_size);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
@@ -137,39 +142,39 @@ absl::Status CreateWindow(Window& window, gfx::IRenderer* renderer, int flags) {
|
||||
absl::Status ShutdownWindow(Window& window) {
|
||||
SDL_PauseAudioDevice(window.audio_device_, 1);
|
||||
SDL_CloseAudioDevice(window.audio_device_);
|
||||
|
||||
|
||||
// Stop test engine WHILE ImGui context is still valid
|
||||
#ifdef YAZE_ENABLE_IMGUI_TEST_ENGINE
|
||||
test::TestManager::Get().StopUITesting();
|
||||
#endif
|
||||
|
||||
|
||||
// TODO: BAD FIX, SLOW SHUTDOWN TAKES TOO LONG NOW
|
||||
// CRITICAL FIX: Shutdown graphics arena FIRST
|
||||
// This ensures all textures are destroyed while renderer is still valid
|
||||
LOG_INFO("Window", "Shutting down graphics arena...");
|
||||
gfx::Arena::Get().Shutdown();
|
||||
|
||||
|
||||
// Shutdown ImGui implementations (after Arena but before context)
|
||||
LOG_INFO("Window", "Shutting down ImGui implementations...");
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui_ImplSDLRenderer2_Shutdown();
|
||||
|
||||
|
||||
// Destroy ImGui context
|
||||
LOG_INFO("Window", "Destroying ImGui context...");
|
||||
ImGui::DestroyContext();
|
||||
|
||||
|
||||
// NOW destroy test engine context (after ImGui context is destroyed)
|
||||
#ifdef YAZE_ENABLE_IMGUI_TEST_ENGINE
|
||||
test::TestManager::Get().DestroyUITestingContext();
|
||||
#endif
|
||||
|
||||
|
||||
// Finally destroy window
|
||||
LOG_INFO("Window", "Destroying window...");
|
||||
SDL_DestroyWindow(window.window_.get());
|
||||
|
||||
|
||||
LOG_INFO("Window", "Shutting down SDL...");
|
||||
SDL_Quit();
|
||||
|
||||
|
||||
LOG_INFO("Window", "Shutdown complete");
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -177,7 +182,7 @@ absl::Status ShutdownWindow(Window& window) {
|
||||
absl::Status HandleEvents(Window& window) {
|
||||
SDL_Event event;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
|
||||
// Protect SDL_PollEvent from crashing the app
|
||||
// macOS NSPersistentUIManager corruption can crash during event polling
|
||||
while (SDL_PollEvent(&event)) {
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "util/sdl_deleter.h"
|
||||
#include "app/gfx/core/bitmap.h"
|
||||
#include "app/gfx/backend/irenderer.h"
|
||||
#include "app/gfx/core/bitmap.h"
|
||||
#include "util/sdl_deleter.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace core {
|
||||
@@ -23,10 +23,10 @@ struct Window {
|
||||
|
||||
// Legacy CreateWindow (deprecated - use Controller::OnEntry instead)
|
||||
// Kept for backward compatibility with test code
|
||||
absl::Status CreateWindow(Window& window, gfx::IRenderer* renderer = nullptr,
|
||||
int flags = SDL_WINDOW_RESIZABLE);
|
||||
absl::Status HandleEvents(Window &window);
|
||||
absl::Status ShutdownWindow(Window &window);
|
||||
absl::Status CreateWindow(Window& window, gfx::IRenderer* renderer = nullptr,
|
||||
int flags = SDL_WINDOW_RESIZABLE);
|
||||
absl::Status HandleEvents(Window& window);
|
||||
absl::Status ShutdownWindow(Window& window);
|
||||
|
||||
} // namespace core
|
||||
} // namespace yaze
|
||||
|
||||
Reference in New Issue
Block a user