diff --git a/source/hyporo/gpu/context.hpp b/source/hyporo/gpu/context.hpp index 821ed64..487636d 100644 --- a/source/hyporo/gpu/context.hpp +++ b/source/hyporo/gpu/context.hpp @@ -28,7 +28,8 @@ public: Context(DeviceAPI api); - virtual ~Context(); + virtual + ~Context(); // Member functions diff --git a/source/hyporo/gpu/device.cpp b/source/hyporo/gpu/device.cpp index 981a70d..694dfb5 100644 --- a/source/hyporo/gpu/device.cpp +++ b/source/hyporo/gpu/device.cpp @@ -8,16 +8,16 @@ namespace hpr::gpu Device::Device() : Context {DeviceAPI::Unknown}, - p_currentVertexBuffer {nullptr}, - p_currentIndexBuffer {nullptr}, - p_currentShaderProgram {nullptr} + p_currentVertexBuffer {}, + p_currentIndexBuffer {}, + p_currentShaderProgram {} {} Device::Device(DeviceAPI api) : Context {api}, - p_currentVertexBuffer {nullptr}, - p_currentIndexBuffer {nullptr}, - p_currentShaderProgram {nullptr} + p_currentVertexBuffer {}, + p_currentIndexBuffer {}, + p_currentShaderProgram {} {} Device::~Device() @@ -28,16 +28,16 @@ Device::~Device() void Device::create(Device** device, DeviceAPI api) { if (device == nullptr) - throw "Invalid parameter"; + throw std::invalid_argument("Invalid parameter 'nullptr'"); if (api == DeviceAPI::Unknown) - throw "Invalid parameter"; + throw std::invalid_argument("Cannot create device for 'Unknown'"); *device = nullptr; if (api == DeviceAPI::OpenGL) *device = new opengl::Device; else - throw "Unsupported device"; + throw std::invalid_argument("Unsupported device"); } // Buffers diff --git a/source/hyporo/gpu/device.hpp b/source/hyporo/gpu/device.hpp index a939a8f..375ed9c 100644 --- a/source/hyporo/gpu/device.hpp +++ b/source/hyporo/gpu/device.hpp @@ -6,7 +6,7 @@ #include "shader_program.hpp" #include "texture.hpp" -#include +#include "../hyplib/array/array.hpp" namespace hpr::gpu @@ -27,10 +27,10 @@ public: protected: - std::vector p_buffers; - std::vector p_shaders; - std::vector p_shaderPrograms; - std::vector p_textures; + darray p_buffers; + darray p_shaders; + darray p_shaderPrograms; + darray p_textures; Buffer* p_currentVertexBuffer; Buffer* p_currentIndexBuffer; diff --git a/source/hyporo/gpu/glfw/monitor.cpp b/source/hyporo/gpu/glfw/monitor.cpp new file mode 100644 index 0000000..63a4070 --- /dev/null +++ b/source/hyporo/gpu/glfw/monitor.cpp @@ -0,0 +1,5 @@ +// +// Created by L-Nafaryus on 10/27/2022. +// + +#include "monitor.hpp" diff --git a/source/hyporo/gpu/glfw/monitor.hpp b/source/hyporo/gpu/glfw/monitor.hpp new file mode 100644 index 0000000..068371f --- /dev/null +++ b/source/hyporo/gpu/glfw/monitor.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "../monitor.hpp" + + +namespace hpr::gpu::glfw +{ + +class Monitor : public gpu::Monitor +{ + +}; + +} \ No newline at end of file diff --git a/source/hyporo/gpu/glfw/window.cpp b/source/hyporo/gpu/glfw/window.cpp new file mode 100644 index 0000000..71ec96e --- /dev/null +++ b/source/hyporo/gpu/glfw/window.cpp @@ -0,0 +1,5 @@ +// +// Created by L-Nafaryus on 10/27/2022. +// + +#include "window.hpp" diff --git a/source/hyporo/gpu/glfw/window.hpp b/source/hyporo/gpu/glfw/window.hpp new file mode 100644 index 0000000..2695d9f --- /dev/null +++ b/source/hyporo/gpu/glfw/window.hpp @@ -0,0 +1,8 @@ +// +// Created by L-Nafaryus on 10/27/2022. +// + +#ifndef HYPORO_WINDOW_HPP +#define HYPORO_WINDOW_HPP + +#endif //HYPORO_WINDOW_HPP diff --git a/source/hyporo/gpu/glfw/window_system.cpp b/source/hyporo/gpu/glfw/window_system.cpp new file mode 100644 index 0000000..06171e1 --- /dev/null +++ b/source/hyporo/gpu/glfw/window_system.cpp @@ -0,0 +1,5 @@ +// +// Created by L-Nafaryus on 10/27/2022. +// + +#include "window_system.hpp" diff --git a/source/hyporo/gpu/glfw/window_system.hpp b/source/hyporo/gpu/glfw/window_system.hpp new file mode 100644 index 0000000..16cac12 --- /dev/null +++ b/source/hyporo/gpu/glfw/window_system.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "../window_system.hpp" + +#include + + +namespace hpr::gpu::glfw +{ + +class WindowSystem : public gpu::WindowSystem +{ + +protected: + + GLFWwindow p_instance; + +public: + + WindowSystem(); + + ~WindowSystem(); + + virtual + void newWindow(Window** window); +}; + +} \ No newline at end of file diff --git a/source/hyporo/gpu/monitor.cpp b/source/hyporo/gpu/monitor.cpp new file mode 100644 index 0000000..cb5db9a --- /dev/null +++ b/source/hyporo/gpu/monitor.cpp @@ -0,0 +1,44 @@ +#include "monitor.hpp" + + +namespace hpr::gpu +{ + +Monitor::Monitor() : + WindowContext(Provider::Unknown), + p_deviceName {}, + p_originX {0}, + p_originY {0}, + p_width {0}, + p_height {0}, + p_logicalWidth {0}, + p_logicalHeight {0} +{} + +Monitor::~Monitor() = default; + +void Monitor::origin(int x, int y) +{ + p_originX = x; + p_originY = y; +} + +void Monitor::size(int width, int height) +{ + p_width = width; + p_height = height; +} + +void Monitor::logicalSize(int width, int height) +{ + p_logicalWidth = width; + p_logicalHeight = height; +} + +void Monitor::deviceName(const std::string &name) +{ + p_deviceName = name; +} + + +} \ No newline at end of file diff --git a/source/hyporo/gpu/monitor.hpp b/source/hyporo/gpu/monitor.hpp new file mode 100644 index 0000000..c466ea7 --- /dev/null +++ b/source/hyporo/gpu/monitor.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include "window_context.hpp" + +#include + + +namespace hpr::gpu +{ + +class Monitor : WindowContext +{ + +protected: + + std::string p_deviceName; + int p_originX; + int p_originY; + int p_width; + int p_height; + int p_logicalWidth; + int p_logicalHeight; + +public: + + Monitor(); + + virtual + ~Monitor(); + + // Member functions + + void origin(int x, int y); + void size(int width, int height); + void logicalSize(int width, int height); + void deviceName(const std::string& name); + + inline + int width() const + { + return p_width; + } + + inline + int height() const + { + return p_height; + } + + inline + int logicalWidth() const + { + return p_logicalWidth; + } + + inline + int logicalHeight() const + { + return p_logicalHeight; + } + + inline + int originX() const + { + return p_originX; + } + + inline + int originY() const + { + return p_originY; + } + + inline + std::string deviceName() const + { + return p_deviceName; + } + +}; + +} \ No newline at end of file diff --git a/source/hyporo/gpu/opengl/device.hpp b/source/hyporo/gpu/opengl/device.hpp index 7f1410c..24dc557 100644 --- a/source/hyporo/gpu/opengl/device.hpp +++ b/source/hyporo/gpu/opengl/device.hpp @@ -19,7 +19,7 @@ public: Device(); - ~Device(); + ~Device() override; // Member functions diff --git a/source/hyporo/gpu/shader_program.hpp b/source/hyporo/gpu/shader_program.hpp index 4ae25ae..85f2155 100644 --- a/source/hyporo/gpu/shader_program.hpp +++ b/source/hyporo/gpu/shader_program.hpp @@ -3,7 +3,7 @@ #include "context.hpp" #include "shader.hpp" -#include +#include "../hyplib/array/array.hpp" namespace hpr::gpu @@ -15,7 +15,7 @@ class ShaderProgram : public Context protected: - std::array p_slots; + sarray p_slots; bool p_isLinked; public: diff --git a/source/hyporo/gpu/window.cpp b/source/hyporo/gpu/window.cpp new file mode 100644 index 0000000..5daf32e --- /dev/null +++ b/source/hyporo/gpu/window.cpp @@ -0,0 +1,103 @@ +#include "window.hpp" + + +namespace hpr::gpu +{ + +Window::Window() : + WindowContext(Provider::Unknown), + p_width {0}, + p_height {0}, + p_posX {0}, + p_posY {0}, + p_title {}, + p_state {State::Hidden}, + p_style {Style::Unknown}, + p_parent {nullptr}, + p_monitor {nullptr}, + p_isActive {true}, + p_isResizing {false} +{} + +Window::~Window() = default; + +void Window::init(const std::string& title, Style style, int x, int y, int width, int height, Window* parent, Monitor* monitor) +{ + p_width = width; + p_height = height; + p_posX = x; + p_posY = y; + + p_title = title; + p_state = State::Hidden; + p_style = style; + + p_parent = parent; + p_monitor = monitor; +} + +void Window::init(const std::string& title, Style style, Window* parent, Monitor* monitor) +{ + init(title, style, monitor->originX(), monitor->originY(), monitor->width(), monitor->height(), parent, monitor); +} + +void Window::state(State state) +{ + p_state = state; +} + +void Window::close() +{ + state(State::Closed); +} + +void Window::restore() +{ + State prevState {p_state}; + init(p_title, p_style, p_posX, p_posY, p_width, p_height, p_parent, p_monitor); + state(prevState); +} + +bool Window::isOpen() const +{ + return p_state != State::Closed; +} + +bool Window::isActive() const +{ + return p_isActive; +} + +void Window::size(int width, int height) +{ + resizeCallback(width, height); +} + +void Window::position(int x, int y) +{ + moveCallback(x, y); +} + +void Window::title(const std::string& title) +{ + p_title = title; +} + +void Window::style(Style style) +{ + p_style = style; +} + +void Window::resizeCallback(int width, int height) +{ + p_width = width; + p_height = height; +} + +void Window::moveCallback(int x, int y) +{ + p_posX = x; + p_posY = y; +} + +} diff --git a/source/hyporo/gpu/window.hpp b/source/hyporo/gpu/window.hpp new file mode 100644 index 0000000..87a17a3 --- /dev/null +++ b/source/hyporo/gpu/window.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include "window_context.hpp" +#include "monitor.hpp" + + +namespace hpr::gpu +{ + +class Window : public WindowContext +{ + +public: + + enum class State + { + Unknown, + Visible, + Hidden, + Maximized, + Minimized, + Closed, + }; + + enum class Style + { + Unknown, + Windowed, + Fullscreen, + Popup + }; + +protected: + + int p_width; + int p_height; + int p_posX; + int p_posY; + std::string p_title; + + State p_state; + Style p_style; + Window* p_parent; + Monitor* p_monitor; + + bool p_isActive; + bool p_isResizing; + +public: + + Window(); + + virtual + ~Window(); + + // Member functions + + virtual + void init(const std::string& title, Style style, int x, int y, int width, int height, Window* parent, Monitor* monitor); + + virtual + void init(const std::string& title, Style style, Window* parent, Monitor* monitor); + + virtual + void state(State state = State::Visible); + + virtual + void close(); + + virtual + void restore(); + + virtual + bool isOpen() const; + + virtual + bool isActive() const; + + virtual + void size(int width, int height); + + virtual + void position(int x, int y); + + virtual + void title(const std::string& title); + + virtual + void style(Style style); + + void resizeCallback(int width, int height); + + void moveCallback(int x, int y); + +}; + +} \ No newline at end of file diff --git a/source/hyporo/gpu/window_context.hpp b/source/hyporo/gpu/window_context.hpp new file mode 100644 index 0000000..3f84d53 --- /dev/null +++ b/source/hyporo/gpu/window_context.hpp @@ -0,0 +1,39 @@ +#pragma once + + +namespace hpr::gpu +{ + +class WindowContext +{ + +public: + + enum class Provider + { + Unknown, + GLFW + }; + +private: + + Provider p_provider; + +public: + + inline + WindowContext() : + p_provider {Provider::Unknown} + {} + + inline + WindowContext(Provider provider) : + p_provider {provider} + {} + + virtual + ~WindowContext() = default; + +}; + +} diff --git a/source/hyporo/gpu/window_system.cpp b/source/hyporo/gpu/window_system.cpp new file mode 100644 index 0000000..4b8d6c7 --- /dev/null +++ b/source/hyporo/gpu/window_system.cpp @@ -0,0 +1,63 @@ +#include "window_system.hpp" +#include "glfw/window_system.hpp" + + +namespace hpr::gpu +{ + +WindowSystem::WindowSystem() : + WindowContext {Provider::Unknown} +{} + +WindowSystem::WindowSystem(Provider provider) : + WindowContext {provider} +{} + +WindowSystem::~WindowSystem() = default; + +void WindowSystem::create(WindowSystem** ws, Provider provider) +{ + if (ws == nullptr) + throw std::invalid_argument("Invalid parameter 'nullptr'"); + if (provider == Provider::Unknown) + throw std::invalid_argument("Cannot create window system from 'Unknown' provider"); + + *ws = nullptr; + + if (provider == Provider::GLFW) + *ws = new glfw::WindowSystem; + else + throw std::invalid_argument("Unsupported window system"); +} + +void WindowSystem::destroy(WindowSystem*& ws) +{ + delete ws; + ws = nullptr; +} + +Window& WindowSystem::window(int index) +{ + return p_windows[index]; +} + +void WindowSystem::closeWindow(Window* window) +{ + window->close(); +} + +void WindowSystem::destroyWindow(Window* window) +{ + p_windows.remove(*window); +} + +Monitor& WindowSystem::monitor(int index) +{ + return p_monitors[index]; +} + +void WindowSystem::destroyMonitor(Monitor* monitor) +{ + p_monitors.remove(*monitor); +} +} diff --git a/source/hyporo/gpu/window_system.hpp b/source/hyporo/gpu/window_system.hpp new file mode 100644 index 0000000..f9f84d4 --- /dev/null +++ b/source/hyporo/gpu/window_system.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "window.hpp" +#include "monitor.hpp" +#include "../hyplib/array/array.hpp" + +#include + + +namespace hpr::gpu +{ + +class WindowSystem : WindowContext +{ + +protected: + + darray p_windows; + darray p_monitors; + +protected: + + WindowSystem(); + + WindowSystem(Provider provider); + + virtual + ~WindowSystem(); + +public: + + // Global functions + + static + void create(WindowSystem** ws, Provider provider); + + static + void destroy(WindowSystem*& ws); + + // Window interface + + virtual + void newWindow(Window** window) = 0; + + Window& window(int index); + + void closeWindow(Window* window); + + void destroyWindow(Window* window); + + // Monitor interface + + virtual + void newMonitor(Monitor** monitor) = 0; + + Monitor& monitor(int index); + + void destroyMonitor(Monitor* monitor); + +}; + +} \ No newline at end of file diff --git a/source/hyporo/hyplib/CMakeLists.txt b/source/hyporo/hyplib/CMakeLists.txt index 923f88a..339c5b8 100644 --- a/source/hyporo/hyplib/CMakeLists.txt +++ b/source/hyporo/hyplib/CMakeLists.txt @@ -10,7 +10,6 @@ include_directories( add_library(hyporo-hyplib STATIC # Header files - integer/integer.hpp scalar/scalar.hpp array/iterator.hpp @@ -20,26 +19,31 @@ add_library(hyporo-hyplib STATIC vector/vector_space.hpp - vector/VectorSpace.hpp vector/vector.hpp - matrix/MatrixSpace.hpp + matrix/matrix_space.hpp + matrix/matrix.hpp io/file.hpp io/io.hpp # Source files - scalar/scalar.cpp io/file.cpp + + matrix/matrix_space.cpp ) if(WITH_GTESTS) add_executable(hyporo-hyplib-test tests/hyplib-test.cpp + + matrix/matrix_space.hpp ) target_link_libraries(hyporo-hyplib-test + + hyporo-hyplib GTest::gtest_main ) diff --git a/source/hyporo/hyplib/array/dynamic_array.hpp b/source/hyporo/hyplib/array/dynamic_array.hpp index acbd25b..22e6ddf 100644 --- a/source/hyporo/hyplib/array/dynamic_array.hpp +++ b/source/hyporo/hyplib/array/dynamic_array.hpp @@ -255,6 +255,35 @@ public: ++p_end; } + virtual + int findByAddress(const value_type& value) + { + for (int n = 0; n < p_size; ++n) + if (std::addressof(*(p_start + n)) == std::addressof(value)) + return n; + return -1; + } + + virtual + void remove(size_type position) + { + for (size_type n = position; n < p_size - 1; ++n) + *(p_start + n) = std::move(*(p_start + n + 1)); + std::destroy_at(p_end); + --p_end; + --p_size; + } + + virtual + void remove(const value_type& value) + { + size_type index = findByAddress(value); + if (index != -1) + remove(index); + else + throw std::runtime_error("Value is not found to remove it"); + } + // Friend functions friend diff --git a/source/hyporo/hyplib/array/static_array.hpp b/source/hyporo/hyplib/array/static_array.hpp index 1b01095..8ddd0a7 100644 --- a/source/hyporo/hyplib/array/static_array.hpp +++ b/source/hyporo/hyplib/array/static_array.hpp @@ -2,6 +2,8 @@ #include "iterator.hpp" #include +#include + namespace hpr { @@ -20,7 +22,7 @@ public: using iterator = Iterator; using const_pointer = Type const*; using const_reference = Type const&; - using const_iterator = Iterator const; + using const_iterator = Iterator; protected: @@ -64,12 +66,50 @@ public: } inline - StaticArray(std::initializer_list list) : - p_size {Size}, - p_start {new value_type[p_size]}, - p_end {p_start + p_size} + StaticArray(const_iterator start, const_iterator end) : + p_size {Size}, + p_start {new value_type[p_size]}, + p_end {p_start + p_size} { - std::copy(list.begin(), list.end(), p_start); + std::copy(start, end, p_start); + } + + inline + StaticArray(iterator start, iterator end) : + p_size {Size}, + p_start {new value_type[p_size]}, + p_end {p_start + p_size} + { + std::copy(start, end, p_start); + } + + inline + StaticArray(std::initializer_list list) : + StaticArray {list.begin(), list.end()} + {} + + template ... Args> + inline + StaticArray(value_type&& v, Args&& ...args) : + StaticArray {std::initializer_list({v, static_cast(args)...})} + { + static_assert(1 + sizeof...(args) == Size, "Number of arguments must be equal to size of array"); + } + + template ... Args> + inline + StaticArray(const StaticArray& subarr, const value_type& v, const Args& ...args) : + p_size {Size}, + p_start {new value_type[p_size]}, + p_end {p_start + p_size} + { + static_assert(SubSize + 1 + sizeof...(args) == Size, + "Number of arguments and sub-array elements must be equal to size of main array"); + std::initializer_list list {v, static_cast(args)...}; + std::copy(subarr.begin(), subarr.end(), begin()); + size_type pos {subarr.size()}; + for (auto& val : list) + (*this)[pos++] = val; } inline @@ -165,10 +205,18 @@ public: friend void swap(StaticArray& lhs, StaticArray& rhs) { - lhs.p_size = rhs.p_size; std::swap(lhs.p_start, rhs.p_start); std::swap(lhs.p_end, rhs.p_end); } + + friend + bool operator==(const StaticArray& lhs, const StaticArray& rhs) + { + for (auto n = 0; n < Size; ++n) + if (lhs[n] != rhs[n]) + return false; + return true; + } }; } diff --git a/source/hyporo/hyplib/integer/integer.hpp b/source/hyporo/hyplib/integer/integer.hpp deleted file mode 100644 index 98ecdbc..0000000 --- a/source/hyporo/hyplib/integer/integer.hpp +++ /dev/null @@ -1,12 +0,0 @@ - -#include - - -namespace hyporo -{ - -using uint = unsigned int; - -using sizet = std::size_t; - -} // end namespace hyporo diff --git a/source/hyporo/hyplib/matrix/MatrixSpace.hpp b/source/hyporo/hyplib/matrix/MatrixSpace.hpp deleted file mode 100644 index 499fe44..0000000 --- a/source/hyporo/hyplib/matrix/MatrixSpace.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "VectorSpace.hpp" - - -namespace hyporo -{ - -template -class MatrixSpace : public VectorSpace -{ - -public: - - // Member constants - - static const sizet mRows = Mrows; - static const sizet nColumns = Ncols; - - // Constructors - - inline MatrixSpace(); - - template - inline MatrixSpace(const Args... components); - - // Member operators - - inline const C& operator()(const sizet& n, const sizet& m); - -}; - -} // end namespace hyporo - -#include "MatrixSpace.hxx" diff --git a/source/hyporo/hyplib/matrix/MatrixSpace.hxx b/source/hyporo/hyplib/matrix/MatrixSpace.hxx deleted file mode 100644 index 66b869c..0000000 --- a/source/hyporo/hyplib/matrix/MatrixSpace.hxx +++ /dev/null @@ -1,27 +0,0 @@ - -namespace hyporo -{ - -// Constructors - -template -inline MatrixSpace::MatrixSpace() -{} - -template -template -inline MatrixSpace::MatrixSpace(const Args... components) - //: row { static_cast(components)... } -{ - this->row = { static_cast(components)... }; -} - -// Member operators - -template -inline const C& MatrixSpace::operator()(const sizet& n, const sizet& m) -{ - return this->row[n * Ncols + m]; -} - -} // end namespace hyporo diff --git a/source/hyporo/hyplib/matrix/clip_space.hpp b/source/hyporo/hyplib/matrix/clip_space.hpp new file mode 100644 index 0000000..dfdf505 --- /dev/null +++ b/source/hyporo/hyplib/matrix/clip_space.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "matrix.hpp" + + +namespace hpr +{ + +template +inline +MatrixSpace ortho(Type left, Type right, Type bottom, Type top) +{ + MatrixSpace ms; + ms.fill(1); + ms(0, 0) = 2 / (right - left); + ms(1, 1) = 2 / (top - bottom); + ms(2, 2) = -1; + ms(3, 0) = -(right + left) / (right - left); + ms(3, 1) = -(top + bottom) / (top - bottom); + return ms; +} + +template +inline +MatrixSpace ortho(Type left, Type right, Type bottom, Type top, Type zNear, Type zFar) +{ + MatrixSpace ms; + ms.fill(1); + ms(0, 0) = 2 / (right - left); + ms(1, 1) = 2 / (top - bottom); + ms(2, 2) = 2 / (zFar - zNear); + ms(3, 0) = -(right + left) / (right - left); + ms(3, 1) = -(top + bottom) / (top - bottom); + ms(3, 2) = -(zFar + zNear) / (zFar - zNear); + return ms; +} + +template +inline +MatrixSpace perspective(Type fovy, Type aspect, Type zNear, Type zFar) +{ + assert(abs(aspect - std::numeric_limits::epsilon()) > 0); + MatrixSpace ms; + const Type halfFovyTan = tan(fovy / 2); + ms(0, 0) = 1 / (aspect * halfFovyTan); + ms(1, 1) = 1 / halfFovyTan; + ms(2, 2) = (zFar + zNear) / (zFar - zNear); + ms(2, 3) = 1; + ms(3, 2) = -(2 * zFar * zNear) / (zFar - zNear); + return ms; +} + + +} diff --git a/source/hyporo/hyplib/matrix/matrix.hpp b/source/hyporo/hyplib/matrix/matrix.hpp index 7a66792..a30052b 100644 --- a/source/hyporo/hyplib/matrix/matrix.hpp +++ b/source/hyporo/hyplib/matrix/matrix.hpp @@ -1,11 +1,15 @@ -#include "MatrixSpace.hpp" +#include "../scalar/scalar.hpp" +#include "matrix_space.hpp" -namespace hyporo +namespace hpr { -using mat3 = MatrixSpace; +template +using mat = MatrixSpace; +using mat2 = MatrixSpace; +using mat3 = MatrixSpace; using mat4 = MatrixSpace; -} // end namespace hyporo +} diff --git a/source/hyporo/hyplib/matrix/matrix_space.hpp b/source/hyporo/hyplib/matrix/matrix_space.hpp new file mode 100644 index 0000000..984df7c --- /dev/null +++ b/source/hyporo/hyplib/matrix/matrix_space.hpp @@ -0,0 +1,249 @@ +#pragma once + +#include "../vector/vector.hpp" + +namespace hpr +{ + +template +class MatrixSpace : public VectorSpace +{ + static_assert(Rows >= 1); + static_assert(Cols >= 1); + using base = VectorSpace; + + using Minor = typename std::conditional<(Rows >= 2 && Cols >= 2), MatrixSpace, MatrixSpace>::type; +public: + + using value_type = Type; + using size_type = size_t; + using pointer = Type*; + using reference = Type&; + using iterator = Iterator; + using const_iterator = Iterator; + +protected: + + static + const size_type p_mrows = Rows - 1; + static + const size_type p_mcols = Cols - 1; + size_type p_rows; + size_type p_cols; + +public: + + inline + MatrixSpace() : + base {}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + MatrixSpace(const MatrixSpace& ms) : + base {static_cast(ms)}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + MatrixSpace(const base& ms) : + base {ms}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + MatrixSpace(MatrixSpace&& ms) noexcept : + base {std::move(static_cast(ms))}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + MatrixSpace(typename base::iterator start, typename base::iterator end) : + base {start, end}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + MatrixSpace(typename base::const_iterator start, typename base::const_iterator end) : + base {start, end}, + p_rows {Rows}, + p_cols {Cols} + {} + + inline + MatrixSpace(std::initializer_list list) : + base {list}, + p_rows {Rows}, + p_cols {Cols} + {} + + template ... Args> + inline + MatrixSpace(value_type&& v, Args&& ...args) : + base {v, static_cast(std::forward(args))...}, + p_rows {Rows}, + p_cols {Cols} + { + static_assert(1 + sizeof...(args) == Rows * Cols, "Number of arguments must be equal to rows * cols of matrix"); + } + + // Member functions + + inline + reference operator()(size_type row, size_type col) + { + if (row >= p_rows || std::numeric_limits::max() - p_rows < row) + throw std::out_of_range("Row index is out of range"); + if (col >= p_cols || std::numeric_limits::max() - p_cols < col) + throw std::out_of_range("Column index is out of range"); + return (*this)[col + p_rows * row]; + } + + VectorSpace row(size_type row) + { + VectorSpace vs; + for (auto n = 0; n < Cols; ++n) + vs[n] = (*this)(row, n); + return vs; + } + + void row(size_type row, const VectorSpace& vs) + { + for (auto n = 0; n < Cols; ++n) + (*this)(n, row) = vs[n]; + } + + VectorSpace col(size_type col) + { + VectorSpace vs; + for (auto n = 0; n < Rows; ++n) + vs[n] = (*this)(n, col); + return vs; + } + + void col(size_type col, const VectorSpace& vs) + { + for (auto n = 0; n < Rows; ++n) + (*this)(n, col) = vs[n]; + } + + size_type rows() const { return p_rows; } + size_type cols() const { return p_cols; } + + [[nodiscard]] + inline + bool is_square() const + { + return p_rows == p_cols; + } + + inline + Minor minor(size_type row, size_type col) + { + if (this->size() < 4) + throw std::runtime_error("Impossible to find minor for matrix with size less than 2x2"); + Minor minor; + auto minor_iter = minor.begin(); + for (auto n = 0; n < Rows; ++n) + for (auto k = 0; k < Cols; ++k) + if (k != col && n != row) + *(minor_iter++) = (*this)[k + p_rows * n]; + return minor; + } + + inline + value_type det() + { + if (!is_square()) + throw std::runtime_error("Matrix must be square"); + if (this->size() == 1) + return (*this)[0]; + else if (this->size() == 4) + return (*this)(0, 0) * (*this)(1, 1) - (*this)(0, 1) * (*this)(1, 0); + else { + auto res = 0; + for (auto m = 0; m < Cols; ++m) + res += pow(-1, m) * (*this)(0, m) * minor(0, m).det(); + return res; + } + } + + inline + MatrixSpace transpose() + { + MatrixSpace ms; + for (auto n = 0; n < Rows; ++n) + for (auto k = 0; k < Cols; ++k) + ms(k, n) = (*this)(n, k); + return ms; + } + + inline + MatrixSpace adj() + { + MatrixSpace ms; + for (auto n = 0; n < Rows; ++n) + for (auto k = 0; k < Cols; ++k) + { + ms(n, k) = pow(-1, n + k) * minor(n, k).det(); + } + return ms.transpose(); + } + + inline + MatrixSpace inv() + { + return adj() / det(); + } + + // Friend functions + + friend inline + bool operator==(const MatrixSpace& lhs, const MatrixSpace& rhs) + { + for (auto n = 0; n < lhs.size(); ++n) + if (lhs[n] != rhs[n]) + return false; + return true; + } + + friend inline + bool operator!=(const MatrixSpace& lhs, const MatrixSpace& rhs) + { + return !(lhs == rhs); + } + + template + friend inline + bool operator==(const MatrixSpace& lhs, const VectorSpace& rhs) + { + return false; + } + + MatrixSpace& fill(value_type value) + { + for (auto n = 0; n < this->size(); ++n) + (*this)[n] = value; + return *this; + } + + // Global functions + + static inline + MatrixSpace identity() + { + MatrixSpace ms; + for (auto n = 0; n < Rows; ++n) + for (auto k = 0; k < Cols; ++k) + ms(n, k) = 1; + return ms; + } +}; + + +} \ No newline at end of file diff --git a/source/hyporo/hyplib/matrix/transform.hpp b/source/hyporo/hyplib/matrix/transform.hpp new file mode 100644 index 0000000..ee313b1 --- /dev/null +++ b/source/hyporo/hyplib/matrix/transform.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include "matrix.hpp" + + +namespace hpr +{ + +template +inline +mat translate(const mat& ms, const vec& vs) +{ + mat res {ms}; + res.row(3, ms.row(0) * vs[0] + ms.row(1) * vs[1] + ms.row(2) * vs[2] + ms.row(3)); + + return res; +} + +template +inline +mat rotate(const mat& ms, const vec& vs, Type angle) +{ + const Type cos {cos(angle)}; + const Type sin {sin(angle)}; + vec axis {normalize(vs)}; + vec temp {(1. - cos) * axis}; + + mat rot; + rot(0, 0) = cos + temp[0] * axis[0]; + rot(0, 1) = temp[0] * axis[1] + sin * axis[2]; + rot(0, 2) = temp[0] * axis[2] - sin * axis[1]; + rot(1, 0) = temp[1] * axis[0] - sin * axis[2]; + rot(1, 1) = cos + temp[1] * axis[1]; + rot(1, 2) = temp[1] * axis[2] + sin * axis[0]; + rot(2, 0) = temp[2] * axis[0] + sin * axis[1]; + rot(2, 1) = temp[2] * axis[1] - sin * axis[0]; + rot(2, 2) = cos + temp[2] * axis[2]; + + mat res {ms}; + res.row(0, ms.row(0) * rot(0, 0) + ms.row(1) * rot(0, 1) + ms.row(2) * rot(0, 2)); + res.row(0, ms.row(0) * rot(1, 0) + ms.row(1) * rot(1, 1) + ms.row(2) * rot(1, 2)); + res.row(0, ms.row(0) * rot(2, 0) + ms.row(1) * rot(2, 1) + ms.row(2) * rot(2, 2)); + res.row(3, ms.row(3)); + + return res; +} + +template +inline +mat scale(const mat& ms, const vec& vs) +{ + mat res; + res.row(0, ms.row(0) * vs[0]); + res.row(1, ms.row(1) * vs[1]); + res.row(2, ms.row(2) * vs[2]); + res.row(3, ms.row(3)); + + return res; +} + + +template +inline +mat lookAt(const mat& ms, const vec& eye, const vec& center, const vec& up) +{ + const vec forward {normalize(center - eye)}; + const vec left {normalize(cross(up, forward))}; + const vec nup {cross(forward, left)}; + + mat res; + res.col(0, vec(left, 0)); + res.col(1, vec(nup, 0)); + res.col(2, vec(forward, 0)); + res.row(3, -vec(dot(left, eye), dot(nup, eye), dot(forward, eye), -1.)); + + return res; +} + +} diff --git a/source/hyporo/hyplib/scalar/scalar.cpp b/source/hyporo/hyplib/scalar/scalar.cpp deleted file mode 100644 index 4476a79..0000000 --- a/source/hyporo/hyplib/scalar/scalar.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "scalar.hpp" - - diff --git a/source/hyporo/hyplib/scalar/scalar.hpp b/source/hyporo/hyplib/scalar/scalar.hpp index 60e60fe..5948fcf 100644 --- a/source/hyporo/hyplib/scalar/scalar.hpp +++ b/source/hyporo/hyplib/scalar/scalar.hpp @@ -4,7 +4,7 @@ #include -namespace hyporo +namespace hpr { #if defined(PRECISION_FLOAT) @@ -26,7 +26,7 @@ using scalar = float; #endif static const scalar small = std::numeric_limits::epsilon(); -static const scalar great = 1.0 / small; +static const scalar great = static_cast(1.0) / small; static const scalar valueSmall = std::numeric_limits::min(); static const scalar valueGreat = std::numeric_limits::max() * 0.1; static const scalar NaN = std::numeric_limits::signaling_NaN(); @@ -43,5 +43,23 @@ inline scalar mag(const scalar s) return std::fabs(s); } +// trigonometric -} // end namespace hyporo +static const scalar PI = static_cast(M_PIl); +template +constexpr +Type radians(Type degrees) +{ + static_assert(std::numeric_limits::is_iec559); + return degrees * PI / static_cast(180); +} + +template +constexpr +Type degrees(Type radians) +{ + static_assert(std::numeric_limits::is_iec559); + return radians * static_cast(180) / PI; +} + +} diff --git a/source/hyporo/hyplib/tests/hyplib-test.cpp b/source/hyporo/hyplib/tests/hyplib-test.cpp index e3d2c0c..663f04f 100644 --- a/source/hyporo/hyplib/tests/hyplib-test.cpp +++ b/source/hyporo/hyplib/tests/hyplib-test.cpp @@ -1,20 +1,79 @@ #include + +#include "array.hpp" #include "vector.hpp" +#include "matrix.hpp" -TEST(hyplibTest, VectorCreation) + +TEST(hyplib, Array) { - hyporo::vec3 v {1, 3, 2}; - EXPECT_EQ(v[0], 1); - EXPECT_EQ(v[1], 3); - EXPECT_EQ(v[2], 2); + hpr::StaticArray arr {1, 3, 2}; + hpr::StaticArray sarr {arr, 5}; + hpr::StaticArray sarr2 {1, 3, 2, 5}; + EXPECT_EQ(sarr, sarr2); } -TEST(hyplibTest, VectorOperations) +TEST(hyplib, Vector) { - using hyporo::vec3; - vec3 v1 {1, 3, 2}; - vec3 v2 {5, 7, -1}; - EXPECT_EQ(-v1, vec3(-1, -3, -2)); - EXPECT_EQ(v1 + v2, vec3(6, 10, 1)); - EXPECT_EQ(v1 - v2, vec3(-4, -4, 3)); + hpr::vec3 v1 {1, 3, 2}; + hpr::vec3 v2 {5, 7, -1}; + hpr::vec2 v31 {13, -2}; + hpr::vec3 v32 {v31, 9}; + EXPECT_EQ((hpr::vec3(v2.begin(), v2.end())), v2); + EXPECT_EQ(v32, hpr::vec3(13, -2, 9)); + EXPECT_EQ(-v1, hpr::vec3(-1, -3, -2)); + EXPECT_EQ(v1 + v2, hpr::vec3(6, 10, 1)); + EXPECT_EQ(v1 - v2, hpr::vec3(-4, -4, 3)); + EXPECT_EQ((hpr::dot(v1, v2) ), 24); } + +TEST(hyplib, Matrix) +{ + hpr::mat2 m1; + hpr::vec4 v1; + EXPECT_FALSE(v1 == m1); + hpr::mat2 m2 {3, 2, 7, 4}; + hpr::vec2 v2 {2, 4}; + EXPECT_EQ(m2.col(1), v2); + hpr::vec2 v3 {13, 51}; + m2.col(1, v3); + EXPECT_EQ(m2.col(1), v3); + hpr::mat3 m4 {1, 2, 3, 4, 5, 6, 7, 8, 9}; + hpr::mat2 m41 {5, 6, 8, 9}; + EXPECT_EQ(m41.minor(0, 0), 9); + hpr::mat2 m5 {1, 2, 3, 4}; + + EXPECT_EQ((m4.det()), 0); + EXPECT_EQ(hpr::mat3(-9, 23, 3, 5, 5, 6, 7, -3, 9).det(), -786); + + hpr::mat2 m6 {2, 1, 7, 4}; + EXPECT_EQ(m6.inv(), hpr::mat2(4, -1, -7, 2)); + //EXPECT_EQ(m4.det(), 0); +} +/*using Minor = typename std::conditional<(Rows > 2 && Cols > 2), + MatrixSpace, MatrixSpace>::type; + +value_type det() +{ + + if (!is_square()) + throw std::runtime_error("Matrix must be square"); + if (this->size() == 1) + return (*this)[0]; + else if (this->size() == 4) + return (*this)(0, 0) * (*this)(1, 1) - (*this)(0, 1) * (*this)(1, 0); + else { + auto res = 0; + for (auto m = 0; m < Cols; ++m) { + Minor minor; + auto minor_iter = minor.begin(); + for (auto n = 0; n < Rows; ++n) + for (auto k = 0; k < Cols; ++k) + if (k != 0 && n != m) + *(minor_iter++) = (*this)[k + p_rows * n]; + res += pow(-1, m) * (*this)(0, m) * minor.det(); + } + return res; + } +} +*/ \ No newline at end of file diff --git a/source/hyporo/hyplib/vector/VectorSpace.hpp b/source/hyporo/hyplib/vector/VectorSpace.hpp deleted file mode 100644 index 798b1e6..0000000 --- a/source/hyporo/hyplib/vector/VectorSpace.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -/** \file - * \ingroup hyplib - **/ - -#include "integer.hpp" -#include "scalar.hpp" -#include -#include - -namespace hyporo -{ - -// Forward declaration of friend functions and operators - -template class VectorSpace; - -template -std::ostream& operator<<(std::ostream&, const VectorSpace&); - -// Class declaration - -template -class VectorSpace -{ - -public: - - //- The components of this vector space - std::array row; - - // Static constants - - static const sizet nComponents = NC; - - // Constructors - - inline VectorSpace(); - - //inline VectorSpace(const VectorSpace&); - - template - inline VectorSpace(const Args... components); - - - // Member functions - - inline static sizet size(); - - // Member operators - - inline C& operator[](const sizet); - - inline VectorSpace& operator*=(const scalar); - - inline VectorSpace& operator/=(const scalar); - - // Friend operators - - friend std::ostream& operator<< (std::ostream&, const VectorSpace&); -}; - -} // end namespace hyporo - -#include "VectorSpace.hxx" diff --git a/source/hyporo/hyplib/vector/VectorSpace.hxx b/source/hyporo/hyplib/vector/VectorSpace.hxx deleted file mode 100644 index 71c3eff..0000000 --- a/source/hyporo/hyplib/vector/VectorSpace.hxx +++ /dev/null @@ -1,143 +0,0 @@ - -#include - - -namespace hyporo -{ - -// Constructors - -template -inline VectorSpace::VectorSpace() -{} - -template -template -inline VectorSpace::VectorSpace(const Args... components) - : row { static_cast(components)... } -{} - - -// Member functions - -template -inline sizet VectorSpace::size() -{ - return NC; -} - -// Member operators - -template -inline C& VectorSpace::operator[](const sizet n) -{ - return row[n]; -} - - -template -inline VectorSpace& VectorSpace::operator*=(const scalar s) -{ - for (C& v : row) - v *= s; - return *this; -} - -template -inline VectorSpace& VectorSpace::operator/=(const scalar s) -{ - for (C& v : row) - v /= s; - return *this; -} - -// Friend operators - -template -std::ostream& operator<<(std::ostream& os, const VectorSpace& vs) -{ - os << "("; - for (sizet n = 0; n < NC; n++) - { - os << vs.row[n]; - if (n != NC - 1) - os << ", "; - } - os << ")"; - return os; -} - - -// Global operators - -template -inline VectorSpace operator-(const VectorSpace& vs) -{ - VectorSpace nvs; - for (sizet n = 0; n < NC; n++) - nvs.row[n] = -vs.row[n]; - return nvs; -} - -template -inline VectorSpace operator+(const VectorSpace& vs1, const VectorSpace& vs2) -{ - VectorSpace nvs; - for (sizet n = 0; n < NC; n++) - nvs.row[n] = vs1.row[n] + vs2.row[n]; - return nvs; -} - -template -inline VectorSpace operator-(const VectorSpace& vs1, const VectorSpace& vs2) -{ - VectorSpace nvs; - for (sizet n = 0; n < NC; n++) - nvs.row[n] = vs1.row[n] - vs2.row[n]; - return nvs; -} - -template -inline VectorSpace operator*(const scalar& s, const VectorSpace& vs) -{ - VectorSpace nvs; - for (sizet n = 0; n < NC; n++) - nvs.row[n] = s * vs.row[n]; - return nvs; -} - -template -inline VectorSpace operator*(const VectorSpace& vs, const scalar& s) -{ - VectorSpace nvs; - for (sizet n = 0; n < NC; n++) - nvs.row[n] = vs.row[n] * s; - return nvs; -} - -template -inline VectorSpace operator/(const VectorSpace& vs, const scalar& s) -{ - VectorSpace nvs; - for (sizet n = 0; n < NC; n++) - nvs.row[n] = vs.row[n] / s; - return nvs; -} - -template -inline bool operator==(const VectorSpace& vs1, const VectorSpace& vs2) -{ - bool eq = true; - for (sizet n = 0; n < NC; n++) - if (!(eq &= (vs1.row[n] == vs2.row[n]))) - break; - return eq; -} - -template -inline bool operator!=(const VectorSpace& vs1, const VectorSpace& vs2) -{ - return !(vs1 == vs2); -} - -} // end namespace hyporo diff --git a/source/hyporo/hyplib/vector/vector.hpp b/source/hyporo/hyplib/vector/vector.hpp index aefe921..468689b 100644 --- a/source/hyporo/hyplib/vector/vector.hpp +++ b/source/hyporo/hyplib/vector/vector.hpp @@ -1,16 +1,17 @@ #pragma once #include "scalar.hpp" -#include "VectorSpace.hpp" +#include "vector_space.hpp" -namespace hyporo +namespace hpr { +template +using vec = VectorSpace; + using vec2 = VectorSpace; - using vec3 = VectorSpace; - using vec4 = VectorSpace; -} // end namespace hyporo +} diff --git a/source/hyporo/hyplib/vector/vector_space.cpp b/source/hyporo/hyplib/vector/vector_space.cpp new file mode 100644 index 0000000..56a2e66 --- /dev/null +++ b/source/hyporo/hyplib/vector/vector_space.cpp @@ -0,0 +1,4 @@ +// +// Created by L-Nafaryus on 10/17/2022. +// +#include "vector_space.hpp" \ No newline at end of file diff --git a/source/hyporo/hyplib/vector/vector_space.hpp b/source/hyporo/hyplib/vector/vector_space.hpp new file mode 100644 index 0000000..6abc400 --- /dev/null +++ b/source/hyporo/hyplib/vector/vector_space.hpp @@ -0,0 +1,332 @@ +#pragma once + +#include "../array/array.hpp" + +namespace hpr +{ + +template +class VectorSpace : public StaticArray +{ + static_assert(std::is_arithmetic::value, "Type must be numeric"); + + using base = StaticArray; + + using SubVector = typename std::conditional= 2, VectorSpace, VectorSpace>::type; +public: + + using value_type = Type; + using size_type = size_t; + using pointer = Type*; + using reference = Type&; + using iterator = Iterator; + using const_iterator = Iterator; + +public: + + inline + VectorSpace() : + base {} + {} + + inline + VectorSpace(const VectorSpace& vs) : + base {static_cast(vs)} + {} + + inline + VectorSpace(VectorSpace&& vs) noexcept : + base {std::move(static_cast(vs))} + {} + + inline + VectorSpace(typename base::iterator start, typename base::iterator end) : + base {start, end} + {} + + inline + VectorSpace(typename base::const_iterator start, typename base::const_iterator end) : + base {start, end} + {} + + inline + VectorSpace(std::initializer_list list) : + base {list} + {} + + template ... Args> + inline + VectorSpace(value_type&& v, Args&& ...args) : + base {v, static_cast(std::forward(args))...} + { + static_assert(1 + sizeof...(args) == Size, "Number of arguments must be equal to size of vector"); + } + + /*template ... Args> + inline + VectorSpace(const VectorSpace& subvec, const value_type& v, const Args& ...args) : + base {static_cast>(subvec), v, + static_cast(std::forward(args))...} + {}*/ + + inline + VectorSpace(const SubVector& subvs, const value_type& v) : + base {} + { + for (auto n = 0; n < subvs.size(); ++n) + (*this)[n] = subvs[n]; + (*this)[subvs.size() - 1] = v; + } + + // Member functions + + // vector versus scalar (per element operations) + + friend inline + VectorSpace operator-(const VectorSpace& rhs) + { + VectorSpace vs {rhs}; + for (value_type& v : vs) + v = -v; + return vs; + } + + inline + void operator*=(const value_type& val) + { + //for (value_type& v : *this) + // v *= val; + for (auto n = 0; n < Size; ++n) + (*this)[n] *= val; + } + + inline + void operator+=(const value_type& val) + { + for (auto n = 0; n < Size; ++n) + (*this)[n] += val; + } + + inline + void operator-=(const value_type& val) + { + //for (value_type& v : *this) + // v -= val; + for (auto n = 0; n < Size; ++n) + (*this)[n] -= val; + } + + inline + void operator/=(const value_type& val) + { + for (value_type& v : *this) + v /= val; + } + + using type = VectorSpace; + + friend inline + type operator+(const VectorSpace& lhs, const value_type& rhs) + { + VectorSpace vs {lhs}; + vs += rhs; + return vs; + } + + friend inline + VectorSpace operator+(const value_type& lhs, const VectorSpace& rhs) + { + return operator+(rhs, lhs); + } + + friend inline + VectorSpace operator*(const VectorSpace& lhs, const value_type& rhs) + { + VectorSpace vs {lhs}; + vs *= rhs; + return vs; + } + + friend inline + VectorSpace operator*(const value_type& lhs, const VectorSpace& rhs) + { + return operator*(rhs, lhs); + } + + friend inline + VectorSpace operator/(const VectorSpace& lhs, const value_type& rhs) + { + VectorSpace vs {lhs}; + vs /= rhs; + return vs; + } + + friend inline + VectorSpace operator/(const value_type& lhs, const VectorSpace& rhs) + { + VectorSpace vs; + for (auto n = 0; n < vs.size(); ++n) + vs[n] = lhs / rhs[n]; + return vs; + } + + // vector versus vector (per element operations) + + inline + void operator*=(const VectorSpace& vs) + { + for (auto n = 0; n < Size; ++n) + (*this)[n] *= vs[n]; + } + + inline + void operator+=(const VectorSpace& vs) + { + for (auto n = 0; n < Size; ++n) + (*this)[n] += vs[n]; + } + + inline + void operator-=(const VectorSpace& vs) + { + for (auto n = 0; n < Size; ++n) + (*this)[n] -= vs[n]; + } + + inline + void operator/=(const VectorSpace& vs) + { + for (auto n = 0; n < Size; ++n) + (*this)[n] /= vs[n]; + } + + friend inline + VectorSpace operator+(const VectorSpace& lhs, const VectorSpace& rhs) + { + VectorSpace vs {lhs}; + vs += rhs; + return vs; + } + + friend inline + VectorSpace operator-(const VectorSpace& lhs, const VectorSpace& rhs) + { + VectorSpace vs {lhs}; + vs -= rhs; + return vs; + } + + friend inline + VectorSpace operator*(const VectorSpace& lhs, const VectorSpace& rhs) + { + VectorSpace vs {lhs}; + vs *= rhs; + return vs; + } + + friend inline + VectorSpace operator/(const VectorSpace& lhs, const VectorSpace& rhs) + { + VectorSpace vs {lhs}; + vs /= rhs; + return vs; + } + + friend inline + bool operator==(const VectorSpace& lhs, const VectorSpace& rhs) + { + for (auto n = 0; n < Size; ++n) + if (lhs[n] != rhs[n]) + return false; + return true; + } + + friend inline + bool operator!=(const VectorSpace& lhs, const VectorSpace& rhs) + { + return !(lhs == rhs); + } + + +}; + +template +inline +Type sum(const VectorSpace& vs) +{ + Type sum {0}; + for (const Type& v : vs) + sum += v; + return sum; +} + +template +constexpr +Type dot(const VectorSpace& lhs, const VectorSpace& rhs) +{ + return sum(lhs * rhs); +} + +template +inline +Type length(const VectorSpace& vs) +{ + return sqrt(dot(vs, vs)); +} + +template +inline +Type distance(const VectorSpace& point1, const VectorSpace& point2) +{ + return length(point1 - point2); +} + +template +constexpr +VectorSpace cross(const VectorSpace& lhs, const VectorSpace& rhs) +{ + return VectorSpace( + lhs[2] * rhs[3] - lhs[3] * rhs[2], + lhs[3] * rhs[1] - lhs[1] * rhs[3], + lhs[1] * rhs[2] - lhs[2] * rhs[1] + ); +} + +template +inline +VectorSpace normalize(const VectorSpace& vs) +{ + return vs * inversesqrt(dot(vs, vs)); +} + +template +constexpr +VectorSpace equal(const VectorSpace& lhs, const VectorSpace& rhs) +{ + VectorSpace vs; + for (auto n = 0; n < Size; ++n) + vs[n] = lhs[n] == rhs[n]; + return vs; +} + +template +constexpr +bool any(const VectorSpace& vs) +{ + bool res = false; + for (auto e : vs) + res = res || e; + return res; +} + +template +constexpr +bool all(const VectorSpace& vs) +{ + bool res = true; + for (auto e : vs) + res = res && e; + return res; +} + +}