diff --git a/samples/.clang-format b/.clang-format similarity index 97% rename from samples/.clang-format rename to .clang-format index a114609f392618fec5fd1d6907e7298cc71d0ee7..cb0ac8b90a4575b18e8f0491ba08dca9ec846bd4 100644 --- a/samples/.clang-format +++ b/.clang-format @@ -54,3 +54,6 @@ AccessModifierOffset: -4 FixNamespaceComments: false AlignTrailingComments: true CommentPragmas: '!Api.*' + +# Includes +IncludeBlocks: Preserve \ No newline at end of file diff --git a/extern/AntTweakBar b/extern/AntTweakBar index 1095daea8d2577809aeb5293c445ef53f433bed8..ff1f8588a0e2a45fdb5f113d5d8a87775ceac3c7 160000 --- a/extern/AntTweakBar +++ b/extern/AntTweakBar @@ -1 +1 @@ -Subproject commit 1095daea8d2577809aeb5293c445ef53f433bed8 +Subproject commit ff1f8588a0e2a45fdb5f113d5d8a87775ceac3c7 diff --git a/extern/glow b/extern/glow index 9d530fdab79ef0ab428142e730866cb5e66a3188..fc0789b07bbb79044b020a4a3a8deee4b877d70b 160000 --- a/extern/glow +++ b/extern/glow @@ -1 +1 @@ -Subproject commit 9d530fdab79ef0ab428142e730866cb5e66a3188 +Subproject commit fc0789b07bbb79044b020a4a3a8deee4b877d70b diff --git a/extern/glow-extras b/extern/glow-extras index 2f3aa099ae50bed454a76911421db7279782464b..fef1175dbf808a72f4c497fd6f693dddbbeaa4b7 160000 --- a/extern/glow-extras +++ b/extern/glow-extras @@ -1 +1 @@ -Subproject commit 2f3aa099ae50bed454a76911421db7279782464b +Subproject commit fef1175dbf808a72f4c497fd6f693dddbbeaa4b7 diff --git a/extern/polymesh b/extern/polymesh index 57ca2e57105f4672f031dad0356f863343410cc8..129ee6f9efa0302b4ee9a0678326bee07cad0996 160000 --- a/extern/polymesh +++ b/extern/polymesh @@ -1 +1 @@ -Subproject commit 57ca2e57105f4672f031dad0356f863343410cc8 +Subproject commit 129ee6f9efa0302b4ee9a0678326bee07cad0996 diff --git a/extern/typed-geometry b/extern/typed-geometry index ac9db8c462fa3f41e84519b97ecfb8bfc9730820..aab762b3f57a650c6fe95a3762c79dfc65a699b6 160000 --- a/extern/typed-geometry +++ b/extern/typed-geometry @@ -1 +1 @@ -Subproject commit ac9db8c462fa3f41e84519b97ecfb8bfc9730820 +Subproject commit aab762b3f57a650c6fe95a3762c79dfc65a699b6 diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index aa2a58b2277d8e7513e31ffca3e97f4b34462df5..d008c685d00f65aedfd25ca7dbcd2d18201f0327 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -8,6 +8,7 @@ endif() file(GLOB_RECURSE mains "main.cc") foreach(main ${mains}) get_filename_component(path ${main} DIRECTORY) - message(STATUS "Adding sample ${path}") + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" spath ${path}) + message(STATUS "[glow samples] adding sample ${spath}") add_subdirectory(${path}) endforeach() diff --git a/samples/wip/viewer/CMakeLists.txt b/samples/basic/viewer/CMakeLists.txt similarity index 87% rename from samples/wip/viewer/CMakeLists.txt rename to samples/basic/viewer/CMakeLists.txt index 51759ec1c736e26f6101775d5ccbb833cfe4d7dd..7c84d677f87492f56196ec8100fa610537ffbf2c 100644 --- a/samples/wip/viewer/CMakeLists.txt +++ b/samples/basic/viewer/CMakeLists.txt @@ -8,7 +8,7 @@ file(GLOB_RECURSE SOURCES "*.cc" "*.hh" "*.*sh") add_executable(${PROJECT_NAME} ${SOURCES}) target_link_libraries(${PROJECT_NAME} PUBLIC glow glow-extras glfw polymesh) target_compile_options(${PROJECT_NAME} PUBLIC ${GLOW_SAMPLES_DEF_OPTIONS}) -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Samples/WIP") +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Samples/Basic") if (GLOW_EXTRAS_EMBED_SHADERS) target_compile_definitions(${PROJECT_NAME} PUBLIC GLOW_SAMPLES_VIEWER_EMBED_SHADERS) diff --git a/samples/basic/viewer/main.cc b/samples/basic/viewer/main.cc new file mode 100644 index 0000000000000000000000000000000000000000..c16c926b20649bd76e08d8c0e73d289323e87685 --- /dev/null +++ b/samples/basic/viewer/main.cc @@ -0,0 +1,444 @@ +#include <imgui/imgui.h> + +#include <glow/common/str_utils.hh> +#include <glow/data/TextureData.hh> +#include <glow/objects/TextureCubeMap.hh> +#include <glow/util/AsyncTextureLoader.hh> + +#include <polymesh/algorithms/normalize.hh> +#include <polymesh/formats.hh> +#include <polymesh/objects/quad.hh> + +#include <glow-extras/glfw/GlfwContext.hh> +#include <glow-extras/vector/graphics2D.hh> +#include <glow-extras/vector/image2D.hh> +#include <glow-extras/viewer/view.hh> + +#include <typed-geometry/tg.hh> + +void simple_view(pm::vertex_attribute<tg::pos3> const& pos) +{ + // the simplest possible view: just a mesh + gv::view(pos); +} + +void basic_concepts(pm::vertex_attribute<tg::pos3> const& pos) +{ + // gv::view(obj, args...) takes some object and a list of arguments + // - the object is converted via make_renderable(obj) into a gv::SharedRenderable + // - for each arg, configure(r, arg) is called (where r is the created gv::Renderable&) + // - arguments can change the renderable, the scene, or global settings (see advanced_config function for more) + + // gv::view(...); opens a view at the end of the statement + // auto v = gv::view(...); opens the view when `v` is destroyed + // - all views created while `v` is alive are added to the same scene + // - auto g = gv::grid(); creates a container view and views are added as grid cells while `g` is alive + + auto g = gv::grid(); + + // a named view (shown in lower-left corner) + gv::view(pos, "Suzanne"); + + // no grid + gv::view(pos, gv::no_grid); + + // colored mesh + gv::view(pos, tg::color3::red); + + // different object + gv::view(tg::sphere3::unit); + + // multiple objects in the same scene + { + auto v = gv::view(pos); + gv::view(pos, tg::translation(2, 0, 0)); + gv::view(tg::sphere3::unit, tg::translation(-2, 0, 0)); + } +} + +void advanced_objects(pm::vertex_attribute<tg::pos3> const& pos) +{ + // + // gv::opaque, gv::transparent +} + +void advanced_visualization(pm::vertex_attribute<tg::pos3> const& pos) +{ + // + // gv::opaque, gv::transparent +} + +void advanced_configs(pm::vertex_attribute<tg::pos3> const& pos) +{ + // with this macro, all configurations are added to ALL views created until the end of the scope + GLOW_VIEWER_CONFIG(gv::dark_ui); + + auto g = gv::grid(); + + // graphics settings + gv::view(pos, gv::no_grid, "no grid"); + gv::view(pos, gv::no_shadow, "no shadow"); + gv::view(pos, gv::no_outline, "no outline"); + gv::view(pos, gv::no_ssao, "no ssao"); + gv::view(pos, gv::print_mode, "print-friendly mode"); + gv::view(pos, gv::ssao_power(1.0f), "weaker SSAO"); + gv::view(pos, gv::ssao_radius(0.2f), "smaller SSAO"); + gv::view(pos, gv::background_color(tg::color3::blue), "custom BG color"); + gv::view(pos, gv::tonemap_exposure(1.5f), "tonemapping"); + + // some configurations have booleans that can be passed + gv::view(pos, gv::print_mode(false), "disabled print mode"); +} + +void interactive_viewer(pm::vertex_attribute<tg::pos3> const& pos) +{ + // +} + +void custom_renderables() +{ + // +} + +void headless_screenshot(pm::vertex_attribute<tg::pos3> const& pos) +{ + // Viewer never shows a window, returns once screenshot is rendered + GLOW_VIEWER_CONFIG(gv::headless_screenshot(tg::ivec2(1000, 1000), 32, "demo_screenshot.png")); + gv::view(pos); +} + +void special_use_cases(pm::vertex_attribute<tg::pos3> const& pos) +{ + gv::view(pos, gv::maybe_empty, "allows empty renderable"); + + gv::view(pos, gv::infinite_accumulation, "progressive rendering is not stopped early"); + + // global settings (affect complete viewer) + gv::view(pos, gv::dark_ui, "dark mode"); + gv::view(pos, gv::no_left_mouse_control, "disabled left mouse interaction"); + gv::view(pos, gv::no_right_mouse_control, "disabled right mouse interaction"); + { + auto g = gv::grid(); + gv::view(pos, gv::subview_margin(5, tg::color3::red), "custom grid margin and color"); + gv::view(pos); + gv::view(pos); + gv::view(pos); + } +} + +int main() +{ + std::string const dataPath = glow::util::pathOf(__FILE__) + "/../../../data/"; + + // Create a context + glow::glfw::GlfwContext ctx; + + tg::rng rng; + + // Load a sample polymesh mesh + pm::Mesh m; + auto pos = m.vertices().make_attribute<tg::pos3>(); + load(dataPath + "suzanne.obj", m, pos); + normalize(pos); // make it -1..1 + + // prepare some data + pm::vertex_attribute<glm::vec2> uv = pos.map([](tg::pos3 v) { return glm::vec2(v.x, v.y); }); + pm::vertex_attribute<float> vdata = pos.map([](tg::pos3 v) { return v.y; }); + pm::vertex_attribute<tg::vec3> vnormals = vertex_normals_by_area(pos); + pm::face_attribute<float> fdata = m.faces().map([&](pm::face_handle f) { return f.vertices().avg(pos).z; }); + glow::SharedTexture2D tex = glow::Texture2D::createFromFile(dataPath + "textures/tiles.color.png", glow::ColorSpace::sRGB); + glow::AsyncTexture2D atex = glow::AsyncTextureLoader::load2D(dataPath + "textures/tiles.color.png", glow::ColorSpace::sRGB); + pm::face_attribute<tg::color3> fcolors = m.faces().map([&](pm::face_handle) { return tg::uniform<tg::color3>(rng); }); + pm::vertex_attribute<tg::color3> vcolors = attribute(m.vertices(), tg::color3(1, 0, 0)); + pm::edge_attribute<float> edge_lengths = m.edges().map([&](pm::edge_handle e) { return edge_length(e, pos); }); + pm::vertex_attribute<float> ptsize = m.vertices().map([&](pm::vertex_handle v) { return v.edges().avg(edge_lengths); }); + + // demo views + { + simple_view(pos); + + basic_concepts(pos); + + advanced_objects(pos); + + advanced_visualization(pos); + + advanced_configs(pos); + + interactive_viewer(pos); + + custom_renderables(); + + special_use_cases(pos); + + headless_screenshot(pos); + } + + // Grid of examples + { + auto v = gv::grid(); + + // Scoped configuration + { + GLOW_VIEWER_CONFIG(gv::no_grid); + + // ADL view + gv::view(pos); + } + + // smooth normals + gv::view(gv::polygons(pos).smooth_normals(), "smoothed normals"); + + // Configuration nesting + { + GLOW_VIEWER_CONFIG(gv::print_mode); + + // Colored faces + gv::view(pos, fcolors, "colored faces"); + + { + GLOW_VIEWER_CONFIG(gv::no_shadow); + + // Colored vertices + gv::view(pos, vcolors, "colored vertices"); + } + } + + // Mapped 1D vertex data + gv::view(pos, gv::mapping(vdata).linear({0, 0, 0}, {1, 0, 0}, 0.1f, 0.3f), "vertex data"); + + // Mapped 1D face data + gv::view(pos, gv::mapping(fdata).linear({0, 1, 0}, {0, 0, 1}, -0.5f, 0.5f).clamped(), "face data"); + + // Textured mesh + gv::view(pos, gv::textured(uv, tex), "textured"); + + // Textured mesh (async texture) + gv::view(pos, gv::textured(uv, atex), "textured (async)"); + + // Simple point cloud + gv::view(gv::points(pos), "point cloud"); + + // Square, oriented point cloud with adaptive point size + gv::view(gv::points(pos).point_size_world(ptsize).normals(vnormals).square(), "normal oriented squares"); + + // Points rendered as 3D spheres + gv::view(gv::points(pos).spheres().point_size_world(0.03f), "sphere cloud"); + + // Simple line soup + gv::view(gv::lines(pos), "edges"); + + // Configure view + { + auto v = gv::view(); + v.view(pos, glow::colors::color(0, 1, 0), "configured view"); + // when out-of-scope, v immediately shows + } + + // Multiple objects + { + auto v = gv::view(); + v.view(gv::polygons(pos).move({-1.5f, 0, 0}), glow::colors::color(1, 0, 0), "multiple objects"); + v.view(gv::polygons(pos).move({+1.5f, 0, 0}), glow::colors::color(0, 0, 1)); + + // or: + v.view(pos, scaling(tg::size3(0.5f, 1, 1.5f)), glow::colors::color(0, 1, 0)); + } + + // transparencies + gv::view(pos, tg::color4(0, 0.4f, 0.3f, 0.2f), "transparency with fresnel"); + gv::view(pos, tg::color4(0, 0.4f, 0.3f, 0.2f), gv::no_fresnel, "transparency without fresnel"); + + // Complex material + // TODO + + // Text + // TODO + + // Vector Graphics + // see Vector2DSample for more sample code + { + glow::vector::image2D img; + auto g = graphics(img); + g.fill(tg::disk2({100.f, 100.f}, 70), tg::color3::red); + g.draw(tg::circle2({100.f, 100.f}, 70), {tg::color3::black, 2}); + gv::view(img); + } + + // Images + // TODO + + // Scene setup + // TODO + + // Multiple views + { + auto v = gv::columns(); + gv::view(pos, glow::colors::color(0, 0, 1)); // attaches to columns view + v.view(pos, glow::colors::color(0, 0, 1)); // explicitly adds view + { + auto r = v.rows(); + r.view(pos, glow::colors::color(0, 1, 1)); + r.view(pos, glow::colors::color(1, 1, 0)); + // when out-of-scope, r attaches to v + } + // when out-of-scope, v immediately shows + } + + // Picking + { + // TODO + } + } + + // Interactive + { + auto v = gv::grid(); + + // Non-interactive + gv::view(pos); + + // Interactive + { + // Creating renderables is expensive, cache them whenever possible, and capture by value! + auto r1 = gv::make_renderable(pos); + gv::interactive([r1](auto dt) { + static auto time = 0.f; + time += dt; + + // Always a cleared view, resetting accumulation each frame + gv::view_cleared(r1, tg::translation(tg::vec3(tg::sin(tg::radians(time * .5f)) * .5f, 0.f, 0.f))); + }); + + // Using imgui in an interactive view + auto r2 = gv::make_renderable(pos); + gv::interactive([r2](auto) { + static float configurable = 0.f; + + auto const input = ImGui::SliderFloat("Height", &configurable, -3.f, 3.f); + + // conditionally clear view if input has changed + gv::view(r2, tg::translation(tg::vec3(0.f, configurable, 0.f)), gv::clear_accumulation(input)); + }); + } + } + + // Conditional RAII objects + { + // Use an outer viewer object conditionally + auto o = (sizeof(int) > 1) ? gv::rows() : gv::nothing(); + + { + // Camera starting position + GLOW_VIEWER_CONFIG(gv::camera_orientation(125_deg, -15_deg, 1.7f)); + + // Tonemapping + GLOW_VIEWER_CONFIG(gv::tonemap_exposure(3.5f)); + + // These two either nest into the outer object, or create their own windows + gv::view(pos, gv::textured(uv, tex)); + gv::view(gv::points(pos)); + } + } + + // tg objects + { + auto v = gv::grid(); + tg::rng rng; + + gv::view(tg::segment3(tg::pos3(0, 0, 0), tg::pos3(1, 0, 0)), tg::color3::red); + gv::view(tg::triangle3({0, 0, 0}, {1, 0, 0}, {0, 1, 0}), tg::color3::blue); + gv::view(tg::aabb3({-0.3f, 0, -0.4f}, {0.2f, 0.5f, 0.1f}), tg::color3::green); + gv::view(gv::lines(tg::aabb3({-0.3f, 0, -0.4f}, {0.2f, 0.5f, 0.1f}))); + + // vector versions + { + std::vector<tg::segment3> segs; + for (auto i = 0; i < 20; ++i) + segs.emplace_back(uniform(rng, tg::sphere3::unit), uniform(rng, tg::sphere3::unit)); + gv::view(segs); + } + { + std::vector<tg::triangle3> tris; + for (auto i = 0; i < 20; ++i) + tris.emplace_back(uniform(rng, tg::sphere3::unit), uniform(rng, tg::sphere3::unit), uniform(rng, tg::sphere3::unit)); + gv::view(tris); + } + { + std::vector<tg::pos3> pts; + for (auto i = 0; i < 500; ++i) + pts.push_back(uniform(rng, tg::sphere3::unit)); + gv::view(pts); + } + + { + std::vector<tg::box3> bbs; + for (auto i = 0; i < 4; ++i) + { + auto e0 = uniform_vec(rng, tg::sphere3::unit); + auto e1 = cross(e0, uniform_vec(rng, tg::sphere3::unit)); + auto e2 = cross(e1, e0); + + auto c = uniform(rng, tg::sphere3::unit); + + e0 = normalize(e0) * uniform(rng, 0.2f, 0.5f); + e1 = normalize(e1) * uniform(rng, 0.2f, 0.5f); + e2 = normalize(e2) * uniform(rng, 0.2f, 0.5f); + bbs.push_back(tg::box3(c, {e0, e1, e2})); + } + + gv::view(gv::lines(bbs)); + gv::view(bbs); + } + } + + // custom close keys + { + gv::view(pos, gv::close_keys('A', 'B', 'C')); + glow::info() << gv::get_last_close_info().closed_by_key; + } + + // Interactive Torus + { + pm::Mesh m; + + auto pos = m.vertices().make_attribute<tg::pos3>(); + auto uv = m.vertices().make_attribute<glm::vec2>(); + pm::objects::add_quad( + m, + [&](pm::vertex_handle v, float x, float y) { + auto [cx, sx] = tg::sin_cos(tg::pi<float> * 2 * x); + auto [cy, sy] = tg::sin_cos(tg::pi<float> * 2 * y); + auto orad = 8.f; + auto irad = 3.f; + tg::vec3 t; + t.x = cx; + t.z = sx; + tg::pos3 p; + p.x = orad * cx; + p.y = irad * cy; + p.z = orad * sx; + p += t * irad * sy; + pos[v] = p; + uv[v] = {1 - x, y}; + }, + 32, 32); + + auto a = 0.f; + auto animate = false; + gv::interactive([&](auto dt) { + ImGui::Begin("Torus"); + auto changed = ImGui::SliderFloat("angle", &a, 0.f, 360.f); + ImGui::Checkbox("Animate", &animate); + ImGui::End(); + + if (animate) + a += 5 * dt; + changed |= animate; + + view(pos, gv::textured(uv, tex).transform(tg::rotation_around(tg::pos2::zero, tg::degree(a))), gv::clear_accumulation(changed)); + }); + } + + return 0; +} diff --git a/samples/wip/viewer/main.cc b/samples/wip/viewer/main.cc deleted file mode 100644 index 1410ed925149e65c72ea644f7f22931124696d45..0000000000000000000000000000000000000000 --- a/samples/wip/viewer/main.cc +++ /dev/null @@ -1,330 +0,0 @@ -#include <random> - -#include <imgui/imgui.h> - -#include <glow/common/str_utils.hh> -#include <glow/data/TextureData.hh> -#include <glow/objects/TextureCubeMap.hh> -#include <glow/util/AsyncTextureLoader.hh> - -#include <polymesh/algorithms/normalize.hh> -#include <polymesh/formats.hh> -#include <polymesh/objects/quad.hh> - -#include <glow-extras/glfw/GlfwContext.hh> -#include <glow-extras/vector/graphics2D.hh> -#include <glow-extras/vector/image2D.hh> -#include <glow-extras/viewer/view.hh> - -#include <GLFW/glfw3.h> - -#include <typed-geometry/tg.hh> - -int main() -{ - std::string const dataPath = glow::util::pathOf(__FILE__) + "/../../../data/"; - - // Create a context - glow::glfw::GlfwContext ctx; - - std::uniform_real_distribution<float> dis(0.0f, 1.0f); - std::default_random_engine rng; - - // Load a polymesh mesh - pm::Mesh m; - auto pos = m.vertices().make_attribute<tg::pos3>(); - load(dataPath + "suzanne.obj", m, pos); - normalize(pos); // make it -1..1 - - // prepare some data - pm::vertex_attribute<glm::vec2> uv = pos.map([](tg::pos3 v) { return glm::vec2(v.x, v.y); }); - pm::vertex_attribute<float> vdata = pos.map([](tg::pos3 v) { return v.y; }); - pm::vertex_attribute<tg::vec3> vnormals = vertex_normals_by_area(pos); - pm::face_attribute<float> fdata = m.faces().map([&](pm::face_handle f) { return f.vertices().avg(pos).z; }); - glow::SharedTexture2D tex = glow::Texture2D::createFromFile(dataPath + "textures/tiles.color.png", glow::ColorSpace::sRGB); - glow::AsyncTexture2D atex = glow::AsyncTextureLoader::load2D(dataPath + "textures/tiles.color.png", glow::ColorSpace::sRGB); - pm::face_attribute<glow::colors::color> fcolors = m.faces().map([&](pm::face_handle) { return glow::colors::color(dis(rng), dis(rng), dis(rng)); }); - pm::vertex_attribute<glow::colors::color> vcolors = attribute(m.vertices(), glow::colors::color(1, 0, 0)); - pm::edge_attribute<float> edge_lengths = m.edges().map([&](pm::edge_handle e) { return edge_length(e, pos); }); - pm::vertex_attribute<float> ptsize = m.vertices().map([&](pm::vertex_handle v) { return v.edges().avg(edge_lengths); }); - - // Simplest view - gv::view(pos); - - // Grid of examples - { - auto v = glow::viewer::grid(); - - // Scoped configuration - { - GLOW_VIEWER_CONFIG(glow::viewer::no_grid); - - // ADL view - view(pos); - } - - // named view - view(pos, "Suzanne"); - - // smooth normals - view(polygons(pos).smooth_normals(), "smoothed normals"); - - // Configuration nesting - { - GLOW_VIEWER_CONFIG(glow::viewer::print_mode); - - // Colored faces - view(pos, fcolors, "colored faces"); - - { - GLOW_VIEWER_CONFIG(glow::viewer::no_shadow); - - // Colored vertices - view(pos, vcolors, "colored vertices"); - } - } - - // Mapped 1D vertex data - view(pos, mapping(vdata).linear({0, 0, 0}, {1, 0, 0}, 0.1f, 0.3f), "vertex data"); - - // Mapped 1D face data - view(pos, mapping(fdata).linear({0, 1, 0}, {0, 0, 1}, -0.5f, 0.5f).clamped(), "face data"); - - // Textured mesh - view(pos, textured(uv, tex), "textured"); - - // Textured mesh (async texture) - view(pos, textured(uv, atex), "textured (async)"); - - // Simple point cloud - view(points(pos), "point cloud"); - - // Square, oriented point cloud with adaptive point size - view(points(pos).point_size_world(ptsize).normals(vnormals).square(), "normal oriented squares"); - - // Points rendered as 3D spheres - view(points(pos).spheres().point_size_world(0.03f), "sphere cloud"); - - // Simple line soup - view(lines(pos), "edges"); - - // Configure view - { - auto v = glow::viewer::view(); - v.view(pos, glow::colors::color(0, 1, 0), "configured view"); - // when out-of-scope, v immediately shows - } - - // Multiple objects - { - auto v = glow::viewer::view(); - v.view(polygons(pos).move({-1.5f, 0, 0}), glow::colors::color(1, 0, 0), "multiple objects"); - v.view(polygons(pos).move({+1.5f, 0, 0}), glow::colors::color(0, 0, 1)); - - // or: - v.view(pos, scaling(tg::size3(0.5f, 1, 1.5f)), glow::colors::color(0, 1, 0)); - } - - // transparencies - view(pos, tg::color4(0, 0.4f, 0.3f, 0.2f), "transparency with fresnel"); - view(pos, tg::color4(0, 0.4f, 0.3f, 0.2f), glow::viewer::no_fresnel, "transparency without fresnel"); - - // Complex material - // TODO - - // Text - // TODO - - // Vector Graphics - // see Vector2DSample for more sample code - { - glow::vector::image2D img; - auto g = graphics(img); - g.fill(tg::disk2({100, 100}, 70), tg::color3::red); - g.draw(tg::circle2({100, 100}, 70), {tg::color3::black, 2}); - view(img); - } - - // Images - // TODO - - // Scene setup - // TODO - - // Multiple views - { - auto v = glow::viewer::columns(); - glow::viewer::view(pos, glow::colors::color(0, 0, 1)); // attaches to columns view - v.view(pos, glow::colors::color(0, 0, 1)); // explicitly adds view - { - auto r = v.rows(); - r.view(pos, glow::colors::color(0, 1, 1)); - r.view(pos, glow::colors::color(1, 1, 0)); - // when out-of-scope, r attaches to v - } - // when out-of-scope, v immediately shows - } - - // Picking - { - // TODO - } - } - - // Interactive - { - auto v = glow::viewer::grid(); - - // Non-interactive - glow::viewer::view(pos); - - // Interactive - { - // Creating renderables is expensive, cache them whenever possible, and capture by value! - auto r1 = glow::viewer::make_renderable(pos); - glow::viewer::interactive([r1](auto dt) { - static auto time = 0.f; - time += dt; - - // Always a cleared view, resetting accumulation each frame - glow::viewer::view_cleared(r1, tg::translation(tg::vec3(tg::sin(tg::radians(time * .5f)) * .5f, 0.f, 0.f))); - }); - - // Using imgui in an interactive view - auto r2 = glow::viewer::make_renderable(pos); - glow::viewer::interactive([r2](auto) { - static float configurable = 0.f; - - auto const input = ImGui::SliderFloat("Height", &configurable, -3.f, 3.f); - - // conditionally clear view if input has changed - glow::viewer::view(r2, tg::translation(tg::vec3(0.f, configurable, 0.f)), glow::viewer::clear_accumulation(input)); - }); - } - } - - // Create a "headless" screenshot - { - // Viewer never shows a window, returns once screenshot is rendered - GLOW_VIEWER_CONFIG(glow::viewer::headless_screenshot(tg::ivec2(1000, 1000), 32, "demo_screenshot.png")); - glow::viewer::view(pos); - } - - // Conditional RAII objects - { - // Use an outer viewer object conditionally - auto o = (sizeof(int) > 1) ? glow::viewer::rows() : glow::viewer::nothing(); - - { - // Camera starting position - GLOW_VIEWER_CONFIG(glow::viewer::camera_orientation(125_deg, -15_deg, 1.7f)); - - // Tonemapping - GLOW_VIEWER_CONFIG(glow::viewer::tonemap_exposure(3.5f)); - - // These two either nest into the outer object, or create their own windows - view(pos, textured(uv, tex)); - view(points(pos)); - } - } - - // tg objects - { - auto v = glow::viewer::grid(); - tg::rng rng; - - view(tg::segment3(tg::pos3(0, 0, 0), tg::pos3(1, 0, 0)), tg::color3::red); - view(tg::triangle3({0, 0, 0}, {1, 0, 0}, {0, 1, 0}), tg::color3::blue); - view(tg::aabb3({-0.3f, 0, -0.4f}, {0.2f, 0.5f, 0.1f}), tg::color3::green); - view(lines(tg::aabb3({-0.3f, 0, -0.4f}, {0.2f, 0.5f, 0.1f}))); - - // vector versions - { - std::vector<tg::segment3> segs; - for (auto i = 0; i < 20; ++i) - segs.emplace_back(uniform(rng, tg::sphere3::unit), uniform(rng, tg::sphere3::unit)); - view(segs); - } - { - std::vector<tg::triangle3> tris; - for (auto i = 0; i < 20; ++i) - tris.emplace_back(uniform(rng, tg::sphere3::unit), uniform(rng, tg::sphere3::unit), uniform(rng, tg::sphere3::unit)); - view(tris); - } - { - std::vector<tg::pos3> pts; - for (auto i = 0; i < 500; ++i) - pts.push_back(uniform(rng, tg::sphere3::unit)); - view(pts); - } - - { - std::vector<tg::box3> bbs; - for (auto i = 0; i < 4; ++i) - { - auto e0 = uniform_vec(rng, tg::sphere3::unit); - auto e1 = cross(e0, uniform_vec(rng, tg::sphere3::unit)); - auto e2 = cross(e1, e0); - - auto c = uniform(rng, tg::sphere3::unit); - - e0 = normalize(e0) * uniform(rng, 0.2f, 0.5f); - e1 = normalize(e1) * uniform(rng, 0.2f, 0.5f); - e2 = normalize(e2) * uniform(rng, 0.2f, 0.5f); - bbs.push_back(tg::box3(c, {e0, e1, e2})); - } - - view(lines(bbs)); - view(bbs); - } - } - - // custom close keys - { - gv::view(pos, gv::close_keys('A', 'B', 'C')); - glow::info() << gv::get_last_close_info().closed_by_key; - } - - // Interactive Torus - { - pm::Mesh m; - - auto pos = m.vertices().make_attribute<tg::pos3>(); - auto uv = m.vertices().make_attribute<glm::vec2>(); - pm::objects::add_quad(m, - [&](pm::vertex_handle v, float x, float y) { - auto [cx, sx] = tg::sin_cos(tg::pi<float> * 2 * x); - auto [cy, sy] = tg::sin_cos(tg::pi<float> * 2 * y); - auto orad = 8.f; - auto irad = 3.f; - tg::vec3 t; - t.x = cx; - t.z = sx; - tg::pos3 p; - p.x = orad * cx; - p.y = irad * cy; - p.z = orad * sx; - p += t * irad * sy; - pos[v] = p; - uv[v] = {1 - x, y}; - }, - 32, 32); - - auto a = 0.f; - auto animate = false; - glow::viewer::interactive([&](auto dt) { - ImGui::Begin("Torus"); - auto changed = ImGui::SliderFloat("angle", &a, 0.f, 360.f); - ImGui::Checkbox("Animate", &animate); - ImGui::End(); - - if (animate) - a += 5 * dt; - changed |= animate; - - view(pos, glow::viewer::textured(uv, tex).transform(tg::rotation_around(tg::pos2::zero, tg::degree(a))), glow::viewer::clear_accumulation(changed)); - }); - } - - return 0; -}