69 lines
5.0 KiB
Markdown
69 lines
5.0 KiB
Markdown
# Architecture
|
|
|
|
`plot` is one library, `plot_core`, plus optional adapter targets. The public headers are
|
|
grouped into seven directories, and the umbrella header `include/plot/plot.hpp` includes
|
|
them in this order:
|
|
|
|
```
|
|
core / math → gl → data → render → plot → input
|
|
```
|
|
|
|
with the host adapters (`adapters/glfw`, `adapters/imgui`, `adapters/qt6`, `adapters/gtk4`)
|
|
built on top. This page says what each layer owns and the rules the build enforces.
|
|
|
|
## What each layer owns
|
|
|
|
| layer | directory | owns |
|
|
|---|---|---|
|
|
| `core` | `include/plot/core/`, `src/core/` | the vocabulary: `f32`/`f64`/`u32`/`usize`, `kInvalid`, `Range`, `Rect`, `Color`, `Span`, and `Status`/`ErrorCode` for fallible operations. |
|
|
| `math` | `include/plot/math/`, `src/math/` | `Vec2`, `Mat3`, and `Transform` — the data↔pixel affine mapping, including the log-axis handling and its invertibility guarantee. |
|
|
| `gl` | `include/plot/gl/`, `src/gl/` | a hand-written OpenGL surface: enumerator typedefs, the entry-point table `plot::gl::load()` fills, `plot::gl::caps()`, and the move-only RAII wrappers (`gl::Buffer`, `VertexArray`, `Program`, `Texture`, `Framebuffer`, `Fence`). No GL loader library is used. |
|
|
| `data` | `include/plot/data/`, `src/data/` | the sample stores: the `Series` interface, `ArraySeries`, `StreamSeries`, `RingBuffer`, and the min/max LOD `MinMaxPyramid`. |
|
|
| `render` | `include/plot/render/`, `src/render/` | presentation: `Style`, the `Renderer`, the text machinery (`TextBackend`, `TextAtlas`, `EmbeddedMonoFont`), and the shader/program/buffer/vertex-array primitives. |
|
|
| `plot` | `include/plot/plot/`, `src/plot/` | the scene model: `Plot`, `Figure`, and the primitives they own — `Axis`, `Trace`, `Cursor`, `Region`, `Measure`, `Legend`, `Crosshair`, `Annotation`, `Grid`, `Ticks`. Pure CPU state, no GL. |
|
|
| `input` | `include/plot/input/`, `src/input/` | `Controller` and the host-neutral event types (`PointerEvent`, `WheelEvent`, `KeyEvent`); turns events into gestures. |
|
|
| adapters | `adapters/*/` | one per host: they own the window/context/event loop and translate their toolkit's events into `input` events. |
|
|
|
|
## The dependency rules
|
|
|
|
- **`plot_core` is third-party-free.** Its `CMakeLists.txt` links only
|
|
`${CMAKE_DL_LIBS}`, and the public headers under `include/plot/` include no third-party
|
|
header. The one exception is the optional `plot::font_ttf` target, which compiles the
|
|
vendored `third_party/stb_truetype.h` (stb_truetype v1.26, public domain) in its own
|
|
object library `plot_stb_truetype`, whose include directory is `PRIVATE` — so nothing
|
|
else in the build, and no consumer, can reach it by accident. `PLOT_BUILD_TTF_FONT`
|
|
defaults to on exactly when the vendored header is present.
|
|
- **Every public header compiles standalone, and `plot.hpp` includes every one of them.**
|
|
`tests/CMakeLists.txt` generates one translation unit per header (globbed, so a new
|
|
header is picked up automatically), builds an umbrella TU, and registers ctest cases
|
|
(`plot_headers_self_contained`, `plot_umbrella_covers_public_headers`,
|
|
`plot_umbrella_check`) that fail the build if either rule breaks.
|
|
- **The umbrella stops at the library.** It never includes an adapter header, so
|
|
`#include <plot/plot.hpp>` cannot drag in GLFW, ImGui, Qt or GTK. The adapter headers are
|
|
reached as `<glfw/glfw_host.hpp>`, `<imgui/imgui_plot.hpp>`, `<qt6/qt_plot_widget.hpp>`
|
|
and `<gtk4/gtk_plot_area.hpp>`.
|
|
- **The renderer never owns the context or the event loop.** `Renderer` never creates,
|
|
binds or resizes a framebuffer: `begin_frame(fb_w, fb_h, viewport_px)` draws into
|
|
whatever framebuffer is bound, clears exactly the given rectangle (scissored, so a host
|
|
that painted the rest of its surface keeps it), and `end_frame()` turns the GL state it
|
|
moved back off. The renderer also never sees a pointer, a button or a modifier — it draws
|
|
the handles the plot reports as hot, and only a host that drives the plot with an
|
|
`input::Controller` ever makes anything hot. Owning the window, the context and the loop
|
|
is the adapter's job (or, for a library user, the application's).
|
|
|
|
One direction is worth stating precisely, because it is the one place the layer order is
|
|
not a strict include chain: `Renderer` (in `render/`) includes `plot/plot.hpp` and
|
|
`plot/figure.hpp`, because drawing *is* being handed a `Plot` or a `Figure` to draw. The
|
|
`plot` layer names only `render`'s value types — `render::Style` and
|
|
`render::TextBackend` — and never names `Renderer`. So the runtime direction is
|
|
"the renderer knows the plot, the plot does not know the renderer".
|
|
|
|
## The design record
|
|
|
|
The specifications and implementation plans — the requirements, the numbered spec sections
|
|
this documentation sometimes refers to, and the reasoning behind decisions — live under
|
|
[`docs/superpowers/`](superpowers/) (`specs/` and `plans/`). That tree is the project's
|
|
design record, not user documentation: it is where a decision is argued, not where the
|
|
library is explained. This `docs/` guide and [docs/coverage.md](coverage.md) are the
|
|
user-facing documents.
|