| @@ -2,13 +2,15 @@ | |||
| [submodule "core"] | |||
| path = lol-core | |||
| url = ../../lolengine/lol.git | |||
| branch = core/master | |||
| branch = core | |||
| # A very large repository with Windows binaries | |||
| [submodule "external"] | |||
| path = external | |||
| url = ../../lolengine/ext-binaries.git | |||
| branch = master | |||
| # Some libraries we embed in the engine | |||
| [submodule "imgui"] | |||
| path = src/3rdparty/imgui | |||
| url = ../../lolengine/ext-imgui.git | |||
| @@ -21,14 +23,6 @@ | |||
| path = src/3rdparty/lua | |||
| url = ../../lolengine/ext-lua.git | |||
| branch = lol | |||
| [submodule "pegtl"] | |||
| path = src/3rdparty/pegtl | |||
| url = ../../lolengine/ext-pegtl.git | |||
| branch = lol | |||
| [submodule "mingw-std-threads"] | |||
| path = src/3rdparty/mingw-std-threads | |||
| url = ../../lolengine/ext-mingw-std-threads.git | |||
| branch = master | |||
| [submodule "cpp-httplib"] | |||
| path = src/3rdparty/cpp-httplib | |||
| url = ../../lolengine/ext-cpp-httplib.git | |||
| @@ -99,7 +99,7 @@ public: | |||
| m_aabb.aa = m_position; | |||
| m_aabb.bb = vec3((vec2)m_window_size, 0); | |||
| if (has_threads()) | |||
| if (thread::has_threads()) | |||
| { | |||
| // Spawn worker threads and wait for their readiness | |||
| for (int i = 0; i < MAX_THREADS; i++) | |||
| @@ -111,7 +111,7 @@ public: | |||
| ~Fractal() | |||
| { | |||
| if (has_threads()) | |||
| if (thread::has_threads()) | |||
| { | |||
| // Signal worker threads for completion and wait for them to quit | |||
| for (int i = 0; i < MAX_THREADS; i++) | |||
| @@ -291,7 +291,7 @@ public: | |||
| for (int i = 0; i < m_size.y; i += MAX_LINES * 2) | |||
| { | |||
| if (has_threads()) | |||
| if (thread::has_threads()) | |||
| m_jobqueue.push(i); | |||
| else | |||
| DoWork(i); | |||
| @@ -473,7 +473,7 @@ public: | |||
| if (m_dirty[m_frame]) | |||
| { | |||
| if (has_threads()) | |||
| if (thread::has_threads()) | |||
| { | |||
| for (int i = 0; i < m_size.y; i += MAX_LINES * 2) | |||
| m_donequeue.pop(); | |||
| @@ -1 +1 @@ | |||
| Subproject commit 29336e3d2fcd112d6f66bc5d8569876ccb22b6ec | |||
| Subproject commit f30c17f180002170d3d25bcc133b6792175c8bb7 | |||
| @@ -13,13 +13,10 @@ liblol_lua_a_CPPFLAGS = $(AM_CPPFLAGS) -DLUA_ANSI $(disable_cflags_lua) | |||
| include lol-lua.am | |||
| EXTRA_DIST += $(imgui_sources) $(mingw_std_threads_sources) $(pegtl_sources) \ | |||
| $(cpp_httplib_sources) | |||
| EXTRA_DIST += $(imgui_sources) $(cpp_httplib_sources) | |||
| EXTRA_DIST += lol-lua.vcxproj lol-lua.vcxproj.filters | |||
| include lol-cpp-httplib.am | |||
| include lol-mingw-std-threads.am | |||
| include lol-pegtl.am | |||
| # XXX: this is included by the parent Makefile instead | |||
| #include lol-imgui.am | |||
| @@ -1 +0,0 @@ | |||
| Subproject commit 86ca7dc89659a556dcd1b6f954ed8f2799e23e2f | |||
| @@ -1 +0,0 @@ | |||
| Subproject commit 5e9e1e8c2792293efced6998ae8e28ac46d93c03 | |||
| @@ -31,15 +31,15 @@ liblol_core_headers = \ | |||
| lol/lua.h \ | |||
| \ | |||
| lol/base/all.h \ | |||
| lol/base/avl_tree.h lol/base/features.h lol/base/tuple.h lol/base/types.h \ | |||
| lol/base/array.h lol/base/assert.h lol/base/string.h lol/base/map.h \ | |||
| lol/base/enum.h lol/base/log.h \ | |||
| lol/base/avl_tree.h ../legacy/features.h lol/base/tuple.h lol/base/types.h \ | |||
| lol/base/array.h lol/base/assert.h lol/base/map.h lol/base/enum.h \ | |||
| lol/base/log.h \ | |||
| \ | |||
| lol/math/all.h \ | |||
| lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \ | |||
| lol/math/geometry.h lol/math/interp.h lol/math/rand.h lol/math/arraynd.h \ | |||
| lol/math/functions.h lol/math/vector.h lol/math/half.h \ | |||
| lol/math/geometry.h lol/math/interp.h lol/math/arraynd.h \ | |||
| lol/math/constants.h lol/math/matrix.h lol/math/ops.h \ | |||
| lol/math/transform.h lol/math/polynomial.h lol/math/bigint.h \ | |||
| lol/math/transform.h lol/math/bigint.h \ | |||
| lol/math/noise/gradient.h lol/math/noise/perlin.h \ | |||
| lol/math/noise/simplex.h \ | |||
| \ | |||
| @@ -53,8 +53,7 @@ liblol_core_headers = \ | |||
| lol/engine/tickable.h \ | |||
| \ | |||
| lol/sys/all.h \ | |||
| lol/sys/init.h lol/sys/file.h lol/sys/getopt.h lol/sys/thread.h \ | |||
| lol/sys/timer.h \ | |||
| lol/sys/init.h lol/sys/file.h \ | |||
| \ | |||
| lol/image/all.h \ | |||
| lol/image/pixel.h lol/image/color.h lol/image/image.h \ | |||
| @@ -94,7 +93,7 @@ liblol_core_sources = \ | |||
| base/assert.cpp base/features.cpp base/log.cpp base/string.cpp \ | |||
| \ | |||
| math/vector.cpp math/matrix.cpp math/transform.cpp math/half.cpp \ | |||
| math/geometry.cpp math/real.cpp \ | |||
| math/geometry.cpp \ | |||
| \ | |||
| gpu/shader.cpp gpu/indexbuffer.cpp gpu/vertexbuffer.cpp \ | |||
| gpu/framebuffer.cpp gpu/texture.cpp gpu/renderer.cpp \ | |||
| @@ -117,7 +116,7 @@ liblol_core_sources = \ | |||
| mesh/mesh.cpp mesh/mesh.h \ | |||
| mesh/primitivemesh.cpp mesh/primitivemesh.h \ | |||
| \ | |||
| sys/init.cpp sys/file.cpp sys/hacks.cpp sys/getopt.cpp \ | |||
| sys/init.cpp sys/file.cpp sys/hacks.cpp \ | |||
| \ | |||
| image/resource.cpp image/resource-private.h \ | |||
| image/image.cpp image/image-private.h image/kernel.cpp image/pixel.cpp \ | |||
| @@ -25,7 +25,7 @@ | |||
| # undef WIN32_LEAN_AND_MEAN | |||
| #endif | |||
| #include "tao/pegtl.hpp" | |||
| #include <lol/base/pegtl.h> | |||
| #include "lolgl.h" | |||
| @@ -178,7 +178,6 @@ | |||
| <ClCompile Include="math\geometry.cpp" /> | |||
| <ClCompile Include="math\half.cpp" /> | |||
| <ClCompile Include="math\matrix.cpp" /> | |||
| <ClCompile Include="math\real.cpp" /> | |||
| <ClCompile Include="math\transform.cpp" /> | |||
| <ClCompile Include="math\vector.cpp" /> | |||
| <ClCompile Include="mesh\mesh.cpp" /> | |||
| @@ -202,7 +201,6 @@ | |||
| <ClCompile Include="scene.cpp" /> | |||
| <ClCompile Include="sprite.cpp" /> | |||
| <ClCompile Include="sys\file.cpp" /> | |||
| <ClCompile Include="sys\getopt.cpp" /> | |||
| <ClCompile Include="sys\hacks.cpp" /> | |||
| <ClCompile Include="sys\init.cpp" /> | |||
| <ClCompile Include="text.cpp" /> | |||
| @@ -256,10 +254,9 @@ | |||
| <ClInclude Include="lol\base\array.h" /> | |||
| <ClInclude Include="lol\base\assert.h" /> | |||
| <ClInclude Include="lol\base\enum.h" /> | |||
| <ClInclude Include="lol\base\features.h" /> | |||
| <ClInclude Include="..\legacy\features.h" /> | |||
| <ClInclude Include="lol\base\log.h" /> | |||
| <ClInclude Include="lol\base\map.h" /> | |||
| <ClInclude Include="lol\base\string.h" /> | |||
| <ClInclude Include="lol\base\types.h" /> | |||
| <ClInclude Include="lol\base\tuple.h" /> | |||
| <ClInclude Include="lol\debug\all.h" /> | |||
| @@ -299,9 +296,6 @@ | |||
| <ClInclude Include="lol\math\noise\perlin.h" /> | |||
| <ClInclude Include="lol\math\noise\simplex.h" /> | |||
| <ClInclude Include="lol\math\ops.h" /> | |||
| <ClInclude Include="lol\math\polynomial.h" /> | |||
| <ClInclude Include="lol\math\rand.h" /> | |||
| <ClInclude Include="lol\math\real.h" /> | |||
| <ClInclude Include="lol\math\transform.h" /> | |||
| <ClInclude Include="lol\math\vector.h" /> | |||
| <ClInclude Include="lol\net\all.h" /> | |||
| @@ -309,10 +303,7 @@ | |||
| <ClInclude Include="lol\public.h" /> | |||
| <ClInclude Include="lol\sys\all.h" /> | |||
| <ClInclude Include="lol\sys\file.h" /> | |||
| <ClInclude Include="lol\sys\getopt.h" /> | |||
| <ClInclude Include="lol\sys\init.h" /> | |||
| <ClInclude Include="lol\sys\thread.h" /> | |||
| <ClInclude Include="lol\sys\timer.h" /> | |||
| <ClInclude Include="mesh\mesh.h" /> | |||
| <ClInclude Include="mesh\primitivemesh.h" /> | |||
| <ClInclude Include="messageservice.h" /> | |||
| @@ -210,9 +210,6 @@ | |||
| <ClCompile Include="math\matrix.cpp"> | |||
| <Filter>math</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="math\real.cpp"> | |||
| <Filter>math</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="math\transform.cpp"> | |||
| <Filter>math</Filter> | |||
| </ClCompile> | |||
| @@ -236,9 +233,6 @@ | |||
| <ClCompile Include="sys\file.cpp"> | |||
| <Filter>sys</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="sys\getopt.cpp"> | |||
| <Filter>sys</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="sys\hacks.cpp"> | |||
| <Filter>sys</Filter> | |||
| </ClCompile> | |||
| @@ -356,7 +350,7 @@ | |||
| <ClInclude Include="lol\base\enum.h"> | |||
| <Filter>lol\base</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\base\features.h"> | |||
| <ClInclude Include="..\legacy\features.h"> | |||
| <Filter>lol\base</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\base\log.h"> | |||
| @@ -365,9 +359,6 @@ | |||
| <ClInclude Include="lol\base\map.h"> | |||
| <Filter>lol\base</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\base\string.h"> | |||
| <Filter>lol\base</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\base\types.h"> | |||
| <Filter>lol\base</Filter> | |||
| </ClInclude> | |||
| @@ -482,15 +473,6 @@ | |||
| <ClInclude Include="lol\math\ops.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\math\polynomial.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\math\rand.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\math\real.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\math\transform.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||
| @@ -512,18 +494,9 @@ | |||
| <ClInclude Include="lol\sys\file.h"> | |||
| <Filter>lol\sys</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\sys\getopt.h"> | |||
| <Filter>lol\sys</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\sys\init.h"> | |||
| <Filter>lol\sys</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\sys\thread.h"> | |||
| <Filter>lol\sys</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\sys\timer.h"> | |||
| <Filter>lol\sys</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="mesh\mesh.h"> | |||
| <Filter>mesh</Filter> | |||
| </ClInclude> | |||
| @@ -12,7 +12,8 @@ | |||
| #pragma once | |||
| #include <lol/base/features.h> | |||
| #include <lol/../../legacy/features.h> | |||
| #include <lol/base/types.h> | |||
| #include <lol/base/log.h> | |||
| #include <lol/base/assert.h> | |||
| @@ -1,46 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright © 2010—2018 Sam Hocevar <sam@hocevar.net> | |||
| // © 2013—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com> | |||
| // | |||
| // Lol Engine is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||
| // See http://www.wtfpl.net/ for more details. | |||
| // | |||
| #pragma once | |||
| // | |||
| // The string tools | |||
| // ---------------- | |||
| // Contains some utilities to work with std::string objects. | |||
| // | |||
| #include <string> | |||
| namespace lol | |||
| { | |||
| /* Split a string along a single separator */ | |||
| array<std::string> split(std::string const &s, char sep = '\n'); | |||
| /* Split a string along multiple separators */ | |||
| array<std::string> split(std::string const &s, std::string const &seps); | |||
| /* Check whether a string starts or ends with a given substring */ | |||
| bool starts_with(std::string const &s, std::string const &prefix); | |||
| bool ends_with(std::string const &s, std::string const &suffix); | |||
| /* Convert a string to lowercase or uppercase */ | |||
| std::string tolower(std::string const &s); | |||
| std::string toupper(std::string const &s); | |||
| /* Format a string, printf-style */ | |||
| std::string format(char const *format, ...) LOL_ATTR_FORMAT(1, 2); | |||
| std::string vformat(char const *format, va_list ap); | |||
| } /* namespace lol */ | |||
| @@ -1,430 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://www.wtfpl.net/ for more details. | |||
| // | |||
| #pragma once | |||
| // | |||
| // The polynomial class | |||
| // -------------------- | |||
| // | |||
| // The data structure is a simple dynamic array of scalars, with the | |||
| // added guarantee that the leading coefficient is always non-zero. | |||
| // | |||
| #include <functional> | |||
| namespace lol | |||
| { | |||
| template<typename T> | |||
| struct LOL_ATTR_NODISCARD polynomial | |||
| { | |||
| /* The zero polynomial */ | |||
| explicit inline polynomial() {} | |||
| /* A constant polynomial */ | |||
| explicit inline polynomial(T const &a) | |||
| { | |||
| m_coefficients.push(a); | |||
| reduce_degree(); | |||
| } | |||
| /* Create a polynomial from a list of coefficients */ | |||
| explicit polynomial(std::initializer_list<T> const &init) | |||
| { | |||
| for (auto a : init) | |||
| m_coefficients.push(a); | |||
| reduce_degree(); | |||
| } | |||
| /* Factory for Chebyshev polynomials */ | |||
| static polynomial<T> chebyshev(int n) | |||
| { | |||
| /* Use T0(x) = 1, T1(x) = x, Tn(x) = 2 x Tn-1(x) - Tn-2(x) */ | |||
| std::function<int64_t (int, int)> coeff = [&](int i, int j) | |||
| { | |||
| if (i > j || i < 0 || ((j ^ i) & 1)) | |||
| return (int64_t)0; | |||
| if (j < 2) | |||
| return (int64_t)1; | |||
| return 2 * coeff(i - 1, j - 1) - coeff(i, j - 2); | |||
| }; | |||
| polynomial<T> ret; | |||
| for (int k = 0; k <= n; ++k) | |||
| ret.m_coefficients.push(T(coeff(k, n))); | |||
| return ret; | |||
| } | |||
| /* We define the zero polynomial (with no coefficients) as having | |||
| * degree -1 on purpose. */ | |||
| inline int degree() const | |||
| { | |||
| return (int)m_coefficients.count() - 1; | |||
| } | |||
| /* Set one of the polynomial’s coefficients */ | |||
| void set(int n, T const &a) | |||
| { | |||
| ASSERT(n >= 0); | |||
| if (n > degree() && !a) | |||
| return; | |||
| while (n > degree()) | |||
| m_coefficients.push(T(0)); | |||
| m_coefficients[n] = a; | |||
| reduce_degree(); | |||
| } | |||
| /* Evaluate polynomial at a given value. This method can also | |||
| * be used to compose polynomials, i.e. using another polynomial | |||
| * as the value instead of a scalar. */ | |||
| template<typename U> LOL_ATTR_NODISCARD U eval(U x) const | |||
| { | |||
| U ret(leading()); | |||
| for (int i = degree() - 1; i >= 0; --i) | |||
| ret = ret * x + U(m_coefficients[i]); | |||
| return ret; | |||
| } | |||
| polynomial<T> derive() const | |||
| { | |||
| /* No need to reduce the degree after deriving. */ | |||
| polynomial<T> ret; | |||
| for (int i = 1; i <= degree(); ++i) | |||
| ret.m_coefficients.push(m_coefficients[i] * T(i)); | |||
| return ret; | |||
| } | |||
| array<T> roots() const | |||
| { | |||
| /* For now we can only solve polynomials of degrees 0, 1, 2 or 3. */ | |||
| ASSERT(degree() >= 0 && degree() <= 3, | |||
| "roots() called on polynomial of degree %d", degree()); | |||
| if (degree() == 0) | |||
| { | |||
| /* p(x) = a > 0 */ | |||
| return array<T> {}; | |||
| } | |||
| else if (degree() == 1) | |||
| { | |||
| /* p(x) = ax + b */ | |||
| T const &a = m_coefficients[1]; | |||
| T const &b = m_coefficients[0]; | |||
| return array<T> { -b / a }; | |||
| } | |||
| else if (degree() == 2) | |||
| { | |||
| /* p(x) = ax² + bx + c */ | |||
| T const &a = m_coefficients[2]; | |||
| T const &b = m_coefficients[1]; | |||
| T const &c = m_coefficients[0]; | |||
| T const k = b / (a + a); | |||
| T const delta = k * k - c / a; | |||
| if (delta < T(0)) | |||
| { | |||
| return array<T> {}; | |||
| } | |||
| else if (delta > T(0)) | |||
| { | |||
| T const sqrt_delta = sqrt(delta); | |||
| return array<T> { -k - sqrt_delta, -k + sqrt_delta }; | |||
| } | |||
| else | |||
| { | |||
| return array<T> { -k }; | |||
| } | |||
| } | |||
| else if (degree() == 3) | |||
| { | |||
| static T const pi = acos(T(-1)); | |||
| /* p(x) = ax³ + bx² + cx + d */ | |||
| T const &a = m_coefficients[3]; | |||
| T const &b = m_coefficients[2]; | |||
| T const &c = m_coefficients[1]; | |||
| T const &d = m_coefficients[0]; | |||
| /* Find k, m, and n such that p(x - k) / a = x³ + mx + n | |||
| * q(x) = p(x - k) / a | |||
| * = x³ + (b/a-3k) x² + ((c-2bk)/a+3k²) x + (d-ck+bk²)/a-k³ | |||
| * | |||
| * So we want k = b/3a and thus: | |||
| * q(x) = x³ + (c-bk)/a x + (d-ck+2bk²/3)/a | |||
| * | |||
| * k = b / 3a | |||
| * m = (c - bk) / a | |||
| * n = (d - ck + 2bk²/3) / a */ | |||
| T const k = b / (T(3) * a); | |||
| T const m = (c - b * k) / a; | |||
| T const n = ((T(2) / T(3) * b * k - c) * k + d) / a; | |||
| /* Let x = u + v, such that 3uv = -m, then: | |||
| * q(u + v) = u³ + v³ + n | |||
| * | |||
| * We then need to solve the following system: | |||
| * u³v³ = -m³/27 | |||
| * u³ + v³ = -n | |||
| * | |||
| * which gives : | |||
| * Δ = n² + 4m³/27 | |||
| * u³ - v³ = √Δ | |||
| * u³ + v³ = -n | |||
| * | |||
| * u³,v³ = (-n ± √Δ) / 2 | |||
| */ | |||
| T const delta = n * n + T(4) / T(27) * m * m * m; | |||
| /* Because 3uv = -m and m is not complex | |||
| * angle(u³) + angle(v³) must equal 0. | |||
| * | |||
| * This is why we compute u³ and v³ by norm and angle separately | |||
| * instead of using a std::complex class */ | |||
| T u_norm, u3_angle; | |||
| T v_norm, v3_angle; | |||
| if (delta < 0) | |||
| { | |||
| v_norm = u_norm = sqrt(m / T(-3)); | |||
| u3_angle = atan2(sqrt(-delta), -n); | |||
| v3_angle = -u3_angle; | |||
| } | |||
| else | |||
| { | |||
| T const sqrt_delta = sqrt(delta); | |||
| u_norm = cbrt(abs(n - sqrt_delta) / T(2)); | |||
| v_norm = cbrt(abs(n + sqrt_delta) / T(2)); | |||
| u3_angle = (n >= sqrt_delta) ? pi : 0; | |||
| v3_angle = (n <= -sqrt_delta) ? 0 : -pi; | |||
| } | |||
| T solutions[3]; | |||
| for (int i : { 0, 1, 2 }) | |||
| { | |||
| T u_angle = (u3_angle + T(2 * i) * pi) / T(3); | |||
| T v_angle = (v3_angle - T(2 * i) * pi) / T(3); | |||
| solutions[i] = u_norm * cos(u_angle) + v_norm * cos(v_angle); | |||
| } | |||
| if (a == d && b == c && b == T(3)*a) // triple solution | |||
| { | |||
| return array<T> { solutions[0] - k }; | |||
| } | |||
| // if root of the derivative is also root of the current polynomial, we have a double root. | |||
| for (auto root : (polynomial<T>{ c, T(2) * b, T(3) * a }).roots()) | |||
| { | |||
| if (eval(root) == T(0)) | |||
| return array<T> { (solutions[0] + solutions[2]) / T(2) - k, | |||
| solutions[1] - k }; | |||
| } | |||
| // we have 3 or 1 root depending on delta sign | |||
| if (delta > 0) | |||
| { | |||
| return array<T> { solutions[0] - k }; | |||
| } | |||
| else // if (delta < 0) 3 real solutions | |||
| { | |||
| return array<T> { solutions[0] - k, | |||
| solutions[1] - k, | |||
| solutions[2] - k }; | |||
| } | |||
| } | |||
| /* It is an error to reach this point. */ | |||
| ASSERT(false); | |||
| return array<T> {}; | |||
| } | |||
| /* Access individual coefficients. This is read-only and returns a | |||
| * copy because we cannot let the user mess with the integrity of | |||
| * the structure (i.e. the guarantee that the leading coefficient | |||
| * remains non-zero). */ | |||
| LOL_ATTR_NODISCARD inline T operator[](ptrdiff_t n) const | |||
| { | |||
| if (n < 0 || n > degree()) | |||
| return T(0); | |||
| return m_coefficients[n]; | |||
| } | |||
| /* Return the leading coefficient */ | |||
| LOL_ATTR_NODISCARD inline T leading() const | |||
| { | |||
| return (*this)[degree()]; | |||
| } | |||
| /* Boolean operations */ | |||
| bool operator !() const | |||
| { | |||
| return degree() < 0; | |||
| } | |||
| operator bool() const | |||
| { | |||
| return !!*this; | |||
| } | |||
| /* Unary plus */ | |||
| polynomial<T> operator +() const | |||
| { | |||
| return *this; | |||
| } | |||
| /* Unary minus */ | |||
| polynomial<T> operator -() const | |||
| { | |||
| polynomial<T> ret; | |||
| for (auto a : m_coefficients) | |||
| ret.m_coefficients.push(-a); | |||
| return ret; | |||
| } | |||
| /* Add two polynomials */ | |||
| polynomial<T> &operator +=(polynomial<T> const &p) | |||
| { | |||
| int min_degree = lol::min(p.degree(), degree()); | |||
| for (int i = 0; i <= min_degree; ++i) | |||
| m_coefficients[i] += p[i]; | |||
| for (int i = min_degree + 1; i <= p.degree(); ++i) | |||
| m_coefficients.push(p[i]); | |||
| reduce_degree(); | |||
| return *this; | |||
| } | |||
| polynomial<T> operator +(polynomial<T> const &p) const | |||
| { | |||
| return polynomial<T>(*this) += p; | |||
| } | |||
| /* Subtract two polynomials */ | |||
| polynomial<T> &operator -=(polynomial<T> const &p) | |||
| { | |||
| return *this += -p; | |||
| } | |||
| polynomial<T> operator -(polynomial<T> const &p) const | |||
| { | |||
| return polynomial<T>(*this) += -p; | |||
| } | |||
| /* Multiply polynomial by a scalar */ | |||
| polynomial<T> &operator *=(T const &k) | |||
| { | |||
| for (auto &a : m_coefficients) | |||
| a *= k; | |||
| reduce_degree(); | |||
| return *this; | |||
| } | |||
| polynomial<T> operator *(T const &k) const | |||
| { | |||
| return polynomial<T>(*this) *= k; | |||
| } | |||
| /* Divide polynomial by a scalar */ | |||
| polynomial<T> &operator /=(T const &k) | |||
| { | |||
| return *this *= (T(1) / k); | |||
| } | |||
| polynomial<T> operator /(T const &k) const | |||
| { | |||
| return *this * (T(1) / k); | |||
| } | |||
| /* Multiply polynomial by another polynomial */ | |||
| polynomial<T> &operator *=(polynomial<T> const &p) | |||
| { | |||
| return *this = *this * p; | |||
| } | |||
| polynomial<T> operator *(polynomial<T> const &p) const | |||
| { | |||
| polynomial<T> ret; | |||
| polynomial<T> const &q = *this; | |||
| if (p.degree() >= 0 && q.degree() >= 0) | |||
| { | |||
| int n = p.degree() + q.degree(); | |||
| for (int i = 0; i <= n; ++i) | |||
| ret.m_coefficients.push(T(0)); | |||
| for (int i = 0; i <= p.degree(); ++i) | |||
| for (int j = 0; j <= q.degree(); ++j) | |||
| ret.m_coefficients[i + j] += p[i] * q[j]; | |||
| ret.reduce_degree(); | |||
| } | |||
| return ret; | |||
| } | |||
| /* Divide a polynomial by another one. There is no /= variant because | |||
| * the return value contains both the quotient and the remainder. */ | |||
| tuple<polynomial<T>, polynomial<T>> operator /(polynomial<T> p) const | |||
| { | |||
| ASSERT(p.degree() >= 0); | |||
| tuple<polynomial<T>, polynomial<T>> ret; | |||
| polynomial<T> "ient = ret.m1; | |||
| polynomial<T> &remainder = ret.m2; | |||
| remainder = *this / p.leading(); | |||
| p /= p.leading(); | |||
| for (int n = remainder.degree() - p.degree(); n >= 0; --n) | |||
| { | |||
| quotient.set(n, remainder.leading()); | |||
| for (int i = 0; i < p.degree(); ++i) | |||
| remainder.m_coefficients[n + i] -= remainder.leading() * p[i]; | |||
| (void)remainder.m_coefficients.pop(); | |||
| } | |||
| return ret; | |||
| } | |||
| private: | |||
| /* Enforce the non-zero leading coefficient rule. */ | |||
| void reduce_degree() | |||
| { | |||
| while (m_coefficients.count() && !m_coefficients.last()) | |||
| (void)m_coefficients.pop(); | |||
| } | |||
| /* The polynomial coefficients */ | |||
| array<T> m_coefficients; | |||
| }; | |||
| template<typename T> | |||
| polynomial<T> operator *(T const &k, polynomial<T> const &p) | |||
| { | |||
| /* We assume k * p is the same as p * k */ | |||
| return p * k; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -1,126 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://www.wtfpl.net/ for more details. | |||
| // | |||
| #pragma once | |||
| // | |||
| // The Random number generators | |||
| // ---------------------------- | |||
| // | |||
| #include <cstdlib> | |||
| #include <stdint.h> | |||
| namespace lol | |||
| { | |||
| /* Random number generators */ | |||
| template<typename T> LOL_ATTR_NODISCARD static inline T rand(); | |||
| template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a); | |||
| template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a, T b); | |||
| /* One-value random number generators */ | |||
| template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a) | |||
| { | |||
| return a ? rand<T>() % a : T(0); | |||
| } | |||
| template<> LOL_ATTR_NODISCARD inline half rand<half>(half a) | |||
| { | |||
| float f = (float)std::rand() / (float)RAND_MAX; | |||
| return (half)(a * f); | |||
| } | |||
| template<> LOL_ATTR_NODISCARD inline float rand<float>(float a) | |||
| { | |||
| float f = (float)std::rand() / (float)RAND_MAX; | |||
| return a * f; | |||
| } | |||
| template<> LOL_ATTR_NODISCARD inline double rand<double>(double a) | |||
| { | |||
| double f = (double)std::rand() / (double)RAND_MAX; | |||
| return a * f; | |||
| } | |||
| template<> LOL_ATTR_NODISCARD inline ldouble rand<ldouble>(ldouble a) | |||
| { | |||
| ldouble f = (ldouble)std::rand() / (ldouble)RAND_MAX; | |||
| return a * f; | |||
| } | |||
| /* Two-value random number generator -- no need for specialisation */ | |||
| template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a, T b) | |||
| { | |||
| return a + rand<T>(b - a); | |||
| } | |||
| /* Default random number generator */ | |||
| template<typename T> LOL_ATTR_NODISCARD static inline T rand() | |||
| { | |||
| switch (sizeof(T)) | |||
| { | |||
| case 1: | |||
| return static_cast<T>(std::rand() & 0x7f); | |||
| case 2: | |||
| { | |||
| uint16_t ret = std::rand(); | |||
| if (RAND_MAX < 0x7fff) | |||
| ret = (ret << 7) ^ std::rand(); | |||
| return static_cast<T>(ret & 0x7fffu); | |||
| } | |||
| case 4: | |||
| { | |||
| uint32_t ret = std::rand(); | |||
| if (RAND_MAX >= 0xffff) | |||
| ret = (ret << 16) ^ std::rand(); | |||
| else | |||
| { | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| } | |||
| return static_cast<T>(ret & 0x7fffffffu); | |||
| } | |||
| case 8: | |||
| { | |||
| uint64_t ret = std::rand(); | |||
| if (RAND_MAX >= 0xffff) | |||
| { | |||
| ret = (ret << 16) ^ std::rand(); | |||
| ret = (ret << 16) ^ std::rand(); | |||
| ret = (ret << 16) ^ std::rand(); | |||
| } | |||
| else | |||
| { | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| ret = (ret << 8) ^ std::rand(); | |||
| } | |||
| return static_cast<T>(ret & (~(uint64_t)0 >> 1)); | |||
| } | |||
| default: | |||
| ASSERT(false, "rand() doesn’t support types of size %d\n", | |||
| (int)sizeof(T)); | |||
| return 0; | |||
| } | |||
| } | |||
| template<> LOL_ATTR_NODISCARD inline half rand<half>() { return rand<half>(1.f); } | |||
| template<> LOL_ATTR_NODISCARD inline float rand<float>() { return rand<float>(1.f); } | |||
| template<> LOL_ATTR_NODISCARD inline double rand<double>() { return rand<double>(1.0); } | |||
| template<> LOL_ATTR_NODISCARD inline ldouble rand<ldouble>() { return rand<ldouble>(1.0); } | |||
| } /* namespace lol */ | |||
| @@ -1,368 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // Lol Engine is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||
| // See http://www.wtfpl.net/ for more details. | |||
| // | |||
| #pragma once | |||
| // | |||
| // The Real class | |||
| // -------------- | |||
| // | |||
| #include <lol/base/types.h> | |||
| #include <vector> | |||
| #include <string> | |||
| #include <cstdint> | |||
| namespace lol | |||
| { | |||
| /* This is OUR namespace. Don't let Windows headers mess with it. */ | |||
| #undef min | |||
| #undef max | |||
| /* | |||
| * The base class for reals. The only real reason for making this a template | |||
| * class is so we can have implicit constructors ("real x = 1" works) but | |||
| * avoid accidental implicit conversions ("int x = 1; sqrt(x)" will never | |||
| * call real::sqrt). | |||
| */ | |||
| template<typename T> | |||
| class LOL_ATTR_NODISCARD Real | |||
| { | |||
| public: | |||
| typedef T bigit_t; | |||
| typedef int64_t exponent_t; | |||
| Real() = default; | |||
| Real(float f); | |||
| Real(double f); | |||
| Real(long double f); | |||
| Real(int32_t i); | |||
| Real(uint32_t i); | |||
| Real(int64_t i); | |||
| Real(uint64_t i); | |||
| Real(char const *str); | |||
| LOL_ATTR_NODISCARD bool is_zero() const { return m_mantissa.size() == 0; } | |||
| LOL_ATTR_NODISCARD bool is_negative() const { return m_sign; } | |||
| LOL_ATTR_NODISCARD bool is_nan() const { return m_nan; } | |||
| LOL_ATTR_NODISCARD bool is_inf() const { return m_inf; } | |||
| LOL_ATTR_NODISCARD operator float() const; | |||
| LOL_ATTR_NODISCARD operator double() const; | |||
| LOL_ATTR_NODISCARD operator long double() const; | |||
| LOL_ATTR_NODISCARD operator int32_t() const; | |||
| LOL_ATTR_NODISCARD operator uint32_t() const; | |||
| LOL_ATTR_NODISCARD operator int64_t() const; | |||
| LOL_ATTR_NODISCARD operator uint64_t() const; | |||
| Real<T> operator +() const; | |||
| Real<T> operator -() const; | |||
| Real<T> operator +(Real<T> const &x) const; | |||
| Real<T> operator -(Real<T> const &x) const; | |||
| Real<T> operator *(Real<T> const &x) const; | |||
| Real<T> operator /(Real<T> const &x) const; | |||
| Real<T> const &operator +=(Real<T> const &x); | |||
| Real<T> const &operator -=(Real<T> const &x); | |||
| Real<T> const &operator *=(Real<T> const &x); | |||
| Real<T> const &operator /=(Real<T> const &x); | |||
| LOL_ATTR_NODISCARD bool operator ==(Real<T> const &x) const; | |||
| LOL_ATTR_NODISCARD bool operator !=(Real<T> const &x) const; | |||
| LOL_ATTR_NODISCARD bool operator <(Real<T> const &x) const; | |||
| LOL_ATTR_NODISCARD bool operator >(Real<T> const &x) const; | |||
| LOL_ATTR_NODISCARD bool operator <=(Real<T> const &x) const; | |||
| LOL_ATTR_NODISCARD bool operator >=(Real<T> const &x) const; | |||
| LOL_ATTR_NODISCARD bool operator !() const; | |||
| LOL_ATTR_NODISCARD operator bool() const; | |||
| /* Comparison functions */ | |||
| template<typename U> friend Real<U> min(Real<U> const &a, Real<U> const &b); | |||
| template<typename U> friend Real<U> max(Real<U> const &a, Real<U> const &b); | |||
| template<typename U> friend Real<U> clamp(Real<U> const &x, | |||
| Real<U> const &a, Real<U> const &b); | |||
| /* Trigonometric functions */ | |||
| template<typename U> friend Real<U> sin(Real<U> const &x); | |||
| template<typename U> friend Real<U> cos(Real<U> const &x); | |||
| template<typename U> friend Real<U> tan(Real<U> const &x); | |||
| template<typename U> friend Real<U> asin(Real<U> const &x); | |||
| template<typename U> friend Real<U> acos(Real<U> const &x); | |||
| template<typename U> friend Real<U> atan(Real<U> const &x); | |||
| template<typename U> friend Real<U> atan2(Real<U> const &y, Real<U> const &x); | |||
| /* Hyperbolic functions */ | |||
| template<typename U> friend Real<U> sinh(Real<U> const &x); | |||
| template<typename U> friend Real<U> cosh(Real<U> const &x); | |||
| template<typename U> friend Real<U> tanh(Real<U> const &x); | |||
| /* Exponential and logarithmic functions */ | |||
| template<typename U> friend Real<U> exp(Real<U> const &x); | |||
| template<typename U> friend Real<U> exp2(Real<U> const &x); | |||
| template<typename U> friend Real<U> erf(Real<U> const &x); | |||
| template<typename U> friend Real<U> log(Real<U> const &x); | |||
| template<typename U> friend Real<U> log2(Real<U> const &x); | |||
| template<typename U> friend Real<U> log10(Real<U> const &x); | |||
| /* Floating-point functions */ | |||
| template<typename U> friend Real<U> frexp(Real<U> const &x, typename Real<U>::exponent_t *exp); | |||
| template<typename U> friend Real<U> ldexp(Real<U> const &x, typename Real<U>::exponent_t exp); | |||
| template<typename U> friend Real<U> modf(Real<U> const &x, Real<U> *iptr); | |||
| template<typename U> friend Real<U> nextafter(Real<U> const &x, Real<U> const &y); | |||
| /* Power functions */ | |||
| template<typename U> friend Real<U> inverse(Real<U> const &x); | |||
| template<typename U> friend Real<U> sqrt(Real<U> const &x); | |||
| template<typename U> friend Real<U> cbrt(Real<U> const &x); | |||
| template<typename U> friend Real<U> pow(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> friend Real<U> gamma(Real<U> const &x); | |||
| /* Rounding, absolute value, remainder etc. */ | |||
| template<typename U> friend Real<U> ceil(Real<U> const &x); | |||
| template<typename U> friend Real<U> copysign(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> friend Real<U> floor(Real<U> const &x); | |||
| template<typename U> friend Real<U> fabs(Real<U> const &x); | |||
| template<typename U> friend Real<U> round(Real<U> const &x); | |||
| template<typename U> friend Real<U> fmod(Real<U> const &x, Real<U> const &y); | |||
| /* Functions inherited from GLSL */ | |||
| template<typename U> friend Real<U> abs(Real<U> const &x); | |||
| template<typename U> friend Real<U> fract(Real<U> const &x); | |||
| template<typename U> friend Real<U> degrees(Real<U> const &x); | |||
| template<typename U> friend Real<U> radians(Real<U> const &x); | |||
| /* Additional functions */ | |||
| template<typename U> friend Real<U> franke(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> friend Real<U> peaks(Real<U> const &x, Real<U> const &y); | |||
| std::string str(int ndigits = 150) const; | |||
| std::string xstr() const; | |||
| /* Additional operators using base C++ types */ | |||
| #define __LOL_REAL_OP_HELPER_GENERIC(op, type) \ | |||
| inline Real<T> operator op(type x) const { return *this op (Real<T>)x; } \ | |||
| inline Real<T> const &operator op##=(type x) { return *this = (*this op x); } | |||
| #define __LOL_REAL_OP_HELPER_FASTMULDIV(op, type) \ | |||
| inline Real<T> operator op(type x) const \ | |||
| { \ | |||
| Real<T> tmp = *this; return tmp op##= x; \ | |||
| } \ | |||
| inline Real<T> const &operator op##=(type x) \ | |||
| { \ | |||
| /* If multiplying or dividing by a power of two, take a shortcut */ \ | |||
| if (!is_zero() && x && !(x & (x - 1))) \ | |||
| { \ | |||
| while (x >>= 1) \ | |||
| m_exponent += 1 op 2 - 1; /* 1 if op is *, -1 if op is / */ \ | |||
| } \ | |||
| else \ | |||
| *this = *this op (Real<T>)x; \ | |||
| return *this; \ | |||
| } | |||
| #define __LOL_REAL_OP_HELPER_INT(type) \ | |||
| __LOL_REAL_OP_HELPER_GENERIC(+, type) \ | |||
| __LOL_REAL_OP_HELPER_GENERIC(-, type) \ | |||
| __LOL_REAL_OP_HELPER_FASTMULDIV(*, type) \ | |||
| __LOL_REAL_OP_HELPER_FASTMULDIV(/, type) | |||
| #define __LOL_REAL_OP_HELPER_FLOAT(type) \ | |||
| __LOL_REAL_OP_HELPER_GENERIC(+, type) \ | |||
| __LOL_REAL_OP_HELPER_GENERIC(-, type) \ | |||
| __LOL_REAL_OP_HELPER_GENERIC(*, type) \ | |||
| __LOL_REAL_OP_HELPER_GENERIC(/, type) | |||
| __LOL_REAL_OP_HELPER_INT(int) | |||
| __LOL_REAL_OP_HELPER_INT(unsigned int) | |||
| __LOL_REAL_OP_HELPER_INT(int64_t) | |||
| __LOL_REAL_OP_HELPER_INT(uint64_t) | |||
| __LOL_REAL_OP_HELPER_FLOAT(float) | |||
| __LOL_REAL_OP_HELPER_FLOAT(double) | |||
| __LOL_REAL_OP_HELPER_FLOAT(long double) | |||
| /* Constants */ | |||
| static Real<T> const R_0(); | |||
| static Real<T> const& R_1(); | |||
| static Real<T> const& R_2(); | |||
| static Real<T> const& R_3(); | |||
| static Real<T> const& R_4(); | |||
| static Real<T> const& R_10(); | |||
| static Real<T> const& R_E(); | |||
| static Real<T> const& R_LOG2E(); | |||
| static Real<T> const& R_LOG10E(); | |||
| static Real<T> const& R_LN2(); | |||
| static Real<T> const& R_LN10(); | |||
| static Real<T> const& R_PI(); | |||
| static Real<T> const& R_PI_2(); | |||
| static Real<T> const& R_PI_3(); | |||
| static Real<T> const& R_PI_4(); | |||
| static Real<T> const& R_TAU(); | |||
| static Real<T> const& R_1_PI(); | |||
| static Real<T> const& R_2_PI(); | |||
| static Real<T> const& R_2_SQRTPI(); | |||
| static Real<T> const& R_SQRT2(); | |||
| static Real<T> const& R_SQRT3(); | |||
| static Real<T> const& R_SQRT1_2(); | |||
| static Real<T> const R_INF(); | |||
| static Real<T> const R_NAN(); | |||
| static Real<T> const& R_MIN(); | |||
| static Real<T> const& R_MAX(); | |||
| private: | |||
| std::vector<T> m_mantissa; | |||
| exponent_t m_exponent = 0; | |||
| bool m_sign = false, m_nan = false, m_inf = false; | |||
| public: | |||
| static int DEFAULT_BIGIT_COUNT; | |||
| static inline int bigit_bits() { return 8 * (int)sizeof(bigit_t); } | |||
| inline int bigit_count() const { return (int)m_mantissa.size(); } | |||
| inline int total_bits() const { return bigit_count() * bigit_bits(); } | |||
| }; | |||
| template<typename U> | |||
| std::ostream& operator <<(std::ostream &s, Real<U> const &x); | |||
| /* | |||
| * Mandatory forward declarations of template specialisations | |||
| */ | |||
| template<> real::Real(float f); | |||
| template<> real::Real(double f); | |||
| template<> real::Real(long double f); | |||
| template<> real::Real(int32_t i); | |||
| template<> real::Real(uint32_t i); | |||
| template<> real::Real(int64_t i); | |||
| template<> real::Real(uint64_t i); | |||
| template<> real::Real(char const *str); | |||
| template<> LOL_ATTR_NODISCARD real::operator float() const; | |||
| template<> LOL_ATTR_NODISCARD real::operator double() const; | |||
| template<> LOL_ATTR_NODISCARD real::operator long double() const; | |||
| template<> LOL_ATTR_NODISCARD real::operator int32_t() const; | |||
| template<> LOL_ATTR_NODISCARD real::operator uint32_t() const; | |||
| template<> LOL_ATTR_NODISCARD real::operator int64_t() const; | |||
| template<> LOL_ATTR_NODISCARD real::operator uint64_t() const; | |||
| template<> real real::operator +() const; | |||
| template<> real real::operator -() const; | |||
| template<> real real::operator +(real const &x) const; | |||
| template<> real real::operator -(real const &x) const; | |||
| template<> real real::operator *(real const &x) const; | |||
| template<> real real::operator /(real const &x) const; | |||
| template<> real const &real::operator +=(real const &x); | |||
| template<> real const &real::operator -=(real const &x); | |||
| template<> real const &real::operator *=(real const &x); | |||
| template<> real const &real::operator /=(real const &x); | |||
| template<> LOL_ATTR_NODISCARD bool real::operator ==(real const &x) const; | |||
| template<> LOL_ATTR_NODISCARD bool real::operator !=(real const &x) const; | |||
| template<> LOL_ATTR_NODISCARD bool real::operator <(real const &x) const; | |||
| template<> LOL_ATTR_NODISCARD bool real::operator >(real const &x) const; | |||
| template<> LOL_ATTR_NODISCARD bool real::operator <=(real const &x) const; | |||
| template<> LOL_ATTR_NODISCARD bool real::operator >=(real const &x) const; | |||
| template<> LOL_ATTR_NODISCARD bool real::operator !() const; | |||
| template<> LOL_ATTR_NODISCARD real::operator bool() const; | |||
| template<typename U> Real<U> min(Real<U> const &a, Real<U> const &b); | |||
| template<typename U> Real<U> max(Real<U> const &a, Real<U> const &b); | |||
| template<typename U> Real<U> clamp(Real<U> const &x, | |||
| Real<U> const &a, Real<U> const &b); | |||
| template<typename U> Real<U> sin(Real<U> const &x); | |||
| template<typename U> Real<U> cos(Real<U> const &x); | |||
| template<typename U> Real<U> tan(Real<U> const &x); | |||
| template<typename U> Real<U> asin(Real<U> const &x); | |||
| template<typename U> Real<U> acos(Real<U> const &x); | |||
| template<typename U> Real<U> atan(Real<U> const &x); | |||
| template<typename U> Real<U> atan2(Real<U> const &y, Real<U> const &x); | |||
| template<typename U> Real<U> sinh(Real<U> const &x); | |||
| template<typename U> Real<U> cosh(Real<U> const &x); | |||
| template<typename U> Real<U> tanh(Real<U> const &x); | |||
| template<typename U> Real<U> exp(Real<U> const &x); | |||
| template<typename U> Real<U> exp2(Real<U> const &x); | |||
| template<typename U> Real<U> erf(Real<U> const &x); | |||
| template<typename U> Real<U> log(Real<U> const &x); | |||
| template<typename U> Real<U> log2(Real<U> const &x); | |||
| template<typename U> Real<U> log10(Real<U> const &x); | |||
| template<typename U> Real<U> frexp(Real<U> const &x, typename Real<U>::exponent_t *exp); | |||
| template<typename U> Real<U> ldexp(Real<U> const &x, typename Real<U>::exponent_t exp); | |||
| template<typename U> Real<U> modf(Real<U> const &x, Real<U> *iptr); | |||
| template<typename U> Real<U> nextafter(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> Real<U> inverse(Real<U> const &x); | |||
| template<typename U> Real<U> sqrt(Real<U> const &x); | |||
| template<typename U> Real<U> cbrt(Real<U> const &x); | |||
| template<typename U> Real<U> pow(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> Real<U> gamma(Real<U> const &x); | |||
| template<typename U> Real<U> ceil(Real<U> const &x); | |||
| template<typename U> Real<U> copysign(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> Real<U> floor(Real<U> const &x); | |||
| template<typename U> Real<U> fabs(Real<U> const &x); | |||
| template<typename U> Real<U> round(Real<U> const &x); | |||
| template<typename U> Real<U> fmod(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> Real<U> abs(Real<U> const &x); | |||
| template<typename U> Real<U> fract(Real<U> const &x); | |||
| template<typename U> Real<U> degrees(Real<U> const &x); | |||
| template<typename U> Real<U> radians(Real<U> const &x); | |||
| template<typename U> Real<U> franke(Real<U> const &x, Real<U> const &y); | |||
| template<typename U> Real<U> peaks(Real<U> const &x, Real<U> const &y); | |||
| template<> real min(real const &a, real const &b); | |||
| template<> real max(real const &a, real const &b); | |||
| template<> real clamp(real const &x, real const &a, real const &b); | |||
| template<> real sin(real const &x); | |||
| template<> real cos(real const &x); | |||
| template<> real tan(real const &x); | |||
| template<> real asin(real const &x); | |||
| template<> real acos(real const &x); | |||
| template<> real atan(real const &x); | |||
| template<> real atan2(real const &y, real const &x); | |||
| template<> real sinh(real const &x); | |||
| template<> real cosh(real const &x); | |||
| template<> real tanh(real const &x); | |||
| template<> real exp(real const &x); | |||
| template<> real exp2(real const &x); | |||
| template<> real erf(real const &x); | |||
| template<> real log(real const &x); | |||
| template<> real log2(real const &x); | |||
| template<> real log10(real const &x); | |||
| template<> real frexp(real const &x, real::exponent_t *exp); | |||
| template<> real ldexp(real const &x, real::exponent_t exp); | |||
| template<> real modf(real const &x, real *iptr); | |||
| template<> real nextafter(real const &x, real const &y); | |||
| template<> real inverse(real const &x); | |||
| template<> real sqrt(real const &x); | |||
| template<> real cbrt(real const &x); | |||
| template<> real pow(real const &x, real const &y); | |||
| template<> real gamma(real const &x); | |||
| template<> real ceil(real const &x); | |||
| template<> real copysign(real const &x, real const &y); | |||
| template<> real floor(real const &x); | |||
| template<> real fabs(real const &x); | |||
| template<> real round(real const &x); | |||
| template<> real fmod(real const &x, real const &y); | |||
| template<> real abs(real const &x); | |||
| template<> real fract(real const &x); | |||
| template<> real degrees(real const &x); | |||
| template<> real radians(real const &x); | |||
| template<> real franke(real const &x, real const &y); | |||
| template<> real peaks(real const &x, real const &y); | |||
| template<> std::string real::str(int ndigits) const; | |||
| template<> std::string real::xstr() const; | |||
| } /* namespace lol */ | |||
| @@ -12,9 +12,6 @@ | |||
| #pragma once | |||
| #include <lol/sys/thread.h> | |||
| #include <lol/sys/timer.h> /* requires thread.h */ | |||
| #include <lol/sys/getopt.h> | |||
| #include <lol/sys/init.h> | |||
| #include <lol/sys/file.h> | |||
| @@ -1,41 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright © 2002—2016 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // Lol Engine is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||
| // See http://www.wtfpl.net/ for more details. | |||
| // | |||
| #pragma once | |||
| // | |||
| // The getopt functions | |||
| // -------------------- | |||
| // | |||
| namespace lol | |||
| { | |||
| class getopt | |||
| { | |||
| public: | |||
| getopt(int argc, char ** _argv); | |||
| getopt(int argc, char * const * _argv); | |||
| ~getopt(); | |||
| void add_opt(int short_opt, char const *long_opt, bool has_arg); | |||
| int parse(); | |||
| int index; | |||
| char *arg; | |||
| private: | |||
| std::unique_ptr<struct getopt_private> m_private; | |||
| }; | |||
| } | |||
| @@ -1,222 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // Lol Engine is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||
| // See http://www.wtfpl.net/ for more details. | |||
| // | |||
| #pragma once | |||
| // | |||
| // The Threading classes | |||
| // --------------------- | |||
| // | |||
| #include <functional> | |||
| #include <thread> | |||
| #include <mutex> | |||
| #include <condition_variable> | |||
| /* XXX: workaround for a bug in Visual Studio 2012 and 2013! | |||
| * https://connect.microsoft.com/VisualStudio/feedback/details/747145 */ | |||
| #if defined(_MSC_VER) && (_MSC_VER < 1900) | |||
| # define LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND 1 | |||
| # ifdef WIN32_LEAN_AND_MEAN | |||
| # include <windows.h> | |||
| # else | |||
| # define WIN32_LEAN_AND_MEAN 1 | |||
| # include <windows.h> | |||
| # undef WIN32_LEAN_AND_MEAN | |||
| # endif | |||
| #endif | |||
| /* XXX: workaround for missing std::thread in mingw */ | |||
| #if _GLIBCXX_MUTEX && !_GLIBCXX_HAS_GTHREADS && _WIN32 | |||
| # include "mingw.thread.h" | |||
| # include "mingw.mutex.h" | |||
| # include "mingw.condition_variable.h" | |||
| # undef near /* Fuck Microsoft */ | |||
| # undef far /* Fuck Microsoft again */ | |||
| #endif | |||
| namespace lol | |||
| { | |||
| // This is like std::mutex but we can add debug information to it | |||
| class mutex | |||
| { | |||
| public: | |||
| inline void lock() { m_mutex.lock(); } | |||
| inline bool try_lock() { return m_mutex.try_lock(); } | |||
| inline void unlock() { m_mutex.unlock(); } | |||
| private: | |||
| std::mutex m_mutex; | |||
| }; | |||
| // A FIFO queue for threads | |||
| template<typename T, int N = 128> | |||
| class queue | |||
| { | |||
| public: | |||
| int size() const { return m_count; } | |||
| // Will block the thread if another has already locked | |||
| void push(T value) | |||
| { | |||
| std::unique_lock<std::mutex> uni_lock(m_mutex); | |||
| if (has_threads()) | |||
| { | |||
| // Wait for the mutex availability or non-fullness | |||
| m_full_cond.wait(uni_lock, [&]{ return m_count < CAPACITY; }); | |||
| } | |||
| do_push(value); /* Push value */ | |||
| if (has_threads()) | |||
| { | |||
| // Release lock and notify empty condition var (in that order) | |||
| uni_lock.unlock(); | |||
| m_empty_cond.notify_one(); | |||
| } | |||
| } | |||
| // Will not block if another has already locked | |||
| bool try_push(T value) | |||
| { | |||
| std::unique_lock<std::mutex> uni_lock(m_mutex, std::defer_lock); | |||
| if (has_threads()) | |||
| { | |||
| // Try to lock, bail out if we fail | |||
| if (!uni_lock.try_lock()) | |||
| return false; | |||
| } | |||
| if (m_count == CAPACITY) | |||
| return false; // unlocks uni_lock | |||
| do_push(value); | |||
| if (has_threads()) | |||
| { | |||
| // Release lock and notify empty condition var (in that order) | |||
| uni_lock.unlock(); | |||
| m_empty_cond.notify_one(); | |||
| } | |||
| return true; | |||
| } | |||
| // Will block the thread if another has already locked | |||
| T pop() | |||
| { | |||
| ASSERT(has_threads(), "Pop should only be used with threads. Use try_pop instead."); | |||
| // Wait for the mutex availability or non-emptiness | |||
| std::unique_lock<std::mutex> uni_lock(m_mutex); | |||
| m_empty_cond.wait(uni_lock, [&]{return m_count > 0; }); | |||
| T ret = do_pop(); | |||
| // Release lock and notify full condition var (in that order) | |||
| uni_lock.unlock(); | |||
| m_full_cond.notify_one(); | |||
| return ret; | |||
| } | |||
| // Will not block if another has already locked | |||
| bool try_pop(T &ret) | |||
| { | |||
| std::unique_lock<std::mutex> uni_lock(m_mutex, std::defer_lock); | |||
| if (has_threads()) | |||
| { | |||
| if (!uni_lock.try_lock()) | |||
| return false; | |||
| } | |||
| if (m_count == 0) | |||
| return false; | |||
| ret = do_pop(); /* Pop value */ | |||
| if (has_threads()) | |||
| { | |||
| // Release lock and notify full condition var (in that order) | |||
| uni_lock.unlock(); | |||
| m_full_cond.notify_one(); | |||
| } | |||
| return true; | |||
| } | |||
| // Inner methods for actual update | |||
| private: | |||
| void do_push(T &value) | |||
| { | |||
| m_values[(m_start + m_count) % CAPACITY] = value; | |||
| m_count++; | |||
| } | |||
| T& do_pop() | |||
| { | |||
| int idx = m_start; | |||
| m_start = (m_start + 1) % CAPACITY; | |||
| m_count--; | |||
| return m_values[idx]; | |||
| } | |||
| private: | |||
| static int const CAPACITY = N; | |||
| T m_values[CAPACITY]; | |||
| int m_start = 0, m_count = 0; | |||
| std::mutex m_mutex; | |||
| std::condition_variable m_empty_cond, m_full_cond; | |||
| }; | |||
| // Base class for threads | |||
| class thread | |||
| { | |||
| public: | |||
| thread(std::function<void(thread*)> fn) | |||
| : m_function(fn) | |||
| { | |||
| m_thread = std::thread(trampoline, this); | |||
| } | |||
| ~thread() | |||
| { | |||
| #if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND | |||
| m_thread.detach(); | |||
| #else | |||
| m_thread.join(); | |||
| #endif | |||
| } | |||
| private: | |||
| static void trampoline(thread *that) | |||
| { | |||
| that->m_function(that); | |||
| #if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND | |||
| ExitThread(0); | |||
| #endif | |||
| } | |||
| std::thread m_thread; | |||
| std::function<void(thread*)> m_function; | |||
| }; | |||
| } /* namespace lol */ | |||
| @@ -25,7 +25,9 @@ | |||
| #include "light.h" | |||
| #include "camera.h" | |||
| #include "mesh/mesh.h" | |||
| #include <lol/gpu/renderer.h> | |||
| #include <lol/base/thread.h> | |||
| #define LOL_MAX_LIGHT_COUNT 8 | |||
| @@ -1,198 +0,0 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // Lol Engine is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||
| // See http://www.wtfpl.net/ for more details. | |||
| // | |||
| #include <lol/engine-internal.h> | |||
| #if HAVE_GETOPT_H | |||
| # include <getopt.h> | |||
| #endif | |||
| #if HAVE_UNISTD_H | |||
| # include <unistd.h> | |||
| #endif | |||
| namespace lol | |||
| { | |||
| struct getopt_private | |||
| { | |||
| getopt_private(int argc, char * const * _argv) | |||
| : m_argc(argc), | |||
| m_argv(_argv) | |||
| {} | |||
| #if HAVE_GETOPT_LONG | |||
| typedef option optdesc; | |||
| #else | |||
| struct optdesc | |||
| { | |||
| char const *name; | |||
| int has_arg; | |||
| int *flag; | |||
| int val; | |||
| }; | |||
| #endif | |||
| int m_argc; | |||
| char * const *m_argv; | |||
| std::string m_optstring; | |||
| array<optdesc> m_opts; | |||
| }; | |||
| getopt::getopt(int argc, char ** _argv) | |||
| : index(1), | |||
| arg(nullptr), | |||
| m_private(new getopt_private(argc, _argv)) | |||
| { | |||
| } | |||
| getopt::getopt(int argc, char * const * _argv) | |||
| : index(1), | |||
| arg(nullptr), | |||
| m_private(new getopt_private(argc, _argv)) | |||
| { | |||
| } | |||
| getopt::~getopt() | |||
| { | |||
| } | |||
| void getopt::add_opt(int short_opt, char const *long_opt, bool has_arg) | |||
| { | |||
| getopt_private::optdesc o { long_opt, has_arg, nullptr, short_opt }; | |||
| m_private->m_opts.push(o); | |||
| /* “The standards require that the argument [to isalnum()] is either | |||
| * EOF or a value that is representable in the type unsigned char.” */ | |||
| if ((int)(unsigned char)short_opt == short_opt && isalnum(short_opt)) | |||
| { | |||
| m_private->m_optstring += (char)short_opt; | |||
| if (has_arg) | |||
| m_private->m_optstring += ':'; | |||
| } | |||
| } | |||
| int getopt::parse() | |||
| { | |||
| int longindex = 0; // FIXME: what is this? | |||
| #if HAVE_GETOPT_LONG | |||
| int ret; | |||
| optind = this->index; | |||
| optarg = this->arg; | |||
| m_private->m_opts.push(getopt_private::optdesc { nullptr, 0, nullptr, 0 }); | |||
| ret = getopt_long(m_private->m_argc, m_private->m_argv, m_private->m_optstring.c_str(), | |||
| (option const *)m_private->m_opts.data(), &longindex); | |||
| this->index = optind; | |||
| this->arg = optarg; | |||
| return ret; | |||
| #else | |||
| /* XXX: this getopt_long implementation should not be trusted for other | |||
| * applications without any serious peer reviewing. It “just works” with | |||
| * zzuf and a few libcaca programs but may fail miserably in other | |||
| * programs. */ | |||
| char **argv = (char **)(uintptr_t)m_private->m_argv; | |||
| char *flag; | |||
| if (this->index >= m_private->m_argc) | |||
| return -1; | |||
| flag = argv[this->index]; | |||
| if (flag[0] == '-' && flag[1] != '-') | |||
| { | |||
| char const *tmp; | |||
| int ret = flag[1]; | |||
| if (ret == '\0') | |||
| return -1; | |||
| tmp = strchr(m_private->m_optstring.c_str(), ret); | |||
| if (!tmp || ret == ':') | |||
| return '?'; | |||
| ++this->index; | |||
| if (tmp[1] == ':') | |||
| { | |||
| if (flag[2] != '\0') | |||
| this->arg = flag + 2; | |||
| else | |||
| { | |||
| if (this->index >= m_private->m_argc) | |||
| goto too_few; | |||
| this->arg = argv[this->index++]; | |||
| } | |||
| return ret; | |||
| } | |||
| if (flag[2] != '\0') | |||
| { | |||
| flag[1] = '-'; | |||
| --this->index; | |||
| ++argv[this->index]; | |||
| } | |||
| return ret; | |||
| } | |||
| if (flag[0] == '-' && flag[1] == '-') | |||
| { | |||
| if (flag[2] == '\0') | |||
| return -1; | |||
| for (int i = 0; m_private->m_opts[i].name; ++i) | |||
| { | |||
| size_t l = strlen(m_private->m_opts[i].name); | |||
| if (strncmp(flag + 2, m_private->m_opts[i].name, l)) | |||
| continue; | |||
| switch (flag[2 + l]) | |||
| { | |||
| case '=': | |||
| if (!m_private->m_opts[i].has_arg) | |||
| goto bad_opt; | |||
| longindex = i; | |||
| ++this->index; | |||
| this->arg = flag + 2 + l + 1; | |||
| return m_private->m_opts[i].val; | |||
| case '\0': | |||
| longindex = i; | |||
| ++this->index; | |||
| if (m_private->m_opts[i].has_arg) | |||
| { | |||
| if (this->index >= m_private->m_argc) | |||
| goto too_few; | |||
| this->arg = argv[this->index++]; | |||
| } | |||
| return m_private->m_opts[i].val; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| bad_opt: | |||
| fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag); | |||
| return '?'; | |||
| too_few: | |||
| fprintf(stderr, "%s: option `%s' requires an argument\n", | |||
| argv[0], flag); | |||
| return '?'; | |||
| } | |||
| return -1; | |||
| #endif | |||
| } | |||
| } // namespace lol | |||
| @@ -51,27 +51,27 @@ lolunit_declare_fixture(string_test) | |||
| lolunit_declare_test(string_split) | |||
| { | |||
| auto l1 = split(std::string("abc")); | |||
| lolunit_assert(l1.count() == 1); | |||
| lolunit_assert(l1.size() == 1); | |||
| lolunit_assert(l1[0] == "abc"); | |||
| auto l2 = split(std::string("\nabc")); | |||
| lolunit_assert(l2.count() == 2); | |||
| lolunit_assert(l2.size() == 2); | |||
| lolunit_assert(l2[0] == ""); | |||
| lolunit_assert(l2[1] == "abc"); | |||
| auto l3 = split(std::string("abc\n")); | |||
| lolunit_assert(l3.count() == 2); | |||
| lolunit_assert(l3.size() == 2); | |||
| lolunit_assert(l3[0] == "abc"); | |||
| lolunit_assert(l3[1] == ""); | |||
| auto l4 = split(std::string("\n\n")); | |||
| lolunit_assert(l4.count() == 3); | |||
| lolunit_assert(l4.size() == 3); | |||
| lolunit_assert(l4[0] == ""); | |||
| lolunit_assert(l4[1] == ""); | |||
| lolunit_assert(l4[2] == ""); | |||
| auto l5 = split(std::string("abc\nde\n\nf\n")); | |||
| lolunit_assert(l5.count() == 5); | |||
| lolunit_assert(l5.size() == 5); | |||
| lolunit_assert(l5[0] == "abc"); | |||
| lolunit_assert(l5[1] == "de"); | |||
| lolunit_assert(l5[2] == ""); | |||
| @@ -196,12 +196,12 @@ lolunit_declare_fixture(polynomial_test) | |||
| * r(x) = 3 + x + x² | |||
| * s(x) = 5 */ | |||
| auto r = p / q; | |||
| lolunit_assert_equal(r.m1.degree(), 2); | |||
| lolunit_assert_doubles_equal(r.m1[0], 3.f, 1e-5f); | |||
| lolunit_assert_doubles_equal(r.m1[1], 1.f, 1e-5f); | |||
| lolunit_assert_doubles_equal(r.m1[2], 1.f, 1e-5f); | |||
| lolunit_assert_equal(r.m2.degree(), 0); | |||
| lolunit_assert_doubles_equal(r.m2[0], 5.f, 1e-5f); | |||
| lolunit_assert_equal(std::get<0>(r).degree(), 2); | |||
| lolunit_assert_doubles_equal(std::get<0>(r)[0], 3.f, 1e-5f); | |||
| lolunit_assert_doubles_equal(std::get<0>(r)[1], 1.f, 1e-5f); | |||
| lolunit_assert_doubles_equal(std::get<0>(r)[2], 1.f, 1e-5f); | |||
| lolunit_assert_equal(std::get<1>(r).degree(), 0); | |||
| lolunit_assert_doubles_equal(std::get<1>(r)[0], 5.f, 1e-5f); | |||
| } | |||
| lolunit_declare_test(composition_degree_2_2) | |||
| @@ -241,7 +241,7 @@ lolunit_declare_fixture(polynomial_test) | |||
| polynomial<float> p { 42.f }; | |||
| auto roots = p.roots(); | |||
| lolunit_assert_equal(roots.count(), 0); | |||
| lolunit_assert_equal(roots.size(), 0); | |||
| } | |||
| lolunit_declare_test(degree_1_root) | |||
| @@ -250,7 +250,7 @@ lolunit_declare_fixture(polynomial_test) | |||
| polynomial<float> p { -6.f, 2.f }; | |||
| auto roots = p.roots(); | |||
| lolunit_assert_equal(roots.count(), 1); | |||
| lolunit_assert_equal(roots.size(), 1); | |||
| lolunit_assert_equal(roots[0], 3.f); | |||
| } | |||
| @@ -260,14 +260,14 @@ lolunit_declare_fixture(polynomial_test) | |||
| polynomial<float> p { 81.f, -18.f, 1.f }; | |||
| auto roots1 = p.roots(); | |||
| lolunit_assert_equal(roots1.count(), 1); | |||
| lolunit_assert_equal(roots1.size(), 1); | |||
| lolunit_assert_equal(roots1[0], 9.f); | |||
| /* p(x) = 42 - 20x + 2x² */ | |||
| polynomial<float> q { 42.f, -20.f, 2.f }; | |||
| auto roots2 = q.roots(); | |||
| lolunit_assert_equal(roots2.count(), 2); | |||
| lolunit_assert_equal(roots2.size(), 2); | |||
| lolunit_assert_equal(roots2[0], 3.f); | |||
| lolunit_assert_equal(roots2[1], 7.f); | |||
| } | |||
| @@ -277,7 +277,7 @@ lolunit_declare_fixture(polynomial_test) | |||
| polynomial<float> p { 1.f, 3.f, 3.f, 1.f }; | |||
| auto roots1 = p.roots(); | |||
| lolunit_assert_equal(roots1.count(), 1); | |||
| lolunit_assert_equal(roots1.size(), 1); | |||
| lolunit_assert_doubles_equal(roots1[0], -1, 0); | |||
| } | |||
| @@ -287,7 +287,7 @@ lolunit_declare_fixture(polynomial_test) | |||
| auto roots1 = p.roots(); | |||
| // Should have 2 solutions only, but precision leads to 3 solutions | |||
| lolunit_assert_equal(roots1.count(), 2); | |||
| lolunit_assert_equal(roots1.size(), 2); | |||
| lolunit_assert_doubles_equal(roots1[0], -1, 1e-6); | |||
| lolunit_assert_doubles_equal(roots1[1], -2, 1e-6); | |||
| } | |||
| @@ -297,7 +297,7 @@ lolunit_declare_fixture(polynomial_test) | |||
| polynomial<float> p { 6.f, 11.f, 6.f, 1.f }; | |||
| auto roots1 = p.roots(); | |||
| lolunit_assert_equal(roots1.count(), 3); | |||
| lolunit_assert_equal(roots1.size(), 3); | |||
| lolunit_assert_doubles_equal(roots1[0], -1, 1e-8); | |||
| lolunit_assert_doubles_equal(roots1[1], -3, 1e-8); | |||
| lolunit_assert_doubles_equal(roots1[2], -2, 1e-8); | |||
| @@ -308,7 +308,7 @@ lolunit_declare_fixture(polynomial_test) | |||
| polynomial<float> p { -12000.f, 1000.f - 1200.f - 120.f, 100.f + 10.0f - 12.f, 1.f }; | |||
| auto roots1 = p.roots(); | |||
| lolunit_assert_equal(roots1.count(), 3); | |||
| lolunit_assert_equal(roots1.size(), 3); | |||
| lolunit_assert_doubles_equal(roots1[0], 12, 1e-5); | |||
| lolunit_assert_doubles_equal(roots1[1], -100, 1e-5); | |||
| @@ -22,16 +22,16 @@ lolunit_declare_fixture(quaternion_test) | |||
| void setup() | |||
| { | |||
| /* Generate identity quaternions */ | |||
| m_vectorpairs.push(vec3::axis_x, vec3::axis_x); | |||
| m_vectorpairs.push(2.f * vec3::axis_x, 3.f * vec3::axis_x); | |||
| push_vector_pair(vec3::axis_x, vec3::axis_x); | |||
| push_vector_pair(2.f * vec3::axis_x, 3.f * vec3::axis_x); | |||
| /* Generate 90-degree rotations */ | |||
| m_vectorpairs.push(vec3::axis_x, vec3::axis_y); | |||
| m_vectorpairs.push(2.f * vec3::axis_x, 3.f * vec3::axis_y); | |||
| push_vector_pair(vec3::axis_x, vec3::axis_y); | |||
| push_vector_pair(2.f * vec3::axis_x, 3.f * vec3::axis_y); | |||
| /* Generate 180-degree rotations */ | |||
| m_vectorpairs.push(vec3::axis_x, -vec3::axis_x); | |||
| m_vectorpairs.push(2.f * vec3::axis_x, -3.f * vec3::axis_x); | |||
| push_vector_pair(vec3::axis_x, -vec3::axis_x); | |||
| push_vector_pair(2.f * vec3::axis_x, -3.f * vec3::axis_x); | |||
| /* Fill array with random test values */ | |||
| for (int i = 0; i < 10000; ++i) | |||
| @@ -40,7 +40,7 @@ lolunit_declare_fixture(quaternion_test) | |||
| * vec3(rand(-1.f, 1.f), rand(-1.f, 1.f), rand(-1.f, 1.f)); | |||
| vec3 v2 = lol::pow(10.f, rand(-5.f, 5.f)) | |||
| * vec3(rand(-1.f, 1.f), rand(-1.f, 1.f), rand(-1.f, 1.f)); | |||
| m_vectorpairs.push(v1, v2); | |||
| push_vector_pair(v1, v2); | |||
| } | |||
| } | |||
| @@ -203,41 +203,44 @@ lolunit_declare_fixture(quaternion_test) | |||
| { | |||
| for (auto pair : m_vectorpairs) | |||
| { | |||
| vec3 a = pair.m1; | |||
| vec3 b = pair.m2; | |||
| vec3 da = normalize(a); | |||
| vec3 db = normalize(b); | |||
| vec3 a0 = std::get<0>(pair); | |||
| vec3 b0 = std::get<1>(pair); | |||
| vec3 a = normalize(a0); | |||
| vec3 b = normalize(b0); | |||
| quat q = quat::rotate(a, b); | |||
| quat q = quat::rotate(a0, b0); | |||
| auto ctx = a0.tostring() + " " + b0.tostring(); | |||
| lolunit_set_context(ctx); | |||
| /* Check that q is a unit quaternion */ | |||
| lolunit_assert_doubles_equal(1.0, (double)norm(q), 1e-5); | |||
| /* Check that q transforms da into db */ | |||
| vec3 c = q.transform(da); | |||
| /* Check that q transforms a into b */ | |||
| vec3 c = q.transform(a); | |||
| lolunit_assert_doubles_equal(c.x, db.x, 1e-5); | |||
| lolunit_assert_doubles_equal(c.y, db.y, 1e-5); | |||
| lolunit_assert_doubles_equal(c.z, db.z, 1e-5); | |||
| lolunit_assert_doubles_equal(c.x, b.x, 2e-5); | |||
| lolunit_assert_doubles_equal(c.y, b.y, 2e-5); | |||
| lolunit_assert_doubles_equal(c.z, b.z, 2e-5); | |||
| /* Check that ~q transforms db into da */ | |||
| vec3 d = (~q).transform(db); | |||
| /* Check that ~q transforms b into a */ | |||
| vec3 d = (~q).transform(b); | |||
| lolunit_assert_doubles_equal(d.x, da.x, 1e-5); | |||
| lolunit_assert_doubles_equal(d.y, da.y, 1e-5); | |||
| lolunit_assert_doubles_equal(d.z, da.z, 1e-5); | |||
| lolunit_assert_doubles_equal(d.x, a.x, 2e-5); | |||
| lolunit_assert_doubles_equal(d.y, a.y, 2e-5); | |||
| lolunit_assert_doubles_equal(d.z, a.z, 2e-5); | |||
| if (distance(da, db) > 1e-6f) | |||
| if (distance(a, b) > 1e-6f) | |||
| { | |||
| /* If da and db differ, check that the rotation axis is normal to both | |||
| /* If a and b differ, check that the rotation axis is normal to both | |||
| * vectors, which is only true if the rotation uses the shortest path. */ | |||
| vec3 axis = q.axis(); | |||
| lolunit_assert_doubles_equal(0.0, (double)dot(axis, da), 1e-5); | |||
| lolunit_assert_doubles_equal(0.0, (double)dot(axis, db), 1e-5); | |||
| lolunit_assert_doubles_equal(0.0, (double)dot(axis, a), 1e-5); | |||
| lolunit_assert_doubles_equal(0.0, (double)dot(axis, b), 1e-5); | |||
| } | |||
| else | |||
| { | |||
| /* If da and db are roughly the same, check that the rotation angle | |||
| /* If a and b are roughly the same, check that the rotation angle | |||
| * is zero. */ | |||
| lolunit_assert_doubles_equal(0.0, (double)q.angle(), 1e-5); | |||
| } | |||
| @@ -533,7 +536,12 @@ lolunit_declare_fixture(quaternion_test) | |||
| } | |||
| private: | |||
| array<vec3, vec3> m_vectorpairs; | |||
| void push_vector_pair(vec3 p, vec3 q) | |||
| { | |||
| m_vectorpairs.push_back(std::make_tuple(p, q)); | |||
| } | |||
| std::vector<std::tuple<vec3, vec3>> m_vectorpairs; | |||
| }; | |||
| } /* namespace lol */ | |||