WIP
This commit is contained in:
parent
2919c47e99
commit
114f17a499
13 changed files with 327 additions and 519 deletions
|
@ -1,5 +1,5 @@
|
|||
# first build dependencies
|
||||
# add_subdirectory(deps)
|
||||
add_subdirectory(deps)
|
||||
|
||||
# build internal core
|
||||
add_subdirectory(core)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>{});
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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_{};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
20
src/core/tests/pwcore_test_color.cpp
Normal file
20
src/core/tests/pwcore_test_color.cpp
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -38,4 +38,4 @@ target_include_directories(
|
|||
include
|
||||
)
|
||||
|
||||
target_link_libraries(pwvisual pwscene glad)
|
||||
target_link_libraries(pwvisual pwcore pwscene glad)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue