refactor(render): TextBackend owns its atlas, and staged glyphs carry a rotation basis
This commit is contained in:
1 parent
90e17a0a11
commit
e074f57ddf
23 files changed
+1073
-227
No files matched your search
@@ -6,7 +6,6 @@
|
||||
#include <plot/core/rect.hpp>
|
||||
#include <plot/core/status.hpp>
|
||||
#include <plot/core/types.hpp>
|
||||
#include <plot/gl/handle.hpp>
|
||||
#include <plot/math/vec2.hpp>
|
||||
#include <plot/plot/plot.hpp>
|
||||
#include <plot/render/bitmap_font.hpp>
|
||||
@@ -14,6 +13,7 @@
|
||||
#include <plot/render/primitives.hpp>
|
||||
#include <plot/render/program.hpp>
|
||||
#include <plot/render/style.hpp>
|
||||
#include <plot/render/text_atlas.hpp>
|
||||
#include <plot/render/vertex_array.hpp>
|
||||
|
||||
namespace plot {
|
||||
@@ -70,7 +70,7 @@ class Renderer {
|
||||
Renderer(const Renderer&) = delete;
|
||||
Renderer& operator=(const Renderer&) = delete;
|
||||
|
||||
/// Compiles both programs, builds the glyph atlas and allocates the vertex
|
||||
/// Compiles both programs, uploads the font's atlas and allocates the vertex
|
||||
/// buffers. The calling thread must have the context current and
|
||||
/// `plot::gl::load()` must have succeeded, otherwise the returned `Status` is
|
||||
/// `Unsupported`; anything the driver refuses is `GLFailure` plus its log.
|
||||
@@ -114,13 +114,17 @@ class Renderer {
|
||||
/// vertex array 0, program 0, `GL_ARRAY_BUFFER` 0, texture unit 0 active and
|
||||
/// nothing bound to `GL_TEXTURE_2D` on it, blending off, scissoring off, and the
|
||||
/// viewport left at the frame's rect (the caller sets its own for the next pass).
|
||||
/// Two pieces of global state the frame *changed* are handed back rather than
|
||||
/// left where the frame wanted them: `GL_UNPACK_ALIGNMENT`, which `init()` set
|
||||
/// to 1 for the glyph atlas' single-channel rows, and the clear colour, which is
|
||||
/// The one piece of global state the frame *changed* is handed back rather than
|
||||
/// left where the frame wanted it: the clear colour, which is
|
||||
/// `style().background` only for the duration of the frame. GL keeps no history
|
||||
/// for the clear colour, so the host's value is queried on the first
|
||||
/// `begin_frame()`; that first value is what comes back here, so a colour the
|
||||
/// host changes after the first frame is restored over by it.
|
||||
/// for it, so the host's value is queried on the first `begin_frame()`; that
|
||||
/// first value is what comes back here, so a colour the host changes after the
|
||||
/// first frame is restored over by it.
|
||||
///
|
||||
/// `GL_UNPACK_ALIGNMENT` is deliberately not in that list any more: the atlas
|
||||
/// upload needs it at 1 for single-channel rows, and `render::TextAtlas` saves
|
||||
/// and restores it around every upload it performs, so no frame -- initial or
|
||||
/// mid-run -- leaves it moved for the host's own uploads to inherit.
|
||||
/// The framebuffer binding is never touched -- it is the caller's, and so is the
|
||||
/// pixel-pack alignment if `dump_frame_ppm()` ran.
|
||||
void end_frame() noexcept;
|
||||
@@ -176,19 +180,40 @@ class Renderer {
|
||||
/// by whole multiples of its cell only -- anything else lands a 1-bit glyph's
|
||||
/// strokes unevenly -- so `reset()` picks the multiple nearest the requested
|
||||
/// size.
|
||||
///
|
||||
/// It is also the backend the renderer uploads the atlas from, so it forwards
|
||||
/// the whole interface: the metrics and the glyph bearings and advances are
|
||||
/// scaled, while the artwork itself -- the atlas bytes, its size and its
|
||||
/// revision -- is the font's own and passes through untouched.
|
||||
class AxisFont final : public render::TextBackend {
|
||||
public:
|
||||
void reset(const render::BitmapFont& font, f32 requested_px) noexcept;
|
||||
f32 measure(const char* utf8) const override;
|
||||
f32 height() const override;
|
||||
f32 ascent() const override;
|
||||
/// The font's glyph at this wrapper's scale: the atlas rect is unchanged (it
|
||||
/// is scale-free) and the bearing and advance are multiplied by it, so one
|
||||
/// `Glyph` describes the glyph this backend draws. The result lives in the
|
||||
/// wrapper until the next call, which is enough for a caller measuring or
|
||||
/// laying out one glyph at a time.
|
||||
const render::Glyph* glyph(u32 codepoint) const override;
|
||||
const u8* atlas_pixels() const override;
|
||||
u32 atlas_width() const override;
|
||||
u32 atlas_height() const override;
|
||||
u32 revision() const override;
|
||||
/// On-screen size of one glyph cell, in pixels.
|
||||
f32 cell_px() const noexcept { return cell_px_; }
|
||||
/// On-screen pixels per font pixel: the factor `measure()` and `glyph()` are
|
||||
/// scaled by, and what `TextBatch::add_text` is handed as its size.
|
||||
f32 scale() const noexcept { return scale_; }
|
||||
|
||||
private:
|
||||
const render::BitmapFont* font_ = nullptr;
|
||||
f32 cell_px_ = 1.0f;
|
||||
f32 scale_ = 1.0f;
|
||||
/// `glyph()`'s scaled result, returned by pointer because the interface is
|
||||
/// `const Glyph*` and the scale is the one thing this wrapper adds.
|
||||
mutable render::Glyph scaled_{};
|
||||
};
|
||||
|
||||
/// One axis pair's data -> pixel mapping, already shifted so the viewport's
|
||||
@@ -254,7 +279,7 @@ class Renderer {
|
||||
AxisFont font_backend_;
|
||||
render::Style style_;
|
||||
|
||||
gl::Texture atlas_;
|
||||
render::TextAtlas atlas_;
|
||||
render::LineProgram line_program_;
|
||||
render::TextProgram text_program_;
|
||||
render::LineVertexArray line_vao_;
|
||||
@@ -265,9 +290,6 @@ class Renderer {
|
||||
std::vector<f32> gather_; ///< scratch for one gathered window, re-used
|
||||
mutable std::vector<u8> readback_; ///< dump_frame_ppm's row buffer
|
||||
|
||||
/// The host's `GL_UNPACK_ALIGNMENT`, saved by `init()` before the atlas upload
|
||||
/// set it to 1 and handed back by `end_frame()`. GL's default is 4.
|
||||
gl::GLint host_unpack_alignment_ = 4;
|
||||
/// The host's `GL_COLOR_CLEAR_VALUE`, queried on the first `begin_frame()` (GL
|
||||
/// has no other way to recover it once the frame has set it) and handed back by
|
||||
/// `end_frame()`.
|
||||
|
||||
Reference in new issue
Block a user