#pragma once #include #include #include namespace plot::render { /// Per-instance payload of the line pipeline: one segment in data space. It /// mirrors the interleaved floats `LineBatch::data()` produces, which is why the /// attribute offsets in vertex_array.cpp come from `offsetof` rather than from /// hand-written numbers. struct LineInstance { f32 x0; f32 y0; f32 x1; f32 y1; }; /// Per-instance payload of the text pipeline: the glyph quad's top-left corner /// in Rect pixels plus the glyph's atlas texel origin. struct TextInstance { f32 x; f32 y; f32 u; f32 v; }; static_assert(sizeof(LineInstance) == 4 * sizeof(f32), "line instance must stay 4 floats"); static_assert(sizeof(TextInstance) == 4 * sizeof(f32), "text instance must stay 4 floats"); namespace detail { /// The growth half of an instance buffer, shared by both pipelines so neither /// duplicates the GL ownership or the "grow only when the frame needs it" rule. class InstanceStore { public: /// Creates the vertex buffer. Reports `ErrorCode::Unsupported` while the GL /// entry points are unresolved, `GLFailure` if the driver hands out no name. bool create(Status* st = nullptr) noexcept; /// Uploads `count` instances of `instance_bytes`. The store only reallocates /// when the frame's workload outgrows it, so steady-state frames write into /// the existing allocation. void upload(const void* data, u32 count, usize instance_bytes) noexcept; void bind() const noexcept { buffer_.bind(); } private: gl::Buffer buffer_; u32 capacity_ = 0; ///< instances the store can hold }; } // namespace detail /// Instance buffer of the line pipeline: one `LineInstance` per segment. class LineBuffer { public: bool create(Status* st = nullptr) noexcept { return store_.create(st); } void upload(const f32* interleaved, u32 count) noexcept { store_.upload(interleaved, count, sizeof(LineInstance)); } void bind() const noexcept { store_.bind(); } private: detail::InstanceStore store_; }; /// Instance buffer of the text pipeline: one `TextInstance` per glyph. class TextBuffer { public: bool create(Status* st = nullptr) noexcept { return store_.create(st); } void upload(const f32* interleaved, u32 count) noexcept { store_.upload(interleaved, count, sizeof(TextInstance)); } void bind() const noexcept { store_.bind(); } private: detail::InstanceStore store_; }; } // namespace plot::render