This commit is contained in:
Hartmut Seichter 2024-07-13 00:29:47 +02:00
parent 2919c47e99
commit 114f17a499
13 changed files with 327 additions and 519 deletions

View file

@ -1,5 +1,5 @@
# first build dependencies
# add_subdirectory(deps)
add_subdirectory(deps)
# build internal core
add_subdirectory(core)

View file

@ -8,7 +8,6 @@ set(hdrs
include/pw/core/globals.hpp
include/pw/core/material.hpp
include/pw/core/math.hpp
include/pw/core/matrixbase.hpp
include/pw/core/matrix.hpp
include/pw/core/quaternion.hpp
include/pw/core/image.hpp

View file

@ -8,8 +8,8 @@
* 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 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,
@ -24,39 +24,31 @@
#define PW_CORE_COLOR_HPP
#include <pw/core/vector.hpp>
#include <limits>
#include <cstdint>
namespace pw {
struct color {
vector4 rgba {0, 0, 0, 1};
vector4f rgba{vector4f::all(1)};
color() = default;
static constexpr auto from_rgb8888(uint8_t r8, uint8_t g8, uint8_t b8,
uint8_t a8) -> color {
return {static_cast<float>(r8) / std::numeric_limits<uint8_t>::max(),
static_cast<float>(g8) / std::numeric_limits<uint8_t>::max(),
static_cast<float>(b8) / std::numeric_limits<uint8_t>::max(),
static_cast<float>(a8) / std::numeric_limits<uint8_t>::max()};
}
color(uint8_t r8,uint8_t g8,uint8_t b8,uint8_t a8)
: color(static_cast<real_t>(r8 / std::numeric_limits<uint8_t>::max()),
static_cast<real_t>(g8 / std::numeric_limits<uint8_t>::max()),
static_cast<real_t>(b8 / std::numeric_limits<uint8_t>::max()),
static_cast<real_t>(a8 / std::numeric_limits<uint8_t>::max()))
{
}
static constexpr auto from_rgb8888(uint32_t v) -> color {
return from_rgb8888((v & 0xff000000) >> 24, (v & 0x00ff0000) >> 16,
(v & 0x0000ff00) >> 8, (v & 0x000000ff));
}
color(real_t r,real_t g,real_t b,real_t a)
: rgba({r,g,b,a})
{
}
color(const vector4& v) : rgba(v) { }
operator vector4() const { return rgba; }
uint32_t to_rgb8888() const {
return 0;
}
uint32_t to_rgb8888() const { return 0; }
};
}
} // namespace pw
#endif

View file

@ -26,9 +26,11 @@
#include <pw/core/globals.hpp>
#include <pw/core/math.hpp>
#include <pw/core/vector.hpp>
#include <utility>
namespace pw {
template <typename Scalar, unsigned int Rows, unsigned int Cols>
struct matrix final {
@ -69,8 +71,7 @@ struct matrix final {
}(std::make_index_sequence<diag_size>{});
}
constexpr auto
column(std::unsigned_integral auto c) const noexcept -> column_type {
constexpr auto column(const unsigned int& c) const noexcept -> column_type {
return [this, &c]<std::size_t... Rs>(std::index_sequence<Rs...>) {
return column_type{(*this)[Rs][c]...};
}(std::make_index_sequence<Cols>{});

View file

@ -1,198 +0,0 @@
/*
* 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 PW_CORE_MATRIXBASE_HPP
#define PW_CORE_MATRIXBASE_HPP
#include <algorithm>
#include <iterator>
#include <numeric>
#include <type_traits>
#include <cmath>
namespace pw {
template <typename T, typename Derived>
struct matrixbase_ {
using value_type = T;
using derived_type = Derived;
using iterator = value_type*;
using const_iterator = const value_type*;
constexpr Derived& derived() noexcept { return static_cast<Derived&>(*this); }
constexpr const Derived& derived() const noexcept { return static_cast<const Derived&>(*this); }
constexpr std::size_t size() const noexcept {
return std::extent<decltype(Derived::data)>::value;
}
constexpr Derived& fill(const T& v) noexcept {
std::fill(std::begin(derived().data), std::end(derived().data), T(v));
return derived();
}
constexpr Derived& zero() {
return derived().fill(0);
}
constexpr T squared_norm() const noexcept {
return std::accumulate(std::begin(derived().data),std::end(derived().data), T(0),
[&](const T& a,const T& b){
return a + b * b;
});
}
static constexpr Derived
all(const std::convertible_to<T> auto& v) noexcept {
Derived d;
d.fill(v);
return d;
}
constexpr T norm() const noexcept {
return std::sqrt(squared_norm());
}
constexpr Derived normalized() const noexcept {
return *this / this->norm() ;
}
constexpr void normalize() {
*this /= this->norm();
}
constexpr iterator begin() { return &derived().data[0]; }
constexpr iterator end() { return &derived().data[0] + size(); }
constexpr const_iterator begin() const { return &derived().data[0]; }
constexpr const_iterator end() const { return &derived().data[0] + size(); }
constexpr T& operator [] (std::size_t i) {
return derived().data[i];
}
constexpr const T& operator [] (std::size_t i) const {
return derived().data[i];
}
static constexpr T dot(const Derived &a,const Derived &b) noexcept
{
return std::inner_product(std::begin(a),std::end(a),std::begin(b),T(0));
}
static constexpr Derived lerp(const Derived &a,const Derived &b,const T& t) noexcept
{
return a + (b - a) * t;
}
//
// M (op) scalar
//
constexpr Derived operator*(const T& b) const {
Derived r(derived());
for (auto& e : r)
e *= b;
return r;
}
constexpr Derived operator/(const T& b) const {
Derived r(derived());
for (auto& e : r)
e /= b;
return r;
}
constexpr Derived operator+(const T& b) const {
Derived r(derived());
for (auto& e : r)
e += b;
return r;
}
constexpr Derived operator-(const T& b) const {
Derived r(derived());
for (auto& e : r)
e -= b;
return r;
}
//
// M (op)== N
//
constexpr void operator*=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e *= b;
}
constexpr void operator/=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e /= b;
}
constexpr void operator+=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e += b;
}
constexpr void operator-=(const std::convertible_to<T> auto& b) {
for (auto& e : derived())
e -= b;
}
//
// M (op) N
//
/// @brief in-place addition with matrix of same size
/// @param rhs righthand-side matrix
constexpr void operator+=(const Derived& b) noexcept {
std::transform(b.cbegin(), b.cend(), (*this).cbegin(), (*this).begin(),
std::plus<>{});
}
/// @brief in-place subtraction with matrix of same size
/// @param rhs righthand-side matrix
constexpr void operator-=(const Derived& b) noexcept {
std::transform(b.cbegin(), b.cend(), (*this).cbegin(), (*this).begin(),
std::minus<>{});
}
/// @brief addition with matrix of same size
/// @param rhs righthand-side matrix
constexpr Derived operator+(const std::convertible_to<Derived> auto& rhs) const noexcept {
Derived d{derived()};
std::transform(std::begin(rhs), std::end(rhs), (d).begin(), std::plus<>{});
return d;
}
/// @brief subtraction with matrix of same size
/// @param rhs righthand-side matrix
constexpr Derived operator-(const Derived& rhs) const noexcept {
Derived d(derived());
d -= rhs;
return d;
}
};
}
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2021 Hartmut Seichter
* Copyright (c) 1999-2024 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
@ -8,8 +8,8 @@
* 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 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,
@ -23,172 +23,241 @@
#ifndef PW_CORE_QUATERNION_HPP
#define PW_CORE_QUATERNION_HPP
#include <pw/core/vector.hpp>
#include <pw/core/matrix.hpp>
#include <pw/core/axisangle.hpp>
#include <pw/core/vector.hpp>
#include <concepts>
namespace pw {
/**
* simplified quaternion class
*/
template <typename T>
struct quaternion_ : vector4_<T> {
template <std::floating_point Scalar> struct quaternion final {
typedef vector4_<T> base_type;
using value_type = vector<Scalar, 4>;
using typename base_type::value_type;
using base_type::base_type;
using base_type::x;
using base_type::y;
using base_type::z;
using base_type::w;
using base_type::lerp;
using base_type::xyz;
// using base_type::operator*;
// using base_type::operator/;
value_type q_{value_type::basis(3)}; // preset to identity
auto&& x(this auto&& self) {
return std::forward<decltype(self)>(self).q_.x();
}
auto&& y(this auto&& self) {
return std::forward<decltype(self)>(self).q_.y();
}
auto&& z(this auto&& self) {
return std::forward<decltype(self)>(self).q_.z();
}
auto&& w(this auto&& self) {
return std::forward<decltype(self)>(self).q_.w();
}
quaternion_(const base_type& other) : base_type(other) {}
constexpr auto
operator*(const quaternion& rhs) const noexcept -> quaternion {
return {rhs.w() * x() + rhs.x() * w() + rhs.y() * z() - rhs.z() * y(),
rhs.w() * y() - rhs.x() * z() + rhs.y() * w() + rhs.z() * x(),
rhs.w() * z() + rhs.x() * y() - rhs.y() * x() + rhs.z() * w(),
rhs.w() * w() - rhs.x() * x() - rhs.y() * y() - rhs.z() * z()};
}
inline const quaternion_ operator * (const quaternion_& rhs) const {
return quaternion_(
rhs.w()*x() + rhs.x()*w() + rhs.y()*z() - rhs.z()*y(),
rhs.w()*y() - rhs.x()*z() + rhs.y()*w() + rhs.z()*x(),
rhs.w()*z() + rhs.x()*y() - rhs.y()*x() + rhs.z()*w(),
rhs.w()*w() - rhs.x()*x() - rhs.y()*y() - rhs.z()*z()
);
}
constexpr auto conjugate() const noexcept -> quaternion {
return {-x(), -y(), -z(), w()};
}
inline auto operator / (const T& rhs) const {
return quaternion_( { x() / rhs, y() / rhs, z() / rhs, w() / rhs, } );
}
constexpr auto norm() const noexcept -> Scalar { return q_.norm(); }
//! conjugate
inline auto conjugate() const { return quaternion_( { -x(),-y(),-z(),w() } ); }
constexpr auto operator*(const Scalar& rhs) const noexcept -> quaternion {
return {.q_ = q_ * rhs};
}
//! compute inverse
inline auto inverse() const {
return conjugate() / this->norm();
}
constexpr auto operator/(const Scalar& rhs) const noexcept -> quaternion {
return operator*(Scalar{1} / rhs);
}
inline static auto identity() {
return quaternion_({0,0,0,1});
}
constexpr auto normalized() const noexcept -> quaternion {
return {.q_ = q_.normalized()};
}
const matrix4x4_<T> to_matrix() const {
constexpr auto inverse() const noexcept -> quaternion {
return conjugate() / this->norm();
}
matrix4x4_<T> m; m.set_identity();
constexpr auto to_matrix() const noexcept -> matrix<Scalar, 3, 3> {
T xx = x() * x();
T xy = x() * y();
T xz = x() * z();
T xw = x() * w();
const Scalar xx = x() * x();
const Scalar xy = x() * y();
const Scalar xz = x() * z();
const Scalar xw = x() * w();
T yy = y() * y();
T yz = y() * z();
T yw = y() * w();
const Scalar yy = y() * y();
const Scalar yz = y() * z();
const Scalar yw = y() * w();
T zz = z() * z();
T zw = z() * w();
const Scalar zz = z() * z();
const Scalar zw = z() * w();
m(0,0) = 1 - 2 * ( yy + zz );
m(0,1) = 2 * ( xy - zw );
m(0,2) = 2 * ( xz + yw );
return {
vector{1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw)},
vector{2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw)},
vector{2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy)},
};
}
m(1,0) = 2 * ( xy + zw );
m(1,1) = 1 - 2 * ( xx + zz );
m(1,2) = 2 * ( yz - xw );
static constexpr auto identity() noexcept -> quaternion { return {}; }
m(2,0) = 2 * ( xz - yw );
m(2,1) = 2 * ( yz + xw );
m(2,2) = 1 - 2 * ( xx + yy );
static constexpr auto pi_around_x() noexcept -> quaternion {
return {Scalar{1}, Scalar{0}, Scalar{0}, Scalar{0}};
}
return m;
}
static constexpr auto pi_around_y() noexcept -> quaternion {
return {Scalar{0}, Scalar{1}, Scalar{0}, Scalar{0}};
}
static auto from_matrix(const matrix_<4,4,T> &m) {
using std::sqrt;
auto wtemp = sqrt(T(1) + m(0,0) + m(1,1) + m(2,2)) / T(2);
auto w4 = T(4.0) * wtemp;
static constexpr auto pi_around_z() noexcept -> quaternion {
return {Scalar{0}, Scalar{0}, Scalar{1}, Scalar{0}};
}
static constexpr auto lerp(const quaternion& a, const quaternion& b,
const Scalar& t) -> quaternion {
return {value_type::lerp(a.q_, b.q_, t).normalized()};
}
};
// deduction guide for quaternion
template <class T, class... U, class CT = std::common_type_t<T, U...>>
quaternion(T, U...) -> quaternion<CT>;
#if 0
constexpr quaternion_ operator*(const quaternion_& rhs) const {
return quaternion_(
rhs.w() * x() + rhs.x() * w() + rhs.y() * z() - rhs.z() * y(),
rhs.w() * y() - rhs.x() * z() + rhs.y() * w() + rhs.z() * x(),
rhs.w() * z() + rhs.x() * y() - rhs.y() * x() + rhs.z() * w(),
rhs.w() * w() - rhs.x() * x() - rhs.y() * y() - rhs.z() * z());
}
inline auto operator/(const T& rhs) const {
return quaternion_({
(m(2,1) - m(1,2)) / w4,
(m(0,2) - m(2,0)) / w4,
(m(1,0) - m(0,1)) / w4,
wtemp});
}
x() / rhs,
y() / rhs,
z() / rhs,
w() / rhs,
});
}
static auto normalized_lerp(const quaternion_ &a,const quaternion_ &b,const T &t) {
return quaternion_(lerp(a,b,t).normalized());
}
//! conjugate
inline auto conjugate() const {
return quaternion_({-x(), -y(), -z(), w()});
}
static auto slerp(const quaternion_& qa,const quaternion_& qb,const T& t)
{
using std::abs;
using std::sqrt;
using std::acos;
//! compute inverse
inline auto inverse() const { return conjugate() / this->norm(); }
// quaternion to return
quaternion_ qm;
// Calculate angle between them.
T cosHalfTheta = qa.w() * qb.w() + qa.x() * qb.x() + qa.y() * qb.y() + qa.z() * qb.z();
// if qa=qb or qa=-qb then theta = 0 and we can return qa
if (abs(cosHalfTheta) >= T(1)) {
return qa;
}
inline static auto identity() { return quaternion_({0, 0, 0, 1}); }
// Calculate temporary values.
const T halfTheta = acos(cosHalfTheta);
const T sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta);
// if theta = 180 degrees then result is not fully defined
// we could rotate around any axis normal to qa or qb
if (abs(sinHalfTheta) < 0.001){ // fabs is floating point absolute
qm.w() = (qa.w() * T(0.5) + qb.w() * T(0.5));
qm.x() = (qa.x() * T(0.5) + qb.x() * T(0.5));
qm.y() = (qa.y() * T(0.5) + qb.y() * T(0.5));
qm.z() = (qa.z() * T(0.5) + qb.z() * T(0.5));
return qm;
}
const T ratioA = sin((value_type(1) - t) * halfTheta) / sinHalfTheta;
const T ratioB = sin(t * halfTheta) / sinHalfTheta;
//calculate Quaternion.
qm.w() = (qa.w() * ratioA + qb.w() * ratioB);
qm.x() = (qa.x() * ratioA + qb.x() * ratioB);
qm.y() = (qa.y() * ratioA + qb.y() * ratioB);
qm.z() = (qa.z() * ratioA + qb.z() * ratioB);
const matrix4x4_<T> to_matrix() const {
return qm;
}
matrix4x4_<T> m;
m.set_identity();
T xx = x() * x();
T xy = x() * y();
T xz = x() * z();
T xw = x() * w();
static auto from_axisangle(const axisangle_<T> &aa) {
using std::sin;
using std::cos;
T yy = y() * y();
T yz = y() * z();
T yw = y() * w();
const T sinHalfAngle( sin(aa.angle * T(0.5) ));
T zz = z() * z();
T zw = z() * w();
return quaternion_<T>( { aa.axis.x() * sinHalfAngle, // x
aa.axis.y() * sinHalfAngle, // y
aa.axis.z() * sinHalfAngle, // z
cos(aa.angle * T(0.5)) // w
}
);
m(0, 0) = 1 - 2 * (yy + zz);
m(0, 1) = 2 * (xy - zw);
m(0, 2) = 2 * (xz + yw);
}
m(1, 0) = 2 * (xy + zw);
m(1, 1) = 1 - 2 * (xx + zz);
m(1, 2) = 2 * (yz - xw);
m(2, 0) = 2 * (xz - yw);
m(2, 1) = 2 * (yz + xw);
m(2, 2) = 1 - 2 * (xx + yy);
return m;
}
static auto from_matrix(const matrix_<4, 4, T>& m) {
using std::sqrt;
auto wtemp = sqrt(T(1) + m(0, 0) + m(1, 1) + m(2, 2)) / T(2);
auto w4 = T(4.0) * wtemp;
return quaternion_({(m(2, 1) - m(1, 2)) / w4, (m(0, 2) - m(2, 0)) / w4,
(m(1, 0) - m(0, 1)) / w4, wtemp});
}
static auto normalized_lerp(const quaternion_& a, const quaternion_& b,
const T& t) {
return quaternion_(lerp(a, b, t).normalized());
}
static auto slerp(const quaternion_& qa, const quaternion_& qb,
const T& t) {
using std::abs;
using std::acos;
using std::sqrt;
// quaternion to return
quaternion_ qm;
// Calculate angle between them.
T cosHalfTheta = qa.w() * qb.w() + qa.x() * qb.x() + qa.y() * qb.y() +
qa.z() * qb.z();
// if qa=qb or qa=-qb then theta = 0 and we can return qa
if (abs(cosHalfTheta) >= T(1)) {
return qa;
}
// Calculate temporary values.
const T halfTheta = acos(cosHalfTheta);
const T sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta);
// if theta = 180 degrees then result is not fully defined
// we could rotate around any axis normal to qa or qb
if (abs(sinHalfTheta) < 0.001) { // fabs is floating point absolute
qm.w() = (qa.w() * T(0.5) + qb.w() * T(0.5));
qm.x() = (qa.x() * T(0.5) + qb.x() * T(0.5));
qm.y() = (qa.y() * T(0.5) + qb.y() * T(0.5));
qm.z() = (qa.z() * T(0.5) + qb.z() * T(0.5));
return qm;
}
const T ratioA = sin((value_type(1) - t) * halfTheta) / sinHalfTheta;
const T ratioB = sin(t * halfTheta) / sinHalfTheta;
// calculate Quaternion.
qm.w() = (qa.w() * ratioA + qb.w() * ratioB);
qm.x() = (qa.x() * ratioA + qb.x() * ratioB);
qm.y() = (qa.y() * ratioA + qb.y() * ratioB);
qm.z() = (qa.z() * ratioA + qb.z() * ratioB);
return qm;
}
static auto from_axisangle(const axisangle_<T>& aa) {
using std::cos;
using std::sin;
const T sinHalfAngle(sin(aa.angle * T(0.5)));
return quaternion_<T>({
aa.axis.x() * sinHalfAngle, // x
aa.axis.y() * sinHalfAngle, // y
aa.axis.z() * sinHalfAngle, // z
cos(aa.angle * T(0.5)) // w
});
}
};
//
//
//
using quaternion = quaternion_<real_t>;
using quaternionf = quaternion_<float>;
using quaterniond = quaternion_<double>;
}
#endif
} // namespace pw
#if 0
/**
@ -412,9 +481,6 @@ const quaternion_<T> quaternion_<T>::slerp(const quaternion_<T>& qa,const quater
return qm;
}
#endif
#endif

View file

@ -28,18 +28,15 @@
namespace pw {
class resource {
public:
using change_t = std::atomic_int_fast64_t;
struct resource final {
resource() = default;
using change_t = std::atomic_int_fast64_t;
int64_t changecount() const { return _changecount; }
void dirty() { ++_changecount; };
constexpr int64_t changecount() const noexcept { return changecount_; }
void touch() { ++changecount_; };
protected:
change_t _changecount;
change_t changecount_{};
};
}

View file

@ -8,8 +8,8 @@
* 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 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,
@ -23,38 +23,53 @@
#ifndef PW_CORE_SERIALIZE_HPP
#define PW_CORE_SERIALIZE_HPP
#include "vector.hpp"
#include <pw/core/axisangle.hpp>
#include <pw/core/matrix.hpp>
#include <pw/core/quaternion.hpp>
#include <pw/core/vector.hpp>
#include <pw/core/color.hpp>
#include <string>
#include <sstream>
#include <string>
namespace pw {
struct serialize {
template <typename T,auto N>
template <typename T, auto N>
constexpr static std::string to_string(const vector<T, N>& v) {
std::stringstream ss;
for(const auto& e : v) ss << e << ' ';
for (const auto& e : v)
ss << e << ' ';
return ss.str();
}
template <typename T,auto R,auto C>
constexpr static std::string to_string(const matrix<T,R,C>& m) {
template <typename T, auto R, auto C>
constexpr static std::string to_string(const matrix<T, R, C>& m) {
std::stringstream ss;
for (int r = 0; r < R;r++) {
for (int r = 0; r < R; r++) {
ss << to_string(m[r]) << '\n';
}
return ss.str();
}
template <typename T>
constexpr static std::string to_string(const quaternion<T>& v) {
std::stringstream ss;
ss << to_string(v.q_);
return ss.str();
}
constexpr static std::string to_string(const color& v) {
std::stringstream ss;
ss << to_string(v.rgba);
return ss.str();
}
};
}
} // namespace pw
#endif

View file

@ -1,15 +1,13 @@
macro(make_test arg1)
add_executable(${arg1}
${arg1}.cpp
)
target_link_libraries(${arg1}
pwcore)
add_executable(${arg1} ${arg1}.cpp)
target_link_libraries(${arg1} pwcore)
endmacro()
# make_test(pwcore_test_matrix)
make_test(pwcore_test_vector)
make_test(pwcore_test_matrix)
make_test(pwcore_test_axisangle)
# make_test(pwcore_test_quaternion)
make_test(pwcore_test_quaternion)
make_test(pwcore_test_color)
# make_test(pwcore_test_transform_tools)
# make_test(pwcore_test_mesh)

View file

@ -0,0 +1,20 @@
#include <cstdio>
#include <pw/core/color.hpp>
#include <pw/core/debug.hpp>
#include <pw/core/serialize.hpp>
auto main() -> int {
pw::debug::d() << "pixwerx.color.test\n";
auto col = pw::color::from_rgb8888(255,0,0,255);
pw::debug::d() << "col -> \n" << pw::serialize::to_string(col);
auto col_hx = pw::color::from_rgb8888(0xFF'EE'BB'AA);
pw::debug::d() << "col_hx(0xFFAABBAA) -> \n" << pw::serialize::to_string(col_hx);
return 0;
}

View file

@ -1,130 +1,41 @@
#include <pw/core/matrix.hpp>
#include <pw/core/vector.hpp>
#include <pw/core/serialize.hpp>
#include <pw/core/debug.hpp>
#include <pw/core/matrix.hpp>
#include <pw/core/serialize.hpp>
#include <pw/core/vector.hpp>
#include <iostream>
#include <sstream>
auto main() -> int {
pw::debug::d() << "pixwerx.matrix.test\n";
int main(int argc,char **argv) {
auto m22 = pw::matrix<float, 2, 2>{};
pw::debug::d() << "matrix<2,2>{} -> \n" << pw::serialize::to_string(m22);
using namespace pw;
m22[0][0] = 1;
m22[0][1] = 2;
m22[1][0] = 3;
m22[1][1] = 4;
matrix2x2f m22; m22.zero();
pw::debug::d() << "matrix<2,2>{1,2,3,4} -> \n"
<< pw::serialize::to_string(m22);
auto m22_inv = m22.inverse();
m22(0,0) = 1; m22(0,1) = 2;
m22(1,0) = 3; m22(1,1) = 4;
pw::debug::d() << "matrix<2,2>{1,2,3,4}.inverse() -> \n"
<< pw::serialize::to_string(m22_inv);
vector2f v2;
v2[0] = 1; v2[1] = 3;
auto m22_inv_inv = m22_inv.inverse();
pw::debug::d() << "matrix<2,2>{1,2,3,4}.inverse().inverse() -> \n"
<< pw::serialize::to_string(m22_inv_inv);
vector2f v3( { 1.f,2.f } );
auto row_1 = m22_inv[1];
pw::debug::d() << "matrix<2,2>{1,2,3,4}.inverse()[1] -> \n"
<< pw::serialize::to_string(row_1);
auto m22_tp = m22.transposed();
pw::debug::d() << "matrix<2,2>{1,2,3,4}.transposed() -> \n"
<< pw::serialize::to_string(m22_tp);
auto m22_inv = m22.inverse();
auto m22_id = m22_inv * m22;
auto v2_t = m22_id * v2;
auto v3_t = m22_id * v3;
auto v2_f = m22 * v2;
auto v2_b = m22_inv * v2_f;
vector2_<float> r_m22 = m22.row(0).transposed();
vector2_<float> c_m22 = m22.column(1);
auto r_m22_h = r_m22.homogenous();
debug::d() << "offset(0,1) col-major " << m22.offset(0,1);
debug::d() << "det " << m22.determinant();
std::cout << "m22 " << pw::serialize::matrix(m22) << std::endl;
std::cout << "m22-1 " << pw::serialize::matrix(m22_inv) << std::endl;
std::cout << "m22-i " << pw::serialize::matrix(m22_id) << std::endl;
std::cout << "v22_t " << pw::serialize::matrix(v2_t) << std::endl;
std::cout << "v3_t " << pw::serialize::matrix(v3_t) << std::endl;
std::cout << "v2_f " << pw::serialize::matrix(v2_f) << std::endl;
std::cout << "v2_b " << pw::serialize::matrix(v2_b) << std::endl;
std::cout << "v2_b.norm " << v2_b.norm() << std::endl;
// v2_b.normalize();
std::cout << "v2_b.normalized " << pw::serialize::matrix(v2_b.normalized()) << std::endl;
// std::cout << "v2_b~v3_t " << rad_to_deg(vector2f::angle_between(v2,v3)) << std::endl;
// vector2f v2 = m22.slice<2,1>(0,0);
// m22.set_slice<2,1>(v2,0,0);
// v2 *= 2;
// v2 += 1;
// m22 *= 3;
// m22.determinant();
// debug::d() << sizeof(v2);
// auto m22_i = m22.inverse();
#if 0
pw::matrix4x4d m;
m.set_identity();
std::cout << "m = " << pw::serialize::matrix(m) << std::endl;
std::cout << "row_stride() : " << m.row_stride() << std::endl;
std::cout << "col_stride() : " << m.col_stride() << std::endl;
std::cout << "rows() : " << m.rows() << std::endl;
std::cout << "cols() : " << m.cols() << std::endl;
std::cout << "data() : " << m.data() << std::endl;
std::cout << "data()[0] : " << m.data()[0] << std::endl;
std::cout << "at(0,0) : " << m.at(0,0) << std::endl;
std::cout << "determinant(): " << m.determinant() << std::endl;
pw::matrix4x4d mi = m.get_inverse();
std::cout << "mi.at(0,0) : " << mi.at(0,0) << std::endl;
pw::matrix4x4d mscale = m * 4.2;
std::cout << "mscale = " << pw::serialize::matrix(mscale) << std::endl;
pw::matrix4x4d a;
for (int r = 0; r < m.rows(); r++) {
for (int c = 0; c < m.cols(); c++) {
a.at(r,c) = r * m.cols() + c;
}
}
std::cout << "a = " << pw::serialize::matrix(a) << std::endl;
pw::matrix4x4d r = a * mscale;
std::cout << "a * mscale = " << pw::serialize::matrix(r) << std::endl;
return 0;
#endif
auto m22_tp_col1 = m22_tp.column(1);
pw::debug::d() << "matrix<2,2>{1,2,3,4}.transposed().column(1) -> \n"
<< pw::serialize::to_string(m22_tp_col1);
}

View file

@ -1,29 +1,36 @@
#include <pw/core/debug.hpp>
#include <pw/core/quaternion.hpp>
#include <pw/core/serialize.hpp>
#include <iostream>
auto main() -> int {
int main(int argc,char **argv) {
pw::debug::d() << "pixwerx.quaternion.test\n";
pw::quaternion_<float> qf;
auto q0 = pw::quaternion<float>{};
auto q1 = pw::quaternion{1.f, 2.f, 3.f, 4.f};
std::cout << "qf = " << pw::serialize::matrix(qf) << std::endl;
std::cout << "qf.matrix() = " << pw::serialize::matrix(qf.to_matrix()) << std::endl;
pw::debug::d() << "q0 = quaternion{} -> \n" << pw::serialize::to_string(q0);
pw::debug::d() << "q1 = quaternion{1,2,3,4} -> \n"
<< pw::serialize::to_string(q1);
std::cout << "qf.squared_norm() = " << qf.squared_norm() << std::endl;
// std::cout << "qf.dot(qf) = " << qf.dot(qf) << std::endl;
std::cout << "qf.conjugate() = " << pw::serialize::matrix(qf.conjugate()) << std::endl;
auto q0_x_q1 = q0 * q1;
pw::debug::d() << "q0 * q1 -> \n" << pw::serialize::to_string(q0_x_q1);
pw::quaternionf qc = qf.conjugate();
std::cout << "qf.conjugate() (qc) = " << pw::serialize::matrix(qc.to_matrix()) << std::endl;
auto q1_conj = q1.conjugate();
pw::debug::d() << "q1.conjugate() -> \n"
<< pw::serialize::to_string(q1_conj);
pw::quaternionf qi = qf.inverse();
std::cout << "qf.inverse() (qi) = " << pw::serialize::matrix(qi.to_matrix()) << std::endl;
pw::quaternionf qmid = pw::quaternionf::normalized_lerp(qi,qf,0.5f);
// std::cout << "qmid.dot() (half between qf and qi) = " << pw::rad_to_deg(quaternionf::angle_between()) << std::endl;
auto q1_conj_nml = q1_conj.normalized();
pw::debug::d() << "q1.conjugate().normalized() -> \n"
<< pw::serialize::to_string(q1_conj_nml);
auto q1_conj_inv = q1_conj.inverse();
pw::debug::d() << "q1.conjugate().inverse() -> \n"
<< pw::serialize::to_string(q1_conj_inv);
auto lerp_q0_q1_half = decltype(q0)::lerp(q0, q1, 0.5f);
pw::debug::d() << "quaternion::lerp(q0,q1,0.5) -> \n"
<< pw::serialize::to_string(lerp_q0_q1_half);
return 0;

View file

@ -38,4 +38,4 @@ target_include_directories(
include
)
target_link_libraries(pwvisual pwscene glad)
target_link_libraries(pwvisual pwcore pwscene glad)