- BillboardInstance: per-instance uv sub-rect, feet anchor, turn, dithered alpha, flash; BillboardBatch::sharedTexture; Texture createEmpty/update/cellUV/cellAnchor/nearest - SpriteAtlas: fixed-cell runtime atlas with gutters - hd2d::ui: Octopath-style panels, fonts (Cinzel, EB Garamond), dialogue box with typewriter + portraits + choices, menus, nameplates, toasts, ImGui theme - DayCycle (dawn/day/dusk/night keyframes, sun + moon arcs), Weather overcast/mist/ lightning, night-aware presets, stars and moon in the sky - Hidden-window offscreen captures (Window visible=false, Renderer output FBO, OffscreenTarget); --screenshot never opens a window - Camera::worldToScreen; CMake usable via add_subdirectory (HD2D_BUILD_DEMO, HD2D_ENGINE_ASSET_DIR)
87 lines
3.6 KiB
C++
87 lines
3.6 KiB
C++
#pragma once
|
|
#include "hd2d/GL.h"
|
|
|
|
#include <glm/glm.hpp>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace hd2d {
|
|
|
|
struct Image {
|
|
int width = 0, height = 0;
|
|
std::vector<unsigned char> 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);
|
|
// Replaces the colors of fully transparent pixels with their nearest opaque
|
|
// neighbour (loadImage/decodeImage already do this). Call it on images you
|
|
// compose yourself so filtering never bleeds dark fringes into edges.
|
|
void bleedTransparentColors(Image& img);
|
|
|
|
// sRGB pixel-art texture. Sampled with "sharp bilinear" in shaders, so it uses
|
|
// linear filtering with mipmaps rather than GL_NEAREST. `nearest` = GL_NEAREST
|
|
// without mips instead (crisp ImGui previews of pixel art).
|
|
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 nearest = false);
|
|
bool create(const Image& image, bool repeat = false, float anisotropy = 1.0f, bool nearest = false);
|
|
// Fully transparent w x h texture (sRGB RGBA8, mipmapped, clamped) to fill with update().
|
|
bool createEmpty(int w, int h);
|
|
// Uploads `img` with its bottom-left pixel at (x, y) (GL orientation,
|
|
// y = 0 is the bottom row) and regenerates the mips. Does not change
|
|
// opaqueBounds(), which always describes the image given to create().
|
|
void update(int x, int y, const Image& img);
|
|
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_; }
|
|
|
|
// Grid sprite sheets authored top-down (row 0 = top row of the PNG), with
|
|
// `cell` x `cell` pixel frames. cellUV is a BillboardInstance::uv rect;
|
|
// cellAnchor is a BillboardInstance::anchor: the v of the bottom edge of
|
|
// pixel row `feetRowFromCellTop` (0 = the cell's top row) of that cell.
|
|
static glm::vec4 cellUV(glm::ivec2 texSize, glm::ivec2 cell, int col, int rowFromTop);
|
|
static float cellAnchor(glm::ivec2 texSize, glm::ivec2 cell, int rowFromTop, int feetRowFromCellTop);
|
|
|
|
private:
|
|
GLuint id_ = 0;
|
|
int width_ = 0, height_ = 0, levels_ = 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<std::string>& 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
|