Core/AppFilesystemComponent: Add support for default resource parameters

This commit is contained in:
SirLynix 2023-01-28 11:27:49 +01:00
parent 60c00068ca
commit d27ca55943
24 changed files with 364 additions and 85 deletions

View File

@ -25,10 +25,6 @@ NAZARA_REQUEST_DEDICATED_GPU()
int main()
{
std::filesystem::path resourceDir = "assets/examples";
if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory("../.." / resourceDir))
resourceDir = "../.." / resourceDir;
Nz::Renderer::Config rendererConfig;
std::cout << "Run using Vulkan? (y/n)" << std::endl;
if (std::getchar() != 'n')
@ -46,7 +42,13 @@ int main()
auto& ecs = app.AddComponent<Nz::AppEntitySystemComponent>();
auto& fs = app.AddComponent<Nz::AppFilesystemComponent>();
fs.RegisterPath(resourceDir);
{
std::filesystem::path resourceDir = "assets/examples";
if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory("../.." / resourceDir))
resourceDir = "../.." / resourceDir;
fs.Mount("assets", resourceDir);
}
Nz::RenderSystem& renderSystem = ecs.AddSystem<Nz::RenderSystem>();
auto& windowSwapchain = renderSystem.CreateSwapchain(mainWindow);
@ -74,12 +76,8 @@ int main()
Nz::TextureSamplerInfo samplerInfo;
samplerInfo.anisotropyLevel = 8;
Nz::TextureParams texParams;
texParams.renderDevice = Nz::Graphics::Instance()->GetRenderDevice();
texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB;
std::shared_ptr<Nz::MaterialInstance> materialInstance = material->Instantiate();
materialInstance->SetTextureProperty("BaseColorMap", fs.GetOrLoad<Nz::Texture>("Spaceship/Texture/diffuse.png", texParams));
materialInstance->SetTextureProperty("BaseColorMap", fs.GetOrLoad<Nz::Texture>("assets/lynix.jpg"));
Nz::ImageWidget* imageWidget = canvas2D.Add<Nz::ImageWidget>(materialInstance);
imageWidget->SetPosition(1200.f, 200.f);

View File

@ -45,6 +45,8 @@ namespace Nz
friend Sound;
public:
using Params = SoundBufferParams;
SoundBuffer() = default;
SoundBuffer(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const Int16* samples);
SoundBuffer(const SoundBuffer&) = delete;

View File

@ -18,7 +18,7 @@
namespace Nz
{
struct SoundStreamParams : public ResourceParameters
struct SoundStreamParams : ResourceParameters
{
bool forceMono = false;
@ -33,6 +33,8 @@ namespace Nz
class NAZARA_AUDIO_API SoundStream : public Resource
{
public:
using Params = SoundStreamParams;
SoundStream() = default;
virtual ~SoundStream();

View File

@ -10,32 +10,50 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/ApplicationComponent.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/ResourceParameters.hpp>
#include <Nazara/Core/VirtualDirectory.hpp>
#include <memory>
#include <vector>
namespace Nz
{
class Font;
class Image;
class ImageStream;
class Material;
class MaterialInstance;
class Mesh;
class SoundBuffer;
class SoundStream;
class Texture;
class NAZARA_CORE_API AppFilesystemComponent : public ApplicationComponent
{
public:
using ApplicationComponent::ApplicationComponent;
inline AppFilesystemComponent(ApplicationBase& app);
AppFilesystemComponent(const AppFilesystemComponent&) = delete;
AppFilesystemComponent(AppFilesystemComponent&&) = delete;
~AppFilesystemComponent() = default;
template<typename T, typename... Args> std::shared_ptr<T> GetOrLoad(std::string_view assetPath, Args&&... args);
template<typename T> const typename T::Params* GetDefaultResourceParameters() const;
inline const VirtualDirectoryPtr& RegisterPath(std::filesystem::path filepath);
inline const VirtualDirectoryPtr& RegisterVirtualDirectory(VirtualDirectoryPtr directory);
template<typename T> std::shared_ptr<T> GetOrLoad(std::string_view assetPath);
template<typename T> std::shared_ptr<T> GetOrLoad(std::string_view assetPath, typename T::Params params);
inline void UnregisterVirtualDirectory(const VirtualDirectoryPtr& directory);
inline const VirtualDirectoryPtr& Mount(std::string_view name, std::filesystem::path filepath);
inline const VirtualDirectoryPtr& Mount(std::string_view name, VirtualDirectoryPtr directory);
template<typename T> void SetDefaultResourceParameters(typename T::Params params);
AppFilesystemComponent& operator=(const AppFilesystemComponent&) = delete;
AppFilesystemComponent& operator=(AppFilesystemComponent&&) = delete;
private:
std::vector<VirtualDirectoryPtr> m_virtualDirectories;
template<typename T> std::shared_ptr<T> GetOrLoadImpl(std::string_view assetPath, const typename T::Params& params);
inline void RegisterResourceTypes();
std::vector<std::unique_ptr<ResourceParameters>> m_defaultParameters;
VirtualDirectoryPtr m_rootDirectory;
};
}

View File

@ -4,68 +4,153 @@
#include <Nazara/Core/AppFilesystemComponent.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ResourceRegistry.hpp>
#include <stdexcept>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
template<typename T, typename... Args>
std::shared_ptr<T> AppFilesystemComponent::GetOrLoad(std::string_view assetPath, Args&&... args)
namespace Detail
{
std::shared_ptr<T> resource;
for (const VirtualDirectoryPtr& virtualDir : m_virtualDirectories)
{
auto callback = [&](const VirtualDirectory::Entry& entry)
{
return std::visit([&](auto&& arg)
{
using Param = std::decay_t<decltype(arg)>;
if constexpr (std::is_base_of_v<VirtualDirectory::DirectoryEntry, Param>)
{
NazaraError(std::string(assetPath) + " is a directory");
return false;
}
else if constexpr (std::is_same_v<Param, VirtualDirectory::DataPointerEntry>)
{
resource = T::LoadFromMemory(arg.data, arg.size, std::forward<Args>(args)...);
return true;
}
else if constexpr (std::is_same_v<Param, VirtualDirectory::FileContentEntry>)
{
resource = T::LoadFromMemory(&arg.data[0], arg.data.size(), std::forward<Args>(args)...);
return true;
}
else if constexpr (std::is_same_v<Param, VirtualDirectory::PhysicalFileEntry>)
{
resource = T::LoadFromFile(arg.filePath, std::forward<Args>(args)...);
return true;
}
else
static_assert(AlwaysFalse<Param>(), "unhandled case");
}, entry);
};
template<typename, typename = void>
struct ResourceParameterHasMerge : std::false_type {};
if (virtualDir->GetEntry(assetPath, callback) && resource)
return resource;
template<typename T>
struct ResourceParameterHasMerge<T, std::void_t<decltype(std::declval<T>().Merge(std::declval<T>()))>> : std::true_type {};
}
inline AppFilesystemComponent::AppFilesystemComponent(ApplicationBase& app) :
ApplicationComponent(app)
{
RegisterResourceTypes();
}
template<typename T>
const typename T::Params* AppFilesystemComponent::GetDefaultResourceParameters() const
{
std::size_t resourceIndex = ResourceRegistry<T>::GetResourceId();
if (resourceIndex >= m_defaultParameters.size())
return nullptr;
return static_cast<const typename T::Params*>(m_defaultParameters[resourceIndex].get());
}
template<typename T>
std::shared_ptr<T> AppFilesystemComponent::GetOrLoad(std::string_view assetPath)
{
return GetOrLoad<T>(assetPath, typename T::Params{});
}
template<typename T>
std::shared_ptr<T> AppFilesystemComponent::GetOrLoad(std::string_view assetPath, typename T::Params params)
{
if constexpr (Detail::ResourceParameterHasMerge<typename T::Params>::value)
{
if (const auto* defaultParams = GetDefaultResourceParameters<T>())
params.Merge(*defaultParams);
}
return GetOrLoadImpl<T>(assetPath, params);
}
inline const VirtualDirectoryPtr& AppFilesystemComponent::Mount(std::string_view name, std::filesystem::path filepath)
{
return Mount(name, std::make_shared<VirtualDirectory>(std::move(filepath)));
}
inline const VirtualDirectoryPtr& AppFilesystemComponent::Mount(std::string_view name, VirtualDirectoryPtr directory)
{
if (name.empty())
{
m_rootDirectory = std::move(directory);
return m_rootDirectory;
}
if (!m_rootDirectory)
m_rootDirectory = std::make_shared<VirtualDirectory>();
return m_rootDirectory->StoreDirectory(name, std::move(directory)).directory;
}
template<typename T>
void AppFilesystemComponent::SetDefaultResourceParameters(typename T::Params params)
{
std::size_t resourceIndex = ResourceRegistry<T>::GetResourceId();
if (resourceIndex >= m_defaultParameters.size())
m_defaultParameters.resize(resourceIndex + 1);
m_defaultParameters[resourceIndex] = std::make_unique<typename T::Params>(std::move(params));
}
template<typename T>
std::shared_ptr<T> AppFilesystemComponent::GetOrLoadImpl(std::string_view assetPath, const typename T::Params& params)
{
std::shared_ptr<T> resource;
if (!m_rootDirectory)
return resource;
auto callback = [&](const VirtualDirectory::Entry& entry)
{
return std::visit([&](auto&& arg)
{
using Param = std::decay_t<decltype(arg)>;
if constexpr (std::is_base_of_v<VirtualDirectory::DirectoryEntry, Param>)
{
NazaraError(std::string(assetPath) + " is a directory");
return false;
}
else if constexpr (std::is_same_v<Param, VirtualDirectory::DataPointerEntry>)
{
resource = T::LoadFromMemory(arg.data, arg.size, params);
return true;
}
else if constexpr (std::is_same_v<Param, VirtualDirectory::FileContentEntry>)
{
resource = T::LoadFromMemory(&arg.data[0], arg.data.size(), params);
return true;
}
else if constexpr (std::is_same_v<Param, VirtualDirectory::PhysicalFileEntry>)
{
resource = T::LoadFromFile(arg.filePath, params);
return true;
}
else
static_assert(AlwaysFalse<Param>(), "unhandled case");
}, entry);
};
m_rootDirectory->GetEntry(assetPath, callback);
return resource;
}
inline const VirtualDirectoryPtr& AppFilesystemComponent::RegisterPath(std::filesystem::path filepath)
inline void AppFilesystemComponent::RegisterResourceTypes()
{
return RegisterVirtualDirectory(std::make_shared<VirtualDirectory>(std::move(filepath)));
}
if (ResourceRegistry<Font>::GetResourceId() != 0)
throw std::runtime_error("Font has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
inline const VirtualDirectoryPtr& AppFilesystemComponent::RegisterVirtualDirectory(VirtualDirectoryPtr directory)
{
return m_virtualDirectories.emplace_back(std::move(directory));
}
if (ResourceRegistry<Image>::GetResourceId() != 1)
throw std::runtime_error("Image has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
inline void AppFilesystemComponent::UnregisterVirtualDirectory(const VirtualDirectoryPtr& directory)
{
auto it = std::find(m_virtualDirectories.begin(), m_virtualDirectories.end(), directory);
if (it == m_virtualDirectories.end())
m_virtualDirectories.erase(it);
if (ResourceRegistry<ImageStream>::GetResourceId() != 2)
throw std::runtime_error("ImageStream has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
if (ResourceRegistry<Material>::GetResourceId() != 3)
throw std::runtime_error("Material has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
if (ResourceRegistry<MaterialInstance>::GetResourceId() != 4)
throw std::runtime_error("MaterialInstance has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
if (ResourceRegistry<Mesh>::GetResourceId() != 5)
throw std::runtime_error("Mesh has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
if (ResourceRegistry<SoundBuffer>::GetResourceId() != 6)
throw std::runtime_error("SoundBuffer has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
if (ResourceRegistry<SoundStream>::GetResourceId() != 7)
throw std::runtime_error("SoundStream has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
if (ResourceRegistry<Texture>::GetResourceId() != 8)
throw std::runtime_error("Texture has wrong resource index, please initialize AppFilesystemComponent before using ResourceRegistry");
}
}

View File

@ -24,6 +24,8 @@ namespace Nz
Application(Application&&) = delete;
~Application();
template<typename T, typename... Args> T& AddComponent(Args&&... args);
Application& operator=(const Application&) = delete;
Application& operator=(Application&&) = delete;

View File

@ -7,6 +7,39 @@
namespace Nz
{
namespace Detail
{
template<typename, typename, typename = void>
struct ModuleHasRegister : std::false_type {};
template<typename M, typename C>
struct ModuleHasRegister<M, C, std::void_t<decltype(std::declval<M>().RegisterComponent(std::declval<C&>()))>> : std::true_type {};
template<typename> struct ModuleRegisterer;
template<typename Module, typename... Rest>
struct ModuleRegisterer<TypeList<Module, Rest...>>
{
template<typename T, typename C>
static void Register(T& modules, C& component)
{
if constexpr (ModuleHasRegister<Module, C>::value)
modules.template Get<Module>().RegisterComponent(component);
ModuleRegisterer<TypeList<Rest...>>::Register(modules, component);
}
};
template<>
struct ModuleRegisterer<TypeList<>>
{
template<typename T, typename C>
static void Register(T& /*modules*/, C& /*component*/)
{
}
};
}
template<typename... ModuleList>
template<typename... ModuleConfig>
Application<ModuleList...>::Application(ModuleConfig&&... configs) :
@ -30,6 +63,16 @@ namespace Nz
{
}
template<typename... ModuleList>
template<typename T, typename... Args>
T& Application<ModuleList...>::AddComponent(Args&&... args)
{
T& component = ApplicationBase::AddComponent<T>(std::forward<Args>(args)...);
Detail::ModuleRegisterer<typename decltype(m_modules)::ModuleTypeList>::template Register(m_modules, component);
return component;
}
template<typename... ModuleList>
Application<ModuleList...>::~Application()
{

View File

@ -26,7 +26,6 @@ namespace Nz
ApplicationBase(ApplicationBase&&) = delete;
~ApplicationBase() = default;
template<typename T, typename... Args> T& AddComponent(Args&&... args);
template<typename F> void AddUpdater(F&& functor);
inline void ClearComponents();
@ -43,6 +42,9 @@ namespace Nz
ApplicationBase& operator=(const ApplicationBase&) = delete;
ApplicationBase& operator=(ApplicationBase&&) = delete;
protected:
template<typename T, typename... Args> T& AddComponent(Args&&... args);
private:
std::atomic_bool m_running;
std::vector<std::unique_ptr<ApplicationComponent>> m_components;

View File

@ -9,7 +9,7 @@ namespace Nz
{
namespace Detail
{
std::size_t ComponentCounter()
inline std::size_t ComponentCounter()
{
static std::size_t counter = 0;
return counter++;

View File

@ -13,14 +13,13 @@ namespace Nz
{
namespace Detail
{
template<typename>
struct BuildDepList;
template<typename Module, typename... Modules>
struct ModuleTuple : ModuleTuple<Module>, ModuleTuple<Modules...>
{
template<typename... ModuleConfig>
ModuleTuple(ModuleConfig&&... configs);
template<typename T> T& Get();
};
template<typename Module>
@ -29,10 +28,16 @@ namespace Nz
template<typename... ModuleConfig>
ModuleTuple(ModuleConfig&&... configs);
template<typename T> T& Get();
Module m;
};
}
template<typename> struct OrderedModuleDependencyList;
template<typename ModuleList> using OrderedModuleDependencies = TypeListUnique<typename OrderedModuleDependencyList<ModuleList>::Result>;
template<typename... ModuleList>
class Modules
{
@ -41,12 +46,31 @@ namespace Nz
Modules(ModuleConfig&&... configs);
~Modules() = default;
template<typename T> T& Get();
using ModuleTypeList = OrderedModuleDependencies<TypeList<ModuleList...>>;
private:
using OrderedModuleList = TypeListUnique<typename Detail::BuildDepList<TypeList<ModuleList...>>::Result>;
using Tuple = TypeListInstantiate<OrderedModuleList, Detail::ModuleTuple>;
using Tuple = TypeListInstantiate<ModuleTypeList, Detail::ModuleTuple>;
Tuple m_modules;
};
template<>
struct OrderedModuleDependencyList<TypeList<>>
{
using Result = TypeList<>;
};
template<typename Module, typename... ModuleList>
struct OrderedModuleDependencyList<TypeList<Module, ModuleList...>>
{
using ModuleDependencies = typename OrderedModuleDependencyList<typename Module::Dependencies>::Result;
using ModuleDependenciesIncModule = TypeListAppend<ModuleDependencies, Module>;
using RestDependencies = typename OrderedModuleDependencyList<TypeList<ModuleList...>>::Result;
using Result = TypeListConcat<ModuleDependenciesIncModule, RestDependencies>;
};
}
#include <Nazara/Core/Modules.inl>

View File

@ -39,6 +39,16 @@ namespace Nz
{
}
template<typename Module, typename... Modules>
template<typename T>
T& ModuleTuple<Module, Modules...>::Get()
{
if constexpr (std::is_same_v<T, Module>)
return ModuleTuple<Module>::template Get<T>();
else
return ModuleTuple<Modules...>::template Get<T>();
}
template<typename Module>
template<typename... ModuleConfig>
ModuleTuple<Module>::ModuleTuple(ModuleConfig&&... configs) :
@ -46,20 +56,13 @@ namespace Nz
{
}
template<>
struct BuildDepList<TypeList<>>
template<typename Module>
template<typename T>
T& ModuleTuple<Module>::Get()
{
using Result = TypeList<>;
};
template<typename Module, typename... ModuleList>
struct BuildDepList<TypeList<Module, ModuleList...>>
{
using ModuleDependencies = typename BuildDepList<typename Module::Dependencies>::Result;
using ModuleDependenciesIncModule = TypeListAppend<ModuleDependencies, Module>;
using RestDependencies = typename BuildDepList<TypeList<ModuleList...>>::Result;
using Result = TypeListConcat<ModuleDependenciesIncModule, RestDependencies>;
};
static_assert(std::is_same_v<T, Module>, "module is not in the list");
return m;
}
}
template<typename... ModuleList>
@ -68,6 +71,13 @@ namespace Nz
m_modules(std::forward<ModuleConfig>(configs)...)
{
}
template<typename... ModuleList>
template<typename T>
T& Modules<ModuleList...>::Get()
{
return m_modules.template Get<T>();
}
}
#include <Nazara/Core/DebugOff.hpp>

View File

@ -0,0 +1,24 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_CORE_RESOURCEREGISTRY_HPP
#define NAZARA_CORE_RESOURCEREGISTRY_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Config.hpp>
namespace Nz
{
template<typename T>
struct ResourceRegistry
{
static std::size_t GetResourceId();
};
}
#include <Nazara/Core/ResourceRegistry.inl>
#endif // NAZARA_CORE_RESOURCEREGISTRY_HPP

View File

@ -0,0 +1,27 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/ResourceRegistry.hpp>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
namespace Detail
{
inline std::size_t ResourceTypeIndexCounter()
{
static std::size_t counter = 0;
return counter++;
}
}
template<typename T>
std::size_t ResourceRegistry<T>::GetResourceId()
{
static std::size_t typeId = Detail::ResourceTypeIndexCounter();
return typeId;
}
}
#include <Nazara/Core/DebugOff.hpp>

View File

@ -22,6 +22,7 @@
namespace Nz
{
class AppFilesystemComponent;
class RenderBuffer;
class NAZARA_GRAPHICS_API Graphics : public ModuleBase<Graphics>
@ -55,6 +56,8 @@ namespace Nz
inline TextureSamplerCache& GetSamplerCache();
inline const std::shared_ptr<nzsl::FilesystemModuleResolver>& GetShaderModuleResolver() const;
void RegisterComponent(AppFilesystemComponent& component);
struct Config
{
RenderDeviceFeatures forceDisableFeatures;

View File

@ -43,6 +43,7 @@ namespace Nz
public:
struct TextureData;
struct UniformBlockData;
using Params = MaterialParams;
Material(MaterialSettings settings, const std::string& referenceModuleName);
Material(MaterialSettings settings, const nzsl::Ast::ModulePtr& referenceModule);

View File

@ -44,6 +44,8 @@ namespace Nz
struct CopyToken {};
public:
using Params = MaterialInstanceParams;
MaterialInstance(std::shared_ptr<const Material> parent);
MaterialInstance(const MaterialInstance&) = delete;
MaterialInstance(const MaterialInstance& material, CopyToken);

View File

@ -49,6 +49,7 @@ namespace Nz
TextureUsageFlags usageFlags = TextureUsage::ShaderSampling | TextureUsage::TransferDestination;
bool IsValid() const;
void Merge(const TextureParams& params);
};
class Texture;
@ -60,6 +61,8 @@ namespace Nz
class NAZARA_RENDERER_API Texture : public AbstractImage, public Resource, public std::enable_shared_from_this<Texture> //< FIXME
{
public:
using Params = TextureParams;
Texture() = default;
Texture(const Texture&) = delete;
Texture(Texture&&) = delete;

View File

@ -43,6 +43,7 @@ namespace Nz
public:
struct Glyph;
struct SizeInfo;
using Params = FontParams;
Font();
Font(const Font&) = delete;

View File

@ -34,6 +34,7 @@ namespace Nz
UInt8 levelCount = 0;
bool IsValid() const;
void Merge(const ImageParams& params);
};
class Image;
@ -46,6 +47,7 @@ namespace Nz
class NAZARA_UTILITY_API Image : public AbstractImage, public Resource
{
public:
using Params = ImageParams;
struct SharedImage;
Image();

View File

@ -30,6 +30,8 @@ namespace Nz
class NAZARA_UTILITY_API ImageStream : public Resource
{
public:
using Params = ImageStreamParams;
ImageStream() = default;
virtual ~ImageStream();

View File

@ -93,6 +93,8 @@ namespace Nz
class NAZARA_UTILITY_API Mesh : public Resource
{
public:
using Params = MeshParams;
inline Mesh();
Mesh(const Mesh&) = delete;
Mesh(Mesh&&) = delete;

View File

@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Core/AppFilesystemComponent.hpp>
#include <Nazara/Graphics/GuillotineTextureAtlas.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/MaterialPipeline.hpp>
@ -174,6 +175,14 @@ namespace Nz
m_defaultTextures = DefaultTextures{};
}
void Graphics::RegisterComponent(AppFilesystemComponent& component)
{
TextureParams defaultTexParams;
defaultTexParams.renderDevice = m_renderDevice;
component.SetDefaultResourceParameters<Texture>(defaultTexParams);
}
void Graphics::BuildBlitPipeline()
{
RenderPipelineLayoutInfo layoutInfo;

View File

@ -32,6 +32,16 @@ namespace Nz
return true;
}
void TextureParams::Merge(const TextureParams& params)
{
ImageParams::Merge(params);
if (!renderDevice)
renderDevice = params.renderDevice;
usageFlags |= params.usageFlags;
}
std::shared_ptr<Texture> Texture::CreateFromImage(const Image& image, const TextureParams& params)
{
NazaraAssert(params.IsValid(), "Invalid TextureParams");

View File

@ -39,6 +39,13 @@ namespace Nz
return true; // Rien à vérifier
}
void ImageParams::Merge(const ImageParams& params)
{
if (loadFormat == PixelFormat::Undefined)
loadFormat = params.loadFormat;
}
Image::Image() :
m_sharedImage(&emptyImage)
{