#pragma once #include "hd2d/GL.h" #include "hd2d/Texture.h" #include #include 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 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