@@ -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 */ | |||