diff options
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;  | 
