reorganized repo to show clear module boundaries

This commit is contained in:
Hartmut Seichter 2023-06-30 22:41:56 +02:00
parent 8e00b668ea
commit 536a639bfd
396 changed files with 355 additions and 391 deletions

View file

@ -0,0 +1,47 @@
#ifndef PARADISO_BITMAP_HPP
#define PARADISO_BITMAP_HPP
#include "geometry.hpp"
#include "globals.hpp"
#include "rgba.hpp"
#include <type_traits>
#include <vector>
#include <cassert>
namespace paradiso {
struct Bitmap final {
constexpr static Bitmap empty(Size size) noexcept {
return {.size = size, .data = std::vector<RGBA>{size.area()}};
}
template <typename... Arguments>
static constexpr Bitmap from_data(Size size, Arguments... values) noexcept {
assert(sizeof...(Arguments) == size.height * size.width);
return {
.size = size,
.data = {values...}
};
}
constexpr auto fill(const RGBA& color) noexcept {
std::fill(data.begin(), data.end(), color);
return *this;
}
constexpr RGBA& pixel(std::integral auto x, std::integral auto y) {
return data[y * size.width + x];
}
constexpr const RGBA& pixel(std::integral auto x,
std::integral auto y) const {
return data[y * size.width + x];
}
Size size{.width = 0, .height = 0};
std::vector<RGBA> data{};
};
} // namespace paradiso
#endif

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 1999-2021 Hartmut Seichter
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifndef PARADISO_CONTEXT_HPP
#define PARADISO_CONTEXT_HPP
#include "geometry.hpp"
#include "rgba.hpp"
#include <memory>
namespace paradiso {
struct Context final {
Context();
~Context();
Context& set_blend();
Context& set_depth();
Context& set_viewport(const Rectangle& v);
Rectangle viewport() const;
Size viewport_size() const;
Point viewport_origin() const;
Context& set_clearcolor(const RGBA &clear_color);
RGBA clearcolor() const;
void clear();
uint32_t get_error() const;
struct impl;
private:
std::unique_ptr<impl> impl_;
};
}
#endif

View file

@ -0,0 +1,39 @@
#ifndef PARADISO_GEOMETRY_HPP
#define PARADISO_GEOMETRY_HPP
#include "globals.hpp"
namespace paradiso
{
struct Point final
{
using value_type = int32_t;
value_type x{0}, y{0};
};
struct Size final
{
using value_type = uint32_t;
value_type width{0}, height{0};
constexpr auto area() const noexcept
{
return width * height;
}
};
struct Rectangle
{
Point position;
Size size;
constexpr bool contains(const Point &p) const noexcept
{
return p.x >= position.x && p.x <= position.x + size.width &&
p.y >= position.y && p.y <= position.y + size.height;
}
};
}
#endif

View file

@ -0,0 +1,12 @@
#ifndef PARADISO_GLOBALS_HPP
#define PARADISO_GLOBALS_HPP
#include <cstdint>
namespace paradiso
{
}
#endif

View file

@ -0,0 +1,188 @@
#ifndef PW_CORE_MATRIX_HPP
#define PW_CORE_MATRIX_HPP
#include "matrixbase.hpp"
#include <numeric>
namespace paradiso {
template <std::size_t R, std::size_t C, typename Scalar, bool RowMajor = false>
struct Matrix : MatrixBase<Scalar, Matrix<R, C, Scalar>> {
Scalar data[R * C]{};
static constexpr std::size_t rows{R};
static constexpr std::size_t cols{C};
static constexpr std::size_t coefficients{R * C};
using col_type = Matrix<R, 1, Scalar>;
using row_type = Matrix<1, C, Scalar>;
using transpose_type = Matrix<C, R, Scalar>;
template <typename... Arguments>
static constexpr Matrix<R, C, Scalar> make(Arguments... values) noexcept {
static_assert(sizeof...(Arguments) == R * C,
"Incorrect number of arguments");
return {.data = {values...}};
}
constexpr size_t offset(size_t r, size_t c) const {
return (RowMajor) ? r * C + c : c * R + r;
}
constexpr Scalar& operator()(std::size_t r, std::size_t c) {
return data[offset(r, c)];
}
constexpr const Scalar& operator()(std::size_t r, std::size_t c) const {
return data[offset(r, c)];
}
constexpr const Scalar* ptr() const { return &data[0]; }
//! set identity
constexpr Matrix& set_identity() {
for (std::size_t r = 0; r < rows; r++)
for (std::size_t c = 0; c < cols; c++)
(*this)(r, c) = (c == r) ? Scalar(1) : Scalar(0);
return *this;
}
constexpr Matrix& set_uniform(const Scalar& v) {
std::fill(std::begin(data), std::end(data), v);
return *this;
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
auto slice(std::size_t r, std::size_t c) const {
Matrix<Rs, Cs, Scalar, RowMajorSlice> s;
for (std::size_t ri = 0; ri < Rs; ri++)
for (std::size_t ci = 0; ci < Cs; ci++)
s(ri, ci) = (*this)(ri + r, ci + c);
return s;
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
Matrix& set_slice(const Matrix<Rs, Cs, Scalar, RowMajorSlice>& s,
std::size_t r, std::size_t c) {
for (std::size_t ri = 0; ri < Rs; ri++)
for (std::size_t ci = 0; ci < Cs; ci++)
(*this)(ri + r, ci + c) = s(ri, ci);
return *this;
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
auto minor(std::size_t r0, std::size_t c0) const {
Matrix<Rs, Cs, Scalar, RowMajorSlice> m;
size_t r = 0;
for (size_t ri = 0; ri < R; ri++) {
size_t c = 0;
if (ri == r0)
continue;
for (size_t ci = 0; ci < C; ci++) {
if (ci == c0)
continue;
m(r, c) = (*this)(ri, ci);
c++;
}
r++;
}
return m;
}
Scalar determinant() const {
Scalar det(0);
for (size_t c = 0; c < C; c++)
det += ((c % 2 == 0) ? (*this)(0, c) : -(*this)(0, c)) *
this->minor<R - 1, C - 1, RowMajor>(0, c).determinant();
return det;
}
auto transposed() const {
transpose_type res;
for (size_t r = rows; r-- > 0;)
for (size_t c = cols; c-- > 0;)
res(c, r) = (*this)(r, c);
return res;
}
auto inverse() const {
Scalar invDet = Scalar(1) / this->determinant();
Matrix<R, C, Scalar, RowMajor> inv;
for (int j = 0; j < C; j++)
for (int i = 0; i < R; i++) {
const Scalar minorDet =
this->minor<R - 1, C - 1, RowMajor>(j, i).determinant();
const Scalar coFactor =
((i + j) % 2 == 1) ? -minorDet : minorDet;
inv(i, j) = invDet * coFactor;
}
return inv;
}
inline bool row_major() const { return RowMajor; }
inline bool square() const { return R == C; }
inline const Matrix operator+(const Matrix& other) const {
Matrix res(*this);
for (size_t r = 0; r < R; r++)
for (size_t c = 0; c < C; c++)
res(r, c) += other(r, c);
return res;
}
inline const Matrix operator-(const Matrix& other) const {
Matrix res(*this);
for (size_t r = 0; r < R; r++)
for (size_t c = 0; c < C; c++)
res(r, c) -= other(r, c);
return res;
}
auto row(size_t row_) const {
row_type r;
for (size_t i = 0; i < cols; i++)
r[i] = (*this)(row_, i);
return r;
}
auto column(size_t col_) const {
col_type c;
for (size_t i = 0; i < rows; i++)
c[i] = (*this)(i, col_);
return c;
}
static constexpr auto identity() {
Matrix res;
for (std::size_t r = 0; r < rows; r++)
for (std::size_t c = 0; c < cols; c++)
res(r, c) = (c == r) ? Scalar(1) : Scalar(0);
return res;
}
};
template <> inline float Matrix<1, 1, float>::determinant() const {
return (*this)(0, 0);
}
template <> inline double Matrix<1, 1, double>::determinant() const {
return (*this)(0, 0);
}
template <typename Scalar, std::size_t R, std::size_t Ca, std::size_t Cb>
auto operator*(const Matrix<R, Ca, Scalar>& A, const Matrix<R, Cb, Scalar>& B) {
Matrix<R, Cb, Scalar> result;
result.zero(); // zero the output
for (size_t r = 0; r < R; r++)
for (size_t c = 0; c < Cb; c++)
for (size_t iI = 0; iI < R; iI++)
result(r, c) += A(r, iI) * B(iI, c); // inner product
return result;
}
} // namespace paradiso
#endif

View file

@ -0,0 +1,116 @@
#ifndef PARADISO_MATRIXBASE_HPP
#define PARADISO_MATRIXBASE_HPP
#include <cmath>
#include <numeric>
namespace paradiso {
template <typename Scalar, typename Derived> struct MatrixBase {
using value_type = Scalar;
using reference = Scalar&;
using const_reference = const Scalar&;
using pointer = Scalar*;
using const_pointer = const Scalar*;
using iterator = Scalar*;
using const_iterator = const Scalar*;
constexpr pointer data() { return &derived().data[0]; }
constexpr const_pointer data() const noexcept { return &derived().data[0]; }
constexpr iterator begin() noexcept { return this->data(); }
constexpr iterator end() noexcept { return this->data() + size(); }
constexpr const_iterator begin() const noexcept { return this->data(); }
constexpr const_iterator end() const noexcept { return this->data() + size(); }
constexpr const_iterator cbegin() const noexcept { return this->data(); }
constexpr const_iterator cend() const noexcept { return this->data() + size(); }
constexpr Scalar& operator[](std::size_t i) { return this->data()[i]; }
constexpr const Scalar& operator[](std::size_t i) const {
return this->data()[i];
}
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const {
return static_cast<const Derived&>(*this);
}
std::size_t size() const {
return std::extent<decltype(Derived::data)>::value;
}
constexpr Derived& fill(const Scalar& v) noexcept {
std::fill(std::begin(*this), std::end(*this), Scalar(v));
return derived();
}
static constexpr Derived zero() noexcept {
Derived d;
d.fill(0);
return d;
}
constexpr Scalar squared_norm() const { return dot(*this, *this); }
constexpr Scalar norm() const { return std::sqrt(squared_norm()); }
constexpr Derived normalized() const { return *this / this->norm(); }
constexpr void normalize() { *this /= this->norm(); }
static constexpr Scalar dot(const Derived& a, const Derived& b) {
return std::inner_product(std::begin(a), std::end(a), std::begin(b),
Scalar{0});
}
static constexpr Derived lerp(const Derived& a, const Derived& b,
const Scalar& t) {
return a + (b - a) * t;
}
constexpr void operator*=(const Scalar& b) {
for (auto& e : *this)
e *= b;
}
constexpr void operator/=(const Scalar& b) {
for (auto& e : *this)
e /= b;
}
constexpr void operator+=(const Scalar& b) {
for (auto& e : *this)
e += b;
}
constexpr void operator-=(const Scalar& b) {
for (auto& e : *this)
e -= b;
}
constexpr const Derived operator*(const Scalar& b) const {
Derived r(derived());
for (auto& e : r)
e *= b;
return r;
}
constexpr const Derived operator/(const Scalar& b) const {
Derived r(derived());
for (auto& e : r)
e /= b;
return r;
}
constexpr const Derived operator+(const Scalar& b) const {
Derived r(derived());
for (auto& e : r)
e += b;
return r;
}
constexpr const Derived operator-(const Scalar& b) const {
Derived r(derived());
for (auto& e : r)
e -= b;
return r;
}
};
} // namespace paradiso
#endif

View file

@ -0,0 +1,32 @@
#ifndef PW_VISUAL_MESH_RENDERER_HPP
#define PW_VISUAL_MESH_RENDERER_HPP
#include <map>
#include <memory>
namespace paradiso {
struct Sprite;
struct Shader;
/**
* @brief a Renderer2D for sprites
*/
struct Renderer final {
Renderer();
~Renderer();
Renderer(const Renderer&) = delete;
bool draw(const Sprite& sprite, const Shader& shader);
bool ready() const;
private:
struct impl;
std::unique_ptr<impl> impl_;
};
} // namespace paradiso
#endif

View file

@ -0,0 +1,63 @@
#ifndef PARADISO_RGBA_HPP
#define PARADISO_RGBA_HPP
#include "globals.hpp"
namespace paradiso {
struct RGBA final {
using value_type = std::uint32_t;
value_type pixel{0x0};
static constexpr RGBA from_rgb(uint8_t red, uint8_t green,
uint8_t blue) noexcept {
return from_rgba(red, green, blue, 0xFF);
}
static constexpr RGBA from_rgba(uint8_t red, uint8_t green, uint8_t blue,
uint8_t alpha) noexcept {
return {.pixel =
(value_type)(((((red << 8) | green) << 8) | blue) << 8) |
alpha};
}
constexpr void to_float(float rgba_f[4]) const noexcept {
rgba_f[0] = static_cast<float>(this->red()) / 0xFF;
rgba_f[1] = static_cast<float>(this->green()) / 0xFF;
rgba_f[2] = static_cast<float>(this->blue()) / 0xFF;
rgba_f[3] = static_cast<float>(this->alpha()) / 0xFF;
}
constexpr uint8_t red() const noexcept {
return (pixel & 0xFF000000) >> 24;
}
constexpr uint8_t green() const noexcept {
return uint8_t((pixel & 0xFF0000) >> 16);
}
constexpr uint8_t blue() const noexcept {
return uint8_t((pixel & 0xFF00) >> 8);
}
constexpr uint8_t alpha() const noexcept { return uint8_t(pixel & 0xFF); }
constexpr RGBA& set_red(uint8_t v) noexcept {
pixel = (pixel & 0x00FFFFFF) | (v << 24);
return *this;
}
constexpr RGBA& set_green(uint8_t v) noexcept {
pixel = (pixel & 0xFF00FFFF) | (v << 16);
return *this;
}
constexpr RGBA& set_blue(uint8_t v) noexcept {
pixel = (pixel & 0xFFFF00FF) | (v << 8);
return *this;
}
constexpr RGBA& set_alpha(uint8_t v) noexcept {
pixel = (pixel & 0xFFFFFF00) | v;
return *this;
}
};
} // namespace paradiso
#endif

View file

@ -0,0 +1,88 @@
#ifndef PARADISO_SHADER_HPP
#define PARADISO_SHADER_HPP
#include "globals.hpp"
#include <memory>
#include <string>
#include <tuple>
#include <unordered_map>
#include <variant>
#include <vector>
namespace paradiso {
struct Shader final {
Shader();
~Shader();
Shader(const Shader&) = delete;
Shader(Shader&&) = default;
enum class Type { Vertex, Fragment, Geometry, Compute };
void set_source(Type t, const std::string& c) { source_[t] = c; }
std::string source(Type t) const { return source_.at(t); }
bool build();
bool ready() const;
void use() const;
Shader& set_uniform_at_location(int location,
float v); //!< sets a float in a shader
Shader&
set_uniform_at_location(int location,
uint32_t v); //!< sets a 32bit unsigned in a shader
Shader&
set_uniform_at_location(int location,
int32_t v); //!< sets a 32bit signed in a shader
/**
* @brief retrieves the position of a uniform
* @param name of the uniform
* @return position of the uniform or negative if it doesn't exist
*/
int uniform_location(std::string const& name) const;
/**
* @brief check if a uniform with the given name exists
* @param name of the uniform
* @return true if found
*/
bool has_uniform(std::string const& name) const {
return uniform_location(name) >= 0;
}
/**
* sets data of the
*/
template <typename T>
Shader& set_uniform(std::string const& name, T&& value) {
return set_uniform_at_location(uniform_location(name),
std::forward<T>(value));
}
using uniform_t =
std::variant<bool, int, float,
double /*,vector2f,vector3f,vector4f,matrix4x4f*/>;
using uniform_entry_t = std::tuple<std::string, uniform_t, int>;
using uniform_cache_t = std::vector<uniform_entry_t>;
void set_uniforms(uniform_cache_t c);
uint32_t native_handle() const;
private:
std::unordered_map<Type, std::string> source_;
struct impl;
std::unique_ptr<impl> impl_;
};
} // namespace paradiso
#endif

View file

@ -0,0 +1,42 @@
#ifndef PARADISO_SPRITE_HPP
#define PARADISO_SPRITE_HPP
#include "bitmap.hpp"
#include "matrix.hpp"
#include "vector.hpp"
#include <array>
namespace paradiso {
struct Sprite final {
using ChangeCountType = std::uint64_t;
static constexpr Sprite create() noexcept { return {}; }
Vector2<float> pivot{Vector2<float>::zero()};
std::array<std::uint32_t, 6> indices{0, 3, 2, 2, 1, 0};
std::array<Vector3<float>, 4> vertices{
Vector3<float>::make(-1.0f, -1.0f, 0.0f),
Vector3<float>::make(-1.0f, +1.0f, 0.0f),
Vector3<float>::make(+1.0f, +1.0f, 0.0f),
Vector3<float>::make(+1.0f, -1.0f, 0.0f)};
std::array<Vector3<float>, 4> normals{
Vector3<float>::z_axis(), Vector3<float>::z_axis(),
Vector3<float>::z_axis(), Vector3<float>::z_axis()};
std::array<Vector2<float>, 4> texture_coordinates{
Vector2<float>::make(0.0f, 0.0f), /// 0
Vector2<float>::make(0.0f, 1.0f), /// 1
Vector2<float>::make(1.0f, 1.0f), /// 2
Vector2<float>::make(1.0f, 0.0f) /// 3
};
ChangeCountType change_count{};
};
} // namespace paradiso
#endif

View file

@ -0,0 +1,62 @@
#ifndef PARADISO_VECTOR_HPP
#define PARADISO_VECTOR_HPP
#include "matrix.hpp"
namespace paradiso {
/**
* Basic vector types used in pixwerx.
*/
template <typename T> struct Vector2 : Matrix<2, 1, T> {
using base_type = Matrix<2, 1, T>;
constexpr const T& x() const noexcept { return (*this)[0]; }
constexpr T& x() { return (*this)[0]; }
constexpr const T& y() const { return (*this)[1]; }
constexpr T& y() { return (*this)[1]; }
inline auto homogenous(T w = 1) const {
return Matrix<3, 1, T>({x(), y(), w});
}
static T angle_between(const Vector2& a, const Vector2& b) {
return std::acos(dot(a.normalized(), b.normalized()));
}
};
template <typename T> struct Vector3 : Matrix<3, 1, T> {
using base_type = Matrix<3, 1, T>;
constexpr const T& x() const { return (*this)[0]; }
constexpr T& x() { return (*this)[0]; }
constexpr const T& y() const { return (*this)[1]; }
constexpr T& y() { return (*this)[1]; }
constexpr Vector2<T> xy() const noexcept { return {x(), y()}; }
static constexpr Vector3 cross(const Vector3& lhs, const Vector3& rhs) {
return vector3_({lhs[1] * rhs[2] - rhs[1] * lhs[2],
lhs[2] * rhs[0] - rhs[2] * lhs[0],
lhs[0] * rhs[1] - rhs[0] * lhs[1]});
}
static constexpr auto x_axis() noexcept {
return Vector3::make(T{1}, T{0}, T{0});
}
static constexpr auto y_axis() noexcept {
return Vector3::make(T{0}, T{1}, T{0});
}
static constexpr auto z_axis() noexcept {
return Vector3<T>::make(T{0}, T{0}, T{1});
}
};
}; // namespace paradiso
#endif

View file

@ -0,0 +1,64 @@
#ifndef PARADISO_WINDOW_HPP
#define PARADISO_WINDOW_HPP
#include "geometry.hpp"
#include "globals.hpp"
#include <functional>
#include <memory>
#include <string>
namespace paradiso {
struct Window final {
using Size = paradiso::Size;
using Position = paradiso::Point;
using on_updatecallback_t = std::function<bool(
Window&)>; //! update needs to return true to continue
using on_resizecallback_t =
std::function<void(Window&)>; //! resize is 'informal'
using on_keyboardcallback_t =
std::function<void(Window&, int, int, int, int)>;
Window();
~Window();
Window(const Window&) = delete; // no copy!
Window(Window&&) = default;
/**
* @brief update internal state
* @param cb callback to process data and render
* @return returns false if process needs to quit
* */
bool update(on_updatecallback_t cb);
Window& set_title(std::string_view title);
Window& set_size(const Size& size);
Size size() const;
Size client_size() const;
Window& set_position(const Position& position);
Position position() const;
bool fullscreen() const;
Window& set_fullscreen(bool use_fullscreen);
void set_resizecallback(on_resizecallback_t f) { on_resize_ = f; }
void set_keyboardcallback(on_keyboardcallback_t f) { on_keyboard_ = f; }
bool visible() const;
Window& set_visible(bool is_visible);
private:
struct impl;
std::unique_ptr<impl> impl_;
on_resizecallback_t on_resize_;
on_keyboardcallback_t on_keyboard_;
};
} // namespace paradiso
#endif