Add Texture2DArray as Sampler
- Add Texture2DArray support
- Add Mapper class, that acts a a 1-to-1 map
- Make all Assets take in MetaFileClass instead of MetaClass, to avoid
doing metaFile.GetMetaClass("Texture2DArray") in every Asset
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "copium/asset/AssetMeta.h"
|
||||
#include "copium/util/Common.h"
|
||||
#include "copium/util/Uuid.h"
|
||||
|
||||
namespace Copium
|
||||
@@ -15,6 +16,7 @@ namespace Copium
|
||||
public:
|
||||
Asset();
|
||||
virtual ~Asset();
|
||||
CP_DELETE_COPY_AND_MOVE_CTOR(Asset);
|
||||
|
||||
const std::string& GetName() const;
|
||||
Uuid GetUuid() const;
|
||||
|
||||
@@ -42,6 +42,8 @@ namespace Copium
|
||||
template <typename AssetType>
|
||||
static void RegisterAssetType(const std::string& assetType)
|
||||
{
|
||||
static_assert(std::is_constructible_v<AssetType, const MetaFileClass&>,
|
||||
"AssetType must be constructable from MetaFileClass");
|
||||
CP_ASSERT(assetTypes.emplace(assetType, &AssetManager::CreateAsset<AssetType>).second,
|
||||
"Asset type already exists: {}",
|
||||
assetType.c_str());
|
||||
@@ -97,14 +99,16 @@ namespace Copium
|
||||
static Asset& LoadAssetFromPath(const std::string& filepath);
|
||||
|
||||
template <typename T>
|
||||
static Asset& CreateAsset(const MetaFile& metaFile, const std::string& metaFileClass)
|
||||
static Asset& CreateAsset(const MetaFile& metaFile, const std::string& assetName)
|
||||
{
|
||||
const MetaFileClass& metaFileClass = metaFile.GetMetaClass(assetName);
|
||||
|
||||
AssetId id = assetId++;
|
||||
pathToAssetCache.emplace(metaFile.GetFilePath(), id);
|
||||
Asset& asset = *assets.emplace(id, std::make_unique<T>(metaFile)).first->second.get();
|
||||
Asset& asset = *assets.emplace(id, std::make_unique<T>(metaFileClass)).first->second.get();
|
||||
asset.metaData.id = id;
|
||||
asset.metaData.name = metaFile.GetFilePath();
|
||||
asset.metaData.uuid = Uuid{metaFile.GetMetaClass(metaFileClass).GetValue("uuid")};
|
||||
asset.metaData.uuid = Uuid{metaFileClass.GetValue("uuid")};
|
||||
asset.metaData.isRuntime = false;
|
||||
return asset;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
Framebuffer::Framebuffer(const MetaFile& metaFile)
|
||||
Framebuffer::Framebuffer(const MetaFileClass& metaClass)
|
||||
{
|
||||
const MetaFileClass& metaClass = metaFile.GetMetaClass("Framebuffer");
|
||||
colorAttachment = AssetRef<ColorAttachment>(Uuid{metaClass.GetValue("rendertexture-uuid")});
|
||||
ColorAttachment& attachment = colorAttachment.GetAsset();
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Copium
|
||||
int height;
|
||||
|
||||
public:
|
||||
Framebuffer(const MetaFile& metaFile);
|
||||
Framebuffer(const MetaFileClass& metaClass);
|
||||
Framebuffer(int width, int height, const SamplerCreator& samplerCreator);
|
||||
~Framebuffer();
|
||||
|
||||
|
||||
@@ -264,7 +264,8 @@ namespace Copium
|
||||
imageViews.resize(images.size());
|
||||
for (size_t i = 0; i < images.size(); i++)
|
||||
{
|
||||
imageViews[i] = Image::InitializeImageView(images[i], imageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
imageViews[i] =
|
||||
Image::InitializeImageView(images[i], imageFormat, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "copium/sampler/ColorAttachment.h"
|
||||
#include "copium/sampler/Font.h"
|
||||
#include "copium/sampler/Texture2D.h"
|
||||
#include "copium/sampler/Texture2DArray.h"
|
||||
#include "copium/util/Timer.h"
|
||||
|
||||
namespace Copium
|
||||
@@ -35,6 +36,7 @@ namespace Copium
|
||||
|
||||
timer.Start();
|
||||
AssetManager::RegisterAssetType<Texture2D>("Texture2D");
|
||||
AssetManager::RegisterAssetType<Texture2DArray>("Texture2DArray");
|
||||
AssetManager::RegisterAssetType<ColorAttachment>("RenderTexture");
|
||||
AssetManager::RegisterAssetType<Pipeline>("Pipeline");
|
||||
AssetManager::RegisterAssetType<Framebuffer>("Framebuffer");
|
||||
|
||||
@@ -10,15 +10,13 @@
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
Pipeline::Pipeline(const MetaFile& metaFile)
|
||||
: shaderReflector{ShaderReflector{metaFile.GetMetaClass("Pipeline").GetValue("vert-filepath"),
|
||||
metaFile.GetMetaClass("Pipeline").GetValue("frag-filepath")}}
|
||||
Pipeline::Pipeline(const MetaFileClass& metaClass)
|
||||
: shaderReflector{ShaderReflector{metaClass.GetValue("vert-filepath"), metaClass.GetValue("frag-filepath")}}
|
||||
{
|
||||
const MetaFileClass& metaFileClass = metaFile.GetMetaClass("Pipeline");
|
||||
VkRenderPass renderPass;
|
||||
if (metaFileClass.HasValue("framebuffer-uuid"))
|
||||
if (metaClass.HasValue("framebuffer-uuid"))
|
||||
{
|
||||
framebuffer = AssetRef<Framebuffer>(Uuid{metaFileClass.GetValue("framebuffer-uuid")});
|
||||
framebuffer = AssetRef<Framebuffer>(Uuid{metaClass.GetValue("framebuffer-uuid")});
|
||||
Framebuffer& fb = framebuffer.GetAsset();
|
||||
renderPass = fb.GetRenderPass();
|
||||
}
|
||||
@@ -26,9 +24,8 @@ namespace Copium
|
||||
{
|
||||
renderPass = Vulkan::GetSwapChain().GetRenderPass();
|
||||
}
|
||||
PipelineCreator creator{
|
||||
renderPass, metaFileClass.GetValue("vert-filepath"), metaFileClass.GetValue("frag-filepath")};
|
||||
std::string type = metaFileClass.GetValue("type");
|
||||
PipelineCreator creator{renderPass, metaClass.GetValue("vert-filepath"), metaClass.GetValue("frag-filepath")};
|
||||
std::string type = metaClass.GetValue("type");
|
||||
if (type == "Renderer")
|
||||
{
|
||||
creator.SetVertexDescriptor(RendererVertex::GetDescriptor());
|
||||
@@ -43,14 +40,14 @@ namespace Copium
|
||||
else if (type == "Mesh")
|
||||
{
|
||||
creator.SetVertexDescriptor(Vertex::GetDescriptor());
|
||||
creator.SetBlending(metaFileClass.GetValue("alpha-blending", "false") == "true" ? true : false);
|
||||
creator.SetDepthTest(metaFileClass.GetValue("depth-test", "true") == "true" ? true : false);
|
||||
creator.SetBlending(metaClass.GetValue("alpha-blending", "false") == "true" ? true : false);
|
||||
creator.SetDepthTest(metaClass.GetValue("depth-test", "true") == "true" ? true : false);
|
||||
}
|
||||
else if (type == "LineRenderer")
|
||||
{
|
||||
creator.SetVertexDescriptor(LineVertex::GetDescriptor());
|
||||
creator.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
|
||||
creator.SetDepthTest(metaFileClass.GetValue("depth-test", "false") == "true" ? true : false);
|
||||
creator.SetDepthTest(metaClass.GetValue("depth-test", "false") == "true" ? true : false);
|
||||
}
|
||||
InitializeDescriptorSetLayout(creator);
|
||||
InitializePipeline(creator);
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Copium
|
||||
AssetRef<Framebuffer> framebuffer;
|
||||
|
||||
public:
|
||||
Pipeline(const MetaFile& metaFile);
|
||||
Pipeline(const MetaFileClass& metaClass);
|
||||
Pipeline(PipelineCreator creator);
|
||||
~Pipeline();
|
||||
void Bind(const CommandBuffer& commandBuffer);
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace Copium
|
||||
}
|
||||
|
||||
ParseLine(str, index);
|
||||
if (type == "sampler2D")
|
||||
if (type == "sampler2D" || type == "sampler2DArray")
|
||||
shaderBinding.bindingType = BindingType::Sampler2D;
|
||||
else
|
||||
shaderBinding.bindingType = BindingType::UniformBuffer;
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
namespace Copium
|
||||
{
|
||||
|
||||
ColorAttachment::ColorAttachment(const MetaFile& metaFile)
|
||||
: Sampler{SamplerCreator{metaFile.GetMetaClass("RenderTexture")}}
|
||||
ColorAttachment::ColorAttachment(const MetaFileClass& metaClass)
|
||||
: Sampler{SamplerCreator{metaClass}}
|
||||
{
|
||||
const MetaFileClass& metaClass = metaFile.GetMetaClass("RenderTexture");
|
||||
if (metaClass.HasValue("width"))
|
||||
{
|
||||
char* endPtr;
|
||||
@@ -109,7 +108,8 @@ namespace Copium
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
&images[i],
|
||||
&imageMemories[i]);
|
||||
imageViews[i] = Image::InitializeImageView(images[i], VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
imageViews[i] = Image::InitializeImageView(
|
||||
images[i], VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Copium
|
||||
int height;
|
||||
|
||||
public:
|
||||
ColorAttachment(const MetaFile& metaFile);
|
||||
ColorAttachment(const MetaFileClass& metaClass);
|
||||
ColorAttachment(int width, int height, const SamplerCreator& samplerCreator);
|
||||
~ColorAttachment() override;
|
||||
|
||||
|
||||
@@ -58,6 +58,6 @@ namespace Copium
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
&image,
|
||||
&imageMemory);
|
||||
imageView = Image::InitializeImageView(image, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
imageView = Image::InitializeImageView(image, depthFormat, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
Font::Font(const MetaFile& metaFile)
|
||||
: Sampler{SamplerCreator{metaFile.GetMetaClass("Font")}}
|
||||
Font::Font(const MetaFileClass& metaClass)
|
||||
: Sampler{SamplerCreator{metaClass}}
|
||||
{
|
||||
msdfgen::FreetypeHandle* ft = msdfgen::initializeFreetype();
|
||||
CP_ASSERT(ft, "Failed to initialize FreeType"); // TODO: Move to Vulkan singleton class?
|
||||
std::string fontPath = metaFile.GetMetaClass("Font").GetValue("filepath");
|
||||
std::string fontPath = metaClass.GetValue("filepath");
|
||||
msdfgen::FontHandle* font = msdfgen::loadFont(ft, fontPath.c_str());
|
||||
CP_ASSERT(font, "Failed to initialize font: {}", fontPath);
|
||||
|
||||
@@ -178,6 +178,7 @@ namespace Copium
|
||||
Image::CopyBufferToImage(stagingBuffer, image, width, height);
|
||||
Image::TransitionImageLayout(
|
||||
image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
imageView = Image::InitializeImageView(image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
imageView =
|
||||
Image::InitializeImageView(image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Copium
|
||||
float baseHeight;
|
||||
|
||||
public:
|
||||
Font(const MetaFile& metaFile);
|
||||
Font(const MetaFileClass& metaClass);
|
||||
~Font() override;
|
||||
|
||||
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override;
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "copium/buffer/CommandBufferScoped.h"
|
||||
#include "copium/core/Vulkan.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
void Image::InitializeImage(uint32_t width,
|
||||
@@ -13,6 +16,19 @@ namespace Copium
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkImage* image,
|
||||
VkDeviceMemory* imageMemory)
|
||||
{
|
||||
InitializeImage(width, height, 1, format, tiling, usage, properties, image, imageMemory);
|
||||
}
|
||||
|
||||
void Image::InitializeImage(uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t layers,
|
||||
VkFormat format,
|
||||
VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkImage* image,
|
||||
VkDeviceMemory* imageMemory)
|
||||
{
|
||||
VkImageCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
@@ -21,7 +37,7 @@ namespace Copium
|
||||
createInfo.extent.height = height;
|
||||
createInfo.extent.depth = 1;
|
||||
createInfo.mipLevels = 1;
|
||||
createInfo.arrayLayers = 1;
|
||||
createInfo.arrayLayers = layers;
|
||||
createInfo.format = format;
|
||||
createInfo.tiling = tiling;
|
||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
@@ -46,13 +62,14 @@ namespace Copium
|
||||
vkBindImageMemory(Vulkan::GetDevice(), *image, *imageMemory, 0);
|
||||
}
|
||||
|
||||
VkImageView Image::InitializeImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags)
|
||||
VkImageView Image::InitializeImageView(
|
||||
VkImage image, VkFormat format, VkImageViewType imageViewType, VkImageAspectFlags aspectFlags, uint32_t layers)
|
||||
{
|
||||
VkImageView imageView;
|
||||
VkImageViewCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = image;
|
||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
createInfo.viewType = imageViewType;
|
||||
createInfo.format = format;
|
||||
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
@@ -62,13 +79,18 @@ namespace Copium
|
||||
createInfo.subresourceRange.baseMipLevel = 0;
|
||||
createInfo.subresourceRange.levelCount = 1;
|
||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||
createInfo.subresourceRange.layerCount = 1;
|
||||
createInfo.subresourceRange.layerCount = layers;
|
||||
CP_VK_ASSERT(vkCreateImageView(Vulkan::GetDevice(), &createInfo, nullptr, &imageView),
|
||||
"Failed to initialize image view");
|
||||
return imageView;
|
||||
}
|
||||
|
||||
void Image::TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout)
|
||||
void Image::TransitionImageLayout(VkImage image,
|
||||
VkFormat format,
|
||||
VkImageLayout oldLayout,
|
||||
VkImageLayout newLayout,
|
||||
uint32_t baseLayer,
|
||||
uint32_t layers)
|
||||
{
|
||||
CommandBufferScoped commandBuffer{};
|
||||
|
||||
@@ -81,8 +103,8 @@ namespace Copium
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = baseLayer;
|
||||
barrier.subresourceRange.layerCount = layers;
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = 0;
|
||||
|
||||
@@ -144,7 +166,8 @@ namespace Copium
|
||||
vkCmdPipelineBarrier(commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
void Image::CopyBufferToImage(const Buffer& buffer, VkImage image, uint32_t width, uint32_t height)
|
||||
void Image::CopyBufferToImage(
|
||||
const Buffer& buffer, VkImage image, uint32_t width, uint32_t height, uint32_t baseLayer, uint32_t layers)
|
||||
{
|
||||
CommandBufferScoped commandBuffer{};
|
||||
|
||||
@@ -155,8 +178,8 @@ namespace Copium
|
||||
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageSubresource.baseArrayLayer = baseLayer;
|
||||
region.imageSubresource.layerCount = layers;
|
||||
|
||||
region.imageOffset = {0, 0, 0};
|
||||
region.imageExtent = {width, height, 1};
|
||||
|
||||
@@ -20,9 +20,33 @@ namespace Copium
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkImage* image,
|
||||
VkDeviceMemory* imageMemory);
|
||||
static VkImageView InitializeImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags);
|
||||
static void TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||
static void CopyBufferToImage(const Buffer& buffer, VkImage image, uint32_t width, uint32_t height);
|
||||
static void InitializeImage(uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t layers,
|
||||
VkFormat format,
|
||||
VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkImage* image,
|
||||
VkDeviceMemory* imageMemory);
|
||||
|
||||
static VkImageView InitializeImageView(VkImage image,
|
||||
VkFormat format,
|
||||
VkImageViewType imageViewType,
|
||||
VkImageAspectFlags aspectFlags,
|
||||
uint32_t layers = 1);
|
||||
static void TransitionImageLayout(VkImage image,
|
||||
VkFormat format,
|
||||
VkImageLayout oldLayout,
|
||||
VkImageLayout newLayout,
|
||||
uint32_t baseLayer = 0,
|
||||
uint32_t layers = 1);
|
||||
static void CopyBufferToImage(const Buffer& buffer,
|
||||
VkImage image,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t baseLayer = 0,
|
||||
uint32_t layers = 1);
|
||||
static VkFormat SelectDepthFormat();
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
#include "copium/sampler/Texture2D.h"
|
||||
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "copium/core/Vulkan.h"
|
||||
#include "copium/sampler/Image.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
Texture2D::Texture2D(const MetaFile& metaFile)
|
||||
: Sampler{metaFile.GetMetaClass("Texture2D")}
|
||||
Texture2D::Texture2D(const MetaFileClass& metaClass)
|
||||
: Sampler{metaClass}
|
||||
{
|
||||
const std::string& filepath = metaFile.GetMetaClass("Texture2D").GetValue("filepath");
|
||||
const std::string& filepath = metaClass.GetValue("filepath");
|
||||
CP_DEBUG("Loading texture file: {}", filepath);
|
||||
InitializeTextureImageFromFile(filepath);
|
||||
}
|
||||
@@ -106,6 +105,7 @@ namespace Copium
|
||||
Image::CopyBufferToImage(stagingBuffer, image, width, height);
|
||||
Image::TransitionImageLayout(
|
||||
image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
imageView = Image::InitializeImageView(image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
imageView =
|
||||
Image::InitializeImageView(image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Copium
|
||||
int height;
|
||||
|
||||
public:
|
||||
Texture2D(const MetaFile& metaFile);
|
||||
Texture2D(const MetaFileClass& metaClass);
|
||||
Texture2D(const std::vector<uint8_t>& rgbaData, int width, int height, const SamplerCreator& samplerCreator);
|
||||
~Texture2D() override;
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
#include "copium/sampler/Texture2DArray.h"
|
||||
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "copium/core/Vulkan.h"
|
||||
#include "copium/sampler/Image.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
#define IMAGE_SIZE_BYTES (width * height * 4u)
|
||||
|
||||
Texture2DArray::Texture2DArray(const MetaFileClass& metaClass)
|
||||
: Sampler{metaClass},
|
||||
width{std::stoi(metaClass.GetValue("width"))},
|
||||
height{std::stoi(metaClass.GetValue("height"))},
|
||||
layers{std::stoi(metaClass.GetValue("layers"))}
|
||||
{
|
||||
InitializeTextureImage();
|
||||
}
|
||||
|
||||
Texture2DArray::Texture2DArray(const SamplerCreator& samplerCreator, int width, int height, int layers)
|
||||
: Sampler{samplerCreator},
|
||||
width{width},
|
||||
height{height},
|
||||
layers{layers}
|
||||
{
|
||||
InitializeTextureImage();
|
||||
}
|
||||
|
||||
Texture2DArray::~Texture2DArray()
|
||||
{
|
||||
VkImage imageCpy = image;
|
||||
VkDeviceMemory imageMemoryCpy = imageMemory;
|
||||
VkImageView imageViewCpy = imageView;
|
||||
Vulkan::GetDevice().QueueIdleCommand(
|
||||
[imageCpy, imageMemoryCpy, imageViewCpy]()
|
||||
{
|
||||
vkDestroyImage(Vulkan::GetDevice(), imageCpy, nullptr);
|
||||
vkFreeMemory(Vulkan::GetDevice(), imageMemoryCpy, nullptr);
|
||||
vkDestroyImageView(Vulkan::GetDevice(), imageViewCpy, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
VkDescriptorImageInfo Texture2DArray::GetDescriptorImageInfo(int index) const
|
||||
{
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.sampler = sampler;
|
||||
imageInfo.imageView = imageView;
|
||||
|
||||
return imageInfo;
|
||||
}
|
||||
|
||||
int Texture2DArray::GetWidth() const
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
int Texture2DArray::GetHeight() const
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
void Texture2DArray::InitializeTextureImage()
|
||||
{
|
||||
Image::InitializeImage(width,
|
||||
height,
|
||||
layers,
|
||||
VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
&image,
|
||||
&imageMemory);
|
||||
imageView = Image::InitializeImageView(
|
||||
image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, layers);
|
||||
|
||||
imageData.resize(width * height * layers * 4);
|
||||
for (int i = 0; i < layers; i++)
|
||||
{
|
||||
for (int j = 0; j < width * height; j++)
|
||||
{
|
||||
imageData[i * IMAGE_SIZE_BYTES + j * 4 + 0] = 255;
|
||||
imageData[i * IMAGE_SIZE_BYTES + j * 4 + 1] = 0;
|
||||
imageData[i * IMAGE_SIZE_BYTES + j * 4 + 2] = 255;
|
||||
imageData[i * IMAGE_SIZE_BYTES + j * 4 + 3] = 255;
|
||||
}
|
||||
}
|
||||
used.resize(layers, false);
|
||||
Update();
|
||||
}
|
||||
|
||||
size_t Texture2DArray::AddImage(const std::string& filePath)
|
||||
{
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
int texWidth;
|
||||
int texHeight;
|
||||
int texChannels;
|
||||
stbi_uc* pixels = stbi_load(filePath.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
|
||||
CP_ASSERT(pixels, "Failed to load texture image");
|
||||
CP_ASSERT(texWidth == width, "width={} of {} doesn't match width={} of Texture2DArray", texWidth, filePath, width);
|
||||
CP_ASSERT(
|
||||
texHeight == height, "height={} of {} doesn't match height={} of Texture2DArray", texHeight, filePath, height);
|
||||
return AddImage(pixels);
|
||||
}
|
||||
|
||||
size_t Texture2DArray::AddImage(const std::vector<uint8_t>& rgbaData)
|
||||
{
|
||||
CP_ASSERT(rgbaData.size() == width * height * 4,
|
||||
"Invalid rgbaData size. size = {}, but expected size is {}",
|
||||
rgbaData.size(),
|
||||
width * height * 4);
|
||||
return AddImage(rgbaData.data());
|
||||
}
|
||||
|
||||
size_t Texture2DArray::AddImage(const uint8_t* rgbaData)
|
||||
{
|
||||
for (int i = 0; i < used.size(); i++)
|
||||
{
|
||||
if (used[i])
|
||||
continue;
|
||||
|
||||
used[i] = true;
|
||||
for (int j = 0; j < width * height * 4; j++)
|
||||
{
|
||||
imageData[i * width * height * 4 + j] = rgbaData[j];
|
||||
}
|
||||
// TODO: Probably shouldn't run this every time an image is added (especially when initializing the Texture2DArray
|
||||
Update(i);
|
||||
return i;
|
||||
}
|
||||
|
||||
CP_ABORT("Texture2DArray is full");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Texture2DArray::RemoveImage(size_t index)
|
||||
{
|
||||
CP_ASSERT(index < layers, "index={} out of range of texture array with size={}", index, layers);
|
||||
CP_ASSERT(used[index], "index={} is not in use", index);
|
||||
|
||||
used[index] = false;
|
||||
}
|
||||
|
||||
void Texture2DArray::Update(uint32_t layer)
|
||||
{
|
||||
Buffer stagingBuffer{VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
IMAGE_SIZE_BYTES,
|
||||
1};
|
||||
void* data = stagingBuffer.Map();
|
||||
memcpy(data, imageData.data() + layer * IMAGE_SIZE_BYTES, IMAGE_SIZE_BYTES);
|
||||
stagingBuffer.Unmap();
|
||||
|
||||
Image::TransitionImageLayout(
|
||||
image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layer);
|
||||
Image::CopyBufferToImage(stagingBuffer, image, width, height, layer);
|
||||
Image::TransitionImageLayout(image,
|
||||
VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
layer);
|
||||
}
|
||||
|
||||
void Texture2DArray::Update()
|
||||
{
|
||||
Buffer stagingBuffer{VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
imageData.size(),
|
||||
1};
|
||||
void* data = stagingBuffer.Map();
|
||||
memcpy(data, imageData.data(), imageData.size());
|
||||
stagingBuffer.Unmap();
|
||||
|
||||
Image::TransitionImageLayout(
|
||||
image, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, layers);
|
||||
Image::CopyBufferToImage(stagingBuffer, image, width, height, 0, layers);
|
||||
Image::TransitionImageLayout(image,
|
||||
VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
0,
|
||||
layers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "copium/sampler/Sampler.h"
|
||||
#include "copium/util/Common.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
class Texture2DArray final : public Sampler
|
||||
{
|
||||
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2DArray);
|
||||
|
||||
private:
|
||||
VkImage image;
|
||||
VkDeviceMemory imageMemory;
|
||||
VkImageView imageView;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int layers;
|
||||
|
||||
std::vector<uint8_t> imageData;
|
||||
std::vector<bool> used;
|
||||
|
||||
public:
|
||||
Texture2DArray(const MetaFileClass& metaClass);
|
||||
Texture2DArray(const SamplerCreator& samplerCreator, int width, int height, int layers);
|
||||
~Texture2DArray() override;
|
||||
|
||||
size_t AddImage(const std::string& filePath);
|
||||
size_t AddImage(const std::vector<uint8_t>& rgbaData);
|
||||
void RemoveImage(size_t index);
|
||||
|
||||
void Update();
|
||||
void Update(uint32_t layer);
|
||||
|
||||
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override;
|
||||
|
||||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
|
||||
private:
|
||||
void InitializeTextureImage();
|
||||
size_t AddImage(const uint8_t* rgbaData);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "copium/util/Trace.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
template <typename First, typename Second>
|
||||
class Mapper
|
||||
{
|
||||
public:
|
||||
Mapper() = default;
|
||||
|
||||
Mapper(const std::map<First, Second>& map)
|
||||
{
|
||||
for (const auto& [first, second] : map)
|
||||
{
|
||||
Emplace(first, second);
|
||||
}
|
||||
}
|
||||
|
||||
void Emplace(const First& first, const Second& second)
|
||||
{
|
||||
CP_ASSERT(secondToFirst.count(second) == 0, "Duplicate second key={}", second);
|
||||
|
||||
firstToSecond.emplace(first, second);
|
||||
secondToFirst.emplace(second, first);
|
||||
}
|
||||
|
||||
Second& operator[](const First& first)
|
||||
{
|
||||
return firstToSecond[first];
|
||||
}
|
||||
|
||||
void Erase(const First& first)
|
||||
{
|
||||
auto it = firstToSecond.find(first);
|
||||
CP_ASSERT(it != firstToSecond.end(), "First key={} not found in Mapper", first);
|
||||
|
||||
const auto& second = it->second;
|
||||
secondToFirst.erase(second);
|
||||
firstToSecond.erase(first);
|
||||
}
|
||||
|
||||
void Erase(const Second& second)
|
||||
{
|
||||
auto it = secondToFirst.find(second);
|
||||
CP_ASSERT(it != secondToFirst.end(), "Second key={} not found in Mapper", second);
|
||||
|
||||
const auto& first = it->second;
|
||||
secondToFirst.erase(first);
|
||||
firstToSecond.erase(second);
|
||||
}
|
||||
|
||||
const Second& GetSecond(const First& first) const
|
||||
{
|
||||
auto it = firstToSecond.find(first);
|
||||
CP_ASSERT(it != firstToSecond.end(), "First key={} not found in Mapper", first);
|
||||
}
|
||||
|
||||
const First& GetFirst(const Second& second) const
|
||||
{
|
||||
auto it = secondToFirst.find(second);
|
||||
CP_ASSERT(it != secondToFirst.end(), "Second key={} not found in Mapper", second);
|
||||
}
|
||||
|
||||
bool HasSecond(const First& first) const
|
||||
{
|
||||
return firstToSecond.find(first) != firstToSecond.end();
|
||||
}
|
||||
|
||||
bool HasFirst(const Second& second) const
|
||||
{
|
||||
return secondToFirst.find(second) != secondToFirst.end();
|
||||
}
|
||||
|
||||
typename std::map<First, Second>::const_iterator FindSecond(const First& first) const
|
||||
{
|
||||
return firstToSecond.find(first);
|
||||
}
|
||||
|
||||
typename std::map<Second, First>::const_iterator FindFirst(const Second& second) const
|
||||
{
|
||||
return secondToFirst.find(second);
|
||||
}
|
||||
|
||||
typename std::map<First, Second>::iterator begin()
|
||||
{
|
||||
return firstToSecond.begin();
|
||||
}
|
||||
|
||||
typename std::map<First, Second>::iterator end()
|
||||
{
|
||||
return firstToSecond.end();
|
||||
}
|
||||
|
||||
typename std::map<First, Second>::const_iterator begin() const
|
||||
{
|
||||
return firstToSecond.cbegin();
|
||||
}
|
||||
|
||||
typename std::map<First, Second>::const_iterator end() const
|
||||
{
|
||||
return firstToSecond.cend();
|
||||
}
|
||||
|
||||
typename std::map<First, Second>::const_iterator cbegin() const
|
||||
{
|
||||
return firstToSecond.cbegin();
|
||||
}
|
||||
|
||||
typename std::map<First, Second>::const_iterator cend() const
|
||||
{
|
||||
return firstToSecond.cend();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<First, Second> firstToSecond;
|
||||
std::map<Second, First> secondToFirst;
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
namespace copium
|
||||
namespace Copium
|
||||
{
|
||||
template <typename State, typename Trigger>
|
||||
class StateMachine
|
||||
|
||||
Reference in New Issue
Block a user