diff --git a/libs/yocto/yocto_geometryt.h b/libs/yocto/yocto_geometryt.h deleted file mode 100644 index 2db823ec7..000000000 --- a/libs/yocto/yocto_geometryt.h +++ /dev/null @@ -1,1254 +0,0 @@ -// -// # Yocto/Geometry: Geometry operations -// -// Yocto/Geometry defines basic geometry operations, including computation of -// basic geometry quantities, ray-primitive intersection, point-primitive -// distance, primitive bounds, and several interpolation functions. -// Yocto/Geometry is implemented in `yocto_geometry.h`. -// - -// -// LICENSE: -// -// Copyright (c) 2016 -- 2022 Fabio Pellacini -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#ifndef _YOCTO_GEOMETRY_H_ -#define _YOCTO_GEOMETRY_H_ - -// ----------------------------------------------------------------------------- -// INCLUDES -// ----------------------------------------------------------------------------- - -#include - -#include "yocto_math.h" - -// ----------------------------------------------------------------------------- -// USING DIRECTIVES -// ----------------------------------------------------------------------------- -namespace yocto { - -// using directives -using std::pair; - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// AXIS ALIGNED BOUNDING BOXES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Axis aligned bounding box represented as a min/max vector pairs. -template -struct bbox; - -// Axis aligned bounding box represented as a min/max vector pairs. -template -struct bbox { - vec min = {num_max, num_max}; - vec max = {num_min, num_min}; - - inline vec& operator[](int i); - inline const vec& operator[](int i) const; -}; - -// Axis aligned bounding box represented as a min/max vector pairs. -template -struct bbox { - vec min = {num_max, num_max, num_max}; - vec max = {num_min, num_min, num_min}; - - inline vec& operator[](int i); - inline const vec& operator[](int i) const; -}; - -// Bbox aliases -using bbox2f = bbox; -using bbox3f = bbox; - -// Empty bbox constant. -constexpr auto invalidb2f = bbox2f{}; -constexpr auto invalidb3f = bbox3f{}; - -// Bounding box properties -template -inline vec center(const bbox& a); -template -inline vec size(const bbox& a); - -// Bounding box comparisons. -template -inline bool operator==(const bbox& a, const bbox& b); -template -inline bool operator!=(const bbox& a, const bbox& b); - -// Bounding box expansions with points and other boxes. -template -inline bbox merge(const bbox& a, const vec& b); -template -inline bbox merge(const bbox& a, const bbox& b); -template -inline void expand(bbox& a, const vec& b); -template -inline void expand(bbox& a, const bbox& b); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// RAYS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Ray epsilon -template -constexpr auto ray_eps = (T)1e-4; - -// Rays with origin, direction and min/max t value. -template -struct ray; - -// Rays with origin, direction and min/max t value. -template -struct ray { - vec o = {0, 0}; - vec d = {0, 1}; - T tmin = ray_eps; - T tmax = num_max; -}; - -// Rays with origin, direction and min/max t value. -template -struct ray { - vec o = {0, 0, 0}; - vec d = {0, 0, 1}; - T tmin = ray_eps; - T tmax = num_max; -}; - -// Ray aliases -using ray2f = ray; -using ray3f = ray; - -// Computes a point on a ray -template -inline vec ray_point(const ray& ray, T t); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// TRANSFORMS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Transforms rays. -template -inline ray transform_ray(const mat& a, const ray& b); -template -inline ray transform_ray(const frame& a, const ray& b); - -// Transforms bounding boxes by matrices. -template -inline bbox transform_bbox(const mat& a, const bbox& b); -template -inline bbox transform_bbox(const frame& a, const bbox& b); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// PRIMITIVE BOUNDS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Primitive bounds. -template -inline bbox point_bounds(const vec& p); -template -inline bbox point_bounds(const vec& p, T r); -template -inline bbox line_bounds(const vec& p0, const vec& p1); -template -inline bbox line_bounds( - const vec& p0, const vec& p1, T r0, T r1); -template -inline bbox triangle_bounds( - const vec& p0, const vec& p1, const vec& p2); -template -inline bbox quad_bounds(const vec& p0, const vec& p1, - const vec& p2, const vec& p3); -template -inline bbox sphere_bounds(const vec& p, T r); -template -inline bbox capsule_bounds( - const vec& p0, const vec& p1, T r0, T r1); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// GEOMETRY UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Line properties. -template -inline vec line_point(const vec& p0, const vec& p1, T u); -template -inline vec line_tangent(const vec& p0, const vec& p1); -template -inline T line_length(const vec& p0, const vec& p1); - -// Triangle properties. -template -inline vec triangle_point(const vec& p0, const vec& p1, - const vec& p2, const vec& uv); -template -inline vec triangle_normal( - const vec& p0, const vec& p1, const vec& p2); -template -inline T triangle_area( - const vec& p0, const vec& p1, const vec& p2); - -// Quad properties. -template -inline vec quad_point(const vec& p0, const vec& p1, - const vec& p2, const vec& uv); -template -inline vec quad_normal(const vec& p0, const vec& p1, - const vec& p2, const vec& p3); -template -inline T quad_area(const vec& p0, const vec& p1, - const vec& p2, const vec& p3); - -// Triangle tangent and bitangent from uv -template -inline pair, vec> triangle_tangents_fromuv(const vec& p0, - const vec& p1, const vec& p2, const vec& uv0, - const vec& uv1, const vec& uv2); - -// Quad tangent and bitangent from uv. Note that we pass a current_uv since -// internally we may want to split the quad in two and we need to known where -// to do it. If not interested in the split, just pass vec2f{0,0} here. -template -inline pair, vec> quad_tangents_fromuv(const vec& p0, - const vec& p1, const vec& p2, const vec& p3, - const vec& uv0, const vec& uv1, const vec& uv2, - const vec& uv3, const vec& current_uv); - -// Interpolates values over a line parameterized from a to b by u. Same as lerp. -template -inline T interpolate_line(const T& p0, const T& p1, T1 u); - -// Interpolates values over a triangle parameterized by u and v along the -// (p1-p0) and (p2-p0) directions. Same as barycentric interpolation. -template -inline T interpolate_triangle( - const T& p0, const T& p1, const T& p2, const vec& uv); - -// Interpolates values over a quad parameterized by u and v along the -// (p1-p0) and (p2-p1) directions. Same as bilinear interpolation. -template -inline T interpolate_quad( - const T& p0, const T& p1, const T& p2, const T& p3, const vec& uv); - -// Interpolates values along a cubic Bezier segment parametrized by u. -template -inline T interpolate_bezier( - const T& p0, const T& p1, const T& p2, const T& p3, T1 u); - -// Computes the derivative of a cubic Bezier segment parametrized by u. -template -inline T interpolate_bezier_derivative( - const T& p0, const T& p1, const T& p2, const T& p3, T1 u); - -// Interpolated line properties. -template -inline vec line_point(const vec& p0, const vec& p1, T u); -template -inline vec line_tangent(const vec& t0, const vec& t1, T u); - -// Interpolated triangle properties. -template -inline vec triangle_point(const vec& p0, const vec& p1, - const vec& p2, const vec& uv); -template -inline vec triangle_normal(const vec& n0, const vec& n1, - const vec& n2, const vec& uv); - -// Interpolated quad properties. -template -inline vec quad_point(const vec& p0, const vec& p1, - const vec& p2, const vec& p3, const vec& uv); -template -inline vec quad_normal(const vec& n0, const vec& n1, - const vec& n2, const vec& n3, const vec& uv); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// USER INTERFACE UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Generate a ray from a camera -template -inline ray camera_ray(const frame3f& frame, T lens, const vec& film, - const vec& image_uv); - -// Generate a ray from a camera -template -inline ray camera_ray( - const frame3f& frame, T lens, T aspect, T film, const vec& image_uv); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// RAY-PRIMITIVE INTERSECTION FUNCTIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Primitive intersection -template -struct prim_intersection { - vec uv = {0, 0}; - T distance = num_max; // TODO: num_max - bool hit = false; -}; - -// Intersect a ray with a point (approximate) -template -inline prim_intersection intersect_point( - const ray& ray, const vec& p, T r); - -// Intersect a ray with a line -template -inline prim_intersection intersect_line( - const ray& ray, const vec& p0, const vec& p1, T r0, T r1); - -// Intersect a ray with a triangle -template -inline prim_intersection intersect_triangle(const ray& ray, - const vec& p0, const vec& p1, const vec& p2); - -// Intersect a ray with a quad. -template -inline prim_intersection intersect_quad(const ray& ray, - const vec& p0, const vec& p1, const vec& p2, - const vec& p3); - -// Intersect a ray with a axis-aligned bounding box -template -inline bool intersect_bbox(const ray& ray, const bbox& bbox); - -// Intersect a ray with a axis-aligned bounding box -template -inline bool intersect_bbox( - const ray& ray, const vec& ray_dinv, const bbox& bbox); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// POINT-PRIMITIVE DISTANCE FUNCTIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Check if a point overlaps a position pos withint a maximum distance dist_max. -template -inline prim_intersection overlap_point( - const vec& pos, T dist_max, const vec& p, T r); - -// Compute the closest line uv to a give position pos. -template -inline T closestuv_line( - const vec& pos, const vec& p0, const vec& p1); - -// Check if a line overlaps a position pos withint a maximum distance dist_max. -template -inline prim_intersection overlap_line(const vec& pos, T dist_max, - const vec& p0, const vec& p1, T r0, T r1); - -// Compute the closest triangle uv to a give position pos. -template -inline vec closestuv_triangle(const vec& pos, const vec& p0, - const vec& p1, const vec& p2); - -// Check if a triangle overlaps a position pos withint a maximum distance -// dist_max. -template -inline prim_intersection overlap_triangle(const vec& pos, T dist_max, - const vec& p0, const vec& p1, const vec& p2, T r0, T r1, - T r2); - -// Check if a quad overlaps a position pos withint a maximum distance dist_max. -template -inline prim_intersection overlap_quad(const vec& pos, T dist_max, - const vec& p0, const vec& p1, const vec& p2, - const vec& p3, T r0, T r1, T r2, T r3); - -// Check if a bbox overlaps a position pos withint a maximum distance dist_max. -template -inline bool overlap_bbox( - const vec& pos, T dist_max, const bbox& bbox); - -// Check if two bboxes overlap. -template -inline bool overlap_bbox(const bbox& bbox1, const bbox& bbox2); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// -// -// IMPLEMENTATION -// -// -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// AXIS ALIGNED BOUNDING BOXES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Axis aligned bounding box represented as a min/max vector pairs. -template -inline vec& bbox::operator[](int i) { - return (&min)[i]; -} -template -inline const vec& bbox::operator[](int i) const { - return (&min)[i]; -} - -// Axis aligned bounding box represented as a min/max vector pairs. -template -inline vec& bbox::operator[](int i) { - return (&min)[i]; -} -template -inline const vec& bbox::operator[](int i) const { - return (&min)[i]; -} - -// Bounding box properties -template -inline vec center(const bbox& a) { - return (a.min + a.max) / 2; -} -template -inline vec size(const bbox& a) { - return a.max - a.min; -} - -// Bounding box comparisons. -template -inline bool operator==(const bbox& a, const bbox& b) { - return a.min == b.min && a.max == b.max; -} -template -inline bool operator!=(const bbox& a, const bbox& b) { - return a.min != b.min || a.max != b.max; -} - -// Bounding box expansions with points and other boxes. -template -inline bbox merge(const bbox& a, const vec& b) { - return {min(a.min, b), max(a.max, b)}; -} -template -inline bbox merge(const bbox& a, const bbox& b) { - return {min(a.min, b.min), max(a.max, b.max)}; -} -template -inline void expand(bbox& a, const vec& b) { - a = merge(a, b); -} -template -inline void expand(bbox& a, const bbox& b) { - a = merge(a, b); -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// RAYS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Computes a point on a ray -template -inline vec ray_point(const ray& ray, T t) { - return ray.o + ray.d * t; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// TRANSFORMS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Transforms rays and bounding boxes by matrices. -template -inline ray transform_ray(const mat& a, const ray& b) { - return {transform_point(a, b.o), transform_vector(a, b.d), b.tmin, b.tmax}; -} -template -inline ray transform_ray(const frame& a, const ray& b) { - return {transform_point(a, b.o), transform_vector(a, b.d), b.tmin, b.tmax}; -} -template -inline bbox transform_bbox(const mat& a, const bbox& b) { - if constexpr (N == 3) { - auto corners = {vec{b.min.x, b.min.y, b.min.z}, - vec{b.min.x, b.min.y, b.max.z}, - vec{b.min.x, b.max.y, b.min.z}, - vec{b.min.x, b.max.y, b.max.z}, - vec{b.max.x, b.min.y, b.min.z}, - vec{b.max.x, b.min.y, b.max.z}, - vec{b.max.x, b.max.y, b.min.z}, - vec{b.max.x, b.max.y, b.max.z}}; - auto xformed = bbox(); - for (auto& corner : corners) - xformed = merge(xformed, transform_point(a, corner)); - return xformed; - } -} -template -inline bbox transform_bbox(const frame& a, const bbox& b) { - if constexpr (N == 3) { - auto corners = {vec{b.min.x, b.min.y, b.min.z}, - vec{b.min.x, b.min.y, b.max.z}, - vec{b.min.x, b.max.y, b.min.z}, - vec{b.min.x, b.max.y, b.max.z}, - vec{b.max.x, b.min.y, b.min.z}, - vec{b.max.x, b.min.y, b.max.z}, - vec{b.max.x, b.max.y, b.min.z}, - vec{b.max.x, b.max.y, b.max.z}}; - auto xformed = bbox(); - for (auto& corner : corners) - xformed = merge(xformed, transform_point(a, corner)); - return xformed; - } -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// PRIMITIVE BOUNDS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Primitive bounds. -template -inline bbox point_bounds(const vec& p) { - return {p, p}; -} -template -inline bbox point_bounds(const vec& p, T r) { - return {min(p - r, p + r), max(p - r, p + r)}; -} -template -inline bbox line_bounds(const vec& p0, const vec& p1) { - return {min(p0, p1), max(p0, p1)}; -} -template -inline bbox line_bounds( - const vec& p0, const vec& p1, T r0, T r1) { - return {min(p0 - r0, p1 - r1), max(p0 + r0, p1 + r1)}; -} -template -inline bbox triangle_bounds( - const vec& p0, const vec& p1, const vec& p2) { - return {min(p0, min(p1, p2)), max(p0, max(p1, p2))}; -} -template -inline bbox quad_bounds(const vec& p0, const vec& p1, - const vec& p2, const vec& p3) { - return {min(p0, min(p1, min(p2, p3))), max(p0, max(p1, max(p2, p3)))}; -} -template -inline bbox sphere_bounds(const vec& p, T r) { - return {p - r, p + r}; -} -template -inline bbox capsule_bounds( - const vec& p0, const vec& p1, T r0, T r1) { - return {min(p0 - r0, p1 - r1), max(p0 + r0, p1 + r1)}; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// GEOMETRY UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Line properties. -template -inline vec line_tangent(const vec& p0, const vec& p1) { - return normalize(p1 - p0); -} -template -inline T line_length(const vec& p0, const vec& p1) { - return length(p1 - p0); -} - -// Triangle properties. -template -inline vec triangle_normal( - const vec& p0, const vec& p1, const vec& p2) { - return normalize(cross(p1 - p0, p2 - p0)); -} -template -inline T triangle_area( - const vec& p0, const vec& p1, const vec& p2) { - return length(cross(p1 - p0, p2 - p0)) / 2; -} - -// Quad propeties. -template -inline vec quad_normal(const vec& p0, const vec& p1, - const vec& p2, const vec& p3) { - return normalize(triangle_normal(p0, p1, p3) + triangle_normal(p2, p3, p1)); -} -template -inline T quad_area(const vec& p0, const vec& p1, - const vec& p2, const vec& p3) { - return triangle_area(p0, p1, p3) + triangle_area(p2, p3, p1); -} - -// Interpolates values over a line parameterized from a to b by u. Same as lerp. -template -inline T interpolate_line(const T& p0, const T& p1, T1 u) { - return p0 * (1 - u) + p1 * u; -} -// Interpolates values over a triangle parameterized by u and v along the -// (p1-p0) and (p2-p0) directions. Same as barycentric interpolation. -template -inline T interpolate_triangle( - const T& p0, const T& p1, const T& p2, const vec& uv) { - return p0 * (1 - uv.x - uv.y) + p1 * uv.x + p2 * uv.y; -} -// Interpolates values over a quad parameterized by u and v along the -// (p1-p0) and (p2-p1) directions. Same as bilinear interpolation. -template -inline T interpolate_quad( - const T& p0, const T& p1, const T& p2, const T& p3, const vec& uv) { - if (uv.x + uv.y <= 1) { - return interpolate_triangle(p0, p1, p3, uv); - } else { - return interpolate_triangle(p2, p3, p1, 1 - uv); - } -} - -// Interpolates values along a cubic Bezier segment parametrized by u. -template -inline T interpolate_bezier( - const T& p0, const T& p1, const T& p2, const T& p3, T1 u) { - return p0 * (1 - u) * (1 - u) * (1 - u) + p1 * 3 * u * (1 - u) * (1 - u) + - p2 * 3 * u * u * (1 - u) + p3 * u * u * u; -} -// Computes the derivative of a cubic Bezier segment parametrized by u. -template -inline T interpolate_bezier_derivative( - const T& p0, const T& p1, const T& p2, const T& p3, T1 u) { - return (p1 - p0) * 3 * (1 - u) * (1 - u) + (p2 - p1) * 6 * u * (1 - u) + - (p3 - p2) * 3 * u * u; -} - -// Interpolated line properties. -template -inline vec line_point(const vec& p0, const vec& p1, T u) { - return p0 * (1 - u) + p1 * u; -} -template -inline vec line_tangent(const vec& t0, const vec& t1, T u) { - return normalize(t0 * (1 - u) + t1 * u); -} - -// Interpolated triangle properties. -template -inline vec triangle_point(const vec& p0, const vec& p1, - const vec& p2, const vec& uv) { - return p0 * (1 - uv.x - uv.y) + p1 * uv.x + p2 * uv.y; -} -template -inline vec triangle_normal(const vec& n0, const vec& n1, - const vec& n2, const vec& uv) { - return normalize(n0 * (1 - uv.x - uv.y) + n1 * uv.x + n2 * uv.y); -} - -// Interpolated quad properties. -template -inline vec quad_point(const vec& p0, const vec& p1, - const vec& p2, const vec& p3, const vec& uv) { - if (uv.x + uv.y <= 1) { - return triangle_point(p0, p1, p3, uv); - } else { - return triangle_point(p2, p3, p1, 1 - uv); - } -} -template -inline vec quad_normal(const vec& n0, const vec& n1, - const vec& n2, const vec& n3, const vec& uv) { - if (uv.x + uv.y <= 1) { - return triangle_normal(n0, n1, n3, uv); - } else { - return triangle_normal(n2, n3, n1, 1 - uv); - } -} - -// Interpolated sphere properties. -template -inline vec sphere_point(const vec p, T r, const vec& uv) { - return p + r * vec{cos(uv.x * 2 * (T)pi) * sin(uv.y * (T)pi), - sin(uv.x * 2 * (T)pi) * sin(uv.y * (T)pi), - cos(uv.y * (T)pi)}; -} -template -inline vec sphere_normal(const vec p, T r, const vec& uv) { - return normalize(vec{cos(uv.x * 2 * (T)pi) * sin(uv.y * (T)pi), - sin(uv.x * 2 * (T)pi) * sin(uv.y * (T)pi), cos(uv.y * (T)pi)}); -} - -// Triangle tangent and bitangent from uv -template -inline pair, vec> triangle_tangents_fromuv(const vec& p0, - const vec& p1, const vec& p2, const vec& uv0, - const vec& uv1, const vec& uv2) { - // Follows the definition in http://www.terathon.com/code/tangent.html and - // https://gist.github.com/aras-p/2843984 - // normal points up from texture space - auto p = p1 - p0; - auto q = p2 - p0; - auto s = vec{uv1.x - uv0.x, uv2.x - uv0.x}; - auto t = vec{uv1.y - uv0.y, uv2.y - uv0.y}; - auto div = s.x * t.y - s.y * t.x; - - if (div != 0) { - auto tu = vec{t.y * p.x - t.x * q.x, t.y * p.y - t.x * q.y, - t.y * p.z - t.x * q.z} / - div; - auto tv = vec{s.x * q.x - s.y * p.x, s.x * q.y - s.y * p.y, - s.x * q.z - s.y * p.z} / - div; - return {tu, tv}; - } else { - return {{1, 0, 0}, {0, 1, 0}}; - } -} - -// Quad tangent and bitangent from uv. -template -inline pair, vec> quad_tangents_fromuv(const vec& p0, - const vec& p1, const vec& p2, const vec& p3, - const vec& uv0, const vec& uv1, const vec& uv2, - const vec& uv3, const vec& current_uv) { - if (current_uv.x + current_uv.y <= 1) { - return triangle_tangents_fromuv(p0, p1, p3, uv0, uv1, uv3); - } else { - return triangle_tangents_fromuv(p2, p3, p1, uv2, uv3, uv1); - } -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// IMPLEMENTATION OF USER INTERFACE UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Generate a ray from a camera -template -inline ray camera_ray(const frame3f& frame, T lens, const vec& film, - const vec& image_uv) { - auto e = vec{0, 0, 0}; - auto q = vec{ - film.x * ((T)0.5 - image_uv.x), film.y * (image_uv.y - (T)0.5), lens}; - auto q1 = -q; - auto d = normalize(q1 - e); - auto ray = yocto::ray{ - transform_point(frame, e), transform_direction(frame, d)}; - return ray; -} - -// Generate a ray from a camera -template -inline ray camera_ray(const frame3f& frame, T lens, T aspect, T film_, - const vec& image_uv) { - auto film = aspect >= 1 ? vec{film_, film_ / aspect} - : vec{film_ * aspect, film_}; - auto e = vec{0, 0, 0}; - auto q = vec{ - film.x * ((T)0.5 - image_uv.x), film.y * (image_uv.y - (T)0.5), lens}; - auto q1 = -q; - auto d = normalize(q1 - e); - auto ray = yocto::ray{ - transform_point(frame, e), transform_direction(frame, d)}; - return ray; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// IMPLEMENTATION OF RAY-PRIMITIVE INTERSECTION FUNCTIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Intersect a ray with a point (approximate) -template -inline prim_intersection intersect_point( - const ray& ray, const vec& p, T r) { - // find parameter for line-point minimum distance - auto w = p - ray.o; - auto t = dot(w, ray.d) / dot(ray.d, ray.d); - - // exit if not within bounds - if (t < ray.tmin || t > ray.tmax) return {}; - - // test for line-point distance vs point radius - auto rp = ray.o + ray.d * t; - auto prp = p - rp; - if (dot(prp, prp) > r * r) return {}; - - // intersection occurred: set params and exit - return {{0, 0}, t, true}; -} - -// Intersect a ray with a line -template -inline prim_intersection intersect_line(const ray& ray, - const vec& p0, const vec& p1, T r0, T r1) { - // setup intersection params - auto u = ray.d; - auto v = p1 - p0; - auto w = ray.o - p0; - - // compute values to solve a linear system - auto a = dot(u, u); - auto b = dot(u, v); - auto c = dot(v, v); - auto d = dot(u, w); - auto e = dot(v, w); - auto det = a * c - b * b; - - // check determinant and exit if lines are parallel - // (could use EPSILONS if desired) - if (det == 0) return {}; - - // compute Parameters on both ray and segment - auto t = (b * e - c * d) / det; - auto s = (a * e - b * d) / det; - - // exit if not within bounds - if (t < ray.tmin || t > ray.tmax) return {}; - - // clamp segment param to segment corners - s = clamp(s, (T)0, (T)1); - - // compute segment-segment distance on the closest points - auto pr = ray.o + ray.d * t; - auto pl = p0 + (p1 - p0) * s; - auto prl = pr - pl; - - // check with the line radius at the same point - auto d2 = dot(prl, prl); - auto r = r0 * (1 - s) + r1 * s; - if (d2 > r * r) return {}; - - // intersection occurred: set params and exit - return {{s, sqrt(d2) / r}, t, true}; -} - -// Intersect a ray with a sphere -template -inline prim_intersection intersect_sphere( - const ray& ray, const vec& p, T r) { - // compute parameters - auto a = dot(ray.d, ray.d); - auto b = 2 * dot(ray.o - p, ray.d); - auto c = dot(ray.o - p, ray.o - p) - r * r; - - // check discriminant - auto dis = b * b - 4 * a * c; - if (dis < 0) return {}; - - // compute ray parameter - auto t = (-b - sqrt(dis)) / (2 * a); - - // exit if not within bound(T)pi - if (t < ray.tmin || t > ray.tmax) return {}; - - // try other ray parameter - t = (-b + sqrt(dis)) / (2 * a); - - // exit if not within bounds - if (t < ray.tmin || t > ray.tmax) return {}; - - // compute local point for uvs - auto plocal = ((ray.o + ray.d * t) - p) / r; - auto u = atan2(plocal.y, plocal.x) / (2 * (T)pi); - if (u < 0) u += 1; - auto v = acos(clamp(plocal.z, (T)-1, (T)1)) / (T)pi; - - // intersection occurred: set params and exit - return {{u, v}, t, true}; -} - -// Intersect a ray with a triangle -template -inline prim_intersection intersect_triangle(const ray& ray, - const vec& p0, const vec& p1, const vec& p2) { - // compute triangle edges - auto edge1 = p1 - p0; - auto edge2 = p2 - p0; - - // compute determinant to solve a linear system - auto pvec = cross(ray.d, edge2); - auto det = dot(edge1, pvec); - - // check determinant and exit if triangle and ray are parallel - // (could use EPSILONS if desired) - if (det == 0) return {}; - auto inv_det = (T)1.0 / det; - - // compute and check first bricentric coordinated - auto tvec = ray.o - p0; - auto u = dot(tvec, pvec) * inv_det; - if (u < 0 || u > 1) return {}; - - // compute and check second bricentric coordinated - auto qvec = cross(tvec, edge1); - auto v = dot(ray.d, qvec) * inv_det; - if (v < 0 || u + v > 1) return {}; - - // compute and check ray parameter - auto t = dot(edge2, qvec) * inv_det; - if (t < ray.tmin || t > ray.tmax) return {}; - - // intersection occurred: set params and exit - return {{u, v}, t, true}; -} - -// Intersect a ray with a quad. -template -inline prim_intersection intersect_quad(const ray& ray, - const vec& p0, const vec& p1, const vec& p2, - const vec& p3) { - if (p2 == p3) return intersect_triangle(ray, p0, p1, p3); - auto isec1 = intersect_triangle(ray, p0, p1, p3); - auto isec2 = intersect_triangle(ray, p2, p3, p1); - if (isec2.hit) isec2.uv = 1 - isec2.uv; - return isec1.distance < isec2.distance ? isec1 : isec2; -} - -// Intersect a ray with a axis-aligned bounding box -template -inline bool intersect_bbox(const ray& ray, const bbox& bbox) { - // determine intersection ranges - auto invd = (T)1.0 / ray.d; - auto t0 = (bbox.min - ray.o) * invd; - auto t1 = (bbox.max - ray.o) * invd; - // flip based on range directions - if (invd.x < (T)0.0) swap(t0.x, t1.x); - if (invd.y < (T)0.0) swap(t0.y, t1.y); - if (invd.z < (T)0.0) swap(t0.z, t1.z); - auto tmin = max(t0.z, max(t0.y, max(t0.x, ray.tmin))); - auto tmax = min(t1.z, min(t1.y, min(t1.x, ray.tmax))); - if constexpr (std::is_same_v) tmax *= 1.00000024f; - if constexpr (std::is_same_v) tmax *= 1.0000000000000004; - return tmin <= tmax; -} - -// Intersect a ray with a axis-aligned bounding box -template -inline bool intersect_bbox( - const ray& ray, const vec& ray_dinv, const bbox& bbox) { - auto it_min = (bbox.min - ray.o) * ray_dinv; - auto it_max = (bbox.max - ray.o) * ray_dinv; - auto tmin = min(it_min, it_max); - auto tmax = max(it_min, it_max); - auto t0 = max(max(tmin), ray.tmin); - auto t1 = min(min(tmax), ray.tmax); - if constexpr (std::is_same_v) t1 *= 1.00000024f; - if constexpr (std::is_same_v) t1 *= 1.0000000000000004; - return t0 <= t1; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// IMPLEMENTATION OF POINT-PRIMITIVE DISTANCE FUNCTIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Check if a point overlaps a position pos withint a maximum distance dist_max. -template -inline prim_intersection overlap_point( - const vec& pos, T dist_max, const vec& p, T r) { - auto d2 = dot(pos - p, pos - p); - if (d2 > (dist_max + r) * (dist_max + r)) return {}; - return {{0, 0}, sqrt(d2), true}; -} - -// Compute the closest line uv to a give position pos. -template -inline T closestuv_line( - const vec& pos, const vec& p0, const vec& p1) { - auto ab = p1 - p0; - auto d = dot(ab, ab); - // Project c onto ab, computing parameterized position d(t) = a + t*(b – - // a) - auto u = dot(pos - p0, ab) / d; - u = clamp(u, (T)0, (T)1); - return u; -} - -// Check if a line overlaps a position pos withint a maximum distance dist_max. -template -inline prim_intersection overlap_line(const vec& pos, T dist_max, - const vec& p0, const vec& p1, T r0, T r1) { - auto u = closestuv_line(pos, p0, p1); - // Compute projected position from the clamped t d = a + t * ab; - auto p = p0 + (p1 - p0) * u; - auto r = r0 + (r1 - r0) * u; - auto d2 = dot(pos - p, pos - p); - // check distance - if (d2 > (dist_max + r) * (dist_max + r)) return {}; - // done - return {{u, 0}, sqrt(d2), true}; -} - -// Compute the closest triangle uv to a give position pos. -template -inline vec closestuv_triangle(const vec& pos, const vec& p0, - const vec& p1, const vec& p2) { - // this is a complicated test -> I probably "--"+prefix to use a sequence of - // test (triangle body, and 3 edges) - auto ab = p1 - p0; - auto ac = p2 - p0; - auto ap = pos - p0; - - auto d1 = dot(ab, ap); - auto d2 = dot(ac, ap); - - // corner and edge cases - if (d1 <= 0 && d2 <= 0) return {0, 0}; - - auto bp = pos - p1; - auto d3 = dot(ab, bp); - auto d4 = dot(ac, bp); - if (d3 >= 0 && d4 <= d3) return {1, 0}; - - auto vc = d1 * d4 - d3 * d2; - if ((vc <= 0) && (d1 >= 0) && (d3 <= 0)) return {d1 / (d1 - d3), 0}; - - auto cp = pos - p2; - auto d5 = dot(ab, cp); - auto d6 = dot(ac, cp); - if (d6 >= 0 && d5 <= d6) return {0, 1}; - - auto vb = d5 * d2 - d1 * d6; - if ((vb <= 0) && (d2 >= 0) && (d6 <= 0)) return {0, d2 / (d2 - d6)}; - - auto va = d3 * d6 - d5 * d4; - if ((va <= 0) && (d4 - d3 >= 0) && (d5 - d6 >= 0)) { - auto w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); - return {1 - w, w}; - } - - // face case - auto denom = 1 / (va + vb + vc); - auto u = vb * denom; - auto v = vc * denom; - return {u, v}; -} - -// Check if a triangle overlaps a position pos withint a maximum distance -// dist_max. -template -inline prim_intersection overlap_triangle(const vec& pos, T dist_max, - const vec& p0, const vec& p1, const vec& p2, T r0, T r1, - T r2) { - auto cuv = closestuv_triangle(pos, p0, p1, p2); - auto p = p0 * (1 - cuv.x - cuv.y) + p1 * cuv.x + p2 * cuv.y; - auto r = r0 * (1 - cuv.x - cuv.y) + r1 * cuv.x + r2 * cuv.y; - auto dd = dot(p - pos, p - pos); - if (dd > (dist_max + r) * (dist_max + r)) return {}; - return {cuv, sqrt(dd), true}; -} - -// Check if a quad overlaps a position pos withint a maximum distance dist_max. -template -inline prim_intersection overlap_quad(const vec& pos, T dist_max, - const vec& p0, const vec& p1, const vec& p2, - const vec& p3, T r0, T r1, T r2, T r3) { - if (p2 == p3) return overlap_triangle(pos, dist_max, p0, p1, p3, r0, r1, r2); - auto isec1 = overlap_triangle(pos, dist_max, p0, p1, p3, r0, r1, r2); - auto isec2 = overlap_triangle(pos, dist_max, p2, p3, p1, r2, r3, r1); - if (isec2.hit) isec2.uv = 1 - isec2.uv; - return isec1.distance < isec2.distance ? isec1 : isec2; -} - -// Check if a bbox overlaps a position pos withint a maximum distance dist_max. -template -inline bool overlap_bbox( - const vec& pos, T dist_max, const bbox& bbox) { - // computing distance - auto dd = (T)0.0; - - // For each axis count any excess distance outside box extents - if (pos.x < bbox.min.x) dd += (bbox.min.x - pos.x) * (bbox.min.x - pos.x); - if (pos.x > bbox.max.x) dd += (pos.x - bbox.max.x) * (pos.x - bbox.max.x); - if (pos.y < bbox.min.y) dd += (bbox.min.y - pos.y) * (bbox.min.y - pos.y); - if (pos.y > bbox.max.y) dd += (pos.y - bbox.max.y) * (pos.y - bbox.max.y); - if (pos.z < bbox.min.z) dd += (bbox.min.z - pos.z) * (bbox.min.z - pos.z); - if (pos.z > bbox.max.z) dd += (pos.z - bbox.max.z) * (pos.z - bbox.max.z); - - // check distance - return dd < dist_max * dist_max; -} - -// Check if two bboxe overlap. -template -inline bool overlap_bbox(const bbox& bbox1, const bbox& bbox2) { - if (bbox1.max.x < bbox2.min.x || bbox1.min.x > bbox2.max.x) return false; - if (bbox1.max.y < bbox2.min.y || bbox1.min.y > bbox2.max.y) return false; - if (bbox1.max.z < bbox2.min.z || bbox1.min.z > bbox2.max.z) return false; - return true; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// BACKWARD COMPATIBILITY -// ----------------------------------------------------------------------------- -namespace yocto { - -// Intersect a ray with a point (approximate) -template -[[deprecated]] inline bool intersect_point( - const ray& ray, const vec& p, T r, vec& uv, T& dist) { - auto intersection = intersect_point(ray, p, r); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Intersect a ray with a line -template -[[deprecated]] inline bool intersect_line(const ray& ray, - const vec& p0, const vec& p1, T r0, T r1, vec& uv, - T& dist) { - auto intersection = intersect_line(ray, p0, p1, r0, r1); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Intersect a ray with a sphere -template -[[deprecated]] inline bool intersect_sphere( - const ray& ray, const vec& p, T r, vec& uv, T& dist) { - auto intersection = intersect_sphere(ray, p, r); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Intersect a ray with a triangle -template -[[deprecated]] inline bool intersect_triangle(const ray& ray, - const vec& p0, const vec& p1, const vec& p2, - vec& uv, T& dist) { - auto intersection = intersect_triangle(ray, p0, p1, p2); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Intersect a ray with a quad. -template -[[deprecated]] inline bool intersect_quad(const ray& ray, - const vec& p0, const vec& p1, const vec& p2, - const vec& p3, vec& uv, T& dist) { - auto intersection = intersect_quad(ray, p0, p1, p2, p3); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Check if a point overlaps a position pos withint a maximum distance dist_max. -template -[[deprecated]] inline bool overlap_point(const vec& pos, T dist_max, - const vec& p, T r, vec& uv, T& dist) { - auto intersection = overlap_point(pos, dist_max, p, r); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Check if a line overlaps a position pos withint a maximum distance dist_max. -template -[[deprecated]] inline bool overlap_line(const vec& pos, T dist_max, - const vec& p0, const vec& p1, T r0, T r1, vec& uv, - T& dist) { - auto intersection = overlap_line(pos, dist_max, p0, p1, r0, r1); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Check if a triangle overlaps a position pos withint a maximum distance -// dist_max. -template -[[deprecated]] inline bool overlap_triangle(const vec& pos, T dist_max, - const vec& p0, const vec& p1, const vec& p2, T r0, T r1, - T r2, vec& uv, T& dist) { - auto intersection = overlap_triangle(pos, dist_max, p0, p1, p2, r0, r1, r2); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -// Check if a quad overlaps a position pos withint a maximum distance dist_max. -template -[[deprecated]] inline bool overlap_quad(const vec& pos, T dist_max, - const vec& p0, const vec& p1, const vec& p2, - const vec& p3, T r0, T r1, T r2, T r3, vec& uv, T& dist) { - auto intersection = overlap_quad( - pos, dist_max, p0, p1, p2, p3, r0, r1, r2, r3); - if (!intersection.hit) return false; - uv = intersection.uv; - dist = intersection.distance; - return true; -} - -} // namespace yocto - -#endif diff --git a/libs/yocto/yocto_matht.h b/libs/yocto/yocto_matht.h deleted file mode 100644 index 32f57f30c..000000000 --- a/libs/yocto/yocto_matht.h +++ /dev/null @@ -1,2771 +0,0 @@ -// -// # Yocto/Math: Math types -// -// Yocto/Math defines the basic math primitives used in graphics, including -// small-sized vectors, matrices, frames, quaternions, rays, bounding boxes -// and their transforms. Yocto/Math is implemented in `yocto_math.h`. -// - -// -// LICENSE: -// -// Copyright (c) 2016 -- 2022 Fabio Pellacini -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#ifndef _YOCTO_MATH_H_ -#define _YOCTO_MATH_H_ - -// ----------------------------------------------------------------------------- -// INCLUDES -// ----------------------------------------------------------------------------- - -#include -#include -#include -#include -#include - -// ----------------------------------------------------------------------------- -// USING DIRECTIVES -// ----------------------------------------------------------------------------- -namespace yocto { - -// using directives -using std::pair; - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// MATH CONSTANTS AND FUNCTIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -using byte = unsigned char; -using uint = unsigned int; -using ushort = unsigned short; - -inline const double pi = 3.14159265358979323846; -inline const float pif = (float)pi; - -constexpr auto int_max = std::numeric_limits::max(); -constexpr auto int_min = std::numeric_limits::lowest(); -constexpr auto flt_max = std::numeric_limits::max(); -constexpr auto flt_min = std::numeric_limits::lowest(); -constexpr auto flt_eps = std::numeric_limits::epsilon(); - -template -constexpr auto num_max = std::numeric_limits::max(); -template -constexpr auto num_min = std::numeric_limits::lowest(); -template -constexpr auto num_eps = std::numeric_limits::epsilon(); - -using std::swap; - -template -inline T abs(T a); -template -inline T min(T a, T b); -template -inline T max(T a, T b); -template -inline T clamp(T a, T min, T max); -template -inline T sign(T a); -template -inline T sqr(T a); -template -inline T sqrt(T a); -template -inline T sin(T a); -template -inline T cos(T a); -template -inline T tan(T a); -template -inline T asin(T a); -template -inline T acos(T a); -template -inline T atan(T a); -template -inline T log(T a); -template -inline T exp(T a); -template -inline T log2(T a); -template -inline T exp2(T a); -template -inline T pow(T a, T b); -template -inline bool isfinite(T a); -template -inline T atan2(T a, T b); -template -inline T fmod(T a, T b); -template -inline T radians(T a); -template -inline T degrees(T a); -template -inline T lerp(T a, T b, T u); -// template -// inline void swap(T& a, T& b); -template -inline T smoothstep(T a, T b, T u); -template -inline T bias(T a, T bias); -template -inline T gain(T a, T gain); -template -inline int pow2(int a); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// VECTORS -// ----------------------------------------------------------------------------- -namespace yocto { - -template -struct vec; - -template -struct vec { - T x = 0; - - T& operator[](int i); - const T& operator[](int i) const; -}; - -template -struct vec { - T x = 0; - T y = 0; - - T& operator[](int i); - const T& operator[](int i) const; -}; - -template -struct vec { - T x = 0; - T y = 0; - T z = 0; - - T& operator[](int i); - const T& operator[](int i) const; -}; - -template -struct vec { - T x = 0; - T y = 0; - T z = 0; - T w = 0; - - T& operator[](int i); - const T& operator[](int i) const; -}; - -// Vector aliases -using vec1f = vec; -using vec2f = vec; -using vec3f = vec; -using vec4f = vec; -using vec1i = vec; -using vec2i = vec; -using vec3i = vec; -using vec4i = vec; -using vec4b = vec; - -// Element access -template -inline vec xyz(const vec& a); - -// Vector sequence operations. -template -inline int size(const vec& a); -template -inline const T* begin(const vec& a); -template -inline const T* end(const vec& a); -template -inline T* begin(vec& a); -template -inline T* end(vec& a); -template -inline const T* data(const vec& a); -template -inline T* data(vec& a); - -// Vector comparison operations. -template -inline bool operator==(const vec& a, const vec& b); -template -inline bool operator!=(const vec& a, const vec& b); - -// Vector operations. -template -inline vec operator+(const vec& a); -template -inline vec operator-(const vec& a); -template -inline vec operator+(const vec& a, const vec& b); -template -inline vec operator+(const vec& a, T1 b); -template -inline vec operator+(T1 a, const vec& b); -template -inline vec operator-(const vec& a, const vec& b); -template -inline vec operator-(const vec& a, T1 b); -template -inline vec operator-(T1 a, const vec& b); -template -inline vec operator*(const vec& a, const vec& b); -template -inline vec operator*(const vec& a, T1 b); -template -inline vec operator*(T1 a, const vec& b); -template -inline vec operator/(const vec& a, const vec& b); -template -inline vec operator/(const vec& a, T1 b); -template -inline vec operator/(T1 a, const vec& b); - -// Vector assignments -template -inline vec& operator+=(vec& a, const vec& b); -template -inline vec& operator+=(vec& a, T1 b); -template -inline vec& operator-=(vec& a, const vec& b); -template -inline vec& operator-=(vec& a, T1 b); -template -inline vec& operator*=(vec& a, const vec& b); -template -inline vec& operator*=(vec& a, T1 b); -template -inline vec& operator/=(vec& a, const vec& b); -template -inline vec& operator/=(vec& a, T1 b); - -// Vector products and lengths. -template -inline T dot(const vec& a, const vec& b); -template -inline T cross(const vec& a, const vec& b); -template -inline vec cross(const vec& a, const vec& b); - -template -inline T length(const vec& a); -template -inline T length_squared(const vec& a); -template -inline vec normalize(const vec& a); -template -inline T distance(const vec& a, const vec& b); -template -inline T distance_squared(const vec& a, const vec& b); -template -inline T angle(const vec& a, const vec& b); - -// Orthogonal vectors. -template -inline vec orthogonal(const vec& v); -template -inline vec orthonormalize(const vec& a, const vec& b); - -// Reflected and refracted vector. -template -inline vec reflect(const vec& w, const vec& n); -template -inline vec refract(const vec& w, const vec& n, T inv_eta); - -// Slerp -template -inline vec slerp(const vec& a, const vec& b, T u); - -// Max element and clamp. -template -inline vec max(const vec& a, T b); -template -inline vec min(const vec& a, T b); -template -inline vec max(const vec& a, const vec& b); -template -inline vec min(const vec& a, const vec& b); -template -inline vec clamp(const vec& x, T min, T max); -template -inline vec lerp(const vec& a, const vec& b, T u); -template -inline vec lerp( - const vec& a, const vec& b, const vec& u); - -template -inline T max(const vec& a); -template -inline T min(const vec& a); -template -inline T sum(const vec& a); -template -inline T mean(const vec& a); - -// Functions applied to vector elements -template -inline vec abs(const vec& a); -template -inline vec sqr(const vec& a); -template -inline vec sqrt(const vec& a); -template -inline vec exp(const vec& a); -template -inline vec log(const vec& a); -template -inline vec exp2(const vec& a); -template -inline vec log2(const vec& a); -template -inline bool isfinite(const vec& a); -template -inline vec pow(const vec& a, T b); -template -inline vec pow(const vec& a, const vec& b); -template -inline vec gain(const vec& a, T b); -// template -// inline void swap(vec& a, vec& b); - -// Quaternion operatons represented as xi + yj + zk + w -// const auto identity_quat4f = vec4f{0, 0, 0, 1}; -template -inline vec quat_mul(const vec& a, T b); -template -inline vec quat_mul(const vec& a, const vec& b); -template -inline vec quat_conjugate(const vec& a); -template -inline vec quat_inverse(const vec& a); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// MATRICES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Small Fixed-size matrices stored in column major format. -template -struct mat; - -// Small Fixed-size matrices stored in column major format. -template -struct mat { - vec x = {1}; - - vec& operator[](int i); - const vec& operator[](int i) const; -}; - -// Small Fixed-size matrices stored in column major format. -template -struct mat { - vec x = {1, 0}; - vec y = {0, 1}; - - vec& operator[](int i); - const vec& operator[](int i) const; -}; - -// Small Fixed-size matrices stored in column major format. -template -struct mat { - vec x = {1, 0, 0}; - vec y = {0, 1, 0}; - vec z = {0, 0, 1}; - - vec& operator[](int i); - const vec& operator[](int i) const; -}; - -// Small Fixed-size matrices stored in column major format. -template -struct mat { - vec x = {1, 0, 0, 0}; - vec y = {0, 1, 0, 0}; - vec z = {0, 0, 1, 0}; - vec w = {0, 0, 0, 1}; - - vec& operator[](int i); - const vec& operator[](int i) const; -}; - -// Matrix aliases -using mat1f = mat; -using mat2f = mat; -using mat3f = mat; -using mat4f = mat; - -// Matrix comparisons. -template -inline bool operator==(const mat& a, const mat& b); -template -inline bool operator!=(const mat& a, const mat& b); - -// Matrix operations. -template -inline mat operator+(const mat& a, const mat& b); -template -inline mat operator*(const mat& a, T1 b); -template -inline vec operator*(const mat& a, const vec& b); -template -inline vec operator*(const vec& a, const mat& b); -template -inline mat operator*(const mat& a, const mat& b); - -// Matrix assignments. -template -inline mat& operator+=(mat& a, const mat& b); -template -inline mat& operator*=(mat& a, const mat& b); -template -inline mat& operator*=(mat& a, T1 b); - -// Matrix diagonals and transposes. -template -inline vec diagonal(const mat& a); -template -inline mat transpose(const mat& a); - -// Matrix adjoints, determinants and inverses. -template -inline T determinant(const mat& a); -template -inline mat adjoint(const mat& a); -template -inline mat inverse(const mat& a); - -// Constructs a basis from a direction -template -inline mat basis_fromz(const vec& v); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// RIGID BODY TRANSFORMS/FRAMES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Rigid frames stored as a column-major affine transform matrix. -template -struct frame; - -// Rigid frames stored as a column-major affine transform matrix. -template -struct frame { - vec x = {1, 0}; - vec y = {0, 1}; - vec o = {0, 0}; - - vec& operator[](int i); - const vec& operator[](int i) const; -}; - -// Rigid frames stored as a column-major affine transform matrix. -template -struct frame { - vec x = {1, 0, 0}; - vec y = {0, 1, 0}; - vec z = {0, 0, 1}; - vec o = {0, 0, 0}; - - vec& operator[](int i); - const vec& operator[](int i) const; -}; - -// Frame aliases -using frame2f = frame; -using frame3f = frame; - -// Frame properties -template -inline mat rotation(const frame& a); -template -inline vec translation(const frame& a); - -// Frame construction -template -inline frame make_frame(const mat& m, const vec& t); - -// Conversion between frame and mat -template -inline mat frame_to_mat(const frame& f); -template -inline frame mat_to_frame(const mat& ma); - -// Frame comparisons. -template -inline bool operator==(const frame& a, const frame& b); -template -inline bool operator!=(const frame& a, const frame& b); - -// Frame composition, equivalent to affine matrix product. -template -inline frame operator*(const frame& a, const frame& b); -template -inline frame& operator*=(frame& a, const frame& b); - -// Frame inverse, equivalent to rigid affine inverse. -template -inline frame inverse(const frame& a, bool non_rigid = false); - -// Frame construction from axis. -template -inline frame frame_fromz(const vec& o, const vec& v); -template -inline frame frame_fromzx( - const vec& o, const vec& z_, const vec& x_); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// QUATERNIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Quaternions to represent rotations -template -struct quat; - -// Quaternions to represent rotations -template -struct quat { - T x = 0; - T y = 0; - T z = 0; - T w = 1; -}; - -// Quaternion aliases -using quat4f = quat; - -// Quaternion operatons -template -inline quat operator+(const quat& a, const quat& b); -template -inline quat operator*(const quat& a, T b); -template -inline quat operator/(const quat& a, T b); -template -inline quat operator*(const quat& a, const quat& b); - -// Quaterion operations -template -inline T dot(const quat& a, const quat& b); -template -inline T length(const quat& a); -template -inline quat normalize(const quat& a); -template -inline quat conjugate(const quat& a); -template -inline quat inverse(const quat& a); -template -inline T uangle(const quat& a, const quat& b); -template -inline quat lerp(const quat& a, const quat& b, T t); -template -inline quat nlerp(const quat& a, const quat& b, T t); -template -inline quat slerp(const quat& a, const quat& b, T t); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// TRANSFORMS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Transforms points, vectors and directions by matrices. -template -inline vec transform_point(const mat& a, const vec& b); -template -inline vec transform_vector(const mat& a, const vec& b); -template -inline vec transform_direction( - const mat& a, const vec& b); -template -inline vec transform_normal(const mat& a, const vec& b); -template -inline vec transform_vector(const mat& a, const vec& b); -template -inline vec transform_direction(const mat& a, const vec& b); -template -inline vec transform_normal(const mat& a, const vec& b); - -// Transforms points, vectors and directions by frames. -template -inline vec transform_point(const frame& a, const vec& b); -template -inline vec transform_vector(const frame& a, const vec& b); -template -inline vec transform_direction(const frame& a, const vec& b); -template -inline vec transform_normal( - const frame& a, const vec& b, bool non_rigid = false); - -// Transforms points, vectors and directions by frames. -template -inline vec transform_point_inverse( - const frame& a, const vec& b); -template -inline vec transform_vector_inverse( - const frame& a, const vec& b); -template -inline vec transform_direction_inverse( - const frame& a, const vec& b); - -// Translation, scaling and rotations transforms. -template -inline frame translation_frame(const vec& a); -template -inline frame scaling_frame(const vec& a); -template -inline frame rotation_frame(const vec& axis, T angle); -template -inline frame rotation_frame(const vec& quat); -template -inline frame rotation_frame(const quat& quat); -template -inline frame rotation_frame(const mat& rot); - -// Lookat frame. Z-axis can be inverted with inv_xz. -template -inline frame lookat_frame(const vec& eye, const vec& center, - const vec& up, bool inv_xz = false); - -// OpenGL frustum, ortho and perspecgive matrices. -template -inline mat frustum_mat(T l, T r, T b, T t, T n, T f); -template -inline mat ortho_mat(T l, T r, T b, T t, T n, T f); -template -inline mat ortho2d_mat(T left, T right, T bottom, T top); -template -inline mat ortho_mat(T xmag, T ymag, T near, T far); -template -inline mat perspective_mat(T fovy, T aspect, T near, T far); -template -inline mat perspective_mat(T fovy, T aspect, T near); - -// Rotation conversions. -template -inline pair, T> rotation_axisangle(const vec& quat); -template -inline vec rotation_quat(const vec& axis, T angle); -template -inline vec rotation_quat(const vec& axisangle); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// USER INTERFACE UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Computes the image uv coordinates corresponding to the view parameters. -// Returns negative coordinates if out of the image. -template -inline vec image_coords(const vec& mouse_pos, - const vec& center, T scale, const vec& txt_size); - -// Center image and autofit. Returns center and scale. -template -inline pair, T> camera_imview(const vec& center, T scale, - const vec& imsize, const vec& winsize, bool zoom_to_fit); - -// Turntable for UI navigation. Returns from and to. -template -inline pair, vec> camera_turntable(const vec& from, - const vec& to, const vec& up, const vec& rotate, T dolly, - const vec& pan); - -// Turntable for UI navigation. Returns frame and focus. -template -inline pair, T> camera_turntable(const frame& frame, T focus, - const vec& rotate, T dolly, const vec& pan); - -// FPS camera for UI navigation for a frame parametrization. Returns frame. -template -inline frame camera_fpscam( - const frame& frame, const vec& transl, const vec& rotate); - -// Computes the image uv coordinates corresponding to the view parameters. -// Returns negative coordinates if out of the image. -template -[[deprecated]] inline vec get_image_coords(const vec& mouse_pos, - const vec& center, T scale, const vec& txt_size); - -// Center image and autofit. -template -[[deprecated]] inline void update_imview(vec& center, T& scale, - const vec& imsize, const vec& winsize, bool zoom_to_fit); - -// Turntable for UI navigation. -template -[[deprecated]] inline void update_turntable(vec& from, vec& to, - const vec& up, const vec& rotate, T dolly, - const vec& pan); - -// Turntable for UI navigation. -template -[[deprecated]] inline void update_turntable(frame& frame, T& focus, - const vec& rotate, T dolly, const vec& pan); - -// FPS camera for UI navigation for a frame parametrization. -template -[[deprecated]] inline void update_fpscam( - frame& frame, const vec& transl, const vec& rotate); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// PYTHON-LIKE ITERATORS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Python range. Construct an object that iterates over an integer sequence. -template -constexpr auto range(T max); -template -constexpr auto range(T min, T max); -template -constexpr auto range(T min, T max, T step); - -// Python enumerate -template -constexpr auto enumerate(const Sequence& sequence, T start = 0); -template -constexpr auto enumerate(Sequence& sequence, T start = 0); - -// Python zip -template -constexpr auto zip(const Sequence1& sequence1, const Sequence2& sequence2); -template -constexpr auto zip(Sequence1& sequence1, Sequence2& sequence2); -template -constexpr auto zip(const Sequence1& sequence1, Sequence2& sequence2); -template -constexpr auto zip(Sequence1& sequence1, const Sequence2& sequence2); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// SIGNED-SIZE -// ----------------------------------------------------------------------------- -namespace yocto { - -template -inline std::ptrdiff_t ssize(const T& container); - -} - -// ----------------------------------------------------------------------------- -// -// -// IMPLEMENTATION -// -// -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// MATH CONSTANTS AND FUNCTIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -template -inline T abs(T a) { - return a < 0 ? -a : a; -} -template -inline T min(T a, T b) { - return (a < b) ? a : b; -} -template -inline T max(T a, T b) { - return (a > b) ? a : b; -} -template -inline T clamp(T a, T min_, T max_) { - return min(max(a, min_), max_); -} -template -inline T sign(T a) { - return a < 0 ? (T)-1 : (T)1; -} -template -inline T sqr(T a) { - return a * a; -} -template -inline T sqrt(T a) { - return std::sqrt(a); -} -template -inline T sin(T a) { - return std::sin(a); -} -template -inline T cos(T a) { - return std::cos(a); -} -template -inline T tan(T a) { - return std::tan(a); -} -template -inline T asin(T a) { - return std::asin(a); -} -template -inline T acos(T a) { - return std::acos(a); -} -template -inline T atan(T a) { - return std::atan(a); -} -template -inline T log(T a) { - return std::log(a); -} -template -inline T exp(T a) { - return std::exp(a); -} -template -inline T log2(T a) { - return std::log2(a); -} -template -inline T exp2(T a) { - return std::exp2(a); -} -template -inline T pow(T a, T b) { - return std::pow(a, b); -} -template -inline bool isfinite(T a) { - return std::isfinite(a); -} -template -inline T atan2(T a, T b) { - return std::atan2(a, b); -} -template -inline T fmod(T a, T b) { - return std::fmod(a, b); -} -// template -// inline void swap(T& a, T& b) { -// std::swap(a, b); -// } -template -inline T radians(T a) { - return a * (T)pi / 180; -} -template -inline T degrees(T a) { - return a * 180 / (T)pi; -} -template -inline T lerp(T a, T b, T u) { - return a * (1 - u) + b * u; -} -template -inline T step(T a, T u) { - return u < a ? (T)0 : (T)1; -} -template -inline T smoothstep(T a, T b, T u) { - auto t = clamp((u - a) / (b - a), (T)0, (T)1); - return t * t * (3 - 2 * t); -} -template -inline T bias(T a, T bias) { - return a / ((1 / bias - 2) * (1 - a) + 1); -} -template -inline T gain(T a, T gain) { - return (a < (T)0.5) ? bias(a * 2, gain) / 2 - : bias(a * 2 - 1, 1 - gain) / 2 + (T)0.5; -} -template -inline I pow2(I a) { - return 1 << a; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// VECTORS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Vec2 -template -inline T& vec::operator[](int i) { - return (&x)[i]; -} -template -inline const T& vec::operator[](int i) const { - return (&x)[i]; -} - -// Vec3 -template -inline T& vec::operator[](int i) { - return (&x)[i]; -} -template -inline const T& vec::operator[](int i) const { - return (&x)[i]; -} - -// Vec4 -template -inline T& vec::operator[](int i) { - return (&x)[i]; -} -template -inline const T& vec::operator[](int i) const { - return (&x)[i]; -} - -// Element access -template -inline vec xyz(const vec& a) { - return {a.x, a.y, a.z}; -} - -// Vector sequence operations. -template -inline int size(const vec& a) { - return N; -} -template -inline const T* begin(const vec& a) { - return &a.x; -} -template -inline const T* end(const vec& a) { - return &a.x + N; -} -template -inline T* begin(vec& a) { - return &a.x; -} -template -inline T* end(vec& a) { - return &a.x + N; -} -template -inline const T* data(const vec& a) { - return &a.x; -} -template -inline T* data(vec& a) { - return &a.x; -} - -// Vector comparison operations. -template -inline bool operator==(const vec& a, const vec& b) { - if constexpr (N == 1) { - return a.x == b.x; - } else if constexpr (N == 2) { - return a.x == b.x && a.y == b.y; - } else if constexpr (N == 3) { - return a.x == b.x && a.y == b.y && a.z == b.z; - } else if constexpr (N == 4) { - return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; - } -} -template -inline bool operator!=(const vec& a, const vec& b) { - if constexpr (N == 1) { - return a.x != b.x; - } else if constexpr (N == 2) { - return a.x != b.x || a.y != b.y; - } else if constexpr (N == 3) { - return a.x != b.x || a.y != b.y || a.z != b.z; - } else if constexpr (N == 4) { - return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; - } -} - -// Vector operations. -template -inline vec operator+(const vec& a) { - return a; -} -template -inline vec operator-(const vec& a) { - if constexpr (N == 1) { - return {-a.x}; - } else if constexpr (N == 2) { - return {-a.x, -a.y}; - } else if constexpr (N == 3) { - return {-a.x, -a.y, -a.z}; - } else if constexpr (N == 4) { - return {-a.x, -a.y, -a.z, -a.w}; - } -} - -template -inline vec operator+(const vec& a, const vec& b) { - if constexpr (N == 1) { - return {a.x + b.x}; - } else if constexpr (N == 2) { - return {a.x + b.x, a.y + b.y}; - } else if constexpr (N == 3) { - return {a.x + b.x, a.y + b.y, a.z + b.z}; - } else if constexpr (N == 4) { - return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w}; - } -} -template -inline vec operator+(const vec& a, T1 b) { - if constexpr (N == 1) { - return {a.x + b}; - } else if constexpr (N == 2) { - return {a.x + b, a.y + b}; - } else if constexpr (N == 3) { - return {a.x + b, a.y + b, a.z + b}; - } else if constexpr (N == 4) { - return {a.x + b, a.y + b, a.z + b, a.w + b}; - } -} -template -inline vec operator+(T1 a, const vec& b) { - if constexpr (N == 1) { - return {a + b.x}; - } else if constexpr (N == 2) { - return {a + b.x, a + b.y}; - } else if constexpr (N == 3) { - return {a + b.x, a + b.y, a + b.z}; - } else if constexpr (N == 4) { - return {a + b.x, a + b.y, a + b.z, a + b.w}; - } -} -template -inline vec operator-(const vec& a, const vec& b) { - if constexpr (N == 1) { - return {a.x - b.x}; - } else if constexpr (N == 2) { - return {a.x - b.x, a.y - b.y}; - } else if constexpr (N == 3) { - return {a.x - b.x, a.y - b.y, a.z - b.z}; - } else if constexpr (N == 4) { - return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w}; - } -} -template -inline vec operator-(const vec& a, T1 b) { - if constexpr (N == 1) { - return {a.x - b}; - } else if constexpr (N == 2) { - return {a.x - b, a.y - b}; - } else if constexpr (N == 3) { - return {a.x - b, a.y - b, a.z - b}; - } else if constexpr (N == 4) { - return {a.x - b, a.y - b, a.z - b, a.w - b}; - } -} -template -inline vec operator-(T1 a, const vec& b) { - if constexpr (N == 1) { - return {a - b.x}; - } else if constexpr (N == 2) { - return {a - b.x, a - b.y}; - } else if constexpr (N == 3) { - return {a - b.x, a - b.y, a - b.z}; - } else if constexpr (N == 4) { - return {a - b.x, a - b.y, a - b.z, a - b.w}; - } -} -template -inline vec operator*(const vec& a, const vec& b) { - if constexpr (N == 1) { - return {a.x * b.x}; - } else if constexpr (N == 2) { - return {a.x * b.x, a.y * b.y}; - } else if constexpr (N == 3) { - return {a.x * b.x, a.y * b.y, a.z * b.z}; - } else if constexpr (N == 4) { - return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w}; - } -} -template -inline vec operator*(const vec& a, T1 b) { - if constexpr (N == 1) { - return {a.x * b}; - } else if constexpr (N == 2) { - return {a.x * b, a.y * b}; - } else if constexpr (N == 3) { - return {a.x * b, a.y * b, a.z * b}; - } else if constexpr (N == 4) { - return {a.x * b, a.y * b, a.z * b, a.w * b}; - } -} -template -inline vec operator*(T1 a, const vec& b) { - if constexpr (N == 1) { - return {a * b.x}; - } else if constexpr (N == 2) { - return {a * b.x, a * b.y}; - } else if constexpr (N == 3) { - return {a * b.x, a * b.y, a * b.z}; - } else if constexpr (N == 4) { - return {a * b.x, a * b.y, a * b.z, a * b.w}; - } -} -template -inline vec operator/(const vec& a, const vec& b) { - if constexpr (N == 1) { - return {a.x / b.x}; - } else if constexpr (N == 2) { - return {a.x / b.x, a.y / b.y}; - } else if constexpr (N == 3) { - return {a.x / b.x, a.y / b.y, a.z / b.z}; - } else if constexpr (N == 4) { - return {a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w}; - } -} -template -inline vec operator/(const vec& a, T1 b) { - if constexpr (N == 1) { - return {a.x / b}; - } else if constexpr (N == 2) { - return {a.x / b, a.y / b}; - } else if constexpr (N == 3) { - return {a.x / b, a.y / b, a.z / b}; - } else if constexpr (N == 4) { - return {a.x / b, a.y / b, a.z / b, a.w / b}; - } -} -template -inline vec operator/(T1 a, const vec& b) { - if constexpr (N == 1) { - return {a / b.x}; - } else if constexpr (N == 2) { - return {a / b.x, a / b.y}; - } else if constexpr (N == 3) { - return {a / b.x, a / b.y, a / b.z}; - } else if constexpr (N == 4) { - return {a / b.x, a / b.y, a / b.z, a / b.w}; - } -} - -// Vector assignments -template -inline vec& operator+=(vec& a, const vec& b) { - return a = a + b; -} -template -inline vec& operator+=(vec& a, T1 b) { - return a = a + b; -} -template -inline vec& operator-=(vec& a, const vec& b) { - return a = a - b; -} -template -inline vec& operator-=(vec& a, T1 b) { - return a = a - b; -} -template -inline vec& operator*=(vec& a, const vec& b) { - return a = a * b; -} -template -inline vec& operator*=(vec& a, T1 b) { - return a = a * b; -} -template -inline vec& operator/=(vec& a, const vec& b) { - return a = a / b; -} -template -inline vec& operator/=(vec& a, T1 b) { - return a = a / b; -} - -// Vector products and lengths. -template -inline T dot(const vec& a, const vec& b) { - if constexpr (N == 1) { - return a.x * b.x; - } else if constexpr (N == 2) { - return a.x * b.x + a.y * b.y; - } else if constexpr (N == 3) { - return a.x * b.x + a.y * b.y + a.z * b.z; - } else if constexpr (N == 4) { - return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; - } -} -template -inline T cross(const vec& a, const vec& b) { - return a.x * b.y - a.y * b.x; -} -template -inline vec cross(const vec& a, const vec& b) { - return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; -} -template -inline T angle(const vec& a, const vec& b) { - return acos(clamp(dot(normalize(a), normalize(b)), (T)-1, (T)1)); -} - -// Orthogonal vectors. -template -inline vec orthogonal(const vec& v) { - // http://lolengine.net/blog/2013/09/21/picking-orthogonal-vector-combing-coconuts) - return abs(v.x) > abs(v.z) ? vec{-v.y, v.x, 0} - : vec{0, -v.z, v.y}; -} -template -inline vec orthonormalize(const vec& a, const vec& b) { - return normalize(a - b * dot(a, b)); -} - -// Reflected and refracted vector. -template -inline vec reflect(const vec& w, const vec& n) { - return -w + 2 * dot(n, w) * n; -} -template -inline vec refract(const vec& w, const vec& n, T inv_eta) { - auto cosine = dot(n, w); - auto k = 1 + inv_eta * inv_eta * (cosine * cosine - 1); - if (k < 0) return {0, 0, 0}; // tir - return -w * inv_eta + (inv_eta * cosine - sqrt(k)) * n; -} - -template -inline T length(const vec& a) { - return sqrt(dot(a, a)); -} -template -inline T length_squared(const vec& a) { - return dot(a, a); -} -template -inline vec normalize(const vec& a) { - auto l = length(a); - return (l != 0) ? a / l : a; -} -template -inline T distance(const vec& a, const vec& b) { - return length(a - b); -} -template -inline T distance_squared(const vec& a, const vec& b) { - return dot(a - b, a - b); -} -template -inline T angle(const vec& a, const vec& b) { - return acos(clamp(dot(normalize(a), normalize(b)), (T)-1, (T)1)); -} - -template -inline vec slerp(const vec& a, const vec& b, T u) { - // https://en.wikipedia.org/wiki/Slerp - auto an = normalize(a), bn = normalize(b); - auto d = dot(an, bn); - if (d < 0) { - bn = -bn; - d = -d; - } - if (d > (T)0.9995) return normalize(an + u * (bn - an)); - auto th = acos(clamp(d, (T)-1, (T)1)); - if (th == 0) return an; - return an * (sin(th * (1 - u)) / sin(th)) + bn * (sin(th * u) / sin(th)); -} - -// Max element and clamp. -template -inline vec max(const vec& a, T b) { - if constexpr (N == 1) { - return {max(a.x, b)}; - } else if constexpr (N == 2) { - return {max(a.x, b), max(a.y, b)}; - } else if constexpr (N == 3) { - return {max(a.x, b), max(a.y, b), max(a.z, b)}; - } else if constexpr (N == 4) { - return {max(a.x, b), max(a.y, b), max(a.z, b), max(a.w, b)}; - } -} -template -inline vec min(const vec& a, T b) { - if constexpr (N == 1) { - return {min(a.x, b)}; - } else if constexpr (N == 2) { - return {min(a.x, b), min(a.y, b)}; - } else if constexpr (N == 3) { - return {min(a.x, b), min(a.y, b), min(a.z, b)}; - } else if constexpr (N == 4) { - return {min(a.x, b), min(a.y, b), min(a.z, b), min(a.w, b)}; - } -} -template -inline vec max(const vec& a, const vec& b) { - if constexpr (N == 1) { - return {max(a.x, b.x)}; - } else if constexpr (N == 2) { - return {max(a.x, b.x), max(a.y, b.y)}; - } else if constexpr (N == 3) { - return {max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)}; - } else if constexpr (N == 4) { - return {max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)}; - } -} -template -inline vec min(const vec& a, const vec& b) { - if constexpr (N == 1) { - return {min(a.x, b.x)}; - } else if constexpr (N == 2) { - return {min(a.x, b.x), min(a.y, b.y)}; - } else if constexpr (N == 3) { - return {min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)}; - } else if constexpr (N == 4) { - return {min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)}; - } -} -template -inline vec clamp(const vec& x, T min, T max) { - if constexpr (N == 1) { - return {clamp(x.x, min, max)}; - } else if constexpr (N == 2) { - return {clamp(x.x, min, max), clamp(x.y, min, max)}; - } else if constexpr (N == 3) { - return {clamp(x.x, min, max), clamp(x.y, min, max), clamp(x.z, min, max)}; - } else if constexpr (N == 4) { - return {clamp(x.x, min, max), clamp(x.y, min, max), clamp(x.z, min, max), - clamp(x.w, min, max)}; - } -} -template -inline vec lerp(const vec& a, const vec& b, T u) { - return a * (1 - u) + b * u; -} -template -inline vec lerp( - const vec& a, const vec& b, const vec& u) { - return a * (1 - u) + b * u; -} - -template -inline T max(const vec& a) { - if constexpr (N == 1) { - return a.x; - } else if constexpr (N == 2) { - return max(a.x, a.y); - } else if constexpr (N == 3) { - return max(max(a.x, a.y), a.z); - } else if constexpr (N == 4) { - return max(max(max(a.x, a.y), a.z), a.w); - } -} -template -inline T min(const vec& a) { - if constexpr (N == 1) { - return a.x; - } else if constexpr (N == 2) { - return min(a.x, a.y); - } else if constexpr (N == 3) { - return min(min(a.x, a.y), a.z); - } else if constexpr (N == 4) { - return min(min(min(a.x, a.y), a.z), a.w); - } -} -template -inline T sum(const vec& a) { - if constexpr (N == 1) { - return a.x; - } else if constexpr (N == 2) { - return a.x + a.y; - } else if constexpr (N == 3) { - return a.x + a.y + a.z; - } else if constexpr (N == 4) { - return a.x + a.y + a.z + a.w; - } -} -template -inline T mean(const vec& a) { - return sum(a) / N; -} - -// Functions applied to vector elements -template -inline vec abs(const vec& a) { - if constexpr (N == 1) { - return {abs(a.x)}; - } else if constexpr (N == 2) { - return {abs(a.x), abs(a.y)}; - } else if constexpr (N == 3) { - return {abs(a.x), abs(a.y), abs(a.z)}; - } else if constexpr (N == 4) { - return {abs(a.x), abs(a.y), abs(a.z), abs(a.w)}; - } -} -template -inline vec sqr(const vec& a) { - if constexpr (N == 1) { - return {sqr(a.x)}; - } else if constexpr (N == 2) { - return {sqr(a.x), sqr(a.y)}; - } else if constexpr (N == 3) { - return {sqr(a.x), sqr(a.y), sqr(a.z)}; - } else if constexpr (N == 4) { - return {sqr(a.x), sqr(a.y), sqr(a.z), sqr(a.w)}; - } -} -template -inline vec sqrt(const vec& a) { - if constexpr (N == 1) { - return {sqrt(a.x)}; - } else if constexpr (N == 2) { - return {sqrt(a.x), sqrt(a.y)}; - } else if constexpr (N == 3) { - return {sqrt(a.x), sqrt(a.y), sqrt(a.z)}; - } else if constexpr (N == 4) { - return {sqrt(a.x), sqrt(a.y), sqrt(a.z), sqrt(a.w)}; - } -} -template -inline vec exp(const vec& a) { - if constexpr (N == 1) { - return {exp(a.x)}; - } else if constexpr (N == 2) { - return {exp(a.x), exp(a.y)}; - } else if constexpr (N == 3) { - return {exp(a.x), exp(a.y), exp(a.z)}; - } else if constexpr (N == 4) { - return {exp(a.x), exp(a.y), exp(a.z), exp(a.w)}; - } -} -template -inline vec log(const vec& a) { - if constexpr (N == 1) { - return {log(a.x)}; - } else if constexpr (N == 2) { - return {log(a.x), log(a.y)}; - } else if constexpr (N == 3) { - return {log(a.x), log(a.y), log(a.z)}; - } else if constexpr (N == 4) { - return {log(a.x), log(a.y), log(a.z), log(a.w)}; - } -} -template -inline vec exp2(const vec& a) { - if constexpr (N == 1) { - return {exp2(a.x)}; - } else if constexpr (N == 2) { - return {exp2(a.x), exp2(a.y)}; - } else if constexpr (N == 3) { - return {exp2(a.x), exp2(a.y), exp2(a.z)}; - } else if constexpr (N == 4) { - return {exp2(a.x), exp2(a.y), exp2(a.z), exp2(a.w)}; - } -} -template -inline vec log2(const vec& a) { - if constexpr (N == 1) { - return {log2(a.x)}; - } else if constexpr (N == 2) { - return {log2(a.x), log2(a.y)}; - } else if constexpr (N == 3) { - return {log2(a.x), log2(a.y), log2(a.z)}; - } else if constexpr (N == 4) { - return {log2(a.x), log2(a.y), log2(a.z), log2(a.w)}; - } -} -template -inline vec pow(const vec& a, T b) { - if constexpr (N == 1) { - return {pow(a.x, b)}; - } else if constexpr (N == 2) { - return {pow(a.x, b), pow(a.y, b)}; - } else if constexpr (N == 3) { - return {pow(a.x, b), pow(a.y, b), pow(a.z, b)}; - } else if constexpr (N == 4) { - return {pow(a.x, b), pow(a.y, b), pow(a.z, b), pow(a.w, b)}; - } -} -template -inline vec pow(const vec& a, const vec& b) { - if constexpr (N == 1) { - return {pow(a.x, b.x)}; - } else if constexpr (N == 2) { - return {pow(a.x, b.x), pow(a.y, b.y)}; - } else if constexpr (N == 3) { - return {pow(a.x, b.x), pow(a.y, b.y), pow(a.z, b.z)}; - } else if constexpr (N == 4) { - return {pow(a.x, b.x), pow(a.y, b.y), pow(a.z, b.z), pow(a.w, b.w)}; - } -} -template -inline vec gain(const vec& a, T b) { - if constexpr (N == 1) { - return {gain(a.x, b)}; - } else if constexpr (N == 2) { - return {gain(a.x, b), gain(a.y, b)}; - } else if constexpr (N == 3) { - return {gain(a.x, b), gain(a.y, b), gain(a.z, b)}; - } else if constexpr (N == 4) { - return {gain(a.x, b), gain(a.y, b), gain(a.z, b), gain(a.w, b)}; - } -} -// template -// inline void swap(vec& a, vec& b) { -// std::swap(a, b); -// } -template -inline bool isfinite(const vec& a) { - if constexpr (N == 1) { - return isfinite(a.x); - } else if constexpr (N == 2) { - return isfinite(a.x) && isfinite(a.y); - } else if constexpr (N == 3) { - return isfinite(a.x) && isfinite(a.y) && isfinite(a.z); - } else if constexpr (N == 4) { - return isfinite(a.x) && isfinite(a.y) && isfinite(a.z) && isfinite(a.w); - } -} - -// Quaternion operatons represented as xi + yj + zk + w -// const auto identity_quat4f = vec4f{0, 0, 0, 1}; -template -inline vec quat_mul(const vec& a, T b) { - return {a.x * b, a.y * b, a.z * b, a.w * b}; -} -template -inline vec quat_mul(const vec& a, const vec& b) { - return {a.x * b.w + a.w * b.x + a.y * b.w - a.z * b.y, - a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z, - a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x, - a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z}; -} -template -inline vec quat_conjugate(const vec& a) { - return {-a.x, -a.y, -a.z, a.w}; -} -template -inline vec quat_inverse(const vec& a) { - return quat_conjugate(a) / dot(a, a); -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// MATRICES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Small Fixed-size matrices stored in column major format. -template -inline vec& mat::operator[](int i) { - return (&x)[i]; -} -template -inline const vec& mat::operator[](int i) const { - return (&x)[i]; -} - -// Small Fixed-size matrices stored in column major format. -template -inline vec& mat::operator[](int i) { - return (&x)[i]; -} -template -inline const vec& mat::operator[](int i) const { - return (&x)[i]; -} - -// Small Fixed-size matrices stored in column major format. -template -inline vec& mat::operator[](int i) { - return (&x)[i]; -} -template -inline const vec& mat::operator[](int i) const { - return (&x)[i]; -} - -// Small Fixed-size matrices stored in column major format. -template -inline vec& mat::operator[](int i) { - return (&x)[i]; -} -template -inline const vec& mat::operator[](int i) const { - return (&x)[i]; -} - -// Matrix comparisons. -template -inline bool operator==(const mat& a, const mat& b) { - if constexpr (N == 1) { - return a.x == b.x; - } else if constexpr (N == 2) { - return a.x == b.x && a.y == b.y; - } else if constexpr (N == 3) { - return a.x == b.x && a.y == b.y && a.z == b.z; - } else if constexpr (N == 4) { - return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; - } -} -template -inline bool operator!=(const mat& a, const mat& b) { - return !(a == b); -} - -// Matrix operations. -template -inline mat operator+(const mat& a, const mat& b) { - if constexpr (N == 1) { - return {a.x + b.x}; - } else if constexpr (N == 2) { - return {a.x + b.x, a.y + b.y}; - } else if constexpr (N == 3) { - return {a.x + b.x, a.y + b.y, a.z + b.z}; - } else if constexpr (N == 4) { - return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w}; - } -} -template -inline mat operator*(const mat& a, T1 b) { - if constexpr (N == 1) { - return {a.x * b}; - } else if constexpr (N == 2) { - return {a.x * b, a.y * b}; - } else if constexpr (N == 3) { - return {a.x * b, a.y * b, a.z * b}; - } else if constexpr (N == 4) { - return {a.x * b, a.y * b, a.z * b, a.w * b}; - } -} -template -inline vec operator*(const mat& a, const vec& b) { - if constexpr (N == 1) { - return a.x * b.x; - } else if constexpr (N == 2) { - return a.x * b.x + a.y * b.y; - } else if constexpr (N == 3) { - return a.x * b.x + a.y * b.y + a.z * b.z; - } else if constexpr (N == 4) { - return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; - } -} -template -inline vec operator*(const vec& a, const mat& b) { - if constexpr (N == 1) { - return {dot(a, b.x)}; - } else if constexpr (N == 2) { - return {dot(a, b.x), dot(a, b.y)}; - } else if constexpr (N == 3) { - return {dot(a, b.x), dot(a, b.y), dot(a, b.z)}; - } else if constexpr (N == 4) { - return {dot(a, b.x), dot(a, b.y), dot(a, b.z), dot(a, b.w)}; - } -} -template -inline mat operator*(const mat& a, const mat& b) { - if constexpr (N == 1) { - return {a * b.x}; - } else if constexpr (N == 2) { - return {a * b.x, a * b.y}; - } else if constexpr (N == 3) { - return {a * b.x, a * b.y, a * b.z}; - } else if constexpr (N == 4) { - return {a * b.x, a * b.y, a * b.z, a * b.w}; - } -} - -// Matrix assignments. -template -inline mat& operator+=(mat& a, const mat& b) { - return a = a + b; -} -template -inline mat& operator*=(mat& a, const mat& b) { - return a = a * b; -} -template -inline mat& operator*=(mat& a, T1 b) { - return a = a * b; -} - -// Matrix diagonals and transposes. -template -inline vec diagonal(const mat& a) { - if constexpr (N == 1) { - return {a.x.x}; - } else if constexpr (N == 2) { - return {a.x.x, a.y.y}; - } else if constexpr (N == 3) { - return {a.x.x, a.y.y, a.z.z}; - } else if constexpr (N == 4) { - return {a.x.x, a.y.y, a.z.z, a.w.w}; - } -} -template -inline mat transpose(const mat& a) { - if constexpr (N == 1) { - return {{a.x.x}}; - } else if constexpr (N == 2) { - return {{a.x.x, a.y.x}, {a.x.y, a.y.y}}; - } else if constexpr (N == 3) { - return { - {a.x.x, a.y.x, a.z.x}, - {a.x.y, a.y.y, a.z.y}, - {a.x.z, a.y.z, a.z.z}, - }; - } else if constexpr (N == 4) { - return { - {a.x.x, a.y.x, a.z.x, a.w.x}, - {a.x.y, a.y.y, a.z.y, a.w.y}, - {a.x.z, a.y.z, a.z.z, a.w.z}, - {a.x.w, a.y.w, a.z.w, a.w.w}, - }; - } -} - -// Matrix adjoints, determinants and inverses. -template -inline T determinant(const mat& a) { - if constexpr (N == 1) { - return a.x; - } else if constexpr (N == 2) { - return cross(a.x, a.y); - } else if constexpr (N == 3) { - return dot(a.x, cross(a.y, a.z)); - } else if constexpr (N == 4) { - return 0; // TODO - } -} -template -inline mat adjoint(const mat& a) { - if constexpr (N == 1) { - return {{a.x.x}}; - } else if constexpr (N == 2) { - return {{a.y.y, -a.x.y}, {-a.y.x, a.x.x}}; - } else if constexpr (N == 3) { - return transpose( - mat{cross(a.y, a.z), cross(a.z, a.x), cross(a.x, a.y)}); - } else if constexpr (N == 4) { - return {}; // TODO - } -} -template -inline mat inverse(const mat& a) { - return adjoint(a) * (1 / determinant(a)); -} - -// Constructs a basis from a direction -template -inline mat basis_fromz(const vec& v) { - // https://graphics.pixar.com/library/OrthonormalB/paper.pdf - if constexpr (std::is_same_v) { - auto z = normalize(v); - auto sign = copysignf(1.0f, z.z); - auto a = -1.0f / (sign + z.z); - auto b = z.x * z.y * a; - auto x = vec{1.0f + sign * z.x * z.x * a, sign * b, -sign * z.x}; - auto y = vec{b, sign + z.y * z.y * a, -z.y}; - return {x, y, z}; - } else if constexpr (std::is_same_v) { - // TODO: double - return {}; - } -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// RIGID BODY TRANSFORMS/FRAMES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Rigid frames stored as a column-major affine transform matrix. -template -inline vec& frame::operator[](int i) { - return (&x)[i]; -} -template -inline const vec& frame::operator[](int i) const { - return (&x)[i]; -} - -// Rigid frames stored as a column-major affine transform matrix. -template -inline vec& frame::operator[](int i) { - return (&x)[i]; -} -template -inline const vec& frame::operator[](int i) const { - return (&x)[i]; -} - -// Frame properties -template -inline mat rotation(const frame& a) { - if constexpr (N == 2) { - return {a.x, a.y}; - } else if constexpr (N == 3) { - return {a.x, a.y, a.z}; - } -} -template -inline vec translation(const frame& a) { - if constexpr (N == 2) { - return a.o; - } else if constexpr (N == 3) { - return a.o; - } -} - -// Frame construction -template -inline frame make_frame(const mat& m, const vec& t) { - if constexpr (N == 2) { - return {m.x, m.y, t}; - } else if constexpr (N == 3) { - return {m.x, m.y, m.z, t}; - } -} - -// Frame/mat conversion -template -inline frame mat_to_frame(const mat& m) { - constexpr auto N = N_ - 1; - if constexpr (N == 2) { - return {{m.x.x, m.x.y}, {m.y.x, m.y.y}, {m.z.x, m.z.y}}; - } else if constexpr (N == 3) { - return {{m.x.x, m.x.y, m.x.z}, {m.y.x, m.y.y, m.y.z}, {m.z.x, m.z.y, m.z.z}, - {m.w.x, m.w.y, m.w.z}}; - } -} -template -inline mat frame_to_mat(const frame& f) { - if constexpr (N == 2) { - return {{f.x.x, f.x.y, 0}, {f.y.x, f.y.y, 0}, {f.o.x, f.o.y, 1}}; - } else if constexpr (N == 3) { - return {{f.x.x, f.x.y, f.x.z, 0}, {f.y.x, f.y.y, f.y.z, 0}, - {f.z.x, f.z.y, f.z.z, 0}, {f.o.x, f.o.y, f.o.z, 1}}; - } -} - -// Frame comparisons. -template -inline bool operator==(const frame& a, const frame& b) { - if constexpr (N == 2) { - return a.x == b.x && a.y == b.y && a.o == b.o; - } else if constexpr (N == 3) { - return a.x == b.x && a.y == b.y && a.z == b.z && a.o == b.o; - } -} -template -inline bool operator!=(const frame& a, const frame& b) { - return !(a == b); -} - -// Frame composition, equivalent to affine matrix product. -template -inline frame operator*(const frame& a, const frame& b) { - return make_frame(rotation(a) * rotation(b), rotation(a) * b.o + a.o); -} -template -inline frame& operator*=(frame& a, const frame& b) { - return a = a * b; -} - -// Frame inverse, equivalent to rigid affine inverse. -template -inline frame inverse(const frame& a, bool non_rigid) { - if (non_rigid) { - auto minv = inverse(rotation(a)); - return make_frame(minv, -(minv * a.o)); - } else { - auto minv = transpose(rotation(a)); - return make_frame(minv, -(minv * a.o)); - } -} - -// Frame construction from axis. -template -inline frame frame_fromz(const vec& o, const vec& v) { - // https://graphics.pixar.com/library/OrthonormalB/paper.pdf - if constexpr (std::is_same_v) { - auto z = normalize(v); - auto sign = copysignf(1.0f, z.z); - auto a = -1.0f / (sign + z.z); - auto b = z.x * z.y * a; - auto x = vec{1.0f + sign * z.x * z.x * a, sign * b, -sign * z.x}; - auto y = vec{b, sign + z.y * z.y * a, -z.y}; - return {x, y, z, o}; - } else if constexpr (std::is_same_v) { - // TODO: double - return {}; - } -} -template -inline frame frame_fromzx( - const vec& o, const vec& z_, const vec& x_) { - auto z = normalize(z_); - auto x = orthonormalize(x_, z); - auto y = normalize(cross(z, x)); - return {x, y, z, o}; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// QUATERNIONS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Quaternion operatons -template -inline quat operator+(const quat& a, const quat& b) { - return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w}; -} -template -inline quat operator*(const quat& a, T b) { - return {a.x * b, a.y * b, a.z * b, a.w * b}; -} -template -inline quat operator/(const quat& a, T b) { - return {a.x / b, a.y / b, a.z / b, a.w / b}; -} -template -inline quat operator*(const quat& a, const quat& b) { - return {a.x * b.w + a.w * b.x + a.y * b.w - a.z * b.y, - a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z, - a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x, - a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z}; -} - -// Quaterion operations -template -inline T dot(const quat& a, const quat& b) { - return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; -} -template -inline T length(const quat& a) { - return sqrt(dot(a, a)); -} -template -inline quat normalize(const quat& a) { - auto l = length(a); - return (l != 0) ? a / l : a; -} -template -inline quat conjugate(const quat& a) { - return {-a.x, -a.y, -a.z, a.w}; -} -template -inline quat inverse(const quat& a) { - return conjugate(a) / dot(a, a); -} -template -inline T uangle(const quat& a, const quat& b) { - auto d = dot(a, b); - return d > 1 ? 0 : acos(d < -1 ? -1 : d); -} -template -inline quat lerp(const quat& a, const quat& b, T t) { - return a * (1 - t) + b * t; -} -template -inline quat nlerp(const quat& a, const quat& b, T t) { - return normalize(lerp(a, b, t)); -} -template -inline quat slerp(const quat& a, const quat& b, T t) { - auto th = uangle(a, b); - return th == 0 - ? a - : a * (sin(th * (1 - t)) / sin(th)) + b * (sin(th * t) / sin(th)); -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// TRANSFORMS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Transforms points, vectors and directions by matrices. -template -inline vec transform_point(const mat& a, const vec& b) { - if constexpr (N == 2) { - auto tvb = a * vec{b.x, b.y, 1}; - return vec{tvb.x, tvb.y} / tvb.z; - } else if constexpr (N == 3) { - auto tvb = a * vec{b.x, b.y, b.z, 1}; - return vec{tvb.x, tvb.y, tvb.z} / tvb.w; - } -} -template -inline vec transform_vector(const mat& a, const vec& b) { - if constexpr (N == 2) { - auto tvb = a * vec{b.x, b.y, 0}; - return vec{tvb.x, tvb.y} / tvb.z; - } else if constexpr (N == 3) { - auto tvb = a * vec{b.x, b.y, b.z, 0}; - return vec{tvb.x, tvb.y, tvb.z} / tvb.w; - } -} -template -inline vec transform_direction( - const mat& a, const vec& b) { - return normalize(transform_vector(a, b)); -} -template -inline vec transform_normal(const mat& a, const vec& b) { - return normalize(transform_vector(transpose(inverse(a)), b)); -} -template -inline vec transform_vector(const mat& a, const vec& b) { - return a * b; -} -template -inline vec transform_direction(const mat& a, const vec& b) { - return normalize(transform_vector(a, b)); -} -template -inline vec transform_normal(const mat& a, const vec& b) { - return normalize(transform_vector(transpose(inverse(a)), b)); -} - -// Transforms points, vectors and directions by frames. -template -inline vec transform_point(const frame& a, const vec& b) { - if constexpr (N == 2) { - return a.x * b.x + a.y * b.y + a.o; - } else if constexpr (N == 3) { - return a.x * b.x + a.y * b.y + a.z * b.z + a.o; - } -} -template -inline vec transform_vector(const frame& a, const vec& b) { - if constexpr (N == 2) { - return a.x * b.x + a.y * b.y; - } else if constexpr (N == 3) { - return a.x * b.x + a.y * b.y + a.z * b.z; - } -} -template -inline vec transform_direction(const frame& a, const vec& b) { - return normalize(transform_vector(a, b)); -} -template -inline vec transform_normal( - const frame& a, const vec& b, bool non_rigid) { - if (non_rigid) { - return transform_normal(rotation(a), b); - } else { - return normalize(transform_vector(a, b)); - } -} - -// Transforms points, vectors and directions by frames. -template -inline vec transform_point_inverse( - const frame& a, const vec& b) { - if constexpr (N == 2) { - return {dot(a.x, (b - a.o)), dot(a.y, (b - a.o))}; - } else if constexpr (N == 3) { - return {dot(a.x, (b - a.o)), dot(a.y, (b - a.o)), dot(a.z, (b - a.o))}; - } -} -template -inline vec transform_vector_inverse( - const frame& a, const vec& b) { - if constexpr (N == 2) { - return {dot(a.x, b), dot(a.y, b)}; - } else if constexpr (N == 3) { - return {dot(a.x, b), dot(a.y, b), dot(a.z, b)}; - } -} -template -inline vec transform_direction_inverse( - const frame& a, const vec& b) { - return normalize(transform_vector_inverse(a, b)); -} - -// Translation, scaling and rotations transforms. -template -inline frame translation_frame(const vec& a) { - return {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, a}; -} -template -inline frame scaling_frame(const vec& a) { - return {{a.x, 0, 0}, {0, a.y, 0}, {0, 0, a.z}, {0, 0, 0}}; -} -template -inline frame rotation_frame(const vec& axis, T angle) { - auto s = sin(angle), c = cos(angle); - auto vv = normalize(axis); - return {{c + (1 - c) * vv.x * vv.x, (1 - c) * vv.x * vv.y + s * vv.z, - (1 - c) * vv.x * vv.z - s * vv.y}, - {(1 - c) * vv.x * vv.y - s * vv.z, c + (1 - c) * vv.y * vv.y, - (1 - c) * vv.y * vv.z + s * vv.x}, - {(1 - c) * vv.x * vv.z + s * vv.y, (1 - c) * vv.y * vv.z - s * vv.x, - c + (1 - c) * vv.z * vv.z}, - {0, 0, 0}}; -} -template -inline frame rotation_frame(const vec& quat) { - auto v = quat; - return {{v.w * v.w + v.x * v.x - v.y * v.y - v.z * v.z, - (v.x * v.y + v.z * v.w) * 2, (v.z * v.x - v.y * v.w) * 2}, - {(v.x * v.y - v.z * v.w) * 2, - v.w * v.w - v.x * v.x + v.y * v.y - v.z * v.z, - (v.y * v.z + v.x * v.w) * 2}, - {(v.z * v.x + v.y * v.w) * 2, (v.y * v.z - v.x * v.w) * 2, - v.w * v.w - v.x * v.x - v.y * v.y + v.z * v.z}, - {0, 0, 0}}; -} -template -inline frame rotation_frame(const quat& quat) { - auto v = quat; - return {{v.w * v.w + v.x * v.x - v.y * v.y - v.z * v.z, - (v.x * v.y + v.z * v.w) * 2, (v.z * v.x - v.y * v.w) * 2}, - {(v.x * v.y - v.z * v.w) * 2, - v.w * v.w - v.x * v.x + v.y * v.y - v.z * v.z, - (v.y * v.z + v.x * v.w) * 2}, - {(v.z * v.x + v.y * v.w) * 2, (v.y * v.z - v.x * v.w) * 2, - v.w * v.w - v.x * v.x - v.y * v.y + v.z * v.z}, - {0, 0, 0}}; -} -template -inline frame rotation_frame(const mat& rot) { - return {rot.x, rot.y, rot.z, {0, 0, 0}}; -} - -// Lookat frame. Z-axis can be inverted with inv_xz. -template -inline frame lookat_frame(const vec& eye, const vec& center, - const vec& up, bool inv_xz) { - auto w = normalize(eye - center); - auto u = normalize(cross(up, w)); - auto v = normalize(cross(w, u)); - if (inv_xz) { - w = -w; - u = -u; - } - return {u, v, w, eye}; -} - -// OpenGL frustum, ortho and perspecgive matrices. -template -inline mat frustum_mat(T l, T r, T b, T t, T n, T f) { - return {{2 * n / (r - l), 0, 0, 0}, {0, 2 * n / (t - b), 0, 0}, - {(r + l) / (r - l), (t + b) / (t - b), -(f + n) / (f - n), -1}, - {0, 0, -2 * f * n / (f - n), 0}}; -} -template -inline mat ortho_mat(T l, T r, T b, T t, T n, T f) { - return {{2 / (r - l), 0, 0, 0}, {0, 2 / (t - b), 0, 0}, - {0, 0, -2 / (f - n), 0}, - {-(r + l) / (r - l), -(t + b) / (t - b), -(f + n) / (f - n), 1}}; -} -template -inline mat ortho2d_mat(T left, T right, T bottom, T top) { - return ortho_mat(left, right, bottom, top, -1, 1); -} -template -inline mat ortho_mat(T xmag, T ymag, T near, T far) { - return {{1 / xmag, 0, 0, 0}, {0, 1 / ymag, 0, 0}, {0, 0, 2 / (near - far), 0}, - {0, 0, (far + near) / (near - far), 1}}; -} -template -inline mat perspective_mat(T fovy, T aspect, T near, T far) { - auto tg = tan(fovy / 2); - return {{1 / (aspect * tg), 0, 0, 0}, {0, 1 / tg, 0, 0}, - {0, 0, (far + near) / (near - far), -1}, - {0, 0, 2 * far * near / (near - far), 0}}; -} -template -inline mat perspective_mat(T fovy, T aspect, T near) { - auto tg = tan(fovy / 2); - return {{1 / (aspect * tg), 0, 0, 0}, {0, 1 / tg, 0, 0}, {0, 0, -1, -1}, - {0, 0, 2 * near, 0}}; -} - -// Rotation conversions. -template -inline pair, T> rotation_axisangle(const vec& quat) { - return {normalize(vec{quat.x, quat.y, quat.z}), 2 * acos(quat.w)}; -} -template -inline vec rotation_quat(const vec& axis, T angle) { - auto len = length(axis); - if (len == 0) return {0, 0, 0, 1}; - return vec{sin(angle / 2) * axis.x / len, sin(angle / 2) * axis.y / len, - sin(angle / 2) * axis.z / len, cos(angle / 2)}; -} -template -inline vec rotation_quat(const vec& axisangle) { - return rotation_quat( - vec{axisangle.x, axisangle.y, axisangle.z}, axisangle.w); -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// USER INTERFACE UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Computes the image uv coordinates corresponding to the view parameters. -// Returns negative coordinates if out of the image. -template -inline vec image_coords(const vec& mouse_pos, - const vec& center, T scale, const vec& txt_size) { - auto xyf = (mouse_pos - center) / scale; - return vec{(int)round(xyf.x + txt_size.x / (T)2), - (int)round(xyf.y + txt_size.y / (T)2)}; -} - -// Center image and autofit. Returns center and scale. -template -inline pair, T> camera_imview(const vec& center, T scale, - const vec& imsize, const vec& winsize, bool zoom_to_fit) { - if (zoom_to_fit) { - return {{(T)winsize.x / 2, (T)winsize.y / 2}, - min(winsize.x / (T)imsize.x, winsize.y / (T)imsize.y)}; - } else { - return {{(winsize.x >= imsize.x * scale) ? (T)winsize.x / 2 : center.x, - (winsize.y >= imsize.y * scale) ? (T)winsize.y / 2 : center.y}, - scale}; - } -} - -// Turntable for UI navigation. Returns from and to. -template -inline pair, vec> camera_turntable(const vec& from_, - const vec& to_, const vec& up, const vec& rotate, T dolly, - const vec& pan) { - // copy values - auto from = from_, to = to_; - - // rotate if necessary - if (rotate != vec{0, 0}) { - auto z = normalize(to - from); - auto lz = length(to - from); - auto phi = atan2(z.z, z.x) + rotate.x; - auto theta = acos(z.y) + rotate.y; - theta = clamp(theta, (T)0.001, (T)pi - (T)0.001); - auto nz = vec{sin(theta) * cos(phi) * lz, cos(theta) * lz, - sin(theta) * sin(phi) * lz}; - from = to - nz; - } - - // dolly if necessary - if (dolly != 0) { - auto z = normalize(to - from); - auto lz = max((T)0.001, length(to - from) * (1 + dolly)); - z *= lz; - from = to - z; - } - - // pan if necessary - if (pan != vec{0, 0}) { - auto z = normalize(to - from); - auto x = normalize(cross(up, z)); - auto y = normalize(cross(z, x)); - auto t = vec{pan.x * x.x + pan.y * y.x, pan.x * x.y + pan.y * y.y, - pan.x * x.z + pan.y * y.z}; - from += t; - to += t; - } - - // done - return {from, to}; -} - -// Turntable for UI navigation. Returns frame and focus. -template -inline pair, T> camera_turntable(const frame& frame_, T focus, - const vec& rotate, T dolly, const vec& pan) { - // copy values - auto frame = frame_; - - // rotate if necessary - if (rotate != vec{0, 0}) { - auto phi = atan2(frame.z.z, frame.z.x) + rotate.x; - auto theta = acos(frame.z.y) + rotate.y; - theta = clamp(theta, (T)0.001, (T)pi - (T)0.001); - auto new_z = vec{ - sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi)}; - auto new_center = frame.o - frame.z * focus; - auto new_o = new_center + new_z * focus; - frame = lookat_frame(new_o, new_center, {0, 1, 0}); - focus = length(new_o - new_center); - } - - // pan if necessary - if (dolly != 0) { - auto c = frame.o - frame.z * focus; - focus = max(focus * (1 + dolly), (T)0.001); - frame.o = c + frame.z * focus; - } - - // pan if necessary - if (pan != vec{0, 0}) { - frame.o += frame.x * pan.x + frame.y * pan.y; - } - - // done - return {frame, focus}; -} - -// FPS camera for UI navigation for a frame parametrization. Returns frame. -template -inline frame camera_fpscam(const frame& frame, - const vec& transl, const vec& rotate) { - // https://gamedev.stackexchange.com/questions/30644/how-to-keep-my-quaternion-using-fps-camera-from-tilting-and-messing-up - auto y = vec{0, 1, 0}; - auto z = orthonormalize(frame.z, y); - auto x = cross(y, z); - - auto rot = rotation_frame(vec{1, 0, 0}, rotate.y) * - yocto::frame{frame.x, frame.y, frame.z, vec{0, 0, 0}} * - rotation_frame(vec{0, 1, 0}, rotate.x); - auto pos = frame.o + transl.x * x + transl.y * y + transl.z * z; - - return {rot.x, rot.y, rot.z, pos}; -} - -// Computes the image uv coordinates corresponding to the view parameters. -// Returns negative coordinates if out of the image. -template -inline vec2i get_image_coords(const vec& mouse_pos, - const vec& center, T scale, const vec& txt_size) { - auto xyf = (mouse_pos - center) / scale; - return vec2i{(int)round(xyf.x + txt_size.x / (T)2), - (int)round(xyf.y + txt_size.y / (T)2)}; -} - -// Center image and autofit. -template -inline void update_imview(vec& center, T& scale, const vec& imsize, - const vec& winsize, bool zoom_to_fit) { - if (zoom_to_fit) { - scale = min(winsize.x / (T)imsize.x, winsize.y / (T)imsize.y); - center = {(T)winsize.x / 2, (T)winsize.y / 2}; - } else { - if (winsize.x >= imsize.x * scale) center.x = (T)winsize.x / 2; - if (winsize.y >= imsize.y * scale) center.y = (T)winsize.y / 2; - } -} - -// Turntable for UI navigation. -template -inline void update_turntable(vec& from, vec& to, vec& up, - const vec& rotate, T dolly, const vec& pan) { - // rotate if necessary - if (rotate != vec{0, 0}) { - auto z = normalize(to - from); - auto lz = length(to - from); - auto phi = atan2(z.z, z.x) + rotate.x; - auto theta = acos(z.y) + rotate.y; - theta = clamp(theta, (T)0.001, (T)pi - (T)0.001); - auto nz = vec{sin(theta) * cos(phi) * lz, cos(theta) * lz, - sin(theta) * sin(phi) * lz}; - from = to - nz; - } - - // dolly if necessary - if (dolly != 0) { - auto z = normalize(to - from); - auto lz = max(0.001f, length(to - from) * (1 + dolly)); - z *= lz; - from = to - z; - } - - // pan if necessary - if (pan != vec{0, 0}) { - auto z = normalize(to - from); - auto x = normalize(cross(up, z)); - auto y = normalize(cross(z, x)); - auto t = vec{pan.x * x.x + pan.y * y.x, pan.x * x.y + pan.y * y.y, - pan.x * x.z + pan.y * y.z}; - from += t; - to += t; - } -} - -// Turntable for UI navigation. -template -inline void update_turntable(frame& frame, T& focus, - const vec& rotate, T dolly, const vec& pan) { - // rotate if necessary - if (rotate != vec{0, 0}) { - auto phi = atan2(frame.z.z, frame.z.x) + rotate.x; - auto theta = acos(frame.z.y) + rotate.y; - theta = clamp(theta, (T)0.001, (T)pi - (T)0.001); - auto new_z = vec{ - sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi)}; - auto new_center = frame.o - frame.z * focus; - auto new_o = new_center + new_z * focus; - frame = lookat_frame(new_o, new_center, {0, 1, 0}); - focus = length(new_o - new_center); - } - - // pan if necessary - if (dolly != 0) { - auto c = frame.o - frame.z * focus; - focus = max(focus * (1 + dolly), (T)0.001); - frame.o = c + frame.z * focus; - } - - // pan if necessary - if (pan != vec{0, 0}) { - frame.o += frame.x * pan.x + frame.y * pan.y; - } -} - -// FPS camera for UI navigation for a frame parametrization. -template -inline void update_fpscam( - frame& frame, const vec& transl, const vec& rotate) { - // https://gamedev.stackexchange.com/questions/30644/how-to-keep-my-quaternion-using-fps-camera-from-tilting-and-messing-up - auto y = vec{0, 1, 0}; - auto z = orthonormalize(frame.z, y); - auto x = cross(y, z); - - auto rot = rotation_frame(vec{1, 0, 0}, rotate.y) * - yocto::frame{frame.x, frame.y, frame.z, vec{0, 0, 0}} * - rotation_frame(vec{0, 1, 0}, rotate.x); - auto pos = frame.o + transl.x * x + transl.y * y + transl.z * z; - - frame = {rot.x, rot.y, rot.z, pos}; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// PYTHON-LIKE ITERATORS -// ----------------------------------------------------------------------------- -namespace yocto { - -// Python `range()` equivalent. Construct an object to iterate over a sequence. -template -constexpr auto range(T max) { - return range((T)0, max); -} -template -constexpr auto range(T min, T max) { - struct range_iterator { - T index; - void operator++() { ++index; } - bool operator!=(const range_iterator& other) const { - return index != other.index; - } - T operator*() const { return index; } - }; - struct range_helper { - T begin_ = 0, end_ = 0; - range_iterator begin() const { return {begin_}; } - range_iterator end() const { return {end_}; } - }; - return range_helper{min, max}; -} -template -constexpr auto range(T min, T max, T step) { - struct range_iterator { - T index; - T step; - void operator++() { index += step; } - bool operator!=(const range_iterator& other) const { - return index != other.index; - } - T operator*() const { return index; } - }; - struct range_helper { - T begin_ = 0, end_ = 0, step_ = 0; - range_iterator begin() const { return {begin_, step_}; } - range_iterator end() const { - return {begin_ + ((end_ - begin_) / step_) * step_, step_}; - } - }; - return range_helper{min, max, step}; -} - -// Python enumerate -template -constexpr auto enumerate(const Sequence& sequence, T start) { - using Iterator = typename Sequence::const_iterator; - using Reference = typename Sequence::const_reference; - struct enumerate_iterator { - T index; - Iterator iterator; - bool operator!=(const enumerate_iterator& other) const { - return index != other.index; - } - void operator++() { - ++index; - ++iterator; - } - pair operator*() const { return {index, *iterator}; } - }; - struct enumerate_helper { - const Sequence& sequence; - T begin_, end_; - auto begin() { return enumerate_iterator{begin_, std::begin(sequence)}; } - auto end() { return enumerate_iterator{end_, std::end(sequence)}; } - }; - return enumerate_helper{sequence, 0, size(sequence)}; -} - -// Python enumerate -template -constexpr auto enumerate(Sequence& sequence, T start) { - using Iterator = typename Sequence::iterator; - using Reference = typename Sequence::reference; - struct enumerate_iterator { - T index; - Iterator iterator; - bool operator!=(const enumerate_iterator& other) const { - return index != other.index; - } - void operator++() { - ++index; - ++iterator; - } - pair operator*() const { return {index, *iterator}; } - }; - struct enumerate_helper { - Sequence& sequence; - T begin_, end_; - auto begin() { return enumerate_iterator{begin_, std::begin(sequence)}; } - auto end() { return enumerate_iterator{end_, std::end(sequence)}; } - }; - return enumerate_helper{sequence, 0, size(sequence)}; -} - -// Python zip -template -constexpr auto zip(const Sequence1& sequence1, const Sequence2& sequence2) { - using Iterator1 = typename Sequence1::const_iterator; - using Reference1 = typename Sequence1::const_reference; - using Iterator2 = typename Sequence2::const_iterator; - using Reference2 = typename Sequence2::const_reference; - struct zip_iterator { - Iterator1 iterator1; - Iterator2 iterator2; - bool operator!=(const zip_iterator& other) const { - return iterator1 != other.iterator1; - } - void operator++() { - ++iterator1; - ++iterator2; - } - pair operator*() const { - return {*iterator1, *iterator2}; - } - }; - struct zip_helper { - const Sequence1& sequence1; - const Sequence2& sequence2; - auto begin() { - return zip_iterator{std::begin(sequence1), std::begin(sequence2)}; - } - auto end() { - return zip_iterator{std::end(sequence1), std::end(sequence2)}; - } - }; - return zip_helper{sequence1, sequence2}; -} - -// Python zip -template -constexpr auto zip(Sequence1& sequence1, Sequence2& sequence2) { - using Iterator1 = typename Sequence1::iterator; - using Reference1 = typename Sequence1::reference; - using Iterator2 = typename Sequence2::iterator; - using Reference2 = typename Sequence2::reference; - struct zip_iterator { - Iterator1 iterator1; - Iterator2 iterator2; - bool operator!=(const zip_iterator& other) const { - return iterator1 != other.iterator1; - } - void operator++() { - ++iterator1; - ++iterator2; - } - pair operator*() const { - return {*iterator1, *iterator2}; - } - }; - struct zip_helper { - Sequence1& sequence1; - Sequence2& sequence2; - auto begin() { - return zip_iterator{std::begin(sequence1), std::begin(sequence2)}; - } - auto end() { - return zip_iterator{std::end(sequence1), std::end(sequence2)}; - } - }; - return zip_helper{sequence1, sequence2}; -} - -// Python zip -template -constexpr auto zip(const Sequence1& sequence1, Sequence2& sequence2) { - using Iterator1 = typename Sequence1::const_iterator; - using Reference1 = typename Sequence1::const_reference; - using Iterator2 = typename Sequence2::iterator; - using Reference2 = typename Sequence2::reference; - struct zip_iterator { - Iterator1 iterator1; - Iterator2 iterator2; - bool operator!=(const zip_iterator& other) const { - return iterator1 != other.iterator1; - } - void operator++() { - ++iterator1; - ++iterator2; - } - pair operator*() const { - return {*iterator1, *iterator2}; - } - }; - struct zip_helper { - const Sequence1& sequence1; - Sequence2& sequence2; - auto begin() { - return zip_iterator{std::begin(sequence1), std::begin(sequence2)}; - } - auto end() { - return zip_iterator{std::end(sequence1), std::end(sequence2)}; - } - }; - return zip_helper{sequence1, sequence2}; -} - -// Python zip -template -constexpr auto zip(Sequence1& sequence1, const Sequence2& sequence2) { - using Iterator1 = typename Sequence1::iterator; - using Reference1 = typename Sequence1::reference; - using Iterator2 = typename Sequence2::const_iterator; - using Reference2 = typename Sequence2::const_reference; - struct zip_iterator { - Iterator1 iterator1; - Iterator2 iterator2; - bool operator!=(const zip_iterator& other) const { - return iterator1 != other.iterator1; - } - void operator++() { - ++iterator1; - ++iterator2; - } - pair operator*() const { - return {*iterator1, *iterator2}; - } - }; - struct zip_helper { - Sequence1& sequence1; - const Sequence2& sequence2; - auto begin() { - return zip_iterator{std::begin(sequence1), std::begin(sequence2)}; - } - auto end() { - return zip_iterator{std::end(sequence1), std::end(sequence2)}; - } - }; - return zip_helper{sequence1, sequence2}; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// SIGNED-SIZE -// ----------------------------------------------------------------------------- -namespace yocto { - -template -inline std::ptrdiff_t ssize(const T& container) { - return (std::ptrdiff_t)std::size(container); -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// BACKWARD COMPATIBILITY -// ----------------------------------------------------------------------------- -namespace yocto { - -// Zero vector constants. -[[deprecated]] constexpr auto zero1f = vec1f{0}; -[[deprecated]] constexpr auto zero2f = vec2f{0, 0}; -[[deprecated]] constexpr auto zero3f = vec3f{0, 0, 0}; -[[deprecated]] constexpr auto zero4f = vec4f{0, 0, 0, 0}; -[[deprecated]] constexpr auto zero2i = vec2i{0, 0}; -[[deprecated]] constexpr auto zero3i = vec3i{0, 0, 0}; -[[deprecated]] constexpr auto zero4i = vec4i{0, 0, 0, 0}; -[[deprecated]] constexpr auto zero4b = vec4b{0, 0, 0, 0}; - -// Indentity frames. -[[deprecated]] constexpr auto identity2x3f = frame2f{{1, 0}, {0, 1}, {0, 0}}; -[[deprecated]] constexpr auto identity3x4f = frame3f{ - {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, 0}}; - -// Identity matrices constants. -[[deprecated]] constexpr auto identity2x2f = mat2f{{1, 0}, {0, 1}}; -[[deprecated]] constexpr auto identity3x3f = mat3f{ - {1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; -[[deprecated]] constexpr auto identity4x4f = mat4f{ - {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}; - -// Constants -[[deprecated]] constexpr auto identity_quat4f = quat4f{0, 0, 0, 1}; - -} // namespace yocto - -#endif