diff --git a/src/engine/EngineContext.cpp b/src/engine/EngineContext.cpp index 516fb25..aaf1197 100644 --- a/src/engine/EngineContext.cpp +++ b/src/engine/EngineContext.cpp @@ -12,6 +12,7 @@ #include #include "KeyboardMovementController.hpp" +#include "assets/stores.hpp" #include "engine/Average.hpp" #include "engine/buffers/UniqueFrameSuballocation.hpp" #include "engine/debug/drawers.hpp" @@ -39,6 +40,19 @@ namespace fgl::engine static Average< float, 60 * 15 > rolling_ms_average; + void preStage( vk::CommandBuffer& cmd_buffer ) + { + ZoneScopedN( "Pre-Stage" ); + + getTextureStore().stage( cmd_buffer ); + } + + void postStage() + { + ZoneScopedN( "Post-Stage" ); + getTextureStore().confirmStaged(); + } + void EngineContext::run() { TracyCZoneN( TRACY_PrepareEngine, "Inital Run", true ); @@ -54,12 +68,9 @@ namespace fgl::engine PerFrameSuballocation< HostSingleT< PointLight > > point_lights { global_ubo_buffer, SwapChain::MAX_FRAMES_IN_FLIGHT }; - Texture debug_tex { Texture::loadFromFile( "models/textures/DebugTexture.png" ) }; - Sampler sampler { vk::Filter::eLinear, - vk::Filter::eLinear, - vk::SamplerMipmapMode::eLinear, - vk::SamplerAddressMode::eClampToEdge }; - debug_tex.getImageView().getSampler() = std::move( sampler ); + std::shared_ptr< Texture > debug_tex { + getTextureStore().load( "models/textures/DebugTexture.png", vk::Format::eR8G8B8A8Unorm ) + }; constexpr std::uint32_t matrix_default_size { 64_MiB }; constexpr std::uint32_t draw_parameter_default_size { 64_MiB }; @@ -146,6 +157,8 @@ namespace fgl::engine if ( auto command_buffer = m_renderer.beginFrame(); command_buffer ) { + preStage( command_buffer ); + ZoneScopedN( "Render" ); //Update const std::uint16_t frame_index { m_renderer.getFrameIndex() }; @@ -194,6 +207,8 @@ namespace fgl::engine FrameMark; } + + postStage(); } Device::getInstance().device().waitIdle(); @@ -259,6 +274,7 @@ namespace fgl::engine } }*/ + /* { ZoneScopedN( "Load phyiscs test" ); std::vector< std::shared_ptr< Model > > models { Model::createModelsFromScene( @@ -312,6 +328,7 @@ namespace fgl::engine m_game_objects_root.addGameObject( std::move( floor ) ); } + */ /* { diff --git a/src/engine/assets/AssetManager.cpp b/src/engine/assets/AssetManager.cpp new file mode 100644 index 0000000..a2457b9 --- /dev/null +++ b/src/engine/assets/AssetManager.cpp @@ -0,0 +1,18 @@ +// +// Created by kj16609 on 6/6/24. +// + +#include "AssetManager.hpp" + +#include "stores.hpp" + +namespace fgl::engine +{ + inline static TextureStore tex_store {}; + + TextureStore& getTextureStore() + { + return tex_store; + } + +} // namespace fgl::engine diff --git a/src/engine/assets/AssetManager.hpp b/src/engine/assets/AssetManager.hpp new file mode 100644 index 0000000..38e66be --- /dev/null +++ b/src/engine/assets/AssetManager.hpp @@ -0,0 +1,117 @@ +// +// Created by kj16609 on 6/6/24. +// + +#pragma once + +#include + +#include +#include +#include + +namespace fgl::engine +{ + + template < typename T > + class AssetStore; + + template < typename T > + struct AssetInterface + { + //! Stages the asset to the device (GPU) + virtual void stage( vk::CommandBuffer& buffer ) = 0; + + friend class AssetStore< T >; + + bool m_been_staged { false }; + + public: + + //! Is the Asset ready to be used. (Returns false if not staged) + inline bool isReady() const { return m_been_staged; } + + inline void setReady() { m_been_staged = true; }; + + virtual ~AssetInterface() = default; + }; + + template < typename T > + class AssetStore + { + static_assert( + std::is_base_of_v< AssetInterface< T >, T >, "AssetStore: T must inherit from AssetInterface" ); + + //! Items that are actively in use. + //std::unordered_map< TKey, std::weak_ptr< T > > active_map {}; + + //! Assets needing to be staged + //TODO: ASYNC Ring buffer queue + std::queue< std::shared_ptr< T > > to_stage; + //TODO: Add tracy monitor to mutex + std::mutex queue_mtx {}; + + //! Assets currently being staged. + std::vector< std::shared_ptr< T > > processing {}; + + public: + + //TODO: Come up with a better design the the loading function. + /// We should have a way to prevent a asset from being loaded multiple times. + template < typename... T_Args > + //TODO: This genuinely seems like a GCC Bug. Perhaps try to find a workaround later or report as such. + //requires std::constructible_from< T, T_Args... > + std::shared_ptr< T > load( T_Args&&... args ) + { + ZoneScoped; + std::lock_guard guard { queue_mtx }; + + T* ptr { new T( std::forward< T_Args >( args )... ) }; + std::shared_ptr< T > s_ptr { ptr }; + + to_stage.push( s_ptr ); + + return s_ptr; + } + + //! Returns true if all items to be staged were submitted to the queue + //! Returns false if more items remain + bool stage( vk::CommandBuffer& buffer ) + { + ZoneScoped; + std::lock_guard guard { queue_mtx }; + //! Number of items to process during a stage step + constexpr std::size_t max_count { 16 }; + + for ( std::size_t i = 0; i < max_count; ++i ) + { + if ( to_stage.empty() ) break; + + processing.emplace_back( to_stage.front() ); + to_stage.pop(); + } + + if ( processing.size() == 0 ) return true; + + for ( const auto& ptr : processing ) + { + ptr->stage( buffer ); + } + + return to_stage.empty(); + } + + void confirmStaged() + { + for ( const auto& ptr : processing ) + { + ptr->dropStaging(); + ptr->setReady(); + } + + //TODO: Map this into a weak ptr in order to prevent duplication. + processing.clear(); + } + }; + +} // namespace fgl::engine diff --git a/src/engine/assets/stores.hpp b/src/engine/assets/stores.hpp new file mode 100644 index 0000000..db92c8d --- /dev/null +++ b/src/engine/assets/stores.hpp @@ -0,0 +1,17 @@ +// +// Created by kj16609 on 6/7/24. +// + +#pragma once + +#include "engine/texture/Texture.hpp" + +namespace fgl::engine +{ + class Texture; + + using TextureStore = AssetStore< Texture>; + + TextureStore& getTextureStore(); + +} // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/descriptors/DescriptorSet.cpp b/src/engine/descriptors/DescriptorSet.cpp index 9c895b1..9786c28 100644 --- a/src/engine/descriptors/DescriptorSet.cpp +++ b/src/engine/descriptors/DescriptorSet.cpp @@ -87,15 +87,21 @@ namespace fgl::engine descriptor_writes.push_back( write ); } - void DescriptorSet::bindTexture( std::uint32_t binding_idx, Texture& tex ) + void DescriptorSet::bindTexture( std::uint32_t binding_idx, std::shared_ptr< Texture >& tex_ptr ) { assert( binding_idx < m_infos.size() && "Binding index out of range" ); assert( std::holds_alternative< std::monostate >( m_infos[ binding_idx ] ) && "Update must be called between each array bind" ); + assert( tex_ptr ); + + //TODO: Bind temporary texture if tex_ptr is not ready. + + Texture& tex { *tex_ptr }; + m_infos[ binding_idx ] = tex.getImageView().descriptorInfo( - tex.getImageView().getSampler()->getVkSampler(), vk::ImageLayout::eShaderReadOnlyOptimal ); + tex.getImageView().getSampler().getVkSampler(), vk::ImageLayout::eShaderReadOnlyOptimal ); vk::WriteDescriptorSet write {}; write.dstSet = m_set; diff --git a/src/engine/descriptors/DescriptorSet.hpp b/src/engine/descriptors/DescriptorSet.hpp index 2876eac..b9c8ee1 100644 --- a/src/engine/descriptors/DescriptorSet.hpp +++ b/src/engine/descriptors/DescriptorSet.hpp @@ -61,7 +61,7 @@ namespace fgl::engine void bindAttachment( std::uint32_t binding_idx, ImageView& view, vk::ImageLayout layout, vk::Sampler sampler = VK_NULL_HANDLE ); - void bindTexture( std::uint32_t binding_idx, Texture& tex ); + void bindTexture( std::uint32_t binding_idx, std::shared_ptr< Texture >& tex_ptr ); void setName( const std::string str ); }; diff --git a/src/engine/filesystem/FileBrowser.cpp b/src/engine/filesystem/FileBrowser.cpp index db51b10..7123272 100644 --- a/src/engine/filesystem/FileBrowser.cpp +++ b/src/engine/filesystem/FileBrowser.cpp @@ -4,49 +4,43 @@ #include "FileBrowser.hpp" +#include "engine/assets/stores.hpp" #include "engine/filesystem/scanner/FileScanner.hpp" #include "engine/gui/safe_include.hpp" #include "engine/image/ImageView.hpp" -#include "engine/image/Sampler.hpp" #include "engine/texture/Texture.hpp" namespace fgl::engine::filesystem { - inline static std::vector< std::unique_ptr< FileScanner > > scanners {}; - inline static FileScanner* current_scanner { nullptr }; + inline static std::optional< DirInfo > root {}; + inline static DirInfo* current { nullptr }; inline static std::once_flag flag {}; - inline static std::optional< Texture > folder_texture { std::nullopt }; + inline static std::shared_ptr< Texture > folder_texture { nullptr }; + inline static std::shared_ptr< Texture > file_texture { nullptr }; - const std::filesystem::path path { "/home/kj16609/Desktop/Projects/cxx/Mecha/models" }; + const std::filesystem::path test_path { "/home/kj16609/Desktop/Projects/cxx/Mecha/models" }; void prepareFileGUI() { ZoneScoped; - scanners.emplace_back( std::make_unique< FileScanner >( path ) ); //Prepare textures needed. - folder_texture = Texture::loadFromFile( "./models/folder.png" ); - Sampler sampler { vk::Filter::eLinear, - vk::Filter::eLinear, - vk::SamplerMipmapMode::eLinear, - vk::SamplerAddressMode::eClampToEdge }; - - folder_texture->getImageView().getSampler() = std::move( sampler ); + folder_texture = getTextureStore().load( "./models/folder.png", vk::Format::eR8G8B8A8Unorm ); + file_texture = getTextureStore().load( "./models/file.png", vk::Format::eR8G8B8A8Unorm ); auto cmd_buffer { Device::getInstance().beginSingleTimeCommands() }; - folder_texture->stage( cmd_buffer ); - Device::getInstance().endSingleTimeCommands( cmd_buffer ); - folder_texture->dropStaging(); + root = DirInfo( test_path ); + current = &root.value(); } void FileBrowser::drawGui( FrameInfo& info ) { ZoneScoped; - //std::call_once( flag, []() { scanners.emplace_back( std::make_unique< FileScanner >( path ) ); } ); + //std::call_once( flag, []() { scanners.emplace_back( std::make_unique< FileScanner >( test_path ) ); } ); std::call_once( flag, []() { prepareFileGUI(); } ); /* @@ -67,23 +61,24 @@ namespace fgl::engine::filesystem } */ - ImGui::Text( "Scanners: %ld", scanners.size() ); - const auto size { ImGui::GetWindowSize() }; constexpr float desired_size { 128.0f }; const float extra { std::fmod( size.x, desired_size ) }; const auto cols { ( size.x - extra ) / desired_size }; - if ( ImGui::BeginTable( "Files", cols ) ) + if ( current && ImGui::BeginTable( "Files", cols ) ) { - for ( auto& scanner : scanners ) + //List folders first + for ( std::size_t i = 0; i < current->folderCount(); ++i ) { - //Print out all files found at the inital depth - for ( const FileInfo& file : *scanner ) - { - if ( file.depth > 1 ) continue; - if ( ImGui::TableNextColumn() ) drawFile( file ); - } + ImGui::TableNextColumn(); + drawFolder( current->dir( i ) ); + } + + for ( std::size_t i = 0; i < current->fileCount(); ++i ) + { + ImGui::TableNextColumn(); + drawFile( current->file( i ) ); } ImGui::EndTable(); @@ -92,19 +87,62 @@ namespace fgl::engine::filesystem ImGui::Columns( 1 ); } - void FileBrowser::drawFile( const FileInfo& data ) + enum FileType + { + TEXTURE, + MODEL, + BINARY, + DEFAULT = BINARY, + }; + + FileType getFileType( const std::filesystem::path path ) + { + //TODO: NEVER TRUST FILE EXTENSIONS! + const auto extension { path.extension() }; + + //Map + static const std::map< FileType, std::vector< std::string_view > > map { + { TEXTURE, { ".jpg", ".png" } }, { MODEL, { ".glb", ".obj", ".gltf" } } + }; + + for ( const auto& [ type, extensions ] : map ) + { + //Check if the file extensions matches the list for this type + if ( std::find( extensions.begin(), extensions.end(), extension ) != extensions.end() ) + { + return type; + } + } + + //Default + return DEFAULT; + } + + void drawTexture() + {} + + void drawModel() + {} + + void drawBinary() + {} + + void FileBrowser::drawFile( FileInfo& data ) { ZoneScoped; ImGui::PushID( data.path.c_str() ); ImGui::Text( data.filename.c_str() ); ImGui::Text( data.ext.c_str() ); - if ( data.is_folder ) // Folders have no extension + // file_texture->drawImGui( { 128, 128 } ); + file_texture->drawImGuiButton( { 128, 128 } ); + if ( ImGui::BeginDragDropSource() ) { - if ( folder_texture->drawImGuiButton( { 128, 128 } ) ) - { - std::cout << "Pressed thing" << std::endl; - } + ImGui:: + SetDragDropPayload( "_FILE_INFO", &data, sizeof( data ), ImGuiCond_Once /* Only copy the data once */ ); + ImGui::SetTooltip( data.filename.c_str() ); + + ImGui::EndDragDropSource(); } ImGui::SameLine(); @@ -113,4 +151,27 @@ namespace fgl::engine::filesystem ImGui::PopID(); } + void FileBrowser::drawFolder( DirInfo& data ) + { + ZoneScoped; + ImGui::PushID( data.path.c_str() ); + + ImGui::Text( data.path.filename().c_str() ); + ImGui::Text( "Folder" ); + + if ( folder_texture->drawImGuiButton( { 128, 128 } ) ) + { + openFolder( data ); + } + + ImGui::PopID(); + } + + void FileBrowser::openFolder( DirInfo& dir ) + { + if ( !current ) throw std::runtime_error( "No current folder?" ); + + current = &dir; + } + } // namespace fgl::engine::filesystem diff --git a/src/engine/filesystem/FileBrowser.hpp b/src/engine/filesystem/FileBrowser.hpp index 828bcb6..56e236f 100644 --- a/src/engine/filesystem/FileBrowser.hpp +++ b/src/engine/filesystem/FileBrowser.hpp @@ -18,12 +18,15 @@ namespace fgl::engine::filesystem { static FileBrowser& getInstance(); + static void goUp(); + static void addFolderToRoot(); - static void openFolderRoot( const std::string str ); + static void openFolder( DirInfo& dir ); static void drawGui( FrameInfo& info ); - static void drawFile( const FileInfo& data ); + static void drawFile( FileInfo& data ); + static void drawFolder( DirInfo& data ); }; } // namespace fgl::engine::filesystem \ No newline at end of file diff --git a/src/engine/filesystem/scanner/FileScanner.cpp b/src/engine/filesystem/scanner/FileScanner.cpp index fe1f2cd..c9763d5 100644 --- a/src/engine/filesystem/scanner/FileScanner.cpp +++ b/src/engine/filesystem/scanner/FileScanner.cpp @@ -8,144 +8,59 @@ #include "FileScanner.hpp" -#include - #include "engine/logging/logging.hpp" namespace fgl::engine::filesystem { - FileInfo& FileScannerGenerator::operator()() + DirInfo::DirInfo( const std::filesystem::path& dir, DirInfo* dir_parent ) : + path( dir ), + total_size( 0 ), + parent( dir_parent ) { - if ( m_h.done() ) throw std::runtime_error( "FileScannerGenerator is done but operator was still called" ); - m_h(); - - if ( m_h.promise().exception ) std::rethrow_exception( m_h.promise().exception ); - if ( m_h.promise().value.has_value() ) + for ( auto itter = std::filesystem::directory_iterator( dir ); itter != std::filesystem::directory_iterator(); + ++itter ) { - return m_h.promise().value.value(); + if ( itter->is_regular_file() ) + { + files.emplace_back( *itter ); + } + else if ( itter->is_directory() ) + { + nested_dirs_to_scan.push( *itter ); + } + else + throw std::runtime_error( "Unknown/Unspported file type" ); } - else - throw std::runtime_error( "Failed to get value from FileScannerGenerator." ); } - FileScannerGenerator scan_files( const std::filesystem::path path ) + std::size_t DirInfo::fileCount() const { - if ( !std::filesystem::exists( path ) ) + return files.size(); + } + + FileInfo& DirInfo::file( const std::size_t index ) + { + return files[ index ]; + } + + DirInfo& DirInfo::dir( const std::size_t index ) + { + if ( index >= nested_dirs.size() + nested_dirs_to_scan.size() ) throw std::runtime_error( "Index OOB" ); + + if ( index >= nested_dirs.size() ) { - log::error( "Expected path does not exist: {}", path.string() ); - throw std::runtime_error( format_ns::format( "Path {} does not exist.", path ).c_str() ); - } - - auto dir_empty = []( const std::filesystem::path& dir_path ) -> bool - { return std::filesystem::directory_iterator( dir_path ) == std::filesystem::directory_iterator(); }; - - if ( dir_empty( path ) ) co_return FileInfo { path, path, 0, 0 }; - - std::queue< std::pair< std::filesystem::path, std::uint8_t > > dirs {}; - - dirs.push( { path, 0 } ); - - while ( dirs.size() > 0 ) - { - const auto [ dir, depth ] { std::move( dirs.front() ) }; - dirs.pop(); - std::vector< std::filesystem::path > nested_dirs {}; - - log::debug( "Searching {}", dir ); - - //Recurse through the directory. - for ( auto itter = std::filesystem::directory_iterator( dir ); - itter != std::filesystem::directory_iterator(); ) + while ( nested_dirs.size() <= index ) { - log::debug( "Found: {}", dir ); - if ( itter->is_directory() ) - { - //Add directory to scan list. - nested_dirs.emplace_back( *itter ); - ++itter; - continue; - } + auto to_scan { std::move( nested_dirs_to_scan.front() ) }; + nested_dirs_to_scan.pop(); + log::debug( "Processed folder: {}", to_scan ); - FileInfo info { - *itter, path, itter->is_regular_file() ? itter->file_size() : 0, std::uint8_t( depth + 1 ) - }; - - ++itter; - - //If we are at the last file and there are no more directories to scan then return. - if ( itter == std::filesystem::directory_iterator() && dirs.size() == 0 && nested_dirs.size() == 0 ) - { - log::debug( "co_return: {}", info.path ); - co_return std::move( info ); - } - else - { - log::debug( "co_yield: {}", info.path ); - co_yield std::move( info ); - } - } - - //Add the nested dirs to the scanlist and yield them - for ( std::size_t i = 0; i < nested_dirs.size(); ++i ) - { - FileInfo info { nested_dirs.at( i ), path, 0, std::uint8_t( depth + 1 ) }; - // Check if the directory is empty and if it's not then add it to the scan queue. - - const bool is_empty { dir_empty( nested_dirs.at( i ) ) }; - - //If the dir is empty, if we are done searching our current nested list, and there are no more dirs to process, Return - if ( is_empty && i == nested_dirs.size() - 1 && dirs.size() == 0 ) - { - log::debug( "co_return: {}", info.path ); - co_return std::move( info ); - } - - if ( !is_empty ) - { - dirs.push( { nested_dirs.at( i ), depth + 1 } ); - } - - co_yield std::move( info ); + nested_dirs.emplace_back( to_scan, this ); } } - spdlog::critical( "Got to an illegal spot!" ); - std::unreachable(); + return nested_dirs[ index ]; } - FileScanner::FileScanner( const std::filesystem::path& path ) : m_path( path ), file_scanner( scan_files( path ) ) - { - files.emplace_back( std::move( file_scanner() ) ); - } - - const FileInfo& FileScanner::at( std::size_t index ) - { - if ( index >= files.size() && !file_scanner.m_h.done() ) - { - // Index is higher then what we have. - // Scanner is also NOT done. - // We use the coroutine to fetch what the next file should be. - - std::size_t diff { index - ( files.size() - 1 ) }; - - while ( diff > 0 && !file_scanner.m_h.done() ) - { - files.emplace_back( std::move( file_scanner() ) ); - --diff; - } - } - - if ( index >= files.size() ) - throw std:: - runtime_error( format_ns::format( "index = {}: size < index : {} < {}", index, files.size(), index ) - .c_str() ); - - return files.at( index ); - } - - bool FileScanner::iterator::operator==( const std::unreachable_sentinel_t ) const - { - return m_scanner.file_scanner.m_h.done() && ( m_idx == m_scanner.files.size() ); - } } // namespace fgl::engine::filesystem \ No newline at end of file diff --git a/src/engine/filesystem/scanner/FileScanner.hpp b/src/engine/filesystem/scanner/FileScanner.hpp index a4722ac..d1af845 100644 --- a/src/engine/filesystem/scanner/FileScanner.hpp +++ b/src/engine/filesystem/scanner/FileScanner.hpp @@ -3,19 +3,47 @@ // #pragma once -#ifndef ATLASGAMEMANAGER_FILESCANNER_HPP -#define ATLASGAMEMANAGER_FILESCANNER_HPP #include -#include #include +#include #include #include -#include "engine/logging/logging.hpp" - namespace fgl::engine::filesystem { + struct FileInfo; + + struct DirInfo + { + std::filesystem::path path; + std::size_t total_size; + std::vector< FileInfo > files {}; + std::vector< DirInfo > nested_dirs {}; + std::queue< std::filesystem::path > nested_dirs_to_scan {}; + DirInfo* parent { nullptr }; + + public: + + inline DirInfo* up() const { return parent; } + + std::size_t fileCount() const; + FileInfo& file( const std::size_t index ); + + inline std::size_t folderCount() const { return nested_dirs.size() + nested_dirs_to_scan.size(); } + + DirInfo& dir( const std::size_t index ); + + DirInfo() = delete; + + DirInfo( const std::filesystem::path& path, DirInfo* parent = nullptr ); + + DirInfo( const DirInfo& other ) = delete; + DirInfo& operator=( const DirInfo& other ) = delete; + + DirInfo( DirInfo&& ) = default; + DirInfo& operator=( DirInfo&& ) = default; + }; struct FileInfo { @@ -23,23 +51,15 @@ namespace fgl::engine::filesystem std::string ext; std::filesystem::path path; std::size_t size; - std::uint8_t depth; - std::filesystem::path relative; bool is_folder; FileInfo() = delete; - FileInfo( - std::filesystem::path path_in, - const std::filesystem::path& source, - const std::size_t filesize, - const std::uint8_t file_depth ) : + FileInfo( std::filesystem::path path_in ) : filename( path_in.filename().string() ), ext( path_in.extension().string() ), path( path_in ), - size( filesize ), - depth( file_depth ), - relative( std::filesystem::relative( std::move( path_in ), source ) ), + size( std::filesystem::file_size( path_in ) ), is_folder( std::filesystem::is_directory( path ) ) {} @@ -50,117 +70,4 @@ namespace fgl::engine::filesystem FileInfo& operator=( FileInfo&& other ) = default; }; - struct FileScannerGenerator - { - struct promise_type; - using handle_type = std::coroutine_handle< promise_type >; - - struct promise_type - { - std::optional< FileInfo > value { std::nullopt }; - std::exception_ptr exception { nullptr }; - - FileScannerGenerator get_return_object() - { - return FileScannerGenerator( handle_type::from_promise( *this ) ); - } - - std::suspend_always initial_suspend() noexcept { return {}; } - - std::suspend_always final_suspend() noexcept { return {}; } - - void unhandled_exception() - { - exception = std::current_exception(); - log::critical( "Exception thrown in FileScanner" ); - } - - void return_value( FileInfo&& from ) - { - if ( from.filename == "" ) - throw std::runtime_error( "FileScannerGenerator: return value had no filename!" ); - - value = std::move( from ); - } - - std::suspend_always yield_value( FileInfo&& from ) - { - if ( from.filename == "" ) - throw std::runtime_error( "FromScannerGenerator:: yield value had no filename!" ); - - value = std::forward< FileInfo >( from ); - return {}; - } - }; - - handle_type m_h; - - FileScannerGenerator() = delete; - - FileScannerGenerator( handle_type h ) : m_h( h ) {} - - ~FileScannerGenerator() - { - log::debug( "Destroying Generator" ); - m_h.destroy(); - } - - FileInfo& operator()(); - }; - - class FileScanner - { - private: - - std::filesystem::path m_path; - FileScannerGenerator file_scanner; - std::vector< FileInfo > files {}; - const FileInfo& at( std::size_t index ); - - friend class iterator; - - class iterator - { - std::size_t m_idx { 0 }; - FileScanner& m_scanner; - - public: - - iterator() = delete; - - iterator( const std::size_t idx, FileScanner& scanner ) : m_idx( idx ), m_scanner( scanner ) {} - - FileScanner::iterator& operator++() - { - ++m_idx; - return *this; - } - - // Operator != required to check for end I assume. Where if the this returns true then we are good to continue - // So instead we can just return the state of the scanner. And if the scanner is complete then we'll return false here. - //bool operator != - bool operator==( const std::unreachable_sentinel_t ) const; - - // Required for the for loop - const FileInfo& operator*() { return m_scanner.at( m_idx ); } - }; - - public: - - FileScanner() = delete; - FileScanner( const std::filesystem::path& path ); - - FileScanner( const std::string_view path ) : FileScanner( std::filesystem::path( path ) ) {} - - FileScanner( const FileScanner& other ) = delete; //Copy - FileScanner& operator=( const FileScanner& other ) = delete; //Copy-Assign - - iterator begin() { return iterator( 0, *this ); } - - //This *probably* isn't required(?) but the for loop will want it anyways. So we can just return literaly anything here since it's not used anyways. - std::unreachable_sentinel_t end() { return {}; } - - std::filesystem::path path() const { return m_path; } - }; } // namespace fgl::engine::filesystem -#endif //ATLASGAMEMANAGER_FILESCANNER_HPP diff --git a/src/engine/image/ImageView.cpp b/src/engine/image/ImageView.cpp index 6e7ebac..97b214e 100644 --- a/src/engine/image/ImageView.cpp +++ b/src/engine/image/ImageView.cpp @@ -7,7 +7,7 @@ namespace fgl::engine { - ImageView::ImageView( std::shared_ptr< ImageHandle >& img ) : m_resource( img ) + ImageView::ImageView( std::shared_ptr< ImageHandle >& img ) : m_resource( img ), m_sampler() { vk::ImageViewCreateInfo view_info {}; view_info.image = img->getVkImage(); diff --git a/src/engine/image/ImageView.hpp b/src/engine/image/ImageView.hpp index 4092d7a..4293547 100644 --- a/src/engine/image/ImageView.hpp +++ b/src/engine/image/ImageView.hpp @@ -21,7 +21,7 @@ namespace fgl::engine { std::shared_ptr< ImageHandle > m_resource; - std::optional< Sampler > m_sampler { std::nullopt }; + Sampler m_sampler; vk::DescriptorImageInfo m_descriptor_info {}; @@ -38,7 +38,12 @@ namespace fgl::engine ImageView( ImageView&& other ) noexcept : m_resource( std::move( other.m_resource ) ), m_descriptor_info( std::move( other.m_descriptor_info ) ), - m_image_view( std::move( other.m_image_view ) ) + m_image_view( std::move( other.m_image_view ) ), + m_sampler( + vk::Filter::eLinear, + vk::Filter::eLinear, + vk::SamplerMipmapMode::eLinear, + vk::SamplerAddressMode::eClampToEdge ) { other.m_image_view = VK_NULL_HANDLE; } @@ -59,7 +64,7 @@ namespace fgl::engine vk::Image& getVkImage(); - std::optional< Sampler >& getSampler() { return m_sampler; }; + Sampler& getSampler() { return m_sampler; }; vk::DescriptorImageInfo descriptorInfo( vk::Sampler sampler, vk::ImageLayout layout ) const; vk::DescriptorImageInfo descriptorInfo( vk::ImageLayout layout ) const; diff --git a/src/engine/image/Sampler.hpp b/src/engine/image/Sampler.hpp index 9999a0f..cb2c92a 100644 --- a/src/engine/image/Sampler.hpp +++ b/src/engine/image/Sampler.hpp @@ -16,7 +16,13 @@ namespace fgl::engine public: - Sampler() = delete; + Sampler() : + Sampler( + vk::Filter::eLinear, + vk::Filter::eLinear, + vk::SamplerMipmapMode::eLinear, + vk::SamplerAddressMode::eClampToBorder ) + {} Sampler( vk::Filter min_filter, diff --git a/src/engine/model/Model.cpp b/src/engine/model/Model.cpp index 41942ce..608cf82 100644 --- a/src/engine/model/Model.cpp +++ b/src/engine/model/Model.cpp @@ -133,18 +133,13 @@ namespace fgl::engine return model_ptr; } - void Model::syncBuffers( vk::CommandBuffer& cmd_buffer ) + void Model::stage( vk::CommandBuffer& cmd_buffer ) { assert( !m_primitives.empty() ); for ( auto& primitive : m_primitives ) { primitive.m_vertex_buffer.stage( cmd_buffer ); primitive.m_index_buffer.stage( cmd_buffer ); - - if ( primitive.m_texture.has_value() ) - { - primitive.m_texture->stage( cmd_buffer ); - } } } diff --git a/src/engine/model/Model.hpp b/src/engine/model/Model.hpp index 7e2b6f5..212c00f 100644 --- a/src/engine/model/Model.hpp +++ b/src/engine/model/Model.hpp @@ -64,7 +64,7 @@ namespace fgl::engine static std::vector< std::shared_ptr< Model > > createModelsFromScene( Device& device, const std::filesystem::path& path, Buffer& vertex_buffer, Buffer& index_buffer ); - void syncBuffers( vk::CommandBuffer& cmd_buffer ); + void stage( vk::CommandBuffer& cmd_buffer ); const std::string& getName() const { return m_name; } diff --git a/src/engine/model/Primitive.hpp b/src/engine/model/Primitive.hpp index 56da288..270e1f3 100644 --- a/src/engine/model/Primitive.hpp +++ b/src/engine/model/Primitive.hpp @@ -42,7 +42,7 @@ namespace fgl::engine OrientedBoundingBox< CoordinateSpace::Model > m_bounding_box; PrimitiveMode m_mode; - std::optional< Texture > m_texture { std::nullopt }; + std::shared_ptr< Texture > m_texture; Primitive( VertexBufferSuballocation&& vertex_buffer, @@ -59,13 +59,13 @@ namespace fgl::engine VertexBufferSuballocation&& vertex_buffer, IndexBufferSuballocation&& index_buffer, const OrientedBoundingBox< CoordinateSpace::Model >& bounding_box, - Texture&& texture, + std::shared_ptr< Texture >&& texture, const PrimitiveMode mode ) : m_vertex_buffer( std::move( vertex_buffer ) ), m_index_buffer( std::move( index_buffer ) ), m_bounding_box( bounding_box ), m_mode( mode ), - m_texture( std::move( texture ) ) + m_texture( std::forward< decltype( m_texture ) >( texture ) ) {} Primitive() = delete; diff --git a/src/engine/model/builders/SceneBuilder.cpp b/src/engine/model/builders/SceneBuilder.cpp index faf2745..447a2b4 100644 --- a/src/engine/model/builders/SceneBuilder.cpp +++ b/src/engine/model/builders/SceneBuilder.cpp @@ -131,7 +131,7 @@ namespace fgl::engine return root.accessors.at( prim.attributes.at( attrib ) ); } - Texture SceneBuilder::loadTexture( const tinygltf::Primitive& prim, const tinygltf::Model& root ) + std::shared_ptr< Texture > SceneBuilder::loadTexture( const tinygltf::Primitive& prim, const tinygltf::Model& root ) { ZoneScoped; const auto mat_idx { prim.material }; diff --git a/src/engine/model/builders/SceneBuilder.hpp b/src/engine/model/builders/SceneBuilder.hpp index ffc1608..6c60dfb 100644 --- a/src/engine/model/builders/SceneBuilder.hpp +++ b/src/engine/model/builders/SceneBuilder.hpp @@ -59,7 +59,7 @@ namespace fgl::engine const tinygltf::Accessor& getAccessorForAttribute( const tinygltf::Primitive& prim, const tinygltf::Model& root, const std::string attrib ) const; - Texture loadTexture( const tinygltf::Primitive& prim, const tinygltf::Model& root ); + std::shared_ptr< Texture > loadTexture( const tinygltf::Primitive& prim, const tinygltf::Model& root ); public: diff --git a/src/engine/model/builders/loadGltf.cpp b/src/engine/model/builders/loadGltf.cpp index a46fa57..7d0b71f 100644 --- a/src/engine/model/builders/loadGltf.cpp +++ b/src/engine/model/builders/loadGltf.cpp @@ -9,6 +9,7 @@ #pragma GCC diagnostic pop #include "ModelBuilder.hpp" +#include "engine/assets/stores.hpp" #include "engine/descriptors/DescriptorSet.hpp" #include "engine/image/ImageView.hpp" #include "engine/image/Sampler.hpp" @@ -253,14 +254,18 @@ namespace fgl::engine sampler.wrapS == sampler.wrapT && "Can't support different wrap modes for textures on each axis" ); - Texture tex { Texture::loadFromFile( filepath.parent_path() / source.uri ) }; + //TOOD: Get format from texture info and convert to vkFOrmat + + std::shared_ptr< Texture > tex { + getTextureStore().load( filepath.parent_path() / source.uri, vk::Format::eR8G8B8A8Unorm ) + }; Sampler smp { translateFilterToVK( sampler.minFilter ), translateFilterToVK( sampler.magFilter ), vk::SamplerMipmapMode::eLinear, translateWarppingToVk( sampler.wrapS ) }; - tex.getImageView().getSampler() = std::move( smp ); - tex.createImGuiSet(); + tex->getImageView().getSampler() = std::move( smp ); + tex->createImGuiSet(); Texture::getTextureDescriptorSet().bindTexture( 0, tex ); Texture::getTextureDescriptorSet().update(); @@ -268,10 +273,6 @@ namespace fgl::engine //Stage texture auto cmd { Device::getInstance().beginSingleTimeCommands() }; - tex.stage( cmd ); - Device::getInstance().endSingleTimeCommands( cmd ); - tex.dropStaging(); - Primitive prim { std::move( vertex_buffer ), std::move( index_buffer ), bounding_box, diff --git a/src/engine/systems/DrawPair.cpp b/src/engine/systems/DrawPair.cpp index abbeb77..0e1dd13 100644 --- a/src/engine/systems/DrawPair.cpp +++ b/src/engine/systems/DrawPair.cpp @@ -46,12 +46,12 @@ namespace fgl::engine // If the textureless flag is on and we have a texture then skip the primitive.c if ( options & TEXTURELESS ) { - if ( primitive.m_texture.has_value() ) continue; + if ( primitive.m_texture ) continue; } else { // Flag is not present - if ( !primitive.m_texture.has_value() ) continue; + if ( !primitive.m_texture ) continue; } const auto key { std::make_pair( matrix_info.texture_idx, primitive.m_index_buffer.getOffset() ) }; diff --git a/src/engine/systems/DrawPair.hpp b/src/engine/systems/DrawPair.hpp index d14f414..f083d9b 100644 --- a/src/engine/systems/DrawPair.hpp +++ b/src/engine/systems/DrawPair.hpp @@ -5,7 +5,7 @@ #pragma once #include "engine/GameObject.hpp" #include "engine/primitives/Frustum.hpp" -#include "engine/texture/TextureHandle.hpp" +#include "engine/texture/Texture.hpp" #include "engine/utils.hpp" namespace fgl::engine diff --git a/src/engine/texture/Texture.cpp b/src/engine/texture/Texture.cpp index 80ebe72..c32f911 100644 --- a/src/engine/texture/Texture.cpp +++ b/src/engine/texture/Texture.cpp @@ -6,10 +6,8 @@ #include -#include "TextureHandle.hpp" #include "engine/FrameInfo.hpp" #include "engine/buffers/BufferSuballocation.hpp" -#include "engine/descriptors/DescriptorPool.hpp" #include "engine/descriptors/DescriptorSet.hpp" #include "engine/image/ImageView.hpp" #include "objectloaders/stb_image.h" @@ -27,9 +25,8 @@ namespace fgl::engine { - inline static std::unordered_map< std::string, std::weak_ptr< TextureHandle > > texture_map; - - std::tuple< std::vector< std::byte >, int, int, int > loadTexture( const std::filesystem::path& path ) + std::tuple< std::vector< std::byte >, int, int, vk::Format > + loadTexture( const std::filesystem::path& path, const vk::Format format ) { ZoneScoped; if ( !std::filesystem::exists( path ) ) throw std::runtime_error( "Failed to open file: " + path.string() ); @@ -49,42 +46,14 @@ namespace fgl::engine stbi_image_free( data_c ); - return { std::move( data ), x, y, 4 }; - } + //TODO: Write check to ensure the format matches the number of channels - Texture Texture::loadFromFile( const std::filesystem::path& path ) - { - ZoneScoped; - log::debug( "Loading texture: {}", path ); - //TODO: Make some way of cleaning the map when loading textures - - if ( texture_map.contains( path.string() ) ) - { - if ( auto itter = texture_map.find( path.string() ); !itter->second.expired() ) - { - return Texture( itter->second.lock() ); - } - else - { - //Texture is expired. So it'll need to be reloaded. - texture_map.erase( itter ); - } - } - - const auto data { loadTexture( path ) }; - Texture tex { data }; - tex.m_handle->m_image_view->setName( path.string() ); - - texture_map.emplace( path.string(), tex.m_handle ); - - log::debug( "Loaded texture at {} with res {}x{}", path, tex.getExtent().width, tex.getExtent().height ); - - return std::move( tex ); + return { std::move( data ), x, y, format }; } void Texture::drawImGui( vk::Extent2D extent ) { - if ( this->m_handle->m_imgui_set == VK_NULL_HANDLE ) createImGuiSet(); + if ( this->m_imgui_set == VK_NULL_HANDLE ) createImGuiSet(); if ( extent == vk::Extent2D() ) { @@ -98,7 +67,7 @@ namespace fgl::engine bool Texture::drawImGuiButton( vk::Extent2D extent ) { - if ( this->m_handle->m_imgui_set == VK_NULL_HANDLE ) createImGuiSet(); + if ( this->m_imgui_set == VK_NULL_HANDLE ) createImGuiSet(); if ( extent == vk::Extent2D() ) { @@ -107,44 +76,63 @@ namespace fgl::engine const ImVec2 imgui_size { static_cast< float >( extent.width ), static_cast< float >( extent.height ) }; + if ( !isReady() ) + { + //TODO: Render placeholder + log::warn( "Attempted to render texture {} but texture was not ready!", this->m_texture_id ); + return ImGui::Button( "No texture :(" ); + } + return ImGui::ImageButton( static_cast< ImTextureID >( getImGuiDescriptorSet() ), imgui_size ); } - Texture Texture::generateFromPerlinNoise( int x_size, int y_size, std::size_t seed ) - { - ZoneScoped; - const std::vector< std::byte > data { generatePerlinImage( { x_size, y_size }, 15, seed ) }; - - Texture tex { data, x_size, y_size, 4 }; - - return std::move( tex ); - } - - Texture::Texture( std::shared_ptr< TextureHandle > handle ) : m_handle( std::move( handle ) ) - {} - - Texture::Texture( const std::tuple< std::vector< std::byte >, int, int, int >& tuple ) : + Texture::Texture( const std::tuple< std::vector< std::byte >, int, int, vk::Format >& tuple ) : Texture( std::get< 0 >( tuple ), std::get< 1 >( tuple ), std::get< 2 >( tuple ), std::get< 3 >( tuple ) ) {} - Texture::Texture( const std::vector< std::byte >& data, const int x, const int y, const int channels ) : - Texture( data, vk::Extent2D( x, y ), channels ) + Texture::Texture( const std::vector< std::byte >& data, const int x, const int y, const vk::Format format ) : + Texture( data, vk::Extent2D( x, y ), format ) {} - Texture::Texture( const std::vector< std::byte >& data, const vk::Extent2D extent, const int channels ) : - m_handle( std::make_shared< TextureHandle >( data, extent, channels ) ) + Texture::Texture( const std::vector< std::byte >& data, const vk::Extent2D extent, const vk::Format format ) : + m_extent( extent ) + { + ZoneScoped; + static TextureID tex_counter { 0 }; + + auto image = std::make_shared< Image >( + extent, + format, + vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, + vk::ImageLayout::eUndefined, + vk::ImageLayout::eShaderReadOnlyOptimal ); + + m_image_view = image->getView(); + + m_texture_id = tex_counter++; + + m_staging = std::make_unique< BufferSuballocation >( getGlobalStagingBuffer(), data.size() ); + //Copy data info buffer + std::memcpy( reinterpret_cast< unsigned char* >( m_staging->ptr() ), data.data(), data.size() ); + } + + Texture::Texture( const std::filesystem::path& path, const vk::Format format ) : + Texture( loadTexture( path, format ) ) {} + Texture::~Texture() + { + if ( m_imgui_set != VK_NULL_HANDLE ) ImGui_ImplVulkan_RemoveTexture( m_imgui_set ); + } + void Texture::stage( vk::CommandBuffer& cmd ) { ZoneScoped; - assert( m_handle && "Attempted to stage invalid texture (No handle)" ); - //assert( m_handle->m_staging && "Can't stage. No staging buffer made" ); + //assert( m_staging && "Can't stage. No staging buffer made" ); - //TODO: I need some way of telling if a Texture HAS been staged rather then simply checking if the staging buffer is present - // Since just checking if the buffer is present could not mean it has been staged (IE staged but not dropped, Or never created in the first place) - if ( !m_handle->m_staging ) return; + // Texutres are made with a staging buffer in RAM, Thus if the buffer has been dropped then we have been sucesfully staged. + if ( !m_staging ) return; vk::ImageSubresourceRange range; range.aspectMask = vk::ImageAspectFlagBits::eColor; @@ -156,7 +144,7 @@ namespace fgl::engine vk::ImageMemoryBarrier barrier {}; barrier.oldLayout = vk::ImageLayout::eUndefined; barrier.newLayout = vk::ImageLayout::eTransferDstOptimal; - barrier.image = m_handle->m_image_view->getVkImage(); + barrier.image = m_image_view->getVkImage(); barrier.subresourceRange = range; barrier.srcAccessMask = {}; barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; @@ -172,7 +160,7 @@ namespace fgl::engine barriers_to ); vk::BufferImageCopy region {}; - region.bufferOffset = m_handle->m_staging->getOffset(); + region.bufferOffset = m_staging->getOffset(); region.bufferRowLength = 0; region.bufferImageHeight = 0; @@ -182,21 +170,17 @@ namespace fgl::engine region.imageSubresource.layerCount = 1; region.imageOffset = vk::Offset3D( 0, 0, 0 ); - region.imageExtent = vk::Extent3D( m_handle->m_extent, 1 ); + region.imageExtent = vk::Extent3D( m_extent, 1 ); cmd.copyBufferToImage( - m_handle->m_staging->getVkBuffer(), - m_handle->m_image_view->getVkImage(), - vk::ImageLayout::eTransferDstOptimal, - 1, - ®ion ); + m_staging->getVkBuffer(), m_image_view->getVkImage(), vk::ImageLayout::eTransferDstOptimal, 1, ®ion ); //Transfer back to eGeneral vk::ImageMemoryBarrier barrier_from {}; barrier_from.oldLayout = barrier.newLayout; barrier_from.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier_from.image = m_handle->m_image_view->getVkImage(); + barrier_from.image = m_image_view->getVkImage(); barrier_from.subresourceRange = range; barrier_from.srcAccessMask = vk::AccessFlagBits::eTransferWrite; barrier_from.dstAccessMask = vk::AccessFlagBits::eShaderRead; @@ -214,57 +198,55 @@ namespace fgl::engine void Texture::dropStaging() { - m_handle->m_staging.reset(); + assert( m_staging ); + m_staging.reset(); } vk::DescriptorImageInfo Texture::getDescriptor() const { - return m_handle->m_image_view->descriptorInfo( vk::ImageLayout::eGeneral ); + return m_image_view->descriptorInfo( vk::ImageLayout::eGeneral ); } vk::Extent2D Texture::getExtent() const { - return m_handle->m_image_view->getExtent(); + return m_image_view->getExtent(); } ImageView& Texture::getImageView() { - assert( m_handle ); - assert( m_handle->m_image_view ); - return *m_handle->m_image_view; + assert( m_image_view ); + return *m_image_view; } void Texture::createImGuiSet() { #if ENABLE_IMGUI - if ( m_handle->m_imgui_set != VK_NULL_HANDLE ) return; + if ( m_imgui_set != VK_NULL_HANDLE ) return; - auto& view { m_handle->m_image_view }; + auto& view { m_image_view }; assert( view ); VkImageView vk_view { view->getVkView() }; assert( vk_view ); - assert( view->getSampler() ); - VkSampler vk_sampler { view->getSampler()->getVkSampler() }; + VkSampler vk_sampler { view->getSampler().getVkSampler() }; - m_handle->m_imgui_set = - ImGui_ImplVulkan_AddTexture( vk_sampler, vk_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ); + m_imgui_set = ImGui_ImplVulkan_AddTexture( vk_sampler, vk_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ); #endif } vk::DescriptorSet& Texture::getImGuiDescriptorSet() { - assert( m_handle ); - assert( m_handle->m_imgui_set != VK_NULL_HANDLE ); - return m_handle->m_imgui_set; + assert( !m_staging ); + assert( m_imgui_set != VK_NULL_HANDLE ); + return m_imgui_set; } TextureID Texture::getID() const { - assert( m_handle ); - return m_handle->m_texture_id; + assert( !m_staging ); + return m_texture_id; } DescriptorSet& Texture::getTextureDescriptorSet() diff --git a/src/engine/texture/Texture.hpp b/src/engine/texture/Texture.hpp index c338af0..e86cdf5 100644 --- a/src/engine/texture/Texture.hpp +++ b/src/engine/texture/Texture.hpp @@ -8,36 +8,62 @@ #include -#include "TextureHandle.hpp" +#include "engine/assets/AssetManager.hpp" namespace fgl::engine { + class BufferSuballocation; + class ImageView; class DescriptorSet; class TextureHandle; - //TODO: Implement texture handle map to avoid loading the same texture multiple times - class Texture - { - std::shared_ptr< TextureHandle > m_handle; - //! Has this texture been submitted to the GPU? - bool submitte_to_gpu { false }; + using TextureID = std::uint32_t; - [[nodiscard]] Texture( const std::tuple< std::vector< std::byte >, int, int, int >& ); - [[nodiscard]] Texture( std::shared_ptr< TextureHandle > handle ); + class Texture; + + using TextureStore = AssetStore< Texture >; + + //TODO: Implement texture handle map to avoid loading the same texture multiple times + class Texture final : public AssetInterface< Texture >, public std::enable_shared_from_this< Texture > + { + template < typename T > + friend class AssetStore; + + //TODO: Implement reusing texture ids + TextureID m_texture_id { std::numeric_limits< TextureID >::infinity() }; + + std::shared_ptr< ImageView > m_image_view {}; + + std::unique_ptr< BufferSuballocation > m_staging { nullptr }; + + vk::Extent2D m_extent { 0, 0 }; + + vk::DescriptorSet m_imgui_set { VK_NULL_HANDLE }; + + [[nodiscard]] Texture( const std::tuple< std::vector< std::byte >, int, int, vk::Format >& ); + + [[nodiscard]] + Texture( const std::vector< std::byte >& data, const int x, const int y, const vk::Format texture_format ); + + [[nodiscard]] + Texture( const std::vector< std::byte >& data, const vk::Extent2D extent, const vk::Format texture_format ); + + [[nodiscard]] Texture( const std::filesystem::path& path, const vk::Format format ); + + void stage( vk::CommandBuffer& cmd ) override; + void dropStaging(); public: - [[nodiscard]] Texture( const std::vector< std::byte >& data, const int x, const int y, const int channels ); - [[nodiscard]] Texture( const std::vector< std::byte >& data, const vk::Extent2D extent, const int channels ); + Texture() = delete; - Texture( const Texture& ) = default; + ~Texture(); + + Texture( const Texture& ) = delete; Texture& operator=( const Texture& ) = delete; - Texture( Texture&& other ) = default; - Texture& operator=( Texture&& ) = default; - - void stage( vk::CommandBuffer& cmd ); - void dropStaging(); + Texture( Texture&& other ) = delete; + Texture& operator=( Texture&& ) = delete; [[nodiscard]] TextureID getID() const; @@ -50,11 +76,8 @@ namespace fgl::engine void createImGuiSet(); - [[nodiscard]] static Texture generateFromPerlinNoise( int x_size, int y_size, std::size_t seed = 0 ); - [[nodiscard]] static Texture loadFromFile( const std::filesystem::path& path ); - void drawImGui( vk::Extent2D extent = {} ); - bool drawImGuiButton(vk::Extent2D extent = {}); + bool drawImGuiButton( vk::Extent2D extent = {} ); static DescriptorSet& getTextureDescriptorSet(); }; diff --git a/src/engine/texture/TextureHandle.cpp b/src/engine/texture/TextureHandle.cpp deleted file mode 100644 index cb0adaf..0000000 --- a/src/engine/texture/TextureHandle.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// Created by kj16609 on 1/22/24. -// - -#include "TextureHandle.hpp" - -#include "engine/buffers/BufferSuballocation.hpp" -#include "engine/image/Image.hpp" -#include "engine/image/ImageView.hpp" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Weffc++" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#pragma GCC diagnostic ignored "-Wconversion" -#include "imgui/backends/imgui_impl_vulkan.h" -#pragma GCC diagnostic pop - -namespace fgl::engine -{ - - TextureHandle::TextureHandle( - const std::vector< std::byte >& data, const vk::Extent2D extent, [[maybe_unused]] const int channels ) : - m_extent( extent ) - { - ZoneScoped; - static TextureID tex_counter { 0 }; - - constexpr auto format { vk::Format::eR8G8B8A8Unorm }; - - auto image = std::make_shared< Image >( - extent, - format, - vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, - vk::ImageLayout::eUndefined, - vk::ImageLayout::eShaderReadOnlyOptimal ); - - m_image_view = image->getView(); - - m_texture_id = tex_counter++; - - m_staging = std::make_unique< BufferSuballocation >( getGlobalStagingBuffer(), data.size() ); - //Copy data info buffer - std::memcpy( reinterpret_cast< unsigned char* >( m_staging->ptr() ), data.data(), data.size() ); - } - - TextureHandle::~TextureHandle() - { - if ( m_imgui_set != VK_NULL_HANDLE ) ImGui_ImplVulkan_RemoveTexture( m_imgui_set ); - } - -} // namespace fgl::engine diff --git a/src/engine/texture/TextureHandle.hpp b/src/engine/texture/TextureHandle.hpp deleted file mode 100644 index 1487f50..0000000 --- a/src/engine/texture/TextureHandle.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Created by kj16609 on 1/22/24. -// - -#pragma once - -#include - -#include -#include - -namespace fgl::engine -{ - class ImageView; - class BufferSuballocation; - - using TextureID = std::uint32_t; - - class TextureHandle - { - //TODO: Implement reusing texture ids - TextureID m_texture_id { std::numeric_limits< TextureID >::infinity() }; - - std::shared_ptr< ImageView > m_image_view {}; - - std::unique_ptr< BufferSuballocation > m_staging { nullptr }; - - vk::Extent2D m_extent { 0, 0 }; - - vk::DescriptorSet m_imgui_set { VK_NULL_HANDLE }; - - friend class Texture; - - public: - - TextureHandle( const std::vector< std::byte >& data, const vk::Extent2D extent, const int channels ); - ~TextureHandle(); - }; - -} // namespace fgl::engine