From 8ed20cd99505c5a979a14dea7bd177ec2d66b918 Mon Sep 17 00:00:00 2001 From: Giorgio Gori Date: Tue, 1 Jun 2021 13:31:04 -0700 Subject: [PATCH] Sync with 31b6b34 --- CMakeLists.txt | 2 +- cmake/lagrange/lagrange_add_test.cmake | 11 +- cmake/recipes/external/assimp.cmake | 3 +- cmake/recipes/external/boost.cmake | 10 +- cmake/recipes/external/entt.cmake | 26 + cmake/recipes/external/gl3w.cmake | 2 +- cmake/recipes/external/imgui.cmake | 46 +- cmake/recipes/external/lagrange-assets.cmake | 2 +- cmake/recipes/external/openvdb.cmake | 42 +- modules/core/CMakeLists.txt | 2 +- .../core/include/lagrange/utils/geometry3d.h | 152 +- modules/core/performance/CMakeLists.txt | 3 +- modules/core/performance/marquee.cpp | 99 -- .../core/performance/view_tangent_frame.cpp | 75 +- .../test_resolve_nonmanifoldness.cpp | 10 - modules/fs/tests/CMakeLists.txt | 4 +- .../io/include/lagrange/io/load_mesh_assimp.h | 51 +- modules/testing/CMakeLists.txt | 3 +- .../testing/include/lagrange/testing/common.h | 15 + modules/ui/CMakeLists.txt | 39 +- modules/ui/README.md | 693 +++++++++ modules/ui/examples/CMakeLists.txt | 9 +- modules/ui/examples/ui_basic/main.cpp | 130 -- .../{ui_viz => ui_callbacks}/CMakeLists.txt | 12 +- modules/ui/examples/ui_callbacks/main.cpp | 110 ++ .../examples/ui_dynamic_mesh/CMakeLists.txt | 28 + modules/ui/examples/ui_dynamic_mesh/main.cpp | 127 ++ modules/ui/examples/ui_mesh/main.cpp | 306 ---- .../ui/examples/ui_playground/CMakeLists.txt | 28 + modules/ui/examples/ui_playground/main.cpp | 354 +++++ .../{ui_basic => ui_scene}/CMakeLists.txt | 9 +- modules/ui/examples/ui_scene/main.cpp | 50 + .../examples/ui_show_attribute/CMakeLists.txt | 28 + .../ui/examples/ui_show_attribute/main.cpp | 150 ++ .../{ui_mesh => ui_treenode}/CMakeLists.txt | 10 +- modules/ui/examples/ui_treenode/main.cpp | 58 + modules/ui/examples/ui_viz/VizBuilder.cpp | 246 ---- modules/ui/examples/ui_viz/VizBuilder.h | 92 -- .../examples/ui_viz/initialize_attributes.h | 74 - modules/ui/examples/ui_viz/main.cpp | 191 --- .../ui/include/lagrange/ui/BaseResourceData.h | 84 -- modules/ui/include/lagrange/ui/Callbacks.h | 158 -- modules/ui/include/lagrange/ui/CameraUI.h | 62 - modules/ui/include/lagrange/ui/DetailUI.h | 63 - modules/ui/include/lagrange/ui/Emitter.h | 61 - modules/ui/include/lagrange/ui/Entity.h | 120 ++ .../ui/include/lagrange/ui/FunctionUtils.h | 45 - modules/ui/include/lagrange/ui/IBL.h | 72 - modules/ui/include/lagrange/ui/Light.h | 90 -- modules/ui/include/lagrange/ui/Material.h | 97 -- modules/ui/include/lagrange/ui/MeshBuffer.h | 134 -- .../include/lagrange/ui/MeshBufferFactory.h | 73 - modules/ui/include/lagrange/ui/MeshModel.h | 180 --- .../ui/include/lagrange/ui/MeshModelBase.h | 110 -- modules/ui/include/lagrange/ui/Model.h | 474 ------ modules/ui/include/lagrange/ui/ModelFactory.h | 200 --- modules/ui/include/lagrange/ui/Options.h | 209 --- modules/ui/include/lagrange/ui/ProxyMesh.h | 296 ---- modules/ui/include/lagrange/ui/RenderPass.h | 154 -- .../ui/include/lagrange/ui/RenderPipeline.h | 107 -- .../lagrange/ui/RenderResourceBuilder.h | 91 -- modules/ui/include/lagrange/ui/RenderUtils.h | 71 - modules/ui/include/lagrange/ui/Renderer.h | 187 --- modules/ui/include/lagrange/ui/RendererUI.h | 64 - modules/ui/include/lagrange/ui/Resource.h | 310 ---- modules/ui/include/lagrange/ui/ResourceData.h | 70 - .../ui/include/lagrange/ui/ResourceFactory.h | 207 --- modules/ui/include/lagrange/ui/Scene.h | 146 -- modules/ui/include/lagrange/ui/SceneUI.h | 98 -- modules/ui/include/lagrange/ui/Selection.h | 211 --- modules/ui/include/lagrange/ui/SelectionUI.h | 85 -- modules/ui/include/lagrange/ui/Shader.h | 116 -- modules/ui/include/lagrange/ui/ToolbarUI.h | 53 - modules/ui/include/lagrange/ui/UI.h | 39 +- modules/ui/include/lagrange/ui/UIPanel.h | 161 --- modules/ui/include/lagrange/ui/Viewer.h | 277 +--- modules/ui/include/lagrange/ui/Viewport.h | 85 -- modules/ui/include/lagrange/ui/ViewportUI.h | 180 --- modules/ui/include/lagrange/ui/Viz.h | 375 ----- modules/ui/include/lagrange/ui/Worker.h | 40 - .../ui/components/AcceleratedPicking.h | 33 + .../lagrange/ui/components/AttributeRender.h | 33 + .../lagrange/ui/components/Bounds.h} | 27 +- .../lagrange/ui/components/CameraComponents.h | 70 + .../include/lagrange/ui/components/Common.h | 54 + .../ElementSelection.h} | 17 +- .../lagrange/ui/components/EventEmitter.h | 26 + .../include/lagrange/ui/components/GLMesh.h | 81 ++ .../ui/include/lagrange/ui/components/IBL.h | 42 + .../ui/include/lagrange/ui/components/Input.h | 31 + .../ui/{LogUI.h => components/Layer.h} | 37 +- .../ui/include/lagrange/ui/components/Light.h | 38 + .../include/lagrange/ui/components/MeshData.h | 34 + .../lagrange/ui/components/MeshGeometry.h | 27 + .../NormalsPass.h => components/MeshRender.h} | 26 +- .../ui/components/MeshSelectionRender.h | 40 + .../lagrange/ui/components/ObjectIDViewport.h | 27 + .../RenderContext.h} | 32 +- .../lagrange/ui/components/Selection.h} | 20 +- .../lagrange/ui/components/SelectionContext.h | 94 ++ .../ui/components/SelectionViewport.h | 27 + .../FXAAPass.h => components/ShadowMap.h} | 24 +- .../BRDFLUTPass.h => components/Transform.h} | 28 +- .../include/lagrange/ui/components/TreeNode.h | 33 + .../include/lagrange/ui/components/UIPanel.h | 96 ++ .../VertexData.h} | 36 +- .../include/lagrange/ui/components/Viewport.h | 88 ++ .../include/lagrange/ui/default_components.h | 43 + .../ui/include/lagrange/ui/default_entities.h | 217 +++ .../ui/include/lagrange/ui/default_events.h | 61 + modules/ui/include/lagrange/ui/default_ibls.h | 8 +- .../ui/include/lagrange/ui/default_keybinds.h | 2 +- .../ui/include/lagrange/ui/default_panels.h | 38 + .../lagrange/ui/default_render_passes.h | 112 -- .../include/lagrange/ui/default_resources.h | 229 --- .../ui/include/lagrange/ui/default_shaders.h | 58 + .../ui/include/lagrange/ui/default_tools.h | 87 ++ .../lagrange/ui/{ => imgui}/UIWidget.h | 41 +- .../ui/{BaseObject.h => imgui/buttons.h} | 54 +- .../lagrange/ui/{ => imgui}/imconfig.h | 92 +- .../lagrange/ui/panels/ComponentPanel.h | 24 + .../lagrange/ui/panels/KeybindsPanel.h | 22 + .../include/lagrange/ui/panels/LoggerPanel.h | 21 + .../lagrange/ui/panels/RendererPanel.h | 22 + .../include/lagrange/ui/panels/ScenePanel.h | 38 + .../include/lagrange/ui/panels/ToolbarPanel.h | 31 + .../lagrange/ui/panels/ViewportPanel.h | 71 + .../lagrange/ui/render_passes/GroundPass.h | 118 -- .../lagrange/ui/render_passes/ImmediatePass.h | 53 - .../lagrange/ui/render_passes/ShadowMapPass.h | 52 - .../ui/render_passes/TextureViewPass.h | 39 - .../lagrange/ui/render_passes/common.h | 59 - .../lagrange/ui/systems/camera_systems.h | 32 + .../lagrange/ui/systems/camera_turntable.h | 21 + .../lagrange/ui/systems/render_background.h | 23 + .../lagrange/ui/systems/render_geometry.h | 27 + .../lagrange/ui/systems/render_shadowmaps.h | 23 + .../lagrange/ui/systems/render_viewports.h | 31 + .../ui/systems/update_accelerated_picking.h | 22 + .../lagrange/ui/systems/update_gizmo.h | 57 + .../lagrange/ui/systems/update_lights.h | 27 + .../lagrange/ui/systems/update_mesh_bounds.h | 27 + .../lagrange/ui/systems/update_mesh_buffers.h | 27 + .../ui/systems/update_mesh_elements_hovered.h | 22 + .../lagrange/ui/systems/update_mesh_hovered.h | 24 + .../lagrange/ui/systems/update_scene_bounds.h | 27 + .../ui/systems/update_transform_hierarchy.h | 23 + .../ui/include/lagrange/ui/{ => types}/AABB.h | 19 +- .../include/lagrange/ui/{ => types}/Camera.h | 47 +- .../include/lagrange/ui/{ => types}/Color.h | 0 .../lagrange/ui/{ => types}/FrameBuffer.h | 47 +- .../include/lagrange/ui/{ => types}/Frustum.h | 8 +- .../lagrange/ui/{ => types}/GLContext.h | 22 +- .../lagrange/ui/{ => types}/Keybinds.h | 2 +- .../ui/include/lagrange/ui/{ => types}/MDL.h | 23 +- .../ui/include/lagrange/ui/types/Material.h | 65 + .../include/lagrange/ui/types/RayFacetHit.h | 25 + modules/ui/include/lagrange/ui/types/Shader.h | 277 ++++ .../include/lagrange/ui/types/ShaderLoader.h | 57 + .../ui/include/lagrange/ui/types/Systems.h | 79 + .../include/lagrange/ui/{ => types}/Texture.h | 106 +- modules/ui/include/lagrange/ui/types/Tools.h | 134 ++ .../lagrange/ui/{ => types}/VertexBuffer.h | 34 +- modules/ui/include/lagrange/ui/utils/bounds.h | 61 + .../lagrange/ui/{ => utils}/colormap.h | 8 +- modules/ui/include/lagrange/ui/utils/events.h | 59 + .../lagrange/ui/{ => utils}/file_dialog.h | 0 modules/ui/include/lagrange/ui/utils/ibl.h | 51 + modules/ui/include/lagrange/ui/utils/input.h | 28 + modules/ui/include/lagrange/ui/utils/io.h | 96 ++ .../ui/include/lagrange/ui/utils/io_assimp.h | 163 +++ modules/ui/include/lagrange/ui/utils/layer.h | 57 + modules/ui/include/lagrange/ui/utils/lights.h | 51 + modules/ui/include/lagrange/ui/utils/math.h | 14 +- modules/ui/include/lagrange/ui/utils/mesh.h | 188 +++ .../ui/include/lagrange/ui/utils/mesh.impl.h | 1124 +++++++++++++++ .../include/lagrange/ui/utils/mesh_picking.h | 96 ++ .../lagrange/ui/utils/objectid_viewport.h | 47 + .../ui/{ui_common.h => utils/pair_hash.h} | 25 +- modules/ui/include/lagrange/ui/utils/render.h | 140 ++ .../ui/include/lagrange/ui/utils/selection.h | 88 ++ .../ui/{ResourceUtils.h => utils/template.h} | 48 +- .../ui/include/lagrange/ui/utils/treenode.h | 105 ++ .../ui/include/lagrange/ui/utils/uipanel.h | 64 + .../ui/include/lagrange/ui/utils/viewport.h | 91 ++ modules/ui/src/BaseObject.cpp | 55 - modules/ui/src/CameraUI.cpp | 136 -- modules/ui/src/DetailUI.cpp | 491 ------- modules/ui/src/Emitter.cpp | 49 - modules/ui/src/Light.cpp | 138 -- modules/ui/src/Material.cpp | 149 -- modules/ui/src/MeshBuffer.cpp | 397 ----- modules/ui/src/MeshBufferFactory.cpp | 76 - modules/ui/src/MeshModelBase.cpp | 302 ---- modules/ui/src/Model.cpp | 201 --- modules/ui/src/ModelFactory.cpp | 137 -- modules/ui/src/Options.cpp | 297 ---- modules/ui/src/ProxyMesh.cpp | 838 ----------- modules/ui/src/RenderPass.cpp | 88 -- modules/ui/src/RenderPipeline.cpp | 189 --- modules/ui/src/RenderUtils.cpp | 266 ---- modules/ui/src/Renderer.cpp | 495 ------- modules/ui/src/RendererUI.cpp | 608 -------- modules/ui/src/Scene.cpp | 244 ---- modules/ui/src/SceneUI.cpp | 498 ------- modules/ui/src/SelectionUI.cpp | 408 ------ modules/ui/src/ToolbarUI.cpp | 83 -- modules/ui/src/UIPanel.cpp | 172 --- modules/ui/src/Viewer.cpp | 1277 ++++++++--------- modules/ui/src/Viewport.cpp | 232 --- modules/ui/src/ViewportUI.cpp | 1082 -------------- modules/ui/src/Viz.cpp | 943 ------------ modules/ui/src/Worker.cpp | 46 - modules/ui/src/default_components.cpp | 1172 +++++++++++++++ modules/ui/src/default_entities.cpp | 465 ++++++ modules/ui/src/default_ibls.cpp | 52 +- modules/ui/src/default_keybinds.cpp | 55 +- modules/ui/src/default_panels.cpp | 166 +++ modules/ui/src/default_resources.cpp | 363 ----- modules/ui/src/default_shaders.cpp | 136 ++ modules/ui/src/default_tools.cpp | 284 ++++ modules/ui/src/{ => imgui}/UIWidget.cpp | 194 +-- modules/ui/src/imgui/buttons.cpp | 106 ++ modules/ui/src/imgui/progress.cpp | 10 +- modules/ui/src/panels/ComponentPanel.cpp | 163 +++ .../KeybindsPanel.cpp} | 50 +- .../src/{LogUI.cpp => panels/LoggerPanel.cpp} | 94 +- modules/ui/src/panels/RendererPanel.cpp | 272 ++++ modules/ui/src/panels/ScenePanel.cpp | 332 +++++ modules/ui/src/panels/ToolbarPanel.cpp | 119 ++ modules/ui/src/panels/ViewportPanel.cpp | 817 +++++++++++ modules/ui/src/render_passes/BRDFLUTPass.cpp | 75 - modules/ui/src/render_passes/FXAAPass.cpp | 122 -- modules/ui/src/render_passes/GroundPass.cpp | 243 ---- .../ui/src/render_passes/ImmediatePass.cpp | 141 -- modules/ui/src/render_passes/NormalsPass.cpp | 151 -- .../src/render_passes/ObjectOutlinePass.cpp | 119 -- .../ui/src/render_passes/ShadowMapPass.cpp | 326 ----- modules/ui/src/render_passes/SkyboxPass.cpp | 143 -- .../ui/src/render_passes/TextureViewPass.cpp | 148 -- modules/ui/src/shaders/face_id.shader | 54 +- .../shaders/lines/attribute_to_lines.shader | 119 ++ .../shaders/lines/triangle_to_lines.shader | 22 +- modules/ui/src/shaders/post/outline.shader | 38 +- modules/ui/src/shaders/surface/colormap.frag | 75 + .../src/shaders/surface/edge_attribute.shader | 100 ++ .../ui/src/shaders/surface/objectid.shader | 45 + modules/ui/src/shaders/surface/pbr.frag | 3 + modules/ui/src/shaders/surface/phong.frag | 30 +- modules/ui/src/shaders/surface/simple.shader | 12 +- modules/ui/src/shaders/surface/surface.shader | 5 + .../shaders/surface/vertex_attribute.shader | 52 + modules/ui/src/shaders/test.shader | 92 ++ modules/ui/src/shaders/texture.shader | 58 +- modules/ui/src/shaders/uniforms/common.glsl | 13 +- .../ui/src/shaders/uniforms/materials.glsl | 29 +- modules/ui/src/shaders/util/default.vertex | 35 +- modules/ui/src/shaders/util/pbr_shading.glsl | 6 +- modules/ui/src/shaders/util/skeletal.vertex | 56 + modules/ui/src/systems/camera_systems.cpp | 243 ++++ modules/ui/src/systems/render_background.cpp | 97 ++ modules/ui/src/systems/render_geometry.cpp | 795 ++++++++++ modules/ui/src/systems/render_shadowmaps.cpp | 229 +++ modules/ui/src/systems/render_viewports.cpp | 134 ++ .../systems/update_accelerated_picking.cpp | 34 + modules/ui/src/systems/update_gizmo.cpp | 207 +++ modules/ui/src/systems/update_lights.cpp | 50 + modules/ui/src/systems/update_mesh_bounds.cpp | 66 + .../ui/src/systems/update_mesh_buffers.cpp | 161 +++ .../systems/update_mesh_elements_hovered.cpp | 158 ++ .../ui/src/systems/update_mesh_hovered.cpp | 166 +++ .../ui/src/systems/update_scene_bounds.cpp | 126 ++ .../systems/update_transform_hierarchy.cpp | 71 + modules/ui/src/{ => types}/AABB.cpp | 17 +- modules/ui/src/{ => types}/Camera.cpp | 103 +- modules/ui/src/{ => types}/FrameBuffer.cpp | 54 +- modules/ui/src/{ => types}/Frustum.cpp | 25 +- modules/ui/src/{ => types}/GLContext.cpp | 10 +- modules/ui/src/{ => types}/Keybinds.cpp | 25 +- modules/ui/src/{ => types}/MDL.cpp | 14 +- modules/ui/src/types/Material.cpp | 155 ++ modules/ui/src/{ => types}/Shader.cpp | 311 +++- modules/ui/src/types/ShaderLoader.cpp | 105 ++ modules/ui/src/types/Systems.cpp | 95 ++ modules/ui/src/{ => types}/Texture.cpp | 153 +- modules/ui/src/{ => types}/VertexBuffer.cpp | 34 +- modules/ui/src/utils/bounds.cpp | 111 ++ modules/ui/src/{ => utils}/colormap.cpp | 26 +- modules/ui/src/{ => utils}/file_dialog.cpp | 2 +- modules/ui/src/{IBL.cpp => utils/ibl.cpp} | 399 +++-- modules/ui/src/utils/input.cpp | 40 + modules/ui/src/utils/io.cpp | 341 +++++ modules/ui/src/utils/layer.cpp | 108 ++ modules/ui/src/utils/lights.cpp | 166 +++ modules/ui/src/utils/math.cpp | 7 +- modules/ui/src/utils/mesh.cpp | 427 ++++++ modules/ui/src/utils/mesh_picking.cpp | 433 ++++++ modules/ui/src/utils/objectid_viewport.cpp | 107 ++ modules/ui/src/utils/render.cpp | 471 ++++++ modules/ui/src/utils/selection.cpp | 184 +++ modules/ui/src/utils/treenode.cpp | 291 ++++ modules/ui/src/utils/uipanel.cpp | 174 +++ modules/ui/src/utils/viewport.cpp | 218 +++ modules/ui/tests/CMakeLists.txt | 2 +- modules/ui/tests/main.cpp | 2 +- modules/ui/tests/test_mesh_resource.cpp | 149 -- modules/ui/tests/test_resources.cpp | 585 -------- modules/ui/tests/test_systems.cpp | 172 +++ modules/ui/ui.md | 7 +- 309 files changed, 20179 insertions(+), 20572 deletions(-) create mode 100644 cmake/recipes/external/entt.cmake create mode 100644 modules/ui/README.md delete mode 100644 modules/ui/examples/ui_basic/main.cpp rename modules/ui/examples/{ui_viz => ui_callbacks}/CMakeLists.txt (76%) create mode 100644 modules/ui/examples/ui_callbacks/main.cpp create mode 100644 modules/ui/examples/ui_dynamic_mesh/CMakeLists.txt create mode 100644 modules/ui/examples/ui_dynamic_mesh/main.cpp delete mode 100644 modules/ui/examples/ui_mesh/main.cpp create mode 100644 modules/ui/examples/ui_playground/CMakeLists.txt create mode 100644 modules/ui/examples/ui_playground/main.cpp rename modules/ui/examples/{ui_basic => ui_scene}/CMakeLists.txt (79%) create mode 100644 modules/ui/examples/ui_scene/main.cpp create mode 100644 modules/ui/examples/ui_show_attribute/CMakeLists.txt create mode 100644 modules/ui/examples/ui_show_attribute/main.cpp rename modules/ui/examples/{ui_mesh => ui_treenode}/CMakeLists.txt (78%) create mode 100644 modules/ui/examples/ui_treenode/main.cpp delete mode 100644 modules/ui/examples/ui_viz/VizBuilder.cpp delete mode 100644 modules/ui/examples/ui_viz/VizBuilder.h delete mode 100644 modules/ui/examples/ui_viz/initialize_attributes.h delete mode 100644 modules/ui/examples/ui_viz/main.cpp delete mode 100644 modules/ui/include/lagrange/ui/BaseResourceData.h delete mode 100644 modules/ui/include/lagrange/ui/Callbacks.h delete mode 100644 modules/ui/include/lagrange/ui/CameraUI.h delete mode 100644 modules/ui/include/lagrange/ui/DetailUI.h delete mode 100644 modules/ui/include/lagrange/ui/Emitter.h create mode 100644 modules/ui/include/lagrange/ui/Entity.h delete mode 100644 modules/ui/include/lagrange/ui/FunctionUtils.h delete mode 100644 modules/ui/include/lagrange/ui/IBL.h delete mode 100644 modules/ui/include/lagrange/ui/Light.h delete mode 100644 modules/ui/include/lagrange/ui/Material.h delete mode 100644 modules/ui/include/lagrange/ui/MeshBuffer.h delete mode 100644 modules/ui/include/lagrange/ui/MeshBufferFactory.h delete mode 100644 modules/ui/include/lagrange/ui/MeshModel.h delete mode 100644 modules/ui/include/lagrange/ui/MeshModelBase.h delete mode 100644 modules/ui/include/lagrange/ui/Model.h delete mode 100644 modules/ui/include/lagrange/ui/ModelFactory.h delete mode 100644 modules/ui/include/lagrange/ui/Options.h delete mode 100644 modules/ui/include/lagrange/ui/ProxyMesh.h delete mode 100644 modules/ui/include/lagrange/ui/RenderPass.h delete mode 100644 modules/ui/include/lagrange/ui/RenderPipeline.h delete mode 100644 modules/ui/include/lagrange/ui/RenderResourceBuilder.h delete mode 100644 modules/ui/include/lagrange/ui/RenderUtils.h delete mode 100644 modules/ui/include/lagrange/ui/Renderer.h delete mode 100644 modules/ui/include/lagrange/ui/RendererUI.h delete mode 100644 modules/ui/include/lagrange/ui/Resource.h delete mode 100644 modules/ui/include/lagrange/ui/ResourceData.h delete mode 100644 modules/ui/include/lagrange/ui/ResourceFactory.h delete mode 100644 modules/ui/include/lagrange/ui/Scene.h delete mode 100644 modules/ui/include/lagrange/ui/SceneUI.h delete mode 100644 modules/ui/include/lagrange/ui/Selection.h delete mode 100644 modules/ui/include/lagrange/ui/SelectionUI.h delete mode 100644 modules/ui/include/lagrange/ui/Shader.h delete mode 100644 modules/ui/include/lagrange/ui/ToolbarUI.h delete mode 100644 modules/ui/include/lagrange/ui/UIPanel.h delete mode 100644 modules/ui/include/lagrange/ui/Viewport.h delete mode 100644 modules/ui/include/lagrange/ui/ViewportUI.h delete mode 100644 modules/ui/include/lagrange/ui/Viz.h delete mode 100644 modules/ui/include/lagrange/ui/Worker.h create mode 100644 modules/ui/include/lagrange/ui/components/AcceleratedPicking.h create mode 100644 modules/ui/include/lagrange/ui/components/AttributeRender.h rename modules/ui/{src/ResourceFactory.cpp => include/lagrange/ui/components/Bounds.h} (61%) create mode 100644 modules/ui/include/lagrange/ui/components/CameraComponents.h create mode 100644 modules/ui/include/lagrange/ui/components/Common.h rename modules/ui/include/lagrange/ui/{KeybindsUI.h => components/ElementSelection.h} (72%) create mode 100644 modules/ui/include/lagrange/ui/components/EventEmitter.h create mode 100644 modules/ui/include/lagrange/ui/components/GLMesh.h create mode 100644 modules/ui/include/lagrange/ui/components/IBL.h create mode 100644 modules/ui/include/lagrange/ui/components/Input.h rename modules/ui/include/lagrange/ui/{LogUI.h => components/Layer.h} (61%) create mode 100644 modules/ui/include/lagrange/ui/components/Light.h create mode 100644 modules/ui/include/lagrange/ui/components/MeshData.h create mode 100644 modules/ui/include/lagrange/ui/components/MeshGeometry.h rename modules/ui/include/lagrange/ui/{render_passes/NormalsPass.h => components/MeshRender.h} (63%) create mode 100644 modules/ui/include/lagrange/ui/components/MeshSelectionRender.h create mode 100644 modules/ui/include/lagrange/ui/components/ObjectIDViewport.h rename modules/ui/include/lagrange/ui/{render_passes/SkyboxPass.h => components/RenderContext.h} (60%) rename modules/ui/{src/RenderResourceBuilder.cpp => include/lagrange/ui/components/Selection.h} (75%) create mode 100644 modules/ui/include/lagrange/ui/components/SelectionContext.h create mode 100644 modules/ui/include/lagrange/ui/components/SelectionViewport.h rename modules/ui/include/lagrange/ui/{render_passes/FXAAPass.h => components/ShadowMap.h} (62%) rename modules/ui/include/lagrange/ui/{render_passes/BRDFLUTPass.h => components/Transform.h} (59%) create mode 100644 modules/ui/include/lagrange/ui/components/TreeNode.h create mode 100644 modules/ui/include/lagrange/ui/components/UIPanel.h rename modules/ui/include/lagrange/ui/{render_passes/ObjectOutlinePass.h => components/VertexData.h} (54%) create mode 100644 modules/ui/include/lagrange/ui/components/Viewport.h create mode 100644 modules/ui/include/lagrange/ui/default_components.h create mode 100644 modules/ui/include/lagrange/ui/default_entities.h create mode 100644 modules/ui/include/lagrange/ui/default_events.h create mode 100644 modules/ui/include/lagrange/ui/default_panels.h delete mode 100644 modules/ui/include/lagrange/ui/default_render_passes.h delete mode 100644 modules/ui/include/lagrange/ui/default_resources.h create mode 100644 modules/ui/include/lagrange/ui/default_shaders.h create mode 100644 modules/ui/include/lagrange/ui/default_tools.h rename modules/ui/include/lagrange/ui/{ => imgui}/UIWidget.h (84%) rename modules/ui/include/lagrange/ui/{BaseObject.h => imgui/buttons.h} (52%) rename modules/ui/include/lagrange/ui/{ => imgui}/imconfig.h (68%) create mode 100644 modules/ui/include/lagrange/ui/panels/ComponentPanel.h create mode 100644 modules/ui/include/lagrange/ui/panels/KeybindsPanel.h create mode 100644 modules/ui/include/lagrange/ui/panels/LoggerPanel.h create mode 100644 modules/ui/include/lagrange/ui/panels/RendererPanel.h create mode 100644 modules/ui/include/lagrange/ui/panels/ScenePanel.h create mode 100644 modules/ui/include/lagrange/ui/panels/ToolbarPanel.h create mode 100644 modules/ui/include/lagrange/ui/panels/ViewportPanel.h delete mode 100644 modules/ui/include/lagrange/ui/render_passes/GroundPass.h delete mode 100644 modules/ui/include/lagrange/ui/render_passes/ImmediatePass.h delete mode 100644 modules/ui/include/lagrange/ui/render_passes/ShadowMapPass.h delete mode 100644 modules/ui/include/lagrange/ui/render_passes/TextureViewPass.h delete mode 100644 modules/ui/include/lagrange/ui/render_passes/common.h create mode 100644 modules/ui/include/lagrange/ui/systems/camera_systems.h create mode 100644 modules/ui/include/lagrange/ui/systems/camera_turntable.h create mode 100644 modules/ui/include/lagrange/ui/systems/render_background.h create mode 100644 modules/ui/include/lagrange/ui/systems/render_geometry.h create mode 100644 modules/ui/include/lagrange/ui/systems/render_shadowmaps.h create mode 100644 modules/ui/include/lagrange/ui/systems/render_viewports.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_accelerated_picking.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_gizmo.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_lights.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_mesh_bounds.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_mesh_buffers.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_mesh_elements_hovered.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_mesh_hovered.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_scene_bounds.h create mode 100644 modules/ui/include/lagrange/ui/systems/update_transform_hierarchy.h rename modules/ui/include/lagrange/ui/{ => types}/AABB.h (78%) rename modules/ui/include/lagrange/ui/{ => types}/Camera.h (88%) rename modules/ui/include/lagrange/ui/{ => types}/Color.h (100%) rename modules/ui/include/lagrange/ui/{ => types}/FrameBuffer.h (67%) rename modules/ui/include/lagrange/ui/{ => types}/Frustum.h (88%) rename modules/ui/include/lagrange/ui/{ => types}/GLContext.h (88%) rename modules/ui/include/lagrange/ui/{ => types}/Keybinds.h (99%) rename modules/ui/include/lagrange/ui/{ => types}/MDL.h (82%) create mode 100644 modules/ui/include/lagrange/ui/types/Material.h create mode 100644 modules/ui/include/lagrange/ui/types/RayFacetHit.h create mode 100644 modules/ui/include/lagrange/ui/types/Shader.h create mode 100644 modules/ui/include/lagrange/ui/types/ShaderLoader.h create mode 100644 modules/ui/include/lagrange/ui/types/Systems.h rename modules/ui/include/lagrange/ui/{ => types}/Texture.h (73%) create mode 100644 modules/ui/include/lagrange/ui/types/Tools.h rename modules/ui/include/lagrange/ui/{ => types}/VertexBuffer.h (83%) create mode 100644 modules/ui/include/lagrange/ui/utils/bounds.h rename modules/ui/include/lagrange/ui/{ => utils}/colormap.h (82%) create mode 100644 modules/ui/include/lagrange/ui/utils/events.h rename modules/ui/include/lagrange/ui/{ => utils}/file_dialog.h (100%) create mode 100644 modules/ui/include/lagrange/ui/utils/ibl.h create mode 100644 modules/ui/include/lagrange/ui/utils/input.h create mode 100644 modules/ui/include/lagrange/ui/utils/io.h create mode 100644 modules/ui/include/lagrange/ui/utils/io_assimp.h create mode 100644 modules/ui/include/lagrange/ui/utils/layer.h create mode 100644 modules/ui/include/lagrange/ui/utils/lights.h create mode 100644 modules/ui/include/lagrange/ui/utils/mesh.h create mode 100644 modules/ui/include/lagrange/ui/utils/mesh.impl.h create mode 100644 modules/ui/include/lagrange/ui/utils/mesh_picking.h create mode 100644 modules/ui/include/lagrange/ui/utils/objectid_viewport.h rename modules/ui/include/lagrange/ui/{ui_common.h => utils/pair_hash.h} (67%) create mode 100644 modules/ui/include/lagrange/ui/utils/render.h create mode 100644 modules/ui/include/lagrange/ui/utils/selection.h rename modules/ui/include/lagrange/ui/{ResourceUtils.h => utils/template.h} (87%) create mode 100644 modules/ui/include/lagrange/ui/utils/treenode.h create mode 100644 modules/ui/include/lagrange/ui/utils/uipanel.h create mode 100644 modules/ui/include/lagrange/ui/utils/viewport.h delete mode 100644 modules/ui/src/BaseObject.cpp delete mode 100644 modules/ui/src/CameraUI.cpp delete mode 100644 modules/ui/src/DetailUI.cpp delete mode 100644 modules/ui/src/Emitter.cpp delete mode 100644 modules/ui/src/Light.cpp delete mode 100644 modules/ui/src/Material.cpp delete mode 100644 modules/ui/src/MeshBuffer.cpp delete mode 100644 modules/ui/src/MeshBufferFactory.cpp delete mode 100644 modules/ui/src/MeshModelBase.cpp delete mode 100644 modules/ui/src/Model.cpp delete mode 100644 modules/ui/src/ModelFactory.cpp delete mode 100644 modules/ui/src/Options.cpp delete mode 100644 modules/ui/src/ProxyMesh.cpp delete mode 100644 modules/ui/src/RenderPass.cpp delete mode 100644 modules/ui/src/RenderPipeline.cpp delete mode 100644 modules/ui/src/RenderUtils.cpp delete mode 100644 modules/ui/src/Renderer.cpp delete mode 100644 modules/ui/src/RendererUI.cpp delete mode 100644 modules/ui/src/Scene.cpp delete mode 100644 modules/ui/src/SceneUI.cpp delete mode 100644 modules/ui/src/SelectionUI.cpp delete mode 100644 modules/ui/src/ToolbarUI.cpp delete mode 100644 modules/ui/src/UIPanel.cpp delete mode 100644 modules/ui/src/Viewport.cpp delete mode 100644 modules/ui/src/ViewportUI.cpp delete mode 100644 modules/ui/src/Viz.cpp delete mode 100644 modules/ui/src/Worker.cpp create mode 100644 modules/ui/src/default_components.cpp create mode 100644 modules/ui/src/default_entities.cpp create mode 100644 modules/ui/src/default_panels.cpp delete mode 100644 modules/ui/src/default_resources.cpp create mode 100644 modules/ui/src/default_shaders.cpp create mode 100644 modules/ui/src/default_tools.cpp rename modules/ui/src/{ => imgui}/UIWidget.cpp (51%) create mode 100644 modules/ui/src/imgui/buttons.cpp create mode 100644 modules/ui/src/panels/ComponentPanel.cpp rename modules/ui/src/{KeybindsUI.cpp => panels/KeybindsPanel.cpp} (85%) rename modules/ui/src/{LogUI.cpp => panels/LoggerPanel.cpp} (67%) create mode 100644 modules/ui/src/panels/RendererPanel.cpp create mode 100644 modules/ui/src/panels/ScenePanel.cpp create mode 100644 modules/ui/src/panels/ToolbarPanel.cpp create mode 100644 modules/ui/src/panels/ViewportPanel.cpp delete mode 100644 modules/ui/src/render_passes/BRDFLUTPass.cpp delete mode 100644 modules/ui/src/render_passes/FXAAPass.cpp delete mode 100644 modules/ui/src/render_passes/GroundPass.cpp delete mode 100644 modules/ui/src/render_passes/ImmediatePass.cpp delete mode 100644 modules/ui/src/render_passes/NormalsPass.cpp delete mode 100644 modules/ui/src/render_passes/ObjectOutlinePass.cpp delete mode 100644 modules/ui/src/render_passes/ShadowMapPass.cpp delete mode 100644 modules/ui/src/render_passes/SkyboxPass.cpp delete mode 100644 modules/ui/src/render_passes/TextureViewPass.cpp create mode 100644 modules/ui/src/shaders/lines/attribute_to_lines.shader create mode 100644 modules/ui/src/shaders/surface/colormap.frag create mode 100644 modules/ui/src/shaders/surface/edge_attribute.shader create mode 100644 modules/ui/src/shaders/surface/objectid.shader create mode 100644 modules/ui/src/shaders/surface/vertex_attribute.shader create mode 100644 modules/ui/src/shaders/test.shader create mode 100644 modules/ui/src/shaders/util/skeletal.vertex create mode 100644 modules/ui/src/systems/camera_systems.cpp create mode 100644 modules/ui/src/systems/render_background.cpp create mode 100644 modules/ui/src/systems/render_geometry.cpp create mode 100644 modules/ui/src/systems/render_shadowmaps.cpp create mode 100644 modules/ui/src/systems/render_viewports.cpp create mode 100644 modules/ui/src/systems/update_accelerated_picking.cpp create mode 100644 modules/ui/src/systems/update_gizmo.cpp create mode 100644 modules/ui/src/systems/update_lights.cpp create mode 100644 modules/ui/src/systems/update_mesh_bounds.cpp create mode 100644 modules/ui/src/systems/update_mesh_buffers.cpp create mode 100644 modules/ui/src/systems/update_mesh_elements_hovered.cpp create mode 100644 modules/ui/src/systems/update_mesh_hovered.cpp create mode 100644 modules/ui/src/systems/update_scene_bounds.cpp create mode 100644 modules/ui/src/systems/update_transform_hierarchy.cpp rename modules/ui/src/{ => types}/AABB.cpp (88%) rename modules/ui/src/{ => types}/Camera.cpp (90%) rename modules/ui/src/{ => types}/FrameBuffer.cpp (79%) rename modules/ui/src/{ => types}/Frustum.cpp (87%) rename modules/ui/src/{ => types}/GLContext.cpp (95%) rename modules/ui/src/{ => types}/Keybinds.cpp (94%) rename modules/ui/src/{ => types}/MDL.cpp (98%) create mode 100644 modules/ui/src/types/Material.cpp rename modules/ui/src/{ => types}/Shader.cpp (57%) create mode 100644 modules/ui/src/types/ShaderLoader.cpp create mode 100644 modules/ui/src/types/Systems.cpp rename modules/ui/src/{ => types}/Texture.cpp (74%) rename modules/ui/src/{ => types}/VertexBuffer.cpp (82%) create mode 100644 modules/ui/src/utils/bounds.cpp rename modules/ui/src/{ => utils}/colormap.cpp (81%) rename modules/ui/src/{ => utils}/file_dialog.cpp (96%) rename modules/ui/src/{IBL.cpp => utils/ibl.cpp} (50%) create mode 100644 modules/ui/src/utils/input.cpp create mode 100644 modules/ui/src/utils/io.cpp create mode 100644 modules/ui/src/utils/layer.cpp create mode 100644 modules/ui/src/utils/lights.cpp create mode 100644 modules/ui/src/utils/mesh.cpp create mode 100644 modules/ui/src/utils/mesh_picking.cpp create mode 100644 modules/ui/src/utils/objectid_viewport.cpp create mode 100644 modules/ui/src/utils/render.cpp create mode 100644 modules/ui/src/utils/selection.cpp create mode 100644 modules/ui/src/utils/treenode.cpp create mode 100644 modules/ui/src/utils/uipanel.cpp create mode 100644 modules/ui/src/utils/viewport.cpp delete mode 100644 modules/ui/tests/test_mesh_resource.cpp delete mode 100644 modules/ui/tests/test_resources.cpp create mode 100644 modules/ui/tests/test_systems.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d0fca7e..b7ef6f0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/LagrangeOptions.cmake) endif() ################################################################################ -project(Lagrange VERSION 4.3.0) +project(Lagrange VERSION 5.0.0) # Detects whether internal libs are available if(IS_DIRECTORY "${PROJECT_SOURCE_DIR}/cmake/recipes/internal") diff --git a/cmake/lagrange/lagrange_add_test.cmake b/cmake/lagrange/lagrange_add_test.cmake index d60cab0d..4e8391fb 100644 --- a/cmake/lagrange/lagrange_add_test.cmake +++ b/cmake/lagrange/lagrange_add_test.cmake @@ -17,22 +17,23 @@ function(lagrange_add_test) # Create test executable file(GLOB_RECURSE SRC_FILES "*.cpp" "*.h") include(lagrange_add_executable) - lagrange_add_executable(test_${module_name} ${SRC_FILES}) - set_target_properties(test_${module_name} PROPERTIES FOLDER "Lagrange//Tests") + set(test_target "test_lagrange_${module_name}") + lagrange_add_executable(${test_target} ${SRC_FILES}) + set_target_properties(${test_target} PROPERTIES FOLDER "Lagrange//Tests") # Dependencies lagrange_include_modules(testing) - target_link_libraries(test_${module_name} PUBLIC + target_link_libraries(${test_target} PUBLIC lagrange::${module_name} lagrange::testing ) # Output directory - set_target_properties(test_${module_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests") + set_target_properties(${test_target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests") # Register tests file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/reports") - catch_discover_tests(test_${module_name} + catch_discover_tests(${test_target} REPORTER junit OUTPUT_DIR "${CMAKE_BINARY_DIR}/reports" OUTPUT_SUFFIX ".xml" diff --git a/cmake/recipes/external/assimp.cmake b/cmake/recipes/external/assimp.cmake index 4d8b32bf..9501d1ae 100644 --- a/cmake/recipes/external/assimp.cmake +++ b/cmake/recipes/external/assimp.cmake @@ -19,7 +19,7 @@ include(FetchContent) FetchContent_Declare( assimp GIT_REPOSITORY https://github.com/assimp/assimp.git - GIT_TAG 63f1b66224a02bf1aca76d06d420a8c8113e9b44 + GIT_TAG 40f9d37a38209f0dbd10b71361bc905d314f10a7 ) option(BUILD_SHARED_LIBS "Build package with shared libraries." OFF) @@ -34,6 +34,7 @@ option(ASSIMP_BUILD_TESTS "If the test suite for Assimp is built in addition to option(ASSIMP_INSTALL "Disable this if you want to use assimp as a submodule." OFF) option(ASSIMP_INSTALL_PBD "" OFF) option(ASSIMP_INJECT_DEBUG_POSTFIX "Inject debug postfix in .a/.so/.dll lib names" OFF) +option(ASSIMP_BUILD_PBRT_EXPORTER "Build Assimp with PBRT importer" OFF) # Use a CACHE variable to prevent Assimp from building with its embedded clipper set(Clipper_SRCS "" CACHE STRING "" FORCE) diff --git a/cmake/recipes/external/boost.cmake b/cmake/recipes/external/boost.cmake index 65f52ad6..d217f3dd 100644 --- a/cmake/recipes/external/boost.cmake +++ b/cmake/recipes/external/boost.cmake @@ -19,7 +19,7 @@ include(FetchContent) FetchContent_Declare( boost-cmake GIT_REPOSITORY https://github.com/Orphis/boost-cmake.git - GIT_TAG 70b12f62da331dd402b78102ec8f6a15d59a7af9 + GIT_TAG 7f97a08b64bd5d2e53e932ddf80c40544cf45edf ) set(PREVIOUS_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) @@ -28,7 +28,13 @@ set(OLD_CMAKE_POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE}) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # This guy will download boost using FetchContent -FetchContent_MakeAvailable(boost-cmake) +FetchContent_GetProperties(boost-cmake) +if(NOT boost-cmake_POPULATED) + FetchContent_Populate(boost-cmake) + # File lcid.cpp from Boost_locale.cpp doesn't compile on MSVC, so we exclude them from the default + # targets being built by the project (only targets explicitly used by other targets will be built). + add_subdirectory(${boost-cmake_SOURCE_DIR} ${boost-cmake_BINARY_DIR} EXCLUDE_FROM_ALL) +endif() set(CMAKE_POSITION_INDEPENDENT_CODE ${OLD_CMAKE_POSITION_INDEPENDENT_CODE}) set(CMAKE_CXX_FLAGS "${PREVIOUS_CMAKE_CXX_FLAGS}") diff --git a/cmake/recipes/external/entt.cmake b/cmake/recipes/external/entt.cmake new file mode 100644 index 00000000..2bcfd45d --- /dev/null +++ b/cmake/recipes/external/entt.cmake @@ -0,0 +1,26 @@ +# +# Copyright 2021 Adobe. All rights reserved. +# This file is licensed to you under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +# OF ANY KIND, either express or implied. See the License for the specific language +# governing permissions and limitations under the License. +# + +if(TARGET EnTT::EnTT) + return() +endif() + +message(STATUS "Third-party (external): creating target 'EnTT::EnTT'") + +include(FetchContent) +FetchContent_Declare( + entt + GIT_REPOSITORY https://github.com/skypjack/entt.git + GIT_TAG v3.6.0 +) + +FetchContent_MakeAvailable(entt) diff --git a/cmake/recipes/external/gl3w.cmake b/cmake/recipes/external/gl3w.cmake index dd8c12ad..422143d1 100644 --- a/cmake/recipes/external/gl3w.cmake +++ b/cmake/recipes/external/gl3w.cmake @@ -13,7 +13,7 @@ if(TARGET gl3w::gl3w) return() endif() -message(STATUS "Third-party (internal): creating target 'gl3w::gl3w'") +message(STATUS "Third-party (external): creating target 'gl3w::gl3w'") include(FetchContent) FetchContent_Declare( diff --git a/cmake/recipes/external/imgui.cmake b/cmake/recipes/external/imgui.cmake index 4055d382..ab994c26 100644 --- a/cmake/recipes/external/imgui.cmake +++ b/cmake/recipes/external/imgui.cmake @@ -23,57 +23,19 @@ if(TARGET imgui::imgui) return() endif() +include(glfw) +include(gl3w) + message(STATUS "Third-party (external): creating target 'imgui::imgui' ('docking' branch)") include(FetchContent) FetchContent_Declare( imgui GIT_REPOSITORY https://github.com/adobe/imgui.git - GIT_TAG ee9ae8bae5a453749baea58f65e275f438cfb6e2 + GIT_TAG 3f1593b28346da2ad34edbab9432b93deb305f42 ) FetchContent_MakeAvailable(imgui) -add_library(imgui - "${imgui_SOURCE_DIR}/imgui.h" - "${imgui_SOURCE_DIR}/imgui_internal.h" - "${imgui_SOURCE_DIR}/imgui.cpp" - "${imgui_SOURCE_DIR}/imgui_demo.cpp" - "${imgui_SOURCE_DIR}/imgui_draw.cpp" - "${imgui_SOURCE_DIR}/imgui_widgets.cpp" - "${imgui_SOURCE_DIR}/imgui_spectrum.h" - "${imgui_SOURCE_DIR}/imgui_spectrum.cpp" - "${imgui_SOURCE_DIR}/imgui_tables.cpp" - "${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.h" - "${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp" - "${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.h" - "${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp" - "${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.h" - "${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp" -) -add_library(imgui::imgui ALIAS imgui) - - -# Dark theme option -option(IMGUI_USE_DARK_THEME "Use Dark ImGui Spectrum Theme" OFF) -if(IMGUI_USE_DARK_THEME) - target_compile_definitions(imgui PUBLIC SPECTRUM_USE_DARK_THEME) -endif() - -target_compile_definitions(imgui PUBLIC - IMGUI_IMPL_OPENGL_LOADER_GL3W=1 - - IMGUI_DISABLE_OBSOLETE_FUNCTIONS # to check for obsolete functions - - # IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/path/to/imconfig.h" # to use your own imconfig.h -) - - -target_include_directories(imgui PUBLIC "${imgui_SOURCE_DIR}") - -include(glfw) -include(gl3w) -target_link_libraries(imgui PUBLIC glfw::glfw gl3w::gl3w) - set_target_properties(imgui PROPERTIES FOLDER third_party) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") diff --git a/cmake/recipes/external/lagrange-assets.cmake b/cmake/recipes/external/lagrange-assets.cmake index 2fcc1237..cf979670 100644 --- a/cmake/recipes/external/lagrange-assets.cmake +++ b/cmake/recipes/external/lagrange-assets.cmake @@ -17,7 +17,7 @@ include(FetchContent) FetchContent_Declare( lagrange-assets GIT_REPOSITORY https://github.com/adobe/lagrange-assets.git - GIT_TAG ffd7bf726ac08921948d9e8495eda8d03e381c9d + GIT_TAG f3407b0eb8266111c720b28577050e9a8f7901a5 ) message(STATUS "Lagrange: creating target 'lagrange::assets'") FetchContent_MakeAvailable(lagrange-assets) diff --git a/cmake/recipes/external/openvdb.cmake b/cmake/recipes/external/openvdb.cmake index 61c16982..3c4487e4 100644 --- a/cmake/recipes/external/openvdb.cmake +++ b/cmake/recipes/external/openvdb.cmake @@ -53,10 +53,42 @@ set(OPENVDB_SIMD AVX CACHE STRING "") # - https://gitlab.kitware.com/cmake/cmake/issues/17735 # - https://crascit.com/2018/09/14/do-not-redefine-cmake-commands/ function(openvdb_import_target) + macro(push_variable var value) + if(DEFINED CACHE{${var}}) + set(OPENVDB_OLD_${var}_VALUE "${${var}}") + set(OPENVDB_OLD_${var}_TYPE CACHE_TYPE) + elseif(DEFINED ${var}) + set(OPENVDB_OLD_${var}_VALUE "${${var}}") + set(OPENVDB_OLD_${var}_TYPE NORMAL_TYPE) + else() + set(OPENVDB_OLD_${var}_TYPE NONE_TYPE) + endif() + set(${var} "${value}" CACHE PATH "" FORCE) + endmacro() + + macro(pop_variable var) + if(OPENVDB_OLD_${var}_TYPE STREQUAL CACHE_TYPE) + set(${var} "${OPENVDB_OLD_${var}_VALUE}" CACHE PATH "" FORCE) + elseif(OPENVDB_OLD_${var}_TYPE STREQUAL NORMAL_TYPE) + unset(${var} CACHE) + set(${var} "${OPENVDB_OLD_${var}_VALUE}") + elseif(OPENVDB_OLD_${var}_TYPE STREQUAL NONE_TYPE) + unset(${var} CACHE) + else() + message(FATAL_ERROR "Trying to pop a variable that has not been pushed: ${var}") + endif() + endmacro() + macro(ignore_package NAME) - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${NAME}Config.cmake "") - set(${NAME}_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NAME} CACHE PATH "") - set(${NAME}_ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME} CACHE PATH "") + set(OPENVDB_DUMMY_DIR "${CMAKE_CURRENT_BINARY_DIR}/openvdb_cmake/${NAME}") + file(WRITE ${OPENVDB_DUMMY_DIR}/${NAME}Config.cmake "") + push_variable(${NAME}_DIR ${OPENVDB_DUMMY_DIR}) + push_variable(${NAME}_ROOT ${OPENVDB_DUMMY_DIR}) + endmacro() + + macro(unignore_package NAME) + pop_variable(${NAME}_DIR) + pop_variable(${NAME}_ROOT) endmacro() # Prefer Config mode before Module mode to prevent embree from loading its own FindTBB.cmake @@ -82,6 +114,10 @@ function(openvdb_import_target) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/openvdb ${openvdb_BINARY_DIR}) endif() + unignore_package(TBB) + unignore_package(Boost) + unignore_package(IlmBase) + # Forward ALIAS target for openvdb get_target_property(_aliased openvdb ALIASED_TARGET) if(_aliased) diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index ddc6a4b3..ea82d234 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -21,7 +21,7 @@ target_include_directories(lagrange_core PUBLIC $ ) -target_compile_features(lagrange_core PUBLIC cxx_std_14) +target_compile_features(lagrange_core PUBLIC cxx_std_17) set_target_properties(lagrange_core PROPERTIES POSITION_INDEPENDENT_CODE ON) diff --git a/modules/core/include/lagrange/utils/geometry3d.h b/modules/core/include/lagrange/utils/geometry3d.h index 91477467..41b4b053 100644 --- a/modules/core/include/lagrange/utils/geometry3d.h +++ b/modules/core/include/lagrange/utils/geometry3d.h @@ -18,22 +18,12 @@ namespace lagrange { /// Returns the cosine of the angle between two 3d vectors. /// /// Assumes both vectors are normalized (unit vector). -template +template Scalar cos_angle_between( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2) -{ - Scalar dot = v1.dot(v2); - if (dot < -1) return Scalar(-1.0); - if (dot > 1) return Scalar(1.0); - return dot; -} - -template -Scalar cos_angle_between( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2) + const Eigen::Matrix& v1, + const Eigen::Matrix& v2) { + static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), ""); Scalar dot = v1.dot(v2); if (dot < -1) return Scalar(-1.0); if (dot > 1) return Scalar(1.0); @@ -41,101 +31,113 @@ Scalar cos_angle_between( } /// Returns the angle between two 3d vectors. -template -Scalar angle_between(const Eigen::Matrix& v1, const Eigen::Matrix& v2) -{ - return std::atan2(v1.cross(v2).norm(), v1.dot(v2)); -} - -template -Scalar angle_between(const Eigen::Matrix& v1, const Eigen::Matrix& v2) +template +Scalar angle_between( + const Eigen::Matrix& v1, + const Eigen::Matrix& v2) { + static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), ""); return std::atan2(v1.cross(v2).norm(), v1.dot(v2)); } /// Project the vector v1 on the line defined by its vector v2 /// /// Assumes the vector v2 is normalized (unit vector). -template -Eigen::Matrix project_on_line( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2) -{ - return v1.dot(v2) * v2; -} - -template -Eigen::Matrix project_on_line( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2) +template +Eigen::Matrix project_on_line( + const Eigen::Matrix& v1, + const Eigen::Matrix& v2) { + static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), ""); return v1.dot(v2) * v2; } /// Project the vector on the plane defined by its normal n. /// Assumes the normal n is a unit vector. -template +template Eigen::Matrix project_on_plane( - const Eigen::Matrix& v, - const Eigen::Matrix& n) -{ - return v - project_on_line(v, n); -} - -template -Eigen::Matrix project_on_plane( - const Eigen::Matrix& v, - const Eigen::Matrix& n) + const Eigen::Matrix& v, + const Eigen::Matrix& n) { + static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), ""); return v - project_on_line(v, n); } /// Returns the angle between the vectors v1 and v2 projected on the plane defined /// by its normal n. Assumes the normal n is a unit vector. -template -Scalar projected_cos_angle_between( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2, - const Eigen::Matrix& n) -{ - const Eigen::Matrix proj1 = project_on_plane(v1, n).stableNormalized(); - const Eigen::Matrix proj2 = project_on_plane(v2, n).stableNormalized(); - return cos_angle_between(proj1, proj2); -} - -template +template Scalar projected_cos_angle_between( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2, - const Eigen::Matrix& n) + const Eigen::Matrix& v1, + const Eigen::Matrix& v2, + const Eigen::Matrix& n) { - const Eigen::Matrix proj1 = project_on_plane(v1, n).stableNormalized(); - const Eigen::Matrix proj2 = project_on_plane(v2, n).stableNormalized(); + static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), ""); + const Eigen::Matrix proj1 = project_on_plane(v1, n).stableNormalized(); + const Eigen::Matrix proj2 = project_on_plane(v2, n).stableNormalized(); return cos_angle_between(proj1, proj2); } /// Returns the angle between the vectors v1 and v2 projected on the plane defined /// by its normal n. Assumes the normal n is a unit vector. -template +template Scalar projected_angle_between( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2, - const Eigen::Matrix& n) + const Eigen::Matrix& v1, + const Eigen::Matrix& v2, + const Eigen::Matrix& n) { - const Eigen::Matrix proj1 = project_on_plane(v1, n); - const Eigen::Matrix proj2 = project_on_plane(v2, n); + static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), ""); + const Eigen::Matrix proj1 = project_on_plane(v1, n); + const Eigen::Matrix proj2 = project_on_plane(v2, n); return std::atan2(proj1.cross(proj2).norm(), proj1.dot(proj2)); } +/// +/// Returns the vector from v1 to v2 +/// +/// @param[in] v1 first vertex index (from). +/// @param[in] v2 second vertex index (to) +/// +/// @return The 3D vector +/// +template +auto vector_between(const MeshType& mesh, typename MeshType::Index v1, typename MeshType::Index v2) +{ + static_assert(MeshTrait::is_mesh(), "MeshType is not a mesh"); + return mesh.get_vertices().row(v2) - mesh.get_vertices().row(v1); +} + +/// +/// Build an orthogonal frame given a single vector. +/// +/// @param[in] x First vector of the frame. +/// @param[out] y Second vector of the frame. +/// @param[out] z Third vector of the frame. +/// +/// @tparam Scalar Scalar type. +/// template -Scalar projected_angle_between( - const Eigen::Matrix& v1, - const Eigen::Matrix& v2, - const Eigen::Matrix& n) +void orthogonal_frame( + const Eigen::Matrix& x, + Eigen::Matrix& y, + Eigen::Matrix& z) { - const Eigen::Matrix proj1 = project_on_plane(v1, n); - const Eigen::Matrix proj2 = project_on_plane(v2, n); - return std::atan2(proj1.cross(proj2).norm(), proj1.dot(proj2)); + int imin; + x.array().abs().minCoeff(&imin); + Eigen::Matrix u; + for (int i = 0, s = -1; i < 3; ++i) { + if (i == imin) { + u[i] = 0; + } else { + int j = (i + 1) % 3; + if (j == imin) { + j = (i + 2) % 3; + } + u[i] = s * x[j]; + s *= -1; + } + } + z = x.cross(u).stableNormalized(); + y = z.cross(x).stableNormalized(); } } // namespace lagrange diff --git a/modules/core/performance/CMakeLists.txt b/modules/core/performance/CMakeLists.txt index 6ba26b1d..ffa90988 100644 --- a/modules/core/performance/CMakeLists.txt +++ b/modules/core/performance/CMakeLists.txt @@ -52,8 +52,7 @@ lagrange_add_performance(condense_uv attributes/condense_uv.cpp) target_link_libraries(condense_uv lagrange::core lagrange::io) lagrange_add_performance(marquee marquee.cpp) -target_link_libraries(marquee lagrange::core lagrange::io lagrange::ui CLI11::CLI11) -target_compile_definitions(marquee PRIVATE UI_ENABLED) +target_link_libraries(marquee lagrange::core lagrange::io CLI11::CLI11) lagrange_add_performance(array experimental/array.cpp) target_link_libraries(array lagrange::core lagrange::io) diff --git a/modules/core/performance/marquee.cpp b/modules/core/performance/marquee.cpp index b9c3096f..8d189c3b 100644 --- a/modules/core/performance/marquee.cpp +++ b/modules/core/performance/marquee.cpp @@ -18,11 +18,6 @@ #include #include -#ifdef UI_ENABLED -#include -#include -#endif - int main(int argc, char** argv) { CLI::App app{argv[0]}; @@ -59,69 +54,6 @@ int main(int argc, char** argv) Eigen::Matrix times(N); times.setZero(); -#ifdef UI_ENABLED - using FVertex = lagrange::ui::FrustumVertices; - - auto construct_plane = [](const VertexType& p, const VertexType& n) { - return lagrange::ui::Frustum::Plane(n.cast(), p.cast()); - }; - auto set_frustum_vertex = [](lagrange::ui::Frustum& f, FVertex which, const VertexType& p) { - auto pf = p.cast(); - f.vertices[which] = {pf[0], pf[1], pf[2]}; - }; - - auto construct_frustum = [&]() -> lagrange::ui::Frustum { - // p3 p2 - // +----+ - // | | - // +----+ - // p0 p1 - lagrange::ui::Frustum frustum; - - set_frustum_vertex(frustum, FVertex::FRUSTUM_NEAR_LEFT_BOTTOM, p0); - set_frustum_vertex( - frustum, - FVertex::FRUSTUM_FAR_LEFT_BOTTOM, - p0 + (p0 - camera_pos).normalized() * diagonal_len); - - set_frustum_vertex(frustum, FVertex::FRUSTUM_NEAR_RIGHT_BOTTOM, p1); - set_frustum_vertex( - frustum, - FVertex::FRUSTUM_FAR_RIGHT_BOTTOM, - p1 + (p1 - camera_pos).normalized() * diagonal_len); - - set_frustum_vertex(frustum, FVertex::FRUSTUM_NEAR_LEFT_TOP, p3); - set_frustum_vertex( - frustum, - FVertex::FRUSTUM_FAR_LEFT_TOP, - p3 + (p3 - camera_pos).normalized() * diagonal_len); - - set_frustum_vertex(frustum, FVertex::FRUSTUM_NEAR_RIGHT_TOP, p2); - set_frustum_vertex( - frustum, - FVertex::FRUSTUM_FAR_RIGHT_TOP, - p2 + (p2 - camera_pos).normalized() * diagonal_len); - - - frustum.planes[0] = construct_plane(camera_pos, {0, 0, -1}); // Near plane - frustum.planes[1] = - construct_plane(camera_pos - VertexType(0, 0, 100 * diagonal_len), {0, 0, 1}); // Far - frustum.planes[2] = construct_plane(p3, n30); // Left - frustum.planes[3] = construct_plane(p1, n12); // Right - frustum.planes[4] = construct_plane(p2, n23); // Top - frustum.planes[5] = construct_plane(p0, n01); // Bottom - return frustum; - }; - auto start_time_proxy = lagrange::get_timestamp(); - auto proxy_mesh = std::make_unique(*mesh); - auto end_time_proxy = lagrange::get_timestamp(); - lagrange::logger().info( - "Proxy mesh construction: {}s", - lagrange::timestamp_diff_in_seconds(start_time_proxy, end_time_proxy)); - Eigen::Matrix times_2(N); - times_2.setZero(); -#endif - for (int i = 0; i < N; i++) { const Scalar x = step_x * i + bbox_min[0]; const Scalar y = step_y * i + bbox_min[1]; @@ -140,39 +72,8 @@ int main(int argc, char** argv) auto end_time = lagrange::get_timestamp(); times[i] = lagrange::timestamp_diff_in_seconds(start_time, end_time); lagrange::logger().info("select_facets run {}: {}s selected: {}", i, times[i], r); - -#ifdef UI_ENABLED - auto frustum = construct_frustum(); - start_time = lagrange::get_timestamp(); - bool r2 = proxy_mesh->intersects(frustum); - end_time = lagrange::get_timestamp(); - times_2[i] = lagrange::timestamp_diff_in_seconds(start_time, end_time); - lagrange::logger().info("UI select run {}: {}s selected: {}", i, times_2[i], r2); - - if (r2 != r) { - lagrange::logger().error("Ops, select_facet and UI select disagrees!"); - using VertexArray = typename MeshType::VertexArray; - using FacetArray = typename MeshType::FacetArray; - - VertexArray frustum_vertices(5, 3); - frustum_vertices.row(0) = camera_pos; - frustum_vertices.row(1) = camera_pos + (p0 - camera_pos) * 10; - frustum_vertices.row(2) = camera_pos + (p1 - camera_pos) * 10; - frustum_vertices.row(3) = camera_pos + (p2 - camera_pos) * 10; - frustum_vertices.row(4) = camera_pos + (p3 - camera_pos) * 10; - FacetArray frustum_facets(4, 3); - frustum_facets << 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 1; - auto frustum2 = lagrange::wrap_with_mesh(frustum_vertices, frustum_facets); - auto filename = fmt::format("frustum_{}.obj", i); - lagrange::io::save_mesh(filename, *frustum2); - lagrange::logger().error("Saving frustum as {} for further debugging", filename); - } -#endif } lagrange::logger().info("select_facet average time over {} runs: {}", N, times.mean()); -#ifdef UI_ENABLED - lagrange::logger().info("UI select average time over {} runs: {}", N, times_2.mean()); -#endif return 0; } diff --git a/modules/core/performance/view_tangent_frame.cpp b/modules/core/performance/view_tangent_frame.cpp index 9cf6071e..598c0ee9 100644 --- a/modules/core/performance/view_tangent_frame.cpp +++ b/modules/core/performance/view_tangent_frame.cpp @@ -19,6 +19,8 @@ #include #include +namespace ui = lagrange::ui; + int main(int argc, char* argv[]) { struct @@ -83,58 +85,35 @@ int main(int argc, char* argv[]) timer.tock("Unify buffers"); } - if(args.headless){ + if (args.headless) { return 0; } - lagrange::ui::Viewer::WindowOptions wopt; - wopt.width = 1920; - wopt.height = 1080; - wopt.window_title = "Tangent Frame Viewer"; - wopt.vsync = false; - - lagrange::ui::Viewer viewer(wopt); - if (!viewer.is_initialized()) return 1; - - lagrange::ui::Scene& scene = viewer.get_scene(); - scene.add_model(lagrange::ui::ModelFactory::make(std::move(mesh))); - - viewer.enable_ground(true); - viewer.get_ground().enable_grid(true).enable_axes(true).set_height(-1.0f); - - auto colormap = [&](const lagrange::ui::Model& /*model*/, - const lagrange::ui::Viz::AttribValue& value) { - Eigen::Vector3f vec = value.head<3>().cast(); - auto rgb = (vec + Eigen::Vector3f::Constant(1.0f)).normalized().eval(); - if (args.pad) { - return lagrange::ui::Color::random((int)value(3)); - } else { - return lagrange::ui::Color(rgb.x(), rgb.y(), rgb.z(), 1.0f); - } - }; - viewer.add_viz(lagrange::ui::Viz::create_attribute_colormapping( - "Tangent", - lagrange::ui::Viz::Attribute::CORNER, - "tangent", - lagrange::ui::Viz::Primitive::TRIANGLES, - colormap)); - viewer.add_viz(lagrange::ui::Viz::create_attribute_colormapping( - "Bitangent", - lagrange::ui::Viz::Attribute::CORNER, - "bitangent", - lagrange::ui::Viz::Primitive::TRIANGLES, - colormap)); - viewer.add_viz(lagrange::ui::Viz::create_attribute_colormapping( - "Normal", - lagrange::ui::Viz::Attribute::CORNER, - "normal", - lagrange::ui::Viz::Primitive::TRIANGLES, - colormap)); - - while (!viewer.should_close()) { - viewer.begin_frame(); - viewer.end_frame(); + + ui::Viewer viewer("Tangent Frame Viewer", 1920, 1080); + + // TODO: use optional arg for mesh name? + auto mesh_view = ui::add_mesh(viewer, std::move(mesh), "Mesh"); + auto mesh_geometry = ui::get_meshdata_entity(viewer, mesh_view); + + const auto M = + ui::get_mesh_bounds(ui::get_mesh_data(viewer, mesh_geometry)).get_normalization_transform(); + + ui::apply_transform(viewer, mesh_view, M); + + // TODO: add ground + // viewer.enable_ground(true); + // viewer.get_ground().enable_grid(true).enable_axes(true).set_height(-1.0f); + + float xpos = -1.0f; + for (auto attr : {"tangent", "bitangent", "normal"}) { + // TODO: map 3-vec to 1-vec for colormapping + auto e = ui::show_indexed_attribute(viewer, mesh_geometry, attr, ui::Glyph::Surface); + ui::apply_transform(viewer, e, Eigen::Translation3f(xpos, 0, -1.0f) * M); + xpos += 1.0f; } + viewer.run(); + return 0; } diff --git a/modules/core/tests/mesh_cleanup/test_resolve_nonmanifoldness.cpp b/modules/core/tests/mesh_cleanup/test_resolve_nonmanifoldness.cpp index 86ca403a..d108ae6f 100644 --- a/modules/core/tests/mesh_cleanup/test_resolve_nonmanifoldness.cpp +++ b/modules/core/tests/mesh_cleanup/test_resolve_nonmanifoldness.cpp @@ -36,7 +36,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(in_mesh->is_uv_initialized()); in_mesh->initialize_connectivity(); - in_mesh->initialize_edge_data(); auto out_mesh = lagrange::resolve_nonmanifoldness(*in_mesh); out_mesh->initialize_topology(); @@ -61,7 +60,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(in_mesh->is_uv_initialized()); in_mesh->initialize_connectivity(); - in_mesh->initialize_edge_data(); auto out_mesh = lagrange::resolve_nonmanifoldness(*in_mesh); out_mesh->initialize_topology(); @@ -86,7 +84,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(in_mesh->get_num_components() == 1); in_mesh->initialize_connectivity(); - in_mesh->initialize_edge_data(); in_mesh->initialize_uv(vertices.leftCols(2).eval(), facets); REQUIRE(in_mesh->is_uv_initialized()); @@ -113,7 +110,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(!in_mesh->is_vertex_manifold()); in_mesh->initialize_connectivity(); - in_mesh->initialize_edge_data(); in_mesh->initialize_uv(vertices.leftCols(2).eval(), facets); REQUIRE(in_mesh->is_uv_initialized()); @@ -138,7 +134,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(!in_mesh->is_vertex_manifold()); in_mesh->initialize_connectivity(); - in_mesh->initialize_edge_data(); Eigen::Matrix uv(3, 2); uv << 0.0, 0.0, 1.0, 0.0, 0.0, 1.0; @@ -180,7 +175,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(!in_mesh->is_vertex_manifold()); in_mesh->initialize_connectivity(); - in_mesh->initialize_edge_data(); auto out_mesh = lagrange::resolve_nonmanifoldness(*in_mesh); out_mesh->initialize_topology(); @@ -217,7 +211,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(!mesh->is_vertex_manifold()); mesh->initialize_connectivity(); - mesh->initialize_edge_data(); mesh = lagrange::resolve_nonmanifoldness(*mesh); mesh->initialize_topology(); @@ -236,7 +229,6 @@ TEST_CASE("resolve_manifoldness", "[nonmanifold][Mesh][cleanup]") REQUIRE(!mesh->is_vertex_manifold()); mesh->initialize_connectivity(); - mesh->initialize_edge_data(); mesh = lagrange::resolve_nonmanifoldness(*mesh); mesh->initialize_topology(); @@ -254,7 +246,6 @@ TEST_CASE("resolve_manifoldness_slow", "[nonmanifold][Mesh][.slow]" LA_CORP_FLAG auto mesh = lagrange::testing::load_mesh("corp/core/splash_08_debug.obj"); mesh->initialize_connectivity(); - mesh->initialize_edge_data(); mesh = lagrange::resolve_nonmanifoldness(*mesh); mesh->initialize_topology(); @@ -268,7 +259,6 @@ TEST_CASE("resolve_manifoldness_slow", "[nonmanifold][Mesh][.slow]" LA_CORP_FLAG REQUIRE(!mesh->is_vertex_manifold()); mesh->initialize_connectivity(); - mesh->initialize_edge_data(); mesh = lagrange::resolve_nonmanifoldness(*mesh); mesh->initialize_topology(); diff --git a/modules/fs/tests/CMakeLists.txt b/modules/fs/tests/CMakeLists.txt index 7e9736cf..d0b0e209 100644 --- a/modules/fs/tests/CMakeLists.txt +++ b/modules/fs/tests/CMakeLists.txt @@ -11,5 +11,5 @@ # lagrange_add_test() -target_compile_definitions(test_fs PRIVATE TEST_APP_PATH="$") -target_compile_definitions(test_fs PRIVATE TEST_WORK_DIR="${CMAKE_CURRENT_BINARY_DIR}") +target_compile_definitions(test_lagrange_fs PRIVATE TEST_APP_PATH="$") +target_compile_definitions(test_lagrange_fs PRIVATE TEST_WORK_DIR="${CMAKE_CURRENT_BINARY_DIR}") diff --git a/modules/io/include/lagrange/io/load_mesh_assimp.h b/modules/io/include/lagrange/io/load_mesh_assimp.h index 15957962..9dd96636 100644 --- a/modules/io/include/lagrange/io/load_mesh_assimp.h +++ b/modules/io/include/lagrange/io/load_mesh_assimp.h @@ -116,21 +116,60 @@ std::unique_ptr convert_mesh_assimp(const aiMesh* mesh) using VertexArray = typename MeshType::VertexArray; using FacetArray = typename MeshType::FacetArray; - VertexArray vertices(mesh->mNumVertices, 3); // should we support arbitrary dimension? - FacetArray faces(mesh->mNumFaces, 3); + // Check that all facets have the same size + unsigned int nvpf = 0; + bool triangulate = false; + for (unsigned int j = 0; j < mesh->mNumFaces; ++j) { + const aiFace& face = mesh->mFaces[j]; + if (nvpf == 0) { + nvpf = face.mNumIndices; + } else if (face.mNumIndices != nvpf) { + logger().warn("Facets with varying number of vertices detected, triangulating"); + nvpf = 3; + triangulate = true; + break; + } + } + if (FacetArray::ColsAtCompileTime != Eigen::Dynamic && FacetArray::ColsAtCompileTime != nvpf) { + logger().warn( + "FacetArray cannot hold facets with n!={} vertex per facet, triangulating", + FacetArray::ColsAtCompileTime); + triangulate = true; + nvpf = 3; + } + + // If triangulating a heterogeneous mesh, we need to count the number of facets + unsigned int num_output_facets = mesh->mNumFaces; + if (triangulate) { + num_output_facets = 0; + for (unsigned int j = 0; j < mesh->mNumFaces; ++j) { + const aiFace& face = mesh->mFaces[j]; + num_output_facets += face.mNumIndices - 2; + } + } + + VertexArray vertices(mesh->mNumVertices, 3); // should we support arbitrary dimension? for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { const aiVector3D& vec = mesh->mVertices[j]; vertices(j, 0) = vec.x; vertices(j, 1) = vec.y; vertices(j, 2) = vec.z; } - for (unsigned int j = 0; j < mesh->mNumFaces; ++j) { + + FacetArray faces(num_output_facets, nvpf); + for (unsigned int j = 0, f = 0; j < mesh->mNumFaces; ++j) { const aiFace& face = mesh->mFaces[j]; - assert(face.mNumIndices == 3); - for (unsigned int k = 0; k < face.mNumIndices; ++k) { - faces(j, k) = face.mIndices[k]; + if (triangulate) { + for (unsigned int k = 2; k < face.mNumIndices; ++k) { + faces.row(f++) << face.mIndices[0], face.mIndices[k - 1], face.mIndices[k]; + } + } else { + for (unsigned int k = 0; k < face.mNumIndices; ++k) { + faces(j, k) = face.mIndices[k]; + } } + assert(f <= num_output_facets); } auto lagrange_mesh = create_mesh(std::move(vertices), std::move(faces)); diff --git a/modules/testing/CMakeLists.txt b/modules/testing/CMakeLists.txt index 2a21cb7d..b47df9fa 100644 --- a/modules/testing/CMakeLists.txt +++ b/modules/testing/CMakeLists.txt @@ -28,11 +28,12 @@ target_sources(lagrange_testing PRIVATE ${INC_FILES} ${SRC_FILES}) set_target_properties(lagrange_testing PROPERTIES FOLDER "Lagrange//Tests") # 3. dependencies -lagrange_include_modules(io) +lagrange_include_modules(io serialization) target_link_libraries(lagrange_testing PUBLIC Catch2::Catch2 Threads::Threads lagrange::io + lagrange::serialization ) # 4. test-specific properties diff --git a/modules/testing/include/lagrange/testing/common.h b/modules/testing/include/lagrange/testing/common.h index 4cb0ec9c..1c5dbb76 100644 --- a/modules/testing/include/lagrange/testing/common.h +++ b/modules/testing/include/lagrange/testing/common.h @@ -18,6 +18,7 @@ #endif #include +#include #include @@ -51,6 +52,20 @@ std::unique_ptr load_mesh(const fs::path &relative_path) return result; } +/// +/// Load any serialized object from test data directory. +/// +/// @param[in] relative_path Relative path of the file to load. +/// @param[out] obj Output reference to the deserialized object. +/// +/// @tparam T The target output type. +/// +template +void deserialize(const fs::path& relative_path, T& obj) +{ + lagrange::serialization::file_utils::load_object(get_data_path(relative_path), obj); +} + /// /// Set up MKL Conditional Numerical Reproducibility to ensure maximum compatibility between /// devices. This is only called before setting up unit tests that depend on reproducible numerical diff --git a/modules/ui/CMakeLists.txt b/modules/ui/CMakeLists.txt index 094eb35a..0f1fc924 100644 --- a/modules/ui/CMakeLists.txt +++ b/modules/ui/CMakeLists.txt @@ -17,7 +17,7 @@ add_library(lagrange::ui ALIAS lagrange_ui) message(STATUS "Lagrange: creating target 'lagrange::ui'") if(WIN32) - target_compile_definitions(lagrange_ui PUBLIC -DNOMINMAX) + target_compile_definitions(lagrange_ui PUBLIC -DNOMINMAX -D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING) endif() target_compile_features(lagrange_ui PUBLIC cxx_std_17) @@ -31,10 +31,16 @@ target_include_directories(lagrange_ui PUBLIC # 2. target sources file(GLOB_RECURSE INC_FILES "include/*.h") file(GLOB_RECURSE SRC_FILES "src/*.cpp") + +source_group( + TREE "${PROJECT_SOURCE_DIR}" + FILES ${INC_FILES} ${SRC_FILES}) + target_sources(lagrange_ui PRIVATE ${INC_FILES} ${SRC_FILES}) # 3. dependencies lagrange_include_modules(io) +include(nanoflann) include(gl3w) include(glfw) include(stb) @@ -44,9 +50,10 @@ include(imgui_fonts) include(nativefiledialog) include(nlohmann_json) include(lagrange-assets) +include(entt) target_link_libraries(imgui PUBLIC Eigen3::Eigen) target_compile_definitions(imgui PUBLIC - IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/modules/ui/include/lagrange/ui/imconfig.h" + IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/modules/ui/include/lagrange/ui/imgui/imconfig.h" ) target_link_libraries(lagrange_ui PRIVATE @@ -62,6 +69,8 @@ target_link_libraries(lagrange_ui imgui::fonts nativefiledialog::nativefiledialog nlohmann_json::nlohmann_json + EnTT::EnTT + nanoflann::nanoflann ) @@ -78,6 +87,10 @@ if(LAGRANGE_UI_USE_MDL) target_link_libraries(lagrange_ui PUBLIC mdl::mdl) endif() +if(LAGRANGE_DEBUG_SHADERS) + target_compile_definitions(lagrange_ui PRIVATE DEFAULT_SHADERS_USE_REAL_PATH="${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/") +endif() + # 4. automatic shader generation set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") file(MAKE_DIRECTORY "${generated_dir}") @@ -102,25 +115,7 @@ if(LAGRANGE_USE_PCH) target_precompile_headers(lagrange_ui_pch INTERFACE - - - - - - - - - - - - - - - - - - - + ) target_compile_features(lagrange_ui_pch INTERFACE cxx_std_17) @@ -141,3 +136,5 @@ endif() if(LAGRANGE_UNIT_TESTS) add_subdirectory(tests) endif() + + diff --git a/modules/ui/README.md b/modules/ui/README.md new file mode 100644 index 00000000..710c5aa1 --- /dev/null +++ b/modules/ui/README.md @@ -0,0 +1,693 @@ + +## Table of Contents +- [Table of Contents](#table-of-contents) +- [Overview](#overview) +- [Geometry loading and registration](#geometry-loading-and-registration) + - [Loading mesh](#loading-mesh) + - [Retrieving and interacting with the mesh](#retrieving-and-interacting-with-the-mesh) + - [Loading scene](#loading-scene) +- [Adding geometry to scene](#adding-geometry-to-scene) + - [Default Physically Based Render (PBR)](#default-physically-based-render-pbr) + - [Mesh visualizations](#mesh-visualizations) + - [`GlyphType::Surface`](#glyphtypesurface) + - [Colormaps](#colormaps) +- [Materials](#materials) + - [Color/Texture Material Properties](#colortexture-material-properties) + - [PBRMaterial](#pbrmaterial) + - [Rasterizer Properties](#rasterizer-properties) + - [Custom Shader Properties](#custom-shader-properties) +- [Common components](#common-components) + - [`Name`](#name) + - [`Transform`](#transform) + - [`Tree`](#tree) + - [`MeshGeometry`](#meshgeometry) + - [`Hovered` and `Selected`](#hovered-and-selected) + - [`Layer`](#layer) + - [`UIPanel`](#uipanel) + - [`Viewport`](#viewport) +- [User Interface Panels](#user-interface-panels) +- [Viewports](#viewports) + - [Entity visibility](#entity-visibility) + - [Multi viewport](#multi-viewport) +- [Entity Component System](#entity-component-system) + - [Registry](#registry) + - [Entity](#entity) + - [Components](#components) + - [Tag Components](#tag-components) + - [Systems](#systems) + - [Context variables](#context-variables) + - [Design considerations](#design-considerations) +- [Customizing Lagrange UI](#customizing-lagrange-ui) + - [Components](#components-1) + - [Tools](#tools) + - [Geometry](#geometry) + - [Rendering](#rendering) + - [Shader and Material properties](#shader-and-material-properties) +- [Examples](#examples) + + +## Overview + +Lagrange UI uses an **Entity-Component-System (ECS)** architecture: +- Entity is a unique identifier +- Components define data and behavior (but no logic) +- Systems define logic (but no data). + +See *[ECS implementation section](#entity-component-system)* for more information about ECS and how it's implemented in Lagrange UI. The underlying library for ECS is [`entt`](https://github.com/skypjack/entt). + + +Recommended namespace usage +```c++ +namespace ui = lagrange::ui; +``` + +The entry point to the library is the `Viewer` class. It instantiates a window and owns a `Registry` instance and `Systems` instance. `Registry` contains all the data (entities, components) and `Systems` contain all the behavior (sequence of functions that is called every frame). To start the UI: + +```c++ +ui::Viewer viewer; +viewer.run([](){ + //Main loop code +}); + +//Or + +viewer.run([](ui::Registry & r){ + //Main loop code + return should_continue_running; +}); +``` + +The API to interact with the UI follows this pattern +```c++ +ui::Entity entity = ui::do_something(registry, params) +SomeData & data = registry.get(entity); +``` + +For example: +```c++ +//Loads mesh from path +ui::Entity mesh_geometry = ui::load_mesh(registry, path); + +//Adds the mesh to scene +ui::Entity mesh_visualization = ui::show_mesh(registry, mesh_geometry); + +//Retrieves Transform component of the visualized mesh +Transform & transform = registry.get(mesh_visualization); +``` + +All entities and their components live in a `Registry`. To access/set/modify the entities and components, use the `Viewer::registry()`. +```c++ +auto & registry = viewer.registry(); +auto entity = registry.create(); +registry.emplace(entity, MyPositionComponent(0,0,0)); +``` + +*TODO: lifetime discussion* + +## Geometry loading and registration + +### Loading mesh + +Creates and entity that represents the mesh. This entity is only a resource - it is not rendered. +It can be referenced by components that need this geometry for rendering/picking/etc. +These entities have `MeshData` component attached that contains a `lagrange::MeshBase` pointer. + +```c++ +ui::Entity mesh_from_disk = ui::load_mesh(registry, path); +ui::Entity mesh_from_memory = ui::register_mesh(registry, lagrange::create_sphere()); +``` + +### Retrieving and interacting with the mesh + +To retrieve a mesh: +```c++ +MeshType & mesh = ui::get_mesh(registry, mesh_entity); +``` + +There are several methods that do not require the knowledge of the mesh type. These may however incur copy and conversion costs. +```c++ +RowMajorMatrixXf get_mesh_vertices(const MeshData& d); +RowMajorMatrixXf get_mesh_facets(const MeshData& d); +bool has_mesh_vertex_attribute(const MeshData& d, const std::string& name); +bool has_mesh_facet_attribute(const MeshData& d, const std::string& name); +... +RowMajorMatrixXf get_mesh_vertex_attribute(const MeshData& d, const std::string& name); +RowMajorMatrixXf get_mesh_facet_attribute(const MeshData& d, const std::string& name); +... +std::optional intersect_ray(const MeshData& d, const Eigen::Vector3f& origin, const Eigen::Vector3f& dir); +... +``` + + +### Loading scene +Loads a scene using Assimp. Creates a hierarchy of entities and loads meshes, materials and textures. Returns the top-level entity. + +```c++ +ui::Entity root = ui::load_scene(registry, path); +``` + +To iterate over the scene, see the [`Tree` component](#tree). + +## Adding geometry to scene + +### Default Physically Based Render (PBR) + +Adds previously registered mesh geometry to the scene. This mesh will be rendered using PBR. + +```c++ +ui::Entity scene_object = ui::show_mesh(registry, mesh_entity); +``` + +Uses `DefaultShaders::PBR` shader. + +See [Materials](#Materials) section to see how to control the appearance. + + +### Mesh visualizations +Adds a visualization of a mesh +([Jeremie's idea](https://git.corp.adobe.com/lagrange/Lagrange/issues/657)). + +```c++ +auto vertex_viz_entity = ui::show_vertex_attribute(registry, mesh_entity, attribute_name, glyph_type); +auto facet_viz_entity = ui::show_facet_attribute(registry, mesh_entity, attribute_name, glyph_type); +auto corner_viz_entity = ui::show_corner_attribute(registry, mesh_entity, attribute_name, glyph_type); +auto edge_viz_entity = ui::show_edge_attribute(registry, mesh_entity, attribute_name, glyph_type); +``` + +These functions will create a new scene object and render the supplied attribute using the selected glyph type. + +#### `GlyphType::Surface` + +Renders unshaded surface with color mapped from the supplied attribute. Supports attributes of dimension: 1, 2, 3, and 4. + +*Normalization*: The attribute value is automatically remapped to (0,1) range. To change the range, use `ui::set_colormap_range` +*Colormapping*: By default, the attribute is interpreted as R, RG, RGB or RGBA value. To use different mapping, refer to [Colormaps](#Colormaps) section. + +#### Colormaps + +If the glyph or shader supports colormapping, use the following function to set the colormap: + +To use on of the default colormaps: +```c++ +ui::set_colormap(registry, entity, ui::generate_colormap(ui::colormap_magma)) +``` +Or generate your own +```c++ +ui::set_colormap(registry, entity, ui::generate_colormap([](float t){ + return Color( + //... function of t from 0 to 1 + ); +})); +``` + +Default colormaps: +``` +colormap_viridis +colormap_magma +colormap_plasma +colormap_inferno +colormap_turbo +colormap_coolwarm +``` + + + + +## Materials + +Any entity with `MeshRender` component has a `Material` associated with it (`MeshRender::material`). + +To get a reference to entity's material, use: + +```c++ +std::shared_ptr material_ptr = ui::get_material(r, entity_with_meshrender); +``` + +Similarly, you may set a new material: +```c++ +ui::set_material(r, entity_with_mesh_render, std::make_shared(r, DefaultShaders::PBR); +``` + +### Color/Texture Material Properties + +You may set colors and textures of materials using the following API: + +```c++ +auto & material = *ui::get_material(r, entity_with_meshrender); + +//Sets "property name" to a red color +material.set_color("property name", ui::Color(1,0,0)); + +//Sets "texture name" to texture loaded from file +material.set_texture("texture name", ui::load_texture("texture.jpg")); +``` + +#### PBRMaterial +For the default `PBRMaterial`, you may use aliases for the property names: +```c++ + +//Uniform rgba color +material.set_color(PBRMaterial::BaseColor, ui::Color(1,0,0,1)); +//RGB(A) color/albedo texture +material.set_texture(PBRMaterial::BaseColor, ui::load_texture("color.jpg")); + +//Normal texture (and texture only) +material.set_texture(PBRMaterial::Normal, ui::load_texture("normal.jpg")); + +//Uniform roughness +material.set_float(PBRMaterial::Roughness, 0.75f); +//Roughness texture +material.set_texture(PBRMaterial::Roughness, ui::load_texture("metallic.jpg")); + +//Uniform roughness +material.set_float(PBRMaterial::Metallic, 0.75f); +//Metallic texture +material.set_texture(PBRMaterial::Metallic, ui::load_texture("metallic.jpg")); + +//Uniform opacity +material.set_float(PBRMaterial::Opacity, 1.0f); +//Opacity texture +material.set_texture(PBRMaterial::Opacity, ui::load_texture("opacity.jpg")); +``` + +### Rasterizer Properties + +To control OpenGl properties, you may following syntax: + +```c++ +material.set_int(RasterizerOptions::PolygonMode, GL_LINE); +material.set_float(RasterizerOptions::PointSize, PointSize); +``` + +See `` for a list of supported `RasterizerOptions`; + +### Custom Shader Properties + +You may set arbitrary `int` or `float` or `Color` or `Texture` to the material. It will be set as a shader uniform if it exists in the shader, otherwise there will be no effect. + + +## Common components +Entities can have several components that define their behavior. Here is a list of the common components used throughout Lagrange UI. + +### `Name` +Subclassed `std::string`. Acts as a display name. Will be shown in UI if it exists, otherwise a generated name will be used. Does not have to be unique. + +### `Transform` +Contains local and global transformations and a viewport transform. + +```c++ +// Translates entity one unit in X direction +ui::Transform & transform = registry.get(e); +transform.local = Eigen::Translation3f(1,0,0); +``` + +Global transformation is recomputed after each `Simulation` step. Only change the `local` transform. + +### `Tree` +Defines scene tree relationship. Data is stored using `parent`, `first_child`, `previous_sibling` and `next_sibling` entity IDs. + +Use helper functions to query or change the tree structure, do not change directly (unless you know what you're doing). +```c++ +//Orphans entity and parents it under new_parent +ui::reparent(registry, entity, new_parent); + +//Applies lambda to each direct child entity of parent +ui::foreach_child(registry, parent, [](Entity child){ + //... +}); + +//Applies lambda to each child entity of parent, recursively +ui::foreach_child_recursive(registry, parent, [](Entity child){ + //... +}); + +//In-order traversal of scene tree +ui::iterate_inorder(registry, root, [](Entity current){ + //On Enter + + //Return true to continue to traverse children + return true; +},[](Entity current){ + //On Exit +}); + +// See utils/treenode.h for more details +``` + +### `MeshGeometry` +Contains reference to geometry entity + +```c++ +MeshGeometry mg; +mg.entity = .. +``` + + +### `Hovered` and `Selected` + +These components acts as flags whether the entity is hovered or selected respectively. + +Useful helper functions +```c++ +bool is_selected(Registry ®istry, Entity e); +bool is_hovered(Registry ®istry, Entity e); +bool select(Registry& registry, Entity e); +bool deselect(Registry& registry, Entity e); +std::vector collect_selected(const Registry& registry); +std::vector collect_hovered(const Registry& registry); +//See `utils/selection.h` for details +``` + +### `Layer` + +There are 256 layers an entity can belong to. The `Layer` component specifies which layers the entity belongs to. Entity can belong to several layers at once. There are several default layers: +`ui::DefaultLayers::Default` - everything belongs to it by default +`ui::DefaultLayers::Selection` - selected entities +`ui::DefaultLayers::Hover` - hovered entities + +Default constructed `Layer` component belongs to `ui::DefaultLayers::Default`. + +You can register your own layer by calling +```c++ +ui::LayerIndex layer_index = ui::register_layer_name(r, "my layer name"); +``` + +There are several utility functions for working with layers: +```c++ +void add_to_layer(Registry&, Entity e, LayerIndex index); +void remove_from_layer(Registry&, Entity e, LayerIndex index); +bool is_in_layer(Registry&, Entity e, LayerIndex index); +bool is_in_any_layers(Registry&, Entity e, Layer layers_bitset); +bool is_visible_in( + const Registry&, + Entity e, + const Layer& visible_layers, + const Layer& hidden_layers); +``` + + +### `UIPanel` +See [section](#User-Interface-Panels) below. + +### `Viewport` +See [section](#Viewports) below. + +## User Interface Panels + +UI Panels are implemented also as entities. Panels have the `UIPanel` component. The `UIPanel` components describes the ImGui information (panel title, position, etc.). + +To create a new UI panel: +```c++ +auto panel_entity = ui::add_panel(registry, "Title of the panel",[](){ + // Do NOT call Imgui::Begin()/End() + Imgui::Text("Hello world"); +}); +//or +auto panel_entity = ui::add_panel(registry, "Title of the panel", [](Registry ®istry, Entity e){ + //Entity e is the panel_entity +}); +``` + +Example of multiple instances of a same "type" of panel: + +```c++ + +struct MyPanelState { int x = 0; } + +auto panel_fn = [](Registry ®istry, Entity e){ + auto & state = registry.get_or_emplace(e); + ImGui::InputInt("x", &state.x); +}; + +auto panel0 = ui::add_panel(registry,"panel with x = 0",panel_fn) +registry.emplace(panel0, MyPanelState{0}) + +auto panel1 = ui::add_panel(registry,"panel with x = 1",panel_fn); +registry.emplace(panel1, MyPanelState{1}) + +``` + + +## Viewports + +Viewports are implemented as entities with `ViewportComponent` component. Those referenced in `ViewportPanel` are rendered to screen, otherwise they are rendered off-screen. There is always one **focused** `ViewportPanel` (identified by the context variable `FocusedViewportPanel`). + +See `components/Viewport.h` and `utils/viewport.h` for utility functions related to viewport, viewport panels and cameras. + +### Entity visibility + +Each `ViewportComponent` has `visible_layers` and `hidden_layers` that control which entities can be renderer in this viewport (see [`Layer` component](#layer) for details). + +The default viewport shows only `DefaultLayers::DefaultLayer` + + +### Multi viewport + +Additional viewports can be created by calling +```c++ +ui::Entity camera_entity = add_camera(ui::Registry &, ui::Camera camera); +// or use get_focused_camera_entity(ui::Registry &) to reuse current camera + +// Creates an offscreen viewport with the specified camera +ui::Entity viewport_entity = add_viewport(ui::Registry &, ui::Entity camera_entity) + +// Creates a UI panel that shows the viewport +ui::Entity viewport_entity = add_viewport_panel(ui::Registry &, const std::string & name, ui::Entity viewport_entity); +``` + +--- + +## Entity Component System + +For more information about the ECS architecture, see: +- [What you need to know about ECS](https://medium.com/ingeniouslysimple/entities-components-and-systems-89c31464240d) for quick overview +- [Overwatch Gameplay Architecture - GDC Talk](https://www.youtube.com/watch?v=W3aieHjyNvw) for a good example of usage and design considerations. +- [entt Crash Course](https://github.com/skypjack/entt/wiki/Crash-Course:-entity-component-system) for overview of the underlying `entt` library +- [ECS Back and Forth](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) for more details about ECS design, in particular hierarchies +- [Unity ECS documentation](https://docs.unity3d.com/Packages/com.unity.entities@0.1/manual/index.html) for Unity's version of ECS + +### Registry +The `Viewer` uses a `Registry` (alias for `entt::registry`) to store all entities and their data. To manipulate entities and their components directly, use the object: +```c++ +auto & registry = viewer.registry(); +``` +`Viewer` class exposes API that simplifies interaction with the `Registry`, e.g. `Viewer::show_mesh`. + +### Entity +Unique identifier - it's just that. It's used to identify a unique "object" or "entity". Lagrange UI defines a `Entity` alias. Internally implemented as `std::uint32_t`. + +To create a new entity, use: +```c++ +Entity new_entity = registry.create(); +``` + +To destroy: +```c++ +registry.destroy(entity); +``` + +### Components +Any data that is attached to an `Entity`. Uniquely identified by template typename `` and `Entity`. + +Components **don't have logic, that means no code**. They only store data and implicitly define behavior. Ideally, the components should be `structs` with no functions. However, it may be beneficial to have setters/getters as member functions in some cases. + + +To attach a component of type `MyComponent` to an entity : +```c++ +// When it doesn't exist +registry.emplace(entity, MyComponent(42)) + +// When it might exist already +registry.emplace_or_replace(entity, MyComponent(42)) +``` + +To retrieve a component: +```c++ +// If it exists already +MyComponent & c = registry.get(entity); + +// If you're not sure it exists +MyComponent * c = registry.try_get(entity); +//or +if(registry.has()){ + MyComponent& c = registry.get(entity); +} +``` + +#### Tag Components + +"Empty" components may be used to tag entities, e.g. `Selected`, `Hovered`, etc. These types however must have non-zero size: +```c++ +struct Hidden { + bool dummy; +} +``` + +### Systems + +Systems are the logic of the application. They are defined as functions that iterate over entities that have specified components only. +For example, running this system: +```c++ +registry.view().each([](Entity e, Velocity & velocity, Transform & transform){ + transform.local = Eigen::Translation3f(velocity) * transform.local; +}); +``` +will iterate over all entities that have both `Velocity` and `Transform` and apply the velocity vector to the transform. + + +Lagrange UI defines `System` as alias to `std::function`, that is, a function that does something with the `Registry`. Typically these will be defined as: +```c++ +System my_system = [](Registry &w){ + w.view.each([](Entity e, Component1 & c1, Component2 & c2, ...){ + // + }); +}; +``` + + +### Context variables + +Systems **do not have data**. However, it's often useful to have some state associated with a given system, e.g. for caching. Sometimes it's useful that this state be shared among several systems. Instead of storing this state in some single instance of a component, we can use *context* variables. These can be thought of as *singleton* components - only one instance of a `Type` can exist at a given time. + +`InputState` is such a *singleton* component. At the beginning of the frame, it is filled with key/mouse information, including last mouse position, mouse delta, active keybinds, etc.: +```c++ +void update_input_system(Registry & registry){ + InputState & input_state = registry.ctx_or_set(); + input_state.mouse_pos = ... + input_state.mouse_delta = ... + input_state.keybinds.update(...); +} +``` + +It can then be used by any other system down the line: +```c++ +void print_mouse_position(Registry & registry){ + const auto & input_state = registry.ctx(); + + lagrange::logger().info("Mouse position: {}", input_state.mouse_pos); +} +``` + +### Design considerations + +Rules to follow when designing components and systems: +- Components have no functions, only data +- Systems have no data +- State associated with systems is stored as context variable (`registry.ctx()`) + +*TODO: const Systems / const views* + + + +## Customizing Lagrange UI + +TODO: add more details and examples. In the meantime, refer to files named `default_{}` to see how the UI registers the default types and functionality. + +### Components + +You may add any time of component using `registry.emplace(entity)`. However to enable more advanced features, you may register the components in the UI: + +`register_component` +- enables reflection +- enables runtime add/clone/move of components + +`register_component_widget` +- defines ImGui code to render +- enables drag-and-drop + + +### Tools + +*TBD* + +`register_element_type` (Object/Facet/Edge/Vertex/...) + +`register_tool` (Select/Translate/Rotate/Scale/...) + +### Geometry + +Lagrange meshes must be registered to work. By default, only the `TriangleMesh3Df` and `TriangleMesh3D` are registered. + +`ui::register_mesh_type()` + +### Rendering + +#### Shader and Material properties + +Material properties can be defined in the shader using the following syntax: + + +```glsl +#pragma property NAME "DISPLAY NAME" TYPE(DEFAULT VALUE AND/OR RANGE) [TAG1, TAG2] +``` + +For example: +```glsl +//Defines a 2D texture property with the default value of rgba(0.7,0.7,0.7,1) if no texture is bound +#pragma property material_base_color "Base Color" Texture2D(0.7,0.7,0.7,1) +//Defines a 2D texture property with the default value of red=0.4 if no texture is bound +#pragma property material_roughness "Roughness" Texture2D(0.4) +//Defines a 2D texture property with the default value of red=0.1 if no texture is bound +#pragma property material_metallic "Metallic" Texture2D(0.1) +//Defines a 2D texture property that is to be interpreted as normal texture +#pragma property material_normal "Normal" Texture2D [normal] +//Defines a float property, with the default value of 1 and range 0,1 +#pragma property material_opacity "Opacity" float(1,0,1) +``` + +The pragmas are parsed whenever a shader is loaded and replaced with: +```glsl +uniform TYPE NAME = DEFAULT_VALUE +``` +In case of `Texture2D`, these uniforms are generated: +```glsl +uniform sampler2D NAME; +uniform bool NAME_texture_bound = false; +uniform VEC_TYPE NAME_default_value = DEFAULT_VALUE; +``` + + + + +## Examples + +Refer to `modules/ui/examples`. Build Lagrange with `-DLAGRANGE_EXAMPLES=On`. diff --git a/modules/ui/examples/CMakeLists.txt b/modules/ui/examples/CMakeLists.txt index ede6cdc6..8e98bd60 100644 --- a/modules/ui/examples/CMakeLists.txt +++ b/modules/ui/examples/CMakeLists.txt @@ -9,6 +9,9 @@ # OF ANY KIND, either express or implied. See the License for the specific language # governing permissions and limitations under the License. # -add_subdirectory(ui_basic) -add_subdirectory(ui_mesh) -add_subdirectory(ui_viz) \ No newline at end of file +add_subdirectory(ui_playground) +add_subdirectory(ui_show_attribute) +add_subdirectory(ui_dynamic_mesh) +add_subdirectory(ui_scene) +add_subdirectory(ui_callbacks) +add_subdirectory(ui_treenode) \ No newline at end of file diff --git a/modules/ui/examples/ui_basic/main.cpp b/modules/ui/examples/ui_basic/main.cpp deleted file mode 100644 index 589c1383..00000000 --- a/modules/ui/examples/ui_basic/main.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#include - -using namespace lagrange::ui; - - -int main() -{ - /* - Set up initial window and OpenGL context options - */ - - Viewer::WindowOptions wopt; - wopt.width = 1920; - wopt.height = 1080; - wopt.window_title = "Example Basic"; - wopt.vsync = false; - - - /* - Initialize the viewer - */ - Viewer viewer(wopt); - - /* - Check if everything initialized - */ - if (!viewer.is_initialized()) return 1; - - /* - Set up your scene with Models and Emitters. - Models represent geometry. - MeshModel represents geometry made of lagrange::MeshType. - Use ModelFactory to create or load models - - */ - Scene& scene = viewer.get_scene(); - - /* - This creates a sphere MeshModel that contains the sphere mesh. - The type depends on the input MeshType - */ - auto sphere_model = ModelFactory::make(lagrange::create_sphere(4)); - - - /* - Add model to the scene, this makes it available for rendering and interaction - You can save the pointer for later interaction with the model - */ - auto sphere_model_ptr = scene.add_model(std::move(sphere_model)); - - /* - Modify position - */ - sphere_model_ptr->set_transform(Eigen::Translation3f(0, 0.5f * sphere_model_ptr->get_bounds().diagonal().y(),0)); - - /* - Modify material - */ - { - auto& material = sphere_model_ptr->get_material(); - material["baseColor"].value = Color(0.3f, 0.4f, 0.3f); - } - - /* - Emitters - */ - - // By default, an IBL (Image Based Lighting) environmental map is loaded and provides light - // To disable it, use wopt.default_ibl = ""; - // To add your own, use make_unique(image_path) - - // Creates a point light at position with intensity - scene.add_emitter( - std::make_unique(Eigen::Vector3f(0, 3, 3), 20.0f * Eigen::Vector3f(0.8f, 0.5f, 0.2f))); - - - // Creates a directional light with direction and intensity - scene.add_emitter( - std::make_unique(Eigen::Vector3f(0, -3, 3), Eigen::Vector3f(0.2f, 0.5f, 0.8f))); - - /* - Enables infinite ground plane with grid and axes at y = -1 - */ - viewer.enable_ground(true); - viewer.get_ground().enable_grid(true).enable_axes(true).set_height(-1.0f); - - /* - Creates a visualization "my viz" (toggle it in "Render Passes" dropdown) - It takes VERTEX indices, assigns color using the given lambda and renders LINES - */ - viewer.add_viz(Viz::create_indexed_colormapping( - "my viz", Viz::Attribute::VERTEX, Viz::Primitive::LINES, [](const Model& model, int index) { - auto mesh = model.mesh(); - if (!mesh) return Color::empty(); - - auto pos = mesh->get_vertices().row(index).transpose().cast().eval(); - auto bounds = model.get_bounds(); - auto diag = bounds.diagonal(); - - return Color((pos - bounds.min()).cwiseProduct(diag.cwiseInverse()), 1.0f); - })); - - /* - Runs the main loop - If you don't need contorl over the main loop, - you can also use viewer.run(); - */ - while (!viewer.should_close()) { - viewer.begin_frame(); - - ImGui::Begin("Test"); - ImGui::Text("Hello world"); - ImGui::End(); - - viewer.end_frame(); - } - - return 0; -} diff --git a/modules/ui/examples/ui_viz/CMakeLists.txt b/modules/ui/examples/ui_callbacks/CMakeLists.txt similarity index 76% rename from modules/ui/examples/ui_viz/CMakeLists.txt rename to modules/ui/examples/ui_callbacks/CMakeLists.txt index 5841e341..75b86066 100644 --- a/modules/ui/examples/ui_viz/CMakeLists.txt +++ b/modules/ui/examples/ui_callbacks/CMakeLists.txt @@ -9,22 +9,20 @@ # OF ANY KIND, either express or implied. See the License for the specific language # governing permissions and limitations under the License. # +include(cli11) lagrange_include_modules(io) -lagrange_add_example(ui_viz +lagrange_add_example(ui_callbacks main.cpp - VizBuilder.cpp - VizBuilder.h - initialize_attributes.h ) -target_link_libraries(ui_viz lagrange::ui lagrange::io) +target_link_libraries(ui_callbacks lagrange::ui lagrange::io CLI11::CLI11) if(LAGRANGE_UI_USE_MDL) - add_custom_command(TARGET ui_viz POST_BUILD + add_custom_command(TARGET ui_callbacks POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${MDL_DYNAMIC_LIBS} - $ + $ ) endif() diff --git a/modules/ui/examples/ui_callbacks/main.cpp b/modules/ui/examples/ui_callbacks/main.cpp new file mode 100644 index 00000000..1b2a2bf9 --- /dev/null +++ b/modules/ui/examples/ui_callbacks/main.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +#include +#include + + +namespace ui = lagrange::ui; + +int main(int argc, char** argv) +{ + struct + { + bool verbose = false; + } args; + + CLI::App app{argv[0]}; + app.add_flag("-v", args.verbose, "verbose"); + CLI11_PARSE(app, argc, argv) + + if (args.verbose) { + lagrange::logger().set_level(spdlog::level::debug); + } + + + // Initialize the viewer + ui::Viewer viewer("UI Example - Callbacks", 1920, 1080); + + // Get reference to the registry (global state of the ui) + ui::show_mesh(viewer, ui::register_mesh(viewer, lagrange::create_sphere())); + + /* + See for a list of event types + */ + + // System window resized + ui::on(viewer, [](const ui::WindowResizeEvent& e) { + lagrange::logger().info("Window resized to: {}x{}", e.width, e.height); + }); + + // Called just before window closes + ui::on(viewer, [](const ui::WindowCloseEvent& e) { + lagrange::logger().info("Window is closing"); + }); + + // Drag and drop of files + ui::on(viewer, [](const ui::WindowDropEvent& e) { + lagrange::logger().info("Dropped {} files", e.count); + for (auto i = 0; i < e.count; i++) { + lagrange::logger().info("\t{}", e.paths[i]); + } + }); + + // Transform component of an entity changed + ui::on(viewer, [&](const ui::TransformChangedEvent& e) { + lagrange::logger().info( + "Transform of entity {} changed. Position:\n{}", + e.entity, + ui::get_transform(viewer, e.entity).global.translation()); + }); + + // Camera component of an entity changed + ui::on(viewer, [&](const ui::CameraChangedEvent& e) { + const auto& cam = ui::get_camera(viewer, e.entity); + lagrange::logger().info( + "Camera of entity {} changed. Position:\n{}", + e.entity, + cam.get_position()); + }); + + + // You can register custom events + struct TickEvent + { + double t; + }; + + // First register a listener, then use ui::publish to trigger the event + ui::on(viewer, [](const TickEvent& e) { + lagrange::logger().info("Tick, t = {}", e.t); + }); + + + double t_from_last = 0; + viewer.run([&](ui::Registry& r) { + const auto& gtime = r.ctx(); + + // Get elapsed time from last frame, add it to variable + t_from_last += gtime.dt; + + // Trigger event every two seconds + if (t_from_last > 2.0) { + ui::publish(r, gtime.t); + t_from_last = 0; + } + + return true; + }); + + return 0; +} diff --git a/modules/ui/examples/ui_dynamic_mesh/CMakeLists.txt b/modules/ui/examples/ui_dynamic_mesh/CMakeLists.txt new file mode 100644 index 00000000..51555e5e --- /dev/null +++ b/modules/ui/examples/ui_dynamic_mesh/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright 2020 Adobe. All rights reserved. +# This file is licensed to you under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +# OF ANY KIND, either express or implied. See the License for the specific language +# governing permissions and limitations under the License. +# +include(cli11) +lagrange_include_modules(io) + +lagrange_add_example(ui_dynamic_mesh + main.cpp +) + +target_link_libraries(ui_dynamic_mesh lagrange::ui lagrange::io CLI11::CLI11) + +if(LAGRANGE_UI_USE_MDL) + add_custom_command(TARGET ui_dynamic_mesh POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${MDL_DYNAMIC_LIBS} + $ + ) +endif() + diff --git a/modules/ui/examples/ui_dynamic_mesh/main.cpp b/modules/ui/examples/ui_dynamic_mesh/main.cpp new file mode 100644 index 00000000..81ea034e --- /dev/null +++ b/modules/ui/examples/ui_dynamic_mesh/main.cpp @@ -0,0 +1,127 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +#include +#include + +#include +#include + + +namespace ui = lagrange::ui; + +int main(int argc, char** argv) +{ + struct + { + std::string input; + bool verbose = false; + } args; + + CLI::App app{argv[0]}; + app.add_option("input", args.input, "Input mesh."); + app.add_flag("-v", args.verbose, "verbose"); + CLI11_PARSE(app, argc, argv) + + if (args.verbose) { + lagrange::logger().set_level(spdlog::level::debug); + } + + if (args.input.length() == 0) { + lagrange::logger().error("Input mesh must be specified"); + return 1; + } + + // Initialize the viewer + ui::Viewer viewer("UI Example - Dynamic Mesh", 1920, 1080); + + // Load a mesh, returns a handle + // This will only register the mesh, but it will not show it + lagrange::io::MeshLoaderParams params; + params.normalize = true; + auto mesh_entity = ui::load_obj(viewer, args.input, params); + + // Retrieve the mesh and compute some attributes + auto& mesh = ui::get_mesh(viewer, mesh_entity); + { + lagrange::compute_vertex_normal(mesh, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM); + lagrange::compute_facet_area(mesh); + } + + // Show PBR render + { + auto mesh_pbr = ui::show_mesh(viewer, mesh_entity); + ui::set_name(viewer, mesh_pbr, "Mesh PBR"); + } + + // Show vertex normal -> surface visualization + { + auto mesh_normal_viz = + ui::show_vertex_attribute(viewer, mesh_entity, "normal", ui::Glyph::Surface); + ui::set_name(viewer, mesh_normal_viz, "Vertex Normals"); + ui::set_transform(viewer, mesh_normal_viz, Eigen::Translation3f(-2.0f, 0, 0)); + } + + // Show facet area colormap visualization + ui::Entity area_viz; + { + area_viz = ui::show_facet_attribute(viewer, mesh_entity, "area", ui::Glyph::Surface); + ui::set_name(viewer, area_viz, "Facet Area"); + ui::set_transform(viewer, area_viz, Eigen::Translation3f(2.0f, 0, 0)); + ui::set_colormap(viewer, area_viz, ui::generate_colormap(ui::colormap_coolwarm)); + } + + // Copy original vertices + auto V0 = mesh.get_vertices(); + double t = 0.0; + + + viewer.run( + // This function run at the beginning of every frame + [&](ui::Registry& r) { + // Modify the mesh vertices + { + lagrange::TriangleMesh3D::VertexArray V; + mesh.export_vertices(V); + t += viewer.get_frame_elapsed_time(); + double a = (std::sin(2 * t) + 1.0) * 0.5; + + for (auto i = 0; i < V.rows(); i++) { + V.row(i) = V0.row(i).normalized() * a + V0.row(i) * (1.0 - a); + } + mesh.import_vertices(V); + } + + // Recompute normal attribute + if (mesh.has_facet_attribute("normal")) mesh.remove_facet_attribute("normal"); + if (mesh.has_vertex_attribute("normal")) mesh.remove_vertex_attribute("normal"); + if (mesh.has_corner_attribute("normal")) mesh.remove_corner_attribute("normal"); + lagrange::compute_vertex_normal(mesh, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM); + + // Recompute area attribute + if (mesh.has_facet_attribute("area")) mesh.remove_facet_attribute("area"); + lagrange::compute_facet_area(mesh); + + + // Let the UI know what to update + ui::set_mesh_vertices_dirty(viewer, mesh_entity); + ui::set_mesh_normals_dirty(viewer, mesh_entity); + + // Any visualization using facet "area" attribute will get updated + ui::set_mesh_attribute_dirty(viewer, mesh_entity, ui::IndexingMode::FACE, "area"); + + + return true; + }); + + return 0; +} diff --git a/modules/ui/examples/ui_mesh/main.cpp b/modules/ui/examples/ui_mesh/main.cpp deleted file mode 100644 index 052fc95b..00000000 --- a/modules/ui/examples/ui_mesh/main.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#include -#include -#include - -#include - - -const char* obj_cube = R"( -o Cube -v 1.000000 1.000000 -1.000000 -v 1.000000 -1.000000 -1.000000 -v 1.000000 1.000000 1.000000 -v 1.000000 -1.000000 1.000000 -v -1.000000 1.000000 -1.000000 -v -1.000000 -1.000000 -1.000000 -v -1.000000 1.000000 1.000000 -v -1.000000 -1.000000 1.000000 -vt 0.625000 0.500000 -vt 0.875000 0.500000 -vt 0.875000 0.750000 -vt 0.625000 0.750000 -vt 0.375000 0.750000 -vt 0.625000 1.000000 -vt 0.375000 1.000000 -vt 0.375000 0.000000 -vt 0.625000 0.000000 -vt 0.625000 0.250000 -vt 0.375000 0.250000 -vt 0.125000 0.500000 -vt 0.375000 0.500000 -vt 0.125000 0.750000 -vn 0.0000 1.0000 0.0000 -vn 0.0000 0.0000 1.0000 -vn -1.0000 0.0000 0.0000 -vn 0.0000 -1.0000 0.0000 -vn 1.0000 0.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -f 1/1/1 5/2/1 7/3/1 3/4/1 -f 4/5/2 3/4/2 7/6/2 8/7/2 -f 8/8/3 7/9/3 5/10/3 6/11/3 -f 6/12/4 2/13/4 4/5/4 8/14/4 -f 2/13/5 1/1/5 3/4/5 4/5/5 -f 6/11/6 5/10/6 1/1/6 2/13/6 -)"; - -using namespace lagrange::ui; - -std::unique_ptr create_star(int n = 32, float r0 = 1.0f, float r1 = 0.5f) -{ - n = n % 2 ? n + 1 : n; - lagrange::Vertices2Df vertices(n + 1, 2); - lagrange::Triangles triangles((n), 3); - vertices.row(0) << 0, 0; - for (auto i = 0; i < n; i++) { - float angle = (i) / float(n) * lagrange::ui::two_pi(); - float r = (i % 2) ? r0 : r1; - vertices.row(i + 1) << r * sinf(angle), r * cosf(angle); - } - - for (auto i = 0; i < n; i++) { - triangles.row(i) << 0, i + 1, i + 2; - } - triangles.row(n - 1) << 0, n, 1; - - return lagrange::create_mesh(vertices, triangles); -} - - -struct my_mesh_visitor -{ - template - void operator()(MeshType& mesh) - { - lagrange::logger().info("\tMeshType = {}", typeid(MeshType).name()); - lagrange::logger().info("\tnum_vertices = {}", mesh.get_num_vertices()); - lagrange::logger().info("\tnum_facets = {}", mesh.get_num_facets()); - } -}; - -int main(int argc, char** argv) -{ - std::string user_mesh; - CLI::App app{argv[0]}; - app.add_option("input", user_mesh, "Input mesh.")->check(CLI::ExistingFile); - CLI11_PARSE(app, argc, argv) - - - Viewer::WindowOptions wopt; - wopt.width = 1920; - wopt.height = 1080; - wopt.window_title = "Example Mesh"; - - Viewer viewer(wopt); - - if (!viewer.is_initialized()) return 1; - Scene& scene = viewer.get_scene(); - - - /* - Dynamically created mesh (TriangleMesh3D -> MeshModel - */ - int sphere_subdivision = 2; - auto sphere_model = - scene.add_model(ModelFactory::make(lagrange::create_sphere(sphere_subdivision), "Sphere")); - sphere_model->apply_transform(Eigen::Translation3f(0, 0, -1.0f)); - - - /* - Dynamically created 2D mesh, displayed in 3D with z = 0 - */ - int star_vertices = 32; - auto star_model = scene.add_model(ModelFactory::make(create_star(), "Star")); - star_model->apply_transform(Eigen::AngleAxisf(lagrange::ui::pi() / 2.0f, Eigen::Vector3f(0.0f, 1.0f, 0.0f)) * - Eigen::Translation3f(0, 0, -1.0f)); - - - /* - 3D Quad mesh loaded from .obj - Note that load_obj returns a vector of models (in case there are more than in the .obj) - */ - - MeshModel * obj_model = nullptr; - if (user_mesh.length() > 0) { - //Load directly from file, including materials - auto loaded_models = - ModelFactory::load_obj(user_mesh); - - if (loaded_models.size() == 0) { - lagrange::logger().error("Provided .obj doesn't contain any meshes"); - return -1; - } - - //Add all loaded objects, remember reference to the first one - obj_model = scene.add_models(std::move(loaded_models)).front(); - - } else { - - //Load .obj from stream - std::stringstream input_stream; - input_stream << obj_cube; - - //Use lagrange::io module to load mesh from arbitrary input stream - auto result = lagrange::io::load_mesh_ext(input_stream); - - //Create a model using the mesh and add it to scene - obj_model = - scene.add_model(ModelFactory::make(std::move(result.meshes.front()), ".obj cube")); - } - - obj_model->apply_transform(Eigen::Translation3f(0,0,1)); - - /* - Creates a visualization "my viz" (toggle it on/off in "Render Passes" dropdown) - It takes EDGE indices, assigns color using the given lambda and renders LINES - */ - viewer.add_viz(Viz::create_indexed_colormapping( - "my viz", Viz::Attribute::EDGE, Viz::Primitive::LINES, [](const Model&, int index) { - return colormap_turbo((index % 25) / 25.0f); - })); - - while (!viewer.should_close()) { - viewer.begin_frame(); - - - ImGui::Begin("Example Mesh Window"); - - /* - Import new sphere mesh with different subdivision parameters - into existing model - */ - ImGui::Text("Subdivide sphere"); - ImGui::PushID(0); - ImGui::SameLine(); - if (ImGui::Button("+", ImVec2(30, 0))) { - sphere_subdivision += 1; - sphere_model->import_mesh(lagrange::create_sphere(sphere_subdivision)); - } - ImGui::SameLine(); - if (ImGui::Button("-", ImVec2(30, 0)) && sphere_subdivision > 1) { - sphere_subdivision -= 1; - sphere_model->import_mesh(lagrange::create_sphere(sphere_subdivision)); - } - ImGui::PopID(); - - /* - Import new star mesh with different parameters - into existing model - */ - ImGui::Text("Star vertices"); - ImGui::PushID(1); - ImGui::SameLine(); - if (ImGui::Button("+", ImVec2(30, 0))) { - star_vertices += 2; - star_model->import_mesh(create_star(star_vertices)); - } - ImGui::SameLine(); - if (ImGui::Button("-", ImVec2(30, 0)) && star_vertices > 4) { - star_vertices -= 2; - star_model->import_mesh(create_star(star_vertices)); - } - ImGui::PopID(); - - /* - Change existing mesh: - 1. First export the mesh - 2. Modify its data - 3. Import it to model again - */ - ImGui::Text("Twist .obj"); - ImGui::PushID(2); - - float twist_angle = 0.0f; - if (ImGui::SliderFloat("", &twist_angle, -1.0f, 1.0f)) { - // Get original bounds & diagonal - auto bounds = obj_model->get_bounds().transformed(obj_model->get_inverse_transform()); - auto diag = bounds.diagonal(); - - // When modifying mesh, export it first - auto mesh = obj_model->export_mesh(); - - // Export vertices to modify them - lagrange::Vertices3Df V; - mesh->export_vertices(V); - - // Apply "twist" operation - for (auto i : lagrange::range(V.rows())) { - float rotation_angle_y = twist_angle * std::fmod(V(i, 1), diag.y() / 19.0f); - float x = V(i, 0); - float z = V(i, 2); - V(i, 0) = x * cosf(rotation_angle_y) - z * sinf(rotation_angle_y); - V(i, 2) = x * sinf(rotation_angle_y) + z * cosf(rotation_angle_y); - } - - // Import vertices to mesh again - mesh->import_vertices(V); - - // When done with modifications, import the mesh - obj_model->import_mesh(mesh); - } - - ImGui::PopID(); - - - ImGui::PushID(3); - static int instance_count = 0; - if (ImGui::Button("Create sphere instance")) { - auto mesh_ptr_copy = sphere_model->export_mesh(); - sphere_model->import_mesh(mesh_ptr_copy); - auto instance = scene.add_model(ModelFactory::make(mesh_ptr_copy, "instance")); - instance->apply_transform(sphere_model->get_transform() * Eigen::Translation3f( - float(instance_count + 1) * Eigen::Vector3f(2.0f, 0.0f, 0.0f))); - - instance_count++; - } - ImGui::PopID(); - - - /* - If you need to access the type of the mesh, use the visitor pattern - */ - - // Either through a generic lambda - if (ImGui::Button("Visit models through generic lambda")) { - for (auto& model : scene.get_models()) { - lagrange::logger().info("{}", model->get_name()); - - model->visit_mesh([](auto& mesh) { - // If you need to get the specific type, use decltype: - using MeshType = std::remove_reference_t; - - lagrange::logger().info("\tMeshType = {}", typeid(MeshType).name()); - - // Here you have access to all the mesh methods - lagrange::logger().info("\tnum_vertices = {}", mesh.get_num_vertices()); - lagrange::logger().info("\tnum_facets = {}", mesh.get_num_facets()); - }); - } - } - - // Or through a functor (i.e., a struct with overloaded operator()) - if (ImGui::Button("Visit models through visitor functor")) { - for (auto& model : scene.get_models()) { - lagrange::logger().info("{}", model->get_name()); - model->visit_mesh(my_mesh_visitor()); - } - } - - - ImGui::End(); - - viewer.end_frame(); - } - - return 0; -} diff --git a/modules/ui/examples/ui_playground/CMakeLists.txt b/modules/ui/examples/ui_playground/CMakeLists.txt new file mode 100644 index 00000000..eb3b1cda --- /dev/null +++ b/modules/ui/examples/ui_playground/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright 2020 Adobe. All rights reserved. +# This file is licensed to you under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +# OF ANY KIND, either express or implied. See the License for the specific language +# governing permissions and limitations under the License. +# +include(cli11) +lagrange_include_modules(io) + +lagrange_add_example(ui_playground + main.cpp +) + +target_link_libraries(ui_playground lagrange::ui lagrange::io CLI11::CLI11) + +if(LAGRANGE_UI_USE_MDL) + add_custom_command(TARGET ui_playground POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${MDL_DYNAMIC_LIBS} + $ + ) +endif() + diff --git a/modules/ui/examples/ui_playground/main.cpp b/modules/ui/examples/ui_playground/main.cpp new file mode 100644 index 00000000..d3e53867 --- /dev/null +++ b/modules/ui/examples/ui_playground/main.cpp @@ -0,0 +1,354 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +#include + +#include +#include + +#include +#include +#include +#include + +/* + This is an experimental example, combining multiple features of the UI. +*/ + +namespace ui = lagrange::ui; + +void add_subtree( + ui::Viewer& v, + ui::Entity geometry, + ui::Entity parent, + int max_depth, + int depth = 0) +{ + if (depth == max_depth) return; + + auto& w = v.registry(); + + auto sub0 = ui::show_mesh(w, geometry); + auto sub1 = ui::show_mesh(w, geometry); + + + ui::set_name(w, sub0, lagrange::string_format("{}_left", depth)); + ui::set_name(w, sub1, lagrange::string_format("{}_right", depth)); + + + const float scale_factor = 0.5f; + w.get(sub0).local = + Eigen::Translation3f(1.0f, 1.0f, 0) * Eigen::Scaling(scale_factor); + w.get(sub1).local = + Eigen::Translation3f(-1.0f, 1.0f, 0) * Eigen::Scaling(scale_factor); + + ui::set_parent(w, sub0, parent); + ui::set_parent(w, sub1, parent); + + // Todo better api, e.g. ui::set_pbr_material() + w.get(sub0).material->set_color( + "material_base_color", + ui::Color::random(int(sub0))); + + w.get(sub1).material->set_color( + "material_base_color", + ui::Color::random(int(sub1))); + + add_subtree(v, geometry, sub0, max_depth, depth + 1); + add_subtree(v, geometry, sub1, max_depth, depth + 1); +} + + +int main(int argc, char** argv) +{ + /* + Set up initial window and OpenGL context options + */ + + struct + { + std::string input; + } args; + + CLI::App app{argv[0]}; + app.add_option("input", args.input, "Input mesh."); + CLI11_PARSE(app, argc, argv) + + + ui::Viewer::WindowOptions wopt; + wopt.width = 1920; + wopt.height = 1080; + wopt.window_title = "UI Playground Example"; + wopt.vsync = false; + + + /* + Initialize the viewer + */ + ui::Viewer viewer(wopt); + + /* + Check if everything initialized + */ + if (!viewer.is_initialized()) return 1; + + + // Test mesh types and meta + { + ui::MeshData d; + auto cube_double = lagrange::create_cube(); + auto cube_float = lagrange::create_mesh( + cube_double->get_vertices().cast(), + cube_double->get_facets()); + + lagrange::compute_vertex_valence(*cube_double); + lagrange::compute_vertex_valence(*cube_float); + + d.mesh = std::move(cube_double); + d.type = entt::type_id(); + + auto& true_ref = reinterpret_cast(*d.mesh); + lagrange::logger().info("V0:\n{}", true_ref.get_vertices()); + + auto vertices = ui::get_mesh_vertices(d); + auto facets = ui::get_mesh_facets(d); + + lagrange::logger().info("V:\n{}", vertices); + lagrange::logger().info("F:\n{}", facets); + + auto valence = ui::get_mesh_vertex_attribute(d, "valence"); + lagrange::logger().info("valence:\n{}", valence); + + Eigen::MatrixXf m; + m.cast(); + char k; + k = 0; + } + + + + lagrange::logger().set_level(spdlog::level::debug); + auto& registry = viewer.registry(); + + + // Creates a mesh entity + ui::Entity my_mesh; + + if (args.input.length() > 0) { + lagrange::io::MeshLoaderParams p; + p.normalize = true; + my_mesh = ui::load_obj(registry, args.input, p); + } else { + lagrange::Vertices3Df vertices = lagrange::create_cube()->get_vertices().cast(); + lagrange::Triangles facets = lagrange::create_cube()->get_facets(); + my_mesh = ui::register_mesh(registry, lagrange::create_mesh(vertices, facets)); + } + + { + auto* basemesh = registry.get(my_mesh).mesh.get(); + auto* mesh = dynamic_cast(basemesh); + assert(mesh); + if (mesh) { + lagrange::compute_dijkstra_distance(*mesh, 0, Eigen::Vector3f(0.3f, 0.3f, 0.3f)); + lagrange::compute_vertex_valence(*mesh); + lagrange::compute_vertex_normal(*mesh); + lagrange::compute_triangle_normal(*mesh); + if (!mesh->is_uv_initialized()) { + lagrange::logger().info("Creating trivial uvs"); + mesh->import_uv( + mesh->get_vertices().leftCols(2), + lagrange::TriangleMesh3Df::UVIndices(mesh->get_facets())); + } + lagrange::compute_corner_tangent_bitangent(*mesh); + + using AttrArray = lagrange::TriangleMesh3Df::AttributeArray; + + mesh->add_vertex_attribute("bone_ids"); + AttrArray bone_ids = AttrArray(mesh->get_num_vertices(), 4); + + for (auto i = 0; i < bone_ids.rows(); i++) { + bone_ids(i, 0) = (i < bone_ids.rows() / 2) ? 0.0f : 1.0f; + bone_ids(i, 1) = 0.0f; + bone_ids(i, 2) = 0.0f; + bone_ids(i, 3) = 0.0f; + } + mesh->import_vertex_attribute("bone_ids", std::move(bone_ids)); + + mesh->add_vertex_attribute("bone_weights"); + AttrArray bone_weights = AttrArray(mesh->get_num_vertices(), 4); + + for (auto i = 0; i < bone_weights.rows(); i++) { + bone_weights(i, 0) = 1.0; + bone_weights(i, 1) = 0; + bone_weights(i, 2) = 0; + bone_weights(i, 3) = 0; + } + mesh->import_vertex_attribute("bone_weights", std::move(bone_weights)); + } + } + + { + auto dijkstra = + ui::show_vertex_attribute(registry, my_mesh, "dijkstra_distance", ui::Glyph::Surface); + ui::set_transform(registry, dijkstra, Eigen::Translation3f(0, 0, -2.0f)); + + auto viridis = ui::generate_colormap(ui::colormap_viridis); + ui::set_colormap(registry, dijkstra, viridis); + } + + { + auto valence = ui::show_vertex_attribute(registry, my_mesh, "valence", ui::Glyph::Surface); + registry.get(valence).local = Eigen::Translation3f(-1.0f, 0, -2.0f); + } + + { + auto normal = ui::show_vertex_attribute(registry, my_mesh, "normal", ui::Glyph::Surface); + registry.get(normal).local = Eigen::Translation3f(1.0f, 0, -2.0f); + } + + { + auto fnormal = ui::show_facet_attribute(registry, my_mesh, "normal", ui::Glyph::Surface); + registry.get(fnormal).local = Eigen::Translation3f(1.0f, 1.0f, -2.0f); + } + + { + auto attrib_render = + ui::show_corner_attribute(registry, my_mesh, "tangent", ui::Glyph::Surface); + registry.get(attrib_render).local = Eigen::Translation3f(-2.0f, 1.0f, -2.0f); + } + + { + auto attrib_render = + ui::show_corner_attribute(registry, my_mesh, "bitangent", ui::Glyph::Surface); + registry.get(attrib_render).local = + Eigen::Translation3f(-2.0f, -1.0f, -2.0f); + } + + + // Creates a default visualization (PBR) of the mesh entity + auto obj_pbr = ui::show_mesh(registry, my_mesh, ui::DefaultShaders::PBRSkeletal); + + + registry.emplace_or_replace(obj_pbr, "root"); + add_subtree(viewer, my_mesh, obj_pbr, 4); + + + // Window + struct MyPanelState + { + int x = 42; + int y = 7; + }; + + + /* + * Register new window type, set behavior of the window + */ + auto panel_fn = [](ui::Registry& registry, ui::Entity e) { + auto& s = registry.get(e); + ImGui::Text("Local panel state:"); + ImGui::InputInt("x", &s.x); + ImGui::InputInt("y", &s.y); + + ImGui::Text("Shared state from other system:"); + auto pos = ui::get_input(registry).mouse_position; + ImGui::InputFloat2("Mouse pos:", pos.data()); + + ImGui::Text("Shared state created and modified by these panels"); + + + struct MyPrivateContextVar + { + float x; + + ui::Entity viz_e = ui::NullEntity; + }; + auto& priv = registry.ctx_or_set(MyPrivateContextVar{16.0f}); + + ImGui::InputFloat("MyPrivateContextVar.x:", &priv.x); + + if (priv.viz_e != ui::NullEntity) { + ui::show_widget(registry, priv.viz_e, entt::resolve(entt::type_id())); + } + }; + + // Create panel instances with different data + auto w1 = ui::add_panel(registry, "Mypanel", panel_fn); + registry.emplace(w1); + auto w2 = ui::add_panel(registry, "Mypanel 2", panel_fn); + registry.emplace(w2, MyPanelState{0, 0}); + + struct MyRotatingComponent + { + float speed = 1.0f; + Eigen::Vector3f axis = Eigen::Vector3f::UnitY(); + }; + + ui::register_component("My Rotating Component"); + ui::register_component_widget([](ui::Registry* w, ui::Entity e) { + auto& rot = w->get(e); + if (ImGui::DragFloat3("Axis", rot.axis.data())) { + rot.axis.normalize(); + } + ImGui::DragFloat("Speed", &rot.speed); + }); + + + viewer.systems().add(ui::Systems::Stage::Interface, [](ui::Registry& r) { + auto dt = float(r.ctx().dt); + auto view = r.view(); + + for (auto e : view) { + auto& transform = view.get(e); + auto& rot = view.get(e); + transform.local = transform.local * Eigen::AngleAxisf(rot.speed * dt, rot.axis); + } + }); + + ui::add_point_light(registry, 30.0f * Eigen::Vector3f(0, 0, 1), Eigen::Vector3f(-1, 1, -1)); + ui::add_directional_light(registry, Eigen::Vector3f(0, 0.5f, 0), Eigen::Vector3f(1, -1, 1)); + ui::add_spot_light( + registry, + 30.0f * Eigen::Vector3f(1, 0, 0), + Eigen::Vector3f(1, 1, 1), + Eigen::Vector3f(-1, -1, -1)); + + auto ground_plane = + ui::show_mesh(registry, ui::register_mesh(registry, lagrange::create_quad(false))); + + + ui::set_transform( + registry, + ground_plane, + Eigen::Scaling(10.0f, 1.0f, 10.0f) * Eigen::Translation3f(0.0f, -1.0f, 0.0f) * + Eigen::AngleAxisf(-ui::pi() / 2.0f, Eigen::Vector3f::UnitX())); + + + float t = 0; + + viewer.run([&](ui::Registry& registry) { + t += float(viewer.get_frame_elapsed_time()); + + + // Update bones of a mesh + Eigen::Affine3f a, b; + a = Eigen::Translation3f(0, std::sin(t), 0); + b = Eigen::Translation3f(std::sin(t), 0, 0); + Eigen::Matrix4f bones[2] = {a.matrix(), b.matrix()}; + if (registry.valid(obj_pbr)) { + ui::get_material(registry, obj_pbr)->set_mat4_array("bones", bones, 2); + } + + return true; + }); + + return 0; +} diff --git a/modules/ui/examples/ui_basic/CMakeLists.txt b/modules/ui/examples/ui_scene/CMakeLists.txt similarity index 79% rename from modules/ui/examples/ui_basic/CMakeLists.txt rename to modules/ui/examples/ui_scene/CMakeLists.txt index de9d51c5..edce93e5 100644 --- a/modules/ui/examples/ui_basic/CMakeLists.txt +++ b/modules/ui/examples/ui_scene/CMakeLists.txt @@ -9,19 +9,20 @@ # OF ANY KIND, either express or implied. See the License for the specific language # governing permissions and limitations under the License. # +include(cli11) lagrange_include_modules(io) -lagrange_add_example(ui_basic +lagrange_add_example(ui_scene main.cpp ) -target_link_libraries(ui_basic lagrange::ui lagrange::io) +target_link_libraries(ui_scene lagrange::ui lagrange::io CLI11::CLI11) if(LAGRANGE_UI_USE_MDL) - add_custom_command(TARGET ui_basic POST_BUILD + add_custom_command(TARGET ui_scene POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${MDL_DYNAMIC_LIBS} - $ + $ ) endif() diff --git a/modules/ui/examples/ui_scene/main.cpp b/modules/ui/examples/ui_scene/main.cpp new file mode 100644 index 00000000..2b9e3de2 --- /dev/null +++ b/modules/ui/examples/ui_scene/main.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +#include +#include + + +namespace ui = lagrange::ui; + +int main(int argc, char** argv) +{ + struct + { + std::string input; + bool verbose = false; + } args; + + CLI::App app{argv[0]}; + app.add_option("input", args.input, "Input scene"); + app.add_flag("-v", args.verbose, "Verbose"); + CLI11_PARSE(app, argc, argv) + + if (args.verbose) { + lagrange::logger().set_level(spdlog::level::debug); + } + + ui::Viewer viewer("UI Example - Scene", 1920, 1080); + + #ifdef LAGRANGE_WITH_ASSIMP + if (!args.input.empty()) { + auto root = ui::load_scene(viewer, args.input); + ui::camera_focus_and_fit(viewer, ui::get_focused_camera_entity(viewer)); + } + #else + lagrange::logger().error("Load scene is only available with Assimp."); + #endif + + viewer.run(); + + return 0; +} diff --git a/modules/ui/examples/ui_show_attribute/CMakeLists.txt b/modules/ui/examples/ui_show_attribute/CMakeLists.txt new file mode 100644 index 00000000..e08232fc --- /dev/null +++ b/modules/ui/examples/ui_show_attribute/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright 2020 Adobe. All rights reserved. +# This file is licensed to you under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under +# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +# OF ANY KIND, either express or implied. See the License for the specific language +# governing permissions and limitations under the License. +# +include(cli11) +lagrange_include_modules(io) + +lagrange_add_example(ui_show_attribute + main.cpp +) + +target_link_libraries(ui_show_attribute lagrange::ui lagrange::io CLI11::CLI11) + +if(LAGRANGE_UI_USE_MDL) + add_custom_command(TARGET ui_show_attribute POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${MDL_DYNAMIC_LIBS} + $ + ) +endif() + diff --git a/modules/ui/examples/ui_show_attribute/main.cpp b/modules/ui/examples/ui_show_attribute/main.cpp new file mode 100644 index 00000000..72e2a544 --- /dev/null +++ b/modules/ui/examples/ui_show_attribute/main.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include + +namespace ui = lagrange::ui; + +int main(int argc, char** argv) +{ + struct + { + std::string input; + bool verbose = false; + } args; + + CLI::App app{argv[0]}; + app.add_option("input", args.input, "Input mesh."); + app.add_flag("-v", args.verbose, "verbose"); + CLI11_PARSE(app, argc, argv) + + if (args.verbose) { + lagrange::logger().set_level(spdlog::level::debug); + } + + if (args.input.length() == 0) { + lagrange::logger().error("Input mesh must be specified"); + return 1; + } + + // Initialize the viewer + ui::Viewer viewer("UI Example - Show Attribute", 1920, 1080); + + // Get reference to the registry (global state of the ui) + auto& r = viewer.registry(); + + // Load a mesh, returns a handle + // This will only register the mesh, but it will not show it + lagrange::io::MeshLoaderParams p; + p.normalize = true; + auto mesh_entity = ui::load_obj(r, args.input, p); + + // Retrieve the mesh + auto& mesh = ui::get_mesh(r, mesh_entity); + + // Compute attributes to visualize + { + lagrange::compute_dijkstra_distance( + mesh, + 0, + Eigen::Vector3d(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + lagrange::compute_vertex_valence(mesh); + lagrange::compute_vertex_normal(mesh); + lagrange::compute_triangle_normal(mesh); + lagrange::compute_corner_tangent_bitangent(mesh); + lagrange::compute_edge_lengths(mesh); + } + + + // Show attribute in the scene + // This will create a scene object for each of the visualized attributes with material and + // shader setup needed for visualizing the given attribute with given glyph + std::vector scene_entities; + + const auto glyph = ui::Glyph::Surface; + + { + // Show dijkstra_distance vertex attribute using viridis colormap + auto e = ui::show_vertex_attribute(r, mesh_entity, "dijkstra_distance", glyph); + ui::set_colormap(r, e, ui::generate_colormap(ui::colormap_viridis)); + scene_entities.push_back(e); + } + + + { + // Show vertex valence vertex attribute using magma colormap + auto e = ui::show_vertex_attribute(r, mesh_entity, "valence", glyph); + ui::set_colormap(r, e, ui::generate_colormap(ui::colormap_magma)); + scene_entities.push_back(e); + } + + + { + // Show vertex normal, mapped to rgb + auto e = ui::show_vertex_attribute(r, mesh_entity, "normal", glyph); + scene_entities.push_back(e); + } + + { + // Show facet normal, mapped to rgb + auto e = ui::show_facet_attribute(r, mesh_entity, "normal", glyph); + scene_entities.push_back(e); + } + + + { + // Show corner attributes tangent and bitangent + scene_entities.push_back(ui::show_corner_attribute(r, mesh_entity, "tangent", glyph)); + scene_entities.push_back(ui::show_corner_attribute(r, mesh_entity, "bitangent", glyph)); + } + + { + // Show edge lengths attribute + auto e = ui::show_edge_attribute(r, mesh_entity, "length", glyph); + ui::set_colormap(r, e, ui::generate_colormap(ui::colormap_turbo)); + scene_entities.push_back(e); + } + + if (mesh.is_uv_initialized()) { + auto e = ui::show_indexed_attribute(r, mesh_entity, "uv", glyph); + ui::set_colormap(r, e, ui::generate_colormap(ui::colormap_coolwarm)); + scene_entities.push_back(e); + } + + auto group = ui::group(r, scene_entities); + ui::set_name(r, group, "Attribute visualizations"); + + // Distribute all the scene entities in a grid + const int rows = std::max(1, int(sqrtf(float(scene_entities.size())))); + const int cols = (int(scene_entities.size()) + rows - 1) / rows; + + for (auto i = 0; i < scene_entities.size(); i++) { + int row = i % cols; + int col = i / cols; + + r.get(scene_entities[i]).local = + Eigen::Translation3f(float(row), 0.0f, float(col)) * + Eigen::Translation3f(float(rows) * -0.5f, 0.0f, float(cols) * -0.5f); + } + + + viewer.run(); + + return 0; +} diff --git a/modules/ui/examples/ui_mesh/CMakeLists.txt b/modules/ui/examples/ui_treenode/CMakeLists.txt similarity index 78% rename from modules/ui/examples/ui_mesh/CMakeLists.txt rename to modules/ui/examples/ui_treenode/CMakeLists.txt index afebd718..4d251b23 100644 --- a/modules/ui/examples/ui_mesh/CMakeLists.txt +++ b/modules/ui/examples/ui_treenode/CMakeLists.txt @@ -9,20 +9,20 @@ # OF ANY KIND, either express or implied. See the License for the specific language # governing permissions and limitations under the License. # +include(cli11) lagrange_include_modules(io) -lagrange_add_example(ui_mesh +lagrange_add_example(ui_treenode main.cpp ) - -target_link_libraries(ui_mesh lagrange::ui lagrange::io CLI11::CLI11) +target_link_libraries(ui_treenode lagrange::ui lagrange::io CLI11::CLI11) if(LAGRANGE_UI_USE_MDL) - add_custom_command(TARGET ui_mesh POST_BUILD + add_custom_command(TARGET ui_treenode POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${MDL_DYNAMIC_LIBS} - $ + $ ) endif() diff --git a/modules/ui/examples/ui_treenode/main.cpp b/modules/ui/examples/ui_treenode/main.cpp new file mode 100644 index 00000000..57c54fe2 --- /dev/null +++ b/modules/ui/examples/ui_treenode/main.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +#include +#include + +namespace ui = lagrange::ui; + +int main(int argc, char** argv) +{ + ui::Viewer v("UI Example - Tree Node", 1920, 1080); + + // Creates an empty scene node + auto a = ui::create_scene_node(v, "Empty scene node"); + + // Creates an empty scene node with a as parent + auto b = ui::create_scene_node(v, "Another node", a); + + // Light is another scene node, with + auto light = ui::add_directional_light(v); + ui::set_name(v, light, "Light Node"); + + // Group under a scene node + auto group = ui::group(v, {a, light}, "Group"); + + // Ungroup (and remove new parent) + //ui::ungroup(v, group, true); + + + + { + auto top_level = ui::create_scene_node(v, "Top level"); + + // Create nodes recursively + ui::Entity parent = top_level; + for (auto i = 0; i < 5; i++) { + parent = ui::create_scene_node(v, "Recursive", parent); + } + + // Remove recursively + ui::remove(v, top_level, true); + } + + + + v.run(); + + return 0; +} diff --git a/modules/ui/examples/ui_viz/VizBuilder.cpp b/modules/ui/examples/ui_viz/VizBuilder.cpp deleted file mode 100644 index bfda98bc..00000000 --- a/modules/ui/examples/ui_viz/VizBuilder.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#include "VizBuilder.h" - - -Color index_turbo(const Model&, int index) -{ - return colormap_turbo((index % 16) / 16.0f); -} - -Color index_grayscale(const Model&, int index) -{ - float v = (index % 16) / 16.0f; - return Color(v, v, v, 1.0f); -} - - -Color index_rgb_pos_vertex(const Model& model, int index) -{ - Color result; - model.visit_tuple_const([&](auto& meshmodel) { - const auto& v = meshmodel.get_mesh().get_vertices().row(index).eval(); - auto bb = meshmodel.get_bounds(); - result = Color(bb.normalize_point(v.transpose()), 1.0f); - }); - - return result; -} - -Color index_rgb_pos_edge(const Model& model, int index) -{ - Color result; - model.visit_tuple_const([&](auto& meshmodel) { - auto& mesh = meshmodel.get_mesh(); - const auto& e = mesh.get_edges()[index]; - const auto& v1 = mesh.get_vertices().row(e.v1()).eval(); - const auto& v2 = mesh.get_vertices().row(e.v2()).eval(); - const auto v = (v1 + v2) * 0.5; - - auto bb = meshmodel.get_bounds(); - result = Color(bb.normalize_point(v.transpose()), 1.0f); - }); - - return result; -} - -Color index_rgb_pos_facet(const Model& model, int index) -{ - Color result; - model.visit_tuple_const([&](auto& meshmodel) { - auto& mesh = meshmodel.get_mesh(); - auto& V = mesh.get_vertices(); - auto& F = mesh.get_facets(); - Eigen::Vector3d v(0, 0, 0); - int count = 0; - for (auto i = 0; i < F.cols(); i++) { - auto v_index = F(index, i); - if (v_index > V.rows()) break; - v += V.row(v_index).template cast(); - count++; - } - - v *= 1.0f / (count); - auto bb = meshmodel.get_bounds(); - result = Color(bb.normalize_point(v), 1.0f); - }); - - return result; -} - -Color index_rgb_pos_corner(const Model& model, int index) -{ - Color result; - model.visit_tuple_const([&](auto& meshmodel) { - auto& mesh = meshmodel.get_mesh(); - auto& V = mesh.get_vertices(); - auto& F = mesh.get_facets(); - auto v = V.row(F(index / F.cols(), index % F.cols())).eval(); - auto bb = meshmodel.get_bounds(); - result = Color(bb.normalize_point(v.transpose()),1.0f); - }); - - return result; -} - - -Color value_to_rgba(const Model&, const Viz::AttribValue& v) -{ - Color c(0, 0, 0, 1); - for (auto i = 0; i < std::min(4, int(v.cols())); i++) c(i) = float(v(i)); - return c; -} - - - -Color value_invert_color(const Model&, const Viz::AttribValue& v) -{ - Color c(1, 1, 1, 1); - for (auto i = 0; i < std::min(4, int(v.cols())); i++) c(i) = float(1.0 - v(i)); - return c; -} - -Color value_norm_to_turbo(const Model&, const Viz::AttribValue& v) -{ - return colormap_turbo(static_cast(v.norm())); -} - - -VizBuilder::VizBuilder() -{ - cfg.attribute_name = "random_vertex_attribute"; - cfg.attribute = Viz::Attribute::VERTEX; - cfg.primitive = Viz::Primitive::TRIANGLES; - cfg.colormapping = Viz::Colormapping::CUSTOM; -} - -void VizBuilder::operator()(Viewer& v) -{ - cfg.viz_name = Viz::to_string(cfg.attribute) + " -> " + Viz::to_string(cfg.primitive) + "[" + - Viz::to_string(cfg.colormapping) + "]" + "[" + Viz::to_string(cfg.shading) + "]"; - - while (v.get_renderer().get_pipeline().get_pass(cfg.viz_name)) cfg.viz_name += "_"; - - ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Basic")) { - ImGui::InputText("Viz name", &cfg.viz_name); - - combo_box("Colormapping", colormapping_types, cfg.colormapping); - - if (cfg.colormapping == Viz::Colormapping::UNIFORM) { - UIWidget("Uniform color")(cfg.uniform_color); - } - else if (cfg.colormapping == Viz::Colormapping::CUSTOM) { - if (ImGui::RadioButton("By Index", indexed_colormap)) { - indexed_colormap = true; - } - ImGui::SameLine(); - if (ImGui::RadioButton("By Value", !indexed_colormap)) { - indexed_colormap = false; - } - - if (indexed_colormap) { - ImGui::Combo( - "Function (indexed)", &indexed_colormap_fn_index, indexed_colormap_fn_names, 3); - cfg.attribute_name = ""; - } - else { - ImGui::Combo( - "Attribute name", &attribute_name_index, attribute_names, 4); - - cfg.attribute_name = attribute_names[attribute_name_index]; - - ImGui::Combo( - "Function (value)", &value_colormap_fn_index, value_colormap_fn_names, 3); - } - } - - if (cfg.colormapping != Viz::Colormapping::UNIFORM) { - combo_box("Attributes", attrib_types, cfg.attribute); - } - - combo_box("Primitive", primitive_types, cfg.primitive); - - - combo_box("Shading", shading_types, cfg.shading); - - ImGui::TreePop(); - } - - if (ImGui::TreeNode("Advanced")) { - combo_box("Filter Global", filter_types, cfg.filter_global); - combo_box("Filter Local", filter_types, cfg.filter_local); - - ImGui::SliderFloat("Backside Alpha", &cfg.backside_alpha, 0, 1); - ImGui::Checkbox("Cull Backface", &cfg.cull_backface); - ImGui::Checkbox("Replace with bounds", &cfg.replace_with_bounding_box); - ImGui::InputText("Custom Sub Buffer ID", &cfg.custom_sub_buffer_id); - ImGui::Checkbox("FBOConfig::create_color", &cfg.fbo_config.create_color); - ImGui::Checkbox("FBOConfig::create_depth", &cfg.fbo_config.create_depth); - ImGui::Text("FBOConfig::target_fbo %u", cfg.fbo_config.target_fbo->get_id()); - ImGui::TreePop(); - } - - - if (ImGui::Button("Create", ImVec2(ImGui::GetContentRegionAvail().x, 40.f))) { - assign_custom_func(); - - - try { - v.add_viz(cfg, true); - cfg.uniform_color = Color::random(0); - } - catch (std::exception& ex) { - lagrange::logger().error("Couldn't create render pass:\n{}", ex.what()); - } - } -} - -void VizBuilder::assign_custom_func() -{ - cfg.custom_index_color_fn = nullptr; - cfg.custom_attrib_color_fn = nullptr; - - - if (cfg.colormapping == Viz::Colormapping::CUSTOM) { - if (indexed_colormap) { - switch (indexed_colormap_fn_index) { - case 0: cfg.custom_index_color_fn = index_turbo; break; - case 1: cfg.custom_index_color_fn = index_grayscale; break; - case 2: - switch (cfg.attribute) { - case lagrange::ui::Viz::Attribute::VERTEX: - cfg.custom_index_color_fn = index_rgb_pos_vertex; - break; - case lagrange::ui::Viz::Attribute::EDGE: - cfg.custom_index_color_fn = index_rgb_pos_edge; - break; - case lagrange::ui::Viz::Attribute::FACET: - cfg.custom_index_color_fn = index_rgb_pos_facet; - break; - case lagrange::ui::Viz::Attribute::CORNER: - cfg.custom_index_color_fn = index_rgb_pos_corner; - break; - default: break; - } - break; - } - } - else { - switch (value_colormap_fn_index) { - case 0: cfg.custom_attrib_color_fn = value_norm_to_turbo; break; - case 1: cfg.custom_attrib_color_fn = value_to_rgba; break; - case 2: cfg.custom_attrib_color_fn = value_invert_color; break; - } - } - } -} diff --git a/modules/ui/examples/ui_viz/VizBuilder.h b/modules/ui/examples/ui_viz/VizBuilder.h deleted file mode 100644 index dfe2b72f..00000000 --- a/modules/ui/examples/ui_viz/VizBuilder.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#include -#include -#include -#include - -#include - -using namespace lagrange::ui; - -struct VizBuilder { - const std::array attrib_types = {Viz::Attribute::VERTEX, - Viz::Attribute::EDGE, - Viz::Attribute::FACET, - Viz::Attribute::CORNER}; - - const std::array primitive_types = {Viz::Primitive::POINTS, - Viz::Primitive::LINES, - Viz::Primitive::TRIANGLES}; - - const std::array shading_types = {Viz::Shading::FLAT, - Viz::Shading::PHONG, - Viz::Shading::PBR}; - - const std::array colormapping_types = {Viz::Colormapping::UNIFORM, - Viz::Colormapping::TEXTURE, - Viz::Colormapping::CUSTOM, - Viz::Colormapping::CUSTOM_INDEX_OBJECT}; - - const std::array filter_types = {Viz::Filter::SHOW_ALL, - Viz::Filter::SHOW_SELECTED, - Viz::Filter::HIDE_SELECTED}; - - - bool indexed_colormap = true; - const char* indexed_colormap_fn_names[3] = { - "Turbo periodic index", - "Grayscale periodic index", - "RGB position", - }; - int indexed_colormap_fn_index = 0; - - const char* value_colormap_fn_names[3] = { - "Norm of value to Turbo", - "Attribute to RGBA", - "Invert color" - }; - int value_colormap_fn_index = 0; - - - const char* attribute_names[4] = {"dijkstra_distance", - "random_vertex_attribute", - "geodesic_distance", - "polar_angle" - }; - int attribute_name_index = 0; - - Viz cfg; - - VizBuilder(); - - template - void combo_box(const char* name, const std::array& types, T& value) - { - if (ImGui::BeginCombo(name, Viz::to_string(value).c_str())) { - for (size_t i = 0; i < types.size(); i++) { - bool selected = types[i] == value; - if (ImGui::Selectable(Viz::to_string(types[i]).c_str(), selected)) { - value = types[i]; - } - if (selected) { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - } - - void operator()(Viewer& v); - - void assign_custom_func(); -}; diff --git a/modules/ui/examples/ui_viz/initialize_attributes.h b/modules/ui/examples/ui_viz/initialize_attributes.h deleted file mode 100644 index 7a9739fe..00000000 --- a/modules/ui/examples/ui_viz/initialize_attributes.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#include -#include -#include - - -using namespace lagrange::ui; - -template -void normalize_matrix(Matrix& m) -{ - auto min_val = m.colwise().minCoeff().eval(); - auto max_val = m.colwise().maxCoeff().eval(); - auto mult = (max_val - min_val).cwiseInverse().eval(); - for (auto i = 0; i < m.rows(); i++) { - m.row(i) = (m.row(i) - min_val).cwiseProduct(mult); - } -} - - -struct initialize_attributes_visitor { - template - void operator()(MeshModelType& mesh_model) - { - auto mesh_ptr = mesh_model.export_mesh(); - auto& mesh = *mesh_ptr; - using MeshType = std::remove_reference_t; - using AttributeArray = typename MeshType::AttributeArray; - - if (!mesh.is_edge_data_initialized()) { - try { - mesh.initialize_edge_data(); - } - catch (std::exception& ex) { - lagrange::logger().info( - "Failed to initialize edge data, some edge vizualizations may not work: {}", - ex.what()); - } - } - - // Create random random_vertex_attribute - if (!mesh.has_vertex_attribute("random_vertex_attribute")) - mesh.add_vertex_attribute("random_vertex_attribute"); - AttributeArray random_vertex_attribute = AttributeArray::Random(mesh.get_num_vertices(), 3); - mesh.import_vertex_attribute("random_vertex_attribute", random_vertex_attribute); - - try { - // Initializes "dijkstra_distance" vertex_attribute - lagrange::compute_dijkstra_distance( - mesh, 0, Eigen::Matrix(1, 1, 1)); - - // Normalize the values - AttributeArray d; - mesh.export_vertex_attribute("dijkstra_distance", d); - normalize_matrix(d); - mesh.import_vertex_attribute("dijkstra_distance", d); - } - catch (std::exception& ex) { - lagrange::logger().info("Failed to initialize dijkstra distance: {}", ex.what()); - } - - mesh_model.import_mesh(mesh_ptr); - } -}; diff --git a/modules/ui/examples/ui_viz/main.cpp b/modules/ui/examples/ui_viz/main.cpp deleted file mode 100644 index c5c62481..00000000 --- a/modules/ui/examples/ui_viz/main.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#include -#include -#include - -#include -#include "VizBuilder.h" -#include "initialize_attributes.h" - - -using namespace lagrange::ui; - - -int main() -{ - Viewer::WindowOptions wopt; - wopt.width = 1920; - wopt.height = 1080; - wopt.window_title = "Example Viz"; - - Viewer viewer(wopt); - - if (!viewer.is_initialized()) return 1; - Scene& scene = viewer.get_scene(); - - scene.add_callback([](Model& model) { - model.visit_tuple(initialize_attributes_visitor()); - model.visit_tuple([](auto&) { - lagrange::logger().error( - "This demo works only for triangle meshes. This mesh has quads"); - }); - - model.add_callback([](Model& model2) { - model2.visit_tuple(initialize_attributes_visitor()); - model2.visit_tuple([](auto&) { - lagrange::logger().error( - "This demo works only for triangle meshes. This mesh has quads"); - }); - }); - }); - - - auto lagrange_mesh = lagrange::to_shared_ptr(lagrange::create_sphere(4)); - - scene.add_model(ModelFactory::make(lagrange_mesh)); - - - /* - Rendering is performed through a series of render passes - Render passes can be added to the Renderer - - Rendering is performed for every Viewport. - Each Viewport can enable/disable different render passes. - */ - - - /* - The Viz can help build render passes with simplified API - 1) use existing functions such as Viz::uniform_color or Viz::indexed_colormapping - 2) Create your own Viz::Config and pass it to viewer.add_viz(); - */ - - Renderer& renderer = viewer.get_renderer(); - - - /* - Will render mesh points in a uniform color - */ - auto uniform = viewer.add_viz( - Viz::create_uniform_color("Uniform Color example", Viz::Primitive::POINTS, Color::white()), false); - uniform->add_tag("custom"); - - - /* - Use indexed colormapping to assign colors using ATTRIBUTE indices. - ATTRIBUTE is either VERTEX, EDGE, FACET or CORNER (mirroring lagrange::Mesh attributes) - PRIMITIVE is the final rendered primitive - */ - auto indexed = viewer.add_viz( - Viz::create_indexed_colormapping("Indexed Colormapping example", - Viz::Attribute::VERTEX, - Viz::Primitive::TRIANGLES, - [](const Model& model, int index) { - Color color; - /* - The model can have a lagrange mesh or arbitrary type, - to access it, either use model.get_mesh if you know the type - or use the following visitor function - */ - model.visit_mesh([&](const auto& mesh) { - auto pos = mesh.get_vertices().row(index).transpose().eval(); - auto bounds = model.get_bounds(); - - color = Color(bounds.normalize_point(pos), 1); - }); - - return color; - }), - false); - indexed->add_tag("custom"); - - /* - Use attribute colormapping to assign colors based on ATTRIBUTE value - In this case, it will try to get mesh->get_vertex_attribute("random_vertex_attribute") and - call the given AttribColorFunc for every row. - Viz::AttribValue is a dynamic row vector - */ - auto attribute = viewer.add_viz(Viz::create_attribute_colormapping("Attribute Colormapping example", - Viz::Attribute::VERTEX, - "random_vertex_attribute", - Viz::Primitive::LINES, - [](const Model&, const Viz::AttribValue& value) { - return Color(float(value.x()), float(value.y()), float(value.z()), 1.0f); - }), - false); - attribute->add_tag("custom"); - - - VizBuilder viz_builder; - - while (!viewer.should_close()) { - viewer.begin_frame(); - - auto& viewport = viewer.get_focused_viewport_ui().get_viewport(); - - ImGui::SetNextWindowSize(ImVec2(400, 0), ImGuiCond_Once); - ImGui::Begin("Viz example"); - - ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Custom Render Passes")) { - // List all passes - auto& passes = renderer.get_pipeline().get_passes(); - for (auto& pass : passes) { - if (pass->has_tag("default")) continue; // Skip system default passes - - ImGui::PushID(pass.get()); - bool enabled = viewport.is_render_pass_enabled(pass.get()); - if (ImGui::Checkbox(pass->get_name().c_str(), &enabled)) { - viewport.enable_render_pass(pass.get(), enabled); - } - - - ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::GetFontSize() * 5); - if (ImGui::Button(ICON_FA_TRASH_ALT)) { - renderer.get_pipeline().remove(pass.get()); - ImGui::PopID(); - break; - } - ImGui::PopID(); - } - - if (ImGui::Button( - "Toggle Custom Passes", ImVec2(ImGui::GetContentRegionAvail().x / 2.f, 40.f))) { - viewport.enable_render_pass_tag( - "custom", !viewport.is_render_pass_enabled_tag("custom")); - } - ImGui::SameLine(); - if (ImGui::Button( - "Toggle Default PBR", ImVec2(ImGui::GetContentRegionAvail().x, 40.f))) { - viewport.enable_render_pass_tag("pbr", !viewport.is_render_pass_enabled_tag("pbr")); - } - - ImGui::TreePop(); - } - - - ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Create your own")) { - viz_builder(viewer); - ImGui::TreePop(); - } - - - ImGui::End(); - - - viewer.end_frame(); - } - - return 0; -} diff --git a/modules/ui/include/lagrange/ui/BaseResourceData.h b/modules/ui/include/lagrange/ui/BaseResourceData.h deleted file mode 100644 index ae39626f..00000000 --- a/modules/ui/include/lagrange/ui/BaseResourceData.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include - -namespace lagrange { - -namespace ui { - -class BaseResourceData -{ -public: - BaseResourceData() = default; - virtual ~BaseResourceData() = default; - - template - BaseResourceData(Params params) - : m_params(std::move(params)) - {} - - /// Sets the dirty flag to value - void set_dirty(bool value) { m_dirty = value; } - - bool is_dirty() const { return m_dirty; } - - /// Adds resource as a dependency of this data - void add_dependency(const std::shared_ptr& resource_data) - { - m_dependencies.push_back(resource_data); - } - - const std::vector>& dependencies() const - { - return m_dependencies; - } - - void clear_dependencies() { m_dependencies.clear(); } - - void clear_params() { m_params.reset(); } - - virtual void realize() = 0; - - virtual void reload() - { - // Free old value - reset(); - - // Realize new value with saved arguments - // This will also setup dependencies again - realize(); - - set_dirty(true); - } - - virtual void reset() = 0; - - const std::any& params() const { return m_params; } - std::any& params() { return m_params; } - -protected: - /// Optional parameters for lazy initialization - std::any m_params; - - /// Dirty flag used to detect changes - bool m_dirty = false; - - /// List of resources that depend on this resource data - std::vector> m_dependencies; -}; - -} // namespace ui -} // namespace lagrange \ No newline at end of file diff --git a/modules/ui/include/lagrange/ui/Callbacks.h b/modules/ui/include/lagrange/ui/Callbacks.h deleted file mode 100644 index e791cc1a..00000000 --- a/modules/ui/include/lagrange/ui/Callbacks.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include - -namespace lagrange { -namespace ui { - -/* - Callback function wrapper with counter. - Counter is used so that callbacks of same - signature are treated as different types. -*/ -template -struct Callback { - using ArgType = T; - using FunType = std::function; - - std::function m_fun; -}; - - -#define UI_CALLBACK(T) Callback - -/* - Container of callbacks specified by Args -*/ -template -class Callbacks { - template - struct CallbacksTuple { - std::tuple callbacks; - }; - -public: - template - const CallbackType& add(const CallbackType& callback) - { - using CallbackTypeNoRef = std::decay_t; - auto& arr = std::get>(m_base.callbacks); - arr.emplace_back(callback); - return arr.back(); - } - - template - void add(CallbackType&& callback) - { - using CallbackTypeNoRef = std::decay_t; - std::get>(m_base.callbacks) - .emplace_back(std::move(callback)); - } - - template - void clear() - { - using CallbackTypeNoRef = std::decay_t; - std::get>(m_base.callbacks).clear(); - } - - template - bool erase(size_t index) - { - using CallbackTypeNoRef = std::decay_t; - auto& vec = std::get>(m_base.callbacks); - if (index >= vec.size()) return false; - vec.erase(vec.begin() + index); - return true; - } - template - size_t size() - { - using CallbackTypeNoRef = std::decay_t; - return std::get>(m_base.callbacks).size(); - } - - - template - void call(CallbackArgs&&... args) const - { - if (!m_enabled) return; - using CallbackTypeNoRef = std::decay_t; - for (auto& callback : std::get>(m_base.callbacks)) { - callback.m_fun(args...); - } - } - - template - bool has_callback() - { - using CallbackTypeNoRef = std::decay_t; - return std::get>(m_base.callbacks).size() > 0; - } - - - void set_enabled(bool enabled) { m_enabled = enabled; } - - bool is_enabled() const { return m_enabled; } - -private: - CallbacksTuple>...> m_base; - bool m_enabled = true; -}; - -/* - * Defines the boilerplate implementations for the `derived()` methods normally - * included in a CRTP base class. - * - * NOTE: This class is a direct copy from optimtools. Maybe in the future we - * will want to include it as dependency - * see e.g., - * https://git.corp.adobe.com/kwampler/optimtools/blob/4a1390515d9880a4de14b8b8feca9d2c31f4fe3f/source/optimtools/general_utils.h#L17 - */ -template -class CRTPBase { -public: - inline const Derived& derived() const& { return static_cast(*this); } - inline Derived& derived() & { return static_cast(*this); } - inline Derived&& derived() && { return std::move(static_cast(*this)); } -}; - -/* - * Base class that uses CRTP to reduce code duplication in the derived classes - * - * CRTP ref: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern - */ -template -class CallbacksBase : public CRTPBase { -public: - template - void add_callback(typename CallbackType::FunType&& fun) - { - this->derived().m_callbacks.template add(CallbackType{fun}); - } - template - void clear_callback() - { - this->derived().m_callbacks.template clear(); - } - template - bool has_callback() - { - return this->derived().m_callbacks.template has_callback(); - } - void set_enabled(const bool enabled) { this->derived().m_callbacks.set_enabled(enabled); } -}; -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/CameraUI.h b/modules/ui/include/lagrange/ui/CameraUI.h deleted file mode 100644 index abcf284d..00000000 --- a/modules/ui/include/lagrange/ui/CameraUI.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace lagrange { -namespace ui { - -class Camera; - -/* - Displays a window showing camera properties -*/ -class CameraUI : public UIPanel, public CallbacksBase { - -public: - CameraUI(Viewer* viewer, std::shared_ptr camera) - : UIPanel(viewer, std::move(camera)) - {} - - const char* get_title() const override { return "Camera"; } - - void draw() final; - void update(double dt) final; - -private: - - struct { - bool enabled = false; - float t = 1.0f; - float speed = 1.0f / 4.0f; - Eigen::Vector3f start_pos; - Eigen::Vector3f axis = Eigen::Vector3f(0,1,0); - } m_turntable; - - struct { - bool rotate_active = false; - float rotate_speed = 4.0f; - float zoom_speed = 0.15f; - } m_control; - -friend CallbacksBase; -}; - -} -} diff --git a/modules/ui/include/lagrange/ui/DetailUI.h b/modules/ui/include/lagrange/ui/DetailUI.h deleted file mode 100644 index 11fa39d3..00000000 --- a/modules/ui/include/lagrange/ui/DetailUI.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include -#include -#include - - -#include -#include -#include -#include - -namespace lagrange { -namespace ui { - -class Model; -class Material; -class Emitter; - -/* - UI Panel for Scene -*/ -class DetailUI : public UIPanelBase { - -public: - DetailUI(Viewer* viewer) - : UIPanelBase(viewer) - {} - - const char* get_title() const override { return "Detail"; }; - - void draw() final; - -private: - - void draw(Model& model); - void draw(Material& material, int index = -1); - void draw(Emitter& emitter); - - struct Pagination { - int current_page = 0; - int per_page = 25; - }; - - std::unordered_map m_paginated_matrices; - -}; - -} -} diff --git a/modules/ui/include/lagrange/ui/Emitter.h b/modules/ui/include/lagrange/ui/Emitter.h deleted file mode 100644 index d0089558..00000000 --- a/modules/ui/include/lagrange/ui/Emitter.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include - -namespace lagrange { -namespace ui { - -class Emitter : public BaseObject, public CallbacksBase { - - -public: - - Emitter(Eigen::Vector3f intensity = Eigen::Vector3f::Constant(1.0f)); - - using OnChange = UI_CALLBACK(void(Emitter&)); - using OnDestroy = UI_CALLBACK(void(Emitter&)); - - enum class Type { - POINT = 0, - DIRECTIONAL, - SPOT, - IBL - }; - - virtual Type get_type() const = 0; - - bool is_enabled() const; - void set_enabled (bool val); - - void set_intensity(const Eigen::Vector3f& intensity); - - Eigen::Vector3f get_intensity() const; - - virtual ~Emitter(); - - -private: - bool m_enabled; - -protected: - Callbacks m_callbacks; - Eigen::Vector3f m_intensity; - -friend CallbacksBase; -}; - -} -} diff --git a/modules/ui/include/lagrange/ui/Entity.h b/modules/ui/include/lagrange/ui/Entity.h new file mode 100644 index 00000000..d2a54269 --- /dev/null +++ b/modules/ui/include/lagrange/ui/Entity.h @@ -0,0 +1,120 @@ +#pragma once + +#include +#include +#include + + +namespace lagrange { +namespace ui { + +using Registry = entt::registry; +using Entity = entt::entity; +inline constexpr entt::null_t NullEntity{}; + +using System = std::function; +using StringID = entt::id_type; + +/* + Globally used enums +*/ +enum class IndexingMode { VERTEX, EDGE, FACE, CORNER, INDEXED }; +enum class PrimitiveType { POINTS, LINES, TRIANGLES }; +enum class SelectionBehavior { SET, ADD, ERASE }; + +using namespace entt::literals; + +inline StringID string_id(const std::string& str) +{ + return entt::hashed_string(str.c_str()); +} +inline StringID string_id(const char* str) +{ + return entt::hashed_string(str); +} + +template +void component_clone(Registry* w, Entity src, Entity dst) +{ + w->emplace_or_replace(dst, w->get(src)); +} + +template +void component_move(Registry* w, Entity src, Entity dst) +{ + w->emplace_or_replace(dst, std::move(w->get(src))); + w->remove(src); +} + +template +void component_add_default(Registry* w, Entity dst) +{ + w->emplace_or_replace(dst); +} + +/// Payload for sending entities through UI +struct PayloadEntity +{ + static const char* id() { return "PayloadEntity"; } + Entity entity; +}; + + +/// Payload for sending components through UI +struct PayloadComponent +{ + static const char* id() { return "PayloadComponent"; } + entt::id_type component_hash; + Entity entity; +}; + + +template +void register_component(const std::string& display_name = entt::type_id().name().data()) +{ + using namespace entt::literals; + entt::meta().type(); + entt::meta().template func<&component_clone>("component_clone"_hs); + entt::meta().template func<&component_move>("component_move"_hs); + entt::meta().template func<&component_add_default>( + "component_add_default"_hs); + entt::meta().prop("display_name"_hs, display_name); +} + +template +void register_component_widget() +{ + using namespace entt::literals; + entt::meta().template func("show_widget"_hs); +} + +template +void register_component_widget(const std::function& fn) +{ + using namespace entt::literals; + entt::meta().prop("show_widget_lambda"_hs, fn); +} + +inline void show_widget(Registry& w, Entity e, const entt::meta_type& meta_type) +{ + using namespace entt::literals; + auto fn = meta_type.func("show_widget"_hs); + if (fn) { + fn.invoke({}, &w, e); + } else { + auto lambda = meta_type.prop("show_widget_lambda"_hs); + if (lambda) { + lambda.value().cast>()(&w, e); + } + } +} + +template +void show_widget(Registry& r, Entity e, const Resolvable& resolvable) +{ + show_widget(r, e, entt::resolve(resolvable)); +} + + +} // namespace ui +} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/FunctionUtils.h b/modules/ui/include/lagrange/ui/FunctionUtils.h deleted file mode 100644 index bce645f8..00000000 --- a/modules/ui/include/lagrange/ui/FunctionUtils.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once -#include - - -namespace lagrange { -namespace ui { -namespace util { - -template -struct AsFunction - : public AsFunction -{}; - -template -struct AsFunction -{ - using arg_type = Arg; -}; - -template -struct AsFunction -{ - using arg_type = Arg; -}; - -template -struct AsFunction -{ - using arg_type = Arg; -}; - -} -} -} diff --git a/modules/ui/include/lagrange/ui/IBL.h b/modules/ui/include/lagrange/ui/IBL.h deleted file mode 100644 index 93464809..00000000 --- a/modules/ui/include/lagrange/ui/IBL.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include - -#include -#include -#include - -#include - -namespace lagrange { -namespace ui { - -class IBL : public Emitter{ - -public: - - Emitter::Type get_type() const; - - /* - Supports .ibl files - */ - IBL(const fs::path& file_path); - - IBL(const std::string & name, Resource bg_texture); - - Texture& get_background() { return *m_background; } - Texture& get_diffuse() { return *m_diffuse; } - Texture& get_specular() { return *m_specular; } - - const Texture& get_background() const { return *m_background; } - const Texture& get_diffuse() const { return *m_diffuse; } - const Texture& get_specular() const { return *m_specular; } - - Texture& get_background_rect() { return *m_background_rect; } - const Texture& get_background_rect() const { return *m_background_rect; } - - bool save_to(const fs::path& file_path); - - const std::string& get_name() const { return m_name; } - -private: - - void generate_textures(const Texture& input_tex); - - Resource get_bg_texture_ibl_file( - const fs::path& ibl_file_path - ); - - Resource m_background_rect; - Resource m_background; - Resource m_diffuse; - Resource m_specular; - std::string m_name; - fs::path m_file_path; -}; - -} -} diff --git a/modules/ui/include/lagrange/ui/Light.h b/modules/ui/include/lagrange/ui/Light.h deleted file mode 100644 index 838850bc..00000000 --- a/modules/ui/include/lagrange/ui/Light.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include - - -namespace lagrange { -namespace ui { - - -class PointLight : public Emitter -{ -public: - Emitter::Type get_type() const override; - - PointLight(Eigen::Vector3f pos, Eigen::Vector3f intensity); - - Eigen::Vector3f get_position() const; - void set_position(Eigen::Vector3f value); - - void set_attenuation(float value) { m_attenuation = value; } - float get_attenuation() const { return m_attenuation; } - -private: - Eigen::Vector3f m_position; - float m_attenuation; -}; - - -class DirectionalLight : public Emitter -{ -public: - Emitter::Type get_type() const override; - - DirectionalLight(Eigen::Vector3f direction, Eigen::Vector3f intensity); - - Eigen::Vector3f get_direction() const; - void set_direction(Eigen::Vector3f value); - - std::pair get_perpendicular_plane() const; - -private: - Eigen::Vector3f m_direction; -}; - - -class SpotLight : public Emitter -{ -public: - Emitter::Type get_type() const override; - - SpotLight(Eigen::Vector3f pos, Eigen::Vector3f direction, Eigen::Vector3f intensity); - - Eigen::Vector3f get_position() const; - void set_position(Eigen::Vector3f value); - - Eigen::Vector3f get_direction() const; - void set_direction(Eigen::Vector3f value); - - void set_attenuation(float value); - float get_attenuation() const; - - void set_cone_angle(float value); - - float get_cone_angle() const; - - std::pair get_perpendicular_plane() const; - - -private: - Eigen::Vector3f m_position; - Eigen::Vector3f m_direction; - float m_attenuation; - // In radians - float m_cone_angle; -}; - - -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/Material.h b/modules/ui/include/lagrange/ui/Material.h deleted file mode 100644 index 1142d151..00000000 --- a/modules/ui/include/lagrange/ui/Material.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace lagrange { -namespace ui { - -class Texture; - -/* - Currently supports only - MATERIAL_ADOBE_STANDARD - Individual material maps: - "baseColor" - "normal" (must be texture) - "opacity" - "roughness" - "metallic" - "glow" (unused) - "translucence" (unused) - "indexOfRefraction" (unused) - "density" (unused) - "interiorColor" (unused) - "height" (unused) - "heightScale" (unused) - Set value by - material["baseColor"].value = Color(1,0,0,1); //red - material["opacity"].value = Color(0.75f,0,0,0); // 75% opacity - Set texture by - material["normal"].texture = std::make_shared("normal_texture.jpg"); - -*/ - -class Material : public BaseObject { -public: - enum Type { MATERIAL_ADOBE_STANDARD, MATERIAL_PHONG, MATERIAL_CUSTOM }; - - // Creates empty custom material - Material(); - - static Material create_default(Type type = Type::MATERIAL_ADOBE_STANDARD); - static std::shared_ptr create_default_shared( - Type type = Type::MATERIAL_ADOBE_STANDARD); - - struct Map { - Resource texture; - Color value; // Used if there is no texture - }; - - const Map& operator[](const std::string& name) const; - - Map& operator[](const std::string& name); - - bool has_map(const std::string& name) const; - - bool is_valid() const; - - bool convert_to(Type new_type); - - Type get_type() const { return m_type; } - - void set_name(const std::string& name) { m_name = name; } - std::string get_name() const { return m_name; } - - ~Material(); - - std::unordered_map& get_maps() { return m_maps; } - -private: - Type m_type; - std::unordered_map m_maps; - std::string m_name; -}; - -using MaterialLibrary = std::unordered_map>; - -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/MeshBuffer.h b/modules/ui/include/lagrange/ui/MeshBuffer.h deleted file mode 100644 index d207695d..00000000 --- a/modules/ui/include/lagrange/ui/MeshBuffer.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once -#include -#include -#include - -#include -#include -#include - -namespace lagrange { -namespace ui { - - -struct VertexBufferWrapper; - -/* - Manages GPU Vertex Buffer Objects for a single mesh. - Can optionally contain additional SubBufferType buffers identified by SubBufferID, i.e. - have different version identified by SubBufferID (e.g. different color buffers for - different visualizations) -*/ -class MeshBuffer { -public: - - enum class SubBufferType : uint8_t { - POSITION = 0, - NORMAL = 1, - UV = 2, - COLOR = 3, - TANGENT = 4, - BITANGENT = 5, - _COUNT = 6, - INDICES = 255 - }; - - /* - OpenGL primitive that gets rendered - */ - enum class Primitive { POINTS, LINES, TRIANGLES }; - - - using SubBufferID = std::string; - static SubBufferID default_sub_id(); - - static SubBufferID vertex_index_id() { return "__default::vertices"; } - static SubBufferID edge_index_id() { return "__default::edges"; } - static SubBufferID facet_index_id() { return default_sub_id(); } - static SubBufferID corner_index_id() { return default_sub_id(); } - static SubBufferID material_index_id(int material_id) - { - return lagrange::string_format("material_indices_{}", material_id); - } - - - MeshBuffer(bool homogeneous = false); - ~MeshBuffer(); - - // Creates on demand if does not exist - VertexBuffer& get_sub_buffer(SubBufferType subbuffer_type, - const SubBufferID& id = MeshBuffer::default_sub_id()); - - // Tries to get sub buffer with id, if that fails, it tries to get default one - VertexBuffer* try_get_sub_buffer(SubBufferType subbuffer_type, - const SubBufferID& id = MeshBuffer::default_sub_id()); - - using SubBufferSelection = std::unordered_map; - - bool render(Primitive primitive, - const SubBufferSelection & selection = {}); - - size_t get_attribute_num() const; - - /* - [-1,1]^2 Quad - */ - static MeshBuffer& quad(); - - /* - Single point at [0,0,0] - */ - static MeshBuffer& point(); - - /* - Returns an infinite plane mesh (w=0 for corners, w=1 for center) - */ - static MeshBuffer& infinite_plane(); - - /* - [-1,1]^3 Cube - */ - static MeshBuffer& cube(bool edges = false); - - //Explicit destructor for static data - //Must be called before OpenGL shutdown - static void clear_static_data() { - m_quad = nullptr; - m_cube_triangles = nullptr; - m_cube_edges = nullptr; - m_point = nullptr; - } -private: - /* - Try to find index buffer whose id != default_sub_id() - E.g. for selection - */ - VertexBuffer* non_default_index_buffer(const std::string& sub_id) const; - using key_t = std::pair; - - std::unordered_map, utils::pair_hash> m_sub_buffers; - VAO m_vao; - bool m_homogeneous; - - static std::unique_ptr m_quad; - static std::unique_ptr m_cube_triangles; - static std::unique_ptr m_cube_edges; - static std::unique_ptr m_point; - static std::unique_ptr m_infinite_plane; -}; - - - -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/MeshBufferFactory.h b/modules/ui/include/lagrange/ui/MeshBufferFactory.h deleted file mode 100644 index e87793a1..00000000 --- a/modules/ui/include/lagrange/ui/MeshBufferFactory.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include - -namespace lagrange { -namespace ui { - -// Creates MeshBuffer from Model -class MeshBufferFactory -{ -public: - - /// Uploads vertex attribute - /// data is an attribute matrix indexed per the original mesh - template - static bool upload_vertex_attribute( - VertexBuffer& target_buffer, const MatrixType& data, const ProxyMesh& pm) - { - target_buffer.upload(pm.flatten_vertex_attribute(data)); - return true; - } - - /// Uploads facet attribute - /// data is an attribute matrix indexed per the original mesh - template - static bool upload_facet_attribute( - VertexBuffer& target_buffer, const MatrixType& data, const ProxyMesh& pm) - { - target_buffer.upload(pm.flatten_facet_attribute(data)); - return true; - } - - /// Uploads edge attribute - /// data is an attribute matrix indexed per the original mesh - template - static bool upload_edge_attribute( - VertexBuffer& target_buffer, const MatrixType& data, const ProxyMesh& pm) - { - target_buffer.upload(pm.flatten_edge_attribute(data)); - return true; - } - - /// Uploads corner attribute - /// data is an attribute matrix indexed per the original mesh - template - static bool upload_corner_attribute( - VertexBuffer& target_buffer, const MatrixType& data, const ProxyMesh& pm) - { - target_buffer.upload(pm.flatten_corner_attribute(data)); - return true; - } - - static bool update_selection_indices(const ProxyMesh& proxy, - const ElementSelection& selection, - bool persistent, - MeshBuffer& target_buffer); -}; - -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/MeshModel.h b/modules/ui/include/lagrange/ui/MeshModel.h deleted file mode 100644 index 51d89544..00000000 --- a/modules/ui/include/lagrange/ui/MeshModel.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once -#include -#include -#include - -#include -#include -#include -#include - -namespace lagrange { -namespace ui { - -namespace util { - -/// Transforms a single vertex using Affine3f transform -/// If VertexType is 2D, the z coordinate is padded with 0 -template -VertexType transform_vertex(const VertexType& v, const Eigen::Affine3f& T) -{ - Eigen::Vector4f v_ = Eigen::Vector4f::Zero(); - for (auto i = 0; i < v.cols(); i++) v_(i) = float(v(i)); - v_(3) = 1.0f; - - const auto vt = (T * v_).head<3>(); - VertexType v_new; - for (auto i = 0; i < v.cols(); i++) v_new(i) = vt(i); - return v_new; -} - -} // namespace util - -template -class MeshModel : public MeshModelBase -{ -public: - using MeshType = _MeshType; - - MeshModel(std::unique_ptr&& mesh, const std::string& name = "Unnamed") - : MeshModel(lagrange::to_shared_ptr(std::move(mesh)), name) - {} - - MeshModel( - Resource mesh, - const std::string& name = "Unnamed", - Resource proxy = {}) - : MeshModelBase(name) - { - m_mesh = mesh; - if (proxy) { - set_proxy(proxy); - } else { - update_proxy_mesh(); - } - } - - // TODO constructor taking resource instead - MeshModel(std::shared_ptr mesh, const std::string& name = "Unnamed") - : MeshModelBase(name) - { - m_mesh = Resource::create(std::move(mesh)); - update_proxy_mesh(); - } - - const MeshType& get_mesh() const - { - return m_mesh.cast(); - } - - bool has_mesh() const override { return m_mesh; } - - std::shared_ptr export_mesh() - { - return std::static_pointer_cast(m_mesh.data()->data()); - } - - - void import_mesh(std::shared_ptr mesh) - { - m_mesh = Resource::create(std::move(mesh)); - trigger_change(); - } - - bool transform_selection(const Eigen::Affine3f& T) override - { - using VertexArray = typename MeshType::VertexArray; - using VertexType = typename MeshType::VertexType; - using Index = typename MeshType::Index; - - if (!has_mesh()) return false; - - if (get_selection().get_type() == SelectionElementType::EDGE && - !get_mesh().is_edge_data_initialized()) { - lagrange::logger().warn("Cannot transform, edge data is not initalized."); - return false; - } - - auto mesh = export_mesh(); - VertexArray V; - mesh->export_vertices(V); - - auto& sel = get_selection().get_persistent().get_selection(); - if (get_selection().get_type() == SelectionElementType::VERTEX) { - for (auto i : sel) { - V.row(i) = util::transform_vertex(V.row(i), T); - } - } else if ( - get_selection().get_type() == SelectionElementType::EDGE && - mesh->is_edge_data_initialized()) { - std::unordered_set unique_vertex_indices; - - auto& E = mesh->get_edges(); - for (auto i : sel) { - auto& e = E[i]; - unique_vertex_indices.insert(e.v1()); - unique_vertex_indices.insert(e.v2()); - } - for (auto i : unique_vertex_indices) { - V.row(i) = util::transform_vertex(V.row(i), T); - } - } else if (get_selection().get_type() == SelectionElementType::FACE) { - std::unordered_set unique_vertex_indices; - auto& F = mesh->get_facets(); - for (auto i : sel) { - for (auto k = 0; k < F.cols(); k++) { - unique_vertex_indices.insert(F(i, k)); - } - } - for (auto i : unique_vertex_indices) { - V.row(i) = util::transform_vertex(V.row(i), T); - } - } - - mesh->import_vertices(V); - import_mesh(mesh); - - return true; - } - - DataGUID get_data_guid() const override { return DataGUID(m_mesh.get()); }; - - void trigger_change() override - { - update_proxy_mesh(); - Model::trigger_change(); - } - -protected: - bool update_proxy_mesh() - { - bool picking_enabled = true; - if (m_proxy.data()->get() != nullptr) { - picking_enabled = m_proxy->is_picking_enabled(); - } - set_proxy(Resource::create_deferred(m_mesh, (MeshType*)(nullptr))); - - if (!picking_enabled) { - m_proxy->set_picking_enabled(false); - } - return true; - } - -private: - - Resource m_mesh; -}; - -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/MeshModelBase.h b/modules/ui/include/lagrange/ui/MeshModelBase.h deleted file mode 100644 index 8f53132f..00000000 --- a/modules/ui/include/lagrange/ui/MeshModelBase.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace lagrange { -namespace ui { - - -class MeshModelBase : public Model -{ -public: - MeshModelBase(const std::string& name); - - /// Sets new proxy resource - /// Updates MeshBuffer - void set_proxy(Resource proxy); - - - const ProxyMesh& get_proxy_mesh() const; - - AABB get_bounds() const override; - - /* - World space raycasting - */ - bool get_facet_at( - Eigen::Vector3f origin, - Eigen::Vector3f dir, - int& facet_id_out, - float& t_out, - Eigen::Vector3f& barycentric_out); - std::unordered_set get_facets_in_frustum(const Frustum& f, bool ignore_backfacing) const; - std::unordered_set get_vertices_in_frustum(const Frustum& f, bool ignore_backfacing) const; - std::unordered_set get_edges_in_frustum(const Frustum& f, bool ignore_backfacing) const; - bool intersects(const Frustum& f) override; - bool intersects(const Eigen::Vector3f& ray_origin, const Eigen::Vector3f& ray_dir, float& t_out) - override; - - /* - Screen space raycasting (applies viewport transform) - */ - bool get_facet_at(const Camera& cam, Eigen::Vector2f pixel, int& facet_id_out); - bool - get_vertex_at(const Camera& cam, Eigen::Vector2f pixel, float max_radius, int& vertex_id_out); - bool get_edge_at(const Camera& cam, Eigen::Vector2f pixel, float max_radius, int& edge_id_out); - - std::unordered_set get_facets_in_frustum( - const Camera& cam, - Eigen::Vector2f begin, - Eigen::Vector2f end, - bool ignore_backfacing) const; - std::unordered_set get_vertices_in_frustum( - const Camera& cam, - Eigen::Vector2f begin, - Eigen::Vector2f end, - bool ignore_backfacing) const; - std::unordered_set get_edges_in_frustum( - const Camera& cam, - Eigen::Vector2f begin, - Eigen::Vector2f end, - bool ignore_backfacing) const; - - /* - Mesh can be exported/imported - has_mesh returns false if it's in the exported state - */ - virtual bool has_mesh() const = 0; - - - AABB get_selection_bounds() const override; - virtual bool transform_selection(const Eigen::Affine3f& T) = 0; - - Resource get_buffer() const override { return m_buffer; } - - void set_picking_enabled(bool value) override; - bool is_picking_enabled() const override; - -protected: - - /// Triangle Proxy mesh for rendering, picking and bounds - /// Depends on Resource - Resource m_proxy; - - /// GPU Buffer containing sub buffers (vertices, indices, attributes, etc.) - /// Depends on proxy - Resource m_buffer; - -}; - - -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/Model.h b/modules/ui/include/lagrange/ui/Model.h deleted file mode 100644 index ab30316f..00000000 --- a/modules/ui/include/lagrange/ui/Model.h +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - - -#include -#include -#include -#include -#include -#include - -namespace lagrange { -namespace ui { - -class Renderable; -class Material; - -template -class MeshModel; - -using SupportedMeshTypes = std::tuple>, - MeshModel>, - MeshModel>, - MeshModel>, - MeshModel>, - MeshModel>, - MeshModel>, - MeshModel>, - MeshModel, - Eigen::Matrix>>, - MeshModel, - Eigen::Matrix>>>; - -using SupportedMeshTypes3D = std::tuple>, - MeshModel>, - MeshModel>, - MeshModel>, - MeshModel, - Eigen::Matrix>>, - MeshModel, - Eigen::Matrix>>>; - -using SupportedMeshTypes3DTriangle = std::tuple>, - MeshModel>, - MeshModel, - Eigen::Matrix>>, - MeshModel, - Eigen::Matrix>>>; - -using SupportedMeshTypes3DQuad = - std::tuple>, MeshModel>>; - -using SupportedMeshTypes2D = std::tuple>, - MeshModel>, - MeshModel>, - MeshModel>, - MeshModel, - Eigen::Matrix>>, - MeshModel, - Eigen::Matrix>>>; - -struct DataGUID -{ - explicit DataGUID(void* value) - : ptr(value) - {} - - bool operator<(const DataGUID& r) const { return ptr < r.ptr; } - bool operator==(const DataGUID& r) const { return ptr == r.ptr; } - const void* value() const { return ptr; } - -private: - const void* ptr; -}; - - -class Model : public BaseObject, public CallbacksBase -{ -public: - using OnChange = UI_CALLBACK(void(Model&)); - using OnSelectionChange = UI_CALLBACK(void(Model&, bool persistent, SelectionElementType type)); - using OnDestroy = UI_CALLBACK(void(Model&)); - - Model(const std::string& file_path = ""); - virtual ~Model(); - - /// - /// @brief Get mesh of type MeshType - /// - /// \warning Temporary, will be redesigned - /// - template - MeshType* mesh() - { - auto meshmodel = dynamic_cast*>(this); - - if (meshmodel) { - if (!meshmodel->has_mesh()) return nullptr; - return &meshmodel->get_mesh(); - } - - return nullptr; - } - - /// - /// @brief Get mesh of type MeshType - /// - /// \warning Temporary, will be redesigned - /// - template - const MeshType* mesh() const - { - auto meshmodel = dynamic_cast*>(this); - - if (meshmodel) { - if (!meshmodel->has_mesh()) return nullptr; - return &meshmodel->get_mesh(); - } - return nullptr; - } - - - /// - /// @brief Visit supported mesh types - /// - /// Example: - /// \code - /// model.visit([](auto & mesh){ mesh.get_vertices(); }) - /// \endcode - /// \warning Temporary, will be redesigned - /// - template - void visit_mesh(F&& fn) - { - visit_tuple([&](auto& mesh_model) { - if (mesh_model.has_mesh()) fn(mesh_model.get_mesh()); - }); - } - - /// - /// @brief Visit supported mesh types - /// - /// \code - /// model.visit([](const auto & mesh){ mesh.get_vertices(); }) - /// \endcode - /// \warning Temporary, will be redesigned - /// - template - void visit_mesh(F&& fn) const - { - visit_tuple_const([&](const auto& mesh_model) { - if (mesh_model.has_mesh()) fn(mesh_model.get_mesh()); - }); - } - - /** - * Returns name of the model - */ - const std::string& get_name() const; - - /** - * Sets name of the model - */ - void set_name(const std::string& name); - - /** - * Visibility for rendering & selection - */ - bool is_visible() const; - void set_visible(bool val); - - /** - * Returns affine transform - */ - Eigen::Affine3f get_transform() const; - Eigen::Affine3f get_inverse_transform() const; - - /** - * Sets affine transform - */ - void set_transform(const Eigen::Affine3f& T); - - /** - * Sets affine transform - * Handles non-existence of implicit conversions to Affine3f - */ - template - void set_transform(const EigenTransform& T) - { - Eigen::Affine3f A; - A = T; - set_transform(A); - } - - /** - * Applies affine T transform to existing transform (T_new = T_old * T) - */ - void apply_transform(const Eigen::Affine3f& T); - - /** - * Applies affine T transform to existing transform (T_new = T_old * T) - * Handles non-existence of implicit conversions to Affine3f - */ - template - void apply_transform(const EigenTransform & T){ - Eigen::Affine3f A; - A = T; - apply_transform(A); - } - - /** - * Get axis aligned bounding box of the model - */ - virtual AABB get_bounds() const = 0; - - /** - * Frustum intersection test - */ - virtual bool intersects(const Frustum& f) = 0; - - /** - * Ray intersection test and distance - */ - virtual bool intersects( - const Eigen::Vector3f& ray_origin, const Eigen::Vector3f& ray_dir, float& t_out) = 0; - - /** - * Get/Set a viewport transformation (scale/translation) - * Values can be between 0 and 1 - */ - void set_viewport_transform(const Camera::ViewportTransform& vt); - const Camera::ViewportTransform& get_viewport_transform() const; - - /** - * Returns frustum transformed by model's viewport transform - */ - Frustum get_transformed_frustum( - const Camera& cam, Eigen::Vector2f begin, Eigen::Vector2f end, bool& is_visible) const; - - /* - Returns pixel transformed by model's viewport transform - */ - Eigen::Vector2f get_transformed_pixel(const Camera& cam, Eigen::Vector2f pixel, bool& is_visible) const; - - /** - * Gets current material - * -1 gets default material - */ - Material& get_material(int material_id = -1) const; - - std::unordered_map>& get_materials(); - const std::unordered_map>& get_materials() const; - - bool has_material(int material_id) const; - int num_materials() const; - - /** - * Set material - * Returns false if material_id already exists - */ - bool set_material(std::shared_ptr mat, int material_id); - bool set_material(Resource mat, int material_id); - - /** - * Element (vertex/edge/face) selection - */ - ElementSelection& get_selection(); - const ElementSelection& get_selection() const; - - virtual AABB get_selection_bounds() const = 0; - - /** - * Returns all base objects in the hierarchy below this model - * Currently used to get Model + all its materials - */ - virtual std::vector get_selection_subtree() override; - - - template - bool visit(F f, bool require_type = false) - { - return visit_impl::arg_type>(f, require_type); - } - - template - bool visit(F f, bool require_type = false) const - { - return visit_impl_const::arg_type>( - f, require_type); - } - - template - bool visit_tuple(F f) - { - return visit_tuple_impl::value>()(f, this); - } - - template - bool visit_tuple_const(F f) const - { - return visit_tuple_impl_const::value>()(f, this); - } - - template - bool visit_multiple(F& f, bool require_type = false) - { - return visit_multiple_impl(f, require_type); - } - - template - bool visit_multiple_const(F& f, bool require_type = false) const - { - return visit_multiple_impl_const(f, require_type); - } - - - /* - Returns globally unique identifier of CPU data - If equal with other model's DataGUID, they are instance of the same data - with (possibly) different transforms and materials - */ - virtual DataGUID get_data_guid() const = 0; - - - //TODO: this will be replace by a component - //If not a mesh, return empty resource - virtual Resource get_buffer() const { return Resource(); } - - virtual void set_picking_enabled(bool value) = 0; - virtual bool is_picking_enabled() const { return false; } - - virtual void trigger_change(); - -protected: - template - struct visit_tuple_impl - { - bool operator()(F f, Model* model) - { - using current_type = typename std::tuple_element::type; - return model->visit_multiple(f, false) || - visit_tuple_impl()(f, model); - } - }; - template - struct visit_tuple_impl - { - bool operator()(F LGUI_UNUSED(f), Model* LGUI_UNUSED(model)) { return false; } - }; - - template - struct visit_tuple_impl_const - { - bool operator()(F f, const Model* model) - { - using current_type = typename std::tuple_element::type; - return model->visit_multiple_const(f, false) || - visit_tuple_impl_const()(f, model); - } - }; - template - struct visit_tuple_impl_const - { - bool operator()(F LGUI_UNUSED(f), const Model* LGUI_UNUSED(model)) { return false; } - }; - - template - bool visit_multiple_impl(F f, bool require_type = false) - { - return visit_impl(f, require_type); - } - - template - typename std::enable_if::type visit_multiple_impl( - F f, bool require_type = false) - { - return visit_impl(f, require_type) || - visit_multiple_impl(f, require_type); - } - - template - bool visit_multiple_impl_const(F f, bool require_type = false) const - { - return visit_impl_const(f, require_type); - } - - template - typename std::enable_if::type visit_multiple_impl_const( - F f, bool require_type = false) const - { - return visit_impl_const(f, require_type) || - visit_multiple_impl_const(f, require_type); - } - - template - bool visit_impl(std::function fn, bool require_type) - { - auto* ptr = dynamic_cast::type*>(this); - if (ptr) { - fn(*ptr); - return true; - } - - LA_ASSERT(!require_type, "Wrong type"); - return false; - } - - template - bool visit_impl_const(std::function fn, bool require_type) const - { - auto* ptr = dynamic_cast::type*>(this); - if (ptr) { - fn(*ptr); - return true; - } - - LA_ASSERT(!require_type, "Wrong type"); - return false; - } - - - Callbacks m_callbacks; - - std::unordered_map> m_materials; - - std::string m_name; - bool m_visible; - - Eigen::Affine3f m_transform; - Camera::ViewportTransform m_viewport_transform; - - ElementSelection m_element_selection; - - friend CallbacksBase; -}; - -} // namespace ui -} // namespace lagrange - - -namespace std { -template <> -struct hash -{ - size_t operator()(const lagrange::ui::DataGUID& x) const - { - return hash()(x.value()); - } -}; -} // namespace std diff --git a/modules/ui/include/lagrange/ui/ModelFactory.h b/modules/ui/include/lagrange/ui/ModelFactory.h deleted file mode 100644 index c711ab09..00000000 --- a/modules/ui/include/lagrange/ui/ModelFactory.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - - -namespace lagrange { -namespace ui { - -/* - Static factory for loading/saving/creating models -*/ -class ModelFactory -{ -public: - using OnModelLoad = UI_CALLBACK(void(Model&)); - using OnModelSave = UI_CALLBACK(void(Model&)); - - template - static void add_callback(typename CallbackType::FunType&& fun) - { - m_callbacks.add(CallbackType{fun}); - } - - template - static std::vector>> load_obj( - const fs::path& file_path, bool normalize) - { - io::MeshLoaderParams params; - params.normalize = normalize; - return load_obj(file_path, params); - } - - - static io::MeshLoaderParams default_ui_meshloaderparams() - { - io::MeshLoaderParams p; - p.normalize = true; - return p; - } - - template - static std::vector>> load_obj(const fs::path& file_path, - const io::MeshLoaderParams& params = ModelFactory::default_ui_meshloaderparams()) - { - using V = typename MeshType::VertexArray; - using F = typename MeshType::FacetArray; - auto obj = Resource>::create(file_path.string(), params); - - std::vector>> result; - - for (size_t i = 0; i < obj->meshes.size(); i++) { - - auto mesh = obj->meshes[i]; - const auto& mats = obj->mesh_to_material[i]; - - auto mm = std::make_unique>(mesh, string_format("{}[{}]", file_path.stem(), i)); - - for (auto & mat_and_id : mats) { - mm->set_material(mat_and_id.first.data()->data(), mat_and_id.second); - } - - m_callbacks.call(*mm); - - result.push_back(std::move(mm)); - - } - - return result; - } - - static std::shared_ptr convert_material( - const fs::path& base_dir, const tinyobj::material_t& tinymat); - - template - struct proxy_false : std::false_type - { - }; - - - template - static std::unique_ptr> make(MeshType&& m, - const std::string& name = "Unnamed", - std::shared_ptr material = Material::create_default_shared()) - { - auto model = - std::make_unique>(std::make_shared(std::move(m)), name); - - model->set_material(material, -1); - return model; - } - - template - static std::unique_ptr> make(std::unique_ptr&& m, - const std::string& name = "Unnamed", - std::shared_ptr material = Material::create_default_shared()) - { - auto model = std::make_unique>(to_shared_ptr(std::move(m)), name); - model->set_material(material, -1); - if (material->get_name() == "") material->set_name(name); - return model; - } - - template - static std::unique_ptr> make(const std::unique_ptr& m, - const std::string& name = "Unnamed", - std::shared_ptr material = Material::create_default_shared()) - { - static_assert( - proxy_false::value, "Use std::move or use std::shared_ptr to make model."); - return nullptr; - } - - template - static std::unique_ptr> make(std::unique_ptr& m, - const std::string& name = "Unnamed", - std::shared_ptr material = Material::create_default_shared()) - { - static_assert( - proxy_false::value, "Use std::move or use std::shared_ptr to make model."); - return nullptr; - } - - template - static std::unique_ptr> make(std::shared_ptr m, - const std::string& name = "Unnamed", - std::shared_ptr material = Material::create_default_shared()) - { - auto model = std::make_unique>(std::move(m), name); - model->set_material(material, -1); - if (material->get_name() == "") material->set_name(name); - return model; - } - - [[deprecated("Use Viewer::enable_ground() and Viewer::get_ground() instead for infinite " - "ground plane and grid")]] - static std::unique_ptr> - make_ground_plane(float height = 0.0f, - float extent = 9999.0f, - const std::string& name = "Ground Plane", - std::shared_ptr material = Material::create_default_shared()) - { - Quads F(1, 4); - F << 0, 1, 2, 3; - - Vertices3Df V(4, 3); - V.row(0) << -1.0f, 0, -1.0f; - V.row(1) << -1.0f, 0, 1.0f; - V.row(2) << 1.0f, 0, 1.0f; - V.row(3) << 1.0f, 0, -1.0f; - - Eigen::Matrix UV(4, 2); - - UV.row(0) = Eigen::Vector2f{0, 0}; - UV.row(1) = Eigen::Vector2f{1, 0}; - UV.row(2) = Eigen::Vector2f{1, 1}; - UV.row(3) = Eigen::Vector2f{0, 1}; - - auto lg_mesh = lagrange::create_mesh(std::move(V), std::move(F)); - lg_mesh->initialize_uv(UV, lg_mesh->get_facets()); - - auto model = make(std::move(lg_mesh), name, material); - model->set_selectable(false); - model->set_visualizable(false); - model->set_transform(Eigen::Translation3f(0,height,0) * Eigen::Scaling(extent,1.0f, extent)); - return model; - } - -private: - static Callbacks m_callbacks; -}; - - -} // namespace ui -} // namespace lagrange diff --git a/modules/ui/include/lagrange/ui/Options.h b/modules/ui/include/lagrange/ui/Options.h deleted file mode 100644 index e74d38c5..00000000 --- a/modules/ui/include/lagrange/ui/Options.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2020 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -#pragma once - - -#include -#include -#include -#include -#include -#include -#include - - -#include - -#include -#include -#include - -namespace lagrange { -namespace ui { - -using OptionType = std::variant< - std::string, - char, int, - float, double, - bool, - Color, - Eigen::Vector2f, Eigen::Vector3f, Eigen::Vector4f, - Eigen::Vector2i, Eigen::Vector3i, Eigen::Vector4i, - Eigen::Matrix2f, Eigen::Matrix3f, Eigen::Matrix4f ->; - - -struct OptionDomain { - OptionType min_value; - OptionType max_value; - OptionType delta; -}; - -namespace option_detail { -template -struct defaults { - static T min() { return std::numeric_limits::lowest(); } - static T max() { return (std::numeric_limits::max)(); } - static T delta() { return T(1); } -}; - - -template -struct eigen_defaults -{ - static T min() { return T::Constant(std::numeric_limits::lowest()); } - static T max() { return T::Constant((std::numeric_limits::max)()); } - static T delta() { return T::Ones(); } -}; - -template <> struct defaults -{ - static std::string min() { return ""; } - static std::string max() { return ""; } - static std::string delta() { return ""; } -}; - -template <> struct defaults : public eigen_defaults {}; -template <> struct defaults : public eigen_defaults {}; -template <> struct defaults : public eigen_defaults {}; - -template <> struct defaults : public eigen_defaults {}; -template <> struct defaults : public eigen_defaults {}; -template <> struct defaults : public eigen_defaults {}; - -template <> struct defaults : public eigen_defaults {}; -template <> struct defaults : public eigen_defaults {}; -template <> struct defaults : public eigen_defaults {}; - -template <> struct defaults -{ - static Color min() { return Color(0, 0, 0, 0); } - static Color max() { return Color(1, 1, 1, 1); } - static Color delta() { return Color(0.05f); } -}; -} - -struct Option { - OptionType value; - OptionDomain domain; -}; - -class OptionSet : public CallbacksBase{ - -public: - - using OnChanged = UI_CALLBACK(void(const OptionSet&)); - using OnDestroyed = UI_CALLBACK(void(const OptionSet&)); - - OptionSet& operator[](const std::string& childName); - const OptionSet& operator[](const std::string& childName) const; - - std::shared_ptr get_child_ptr(const std::string& childName); - - ~OptionSet() { - m_callbacks.call(*this); - } - - template - const T& get(const std::string& optionName) const; - - template - void set(const std::string& optionName, T value, bool suppressCallback = false); - - template - bool add( - const std::string& optionName, - T value, - T min_val = option_detail::defaults::min(), - T max_val = option_detail::defaults::max(), - T delta = option_detail::defaults::delta() - ); - - bool add_child(const std::string & child_name, std::shared_ptr child); - - bool erase(const std::string& optionName); - - bool has(const std::string& optionName) const; - - void clear(); - - std::map>& get_options(); - const std::map>& get_options() const; - - std::map>& get_children(); - const std::map>& get_children() const; - - size_t num_children() const; - - size_t num_options() const; - - void trigger_change() { - m_callbacks.call(*this); - } - -private: - std::map> options; - std::map> children; - - Callbacks m_callbacks; - -friend CallbacksBase; -}; - -template -const T& OptionSet::get(const std::string& optionName) const -{ - auto& optPtr = options.at(optionName); - return std::get(optPtr->value); -} - -template -void OptionSet::set(const std::string& optionName, T value, bool suppressCallback) -{ - auto& optPtr = options[optionName]; - if (!optPtr) - optPtr = std::make_shared