Files
Vibe-HD-2D/engine/include/hd2d/Billboard.h
Gabrieal Jimmy 83a1f16806 Sprite sheets, atlases, game UI, time of day, weather presets, headless captures
- 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)
2026-10-02 15:05:23 -05:00

70 lines
3.0 KiB
C++

#pragma once
#include "hd2d/GL.h"
#include "hd2d/Texture.h"
#include <glm/glm.hpp>
#include <vector>
namespace hd2d {
// One upright pixel-art sprite. `pos` is where the feet (pivot) row touches
// the ground; sprites face the camera around the Y axis. 64 bytes, read by
// billboard.vert as four vec4 attributes (keep both in sync).
//
// A default-initialised instance draws the whole texture, planted by its
// lowest opaque row. Set `uv` to draw one frame of a sprite sheet / atlas
// cell (see Texture::cellUV, SpriteAtlas::uv) and `anchor` to that frame's
// feet row (Texture::cellAnchor, SpriteAtlas::anchor).
struct BillboardInstance {
glm::vec3 pos{0.0f};
float sway = 0.0f; // wind / player-push response (0 = rigid)
glm::vec2 size{1.0f}; // world size of the `uv` sub-rect quad
float flip = 0.0f; // 1 = mirror horizontally (inside the sub-rect)
float tint = 1.0f; // brightness multiplier (breaks up repetition)
glm::vec4 uv{0, 0, 1, 1}; // texture sub-rect (minU, minV, maxU, maxV), GL orientation (v = 0 is the image bottom)
float anchor = -1.0f; // texture-space v of the feet (pivot) row; < 0 = use tex().opaqueBounds().y
float turn = 0.0f; // extra yaw (radians) away from camera-facing; color pass only, shadow cards stay sun-facing
float alpha = 1.0f; // 0..1 fade, dithered discard in color and shadow passes (no blending)
float flash = 0.0f; // 0..1 blend toward bright emissive white (hit / capture flash)
};
// Instanced batch of billboards sharing one texture: its own `texture`, or
// `sharedTexture` (e.g. a SpriteAtlas page shared by many batches) when set.
class BillboardBatch {
public:
BillboardBatch() = default;
BillboardBatch(const BillboardBatch&) = delete;
BillboardBatch& operator=(const BillboardBatch&) = delete;
~BillboardBatch();
bool loadTexture(const std::string& path) { return texture.load(path); }
void upload(); // call after editing `instances`
void draw() const;
// Texture the renderer binds: `sharedTexture` if set, else `texture`.
const Texture& tex() const { return sharedTexture ? *sharedTexture : texture; }
// World size that keeps the own `texture` at `pixelsPerUnit` texel density.
glm::vec2 sizeForDensity(float pixelsPerUnit) const {
return glm::vec2(texture.size()) / pixelsPerUnit;
}
// World size of one `cellPixels` sheet frame / atlas cell at `pixelsPerUnit`.
static glm::vec2 cellSize(glm::ivec2 cellPixels, float pixelsPerUnit) {
return glm::vec2(cellPixels) / pixelsPerUnit;
}
Texture texture;
const Texture* sharedTexture = nullptr; // not owned; must outlive the batch's use
std::vector<BillboardInstance> instances;
bool castShadows = true;
bool inReflections = true;
float emissive = 0.0f; // unlit contribution, for glowing sprites
private:
GLuint vao_ = 0, vbo_ = 0;
size_t capacity_ = 0;
GLsizei count_ = 0;
};
} // namespace hd2d