vulkan-project/texture_atlas.hpp
2022-10-14 20:58:20 +02:00

92 lines
3.4 KiB
C++

#pragma once
#include <glm/glm.hpp>
#include <vulkan/vulkan_core.h>
#include <vector>
#include <string>
#include <set>
namespace gz::vk {
/**
* @brief Describes an area in the textureImage that is not in use
*/
struct TextureImageArea {
// topleft slot
uint16_t x;
uint16_t y;
// in slots
uint16_t width;
uint16_t height;
std::string toString() const;
};
/// strict weak ordering comparison, true if a < b
inline auto freeAreaCmp = [](const TextureImageArea& a, const TextureImageArea& b) {
// if a size < b size
if (a.width * a.height < b.width * b.height) { return true; }
if (a.width * a.height != b.width * b.height) { return false; }
// if a size == b size, return true if a is toplefter
if (a.x + a.y < b.x + b.y) { return true; }
if (a.x + a.y != b.x + b.y) { return false; }
// if both are same topleft return if a is lefter
return a.x < b.x;
};
/// Defined in vulkan_instance.hpp
class VulkanInstance;
class TextureAtlas {
public:
/**
* @brief Create a texture atlas
* @details
* -# @ref VulkanInstance::registerCleanupCallback "register" @ref cleanup() "cleanup callback"
* -# @ref createImageResources "create texture image, view and sampler"
*
* The textureImage will have the dimensions slotWidth * slotCountX, slotHeight * slotCountY
*/
TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_t slotHeight, uint16_t slotCountX, uint16_t slotCountY);
/**
* @brief Add a texture to the atlas
* @param textureWidth Width in pixels
* @param textureHeight Height in pixels
* @returns The topleft and bottomright texture coordinates in the image of the atlas
* @throws Exception when there is no space in the atlas to add the texture
*/
std::pair<glm::vec2, glm::vec2> addTexture(uint8_t* pixels, uint16_t textureWidth, uint16_t textureHeight);
const VkImageView& getTextureImageView() const { return textureImageView; }
const VkSampler& getTextureSampler() const { return textureSampler; }
std::string toString() const;
private:
VulkanInstance& vk;
/**
* @brief Destroy all vulkan objects owned by this object
*/
void cleanup();
void blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t slotY, uint16_t textureWidth, uint16_t textureHeight);
/**
* @brief Create textureImage, textureImageView and textureSampler
* @details
* the textureImage is created with missingTextureColor and then transitioned to SHADER_READ_ONLY_OPTIMAL layout.
*/
void createImageResources();
VkImage textureImage;
VkDeviceMemory textureImageMemory;
VkImageView textureImageView;
VkSampler textureSampler;
std::set<TextureImageArea, decltype(freeAreaCmp)> freeAreas;
/**
* @todo implement merge
*/
void mergeFreeAreas();
uint16_t slotWidth;
uint16_t slotHeight;
uint16_t slotCountX;
uint16_t slotCountY;
};
} // namespace gz::vk