From babc74ba05000aa5dedbe5e8791c127c2d4c8354 Mon Sep 17 00:00:00 2001 From: Fabio Pellacini Date: Wed, 31 Jan 2024 22:37:10 +0100 Subject: [PATCH] updated --- apps/ycolorgrade.cpp | 16 +- apps/yimalpha.cpp | 12 +- apps/ytrace.cpp | 29 +- libs/yocto/CMakeLists.txt | 2 +- libs/yocto/yocto_diagram.cpp | 26 +- libs/yocto/yocto_diagram.h | 45 +- libs/yocto/yocto_geometryt.h | 1254 --------------- libs/yocto/yocto_gui.cpp | 64 +- libs/yocto/yocto_gui.h | 16 +- libs/yocto/yocto_image.cpp | 90 +- libs/yocto/yocto_image.h | 219 ++- libs/yocto/yocto_matht.h | 2771 ---------------------------------- libs/yocto/yocto_modeling.h | 18 +- libs/yocto/yocto_parallel.h | 331 ---- libs/yocto/yocto_scene.cpp | 6 +- libs/yocto/yocto_scene.h | 14 +- libs/yocto/yocto_sceneio.cpp | 34 +- libs/yocto/yocto_sceneio.h | 14 +- libs/yocto/yocto_trace.cpp | 55 +- libs/yocto/yocto_trace.h | 56 +- 20 files changed, 352 insertions(+), 4720 deletions(-) delete mode 100644 libs/yocto/yocto_geometryt.h delete mode 100644 libs/yocto/yocto_matht.h delete mode 100644 libs/yocto/yocto_parallel.h diff --git a/apps/ycolorgrade.cpp b/apps/ycolorgrade.cpp index 0a9796119..c16251749 100644 --- a/apps/ycolorgrade.cpp +++ b/apps/ycolorgrade.cpp @@ -53,16 +53,16 @@ void run(const vector& args) { parse_cli(cli, args); // load image - auto image = load_image(imagename); + auto source = load_image(imagename); auto in_linear = is_linear_filename(imagename); // switch between interactive and offline if (!interactive) { // apply color grade - image = colorgrade_image(image, in_linear, params); + auto graded = colorgrade_image(source, in_linear, params); // save image - save_image(outname, image); + save_image(outname, graded); } else { #ifdef YOCTO_OPENGL @@ -70,8 +70,8 @@ void run(const vector& args) { auto params = colorgrade_params{}; // display image - auto display = image; - colorgrade_image(display, image, in_linear, params); + auto display = source; + colorgrade_image(display, source, in_linear, params); // opengl image auto glimage = glimage_state{}; @@ -85,7 +85,7 @@ void run(const vector& args) { }; callbacks.clear = [&](const gui_input& input) { clear_image(glimage); }; callbacks.draw = [&](const gui_input& input) { - update_image_params(input, image, glparams); + update_image_params(input, source, glparams); draw_image(glimage, glparams); }; callbacks.widgets = [&](const gui_input& input) { @@ -110,11 +110,11 @@ void run(const vector& args) { "highlights color", params.highlights_color); end_gui_header(); if (edited) { - colorgrade_image(display, image, true, params); + colorgrade_image(display, source, true, params); set_image(glimage, display); } } - draw_image_widgets(input, image, display, glparams); + draw_image_widgets(input, source, display, glparams); }; callbacks.uiupdate = [&glparams](const gui_input& input) { uiupdate_image_params(input, glparams); diff --git a/apps/yimalpha.cpp b/apps/yimalpha.cpp index 340e8d584..53eaedff2 100644 --- a/apps/yimalpha.cpp +++ b/apps/yimalpha.cpp @@ -56,18 +56,18 @@ void run(const vector& args) { parse_cli(cli, args); // load - auto image = load_image(imagename); - auto alpha = load_image(alphaname); + auto source = load_image(imagename); + auto alpha = load_image(alphaname); // check sizes and types - if (image.size() != alpha.size()) throw io_error("different image sizes"); + if (source.size() != alpha.size()) throw io_error("different image sizes"); if (is_linear_filename(imagename) != is_linear_filename(alphaname) || is_linear_filename(imagename) != is_linear_filename(outname)) throw io_error("different image types"); // edit alpha - auto out = image_t{image.size()}; - for (auto idx : range(image.size())) { + auto out = image{source.size()}; + for (auto idx : range(source.size())) { auto calpha = alpha[idx]; auto alpha_ = from_color ? mean(xyz(calpha)) : from_black ? (mean(xyz(calpha)) > 0.01 ? 1.0f : 0.0f) @@ -75,7 +75,7 @@ void run(const vector& args) { if (to_color) { out[idx] = {alpha_, alpha_, alpha_, alpha_}; } else { - auto color = image[idx]; + auto color = source[idx]; color.w = alpha_; out[idx] = color; } diff --git a/apps/ytrace.cpp b/apps/ytrace.cpp index c651094fb..300f5f4e9 100644 --- a/apps/ytrace.cpp +++ b/apps/ytrace.cpp @@ -129,18 +129,19 @@ void run(const vector& args) { print_info("render sample {}/{}: {}", state.samples, params.samples, elapsed_formatted(sample_timer)); if (savebatch && state.samples % params.batch == 0) { - auto image = get_image(state); + auto render = get_image(state); auto batchname = replace_extension(outname, "-" + std::to_string(state.samples) + path_extension(outname)); - save_image(batchname, image); + save_image(batchname, render); } } print_info("render image: {}", elapsed_formatted(timer)); // save image - timer = simple_timer{}; - auto image = get_image(state); - save_image(outname, is_srgb_filename(outname) ? rgb_to_srgb(image) : image); + timer = simple_timer{}; + auto render = get_image(state); + save_image( + outname, is_srgb_filename(outname) ? rgb_to_srgb(render) : render); print_info("save image: {}", elapsed_formatted(timer)); } else { #ifdef YOCTO_OPENGL @@ -148,7 +149,7 @@ void run(const vector& args) { auto context = make_trace_context(params); // init image - auto image = image_t{state.render.size()}; + auto render = image{state.render.size()}; // opengl image auto glimage = glimage_state{}; @@ -174,14 +175,14 @@ void run(const vector& args) { // make sure we can start trace_cancel(context); state = make_trace_state(scene, params); - if (image.size() != state.render.size()) - image = image_t{state.render.size()}; + if (render.size() != state.render.size()) + render = image{state.render.size()}; // render preview - trace_preview(image, context, state, scene, bvh, lights, params); + trace_preview(render, context, state, scene, bvh, lights, params); // update image - set_image(glimage, image); + set_image(glimage, render); // start trace_start(context, state, scene, bvh, lights, params); @@ -193,8 +194,8 @@ void run(const vector& args) { // render update auto render_update = [&]() { if (context.done) { - get_image(image, state); - set_image(glimage, image); + get_image(render, state); + set_image(glimage, render); trace_start(context, state, scene, bvh, lights, params); } }; @@ -211,7 +212,7 @@ void run(const vector& args) { callbacks.clear = [&](const gui_input& input) { clear_image(glimage); }; callbacks.draw = [&](const gui_input& input) { render_update(); - update_image_params(input, image, glparams); + update_image_params(input, render, glparams); draw_image(glimage, glparams); }; callbacks.widgets = [&](const gui_input& input) { @@ -222,7 +223,7 @@ void run(const vector& args) { render_restart(); } draw_tonemap_widgets(input, glparams.exposure, glparams.filmic); - draw_image_widgets(input, image, glparams); + draw_image_widgets(input, render, glparams); if (edit) { if (draw_scene_widgets(scene, selection, render_cancel)) { render_restart(); diff --git a/libs/yocto/CMakeLists.txt b/libs/yocto/CMakeLists.txt index 540c36152..8fe46afab 100644 --- a/libs/yocto/CMakeLists.txt +++ b/libs/yocto/CMakeLists.txt @@ -13,7 +13,7 @@ add_library(yocto STATIC yocto_sceneio.h yocto_sceneio.cpp yocto_gui.h yocto_gui.cpp yocto_cutrace.h yocto_cutrace.cpp - yocto_parallel.h yocto_cli.h + yocto_cli.h yocto_diagram.h yocto_diagram.cpp ) diff --git a/libs/yocto/yocto_diagram.cpp b/libs/yocto/yocto_diagram.cpp index 4d4c9b084..5e7d5c148 100644 --- a/libs/yocto/yocto_diagram.cpp +++ b/libs/yocto/yocto_diagram.cpp @@ -1232,7 +1232,7 @@ diagram_shape dimagerect(vec2i size) { return shape; } -diagram_shape dimagerect(const image_t& img) { +diagram_shape dimagerect(const image& img) { return dimagerect(img.size()); } @@ -1246,7 +1246,7 @@ diagram_shape dimagegrid(vec2i size) { shape.quads = shape_.quads; return shape; } -diagram_shape dimagegrid(const image_t& img) { +diagram_shape dimagegrid(const image& img) { return dimagegrid(img.size()); } @@ -1263,7 +1263,7 @@ diagram_shape dimagelabel(vec2i size, float scale) { .quads = dconstants::quad_quads, }; } -diagram_shape dimagelabel(const image_t& image, float scale) { +diagram_shape dimagelabel(const image& image, float scale) { return dimagelabel(image.size(), scale); } @@ -1988,7 +1988,7 @@ static material_data make_stroke_material( // Make an image texture static texture_data make_image_texture( - const image_t& image, bool linear, bool nearest) { + const image& image, bool linear, bool nearest) { if (linear) { return texture_data{.pixelsf = image, .nearest = nearest}; } else { @@ -2104,7 +2104,7 @@ static scene_data convert_scene(const diagram_scene& diagram) { } // crop image vertically -static image_t crop_image(const image_t& source) { +static image crop_image(const image& source) { // find min and max auto [width, height] = source.size(); auto min = 0, max = height; @@ -2135,7 +2135,7 @@ static image_t crop_image(const image_t& source) { if (max < min) return source; // crop - auto cropped = image_t({width, max - min}); + auto cropped = image({width, max - min}); for (auto j : range(min, max)) { for (auto i : range(width)) { cropped[{i, j - min}] = source[{i, j}]; @@ -2147,14 +2147,14 @@ static image_t crop_image(const image_t& source) { } // Image rendering -static image_t render_image(const scene_data& scene, int resolution, +static image render_image(const scene_data& scene, int resolution, int samples, bool noparallel = false); // Render a diagram to an image -image_t render_diagram(const diagram_data& diagram, int resolution, +image render_diagram(const diagram_data& diagram, int resolution, int samples, bool boxes, bool crop) { // final image - auto composite = image_t{{resolution, resolution}, {1, 1, 1, 1}}; + auto composite = image{{resolution, resolution}, {1, 1, 1, 1}}; // render scenes for (auto& scene : diagram.scenes) { @@ -2165,7 +2165,7 @@ image_t render_diagram(const diagram_data& diagram, int resolution, auto render = render_image(yscene, resolution, samples, false); // helpers - auto draw_quad = [](image_t& composite, vec2i center, vec2i size, + auto draw_quad = [](image& composite, vec2i center, vec2i size, vec4f color) { auto extents = composite.size(); for (auto i : range(-size.x / 2, +size.x / 2)) { @@ -2181,7 +2181,7 @@ image_t render_diagram(const diagram_data& diagram, int resolution, center + vec2i{+size.x / 2, j}, vec2i{0, 0}, extents - 1)] = color; } }; - auto copy_quad = [](image_t& composite, const image_t& source, + auto copy_quad = [](image& composite, const image& source, vec2i icenter, vec2i scenter, vec2i size) { auto csize = composite.size(); auto ssize = source.size(); @@ -2325,7 +2325,7 @@ static vec4f render_ray( } // Progressively computes an image. -static image_t render_image( +static image render_image( const scene_data& scene, int resolution, int samples, bool noparallel) { // Bvh auto bvh = make_scene_bvh(scene, false, noparallel); @@ -2333,7 +2333,7 @@ static image_t render_image( auto& camera = scene.cameras[0]; // Image auto size = vec2i{resolution, (int)round(resolution / camera.aspect)}; - auto render = image_t{size, {0, 0, 0, 0}}; + auto render = image{size, {0, 0, 0, 0}}; // Start rendering auto nsamples = (int)round(sqrt((float)samples)); if (noparallel) { diff --git a/libs/yocto/yocto_diagram.h b/libs/yocto/yocto_diagram.h index 08fffaa1b..a039a7a43 100644 --- a/libs/yocto/yocto_diagram.h +++ b/libs/yocto/yocto_diagram.h @@ -103,18 +103,18 @@ struct diagram_labels { // Diagram style struct diagram_style { // Style data - vec4f stroke = {0, 0, 0, 1}; - vec4f fill = {0.4, 1.0, 1.0, 1}; - vec4f text = {0, 0, 0, 1}; - image_t texture = {}; - bool highlight = false; - bool arrow = false; - bool nearest = false; - bool linear = false; - bool wireframe = true; - float thickness = 0.015f; - float textscale = 0.05f; - float connect = 0; + vec4f stroke = {0, 0, 0, 1}; + vec4f fill = {0.4, 1.0, 1.0, 1}; + vec4f text = {0, 0, 0, 1}; + image texture = {}; + bool highlight = false; + bool arrow = false; + bool nearest = false; + bool linear = false; + bool wireframe = true; + float thickness = 0.015f; + float textscale = 0.05f; + float connect = 0; }; // Diagram object @@ -156,9 +156,8 @@ namespace yocto { diagram_data make_diagram(); // Rendering a diagram -image_t render_diagram(const diagram_data& diagram, - int resolution = 1440, int samples = 64, bool boxes = false, - bool crop = true); +image render_diagram(const diagram_data& diagram, int resolution = 1440, + int samples = 64, bool boxes = false, bool crop = true); } // namespace yocto @@ -365,14 +364,14 @@ inline diagram_style dfilled(vec4f fill = dcolors::fill1, vec4f stroke = dcolors::black, float thickness = dthickness::default_) { return {.stroke = stroke, .fill = fill, .thickness = thickness}; } -inline diagram_style dtextured(const image_t& texture, +inline diagram_style dtextured(const image& texture, vec4f stroke = dcolors::black, float thickness = dthickness::default_) { return {.stroke = stroke, .fill = {1, 1, 1, 1}, .thickness = thickness, .texture = texture}; } -inline diagram_style dtextured(const image_t& texture, bool interpolate, +inline diagram_style dtextured(const image& texture, bool interpolate, vec4f stroke = dcolors::black, float thickness = dthickness::default_) { return {.stroke = stroke, .fill = {1, 1, 1, 1}, @@ -380,7 +379,7 @@ inline diagram_style dtextured(const image_t& texture, bool interpolate, .texture = texture, .nearest = !interpolate}; } -inline diagram_style dimtextured(const image_t& texture, +inline diagram_style dimtextured(const image& texture, vec4f stroke = dcolors::transparent, float thickness = dthickness::default_) { return { @@ -391,8 +390,8 @@ inline diagram_style dimtextured(const image_t& texture, .nearest = true, }; } -inline diagram_style dimtextured(const image_t& texture, - bool interpolate, vec4f stroke = dcolors::transparent, +inline diagram_style dimtextured(const image& texture, bool interpolate, + vec4f stroke = dcolors::transparent, float thickness = dthickness::default_) { return {.stroke = stroke, .fill = {1, 1, 1, 1}, @@ -576,11 +575,11 @@ diagram_shape daffinegrid( // Image diagram_shape dimagerect(vec2i size); -diagram_shape dimagerect(const image_t& image); +diagram_shape dimagerect(const image& image); diagram_shape dimagegrid(vec2i size); -diagram_shape dimagegrid(const image_t& image); +diagram_shape dimagegrid(const image& image); diagram_shape dimagelabel(vec2i size, float scale = 1); -diagram_shape dimagelabel(const image_t& image, float scale = 1); +diagram_shape dimagelabel(const image& image, float scale = 1); // Random points enum struct drandompoints_type { 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_gui.cpp b/libs/yocto/yocto_gui.cpp index 71c5e57f0..ddd4b0aab 100644 --- a/libs/yocto/yocto_gui.cpp +++ b/libs/yocto/yocto_gui.cpp @@ -177,7 +177,7 @@ static void draw_scene(glscene_state& glscene, const scene_data& scene, // ----------------------------------------------------------------------------- namespace yocto { -void update_image_params(const gui_input& input, const image_t& image, +void update_image_params(const gui_input& input, const image& image, glimage_params& glparams) { glparams.window = input.window; glparams.framebuffer = input.framebuffer; @@ -234,21 +234,21 @@ bool draw_tonemap_widgets( return (bool)edited; } -bool draw_image_widgets(const gui_input& input, const image_t& image, - const image_t& display, glimage_params& glparams) { +bool draw_image_widgets(const gui_input& input, const image& source, + const image& display, glimage_params& glparams) { if (draw_gui_header("inspect")) { draw_gui_slider("zoom", glparams.scale, 0.1f, 10); draw_gui_checkbox("fit", glparams.fit); draw_gui_coloredit("background", glparams.background); auto ij = image_coords( - input.cursor, glparams.center, glparams.scale, image.size()); + input.cursor, glparams.center, glparams.scale, source.size()); draw_gui_dragger("mouse", ij); auto image_pixel = vec4f{0, 0, 0, 0}; auto display_pixel = vec4f{0, 0, 0, 0}; - if (ij.x >= 0 && ij.x < image.size().x && ij.y >= 0 && - ij.y < image.size().y) { - image_pixel = image[ij]; - display_pixel = image[ij]; + if (ij.x >= 0 && ij.x < source.size().x && ij.y >= 0 && + ij.y < source.size().y) { + image_pixel = source[ij]; + display_pixel = source[ij]; } draw_gui_coloredit("image", image_pixel); draw_gui_coloredit("display", display_pixel); @@ -257,20 +257,20 @@ bool draw_image_widgets(const gui_input& input, const image_t& image, return false; } -bool draw_image_widgets(const gui_input& input, const image_t& image, +bool draw_image_widgets(const gui_input& input, const image& source, glimage_params& glparams) { if (draw_gui_header("inspect")) { draw_gui_slider("zoom", glparams.scale, 0.1f, 10); draw_gui_checkbox("fit", glparams.fit); draw_gui_coloredit("background", glparams.background); auto ij = image_coords( - input.cursor, glparams.center, glparams.scale, image.size()); + input.cursor, glparams.center, glparams.scale, source.size()); draw_gui_dragger("mouse", ij); auto image_pixel = vec4f{0, 0, 0, 0}; auto display_pixel = vec4f{0, 0, 0, 0}; - if (ij.x >= 0 && ij.x < image.size().x && ij.y >= 0 && - ij.y < image.size().y) { - image_pixel = image[ij]; + if (ij.x >= 0 && ij.x < source.size().x && ij.y >= 0 && + ij.y < source.size().y) { + image_pixel = source[ij]; display_pixel = tonemap( image_pixel, glparams.exposure, glparams.filmic, glparams.srgb); } @@ -420,7 +420,7 @@ namespace yocto { // Open a window and show an image void show_image_gui(const string& title, const string& name, - const image_t& image, bool linear) { + const image& image, bool linear) { // display image auto display = image; float exposure = 0; @@ -464,9 +464,9 @@ void show_image_gui(const string& title, const string& name, // Open a window and show an image void show_image_gui(const string& title, const vector& names, - const vector>& images, const vector& linears) { + const vector>& images, const vector& linears) { // display image - auto displays = vector>(images.size()); + auto displays = vector>(images.size()); auto exposures = vector(images.size(), 0); auto filmics = vector(images.size(), false); for (auto idx : range((int)images.size())) { @@ -522,7 +522,7 @@ void show_image_gui(const string& title, const vector& names, // Open a window and show an image void show_colorgrade_gui(const string& title, const string& name, - const image_t& image, bool linear) { + const image& image, bool linear) { // color grading parameters auto params = colorgrade_params{}; @@ -606,8 +606,8 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, } // init state - auto state = make_trace_state(scene, params); - auto image = image_t{state.render.size()}; + auto state = make_trace_state(scene, params); + auto render = image{state.render.size()}; // opengl image auto glimage = glimage_state{}; @@ -640,8 +640,8 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, trace_samples(pstate, scene, bvh, lights, pparams); auto preview = get_image(pstate); for (auto idx : range(state.render.size())) { - auto pij = clamp(idx / params.pratio, {0, 0}, preview.size() - 1); - image[idx] = preview[pij]; + auto pij = clamp(idx / params.pratio, {0, 0}, preview.size() - 1); + render[idx] = preview[pij]; } return true; }; @@ -651,7 +651,7 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, // make sure we can start trace_cancel(context); state = make_trace_state(scene, params); - if (image.size() != state.render.size()) image = state.render.size(); + if (render.size() != state.render.size()) render = state.render.size(); }; // start rendering batch @@ -666,7 +666,7 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, // check if batch is done and update image auto render_done = [&]() { if (context.done) { - get_image(image, state); + get_image(render, state); return true; } else { return false; @@ -682,17 +682,17 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, init_image(glimage); render_reset(); render_preview(); - set_image(glimage, image); + set_image(glimage, render); render_start(); }; callbacks.clear = [&](const gui_input& input) { clear_image(glimage); }; callbacks.draw = [&](const gui_input& input) { // update image if (render_done()) { - set_image(glimage, image); + set_image(glimage, render); render_start(); } - update_image_params(input, image, glparams); + update_image_params(input, render, glparams); draw_image(glimage, glparams); }; callbacks.widgets = [&](const gui_input& input) { @@ -723,7 +723,7 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, render_cancel(); params = tparams; render_reset(); - if (render_preview()) set_image(glimage, image); + if (render_preview()) set_image(glimage, render); render_start(); } } @@ -731,13 +731,13 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, edited += draw_gui_slider("exposure", glparams.exposure, -5, 5); edited += draw_gui_checkbox("filmic", glparams.filmic); end_gui_header(); - if (edited) set_image(glimage, image); + if (edited) set_image(glimage, render); } - draw_image_widgets(input, image, glparams); + draw_image_widgets(input, render, glparams); if (edit) { if (draw_scene_widgets(scene, selection, [&]() { render_cancel(); })) { render_reset(); - if (render_preview()) set_image(glimage, image); + if (render_preview()) set_image(glimage, render); render_start(); } } @@ -748,7 +748,7 @@ void show_trace_gui(const string& title, const string& name, scene_data& scene, render_cancel(); scene.cameras[params.camera] = camera; render_reset(); - if (render_preview()) set_image(glimage, image); + if (render_preview()) set_image(glimage, render); render_start(); } }; @@ -1263,7 +1263,7 @@ void clear_image(glimage_state& glimage) { glimage = {}; } -void set_image(glimage_state& glimage, const image_t& image) { +void set_image(glimage_state& glimage, const image& image) { if (!glimage.texture || glimage.width != image.size().x || glimage.height != image.size().y) { if (!glimage.texture) glGenTextures(1, &glimage.texture); diff --git a/libs/yocto/yocto_gui.h b/libs/yocto/yocto_gui.h index 556bda804..bbcec45cf 100644 --- a/libs/yocto/yocto_gui.h +++ b/libs/yocto/yocto_gui.h @@ -65,15 +65,15 @@ namespace yocto { // Open a window and show an image void show_image_gui( - const string& title, const string& name, const image_t& image); + const string& title, const string& name, const image& image); // Open a window and show a set of images void show_image_gui(const string& title, const vector& names, - const vector>& images); + const vector>& images); // Open a window and show an image for color grading void show_colorgrade_gui( - const string& title, const string& name, const image_t& image); + const string& title, const string& name, const image& image); // Open a window and show an scene via path tracing void show_trace_gui(const string& title, const string& name, scene_data& scene, @@ -166,7 +166,7 @@ bool init_image(glimage_state& glimage); void clear_image(glimage_state& glimage); // update image data -void set_image(glimage_state& glimage, const image_t& image); +void set_image(glimage_state& glimage, const image& image); // draw image void draw_image(glimage_state& image, const glimage_params& params); @@ -294,13 +294,13 @@ bool draw_tonemap_widgets( const gui_input& input, float& exposure, bool& filmic); // draw image inspector -bool draw_image_widgets(const gui_input& input, const image_t& image, - const image_t& display, glimage_params& glparams); -bool draw_image_widgets(const gui_input& input, const image_t& image, +bool draw_image_widgets(const gui_input& input, const image& source, + const image& display, glimage_params& glparams); +bool draw_image_widgets(const gui_input& input, const image& source, glimage_params& glparams); // update image params -void update_image_params(const gui_input& input, const image_t& image, +void update_image_params(const gui_input& input, const image& source, glimage_params& glparams); // update image params from mouse diff --git a/libs/yocto/yocto_image.cpp b/libs/yocto/yocto_image.cpp index a82d122dd..345ff24a0 100644 --- a/libs/yocto/yocto_image.cpp +++ b/libs/yocto/yocto_image.cpp @@ -55,61 +55,61 @@ using std::unique_ptr; namespace yocto { // Conversion from/to floats. -image_t byte_to_float(const image_t& bt) { +image byte_to_float(const image& bt) { return transform_image(bt, [](vec4b a) { return byte_to_float(a); }); } -image_t float_to_byte(const image_t& fl) { +image float_to_byte(const image& fl) { return transform_image(fl, [](vec4f a) { return float_to_byte(a); }); } // Conversion between linear and gamma-encoded images. -image_t srgb_to_rgb(const image_t& srgb) { +image srgb_to_rgb(const image& srgb) { return transform_image(srgb, [](vec4f a) { return srgb_to_rgb(a); }); } -image_t rgb_to_srgb(const image_t& rgb) { +image rgb_to_srgb(const image& rgb) { return transform_image(rgb, [](vec4f a) { return rgb_to_srgb(a); }); } -image_t srgbb_to_rgb(const image_t& srgb) { +image srgbb_to_rgb(const image& srgb) { return transform_image(srgb, [](vec4b a) { return srgbb_to_rgb(a); }); } -image_t rgb_to_srgbb(const image_t& rgb) { +image rgb_to_srgbb(const image& rgb) { return transform_image(rgb, [](vec4f a) { return rgb_to_srgbb(a); }); } // Apply exposure and filmic tone mapping -image_t tonemap_image( - const image_t& hdr, float exposure, bool filmic, bool srgb) { +image tonemap_image( + const image& hdr, float exposure, bool filmic, bool srgb) { return transform_image(hdr, [exposure, filmic, srgb](vec4f a) { return tonemap(a, exposure, filmic, srgb); }); } -image_t tonemapb_image( - const image_t& hdr, float exposure, bool filmic, bool srgb) { +image tonemapb_image( + const image& hdr, float exposure, bool filmic, bool srgb) { return transform_image(hdr, [exposure, filmic, srgb](vec4f a) { return float_to_byte(tonemap(a, exposure, filmic, srgb)); }); } -void tonemap_image(image_t& ldr, const image_t& hdr, - float exposure, bool filmic, bool srgb) { +void tonemap_image(image& ldr, const image& hdr, float exposure, + bool filmic, bool srgb) { return transform_image(ldr, hdr, [exposure, filmic, srgb](vec4f a) { return tonemap(a, exposure, filmic, srgb); }); } // Apply exposure and filmic tone mapping -image_t colorgrade_image( - const image_t& img, bool linear, const colorgrade_params& params) { +image colorgrade_image( + const image& img, bool linear, const colorgrade_params& params) { return transform_image( img, [linear, params](vec4f a) { return colorgrade(a, linear, params); }); } -void colorgrade_image(image_t& graded, const image_t& img, +void colorgrade_image(image& graded, const image& img, bool linear, const colorgrade_params& params) { return transform_image(graded, img, [linear, params](vec4f a) { return colorgrade(a, linear, params); }); } // compute white balance -vec3f compute_white_balance(const image_t& img) { +vec3f compute_white_balance(const image& img) { auto rgb = vec3f{0, 0, 0}; for (auto& p : img) rgb += xyz(p); if (rgb == vec3f{0, 0, 0}) return {0, 0, 0}; @@ -117,27 +117,27 @@ vec3f compute_white_balance(const image_t& img) { } // image compositing -image_t composite_image( - const image_t& foreground, const image_t& background) { +image composite_image( + const image& foreground, const image& background) { return transform_images( foreground, background, [](vec4f a, vec4f b) { return composite(a, b); }); } // removes alpha -image_t remove_alpha(const image_t& img) { +image remove_alpha(const image& img) { return transform_image(img, [](vec4f a) -> vec4f { return {xyz(a), 1}; }); } // turns alpha into a gray scale image -image_t alpha_to_gray(const image_t& img) { +image alpha_to_gray(const image& img) { return transform_image(img, [](vec4f a) -> vec4f { auto g = a.w; return {g, g, g, 1}; }); } -image_t image_difference( - const image_t& a, const image_t& b, bool display) { +image image_difference( + const image& a, const image& b, bool display) { return transform_images(a, b, [display](vec4f a, vec4f b) -> vec4f { auto diff = abs(a - b); if (display) { @@ -149,7 +149,7 @@ image_t image_difference( }); } -image_t resize_image(const image_t& img, vec2i resize) { +image resize_image(const image& img, vec2i resize) { auto size = img.size(); if (resize.x == 0 && resize.y == 0) { throw std::invalid_argument{"bad image size in resize"}; @@ -159,13 +159,13 @@ image_t resize_image(const image_t& img, vec2i resize) { } else if (resize.x == 0) { resize.x = (int)round(resize.y * (double)size.x / (double)size.y); } - auto res = image_t{resize}; + auto res = image{resize}; stbir_resize_float_linear((float*)img.data(), size.x, size.y, sizeof(vec4f) * size.x, (float*)res.data(), resize.x, resize.y, sizeof(vec4f) * resize.x, STBIR_RGBA); return res; } -image_t resize_image(const image_t& img, vec2i resize) { +image resize_image(const image& img, vec2i resize) { auto size = img.size(); if (resize.x == 0 && resize.y == 0) { throw std::invalid_argument{"bad image size in resize"}; @@ -175,7 +175,7 @@ image_t resize_image(const image_t& img, vec2i resize) { } else if (resize.x == 0) { resize.x = (int)round(resize.y * (double)size.x / (double)size.y); } - auto res = image_t{resize}; + auto res = image{resize}; stbir_resize_uint8_linear((byte*)img.data(), size.x, size.y, sizeof(vec4b) * size.x, (byte*)res.data(), resize.x, resize.y, sizeof(vec4b) * resize.x, STBIR_RGBA); @@ -191,7 +191,7 @@ namespace yocto { // Comvert a bump map to a normal map. void bump_to_normal( - image_t& normalmap, const image_t& bumpmap, float scale) { + image& normalmap, const image& bumpmap, float scale) { if (normalmap.size() != bumpmap.size()) normalmap = {bumpmap.size()}; auto dx = 1.0f / bumpmap.size().x, dy = 1.0f / bumpmap.size().y; auto size = bumpmap.size(); @@ -209,15 +209,15 @@ void bump_to_normal( normalmap[{i, j}] = {normal.x, normal.y, normal.z, 1}; } } -image_t bump_to_normal(const image_t& bumpmap, float scale) { - auto normalmap = image_t{bumpmap.size()}; +image bump_to_normal(const image& bumpmap, float scale) { + auto normalmap = image{bumpmap.size()}; bump_to_normal(normalmap, bumpmap, scale); return normalmap; } template -static image_t make_proc_image(vec2i size, Shader&& shader) { - auto image_ = image_t{size}; +static image make_proc_image(vec2i size, Shader&& shader) { + auto image_ = image{size}; auto scale = 1.0f / max(size); for (auto ij : range(size)) { image_[ij] = shader((vec2f)ij * scale); @@ -226,7 +226,7 @@ static image_t make_proc_image(vec2i size, Shader&& shader) { } // Make an image -image_t make_grid(vec2i size, float scale, vec4f color0, vec4f color1) { +image make_grid(vec2i size, float scale, vec4f color0, vec4f color1) { return make_proc_image(size, [=](vec2f uv) { uv *= 4 * scale; uv -= vec2f{(float)(int)uv.x, (float)(int)uv.y}; @@ -239,8 +239,7 @@ image_t make_grid(vec2i size, float scale, vec4f color0, vec4f color1) { }); } -image_t make_checker( - vec2i size, float scale, vec4f color0, vec4f color1) { +image make_checker(vec2i size, float scale, vec4f color0, vec4f color1) { return make_proc_image(size, [=](vec2f uv) { uv *= 4 * scale; uv -= vec2f{(float)(int)uv.x, (float)(int)uv.y}; @@ -249,7 +248,7 @@ image_t make_checker( }); } -image_t make_bumps(vec2i size, float scale, vec4f color0, vec4f color1) { +image make_bumps(vec2i size, float scale, vec4f color0, vec4f color1) { return make_proc_image(size, [=](vec2f uv) { uv *= 4 * scale; uv -= vec2f{(float)(int)uv.x, (float)(int)uv.y}; @@ -265,7 +264,7 @@ image_t make_bumps(vec2i size, float scale, vec4f color0, vec4f color1) { }); } -image_t make_ramp(vec2i size, float scale, vec4f color0, vec4f color1) { +image make_ramp(vec2i size, float scale, vec4f color0, vec4f color1) { return make_proc_image(size, [=](vec2f uv) { uv *= scale; uv -= vec2f{(float)(int)uv.x, (float)(int)uv.y}; @@ -273,7 +272,7 @@ image_t make_ramp(vec2i size, float scale, vec4f color0, vec4f color1) { }); } -image_t make_gammaramp( +image make_gammaramp( vec2i size, float scale, vec4f color0, vec4f color1) { return make_proc_image(size, [=](vec2f uv) { uv *= scale; @@ -288,7 +287,7 @@ image_t make_gammaramp( }); } -image_t make_uvramp(vec2i size, float scale) { +image make_uvramp(vec2i size, float scale) { return make_proc_image(size, [=](vec2f uv) { uv *= scale; uv -= vec2f{(float)(int)uv.x, (float)(int)uv.y}; @@ -296,7 +295,7 @@ image_t make_uvramp(vec2i size, float scale) { }); } -image_t make_uvgrid(vec2i size, float scale, bool colored) { +image make_uvgrid(vec2i size, float scale, bool colored) { return make_proc_image(size, [=](vec2f uv) { uv *= scale; uv -= vec2f{(float)(int)uv.x, (float)(int)uv.y}; @@ -324,7 +323,7 @@ image_t make_uvgrid(vec2i size, float scale, bool colored) { }); } -image_t make_colormapramp(vec2i size, float scale) { +image make_colormapramp(vec2i size, float scale) { return make_proc_image(size, [=](vec2f uv) { uv *= scale; uv -= vec2f{(float)(int)uv.x, (float)(int)uv.y}; @@ -343,8 +342,7 @@ image_t make_colormapramp(vec2i size, float scale) { } // Add image border -image_t add_border( - const image_t& image, float width, vec4f color) { +image add_border(const image& image, float width, vec4f color) { auto result = image; auto scale = 1.0f / max(image.size()); for (auto ij : range(image.size())) { @@ -358,7 +356,7 @@ image_t add_border( } // Implementation of sunsky modified heavily from pbrt -image_t make_sunsky(vec2i size, float theta_sun, float turbidity, +image make_sunsky(vec2i size, float theta_sun, float turbidity, bool has_sun, float sun_intensity, float sun_radius, vec3f ground_albedo) { auto zenith_xyY = vec3f{ (+0.00165f * pow(theta_sun, 3.f) - 0.00374f * pow(theta_sun, 2.f) + @@ -448,7 +446,7 @@ image_t make_sunsky(vec2i size, float theta_sun, float turbidity, }; // Make the sun sky image - auto img = image_t{size}; + auto img = image{size}; for (auto j = 0; j < size.y / 2; j++) { auto theta = pif * ((j + 0.5f) / size.y); theta = clamp(theta, 0.0f, pif / 2 - flt_eps); @@ -492,9 +490,9 @@ image_t make_sunsky(vec2i size, float theta_sun, float turbidity, } // Make an image of multiple lights. -image_t make_lights(vec2i size, vec3f le, int nlights, float langle, +image make_lights(vec2i size, vec3f le, int nlights, float langle, float lwidth, float lheight) { - auto img = image_t{size}; + auto img = image{size}; for (auto j = 0; j < size.y / 2; j++) { auto theta = pif * ((j + 0.5f) / size.y); theta = clamp(theta, 0.0f, pif / 2 - 0.00001f); diff --git a/libs/yocto/yocto_image.h b/libs/yocto/yocto_image.h index 0c889cb8e..1ee911d30 100644 --- a/libs/yocto/yocto_image.h +++ b/libs/yocto/yocto_image.h @@ -68,7 +68,7 @@ namespace yocto { // Image data as array of float or byte pixels. Images can be stored in linear // or non linear color space. template -struct image_t { +struct image { // iterators and references using iterator = typename vector::iterator; using const_iterator = typename vector::const_iterator; @@ -76,9 +76,9 @@ struct image_t { using const_reference = typename vector::const_reference; // image api similar to vector - image_t(); - image_t(vec2i size, const T& value = T{}); - image_t(vec2i size, const T* values); + image(); + image(vec2i size, const T& value = T{}); + image(vec2i size, const T* values); // size bool empty() const; @@ -107,68 +107,66 @@ struct image_t { // equality template -inline bool operator==(const image_t& a, const image_t& b); +inline bool operator==(const image& a, const image& b); template -inline bool operator!=(const image_t& a, const image_t& b); +inline bool operator!=(const image& a, const image& b); // Image data template -inline float image_aspect(const image_t& image); +inline float image_aspect(const image& image); // Evaluates an image at a point `uv`. template -inline T eval_image(const image_t& image, vec2f uv, +inline T eval_image(const image& image, vec2f uv, bool no_interpolation = false, bool clamp_to_edge = false); // Make an image from a function that goes from [0,1]x[0,1] to T. template > -inline image_t make_image(vec2i size, Func&& func); +inline image make_image(vec2i size, Func&& func); template > -inline image_t make_image(vec2i size, int samples, Func&& func); +inline image make_image(vec2i size, int samples, Func&& func); // Make an image by applying a function to reach pixel of another. template > -inline image_t transform_image(const image_t& source, Func&& func); +inline image transform_image(const image& source, Func&& func); template inline void transform_image( - image_t& result, const image_t& source, Func&& func); + image& result, const image& source, Func&& func); template > -inline image_t transform_images( - const image_t& source1, const image_t& source2, Func&& func); +inline image transform_images( + const image& source1, const image& source2, Func&& func); template -inline void transform_images(image_t& result, const image_t& source1, - const image_t& source2, Func&& func); +inline void transform_images(image& result, const image& source1, + const image& source2, Func&& func); // Convolve an image with a kernel template -inline image_t convolve_image( - const image_t& img, const image_t& kernel); +inline image convolve_image(const image& img, const image& kernel); // Convolve an image with a separable kernel template -inline image_t convolve_image( - const image_t& img, const vector& kernel); +inline image convolve_image( + const image& img, const vector& kernel); // Gaussian kernel -inline vector make_gaussian_kernel1d(float sigma); -inline image_t make_gaussian_kernel2d(float sigma); +inline vector make_gaussian_kernel1d(float sigma); +inline image make_gaussian_kernel2d(float sigma); // Sharpening kernel -inline vector make_sharpening_kernel1d(float sigma, float scale = 1); -inline image_t make_sharpening_kernel2d(float sigma, float scale = 1); +inline vector make_sharpening_kernel1d(float sigma, float scale = 1); +inline image make_sharpening_kernel2d(float sigma, float scale = 1); // Get/Set region template -inline image_t get_region( - const image_t& source, vec2i offset, vec2i size); +inline image get_region(const image& source, vec2i offset, vec2i size); template inline void get_region( - image_t& region, const image_t& source, vec2i offset, vec2i size); + image& region, const image& source, vec2i offset, vec2i size); template inline void set_region( - image_t& destination, const image_t& source, vec2i offset); + image& destination, const image& source, vec2i offset); // Convenience functions template -inline T sum(const image_t& img); +inline T sum(const image& img); template inline T sum(const vector& img); @@ -192,10 +190,10 @@ inline int reconstruction_radius(reconstruction_type ktype); // Image reconstruction template -inline T reconstruct_image(const image_t& img, vec2f uv, Func&& kernel, +inline T reconstruct_image(const image& img, vec2f uv, Func&& kernel, int kradius = 2, bool clamp_to_edge = false); template -inline T reconstruct_image(const image_t& img, vec2f uv, +inline T reconstruct_image(const image& img, vec2f uv, reconstruction_type ktype, bool clamp_to_edge = false); } // namespace yocto @@ -206,50 +204,50 @@ inline T reconstruct_image(const image_t& img, vec2f uv, namespace yocto { // Conversion from/to floats. -image_t byte_to_float(const image_t& bt); -image_t float_to_byte(const image_t& fl); +image byte_to_float(const image& bt); +image float_to_byte(const image& fl); // Conversion between linear and gamma-encoded images. -image_t srgb_to_rgb(const image_t& srgb); -image_t rgb_to_srgb(const image_t& rgb); -image_t srgbb_to_rgb(const image_t& srgb); -image_t rgb_to_srgbb(const image_t& rgb); +image srgb_to_rgb(const image& srgb); +image rgb_to_srgb(const image& rgb); +image srgbb_to_rgb(const image& srgb); +image rgb_to_srgbb(const image& rgb); // Apply exposure and filmic tone mapping -image_t tonemap_image(const image_t& hdr, float exposure = 0, +image tonemap_image(const image& hdr, float exposure = 0, bool filmic = false, bool srgb = true); -image_t tonemapb_image(const image_t& hdr, float exposure = 0, +image tonemapb_image(const image& hdr, float exposure = 0, bool filmic = false, bool srgb = true); // fast tone map for UI -void tonemap_image(image_t& ldr, const image_t& hdr, +void tonemap_image(image& ldr, const image& hdr, float exposure = 0, bool filmic = false, bool srgb = true); // Apply exposure and filmic tone mapping -image_t colorgrade_image( - const image_t& img, bool linear, const colorgrade_params& params); +image colorgrade_image( + const image& img, bool linear, const colorgrade_params& params); // compute white balance -vec3f compute_white_balance(const image_t& img); +vec3f compute_white_balance(const image& img); // fast color grade for UI -void colorgrade_image(image_t& graded, const image_t& img, +void colorgrade_image(image& graded, const image& img, bool linear, const colorgrade_params& params); // image compositing -image_t composite_image( - const image_t& foreground, const image_t& background); +image composite_image( + const image& foreground, const image& background); // removes alpha -image_t remove_alpha(const image_t& img); +image remove_alpha(const image& img); // turns alpha into a gray scale image -image_t alpha_to_gray(const image_t& img); +image alpha_to_gray(const image& img); // image difference -image_t image_difference( - const image_t& a, const image_t& b, bool display); +image image_difference( + const image& a, const image& b, bool display); // image resizing -image_t resize_image(const image_t& img, vec2i resize); -image_t resize_image(const image_t& img, vec2i resize); +image resize_image(const image& img, vec2i resize); +image resize_image(const image& img, vec2i resize); } // namespace yocto @@ -259,47 +257,47 @@ image_t resize_image(const image_t& img, vec2i resize); namespace yocto { // Make a grid image. -image_t make_grid(vec2i size, float scale = 1, +image make_grid(vec2i size, float scale = 1, vec4f color0 = vec4f{0.2f, 0.2f, 0.2f, 1.0f}, vec4f color1 = vec4f{0.5f, 0.5f, 0.5f, 1.0f}); // Make a checker image. -image_t make_checker(vec2i size, float scale = 1, +image make_checker(vec2i size, float scale = 1, vec4f color0 = vec4f{0.2f, 0.2f, 0.2f, 1.0f}, vec4f color1 = vec4f{0.5f, 0.5f, 0.5f, 1.0f}); // Make a bump map. -image_t make_bumps(vec2i size, float scale = 1, +image make_bumps(vec2i size, float scale = 1, vec4f color0 = vec4f{0, 0, 0, 1}, vec4f color1 = vec4f{1, 1, 1, 1}); // Make a ramp -image_t make_ramp(vec2i size, float scale = 1, +image make_ramp(vec2i size, float scale = 1, vec4f color0 = vec4f{0, 0, 0, 1}, vec4f color1 = vec4f{1, 1, 1, 1}); // Make a gamma ramp. -image_t make_gammaramp(vec2i size, float scale = 1, +image make_gammaramp(vec2i size, float scale = 1, vec4f color0 = vec4f{0, 0, 0, 1}, vec4f color1 = vec4f{1, 1, 1, 1}); // Make a uv ramp -image_t make_uvramp(vec2i size, float scale = 1); +image make_uvramp(vec2i size, float scale = 1); // Make a uv grid -image_t make_uvgrid(vec2i size, float scale = 1, bool colored = true); +image make_uvgrid(vec2i size, float scale = 1, bool colored = true); // Make color map ramp. -image_t make_colormapramp(vec2i size, float scale = 1); +image make_colormapramp(vec2i size, float scale = 1); // Make a sunsky HDR model with sun at sun_angle elevation in [0,pif/2], // turbidity in [1.7,10] with or without sun. The sun can be enabled or // disabled with has_sun. The sun parameters can be slightly modified by // changing the sun intensity and temperature. Has a convention, a temperature // of 0 sets the eath sun defaults (ignoring intensity too). -image_t make_sunsky(vec2i size, float sun_angle, float turbidity = 3, +image make_sunsky(vec2i size, float sun_angle, float turbidity = 3, bool has_sun = false, float sun_intensity = 1, float sun_radius = 1, vec3f ground_albedo = {0.2f, 0.2f, 0.2f}); // Make an image of multiple lights. -image_t make_lights(vec2i size, vec3f le = {1, 1, 1}, int nlights = 4, +image make_lights(vec2i size, vec3f le = {1, 1, 1}, int nlights = 4, float langle = pif / 4, float lwidth = pif / 16, float lheight = pif / 16); // Comvert a bump map to a normal map. All linear color spaces. -image_t bump_to_normal(const image_t& image, float scale = 1); +image bump_to_normal(const image& image, float scale = 1); // Add a border to an image -image_t add_border( - const image_t& img, float width, vec4f color = {0, 0, 0, 1}); +image add_border( + const image& img, float width, vec4f color = {0, 0, 0, 1}); } // namespace yocto @@ -318,90 +316,90 @@ namespace yocto { // image api similar to vector template -inline image_t::image_t() : _size{0, 0}, _data{} {} +inline image::image() : _size{0, 0}, _data{} {} template -inline image_t::image_t(vec2i size, const T& value) +inline image::image(vec2i size, const T& value) : _size{size}, _data((size_t)size.x * (size_t)size.y, value) {} template -inline image_t::image_t(vec2i size, const T* values) +inline image::image(vec2i size, const T* values) : _size{size}, _data{values, values + size.x * size.y} {} // size template -inline bool image_t::empty() const { +inline bool image::empty() const { return _size == zero2i; } template -inline vec2i image_t::size() const { +inline vec2i image::size() const { return _size; } // iterator access template -inline typename image_t::iterator image_t::begin() { +inline typename image::iterator image::begin() { return _data.begin(); } template -inline typename image_t::iterator image_t::end() { +inline typename image::iterator image::end() { return _data.end(); } template -inline typename image_t::const_iterator image_t::begin() const { +inline typename image::const_iterator image::begin() const { return _data.begin(); } template -inline typename image_t::const_iterator image_t::end() const { +inline typename image::const_iterator image::end() const { return _data.end(); } // pixel access template -inline T& image_t::operator[](vec2i ij) { +inline T& image::operator[](vec2i ij) { return _data[ij.y * _size.x + ij.x]; } template -inline const T& image_t::operator[](vec2i ij) const { +inline const T& image::operator[](vec2i ij) const { return _data[ij.y * _size.x + ij.x]; } // data access template -inline T* image_t::data() { +inline T* image::data() { return _data.data(); } template -inline const T* image_t::data() const { +inline const T* image::data() const { return _data.data(); } template -inline vector& image_t::pixels() { +inline vector& image::pixels() { return _data; } template -inline const vector& image_t::pixels() const { +inline const vector& image::pixels() const { return _data; } // equality template -inline bool operator==(const image_t& a, const image_t& b) { +inline bool operator==(const image& a, const image& b) { return a.size() == b.size() && a.pixels() == b.pixels(); } template -inline bool operator!=(const image_t& a, const image_t& b) { +inline bool operator!=(const image& a, const image& b) { return a.size() != b.size() || a.pixels() != b.pixels(); } // Image data template -inline float image_aspect(const image_t& image) { +inline float image_aspect(const image& image) { if (image.empty()) return 0; return float{image.size().x} / float{image.size().y}; } // Evaluates an image at a point `uv`. template -inline T eval_image(const image_t& image, vec2f uv, bool no_interpolation, +inline T eval_image(const image& image, vec2f uv, bool no_interpolation, bool clamp_to_edge) { if (image.empty()) return T{}; @@ -439,8 +437,8 @@ inline T eval_image(const image_t& image, vec2f uv, bool no_interpolation, // Make an image from a function that goes from [0,1]x[0,1] to T. template -inline image_t make_image(vec2i size, Func&& func) { - auto img = image_t(size); +inline image make_image(vec2i size, Func&& func) { + auto img = image(size); for (auto ij : range(size)) { img[ij] = func(((vec2f)ij + 0.5f) / (vec2f)size); } @@ -449,10 +447,10 @@ inline image_t make_image(vec2i size, Func&& func) { // Make an image from a function that goes from [0,1]x[0,1] to T. template -inline image_t make_image(vec2i size, int samples, Func&& func) { +inline image make_image(vec2i size, int samples, Func&& func) { if (samples <= 1) return make_image(size, std::forward(func)); auto ns = (int)round(sqrt((float)samples)); - auto img = image_t(size, T{}); + auto img = image(size, T{}); for (auto ij : range(size)) { for (auto sij : range({ns, ns})) { img[ij] += func(((vec2f)ij + ((vec2f)sij + 0.5f) / ns) / (vec2f)size); @@ -464,24 +462,24 @@ inline image_t make_image(vec2i size, int samples, Func&& func) { // Make an image by applying a function to reach pixel of another. template -inline image_t transform_image(const image_t& source, Func&& func) { - auto result = image_t(source.size()); +inline image transform_image(const image& source, Func&& func) { + auto result = image(source.size()); for (auto&& [res, src] : zip(result, source)) res = func(src); return result; } template inline void transform_image( - image_t& result, const image_t& source, Func&& func) { + image& result, const image& source, Func&& func) { if (result.size() != source.size()) throw std::runtime_error("image size mismatch"); for (auto&& [res, src] : zip(result, source)) res = func(src); } template -inline image_t transform_images( - const image_t& source1, const image_t& source2, Func&& func) { +inline image transform_images( + const image& source1, const image& source2, Func&& func) { if (source1.size() != source2.size()) throw std::runtime_error("image size mismatch"); - auto result = image_t(source1.size()); + auto result = image(source1.size()); for (auto&& [res, src1, src2] : zip(result, source1, source2)) res = func(src1, src2); return result; @@ -525,7 +523,7 @@ inline vector make_curve(int size, Func&& func) { // Convenience functions template -inline T sum(const image_t& img) { +inline T sum(const image& img) { auto sum = T{}; for (auto& value : img) sum += value; return sum; @@ -539,9 +537,9 @@ inline T sum(const vector& values) { // Convolve an image with a kernel template -inline image_t convolve_image( - const image_t& img, const image_t& kernel) { - auto result = image_t(img.size()); +inline image convolve_image( + const image& img, const image& kernel) { + auto result = image(img.size()); auto kcenter = kernel.size() / 2; for (auto ij : range(img.size())) { auto sum = T{}; @@ -560,8 +558,8 @@ inline image_t convolve_image( } // Convolve an image with a separable kernel template -inline image_t convolve_image( - const image_t& img, const vector& kernel); +inline image convolve_image( + const image& img, const vector& kernel); // Gaussian kernel inline vector make_gaussian_kernel1d(float sigma) { auto width = (int)ceil(sigma * 3); @@ -572,9 +570,9 @@ inline vector make_gaussian_kernel1d(float sigma) { for (auto& value : kernel) value /= sum(kernel); return kernel; } -inline image_t make_gaussian_kernel2d(float sigma) { +inline image make_gaussian_kernel2d(float sigma) { auto kernel1d = make_gaussian_kernel1d(sigma); - auto kernel = image_t({(int)kernel1d.size(), (int)kernel1d.size()}); + auto kernel = image({(int)kernel1d.size(), (int)kernel1d.size()}); for (auto ij : range(kernel.size())) kernel[ij] = kernel1d[ij.x] * kernel1d[ij.y]; for (auto& value : kernel) value /= sum(kernel); @@ -588,7 +586,7 @@ inline vector make_sharpening_kernel1d(float sigma, float scale) { return kernel; } // Sharpening kernel -inline image_t make_sharpening_kernel2d(float sigma, float scale) { +inline image make_sharpening_kernel2d(float sigma, float scale) { auto kernel = make_gaussian_kernel2d(sigma); for (auto& value : kernel) value = -scale * value; kernel[kernel.size() / 2] += 1 + scale; @@ -597,21 +595,20 @@ inline image_t make_sharpening_kernel2d(float sigma, float scale) { // Get/Set region template -inline image_t get_region( - const image_t& source, vec2i offset, vec2i size) { - auto region = image_t(size); +inline image get_region(const image& source, vec2i offset, vec2i size) { + auto region = image(size); for (auto ij : range(region.size())) region[ij] = source[ij + offset]; return region; } template inline void get_region( - image_t& region, const image_t& source, vec2i offset, vec2i size) { - if (region.size() != size) region = image_t(size); + image& region, const image& source, vec2i offset, vec2i size) { + if (region.size() != size) region = image(size); for (auto ij : range(region.size())) region[ij] = source[ij + offset]; } template inline void set_region( - image_t& destination, const image_t& source, vec2i offset) { + image& destination, const image& source, vec2i offset) { for (auto ij : range(source.size())) destination[ij + offset] = source[ij]; } @@ -699,7 +696,7 @@ inline int reconstruction_radius(reconstruction_type ktype) { // Image reconstruction template -inline T reconstruct_image(const image_t& img, vec2f uv, Func&& kernel, +inline T reconstruct_image(const image& img, vec2f uv, Func&& kernel, int kradius, bool clamp_to_edge) { auto x = uv * (vec2f)img.size(); auto ij = (vec2i)(x + 0.5f); @@ -715,7 +712,7 @@ inline T reconstruct_image(const image_t& img, vec2f uv, Func&& kernel, return sum; } template -inline T reconstruct_image(const image_t& img, vec2f uv, +inline T reconstruct_image(const image& img, vec2f uv, reconstruction_type ktype, bool clamp_to_edge) { switch (ktype) { case reconstruction_type::box: 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 diff --git a/libs/yocto/yocto_modeling.h b/libs/yocto/yocto_modeling.h index 12c621a1d..1201c8584 100644 --- a/libs/yocto/yocto_modeling.h +++ b/libs/yocto/yocto_modeling.h @@ -342,18 +342,16 @@ namespace yocto { // Displace vertices inline vector displace_vertices(const vector& positions, const vector& normals, const vector& texcoords, - const image_t& displacement, float scale = 1.0f, - float offset = 0.5f); + const image& displacement, float scale = 1.0f, float offset = 0.5f); inline vector displace_vertices(const vector& positions, const vector& normals, const vector& texcoords, - const image_t& displacement, float scale = 1.0f, - float offset = 0.5f); + const image& displacement, float scale = 1.0f, float offset = 0.5f); // Shape displacement inline shape_data displace_shape(const shape_data& shape, - const image_t& displacement, float height = 1, float offset = 0.5f); + const image& displacement, float height = 1, float offset = 0.5f); inline shape_data displace_shape(const shape_data& shape, - const image_t& displacement, float height = 1, float offset = 0.5f); + const image& displacement, float height = 1, float offset = 0.5f); } // namespace yocto @@ -2253,7 +2251,7 @@ namespace yocto { // Displace vertices inline vector displace_vertices(const vector& positions, const vector& normals, const vector& texcoords, - const image_t& displacement, float scale, float offset) { + const image& displacement, float scale, float offset) { if (texcoords.empty()) return positions; auto displaced = positions; for (auto idx : range(displaced.size())) { @@ -2265,7 +2263,7 @@ inline vector displace_vertices(const vector& positions, } inline vector displace_vertices(const vector& positions, const vector& normals, const vector& texcoords, - const image_t& displacement, float scale, float offset) { + const image& displacement, float scale, float offset) { if (texcoords.empty()) return positions; auto displaced = positions; for (auto idx : range(displaced.size())) { @@ -2278,7 +2276,7 @@ inline vector displace_vertices(const vector& positions, // Displacement inline shape_data displace_shape(const shape_data& shape, - const image_t& displacement, float height, float offset) { + const image& displacement, float height, float offset) { if (displacement.empty() || shape.texcoords.empty() || shape.normals.empty() || (shape.triangles.empty() && shape.quads.empty())) return shape; @@ -2289,7 +2287,7 @@ inline shape_data displace_shape(const shape_data& shape, return displaced; } inline shape_data displace_shape(const shape_data& shape, - const image_t& displacement, float height, float offset) { + const image& displacement, float height, float offset) { if (displacement.empty() || shape.texcoords.empty() || shape.normals.empty() || (shape.triangles.empty() && shape.quads.empty())) return shape; diff --git a/libs/yocto/yocto_parallel.h b/libs/yocto/yocto_parallel.h deleted file mode 100644 index 7acd0395b..000000000 --- a/libs/yocto/yocto_parallel.h +++ /dev/null @@ -1,331 +0,0 @@ -// -// # Yocto/Parallel: Parallel utilities -// -// Yocto/Parallel is a collection of utilities helpful in implementing other -// Yocto/GL libraries. Yocto/Parallel is implemented in `yocto_parallel.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_PARALLEL_H_ -#define _YOCTO_PARALLEL_H_ - -// ----------------------------------------------------------------------------- -// INCLUDES -// ----------------------------------------------------------------------------- - -#include -#include -#include -#include -#include -#include -#include - -// ----------------------------------------------------------------------------- -// USING DIRECTIVES -// ----------------------------------------------------------------------------- -namespace yocto { - -// using directives -using std::atomic; -using std::deque; -using std::future; -using std::mutex; -using std::vector; - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// CONCURRENCY UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// a simple concurrent queue that locks at every call -template -struct concurrent_queue { - concurrent_queue() = default; - concurrent_queue(const concurrent_queue& other) = delete; - concurrent_queue& operator=(const concurrent_queue& other) = delete; - - bool empty(); - void clear(); - void push(const T& value); - bool try_pop(T& value); - - private: - std::mutex mutex; - deque queue; -}; - -// Run a task asynchronously -template -inline auto run_async(Func&& func, Args&&... args); - -// Check if an async task is ready -inline bool is_valid(const future& result); -inline bool is_running(const future& result); -inline bool is_ready(const future& result); - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the integer index. -template -inline void parallel_for(T num, Func&& func); -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the two integer indices. -template -inline void parallel_for(T num1, T num2, Func&& func); -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the integer index. -// Works on `batch` sized chunks. -template -inline void parallel_for_batch(T num, T batch, Func&& func); - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes a reference to a `T`. -template -inline void parallel_foreach(vector& values, Func&& func); -template -inline void parallel_foreach(const vector& values, Func&& func); - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the integer index, a string ref, -// and returns a bool. Handles errors explicitly. -template -inline bool parallel_for(T num, string& error, Func&& func); - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes a reference to a `T`, a string ref, -// and returns a bool. Handles errors explicitly. -template -inline bool parallel_foreach(vector& values, string& error, Func&& func); -template -inline bool parallel_foreach( - const vector& values, string& error, Func&& func); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// -// -// IMPLEMENTATION -// -// -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// CONCURRENCY UTILITIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// a simple concurrent queue that locks at every call -template -bool concurrent_queue::empty() { - std::lock_guard lock(mutex); - return queue.empty(); -} -template -void concurrent_queue::clear() { - std::lock_guard lock(mutex); - queue.clear(); -} -template -void concurrent_queue::push(const T& value) { - std::lock_guard lock(mutex); - queue.push_back(value); -} -template -bool concurrent_queue::try_pop(T& value) { - std::lock_guard lock(mutex); - if (queue.empty()) return false; - value = queue.front(); - queue.pop_front(); - return true; -} - -// Run a task asynchronously -template -inline auto run_async(Func&& func, Args&&... args) { - return std::async(std::launch::async, std::forward(func), - std::forward(args)...); -} -// Check if an async task is ready -inline bool is_valid(const future& result) { return result.valid(); } -inline bool is_running(const future& result) { - return result.valid() && result.wait_for(std::chrono::microseconds(0)) != - std::future_status::ready; -} -inline bool is_ready(const future& result) { - return result.valid() && result.wait_for(std::chrono::microseconds(0)) == - std::future_status::ready; -} - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the integer index. -template -inline void parallel_for(T num, Func&& func) { - auto futures = vector>{}; - auto nthreads = std::thread::hardware_concurrency(); - atomic next_idx(0); - atomic has_error(false); - for (auto thread_id = 0; thread_id < (int)nthreads; thread_id++) { - futures.emplace_back( - std::async(std::launch::async, [&func, &next_idx, &has_error, num]() { - try { - while (true) { - auto idx = next_idx.fetch_add(1); - if (idx >= num) break; - if (has_error) break; - func(idx); - } - } catch (...) { - has_error = true; - throw; - } - })); - } - for (auto& f : futures) f.get(); -} - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the two integer indices. -template -inline void parallel_for(T num1, T num2, Func&& func) { - auto futures = vector>{}; - auto nthreads = std::thread::hardware_concurrency(); - atomic next_idx(0); - atomic has_error(false); - for (auto thread_id = 0; thread_id < (int)nthreads; thread_id++) { - futures.emplace_back(std::async( - std::launch::async, [&func, &next_idx, &has_error, num1, num2]() { - try { - while (true) { - auto j = next_idx.fetch_add(1); - if (j >= num2) break; - if (has_error) break; - for (auto i = (T)0; i < num1; i++) func(i, j); - } - } catch (...) { - has_error = true; - throw; - } - })); - } - for (auto& f : futures) f.get(); -} - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the integer index. -template -inline void parallel_for_batch(T num, T batch, Func&& func) { - auto futures = vector>{}; - auto nthreads = std::thread::hardware_concurrency(); - atomic next_idx(0); - atomic has_error(false); - for (auto thread_id = 0; thread_id < (int)nthreads; thread_id++) { - futures.emplace_back(std::async( - std::launch::async, [&func, &next_idx, &has_error, num, batch]() { - try { - while (true) { - auto start = next_idx.fetch_add(batch); - if (start >= num) break; - if (has_error) break; - auto end = std::min(num, start + batch); - for (auto i = (T)start; i < end; i++) func(i); - } - } catch (...) { - has_error = true; - throw; - } - })); - } - for (auto& f : futures) f.get(); -} - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes a reference to a `T`. -template -inline void parallel_foreach(vector& values, Func&& func) { - parallel_for( - values.size(), [&func, &values](size_t idx) { func(values[idx]); }); -} -template -inline void parallel_foreach(const vector& values, Func&& func) { - parallel_for( - values.size(), [&func, &values](size_t idx) { func(values[idx]); }); -} - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes the integer index. -template -inline bool parallel_for(T num, string& error, Func&& func) { - auto futures = vector>{}; - auto nthreads = std::thread::hardware_concurrency(); - atomic next_idx(0); - atomic has_error(false); - mutex error_mutex; - for (auto thread_id = 0; thread_id < (int)nthreads; thread_id++) { - futures.emplace_back(std::async(std::launch::async, - [&func, &next_idx, &has_error, &error_mutex, &error, num]() { - auto this_error = string{}; - while (true) { - if (has_error) break; - auto idx = next_idx.fetch_add(1); - if (idx >= num) break; - if (!func(idx, this_error)) { - has_error = true; - auto _ = std::lock_guard{error_mutex}; - error = this_error; - break; - } - } - })); - } - for (auto& f : futures) f.get(); - return !(bool)has_error; -} - -// Simple parallel for used since our target platforms do not yet support -// parallel algorithms. `Func` takes a reference to a `T`. -template -inline bool parallel_foreach(vector& values, string& error, Func&& func) { - return parallel_for( - values.size(), error, [&func, &values](size_t idx, string& error) { - return func(values[idx], error); - }); -} -template -inline bool parallel_foreach( - const vector& values, string& error, Func&& func) { - return parallel_for( - values.size(), error, [&func, &values](size_t idx, string& error) { - return func(values[idx], error); - }); -} - -} // namespace yocto - -#endif diff --git a/libs/yocto/yocto_scene.cpp b/libs/yocto/yocto_scene.cpp index 6256e3080..8b1fa17a1 100644 --- a/libs/yocto/yocto_scene.cpp +++ b/libs/yocto/yocto_scene.cpp @@ -159,7 +159,7 @@ vec4f eval_texture( } // conversion from image -texture_data image_to_texture(const image_t& image, bool linear) { +texture_data image_to_texture(const image& image, bool linear) { auto texture = texture_data{}; if (linear) { texture.pixelsf = image; @@ -833,7 +833,7 @@ int add_environment(scene_data& scene, const string& name, const frame3f& frame, // Scene creation helpers int add_texture(scene_data& scene, const string& name, - const image_t& texture, bool linear) { + const image& texture, bool linear) { if (texture.empty()) return invalidid; if (linear) { scene.textures.push_back({.pixelsf = texture}); @@ -845,7 +845,7 @@ int add_texture(scene_data& scene, const string& name, // Scene creation helpers int add_texture(scene_data& scene, const string& name, - const image_t& texture, bool linear) { + const image& texture, bool linear) { if (texture.empty()) return invalidid; if (linear) { scene.textures.push_back({.pixelsf = srgbb_to_rgb(texture)}); diff --git a/libs/yocto/yocto_scene.h b/libs/yocto/yocto_scene.h index a95981bc1..95c280a14 100644 --- a/libs/yocto/yocto_scene.h +++ b/libs/yocto/yocto_scene.h @@ -94,10 +94,10 @@ struct camera_data { // Texture data as array of float or byte pixels. Textures can be stored in // linear or non linear color space. struct texture_data { - image_t pixelsf = {}; - image_t pixelsb = {}; - bool nearest = false; - bool clamp = false; + image pixelsf = {}; + image pixelsb = {}; + bool nearest = false; + bool clamp = false; }; // Material type @@ -253,7 +253,7 @@ vec4f lookup_texture( const texture_data& texture, vec2i ij, bool ldr_as_linear = false); // conversion from image -texture_data image_to_texture(const image_t& image, bool linear); +texture_data image_to_texture(const image& image, bool linear); } // namespace yocto @@ -402,9 +402,9 @@ int add_instance(scene_data& scene, const string& name, const frame3f& frame, int add_environment(scene_data& scene, const string& name, const frame3f& frame, vec3f emission, int emission_tex = invalidid); int add_texture(scene_data& scene, const string& name, - const image_t& texture, bool linear = true); + const image& texture, bool linear = true); int add_texture(scene_data& scene, const string& name, - const image_t& texture, bool linear = false); + const image& texture, bool linear = false); } // namespace yocto diff --git a/libs/yocto/yocto_sceneio.cpp b/libs/yocto/yocto_sceneio.cpp index b4096bdb8..81ca56fcc 100644 --- a/libs/yocto/yocto_sceneio.cpp +++ b/libs/yocto/yocto_sceneio.cpp @@ -443,7 +443,7 @@ bool is_srgb_filename(const string& filename) { } // Loads a float image. -image_t load_image(const string& filename) { +image load_image(const string& filename) { auto ext = path_extension(filename); if (ext == ".exr" || ext == ".EXR") { auto buffer = load_binary(filename); @@ -452,32 +452,32 @@ image_t load_image(const string& filename) { if (LoadEXRFromMemory(&pixels, &width, &height, buffer.data(), buffer.size(), nullptr) != 0) throw io_error{"cannot read " + filename}; - auto image = image_t{{width, height}, (vec4f*)pixels}; + auto ret = image{{width, height}, (vec4f*)pixels}; free(pixels); - return image; + return ret; } else if (ext == ".hdr" || ext == ".HDR") { auto buffer = load_binary(filename); auto width = 0, height = 0, ncomp = 0; auto pixels = stbi_loadf_from_memory( buffer.data(), (int)buffer.size(), &width, &height, &ncomp, 4); if (pixels == nullptr) throw io_error{"cannot read " + filename}; - auto image = image_t{{width, height}, (vec4f*)pixels}; + auto ret = image{{width, height}, (vec4f*)pixels}; free(pixels); - return image; + return ret; } else if (ext == ".png" || ext == ".PNG" || ext == ".jpg" || ext == ".JPG" || ext == ".jpeg" || ext == ".JPEG" || ext == ".tga" || ext == ".TGA" || ext == ".bmp" || ext == ".BMP") { return byte_to_float(load_imageb(filename)); } else if (ext == ".ypreset" || ext == ".YPRESET") { - auto image = make_image_preset(filename); - return is_srgb_preset(filename) ? srgb_to_rgb(image) : image; + auto ret = make_image_preset(filename); + return is_srgb_preset(filename) ? srgb_to_rgb(ret) : ret; } else { throw io_error{"unsupported format " + filename}; } } // Loads a byte image. -image_t load_imageb(const string& filename) { +image load_imageb(const string& filename) { auto ext = path_extension(filename); if (ext == ".exr" || ext == ".EXR" || ext == ".hdr" || ext == ".HDR") { return float_to_byte(load_image(filename)); @@ -489,9 +489,9 @@ image_t load_imageb(const string& filename) { auto pixels = stbi_load_from_memory( buffer.data(), (int)buffer.size(), &width, &height, &ncomp, 4); if (pixels == nullptr) throw io_error{"cannot read " + filename}; - auto image = image_t{{width, height}, (vec4b*)pixels}; + auto ret = image{{width, height}, (vec4b*)pixels}; free(pixels); - return image; + return ret; } else if (ext == ".ypreset" || ext == ".YPRESET") { return float_to_byte(load_image(filename)); } else { @@ -507,7 +507,7 @@ bool is_srgb_preset(const string& type_) { auto type = path_basename(type_); return type.find("sky") == string::npos; } -image_t make_image_preset(const string& type_) { +image make_image_preset(const string& type_) { auto type = path_basename(type_); auto extents = vec2i{1024, 1024}; if (type.find("sky") != string::npos) extents = {2048, 1024}; @@ -539,7 +539,7 @@ image_t make_image_preset(const string& type_) { } else if (type == "images1") { auto sub_types = vector{"grid", "uvgrid", "checker", "gammaramp", "bumps", "bump-normal", "noise", "fbm", "blackbodyramp"}; - auto sub_images = vector>(); + auto sub_images = vector>(); for (auto& sub_type : sub_types) sub_images.push_back(make_image_preset(sub_type)); auto montage_size = vec2i{0, 0}; @@ -547,7 +547,7 @@ image_t make_image_preset(const string& type_) { montage_size = {montage_size.x + sub_image.size().x, max(montage_size.y, sub_image.size().y)}; } - auto composite = image_t(montage_size); + auto composite = image(montage_size); auto pos = 0; for (auto& sub_image : sub_images) { set_region(composite, sub_image, {pos, 0}); @@ -556,7 +556,7 @@ image_t make_image_preset(const string& type_) { return composite; } else if (type == "images2") { auto sub_types = vector{"sky", "sunsky"}; - auto sub_images = vector>(); + auto sub_images = vector>(); for (auto& sub_type : sub_types) sub_images.push_back(make_image_preset(sub_type)); auto montage_size = vec2i{0, 0}; @@ -564,7 +564,7 @@ image_t make_image_preset(const string& type_) { montage_size = {montage_size.x + sub_image.size().x, max(montage_size.y, sub_image.size().y)}; } - auto composite = image_t(montage_size); + auto composite = image(montage_size); auto pos = 0; for (auto& sub_image : sub_images) { set_region(composite, sub_image, {pos, 0}); @@ -611,7 +611,7 @@ image_t make_image_preset(const string& type_) { } // Saves a float image. -void save_image(const string& filename, const image_t& image) { +void save_image(const string& filename, const image& image) { // write data auto stbi_write_data = [](void* context, void* data, int size) { auto& buffer = *(vector*)context; @@ -648,7 +648,7 @@ void save_image(const string& filename, const image_t& image) { } // Saves a byte image. -void save_imageb(const string& filename, const image_t& image) { +void save_imageb(const string& filename, const image& image) { // write data auto stbi_write_data = [](void* context, void* data, int size) { auto& buffer = *(vector*)context; diff --git a/libs/yocto/yocto_sceneio.h b/libs/yocto/yocto_sceneio.h index 3d12d30aa..b441caf55 100644 --- a/libs/yocto/yocto_sceneio.h +++ b/libs/yocto/yocto_sceneio.h @@ -79,17 +79,17 @@ bool is_linear_filename(const string& filename); bool is_srgb_filename(const string& filename); // Loads/saves a 4 channels float/byte image in linear/srgb color space. -image_t load_image(const string& filename); -void save_image(const string& filename, const image_t& image); +image load_image(const string& filename); +void save_image(const string& filename, const image& image); // Loads/saves a byte image. -image_t load_imageb(const string& filename); -void save_imageb(const string& filename, const image_t& image); +image load_imageb(const string& filename); +void save_imageb(const string& filename, const image& image); // Make presets. Supported mostly in IO. -bool is_linear_preset(const string& type_); -bool is_srgb_preset(const string& type_); -image_t make_image_preset(const string& type); +bool is_linear_preset(const string& type_); +bool is_srgb_preset(const string& type_); +image make_image_preset(const string& type); } // namespace yocto diff --git a/libs/yocto/yocto_trace.cpp b/libs/yocto/yocto_trace.cpp index 253fccc6f..a135de306 100644 --- a/libs/yocto/yocto_trace.cpp +++ b/libs/yocto/yocto_trace.cpp @@ -1523,17 +1523,17 @@ trace_state make_trace_state( : vec2i{(int)round(params.resolution * camera.aspect), params.resolution}; state.samples = 0; - state.render = image_t{resolution}; - state.albedo = image_t{resolution}; - state.normal = image_t{resolution}; - state.hits = image_t{resolution}; - state.rngs = image_t{resolution}; + state.render = image{resolution}; + state.albedo = image{resolution}; + state.normal = image{resolution}; + state.hits = image{resolution}; + state.rngs = image{resolution}; auto rng_ = make_rng(1301081); for (auto& rng : state.rngs) { rng = make_rng(params.seed, rand1i(rng_, 1 << 31) / 2 + 1); } if (params.denoise) { - state.denoised = image_t{resolution}; + state.denoised = image{resolution}; } return state; } @@ -1601,7 +1601,7 @@ trace_lights make_trace_lights( } // Convenience helper -image_t trace_image(const scene_data& scene, trace_sampler_type type, +image trace_image(const scene_data& scene, trace_sampler_type type, int resolution, int samples, int bounces) { auto params = trace_params{}; params.sampler = type; @@ -1618,8 +1618,7 @@ image_t trace_image(const scene_data& scene, trace_sampler_type type, } // Progressively computes an image. -image_t trace_image( - const scene_data& scene, const trace_params& params) { +image trace_image(const scene_data& scene, const trace_params& params) { auto bvh = make_trace_bvh(scene, params); auto lights = make_trace_lights(scene, params); auto state = make_trace_state(scene, params); @@ -1691,7 +1690,7 @@ void trace_cancel(trace_context& context) { // Async done bool trace_done(const trace_context& context) { return context.done; } -void trace_preview(image_t& image, trace_context& context, +void trace_preview(image& image, trace_context& context, trace_state& state, const scene_data& scene, const trace_bvh& bvh, const trace_lights& lights, const trace_params& params) { // preview @@ -1709,18 +1708,18 @@ void trace_preview(image_t& image, trace_context& context, // Check image type template -static void check_image(const image_t& image, vec2i size) { +static void check_image(const image& image, vec2i size) { if (image.size() != size) throw std::invalid_argument{"image should have the same size"}; } // Get resulting render, denoised if requested -image_t get_image(const trace_state& state) { - auto render = image_t{state.render.size()}; +image get_image(const trace_state& state) { + auto render = image{state.render.size()}; get_image(render, state); return render; } -void get_image(image_t& render, const trace_state& state) { +void get_image(image& render, const trace_state& state) { check_image(render, state.render.size()); if (state.denoised.empty()) { render = state.render; @@ -1730,21 +1729,21 @@ void get_image(image_t& render, const trace_state& state) { } // Get resulting render -image_t get_rendered_image(const trace_state& state) { +image get_rendered_image(const trace_state& state) { return state.render; } -void get_rendered_image(image_t& image, const trace_state& state) { +void get_rendered_image(image& image, const trace_state& state) { check_image(image, state.render.size()); image = state.render; } // Get denoised render -image_t get_denoised_image(const trace_state& state) { +image get_denoised_image(const trace_state& state) { auto image = state.render; get_denoised_image(image, state); return image; } -void get_denoised_image(image_t& image, const trace_state& state) { +void get_denoised_image(image& image, const trace_state& state) { #if YOCTO_DENOISE // Create an Intel Open Image Denoise device oidn::DeviceRef device = oidn::newDevice(); @@ -1778,28 +1777,24 @@ void get_denoised_image(image_t& image, const trace_state& state) { } // Get denoising buffers -image_t get_albedo_image(const trace_state& state) { - return state.albedo; -} -void get_albedo_image(image_t& albedo, const trace_state& state) { +image get_albedo_image(const trace_state& state) { return state.albedo; } +void get_albedo_image(image& albedo, const trace_state& state) { albedo = state.albedo; } -image_t get_normal_image(const trace_state& state) { - return state.normal; -} -void get_normal_image(image_t& normal, const trace_state& state) { +image get_normal_image(const trace_state& state) { return state.normal; } +void get_normal_image(image& normal, const trace_state& state) { normal = state.normal; } // Denoise image -image_t denoise_image(const image_t& render, - const image_t& albedo, const image_t& normal) { +image denoise_image(const image& render, + const image& albedo, const image& normal) { auto denoised = render; denoise_image(denoised, render, albedo, normal); return denoised; } -void denoise_image(image_t& denoised, const image_t& render, - const image_t& albedo, const image_t& normal) { +void denoise_image(image& denoised, const image& render, + const image& albedo, const image& normal) { check_image(denoised, render.size()); check_image(albedo, render.size()); check_image(normal, render.size()); diff --git a/libs/yocto/yocto_trace.h b/libs/yocto/yocto_trace.h index d12c9bea8..6aa6e39ba 100644 --- a/libs/yocto/yocto_trace.h +++ b/libs/yocto/yocto_trace.h @@ -114,15 +114,15 @@ struct trace_params { }; // Progressively computes an image. -image_t trace_image(const scene_data& scene, const trace_params& params); +image trace_image(const scene_data& scene, const trace_params& params); // Convenience helper -image_t trace_image(const scene_data& scene, +image trace_image(const scene_data& scene, trace_sampler_type type = trace_sampler_type::path, int resolution = 1440, int samples = 256, int bounces = 8); // Forward compatibility -inline image_t pathtrace_image(const scene_data& scene, +inline image pathtrace_image(const scene_data& scene, trace_sampler_type type = trace_sampler_type::path, int resolution = 1440, int samples = 256, int bounces = 8) { return trace_image(scene, type, resolution, samples, bounces); @@ -158,13 +158,13 @@ bool is_sampler_lit(const trace_params& params); // Trace state struct trace_state { - image_t render = {}; - image_t albedo = {}; - image_t normal = {}; - image_t hits = {}; - image_t rngs = {}; - image_t denoised = {}; - int samples = 0; + image render = {}; + image albedo = {}; + image normal = {}; + image hits = {}; + image rngs = {}; + image denoised = {}; + int samples = 0; vec2i size() const { return render.size(); } }; @@ -189,27 +189,27 @@ void trace_sample(trace_state& state, const scene_data& scene, const trace_params& params); // Get resulting render, denoised if requested -image_t get_image(const trace_state& state); -void get_image(image_t& image, const trace_state& state); +image get_image(const trace_state& state); +void get_image(image& image, const trace_state& state); // Get internal images from state -image_t get_rendered_image(const trace_state& state); -void get_rendered_image(image_t& image, const trace_state& state); -image_t get_denoised_image(const trace_state& state); -void get_denoised_image(image_t& image, const trace_state& state); -image_t get_albedo_image(const trace_state& state); -void get_albedo_image(image_t& image, const trace_state& state); -image_t get_normal_image(const trace_state& state); -void get_normal_image(image_t& image, const trace_state& state); +image get_rendered_image(const trace_state& state); +void get_rendered_image(image& image, const trace_state& state); +image get_denoised_image(const trace_state& state); +void get_denoised_image(image& image, const trace_state& state); +image get_albedo_image(const trace_state& state); +void get_albedo_image(image& image, const trace_state& state); +image get_normal_image(const trace_state& state); +void get_normal_image(image& image, const trace_state& state); // Denoise image -image_t denoise_image(const image_t& render, - const image_t& albedo, const image_t& normal); -void denoise_image(image_t& image, const image_t& render, - const image_t& albedo, const image_t& normal); -void denoise_image(vector& denoised, int width, int height, - const vector& render, const vector& albedo, - const vector& normal); +image denoise_image(const image& render, + const image& albedo, const image& normal); +void denoise_image(image& denoised, const image& render, + const image& albedo, const image& normal); +void denoise_image(vector& denoised, int width, int height, + const vector& render, const vector& albedo, + const vector& normal); // Async implementation struct trace_context { @@ -233,7 +233,7 @@ void trace_cancel(trace_context& context); void trace_done(trace_context& context); // Async preview -void trace_preview(image_t& image, trace_context& context, +void trace_preview(image& image, trace_context& context, trace_state& state, const scene_data& scene, const trace_bvh& bvh, const trace_lights& lights, const trace_params& params);