92 lines
3.4 KiB
C++
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
|