diff options
author | Frederico Linhares <fred@linhares.blue> | 2025-03-12 20:40:25 -0300 |
---|---|---|
committer | Frederico Linhares <fred@linhares.blue> | 2025-03-12 20:40:25 -0300 |
commit | 96228c92004fefae3cb3392c20d90ec4ede753cd (patch) | |
tree | 3fa37641dbc915ddf1096efd6e21ddcb3884fe78 /src/blu_cat/int | |
parent | daa767aa5ea95fa2386c5ecaff31bd5598c43700 (diff) |
refa Move initialization code to BluCat
Diffstat (limited to 'src/blu_cat/int')
-rw-r--r-- | src/blu_cat/int/core.cpp | 260 | ||||
-rw-r--r-- | src/blu_cat/int/core.hpp | 28 |
2 files changed, 282 insertions, 6 deletions
diff --git a/src/blu_cat/int/core.cpp b/src/blu_cat/int/core.cpp index eafdab7..d631d17 100644 --- a/src/blu_cat/int/core.cpp +++ b/src/blu_cat/int/core.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Frederico de Oliveira Linhares + * Copyright 2022-2025 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,258 @@ vk_debug_callback( #endif void +load_sdl(void *obj) +{ + if(SDL_Init(SDL_INIT_EVERYTHING) < 0) + { + std::string error{"SDL could not initialize! SDL Error → "}; + error += SDL_GetError(); + throw error; + } + + if(SDL_Vulkan_LoadLibrary(nullptr) != 0) + { + SDL_Quit(); + std::string error{"SDL could not initialize Vulkan! SDL_Error → "}; + error += SDL_GetError(); + throw CommandError{error}; + } +} + +void +unload_sdl(void *obj) +{ + SDL_Vulkan_UnloadLibrary(); + SDL_Quit(); +} + +void +load_sdl_mixer(void *obj) +{ + int flags = MIX_INIT_OGG|MIX_INIT_MOD; + int initted = Mix_Init(flags); + if(initted&flags != flags) + { + std::string error{"Could not initialize SDL mixer → "}; + error += Mix_GetError(); + throw CommandError{error}; + } +} + +void +unload_sdl_mixer(void *obj) +{ + while(Mix_Init(0)) Mix_Quit(); +} + +void +load_sdl_open_audio(void *obj) +{ + if(Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 1024) == -1) + { + std::string error{"Could not open SDL mixer audio → "}; + error += Mix_GetError(); + throw CommandError{error}; + } +} + +void +unload_sdl_open_audio(void *obj) +{ + Mix_CloseAudio(); +} + +void +load_window(void *obj) +{ + BluCat::INT::core.window = nullptr; + BluCat::INT::core.window = SDL_CreateWindow( + BluCat::INT::core.game_name.c_str(), + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + BluCat::INT::core.display_width, BluCat::INT::core.display_height, + SDL_WINDOW_VULKAN); + if(BluCat::INT::core.window == nullptr) + { + std::string error{"Window could not be created! SDL_Error → "}; + error += SDL_GetError(); + throw CommandError{error}; + } +} + +void +unload_window(void *obj) +{ + SDL_DestroyWindow(BluCat::INT::core.window); +} + +void +load_vk_instance(void *obj) +{ + std::vector<const char*> vk_extensions; + std::vector<const char*> vk_required_layers_names; + + // Get extensions. + { + uint32_t vk_extensions_count; + std::vector<const char*> vk_required_extensions; + + // Load debuging layers. +#ifdef DEBUG + vk_required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + vk_required_layers_names.push_back("VK_LAYER_KHRONOS_validation"); +#endif + + // Get extensions for SDL. + { + uint32_t vk_sdl_extension_count; + std::vector<const char*> vk_sdl_extensions; + + if(!SDL_Vulkan_GetInstanceExtensions( + BluCat::INT::core.window, &vk_sdl_extension_count, nullptr)) + { + std::string error{ + "Vulkan extensions could not be loaded by SDL! SDL_Error: "}; + error += SDL_GetError(); + throw CommandError{error}; + } + + vk_sdl_extensions.resize(vk_sdl_extension_count); + SDL_Vulkan_GetInstanceExtensions( + BluCat::INT::core.window, &vk_sdl_extension_count, + vk_sdl_extensions.data()); + + // Combine all extensions. + vk_extensions_count = vk_sdl_extension_count + + vk_required_extensions.size(); + vk_extensions.resize(vk_extensions_count); + for(auto i{0}; i < vk_sdl_extension_count; i++) + vk_extensions[i] = vk_sdl_extensions[i]; + for(auto i{0}; i < vk_required_extensions.size(); i++) + vk_extensions[i + vk_sdl_extension_count] = vk_required_extensions[i]; + } + +#ifdef DEBUG + BluCat::INT::core.log.message(Log::Level::Trace, "Enabled VK extensions."); + for(auto vk_extension: vk_extensions) + { + std::string message{"Extension name: "}; + message += vk_extension; + BluCat::INT::core.log.message(Log::Level::Trace, message); + } +#endif + } + + // Get available instance layers. + { + uint32_t vk_available_layers_count; + std::vector<VkLayerProperties> vk_available_layers; + std::vector<const char*> vk_available_layers_names; + + vkEnumerateInstanceLayerProperties(&vk_available_layers_count, nullptr); + vk_available_layers.resize(vk_available_layers_count); + vkEnumerateInstanceLayerProperties(&vk_available_layers_count, + vk_available_layers.data()); + vk_available_layers_names.resize(vk_available_layers_count); +#ifdef DEBUG + BluCat::INT::core.log.message( + Log::Level::Trace, "Available VK instance layers."); +#endif + for(uint32_t i = 0; i < vk_available_layers_count; i++) + { +#ifdef DEBUG + std::stringstream message{}; + message << "\nname: " << vk_available_layers[i].layerName << std::endl; + message << "Description: " << vk_available_layers[i].description << + std::endl; + message << "Spec version: " << vk_available_layers[i].specVersion << + std::endl; + message << "Implementation version: " << + vk_available_layers[i].implementationVersion << std::endl; + BluCat::INT::core.log.message(Log::Level::Trace, message.str()); +#endif + + vk_available_layers_names[i] = vk_available_layers[i].layerName; + } + + // If required layers are not all available. + if(!std::includes( + vk_available_layers_names.begin(), vk_available_layers_names.end(), + vk_required_layers_names.begin(), vk_required_layers_names.begin())) + throw CommandError{"Some required Vulkan layers are not available."}; + } + + { + VkApplicationInfo app_info; + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.pNext = nullptr; + app_info.pApplicationName = BluCat::INT::core.game_name.c_str(); + app_info.applicationVersion = VK_MAKE_VERSION( + BluCat::INT::core.game_version_major, + BluCat::INT::core.game_version_minor, + BluCat::INT::core.game_version_patch); + app_info.pEngineName = "BluCat::GRA"; + app_info.engineVersion = VK_MAKE_VERSION( + BLU_CAT_VERSION_MAJOR, + BLU_CAT_VERSION_MINOR, + BLU_CAT_VERSION_PATCH); + app_info.apiVersion = VK_API_VERSION_1_0; + + VkInstanceCreateInfo create_info; + create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + create_info.pNext = nullptr; + create_info.flags = 0; + create_info.pApplicationInfo = &app_info; + create_info.enabledExtensionCount = vk_extensions.size(); + create_info.ppEnabledExtensionNames = vk_extensions.data(); + create_info.enabledLayerCount = vk_required_layers_names.size(); + create_info.ppEnabledLayerNames = vk_required_layers_names.data(); + + VkResult result = + vkCreateInstance(&create_info, nullptr, &BluCat::INT::core.vk_instance); + if(result != VK_SUCCESS) + { + std::string error{""}; + switch(result) + { + case VK_ERROR_LAYER_NOT_PRESENT: + error = " Layer not present."; + break; + case VK_ERROR_EXTENSION_NOT_PRESENT: + error = " Extension not present."; + } + error = "Failed to create Vulkan instance." + error; + throw CommandError{error}; + } + } +} + +void +unload_vk_instance(void *obj) +{ + vkDestroyInstance(BluCat::INT::core.vk_instance, nullptr); +} + +void +load_window_surface(void *obj) +{ + if(!SDL_Vulkan_CreateSurface( + BluCat::INT::core.window, BluCat::INT::core.vk_instance, + &BluCat::INT::core.window_surface)) + { + std::string error{"Failed to create a window surface → "}; + error += SDL_GetError(); + throw CommandError{error}; + } +} + +void +unload_window_surface(void *obj) +{ + vkDestroySurfaceKHR( + BluCat::INT::core.vk_instance, BluCat::INT::core.window_surface, nullptr); +} + +void load_threads(void *obj) { auto num_threads{std::thread::hardware_concurrency() - 1}; @@ -469,6 +721,12 @@ std::random_device random_seed; std::mt19937 random_number_generator; const CommandChain Core::loader{ + {&load_sdl, &unload_sdl}, + {&load_sdl_mixer, &unload_sdl_mixer}, + {&load_sdl_open_audio, &unload_sdl_open_audio}, + {&load_window, &unload_window}, + {&load_vk_instance, &unload_vk_instance}, + {&load_window_surface, &unload_window_surface}, {&load_threads, &unload_threads}, {&load_fps, nullptr}, {&load_font_library, &unload_font_library}, diff --git a/src/blu_cat/int/core.hpp b/src/blu_cat/int/core.hpp index 0900b81..a334dfa 100644 --- a/src/blu_cat/int/core.hpp +++ b/src/blu_cat/int/core.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Frederico de Oliveira Linhares + * Copyright 2022-2025 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,19 @@ #include <memory> #include <random> +#define SDL_MAIN_HANDLED + +#ifdef _WIN64 +#include <Windows.h> +#endif + +#include <SDL2/SDL.h> +#include <SDL2/SDL_vulkan.h> +#include <SDL2/SDL_mixer.h> + +#include <ft2build.h> +#include FT_FREETYPE_H + #include "../com/command.hpp" #include "../com/job_queue.hpp" #include "../com/worker.hpp" @@ -64,22 +77,27 @@ struct Core std::vector<std::thread> threads; /// Text displayed in the game window. - std::string game_name; + std::string game_name{"BluCat Game"}; /** * @{ * This is the ammount of pixel that the games uses when rendering to the * screen. */ - uint32_t display_width, display_height; + uint32_t display_width{800}; + uint32_t display_height{600}; /// @} - int game_version_major, game_version_minor, game_version_patch; + int game_version_major{0}; + int game_version_minor{1}; + int game_version_patch{0}; - uint32_t fps; + uint32_t fps{30}; std::chrono::duration<long long, std::milli> max_frame_duration; float delta_time; + SDL_Window *window; + FT_Library font_library; VkSurfaceKHR window_surface; |