feat: project skeleton, core types and math with transform tests
This commit is contained in:
1 parent
e4051bc6b5
commit
8a7e9e97f8
21 files changed
+515
-2
No files matched your search
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
namespace plot {
|
||||
|
||||
/// RGBA colour with components in [0,1].
|
||||
struct Color {
|
||||
f32 r = 0.0f;
|
||||
f32 g = 0.0f;
|
||||
f32 b = 0.0f;
|
||||
f32 a = 1.0f;
|
||||
|
||||
/// Build from a packed 0xRRGGBB literal, with an optional alpha override.
|
||||
static constexpr Color hex(u32 rgb, f32 alpha = 1.0f) noexcept {
|
||||
constexpr f32 kInv255 = 1.0f / 255.0f;
|
||||
return Color{static_cast<f32>((rgb >> 16) & 0xFFu) * kInv255,
|
||||
static_cast<f32>((rgb >> 8) & 0xFFu) * kInv255,
|
||||
static_cast<f32>(rgb & 0xFFu) * kInv255, alpha};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace plot
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
namespace plot {
|
||||
|
||||
/// Axis-aligned rectangle in pixels, origin at the top-left.
|
||||
struct Rect {
|
||||
f32 x = 0.0f;
|
||||
f32 y = 0.0f;
|
||||
f32 w = 0.0f;
|
||||
f32 h = 0.0f;
|
||||
|
||||
constexpr f32 right() const noexcept { return x + w; }
|
||||
constexpr f32 bottom() const noexcept { return y + h; }
|
||||
|
||||
/// Half-open containment: the right/bottom edges are outside the rect.
|
||||
constexpr bool contains(f32 px, f32 py) const noexcept {
|
||||
return px >= x && px < right() && py >= y && py < bottom();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace plot
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <span>
|
||||
|
||||
namespace plot {
|
||||
|
||||
/// `std::span` re-exported so public headers and callers share one spelling.
|
||||
template <class T, std::size_t Extent = std::dynamic_extent>
|
||||
using Span = std::span<T, Extent>;
|
||||
|
||||
} // namespace plot
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
namespace plot {
|
||||
|
||||
enum class ErrorCode {
|
||||
Ok,
|
||||
InvalidArgument,
|
||||
OutOfMemory,
|
||||
GLFailure,
|
||||
Unsupported,
|
||||
NotImplemented,
|
||||
};
|
||||
|
||||
/// Never-null human-readable name of an error code.
|
||||
const char* to_string(ErrorCode code) noexcept;
|
||||
|
||||
/// Result of a fallible operation. Falsy unless `code == ErrorCode::Ok`.
|
||||
struct Status {
|
||||
ErrorCode code = ErrorCode::Ok;
|
||||
const char* message = "";
|
||||
|
||||
constexpr explicit operator bool() const noexcept { return code == ErrorCode::Ok; }
|
||||
};
|
||||
|
||||
} // namespace plot
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace plot {
|
||||
|
||||
using f32 = float;
|
||||
using f64 = double;
|
||||
using i32 = std::int32_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
using usize = std::size_t;
|
||||
|
||||
/// Sentinel for "no index", e.g. an unmatched cursor id.
|
||||
constexpr u64 kInvalid = ~u64{0};
|
||||
|
||||
/// Closed numeric interval on one axis.
|
||||
struct Range {
|
||||
f64 min = 0.0;
|
||||
f64 max = 1.0;
|
||||
|
||||
constexpr f64 span() const noexcept { return max - min; }
|
||||
constexpr f64 clamp(f64 v) const noexcept { return v < min ? min : (v > max ? max : v); }
|
||||
};
|
||||
|
||||
} // namespace plot
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
namespace plot::math {
|
||||
|
||||
/// Column-major 3x3 matrix of `f32`, the layout OpenGL expects for `mat3`
|
||||
/// uniforms.
|
||||
struct Mat3 {
|
||||
f32 m[9] = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
static constexpr Mat3 identity() noexcept { return Mat3{}; }
|
||||
|
||||
/// Column-major product `(*this) * rhs`.
|
||||
constexpr Mat3 operator*(const Mat3& rhs) const noexcept {
|
||||
Mat3 out{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
|
||||
for (usize col = 0; col < 3; ++col) {
|
||||
for (usize row = 0; row < 3; ++row) {
|
||||
f32 acc = 0.0f;
|
||||
for (usize k = 0; k < 3; ++k) acc += m[k * 3 + row] * rhs.m[col * 3 + k];
|
||||
out.m[col * 3 + row] = acc;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace plot::math
|
||||
|
||||
namespace plot {
|
||||
using math::Mat3;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
namespace plot::math {
|
||||
|
||||
/// Affine data->screen mapping: `screen = data * s + t`, applied after `log10`
|
||||
/// when the corresponding log flag is set.
|
||||
struct Transform {
|
||||
f64 sx = 1.0, tx = 0.0;
|
||||
f64 sy = 1.0, ty = 0.0;
|
||||
bool log_x = false, log_y = false;
|
||||
|
||||
f64 to_screen_x(f64 x) const noexcept {
|
||||
const f64 v = log_x ? log10_positive(x) : x;
|
||||
return v * sx + tx;
|
||||
}
|
||||
|
||||
f64 to_screen_y(f64 y) const noexcept {
|
||||
const f64 v = log_y ? log10_positive(y) : y;
|
||||
return v * sy + ty;
|
||||
}
|
||||
|
||||
f64 to_data_x(f64 screen_x) const noexcept {
|
||||
const f64 v = (screen_x - tx) / sx;
|
||||
return log_x ? std::pow(10.0, v) : v;
|
||||
}
|
||||
|
||||
f64 to_data_y(f64 screen_y) const noexcept {
|
||||
const f64 v = (screen_y - ty) / sy;
|
||||
return log_y ? std::pow(10.0, v) : v;
|
||||
}
|
||||
|
||||
/// Set scale/offset so `x` and `y` map onto `[px0,px1]` and `[py0,py1]`.
|
||||
/// A degenerate range is widened by +/-0.5 in the (possibly logarithmic)
|
||||
/// coordinate so the resulting mapping always stays invertible.
|
||||
static Transform from_range(Range x, Range y, f64 px0, f64 px1, f64 py0, f64 py1, bool lx,
|
||||
bool ly) noexcept;
|
||||
|
||||
/// `log10` of `v`, with `v` clamped to at least 1e-300 first.
|
||||
static f64 log10_positive(f64 v) noexcept;
|
||||
};
|
||||
|
||||
} // namespace plot::math
|
||||
|
||||
namespace plot {
|
||||
using math::Transform;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
namespace plot::math {
|
||||
|
||||
/// 2D vector of `f32`, used for pixel offsets and normalised device coords.
|
||||
struct Vec2 {
|
||||
f32 x = 0.0f;
|
||||
f32 y = 0.0f;
|
||||
|
||||
constexpr Vec2 operator+(const Vec2& o) const noexcept { return {x + o.x, y + o.y}; }
|
||||
constexpr Vec2 operator-(const Vec2& o) const noexcept { return {x - o.x, y - o.y}; }
|
||||
constexpr Vec2 operator*(f32 s) const noexcept { return {x * s, y * s}; }
|
||||
constexpr Vec2 operator/(f32 s) const noexcept { return {x / s, y / s}; }
|
||||
|
||||
constexpr f32 dot(const Vec2& o) const noexcept { return x * o.x + y * o.y; }
|
||||
|
||||
f32 length() const noexcept { return std::sqrt(x * x + y * y); }
|
||||
};
|
||||
|
||||
constexpr Vec2 operator*(f32 s, const Vec2& v) noexcept { return v * s; }
|
||||
|
||||
} // namespace plot::math
|
||||
|
||||
namespace plot {
|
||||
using math::Vec2;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
/// Umbrella header: pulls in every public component of the plot library.
|
||||
/// Later layers (gl, data, render, plot, input) are added here as they land.
|
||||
|
||||
#include <plot/core/color.hpp>
|
||||
#include <plot/core/rect.hpp>
|
||||
#include <plot/core/span.hpp>
|
||||
#include <plot/core/status.hpp>
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
#include <plot/math/mat3.hpp>
|
||||
#include <plot/math/transform.hpp>
|
||||
#include <plot/math/vec2.hpp>
|
||||
Reference in new issue
Block a user