backend-infra-engineer: Release v0.3.3 snapshot

This commit is contained in:
scawful
2025-11-21 21:35:50 -05:00
parent 3d71417f62
commit 476dd1cd1c
818 changed files with 65706 additions and 35514 deletions

View File

@@ -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"

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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