From 5f59ba420aa0efbc17d5608035717697e2a18859 Mon Sep 17 00:00:00 2001 From: falsycat Date: Mon, 23 Aug 2021 14:22:56 +0900 Subject: [PATCH] Adds interfaces for base objects. --- Font.h | 2 +- Game.h | 44 ++ GlyphsJuke.vcxproj | 9 +- GlyphsJuke.vcxproj.filters | 30 +- Logger.h | 52 ++ Text.h | 47 ++ Win32Console.cc | 2 +- Win32Console.h | 4 +- common.h | 12 +- iDrawable.h | 51 ++ iLogger.h | 24 + iWritable.h | 46 ++ main.cc | 59 +- thirdparty/linalg.h | 721 ++++++++++++++++++++ stb_truetype.h => thirdparty/stb_truetype.h | 0 15 files changed, 1048 insertions(+), 55 deletions(-) create mode 100644 Game.h create mode 100644 Logger.h create mode 100644 Text.h create mode 100644 iDrawable.h create mode 100644 iLogger.h create mode 100644 iWritable.h create mode 100644 thirdparty/linalg.h rename stb_truetype.h => thirdparty/stb_truetype.h (100%) diff --git a/Font.h b/Font.h index 98b3d17..094915c 100644 --- a/Font.h +++ b/Font.h @@ -5,7 +5,7 @@ #include #include -#include "stb_truetype.h" +#include "thirdparty/stb_truetype.h" #include "common.h" #include "iAllocator.h" diff --git a/Game.h b/Game.h new file mode 100644 index 0000000..37fd894 --- /dev/null +++ b/Game.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include "iDrawable.h" +#include "iWritable.h" +#include "Logger.h" + + +namespace gj { + + +class Game : public iDrawable, public iWritable { + public: + Game() = delete; + Game(Game&&) = delete; + Game(const Game&) = delete; + + Game& operator=(Game&&) = delete; + Game& operator=(const Game&) = delete; + + Game(uint32_t w, uint32_t h) : w_(w), h_(h), logger_(h) { + logger_.Print(L"こんにちは"); + } + + void Update() { + static int i = 0; + ++i; + logger_.Print(L"すべての人類は死滅する: "+std::to_wstring(i)); + } + + void Draw(Colorbuffer& fb) const override { + } + void Write(Textbuffer& fb) const override { + logger_.Write(fb); + } + + private: + uint32_t w_, h_; + Logger logger_; +}; + + +} \ No newline at end of file diff --git a/GlyphsJuke.vcxproj b/GlyphsJuke.vcxproj index 2f1ffcf..3a8456b 100644 --- a/GlyphsJuke.vcxproj +++ b/GlyphsJuke.vcxproj @@ -147,12 +147,19 @@ + + + + + - + + + diff --git a/GlyphsJuke.vcxproj.filters b/GlyphsJuke.vcxproj.filters index db091aa..0a4d344 100644 --- a/GlyphsJuke.vcxproj.filters +++ b/GlyphsJuke.vcxproj.filters @@ -13,6 +13,9 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {116a3690-393e-42ef-9dd3-935486b59155} + @@ -44,14 +47,35 @@ Header Files - - Header Files - Header Files Header Files + + Header Files\thirdparty + + + Header Files\thirdparty + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/Logger.h b/Logger.h new file mode 100644 index 0000000..fd904a6 --- /dev/null +++ b/Logger.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include "iDrawable.h" +#include "iLogger.h" +#include "Text.h" + + +namespace gj { + + +class Logger : public iWritable, public iLogger { + public: + Logger(Logger&&) = delete; + Logger(const Logger&) = delete; + + Logger& operator=(Logger&&) = delete; + Logger& operator=(const Logger&) = delete; + + Logger(uint32_t height) : height_(height) { + } + + void Write(Textbuffer& fb) const override { + for (const auto& text : lines_) { + text.Write(fb); + } + } + + void Print(const std::wstring& msg) override { + size_t n = lines_.size(); + + if (n >= height_) { + lines_.erase(lines_.begin()); + --n; + for (size_t i = 0; i < n; ++i) { + lines_[i].SetPosition(0, i); + } + } + + Text text(msg, 0, static_cast(n)); + lines_.push_back(std::move(text)); + } + + private: + uint32_t height_; + + std::vector lines_; +}; + + +} \ No newline at end of file diff --git a/Text.h b/Text.h new file mode 100644 index 0000000..c6ae9a6 --- /dev/null +++ b/Text.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#include "iWritable.h" + +namespace gj { + + +class Text : public WritableBase { + public: + Text(Text&&) = default; + Text(const Text&) = default; + + Text& operator=(Text&&) = default; + Text& operator=(const Text&) = default; + + Text(const std::wstring& str, uint32_t x = 0, uint32_t y = 0) : + WritableBase(x, y), entity_(str) { + } + + void Write(Textbuffer& fb) const override { + const int32_t w = static_cast(fb.width()); + const int32_t h = static_cast(fb.height()); + + char16_t* ptr = fb.ptr(); + + int32_t x = x_, y = y_; + if (y >= h) return; + + const size_t len = entity_.size(); + for (size_t i = 0; i < len; ++i) { + if (x < 0) continue; + if (x >= w) return; + + ptr[x+y*w] = entity_[i]; + x += (entity_[i] > UINT8_MAX)? 2: 1; + } + } + + private: + std::wstring entity_; +}; + + +} \ No newline at end of file diff --git a/Win32Console.cc b/Win32Console.cc index 292d452..548b609 100644 --- a/Win32Console.cc +++ b/Win32Console.cc @@ -64,7 +64,7 @@ void gj::Win32Console::main() { mb = false; } else { CalcChar(*c, *cb, *tb); - mb = (*tb & 0x80); + mb = *tb > UINT8_MAX; } ++cb, ++tb, ++c; } diff --git a/Win32Console.h b/Win32Console.h index bc8cde3..41cfcb7 100644 --- a/Win32Console.h +++ b/Win32Console.h @@ -6,7 +6,9 @@ #include #include +#define NOMINMAX #include +#undef NOMINMAX #include "iConsole.h" @@ -14,7 +16,7 @@ namespace gj { -class Win32Console : iConsole { +class Win32Console : public iConsole { public: Win32Console() = delete; Win32Console(Win32Console&&) = delete; diff --git a/common.h b/common.h index 5c08d74..726f5d4 100644 --- a/common.h +++ b/common.h @@ -10,12 +10,16 @@ namespace gj { +static inline std::wstring ConvertUtf8ToUtf16(const std::string& str) { + std::wostringstream conv; + conv << str.c_str(); + return conv.str(); +} + + [[noreturn]] static inline void Abort(const std::string& msg) { - std::wostringstream conv; - conv << msg.c_str(); - - MessageBox(NULL, conv.str().c_str(), L"PROGRAM ABORTED", MB_OK); + MessageBox(NULL, ConvertUtf8ToUtf16(msg).c_str(), L"PROGRAM ABORTED", MB_OK); std::exit(1); } diff --git a/iDrawable.h b/iDrawable.h new file mode 100644 index 0000000..fc81d52 --- /dev/null +++ b/iDrawable.h @@ -0,0 +1,51 @@ +#pragma once + +#include "thirdparty/linalg.h" + +#include "Rasterbuffer.h" + + +namespace gj { + + +using mat4 = ::linalg::mat; +using vec4 = ::linalg::vec; + +class iDrawable { + public: + iDrawable(iDrawable&&) = default; + iDrawable(const iDrawable&) = default; + + iDrawable& operator=(iDrawable&&) = default; + iDrawable& operator=(const iDrawable&) = default; + + iDrawable() = default; + virtual ~iDrawable() = default; + + virtual void Draw(Colorbuffer& buf) const = 0; +}; + +class DrawableBase : public iDrawable { + public: + DrawableBase() = default; + ~DrawableBase() = default; + + DrawableBase(DrawableBase&&) = default; + DrawableBase(const DrawableBase&) = default; + + DrawableBase& operator=(DrawableBase&&) = default; + DrawableBase& operator=(const DrawableBase&) = default; + + void setMatrix(const mat4& m) { + setMatrix(mat4(m)); + } + void setMatrix(mat4&& m) { + mat_ = std::move(m); + } + + protected: + mat4 mat_ = ::linalg::identity; +}; + + +} \ No newline at end of file diff --git a/iLogger.h b/iLogger.h new file mode 100644 index 0000000..e2706d9 --- /dev/null +++ b/iLogger.h @@ -0,0 +1,24 @@ +#pragma once + +#include + + +namespace gj { + + +class iLogger { + public: + iLogger(iLogger&&) = delete; + iLogger(const iLogger&) = delete; + + iLogger& operator=(iLogger&&) = delete; + iLogger& operator=(const iLogger&) = delete; + + iLogger() = default; + virtual ~iLogger() = default; + + virtual void Print(const std::wstring& msg) = 0; +}; + + +} \ No newline at end of file diff --git a/iWritable.h b/iWritable.h new file mode 100644 index 0000000..098e164 --- /dev/null +++ b/iWritable.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include "Rasterbuffer.h" + + +namespace gj { + + +class iWritable { + public: + iWritable(iWritable&&) = default; + iWritable(const iWritable&) = default; + + iWritable& operator=(iWritable&&) = default; + iWritable& operator=(const iWritable&) = default; + + iWritable() = default; + virtual ~iWritable() = default; + + virtual void Write(Textbuffer&) const = 0; +}; + +class WritableBase : public iWritable { + public: + WritableBase(WritableBase&&) = default; + WritableBase(const WritableBase&) = default; + + WritableBase& operator=(WritableBase&&) = default; + WritableBase& operator=(const WritableBase&) = default; + + WritableBase(int32_t x, int32_t y) : x_(x), y_(y) { + } + + void SetPosition(int32_t x, int32_t y) { + x_ = x; + y_ = y; + } + + protected: + int32_t x_ = 0, y_ = 0; +}; + + +} \ No newline at end of file diff --git a/main.cc b/main.cc index 47b3943..3b59ed4 100644 --- a/main.cc +++ b/main.cc @@ -1,10 +1,13 @@ #include #include +#define NOMINMAX #include +#undef NOMINMAX #include "common.h" #include "Font.h" +#include "Game.h" #include "LinearAllocator.h" #include "Win32Console.h" @@ -21,54 +24,22 @@ int main() { gj::Win32Console console(&alloc, kWidth, kHeight); console.Show(); - gj::Font font(&alloc, "./font/shippori.ttf"); - gj::Colorbuffer glyph = font.RenderGlyph(L'繍', 50); + gj::Game game(kWidth, kHeight); - size_t t = 0; while (true) { + game.Update(); { - const std::u16string s = u"世界は猫によって支配されている"; - - gj::Textbuffer& tb = console.TakeTextbuffer(); - tb.Clear(); - - char16_t* ptr = tb.ptr() + kWidth*(kHeight/2)+(t%(kWidth-s.length()*2)); - for (size_t i = 0; i < s.length(); ++i) { - ptr[i*2] = s[i]; - } - console.SwapTextbuffer(); - } - - { - gj::Colorbuffer& cb = console.TakeColorbuffer(); - float* ptr = cb.ptr(); - - constexpr uintmax_t max = kHeight + kWidth; - for (uint32_t y = 0; y < kHeight; ++y) { - for (uint32_t x = 0; x < kWidth; ++x) { - *ptr = static_cast((static_cast(y)+x+t)%(max*2)*1./max); - if (*ptr > 1) *ptr = 2-*ptr; - ++ptr; - } - } - - ptr = cb.ptr(); - const uint32_t w = glyph.width(); - const uint32_t h = glyph.height(); - const float* src = glyph.ptr(); - for (uint32_t y = 0; y < h; ++y) { - if (y >= kHeight) break; - for (uint32_t x = 0; x < w; ++x) { - if (x*2+1 >= kWidth) break; - ptr[y*kWidth+x*2] += src[y*w+x]*.3; - ptr[y*kWidth+x*2+1] += src[y*w+x]*.3; - } - } - + auto& fb = console.TakeColorbuffer(); + fb.Clear(); + game.Draw(fb); console.SwapColorbuffer(); } - - Sleep(60); - ++t; + { + auto& fb = console.TakeTextbuffer(); + fb.Clear(); + game.Write(fb); + console.SwapTextbuffer(); + } + Sleep(100); } } \ No newline at end of file diff --git a/thirdparty/linalg.h b/thirdparty/linalg.h new file mode 100644 index 0000000..aff292a --- /dev/null +++ b/thirdparty/linalg.h @@ -0,0 +1,721 @@ +// linalg.h - 2.2-beta - Single-header public domain linear algebra library +// +// The intent of this library is to provide the bulk of the functionality +// you need to write programs that frequently use small, fixed-size vectors +// and matrices, in domains such as computational geometry or computer +// graphics. It strives for terse, readable source code. +// +// The original author of this software is Sterling Orsten, and its permanent +// home is . If you find this software +// useful, an acknowledgement in your source text and/or product documentation +// is appreciated, but not required. +// +// The author acknowledges significant insights and contributions by: +// Stan Melax +// Dimitri Diakopoulos +// +// Some features are deprecated. Define LINALG_FORWARD_COMPATIBLE to remove them. + + + +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// 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 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. +// +// For more information, please refer to + + + +#pragma once +#ifndef LINALG_H +#define LINALG_H + +#include // For various unary math functions, such as std::sqrt +#include // To resolve std::abs ambiguity on clang +#include // For implementing namespace linalg::aliases +#include // For std::array +#include // For forward definitions of std::ostream +#include // For std::enable_if, std::is_same, std::declval +#include // For std::hash declaration + +// In Visual Studio 2015, `constexpr` applied to a member function implies `const`, which causes ambiguous overload resolution +#if _MSC_VER <= 1900 +#define LINALG_CONSTEXPR14 +#else +#define LINALG_CONSTEXPR14 constexpr +#endif + +namespace linalg +{ + // Small, fixed-length vector type, consisting of exactly M elements of type T, and presumed to be a column-vector unless otherwise noted. + template struct vec; + + // Small, fixed-size matrix type, consisting of exactly M rows and N columns of type T, stored in column-major order. + template struct mat; + + // Specialize converter with a function application operator that converts type U to type T to enable implicit conversions + template struct converter {}; + namespace detail + { + template using conv_t = typename std::enable_if::value, decltype(converter{}(std::declval()))>::type; + + // Trait for retrieving scalar type of any linear algebra object + template struct scalar_type {}; + template struct scalar_type> { using type = T; }; + template struct scalar_type> { using type = T; }; + + // Type returned by the compare(...) function which supports all six comparison operators against 0 + template struct ord { T a,b; }; + template constexpr bool operator == (const ord & o, std::nullptr_t) { return o.a == o.b; } + template constexpr bool operator != (const ord & o, std::nullptr_t) { return !(o.a == o.b); } + template constexpr bool operator < (const ord & o, std::nullptr_t) { return o.a < o.b; } + template constexpr bool operator > (const ord & o, std::nullptr_t) { return o.b < o.a; } + template constexpr bool operator <= (const ord & o, std::nullptr_t) { return !(o.b < o.a); } + template constexpr bool operator >= (const ord & o, std::nullptr_t) { return !(o.a < o.b); } + + // Patterns which can be used with the compare(...) function + template struct any_compare {}; + template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return ord{a.x,b.x}; } }; + template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : ord{a.y,b.y}; } }; + template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : !(a.y==b.y) ? ord{a.y,b.y} : ord{a.z,b.z}; } }; + template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : !(a.y==b.y) ? ord{a.y,b.y} : !(a.z==b.z) ? ord{a.z,b.z} : ord{a.w,b.w}; } }; + template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return compare(a.x,b.x); } }; + template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : compare(a.y,b.y); } }; + template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : a.y!=b.y ? compare(a.y,b.y) : compare(a.z,b.z); } }; + template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : a.y!=b.y ? compare(a.y,b.y) : a.z!=b.z ? compare(a.z,b.z) : compare(a.w,b.w); } }; + + // Helper for compile-time index-based access to members of vector and matrix types + template struct getter; + template<> struct getter<0> { template constexpr auto operator() (A & a) const -> decltype(a.x) { return a.x; } }; + template<> struct getter<1> { template constexpr auto operator() (A & a) const -> decltype(a.y) { return a.y; } }; + template<> struct getter<2> { template constexpr auto operator() (A & a) const -> decltype(a.z) { return a.z; } }; + template<> struct getter<3> { template constexpr auto operator() (A & a) const -> decltype(a.w) { return a.w; } }; + + // Stand-in for std::integer_sequence/std::make_integer_sequence + template struct seq {}; + template struct make_seq_impl; + template struct make_seq_impl { using type=seq<>; }; + template struct make_seq_impl { using type=seq; }; + template struct make_seq_impl { using type=seq; }; + template struct make_seq_impl { using type=seq; }; + template struct make_seq_impl { using type=seq; }; + template using make_seq = typename make_seq_impl::type; + template vec constexpr swizzle(const vec & v, seq i) { return {getter{}(v)...}; } + template mat constexpr swizzle(const mat & m, seq i, seq j) { return {swizzle(getter{}(m),i)...}; } + + // SFINAE helpers to determine result of function application + template using ret_t = decltype(std::declval()(std::declval()...)); + + // SFINAE helper which is defined if all provided types are scalars + struct empty {}; + template struct scalars; + template<> struct scalars<> { using type=void; }; + template struct scalars : std::conditional::value, scalars, empty>::type {}; + template using scalars_t = typename scalars::type; + + // Helpers which indicate how apply(F, ...) should be called for various arguments + template struct apply {}; // Patterns which contain only vectors or scalars + template struct apply, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a ) { return {f(getter{}(a) )...}; } }; + template struct apply, vec, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b ) { return {f(getter{}(a), getter{}(b) )...}; } }; + template struct apply, vec, B > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b ) { return {f(getter{}(a), b )...}; } }; + template struct apply, A, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b ) { return {f(a, getter{}(b) )...}; } }; + template struct apply, vec, vec, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b, const vec & c) { return {f(getter{}(a), getter{}(b), getter{}(c))...}; } }; + template struct apply, vec, vec, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b, C c) { return {f(getter{}(a), getter{}(b), c )...}; } }; + template struct apply, vec, B, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b, const vec & c) { return {f(getter{}(a), b, getter{}(c))...}; } }; + template struct apply, vec, B, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b, C c) { return {f(getter{}(a), b, c )...}; } }; + template struct apply, A, vec, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b, const vec & c) { return {f(a, getter{}(b), getter{}(c))...}; } }; + template struct apply, A, vec, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b, C c) { return {f(a, getter{}(b), c )...}; } }; + template struct apply, A, B, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, B b, const vec & c) { return {f(a, b, getter{}(c))...}; } }; + template struct apply, mat > { using type=mat,M,N>; enum {size=N, mm=0}; template static constexpr type impl(seq, F f, const mat & a ) { return {apply >::impl(make_seq<0,M>{}, f, getter{}(a) )...}; } }; + template struct apply, mat, mat> { using type=mat,M,N>; enum {size=N, mm=1}; template static constexpr type impl(seq, F f, const mat & a, const mat & b) { return {apply, vec>::impl(make_seq<0,M>{}, f, getter{}(a), getter{}(b))...}; } }; + template struct apply, mat, B > { using type=mat,M,N>; enum {size=N, mm=0}; template static constexpr type impl(seq, F f, const mat & a, B b) { return {apply, B >::impl(make_seq<0,M>{}, f, getter{}(a), b )...}; } }; + template struct apply, A, mat> { using type=mat,M,N>; enum {size=N, mm=0}; template static constexpr type impl(seq, F f, A a, const mat & b) { return {apply>::impl(make_seq<0,M>{}, f, a, getter{}(b))...}; } }; + template struct apply, A...> { using type = ret_t; enum {size=0, mm=0}; static constexpr type impl(seq<>, F f, A... a) { return f(a...); } }; + + // Function objects for selecting between alternatives + struct min { template constexpr auto operator() (A a, B b) const -> typename std::remove_reference::type { return a constexpr auto operator() (A a, B b) const -> typename std::remove_reference::type { return a constexpr auto operator() (A a, B b, C c) const -> typename std::remove_reference::type { return a constexpr auto operator() (A a, B b, C c) const -> typename std::remove_reference::type { return a ? b : c; } }; + struct lerp { template constexpr auto operator() (A a, B b, C c) const -> decltype(a*(1-c) + b*c) { return a*(1-c) + b*c; } }; + + // Function objects for applying operators + struct op_pos { template constexpr auto operator() (A a) const -> decltype(+a) { return +a; } }; + struct op_neg { template constexpr auto operator() (A a) const -> decltype(-a) { return -a; } }; + struct op_not { template constexpr auto operator() (A a) const -> decltype(!a) { return !a; } }; + struct op_cmp { template constexpr auto operator() (A a) const -> decltype(~(a)) { return ~a; } }; + struct op_mul { template constexpr auto operator() (A a, B b) const -> decltype(a * b) { return a * b; } }; + struct op_div { template constexpr auto operator() (A a, B b) const -> decltype(a / b) { return a / b; } }; + struct op_mod { template constexpr auto operator() (A a, B b) const -> decltype(a % b) { return a % b; } }; + struct op_add { template constexpr auto operator() (A a, B b) const -> decltype(a + b) { return a + b; } }; + struct op_sub { template constexpr auto operator() (A a, B b) const -> decltype(a - b) { return a - b; } }; + struct op_lsh { template constexpr auto operator() (A a, B b) const -> decltype(a << b) { return a << b; } }; + struct op_rsh { template constexpr auto operator() (A a, B b) const -> decltype(a >> b) { return a >> b; } }; + struct op_lt { template constexpr auto operator() (A a, B b) const -> decltype(a < b) { return a < b; } }; + struct op_gt { template constexpr auto operator() (A a, B b) const -> decltype(a > b) { return a > b; } }; + struct op_le { template constexpr auto operator() (A a, B b) const -> decltype(a <= b) { return a <= b; } }; + struct op_ge { template constexpr auto operator() (A a, B b) const -> decltype(a >= b) { return a >= b; } }; + struct op_eq { template constexpr auto operator() (A a, B b) const -> decltype(a == b) { return a == b; } }; + struct op_ne { template constexpr auto operator() (A a, B b) const -> decltype(a != b) { return a != b; } }; + struct op_int { template constexpr auto operator() (A a, B b) const -> decltype(a & b) { return a & b; } }; + struct op_xor { template constexpr auto operator() (A a, B b) const -> decltype(a ^ b) { return a ^ b; } }; + struct op_un { template constexpr auto operator() (A a, B b) const -> decltype(a | b) { return a | b; } }; + struct op_and { template constexpr auto operator() (A a, B b) const -> decltype(a && b) { return a && b; } }; + struct op_or { template constexpr auto operator() (A a, B b) const -> decltype(a || b) { return a || b; } }; + + // Function objects for applying standard library math functions + struct std_abs { template auto operator() (A a) const -> decltype(std::abs (a)) { return std::abs (a); } }; + struct std_floor { template auto operator() (A a) const -> decltype(std::floor(a)) { return std::floor(a); } }; + struct std_ceil { template auto operator() (A a) const -> decltype(std::ceil (a)) { return std::ceil (a); } }; + struct std_exp { template auto operator() (A a) const -> decltype(std::exp (a)) { return std::exp (a); } }; + struct std_log { template auto operator() (A a) const -> decltype(std::log (a)) { return std::log (a); } }; + struct std_log10 { template auto operator() (A a) const -> decltype(std::log10(a)) { return std::log10(a); } }; + struct std_sqrt { template auto operator() (A a) const -> decltype(std::sqrt (a)) { return std::sqrt (a); } }; + struct std_sin { template auto operator() (A a) const -> decltype(std::sin (a)) { return std::sin (a); } }; + struct std_cos { template auto operator() (A a) const -> decltype(std::cos (a)) { return std::cos (a); } }; + struct std_tan { template auto operator() (A a) const -> decltype(std::tan (a)) { return std::tan (a); } }; + struct std_asin { template auto operator() (A a) const -> decltype(std::asin (a)) { return std::asin (a); } }; + struct std_acos { template auto operator() (A a) const -> decltype(std::acos (a)) { return std::acos (a); } }; + struct std_atan { template auto operator() (A a) const -> decltype(std::atan (a)) { return std::atan (a); } }; + struct std_sinh { template auto operator() (A a) const -> decltype(std::sinh (a)) { return std::sinh (a); } }; + struct std_cosh { template auto operator() (A a) const -> decltype(std::cosh (a)) { return std::cosh (a); } }; + struct std_tanh { template auto operator() (A a) const -> decltype(std::tanh (a)) { return std::tanh (a); } }; + struct std_round { template auto operator() (A a) const -> decltype(std::round(a)) { return std::round(a); } }; + struct std_fmod { template auto operator() (A a, B b) const -> decltype(std::fmod (a, b)) { return std::fmod (a, b); } }; + struct std_pow { template auto operator() (A a, B b) const -> decltype(std::pow (a, b)) { return std::pow (a, b); } }; + struct std_atan2 { template auto operator() (A a, B b) const -> decltype(std::atan2 (a, b)) { return std::atan2 (a, b); } }; + struct std_copysign { template auto operator() (A a, B b) const -> decltype(std::copysign(a, b)) { return std::copysign(a, b); } }; + } + + // Small, fixed-length vector type, consisting of exactly M elements of type T, and presumed to be a column-vector unless otherwise noted + template struct vec + { + T x; + constexpr vec() : x() {} + constexpr vec(const T & x_) : x(x_) {} + // NOTE: vec does NOT have a constructor from pointer, this can conflict with initializing its single element from zero + template + constexpr explicit vec(const vec & v) : vec(static_cast(v.x)) {} + constexpr const T & operator[] (int i) const { return x; } + LINALG_CONSTEXPR14 T & operator[] (int i) { return x; } + + template> constexpr vec(const U & u) : vec(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + template struct vec + { + T x,y; + constexpr vec() : x(), y() {} + constexpr vec(const T & x_, const T & y_) : x(x_), y(y_) {} + constexpr explicit vec(const T & s) : vec(s, s) {} + constexpr explicit vec(const T * p) : vec(p[0], p[1]) {} + template + constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y)) {} + constexpr const T & operator[] (int i) const { return i==0?x:y; } + LINALG_CONSTEXPR14 T & operator[] (int i) { return i==0?x:y; } + + template> constexpr vec(const U & u) : vec(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + template struct vec + { + T x,y,z; + constexpr vec() : x(), y(), z() {} + constexpr vec(const T & x_, const T & y_, + const T & z_) : x(x_), y(y_), z(z_) {} + constexpr vec(const vec & xy, + const T & z_) : vec(xy.x, xy.y, z_) {} + constexpr explicit vec(const T & s) : vec(s, s, s) {} + constexpr explicit vec(const T * p) : vec(p[0], p[1], p[2]) {} + template + constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y), static_cast(v.z)) {} + constexpr const T & operator[] (int i) const { return i==0?x:i==1?y:z; } + LINALG_CONSTEXPR14 T & operator[] (int i) { return i==0?x:i==1?y:z; } + constexpr const vec & xy() const { return *reinterpret_cast *>(this); } + vec & xy() { return *reinterpret_cast *>(this); } + + template> constexpr vec(const U & u) : vec(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + template struct vec + { + T x,y,z,w; + constexpr vec() : x(), y(), z(), w() {} + constexpr vec(const T & x_, const T & y_, + const T & z_, const T & w_) : x(x_), y(y_), z(z_), w(w_) {} + constexpr vec(const vec & xy, + const T & z_, const T & w_) : vec(xy.x, xy.y, z_, w_) {} + constexpr vec(const vec & xyz, + const T & w_) : vec(xyz.x, xyz.y, xyz.z, w_) {} + constexpr explicit vec(const T & s) : vec(s, s, s, s) {} + constexpr explicit vec(const T * p) : vec(p[0], p[1], p[2], p[3]) {} + template + constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y), static_cast(v.z), static_cast(v.w)) {} + constexpr const T & operator[] (int i) const { return i==0?x:i==1?y:i==2?z:w; } + LINALG_CONSTEXPR14 T & operator[] (int i) { return i==0?x:i==1?y:i==2?z:w; } + constexpr const vec & xy() const { return *reinterpret_cast *>(this); } + constexpr const vec & xyz() const { return *reinterpret_cast *>(this); } + vec & xy() { return *reinterpret_cast *>(this); } + vec & xyz() { return *reinterpret_cast *>(this); } + + template> constexpr vec(const U & u) : vec(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + + // Small, fixed-size matrix type, consisting of exactly M rows and N columns of type T, stored in column-major order. + template struct mat + { + typedef vec V; + V x; + constexpr mat() : x() {} + constexpr mat(const V & x_) : x(x_) {} + constexpr explicit mat(const T & s) : x(s) {} + constexpr explicit mat(const T * p) : x(p+M*0) {} + template + constexpr explicit mat(const mat & m) : mat(V(m.x)) {} + constexpr vec row(int i) const { return {x[i]}; } + constexpr const V & operator[] (int j) const { return x; } + LINALG_CONSTEXPR14 V & operator[] (int j) { return x; } + + template> constexpr mat(const U & u) : mat(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + template struct mat + { + typedef vec V; + V x,y; + constexpr mat() : x(), y() {} + constexpr mat(const V & x_, const V & y_) : x(x_), y(y_) {} + constexpr explicit mat(const T & s) : x(s), y(s) {} + constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1) {} + template + constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y)) {} + constexpr vec row(int i) const { return {x[i], y[i]}; } + constexpr const V & operator[] (int j) const { return j==0?x:y; } + LINALG_CONSTEXPR14 V & operator[] (int j) { return j==0?x:y; } + + template> constexpr mat(const U & u) : mat(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + template struct mat + { + typedef vec V; + V x,y,z; + constexpr mat() : x(), y(), z() {} + constexpr mat(const V & x_, const V & y_, + const V & z_) : x(x_), y(y_), z(z_) {} + constexpr explicit mat(const T & s) : x(s), y(s), z(s) {} + constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1), z(p+M*2) {} + template + constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y), V(m.z)) {} + constexpr vec row(int i) const { return {x[i], y[i], z[i]}; } + constexpr const V & operator[] (int j) const { return j==0?x:j==1?y:z; } + LINALG_CONSTEXPR14 V & operator[] (int j) { return j==0?x:j==1?y:z; } + + template> constexpr mat(const U & u) : mat(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + template struct mat + { + typedef vec V; + V x,y,z,w; + constexpr mat() : x(), y(), z(), w() {} + constexpr mat(const V & x_, const V & y_, + const V & z_, const V & w_) : x(x_), y(y_), z(z_), w(w_) {} + constexpr explicit mat(const T & s) : x(s), y(s), z(s), w(s) {} + constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1), z(p+M*2), w(p+M*3) {} + template + constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y), V(m.z), V(m.w)) {} + constexpr vec row(int i) const { return {x[i], y[i], z[i], w[i]}; } + constexpr const V & operator[] (int j) const { return j==0?x:j==1?y:j==2?z:w; } + LINALG_CONSTEXPR14 V & operator[] (int j) { return j==0?x:j==1?y:j==2?z:w; } + + template> constexpr mat(const U & u) : mat(converter{}(u)) {} + template> constexpr operator U () const { return converter{}(*this); } + }; + + // Define a type which will convert to the multiplicative identity of any square matrix + struct identity_t { constexpr explicit identity_t(int) {} }; + template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {vec{1}}; } }; + template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {{1,0},{0,1}}; } }; + template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {{1,0,0},{0,1,0},{0,0,1}}; } }; + template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}; } }; + constexpr identity_t identity {1}; + + // Produce a scalar by applying f(A,B) -> A to adjacent pairs of elements from a vec/mat in left-to-right/column-major order (matching the associativity of arithmetic and logical operators) + template constexpr A fold(F f, A a, const vec & b) { return f(a, b.x); } + template constexpr A fold(F f, A a, const vec & b) { return f(f(a, b.x), b.y); } + template constexpr A fold(F f, A a, const vec & b) { return f(f(f(a, b.x), b.y), b.z); } + template constexpr A fold(F f, A a, const vec & b) { return f(f(f(f(a, b.x), b.y), b.z), b.w); } + template constexpr A fold(F f, A a, const mat & b) { return fold(f, a, b.x); } + template constexpr A fold(F f, A a, const mat & b) { return fold(f, fold(f, a, b.x), b.y); } + template constexpr A fold(F f, A a, const mat & b) { return fold(f, fold(f, fold(f, a, b.x), b.y), b.z); } + template constexpr A fold(F f, A a, const mat & b) { return fold(f, fold(f, fold(f, fold(f, a, b.x), b.y), b.z), b.w); } + + // Type aliases for the result of calling apply(...) with various arguments, can be used with return type SFINAE to constrian overload sets + template using apply_t = typename detail::apply::type; + template using mm_apply_t = typename std::enable_if::mm, apply_t>::type; + template using no_mm_apply_t = typename std::enable_if::mm, apply_t>::type; + template using scalar_t = typename detail::scalar_type::type; // Underlying scalar type when performing elementwise operations + + // apply(f,...) applies the provided function in an elementwise fashion to its arguments, producing an object of the same dimensions + template constexpr apply_t apply(F func, const A & ... args) { return detail::apply::impl(detail::make_seq<0,detail::apply::size>{}, func, args...); } + + // map(a,f) is equivalent to apply(f,a) + template constexpr apply_t map(const A & a, F func) { return apply(func, a); } + + // zip(a,b,f) is equivalent to apply(f,a,b) + template constexpr apply_t zip(const A & a, const B & b, F func) { return apply(func, a, b); } + + // Relational operators are defined to compare the elements of two vectors or matrices lexicographically, in column-major order + template constexpr typename detail::any_compare::type compare(const A & a, const B & b) { return detail::any_compare()(a,b); } + template constexpr auto operator == (const A & a, const B & b) -> decltype(compare(a,b) == 0) { return compare(a,b) == 0; } + template constexpr auto operator != (const A & a, const B & b) -> decltype(compare(a,b) != 0) { return compare(a,b) != 0; } + template constexpr auto operator < (const A & a, const B & b) -> decltype(compare(a,b) < 0) { return compare(a,b) < 0; } + template constexpr auto operator > (const A & a, const B & b) -> decltype(compare(a,b) > 0) { return compare(a,b) > 0; } + template constexpr auto operator <= (const A & a, const B & b) -> decltype(compare(a,b) <= 0) { return compare(a,b) <= 0; } + template constexpr auto operator >= (const A & a, const B & b) -> decltype(compare(a,b) >= 0) { return compare(a,b) >= 0; } + + // Functions for coalescing scalar values + template constexpr bool any (const A & a) { return fold(detail::op_or{}, false, a); } + template constexpr bool all (const A & a) { return fold(detail::op_and{}, true, a); } + template constexpr scalar_t sum (const A & a) { return fold(detail::op_add{}, scalar_t(0), a); } + template constexpr scalar_t product(const A & a) { return fold(detail::op_mul{}, scalar_t(1), a); } + template constexpr scalar_t minelem(const A & a) { return fold(detail::min{}, a.x, a); } + template constexpr scalar_t maxelem(const A & a) { return fold(detail::max{}, a.x, a); } + template int argmin(const vec & a) { int j=0; for(int i=1; i int argmax(const vec & a) { int j=0; for(int i=1; i a[j]) j = i; return j; } + + // Unary operators are defined component-wise for linalg types + template constexpr apply_t operator + (const A & a) { return apply(detail::op_pos{}, a); } + template constexpr apply_t operator - (const A & a) { return apply(detail::op_neg{}, a); } + template constexpr apply_t operator ~ (const A & a) { return apply(detail::op_cmp{}, a); } + template constexpr apply_t operator ! (const A & a) { return apply(detail::op_not{}, a); } + + // Binary operators are defined component-wise for linalg types, EXCEPT for `operator *` + template constexpr apply_t operator + (const A & a, const B & b) { return apply(detail::op_add{}, a, b); } + template constexpr apply_t operator - (const A & a, const B & b) { return apply(detail::op_sub{}, a, b); } + template constexpr apply_t cmul (const A & a, const B & b) { return apply(detail::op_mul{}, a, b); } + template constexpr apply_t operator / (const A & a, const B & b) { return apply(detail::op_div{}, a, b); } + template constexpr apply_t operator % (const A & a, const B & b) { return apply(detail::op_mod{}, a, b); } + template constexpr apply_t operator | (const A & a, const B & b) { return apply(detail::op_un{}, a, b); } + template constexpr apply_t operator ^ (const A & a, const B & b) { return apply(detail::op_xor{}, a, b); } + template constexpr apply_t operator & (const A & a, const B & b) { return apply(detail::op_int{}, a, b); } + template constexpr apply_t operator << (const A & a, const B & b) { return apply(detail::op_lsh{}, a, b); } + template constexpr apply_t operator >> (const A & a, const B & b) { return apply(detail::op_rsh{}, a, b); } + + // Binary `operator *` was originally defined component-wise for all patterns, in a fashion consistent with the other operators. However, + // this was one of the most frequent sources of confusion among new users of this library, with the binary `operator *` being used accidentally + // by users who INTENDED the semantics of the algebraic matrix product, but RECEIVED the semantics of the Hadamard product. While there is + // precedent within the HLSL, Fortran, R, APL, J, and Mathematica programming languages for `operator *` having the semantics of the Hadamard + // product between matrices, it is counterintuitive to users of GLSL, Eigen, and many other languages and libraries that chose matrix product + // semantics for `operator *`. + // + // For these reasons, binary `operator *` is now DEPRECATED between pairs of matrices. Users may call `cmul(...)` for component-wise multiplication, + // or `mul(...)` for matrix multiplication. Binary `operator *` continues to be available for vector * vector, vector * scalar, matrix * scalar, etc. + template constexpr no_mm_apply_t operator * (const A & a, const B & b) { return cmul(a,b); } + #ifndef LINALG_FORWARD_COMPATIBLE + template [[deprecated("`operator *` between pairs of matrices is deprecated. See the source text for details.")]] constexpr mm_apply_t operator * (const A & a, const B & b) { return cmul(a,b); } + #endif + + // Binary assignment operators a $= b is always defined as though it were explicitly written a = a $ b + template constexpr auto operator += (A & a, const B & b) -> decltype(a = a + b) { return a = a + b; } + template constexpr auto operator -= (A & a, const B & b) -> decltype(a = a - b) { return a = a - b; } + template constexpr auto operator *= (A & a, const B & b) -> decltype(a = a * b) { return a = a * b; } + template constexpr auto operator /= (A & a, const B & b) -> decltype(a = a / b) { return a = a / b; } + template constexpr auto operator %= (A & a, const B & b) -> decltype(a = a % b) { return a = a % b; } + template constexpr auto operator |= (A & a, const B & b) -> decltype(a = a | b) { return a = a | b; } + template constexpr auto operator ^= (A & a, const B & b) -> decltype(a = a ^ b) { return a = a ^ b; } + template constexpr auto operator &= (A & a, const B & b) -> decltype(a = a & b) { return a = a & b; } + template constexpr auto operator <<= (A & a, const B & b) -> decltype(a = a << b) { return a = a << b; } + template constexpr auto operator >>= (A & a, const B & b) -> decltype(a = a >> b) { return a = a >> b; } + + // Swizzles and subobjects + template constexpr vec swizzle(const vec & a) { return {detail::getter{}(a)...}; } + template constexpr vec subvec (const vec & a) { return detail::swizzle(a, detail::make_seq{}); } + template constexpr mat submat (const mat & a) { return detail::swizzle(a, detail::make_seq{}, detail::make_seq{}); } + + // Component-wise standard library math functions + template apply_t abs (const A & a) { return apply(detail::std_abs{}, a); } + template apply_t floor(const A & a) { return apply(detail::std_floor{}, a); } + template apply_t ceil (const A & a) { return apply(detail::std_ceil{}, a); } + template apply_t exp (const A & a) { return apply(detail::std_exp{}, a); } + template apply_t log (const A & a) { return apply(detail::std_log{}, a); } + template apply_t log10(const A & a) { return apply(detail::std_log10{}, a); } + template apply_t sqrt (const A & a) { return apply(detail::std_sqrt{}, a); } + template apply_t sin (const A & a) { return apply(detail::std_sin{}, a); } + template apply_t cos (const A & a) { return apply(detail::std_cos{}, a); } + template apply_t tan (const A & a) { return apply(detail::std_tan{}, a); } + template apply_t asin (const A & a) { return apply(detail::std_asin{}, a); } + template apply_t acos (const A & a) { return apply(detail::std_acos{}, a); } + template apply_t atan (const A & a) { return apply(detail::std_atan{}, a); } + template apply_t sinh (const A & a) { return apply(detail::std_sinh{}, a); } + template apply_t cosh (const A & a) { return apply(detail::std_cosh{}, a); } + template apply_t tanh (const A & a) { return apply(detail::std_tanh{}, a); } + template apply_t round(const A & a) { return apply(detail::std_round{}, a); } + + template apply_t fmod (const A & a, const B & b) { return apply(detail::std_fmod{}, a, b); } + template apply_t pow (const A & a, const B & b) { return apply(detail::std_pow{}, a, b); } + template apply_t atan2 (const A & a, const B & b) { return apply(detail::std_atan2{}, a, b); } + template apply_t copysign(const A & a, const B & b) { return apply(detail::std_copysign{}, a, b); } + + // Component-wise relational functions on vectors + template constexpr apply_t equal (const A & a, const B & b) { return apply(detail::op_eq{}, a, b); } + template constexpr apply_t nequal (const A & a, const B & b) { return apply(detail::op_ne{}, a, b); } + template constexpr apply_t less (const A & a, const B & b) { return apply(detail::op_lt{}, a, b); } + template constexpr apply_t greater(const A & a, const B & b) { return apply(detail::op_gt{}, a, b); } + template constexpr apply_t lequal (const A & a, const B & b) { return apply(detail::op_le{}, a, b); } + template constexpr apply_t gequal (const A & a, const B & b) { return apply(detail::op_ge{}, a, b); } + + // Component-wise selection functions on vectors + template constexpr apply_t min(const A & a, const B & b) { return apply(detail::min{}, a, b); } + template constexpr apply_t max(const A & a, const B & b) { return apply(detail::max{}, a, b); } + template constexpr apply_t clamp (const X & x, const L & l, const H & h) { return apply(detail::clamp{}, x, l, h); } + template constexpr apply_t select(const P & p, const A & a, const B & b) { return apply(detail::select{}, p, a, b); } + template constexpr apply_t lerp (const A & a, const B & b, const T & t) { return apply(detail::lerp{}, a, b, t); } + + // Support for vector algebra + template constexpr T cross (const vec & a, const vec & b) { return a.x*b.y-a.y*b.x; } + template constexpr vec cross (T a, const vec & b) { return {-a*b.y, a*b.x}; } + template constexpr vec cross (const vec & a, T b) { return {a.y*b, -a.x*b}; } + template constexpr vec cross (const vec & a, const vec & b) { return {a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x}; } + template constexpr T dot (const vec & a, const vec & b) { return sum(a*b); } + template constexpr T length2 (const vec & a) { return dot(a,a); } + template T length (const vec & a) { return std::sqrt(length2(a)); } + template vec normalize(const vec & a) { return a / length(a); } + template constexpr T distance2(const vec & a, const vec & b) { return length2(b-a); } + template T distance (const vec & a, const vec & b) { return length(b-a); } + template T uangle (const vec & a, const vec & b) { T d=dot(a,b); return d > 1 ? 0 : std::acos(d < -1 ? -1 : d); } + template T angle (const vec & a, const vec & b) { return uangle(normalize(a), normalize(b)); } + template vec rot (T a, const vec & v) { const T s = std::sin(a), c = std::cos(a); return {v.x*c - v.y*s, v.x*s + v.y*c}; } + template vec nlerp (const vec & a, const vec & b, T t) { return normalize(lerp(a,b,t)); } + template vec slerp (const vec & a, const vec & b, T t) { T th=uangle(a,b); return th == 0 ? a : a*(std::sin(th*(1-t))/std::sin(th)) + b*(std::sin(th*t)/std::sin(th)); } + + // Support for quaternion algebra using 4D vectors, representing xi + yj + zk + w + template constexpr vec qconj(const vec & q) { return {-q.x,-q.y,-q.z,q.w}; } + template vec qinv (const vec & q) { return qconj(q)/length2(q); } + template vec qexp (const vec & q) { const auto v = q.xyz(); const auto vv = length(v); return std::exp(q.w) * vec{v * (vv > 0 ? std::sin(vv)/vv : 0), std::cos(vv)}; } + template vec qlog (const vec & q) { const auto v = q.xyz(); const auto vv = length(v), qq = length(q); return {v * (vv > 0 ? std::acos(q.w/qq)/vv : 0), std::log(qq)}; } + template vec qpow (const vec & q, const T & p) { const auto v = q.xyz(); const auto vv = length(v), qq = length(q), th = std::acos(q.w/qq); return std::pow(qq,p)*vec{v * (vv > 0 ? std::sin(p*th)/vv : 0), std::cos(p*th)}; } + template constexpr vec qmul (const vec & a, const vec & b) { return {a.x*b.w+a.w*b.x+a.y*b.z-a.z*b.y, a.y*b.w+a.w*b.y+a.z*b.x-a.x*b.z, a.z*b.w+a.w*b.z+a.x*b.y-a.y*b.x, a.w*b.w-a.x*b.x-a.y*b.y-a.z*b.z}; } + template constexpr vec qmul(const vec & a, R... r) { return qmul(a, qmul(r...)); } + + // Support for 3D spatial rotations using quaternions, via qmul(qmul(q, v), qconj(q)) + template constexpr vec qxdir (const vec & q) { return {q.w*q.w+q.x*q.x-q.y*q.y-q.z*q.z, (q.x*q.y+q.z*q.w)*2, (q.z*q.x-q.y*q.w)*2}; } + template constexpr vec qydir (const vec & q) { return {(q.x*q.y-q.z*q.w)*2, q.w*q.w-q.x*q.x+q.y*q.y-q.z*q.z, (q.y*q.z+q.x*q.w)*2}; } + template constexpr vec qzdir (const vec & q) { return {(q.z*q.x+q.y*q.w)*2, (q.y*q.z-q.x*q.w)*2, q.w*q.w-q.x*q.x-q.y*q.y+q.z*q.z}; } + template constexpr mat qmat (const vec & q) { return {qxdir(q), qydir(q), qzdir(q)}; } + template constexpr vec qrot (const vec & q, const vec & v) { return qxdir(q)*v.x + qydir(q)*v.y + qzdir(q)*v.z; } + template T qangle(const vec & q) { return std::atan2(length(q.xyz()), q.w)*2; } + template vec qaxis (const vec & q) { return normalize(q.xyz()); } + template vec qnlerp(const vec & a, const vec & b, T t) { return nlerp(a, dot(a,b) < 0 ? -b : b, t); } + template vec qslerp(const vec & a, const vec & b, T t) { return slerp(a, dot(a,b) < 0 ? -b : b, t); } + + // Support for matrix algebra + template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x; } + template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y; } + template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y + a.z*b.z; } + template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; } + template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x)}; } + template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y)}; } + template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y), mul(a,b.z)}; } + template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y), mul(a,b.z), mul(a,b.w)}; } + template constexpr vec mul(const mat & a, const mat & b, const vec & c) { return mul(mul(a,b),c); } + template constexpr mat mul(const mat & a, const mat & b, const mat & c) { return mul(mul(a,b),c); } + template constexpr vec mul(const mat & a, const mat & b, const mat & c, const vec & d) { return mul(mul(a,b,c),d); } + template constexpr mat mul(const mat & a, const mat & b, const mat & c, const mat & d) { return mul(mul(a,b,c),d); } + template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x}; } + template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y}; } + template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y, a*b.z}; } + template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y, a*b.z, a*b.w}; } + template constexpr vec diagonal(const mat & a) { return {a.x.x}; } + template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y}; } + template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y, a.z.z}; } + template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y, a.z.z, a.w.w}; } + template constexpr T trace(const mat & a) { return sum(diagonal(a)); } + template constexpr mat transpose(const mat & m) { return {m.row(0)}; } + template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1)}; } + template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1), m.row(2)}; } + template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1), m.row(2), m.row(3)}; } + template constexpr mat transpose(const vec & m) { return transpose(mat(m)); } + template constexpr mat adjugate(const mat & a) { return {vec{1}}; } + template constexpr mat adjugate(const mat & a) { return {{a.y.y, -a.x.y}, {-a.y.x, a.x.x}}; } + template constexpr mat adjugate(const mat & a); + template constexpr mat adjugate(const mat & a); + template constexpr mat comatrix(const mat & a) { return transpose(adjugate(a)); } + template constexpr T determinant(const mat & a) { return a.x.x; } + template constexpr T determinant(const mat & a) { return a.x.x*a.y.y - a.x.y*a.y.x; } + template constexpr T determinant(const mat & a) { return a.x.x*(a.y.y*a.z.z - a.z.y*a.y.z) + a.x.y*(a.y.z*a.z.x - a.z.z*a.y.x) + a.x.z*(a.y.x*a.z.y - a.z.x*a.y.y); } + template constexpr T determinant(const mat & a); + template constexpr mat inverse(const mat & a) { return adjugate(a)/determinant(a); } + + // Vectors and matrices can be used as ranges + template T * begin( vec & a) { return &a.x; } + template const T * begin(const vec & a) { return &a.x; } + template T * end ( vec & a) { return begin(a) + M; } + template const T * end (const vec & a) { return begin(a) + M; } + template vec * begin( mat & a) { return &a.x; } + template const vec * begin(const mat & a) { return &a.x; } + template vec * end ( mat & a) { return begin(a) + N; } + template const vec * end (const mat & a) { return begin(a) + N; } + + // Factory functions for 3D spatial transformations (will possibly be removed or changed in a future version) + enum fwd_axis { neg_z, pos_z }; // Should projection matrices be generated assuming forward is {0,0,-1} or {0,0,1} + enum z_range { neg_one_to_one, zero_to_one }; // Should projection matrices map z into the range of [-1,1] or [0,1]? + template vec rotation_quat (const vec & axis, T angle) { return {axis*std::sin(angle/2), std::cos(angle/2)}; } + template vec rotation_quat (const mat & m); + template mat translation_matrix(const vec & translation) { return {{1,0,0,0},{0,1,0,0},{0,0,1,0},{translation,1}}; } + template mat rotation_matrix (const vec & rotation) { return {{qxdir(rotation),0}, {qydir(rotation),0}, {qzdir(rotation),0}, {0,0,0,1}}; } + template mat scaling_matrix (const vec & scaling) { return {{scaling.x,0,0,0}, {0,scaling.y,0,0}, {0,0,scaling.z,0}, {0,0,0,1}}; } + template mat pose_matrix (const vec & q, const vec & p) { return {{qxdir(q),0}, {qydir(q),0}, {qzdir(q),0}, {p,1}}; } + template mat lookat_matrix (const vec & eye, const vec & center, const vec & view_y_dir, fwd_axis fwd = neg_z); + template mat frustum_matrix (T x0, T x1, T y0, T y1, T n, T f, fwd_axis a = neg_z, z_range z = neg_one_to_one); + template mat perspective_matrix(T fovy, T aspect, T n, T f, fwd_axis a = neg_z, z_range z = neg_one_to_one) { T y = n*std::tan(fovy / 2), x = y*aspect; return frustum_matrix(-x, x, -y, y, n, f, a, z); } + + // Provide implicit conversion between linalg::vec and std::array + template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0]}; } }; + template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0], a[1]}; } }; + template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0], a[1], a[2]}; } }; + template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0], a[1], a[2], a[3]}; } }; + + template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0]}; } }; + template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0], a[1]}; } }; + template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0], a[1], a[2]}; } }; + template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0], a[1], a[2], a[3]}; } }; + + // Provide typedefs for common element types and vector/matrix sizes + namespace aliases + { + typedef vec bool1; typedef vec byte1; typedef vec short1; typedef vec ushort1; + typedef vec bool2; typedef vec byte2; typedef vec short2; typedef vec ushort2; + typedef vec bool3; typedef vec byte3; typedef vec short3; typedef vec ushort3; + typedef vec bool4; typedef vec byte4; typedef vec short4; typedef vec ushort4; + typedef vec int1; typedef vec uint1; typedef vec float1; typedef vec double1; + typedef vec int2; typedef vec uint2; typedef vec float2; typedef vec double2; + typedef vec int3; typedef vec uint3; typedef vec float3; typedef vec double3; + typedef vec int4; typedef vec uint4; typedef vec float4; typedef vec double4; + typedef mat bool1x1; typedef mat int1x1; typedef mat float1x1; typedef mat double1x1; + typedef mat bool1x2; typedef mat int1x2; typedef mat float1x2; typedef mat double1x2; + typedef mat bool1x3; typedef mat int1x3; typedef mat float1x3; typedef mat double1x3; + typedef mat bool1x4; typedef mat int1x4; typedef mat float1x4; typedef mat double1x4; + typedef mat bool2x1; typedef mat int2x1; typedef mat float2x1; typedef mat double2x1; + typedef mat bool2x2; typedef mat int2x2; typedef mat float2x2; typedef mat double2x2; + typedef mat bool2x3; typedef mat int2x3; typedef mat float2x3; typedef mat double2x3; + typedef mat bool2x4; typedef mat int2x4; typedef mat float2x4; typedef mat double2x4; + typedef mat bool3x1; typedef mat int3x1; typedef mat float3x1; typedef mat double3x1; + typedef mat bool3x2; typedef mat int3x2; typedef mat float3x2; typedef mat double3x2; + typedef mat bool3x3; typedef mat int3x3; typedef mat float3x3; typedef mat double3x3; + typedef mat bool3x4; typedef mat int3x4; typedef mat float3x4; typedef mat double3x4; + typedef mat bool4x1; typedef mat int4x1; typedef mat float4x1; typedef mat double4x1; + typedef mat bool4x2; typedef mat int4x2; typedef mat float4x2; typedef mat double4x2; + typedef mat bool4x3; typedef mat int4x3; typedef mat float4x3; typedef mat double4x3; + typedef mat bool4x4; typedef mat int4x4; typedef mat float4x4; typedef mat double4x4; + } + + // Provide output streaming operators, writing something that resembles an aggregate literal that could be used to construct the specified value + namespace ostream_overloads + { + template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << '}'; } + template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << ',' << v[1] << '}'; } + template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << '}'; } + template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << ',' << v[3] << '}'; } + + template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << '}'; } + template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << ',' << m[1] << '}'; } + template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << '}'; } + template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << ',' << m[3] << '}'; } + } +} + +namespace std +{ + // Provide specializations for std::hash<...> with linalg types + template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x); } }; + template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1); } }; + template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1) ^ (h(v.z) << 2); } }; + template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1) ^ (h(v.z) << 2) ^ (h(v.w) << 3); } }; + + template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x); } }; + template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M); } }; + template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M) ^ (h(v.z) << (M*2)); } }; + template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M) ^ (h(v.z) << (M*2)) ^ (h(v.w) << (M*3)); } }; +} + +// Definitions of functions too long to be defined inline +template constexpr linalg::mat linalg::adjugate(const mat & a) +{ + return {{a.y.y*a.z.z - a.z.y*a.y.z, a.z.y*a.x.z - a.x.y*a.z.z, a.x.y*a.y.z - a.y.y*a.x.z}, + {a.y.z*a.z.x - a.z.z*a.y.x, a.z.z*a.x.x - a.x.z*a.z.x, a.x.z*a.y.x - a.y.z*a.x.x}, + {a.y.x*a.z.y - a.z.x*a.y.y, a.z.x*a.x.y - a.x.x*a.z.y, a.x.x*a.y.y - a.y.x*a.x.y}}; +} + +template constexpr linalg::mat linalg::adjugate(const mat & a) +{ + return {{a.y.y*a.z.z*a.w.w + a.w.y*a.y.z*a.z.w + a.z.y*a.w.z*a.y.w - a.y.y*a.w.z*a.z.w - a.z.y*a.y.z*a.w.w - a.w.y*a.z.z*a.y.w, + a.x.y*a.w.z*a.z.w + a.z.y*a.x.z*a.w.w + a.w.y*a.z.z*a.x.w - a.w.y*a.x.z*a.z.w - a.z.y*a.w.z*a.x.w - a.x.y*a.z.z*a.w.w, + a.x.y*a.y.z*a.w.w + a.w.y*a.x.z*a.y.w + a.y.y*a.w.z*a.x.w - a.x.y*a.w.z*a.y.w - a.y.y*a.x.z*a.w.w - a.w.y*a.y.z*a.x.w, + a.x.y*a.z.z*a.y.w + a.y.y*a.x.z*a.z.w + a.z.y*a.y.z*a.x.w - a.x.y*a.y.z*a.z.w - a.z.y*a.x.z*a.y.w - a.y.y*a.z.z*a.x.w}, + {a.y.z*a.w.w*a.z.x + a.z.z*a.y.w*a.w.x + a.w.z*a.z.w*a.y.x - a.y.z*a.z.w*a.w.x - a.w.z*a.y.w*a.z.x - a.z.z*a.w.w*a.y.x, + a.x.z*a.z.w*a.w.x + a.w.z*a.x.w*a.z.x + a.z.z*a.w.w*a.x.x - a.x.z*a.w.w*a.z.x - a.z.z*a.x.w*a.w.x - a.w.z*a.z.w*a.x.x, + a.x.z*a.w.w*a.y.x + a.y.z*a.x.w*a.w.x + a.w.z*a.y.w*a.x.x - a.x.z*a.y.w*a.w.x - a.w.z*a.x.w*a.y.x - a.y.z*a.w.w*a.x.x, + a.x.z*a.y.w*a.z.x + a.z.z*a.x.w*a.y.x + a.y.z*a.z.w*a.x.x - a.x.z*a.z.w*a.y.x - a.y.z*a.x.w*a.z.x - a.z.z*a.y.w*a.x.x}, + {a.y.w*a.z.x*a.w.y + a.w.w*a.y.x*a.z.y + a.z.w*a.w.x*a.y.y - a.y.w*a.w.x*a.z.y - a.z.w*a.y.x*a.w.y - a.w.w*a.z.x*a.y.y, + a.x.w*a.w.x*a.z.y + a.z.w*a.x.x*a.w.y + a.w.w*a.z.x*a.x.y - a.x.w*a.z.x*a.w.y - a.w.w*a.x.x*a.z.y - a.z.w*a.w.x*a.x.y, + a.x.w*a.y.x*a.w.y + a.w.w*a.x.x*a.y.y + a.y.w*a.w.x*a.x.y - a.x.w*a.w.x*a.y.y - a.y.w*a.x.x*a.w.y - a.w.w*a.y.x*a.x.y, + a.x.w*a.z.x*a.y.y + a.y.w*a.x.x*a.z.y + a.z.w*a.y.x*a.x.y - a.x.w*a.y.x*a.z.y - a.z.w*a.x.x*a.y.y - a.y.w*a.z.x*a.x.y}, + {a.y.x*a.w.y*a.z.z + a.z.x*a.y.y*a.w.z + a.w.x*a.z.y*a.y.z - a.y.x*a.z.y*a.w.z - a.w.x*a.y.y*a.z.z - a.z.x*a.w.y*a.y.z, + a.x.x*a.z.y*a.w.z + a.w.x*a.x.y*a.z.z + a.z.x*a.w.y*a.x.z - a.x.x*a.w.y*a.z.z - a.z.x*a.x.y*a.w.z - a.w.x*a.z.y*a.x.z, + a.x.x*a.w.y*a.y.z + a.y.x*a.x.y*a.w.z + a.w.x*a.y.y*a.x.z - a.x.x*a.y.y*a.w.z - a.w.x*a.x.y*a.y.z - a.y.x*a.w.y*a.x.z, + a.x.x*a.y.y*a.z.z + a.z.x*a.x.y*a.y.z + a.y.x*a.z.y*a.x.z - a.x.x*a.z.y*a.y.z - a.y.x*a.x.y*a.z.z - a.z.x*a.y.y*a.x.z}}; +} + +template constexpr T linalg::determinant(const mat & a) +{ + return a.x.x*(a.y.y*a.z.z*a.w.w + a.w.y*a.y.z*a.z.w + a.z.y*a.w.z*a.y.w - a.y.y*a.w.z*a.z.w - a.z.y*a.y.z*a.w.w - a.w.y*a.z.z*a.y.w) + + a.x.y*(a.y.z*a.w.w*a.z.x + a.z.z*a.y.w*a.w.x + a.w.z*a.z.w*a.y.x - a.y.z*a.z.w*a.w.x - a.w.z*a.y.w*a.z.x - a.z.z*a.w.w*a.y.x) + + a.x.z*(a.y.w*a.z.x*a.w.y + a.w.w*a.y.x*a.z.y + a.z.w*a.w.x*a.y.y - a.y.w*a.w.x*a.z.y - a.z.w*a.y.x*a.w.y - a.w.w*a.z.x*a.y.y) + + a.x.w*(a.y.x*a.w.y*a.z.z + a.z.x*a.y.y*a.w.z + a.w.x*a.z.y*a.y.z - a.y.x*a.z.y*a.w.z - a.w.x*a.y.y*a.z.z - a.z.x*a.w.y*a.y.z); +} + +template linalg::vec linalg::rotation_quat(const mat & m) +{ + const vec q {m.x.x-m.y.y-m.z.z, m.y.y-m.x.x-m.z.z, m.z.z-m.x.x-m.y.y, m.x.x+m.y.y+m.z.z}, s[] { + {1, m.x.y + m.y.x, m.z.x + m.x.z, m.y.z - m.z.y}, + {m.x.y + m.y.x, 1, m.y.z + m.z.y, m.z.x - m.x.z}, + {m.x.z + m.z.x, m.y.z + m.z.y, 1, m.x.y - m.y.x}, + {m.y.z - m.z.y, m.z.x - m.x.z, m.x.y - m.y.x, 1}}; + return copysign(normalize(sqrt(max(T(0), T(1)+q))), s[argmax(q)]); +} + +template linalg::mat linalg::lookat_matrix(const vec & eye, const vec & center, const vec & view_y_dir, fwd_axis a) +{ + const vec f = normalize(center - eye), z = a == pos_z ? f : -f, x = normalize(cross(view_y_dir, z)), y = cross(z, x); + return inverse(mat{{x,0},{y,0},{z,0},{eye,1}}); +} + +template linalg::mat linalg::frustum_matrix(T x0, T x1, T y0, T y1, T n, T f, fwd_axis a, z_range z) +{ + const T s = a == pos_z ? T(1) : T(-1), o = z == neg_one_to_one ? n : 0; + return {{2*n/(x1-x0),0,0,0}, {0,2*n/(y1-y0),0,0}, {-s*(x0+x1)/(x1-x0),-s*(y0+y1)/(y1-y0),s*(f+o)/(f-n),s}, {0,0,-(n+o)*f/(f-n),0}}; +} + +#endif diff --git a/stb_truetype.h b/thirdparty/stb_truetype.h similarity index 100% rename from stb_truetype.h rename to thirdparty/stb_truetype.h