#pragma once #include "hd2d/GL.h" #include #include #include namespace hd2d { struct Image { int width = 0, height = 0; std::vector rgba; // row 0 = bottom (GL convention) }; // Loads an RGBA8 image flipped to GL orientation. Colors of fully transparent // pixels are replaced with their nearest opaque neighbour so that filtering // never bleeds dark fringes into sprite edges. bool loadImage(const std::string& path, Image& out); // Decodes PNG bytes from memory. glTF images use flipY = false (their UV // origin is top-left, which matches GL when rows are uploaded unflipped). bool decodeImage(const unsigned char* data, size_t size, Image& out, bool flipY); // sRGB pixel-art texture. Sampled with "sharp bilinear" in shaders, so it uses // linear filtering with mipmaps rather than GL_NEAREST. class Texture { public: Texture() = default; Texture(const Texture&) = delete; Texture& operator=(const Texture&) = delete; Texture(Texture&& o) noexcept { *this = std::move(o); } Texture& operator=(Texture&& o) noexcept; ~Texture(); bool load(const std::string& path, bool repeat = false); bool create(const Image& image, bool repeat = false, float anisotropy = 1.0f); void bind(GLuint unit) const { glBindTextureUnit(unit, id_); } GLuint id() const { return id_; } glm::ivec2 size() const { return {width_, height_}; } // UV-space rectangle (minX, minY, maxX, maxY) of pixels with alpha >= 128. // Billboards use minY to plant the visible feet on the ground. glm::vec4 opaqueBounds() const { return opaqueBounds_; } private: GLuint id_ = 0; int width_ = 0, height_ = 0; glm::vec4 opaqueBounds_{0, 0, 1, 1}; }; // 2D array of equally sized sRGB layers (terrain materials). class TextureArray { public: TextureArray() = default; TextureArray(const TextureArray&) = delete; TextureArray& operator=(const TextureArray&) = delete; ~TextureArray(); bool load(const std::vector& paths); void bind(GLuint unit) const { glBindTextureUnit(unit, id_); } glm::ivec2 size() const { return {width_, height_}; } int layers() const { return layers_; } private: GLuint id_ = 0; int width_ = 0, height_ = 0, layers_ = 0; }; } // namespace hd2d