start to refactor for C++23

This commit is contained in:
Hartmut Seichter 2024-06-06 23:45:53 +02:00
parent 42c7221318
commit cd19543627
19 changed files with 489 additions and 434 deletions

12
.clang-format Normal file
View file

@ -0,0 +1,12 @@
# We'll use defaults from the LLVM style, but with 4 columns indentation.
BasedOnStyle: LLVM
IndentWidth: 4
Language: Cpp
# Force pointers to the type for C++.
DerivePointerAlignment: false
PointerAlignment: Left
AlignConsecutiveAssignments: true
LambdaBodyIndentation: OuterScope

36
.vscode/settings.json vendored
View file

@ -16,7 +16,41 @@
"stdexcept": "cpp", "stdexcept": "cpp",
"streambuf": "cpp", "streambuf": "cpp",
"type_traits": "cpp", "type_traits": "cpp",
"tuple": "cpp" "tuple": "cpp",
"cmath": "cpp",
"span": "cpp",
"*.tcc": "cpp",
"*.inc": "cpp",
"*.ipp": "cpp",
"bit": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"format": "cpp",
"future": "cpp",
"optional": "cpp",
"ranges": "cpp",
"shared_mutex": "cpp",
"stop_token": "cpp",
"regex": "cpp",
"valarray": "cpp",
"*.def": "cpp",
"boundingsphere": "cpp",
"callback": "cpp",
"geometry": "cpp",
"node": "cpp",
"nodevisitor": "cpp",
"object": "cpp",
"plane": "cpp",
"program": "cpp",
"shape": "cpp",
"stateattribute": "cpp",
"observer_ptr": "cpp",
"thread": "cpp",
"concepts": "cpp",
"typeinfo": "cpp",
"drawable": "cpp",
"userdatacontainer": "cpp",
"*.txx": "cpp"
}, },
"mesonbuild.configureOnOpen": false "mesonbuild.configureOnOpen": false
} }

View file

@ -1,15 +1,15 @@
# #
# CMake build system for pixwerx # CMake build system for pixwerx
# #
cmake_minimum_required(VERSION 3.8) cmake_minimum_required(VERSION 3.28)
project(pixwerx) project(pixwerx)
# #
# pixwerx ist C++20 # pixwerx ist C++23
# #
set (CMAKE_CXX_STANDARD 20) set (CMAKE_CXX_STANDARD 23)
# internal cmake modules # internal cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/etc/cmake ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/etc/cmake ${CMAKE_MODULE_PATH})
@ -28,3 +28,4 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# #
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(share) add_subdirectory(share)
add_subdirectory(tests)

View file

@ -1,34 +1,27 @@
# pixwerx # pixwerx
pixwerx is an opinionated, academic approach to a 3D engine. It tries to mix pixwerx is an opinionated, academic approach to a 3D graphics engine. It mixes
modern andproven methods to build a fast and portable engine beyond pure 3D. modern and proven methods to build a fast and portable graphics system.
## Design Principles ## Design Principles
Dogdooding: pixwerx is built on the principle of dogfooding. The engine is a Dogfooding: pixwerx is built on the principle of dogfooding. The engine is a
full-stack system that tries to implement all necessary functions. The engine full-stack system that tries to implement all necessary functions. The engine
editor is just a UI build with the engine. editor is just a UI build with the engine.
Reasonable dependencies: like many engines pixwerx tries to include as much 3rd- Reasonable dependencies: like many engines pixwerx tries to include as much 3rd-party code as possible and implements some of the core systems itself.
party code as possible and implements some of the core systems itself.
No premature optimization: pixwerx implements only very few systems with machine No premature optimization: pixwerx implements only very few systems with machine code. It tries to utilize the power of the compiler as much as possible.
code. It tries to utilize the power of the compiler as much as possible.
Computer graphics 101: pixwerx does implement graphics components and systems in Computer graphics 101: pixwerx does implement graphics components and systems in a way that makes code portable and not over-parameterized. Usability is
a way that makes code portable and not over-parameterized. Usability is achieved through layers on top of the core components.
achieved through layers on top of the core components.
## License ## License
pixwerx is licenced under the terms of the MIT License. Please consult the pixwerx is licenced under the terms of the MIT License. Please consult the
LICENSE file. LICENSE file.
## Authors ## Authors
© 1999-2020 Hartmut Seichter © 1999-2020 Hartmut Seichter

View file

@ -1,4 +1,4 @@
find_package(mkdocs 1.0) # find_package(mkdocs 1.0)
# if(MKDOCS_FOUND) # if(MKDOCS_FOUND)
# configure_file(mkdocs.yml "${CMAKE_CURRENT_BINARY_DIR}/mkdocs.yml" COPYONLY) # configure_file(mkdocs.yml "${CMAKE_CURRENT_BINARY_DIR}/mkdocs.yml" COPYONLY)

View file

@ -1,15 +1,15 @@
# first build dependencies # first build dependencies
add_subdirectory(deps) # add_subdirectory(deps)
# build internal core # build internal core
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(scene) # add_subdirectory(scene)
add_subdirectory(system) # add_subdirectory(system)
add_subdirectory(io) # add_subdirectory(io)
#add_subdirectory(ui) #add_subdirectory(ui)
add_subdirectory(binding) # add_subdirectory(binding)
add_subdirectory(visual) # add_subdirectory(visual)
add_subdirectory(geometry) # add_subdirectory(geometry)
add_subdirectory(runtime) # add_subdirectory(runtime)

View file

@ -33,14 +33,14 @@ set(misc
set(srcs set(srcs
# src/buffer.cpp # src/buffer.cpp
src/core.cpp src/core.cpp
src/image.cpp # src/image.cpp
src/debug.cpp # src/debug.cpp
src/geometry.cpp # src/geometry.cpp
src/material.cpp # src/material.cpp
src/resource.cpp # src/resource.cpp
src/serialize.cpp # src/serialize.cpp
src/time.cpp # src/time.cpp
src/image.cpp # src/image.cpp
) )
add_library(pwcore add_library(pwcore
@ -58,5 +58,5 @@ target_include_directories(
target_link_libraries(pwcore) target_link_libraries(pwcore)
add_subdirectory(tests) # add_subdirectory(tests)

View file

@ -8,8 +8,8 @@
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@ -29,24 +29,12 @@ namespace pw {
struct aabb { struct aabb {
vector3 min; vector3 min{};
vector3 max; vector3 max{};
aabb(const vector3 min_vec,const vector3 max_vec)
: min(min_vec)
, max(max_vec)
{}
aabb() {
min.zero(); max.zero();
}
vector3 dimension() const {
return max - min;
}
constexpr vector3 dimension() const noexcept { return max - min; }
}; };
} } // namespace pw
#endif #endif

View file

@ -31,23 +31,12 @@ template <typename T>
struct axisangle_ { struct axisangle_ {
using value_type = T; using value_type = T;
using axis_type = vector3_<T>; using axis_type = vector3_<T>; // todo - should default to UP
axis_type axis; axis_type axis{};
T angle; T angle{};
axisangle_() static axisangle_ from_matrix(const matrix_<4,4,T>& m)
: axis(vector3_<T>::up()),
angle(0)
{}
axisangle_(vector3_<T> axis,T angle)
: axis(std::move(axis))
, angle(std::move(angle))
{
}
static const axisangle_ from_matrix(const matrix_<4,4,T>& m)
{ {
using std::acos; using std::acos;
using std::sqrt; using std::sqrt;

View file

@ -58,13 +58,10 @@ public:
using texture_t = std::tuple<texture_type,std::string,uint32_t>; using texture_t = std::tuple<texture_type,std::string,uint32_t>;
protected: protected:
vector4 _color = {{}, {1.0, 0.0, 1.0, 1.0}};
vector4 _color = vector4 { 1.0, 0.0, 1.0, 1.0 }; std::vector<texture_t> _textures;
std::vector<texture_t> _textures;
}; };

View file

@ -8,8 +8,8 @@
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@ -27,253 +27,213 @@
#include <pw/core/math.hpp> #include <pw/core/math.hpp>
#include <pw/core/matrixbase.hpp> #include <pw/core/matrixbase.hpp>
// #include <array>
#include <numeric> #include <numeric>
#include <array>
namespace pw namespace pw {
{
template <std::size_t R, std::size_t C, typename T, bool RowMajor = false> template <std::size_t R, std::size_t C, typename T, bool RowMajor = false>
struct matrix_ : matrixbase_<T, matrix_<R, C, T>> struct matrix_ : matrixbase_<T, matrix_<R, C, T>> {
{
T data[R * C];
using matrixbase_<T, matrix_<R, C, T>>::matrixbase_; using base_type = matrixbase_<T, matrix_<R, C, T>>;
using typename base_type::value_type;
using typename base_type::derived_type;
static constexpr std::size_t rows{R}; static constexpr std::size_t rows{R};
static constexpr std::size_t cols{C}; static constexpr std::size_t cols{C};
static constexpr std::size_t coefficients{R * C};
static constexpr std::size_t diagonal_size{std::min(R,C)};
static constexpr std::size_t coefficients{R * C}; using col_type = matrix_<R, 1, T>;
using row_type = matrix_<1, C, T>;
using diag_type = matrix_<diagonal_size, 1, T>;
using transpose_type = matrix_<C, R, T>;
using col_type = matrix_<R, 1, T>;
using row_type = matrix_<1, C, T>;
using transpose_type = matrix_<C, R, T>;
matrix_<R, C, T> &operator=(const matrix_<R, C, T> &other) value_type data[R * C]{};
{
for (size_t i = 0; i < other.size(); i++)
(*this)[i] = other[i];
return *this;
}
matrix_(std::initializer_list<T> args)
{
typename std::initializer_list<T>::iterator it = args.begin();
for (; it != args.end(); it++)
data[it - args.begin()] = *it;
}
template <typename... Arguments> template <typename... Arguments>
matrix_ &set(Arguments... values) static constexpr auto make(Arguments&&... values) -> matrix_ {
{ static_assert(sizeof...(Arguments) == coefficients,
static_assert(sizeof...(Arguments) == R * C, "Incorrect number of arguments"); "Incorrect number of arguments");
data = {values...}; return {.data = { T(values)... } };
return *this; }
}
inline size_t offset(size_t r, size_t c) const constexpr size_t offset(size_t r, size_t c) const noexcept {
{ return (RowMajor) ? r * C + c : c * R + r;
return (RowMajor) ? r * C + c : c * R + r; }
}
inline T &operator()(std::size_t r, std::size_t c) constexpr T& operator()(std::size_t r, std::size_t c) noexcept {
{ return data[offset(r, c)];
return data[offset(r, c)]; }
}
inline const T &operator()(std::size_t r, std::size_t c) const constexpr const T& operator()(std::size_t r, std::size_t c) const noexcept {
{ return data[offset(r, c)];
return data[offset(r, c)]; }
}
inline const T *ptr() const { return &data[0]; } constexpr const T* ptr() const noexcept { return &data[0]; }
//! set identity //! set identity
inline matrix_ &set_identity() constexpr matrix_& set_identity() {
{ for (std::size_t r = 0; r < rows; r++)
for (std::size_t r = 0; r < rows; r++) for (std::size_t c = 0; c < cols; c++)
for (std::size_t c = 0; c < cols; c++) (*this)(r, c) = (c == r) ? T(1) : T(0);
(*this)(r, c) = (c == r) ? T(1) : T(0); return *this;
return *this; }
}
inline matrix_ &set_uniform(const T& v) constexpr matrix_& set_uniform(const T& v) {
{ std::fill(std::begin(data), std::end(data), v);
std::fill(std::begin(data),std::end(data),v); return *this;
return *this; }
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor> template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
auto slice(std::size_t r, std::size_t c) const auto slice(std::size_t r, std::size_t c) const {
{ matrix_<Rs, Cs, T, RowMajorSlice> s;
matrix_<Rs, Cs, T, RowMajorSlice> s; for (std::size_t ri = 0; ri < Rs; ri++)
for (std::size_t ri = 0; ri < Rs; ri++) for (std::size_t ci = 0; ci < Cs; ci++)
for (std::size_t ci = 0; ci < Cs; ci++) s(ri, ci) = (*this)(ri + r, ci + c);
s(ri, ci) = (*this)(ri + r, ci + c); return s;
return s; }
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor> template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
matrix_ &set_slice(const matrix_<Rs, Cs, T, RowMajorSlice> &s, matrix_& set_slice(const matrix_<Rs, Cs, T, RowMajorSlice>& s,
std::size_t r, std::size_t c) std::size_t r, std::size_t c) {
{ for (std::size_t ri = 0; ri < Rs; ri++)
for (std::size_t ri = 0; ri < Rs; ri++) for (std::size_t ci = 0; ci < Cs; ci++)
for (std::size_t ci = 0; ci < Cs; ci++) (*this)(ri + r, ci + c) = s(ri, ci);
(*this)(ri + r, ci + c) = s(ri, ci); return *this;
return *this; }
}
template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor> template <std::size_t Rs, std::size_t Cs, bool RowMajorSlice = RowMajor>
auto minor(std::size_t r0, std::size_t c0) const auto minor(std::size_t r0, std::size_t c0) const {
{ matrix_<Rs, Cs, T, RowMajorSlice> m;
matrix_<Rs, Cs, T, RowMajorSlice> m; size_t r = 0;
size_t r = 0; for (size_t ri = 0; ri < R; ri++) {
for (size_t ri = 0; ri < R; ri++) size_t c = 0;
{ if (ri == r0)
size_t c = 0; continue;
if (ri == r0) for (size_t ci = 0; ci < C; ci++) {
continue; if (ci == c0)
for (size_t ci = 0; ci < C; ci++) continue;
{ m(r, c) = (*this)(ri, ci);
if (ci == c0) c++;
continue; }
m(r, c) = (*this)(ri, ci); r++;
c++; }
} return m;
r++; }
}
return m;
}
T determinant() const constexpr T determinant() const {
{ T det(0);
T det(0); for (size_t c = 0; c < C; c++)
for (size_t c = 0; c < C; c++) det += ((c % 2 == 0) ? (*this)(0, c) : -(*this)(0, c)) *
det += ((c % 2 == 0) ? (*this)(0, c) : -(*this)(0, c)) * this->minor<R - 1, C - 1, RowMajor>(0, c).determinant(); this->minor<R - 1, C - 1, RowMajor>(0, c).determinant();
return det; return det;
} }
auto transposed() const auto transposed() const {
{ transpose_type res;
transpose_type res; for (size_t r = rows; r-- > 0;)
for (size_t r = rows; r-- > 0;) for (size_t c = cols; c-- > 0;)
for (size_t c = cols; c-- > 0;) res(c, r) = (*this)(r, c);
res(c, r) = (*this)(r, c); return res;
return res; }
}
auto inverse() const auto inverse() const {
{ T invDet = T(1) / this->determinant();
T invDet = T(1) / this->determinant(); matrix_<R, C, T, RowMajor> inv;
matrix_<R, C, T, RowMajor> inv; for (int j = 0; j < C; j++)
for (int j = 0; j < C; j++) for (int i = 0; i < R; i++) {
for (int i = 0; i < R; i++) const T minorDet =
{ this->minor<R - 1, C - 1, RowMajor>(j, i).determinant();
const T minorDet = this->minor<R - 1, C - 1, RowMajor>(j, i).determinant(); const T coFactor = ((i + j) % 2 == 1) ? -minorDet : minorDet;
const T coFactor = ((i + j) % 2 == 1) ? -minorDet : minorDet; inv(i, j) = invDet * coFactor;
inv(i, j) = invDet * coFactor; }
} return inv;
return inv; }
}
inline bool row_major() const constexpr bool row_major() const { return RowMajor; }
{
return RowMajor;
}
inline bool square() const { return R == C; } constexpr bool square() const { return R == C; }
inline const matrix_ operator+(const matrix_ &other) const constexpr const matrix_ operator+(const matrix_& other) const {
{ matrix_ res(*this);
matrix_ res(*this); for (size_t r = 0; r < R; r++)
for (size_t r = 0; r < R; r++) for (size_t c = 0; c < C; c++)
for (size_t c = 0; c < C; c++) res(r, c) += other(r, c);
res(r, c) += other(r, c); return res;
return res; }
}
inline const matrix_ operator-(const matrix_ &other) const constexpr const matrix_ operator-(const matrix_& other) const {
{ matrix_ res(*this);
matrix_ res(*this); for (size_t r = 0; r < R; r++)
for (size_t r = 0; r < R; r++) for (size_t c = 0; c < C; c++)
for (size_t c = 0; c < C; c++) res(r, c) -= other(r, c);
res(r, c) -= other(r, c); return res;
return res; }
}
auto row(size_t row_) const auto row(size_t row_) const {
{ row_type r;
row_type r; for (size_t i = 0; i < cols; i++)
for (size_t i = 0; i < cols; i++) r[i] = (*this)(row_, i);
r[i] = (*this)(row_, i); return r;
return r; }
}
auto column(size_t col_) const auto column(size_t col_) const {
{ col_type c;
col_type c; for (size_t i = 0; i < rows; i++)
for (size_t i = 0; i < rows; i++) c[i] = (*this)(i, col_);
c[i] = (*this)(i, col_); return c;
return c; }
}
static constexpr auto identity() static constexpr auto identity() {
{ matrix_ res;
matrix_ res; for (std::size_t r = 0; r < rows; r++)
for (std::size_t r = 0; r < rows; r++) for (std::size_t c = 0; c < cols; c++)
for (std::size_t c = 0; c < cols; c++) res(r, c) = (c == r) ? T(1) : T(0);
res(r, c) = (c == r) ? T(1) : T(0); return res;
return res; }
} };
};
template <> template <> constexpr float matrix_<1, 1, float>::determinant() const {
inline float matrix_<1, 1, float>::determinant() const return (*this)(0, 0);
{
return (*this)(0, 0);
}
template <>
inline double matrix_<1, 1, double>::determinant() const
{
return (*this)(0, 0);
}
template <typename T, std::size_t R, std::size_t Ca, std::size_t Cb>
auto operator*(const matrix_<R, Ca, T> &A,
const matrix_<R, Cb, T> &B)
{
matrix_<R, Cb, T> 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;
}
//
// common matrix types
//
template <typename T>
using matrix2x2_ = matrix_<2, 2, T>;
template <typename T>
using matrix3x3_ = matrix_<3, 3, T>;
template <typename T>
using matrix4x4_ = matrix_<4, 4, T>;
using matrix2x2f = matrix2x2_<float>;
using matrix2x2d = matrix2x2_<double>;
using matrix2x2 = matrix2x2_<real_t>;
using matrix3x3f = matrix3x3_<float>;
using matrix3x3d = matrix3x3_<double>;
using matrix3x3 = matrix3x3_<real_t>;
using matrix4x4f = matrix4x4_<float>;
using matrix4x4d = matrix4x4_<double>;
using matrix4x4 = matrix4x4_<real_t>;
} }
template <> constexpr double matrix_<1, 1, double>::determinant() const {
return (*this)(0, 0);
}
template <typename T, std::size_t R, std::size_t Ca, std::size_t Cb>
auto operator*(const matrix_<R, Ca, T>& A, const matrix_<R, Cb, T>& B) {
matrix_<R, Cb, T> 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;
}
//
// common matrix types
//
template <typename T> using matrix2x2_ = matrix_<2, 2, T>;
template <typename T> using matrix3x3_ = matrix_<3, 3, T>;
template <typename T> using matrix4x4_ = matrix_<4, 4, T>;
using matrix2x2f = matrix2x2_<float>;
using matrix2x2d = matrix2x2_<double>;
using matrix2x2 = matrix2x2_<real_t>;
using matrix3x3f = matrix3x3_<float>;
using matrix3x3d = matrix3x3_<double>;
using matrix3x3 = matrix3x3_<real_t>;
using matrix4x4f = matrix4x4_<float>;
using matrix4x4d = matrix4x4_<double>;
using matrix4x4 = matrix4x4_<real_t>;
} // namespace pw
#endif #endif

View file

@ -30,8 +30,7 @@ namespace pw {
template <typename T> template <typename T>
struct matrix_transform { struct matrix_transform {
inline static constexpr static matrix_<4,4,T> scale_matrix(const vector3_<T>& s) noexcept
matrix_<4,4,T> scale_matrix(const vector3_<T>& s)
{ {
matrix_<4,4,T> scale; scale.zero(); matrix_<4,4,T> scale; scale.zero();
scale(0,0) = s[0]; scale(1,1) = s[1]; scale(2,2) = s[2]; scale(3,3) = T(1); scale(0,0) = s[0]; scale(1,1) = s[1]; scale(2,2) = s[2]; scale(3,3) = T(1);

View file

@ -24,93 +24,97 @@
#define PW_CORE_MATRIXBASE_HPP #define PW_CORE_MATRIXBASE_HPP
#include <algorithm> #include <algorithm>
#include <iostream>
#include <iterator> #include <iterator>
#include <numeric> #include <numeric>
#include <type_traits> #include <type_traits>
#include <utility>
#include <initializer_list>
#include <cmath> #include <cmath>
#include <iostream>
namespace pw { namespace pw {
template <typename T, typename Derived> template <typename T, typename Derived>
struct matrixbase_ { struct matrixbase_ {
using value_type = T; using value_type = T;
using derived_type = Derived;
using iterator = value_type*;
using const_iterator = const value_type*;
Derived& derived() { return static_cast<Derived&>(*this); } constexpr Derived& derived() noexcept { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); } constexpr const Derived& derived() const noexcept { return static_cast<const Derived&>(*this); }
std::size_t size() const { constexpr std::size_t size() const noexcept {
return std::extent<decltype(Derived::data)>::value; return std::extent<decltype(Derived::data)>::value;
} }
Derived& fill(const T& v) { constexpr Derived& fill(const T& v) noexcept {
std::fill(std::begin(derived().data), std::end(derived().data), T(v)); std::fill(std::begin(derived().data), std::end(derived().data), T(v));
return derived(); return derived();
} }
Derived& zero() { constexpr Derived& zero() {
return derived().fill(0); return derived().fill(0);
} }
inline T squared_norm() const { constexpr T squared_norm() const noexcept {
return std::accumulate(std::begin(derived().data),std::end(derived().data), T(0), return std::accumulate(std::begin(derived().data),std::end(derived().data), T(0),
[&](const T& a,const T& b){ [&](const T& a,const T& b){
return a + b * b; return a + b * b;
}); });
} }
inline T norm() const { 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()); return std::sqrt(squared_norm());
} }
inline constexpr Derived normalized() const { constexpr Derived normalized() const noexcept {
return *this / this->norm() ; return *this / this->norm() ;
} }
inline void normalize() { constexpr void normalize() {
*this /= this->norm(); *this /= this->norm();
} }
using iterator = T*;
using const_iterator = const T*;
iterator begin() { return &derived().data[0]; }
iterator end() { return &derived().data[0] + size(); }
const_iterator begin() const { return &derived().data[0]; }
const_iterator end() const { return &derived().data[0] + size(); }
T& operator [] (std::size_t i) { 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]; return derived().data[i];
} }
const T& operator [] (std::size_t i) const { constexpr const T& operator [] (std::size_t i) const {
return derived().data[i]; return derived().data[i];
} }
static constexpr T dot(const Derived &a,const Derived &b) 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)); 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) static constexpr Derived lerp(const Derived &a,const Derived &b,const T& t) noexcept
{ {
return a + (b - a) * t; return a + (b - a) * t;
} }
inline void operator *= (const T& b) { for (auto & e : *this) e *= b; } constexpr void operator *= (const T& b) { for (auto & e : *this) e *= b; }
inline void operator /= (const T& b) { for (auto & e : *this) e /= b; } constexpr void operator /= (const T& b) { for (auto & e : *this) e /= b; }
inline void operator += (const T& b) { for (auto & e : *this) e += b; } constexpr void operator += (const T& b) { for (auto & e : *this) e += b; }
inline void operator -= (const T& b) { for (auto & e : *this) e -= b; } constexpr void operator -= (const T& b) { for (auto & e : *this) e -= b; }
inline const Derived operator * (const T& b) const { Derived r(derived()); for (auto & e : r) e *= b; return r; } constexpr const Derived operator * (const T& b) const { Derived r(derived()); for (auto & e : r) e *= b; return r; }
inline const Derived operator / (const T& b) const { Derived r(derived()); for (auto & e : r) e /= b; return r; } constexpr const Derived operator / (const T& b) const { Derived r(derived()); for (auto & e : r) e /= b; return r; }
inline const Derived operator + (const T& b) const { Derived r(derived()); for (auto & e : r) e += b; return r; } constexpr const Derived operator + (const T& b) const { Derived r(derived()); for (auto & e : r) e += b; return r; }
inline const Derived operator - (const T& b) const { Derived r(derived()); for (auto & e : r) e -= b; return r; } constexpr const Derived operator - (const T& b) const { Derived r(derived()); for (auto & e : r) e -= b; return r; }
}; };

View file

@ -8,8 +8,8 @@
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@ -31,138 +31,130 @@ namespace pw {
* Basic vector types used in pixwerx. * Basic vector types used in pixwerx.
*/ */
template <typename T> template <typename T> struct vector2_ : matrix_<2, 1, T> {
struct vector2_ : matrix_<2,1,T> {
typedef matrix_<2,1,T> base_type; using base_type = matrix_<2, 1, T>;
using base_type::base_type; using base_type::base_type;
using base_type::operator = ; using base_type::operator=;
vector2_(const base_type& m) : base_type(m) {} vector2_(const base_type& m) : base_type(m) {}
vector2_(T x_,T y_) : base_type({x_,y_}) {} vector2_(T x_, T y_) : base_type({x_, y_}) {}
inline const T& x() const { return (*this)[0]; } constexpr const T& x() const { return (*this)[0]; }
inline T& x() { return (*this)[0]; } constexpr T& x() { return (*this)[0]; }
inline const T& y() const { return (*this)[1]; } constexpr const T& y() const { return (*this)[1]; }
inline T& y() { return (*this)[1]; } constexpr T& y() { return (*this)[1]; }
inline auto homogenous(T w = 1) const { return matrix_<3,1,T>( { x(),y(),w } ); } constexpr 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() ) );
} }
static constexpr auto zero() { return vector2_<T>(0,0); } 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> {
typedef matrix_<3,1,T> base_type;
using base_type::base_type;
using base_type::operator = ;
vector3_() : base_type() {}
vector3_(const base_type& m) : base_type(m) {}
vector3_(T x_,T y_,T z_) : base_type({x_,y_,z_}) {}
vector3_(const vector2_<T> &m, T w) : base_type({m(0),m(1),w}) {}
inline const T& x() const { return (*this)[0]; }
inline T& x() { return (*this)[0]; }
inline vector3_& set_x(T val) { (*this)[0] = val; return *this;}
inline const T& y() const { return (*this)[1]; }
inline T& y() { return (*this)[1]; }
inline vector3_& set_y(T val) { (*this)[1] = val; return *this;}
inline const T& z() const { return (*this)[2]; }
inline T& z() { return (*this)[2]; }
inline vector3_& set_z(T val) { (*this)[2] = val; return *this;}
inline auto xy() const { return vector2_( { x(),y() } ); }
inline auto homogenous(T w = 1) const { return matrix_<4,1,T>( { x(),y(),z(),w } ); }
inline 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 zero() { return vector2_<T>(0, 0); }
inline static constexpr vector3_<T> forward() { return vector3_<T> ( { T(0), T(0),-T(1) } ); }
inline static constexpr vector3_<T> backward() { return vector3_<T>( { T(0), T(0), T(1) } ); }
inline static constexpr vector3_<T> right() { return vector3_<T> ( { T(1), T(0), T(0) } ); }
inline static constexpr vector3_<T> left() { return vector3_<T> ( {-T(1), T(0), T(0) } ); }
inline static constexpr vector3_<T> up() { return vector3_<T> ( { T(0), T(1), T(0) } ); }
inline static constexpr vector3_<T> down() { return vector3_<T> ( { T(0),-T(1), T(0) } ); }
inline static vector3_<T> x_axis() { return vector3_<T> ( { T(1), T(0), T(0) } ); }
inline static vector3_<T> y_axis() { return vector3_<T> ( { T(0), T(1), T(0) } ); }
inline static vector3_<T> z_axis() { return vector3_<T> ( { T(0), T(0), T(1) } ); }
static constexpr auto zero() { return vector3_(0,0,0); }
}; };
template <typename T> template <typename T> struct vector3_ : matrix_<3, 1, T> {
struct vector4_ : matrix_<4,1,T> {
typedef matrix_<4,1,T> base_type; typedef matrix_<3, 1, T> base_type;
using base_type::base_type; // using base_type::base_type;
using base_type::operator = ; // using base_type::operator=;
vector4_(T x_,T y_,T z_,T w_) : base_type( {x_,y_,z_,w_} ) {} constexpr const T& x() const { return (*this)[0]; }
vector4_(const base_type& m) : base_type(m) {} constexpr T& x() { return (*this)[0]; }
vector4_(const vector3_<T> &m, T w) : base_type({m(0),m(1),m(2),w}) {} constexpr vector3_& set_x(T val) {
(*this)[0] = val;
return *this;
}
inline const T& x() const { return (*this)[0]; } constexpr const T& y() const { return (*this)[1]; }
inline T& x() { return (*this)[0]; } constexpr T& y() { return (*this)[1]; }
constexpr vector3_& set_y(T val) {
(*this)[1] = val;
return *this;
}
inline const T& y() const { return (*this)[1]; } constexpr const T& z() const { return (*this)[2]; }
inline T& y() { return (*this)[1]; } constexpr T& z() { return (*this)[2]; }
constexpr vector3_& set_z(T val) {
(*this)[2] = val;
return *this;
}
inline const T& z() const { return (*this)[2]; } constexpr auto xy() const { return vector2_({x(), y()}); }
inline T& z() { return (*this)[2]; } constexpr auto homogenous(T w = 1) const {
return matrix_<4, 1, T>::make(x(), y(), z(), w);
}
inline const T& w() const { return (*this)[3]; } constexpr static vector3_ cross(const vector3_& lhs, const vector3_& rhs) {
inline T& w() { return (*this)[3]; } return vector3_::make(lhs[1] * rhs[2] - rhs[1] * lhs[2],
lhs[2] * rhs[0] - rhs[2] * lhs[0],
lhs[0] * rhs[1] - rhs[0] * lhs[1]);
}
inline auto xyz() const { return vector3_<T>({ x(),y(),z() } ); } constexpr static auto forward() { return vector3_<T>::make(0, 0, -1); }
constexpr static auto backward() { return vector3_<T>::make(0, 0, +1); }
constexpr static auto up() { return vector3_<T>::make(0, +1, 0); }
constexpr static auto down() { return vector3_<T>::make(0, -1, 0); }
constexpr static auto right() { return vector3_<T>::make(+1, 0, 0); }
constexpr static auto left() { return vector3_<T>::make(-1, 0, 0); }
constexpr static auto x_axis() { return vector3_<T>::make(0, 0, +1); }
constexpr static auto y_axis() { return vector3_<T>::make(0, 0, +1); }
constexpr static auto z_axis() { return vector3_<T>::make(0, 0, +1); }
inline auto project() const { return vector3_<T>({ x()/w(),y()/w(),z()/w() } ); } static constexpr auto zero() { return vector3_(0, 0, 0); }
};
static constexpr auto zero() { return vector2_<T>(0,0,0,0); } template <typename T> struct vector4_ : matrix_<4, 1, T> {
using base_type = matrix_<4, 1, T>;
// using base_type::operator=;
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 const T& z() const { return (*this)[2]; }
constexpr T& z() { return (*this)[2]; }
constexpr const T& w() const { return (*this)[3]; }
constexpr T& w() { return (*this)[3]; }
constexpr auto xyz() const { return vector3_<T>::make(x(), y(), z()); }
constexpr auto project() const {
return vector3_<T>::make(x() / w(), y() / w(), z() / w());
}
static constexpr auto zero() { return vector2_<T>(0, 0, 0, 0); }
}; };
// //
// //
// //
using vector2f = vector2_<float>; using vector2f = vector2_<float>;
using vector2d = vector2_<double>; using vector2d = vector2_<double>;
using vector2i = vector2_<int>; using vector2i = vector2_<int>;
using vector2 = vector2_<real_t>; using vector2 = vector2_<real_t>;
using vector2_array = std::vector<vector2>; using vector2_array = std::vector<vector2>;
using vector3f = vector3_<float>; using vector3f = vector3_<float>;
using vector3d = vector3_<double>; using vector3d = vector3_<double>;
using vector3 = vector3_<real_t>; using vector3 = vector3_<real_t>;
using vector3_array = std::vector<vector3>; using vector3_array = std::vector<vector3>;
using vector4f = vector4_<float>; using vector4f = vector4_<float>;
using vector4d = vector4_<double>; using vector4d = vector4_<double>;
using vector4 = vector4_<real_t>; using vector4 = vector4_<real_t>;
} } // namespace pw
#endif #endif

View file

@ -3,6 +3,7 @@
#include <limits> #include <limits>
#include <random> #include <random>
#include <algorithm>
namespace pw { namespace pw {

View file

@ -7,9 +7,9 @@ macro(make_test arg1)
endmacro() endmacro()
make_test(pwcore_test_matrix) # make_test(pwcore_test_matrix)
make_test(pwcore_test_vector) # make_test(pwcore_test_vector)
make_test(pwcore_test_axisangle) # make_test(pwcore_test_axisangle)
make_test(pwcore_test_quaternion) # make_test(pwcore_test_quaternion)
make_test(pwcore_test_transform_tools) # make_test(pwcore_test_transform_tools)
make_test(pwcore_test_mesh) # make_test(pwcore_test_mesh)

View file

@ -28,8 +28,6 @@ scene::scene()
// size_t scene::count_all_enties() const // size_t scene::count_all_enties() const
// { // {
// return _registry->storage().
// size_t scene::count_alive_enties() const // size_t scene::count_alive_enties() const
// { // {
// return _registry->storage().alive(); // return _registry->storage().alive();

21
tests/CMakeLists.txt Normal file
View file

@ -0,0 +1,21 @@
include(FetchContent)
FetchContent_Declare(snitch
GIT_REPOSITORY https://github.com/snitch-org/snitch.git
GIT_TAG v1.2.5) # update version number as needed
FetchContent_MakeAvailable(snitch)
set(pixwerx_test_files
pw_test_core.cpp
)
add_executable(pixwerx_tests ${pixwerx_test_files})
target_link_libraries(pixwerx_tests PRIVATE
snitch::snitch
pwcore
)

66
tests/pw_test_core.cpp Normal file
View file

@ -0,0 +1,66 @@
#include <snitch/snitch.hpp>
#include <pw/core/matrix.hpp>
#include <pw/core/vector.hpp>
TEST_CASE("core", "[matrix]") {
auto m44 = pw::matrix_<2, 2, float>{};
REQUIRE(m44(0, 0) == 0);
REQUIRE(m44(0, 1) == 0);
REQUIRE(m44(1, 0) == 0);
REQUIRE(m44(1, 1) == 0);
m44 = pw::matrix2x2_<float>::all(42.42f);
REQUIRE(m44(0, 0) == 42.42f);
REQUIRE(m44(0, 1) == 42.42f);
REQUIRE(m44(1, 0) == 42.42f);
REQUIRE(m44(1, 1) == 42.42f);
m44 *= 2;
REQUIRE(m44(0, 0) == 84.84f);
REQUIRE(m44(0, 1) == 84.84f);
REQUIRE(m44(1, 0) == 84.84f);
REQUIRE(m44(1, 1) == 84.84f);
m44.set_identity();
REQUIRE(m44(0, 0) == 1.0f);
REQUIRE(m44(0, 1) == 0.0f);
REQUIRE(m44(1, 0) == 0.0f);
REQUIRE(m44(1, 1) == 1.0f);
auto m44_2 = pw::matrix2x2::make(0, 1, 2, 3);
REQUIRE(m44_2(0, 0) == 0.0f);
REQUIRE(m44_2(1, 0) == 1.0f);
REQUIRE(m44_2(0, 1) == 2.0f);
REQUIRE(m44_2(1, 1) == 3.0f);
pw::matrix2x2 m44_3 = {{},{1, 2, 3, 4}};
REQUIRE(m44_3(0, 0) == 1.0f);
REQUIRE(m44_3(1, 0) == 2.0f);
REQUIRE(m44_3(0, 1) == 3.0f);
REQUIRE(m44_3(1, 1) == 4.0f);
}
TEST_CASE("core", "[vector]") {
auto vec4_1 = pw::vector4_<float>{};
auto vec4_2 = pw::vector4::make(1, 2, 3, 4);
auto vec4_3 = vec4_1 + vec4_2;
REQUIRE(vec4_3[0] == 1.0f);
REQUIRE(vec4_3[1] == 2.0f);
REQUIRE(vec4_3[2] == 3.0f);
REQUIRE(vec4_3[3] == 4.0f);
}