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:
Thraix
2026-07-08 01:08:45 +02:00
parent 72c2bb5336
commit e9fcb18b73
22 changed files with 461 additions and 55 deletions
+2
View File
@@ -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;
+7 -3
View File
@@ -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();
+1 -1
View File
@@ -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();
+2 -1
View File
@@ -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);
}
}
+2
View File
@@ -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");
+9 -12
View File
@@ -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);
+1 -1
View File
@@ -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);
}
}
}
+5 -4
View File
@@ -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);
}
}
+1 -1
View File
@@ -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;
+33 -10
View File
@@ -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};
+27 -3
View File
@@ -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);
}
}
+1 -1
View File
@@ -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);
};
}
+122
View File
@@ -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;
};
}
+1 -1
View File
@@ -3,7 +3,7 @@
#include <functional>
#include <map>
namespace copium
namespace Copium
{
template <typename State, typename Trigger>
class StateMachine