| 1 |
#ifndef PLOTTER_PAPER_HH |
| 2 |
#define PLOTTER_PAPER_HH |
| 3 |
|
| 4 |
#include "GLUtil.hh" |
| 5 |
#include "MemBuffer.hh" |
| 6 |
#include "gl_vec.hh" |
| 7 |
|
| 8 |
#include <algorithm> |
| 9 |
#include <cassert> |
| 10 |
#include <span> |
| 11 |
#include <utility> |
| 12 |
|
| 13 |
namespace openmsx { |
| 14 |
|
| 15 |
using GrayPixel = uint8_t; |
| 16 |
using RgbPixel = gl::vecN<3, uint8_t>; |
| 17 |
|
| 18 |
template<typename T> class Canvas |
| 19 |
{ |
| 20 |
public: |
| 21 |
Canvas(gl::ivec2 size, T init_value = T{}) |
| 22 |
: pixels(size_t(size.x) * size.y) |
| 23 |
, sz(size) |
| 24 |
{ |
| 25 |
std::ranges::fill(pixels, init_value); |
| 26 |
} |
| 27 |
|
| 28 |
[[nodiscard]] gl::ivec2 size() const { return sz; } |
| 29 |
|
| 30 |
|
| 31 |
[[nodiscard]] std::span<T> getLine(int y) { |
| 32 |
assert(y >= 0 && y < sz.y); |
| 33 |
return std::span<T>(pixels.data() + y * sz.x, sz.x); |
| 34 |
} |
| 35 |
[[nodiscard]] std::span<const T> getLine(int y) const { |
| 36 |
assert(y >= 0 && y < sz.y); |
| 37 |
return std::span<const T>(pixels.data() + y * sz.x, sz.x); |
| 38 |
} |
| 39 |
|
| 40 |
private: |
| 41 |
MemBuffer<T> pixels; |
| 42 |
gl::ivec2 sz; |
| 43 |
}; |
| 44 |
|
| 45 |
struct BoundingBox { |
| 46 |
void clear() { tl = gl::ivec2{0}; br = gl::ivec2{0}; } |
| 47 |
[[nodiscard]] bool empty() const { return br.x <= tl.x || br.y <= tl.y; } |
| 48 |
[[nodiscard]] gl::ivec2 size() const { return br - tl; } |
| 49 |
|
| 50 |
[[nodiscard]] static BoundingBox merge(const BoundingBox& a, const BoundingBox& b) { |
| 51 |
if (a.empty()) return b; |
| 52 |
if (b.empty()) return a; |
| 53 |
return {.tl = min(a.tl, b.tl), .br = max(a.br, b.br)}; |
| 54 |
} |
| 55 |
|
| 56 |
gl::ivec2 tl{}; |
| 57 |
gl::ivec2 br{}; |
| 58 |
}; |
| 59 |
|
| 60 |
class PlotterPaper |
| 61 |
{ |
| 62 |
public: |
| 63 |
explicit PlotterPaper(gl::ivec2 size); |
| 64 |
|
| 65 |
[[nodiscard]] gl::ivec2 size() const { return paper.size(); } |
| 66 |
[[nodiscard]] bool empty() const { return !anythingPlotted; } |
| 67 |
|
| 68 |
void draw_dot(gl::vec2 pos, float radius, gl::vec3 color); |
| 69 |
void draw_motion(gl::vec2 from, gl::vec2 to, float radius, gl::vec3 color); |
| 70 |
|
| 71 |
[[nodiscard]] Canvas<RgbPixel> getRGB() const; |
| 72 |
gl::Texture& updateTexture(gl::ivec2 targetSize); |
| 73 |
|
| 74 |
private: |
| 75 |
Canvas<gl::vec3> paper; |
| 76 |
|
| 77 |
gl::Texture texture{gl::Null{}}; |
| 78 |
gl::ivec2 texSize; |
| 79 |
BoundingBox damage; |
| 80 |
|
| 81 |
bool anythingPlotted = false; |
| 82 |
}; |
| 83 |
|
| 84 |
} |
| 85 |
|
| 86 |
#endif |