Repository: Chaf-Libraries/Ilum
Branch: main
Commit: 1d26a51ac02f
Files: 546
Total size: 5.4 MB
Directory structure:
gitextract_7jr9t7gk/
├── .clang-format
├── .clang-tidy
├── .github/
│ └── workflows/
│ ├── windows_dev.yml
│ └── windows_main.yml
├── .gitignore
├── .gitmodules
├── Asset/
│ ├── BuildIn/
│ │ ├── ImGui.spv.asset
│ │ ├── MaterialBall.asset
│ │ ├── animation.icon.asset
│ │ ├── equirectangular_to_cubemap.shader.asset
│ │ ├── mesh.preview.asset
│ │ ├── pipeline.icon.asset
│ │ ├── prefab.icon.asset
│ │ └── scene.icon.asset
│ ├── Meta/
│ │ └── README.md
│ ├── MustacheTemplate/
│ │ └── Reflection.mustache
│ ├── NRD_Data/
│ │ ├── NRD.rg
│ │ └── Sample/
│ │ ├── Texture2D_89.dds
│ │ ├── blur_buffer.csv
│ │ ├── gIn_Diff.dds
│ │ ├── gIn_Diff_History.dds
│ │ ├── gIn_Normal_Roughness.dds
│ │ ├── gIn_ObjectMotion.dds
│ │ ├── gIn_Prev_AccumSpeeds_MaterialID.dds
│ │ ├── gIn_Prev_Normal_Roughness.dds
│ │ ├── gIn_Prev_ViewZ.dds
│ │ ├── gIn_ViewZ.dds
│ │ ├── history_fix_buffer.csv
│ │ ├── post_blur_buffer.csv
│ │ └── temporal_accumulate_buffer.csv
│ └── SPD/
│ └── metals/
│ ├── Ag.eta.spd
│ ├── Ag.k.spd
│ ├── Al.eta.spd
│ ├── Al.k.spd
│ ├── AlAs.eta.spd
│ ├── AlAs.k.spd
│ ├── AlSb.eta.spd
│ ├── AlSb.k.spd
│ ├── Au.eta.spd
│ ├── Au.k.spd
│ ├── Be.eta.spd
│ ├── Be.k.spd
│ ├── Cr.eta.spd
│ ├── Cr.k.spd
│ ├── CsI.eta.spd
│ ├── CsI.k.spd
│ ├── Cu.eta.spd
│ ├── Cu.k.spd
│ ├── Cu2O.eta.spd
│ ├── Cu2O.k.spd
│ ├── CuO.eta.spd
│ ├── CuO.k.spd
│ ├── Hg.eta.spd
│ ├── Hg.k.spd
│ ├── HgTe.eta.spd
│ ├── HgTe.k.spd
│ ├── Ir.eta.spd
│ ├── Ir.k.spd
│ ├── K.eta.spd
│ ├── K.k.spd
│ ├── KBr.eta.spd
│ ├── KBr.k.spd
│ ├── KCl.eta.spd
│ ├── KCl.k.spd
│ ├── Li.eta.spd
│ ├── Li.k.spd
│ ├── MgO.eta.spd
│ ├── MgO.k.spd
│ ├── Mo.eta.spd
│ ├── Mo.k.spd
│ ├── NaCl.eta.spd
│ ├── NaCl.k.spd
│ ├── Nb.eta.spd
│ ├── Nb.k.spd
│ ├── Rh.eta.spd
│ ├── Rh.k.spd
│ ├── Se-e.eta.spd
│ ├── Se-e.k.spd
│ ├── Se.eta.spd
│ ├── Se.k.spd
│ ├── SiC.eta.spd
│ ├── SiC.k.spd
│ ├── SiO.eta.spd
│ ├── SiO.k.spd
│ ├── SnTe.eta.spd
│ ├── SnTe.k.spd
│ ├── Ta.eta.spd
│ ├── Ta.k.spd
│ ├── Te-e.eta.spd
│ ├── Te-e.k.spd
│ ├── Te.eta.spd
│ ├── Te.k.spd
│ ├── ThF4.eta.spd
│ ├── ThF4.k.spd
│ ├── TiC.eta.spd
│ ├── TiC.k.spd
│ ├── TiN.eta.spd
│ ├── TiN.k.spd
│ ├── TiO2-e.eta.spd
│ ├── TiO2-e.k.spd
│ ├── TiO2.eta.spd
│ ├── TiO2.k.spd
│ ├── VC.eta.spd
│ ├── VC.k.spd
│ ├── VN.eta.spd
│ ├── VN.k.spd
│ ├── W.eta.spd
│ ├── W.k.spd
│ ├── a-C.eta.spd
│ ├── a-C.k.spd
│ ├── a-SiH.eta.spd
│ ├── a-SiH.k.spd
│ ├── d-C.eta.spd
│ └── d-C.k.spd
├── Doc/
│ ├── Material.drawio
│ ├── RHI.drawio
│ ├── RenderGraph.drawio
│ ├── Resource.drawio
│ ├── Scene.drawio
│ └── Shader.drawio
├── LICENSE.txt
├── README.md
├── Source/
│ ├── Editor/
│ │ ├── Editor.cpp
│ │ ├── Editor.hpp
│ │ ├── ImGui/
│ │ │ ├── ImGuiContext.cpp
│ │ │ └── ImGuiContext.hpp
│ │ ├── Precompile.hpp
│ │ └── Widget.hpp
│ ├── Engine/
│ │ ├── Engine.cpp
│ │ ├── Engine.hpp
│ │ ├── Precompile.hpp
│ │ └── main.cpp
│ ├── External/
│ │ ├── dxc/
│ │ │ └── inc/
│ │ │ ├── d3d12shader.h
│ │ │ ├── dxcapi.h
│ │ │ ├── dxcerrors.h
│ │ │ └── dxcisense.h
│ │ ├── imgui_tools/
│ │ │ ├── IconsFontAwesome/
│ │ │ │ └── IconsFontAwesome5.h
│ │ │ ├── imgui_impl_glfw.cpp
│ │ │ ├── imgui_impl_glfw.h
│ │ │ ├── imguizmo/
│ │ │ │ ├── GraphEditor.cpp
│ │ │ │ ├── GraphEditor.h
│ │ │ │ ├── ImCurveEdit.cpp
│ │ │ │ ├── ImCurveEdit.h
│ │ │ │ ├── ImGradient.cpp
│ │ │ │ ├── ImGradient.h
│ │ │ │ ├── ImGuizmo.cpp
│ │ │ │ ├── ImGuizmo.h
│ │ │ │ ├── ImSequencer.cpp
│ │ │ │ ├── ImSequencer.h
│ │ │ │ └── ImZoomSlider.h
│ │ │ ├── imnodes/
│ │ │ │ ├── imnodes.cpp
│ │ │ │ ├── imnodes.h
│ │ │ │ └── imnodes_internal.h
│ │ │ ├── implot/
│ │ │ │ ├── implot.cpp
│ │ │ │ ├── implot.h
│ │ │ │ ├── implot_demo.cpp
│ │ │ │ ├── implot_internal.h
│ │ │ │ └── implot_items.cpp
│ │ │ └── xmake.lua
│ │ ├── mustache/
│ │ │ └── mustache.hpp
│ │ ├── slang/
│ │ │ ├── docs/
│ │ │ │ ├── 64bit-type-support.md
│ │ │ │ ├── README.md
│ │ │ │ ├── api-users-guide.md
│ │ │ │ ├── building.md
│ │ │ │ ├── command-line-slangc.md
│ │ │ │ ├── cpu-target.md
│ │ │ │ ├── cuda-target.md
│ │ │ │ ├── doc-system.md
│ │ │ │ ├── faq.md
│ │ │ │ ├── language-guide.md
│ │ │ │ ├── layout.md
│ │ │ │ ├── linking.md
│ │ │ │ ├── nvapi-support.md
│ │ │ │ ├── repro.md
│ │ │ │ ├── shader-playground.md
│ │ │ │ ├── stdlib-doc.md
│ │ │ │ ├── target-compatibility.md
│ │ │ │ └── wave-intrinsics.md
│ │ │ ├── prelude/
│ │ │ │ ├── slang-cpp-host-prelude.h
│ │ │ │ ├── slang-cpp-prelude.h
│ │ │ │ ├── slang-cpp-scalar-intrinsics.h
│ │ │ │ ├── slang-cpp-types.h
│ │ │ │ ├── slang-cuda-prelude.h
│ │ │ │ ├── slang-hlsl-prelude.h
│ │ │ │ └── slang-llvm.h
│ │ │ ├── slang-com-helper.h
│ │ │ ├── slang-com-ptr.h
│ │ │ ├── slang-gfx.h
│ │ │ ├── slang-tag-version.h
│ │ │ └── slang.h
│ │ └── xmake.lua
│ ├── Plugin/
│ │ ├── Editor/
│ │ │ ├── AnimationEditor.cpp
│ │ │ ├── Console.cpp
│ │ │ ├── Hierarchy.cpp
│ │ │ ├── Inspector.cpp
│ │ │ ├── MainMenu.cpp
│ │ │ ├── MaterialGraphEditor.cpp
│ │ │ ├── MeshEditor.cpp
│ │ │ ├── RenderGraphEditor.cpp
│ │ │ ├── ResourceBrowser.cpp
│ │ │ ├── SceneView.cpp
│ │ │ ├── ShaderToy.cpp
│ │ │ └── xmake.lua
│ │ ├── Geometry/
│ │ │ ├── Parameterization/
│ │ │ │ ├── MinimumSurface.cpp
│ │ │ │ └── Tutte.cpp
│ │ │ ├── Subdivision/
│ │ │ │ └── Loop.cpp
│ │ │ └── xmake.lua
│ │ ├── Importer/
│ │ │ ├── Assimp.cpp
│ │ │ ├── DDS.cpp
│ │ │ ├── STB.cpp
│ │ │ └── xmake.lua
│ │ ├── MaterialNode/
│ │ │ ├── BSDF/
│ │ │ │ ├── ConductorMaterial.cpp
│ │ │ │ ├── DielectricMaterial.cpp
│ │ │ │ ├── DiffuseMaterial.cpp
│ │ │ │ ├── DisneyMaterial.cpp
│ │ │ │ ├── MaskedMaterial.cpp
│ │ │ │ ├── MixMaterial.cpp
│ │ │ │ ├── PrincipledMaterial.cpp
│ │ │ │ ├── ThinDielectricMaterial.cpp
│ │ │ │ └── Utils/
│ │ │ │ └── SPDLoader.hpp
│ │ │ ├── Converter/
│ │ │ │ ├── Calculate.cpp
│ │ │ │ ├── SRGBToLinear.cpp
│ │ │ │ ├── VectorCalculate.cpp
│ │ │ │ ├── VectorMerge.cpp
│ │ │ │ └── VectorSplit.cpp
│ │ │ ├── IMaterialNode.hpp
│ │ │ ├── Input/
│ │ │ │ ├── RGB.cpp
│ │ │ │ └── SurfaceInteraction.cpp
│ │ │ ├── Output/
│ │ │ │ └── MaterialOutput.cpp
│ │ │ ├── Texture/
│ │ │ │ └── ImageTexture.cpp
│ │ │ └── xmake.lua
│ │ ├── RHI/
│ │ │ ├── CUDA/
│ │ │ │ ├── Buffer.cpp
│ │ │ │ ├── Buffer.hpp
│ │ │ │ ├── CUDA.cpp
│ │ │ │ ├── Command.cpp
│ │ │ │ ├── Command.hpp
│ │ │ │ ├── Descriptor.cpp
│ │ │ │ ├── Descriptor.hpp
│ │ │ │ ├── Device.cpp
│ │ │ │ ├── Device.hpp
│ │ │ │ ├── Frame.cpp
│ │ │ │ ├── Frame.hpp
│ │ │ │ ├── Fwd.hpp
│ │ │ │ ├── PipelineState.cpp
│ │ │ │ ├── PipelineState.hpp
│ │ │ │ ├── Profiler.cpp
│ │ │ │ ├── Profiler.hpp
│ │ │ │ ├── Queue.cpp
│ │ │ │ ├── Queue.hpp
│ │ │ │ ├── Sampler.cpp
│ │ │ │ ├── Sampler.hpp
│ │ │ │ ├── Shader.cpp
│ │ │ │ ├── Shader.hpp
│ │ │ │ ├── Synchronization.cpp
│ │ │ │ ├── Synchronization.hpp
│ │ │ │ ├── Texture.cpp
│ │ │ │ └── Texture.hpp
│ │ │ ├── Vulkan/
│ │ │ │ ├── AccelerationStructure.cpp
│ │ │ │ ├── AccelerationStructure.hpp
│ │ │ │ ├── Buffer.cpp
│ │ │ │ ├── Buffer.hpp
│ │ │ │ ├── Command.cpp
│ │ │ │ ├── Command.hpp
│ │ │ │ ├── Definitions.cpp
│ │ │ │ ├── Definitions.hpp
│ │ │ │ ├── Descriptor.cpp
│ │ │ │ ├── Descriptor.hpp
│ │ │ │ ├── Device.cpp
│ │ │ │ ├── Device.hpp
│ │ │ │ ├── Frame.cpp
│ │ │ │ ├── Frame.hpp
│ │ │ │ ├── Fwd.cpp
│ │ │ │ ├── Fwd.hpp
│ │ │ │ ├── PipelineState.cpp
│ │ │ │ ├── PipelineState.hpp
│ │ │ │ ├── Profiler.cpp
│ │ │ │ ├── Profiler.hpp
│ │ │ │ ├── Queue.cpp
│ │ │ │ ├── Queue.hpp
│ │ │ │ ├── RenderTarget.cpp
│ │ │ │ ├── RenderTarget.hpp
│ │ │ │ ├── Sampler.cpp
│ │ │ │ ├── Sampler.hpp
│ │ │ │ ├── Shader.cpp
│ │ │ │ ├── Shader.hpp
│ │ │ │ ├── Swapchain.cpp
│ │ │ │ ├── Swapchain.hpp
│ │ │ │ ├── Synchronization.cpp
│ │ │ │ ├── Synchronization.hpp
│ │ │ │ ├── Texture.cpp
│ │ │ │ ├── Texture.hpp
│ │ │ │ ├── Vulkan.cpp
│ │ │ │ └── vk_mem_alloc.h
│ │ │ └── xmake.lua
│ │ ├── RenderPass/
│ │ │ ├── Bloom.cpp
│ │ │ ├── CompositePass.cpp
│ │ │ ├── CopyImageRGBA16.cpp
│ │ │ ├── Debug.cpp
│ │ │ ├── Deferred.cpp
│ │ │ ├── FXAA.cpp
│ │ │ ├── Forward.cpp
│ │ │ ├── ForwardPlus.cpp
│ │ │ ├── IBL.cpp
│ │ │ ├── IPass.hpp
│ │ │ ├── PassData.hpp
│ │ │ ├── PathTracing.cpp
│ │ │ ├── Present.cpp
│ │ │ ├── RayTracedAO.cpp
│ │ │ ├── RayTracingReflection.cpp
│ │ │ ├── RayTracingShadow.cpp
│ │ │ ├── SSAO.cpp
│ │ │ ├── ShadowMapPass.cpp
│ │ │ ├── SkyboxPass.cpp
│ │ │ ├── Tonemapping.cpp
│ │ │ ├── Triangle.cpp
│ │ │ ├── VisibilityBufferVisualization.cpp
│ │ │ ├── VisibilityGeometryPass.cpp
│ │ │ ├── VisibilityLightingPass.cpp
│ │ │ └── xmake.lua
│ │ └── xmake.lua
│ ├── Runtime/
│ │ ├── Core/
│ │ │ ├── Private/
│ │ │ │ ├── JobSystem.cpp
│ │ │ │ ├── Log.cpp
│ │ │ │ ├── Path.cpp
│ │ │ │ ├── Plugin.cpp
│ │ │ │ ├── Time.cpp
│ │ │ │ ├── Variant.cpp
│ │ │ │ └── Window.cpp
│ │ │ ├── Public/
│ │ │ │ └── Core/
│ │ │ │ ├── API.hpp
│ │ │ │ ├── Container.hpp
│ │ │ │ ├── Core.hpp
│ │ │ │ ├── Delegates.hpp
│ │ │ │ ├── Hash.hpp
│ │ │ │ ├── Input.hpp
│ │ │ │ ├── JobSystem.hpp
│ │ │ │ ├── Log.hpp
│ │ │ │ ├── PRECOMPILE.HPP
│ │ │ │ ├── Path.hpp
│ │ │ │ ├── Plugin.hpp
│ │ │ │ ├── Time.hpp
│ │ │ │ ├── Variant.hpp
│ │ │ │ └── Window.hpp
│ │ │ └── xmake.lua
│ │ ├── Geometry/
│ │ │ ├── Private/
│ │ │ │ ├── AABB.cpp
│ │ │ │ ├── Mesh/
│ │ │ │ │ ├── EMesh.cpp
│ │ │ │ │ ├── FMesh.cpp
│ │ │ │ │ ├── HEMesh.cpp
│ │ │ │ │ └── Mesh.cpp
│ │ │ │ └── MeshProcess.cpp
│ │ │ ├── Public/
│ │ │ │ └── Geometry/
│ │ │ │ ├── AABB.hpp
│ │ │ │ ├── Mesh/
│ │ │ │ │ ├── EMesh.hpp
│ │ │ │ │ ├── FMesh.hpp
│ │ │ │ │ ├── HEMesh.hpp
│ │ │ │ │ └── Mesh.hpp
│ │ │ │ ├── MeshProcess.hpp
│ │ │ │ ├── Meshlet.hpp
│ │ │ │ └── Precompile.hpp
│ │ │ └── xmake.lua
│ │ ├── RHI/
│ │ │ ├── Private/
│ │ │ │ ├── RHIAccelerationStructure.cpp
│ │ │ │ ├── RHIBuffer.cpp
│ │ │ │ ├── RHICommand.cpp
│ │ │ │ ├── RHIContext.cpp
│ │ │ │ ├── RHIDescriptor.cpp
│ │ │ │ ├── RHIDevice.cpp
│ │ │ │ ├── RHIFrame.cpp
│ │ │ │ ├── RHIPipelineState.cpp
│ │ │ │ ├── RHIProfiler.cpp
│ │ │ │ ├── RHIQueue.cpp
│ │ │ │ ├── RHIRenderTarget.cpp
│ │ │ │ ├── RHISampler.cpp
│ │ │ │ ├── RHIShader.cpp
│ │ │ │ ├── RHISwapchain.cpp
│ │ │ │ ├── RHISynchronization.cpp
│ │ │ │ └── RHITexture.cpp
│ │ │ └── Public/
│ │ │ └── RHI/
│ │ │ ├── Fwd.hpp
│ │ │ ├── RHIAccelerationStructure.hpp
│ │ │ ├── RHIBuffer.hpp
│ │ │ ├── RHICommand.hpp
│ │ │ ├── RHIContext.hpp
│ │ │ ├── RHIDefinitions.hpp
│ │ │ ├── RHIDescriptor.hpp
│ │ │ ├── RHIDevice.hpp
│ │ │ ├── RHIFrame.hpp
│ │ │ ├── RHIPipelineState.hpp
│ │ │ ├── RHIProfiler.hpp
│ │ │ ├── RHIQueue.hpp
│ │ │ ├── RHIRenderTarget.hpp
│ │ │ ├── RHISampler.hpp
│ │ │ ├── RHIShader.hpp
│ │ │ ├── RHISwapchain.hpp
│ │ │ ├── RHISynchronization.hpp
│ │ │ └── RHITexture.hpp
│ │ ├── Render/
│ │ │ ├── Material/
│ │ │ │ ├── Private/
│ │ │ │ │ └── Material/
│ │ │ │ │ ├── MaterialCompiler.cpp
│ │ │ │ │ ├── MaterialData.cpp
│ │ │ │ │ ├── MaterialGraph.cpp
│ │ │ │ │ ├── MaterialNode.cpp
│ │ │ │ │ └── Spectrum.cpp
│ │ │ │ └── Public/
│ │ │ │ └── Material/
│ │ │ │ ├── MaterialCompiler.hpp
│ │ │ │ ├── MaterialData.hpp
│ │ │ │ ├── MaterialGraph.hpp
│ │ │ │ ├── MaterialNode.hpp
│ │ │ │ └── Spectrum.hpp
│ │ │ ├── RenderGraph/
│ │ │ │ ├── Private/
│ │ │ │ │ ├── RenderGraph.cpp
│ │ │ │ │ ├── RenderGraphBlackboard.cpp
│ │ │ │ │ ├── RenderGraphBuilder.cpp
│ │ │ │ │ └── RenderPass.cpp
│ │ │ │ └── Public/
│ │ │ │ └── RenderGraph/
│ │ │ │ ├── Impl/
│ │ │ │ │ └── RenderGraphBuilder.inl
│ │ │ │ ├── Precompile.hpp
│ │ │ │ ├── RenderGraph.hpp
│ │ │ │ ├── RenderGraphBlackboard.hpp
│ │ │ │ ├── RenderGraphBuilder.hpp
│ │ │ │ └── RenderPass.hpp
│ │ │ ├── Renderer/
│ │ │ │ ├── Private/
│ │ │ │ │ └── Renderer.cpp
│ │ │ │ └── Public/
│ │ │ │ └── Renderer/
│ │ │ │ ├── RenderData.hpp
│ │ │ │ └── Renderer.hpp
│ │ │ ├── ShaderCompiler/
│ │ │ │ ├── Private/
│ │ │ │ │ ├── ShaderBuilder.cpp
│ │ │ │ │ ├── ShaderCompiler.cpp
│ │ │ │ │ └── SpirvReflection.cpp
│ │ │ │ └── Public/
│ │ │ │ └── ShaderCompiler/
│ │ │ │ ├── Precompile.hpp
│ │ │ │ ├── ShaderBuilder.hpp
│ │ │ │ ├── ShaderCompiler.hpp
│ │ │ │ └── SpirvReflection.hpp
│ │ │ └── xmake.lua
│ │ ├── Resource/
│ │ │ ├── Private/
│ │ │ │ └── Resource/
│ │ │ │ ├── Importer.cpp
│ │ │ │ ├── Resource/
│ │ │ │ │ ├── Animation.cpp
│ │ │ │ │ ├── Material.cpp
│ │ │ │ │ ├── Mesh.cpp
│ │ │ │ │ ├── Prefab.cpp
│ │ │ │ │ ├── RenderPipeline.cpp
│ │ │ │ │ ├── Scene.cpp
│ │ │ │ │ ├── SkinnedMesh.cpp
│ │ │ │ │ ├── Texture2D.cpp
│ │ │ │ │ └── TextureCube.cpp
│ │ │ │ ├── Resource.cpp
│ │ │ │ └── ResourceManager.cpp
│ │ │ └── Public/
│ │ │ └── Resource/
│ │ │ ├── Importer.hpp
│ │ │ ├── Resource/
│ │ │ │ ├── Animation.hpp
│ │ │ │ ├── Material.hpp
│ │ │ │ ├── Mesh.hpp
│ │ │ │ ├── Prefab.hpp
│ │ │ │ ├── RenderPipeline.hpp
│ │ │ │ ├── Scene.hpp
│ │ │ │ ├── SkinnedMesh.hpp
│ │ │ │ ├── Texture2D.hpp
│ │ │ │ └── TextureCube.hpp
│ │ │ ├── Resource.hpp
│ │ │ └── ResourceManager.hpp
│ │ ├── Scene/
│ │ │ ├── Private/
│ │ │ │ └── Scene/
│ │ │ │ ├── Component.cpp
│ │ │ │ ├── Components/
│ │ │ │ │ ├── AllComponents.cpp
│ │ │ │ │ ├── Camera/
│ │ │ │ │ │ ├── Camera.cpp
│ │ │ │ │ │ ├── OrthographicCamera.cpp
│ │ │ │ │ │ └── PerspectiveCamera.cpp
│ │ │ │ │ ├── Light/
│ │ │ │ │ │ ├── DirectionalLight.cpp
│ │ │ │ │ │ ├── EnvironmentLight.cpp
│ │ │ │ │ │ ├── Light.cpp
│ │ │ │ │ │ ├── PointLight.cpp
│ │ │ │ │ │ ├── RectLight.cpp
│ │ │ │ │ │ └── SpotLight.cpp
│ │ │ │ │ ├── Renderable/
│ │ │ │ │ │ ├── MeshRenderer.cpp
│ │ │ │ │ │ ├── Renderable.cpp
│ │ │ │ │ │ └── SkinnedMeshRenderer.cpp
│ │ │ │ │ └── Transform.cpp
│ │ │ │ ├── Node.cpp
│ │ │ │ └── Scene.cpp
│ │ │ └── Public/
│ │ │ └── Scene/
│ │ │ ├── Component.hpp
│ │ │ ├── Components/
│ │ │ │ ├── AllComponents.hpp
│ │ │ │ ├── Camera/
│ │ │ │ │ ├── Camera.hpp
│ │ │ │ │ ├── OrthographicCamera.hpp
│ │ │ │ │ └── PerspectiveCamera.hpp
│ │ │ │ ├── Light/
│ │ │ │ │ ├── DirectionalLight.hpp
│ │ │ │ │ ├── EnvironmentLight.hpp
│ │ │ │ │ ├── Light.hpp
│ │ │ │ │ ├── PointLight.hpp
│ │ │ │ │ ├── RectLight.hpp
│ │ │ │ │ └── SpotLight.hpp
│ │ │ │ ├── Renderable/
│ │ │ │ │ ├── MeshRenderer.hpp
│ │ │ │ │ ├── Renderable.hpp
│ │ │ │ │ └── SkinnedMeshRenderer.hpp
│ │ │ │ └── Transform.hpp
│ │ │ ├── Node.hpp
│ │ │ └── Scene.hpp
│ │ └── xmake.lua
│ ├── Shaders/
│ │ ├── AmbientOcclusion/
│ │ │ ├── RayTracedAO.hlsl
│ │ │ └── SSAO.hlsl
│ │ ├── Attribute.hlsli
│ │ ├── Common.hlsli
│ │ ├── Complex.hlsli
│ │ ├── Editor/
│ │ │ ├── AnimationEditor/
│ │ │ │ └── DrawSkeleton.hlsl
│ │ │ ├── AnimationEditor.hlsl
│ │ │ ├── MaterialEditor.hlsl
│ │ │ ├── MeshEditor.hlsl
│ │ │ └── Preview/
│ │ │ ├── Material.hlsl
│ │ │ └── Mesh.hlsl
│ │ ├── GlobalIllumination/
│ │ │ └── DDGI.hlsl
│ │ ├── ImGui.hlsl
│ │ ├── Interaction.hlsli
│ │ ├── Light.hlsli
│ │ ├── Material/
│ │ │ ├── BSDF/
│ │ │ │ ├── BSDF.hlsli
│ │ │ │ ├── ConductorBSDF.hlsli
│ │ │ │ ├── DielectricBSDF.hlsli
│ │ │ │ ├── DiffuseBSDF.hlsli
│ │ │ │ ├── DisneyBSDF.hlsli
│ │ │ │ ├── LayeredBSDF.hlsli
│ │ │ │ └── ThinDielectricBSDF.hlsli
│ │ │ ├── Fresnel.hlsli
│ │ │ ├── Material/
│ │ │ │ ├── ConductorMaterial.hlsli
│ │ │ │ ├── DielectricMaterial.hlsli
│ │ │ │ ├── DiffuseMaterial.hlsli
│ │ │ │ ├── DisneyMaterial.hlsli
│ │ │ │ ├── MaskedMaterial.hlsli
│ │ │ │ ├── MixMaterial.hlsli
│ │ │ │ └── ThinDielectricMaterial.hlsli
│ │ │ ├── Material.hlsli
│ │ │ ├── Scattering.hlsli
│ │ │ └── Template.material.hlsli
│ │ ├── Material.hlsli
│ │ ├── MaterialResource.hlsli
│ │ ├── Math.hlsli
│ │ ├── PostProcess/
│ │ │ ├── Bloom.hlsl
│ │ │ ├── FXAA.hlsl
│ │ │ └── Tonemapping.hlsl
│ │ ├── PreProcess/
│ │ │ ├── EquirectangularToCubemap.hlsl
│ │ │ └── GGXBRDFLUT.hlsl
│ │ ├── Random.hlsli
│ │ ├── RayTracing/
│ │ │ ├── BidirectionalPathTracing.hlsl
│ │ │ └── PathTracing.hlsl
│ │ ├── Reflection/
│ │ │ └── RayTracedReflection.hlsl
│ │ ├── RenderPath/
│ │ │ ├── VisibilityBufferVisualization.hlsl
│ │ │ ├── VisibilityGeometryPass.hlsl
│ │ │ └── VisibilityLightingPass.hlsl
│ │ ├── Shading/
│ │ │ ├── Composite.hlsl
│ │ │ ├── IBL.hlsl
│ │ │ └── Skybox.hlsl
│ │ ├── Shadow/
│ │ │ ├── CascadeShadowMap.hlsl
│ │ │ ├── OmniShadowMap.hlsl
│ │ │ ├── RayTracedShadow.hlsl
│ │ │ └── ShadowMap.hlsl
│ │ ├── SphericalHarmonic.hlsli
│ │ ├── Tonemapper.hlsli
│ │ └── UpdateBoneMatrics.hlsl
│ └── xmake.lua
├── imgui.ini
├── xmake/
│ ├── module.lua
│ ├── plugin.lua
│ ├── rule.lua
│ └── shader.lua
└── xmake.lua
================================================
FILE CONTENTS
================================================
================================================
FILE: .clang-format
================================================
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 0
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: AfterHash
IndentWidth: 4
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 8
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: ForIndentation
...
================================================
FILE: .clang-tidy
================================================
Checks: '-*,
misc-throw-by-value-catch-by-reference,
misc-misplaced-const,
misc-unconventional-assign-operator,
misc-redundant-expression,
misc-static-assert,
misc-unconventional-assign-operator,
misc-uniqueptr-reset-release,
misc-unused-alias-decls,
misc-unused-parameters,
misc-unused-using-decls,
modernize-avoid-bind,
modernize-loop-convert,
modernize-make-shared,
modernize-make-unique,
modernize-raw-string-literal,
modernize-redundant-void-arg,
modernize-replace-auto-ptr,
modernize-replace-random-shuffle,
modernize-use-bool-literals,
modernize-use-nullptr,
modernize-use-using,
modernize-use-equals-default,
modernize-use-equals-delete,
performance-faster-string-find,
performance-for-range-copy,
performance-implicit-conversion-in-loop,
performance-inefficient-algorithm,
performance-inefficient-vector-operation,
performance-move-constructor-init,
performance-no-automatic-move,
performance-trivially-destructible,
performance-unnecessary-copy-initialization,
readability-avoid-const-params-in-decls,
readability-const-return-type,
readability-container-size-empty,
readability-convert-member-functions-to-static,
readability-delete-null-pointer,
readability-deleted-default,
readability-make-member-function-const,
readability-misplaced-array-index,
readability-non-const-parameter,
readability-qualified-auto,
readability-redundant-access-specifiers,
readability-redundant-control-flow,
readability-redundant-function-ptr-dereference,
readability-redundant-smartptr-get,
readability-redundant-string-cstr,
readability-redundant-string-init,
readability-static-definition-in-anonymous-namespace,
readability-string-compare,
readability-uniqueptr-delete-release,
readability-redundant-member-init,
readability-simplify-subscript-expr,
readability-simplify-boolean-expr,
readability-inconsistent-declaration-parameter-name,
readability-identifier-naming,
bugprone-undelegated-constructor,
bugprone-argument-comment,
bugprone-bad-signal-to-kill-thread,
bugprone-bool-pointer-implicit-conversion,
bugprone-copy-constructor-init,
bugprone-dangling-handle,
bugprone-forward-declaration-namespace,
bugprone-fold-init-type,
bugprone-inaccurate-erase,
bugprone-incorrect-roundings,
bugprone-infinite-loop,
bugprone-integer-division,
bugprone-macro-parentheses,
bugprone-macro-repeated-side-effects,
bugprone-misplaced-operator-in-strlen-in-alloc,
bugprone-misplaced-pointer-artithmetic-in-alloc,
bugprone-misplaced-widening-cast,
bugprone-move-forwarding-reference,
bugprone-multiple-statement-macro,
bugprone-parent-virtual-call,
bugprone-posix-return,
bugprone-reserved-identifier,
bugprone-signed-char-misuse,
bugprone-sizeof-container,
bugprone-sizeof-expression,
bugprone-string-constructor,
bugprone-string-integer-assignment,
bugprone-string-literal-with-embedded-nul,
bugprone-suspicious-enum-usage,
bugprone-suspicious-include,
bugprone-suspicious-memset-usage,
bugprone-suspicious-missing-comma,
bugprone-suspicious-string-compare,
bugprone-swapped-arguments,
bugprone-terminating-continue,
bugprone-throw-keyword-missing,
bugprone-too-small-loop-variable,
bugprone-undefined-memory-manipulation,
bugprone-unhandled-self-assignment,
bugprone-unused-raii,
bugprone-unused-return-value,
bugprone-use-after-move,
bugprone-virtual-near-miss,
cert-dcl21-cpp,
cert-dcl50-cpp,
cert-env33-c,
cert-err34-c,
cert-err52-cpp,
cert-flp30-c,
cert-mem57-cpp,
cert-msc50-cpp,
cert-oop58-cpp,
google-build-explicit-make-pair,
google-build-namespaces,
google-default-arguments,
google-explicit-constructor,
google-readability-casting,
google-readability-avoid-underscore-in-googletest-name,
google-runtime-int,
google-runtime-operator,
hicpp-exception-baseclass,
clang-analyzer-core.CallAndMessage,
clang-analyzer-core.DivideZero,
clang-analyzer-core.NonNullParamChecker,
clang-analyzer-core.NullDereference,
clang-analyzer-core.StackAddressEscape,
clang-analyzer-core.UndefinedBinaryOperatorResult,
clang-analyzer-core.VLASize,
clang-analyzer-core.uninitialized.ArraySubscript,
clang-analyzer-core.uninitialized.Assign,
clang-analyzer-core.uninitialized.Branch,
clang-analyzer-core.uninitialized.CapturedBlockVariable,
clang-analyzer-core.uninitialized.UndefReturn,
clang-analyzer-cplusplus.InnerPointer,
clang-analyzer-cplusplus.NewDelete,
clang-analyzer-cplusplus.NewDeleteLeaks,
clang-analyzer-cplusplus.PlacementNewChecker,
clang-analyzer-cplusplus.SelfAssignment,
clang-analyzer-deadcode.DeadStores,
clang-analyzer-optin.cplusplus.VirtualCall,
clang-analyzer-security.insecureAPI.UncheckedReturn,
clang-analyzer-security.insecureAPI.bcmp,
clang-analyzer-security.insecureAPI.bcopy,
clang-analyzer-security.insecureAPI.bzero,
clang-analyzer-security.insecureAPI.getpw,
clang-analyzer-security.insecureAPI.gets,
clang-analyzer-security.insecureAPI.mkstemp,
clang-analyzer-security.insecureAPI.mktemp,
clang-analyzer-security.insecureAPI.rand,
clang-analyzer-security.insecureAPI.strcpy,
clang-analyzer-unix.Malloc,
clang-analyzer-unix.MallocSizeof,
clang-analyzer-unix.MismatchedDeallocator,
clang-analyzer-unix.Vfork,
clang-analyzer-unix.cstring.BadSizeArg,
clang-analyzer-unix.cstring.NullArg,
boost-use-to-string,
'
WarningsAsErrors: '*'
CheckOptions:
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.EnumCase
value: CamelCase
- key: readability-identifier-naming.LocalVariableCase
value: lower_case
- key: readability-identifier-naming.StaticConstantCase
value: aNy_CasE
- key: readability-identifier-naming.MemberCase
value: lower_case
- key: readability-identifier-naming.ClassMemberPrefix
value: m_
- key: readability-identifier-naming.PrivateMemberPrefix
value: ''
- key: readability-identifier-naming.ProtectedMemberPrefix
value: ''
- key: readability-identifier-naming.PublicMemberCase
value: lower_case
- key: readability-identifier-naming.MethodCase
value: camelBack
- key: readability-identifier-naming.PrivateMethodPrefix
value: ''
- key: readability-identifier-naming.ProtectedMethodPrefix
value: ''
- key: readability-identifier-naming.ParameterPackCase
value: lower_case
- key: readability-identifier-naming.StructCase
value: CamelCase
- key: readability-identifier-naming.TemplateTemplateParameterCase
value: CamelCase
- key: readability-identifier-naming.TemplateUsingCase
value: lower_case
- key: readability-identifier-naming.TypeTemplateParameterCase
value: CamelCase
- key: readability-identifier-naming.TypedefCase
value: CamelCase
- key: readability-identifier-naming.UnionCase
value: CamelCase
- key: readability-identifier-naming.UsingCase
value: CamelCase
================================================
FILE: .github/workflows/windows_dev.yml
================================================
name: Windows_dev
on:
pull_request:
types: [dev]
push:
branches: [dev]
jobs:
build:
runs-on: "windows-latest"
steps:
- uses: actions/checkout@v2
with:
submodules: "recursive"
- uses: Jimver/cuda-toolkit@v0.2.8
id: cuda-toolkit
with:
cuda: '11.7.0'
sub-packages: '["nvcc", "visual_studio_integration", "cudart"]'
- uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
actions-cache-folder: ".xmake-cache"
- name: Build
run: xmake -y
================================================
FILE: .github/workflows/windows_main.yml
================================================
name: Windows_main
on:
pull_request:
types: [main]
push:
branches: [main]
jobs:
build:
runs-on: "windows-latest"
steps:
- uses: actions/checkout@v2
with:
submodules: "recursive"
- uses: Jimver/cuda-toolkit@v0.2.8
id: cuda-toolkit
with:
cuda: '11.7.0'
sub-packages: '["nvcc", "visual_studio_integration", "cudart"]'
- uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
actions-cache-folder: ".xmake-cache"
- name: Build
run: xmake -y
================================================
FILE: .gitignore
================================================
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
*.spv
# Folders
/build/*
/bin/*
/lib/*
/shared/*
**/Archive/*
*.meta
.vscode
.xmake/
build/
vsxmake**
================================================
FILE: .gitmodules
================================================
[submodule "Source/Dependencies"]
path = Source/Dependencies
url = https://github.com/Chaf-Libraries/Dependencies
================================================
FILE: Asset/Meta/README.md
================================================
================================================
FILE: Asset/MustacheTemplate/Reflection.mustache
================================================
{{#Header}}
{{&Include}}
{{/Header}}
namespace Ilum_{{Hash}}
{
RTTR_REGISTRATION
{
{{#Enum}}
rttr::registration::enumeration<{{EnumQualifiedName}}>("{{EnumName}}")
(
{{#EnumValue}}
rttr::value("{{EnumValueName}}", {{EnumValueQualifiedName}}){{^IsLast}},{{/IsLast}}
{{/EnumValue}}
);
{{/Enum}}
{{#Class}}
rttr::registration::class_<{{ClassQualifiedName}}>("{{ClassName}}"){{#Meta}}({{#MetaData}}rttr::metadata("{{&Key}}", {{&Value}}){{^IsLast}}, {{/IsLast}}{{/MetaData}}){{/Meta}}
{{#Field}}
.property("{{FieldName}}", &{{FieldQualifiedName}}, rttr::registration::{{#Public}}public_access{{/Public}}{{#Private}}private_access{{/Private}}{{#Protected}}protected_access{{/Protected}}){{#Meta}}({{#MetaData}}rttr::metadata("{{&Key}}", {{&Value}}){{^IsLast}}, {{/IsLast}}{{/MetaData}}){{/Meta}}
{{/Field}}
{{#Constructor}}
{{^Static}}.constructor<{{#Params}}{{&Param}}{{^IsLast}}, {{/IsLast}}{{/Params}}>(){{/Static}}{{#Static}}.constructor(&{{MethodQualifiedName}}){{/Static}}(rttr::policy::ctor::as_object)
{{/Constructor}}
{{#NoConstructor}}
.constructor<>()(rttr::policy::ctor::as_object)
{{/NoConstructor}}
{{#Method}}
.method("{{&MethodName}}", {{^Overload}}&{{&MethodQualifiedName}}{{/Overload}}{{#Overload}}{{^Const}}rttr::select_overload<{{&ReturnType}}({{#Params}}{{&Param}}{{^IsLast}}, {{/IsLast}}{{/Params}})>{{/Const}}{{#Const}}rttr::select_const<{{&ClassQualifiedName}}, {{&ReturnType}}, {{#Params}}{{&Param}}{{^IsLast}}, {{/IsLast}}{{/Params}}>{{/Const}}(&{{&MethodQualifiedName}}){{/Overload}}, rttr::registration::{{#Public}}public_access{{/Public}}{{#Private}}private_access{{/Private}}{{#Protected}}protected_access{{/Protected}}){{#Meta}}({{#MetaData}}rttr::metadata("{{&Key}}", {{&Value}}){{^IsLast}}, {{/IsLast}}{{/MetaData}}){{/Meta}}
{{/Method}}
;
{{/Class}}
}
}
================================================
FILE: Asset/NRD_Data/Sample/blur_buffer.csv
================================================
gViewToClip,"[1.0000, 0.0000, 0.0000, 0.0000]
[0.0000, 1.7778, 0.0000, 0.0000]
[-0.0000, -0.0000, 1.0000, 1.0000]
[0.0000, 0.0000, -0.0010, 0.0000]"
gViewToWorld,"[-0.9997, -0.0236, -0.0000, 0.0000]
[0.0031, -0.1315, 0.9913, 0.0000]
[0.0234, -0.9910, -0.1315, 0.0000]
[0.0000, 0.0000, 0.0000, 1.0000]"
gFrustum,"[-1.0000, 0.5625, 2.0000, -1.1250]"
gHitDistParams,"[3.0000, 0.1000, 20.0000, -25.0000]"
gViewVectorWorld,"[-0.0234, 0.9910, 0.1315, 0.0000]"
gViewVectorWorldPrev,"[-0.0234, 0.9910, 0.1315, 0.0000]"
gInvScreenSize,"[0.0008, 0.0014]"
gScreenSize,"[1280.0000, 720.0000]"
gInvRectSize,"[0.0008, 0.0014]"
gRectSize,"[1280.0000, 720.0000]"
gRectSizePrev,"[1280.0000, 720.0000]"
gResolutionScale,"[1.0000, 1.0000]"
gRectOffset,"[0.0000, 0.0000]"
gSensitivityToDarkness,"[0.0100, 0.1000]"
gRectOrigin,"[0, 0]"
gReference,0.0000
gOrthoMode,0.0000
gUnproject,0.0016
gDebug,0.0000
gDenoisingRange,60.6960
gPlaneDistSensitivity,0.0050
gFramerateScale,0.5000
gBlurRadius,30.0000
gMaxAccumulatedFrameNum,1.0000
gMaxFastAccumulatedFrameNum,0.0000
gAntiFirefly,0.0000
gMinConvergedStateBaseRadiusScale,0.2500
gLobeAngleFraction,0.1000
gRoughnessFraction,0.0500
gResponsiveAccumulationRoughnessThreshold,0.0000
gDiffPrepassBlurRadius,30.0000
gSpecPrepassBlurRadius,50.0000
gIsWorldSpaceMotionEnabled,1
gFrameIndex,42372
gResetHistory,0
gDiffMaterialMask,1
gSpecMaterialMask,0
gRotator,"[0.2651, -0.9642, 0.9642, 0.2651]"
gSpecLobeTrimmingParams,"[0.9500, 0.0400, 0.1100]"
gBlurRadiusScale,5.0000
================================================
FILE: Asset/NRD_Data/Sample/history_fix_buffer.csv
================================================
gViewToClip,"[1.0000, 0.0000, 0.0000, 0.0000]
[0.0000, 1.7778, 0.0000, 0.0000]
[-0.0000, -0.0000, 1.0000, 1.0000]
[0.0000, 0.0000, -0.0010, 0.0000]",-
gViewToWorld,"[-0.9997, -0.0236, -0.0000, 0.0000]
[0.0031, -0.1315, 0.9913, 0.0000]
[0.0234, -0.9910, -0.1315, 0.0000]
[0.0000, 0.0000, 0.0000, 1.0000]",-
gFrustum,"[-1.0000, 0.5625, 2.0000, -1.1250]",-
gHitDistParams,"[3.0000, 0.1000, 20.0000, -25.0000]",-
gViewVectorWorld,"[-0.0234, 0.9910, 0.1315, 0.0000]",-
gViewVectorWorldPrev,"[-0.0234, 0.9910, 0.1315, 0.0000]",-
gInvScreenSize,"[0.0008, 0.0014]",-
gScreenSize,"[1280.0000, 720.0000]",-
gInvRectSize,"[0.0008, 0.0014]",-
gRectSize,"[1280.0000, 720.0000]",-
gRectSizePrev,"[1280.0000, 720.0000]",-
gResolutionScale,"[1.0000, 1.0000]",-
gRectOffset,"[0.0000, 0.0000]",-
gSensitivityToDarkness,"[0.0100, 0.1000]",-
gRectOrigin,"[0, 0]",-
gReference,0.0000,-
gOrthoMode,0.0000,-
gUnproject,0.0016,-
gDebug,0.0000,-
gDenoisingRange,60.6960,-
gPlaneDistSensitivity,0.0050,-
gFramerateScale,0.5000,-
gBlurRadius,30.0000,-
gMaxAccumulatedFrameNum,1.0000,-
gMaxFastAccumulatedFrameNum,0.0000,-
gAntiFirefly,0.0000,-
gMinConvergedStateBaseRadiusScale,0.2500,-
gLobeAngleFraction,0.1000,-
gRoughnessFraction,0.0500,-
gResponsiveAccumulationRoughnessThreshold,0.0000,-
gDiffPrepassBlurRadius,30.0000,-
gSpecPrepassBlurRadius,50.0000,-
gIsWorldSpaceMotionEnabled,1,-
gFrameIndex,42372,-
gResetHistory,0,-
gDiffMaterialMask,1,-
gSpecMaterialMask,0,-
gHistoryFixStrength,1.0000,-
================================================
FILE: Asset/NRD_Data/Sample/post_blur_buffer.csv
================================================
gViewToClip,gViewToWorld,gFrustum,gHitDistParams,gViewVectorWorld,gViewVectorWorldPrev,gInvScreenSize,gScreenSize,gInvRectSize,gRectSize,gRectSizePrev,gResolutionScale,gRectOffset,gSensitivityToDarkness,gRectOrigin,gReference,gOrthoMode,gUnproject,gDebug,gDenoisingRange,gPlaneDistSensitivity,gFramerateScale,gBlurRadius,gMaxAccumulatedFrameNum,gMaxFastAccumulatedFrameNum,gAntiFirefly,gMinConvergedStateBaseRadiusScale,gLobeAngleFraction,gRoughnessFraction,gResponsiveAccumulationRoughnessThreshold,gDiffPrepassBlurRadius,gSpecPrepassBlurRadius,gIsWorldSpaceMotionEnabled,gFrameIndex,gResetHistory,gDiffMaterialMask,gSpecMaterialMask,gRotator,gSpecLobeTrimmingParams,gBlurRadiusScale
"[1.0000, 0.0000, 0.0000, 0.0000]
[0.0000, 1.7778, 0.0000, 0.0000]
[-0.0000, -0.0000, 1.0000, 1.0000]
[0.0000, 0.0000, -0.0010, 0.0000]","[-0.9997, -0.0236, -0.0000, 0.0000]
[0.0031, -0.1315, 0.9913, 0.0000]
[0.0234, -0.9910, -0.1315, 0.0000]
[0.0000, 0.0000, 0.0000, 1.0000]","[-1.0000, 0.5625, 2.0000, -1.1250]","[3.0000, 0.1000, 20.0000, -25.0000]","[-0.0234, 0.9910, 0.1315, 0.0000]","[-0.0234, 0.9910, 0.1315, 0.0000]","[0.0008, 0.0014]","[1280.0000, 720.0000]","[0.0008, 0.0014]","[1280.0000, 720.0000]","[1280.0000, 720.0000]","[1.0000, 1.0000]","[0.0000, 0.0000]","[0.0100, 0.1000]","[0, 0]",0.0000,0.0000,0.0016,0.0000,60.6960,0.0050,0.5000,30.0000,1.0000,0.0000,0.0000,0.2500,0.1000,0.0500,0.0000,30.0000,50.0000,1,42372,0,1,0,"[-0.9642, -0.2651, 0.2651, -0.9642]","[0.9500, 0.0400, 0.1100]",5.0000
================================================
FILE: Asset/NRD_Data/Sample/temporal_accumulate_buffer.csv
================================================
gViewToClip,"[1.0000, 0.0000, 0.0000, 0.0000]
[0.0000, 1.7778, 0.0000, 0.0000]
[-0.0000, -0.0000, 1.0000, 1.0000]
[0.0000, 0.0000, -0.0010, 0.0000]",-
gViewToWorld,"[-0.9997, -0.0236, -0.0000, 0.0000]
[0.0031, -0.1315, 0.9913, 0.0000]
[0.0234, -0.9910, -0.1315, 0.0000]
[0.0000, 0.0000, 0.0000, 1.0000]",-
gFrustum,"[-1.0000, 0.5625, 2.0000, -1.1250]",-
gHitDistParams,"[3.0000, 0.1000, 20.0000, -25.0000]",-
gViewVectorWorld,"[-0.0234, 0.9910, 0.1315, 0.0000]",-
gViewVectorWorldPrev,"[-0.0234, 0.9910, 0.1315, 0.0000]",-
gInvScreenSize,"[0.0008, 0.0014]",-
gScreenSize,"[1280.0000, 720.0000]",-
gInvRectSize,"[0.0008, 0.0014]",-
gRectSize,"[1280.0000, 720.0000]",-
gRectSizePrev,"[1280.0000, 720.0000]",-
gResolutionScale,"[1.0000, 1.0000]",-
gRectOffset,"[0.0000, 0.0000]",-
gSensitivityToDarkness,"[0.0100, 0.1000]",-
gRectOrigin,"[0, 0]",-
gReference,0.0000,-
gOrthoMode,0.0000,-
gUnproject,0.0016,-
gDebug,0.0000,-
gDenoisingRange,60.6960,-
gPlaneDistSensitivity,0.0050,-
gFramerateScale,0.5000,-
gBlurRadius,30.0000,-
gMaxAccumulatedFrameNum,1.0000,-
gMaxFastAccumulatedFrameNum,0.0000,-
gAntiFirefly,0.0000,-
gMinConvergedStateBaseRadiusScale,0.2500,-
gLobeAngleFraction,0.1000,-
gRoughnessFraction,0.0500,-
gResponsiveAccumulationRoughnessThreshold,0.0000,-
gDiffPrepassBlurRadius,30.0000,-
gSpecPrepassBlurRadius,50.0000,-
gIsWorldSpaceMotionEnabled,1,-
gFrameIndex,42372,-
gResetHistory,0,-
gDiffMaterialMask,1,-
gSpecMaterialMask,0,-
gWorldToViewPrev,"[-0.9997, 0.0031, 0.0234, 0.0000]
[-0.0236, -0.1315, -0.9910, 0.0000]
[-0.0000, 0.9913, -0.1315, 0.0000]
[0.0000, -0.0000, -0.0000, 1.0000]",-
gWorldToClipPrev,"[-0.9997, 0.0055, 0.0234, 0.0234]
[-0.0236, -0.2337, -0.9910, -0.9910]
[0.0000, 1.7623, -0.1315, -0.1315]
[0.0000, 0.0000, -0.0010, 0.0000]",-
gWorldToClip,"[-0.9997, 0.0055, 0.0234, 0.0234]
[-0.0236, -0.2337, -0.9910, -0.9910]
[0.0000, 1.7623, -0.1315, -0.1315]
[0.0000, 0.0000, -0.0010, 0.0000]",-
gWorldPrevToWorld,"[1.0000, 0.0000, 0.0000, 0.0000]
[0.0000, 1.0000, 0.0000, 0.0000]
[0.0000, 0.0000, 1.0000, 0.0000]
[0.0000, 0.0000, 0.0000, 1.0000]",-
gFrustumPrev,"[-1.0000, 0.5625, 2.0000, -1.1250]",-
gCameraDelta,"[0.0000, 0.0000, 0.0000, 0.0000]",-
gRotator,"[-0.5868, 0.8098, -0.8098, -0.5868]",-
gMotionVectorScale,"[1.0000, 1.0000]",-
gCheckerboardResolveAccumSpeed,0.6447,-
gDisocclusionThreshold,0.0071,-
gDiffCheckerboard,2,-
gSpecCheckerboard,2,-
gIsPrepassEnabled,0,-
================================================
FILE: Asset/SPD/metals/Ag.eta.spd
================================================
298.757050 1.519000
302.400421 1.496000
306.133759 1.432500
309.960449 1.323000
313.884003 1.142062
317.908142 0.932000
322.036835 0.719062
326.274139 0.526000
330.624481 0.388125
335.092377 0.294000
339.682678 0.253313
344.400482 0.238000
349.251221 0.221438
354.240509 0.209000
359.374420 0.194813
364.659332 0.186000
370.102020 0.192063
375.709625 0.200000
381.489777 0.198063
387.450562 0.192000
393.600555 0.182000
399.948975 0.173000
406.505493 0.172625
413.280579 0.173000
420.285339 0.166688
427.531647 0.160000
435.032196 0.158500
442.800629 0.157000
450.851562 0.151063
459.200653 0.144000
467.864838 0.137313
476.862213 0.132000
486.212463 0.130250
495.936707 0.130000
506.057861 0.129938
516.600769 0.130000
527.592224 0.130063
539.061646 0.129000
551.040771 0.124375
563.564453 0.120000
576.670593 0.119313
590.400818 0.121000
604.800842 0.125500
619.920898 0.131000
635.816284 0.136125
652.548279 0.140000
670.184753 0.140063
688.800964 0.140000
708.481018 0.144313
729.318665 0.148000
751.419250 0.145875
774.901123 0.143000
799.897949 0.142563
826.561157 0.145000
855.063293 0.151938
885.601257 0.163000
================================================
FILE: Asset/SPD/metals/Ag.k.spd
================================================
298.757050 1.080000
302.400421 0.882000
306.133759 0.761063
309.960449 0.647000
313.884003 0.550875
317.908142 0.504000
322.036835 0.554375
326.274139 0.663000
330.624481 0.818563
335.092377 0.986000
339.682678 1.120687
344.400482 1.240000
349.251221 1.345250
354.240509 1.440000
359.374420 1.533750
364.659332 1.610000
370.102020 1.641875
375.709625 1.670000
381.489777 1.735000
387.450562 1.810000
393.600555 1.878750
399.948975 1.950000
406.505493 2.029375
413.280579 2.110000
420.285339 2.186250
427.531647 2.260000
435.032196 2.329375
442.800629 2.400000
450.851562 2.478750
459.200653 2.560000
467.864838 2.640000
476.862213 2.720000
486.212463 2.798125
495.936707 2.880000
506.057861 2.973750
516.600769 3.070000
527.592224 3.159375
539.061646 3.250000
551.040771 3.348125
563.564453 3.450000
576.670593 3.553750
590.400818 3.660000
604.800842 3.766250
619.920898 3.880000
635.816284 4.010625
652.548279 4.150000
670.184753 4.293125
688.800964 4.440000
708.481018 4.586250
729.318665 4.740000
751.419250 4.908125
774.901123 5.090000
799.897949 5.288750
826.561157 5.500000
855.063293 5.720624
885.601257 5.950000
================================================
FILE: Asset/SPD/metals/Al.eta.spd
================================================
298.757050 0.273375
302.400421 0.280000
306.133759 0.286813
309.960449 0.294000
313.884003 0.301875
317.908142 0.310000
322.036835 0.317875
326.274139 0.326000
330.624481 0.334750
335.092377 0.344000
339.682678 0.353813
344.400482 0.364000
349.251221 0.374375
354.240509 0.385000
359.374420 0.395750
364.659332 0.407000
370.102020 0.419125
375.709625 0.432000
381.489777 0.445688
387.450562 0.460000
393.600555 0.474688
399.948975 0.490000
406.505493 0.506188
413.280579 0.523000
420.285339 0.540063
427.531647 0.558000
435.032196 0.577313
442.800629 0.598000
450.851562 0.620313
459.200653 0.644000
467.864838 0.668625
476.862213 0.695000
486.212463 0.723750
495.936707 0.755000
506.057861 0.789000
516.600769 0.826000
527.592224 0.867000
539.061646 0.912000
551.040771 0.963000
563.564453 1.020000
576.670593 1.080000
590.400818 1.150000
604.800842 1.220000
619.920898 1.300000
635.816284 1.390000
652.548279 1.490000
670.184753 1.600000
688.800964 1.740000
708.481018 1.910000
729.318665 2.140000
751.419250 2.410000
774.901123 2.630000
799.897949 2.800000
826.561157 2.740000
855.063293 2.580000
885.601257 2.240000
================================================
FILE: Asset/SPD/metals/Al.k.spd
================================================
298.757050 3.593750
302.400421 3.640000
306.133759 3.689375
309.960449 3.740000
313.884003 3.789375
317.908142 3.840000
322.036835 3.894375
326.274139 3.950000
330.624481 4.005000
335.092377 4.060000
339.682678 4.113750
344.400482 4.170000
349.251221 4.233750
354.240509 4.300000
359.374420 4.365000
364.659332 4.430000
370.102020 4.493750
375.709625 4.560000
381.489777 4.633750
387.450562 4.710000
393.600555 4.784375
399.948975 4.860000
406.505493 4.938125
413.280579 5.020000
420.285339 5.108750
427.531647 5.200000
435.032196 5.290000
442.800629 5.380000
450.851562 5.480000
459.200653 5.580000
467.864838 5.690000
476.862213 5.800000
486.212463 5.915000
495.936707 6.030000
506.057861 6.150000
516.600769 6.280000
527.592224 6.420000
539.061646 6.550000
551.040771 6.700000
563.564453 6.850000
576.670593 7.000000
590.400818 7.150000
604.800842 7.310000
619.920898 7.480000
635.816284 7.650000
652.548279 7.820000
670.184753 8.010000
688.800964 8.210000
708.481018 8.390000
729.318665 8.570000
751.419250 8.620000
774.901123 8.600000
799.897949 8.450000
826.561157 8.310000
855.063293 8.210000
885.601257 8.210000
================================================
FILE: Asset/SPD/metals/AlAs.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for cubic AlAs
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 4.470000
309.950012 4.920000
317.897003 5.350000
326.263000 5.390000
335.081024 4.990000
344.389008 4.720000
354.229004 4.480000
364.647003 4.300000
375.696991 4.130000
387.437988 3.930000
393.587006 0.000000
397.372009 0.000000
399.935028 0.000000
403.187012 0.000000
406.492004 0.000000
409.850983 0.000000
413.266998 0.000000
416.739990 0.000000
420.270996 0.000000
423.863007 0.000000
427.516998 0.000000
431.235016 0.000000
435.018036 0.000000
442.785980 3.703000
459.185028 3.570000
476.846008 3.472000
495.920013 3.394000
516.583008 3.329000
539.044006 3.273000
563.545044 3.225000
590.381042 3.183000
619.900024 3.145000
652.526001 3.112000
688.778015 3.082000
729.294006 3.056000
774.875000 3.032000
826.533020 3.010000
885.570984 2.990000
================================================
FILE: Asset/SPD/metals/AlAs.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for cubic AlAs
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 2.680000
309.950012 2.490000
317.897003 2.150000
326.263000 1.300000
335.081024 0.752000
344.389008 0.519000
354.229004 0.334000
364.647003 0.233000
375.696991 0.139000
387.437988 0.115000
393.587006 0.119000
397.372009 0.115000
399.935028 0.113000
403.187012 0.110000
406.492004 0.106000
409.850983 0.099800
413.266998 0.063800
416.739990 0.031500
420.270996 0.018900
423.863007 0.011800
427.516998 0.010500
431.235016 0.010300
435.018036 0.009930
442.785980 0.001610
459.185028 0.001560
476.846008 0.001530
495.920013 0.001250
516.583008 0.000682
539.044006 0.000275
563.545044 0.000040
590.381042 0.000002
619.900024 0.000000
652.526001 0.000000
688.778015 0.000000
729.294006 0.000000
774.875000 0.000000
826.533020 0.000000
885.570984 0.000000
================================================
FILE: Asset/SPD/metals/AlSb.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for cubic AlSb
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 3.150000
309.950012 3.500000
317.897003 3.710000
326.263000 3.810000
335.081024 3.930000
344.389008 3.960000
354.229004 3.950000
364.647003 3.970000
375.696991 4.140000
387.437988 4.510000
399.935028 4.570000
413.266998 4.520000
427.516998 4.660000
442.785980 5.270000
459.185028 5.080000
476.846008 4.810000
495.920013 4.610000
516.583008 4.440000
539.044006 4.310000
563.545044 4.200000
590.381042 4.010000
================================================
FILE: Asset/SPD/metals/AlSb.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for cubic AlSb
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 4.000000
309.950012 3.710000
317.897003 3.400000
326.263000 3.160000
335.081024 2.970000
344.389008 2.810000
354.229004 2.690000
364.647003 2.640000
375.696991 2.690000
387.437988 2.470000
399.935028 2.120000
413.266998 1.970000
427.516998 2.060000
442.785980 1.580000
459.185028 0.920000
476.846008 0.630000
495.920013 0.460000
516.583008 0.330000
539.044006 0.240000
563.545044 0.010000
590.381042 0.006000
================================================
FILE: Asset/SPD/metals/Au.eta.spd
================================================
298.757050 1.795000
302.400421 1.812000
306.133759 1.822625
309.960449 1.830000
313.884003 1.837125
317.908142 1.840000
322.036835 1.834250
326.274139 1.824000
330.624481 1.812000
335.092377 1.798000
339.682678 1.782000
344.400482 1.766000
349.251221 1.752500
354.240509 1.740000
359.374420 1.727625
364.659332 1.716000
370.102020 1.705875
375.709625 1.696000
381.489777 1.684750
387.450562 1.674000
393.600555 1.666000
399.948975 1.658000
406.505493 1.647250
413.280579 1.636000
420.285339 1.628000
427.531647 1.616000
435.032196 1.596250
442.800629 1.562000
450.851562 1.502125
459.200653 1.426000
467.864838 1.345875
476.862213 1.242000
486.212463 1.086750
495.936707 0.916000
506.057861 0.754500
516.600769 0.608000
527.592224 0.491750
539.061646 0.402000
551.040771 0.345500
563.564453 0.306000
576.670593 0.267625
590.400818 0.236000
604.800842 0.212375
619.920898 0.194000
635.816284 0.177750
652.548279 0.166000
670.184753 0.161000
688.800964 0.160000
708.481018 0.160875
729.318665 0.164000
751.419250 0.169500
774.901123 0.176000
799.897949 0.181375
826.561157 0.188000
855.063293 0.198125
885.601257 0.210000
================================================
FILE: Asset/SPD/metals/Au.k.spd
================================================
298.757050 1.920375
302.400421 1.920000
306.133759 1.918875
309.960449 1.916000
313.884003 1.911375
317.908142 1.904000
322.036835 1.891375
326.274139 1.878000
330.624481 1.868250
335.092377 1.860000
339.682678 1.851750
344.400482 1.846000
349.251221 1.845250
354.240509 1.848000
359.374420 1.852375
364.659332 1.862000
370.102020 1.883000
375.709625 1.906000
381.489777 1.922500
387.450562 1.936000
393.600555 1.947750
399.948975 1.956000
406.505493 1.959375
413.280579 1.958000
420.285339 1.951375
427.531647 1.940000
435.032196 1.924500
442.800629 1.904000
450.851562 1.875875
459.200653 1.846000
467.864838 1.814625
476.862213 1.796000
486.212463 1.797375
495.936707 1.840000
506.057861 1.956500
516.600769 2.120000
527.592224 2.326250
539.061646 2.540000
551.040771 2.730625
563.564453 2.880000
576.670593 2.940625
590.400818 2.970000
604.800842 3.015000
619.920898 3.060000
635.816284 3.070000
652.548279 3.150000
670.184753 3.445812
688.800964 3.800000
708.481018 4.087687
729.318665 4.357000
751.419250 4.610188
774.901123 4.860000
799.897949 5.125813
826.561157 5.390000
855.063293 5.631250
885.601257 5.880000
================================================
FILE: Asset/SPD/metals/Be.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for polycrystalline Be
# ;
# ; Concatenation of:
# ;
# ; Be_llnl_cxro + Be_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
310.000000 2.470000
326.300018 2.550000
344.399994 2.640000
364.600006 2.730000
387.399994 2.840000
413.300018 2.950000
442.800018 3.070000
476.800018 3.190000
516.600037 3.300000
563.500000 3.390000
619.900024 3.460000
688.799988 3.470000
774.900024 3.440000
885.600037 3.350000
================================================
FILE: Asset/SPD/metals/Be.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for polycrystalline Be
# ;
# ; Concatenation of:
# ;
# ; Be_llnl_cxro + Be_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
310.000000 3.080000
326.300018 3.080000
344.399994 3.080000
364.600006 3.100000
387.399994 3.120000
413.300018 3.140000
442.800018 3.160000
476.800018 3.160000
516.600037 3.180000
563.500000 3.170000
619.900024 3.180000
688.799988 3.230000
774.900024 3.350000
885.600037 3.550000
================================================
FILE: Asset/SPD/metals/Cr.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Cr
# ;
# ; Concatenation of:
# ;
# ; Cr_llnl_cxro + Cr_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
300.194000 0.980000
307.643005 1.020000
316.276001 1.060000
323.708008 1.120000
333.279999 1.180000
341.542999 1.260000
351.217987 1.330000
362.514984 1.390000
372.312012 1.430000
385.031006 1.440000
396.102020 1.480000
409.175018 1.540000
424.589020 1.650000
438.092010 1.800000
455.808990 1.990000
471.406982 2.220000
490.040009 2.490000
512.314026 2.750000
532.102966 2.980000
558.468018 3.180000
582.066040 3.340000
610.739014 3.480000
700.452026 3.840000
815.658020 4.230000
826.533020 4.270000
849.178040 4.310000
860.971985 4.330000
885.570984 4.380000
================================================
FILE: Asset/SPD/metals/Cr.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Cr
# ;
# ; Concatenation of:
# ;
# ; Cr_llnl_cxro + Cr_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
300.194000 2.670000
307.643005 2.760000
316.276001 2.850000
323.708008 2.950000
333.279999 3.040000
341.542999 3.120000
351.217987 3.180000
362.514984 3.240000
372.312012 3.310000
385.031006 3.400000
396.102020 3.540000
409.175018 3.710000
424.589020 3.890000
438.092010 4.060000
455.808990 4.220000
471.406982 4.360000
490.040009 4.440000
512.314026 4.460000
532.102966 4.450000
558.468018 4.410000
582.066040 4.380000
610.739014 4.360000
700.452026 4.370000
815.658020 4.340000
826.533020 4.330000
849.178040 4.320000
860.971985 4.320000
885.570984 4.310000
================================================
FILE: Asset/SPD/metals/CsI.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for CsI
# ;
# ; Concatenation of:
# ;
# ; CsI_llnl_cxro + CsI_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
304.993988 1.967310
309.950012 1.956510
314.989990 1.946580
319.947998 1.937410
324.980011 1.928930
329.997009 1.921060
334.990997 1.913730
339.951019 1.906900
344.963989 1.900510
350.028015 1.894530
354.937988 1.888910
359.988007 1.883630
364.968994 1.878660
369.979004 1.873970
375.014984 1.869540
379.957001 1.865350
385.031006 1.861380
389.997009 1.857620
394.967010 1.854040
399.935028 1.850640
409.987030 1.844330
419.985992 1.838590
430.037994 1.833360
439.957001 1.828570
450.018036 1.824170
460.037018 1.820120
469.977020 1.816370
479.985016 1.812910
490.040009 1.809700
499.919006 1.806720
509.996002 1.803930
520.049988 1.801340
530.056030 1.798910
539.983032 1.796640
550.044006 1.794510
559.981995 1.792500
570.023010 1.790620
579.888000 1.788840
590.100037 1.787170
600.097046 1.785590
619.900024 1.782680
640.062012 1.780060
659.819031 1.777700
680.088013 1.775570
700.056030 1.773630
719.976990 1.771860
740.179016 1.770250
760.147034 1.768770
779.747986 1.767410
799.871033 1.766150
819.974060 1.765000
839.973083 1.763920
859.778015 1.762930
879.915039 1.762010
899.709961 1.761150
================================================
FILE: Asset/SPD/metals/CsI.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for CsI
# ;
# ; Concatenation of:
# ;
# ; CsI_llnl_cxro + CsI_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
304.993988 0.000000
309.950012 0.000000
314.989990 0.000000
319.947998 0.000000
324.980011 0.000000
329.997009 0.000000
334.990997 0.000000
339.951019 0.000000
344.963989 0.000000
350.028015 0.000000
354.937988 0.000000
359.988007 0.000000
364.968994 0.000000
369.979004 0.000000
375.014984 0.000000
379.957001 0.000000
385.031006 0.000000
389.997009 0.000000
394.967010 0.000000
399.935028 0.000000
409.987030 0.000000
419.985992 0.000000
430.037994 0.000000
439.957001 0.000000
450.018036 0.000000
460.037018 0.000000
469.977020 0.000000
479.985016 0.000000
490.040009 0.000000
499.919006 0.000000
509.996002 0.000000
520.049988 0.000000
530.056030 0.000000
539.983032 0.000000
550.044006 0.000000
559.981995 0.000000
570.023010 0.000000
579.888000 0.000000
590.100037 0.000000
600.097046 0.000000
619.900024 0.000000
640.062012 0.000000
659.819031 0.000000
680.088013 0.000000
700.056030 0.000000
719.976990 0.000000
740.179016 0.000000
760.147034 0.000000
779.747986 0.000000
799.871033 0.000000
819.974060 0.000000
839.973083 0.000000
859.778015 0.000000
879.915039 0.000000
899.709961 0.000000
================================================
FILE: Asset/SPD/metals/Cu.eta.spd
================================================
298.757050 1.400313
302.400421 1.380000
306.133759 1.358438
309.960449 1.340000
313.884003 1.329063
317.908142 1.325000
322.036835 1.332500
326.274139 1.340000
330.624481 1.334375
335.092377 1.325000
339.682678 1.317812
344.400482 1.310000
349.251221 1.300313
354.240509 1.290000
359.374420 1.281563
364.659332 1.270000
370.102020 1.249062
375.709625 1.225000
381.489777 1.200000
387.450562 1.180000
393.600555 1.174375
399.948975 1.175000
406.505493 1.177500
413.280579 1.180000
420.285339 1.178125
427.531647 1.175000
435.032196 1.172812
442.800629 1.170000
450.851562 1.165312
459.200653 1.160000
467.864838 1.155312
476.862213 1.150000
486.212463 1.142812
495.936707 1.135000
506.057861 1.131562
516.600769 1.120000
527.592224 1.092437
539.061646 1.040000
551.040771 0.950375
563.564453 0.826000
576.670593 0.645875
590.400818 0.468000
604.800842 0.351250
619.920898 0.272000
635.816284 0.230813
652.548279 0.214000
670.184753 0.209250
688.800964 0.213000
708.481018 0.216250
729.318665 0.223000
751.419250 0.236500
774.901123 0.250000
799.897949 0.254188
826.561157 0.260000
855.063293 0.280000
885.601257 0.300000
================================================
FILE: Asset/SPD/metals/Cu.k.spd
================================================
298.757050 1.662125
302.400421 1.687000
306.133759 1.703313
309.960449 1.720000
313.884003 1.744563
317.908142 1.770000
322.036835 1.791625
326.274139 1.810000
330.624481 1.822125
335.092377 1.834000
339.682678 1.851750
344.400482 1.872000
349.251221 1.894250
354.240509 1.916000
359.374420 1.931688
364.659332 1.950000
370.102020 1.972438
375.709625 2.015000
381.489777 2.121562
387.450562 2.210000
393.600555 2.177188
399.948975 2.130000
406.505493 2.160063
413.280579 2.210000
420.285339 2.249938
427.531647 2.289000
435.032196 2.326000
442.800629 2.362000
450.851562 2.397625
459.200653 2.433000
467.864838 2.469187
476.862213 2.504000
486.212463 2.535875
495.936707 2.564000
506.057861 2.589625
516.600769 2.605000
527.592224 2.595562
539.061646 2.583000
551.040771 2.576500
563.564453 2.599000
576.670593 2.678062
590.400818 2.809000
604.800842 3.010750
619.920898 3.240000
635.816284 3.458187
652.548279 3.670000
670.184753 3.863125
688.800964 4.050000
708.481018 4.239563
729.318665 4.430000
751.419250 4.619563
774.901123 4.817000
799.897949 5.034125
826.561157 5.260000
855.063293 5.485625
885.601257 5.717000
================================================
FILE: Asset/SPD/metals/Cu2O.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Cu2O
# ;
# ; Concatenation of:
# ;
# ; Cu2O_llnl_cxro + Cu2O_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
350.028015 2.400000
399.935028 2.800000
449.854980 3.060000
499.919006 3.120000
549.799988 3.100000
599.806030 3.020000
649.789978 2.900000
700.056030 2.830000
750.029968 2.770000
799.871033 2.700000
849.759949 2.660000
899.709961 2.630000
================================================
FILE: Asset/SPD/metals/Cu2O.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Cu2O
# ;
# ; Concatenation of:
# ;
# ; Cu2O_llnl_cxro + Cu2O_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
350.028015 1.440000
399.935028 0.990000
449.854980 0.600000
499.919006 0.350000
549.799988 0.190000
599.806030 0.130000
649.789978 0.100000
700.056030 0.083000
750.029968 0.070000
799.871033 0.060000
849.759949 0.053000
899.709961 0.048000
================================================
FILE: Asset/SPD/metals/CuO.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for CuO
# ;
# ; Concatenation of:
# ;
# ; CuO_llnl_cxro + CuO_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
350.028015 2.240000
399.935028 2.340000
449.854980 2.450000
499.919006 2.540000
549.799988 2.580000
599.806030 2.650000
649.789978 2.720000
700.056030 2.880000
750.029968 2.970000
799.871033 2.940000
849.759949 2.810000
899.709961 2.740000
================================================
FILE: Asset/SPD/metals/CuO.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for CuO
# ;
# ; Concatenation of:
# ;
# ; CuO_llnl_cxro + CuO_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
350.028015 1.030000
399.935028 0.870000
449.854980 0.770000
499.919006 0.680000
549.799988 0.590000
599.806030 0.500000
649.789978 0.400000
700.056030 0.310000
750.029968 0.220000
799.871033 0.110000
849.759949 0.040000
899.709961 0.030000
================================================
FILE: Asset/SPD/metals/Hg.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Hg
# ;
# ; Concatenation of:
# ;
# ; Hg_llnl_cxro + Hg_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 0.542000
326.263000 0.589000
344.389008 0.644000
364.647003 0.713000
387.437988 0.798000
413.266998 0.898000
442.785980 1.027000
476.846008 1.186000
516.583008 1.384000
563.545044 1.620000
619.900024 1.910000
688.778015 2.284000
774.875000 2.746000
885.570984 3.324000
================================================
FILE: Asset/SPD/metals/Hg.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Hg
# ;
# ; Concatenation of:
# ;
# ; Hg_llnl_cxro + Hg_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.502000
326.263000 2.665000
344.389008 2.860000
364.647003 3.074000
387.437988 3.294000
413.266998 3.538000
442.785980 3.802000
476.846008 4.090000
516.583008 4.407000
563.545044 4.751000
619.900024 5.150000
688.778015 5.582000
774.875000 6.054000
885.570984 6.558000
================================================
FILE: Asset/SPD/metals/HgTe.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for HgTe
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
300.921997 2.481000
302.243011 2.480000
303.575012 2.479000
304.919006 2.478000
306.274994 2.476000
307.643005 2.475000
309.023010 2.474000
310.415985 2.473000
311.821014 2.471000
313.238983 2.470000
314.670013 2.470000
316.113983 2.469000
317.571991 2.468000
319.042999 2.468000
320.610016 2.467000
322.110016 2.467000
323.623016 2.467000
325.151001 2.467000
326.692993 2.467000
328.250000 2.466000
329.821991 2.467000
331.409027 2.467000
333.011017 2.467000
334.628998 2.467000
336.263000 2.468000
337.912018 2.469000
339.578003 2.470000
341.261017 2.470000
343.055023 2.472000
344.772003 2.473000
346.506012 2.474000
348.258026 2.476000
350.028015 2.478000
351.816010 2.480000
353.622009 2.481000
355.446991 2.484000
357.290985 2.487000
359.154022 2.489000
361.037018 2.492000
362.938995 2.495000
364.862030 2.499000
366.805023 2.502000
368.878021 2.506000
370.864990 2.510000
372.872009 2.515000
374.902008 2.520000
376.953003 2.525000
379.028015 2.530000
381.125000 2.536000
383.246002 2.542000
385.389984 2.548000
387.559021 2.555000
389.752014 2.563000
391.970001 2.570000
394.212982 2.578000
396.482025 2.587000
398.906006 2.596000
401.230011 2.606000
403.581024 2.616000
405.959015 2.627000
408.365997 2.639000
410.802002 2.651000
413.266998 2.664000
415.760986 2.678000
418.285980 2.694000
420.842010 2.710000
423.429016 2.727000
426.048004 2.746000
428.700012 2.768000
431.535004 2.790000
434.256012 2.816000
437.010986 2.844000
439.800995 2.874000
442.627991 2.908000
445.489990 2.945000
448.391022 2.983000
451.329010 3.020000
454.306000 3.056000
457.322021 3.088000
460.378998 3.115000
463.477020 3.138000
466.616028 3.159000
469.799042 3.175000
473.206024 3.190000
476.479980 3.203000
479.799042 3.214000
483.164032 3.223000
486.577972 3.231000
490.040009 3.239000
493.550995 3.245000
497.113007 3.252000
500.727020 3.259000
504.394012 3.265000
508.114990 3.272000
511.891022 3.279000
515.724060 3.287000
519.614014 3.294000
523.785034 3.303000
527.799011 3.313000
531.875000 3.324000
536.014038 3.335000
540.218018 3.349000
544.487976 3.364000
548.827026 3.382000
553.235046 3.402000
557.715027 3.425000
562.268005 3.454000
566.895020 3.488000
571.600037 3.532000
576.382996 3.586000
581.247009 3.650000
586.471008 3.719000
591.507996 3.785000
596.631042 3.838000
601.845032 3.876000
607.150024 3.901000
612.549011 3.917000
618.046021 3.925000
623.642029 3.929000
629.340027 3.929000
635.143005 3.924000
641.054993 3.919000
647.077026 3.911000
653.214050 3.903000
659.468018 3.892000
666.200989 3.882000
672.708008 3.870000
679.341980 3.860000
686.110046 3.848000
693.013000 3.837000
700.056030 3.826000
707.245056 3.815000
714.581970 3.805000
722.072998 3.795000
729.723022 3.786000
737.537048 3.776000
745.520020 3.767000
753.677979 3.756000
762.016052 3.747000
771.020020 3.738000
779.747986 3.729000
788.677002 3.719000
797.812012 3.711000
807.161011 3.702000
816.733032 3.691000
826.533020 3.685000
================================================
FILE: Asset/SPD/metals/HgTe.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for HgTe
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
300.921997 1.782000
302.243011 1.771000
303.575012 1.761000
304.919006 1.752000
306.274994 1.744000
307.643005 1.736000
309.023010 1.729000
310.415985 1.722000
311.821014 1.716000
313.238983 1.711000
314.670013 1.706000
316.113983 1.701000
317.571991 1.697000
319.042999 1.693000
320.610016 1.690000
322.110016 1.687000
323.623016 1.684000
325.151001 1.681000
326.692993 1.679000
328.250000 1.677000
329.821991 1.675000
331.409027 1.674000
333.011017 1.673000
334.628998 1.672000
336.263000 1.672000
337.912018 1.671000
339.578003 1.671000
341.261017 1.671000
343.055023 1.672000
344.772003 1.673000
346.506012 1.674000
348.258026 1.675000
350.028015 1.677000
351.816010 1.679000
353.622009 1.681000
355.446991 1.683000
357.290985 1.686000
359.154022 1.689000
361.037018 1.692000
362.938995 1.696000
364.862030 1.699000
366.805023 1.703000
368.878021 1.707000
370.864990 1.712000
372.872009 1.716000
374.902008 1.722000
376.953003 1.727000
379.028015 1.732000
381.125000 1.738000
383.246002 1.743000
385.389984 1.750000
387.559021 1.756000
389.752014 1.763000
391.970001 1.770000
394.212982 1.777000
396.482025 1.784000
398.906006 1.792000
401.230011 1.800000
403.581024 1.808000
405.959015 1.816000
408.365997 1.825000
410.802002 1.834000
413.266998 1.844000
415.760986 1.853000
418.285980 1.863000
420.842010 1.873000
423.429016 1.883000
426.048004 1.893000
428.700012 1.904000
431.535004 1.914000
434.256012 1.924000
437.010986 1.933000
439.800995 1.940000
442.627991 1.945000
445.489990 1.946000
448.391022 1.942000
451.329010 1.932000
454.306000 1.917000
457.322021 1.898000
460.378998 1.877000
463.477020 1.856000
466.616028 1.833000
469.799042 1.812000
473.206024 1.791000
476.479980 1.771000
479.799042 1.753000
483.164032 1.736000
486.577972 1.721000
490.040009 1.707000
493.550995 1.695000
497.113007 1.683000
500.727020 1.674000
504.394012 1.665000
508.114990 1.658000
511.891022 1.653000
515.724060 1.647000
519.614014 1.644000
523.785034 1.641000
527.799011 1.641000
531.875000 1.640000
536.014038 1.642000
540.218018 1.645000
544.487976 1.649000
548.827026 1.653000
553.235046 1.660000
557.715027 1.668000
562.268005 1.677000
566.895020 1.687000
571.600037 1.696000
576.382996 1.700000
581.247009 1.694000
586.471008 1.670000
591.507996 1.626000
596.631042 1.569000
601.845032 1.507000
607.150024 1.443000
612.549011 1.382000
618.046021 1.325000
623.642029 1.272000
629.340027 1.222000
635.143005 1.176000
641.054993 1.134000
647.077026 1.094000
653.214050 1.058000
659.468018 1.024000
666.200989 0.992300
672.708008 0.964200
679.341980 0.935800
686.110046 0.910700
693.013000 0.886300
700.056030 0.863300
707.245056 0.841900
714.581970 0.822600
722.072998 0.802400
729.723022 0.782800
737.537048 0.764400
745.520020 0.747400
753.677979 0.735100
762.016052 0.722500
771.020020 0.709700
779.747986 0.695700
788.677002 0.686400
797.812012 0.671600
807.161011 0.660000
816.733032 0.655200
826.533020 0.638200
================================================
FILE: Asset/SPD/metals/Ir.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Ir
# ;
# ; Concatenation of:
# ;
# ; Ir_llnl_cxro + Ir_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 1.620000
309.950012 1.640000
317.897003 1.640000
326.263000 1.610000
335.081024 1.570000
344.389008 1.520000
354.229004 1.500000
364.647003 1.530000
375.696991 1.570000
387.437988 1.620000
399.935028 1.680000
413.266998 1.730000
427.516998 1.770000
442.785980 1.810000
459.185028 1.850000
476.846008 1.910000
495.920013 1.980000
516.583008 2.070000
539.044006 2.180000
563.545044 2.290000
590.381042 2.400000
619.900024 2.500000
652.526001 2.570000
688.778015 2.640000
729.294006 2.690000
774.875000 2.680000
826.533020 2.650000
885.570984 2.720000
================================================
FILE: Asset/SPD/metals/Ir.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Ir
# ;
# ; Concatenation of:
# ;
# ; Ir_llnl_cxro + Ir_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 2.700000
309.950012 2.680000
317.897003 2.670000
326.263000 2.690000
335.081024 2.720000
344.389008 2.810000
354.229004 2.930000
364.647003 3.050000
375.696991 3.150000
387.437988 3.260000
399.935028 3.350000
413.266998 3.430000
427.516998 3.510000
442.785980 3.610000
459.185028 3.730000
476.846008 3.860000
495.920013 4.000000
516.583008 4.140000
539.044006 4.260000
563.545044 4.380000
590.381042 4.480000
619.900024 4.570000
652.526001 4.680000
688.778015 4.810000
729.294006 4.920000
774.875000 5.080000
826.533020 5.390000
885.570984 5.740000
================================================
FILE: Asset/SPD/metals/K.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for polycrystalline K
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
304.993988 0.380000
309.950012 0.340000
312.291992 0.287000
334.178009 0.089000
364.647003 0.052000
405.162994 0.041000
420.270996 0.041000
439.645020 0.043000
469.621002 0.043000
506.041016 0.046000
546.166992 0.049000
598.937012 0.053000
662.995056 0.050000
751.393982 0.044000
860.971985 0.040000
================================================
FILE: Asset/SPD/metals/K.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for polycrystalline K
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
304.993988 0.070000
309.950012 0.080000
312.291992 0.091000
334.178009 0.288000
364.647003 0.549000
405.162994 0.799000
420.270996 0.898000
439.645020 1.020000
469.621002 1.140000
506.041016 1.280000
546.166992 1.430000
598.937012 1.620000
662.995056 1.840000
751.393982 2.190000
860.971985 2.560000
================================================
FILE: Asset/SPD/metals/KBr.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for cubic KBr
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
310.027008 1.638860
320.031006 1.630710
329.997009 1.623570
339.951019 1.617270
350.028015 1.611670
359.988007 1.606680
369.979004 1.602200
379.957001 1.598160
389.997009 1.594500
399.935028 1.591170
419.985992 1.585370
439.957001 1.580480
460.037018 1.576320
479.985016 1.572740
499.919006 1.569640
520.049988 1.566940
539.983032 1.564560
559.981995 1.562470
579.888000 1.560600
600.097046 1.558940
619.900024 1.557440
640.062012 1.556100
659.819031 1.554880
680.088013 1.553780
700.056030 1.552780
719.976990 1.551860
740.179016 1.551020
760.147034 1.550250
779.747986 1.549540
799.871033 1.548880
819.974060 1.548280
839.973083 1.547720
859.778015 1.547200
879.915039 1.546710
899.709961 1.546260
================================================
FILE: Asset/SPD/metals/KBr.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for cubic KBr
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
310.027008 0.000000
320.031006 0.000000
329.997009 0.000000
339.951019 0.000000
350.028015 0.000000
359.988007 0.000000
369.979004 0.000000
379.957001 0.000000
389.997009 0.000000
399.935028 0.000000
419.985992 0.000000
439.957001 0.000000
460.037018 0.000000
479.985016 0.000000
499.919006 0.000000
520.049988 0.000000
539.983032 0.000000
559.981995 0.000000
579.888000 0.000000
600.097046 0.000000
619.900024 0.000000
640.062012 0.000000
659.819031 0.000000
680.088013 0.000000
700.056030 0.000000
719.976990 0.000000
740.179016 0.000000
760.147034 0.000000
779.747986 0.000000
799.871033 0.000000
819.974060 0.000000
839.973083 0.000000
859.778015 0.000000
879.915039 0.000000
899.709961 0.000000
================================================
FILE: Asset/SPD/metals/KCl.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for KCl
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
310.027008 1.540050
320.031006 1.535180
329.997009 1.530870
339.951019 1.527030
350.028015 1.523580
359.988007 1.520490
369.979004 1.517690
379.957001 1.515150
389.997009 1.512830
399.935028 1.510720
419.985992 1.507010
439.957001 1.503860
460.037018 1.501150
479.985016 1.498820
499.919006 1.496790
520.049988 1.495010
539.983032 1.493440
559.981995 1.492050
579.888000 1.490810
600.097046 1.489690
619.900024 1.488690
640.062012 1.487790
659.819031 1.486970
680.088013 1.486230
700.056030 1.485550
719.976990 1.484930
740.179016 1.484360
760.147034 1.483840
779.747986 1.483360
799.871033 1.482910
819.974060 1.482500
839.973083 1.482120
859.778015 1.481760
879.915039 1.481430
899.709961 1.481110
================================================
FILE: Asset/SPD/metals/KCl.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for KCl
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
310.027008 0.000000
320.031006 0.000000
329.997009 0.000000
339.951019 0.000000
350.028015 0.000000
359.988007 0.000000
369.979004 0.000000
379.957001 0.000000
389.997009 0.000000
399.935028 0.000000
419.985992 0.000000
439.957001 0.000000
460.037018 0.000000
479.985016 0.000000
499.919006 0.000000
520.049988 0.000000
539.983032 0.000000
559.981995 0.000000
579.888000 0.000000
600.097046 0.000000
619.900024 0.000000
640.062012 0.000000
659.819031 0.000000
680.088013 0.000000
700.056030 0.000000
719.976990 0.000000
740.179016 0.000000
760.147034 0.000000
779.747986 0.000000
799.871033 0.000000
819.974060 0.000000
839.973083 0.000000
859.778015 0.000000
879.915039 0.000000
899.709961 0.000000
================================================
FILE: Asset/SPD/metals/Li.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Li
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
306.123016 0.346000
330.613007 0.345000
359.362030 0.334000
393.587006 0.304000
435.018036 0.247000
486.196014 0.217000
551.022034 0.206000
635.795044 0.221000
751.393982 0.265000
================================================
FILE: Asset/SPD/metals/Li.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Li
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
306.123016 1.210000
330.613007 1.320000
359.362030 1.450000
393.587006 1.600000
435.018036 1.820000
486.196014 2.110000
551.022034 2.480000
635.795044 2.940000
751.393982 3.550000
================================================
FILE: Asset/SPD/metals/MgO.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for MgO
# ;
# ; Concatenation of:
# ;
# ; MgO_llnl_cxro + MgO_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.798000
330.613007 1.785000
351.118988 1.776800
355.549011 1.775500
360.932007 1.773200
361.141998 1.773180
364.968994 1.771860
382.065002 1.766800
386.712006 1.765500
393.337982 1.763800
404.634003 1.761040
430.935028 1.755700
435.781982 1.754710
457.829010 1.751200
477.949036 1.748300
486.004974 1.747110
487.918030 1.746900
499.919006 1.745400
502.350006 1.745300
508.531982 1.744460
514.440002 1.743900
546.166992 1.740770
589.258972 1.737370
632.874023 1.734600
643.718018 1.734000
656.325989 1.733350
667.635986 1.732770
690.695984 1.731910
706.439026 1.731010
767.677979 1.728720
================================================
FILE: Asset/SPD/metals/MgO.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for MgO
# ;
# ; Concatenation of:
# ;
# ; MgO_llnl_cxro + MgO_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 0.000000
330.613007 0.000000
351.118988 0.000000
355.549011 0.000001
360.932007 0.000001
361.141998 0.000001
364.968994 0.000000
382.065002 0.000000
386.712006 0.000000
393.337982 0.000000
404.634003 0.000000
430.935028 0.000000
435.781982 0.000000
457.829010 0.000000
477.949036 0.000000
486.004974 0.000000
487.918030 0.000000
499.919006 0.000000
502.350006 0.000000
508.531982 0.000000
514.440002 0.000000
546.166992 0.000000
589.258972 0.000000
632.874023 0.000000
643.718018 0.000000
656.325989 0.000000
667.635986 0.000000
690.695984 0.000000
706.439026 0.000000
767.677979 0.000000
================================================
FILE: Asset/SPD/metals/Mo.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for
# ;
# ; Concatenation of:
# ;
# ; Mo_llnl_cxro + Mo_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 2.910000
309.950012 3.010000
317.897003 3.040000
326.263000 3.040000
335.081024 3.040000
344.389008 3.050000
354.229004 3.060000
364.647003 3.060000
375.696991 3.060000
387.437988 3.050000
399.935028 3.030000
413.266998 3.040000
427.516998 3.050000
442.785980 3.080000
459.185028 3.130000
476.846008 3.220000
495.920013 3.360000
516.583008 3.590000
539.044006 3.790000
563.545044 3.760000
590.381042 3.680000
619.900024 3.680000
652.526001 3.740000
688.778015 3.810000
729.294006 3.840000
774.875000 3.770000
826.533020 3.530000
885.570984 3.150000
================================================
FILE: Asset/SPD/metals/Mo.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for
# ;
# ; Concatenation of:
# ;
# ; Mo_llnl_cxro + Mo_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 3.670000
309.950012 3.510000
317.897003 3.400000
326.263000 3.310000
335.081024 3.270000
344.389008 3.240000
354.229004 3.210000
364.647003 3.190000
375.696991 3.180000
387.437988 3.180000
399.935028 3.220000
413.266998 3.270000
427.516998 3.330000
442.785980 3.420000
459.185028 3.510000
476.846008 3.610000
495.920013 3.730000
516.583008 3.780000
539.044006 3.610000
563.545044 3.410000
590.381042 3.450000
619.900024 3.520000
652.526001 3.580000
688.778015 3.580000
729.294006 3.510000
774.875000 3.410000
826.533020 3.300000
885.570984 3.400000
================================================
FILE: Asset/SPD/metals/NaCl.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for NaCl
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
319.947998 1.595060
339.951019 1.585900
359.988007 1.578520
379.957001 1.572480
399.935028 1.567460
419.985992 1.563240
439.957001 1.559650
460.037018 1.556570
479.985016 1.553900
499.919006 1.551570
520.049988 1.549530
539.983032 1.547730
559.981995 1.546130
579.888000 1.544710
600.097046 1.543430
619.900024 1.542280
640.062012 1.541240
659.819031 1.540300
680.088013 1.539440
700.056030 1.538650
719.976990 1.537940
740.179016 1.537280
760.147034 1.536670
779.747986 1.536110
799.871033 1.535600
819.974060 1.535120
839.973083 1.534670
859.778015 1.534260
879.915039 1.533870
899.709961 1.533510
================================================
FILE: Asset/SPD/metals/NaCl.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for NaCl
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
319.947998 0.000000
339.951019 0.000000
359.988007 0.000000
379.957001 0.000000
399.935028 0.000000
419.985992 0.000000
439.957001 0.000000
460.037018 0.000000
479.985016 0.000000
499.919006 0.000000
520.049988 0.000000
539.983032 0.000000
559.981995 0.000000
579.888000 0.000000
600.097046 0.000000
619.900024 0.000000
640.062012 0.000000
659.819031 0.000000
680.088013 0.000000
700.056030 0.000000
719.976990 0.000000
740.179016 0.000000
760.147034 0.000000
779.747986 0.000000
799.871033 0.000000
819.974060 0.000000
839.973083 0.000000
859.778015 0.000000
879.915039 0.000000
899.709961 0.000000
================================================
FILE: Asset/SPD/metals/Nb.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Nb
# ;
# ; Concatenation of:
# ;
# ; Nb_llnl_cxro + Nb_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.640000
317.897003 2.620000
326.263000 2.590000
335.081024 2.560000
344.389008 2.520000
354.229004 2.480000
364.647003 2.460000
375.696991 2.440000
387.437988 2.450000
399.935028 2.480000
413.266998 2.510000
435.018036 2.580000
450.835999 2.660000
467.849030 2.740000
486.196014 2.830000
506.041016 2.890000
527.575012 2.920000
551.022034 2.930000
576.651001 2.920000
604.781006 2.890000
635.795044 2.820000
670.162048 2.690000
708.456970 2.540000
751.393982 2.360000
799.871033 2.150000
855.033997 1.950000
================================================
FILE: Asset/SPD/metals/Nb.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Nb
# ;
# ; Concatenation of:
# ;
# ; Nb_llnl_cxro + Nb_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.330000
317.897003 2.290000
326.263000 2.280000
335.081024 2.270000
344.389008 2.290000
354.229004 2.330000
364.647003 2.380000
375.696991 2.450000
387.437988 2.530000
399.935028 2.600000
413.266998 2.680000
435.018036 2.800000
450.835999 2.860000
467.849030 2.900000
486.196014 2.920000
506.041016 2.900000
527.575012 2.880000
551.022034 2.870000
576.651001 2.870000
604.781006 2.870000
635.795044 2.860000
670.162048 2.890000
708.456970 2.990000
751.393982 3.130000
799.871033 3.370000
855.033997 3.680000
================================================
FILE: Asset/SPD/metals/Rh.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Rh
# ;
# ; Concatenation of:
# ;
# ; Rh_llnl_cxro + Rh_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 0.840000
309.950012 0.860000
317.897003 0.880000
326.263000 0.910000
335.081024 0.950000
344.389008 0.990000
354.229004 1.040000
364.647003 1.110000
375.696991 1.200000
387.437988 1.300000
399.935028 1.410000
413.266998 1.530000
427.516998 1.630000
459.185028 1.800000
476.846008 1.850000
495.920013 1.880000
516.583008 1.900000
539.044006 1.940000
563.545044 2.000000
590.381042 2.050000
619.900024 2.120000
652.526001 2.200000
688.778015 2.300000
729.294006 2.420000
774.875000 2.600000
826.533020 2.780000
885.570984 3.010000
================================================
FILE: Asset/SPD/metals/Rh.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Rh
# ;
# ; Concatenation of:
# ;
# ; Rh_llnl_cxro + Rh_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 3.030000
309.950012 3.120000
317.897003 3.230000
326.263000 3.340000
335.081024 3.450000
344.389008 3.580000
354.229004 3.710000
364.647003 3.840000
375.696991 3.970000
387.437988 4.090000
399.935028 4.200000
413.266998 4.290000
427.516998 4.360000
459.185028 4.490000
476.846008 4.550000
495.920013 4.650000
516.583008 4.780000
539.044006 4.940000
563.545044 5.110000
590.381042 5.300000
619.900024 5.510000
652.526001 5.760000
688.778015 6.020000
729.294006 6.330000
774.875000 6.640000
826.533020 6.970000
885.570984 7.310000
================================================
FILE: Asset/SPD/metals/Se-e.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Se, extraordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
344.389008 3.390000
364.647003 3.690000
387.437988 3.920000
413.266998 4.440000
442.785980 4.590000
476.846008 4.400000
516.583008 4.280000
563.545044 4.490000
619.900024 4.790000
688.778015 4.460000
================================================
FILE: Asset/SPD/metals/Se-e.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Se, extraordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
344.389008 3.010000
364.647003 2.760000
387.437988 2.590000
413.266998 2.290000
442.785980 1.700000
476.846008 1.320000
516.583008 1.210000
563.545044 1.190000
619.900024 0.760000
688.778015 0.022000
================================================
FILE: Asset/SPD/metals/Se.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Se, ordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.670000
326.263000 2.840000
344.389008 3.060000
364.647003 3.220000
387.437988 3.350000
413.266998 3.300000
442.785980 3.120000
476.846008 3.000000
516.583008 2.930000
563.545044 3.070000
619.900024 3.380000
688.778015 3.320000
================================================
FILE: Asset/SPD/metals/Se.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Se, ordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.990000
326.263000 1.660000
344.389008 1.470000
364.647003 1.240000
387.437988 1.010000
413.266998 0.700000
442.785980 0.580000
476.846008 0.530000
516.583008 0.610000
563.545044 0.730000
619.900024 0.650000
688.778015 0.110000
================================================
FILE: Asset/SPD/metals/SiC.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for crystalline SiC
# ;
# ; Concatenation of:
# ;
# ; SiC_llnl_cxro + SiC_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.850000
317.897003 2.923000
326.263000 2.899000
335.081024 2.877000
344.389008 2.856000
354.229004 2.836000
364.647003 2.817000
375.696991 2.799000
387.437988 2.781000
399.935028 2.765000
413.266998 2.750000
435.781982 2.730500
466.968018 2.707400
495.920013 2.684000
497.912018 2.687000
515.080994 2.678900
546.166992 2.663100
567.934021 2.655700
577.995056 2.651100
588.979004 2.648800
589.539001 2.647500
615.897034 2.641100
619.900024 2.634000
656.325989 2.629600
691.080994 2.624300
826.533020 2.598000
================================================
FILE: Asset/SPD/metals/SiC.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for crystalline SiC
# ;
# ; Concatenation of:
# ;
# ; SiC_llnl_cxro + SiC_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 0.174000
317.897003 0.007650
326.263000 0.005980
335.081024 0.004930
344.389008 0.003750
354.229004 0.002890
364.647003 0.002040
375.696991 0.001380
387.437988 0.000839
399.935028 0.000191
413.266998 0.000044
435.781982 0.000000
466.968018 0.000000
495.920013 0.000012
497.912018 0.000000
515.080994 0.000000
546.166992 0.000000
567.934021 0.000000
577.995056 0.000000
588.979004 0.000000
589.539001 0.000000
615.897034 0.000000
619.900024 0.000000
656.325989 0.000000
691.080994 0.000000
826.533020 0.000000
================================================
FILE: Asset/SPD/metals/SiO.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for SiO
# ;
# ; Concatenation of:
# ;
# ; SiO_llnl_cxro + SiO_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.141000
326.263000 2.157000
344.389008 2.162000
364.647003 2.160000
387.437988 2.144000
413.266998 2.116000
442.785980 2.085000
476.846008 2.053000
516.583008 2.021000
563.545044 1.994000
619.900024 1.969000
688.778015 1.948000
774.875000 1.929000
885.570984 1.913000
================================================
FILE: Asset/SPD/metals/SiO.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for SiO
# ;
# ; Concatenation of:
# ;
# ; SiO_llnl_cxro + SiO_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 0.400600
326.263000 0.345300
344.389008 0.287200
364.647003 0.228700
387.437988 0.170600
413.266998 0.121100
442.785980 0.083740
476.846008 0.055440
516.583008 0.035330
563.545044 0.021530
619.900024 0.011750
688.778015 0.005230
774.875000 0.001510
885.570984 0.000000
================================================
FILE: Asset/SPD/metals/SnTe.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for SnTe
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
311.586029 0.967000
332.118988 1.007000
361.037018 1.103000
390.242004 1.228000
414.372040 1.364000
453.308990 1.551000
498.312012 1.702000
533.476990 1.813000
548.099060 1.878000
550.533020 1.989000
552.987976 2.135000
558.216980 2.442000
566.119019 2.719000
582.339050 2.991000
605.963013 3.273000
621.454041 3.479000
648.091980 3.701000
681.208984 3.912000
748.671021 4.285000
804.020996 4.541000
867.478027 4.803000
================================================
FILE: Asset/SPD/metals/SnTe.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for SnTe
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
311.586029 0.000000
332.118988 0.000000
361.037018 0.000000
390.242004 0.000000
414.372040 0.000000
453.308990 0.000000
498.312012 0.000000
533.476990 0.000000
548.099060 0.000000
550.533020 0.000000
552.987976 0.000000
558.216980 0.000000
566.119019 0.000000
582.339050 0.000000
605.963013 0.000000
621.454041 0.000000
648.091980 0.000000
681.208984 0.000000
748.671021 0.000000
804.020996 0.000000
867.478027 0.000000
================================================
FILE: Asset/SPD/metals/Ta.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Ta
# ;
# ; Concatenation of:
# ;
# ; Ta_llnl_cxro + Ta_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.360000
326.263000 2.400000
344.389008 2.490000
364.647003 2.610000
387.437988 2.730000
413.266998 2.810000
427.516998 2.840000
442.785980 2.850000
459.185028 2.840000
476.846008 2.800000
495.920013 2.750000
516.583008 2.680000
539.044006 2.560000
563.545044 2.360000
590.381042 2.100000
619.900024 1.830000
652.526001 1.570000
688.778015 1.350000
729.294006 1.240000
774.875000 1.150000
826.533020 1.090000
885.570984 1.040000
================================================
FILE: Asset/SPD/metals/Ta.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for Ta
# ;
# ; Concatenation of:
# ;
# ; Ta_llnl_cxro + Ta_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.140000
326.263000 2.220000
344.389008 2.300000
364.647003 2.330000
387.437988 2.310000
413.266998 2.240000
427.516998 2.200000
442.785980 2.140000
459.185028 2.080000
476.846008 2.020000
495.920013 1.980000
516.583008 1.920000
539.044006 1.860000
563.545044 1.810000
590.381042 1.840000
619.900024 1.990000
652.526001 2.240000
688.778015 2.600000
729.294006 2.950000
774.875000 3.330000
826.533020 3.730000
885.570984 4.150000
================================================
FILE: Asset/SPD/metals/Te-e.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for trigonal Te, extraordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.330000
330.613007 1.440000
354.229004 1.690000
381.477020 1.920000
403.975006 2.220000
413.266998 2.300000
416.599030 2.350000
430.037994 2.540000
442.785980 2.730000
444.373016 2.760000
459.696014 2.980000
476.114014 3.210000
476.846008 3.250000
489.266022 3.460000
498.512024 3.630000
507.906982 3.810000
516.583008 3.940000
517.877991 3.990000
528.024048 4.200000
538.809021 4.390000
549.799988 4.650000
561.249023 4.910000
563.545044 4.940000
573.450989 5.170000
599.226990 5.760000
612.851990 6.000000
619.900024 4.670000
627.429016 6.210000
642.382996 6.400000
658.416992 6.580000
674.904968 6.770000
688.778015 6.890000
692.625977 6.850000
710.895020 6.860000
730.583008 6.800000
750.939026 6.780000
772.943054 6.740000
774.875000 6.750000
796.275024 6.730000
820.516052 6.810000
846.858032 6.950000
874.330017 7.140000
885.570984 7.110000
================================================
FILE: Asset/SPD/metals/Te-e.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for trigonal Te, extraordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.640000
330.613007 3.060000
354.229004 3.440000
381.477020 3.780000
403.975006 3.960000
413.266998 4.160000
416.599030 4.150000
430.037994 4.270000
442.785980 4.420000
444.373016 4.390000
459.696014 4.520000
476.114014 4.710000
476.846008 4.770000
489.266022 4.850000
498.512024 4.930000
507.906982 5.010000
516.583008 5.080000
517.877991 5.080000
528.024048 5.160000
538.809021 5.200000
549.799988 5.210000
561.249023 5.200000
563.545044 5.160000
573.450989 5.160000
599.226990 4.920000
612.851990 4.770000
619.900024 4.670000
627.429016 4.600000
642.382996 4.360000
658.416992 4.100000
674.904968 3.860000
688.778015 3.700000
692.625977 3.650000
710.895020 3.470000
730.583008 3.180000
750.939026 3.030000
772.943054 2.930000
774.875000 2.910000
796.275024 2.890000
820.516052 2.860000
846.858032 2.800000
874.330017 2.560000
885.570984 2.460000
================================================
FILE: Asset/SPD/metals/Te.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for trigonal Te,ordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.320000
330.613007 1.500000
354.229004 1.720000
381.477020 2.020000
403.975006 2.370000
413.266998 2.510000
416.599030 2.560000
430.037994 2.770000
442.785980 3.030000
444.373016 3.010000
459.696014 3.270000
476.114014 3.550000
476.846008 3.570000
489.266022 3.760000
498.512024 3.910000
507.906982 4.070000
516.583008 4.240000
517.877991 4.250000
528.024048 4.430000
538.809021 4.620000
549.799988 4.810000
561.249023 5.010000
563.545044 5.100000
573.450989 5.260000
599.226990 5.670000
612.851990 5.820000
619.900024 5.940000
627.429016 5.970000
642.382996 6.070000
658.416992 6.110000
674.904968 6.120000
688.778015 6.100000
692.625977 6.090000
710.895020 6.040000
730.583008 5.950000
750.939026 5.870000
772.943054 5.860000
774.875000 5.880000
796.275024 5.840000
820.516052 5.780000
846.858032 5.680000
874.330017 5.590000
885.570984 5.560000
================================================
FILE: Asset/SPD/metals/Te.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for trigonal Te,ordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.010000
330.613007 2.370000
354.229004 2.700000
381.477020 3.030000
403.975006 3.290000
413.266998 3.390000
416.599030 3.390000
430.037994 3.470000
442.785980 3.630000
444.373016 3.570000
459.696014 3.660000
476.114014 3.720000
476.846008 3.750000
489.266022 3.760000
498.512024 3.770000
507.906982 3.770000
516.583008 3.770000
517.877991 3.780000
528.024048 3.760000
538.809021 3.690000
549.799988 3.630000
561.249023 3.570000
563.545044 3.610000
573.450989 3.520000
599.226990 3.160000
612.851990 2.940000
619.900024 2.690000
627.429016 2.700000
642.382996 2.450000
658.416992 2.250000
674.904968 2.020000
688.778015 1.800000
692.625977 1.720000
710.895020 1.520000
730.583008 1.360000
750.939026 1.260000
772.943054 1.170000
774.875000 1.150000
796.275024 1.060000
820.516052 0.895000
846.858032 0.760000
874.330017 0.659000
885.570984 0.630000
================================================
FILE: Asset/SPD/metals/ThF4.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for polycrystalline ThF4
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.545000
319.947998 1.542000
329.997009 1.540000
340.044006 1.538000
349.929016 1.536000
359.988007 1.534000
369.979004 1.532000
379.957001 1.531000
389.997009 1.530000
399.935028 1.529000
409.987030 1.528000
419.985992 1.527000
430.037994 1.526000
435.781982 1.533000
439.957001 1.526000
450.018036 1.525000
460.037018 1.524000
469.977020 1.524000
479.985016 1.523000
490.040009 1.523000
499.919006 1.523000
509.996002 1.522000
520.049988 1.522000
539.983032 1.521000
545.927002 1.521000
559.981995 1.521000
579.888000 1.520000
600.097046 1.520000
619.900024 1.520000
640.062012 1.519000
659.819031 1.519000
700.056030 1.519000
739.737000 1.518000
779.747986 1.518000
799.871033 1.518000
================================================
FILE: Asset/SPD/metals/ThF4.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for polycrystalline ThF4
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids II', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1991.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 0.000000
319.947998 0.000000
329.997009 0.000000
340.044006 0.000000
349.929016 0.000000
359.988007 0.000000
369.979004 0.000000
379.957001 0.000000
389.997009 0.000000
399.935028 0.000000
409.987030 0.000000
419.985992 0.000000
430.037994 0.000000
435.781982 0.000000
439.957001 0.000000
450.018036 0.000000
460.037018 0.000000
469.977020 0.000000
479.985016 0.000000
490.040009 0.000000
499.919006 0.000000
509.996002 0.000000
520.049988 0.000000
539.983032 0.000000
545.927002 0.000000
559.981995 0.000000
579.888000 0.000000
600.097046 0.000000
619.900024 0.000000
640.062012 0.000000
659.819031 0.000000
700.056030 0.000000
739.737000 0.000000
779.747986 0.000000
799.871033 0.000000
================================================
FILE: Asset/SPD/metals/TiC.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for TiC
# ;
# ; Concatenation of:
# ;
# ; TiC_llnl_cxro + TiC_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.300000
354.229004 2.570000
413.266998 2.780000
495.920013 2.950000
619.900024 3.050000
826.533020 3.510000
================================================
FILE: Asset/SPD/metals/TiC.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for TiC
# ;
# ; Concatenation of:
# ;
# ; TiC_llnl_cxro + TiC_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.330000
354.229004 2.340000
413.266998 2.430000
495.920013 2.380000
619.900024 2.670000
826.533020 3.070000
================================================
FILE: Asset/SPD/metals/TiN.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for TiN
# ;
# ; Concatenation of:
# ;
# ; TiN_llnl_cxro + TiN_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.270000
354.229004 2.140000
413.266998 1.740000
495.920013 1.200000
619.900024 1.320000
826.533020 1.820000
================================================
FILE: Asset/SPD/metals/TiN.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for TiN
# ;
# ; Concatenation of:
# ;
# ; TiN_llnl_cxro + TiN_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.230000
354.229004 1.060000
413.266998 1.040000
495.920013 1.650000
619.900024 2.690000
826.533020 3.810000
================================================
FILE: Asset/SPD/metals/TiO2-e.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for tetragonal TiO2, extraordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
307.033020 3.420000
317.979004 4.000000
327.037994 3.870000
344.007019 4.300000
358.013000 3.380000
388.044006 2.880000
399.935028 3.000000
402.010010 3.000000
419.985992 2.910000
439.957001 2.840000
460.037018 2.790000
479.985016 2.750000
499.919006 2.710000
520.049988 2.680000
539.983032 2.660000
559.981995 2.640000
579.888000 2.620000
600.097046 2.600000
619.900024 2.590000
640.062012 2.580000
659.819031 2.570000
680.088013 2.560000
700.056030 2.550000
719.976990 2.540000
740.179016 2.540000
760.147034 2.530000
779.747986 2.520000
799.871033 2.520000
819.974060 2.520000
839.973083 2.510000
859.778015 2.510000
879.915039 2.500000
899.709961 2.500000
================================================
FILE: Asset/SPD/metals/TiO2-e.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for tetragonal TiO2, extraordinary ray
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
307.033020 1.610000
317.979004 1.790000
327.037994 0.810000
344.007019 0.000000
358.013000 0.117000
388.044006 0.000000
399.935028 0.000000
402.010010 0.008000
419.985992 0.000000
439.957001 0.000000
460.037018 0.000000
479.985016 0.000000
499.919006 0.000000
520.049988 0.000000
539.983032 0.000000
559.981995 0.000000
579.888000 0.000000
600.097046 0.000000
619.900024 0.000000
640.062012 0.000000
659.819031 0.000000
680.088013 0.000000
700.056030 0.000000
719.976990 0.000000
740.179016 0.000000
760.147034 0.000000
779.747986 0.000000
799.871033 0.000000
819.974060 0.000000
839.973083 0.000000
859.778015 0.000000
879.915039 0.000000
899.709961 0.000000
================================================
FILE: Asset/SPD/metals/TiO2.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for tetragonal TiO2, ordinary ray
# ;
# ; Concatenation of:
# ;
# ; TiO2_llnl_cxro + TiO2_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
305.972015 3.840000
317.979004 5.380000
334.990997 4.220000
344.007019 4.360000
359.988007 3.870000
388.044006 3.490000
399.935028 3.400000
412.031006 3.240000
419.985992 3.290000
439.957001 3.200000
460.037018 3.130000
479.985016 3.080000
499.919006 3.030000
520.049988 3.000000
539.044006 2.950000
539.983032 2.970000
559.981995 2.940000
579.888000 2.920000
600.097046 2.900000
619.900024 2.880000
640.062012 2.870000
659.819031 2.850000
680.088013 2.840000
700.056030 2.830000
719.976990 2.820000
740.179016 2.810000
760.147034 2.810000
779.747986 2.800000
799.871033 2.790000
819.974060 2.790000
839.973083 2.780000
859.778015 2.780000
879.915039 2.770000
899.709961 2.770000
================================================
FILE: Asset/SPD/metals/TiO2.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for tetragonal TiO2, ordinary ray
# ;
# ; Concatenation of:
# ;
# ; TiO2_llnl_cxro + TiO2_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
305.972015 1.950000
317.979004 2.180000
334.990997 0.788000
344.007019 0.000000
359.988007 0.251000
388.044006 0.000000
399.935028 0.000000
412.031006 0.022000
419.985992 0.000000
439.957001 0.000000
460.037018 0.000000
479.985016 0.000000
499.919006 0.000000
520.049988 0.000000
539.044006 0.000000
539.983032 0.000000
559.981995 0.000000
579.888000 0.000000
600.097046 0.000000
619.900024 0.000000
640.062012 0.000000
659.819031 0.000000
680.088013 0.000000
700.056030 0.000000
719.976990 0.000000
740.179016 0.000000
760.147034 0.000000
779.747986 0.000000
799.871033 0.000000
819.974060 0.000000
839.973083 0.000000
859.778015 0.000000
879.915039 0.000000
899.709961 0.000000
================================================
FILE: Asset/SPD/metals/VC.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for VC
# ;
# ; Concatenation of:
# ;
# ; VC_llnl_cxro + VC_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.470000
354.229004 2.590000
413.266998 2.770000
495.920013 2.840000
619.900024 3.010000
826.533020 3.370000
================================================
FILE: Asset/SPD/metals/VC.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for VC
# ;
# ; Concatenation of:
# ;
# ; VC_llnl_cxro + VC_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.150000
354.229004 2.120000
413.266998 2.160000
495.920013 2.210000
619.900024 2.510000
826.533020 2.880000
================================================
FILE: Asset/SPD/metals/VN.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for VN
# ;
# ; Concatenation of:
# ;
# ; VN_llnl_cxro + VN_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 2.200000
354.229004 2.180000
413.266998 2.130000
495.920013 2.170000
619.900024 2.350000
826.533020 2.730000
================================================
FILE: Asset/SPD/metals/VN.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for VN
# ;
# ; Concatenation of:
# ;
# ; VN_llnl_cxro + VN_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.540000
354.229004 1.580000
413.266998 1.700000
495.920013 1.980000
619.900024 2.470000
826.533020 2.920000
================================================
FILE: Asset/SPD/metals/W.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for W
# ;
# ; Concatenation of:
# ;
# ; W_llnl_cxro + W_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 2.970000
309.950012 2.950000
313.873016 2.950000
317.897003 2.960000
322.026001 2.980000
326.263000 2.990000
330.613007 3.020000
335.081024 3.050000
339.670990 3.090000
344.389008 3.130000
349.238983 3.180000
354.229004 3.240000
359.362030 3.320000
364.647003 3.390000
370.089996 3.430000
375.696991 3.450000
381.477020 3.450000
387.437988 3.430000
393.587006 3.410000
399.935028 3.390000
406.492004 3.370000
413.266998 3.350000
420.270996 3.330000
427.516998 3.320000
435.018036 3.310000
442.785980 3.300000
450.835999 3.310000
459.185028 3.310000
467.849030 3.320000
476.846008 3.340000
486.196014 3.350000
495.920013 3.380000
506.041016 3.420000
516.583008 3.450000
527.575012 3.480000
539.044006 3.500000
551.022034 3.500000
563.545044 3.490000
576.651001 3.510000
590.381042 3.540000
604.781006 3.570000
619.900024 3.600000
635.795044 3.650000
652.526001 3.700000
670.162048 3.760000
688.778015 3.820000
708.456970 3.850000
729.294006 3.840000
751.393982 3.780000
774.875000 3.670000
799.871033 3.560000
826.533020 3.480000
855.033997 3.380000
885.570984 3.290000
================================================
FILE: Asset/SPD/metals/W.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for W
# ;
# ; Concatenation of:
# ;
# ; W_llnl_cxro + W_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
302.389984 2.370000
309.950012 2.430000
313.873016 2.460000
317.897003 2.500000
322.026001 2.530000
326.263000 2.560000
330.613007 2.600000
335.081024 2.620000
339.670990 2.650000
344.389008 2.670000
349.238983 2.690000
354.229004 2.700000
359.362030 2.700000
364.647003 2.660000
370.089996 2.600000
375.696991 2.550000
381.477020 2.490000
387.437988 2.450000
393.587006 2.430000
399.935028 2.410000
406.492004 2.420000
413.266998 2.420000
420.270996 2.430000
427.516998 2.450000
435.018036 2.470000
442.785980 2.490000
450.835999 2.530000
459.185028 2.550000
467.849030 2.590000
476.846008 2.620000
486.196014 2.640000
495.920013 2.680000
506.041016 2.710000
516.583008 2.720000
527.575012 2.720000
539.044006 2.720000
551.022034 2.730000
563.545044 2.750000
576.651001 2.810000
590.381042 2.840000
604.781006 2.860000
619.900024 2.890000
635.795044 2.920000
652.526001 2.940000
670.162048 2.950000
688.778015 2.910000
708.456970 2.860000
729.294006 2.780000
751.393982 2.720000
774.875000 2.680000
799.871033 2.730000
826.533020 2.790000
855.033997 2.850000
885.570984 2.960000
================================================
FILE: Asset/SPD/metals/a-C.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for amorphous carbon
# ;
# ; Concatenation of:
# ;
# ; a-C_llnl_cxro + a-C_windt88 + a-C_palik
# ;
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 1.840000
326.263000 1.900000
344.389008 1.940000
364.647003 2.000000
387.437988 2.060000
413.266998 2.110000
442.785980 2.170000
476.846008 2.240000
516.583008 2.300000
563.545044 2.380000
619.900024 2.430000
688.778015 2.430000
774.875000 2.330000
885.570984 2.240000
================================================
FILE: Asset/SPD/metals/a-C.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for amorphous carbon
# ;
# ; Concatenation of:
# ;
# ; a-C_llnl_cxro + a-C_windt88 + a-C_palik
# ;
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 0.808000
326.263000 0.910000
344.389008 0.920000
364.647003 0.920000
387.437988 0.910000
413.266998 0.900000
442.785980 0.890000
476.846008 0.880000
516.583008 0.870000
563.545044 0.820000
619.900024 0.750000
688.778015 0.700000
774.875000 0.710000
885.570984 0.800000
================================================
FILE: Asset/SPD/metals/a-SiH.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for a-Si:H, amorphous glow-discharge Si onto
# ; 400 C substrates, ~4 at.% H
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 3.360000
354.229004 4.590000
413.266998 5.430000
495.920013 5.250000
619.900024 4.710000
826.533020 4.130000
================================================
FILE: Asset/SPD/metals/a-SiH.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for a-Si:H, amorphous glow-discharge Si onto
# ; 400 C substrates, ~4 at.% H
# ;
# ; taken from:
# ;
# ; 'Handbook of Optical Constants of Solids', Ed. by Edward D. Palik,
# ; Academic Press, Inc., 1985.
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
309.950012 3.920000
354.229004 3.380000
413.266998 2.190000
495.920013 0.992000
619.900024 0.217000
826.533020 0.000000
================================================
FILE: Asset/SPD/metals/d-C.eta.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for diamond
# ;
# ; Concatenation of:
# ;
# ; d-C_llnl_cxro + d-C_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
346.700012 2.495400
361.037018 2.485400
404.634003 2.462600
467.795990 2.440800
486.120026 2.435400
508.552002 2.430600
546.047058 2.423500
588.979004 2.417500
643.818054 2.411100
656.257019 2.410400
================================================
FILE: Asset/SPD/metals/d-C.k.spd
================================================
# data from www.luxpop.com database
# ; Optical constants for diamond
# ;
# ; Concatenation of:
# ;
# ; d-C_llnl_cxro + d-C_palik
# ;
# ; Lambda (A) n k
# ;-----------------------------------------
346.700012 0.000000
361.037018 0.000000
404.634003 0.000000
467.795990 0.000000
486.120026 0.000000
508.552002 0.000000
546.047058 0.000000
588.979004 0.000000
643.818054 0.000000
656.257019 0.000000
================================================
FILE: Doc/Material.drawio
================================================
================================================
FILE: Doc/RHI.drawio
================================================
================================================
FILE: Doc/RenderGraph.drawio
================================================
================================================
FILE: Doc/Resource.drawio
================================================
================================================
FILE: Doc/Scene.drawio
================================================
================================================
FILE: Doc/Shader.drawio
================================================
================================================
FILE: LICENSE.txt
================================================
MIT License
Copyright (c) 2021 Chaf-Graphics
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Ilum(WIP)
[](https://github.com/Chaf-Libraries/Ilum/actions/workflows/windows.yml) [](https://www.codacy.com/gh/Chaf-Libraries/IlumEngine/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Chaf-Libraries/IlumEngine&utm_campaign=Badge_Grade)
Ilum Graphics Playground, name after *Planet Ilum* from [star wars](https://starwars.fandom.com/wiki/Ilum).
A framework for computer graphics learning and practice (It's not a game engine!)
[bilibili: Project demo video](https://www.bilibili.com/video/BV1Zy4y1f7PX/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=80dfe42ae16a11fb93eda40958202849)

## Install
**Platform**
* Windows 10
* Visual Studio 2022
* xmake >= v2.7.5
* [optional] CUDA >= 11.7
**Build**
Ilum uses [xmake](https://xmake.io/#/) for building. You can compile the whole project by simply run command:
```shell
xmake -y
```
or you can open the project in Visual Studio by generating `.sln` file:
```shell
xmake project -k vsxmake
```
## Feature
### Cross-Platform RHI
* Vulkan
* Mesh Shading
* Dynamic Rendering
* Ray Tracing Pipeline
* Draw/Dispatch Indirect
* Bindless Resource
* CUDA
* CUDA & Vulkan Interop
### Resource Manager

### Scene Graph

### Shader Compilation

### Render Graph
* Static compilation
* Automatic resource state tracking and transition
* Texture memory aliasing
* Seamless interoperation between Graphics API and CUDA
* Easy to customize render pass
**Render Pass**
* Visibility Deferred Shading Pipeline
* Visibility Geometry Pass
* Mesh shading with meshlet frustum culling (if device support `mesh_shader`)
* Usual rasterization without optimization
* Visibility Buffer Visualization
* Visualize visibility buffer: instance and primitive
* Visibility Buffer Lighting Pass
* Indirect dispatch to support multiple material graphs
* Generate lighting result and GBuffer
* Shadow
* Classic Shadow Map (Spot Light)
* Omnidirectional Shadow Map (Point Light)
* Cascade Shadow Map (Directional Light)
* Ambient Occlusion
* SSAO
* IBL
* Spherical Harmonic Encoding Diffuse
* Pre-Filter For Specular
* Ray Tracing
* Path Tracing
* Post Process
* Tone Mapping
* Bloom
* FXAA
**TODO**
* Resource Pool
* Runtime compilation maybe
* Multi-threading
### Material Graph
**Feature**
* Static compilation and HLSL generation
* Easy to customize material node
* Support usual BSDF models
### Plugins
You can extend the renderer features by adding these plugins:
* RHI
* Render Pass
* Material Node
* Importer
* Editor
#### Customize Render Pass
#### Customize Material Node
## Gallery
### Render Graph Editor

### Material Graph Editor

### Path Tracing

## Reference
* [https://www.pbr-book.org/](https://www.pbr-book.org/)
* [http://www.realtimerendering.com/](http://www.realtimerendering.com/)
* [https://learnopengl-cn.github.io/](https://learnopengl-cn.github.io/)
* [https://hazelengine.com/](https://hazelengine.com/)
* [https://advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf](https://advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf)
* [https://www.gdcvault.com/play/1024612/FrameGraph-Extensible-Rendering-Architecture-in](https://www.gdcvault.com/play/1024612/FrameGraph-Extensible-Rendering-Architecture-in)
* [https://github.com/SaschaWillems/Vulkan](https://github.com/SaschaWillems/Vulkan)
* [https://github.com/KhronosGroup/Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples)
* [https://github.com/wdas/brdf](https://github.com/wdas/brdf)
* [http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf.](http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf.)
* [https://www.froyok.fr/blog/2021-12-ue4-custom-bloom/](https://www.froyok.fr/blog/2021-12-ue4-custom-bloom/)
* [https://filmicworlds.com/blog/visibility-buffer-rendering-with-material-graphs](https://filmicworlds.com/blog/visibility-buffer-rendering-with-material-graphs)
================================================
FILE: Source/Editor/Editor.cpp
================================================
#include "Editor.hpp"
#include "ImGui/ImGuiContext.hpp"
#include "Widget.hpp"
#include
#include
#include
#include
#include
#include
namespace Ilum
{
struct Editor::Impl
{
std::unique_ptr imgui_context = nullptr;
RHIContext *rhi_context = nullptr;
Renderer *renderer = nullptr;
std::vector> widgets;
Node *select = nullptr;
Cmpt::Camera *main_camera = nullptr;
};
Editor::Editor(Window *window, RHIContext *rhi_context, Renderer *renderer)
{
m_impl = new Impl;
m_impl->imgui_context = std::make_unique(rhi_context, window);
m_impl->renderer = renderer;
m_impl->rhi_context = rhi_context;
for (const auto &file : std::filesystem::directory_iterator("shared/Editor/"))
{
m_impl->widgets.emplace_back(std::unique_ptr(std::move(PluginManager::GetInstance().Call(file.path().string(), "Create", this, ImGui::GetCurrentContext()))));
}
}
Editor::~Editor()
{
m_impl->imgui_context.reset();
delete m_impl;
}
void Editor::PreTick()
{
m_impl->imgui_context->BeginFrame();
}
void Editor::Tick()
{
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("Widget"))
{
for (auto &widget : m_impl->widgets)
{
ImGui::MenuItem(widget->GetName().c_str(), nullptr, &widget->GetActive());
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
for (auto &widget : m_impl->widgets)
{
if (widget->GetActive())
{
widget->Tick();
}
}
}
void Editor::PostTick()
{
m_impl->imgui_context->EndFrame();
m_impl->imgui_context->Render();
}
Renderer *Editor::GetRenderer() const
{
return m_impl->renderer;
}
RHIContext *Editor::GetRHIContext() const
{
return m_impl->rhi_context;
}
Window *Editor::GetWindow() const
{
return m_impl->imgui_context->GetWindow();
}
void Editor::SelectNode(Node *node)
{
m_impl->select = node;
}
void Editor::SetMainCamera(Cmpt::Camera *camera)
{
m_impl->main_camera = camera;
}
Node *Editor::GetSelectedNode() const
{
return m_impl->select;
}
Cmpt::Camera *Editor::GetMainCamera() const
{
return m_impl->main_camera;
}
} // namespace Ilum
================================================
FILE: Source/Editor/Editor.hpp
================================================
#pragma once
#include
#include
#include
namespace Ilum
{
class Window;
class RHIContext;
class GuiContext;
class Widget;
class Renderer;
class Node;
namespace Cmpt
{
class Camera;
}
class EXPORT_API Editor
{
public:
Editor(Window *window, RHIContext *rhi_context, Renderer *renderer);
~Editor();
void PreTick();
void Tick();
void PostTick();
Renderer *GetRenderer() const;
RHIContext *GetRHIContext() const;
Window *GetWindow() const;
void SelectNode(Node *node = nullptr);
void SetMainCamera(Cmpt::Camera *camera = nullptr);
Node *GetSelectedNode() const;
Cmpt::Camera *GetMainCamera() const;
private:
struct Impl;
Impl* m_impl = nullptr;
};
} // namespace Ilum
================================================
FILE: Source/Editor/ImGui/ImGuiContext.cpp
================================================
#include "ImGuiContext.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#define GLFW_EXPOSE_NATIVE_WIN32
#include
#undef CreateSemaphore
namespace Ilum
{
static RHIContext *gContext = nullptr;
static Window *gWindow = nullptr;
static RHIPipelineState *gPipelineState = nullptr;
static RHIDescriptor *gDescriptor = nullptr;
static RHISampler *gSampler = nullptr;
static RHIRenderTarget *gRenderTarget = nullptr;
struct ConstantBlock
{
glm::vec2 scale;
glm::vec2 translate;
};
struct ViewportResources
{
ViewportResources(const std::string &name = "subwindow")
{
uniform_buffer = gContext->CreateBuffer(BufferDesc{
"imgui_uniform_buffer - " + name + std::to_string((uint64_t) this),
RHIBufferUsage::ConstantBuffer,
RHIMemoryUsage::CPU_TO_GPU,
sizeof(ConstantBlock),
});
for (uint32_t i = 0; i < 3; i++)
{
render_completes[i] = gContext->CreateSemaphore();
present_completes[i] = gContext->CreateSemaphore();
}
}
std::unique_ptr vertex_buffer = nullptr;
std::unique_ptr index_buffer = nullptr;
std::unique_ptr uniform_buffer = nullptr;
std::array, 3> render_completes;
std::array, 3> present_completes;
std::vector cmd_buffers;
uint32_t vertex_count = 0;
uint32_t index_count = 0;
uint32_t frame_index = 0;
};
struct WindowData
{
std::unique_ptr viewport_data;
std::unique_ptr swapchain;
};
static std::unique_ptr gResource;
GuiContext::GuiContext(RHIContext *context, Window *window) :
p_context(context), p_window(window)
{
gContext = p_context;
gWindow = p_window;
gResource = std::make_unique("mainwindows");
ImGui::CreateContext();
SetStyle();
ImGui_ImplGlfw_InitForOther(window->GetHandle(), true);
m_pipeline_state = context->CreatePipelineState();
m_render_target = context->CreateRenderTarget();
m_sampler = context->CreateSampler(SamplerDesc{
RHIFilter::Linear,
RHIFilter::Linear,
RHIAddressMode::Clamp_To_Edge,
RHIAddressMode::Clamp_To_Edge,
RHIAddressMode::Clamp_To_Edge,
RHIMipmapMode::Linear,
RHISamplerBorderColor::Float_Opaque_White});
// Setup pipeline state
DepthStencilState depth_stencil_state = {};
depth_stencil_state.depth_test_enable = false;
depth_stencil_state.depth_write_enable = false;
depth_stencil_state.compare = RHICompareOp::Always;
RasterizationState rasterization_state = {};
rasterization_state.cull_mode = RHICullMode::None;
rasterization_state.polygon_mode = RHIPolygonMode::Solid;
rasterization_state.front_face = RHIFrontFace::Clockwise;
InputAssemblyState input_assembly_state = {};
input_assembly_state.topology = RHIPrimitiveTopology::Triangle;
BlendState blend_state = {};
blend_state.enable = false;
blend_state.attachment_states.push_back(BlendState::AttachmentState{
true,
RHIBlendFactor::Src_Alpha,
RHIBlendFactor::One_Minus_Src_Alpha,
RHIBlendOp::Add,
RHIBlendFactor::One,
RHIBlendFactor::One_Minus_Src_Alpha,
RHIBlendOp::Add,
1 | 2 | 4 | 8});
VertexInputState vertex_input_state = {};
vertex_input_state.input_attributes = {
VertexInputState::InputAttribute{RHIVertexSemantics::Position, 0, 0, RHIFormat::R32G32_FLOAT, offsetof(ImDrawVert, pos)},
VertexInputState::InputAttribute{RHIVertexSemantics::Texcoord, 1, 0, RHIFormat::R32G32_FLOAT, offsetof(ImDrawVert, uv)},
VertexInputState::InputAttribute{RHIVertexSemantics::Texcoord, 2, 0, RHIFormat::R8G8B8A8_UNORM, offsetof(ImDrawVert, col)},
};
vertex_input_state.input_bindings = {
VertexInputState::InputBinding{0, sizeof(ImDrawVert), RHIVertexInputRate::Vertex}};
/*std::vector raw_shader;
Path::GetInstance().Read("./Source/Shaders/ImGui.hlsl", raw_shader);
std::string shader_source;
shader_source.resize(raw_shader.size());
std::memcpy(shader_source.data(), raw_shader.data(), raw_shader.size());
shader_source += "\n";
ShaderDesc vertex_shader_desc = {};
vertex_shader_desc.entry_point = "VSmain";
vertex_shader_desc.stage = RHIShaderStage::Vertex;
vertex_shader_desc.source = ShaderSource::HLSL;
vertex_shader_desc.target = ShaderTarget::SPIRV;
vertex_shader_desc.code = shader_source;
vertex_shader_desc.macros = {"VULKAN_BACKEND"};
ShaderDesc fragment_shader_desc = {};
fragment_shader_desc.entry_point = "PSmain";
fragment_shader_desc.stage = RHIShaderStage::Fragment;
fragment_shader_desc.source = ShaderSource::HLSL;
fragment_shader_desc.target = ShaderTarget::SPIRV;
fragment_shader_desc.code = shader_source;
fragment_shader_desc.macros = {"VULKAN_BACKEND"};
ShaderMeta vertex_meta = {};
ShaderMeta fragment_meta = {};
auto vertex_shader_spirv = ShaderCompiler::GetInstance().Compile(vertex_shader_desc, vertex_meta);
auto fragment_shader_spirv = ShaderCompiler::GetInstance().Compile(fragment_shader_desc, fragment_meta);
m_vertex_shader = p_context->CreateShader("VSmain", vertex_shader_spirv);
m_fragment_shader = p_context->CreateShader("PSmain", fragment_shader_spirv);
ShaderMeta shader_meta= vertex_meta;
shader_meta += fragment_meta;*/
ShaderMeta shader_meta;
std::vector vertex_shader_spirv;
std::vector fragment_shader_spirv;
DESERIALIZE("Asset/BuildIn/ImGui.spv.asset", vertex_shader_spirv, fragment_shader_spirv, shader_meta);
m_vertex_shader = p_context->CreateShader("VSmain", vertex_shader_spirv);
m_fragment_shader = p_context->CreateShader("PSmain", fragment_shader_spirv);
m_descriptor = p_context->CreateDescriptor(shader_meta);
m_pipeline_state->SetDepthStencilState(depth_stencil_state);
m_pipeline_state->SetRasterizationState(rasterization_state);
m_pipeline_state->SetVertexInputState(vertex_input_state);
m_pipeline_state->SetBlendState(blend_state);
m_pipeline_state->SetInputAssemblyState(input_assembly_state);
m_pipeline_state->SetShader(RHIShaderStage::Vertex, m_vertex_shader.get());
m_pipeline_state->SetShader(RHIShaderStage::Fragment, m_fragment_shader.get());
// Font atlas
unsigned char *pixels;
int32_t atlas_width, atlas_height, bpp;
auto &io = ImGui::GetIO();
io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height, &bpp);
const uint32_t size = atlas_width * atlas_height * bpp;
auto buffer = p_context->CreateBuffer(static_cast(size), RHIBufferUsage::Transfer, RHIMemoryUsage::CPU_TO_GPU);
std::memcpy(buffer->Map(), pixels, size);
buffer->Unmap();
m_font_atlas = p_context->CreateTexture2D(atlas_width, atlas_height, RHIFormat::R8G8B8A8_UNORM, RHITextureUsage::ShaderResource | RHITextureUsage::Transfer, false);
auto *cmd_buffer = p_context->CreateCommand(RHIQueueFamily::Graphics);
cmd_buffer->Begin();
cmd_buffer->BeginMarker("UI");
cmd_buffer->ResourceStateTransition({TextureStateTransition{
m_font_atlas.get(),
RHIResourceState::Undefined,
RHIResourceState::TransferDest,
TextureRange{RHITextureDimension::Texture2D, 0, 1, 0, 1}}},
{});
cmd_buffer->CopyBufferToTexture(buffer.get(), m_font_atlas.get(), 0, 0, 1);
cmd_buffer->ResourceStateTransition({TextureStateTransition{
m_font_atlas.get(),
RHIResourceState::TransferDest,
RHIResourceState::ShaderResource,
TextureRange{RHITextureDimension::Texture2D, 0, 1, 0, 1}}},
{});
cmd_buffer->EndMarker();
cmd_buffer->End();
p_context->Execute(cmd_buffer);
io.Fonts->TexID = static_cast(m_font_atlas.get());
gPipelineState = m_pipeline_state.get();
gDescriptor = m_descriptor;
gSampler = m_sampler;
gRenderTarget = m_render_target.get();
InitializePlatformInterface();
}
GuiContext::~GuiContext()
{
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
gContext = nullptr;
gWindow = nullptr;
gPipelineState = nullptr;
gDescriptor = nullptr;
gSampler = nullptr;
gRenderTarget = nullptr;
gResource.reset();
}
void GuiContext::BeginFrame()
{
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking;
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
ImGuiViewport *viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("DockSpace", (bool *) 1, window_flags);
ImGui::PopStyleVar();
ImGui::PopStyleVar(2);
ImGuiIO &io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
ImGuiID dockspace_id = ImGui::GetID("DockSpace");
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None);
}
}
void GuiContext::EndFrame()
{
ImGui::End();
ImGuiIO &io = ImGui::GetIO();
io.DisplaySize = ImVec2(static_cast(gWindow->GetWidth()), static_cast(gWindow->GetHeight()));
ImGui::EndFrame();
ImGui::Render();
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
}
void GuiContext::SetStyle()
{
ImGuiIO &io = ImGui::GetIO();
(void) io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports;
// Set fonts
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
ImFontConfig config;
config.MergeMode = true;
config.GlyphMinAdvanceX = 13.0f;
io.Fonts->AddFontFromFileTTF("./Asset/Font/ArialUnicodeMS.ttf", 20.0f, NULL, io.Fonts->GetGlyphRangesChineseFull());
io.Fonts->AddFontFromFileTTF("./Asset/Font/fontawesome-webfont.ttf", 15.0f, &config, icon_ranges);
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle &style = ImGui::GetStyle();
auto colors = style.Colors;
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.44f, 0.44f, 0.44f, 0.60f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.57f, 0.57f, 0.57f, 0.70f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.76f, 0.76f, 0.76f, 0.80f);
colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.16f, 0.16f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.60f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.13f, 0.75f, 0.55f, 0.80f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.13f, 0.75f, 0.75f, 0.80f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
colors[ImGuiCol_Button] = ImVec4(0.13f, 0.75f, 0.55f, 0.40f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.13f, 0.75f, 0.75f, 0.60f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
colors[ImGuiCol_Header] = ImVec4(0.13f, 0.75f, 0.55f, 0.40f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.13f, 0.75f, 0.75f, 0.60f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
colors[ImGuiCol_Separator] = ImVec4(0.13f, 0.75f, 0.55f, 0.40f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.13f, 0.75f, 0.75f, 0.60f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.13f, 0.75f, 0.55f, 0.40f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.13f, 0.75f, 0.75f, 0.60f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
colors[ImGuiCol_Tab] = ImVec4(0.13f, 0.75f, 0.55f, 0.80f);
colors[ImGuiCol_TabHovered] = ImVec4(0.13f, 0.75f, 0.75f, 0.80f);
colors[ImGuiCol_TabActive] = ImVec4(0.13f, 0.75f, 1.00f, 0.80f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.18f, 0.18f, 0.18f, 1.00f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.36f, 0.36f, 0.36f, 0.54f);
colors[ImGuiCol_DockingPreview] = ImVec4(0.13f, 0.75f, 0.55f, 0.80f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.13f, 0.13f, 0.13f, 0.80f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
style.WindowPadding = ImVec2(8.00f, 8.00f);
style.FramePadding = ImVec2(5.00f, 2.00f);
style.CellPadding = ImVec2(6.00f, 6.00f);
style.ItemSpacing = ImVec2(6.00f, 6.00f);
style.ItemInnerSpacing = ImVec2(6.00f, 6.00f);
style.TouchExtraPadding = ImVec2(0.00f, 0.00f);
style.IndentSpacing = 25;
style.ScrollbarSize = 15;
style.GrabMinSize = 10;
style.WindowBorderSize = 1;
style.ChildBorderSize = 1;
style.PopupBorderSize = 1;
style.FrameBorderSize = 1;
style.TabBorderSize = 1;
style.WindowRounding = 7;
style.ChildRounding = 4;
style.FrameRounding = 3;
style.PopupRounding = 4;
style.ScrollbarRounding = 9;
style.GrabRounding = 3;
style.LogSliderDeadzone = 4;
style.TabRounding = 4;
}
static void RHI_Render(ImDrawData *draw_data, WindowData *window_data = nullptr)
{
size_t vertex_buffer_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_buffer_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
if (draw_data->DisplaySize.x == 0 ||
draw_data->DisplaySize.y == 0)
{
return;
}
bool is_child_window = window_data != nullptr;
RHISwapchain *swapchain = is_child_window ? window_data->swapchain.get() : gContext->GetSwapchain();
ViewportResources *resources = is_child_window ? window_data->viewport_data.get() : gResource.get();
auto &vertex_buffer = resources->vertex_buffer;
auto &index_buffer = resources->index_buffer;
auto &uniform_buffer = resources->uniform_buffer;
auto &vertex_count = resources->vertex_count;
auto &index_count = resources->index_count;
if (vertex_buffer == nullptr || vertex_count != static_cast(draw_data->TotalVtxCount))
{
if (vertex_buffer_size != 0)
{
vertex_buffer.reset();
vertex_buffer = gContext->CreateBuffer(vertex_buffer_size, RHIBufferUsage::Vertex, RHIMemoryUsage::CPU_TO_GPU);
vertex_count = draw_data->TotalVtxCount;
vertex_buffer->Map();
}
}
if (index_buffer == nullptr || index_count < static_cast(draw_data->TotalIdxCount))
{
if (index_buffer_size != 0)
{
index_buffer.reset();
index_buffer = gContext->CreateBuffer(index_buffer_size, RHIBufferUsage::Index, RHIMemoryUsage::CPU_TO_GPU);
index_count = draw_data->TotalIdxCount;
index_buffer->Map();
}
}
ImDrawVert *vtx_dst = vertex_buffer ? (ImDrawVert *) vertex_buffer->Map() : nullptr;
ImDrawIdx *idx_dst = index_buffer ? (ImDrawIdx *) index_buffer->Map() : nullptr;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList *cmd_list = draw_data->CmdLists[n];
if (vtx_dst)
{
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
}
if (idx_dst)
{
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
}
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
if (vertex_buffer)
{
vertex_buffer->Flush(0, vertex_buffer->GetDesc().size);
}
if (index_buffer)
{
index_buffer->Flush(0, index_buffer->GetDesc().size);
}
int32_t fb_width = (int32_t) (draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int32_t fb_height = (int32_t) (draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0)
{
return;
}
ConstantBlock constant_block = {};
constant_block.scale = glm::vec2(2.0f / draw_data->DisplaySize.x, 2.0f / draw_data->DisplaySize.y);
constant_block.translate = glm::vec2(-1.0f - draw_data->DisplayPos.x * constant_block.scale[0], -1.0f - draw_data->DisplayPos.y * constant_block.scale[1]);
std::memcpy(uniform_buffer->Map(), &constant_block, sizeof(constant_block));
gDescriptor->BindSampler("fontSampler", gSampler);
gDescriptor->BindBuffer("constant", uniform_buffer.get());
gRenderTarget->Clear();
ColorAttachment attachment = {};
attachment.clear_value[3] = 1.f;
gRenderTarget->Set(0, swapchain->GetCurrentTexture(), TextureRange{RHITextureDimension::Texture2D, 0, 1, 0, 1}, ColorAttachment{});
auto *cmd_buffer = gContext->CreateCommand(RHIQueueFamily::Graphics);
cmd_buffer->Begin();
cmd_buffer->BeginMarker("UI");
cmd_buffer->ResourceStateTransition({TextureStateTransition{
swapchain->GetCurrentTexture(),
RHIResourceState::Present,
RHIResourceState::RenderTarget,
TextureRange{
RHITextureDimension::Texture2D,
0, 1, 0, 1}}},
{});
cmd_buffer->SetViewport(draw_data->DisplaySize.x, draw_data->DisplaySize.y);
cmd_buffer->BeginRenderPass(gRenderTarget);
int32_t global_vtx_offset = 0;
int32_t global_idx_offset = 0;
const ImVec2 &clip_off = draw_data->DisplayPos;
ImVec2 clip_scale = draw_data->FramebufferScale;
void *current_texture = nullptr;
for (int32_t i = 0; i < draw_data->CmdListsCount; i++)
{
cmd_buffer->BindVertexBuffer(0, vertex_buffer.get());
cmd_buffer->BindIndexBuffer(index_buffer.get(), true);
ImDrawList *cmd_list_imgui = draw_data->CmdLists[i];
for (int32_t cmd_i = 0; cmd_i < cmd_list_imgui->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd *pcmd = &cmd_list_imgui->CmdBuffer[cmd_i];
if (pcmd->UserCallback != nullptr)
{
pcmd->UserCallback(cmd_list_imgui, pcmd);
}
else
{
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
if (clip_min.x < 0.0f)
{
clip_min.x = 0.0f;
}
if (clip_min.y < 0.0f)
{
clip_min.y = 0.0f;
}
if (clip_max.x > fb_width)
{
clip_max.x = (float) fb_width;
}
if (clip_max.y > fb_height)
{
clip_max.y = (float) fb_height;
}
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
{
continue;
}
cmd_buffer->SetScissor((uint32_t) (clip_max.x - clip_min.x), (uint32_t) (clip_max.y - clip_min.y), (int32_t) (clip_min.x), (int32_t) (clip_min.y));
if (current_texture != pcmd->TextureId)
{
auto texture = static_cast(pcmd->TextureId);
gDescriptor->BindTexture("fontTexture", static_cast(pcmd->TextureId), TextureRange{RHITextureDimension::Texture2D, 0, 1, 0, 1});
cmd_buffer->BindDescriptor(gDescriptor);
cmd_buffer->BindPipelineState(gPipelineState);
current_texture = pcmd->TextureId;
}
cmd_buffer->DrawIndexed(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
}
global_idx_offset += cmd_list_imgui->IdxBuffer.Size;
global_vtx_offset += cmd_list_imgui->VtxBuffer.Size;
}
cmd_buffer->EndRenderPass();
cmd_buffer->ResourceStateTransition({TextureStateTransition{
swapchain->GetCurrentTexture(),
RHIResourceState::RenderTarget,
RHIResourceState::Present,
TextureRange{
RHITextureDimension::Texture2D,
0, 1, 0, 1}}},
{});
cmd_buffer->EndMarker();
cmd_buffer->End();
if (is_child_window)
{
resources->cmd_buffers.push_back(cmd_buffer);
}
else
{
gContext->Submit({cmd_buffer}, {}, {});
}
}
static void ImGuiWindowCreate(ImGuiViewport *viewport)
{
WindowData *window = new WindowData();
window->swapchain = gContext->CreateSwapchain(
#ifdef _WIN32
glfwGetWin32Window((GLFWwindow *) viewport->PlatformHandle),
#endif // _WIN32
static_cast(viewport->Size.x),
static_cast(viewport->Size.y),
gContext->IsVsync());
window->viewport_data = std::make_unique();
viewport->RendererUserData = window;
}
static void ImGuiWindowDestroy(ImGuiViewport *viewport)
{
if (WindowData *window = static_cast(viewport->RendererUserData))
{
gContext->WaitIdle();
delete window;
}
viewport->RendererUserData = nullptr;
}
static void ImGuiWindowSetSize(ImGuiViewport *viewport, const ImVec2 size)
{
static_cast(viewport->RendererUserData)->swapchain->Resize(static_cast(size.x), static_cast(size.y), gContext->IsVsync());
}
static void ImGuiWindowRender(ImGuiViewport *viewport, void *)
{
WindowData *window_data = static_cast(viewport->RendererUserData);
window_data->swapchain->AcquireNextTexture(window_data->viewport_data->present_completes.at(window_data->viewport_data->frame_index).get(), nullptr);
RHI_Render(viewport->DrawData, window_data);
}
static void ImGuiWindowPresent(ImGuiViewport *viewport, void *)
{
WindowData *window_data = static_cast(viewport->RendererUserData);
gContext->Execute(
std::move(window_data->viewport_data->cmd_buffers),
{window_data->viewport_data->present_completes.at(window_data->viewport_data->frame_index).get()},
{window_data->viewport_data->render_completes.at(window_data->viewport_data->frame_index).get()},
gContext->CreateFrameFence());
window_data->viewport_data->cmd_buffers.clear();
window_data->swapchain->Present(window_data->viewport_data->render_completes.at(window_data->viewport_data->frame_index).get());
window_data->viewport_data->frame_index = (window_data->viewport_data->frame_index + 1) % 3;
}
void GuiContext::Render()
{
RHI_Render(ImGui::GetDrawData());
}
Window *GuiContext::GetWindow() const
{
return p_window;
}
void GuiContext::InitializePlatformInterface()
{
ImGuiPlatformIO &platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_CreateWindow = ImGuiWindowCreate;
platform_io.Renderer_DestroyWindow = ImGuiWindowDestroy;
platform_io.Renderer_SetWindowSize = ImGuiWindowSetSize;
platform_io.Renderer_RenderWindow = ImGuiWindowRender;
platform_io.Renderer_SwapBuffers = ImGuiWindowPresent;
}
} // namespace Ilum
================================================
FILE: Source/Editor/ImGui/ImGuiContext.hpp
================================================
#pragma once
#include
namespace Ilum
{
class GuiContext
{
public:
GuiContext(RHIContext *context, Window *window);
~GuiContext();
void BeginFrame();
void EndFrame();
void Render();
Window *GetWindow() const;
private:
void SetStyle();
void InitializePlatformInterface();
private:
RHIContext *p_context = nullptr;
Window *p_window = nullptr;
std::unique_ptr m_pipeline_state = nullptr;
RHIDescriptor* m_descriptor = nullptr;
RHISampler* m_sampler = nullptr;
std::unique_ptr m_vertex_shader = nullptr;
std::unique_ptr m_fragment_shader = nullptr;
std::unique_ptr m_render_target = nullptr;
std::unique_ptr m_font_atlas = nullptr;
size_t m_vertex_count = 0;
size_t m_index_count = 0;
};
} // namespace Ilum
================================================
FILE: Source/Editor/Precompile.hpp
================================================
#pragma once
#include
================================================
FILE: Source/Editor/Widget.hpp
================================================
#pragma once
#include
namespace Ilum
{
class Editor;
class Widget
{
public:
Widget(const std::string &name, Editor *editor) :
m_name(name), p_editor(editor)
{
}
virtual ~Widget() = default;
virtual void Tick() = 0;
inline bool &GetActive()
{
return m_active;
}
const std::string& GetName() const
{
return m_name;
}
protected:
Editor *p_editor = nullptr;
std::string m_name;
bool m_active = true;
};
} // namespace Ilum
================================================
FILE: Source/Engine/Engine.cpp
================================================
#include "Engine.hpp"
#include
#include
#include
#include
#include
#include
#include
namespace Ilum
{
Engine::Engine()
{
m_window = std::make_unique("Ilum", "Asset/Icon/logo.bmp");
m_rhi_context = std::make_unique(m_window.get(), "Vulkan", true);
m_resource_manager = std::make_unique(m_rhi_context.get());
m_scene = std::make_unique("Default Scene");
m_renderer = std::make_unique(m_rhi_context.get(), m_scene.get(), m_resource_manager.get());
m_editor = std::make_unique(m_window.get(), m_rhi_context.get(), m_renderer.get());
Path::GetInstance().SetCurrent("./");
}
Engine::~Engine()
{
m_scene.reset();
m_editor.reset();
m_renderer.reset();
m_resource_manager.reset();
m_rhi_context.reset();
m_window.reset();
}
void Engine::Tick()
{
while (m_window->Tick())
{
m_timer.Tick();
if (m_window->GetWidth() != 0 && m_window->GetHeight() != 0)
{
m_rhi_context->BeginFrame();
// Render loop
m_renderer->Tick();
// Update resource manager
m_resource_manager->Tick();
// Render UI
m_editor->PreTick();
m_editor->Tick();
m_editor->PostTick();
m_rhi_context->EndFrame();
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
m_window->SetTitle(fmt::format("IlumEngine v{} | Scene - {} | FPS - {}",
"1.0Beta",
m_scene->GetName(),
m_timer.FrameRate()));
}
}
} // namespace Ilum
================================================
FILE: Source/Engine/Engine.hpp
================================================
#pragma once
#include
namespace Ilum
{
class Window;
class RHIContext;
class Editor;
class ResourceManager;
class Renderer;
class Scene;
class Engine
{
public:
Engine();
~Engine();
void Tick();
private:
std::unique_ptr m_window = nullptr;
std::unique_ptr m_rhi_context = nullptr;
std::unique_ptr m_resource_manager = nullptr;
std::unique_ptr m_scene = nullptr;
std::unique_ptr m_renderer = nullptr;
std::unique_ptr m_editor = nullptr;
Timer m_timer;
};
} // namespace Ilum
================================================
FILE: Source/Engine/Precompile.hpp
================================================
#pragma once
#include
================================================
FILE: Source/Engine/main.cpp
================================================
#include "Engine.hpp"
#include
int main()
{
Ilum::Engine engine;
//Ilum::ShaderCompiler::GetInstance();
engine.Tick();
return 0;
}
================================================
FILE: Source/External/dxc/inc/d3d12shader.h
================================================
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// File: D3D12Shader.h
// Content: D3D12 Shader Types and APIs
//
//////////////////////////////////////////////////////////////////////////////
#ifndef __D3D12SHADER_H__
#define __D3D12SHADER_H__
#include "d3dcommon.h"
typedef enum D3D12_SHADER_VERSION_TYPE
{
D3D12_SHVER_PIXEL_SHADER = 0,
D3D12_SHVER_VERTEX_SHADER = 1,
D3D12_SHVER_GEOMETRY_SHADER = 2,
// D3D11 Shaders
D3D12_SHVER_HULL_SHADER = 3,
D3D12_SHVER_DOMAIN_SHADER = 4,
D3D12_SHVER_COMPUTE_SHADER = 5,
// D3D12 Shaders
D3D12_SHVER_LIBRARY = 6,
D3D12_SHVER_RAY_GENERATION_SHADER = 7,
D3D12_SHVER_INTERSECTION_SHADER = 8,
D3D12_SHVER_ANY_HIT_SHADER = 9,
D3D12_SHVER_CLOSEST_HIT_SHADER = 10,
D3D12_SHVER_MISS_SHADER = 11,
D3D12_SHVER_CALLABLE_SHADER = 12,
D3D12_SHVER_MESH_SHADER = 13,
D3D12_SHVER_AMPLIFICATION_SHADER = 14,
D3D12_SHVER_RESERVED0 = 0xFFF0,
} D3D12_SHADER_VERSION_TYPE;
#define D3D12_SHVER_GET_TYPE(_Version) \
(((_Version) >> 16) & 0xffff)
#define D3D12_SHVER_GET_MAJOR(_Version) \
(((_Version) >> 4) & 0xf)
#define D3D12_SHVER_GET_MINOR(_Version) \
(((_Version) >> 0) & 0xf)
// Slot ID for library function return
#define D3D_RETURN_PARAMETER_INDEX (-1)
typedef D3D_RESOURCE_RETURN_TYPE D3D12_RESOURCE_RETURN_TYPE;
typedef D3D_CBUFFER_TYPE D3D12_CBUFFER_TYPE;
typedef struct _D3D12_SIGNATURE_PARAMETER_DESC
{
LPCSTR SemanticName; // Name of the semantic
UINT SemanticIndex; // Index of the semantic
UINT Register; // Number of member variables
D3D_NAME SystemValueType;// A predefined system value, or D3D_NAME_UNDEFINED if not applicable
D3D_REGISTER_COMPONENT_TYPE ComponentType; // Scalar type (e.g. uint, float, etc.)
BYTE Mask; // Mask to indicate which components of the register
// are used (combination of D3D10_COMPONENT_MASK values)
BYTE ReadWriteMask; // Mask to indicate whether a given component is
// never written (if this is an output signature) or
// always read (if this is an input signature).
// (combination of D3D_MASK_* values)
UINT Stream; // Stream index
D3D_MIN_PRECISION MinPrecision; // Minimum desired interpolation precision
} D3D12_SIGNATURE_PARAMETER_DESC;
typedef struct _D3D12_SHADER_BUFFER_DESC
{
LPCSTR Name; // Name of the constant buffer
D3D_CBUFFER_TYPE Type; // Indicates type of buffer content
UINT Variables; // Number of member variables
UINT Size; // Size of CB (in bytes)
UINT uFlags; // Buffer description flags
} D3D12_SHADER_BUFFER_DESC;
typedef struct _D3D12_SHADER_VARIABLE_DESC
{
LPCSTR Name; // Name of the variable
UINT StartOffset; // Offset in constant buffer's backing store
UINT Size; // Size of variable (in bytes)
UINT uFlags; // Variable flags
LPVOID DefaultValue; // Raw pointer to default value
UINT StartTexture; // First texture index (or -1 if no textures used)
UINT TextureSize; // Number of texture slots possibly used.
UINT StartSampler; // First sampler index (or -1 if no textures used)
UINT SamplerSize; // Number of sampler slots possibly used.
} D3D12_SHADER_VARIABLE_DESC;
typedef struct _D3D12_SHADER_TYPE_DESC
{
D3D_SHADER_VARIABLE_CLASS Class; // Variable class (e.g. object, matrix, etc.)
D3D_SHADER_VARIABLE_TYPE Type; // Variable type (e.g. float, sampler, etc.)
UINT Rows; // Number of rows (for matrices, 1 for other numeric, 0 if not applicable)
UINT Columns; // Number of columns (for vectors & matrices, 1 for other numeric, 0 if not applicable)
UINT Elements; // Number of elements (0 if not an array)
UINT Members; // Number of members (0 if not a structure)
UINT Offset; // Offset from the start of structure (0 if not a structure member)
LPCSTR Name; // Name of type, can be NULL
} D3D12_SHADER_TYPE_DESC;
typedef D3D_TESSELLATOR_DOMAIN D3D12_TESSELLATOR_DOMAIN;
typedef D3D_TESSELLATOR_PARTITIONING D3D12_TESSELLATOR_PARTITIONING;
typedef D3D_TESSELLATOR_OUTPUT_PRIMITIVE D3D12_TESSELLATOR_OUTPUT_PRIMITIVE;
typedef struct _D3D12_SHADER_DESC
{
UINT Version; // Shader version
LPCSTR Creator; // Creator string
UINT Flags; // Shader compilation/parse flags
UINT ConstantBuffers; // Number of constant buffers
UINT BoundResources; // Number of bound resources
UINT InputParameters; // Number of parameters in the input signature
UINT OutputParameters; // Number of parameters in the output signature
UINT InstructionCount; // Number of emitted instructions
UINT TempRegisterCount; // Number of temporary registers used
UINT TempArrayCount; // Number of temporary arrays used
UINT DefCount; // Number of constant defines
UINT DclCount; // Number of declarations (input + output)
UINT TextureNormalInstructions; // Number of non-categorized texture instructions
UINT TextureLoadInstructions; // Number of texture load instructions
UINT TextureCompInstructions; // Number of texture comparison instructions
UINT TextureBiasInstructions; // Number of texture bias instructions
UINT TextureGradientInstructions; // Number of texture gradient instructions
UINT FloatInstructionCount; // Number of floating point arithmetic instructions used
UINT IntInstructionCount; // Number of signed integer arithmetic instructions used
UINT UintInstructionCount; // Number of unsigned integer arithmetic instructions used
UINT StaticFlowControlCount; // Number of static flow control instructions used
UINT DynamicFlowControlCount; // Number of dynamic flow control instructions used
UINT MacroInstructionCount; // Number of macro instructions used
UINT ArrayInstructionCount; // Number of array instructions used
UINT CutInstructionCount; // Number of cut instructions used
UINT EmitInstructionCount; // Number of emit instructions used
D3D_PRIMITIVE_TOPOLOGY GSOutputTopology; // Geometry shader output topology
UINT GSMaxOutputVertexCount; // Geometry shader maximum output vertex count
D3D_PRIMITIVE InputPrimitive; // GS/HS input primitive
UINT PatchConstantParameters; // Number of parameters in the patch constant signature
UINT cGSInstanceCount; // Number of Geometry shader instances
UINT cControlPoints; // Number of control points in the HS->DS stage
D3D_TESSELLATOR_OUTPUT_PRIMITIVE HSOutputPrimitive; // Primitive output by the tessellator
D3D_TESSELLATOR_PARTITIONING HSPartitioning; // Partitioning mode of the tessellator
D3D_TESSELLATOR_DOMAIN TessellatorDomain; // Domain of the tessellator (quad, tri, isoline)
// instruction counts
UINT cBarrierInstructions; // Number of barrier instructions in a compute shader
UINT cInterlockedInstructions; // Number of interlocked instructions
UINT cTextureStoreInstructions; // Number of texture writes
} D3D12_SHADER_DESC;
typedef struct _D3D12_SHADER_INPUT_BIND_DESC
{
LPCSTR Name; // Name of the resource
D3D_SHADER_INPUT_TYPE Type; // Type of resource (e.g. texture, cbuffer, etc.)
UINT BindPoint; // Starting bind point
UINT BindCount; // Number of contiguous bind points (for arrays)
UINT uFlags; // Input binding flags
D3D_RESOURCE_RETURN_TYPE ReturnType; // Return type (if texture)
D3D_SRV_DIMENSION Dimension; // Dimension (if texture)
UINT NumSamples; // Number of samples (0 if not MS texture)
UINT Space; // Register space
UINT uID; // Range ID in the bytecode
} D3D12_SHADER_INPUT_BIND_DESC;
#define D3D_SHADER_REQUIRES_DOUBLES 0x00000001
#define D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL 0x00000002
#define D3D_SHADER_REQUIRES_UAVS_AT_EVERY_STAGE 0x00000004
#define D3D_SHADER_REQUIRES_64_UAVS 0x00000008
#define D3D_SHADER_REQUIRES_MINIMUM_PRECISION 0x00000010
#define D3D_SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS 0x00000020
#define D3D_SHADER_REQUIRES_11_1_SHADER_EXTENSIONS 0x00000040
#define D3D_SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING 0x00000080
#define D3D_SHADER_REQUIRES_TILED_RESOURCES 0x00000100
#define D3D_SHADER_REQUIRES_STENCIL_REF 0x00000200
#define D3D_SHADER_REQUIRES_INNER_COVERAGE 0x00000400
#define D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS 0x00000800
#define D3D_SHADER_REQUIRES_ROVS 0x00001000
#define D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER 0x00002000
#define D3D_SHADER_REQUIRES_WAVE_OPS 0x00004000
#define D3D_SHADER_REQUIRES_INT64_OPS 0x00008000
#define D3D_SHADER_REQUIRES_VIEW_ID 0x00010000
#define D3D_SHADER_REQUIRES_BARYCENTRICS 0x00020000
#define D3D_SHADER_REQUIRES_NATIVE_16BIT_OPS 0x00040000
#define D3D_SHADER_REQUIRES_SHADING_RATE 0x00080000
#define D3D_SHADER_REQUIRES_RAYTRACING_TIER_1_1 0x00100000
#define D3D_SHADER_REQUIRES_SAMPLER_FEEDBACK 0x00200000
#define D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_TYPED_RESOURCE 0x00400000
#define D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_GROUP_SHARED 0x00800000
#define D3D_SHADER_REQUIRES_DERIVATIVES_IN_MESH_AND_AMPLIFICATION_SHADERS 0x01000000
#define D3D_SHADER_REQUIRES_RESOURCE_DESCRIPTOR_HEAP_INDEXING 0x02000000
#define D3D_SHADER_REQUIRES_SAMPLER_DESCRIPTOR_HEAP_INDEXING 0x04000000
#define D3D_SHADER_REQUIRES_WAVE_MMA 0x08000000
#define D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_DESCRIPTOR_HEAP_RESOURCE 0x10000000
typedef struct _D3D12_LIBRARY_DESC
{
LPCSTR Creator; // The name of the originator of the library.
UINT Flags; // Compilation flags.
UINT FunctionCount; // Number of functions exported from the library.
} D3D12_LIBRARY_DESC;
typedef struct _D3D12_FUNCTION_DESC
{
UINT Version; // Shader version
LPCSTR Creator; // Creator string
UINT Flags; // Shader compilation/parse flags
UINT ConstantBuffers; // Number of constant buffers
UINT BoundResources; // Number of bound resources
UINT InstructionCount; // Number of emitted instructions
UINT TempRegisterCount; // Number of temporary registers used
UINT TempArrayCount; // Number of temporary arrays used
UINT DefCount; // Number of constant defines
UINT DclCount; // Number of declarations (input + output)
UINT TextureNormalInstructions; // Number of non-categorized texture instructions
UINT TextureLoadInstructions; // Number of texture load instructions
UINT TextureCompInstructions; // Number of texture comparison instructions
UINT TextureBiasInstructions; // Number of texture bias instructions
UINT TextureGradientInstructions; // Number of texture gradient instructions
UINT FloatInstructionCount; // Number of floating point arithmetic instructions used
UINT IntInstructionCount; // Number of signed integer arithmetic instructions used
UINT UintInstructionCount; // Number of unsigned integer arithmetic instructions used
UINT StaticFlowControlCount; // Number of static flow control instructions used
UINT DynamicFlowControlCount; // Number of dynamic flow control instructions used
UINT MacroInstructionCount; // Number of macro instructions used
UINT ArrayInstructionCount; // Number of array instructions used
UINT MovInstructionCount; // Number of mov instructions used
UINT MovcInstructionCount; // Number of movc instructions used
UINT ConversionInstructionCount; // Number of type conversion instructions used
UINT BitwiseInstructionCount; // Number of bitwise arithmetic instructions used
D3D_FEATURE_LEVEL MinFeatureLevel; // Min target of the function byte code
UINT64 RequiredFeatureFlags; // Required feature flags
LPCSTR Name; // Function name
INT FunctionParameterCount; // Number of logical parameters in the function signature (not including return)
BOOL HasReturn; // TRUE, if function returns a value, false - it is a subroutine
BOOL Has10Level9VertexShader; // TRUE, if there is a 10L9 VS blob
BOOL Has10Level9PixelShader; // TRUE, if there is a 10L9 PS blob
} D3D12_FUNCTION_DESC;
typedef struct _D3D12_PARAMETER_DESC
{
LPCSTR Name; // Parameter name.
LPCSTR SemanticName; // Parameter semantic name (+index).
D3D_SHADER_VARIABLE_TYPE Type; // Element type.
D3D_SHADER_VARIABLE_CLASS Class; // Scalar/Vector/Matrix.
UINT Rows; // Rows are for matrix parameters.
UINT Columns; // Components or Columns in matrix.
D3D_INTERPOLATION_MODE InterpolationMode; // Interpolation mode.
D3D_PARAMETER_FLAGS Flags; // Parameter modifiers.
UINT FirstInRegister; // The first input register for this parameter.
UINT FirstInComponent; // The first input register component for this parameter.
UINT FirstOutRegister; // The first output register for this parameter.
UINT FirstOutComponent; // The first output register component for this parameter.
} D3D12_PARAMETER_DESC;
//////////////////////////////////////////////////////////////////////////////
// Interfaces ////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
typedef interface ID3D12ShaderReflectionType ID3D12ShaderReflectionType;
typedef interface ID3D12ShaderReflectionType *LPD3D12SHADERREFLECTIONTYPE;
typedef interface ID3D12ShaderReflectionVariable ID3D12ShaderReflectionVariable;
typedef interface ID3D12ShaderReflectionVariable *LPD3D12SHADERREFLECTIONVARIABLE;
typedef interface ID3D12ShaderReflectionConstantBuffer ID3D12ShaderReflectionConstantBuffer;
typedef interface ID3D12ShaderReflectionConstantBuffer *LPD3D12SHADERREFLECTIONCONSTANTBUFFER;
typedef interface ID3D12ShaderReflection ID3D12ShaderReflection;
typedef interface ID3D12ShaderReflection *LPD3D12SHADERREFLECTION;
typedef interface ID3D12LibraryReflection ID3D12LibraryReflection;
typedef interface ID3D12LibraryReflection *LPD3D12LIBRARYREFLECTION;
typedef interface ID3D12FunctionReflection ID3D12FunctionReflection;
typedef interface ID3D12FunctionReflection *LPD3D12FUNCTIONREFLECTION;
typedef interface ID3D12FunctionParameterReflection ID3D12FunctionParameterReflection;
typedef interface ID3D12FunctionParameterReflection *LPD3D12FUNCTIONPARAMETERREFLECTION;
// {E913C351-783D-48CA-A1D1-4F306284AD56}
interface DECLSPEC_UUID("E913C351-783D-48CA-A1D1-4F306284AD56") ID3D12ShaderReflectionType;
DEFINE_GUID(IID_ID3D12ShaderReflectionType,
0xe913c351, 0x783d, 0x48ca, 0xa1, 0xd1, 0x4f, 0x30, 0x62, 0x84, 0xad, 0x56);
#undef INTERFACE
#define INTERFACE ID3D12ShaderReflectionType
DECLARE_INTERFACE(ID3D12ShaderReflectionType)
{
STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_SHADER_TYPE_DESC *pDesc) PURE;
STDMETHOD_(ID3D12ShaderReflectionType*, GetMemberTypeByIndex)(THIS_ _In_ UINT Index) PURE;
STDMETHOD_(ID3D12ShaderReflectionType*, GetMemberTypeByName)(THIS_ _In_ LPCSTR Name) PURE;
STDMETHOD_(LPCSTR, GetMemberTypeName)(THIS_ _In_ UINT Index) PURE;
STDMETHOD(IsEqual)(THIS_ _In_ ID3D12ShaderReflectionType* pType) PURE;
STDMETHOD_(ID3D12ShaderReflectionType*, GetSubType)(THIS) PURE;
STDMETHOD_(ID3D12ShaderReflectionType*, GetBaseClass)(THIS) PURE;
STDMETHOD_(UINT, GetNumInterfaces)(THIS) PURE;
STDMETHOD_(ID3D12ShaderReflectionType*, GetInterfaceByIndex)(THIS_ _In_ UINT uIndex) PURE;
STDMETHOD(IsOfType)(THIS_ _In_ ID3D12ShaderReflectionType* pType) PURE;
STDMETHOD(ImplementsInterface)(THIS_ _In_ ID3D12ShaderReflectionType* pBase) PURE;
};
// {8337A8A6-A216-444A-B2F4-314733A73AEA}
interface DECLSPEC_UUID("8337A8A6-A216-444A-B2F4-314733A73AEA") ID3D12ShaderReflectionVariable;
DEFINE_GUID(IID_ID3D12ShaderReflectionVariable,
0x8337a8a6, 0xa216, 0x444a, 0xb2, 0xf4, 0x31, 0x47, 0x33, 0xa7, 0x3a, 0xea);
#undef INTERFACE
#define INTERFACE ID3D12ShaderReflectionVariable
DECLARE_INTERFACE(ID3D12ShaderReflectionVariable)
{
STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_SHADER_VARIABLE_DESC *pDesc) PURE;
STDMETHOD_(ID3D12ShaderReflectionType*, GetType)(THIS) PURE;
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer*, GetBuffer)(THIS) PURE;
STDMETHOD_(UINT, GetInterfaceSlot)(THIS_ _In_ UINT uArrayIndex) PURE;
};
// {C59598B4-48B3-4869-B9B1-B1618B14A8B7}
interface DECLSPEC_UUID("C59598B4-48B3-4869-B9B1-B1618B14A8B7") ID3D12ShaderReflectionConstantBuffer;
DEFINE_GUID(IID_ID3D12ShaderReflectionConstantBuffer,
0xc59598b4, 0x48b3, 0x4869, 0xb9, 0xb1, 0xb1, 0x61, 0x8b, 0x14, 0xa8, 0xb7);
#undef INTERFACE
#define INTERFACE ID3D12ShaderReflectionConstantBuffer
DECLARE_INTERFACE(ID3D12ShaderReflectionConstantBuffer)
{
STDMETHOD(GetDesc)(THIS_ D3D12_SHADER_BUFFER_DESC *pDesc) PURE;
STDMETHOD_(ID3D12ShaderReflectionVariable*, GetVariableByIndex)(THIS_ _In_ UINT Index) PURE;
STDMETHOD_(ID3D12ShaderReflectionVariable*, GetVariableByName)(THIS_ _In_ LPCSTR Name) PURE;
};
// The ID3D12ShaderReflection IID may change from SDK version to SDK version
// if the reflection API changes. This prevents new code with the new API
// from working with an old binary. Recompiling with the new header
// will pick up the new IID.
// {5A58797D-A72C-478D-8BA2-EFC6B0EFE88E}
interface DECLSPEC_UUID("5A58797D-A72C-478D-8BA2-EFC6B0EFE88E") ID3D12ShaderReflection;
DEFINE_GUID(IID_ID3D12ShaderReflection,
0x5a58797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e);
#undef INTERFACE
#define INTERFACE ID3D12ShaderReflection
DECLARE_INTERFACE_(ID3D12ShaderReflection, IUnknown)
{
STDMETHOD(QueryInterface)(THIS_ _In_ REFIID iid,
_Out_ LPVOID *ppv) PURE;
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
STDMETHOD_(ULONG, Release)(THIS) PURE;
STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_SHADER_DESC *pDesc) PURE;
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer*, GetConstantBufferByIndex)(THIS_ _In_ UINT Index) PURE;
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer*, GetConstantBufferByName)(THIS_ _In_ LPCSTR Name) PURE;
STDMETHOD(GetResourceBindingDesc)(THIS_ _In_ UINT ResourceIndex,
_Out_ D3D12_SHADER_INPUT_BIND_DESC *pDesc) PURE;
STDMETHOD(GetInputParameterDesc)(THIS_ _In_ UINT ParameterIndex,
_Out_ D3D12_SIGNATURE_PARAMETER_DESC *pDesc) PURE;
STDMETHOD(GetOutputParameterDesc)(THIS_ _In_ UINT ParameterIndex,
_Out_ D3D12_SIGNATURE_PARAMETER_DESC *pDesc) PURE;
STDMETHOD(GetPatchConstantParameterDesc)(THIS_ _In_ UINT ParameterIndex,
_Out_ D3D12_SIGNATURE_PARAMETER_DESC *pDesc) PURE;
STDMETHOD_(ID3D12ShaderReflectionVariable*, GetVariableByName)(THIS_ _In_ LPCSTR Name) PURE;
STDMETHOD(GetResourceBindingDescByName)(THIS_ _In_ LPCSTR Name,
_Out_ D3D12_SHADER_INPUT_BIND_DESC *pDesc) PURE;
STDMETHOD_(UINT, GetMovInstructionCount)(THIS) PURE;
STDMETHOD_(UINT, GetMovcInstructionCount)(THIS) PURE;
STDMETHOD_(UINT, GetConversionInstructionCount)(THIS) PURE;
STDMETHOD_(UINT, GetBitwiseInstructionCount)(THIS) PURE;
STDMETHOD_(D3D_PRIMITIVE, GetGSInputPrimitive)(THIS) PURE;
STDMETHOD_(BOOL, IsSampleFrequencyShader)(THIS) PURE;
STDMETHOD_(UINT, GetNumInterfaceSlots)(THIS) PURE;
STDMETHOD(GetMinFeatureLevel)(THIS_ _Out_ enum D3D_FEATURE_LEVEL* pLevel) PURE;
STDMETHOD_(UINT, GetThreadGroupSize)(THIS_
_Out_opt_ UINT* pSizeX,
_Out_opt_ UINT* pSizeY,
_Out_opt_ UINT* pSizeZ) PURE;
STDMETHOD_(UINT64, GetRequiresFlags)(THIS) PURE;
};
// {8E349D19-54DB-4A56-9DC9-119D87BDB804}
interface DECLSPEC_UUID("8E349D19-54DB-4A56-9DC9-119D87BDB804") ID3D12LibraryReflection;
DEFINE_GUID(IID_ID3D12LibraryReflection,
0x8e349d19, 0x54db, 0x4a56, 0x9d, 0xc9, 0x11, 0x9d, 0x87, 0xbd, 0xb8, 0x4);
#undef INTERFACE
#define INTERFACE ID3D12LibraryReflection
DECLARE_INTERFACE_(ID3D12LibraryReflection, IUnknown)
{
STDMETHOD(QueryInterface)(THIS_ _In_ REFIID iid, _Out_ LPVOID * ppv) PURE;
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
STDMETHOD_(ULONG, Release)(THIS) PURE;
STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_LIBRARY_DESC * pDesc) PURE;
STDMETHOD_(ID3D12FunctionReflection *, GetFunctionByIndex)(THIS_ _In_ INT FunctionIndex) PURE;
};
// {1108795C-2772-4BA9-B2A8-D464DC7E2799}
interface DECLSPEC_UUID("1108795C-2772-4BA9-B2A8-D464DC7E2799") ID3D12FunctionReflection;
DEFINE_GUID(IID_ID3D12FunctionReflection,
0x1108795c, 0x2772, 0x4ba9, 0xb2, 0xa8, 0xd4, 0x64, 0xdc, 0x7e, 0x27, 0x99);
#undef INTERFACE
#define INTERFACE ID3D12FunctionReflection
DECLARE_INTERFACE(ID3D12FunctionReflection)
{
STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_FUNCTION_DESC * pDesc) PURE;
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex)(THIS_ _In_ UINT BufferIndex) PURE;
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName)(THIS_ _In_ LPCSTR Name) PURE;
STDMETHOD(GetResourceBindingDesc)(THIS_ _In_ UINT ResourceIndex,
_Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc) PURE;
STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(THIS_ _In_ LPCSTR Name) PURE;
STDMETHOD(GetResourceBindingDescByName)(THIS_ _In_ LPCSTR Name,
_Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc) PURE;
// Use D3D_RETURN_PARAMETER_INDEX to get description of the return value.
STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter)(THIS_ _In_ INT ParameterIndex) PURE;
};
// {EC25F42D-7006-4F2B-B33E-02CC3375733F}
interface DECLSPEC_UUID("EC25F42D-7006-4F2B-B33E-02CC3375733F") ID3D12FunctionParameterReflection;
DEFINE_GUID(IID_ID3D12FunctionParameterReflection,
0xec25f42d, 0x7006, 0x4f2b, 0xb3, 0x3e, 0x2, 0xcc, 0x33, 0x75, 0x73, 0x3f);
#undef INTERFACE
#define INTERFACE ID3D12FunctionParameterReflection
DECLARE_INTERFACE(ID3D12FunctionParameterReflection)
{
STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_PARAMETER_DESC * pDesc) PURE;
};
//////////////////////////////////////////////////////////////////////////////
// APIs //////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
#ifdef __cplusplus
}
#endif //__cplusplus
#endif //__D3D12SHADER_H__
================================================
FILE: Source/External/dxc/inc/dxcapi.h
================================================
///////////////////////////////////////////////////////////////////////////////
// //
// dxcapi.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides declarations for the DirectX Compiler API entry point. //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef __DXC_API__
#define __DXC_API__
#ifdef _WIN32
#ifndef DXC_API_IMPORT
#define DXC_API_IMPORT __declspec(dllimport)
#endif
#else
#ifndef DXC_API_IMPORT
#define DXC_API_IMPORT __attribute__ ((visibility ("default")))
#endif
#endif
#ifdef _WIN32
#ifndef CROSS_PLATFORM_UUIDOF
// Warning: This macro exists in WinAdapter.h as well
#define CROSS_PLATFORM_UUIDOF(interface, spec) \
struct __declspec(uuid(spec)) interface;
#endif
#else
#include
#include "dxc/Support/WinAdapter.h"
#endif
struct IMalloc;
struct IDxcIncludeHandler;
typedef HRESULT (__stdcall *DxcCreateInstanceProc)(
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
typedef HRESULT(__stdcall *DxcCreateInstance2Proc)(
_In_ IMalloc *pMalloc,
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
///
/// Creates a single uninitialized object of the class associated with a specified CLSID.
///
///
/// The CLSID associated with the data and code that will be used to create the object.
///
///
/// A reference to the identifier of the interface to be used to communicate
/// with the object.
///
///
/// Address of pointer variable that receives the interface pointer requested
/// in riid. Upon successful return, *ppv contains the requested interface
/// pointer. Upon failure, *ppv contains NULL.
///
/// While this function is similar to CoCreateInstance, there is no COM involvement.
///
extern "C"
DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance(
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
extern "C"
DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance2(
_In_ IMalloc *pMalloc,
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
// For convenience, equivalent definitions to CP_UTF8 and CP_UTF16.
#define DXC_CP_UTF8 65001
#define DXC_CP_UTF16 1200
#define DXC_CP_UTF32 12000
// Use DXC_CP_ACP for: Binary; ANSI Text; Autodetect UTF with BOM
#define DXC_CP_ACP 0
#ifdef _WIN32
#define DXC_CP_WIDE DXC_CP_UTF16
#else
#define DXC_CP_WIDE DXC_CP_UTF32
#endif
// This flag indicates that the shader hash was computed taking into account source information (-Zss)
#define DXC_HASHFLAG_INCLUDES_SOURCE 1
// Hash digest type for ShaderHash
typedef struct DxcShaderHash {
UINT32 Flags; // DXC_HASHFLAG_*
BYTE HashDigest[16];
} DxcShaderHash;
#define DXC_FOURCC(ch0, ch1, ch2, ch3) ( \
(UINT32)(UINT8)(ch0) | (UINT32)(UINT8)(ch1) << 8 | \
(UINT32)(UINT8)(ch2) << 16 | (UINT32)(UINT8)(ch3) << 24 \
)
#define DXC_PART_PDB DXC_FOURCC('I', 'L', 'D', 'B')
#define DXC_PART_PDB_NAME DXC_FOURCC('I', 'L', 'D', 'N')
#define DXC_PART_PRIVATE_DATA DXC_FOURCC('P', 'R', 'I', 'V')
#define DXC_PART_ROOT_SIGNATURE DXC_FOURCC('R', 'T', 'S', '0')
#define DXC_PART_DXIL DXC_FOURCC('D', 'X', 'I', 'L')
#define DXC_PART_REFLECTION_DATA DXC_FOURCC('S', 'T', 'A', 'T')
#define DXC_PART_SHADER_HASH DXC_FOURCC('H', 'A', 'S', 'H')
#define DXC_PART_INPUT_SIGNATURE DXC_FOURCC('I', 'S', 'G', '1')
#define DXC_PART_OUTPUT_SIGNATURE DXC_FOURCC('O', 'S', 'G', '1')
#define DXC_PART_PATCH_CONSTANT_SIGNATURE DXC_FOURCC('P', 'S', 'G', '1')
// Some option arguments are defined here for continuity with D3DCompile interface
#define DXC_ARG_DEBUG L"-Zi"
#define DXC_ARG_SKIP_VALIDATION L"-Vd"
#define DXC_ARG_SKIP_OPTIMIZATIONS L"-Od"
#define DXC_ARG_PACK_MATRIX_ROW_MAJOR L"-Zpr"
#define DXC_ARG_PACK_MATRIX_COLUMN_MAJOR L"-Zpc"
#define DXC_ARG_AVOID_FLOW_CONTROL L"-Gfa"
#define DXC_ARG_PREFER_FLOW_CONTROL L"-Gfp"
#define DXC_ARG_ENABLE_STRICTNESS L"-Ges"
#define DXC_ARG_ENABLE_BACKWARDS_COMPATIBILITY L"-Gec"
#define DXC_ARG_IEEE_STRICTNESS L"-Gis"
#define DXC_ARG_OPTIMIZATION_LEVEL0 L"-O0"
#define DXC_ARG_OPTIMIZATION_LEVEL1 L"-O1"
#define DXC_ARG_OPTIMIZATION_LEVEL2 L"-O2"
#define DXC_ARG_OPTIMIZATION_LEVEL3 L"-O3"
#define DXC_ARG_WARNINGS_ARE_ERRORS L"-WX"
#define DXC_ARG_RESOURCES_MAY_ALIAS L"-res_may_alias"
#define DXC_ARG_ALL_RESOURCES_BOUND L"-all_resources_bound"
#define DXC_ARG_DEBUG_NAME_FOR_SOURCE L"-Zss"
#define DXC_ARG_DEBUG_NAME_FOR_BINARY L"-Zsb"
// IDxcBlob is an alias of ID3D10Blob and ID3DBlob
CROSS_PLATFORM_UUIDOF(IDxcBlob, "8BA5FB08-5195-40e2-AC58-0D989C3A0102")
struct IDxcBlob : public IUnknown {
public:
virtual LPVOID STDMETHODCALLTYPE GetBufferPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcBlobEncoding, "7241d424-2646-4191-97c0-98e96e42fc68")
struct IDxcBlobEncoding : public IDxcBlob {
public:
virtual HRESULT STDMETHODCALLTYPE GetEncoding(_Out_ BOOL *pKnown,
_Out_ UINT32 *pCodePage) = 0;
};
// Notes on IDxcBlobWide and IDxcBlobUtf8
// These guarantee null-terminated text and eithre utf8 or the native wide char encoding.
// GetBufferSize() will return the size in bytes, including null-terminator
// GetStringLength() will return the length in characters, excluding the null-terminator
// Name strings will use IDxcBlobWide, while other string output blobs,
// such as errors/warnings, preprocessed HLSL, or other text will be based
// on the -encoding option.
// The API will use this interface for output name strings
CROSS_PLATFORM_UUIDOF(IDxcBlobWide, "A3F84EAB-0FAA-497E-A39C-EE6ED60B2D84")
struct IDxcBlobWide : public IDxcBlobEncoding {
public:
virtual LPCWSTR STDMETHODCALLTYPE GetStringPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcBlobUtf8, "3DA636C9-BA71-4024-A301-30CBF125305B")
struct IDxcBlobUtf8 : public IDxcBlobEncoding {
public:
virtual LPCSTR STDMETHODCALLTYPE GetStringPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0;
};
// Define legacy name IDxcBlobUtf16 as IDxcBlobWide for Win32
#ifdef _WIN32
typedef IDxcBlobWide IDxcBlobUtf16;
#endif
CROSS_PLATFORM_UUIDOF(IDxcIncludeHandler, "7f61fc7d-950d-467f-b3e3-3c02fb49187c")
struct IDxcIncludeHandler : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE LoadSource(
_In_z_ LPCWSTR pFilename, // Candidate filename.
_COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource // Resultant source object for included file, nullptr if not found.
) = 0;
};
// Structure for supplying bytes or text input to Dxc APIs.
// Use Encoding = 0 for non-text bytes, ANSI text, or unknown with BOM.
typedef struct DxcBuffer {
LPCVOID Ptr;
SIZE_T Size;
UINT Encoding;
} DxcText;
struct DxcDefine {
LPCWSTR Name;
_Maybenull_ LPCWSTR Value;
};
CROSS_PLATFORM_UUIDOF(IDxcCompilerArgs, "73EFFE2A-70DC-45F8-9690-EFF64C02429D")
struct IDxcCompilerArgs : public IUnknown {
// Pass GetArguments() and GetCount() to Compile
virtual LPCWSTR* STDMETHODCALLTYPE GetArguments() = 0;
virtual UINT32 STDMETHODCALLTYPE GetCount() = 0;
// Add additional arguments or defines here, if desired.
virtual HRESULT STDMETHODCALLTYPE AddArguments(
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments to add
_In_ UINT32 argCount // Number of arguments to add
) = 0;
virtual HRESULT STDMETHODCALLTYPE AddArgumentsUTF8(
_In_opt_count_(argCount)LPCSTR *pArguments, // Array of pointers to UTF-8 arguments to add
_In_ UINT32 argCount // Number of arguments to add
) = 0;
virtual HRESULT STDMETHODCALLTYPE AddDefines(
_In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount // Number of defines
) = 0;
};
//////////////////////////
// Legacy Interfaces
/////////////////////////
// NOTE: IDxcUtils replaces IDxcLibrary
CROSS_PLATFORM_UUIDOF(IDxcLibrary, "e5204dc7-d18c-4c3c-bdfb-851673980fe7")
struct IDxcLibrary : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE SetMalloc(_In_opt_ IMalloc *pMalloc) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromBlob(
_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, _COM_Outptr_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromFile(
_In_z_ LPCWSTR pFileName, _In_opt_ UINT32* codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingFromPinned(
_In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnHeapCopy(
_In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnMalloc(
_In_bytecount_(size) LPCVOID pText, IMalloc *pIMalloc, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateIncludeHandler(
_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromBlobReadOnly(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
// Renamed from GetBlobAsUtf16 to GetBlobAsWide
virtual HRESULT STDMETHODCALLTYPE GetBlobAsWide(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
#ifdef _WIN32
// Alias to GetBlobAsWide on Win32
inline HRESULT GetBlobAsUtf16(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) {
return this->GetBlobAsWide(pBlob, pBlobEncoding);
}
#endif
};
// NOTE: IDxcResult replaces IDxcOperationResult
CROSS_PLATFORM_UUIDOF(IDxcOperationResult, "CEDB484A-D4E9-445A-B991-CA21CA157DC2")
struct IDxcOperationResult : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetStatus(_Out_ HRESULT *pStatus) = 0;
// GetResult returns the main result of the operation.
// This corresponds to:
// DXC_OUT_OBJECT - Compile() with shader or library target
// DXC_OUT_DISASSEMBLY - Disassemble()
// DXC_OUT_HLSL - Compile() with -P
// DXC_OUT_ROOT_SIGNATURE - Compile() with rootsig_* target
virtual HRESULT STDMETHODCALLTYPE GetResult(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0;
// GetErrorBuffer Corresponds to DXC_OUT_ERRORS.
virtual HRESULT STDMETHODCALLTYPE GetErrorBuffer(_COM_Outptr_result_maybenull_ IDxcBlobEncoding **ppErrors) = 0;
};
// NOTE: IDxcCompiler3 replaces IDxcCompiler and IDxcCompiler2
CROSS_PLATFORM_UUIDOF(IDxcCompiler, "8c210bf3-011f-4422-8d70-6f9acb8db617")
struct IDxcCompiler : public IUnknown {
// Compile a single entry point to the target shader model
virtual HRESULT STDMETHODCALLTYPE Compile(
_In_ IDxcBlob *pSource, // Source text to compile
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // entry point name
_In_z_ LPCWSTR pTargetProfile, // shader profile to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult // Compiler output status, buffer, and errors
) = 0;
// Preprocess source text
virtual HRESULT STDMETHODCALLTYPE Preprocess(
_In_ IDxcBlob *pSource, // Source text to preprocess
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult // Preprocessor output status, buffer, and errors
) = 0;
// Disassemble a program.
virtual HRESULT STDMETHODCALLTYPE Disassemble(
_In_ IDxcBlob *pSource, // Program to disassemble.
_COM_Outptr_ IDxcBlobEncoding **ppDisassembly // Disassembly text.
) = 0;
};
// NOTE: IDxcCompiler3 replaces IDxcCompiler and IDxcCompiler2
CROSS_PLATFORM_UUIDOF(IDxcCompiler2, "A005A9D9-B8BB-4594-B5C9-0E633BEC4D37")
struct IDxcCompiler2 : public IDxcCompiler {
// Compile a single entry point to the target shader model with debug information.
virtual HRESULT STDMETHODCALLTYPE CompileWithDebug(
_In_ IDxcBlob *pSource, // Source text to compile
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // Entry point name
_In_z_ LPCWSTR pTargetProfile, // Shader profile to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
_Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob. (Must be CoTaskMemFree()'d!)
_COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcLinker, "F1B5BE2A-62DD-4327-A1C2-42AC1E1E78E6")
struct IDxcLinker : public IUnknown {
public:
// Register a library with name to ref it later.
virtual HRESULT RegisterLibrary(
_In_opt_ LPCWSTR pLibName, // Name of the library.
_In_ IDxcBlob *pLib // Library blob.
) = 0;
// Links the shader and produces a shader blob that the Direct3D runtime can
// use.
virtual HRESULT STDMETHODCALLTYPE Link(
_In_opt_ LPCWSTR pEntryName, // Entry point name
_In_ LPCWSTR pTargetProfile, // shader profile to link
_In_count_(libCount)
const LPCWSTR *pLibNames, // Array of library names to link
_In_ UINT32 libCount, // Number of libraries to link
_In_opt_count_(argCount) const LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_COM_Outptr_
IDxcOperationResult **ppResult // Linker output status, buffer, and errors
) = 0;
};
/////////////////////////
// Latest interfaces. Please use these
////////////////////////
// NOTE: IDxcUtils replaces IDxcLibrary
CROSS_PLATFORM_UUIDOF(IDxcUtils, "4605C4CB-2019-492A-ADA4-65F20BB7D67F")
struct IDxcUtils : public IUnknown {
// Create a sub-blob that holds a reference to the outer blob and points to its memory.
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromBlob(
_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, _COM_Outptr_ IDxcBlob **ppResult) = 0;
// For codePage, use 0 (or DXC_CP_ACP) for raw binary or ANSI code page
// Creates a blob referencing existing memory, with no copy.
// User must manage the memory lifetime separately.
// (was: CreateBlobWithEncodingFromPinned)
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromPinned(
_In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
// Create blob, taking ownership of memory allocated with supplied allocator.
// (was: CreateBlobWithEncodingOnMalloc)
virtual HRESULT STDMETHODCALLTYPE MoveToBlob(
_In_bytecount_(size) LPCVOID pData, IMalloc *pIMalloc, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
////
// New blobs and copied contents are allocated with the current allocator
// Copy blob contents to memory owned by the new blob.
// (was: CreateBlobWithEncodingOnHeapCopy)
virtual HRESULT STDMETHODCALLTYPE CreateBlob(
_In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
// (was: CreateBlobFromFile)
virtual HRESULT STDMETHODCALLTYPE LoadFile(
_In_z_ LPCWSTR pFileName, _In_opt_ UINT32* pCodePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateReadOnlyStreamFromBlob(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0;
// Create default file-based include handler
virtual HRESULT STDMETHODCALLTYPE CreateDefaultIncludeHandler(
_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0;
// Convert or return matching encoded text blobs
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobUtf8 **pBlobEncoding) = 0;
// Renamed from GetBlobAsUtf16 to GetBlobAsWide
virtual HRESULT STDMETHODCALLTYPE GetBlobAsWide(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobWide **pBlobEncoding) = 0;
#ifdef _WIN32
// Alias to GetBlobAsWide on Win32
inline HRESULT GetBlobAsUtf16(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobWide **pBlobEncoding) {
return this->GetBlobAsWide(pBlob, pBlobEncoding);
}
#endif
virtual HRESULT STDMETHODCALLTYPE GetDxilContainerPart(
_In_ const DxcBuffer *pShader,
_In_ UINT32 DxcPart,
_Outptr_result_nullonfailure_ void **ppPartData,
_Out_ UINT32 *pPartSizeInBytes) = 0;
// Create reflection interface from serialized Dxil container, or DXC_PART_REFLECTION_DATA.
// TBD: Require part header for RDAT? (leaning towards yes)
virtual HRESULT STDMETHODCALLTYPE CreateReflection(
_In_ const DxcBuffer *pData, REFIID iid, void **ppvReflection) = 0;
virtual HRESULT STDMETHODCALLTYPE BuildArguments(
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // Entry point name. (-E)
_In_z_ LPCWSTR pTargetProfile, // Shader profile to compile. (-T)
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_COM_Outptr_ IDxcCompilerArgs **ppArgs // Arguments you can use with Compile() method
) = 0;
// Takes the shader PDB and returns the hash and the container inside it
virtual HRESULT STDMETHODCALLTYPE GetPDBContents(
_In_ IDxcBlob *pPDBBlob, _COM_Outptr_ IDxcBlob **ppHash, _COM_Outptr_ IDxcBlob **ppContainer) = 0;
};
// For use with IDxcResult::[Has|Get]Output dxcOutKind argument
// Note: text outputs returned from version 2 APIs are UTF-8 or UTF-16 based on -encoding option
typedef enum DXC_OUT_KIND {
DXC_OUT_NONE = 0,
DXC_OUT_OBJECT = 1, // IDxcBlob - Shader or library object
DXC_OUT_ERRORS = 2, // IDxcBlobUtf8 or IDxcBlobWide
DXC_OUT_PDB = 3, // IDxcBlob
DXC_OUT_SHADER_HASH = 4, // IDxcBlob - DxcShaderHash of shader or shader with source info (-Zsb/-Zss)
DXC_OUT_DISASSEMBLY = 5, // IDxcBlobUtf8 or IDxcBlobWide - from Disassemble
DXC_OUT_HLSL = 6, // IDxcBlobUtf8 or IDxcBlobWide - from Preprocessor or Rewriter
DXC_OUT_TEXT = 7, // IDxcBlobUtf8 or IDxcBlobWide - other text, such as -ast-dump or -Odump
DXC_OUT_REFLECTION = 8, // IDxcBlob - RDAT part with reflection data
DXC_OUT_ROOT_SIGNATURE = 9, // IDxcBlob - Serialized root signature output
DXC_OUT_EXTRA_OUTPUTS = 10,// IDxcExtraResults - Extra outputs
DXC_OUT_REMARKS = 11, // IDxcBlobUtf8 or IDxcBlobWide - text directed at stdout
DXC_OUT_TIME_REPORT = 12, // IDxcBlobUtf8 or IDxcBlobWide - text directed at stdout
DXC_OUT_TIME_TRACE = 13, // IDxcBlobUtf8 or IDxcBlobWide - text directed at stdout
DXC_OUT_LAST = DXC_OUT_TIME_TRACE, // Last value for a counter
DXC_OUT_NUM_ENUMS,
DXC_OUT_FORCE_DWORD = 0xFFFFFFFF
} DXC_OUT_KIND;
static_assert(DXC_OUT_NUM_ENUMS == DXC_OUT_LAST + 1,
"DXC_OUT_* Enum added and last value not updated.");
CROSS_PLATFORM_UUIDOF(IDxcResult, "58346CDA-DDE7-4497-9461-6F87AF5E0659")
struct IDxcResult : public IDxcOperationResult {
virtual BOOL STDMETHODCALLTYPE HasOutput(_In_ DXC_OUT_KIND dxcOutKind) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOutput(_In_ DXC_OUT_KIND dxcOutKind,
_In_ REFIID iid, _COM_Outptr_opt_result_maybenull_ void **ppvObject,
_COM_Outptr_ IDxcBlobWide **ppOutputName) = 0;
virtual UINT32 GetNumOutputs() = 0;
virtual DXC_OUT_KIND GetOutputByIndex(UINT32 Index) = 0;
virtual DXC_OUT_KIND PrimaryOutput() = 0;
};
// Special names for extra output that should get written to specific streams
#define DXC_EXTRA_OUTPUT_NAME_STDOUT L"*stdout*"
#define DXC_EXTRA_OUTPUT_NAME_STDERR L"*stderr*"
CROSS_PLATFORM_UUIDOF(IDxcExtraOutputs, "319b37a2-a5c2-494a-a5de-4801b2faf989")
struct IDxcExtraOutputs : public IUnknown {
virtual UINT32 STDMETHODCALLTYPE GetOutputCount() = 0;
virtual HRESULT STDMETHODCALLTYPE GetOutput(_In_ UINT32 uIndex,
_In_ REFIID iid, _COM_Outptr_opt_result_maybenull_ void **ppvObject,
_COM_Outptr_opt_result_maybenull_ IDxcBlobWide **ppOutputType,
_COM_Outptr_opt_result_maybenull_ IDxcBlobWide **ppOutputName) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcCompiler3, "228B4687-5A6A-4730-900C-9702B2203F54")
struct IDxcCompiler3 : public IUnknown {
// Compile a single entry point to the target shader model,
// Compile a library to a library target (-T lib_*),
// Compile a root signature (-T rootsig_*), or
// Preprocess HLSL source (-P)
virtual HRESULT STDMETHODCALLTYPE Compile(
_In_ const DxcBuffer *pSource, // Source text to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, buffer, and errors
) = 0;
// Disassemble a program.
virtual HRESULT STDMETHODCALLTYPE Disassemble(
_In_ const DxcBuffer *pObject, // Program to disassemble: dxil container or bitcode.
_In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, disassembly text, and errors
) = 0;
};
static const UINT32 DxcValidatorFlags_Default = 0;
static const UINT32 DxcValidatorFlags_InPlaceEdit = 1; // Validator is allowed to update shader blob in-place.
static const UINT32 DxcValidatorFlags_RootSignatureOnly = 2;
static const UINT32 DxcValidatorFlags_ModuleOnly = 4;
static const UINT32 DxcValidatorFlags_ValidMask = 0x7;
CROSS_PLATFORM_UUIDOF(IDxcValidator, "A6E82BD2-1FD7-4826-9811-2857E797F49A")
struct IDxcValidator : public IUnknown {
// Validate a shader.
virtual HRESULT STDMETHODCALLTYPE Validate(
_In_ IDxcBlob *pShader, // Shader to validate.
_In_ UINT32 Flags, // Validation flags.
_COM_Outptr_ IDxcOperationResult **ppResult // Validation output status, buffer, and errors
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcValidator2, "458e1fd1-b1b2-4750-a6e1-9c10f03bed92")
struct IDxcValidator2 : public IDxcValidator {
// Validate a shader.
virtual HRESULT STDMETHODCALLTYPE ValidateWithDebug(
_In_ IDxcBlob *pShader, // Shader to validate.
_In_ UINT32 Flags, // Validation flags.
_In_opt_ DxcBuffer *pOptDebugBitcode, // Optional debug module bitcode to provide line numbers
_COM_Outptr_ IDxcOperationResult **ppResult // Validation output status, buffer, and errors
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcContainerBuilder, "334b1f50-2292-4b35-99a1-25588d8c17fe")
struct IDxcContainerBuilder : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pDxilContainerHeader) = 0; // Loads DxilContainer to the builder
virtual HRESULT STDMETHODCALLTYPE AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource) = 0; // Part to add to the container
virtual HRESULT STDMETHODCALLTYPE RemovePart(_In_ UINT32 fourCC) = 0; // Remove the part with fourCC
virtual HRESULT STDMETHODCALLTYPE SerializeContainer(_Out_ IDxcOperationResult **ppResult) = 0; // Builds a container of the given container builder state
};
CROSS_PLATFORM_UUIDOF(IDxcAssembler, "091f7a26-1c1f-4948-904b-e6e3a8a771d5")
struct IDxcAssembler : public IUnknown {
// Assemble dxil in ll or llvm bitcode to DXIL container.
virtual HRESULT STDMETHODCALLTYPE AssembleToContainer(
_In_ IDxcBlob *pShader, // Shader to assemble.
_COM_Outptr_ IDxcOperationResult **ppResult // Assembly output status, buffer, and errors
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcContainerReflection, "d2c21b26-8350-4bdc-976a-331ce6f4c54c")
struct IDxcContainerReflection : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pContainer) = 0; // Container to load.
virtual HRESULT STDMETHODCALLTYPE GetPartCount(_Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartKind(UINT32 idx, _Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartContent(UINT32 idx, _COM_Outptr_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE FindFirstPartKind(UINT32 kind, _Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartReflection(UINT32 idx, REFIID iid, void **ppvObject) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcOptimizerPass, "AE2CD79F-CC22-453F-9B6B-B124E7A5204C")
struct IDxcOptimizerPass : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetOptionName(_COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDescription(_COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgName(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgDescription(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcOptimizer, "25740E2E-9CBA-401B-9119-4FB42F39F270")
struct IDxcOptimizer : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetAvailablePassCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetAvailablePass(UINT32 index, _COM_Outptr_ IDxcOptimizerPass** ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE RunOptimizer(IDxcBlob *pBlob,
_In_count_(optionCount) LPCWSTR *ppOptions, UINT32 optionCount,
_COM_Outptr_ IDxcBlob **pOutputModule,
_COM_Outptr_opt_ IDxcBlobEncoding **ppOutputText) = 0;
};
static const UINT32 DxcVersionInfoFlags_None = 0;
static const UINT32 DxcVersionInfoFlags_Debug = 1; // Matches VS_FF_DEBUG
static const UINT32 DxcVersionInfoFlags_Internal = 2; // Internal Validator (non-signing)
CROSS_PLATFORM_UUIDOF(IDxcVersionInfo, "b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e")
struct IDxcVersionInfo : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcVersionInfo2, "fb6904c4-42f0-4b62-9c46-983af7da7c83")
struct IDxcVersionInfo2 : public IDxcVersionInfo {
virtual HRESULT STDMETHODCALLTYPE GetCommitInfo(
_Out_ UINT32 *pCommitCount, // The total number commits.
_Outptr_result_z_ char **pCommitHash // The SHA of the latest commit. (Must be CoTaskMemFree()'d!)
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcVersionInfo3, "5e13e843-9d25-473c-9ad2-03b2d0b44b1e")
struct IDxcVersionInfo3 : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetCustomVersionString(
_Outptr_result_z_ char **pVersionString // Custom version string for compiler. (Must be CoTaskMemFree()'d!)
) = 0;
};
struct DxcArgPair {
const WCHAR *pName;
const WCHAR *pValue;
};
CROSS_PLATFORM_UUIDOF(IDxcPdbUtils, "E6C9647E-9D6A-4C3B-B94C-524B5A6C343D")
struct IDxcPdbUtils : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pPdbOrDxil) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSourceCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSource(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobEncoding **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSourceName(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFlagCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFlag(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArgCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArg(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArgPairCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArgPair(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pName, _Outptr_result_z_ BSTR *pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDefineCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDefine(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTargetProfile(_Outptr_result_z_ BSTR *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetEntryPoint(_Outptr_result_z_ BSTR *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetMainFileName(_Outptr_result_z_ BSTR *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetHash(_COM_Outptr_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetName(_Outptr_result_z_ BSTR *pResult) = 0;
virtual BOOL STDMETHODCALLTYPE IsFullPDB() = 0;
virtual HRESULT STDMETHODCALLTYPE GetFullPDB(_COM_Outptr_ IDxcBlob **ppFullPDB) = 0;
virtual HRESULT STDMETHODCALLTYPE GetVersionInfo(_COM_Outptr_ IDxcVersionInfo **ppVersionInfo) = 0;
virtual HRESULT STDMETHODCALLTYPE SetCompiler(_In_ IDxcCompiler3 *pCompiler) = 0;
virtual HRESULT STDMETHODCALLTYPE CompileForFullPDB(_COM_Outptr_ IDxcResult **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE OverrideArgs(_In_ DxcArgPair *pArgPairs, UINT32 uNumArgPairs) = 0;
virtual HRESULT STDMETHODCALLTYPE OverrideRootSignature(_In_ const WCHAR *pRootSignature) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcPdbUtils2, "4315D938-F369-4F93-95A2-252017CC3807")
struct IDxcPdbUtils2 : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pPdbOrDxil) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSourceCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSource(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobEncoding **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSourceName(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLibraryPDBCount(UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLibraryPDB(_In_ UINT32 uIndex, _COM_Outptr_ IDxcPdbUtils2 **ppOutPdbUtils, _COM_Outptr_opt_result_maybenull_ IDxcBlobWide **ppLibraryName) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFlagCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFlag(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArgCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArg(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArgPairCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArgPair(_In_ UINT32 uIndex, _COM_Outptr_result_maybenull_ IDxcBlobWide **ppName, _COM_Outptr_result_maybenull_ IDxcBlobWide **ppValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDefineCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDefine(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTargetProfile(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetEntryPoint(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetMainFileName(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetHash(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetName(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetVersionInfo(_COM_Outptr_result_maybenull_ IDxcVersionInfo **ppVersionInfo) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCustomToolchainID(_Out_ UINT32 *pID) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCustomToolchainData(_COM_Outptr_result_maybenull_ IDxcBlob **ppBlob) = 0;
virtual HRESULT STDMETHODCALLTYPE GetWholeDxil(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0;
virtual BOOL STDMETHODCALLTYPE IsFullPDB() = 0;
virtual BOOL STDMETHODCALLTYPE IsPDBRef() = 0;
};
// Note: __declspec(selectany) requires 'extern'
// On Linux __declspec(selectany) is removed and using 'extern' results in link error.
#ifdef _MSC_VER
#define CLSID_SCOPE __declspec(selectany) extern
#else
#define CLSID_SCOPE
#endif
CLSID_SCOPE const CLSID CLSID_DxcCompiler = {
0x73e22d93,
0xe6ce,
0x47f3,
{0xb5, 0xbf, 0xf0, 0x66, 0x4f, 0x39, 0xc1, 0xb0}};
// {EF6A8087-B0EA-4D56-9E45-D07E1A8B7806}
CLSID_SCOPE const GUID CLSID_DxcLinker = {
0xef6a8087,
0xb0ea,
0x4d56,
{0x9e, 0x45, 0xd0, 0x7e, 0x1a, 0x8b, 0x78, 0x6}};
// {CD1F6B73-2AB0-484D-8EDC-EBE7A43CA09F}
CLSID_SCOPE const CLSID CLSID_DxcDiaDataSource = {
0xcd1f6b73,
0x2ab0,
0x484d,
{0x8e, 0xdc, 0xeb, 0xe7, 0xa4, 0x3c, 0xa0, 0x9f}};
// {3E56AE82-224D-470F-A1A1-FE3016EE9F9D}
CLSID_SCOPE const CLSID CLSID_DxcCompilerArgs = {
0x3e56ae82,
0x224d,
0x470f,
{0xa1, 0xa1, 0xfe, 0x30, 0x16, 0xee, 0x9f, 0x9d}};
// {6245D6AF-66E0-48FD-80B4-4D271796748C}
CLSID_SCOPE const GUID CLSID_DxcLibrary = {
0x6245d6af,
0x66e0,
0x48fd,
{0x80, 0xb4, 0x4d, 0x27, 0x17, 0x96, 0x74, 0x8c}};
CLSID_SCOPE const GUID CLSID_DxcUtils = CLSID_DxcLibrary;
// {8CA3E215-F728-4CF3-8CDD-88AF917587A1}
CLSID_SCOPE const GUID CLSID_DxcValidator = {
0x8ca3e215,
0xf728,
0x4cf3,
{0x8c, 0xdd, 0x88, 0xaf, 0x91, 0x75, 0x87, 0xa1}};
// {D728DB68-F903-4F80-94CD-DCCF76EC7151}
CLSID_SCOPE const GUID CLSID_DxcAssembler = {
0xd728db68,
0xf903,
0x4f80,
{0x94, 0xcd, 0xdc, 0xcf, 0x76, 0xec, 0x71, 0x51}};
// {b9f54489-55b8-400c-ba3a-1675e4728b91}
CLSID_SCOPE const GUID CLSID_DxcContainerReflection = {
0xb9f54489,
0x55b8,
0x400c,
{0xba, 0x3a, 0x16, 0x75, 0xe4, 0x72, 0x8b, 0x91}};
// {AE2CD79F-CC22-453F-9B6B-B124E7A5204C}
CLSID_SCOPE const GUID CLSID_DxcOptimizer = {
0xae2cd79f,
0xcc22,
0x453f,
{0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c}};
// {94134294-411f-4574-b4d0-8741e25240d2}
CLSID_SCOPE const GUID CLSID_DxcContainerBuilder = {
0x94134294,
0x411f,
0x4574,
{0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2}};
// {54621dfb-f2ce-457e-ae8c-ec355faeec7c}
CLSID_SCOPE const GUID CLSID_DxcPdbUtils = {
0x54621dfb,
0xf2ce,
0x457e,
{0xae, 0x8c, 0xec, 0x35, 0x5f, 0xae, 0xec, 0x7c}};
#endif
================================================
FILE: Source/External/dxc/inc/dxcerrors.h
================================================
///////////////////////////////////////////////////////////////////////////////
// //
// dxcerror.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides definition of error codes. //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef __DXC_ERRORS__
#define __DXC_ERRORS__
#ifndef FACILITY_GRAPHICS
#define FACILITY_GRAPHICS 36
#endif
#define DXC_EXCEPTION_CODE(name, status) \
static constexpr DWORD EXCEPTION_##name = \
(0xc0000000u | (FACILITY_GRAPHICS << 16) | (0xff00u | (status & 0xffu)));
DXC_EXCEPTION_CODE(LOAD_LIBRARY_FAILED, 0x00u)
DXC_EXCEPTION_CODE(NO_HMODULE, 0x01u)
DXC_EXCEPTION_CODE(GET_PROC_FAILED, 0x02u)
#undef DXC_EXCEPTION_CODE
#endif
================================================
FILE: Source/External/dxc/inc/dxcisense.h
================================================
///////////////////////////////////////////////////////////////////////////////
// //
// dxcisense.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides declarations for the DirectX Compiler IntelliSense component. //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef __DXC_ISENSE__
#define __DXC_ISENSE__
#include "dxcapi.h"
#ifndef _WIN32
#include "Support/WinAdapter.h"
#endif
typedef enum DxcGlobalOptions
{
DxcGlobalOpt_None = 0x0,
DxcGlobalOpt_ThreadBackgroundPriorityForIndexing = 0x1,
DxcGlobalOpt_ThreadBackgroundPriorityForEditing = 0x2,
DxcGlobalOpt_ThreadBackgroundPriorityForAll =
DxcGlobalOpt_ThreadBackgroundPriorityForIndexing | DxcGlobalOpt_ThreadBackgroundPriorityForEditing
} DxcGlobalOptions;
typedef enum DxcTokenKind
{
DxcTokenKind_Punctuation = 0, // A token that contains some kind of punctuation.
DxcTokenKind_Keyword = 1, // A language keyword.
DxcTokenKind_Identifier = 2, // An identifier (that is not a keyword).
DxcTokenKind_Literal = 3, // A numeric, string, or character literal.
DxcTokenKind_Comment = 4, // A comment.
DxcTokenKind_Unknown = 5, // An unknown token (possibly known to a future version).
DxcTokenKind_BuiltInType = 6, // A built-in type like int, void or float3.
} DxcTokenKind;
typedef enum DxcTypeKind
{
DxcTypeKind_Invalid = 0, // Reprents an invalid type (e.g., where no type is available).
DxcTypeKind_Unexposed = 1, // A type whose specific kind is not exposed via this interface.
// Builtin types
DxcTypeKind_Void = 2,
DxcTypeKind_Bool = 3,
DxcTypeKind_Char_U = 4,
DxcTypeKind_UChar = 5,
DxcTypeKind_Char16 = 6,
DxcTypeKind_Char32 = 7,
DxcTypeKind_UShort = 8,
DxcTypeKind_UInt = 9,
DxcTypeKind_ULong = 10,
DxcTypeKind_ULongLong = 11,
DxcTypeKind_UInt128 = 12,
DxcTypeKind_Char_S = 13,
DxcTypeKind_SChar = 14,
DxcTypeKind_WChar = 15,
DxcTypeKind_Short = 16,
DxcTypeKind_Int = 17,
DxcTypeKind_Long = 18,
DxcTypeKind_LongLong = 19,
DxcTypeKind_Int128 = 20,
DxcTypeKind_Float = 21,
DxcTypeKind_Double = 22,
DxcTypeKind_LongDouble = 23,
DxcTypeKind_NullPtr = 24,
DxcTypeKind_Overload = 25,
DxcTypeKind_Dependent = 26,
DxcTypeKind_ObjCId = 27,
DxcTypeKind_ObjCClass = 28,
DxcTypeKind_ObjCSel = 29,
DxcTypeKind_FirstBuiltin = DxcTypeKind_Void,
DxcTypeKind_LastBuiltin = DxcTypeKind_ObjCSel,
DxcTypeKind_Complex = 100,
DxcTypeKind_Pointer = 101,
DxcTypeKind_BlockPointer = 102,
DxcTypeKind_LValueReference = 103,
DxcTypeKind_RValueReference = 104,
DxcTypeKind_Record = 105,
DxcTypeKind_Enum = 106,
DxcTypeKind_Typedef = 107,
DxcTypeKind_ObjCInterface = 108,
DxcTypeKind_ObjCObjectPointer = 109,
DxcTypeKind_FunctionNoProto = 110,
DxcTypeKind_FunctionProto = 111,
DxcTypeKind_ConstantArray = 112,
DxcTypeKind_Vector = 113,
DxcTypeKind_IncompleteArray = 114,
DxcTypeKind_VariableArray = 115,
DxcTypeKind_DependentSizedArray = 116,
DxcTypeKind_MemberPointer = 117
} DxcTypeKind;
// Describes the severity of a particular diagnostic.
typedef enum DxcDiagnosticSeverity
{
// A diagnostic that has been suppressed, e.g., by a command-line option.
DxcDiagnostic_Ignored = 0,
// This diagnostic is a note that should be attached to the previous (non-note) diagnostic.
DxcDiagnostic_Note = 1,
// This diagnostic indicates suspicious code that may not be wrong.
DxcDiagnostic_Warning = 2,
// This diagnostic indicates that the code is ill-formed.
DxcDiagnostic_Error = 3,
// This diagnostic indicates that the code is ill-formed such that future
// parser rec unlikely to produce useful results.
DxcDiagnostic_Fatal = 4
} DxcDiagnosticSeverity;
// Options to control the display of diagnostics.
typedef enum DxcDiagnosticDisplayOptions
{
// Display the source-location information where the diagnostic was located.
DxcDiagnostic_DisplaySourceLocation = 0x01,
// If displaying the source-location information of the diagnostic,
// also include the column number.
DxcDiagnostic_DisplayColumn = 0x02,
// If displaying the source-location information of the diagnostic,
// also include information about source ranges in a machine-parsable format.
DxcDiagnostic_DisplaySourceRanges = 0x04,
// Display the option name associated with this diagnostic, if any.
DxcDiagnostic_DisplayOption = 0x08,
// Display the category number associated with this diagnostic, if any.
DxcDiagnostic_DisplayCategoryId = 0x10,
// Display the category name associated with this diagnostic, if any.
DxcDiagnostic_DisplayCategoryName = 0x20,
// Display the severity of the diagnostic message.
DxcDiagnostic_DisplaySeverity = 0x200
} DxcDiagnosticDisplayOptions;
typedef enum DxcTranslationUnitFlags
{
// Used to indicate that no special translation-unit options are needed.
DxcTranslationUnitFlags_None = 0x0,
// Used to indicate that the parser should construct a "detailed"
// preprocessing record, including all macro definitions and instantiations.
DxcTranslationUnitFlags_DetailedPreprocessingRecord = 0x01,
// Used to indicate that the translation unit is incomplete.
DxcTranslationUnitFlags_Incomplete = 0x02,
// Used to indicate that the translation unit should be built with an
// implicit precompiled header for the preamble.
DxcTranslationUnitFlags_PrecompiledPreamble = 0x04,
// Used to indicate that the translation unit should cache some
// code-completion results with each reparse of the source file.
DxcTranslationUnitFlags_CacheCompletionResults = 0x08,
// Used to indicate that the translation unit will be serialized with
// SaveTranslationUnit.
DxcTranslationUnitFlags_ForSerialization = 0x10,
// DEPRECATED
DxcTranslationUnitFlags_CXXChainedPCH = 0x20,
// Used to indicate that function/method bodies should be skipped while parsing.
DxcTranslationUnitFlags_SkipFunctionBodies = 0x40,
// Used to indicate that brief documentation comments should be
// included into the set of code completions returned from this translation
// unit.
DxcTranslationUnitFlags_IncludeBriefCommentsInCodeCompletion = 0x80,
// Used to indicate that compilation should occur on the caller's thread.
DxcTranslationUnitFlags_UseCallerThread = 0x800
} DxcTranslationUnitFlags;
typedef enum DxcCursorFormatting
{
DxcCursorFormatting_Default = 0x0, // Default rules, language-insensitive formatting.
DxcCursorFormatting_UseLanguageOptions = 0x1, // Language-sensitive formatting.
DxcCursorFormatting_SuppressSpecifiers = 0x2, // Supresses type specifiers.
DxcCursorFormatting_SuppressTagKeyword = 0x4, // Suppressed tag keyword (eg, 'class').
DxcCursorFormatting_IncludeNamespaceKeyword = 0x8, // Include namespace keyword.
} DxcCursorFormatting;
enum DxcCursorKind {
/* Declarations */
DxcCursor_UnexposedDecl = 1, // A declaration whose specific kind is not exposed via this interface.
DxcCursor_StructDecl = 2, // A C or C++ struct.
DxcCursor_UnionDecl = 3, // A C or C++ union.
DxcCursor_ClassDecl = 4, // A C++ class.
DxcCursor_EnumDecl = 5, // An enumeration.
DxcCursor_FieldDecl = 6, // A field (in C) or non-static data member (in C++) in a struct, union, or C++ class.
DxcCursor_EnumConstantDecl = 7, // An enumerator constant.
DxcCursor_FunctionDecl = 8, // A function.
DxcCursor_VarDecl = 9, // A variable.
DxcCursor_ParmDecl = 10, // A function or method parameter.
DxcCursor_ObjCInterfaceDecl = 11, // An Objective-C interface.
DxcCursor_ObjCCategoryDecl = 12, // An Objective-C interface for a category.
DxcCursor_ObjCProtocolDecl = 13, // An Objective-C protocol declaration.
DxcCursor_ObjCPropertyDecl = 14, // An Objective-C property declaration.
DxcCursor_ObjCIvarDecl = 15, // An Objective-C instance variable.
DxcCursor_ObjCInstanceMethodDecl = 16, // An Objective-C instance method.
DxcCursor_ObjCClassMethodDecl = 17, // An Objective-C class method.
DxcCursor_ObjCImplementationDecl = 18, // An Objective-C \@implementation.
DxcCursor_ObjCCategoryImplDecl = 19, // An Objective-C \@implementation for a category.
DxcCursor_TypedefDecl = 20, // A typedef
DxcCursor_CXXMethod = 21, // A C++ class method.
DxcCursor_Namespace = 22, // A C++ namespace.
DxcCursor_LinkageSpec = 23, // A linkage specification, e.g. 'extern "C"'.
DxcCursor_Constructor = 24, // A C++ constructor.
DxcCursor_Destructor = 25, // A C++ destructor.
DxcCursor_ConversionFunction = 26, // A C++ conversion function.
DxcCursor_TemplateTypeParameter = 27, // A C++ template type parameter.
DxcCursor_NonTypeTemplateParameter = 28, // A C++ non-type template parameter.
DxcCursor_TemplateTemplateParameter = 29, // A C++ template template parameter.
DxcCursor_FunctionTemplate = 30, // A C++ function template.
DxcCursor_ClassTemplate = 31, // A C++ class template.
DxcCursor_ClassTemplatePartialSpecialization = 32, // A C++ class template partial specialization.
DxcCursor_NamespaceAlias = 33, // A C++ namespace alias declaration.
DxcCursor_UsingDirective = 34, // A C++ using directive.
DxcCursor_UsingDeclaration = 35, // A C++ using declaration.
DxcCursor_TypeAliasDecl = 36, // A C++ alias declaration
DxcCursor_ObjCSynthesizeDecl = 37, // An Objective-C \@synthesize definition.
DxcCursor_ObjCDynamicDecl = 38, // An Objective-C \@dynamic definition.
DxcCursor_CXXAccessSpecifier = 39, // An access specifier.
DxcCursor_FirstDecl = DxcCursor_UnexposedDecl,
DxcCursor_LastDecl = DxcCursor_CXXAccessSpecifier,
/* References */
DxcCursor_FirstRef = 40, /* Decl references */
DxcCursor_ObjCSuperClassRef = 40,
DxcCursor_ObjCProtocolRef = 41,
DxcCursor_ObjCClassRef = 42,
/**
* \brief A reference to a type declaration.
*
* A type reference occurs anywhere where a type is named but not
* declared. For example, given:
*
* \code
* typedef unsigned size_type;
* size_type size;
* \endcode
*
* The typedef is a declaration of size_type (DxcCursor_TypedefDecl),
* while the type of the variable "size" is referenced. The cursor
* referenced by the type of size is the typedef for size_type.
*/
DxcCursor_TypeRef = 43, // A reference to a type declaration.
DxcCursor_CXXBaseSpecifier = 44,
DxcCursor_TemplateRef = 45, // A reference to a class template, function template, template template parameter, or class template partial specialization.
DxcCursor_NamespaceRef = 46, // A reference to a namespace or namespace alias.
DxcCursor_MemberRef = 47, // A reference to a member of a struct, union, or class that occurs in some non-expression context, e.g., a designated initializer.
/**
* \brief A reference to a labeled statement.
*
* This cursor kind is used to describe the jump to "start_over" in the
* goto statement in the following example:
*
* \code
* start_over:
* ++counter;
*
* goto start_over;
* \endcode
*
* A label reference cursor refers to a label statement.
*/
DxcCursor_LabelRef = 48, // A reference to a labeled statement.
// A reference to a set of overloaded functions or function templates
// that has not yet been resolved to a specific function or function template.
//
// An overloaded declaration reference cursor occurs in C++ templates where
// a dependent name refers to a function.
DxcCursor_OverloadedDeclRef = 49,
DxcCursor_VariableRef = 50, // A reference to a variable that occurs in some non-expression context, e.g., a C++ lambda capture list.
DxcCursor_LastRef = DxcCursor_VariableRef,
/* Error conditions */
DxcCursor_FirstInvalid = 70,
DxcCursor_InvalidFile = 70,
DxcCursor_NoDeclFound = 71,
DxcCursor_NotImplemented = 72,
DxcCursor_InvalidCode = 73,
DxcCursor_LastInvalid = DxcCursor_InvalidCode,
/* Expressions */
DxcCursor_FirstExpr = 100,
/**
* \brief An expression whose specific kind is not exposed via this
* interface.
*
* Unexposed expressions have the same operations as any other kind
* of expression; one can extract their location information,
* spelling, children, etc. However, the specific kind of the
* expression is not reported.
*/
DxcCursor_UnexposedExpr = 100, // An expression whose specific kind is not exposed via this interface.
DxcCursor_DeclRefExpr = 101, // An expression that refers to some value declaration, such as a function, varible, or enumerator.
DxcCursor_MemberRefExpr = 102, // An expression that refers to a member of a struct, union, class, Objective-C class, etc.
DxcCursor_CallExpr = 103, // An expression that calls a function.
DxcCursor_ObjCMessageExpr = 104, // An expression that sends a message to an Objective-C object or class.
DxcCursor_BlockExpr = 105, // An expression that represents a block literal.
DxcCursor_IntegerLiteral = 106, // An integer literal.
DxcCursor_FloatingLiteral = 107, // A floating point number literal.
DxcCursor_ImaginaryLiteral = 108, // An imaginary number literal.
DxcCursor_StringLiteral = 109, // A string literal.
DxcCursor_CharacterLiteral = 110, // A character literal.
DxcCursor_ParenExpr = 111, // A parenthesized expression, e.g. "(1)". This AST node is only formed if full location information is requested.
DxcCursor_UnaryOperator = 112, // This represents the unary-expression's (except sizeof and alignof).
DxcCursor_ArraySubscriptExpr = 113, // [C99 6.5.2.1] Array Subscripting.
DxcCursor_BinaryOperator = 114, // A builtin binary operation expression such as "x + y" or "x <= y".
DxcCursor_CompoundAssignOperator = 115, // Compound assignment such as "+=".
DxcCursor_ConditionalOperator = 116, // The ?: ternary operator.
DxcCursor_CStyleCastExpr = 117, // An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr.cast]), which uses the syntax (Type)expr, eg: (int)f.
DxcCursor_CompoundLiteralExpr = 118, // [C99 6.5.2.5]
DxcCursor_InitListExpr = 119, // Describes an C or C++ initializer list.
DxcCursor_AddrLabelExpr = 120, // The GNU address of label extension, representing &&label.
DxcCursor_StmtExpr = 121, // This is the GNU Statement Expression extension: ({int X=4; X;})
DxcCursor_GenericSelectionExpr = 122, // Represents a C11 generic selection.
/** \brief Implements the GNU __null extension, which is a name for a null
* pointer constant that has integral type (e.g., int or long) and is the same
* size and alignment as a pointer.
*
* The __null extension is typically only used by system headers, which define
* NULL as __null in C++ rather than using 0 (which is an integer that may not
* match the size of a pointer).
*/
DxcCursor_GNUNullExpr = 123,
DxcCursor_CXXStaticCastExpr = 124, // C++'s static_cast<> expression.
DxcCursor_CXXDynamicCastExpr = 125, // C++'s dynamic_cast<> expression.
DxcCursor_CXXReinterpretCastExpr = 126, // C++'s reinterpret_cast<> expression.
DxcCursor_CXXConstCastExpr = 127, // C++'s const_cast<> expression.
/** \brief Represents an explicit C++ type conversion that uses "functional"
* notion (C++ [expr.type.conv]).
*
* Example:
* \code
* x = int(0.5);
* \endcode
*/
DxcCursor_CXXFunctionalCastExpr = 128,
DxcCursor_CXXTypeidExpr = 129, // A C++ typeid expression (C++ [expr.typeid]).
DxcCursor_CXXBoolLiteralExpr = 130, // [C++ 2.13.5] C++ Boolean Literal.
DxcCursor_CXXNullPtrLiteralExpr = 131, // [C++0x 2.14.7] C++ Pointer Literal.
DxcCursor_CXXThisExpr = 132, // Represents the "this" expression in C++
DxcCursor_CXXThrowExpr = 133, // [C++ 15] C++ Throw Expression, both 'throw' and 'throw' assignment-expression.
DxcCursor_CXXNewExpr = 134, // A new expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
DxcCursor_CXXDeleteExpr = 135, // A delete expression for memory deallocation and destructor calls, e.g. "delete[] pArray".
DxcCursor_UnaryExpr = 136, // A unary expression.
DxcCursor_ObjCStringLiteral = 137, // An Objective-C string literal i.e. @"foo".
DxcCursor_ObjCEncodeExpr = 138, // An Objective-C \@encode expression.
DxcCursor_ObjCSelectorExpr = 139, // An Objective-C \@selector expression.
DxcCursor_ObjCProtocolExpr = 140, // An Objective-C \@protocol expression.
/** \brief An Objective-C "bridged" cast expression, which casts between
* Objective-C pointers and C pointers, transferring ownership in the process.
*
* \code
* NSString *str = (__bridge_transfer NSString *)CFCreateString();
* \endcode
*/
DxcCursor_ObjCBridgedCastExpr = 141,
/** \brief Represents a C++0x pack expansion that produces a sequence of
* expressions.
*
* A pack expansion expression contains a pattern (which itself is an
* expression) followed by an ellipsis. For example:
*
* \code
* template
* void forward(F f, Types &&...args) {
* f(static_cast(args)...);
* }
* \endcode
*/
DxcCursor_PackExpansionExpr = 142,
/** \brief Represents an expression that computes the length of a parameter
* pack.
*
* \code
* template
* struct count {
* static const unsigned value = sizeof...(Types);
* };
* \endcode
*/
DxcCursor_SizeOfPackExpr = 143,
/* \brief Represents a C++ lambda expression that produces a local function
* object.
*
* \code
* void abssort(float *x, unsigned N) {
* std::sort(x, x + N,
* [](float a, float b) {
* return std::abs(a) < std::abs(b);
* });
* }
* \endcode
*/
DxcCursor_LambdaExpr = 144,
DxcCursor_ObjCBoolLiteralExpr = 145, // Objective-c Boolean Literal.
DxcCursor_ObjCSelfExpr = 146, // Represents the "self" expression in a ObjC method.
DxcCursor_LastExpr = DxcCursor_ObjCSelfExpr,
/* Statements */
DxcCursor_FirstStmt = 200,
/**
* \brief A statement whose specific kind is not exposed via this
* interface.
*
* Unexposed statements have the same operations as any other kind of
* statement; one can extract their location information, spelling,
* children, etc. However, the specific kind of the statement is not
* reported.
*/
DxcCursor_UnexposedStmt = 200,
/** \brief A labelled statement in a function.
*
* This cursor kind is used to describe the "start_over:" label statement in
* the following example:
*
* \code
* start_over:
* ++counter;
* \endcode
*
*/
DxcCursor_LabelStmt = 201,
DxcCursor_CompoundStmt = 202, // A group of statements like { stmt stmt }. This cursor kind is used to describe compound statements, e.g. function bodies.
DxcCursor_CaseStmt = 203, // A case statement.
DxcCursor_DefaultStmt = 204, // A default statement.
DxcCursor_IfStmt = 205, // An if statement
DxcCursor_SwitchStmt = 206, // A switch statement.
DxcCursor_WhileStmt = 207, // A while statement.
DxcCursor_DoStmt = 208, // A do statement.
DxcCursor_ForStmt = 209, // A for statement.
DxcCursor_GotoStmt = 210, // A goto statement.
DxcCursor_IndirectGotoStmt = 211, // An indirect goto statement.
DxcCursor_ContinueStmt = 212, // A continue statement.
DxcCursor_BreakStmt = 213, // A break statement.
DxcCursor_ReturnStmt = 214, // A return statement.
DxcCursor_GCCAsmStmt = 215, // A GCC inline assembly statement extension.
DxcCursor_AsmStmt = DxcCursor_GCCAsmStmt,
DxcCursor_ObjCAtTryStmt = 216, // Objective-C's overall \@try-\@catch-\@finally statement.
DxcCursor_ObjCAtCatchStmt = 217, // Objective-C's \@catch statement.
DxcCursor_ObjCAtFinallyStmt = 218, // Objective-C's \@finally statement.
DxcCursor_ObjCAtThrowStmt = 219, // Objective-C's \@throw statement.
DxcCursor_ObjCAtSynchronizedStmt = 220, // Objective-C's \@synchronized statement.
DxcCursor_ObjCAutoreleasePoolStmt = 221, // Objective-C's autorelease pool statement.
DxcCursor_ObjCForCollectionStmt = 222, // Objective-C's collection statement.
DxcCursor_CXXCatchStmt = 223, // C++'s catch statement.
DxcCursor_CXXTryStmt = 224, // C++'s try statement.
DxcCursor_CXXForRangeStmt = 225, // C++'s for (* : *) statement.
DxcCursor_SEHTryStmt = 226, // Windows Structured Exception Handling's try statement.
DxcCursor_SEHExceptStmt = 227, // Windows Structured Exception Handling's except statement.
DxcCursor_SEHFinallyStmt = 228, // Windows Structured Exception Handling's finally statement.
DxcCursor_MSAsmStmt = 229, // A MS inline assembly statement extension.
DxcCursor_NullStmt = 230, // The null satement ";": C99 6.8.3p3.
DxcCursor_DeclStmt = 231, // Adaptor class for mixing declarations with statements and expressions.
DxcCursor_OMPParallelDirective = 232, // OpenMP parallel directive.
DxcCursor_OMPSimdDirective = 233, // OpenMP SIMD directive.
DxcCursor_OMPForDirective = 234, // OpenMP for directive.
DxcCursor_OMPSectionsDirective = 235, // OpenMP sections directive.
DxcCursor_OMPSectionDirective = 236, // OpenMP section directive.
DxcCursor_OMPSingleDirective = 237, // OpenMP single directive.
DxcCursor_OMPParallelForDirective = 238, // OpenMP parallel for directive.
DxcCursor_OMPParallelSectionsDirective = 239, // OpenMP parallel sections directive.
DxcCursor_OMPTaskDirective = 240, // OpenMP task directive.
DxcCursor_OMPMasterDirective = 241, // OpenMP master directive.
DxcCursor_OMPCriticalDirective = 242, // OpenMP critical directive.
DxcCursor_OMPTaskyieldDirective = 243, // OpenMP taskyield directive.
DxcCursor_OMPBarrierDirective = 244, // OpenMP barrier directive.
DxcCursor_OMPTaskwaitDirective = 245, // OpenMP taskwait directive.
DxcCursor_OMPFlushDirective = 246, // OpenMP flush directive.
DxcCursor_SEHLeaveStmt = 247, // Windows Structured Exception Handling's leave statement.
DxcCursor_OMPOrderedDirective = 248, // OpenMP ordered directive.
DxcCursor_OMPAtomicDirective = 249, // OpenMP atomic directive.
DxcCursor_OMPForSimdDirective = 250, // OpenMP for SIMD directive.
DxcCursor_OMPParallelForSimdDirective = 251, // OpenMP parallel for SIMD directive.
DxcCursor_OMPTargetDirective = 252, // OpenMP target directive.
DxcCursor_OMPTeamsDirective = 253, // OpenMP teams directive.
DxcCursor_OMPTaskgroupDirective = 254, // OpenMP taskgroup directive.
DxcCursor_OMPCancellationPointDirective = 255, // OpenMP cancellation point directive.
DxcCursor_OMPCancelDirective = 256, // OpenMP cancel directive.
DxcCursor_LastStmt = DxcCursor_OMPCancelDirective,
DxcCursor_TranslationUnit = 300, // Cursor that represents the translation unit itself.
/* Attributes */
DxcCursor_FirstAttr = 400,
/**
* \brief An attribute whose specific kind is not exposed via this
* interface.
*/
DxcCursor_UnexposedAttr = 400,
DxcCursor_IBActionAttr = 401,
DxcCursor_IBOutletAttr = 402,
DxcCursor_IBOutletCollectionAttr = 403,
DxcCursor_CXXFinalAttr = 404,
DxcCursor_CXXOverrideAttr = 405,
DxcCursor_AnnotateAttr = 406,
DxcCursor_AsmLabelAttr = 407,
DxcCursor_PackedAttr = 408,
DxcCursor_PureAttr = 409,
DxcCursor_ConstAttr = 410,
DxcCursor_NoDuplicateAttr = 411,
DxcCursor_CUDAConstantAttr = 412,
DxcCursor_CUDADeviceAttr = 413,
DxcCursor_CUDAGlobalAttr = 414,
DxcCursor_CUDAHostAttr = 415,
DxcCursor_CUDASharedAttr = 416,
DxcCursor_LastAttr = DxcCursor_CUDASharedAttr,
/* Preprocessing */
DxcCursor_PreprocessingDirective = 500,
DxcCursor_MacroDefinition = 501,
DxcCursor_MacroExpansion = 502,
DxcCursor_MacroInstantiation = DxcCursor_MacroExpansion,
DxcCursor_InclusionDirective = 503,
DxcCursor_FirstPreprocessing = DxcCursor_PreprocessingDirective,
DxcCursor_LastPreprocessing = DxcCursor_InclusionDirective,
/* Extra Declarations */
/**
* \brief A module import declaration.
*/
DxcCursor_ModuleImportDecl = 600,
DxcCursor_FirstExtraDecl = DxcCursor_ModuleImportDecl,
DxcCursor_LastExtraDecl = DxcCursor_ModuleImportDecl
};
enum DxcCursorKindFlags
{
DxcCursorKind_None = 0,
DxcCursorKind_Declaration = 0x1,
DxcCursorKind_Reference = 0x2,
DxcCursorKind_Expression = 0x4,
DxcCursorKind_Statement = 0x8,
DxcCursorKind_Attribute = 0x10,
DxcCursorKind_Invalid = 0x20,
DxcCursorKind_TranslationUnit = 0x40,
DxcCursorKind_Preprocessing = 0x80,
DxcCursorKind_Unexposed = 0x100,
};
enum DxcCodeCompleteFlags
{
DxcCodeCompleteFlags_None = 0,
DxcCodeCompleteFlags_IncludeMacros = 0x1,
DxcCodeCompleteFlags_IncludeCodePatterns = 0x2,
DxcCodeCompleteFlags_IncludeBriefComments = 0x4,
};
enum DxcCompletionChunkKind
{
DxcCompletionChunk_Optional = 0,
DxcCompletionChunk_TypedText = 1,
DxcCompletionChunk_Text = 2,
DxcCompletionChunk_Placeholder = 3,
DxcCompletionChunk_Informative = 4,
DxcCompletionChunk_CurrentParameter = 5,
DxcCompletionChunk_LeftParen = 6,
DxcCompletionChunk_RightParen = 7,
DxcCompletionChunk_LeftBracket = 8,
DxcCompletionChunk_RightBracket = 9,
DxcCompletionChunk_LeftBrace = 10,
DxcCompletionChunk_RightBrace = 11,
DxcCompletionChunk_LeftAngle = 12,
DxcCompletionChunk_RightAngle = 13,
DxcCompletionChunk_Comma = 14,
DxcCompletionChunk_ResultType = 15,
DxcCompletionChunk_Colon = 16,
DxcCompletionChunk_SemiColon = 17,
DxcCompletionChunk_Equal = 18,
DxcCompletionChunk_HorizontalSpace = 19,
DxcCompletionChunk_VerticalSpace = 20,
};
struct IDxcCursor;
struct IDxcDiagnostic;
struct IDxcFile;
struct IDxcInclusion;
struct IDxcIntelliSense;
struct IDxcIndex;
struct IDxcSourceLocation;
struct IDxcSourceRange;
struct IDxcToken;
struct IDxcTranslationUnit;
struct IDxcType;
struct IDxcUnsavedFile;
struct IDxcCodeCompleteResults;
struct IDxcCompletionResult;
struct IDxcCompletionString;
CROSS_PLATFORM_UUIDOF(IDxcCursor, "1467b985-288d-4d2a-80c1-ef89c42c40bc")
struct IDxcCursor : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetExtent(_Outptr_result_nullonfailure_ IDxcSourceRange** pRange) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLocation(_Outptr_result_nullonfailure_ IDxcSourceLocation** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetKind(_Out_ DxcCursorKind* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetKindFlags(_Out_ DxcCursorKindFlags* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSemanticParent(_Outptr_result_nullonfailure_ IDxcCursor** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLexicalParent(_Outptr_result_nullonfailure_ IDxcCursor** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCursorType(_Outptr_result_nullonfailure_ IDxcType** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetNumArguments(_Out_ int* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArgumentAt(int index, _Outptr_result_nullonfailure_ IDxcCursor** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetReferencedCursor(_Outptr_result_nullonfailure_ IDxcCursor** pResult) = 0;
/// For a cursor that is either a reference to or a declaration of some entity, retrieve a cursor that describes the definition of that entity.
/// Some entities can be declared multiple times within a translation unit, but only one of those declarations can also be a definition.
/// A cursor to the definition of this entity; nullptr if there is no definition in this translation unit.
virtual HRESULT STDMETHODCALLTYPE GetDefinitionCursor(_Outptr_result_nullonfailure_ IDxcCursor** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE FindReferencesInFile(
_In_ IDxcFile* file, unsigned skip, unsigned top,
_Out_ unsigned* pResultLength, _Outptr_result_buffer_maybenull_(*pResultLength) IDxcCursor*** pResult) = 0;
/// Gets the name for the entity references by the cursor, e.g. foo for an 'int foo' variable.
virtual HRESULT STDMETHODCALLTYPE GetSpelling(_Outptr_result_maybenull_ LPSTR* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcCursor* other, _Out_ BOOL* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE IsDefinition(_Out_ BOOL* pResult) = 0;
/// Gets the display name for the cursor, including e.g. parameter types for a function.
virtual HRESULT STDMETHODCALLTYPE GetDisplayName(_Out_ BSTR* pResult) = 0;
/// Gets the qualified name for the symbol the cursor refers to.
virtual HRESULT STDMETHODCALLTYPE GetQualifiedName(BOOL includeTemplateArgs, _Outptr_result_maybenull_ BSTR* pResult) = 0;
/// Gets a name for the cursor, applying the specified formatting flags.
virtual HRESULT STDMETHODCALLTYPE GetFormattedName(DxcCursorFormatting formatting , _Outptr_result_maybenull_ BSTR* pResult) = 0;
/// Gets children in pResult up to top elements.
virtual HRESULT STDMETHODCALLTYPE GetChildren(
unsigned skip, unsigned top,
_Out_ unsigned* pResultLength, _Outptr_result_buffer_maybenull_(*pResultLength) IDxcCursor*** pResult) = 0;
/// Gets the cursor following a location within a compound cursor.
virtual HRESULT STDMETHODCALLTYPE GetSnappedChild(_In_ IDxcSourceLocation* location, _Outptr_result_maybenull_ IDxcCursor** pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcDiagnostic, "4f76b234-3659-4d33-99b0-3b0db994b564")
struct IDxcDiagnostic : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE FormatDiagnostic(
DxcDiagnosticDisplayOptions options,
_Outptr_result_maybenull_ LPSTR* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSeverity(_Out_ DxcDiagnosticSeverity* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLocation(_Outptr_result_nullonfailure_ IDxcSourceLocation** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSpelling(_Outptr_result_maybenull_ LPSTR* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCategoryText(_Outptr_result_maybenull_ LPSTR* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetNumRanges(_Out_ unsigned* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetRangeAt(unsigned index, _Outptr_result_nullonfailure_ IDxcSourceRange** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetNumFixIts(_Out_ unsigned* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFixItAt(unsigned index,
_Outptr_result_nullonfailure_ IDxcSourceRange** pReplacementRange, _Outptr_result_maybenull_ LPSTR* pText) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcFile, "bb2fca9e-1478-47ba-b08c-2c502ada4895")
struct IDxcFile : public IUnknown
{
/// Gets the file name for this file.
virtual HRESULT STDMETHODCALLTYPE GetName(_Outptr_result_maybenull_ LPSTR* pResult) = 0;
/// Checks whether this file is equal to the other specified file.
virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcFile* other, _Out_ BOOL* pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcInclusion, "0c364d65-df44-4412-888e-4e552fc5e3d6")
struct IDxcInclusion : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetIncludedFile(_Outptr_result_nullonfailure_ IDxcFile** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetStackLength(_Out_ unsigned *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetStackItem(unsigned index, _Outptr_result_nullonfailure_ IDxcSourceLocation **pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcIntelliSense, "b1f99513-46d6-4112-8169-dd0d6053f17d")
struct IDxcIntelliSense : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE CreateIndex(_Outptr_result_nullonfailure_ IDxcIndex** index) = 0;
virtual HRESULT STDMETHODCALLTYPE GetNullLocation(_Outptr_result_nullonfailure_ IDxcSourceLocation** location) = 0;
virtual HRESULT STDMETHODCALLTYPE GetNullRange(_Outptr_result_nullonfailure_ IDxcSourceRange** location) = 0;
virtual HRESULT STDMETHODCALLTYPE GetRange(
_In_ IDxcSourceLocation* start,
_In_ IDxcSourceLocation* end,
_Outptr_result_nullonfailure_ IDxcSourceRange** location) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDefaultDiagnosticDisplayOptions(
_Out_ DxcDiagnosticDisplayOptions* pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDefaultEditingTUOptions(_Out_ DxcTranslationUnitFlags* pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateUnsavedFile(_In_ LPCSTR fileName, _In_ LPCSTR contents, unsigned contentLength, _Outptr_result_nullonfailure_ IDxcUnsavedFile** pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcIndex, "937824a0-7f5a-4815-9ba7-7fc0424f4173")
struct IDxcIndex : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE SetGlobalOptions(DxcGlobalOptions options) = 0;
virtual HRESULT STDMETHODCALLTYPE GetGlobalOptions(_Out_ DxcGlobalOptions* options) = 0;
virtual HRESULT STDMETHODCALLTYPE ParseTranslationUnit(
_In_z_ const char *source_filename,
_In_count_(num_command_line_args) const char * const *command_line_args,
int num_command_line_args,
_In_count_(num_unsaved_files) IDxcUnsavedFile** unsaved_files,
unsigned num_unsaved_files,
DxcTranslationUnitFlags options,
_Out_ IDxcTranslationUnit** pTranslationUnit) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcSourceLocation, "8e7ddf1c-d7d3-4d69-b286-85fccba1e0cf")
struct IDxcSourceLocation : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcSourceLocation* other, _Out_ BOOL* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSpellingLocation(
_Outptr_opt_ IDxcFile** pFile,
_Out_opt_ unsigned* pLine,
_Out_opt_ unsigned* pCol,
_Out_opt_ unsigned* pOffset) = 0;
virtual HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPresumedLocation(
_Outptr_opt_ LPSTR* pFilename,
_Out_opt_ unsigned* pLine,
_Out_opt_ unsigned* pCol) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcSourceRange, "f1359b36-a53f-4e81-b514-b6b84122a13f")
struct IDxcSourceRange : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL* pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetStart(_Out_ IDxcSourceLocation** pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetEnd(_Out_ IDxcSourceLocation** pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOffsets(_Out_ unsigned* startOffset, _Out_ unsigned* endOffset) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcToken, "7f90b9ff-a275-4932-97d8-3cfd234482a2")
struct IDxcToken : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetKind(_Out_ DxcTokenKind* pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLocation(_Out_ IDxcSourceLocation** pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetExtent(_Out_ IDxcSourceRange** pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSpelling(_Out_ LPSTR* pValue) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcTranslationUnit, "9677dee0-c0e5-46a1-8b40-3db3168be63d")
struct IDxcTranslationUnit : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetCursor(_Out_ IDxcCursor** pCursor) = 0;
virtual HRESULT STDMETHODCALLTYPE Tokenize(
_In_ IDxcSourceRange* range,
_Outptr_result_buffer_maybenull_(*pTokenCount) IDxcToken*** pTokens,
_Out_ unsigned* pTokenCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLocation(
_In_ IDxcFile* file,
unsigned line, unsigned column,
_Outptr_result_nullonfailure_ IDxcSourceLocation** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetNumDiagnostics(_Out_ unsigned* pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDiagnostic(unsigned index, _Outptr_result_nullonfailure_ IDxcDiagnostic** pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFile(_In_ const char* name, _Outptr_result_nullonfailure_ IDxcFile** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFileName(_Outptr_result_maybenull_ LPSTR* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE Reparse(
_In_count_(num_unsaved_files) IDxcUnsavedFile** unsaved_files,
unsigned num_unsaved_files) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCursorForLocation(_In_ IDxcSourceLocation* location, _Outptr_result_nullonfailure_ IDxcCursor** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLocationForOffset(_In_ IDxcFile* file, unsigned offset, _Outptr_result_nullonfailure_ IDxcSourceLocation** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSkippedRanges(_In_ IDxcFile* file, _Out_ unsigned* pResultCount, _Outptr_result_buffer_(*pResultCount) IDxcSourceRange*** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDiagnosticDetails(unsigned index, DxcDiagnosticDisplayOptions options,
_Out_ unsigned* errorCode,
_Out_ unsigned* errorLine,
_Out_ unsigned* errorColumn,
_Out_ BSTR* errorFile,
_Out_ unsigned* errorOffset,
_Out_ unsigned* errorLength,
_Out_ BSTR* errorMessage) = 0;
virtual HRESULT STDMETHODCALLTYPE GetInclusionList(_Out_ unsigned* pResultCount, _Outptr_result_buffer_(*pResultCount) IDxcInclusion*** pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE CodeCompleteAt(
_In_ const char *fileName, unsigned line, unsigned column,
_In_ IDxcUnsavedFile** pUnsavedFiles, unsigned numUnsavedFiles,
_In_ DxcCodeCompleteFlags options,
_Outptr_result_nullonfailure_ IDxcCodeCompleteResults **pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcType, "2ec912fd-b144-4a15-ad0d-1c5439c81e46")
struct IDxcType : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetSpelling(_Outptr_result_z_ LPSTR* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcType* other, _Out_ BOOL* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetKind(_Out_ DxcTypeKind* pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcUnsavedFile, "8ec00f98-07d0-4e60-9d7c-5a50b5b0017f")
struct IDxcUnsavedFile : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetFileName(_Outptr_result_z_ LPSTR* pFileName) = 0;
virtual HRESULT STDMETHODCALLTYPE GetContents(_Outptr_result_z_ LPSTR* pContents) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLength(_Out_ unsigned* pLength) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcCodeCompleteResults, "1E06466A-FD8B-45F3-A78F-8A3F76EBB552")
struct IDxcCodeCompleteResults : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetNumResults(_Out_ unsigned* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetResultAt(unsigned index, _Outptr_result_nullonfailure_ IDxcCompletionResult** pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcCompletionResult, "943C0588-22D0-4784-86FC-701F802AC2B6")
struct IDxcCompletionResult : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetCursorKind(_Out_ DxcCursorKind* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCompletionString(_Outptr_result_nullonfailure_ IDxcCompletionString** pResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcCompletionString, "06B51E0F-A605-4C69-A110-CD6E14B58EEC")
struct IDxcCompletionString : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetNumCompletionChunks(_Out_ unsigned* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCompletionChunkKind(unsigned chunkNumber, _Out_ DxcCompletionChunkKind* pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCompletionChunkText(unsigned chunkNumber, _Out_ LPSTR* pResult) = 0;
};
// Fun fact: 'extern' is required because const is by default static in C++, so
// CLSID_DxcIntelliSense is not visible externally (this is OK in C, since const is
// not by default static in C)
#ifdef _MSC_VER
#define CLSID_SCOPE __declspec(selectany) extern
#else
#define CLSID_SCOPE
#endif
CLSID_SCOPE const CLSID
CLSID_DxcIntelliSense = {/* 3047833c-d1c0-4b8e-9d40-102878605985 */
0x3047833c,
0xd1c0,
0x4b8e,
{0x9d, 0x40, 0x10, 0x28, 0x78, 0x60, 0x59, 0x85}};
#endif
================================================
FILE: Source/External/imgui_tools/IconsFontAwesome/IconsFontAwesome5.h
================================================
// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++
// from https://github.com/FortAwesome/Font-Awesome/raw/5.x/metadata/icons.yml
// for use with https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-regular-400.ttf, https://github.com/FortAwesome/Font-Awesome/blob/5.x/webfonts/fa-solid-900.ttf
#pragma once
#define FONT_ICON_FILE_NAME_FAR "fa-regular-400.ttf"
#define FONT_ICON_FILE_NAME_FAS "fa-solid-900.ttf"
#define ICON_MIN_FA 0xe005
#define ICON_MAX_16_FA 0xf8ff
#define ICON_MAX_FA 0xf8ff
#define ICON_FA_AD "\xef\x99\x81" // U+f641
#define ICON_FA_ADDRESS_BOOK "\xef\x8a\xb9" // U+f2b9
#define ICON_FA_ADDRESS_CARD "\xef\x8a\xbb" // U+f2bb
#define ICON_FA_ADJUST "\xef\x81\x82" // U+f042
#define ICON_FA_AIR_FRESHENER "\xef\x97\x90" // U+f5d0
#define ICON_FA_ALIGN_CENTER "\xef\x80\xb7" // U+f037
#define ICON_FA_ALIGN_JUSTIFY "\xef\x80\xb9" // U+f039
#define ICON_FA_ALIGN_LEFT "\xef\x80\xb6" // U+f036
#define ICON_FA_ALIGN_RIGHT "\xef\x80\xb8" // U+f038
#define ICON_FA_ALLERGIES "\xef\x91\xa1" // U+f461
#define ICON_FA_AMBULANCE "\xef\x83\xb9" // U+f0f9
#define ICON_FA_AMERICAN_SIGN_LANGUAGE_INTERPRETING "\xef\x8a\xa3" // U+f2a3
#define ICON_FA_ANCHOR "\xef\x84\xbd" // U+f13d
#define ICON_FA_ANGLE_DOUBLE_DOWN "\xef\x84\x83" // U+f103
#define ICON_FA_ANGLE_DOUBLE_LEFT "\xef\x84\x80" // U+f100
#define ICON_FA_ANGLE_DOUBLE_RIGHT "\xef\x84\x81" // U+f101
#define ICON_FA_ANGLE_DOUBLE_UP "\xef\x84\x82" // U+f102
#define ICON_FA_ANGLE_DOWN "\xef\x84\x87" // U+f107
#define ICON_FA_ANGLE_LEFT "\xef\x84\x84" // U+f104
#define ICON_FA_ANGLE_RIGHT "\xef\x84\x85" // U+f105
#define ICON_FA_ANGLE_UP "\xef\x84\x86" // U+f106
#define ICON_FA_ANGRY "\xef\x95\x96" // U+f556
#define ICON_FA_ANKH "\xef\x99\x84" // U+f644
#define ICON_FA_APPLE_ALT "\xef\x97\x91" // U+f5d1
#define ICON_FA_ARCHIVE "\xef\x86\x87" // U+f187
#define ICON_FA_ARCHWAY "\xef\x95\x97" // U+f557
#define ICON_FA_ARROW_ALT_CIRCLE_DOWN "\xef\x8d\x98" // U+f358
#define ICON_FA_ARROW_ALT_CIRCLE_LEFT "\xef\x8d\x99" // U+f359
#define ICON_FA_ARROW_ALT_CIRCLE_RIGHT "\xef\x8d\x9a" // U+f35a
#define ICON_FA_ARROW_ALT_CIRCLE_UP "\xef\x8d\x9b" // U+f35b
#define ICON_FA_ARROW_CIRCLE_DOWN "\xef\x82\xab" // U+f0ab
#define ICON_FA_ARROW_CIRCLE_LEFT "\xef\x82\xa8" // U+f0a8
#define ICON_FA_ARROW_CIRCLE_RIGHT "\xef\x82\xa9" // U+f0a9
#define ICON_FA_ARROW_CIRCLE_UP "\xef\x82\xaa" // U+f0aa
#define ICON_FA_ARROW_DOWN "\xef\x81\xa3" // U+f063
#define ICON_FA_ARROW_LEFT "\xef\x81\xa0" // U+f060
#define ICON_FA_ARROW_RIGHT "\xef\x81\xa1" // U+f061
#define ICON_FA_ARROW_UP "\xef\x81\xa2" // U+f062
#define ICON_FA_ARROWS_ALT "\xef\x82\xb2" // U+f0b2
#define ICON_FA_ARROWS_ALT_H "\xef\x8c\xb7" // U+f337
#define ICON_FA_ARROWS_ALT_V "\xef\x8c\xb8" // U+f338
#define ICON_FA_ASSISTIVE_LISTENING_SYSTEMS "\xef\x8a\xa2" // U+f2a2
#define ICON_FA_ASTERISK "\xef\x81\xa9" // U+f069
#define ICON_FA_AT "\xef\x87\xba" // U+f1fa
#define ICON_FA_ATLAS "\xef\x95\x98" // U+f558
#define ICON_FA_ATOM "\xef\x97\x92" // U+f5d2
#define ICON_FA_AUDIO_DESCRIPTION "\xef\x8a\x9e" // U+f29e
#define ICON_FA_AWARD "\xef\x95\x99" // U+f559
#define ICON_FA_BABY "\xef\x9d\xbc" // U+f77c
#define ICON_FA_BABY_CARRIAGE "\xef\x9d\xbd" // U+f77d
#define ICON_FA_BACKSPACE "\xef\x95\x9a" // U+f55a
#define ICON_FA_BACKWARD "\xef\x81\x8a" // U+f04a
#define ICON_FA_BACON "\xef\x9f\xa5" // U+f7e5
#define ICON_FA_BACTERIA "\xee\x81\x99" // U+e059
#define ICON_FA_BACTERIUM "\xee\x81\x9a" // U+e05a
#define ICON_FA_BAHAI "\xef\x99\xa6" // U+f666
#define ICON_FA_BALANCE_SCALE "\xef\x89\x8e" // U+f24e
#define ICON_FA_BALANCE_SCALE_LEFT "\xef\x94\x95" // U+f515
#define ICON_FA_BALANCE_SCALE_RIGHT "\xef\x94\x96" // U+f516
#define ICON_FA_BAN "\xef\x81\x9e" // U+f05e
#define ICON_FA_BAND_AID "\xef\x91\xa2" // U+f462
#define ICON_FA_BARCODE "\xef\x80\xaa" // U+f02a
#define ICON_FA_BARS "\xef\x83\x89" // U+f0c9
#define ICON_FA_BASEBALL_BALL "\xef\x90\xb3" // U+f433
#define ICON_FA_BASKETBALL_BALL "\xef\x90\xb4" // U+f434
#define ICON_FA_BATH "\xef\x8b\x8d" // U+f2cd
#define ICON_FA_BATTERY_EMPTY "\xef\x89\x84" // U+f244
#define ICON_FA_BATTERY_FULL "\xef\x89\x80" // U+f240
#define ICON_FA_BATTERY_HALF "\xef\x89\x82" // U+f242
#define ICON_FA_BATTERY_QUARTER "\xef\x89\x83" // U+f243
#define ICON_FA_BATTERY_THREE_QUARTERS "\xef\x89\x81" // U+f241
#define ICON_FA_BED "\xef\x88\xb6" // U+f236
#define ICON_FA_BEER "\xef\x83\xbc" // U+f0fc
#define ICON_FA_BELL "\xef\x83\xb3" // U+f0f3
#define ICON_FA_BELL_SLASH "\xef\x87\xb6" // U+f1f6
#define ICON_FA_BEZIER_CURVE "\xef\x95\x9b" // U+f55b
#define ICON_FA_BIBLE "\xef\x99\x87" // U+f647
#define ICON_FA_BICYCLE "\xef\x88\x86" // U+f206
#define ICON_FA_BIKING "\xef\xa1\x8a" // U+f84a
#define ICON_FA_BINOCULARS "\xef\x87\xa5" // U+f1e5
#define ICON_FA_BIOHAZARD "\xef\x9e\x80" // U+f780
#define ICON_FA_BIRTHDAY_CAKE "\xef\x87\xbd" // U+f1fd
#define ICON_FA_BLENDER "\xef\x94\x97" // U+f517
#define ICON_FA_BLENDER_PHONE "\xef\x9a\xb6" // U+f6b6
#define ICON_FA_BLIND "\xef\x8a\x9d" // U+f29d
#define ICON_FA_BLOG "\xef\x9e\x81" // U+f781
#define ICON_FA_BOLD "\xef\x80\xb2" // U+f032
#define ICON_FA_BOLT "\xef\x83\xa7" // U+f0e7
#define ICON_FA_BOMB "\xef\x87\xa2" // U+f1e2
#define ICON_FA_BONE "\xef\x97\x97" // U+f5d7
#define ICON_FA_BONG "\xef\x95\x9c" // U+f55c
#define ICON_FA_BOOK "\xef\x80\xad" // U+f02d
#define ICON_FA_BOOK_DEAD "\xef\x9a\xb7" // U+f6b7
#define ICON_FA_BOOK_MEDICAL "\xef\x9f\xa6" // U+f7e6
#define ICON_FA_BOOK_OPEN "\xef\x94\x98" // U+f518
#define ICON_FA_BOOK_READER "\xef\x97\x9a" // U+f5da
#define ICON_FA_BOOKMARK "\xef\x80\xae" // U+f02e
#define ICON_FA_BORDER_ALL "\xef\xa1\x8c" // U+f84c
#define ICON_FA_BORDER_NONE "\xef\xa1\x90" // U+f850
#define ICON_FA_BORDER_STYLE "\xef\xa1\x93" // U+f853
#define ICON_FA_BOWLING_BALL "\xef\x90\xb6" // U+f436
#define ICON_FA_BOX "\xef\x91\xa6" // U+f466
#define ICON_FA_BOX_OPEN "\xef\x92\x9e" // U+f49e
#define ICON_FA_BOX_TISSUE "\xee\x81\x9b" // U+e05b
#define ICON_FA_BOXES "\xef\x91\xa8" // U+f468
#define ICON_FA_BRAILLE "\xef\x8a\xa1" // U+f2a1
#define ICON_FA_BRAIN "\xef\x97\x9c" // U+f5dc
#define ICON_FA_BREAD_SLICE "\xef\x9f\xac" // U+f7ec
#define ICON_FA_BRIEFCASE "\xef\x82\xb1" // U+f0b1
#define ICON_FA_BRIEFCASE_MEDICAL "\xef\x91\xa9" // U+f469
#define ICON_FA_BROADCAST_TOWER "\xef\x94\x99" // U+f519
#define ICON_FA_BROOM "\xef\x94\x9a" // U+f51a
#define ICON_FA_BRUSH "\xef\x95\x9d" // U+f55d
#define ICON_FA_BUG "\xef\x86\x88" // U+f188
#define ICON_FA_BUILDING "\xef\x86\xad" // U+f1ad
#define ICON_FA_BULLHORN "\xef\x82\xa1" // U+f0a1
#define ICON_FA_BULLSEYE "\xef\x85\x80" // U+f140
#define ICON_FA_BURN "\xef\x91\xaa" // U+f46a
#define ICON_FA_BUS "\xef\x88\x87" // U+f207
#define ICON_FA_BUS_ALT "\xef\x95\x9e" // U+f55e
#define ICON_FA_BUSINESS_TIME "\xef\x99\x8a" // U+f64a
#define ICON_FA_CALCULATOR "\xef\x87\xac" // U+f1ec
#define ICON_FA_CALENDAR "\xef\x84\xb3" // U+f133
#define ICON_FA_CALENDAR_ALT "\xef\x81\xb3" // U+f073
#define ICON_FA_CALENDAR_CHECK "\xef\x89\xb4" // U+f274
#define ICON_FA_CALENDAR_DAY "\xef\x9e\x83" // U+f783
#define ICON_FA_CALENDAR_MINUS "\xef\x89\xb2" // U+f272
#define ICON_FA_CALENDAR_PLUS "\xef\x89\xb1" // U+f271
#define ICON_FA_CALENDAR_TIMES "\xef\x89\xb3" // U+f273
#define ICON_FA_CALENDAR_WEEK "\xef\x9e\x84" // U+f784
#define ICON_FA_CAMERA "\xef\x80\xb0" // U+f030
#define ICON_FA_CAMERA_RETRO "\xef\x82\x83" // U+f083
#define ICON_FA_CAMPGROUND "\xef\x9a\xbb" // U+f6bb
#define ICON_FA_CANDY_CANE "\xef\x9e\x86" // U+f786
#define ICON_FA_CANNABIS "\xef\x95\x9f" // U+f55f
#define ICON_FA_CAPSULES "\xef\x91\xab" // U+f46b
#define ICON_FA_CAR "\xef\x86\xb9" // U+f1b9
#define ICON_FA_CAR_ALT "\xef\x97\x9e" // U+f5de
#define ICON_FA_CAR_BATTERY "\xef\x97\x9f" // U+f5df
#define ICON_FA_CAR_CRASH "\xef\x97\xa1" // U+f5e1
#define ICON_FA_CAR_SIDE "\xef\x97\xa4" // U+f5e4
#define ICON_FA_CARAVAN "\xef\xa3\xbf" // U+f8ff
#define ICON_FA_CARET_DOWN "\xef\x83\x97" // U+f0d7
#define ICON_FA_CARET_LEFT "\xef\x83\x99" // U+f0d9
#define ICON_FA_CARET_RIGHT "\xef\x83\x9a" // U+f0da
#define ICON_FA_CARET_SQUARE_DOWN "\xef\x85\x90" // U+f150
#define ICON_FA_CARET_SQUARE_LEFT "\xef\x86\x91" // U+f191
#define ICON_FA_CARET_SQUARE_RIGHT "\xef\x85\x92" // U+f152
#define ICON_FA_CARET_SQUARE_UP "\xef\x85\x91" // U+f151
#define ICON_FA_CARET_UP "\xef\x83\x98" // U+f0d8
#define ICON_FA_CARROT "\xef\x9e\x87" // U+f787
#define ICON_FA_CART_ARROW_DOWN "\xef\x88\x98" // U+f218
#define ICON_FA_CART_PLUS "\xef\x88\x97" // U+f217
#define ICON_FA_CASH_REGISTER "\xef\x9e\x88" // U+f788
#define ICON_FA_CAT "\xef\x9a\xbe" // U+f6be
#define ICON_FA_CERTIFICATE "\xef\x82\xa3" // U+f0a3
#define ICON_FA_CHAIR "\xef\x9b\x80" // U+f6c0
#define ICON_FA_CHALKBOARD "\xef\x94\x9b" // U+f51b
#define ICON_FA_CHALKBOARD_TEACHER "\xef\x94\x9c" // U+f51c
#define ICON_FA_CHARGING_STATION "\xef\x97\xa7" // U+f5e7
#define ICON_FA_CHART_AREA "\xef\x87\xbe" // U+f1fe
#define ICON_FA_CHART_BAR "\xef\x82\x80" // U+f080
#define ICON_FA_CHART_LINE "\xef\x88\x81" // U+f201
#define ICON_FA_CHART_PIE "\xef\x88\x80" // U+f200
#define ICON_FA_CHECK "\xef\x80\x8c" // U+f00c
#define ICON_FA_CHECK_CIRCLE "\xef\x81\x98" // U+f058
#define ICON_FA_CHECK_DOUBLE "\xef\x95\xa0" // U+f560
#define ICON_FA_CHECK_SQUARE "\xef\x85\x8a" // U+f14a
#define ICON_FA_CHEESE "\xef\x9f\xaf" // U+f7ef
#define ICON_FA_CHESS "\xef\x90\xb9" // U+f439
#define ICON_FA_CHESS_BISHOP "\xef\x90\xba" // U+f43a
#define ICON_FA_CHESS_BOARD "\xef\x90\xbc" // U+f43c
#define ICON_FA_CHESS_KING "\xef\x90\xbf" // U+f43f
#define ICON_FA_CHESS_KNIGHT "\xef\x91\x81" // U+f441
#define ICON_FA_CHESS_PAWN "\xef\x91\x83" // U+f443
#define ICON_FA_CHESS_QUEEN "\xef\x91\x85" // U+f445
#define ICON_FA_CHESS_ROOK "\xef\x91\x87" // U+f447
#define ICON_FA_CHEVRON_CIRCLE_DOWN "\xef\x84\xba" // U+f13a
#define ICON_FA_CHEVRON_CIRCLE_LEFT "\xef\x84\xb7" // U+f137
#define ICON_FA_CHEVRON_CIRCLE_RIGHT "\xef\x84\xb8" // U+f138
#define ICON_FA_CHEVRON_CIRCLE_UP "\xef\x84\xb9" // U+f139
#define ICON_FA_CHEVRON_DOWN "\xef\x81\xb8" // U+f078
#define ICON_FA_CHEVRON_LEFT "\xef\x81\x93" // U+f053
#define ICON_FA_CHEVRON_RIGHT "\xef\x81\x94" // U+f054
#define ICON_FA_CHEVRON_UP "\xef\x81\xb7" // U+f077
#define ICON_FA_CHILD "\xef\x86\xae" // U+f1ae
#define ICON_FA_CHURCH "\xef\x94\x9d" // U+f51d
#define ICON_FA_CIRCLE "\xef\x84\x91" // U+f111
#define ICON_FA_CIRCLE_NOTCH "\xef\x87\x8e" // U+f1ce
#define ICON_FA_CITY "\xef\x99\x8f" // U+f64f
#define ICON_FA_CLINIC_MEDICAL "\xef\x9f\xb2" // U+f7f2
#define ICON_FA_CLIPBOARD "\xef\x8c\xa8" // U+f328
#define ICON_FA_CLIPBOARD_CHECK "\xef\x91\xac" // U+f46c
#define ICON_FA_CLIPBOARD_LIST "\xef\x91\xad" // U+f46d
#define ICON_FA_CLOCK "\xef\x80\x97" // U+f017
#define ICON_FA_CLONE "\xef\x89\x8d" // U+f24d
#define ICON_FA_CLOSED_CAPTIONING "\xef\x88\x8a" // U+f20a
#define ICON_FA_CLOUD "\xef\x83\x82" // U+f0c2
#define ICON_FA_CLOUD_DOWNLOAD_ALT "\xef\x8e\x81" // U+f381
#define ICON_FA_CLOUD_MEATBALL "\xef\x9c\xbb" // U+f73b
#define ICON_FA_CLOUD_MOON "\xef\x9b\x83" // U+f6c3
#define ICON_FA_CLOUD_MOON_RAIN "\xef\x9c\xbc" // U+f73c
#define ICON_FA_CLOUD_RAIN "\xef\x9c\xbd" // U+f73d
#define ICON_FA_CLOUD_SHOWERS_HEAVY "\xef\x9d\x80" // U+f740
#define ICON_FA_CLOUD_SUN "\xef\x9b\x84" // U+f6c4
#define ICON_FA_CLOUD_SUN_RAIN "\xef\x9d\x83" // U+f743
#define ICON_FA_CLOUD_UPLOAD_ALT "\xef\x8e\x82" // U+f382
#define ICON_FA_COCKTAIL "\xef\x95\xa1" // U+f561
#define ICON_FA_CODE "\xef\x84\xa1" // U+f121
#define ICON_FA_CODE_BRANCH "\xef\x84\xa6" // U+f126
#define ICON_FA_COFFEE "\xef\x83\xb4" // U+f0f4
#define ICON_FA_COG "\xef\x80\x93" // U+f013
#define ICON_FA_COGS "\xef\x82\x85" // U+f085
#define ICON_FA_COINS "\xef\x94\x9e" // U+f51e
#define ICON_FA_COLUMNS "\xef\x83\x9b" // U+f0db
#define ICON_FA_COMMENT "\xef\x81\xb5" // U+f075
#define ICON_FA_COMMENT_ALT "\xef\x89\xba" // U+f27a
#define ICON_FA_COMMENT_DOLLAR "\xef\x99\x91" // U+f651
#define ICON_FA_COMMENT_DOTS "\xef\x92\xad" // U+f4ad
#define ICON_FA_COMMENT_MEDICAL "\xef\x9f\xb5" // U+f7f5
#define ICON_FA_COMMENT_SLASH "\xef\x92\xb3" // U+f4b3
#define ICON_FA_COMMENTS "\xef\x82\x86" // U+f086
#define ICON_FA_COMMENTS_DOLLAR "\xef\x99\x93" // U+f653
#define ICON_FA_COMPACT_DISC "\xef\x94\x9f" // U+f51f
#define ICON_FA_COMPASS "\xef\x85\x8e" // U+f14e
#define ICON_FA_COMPRESS "\xef\x81\xa6" // U+f066
#define ICON_FA_COMPRESS_ALT "\xef\x90\xa2" // U+f422
#define ICON_FA_COMPRESS_ARROWS_ALT "\xef\x9e\x8c" // U+f78c
#define ICON_FA_CONCIERGE_BELL "\xef\x95\xa2" // U+f562
#define ICON_FA_COOKIE "\xef\x95\xa3" // U+f563
#define ICON_FA_COOKIE_BITE "\xef\x95\xa4" // U+f564
#define ICON_FA_COPY "\xef\x83\x85" // U+f0c5
#define ICON_FA_COPYRIGHT "\xef\x87\xb9" // U+f1f9
#define ICON_FA_COUCH "\xef\x92\xb8" // U+f4b8
#define ICON_FA_CREDIT_CARD "\xef\x82\x9d" // U+f09d
#define ICON_FA_CROP "\xef\x84\xa5" // U+f125
#define ICON_FA_CROP_ALT "\xef\x95\xa5" // U+f565
#define ICON_FA_CROSS "\xef\x99\x94" // U+f654
#define ICON_FA_CROSSHAIRS "\xef\x81\x9b" // U+f05b
#define ICON_FA_CROW "\xef\x94\xa0" // U+f520
#define ICON_FA_CROWN "\xef\x94\xa1" // U+f521
#define ICON_FA_CRUTCH "\xef\x9f\xb7" // U+f7f7
#define ICON_FA_CUBE "\xef\x86\xb2" // U+f1b2
#define ICON_FA_CUBES "\xef\x86\xb3" // U+f1b3
#define ICON_FA_CUT "\xef\x83\x84" // U+f0c4
#define ICON_FA_DATABASE "\xef\x87\x80" // U+f1c0
#define ICON_FA_DEAF "\xef\x8a\xa4" // U+f2a4
#define ICON_FA_DEMOCRAT "\xef\x9d\x87" // U+f747
#define ICON_FA_DESKTOP "\xef\x84\x88" // U+f108
#define ICON_FA_DHARMACHAKRA "\xef\x99\x95" // U+f655
#define ICON_FA_DIAGNOSES "\xef\x91\xb0" // U+f470
#define ICON_FA_DICE "\xef\x94\xa2" // U+f522
#define ICON_FA_DICE_D20 "\xef\x9b\x8f" // U+f6cf
#define ICON_FA_DICE_D6 "\xef\x9b\x91" // U+f6d1
#define ICON_FA_DICE_FIVE "\xef\x94\xa3" // U+f523
#define ICON_FA_DICE_FOUR "\xef\x94\xa4" // U+f524
#define ICON_FA_DICE_ONE "\xef\x94\xa5" // U+f525
#define ICON_FA_DICE_SIX "\xef\x94\xa6" // U+f526
#define ICON_FA_DICE_THREE "\xef\x94\xa7" // U+f527
#define ICON_FA_DICE_TWO "\xef\x94\xa8" // U+f528
#define ICON_FA_DIGITAL_TACHOGRAPH "\xef\x95\xa6" // U+f566
#define ICON_FA_DIRECTIONS "\xef\x97\xab" // U+f5eb
#define ICON_FA_DISEASE "\xef\x9f\xba" // U+f7fa
#define ICON_FA_DIVIDE "\xef\x94\xa9" // U+f529
#define ICON_FA_DIZZY "\xef\x95\xa7" // U+f567
#define ICON_FA_DNA "\xef\x91\xb1" // U+f471
#define ICON_FA_DOG "\xef\x9b\x93" // U+f6d3
#define ICON_FA_DOLLAR_SIGN "\xef\x85\x95" // U+f155
#define ICON_FA_DOLLY "\xef\x91\xb2" // U+f472
#define ICON_FA_DOLLY_FLATBED "\xef\x91\xb4" // U+f474
#define ICON_FA_DONATE "\xef\x92\xb9" // U+f4b9
#define ICON_FA_DOOR_CLOSED "\xef\x94\xaa" // U+f52a
#define ICON_FA_DOOR_OPEN "\xef\x94\xab" // U+f52b
#define ICON_FA_DOT_CIRCLE "\xef\x86\x92" // U+f192
#define ICON_FA_DOVE "\xef\x92\xba" // U+f4ba
#define ICON_FA_DOWNLOAD "\xef\x80\x99" // U+f019
#define ICON_FA_DRAFTING_COMPASS "\xef\x95\xa8" // U+f568
#define ICON_FA_DRAGON "\xef\x9b\x95" // U+f6d5
#define ICON_FA_DRAW_POLYGON "\xef\x97\xae" // U+f5ee
#define ICON_FA_DRUM "\xef\x95\xa9" // U+f569
#define ICON_FA_DRUM_STEELPAN "\xef\x95\xaa" // U+f56a
#define ICON_FA_DRUMSTICK_BITE "\xef\x9b\x97" // U+f6d7
#define ICON_FA_DUMBBELL "\xef\x91\x8b" // U+f44b
#define ICON_FA_DUMPSTER "\xef\x9e\x93" // U+f793
#define ICON_FA_DUMPSTER_FIRE "\xef\x9e\x94" // U+f794
#define ICON_FA_DUNGEON "\xef\x9b\x99" // U+f6d9
#define ICON_FA_EDIT "\xef\x81\x84" // U+f044
#define ICON_FA_EGG "\xef\x9f\xbb" // U+f7fb
#define ICON_FA_EJECT "\xef\x81\x92" // U+f052
#define ICON_FA_ELLIPSIS_H "\xef\x85\x81" // U+f141
#define ICON_FA_ELLIPSIS_V "\xef\x85\x82" // U+f142
#define ICON_FA_ENVELOPE "\xef\x83\xa0" // U+f0e0
#define ICON_FA_ENVELOPE_OPEN "\xef\x8a\xb6" // U+f2b6
#define ICON_FA_ENVELOPE_OPEN_TEXT "\xef\x99\x98" // U+f658
#define ICON_FA_ENVELOPE_SQUARE "\xef\x86\x99" // U+f199
#define ICON_FA_EQUALS "\xef\x94\xac" // U+f52c
#define ICON_FA_ERASER "\xef\x84\xad" // U+f12d
#define ICON_FA_ETHERNET "\xef\x9e\x96" // U+f796
#define ICON_FA_EURO_SIGN "\xef\x85\x93" // U+f153
#define ICON_FA_EXCHANGE_ALT "\xef\x8d\xa2" // U+f362
#define ICON_FA_EXCLAMATION "\xef\x84\xaa" // U+f12a
#define ICON_FA_EXCLAMATION_CIRCLE "\xef\x81\xaa" // U+f06a
#define ICON_FA_EXCLAMATION_TRIANGLE "\xef\x81\xb1" // U+f071
#define ICON_FA_EXPAND "\xef\x81\xa5" // U+f065
#define ICON_FA_EXPAND_ALT "\xef\x90\xa4" // U+f424
#define ICON_FA_EXPAND_ARROWS_ALT "\xef\x8c\x9e" // U+f31e
#define ICON_FA_EXTERNAL_LINK_ALT "\xef\x8d\x9d" // U+f35d
#define ICON_FA_EXTERNAL_LINK_SQUARE_ALT "\xef\x8d\xa0" // U+f360
#define ICON_FA_EYE "\xef\x81\xae" // U+f06e
#define ICON_FA_EYE_DROPPER "\xef\x87\xbb" // U+f1fb
#define ICON_FA_EYE_SLASH "\xef\x81\xb0" // U+f070
#define ICON_FA_FAN "\xef\xa1\xa3" // U+f863
#define ICON_FA_FAST_BACKWARD "\xef\x81\x89" // U+f049
#define ICON_FA_FAST_FORWARD "\xef\x81\x90" // U+f050
#define ICON_FA_FAUCET "\xee\x80\x85" // U+e005
#define ICON_FA_FAX "\xef\x86\xac" // U+f1ac
#define ICON_FA_FEATHER "\xef\x94\xad" // U+f52d
#define ICON_FA_FEATHER_ALT "\xef\x95\xab" // U+f56b
#define ICON_FA_FEMALE "\xef\x86\x82" // U+f182
#define ICON_FA_FIGHTER_JET "\xef\x83\xbb" // U+f0fb
#define ICON_FA_FILE "\xef\x85\x9b" // U+f15b
#define ICON_FA_FILE_ALT "\xef\x85\x9c" // U+f15c
#define ICON_FA_FILE_ARCHIVE "\xef\x87\x86" // U+f1c6
#define ICON_FA_FILE_AUDIO "\xef\x87\x87" // U+f1c7
#define ICON_FA_FILE_CODE "\xef\x87\x89" // U+f1c9
#define ICON_FA_FILE_CONTRACT "\xef\x95\xac" // U+f56c
#define ICON_FA_FILE_CSV "\xef\x9b\x9d" // U+f6dd
#define ICON_FA_FILE_DOWNLOAD "\xef\x95\xad" // U+f56d
#define ICON_FA_FILE_EXCEL "\xef\x87\x83" // U+f1c3
#define ICON_FA_FILE_EXPORT "\xef\x95\xae" // U+f56e
#define ICON_FA_FILE_IMAGE "\xef\x87\x85" // U+f1c5
#define ICON_FA_FILE_IMPORT "\xef\x95\xaf" // U+f56f
#define ICON_FA_FILE_INVOICE "\xef\x95\xb0" // U+f570
#define ICON_FA_FILE_INVOICE_DOLLAR "\xef\x95\xb1" // U+f571
#define ICON_FA_FILE_MEDICAL "\xef\x91\xb7" // U+f477
#define ICON_FA_FILE_MEDICAL_ALT "\xef\x91\xb8" // U+f478
#define ICON_FA_FILE_PDF "\xef\x87\x81" // U+f1c1
#define ICON_FA_FILE_POWERPOINT "\xef\x87\x84" // U+f1c4
#define ICON_FA_FILE_PRESCRIPTION "\xef\x95\xb2" // U+f572
#define ICON_FA_FILE_SIGNATURE "\xef\x95\xb3" // U+f573
#define ICON_FA_FILE_UPLOAD "\xef\x95\xb4" // U+f574
#define ICON_FA_FILE_VIDEO "\xef\x87\x88" // U+f1c8
#define ICON_FA_FILE_WORD "\xef\x87\x82" // U+f1c2
#define ICON_FA_FILL "\xef\x95\xb5" // U+f575
#define ICON_FA_FILL_DRIP "\xef\x95\xb6" // U+f576
#define ICON_FA_FILM "\xef\x80\x88" // U+f008
#define ICON_FA_FILTER "\xef\x82\xb0" // U+f0b0
#define ICON_FA_FINGERPRINT "\xef\x95\xb7" // U+f577
#define ICON_FA_FIRE "\xef\x81\xad" // U+f06d
#define ICON_FA_FIRE_ALT "\xef\x9f\xa4" // U+f7e4
#define ICON_FA_FIRE_EXTINGUISHER "\xef\x84\xb4" // U+f134
#define ICON_FA_FIRST_AID "\xef\x91\xb9" // U+f479
#define ICON_FA_FISH "\xef\x95\xb8" // U+f578
#define ICON_FA_FIST_RAISED "\xef\x9b\x9e" // U+f6de
#define ICON_FA_FLAG "\xef\x80\xa4" // U+f024
#define ICON_FA_FLAG_CHECKERED "\xef\x84\x9e" // U+f11e
#define ICON_FA_FLAG_USA "\xef\x9d\x8d" // U+f74d
#define ICON_FA_FLASK "\xef\x83\x83" // U+f0c3
#define ICON_FA_FLUSHED "\xef\x95\xb9" // U+f579
#define ICON_FA_FOLDER "\xef\x81\xbb" // U+f07b
#define ICON_FA_FOLDER_MINUS "\xef\x99\x9d" // U+f65d
#define ICON_FA_FOLDER_OPEN "\xef\x81\xbc" // U+f07c
#define ICON_FA_FOLDER_PLUS "\xef\x99\x9e" // U+f65e
#define ICON_FA_FONT "\xef\x80\xb1" // U+f031
#define ICON_FA_FONT_AWESOME_LOGO_FULL "\xef\x93\xa6" // U+f4e6
#define ICON_FA_FOOTBALL_BALL "\xef\x91\x8e" // U+f44e
#define ICON_FA_FORWARD "\xef\x81\x8e" // U+f04e
#define ICON_FA_FROG "\xef\x94\xae" // U+f52e
#define ICON_FA_FROWN "\xef\x84\x99" // U+f119
#define ICON_FA_FROWN_OPEN "\xef\x95\xba" // U+f57a
#define ICON_FA_FUNNEL_DOLLAR "\xef\x99\xa2" // U+f662
#define ICON_FA_FUTBOL "\xef\x87\xa3" // U+f1e3
#define ICON_FA_GAMEPAD "\xef\x84\x9b" // U+f11b
#define ICON_FA_GAS_PUMP "\xef\x94\xaf" // U+f52f
#define ICON_FA_GAVEL "\xef\x83\xa3" // U+f0e3
#define ICON_FA_GEM "\xef\x8e\xa5" // U+f3a5
#define ICON_FA_GENDERLESS "\xef\x88\xad" // U+f22d
#define ICON_FA_GHOST "\xef\x9b\xa2" // U+f6e2
#define ICON_FA_GIFT "\xef\x81\xab" // U+f06b
#define ICON_FA_GIFTS "\xef\x9e\x9c" // U+f79c
#define ICON_FA_GLASS_CHEERS "\xef\x9e\x9f" // U+f79f
#define ICON_FA_GLASS_MARTINI "\xef\x80\x80" // U+f000
#define ICON_FA_GLASS_MARTINI_ALT "\xef\x95\xbb" // U+f57b
#define ICON_FA_GLASS_WHISKEY "\xef\x9e\xa0" // U+f7a0
#define ICON_FA_GLASSES "\xef\x94\xb0" // U+f530
#define ICON_FA_GLOBE "\xef\x82\xac" // U+f0ac
#define ICON_FA_GLOBE_AFRICA "\xef\x95\xbc" // U+f57c
#define ICON_FA_GLOBE_AMERICAS "\xef\x95\xbd" // U+f57d
#define ICON_FA_GLOBE_ASIA "\xef\x95\xbe" // U+f57e
#define ICON_FA_GLOBE_EUROPE "\xef\x9e\xa2" // U+f7a2
#define ICON_FA_GOLF_BALL "\xef\x91\x90" // U+f450
#define ICON_FA_GOPURAM "\xef\x99\xa4" // U+f664
#define ICON_FA_GRADUATION_CAP "\xef\x86\x9d" // U+f19d
#define ICON_FA_GREATER_THAN "\xef\x94\xb1" // U+f531
#define ICON_FA_GREATER_THAN_EQUAL "\xef\x94\xb2" // U+f532
#define ICON_FA_GRIMACE "\xef\x95\xbf" // U+f57f
#define ICON_FA_GRIN "\xef\x96\x80" // U+f580
#define ICON_FA_GRIN_ALT "\xef\x96\x81" // U+f581
#define ICON_FA_GRIN_BEAM "\xef\x96\x82" // U+f582
#define ICON_FA_GRIN_BEAM_SWEAT "\xef\x96\x83" // U+f583
#define ICON_FA_GRIN_HEARTS "\xef\x96\x84" // U+f584
#define ICON_FA_GRIN_SQUINT "\xef\x96\x85" // U+f585
#define ICON_FA_GRIN_SQUINT_TEARS "\xef\x96\x86" // U+f586
#define ICON_FA_GRIN_STARS "\xef\x96\x87" // U+f587
#define ICON_FA_GRIN_TEARS "\xef\x96\x88" // U+f588
#define ICON_FA_GRIN_TONGUE "\xef\x96\x89" // U+f589
#define ICON_FA_GRIN_TONGUE_SQUINT "\xef\x96\x8a" // U+f58a
#define ICON_FA_GRIN_TONGUE_WINK "\xef\x96\x8b" // U+f58b
#define ICON_FA_GRIN_WINK "\xef\x96\x8c" // U+f58c
#define ICON_FA_GRIP_HORIZONTAL "\xef\x96\x8d" // U+f58d
#define ICON_FA_GRIP_LINES "\xef\x9e\xa4" // U+f7a4
#define ICON_FA_GRIP_LINES_VERTICAL "\xef\x9e\xa5" // U+f7a5
#define ICON_FA_GRIP_VERTICAL "\xef\x96\x8e" // U+f58e
#define ICON_FA_GUITAR "\xef\x9e\xa6" // U+f7a6
#define ICON_FA_H_SQUARE "\xef\x83\xbd" // U+f0fd
#define ICON_FA_HAMBURGER "\xef\xa0\x85" // U+f805
#define ICON_FA_HAMMER "\xef\x9b\xa3" // U+f6e3
#define ICON_FA_HAMSA "\xef\x99\xa5" // U+f665
#define ICON_FA_HAND_HOLDING "\xef\x92\xbd" // U+f4bd
#define ICON_FA_HAND_HOLDING_HEART "\xef\x92\xbe" // U+f4be
#define ICON_FA_HAND_HOLDING_MEDICAL "\xee\x81\x9c" // U+e05c
#define ICON_FA_HAND_HOLDING_USD "\xef\x93\x80" // U+f4c0
#define ICON_FA_HAND_HOLDING_WATER "\xef\x93\x81" // U+f4c1
#define ICON_FA_HAND_LIZARD "\xef\x89\x98" // U+f258
#define ICON_FA_HAND_MIDDLE_FINGER "\xef\xa0\x86" // U+f806
#define ICON_FA_HAND_PAPER "\xef\x89\x96" // U+f256
#define ICON_FA_HAND_PEACE "\xef\x89\x9b" // U+f25b
#define ICON_FA_HAND_POINT_DOWN "\xef\x82\xa7" // U+f0a7
#define ICON_FA_HAND_POINT_LEFT "\xef\x82\xa5" // U+f0a5
#define ICON_FA_HAND_POINT_RIGHT "\xef\x82\xa4" // U+f0a4
#define ICON_FA_HAND_POINT_UP "\xef\x82\xa6" // U+f0a6
#define ICON_FA_HAND_POINTER "\xef\x89\x9a" // U+f25a
#define ICON_FA_HAND_ROCK "\xef\x89\x95" // U+f255
#define ICON_FA_HAND_SCISSORS "\xef\x89\x97" // U+f257
#define ICON_FA_HAND_SPARKLES "\xee\x81\x9d" // U+e05d
#define ICON_FA_HAND_SPOCK "\xef\x89\x99" // U+f259
#define ICON_FA_HANDS "\xef\x93\x82" // U+f4c2
#define ICON_FA_HANDS_HELPING "\xef\x93\x84" // U+f4c4
#define ICON_FA_HANDS_WASH "\xee\x81\x9e" // U+e05e
#define ICON_FA_HANDSHAKE "\xef\x8a\xb5" // U+f2b5
#define ICON_FA_HANDSHAKE_ALT_SLASH "\xee\x81\x9f" // U+e05f
#define ICON_FA_HANDSHAKE_SLASH "\xee\x81\xa0" // U+e060
#define ICON_FA_HANUKIAH "\xef\x9b\xa6" // U+f6e6
#define ICON_FA_HARD_HAT "\xef\xa0\x87" // U+f807
#define ICON_FA_HASHTAG "\xef\x8a\x92" // U+f292
#define ICON_FA_HAT_COWBOY "\xef\xa3\x80" // U+f8c0
#define ICON_FA_HAT_COWBOY_SIDE "\xef\xa3\x81" // U+f8c1
#define ICON_FA_HAT_WIZARD "\xef\x9b\xa8" // U+f6e8
#define ICON_FA_HDD "\xef\x82\xa0" // U+f0a0
#define ICON_FA_HEAD_SIDE_COUGH "\xee\x81\xa1" // U+e061
#define ICON_FA_HEAD_SIDE_COUGH_SLASH "\xee\x81\xa2" // U+e062
#define ICON_FA_HEAD_SIDE_MASK "\xee\x81\xa3" // U+e063
#define ICON_FA_HEAD_SIDE_VIRUS "\xee\x81\xa4" // U+e064
#define ICON_FA_HEADING "\xef\x87\x9c" // U+f1dc
#define ICON_FA_HEADPHONES "\xef\x80\xa5" // U+f025
#define ICON_FA_HEADPHONES_ALT "\xef\x96\x8f" // U+f58f
#define ICON_FA_HEADSET "\xef\x96\x90" // U+f590
#define ICON_FA_HEART "\xef\x80\x84" // U+f004
#define ICON_FA_HEART_BROKEN "\xef\x9e\xa9" // U+f7a9
#define ICON_FA_HEARTBEAT "\xef\x88\x9e" // U+f21e
#define ICON_FA_HELICOPTER "\xef\x94\xb3" // U+f533
#define ICON_FA_HIGHLIGHTER "\xef\x96\x91" // U+f591
#define ICON_FA_HIKING "\xef\x9b\xac" // U+f6ec
#define ICON_FA_HIPPO "\xef\x9b\xad" // U+f6ed
#define ICON_FA_HISTORY "\xef\x87\x9a" // U+f1da
#define ICON_FA_HOCKEY_PUCK "\xef\x91\x93" // U+f453
#define ICON_FA_HOLLY_BERRY "\xef\x9e\xaa" // U+f7aa
#define ICON_FA_HOME "\xef\x80\x95" // U+f015
#define ICON_FA_HORSE "\xef\x9b\xb0" // U+f6f0
#define ICON_FA_HORSE_HEAD "\xef\x9e\xab" // U+f7ab
#define ICON_FA_HOSPITAL "\xef\x83\xb8" // U+f0f8
#define ICON_FA_HOSPITAL_ALT "\xef\x91\xbd" // U+f47d
#define ICON_FA_HOSPITAL_SYMBOL "\xef\x91\xbe" // U+f47e
#define ICON_FA_HOSPITAL_USER "\xef\xa0\x8d" // U+f80d
#define ICON_FA_HOT_TUB "\xef\x96\x93" // U+f593
#define ICON_FA_HOTDOG "\xef\xa0\x8f" // U+f80f
#define ICON_FA_HOTEL "\xef\x96\x94" // U+f594
#define ICON_FA_HOURGLASS "\xef\x89\x94" // U+f254
#define ICON_FA_HOURGLASS_END "\xef\x89\x93" // U+f253
#define ICON_FA_HOURGLASS_HALF "\xef\x89\x92" // U+f252
#define ICON_FA_HOURGLASS_START "\xef\x89\x91" // U+f251
#define ICON_FA_HOUSE_DAMAGE "\xef\x9b\xb1" // U+f6f1
#define ICON_FA_HOUSE_USER "\xee\x81\xa5" // U+e065
#define ICON_FA_HRYVNIA "\xef\x9b\xb2" // U+f6f2
#define ICON_FA_I_CURSOR "\xef\x89\x86" // U+f246
#define ICON_FA_ICE_CREAM "\xef\xa0\x90" // U+f810
#define ICON_FA_ICICLES "\xef\x9e\xad" // U+f7ad
#define ICON_FA_ICONS "\xef\xa1\xad" // U+f86d
#define ICON_FA_ID_BADGE "\xef\x8b\x81" // U+f2c1
#define ICON_FA_ID_CARD "\xef\x8b\x82" // U+f2c2
#define ICON_FA_ID_CARD_ALT "\xef\x91\xbf" // U+f47f
#define ICON_FA_IGLOO "\xef\x9e\xae" // U+f7ae
#define ICON_FA_IMAGE "\xef\x80\xbe" // U+f03e
#define ICON_FA_IMAGES "\xef\x8c\x82" // U+f302
#define ICON_FA_INBOX "\xef\x80\x9c" // U+f01c
#define ICON_FA_INDENT "\xef\x80\xbc" // U+f03c
#define ICON_FA_INDUSTRY "\xef\x89\xb5" // U+f275
#define ICON_FA_INFINITY "\xef\x94\xb4" // U+f534
#define ICON_FA_INFO "\xef\x84\xa9" // U+f129
#define ICON_FA_INFO_CIRCLE "\xef\x81\x9a" // U+f05a
#define ICON_FA_ITALIC "\xef\x80\xb3" // U+f033
#define ICON_FA_JEDI "\xef\x99\xa9" // U+f669
#define ICON_FA_JOINT "\xef\x96\x95" // U+f595
#define ICON_FA_JOURNAL_WHILLS "\xef\x99\xaa" // U+f66a
#define ICON_FA_KAABA "\xef\x99\xab" // U+f66b
#define ICON_FA_KEY "\xef\x82\x84" // U+f084
#define ICON_FA_KEYBOARD "\xef\x84\x9c" // U+f11c
#define ICON_FA_KHANDA "\xef\x99\xad" // U+f66d
#define ICON_FA_KISS "\xef\x96\x96" // U+f596
#define ICON_FA_KISS_BEAM "\xef\x96\x97" // U+f597
#define ICON_FA_KISS_WINK_HEART "\xef\x96\x98" // U+f598
#define ICON_FA_KIWI_BIRD "\xef\x94\xb5" // U+f535
#define ICON_FA_LANDMARK "\xef\x99\xaf" // U+f66f
#define ICON_FA_LANGUAGE "\xef\x86\xab" // U+f1ab
#define ICON_FA_LAPTOP "\xef\x84\x89" // U+f109
#define ICON_FA_LAPTOP_CODE "\xef\x97\xbc" // U+f5fc
#define ICON_FA_LAPTOP_HOUSE "\xee\x81\xa6" // U+e066
#define ICON_FA_LAPTOP_MEDICAL "\xef\xa0\x92" // U+f812
#define ICON_FA_LAUGH "\xef\x96\x99" // U+f599
#define ICON_FA_LAUGH_BEAM "\xef\x96\x9a" // U+f59a
#define ICON_FA_LAUGH_SQUINT "\xef\x96\x9b" // U+f59b
#define ICON_FA_LAUGH_WINK "\xef\x96\x9c" // U+f59c
#define ICON_FA_LAYER_GROUP "\xef\x97\xbd" // U+f5fd
#define ICON_FA_LEAF "\xef\x81\xac" // U+f06c
#define ICON_FA_LEMON "\xef\x82\x94" // U+f094
#define ICON_FA_LESS_THAN "\xef\x94\xb6" // U+f536
#define ICON_FA_LESS_THAN_EQUAL "\xef\x94\xb7" // U+f537
#define ICON_FA_LEVEL_DOWN_ALT "\xef\x8e\xbe" // U+f3be
#define ICON_FA_LEVEL_UP_ALT "\xef\x8e\xbf" // U+f3bf
#define ICON_FA_LIFE_RING "\xef\x87\x8d" // U+f1cd
#define ICON_FA_LIGHTBULB "\xef\x83\xab" // U+f0eb
#define ICON_FA_LINK "\xef\x83\x81" // U+f0c1
#define ICON_FA_LIRA_SIGN "\xef\x86\x95" // U+f195
#define ICON_FA_LIST "\xef\x80\xba" // U+f03a
#define ICON_FA_LIST_ALT "\xef\x80\xa2" // U+f022
#define ICON_FA_LIST_OL "\xef\x83\x8b" // U+f0cb
#define ICON_FA_LIST_UL "\xef\x83\x8a" // U+f0ca
#define ICON_FA_LOCATION_ARROW "\xef\x84\xa4" // U+f124
#define ICON_FA_LOCK "\xef\x80\xa3" // U+f023
#define ICON_FA_LOCK_OPEN "\xef\x8f\x81" // U+f3c1
#define ICON_FA_LONG_ARROW_ALT_DOWN "\xef\x8c\x89" // U+f309
#define ICON_FA_LONG_ARROW_ALT_LEFT "\xef\x8c\x8a" // U+f30a
#define ICON_FA_LONG_ARROW_ALT_RIGHT "\xef\x8c\x8b" // U+f30b
#define ICON_FA_LONG_ARROW_ALT_UP "\xef\x8c\x8c" // U+f30c
#define ICON_FA_LOW_VISION "\xef\x8a\xa8" // U+f2a8
#define ICON_FA_LUGGAGE_CART "\xef\x96\x9d" // U+f59d
#define ICON_FA_LUNGS "\xef\x98\x84" // U+f604
#define ICON_FA_LUNGS_VIRUS "\xee\x81\xa7" // U+e067
#define ICON_FA_MAGIC "\xef\x83\x90" // U+f0d0
#define ICON_FA_MAGNET "\xef\x81\xb6" // U+f076
#define ICON_FA_MAIL_BULK "\xef\x99\xb4" // U+f674
#define ICON_FA_MALE "\xef\x86\x83" // U+f183
#define ICON_FA_MAP "\xef\x89\xb9" // U+f279
#define ICON_FA_MAP_MARKED "\xef\x96\x9f" // U+f59f
#define ICON_FA_MAP_MARKED_ALT "\xef\x96\xa0" // U+f5a0
#define ICON_FA_MAP_MARKER "\xef\x81\x81" // U+f041
#define ICON_FA_MAP_MARKER_ALT "\xef\x8f\x85" // U+f3c5
#define ICON_FA_MAP_PIN "\xef\x89\xb6" // U+f276
#define ICON_FA_MAP_SIGNS "\xef\x89\xb7" // U+f277
#define ICON_FA_MARKER "\xef\x96\xa1" // U+f5a1
#define ICON_FA_MARS "\xef\x88\xa2" // U+f222
#define ICON_FA_MARS_DOUBLE "\xef\x88\xa7" // U+f227
#define ICON_FA_MARS_STROKE "\xef\x88\xa9" // U+f229
#define ICON_FA_MARS_STROKE_H "\xef\x88\xab" // U+f22b
#define ICON_FA_MARS_STROKE_V "\xef\x88\xaa" // U+f22a
#define ICON_FA_MASK "\xef\x9b\xba" // U+f6fa
#define ICON_FA_MEDAL "\xef\x96\xa2" // U+f5a2
#define ICON_FA_MEDKIT "\xef\x83\xba" // U+f0fa
#define ICON_FA_MEH "\xef\x84\x9a" // U+f11a
#define ICON_FA_MEH_BLANK "\xef\x96\xa4" // U+f5a4
#define ICON_FA_MEH_ROLLING_EYES "\xef\x96\xa5" // U+f5a5
#define ICON_FA_MEMORY "\xef\x94\xb8" // U+f538
#define ICON_FA_MENORAH "\xef\x99\xb6" // U+f676
#define ICON_FA_MERCURY "\xef\x88\xa3" // U+f223
#define ICON_FA_METEOR "\xef\x9d\x93" // U+f753
#define ICON_FA_MICROCHIP "\xef\x8b\x9b" // U+f2db
#define ICON_FA_MICROPHONE "\xef\x84\xb0" // U+f130
#define ICON_FA_MICROPHONE_ALT "\xef\x8f\x89" // U+f3c9
#define ICON_FA_MICROPHONE_ALT_SLASH "\xef\x94\xb9" // U+f539
#define ICON_FA_MICROPHONE_SLASH "\xef\x84\xb1" // U+f131
#define ICON_FA_MICROSCOPE "\xef\x98\x90" // U+f610
#define ICON_FA_MINUS "\xef\x81\xa8" // U+f068
#define ICON_FA_MINUS_CIRCLE "\xef\x81\x96" // U+f056
#define ICON_FA_MINUS_SQUARE "\xef\x85\x86" // U+f146
#define ICON_FA_MITTEN "\xef\x9e\xb5" // U+f7b5
#define ICON_FA_MOBILE "\xef\x84\x8b" // U+f10b
#define ICON_FA_MOBILE_ALT "\xef\x8f\x8d" // U+f3cd
#define ICON_FA_MONEY_BILL "\xef\x83\x96" // U+f0d6
#define ICON_FA_MONEY_BILL_ALT "\xef\x8f\x91" // U+f3d1
#define ICON_FA_MONEY_BILL_WAVE "\xef\x94\xba" // U+f53a
#define ICON_FA_MONEY_BILL_WAVE_ALT "\xef\x94\xbb" // U+f53b
#define ICON_FA_MONEY_CHECK "\xef\x94\xbc" // U+f53c
#define ICON_FA_MONEY_CHECK_ALT "\xef\x94\xbd" // U+f53d
#define ICON_FA_MONUMENT "\xef\x96\xa6" // U+f5a6
#define ICON_FA_MOON "\xef\x86\x86" // U+f186
#define ICON_FA_MORTAR_PESTLE "\xef\x96\xa7" // U+f5a7
#define ICON_FA_MOSQUE "\xef\x99\xb8" // U+f678
#define ICON_FA_MOTORCYCLE "\xef\x88\x9c" // U+f21c
#define ICON_FA_MOUNTAIN "\xef\x9b\xbc" // U+f6fc
#define ICON_FA_MOUSE "\xef\xa3\x8c" // U+f8cc
#define ICON_FA_MOUSE_POINTER "\xef\x89\x85" // U+f245
#define ICON_FA_MUG_HOT "\xef\x9e\xb6" // U+f7b6
#define ICON_FA_MUSIC "\xef\x80\x81" // U+f001
#define ICON_FA_NETWORK_WIRED "\xef\x9b\xbf" // U+f6ff
#define ICON_FA_NEUTER "\xef\x88\xac" // U+f22c
#define ICON_FA_NEWSPAPER "\xef\x87\xaa" // U+f1ea
#define ICON_FA_NOT_EQUAL "\xef\x94\xbe" // U+f53e
#define ICON_FA_NOTES_MEDICAL "\xef\x92\x81" // U+f481
#define ICON_FA_OBJECT_GROUP "\xef\x89\x87" // U+f247
#define ICON_FA_OBJECT_UNGROUP "\xef\x89\x88" // U+f248
#define ICON_FA_OIL_CAN "\xef\x98\x93" // U+f613
#define ICON_FA_OM "\xef\x99\xb9" // U+f679
#define ICON_FA_OTTER "\xef\x9c\x80" // U+f700
#define ICON_FA_OUTDENT "\xef\x80\xbb" // U+f03b
#define ICON_FA_PAGER "\xef\xa0\x95" // U+f815
#define ICON_FA_PAINT_BRUSH "\xef\x87\xbc" // U+f1fc
#define ICON_FA_PAINT_ROLLER "\xef\x96\xaa" // U+f5aa
#define ICON_FA_PALETTE "\xef\x94\xbf" // U+f53f
#define ICON_FA_PALLET "\xef\x92\x82" // U+f482
#define ICON_FA_PAPER_PLANE "\xef\x87\x98" // U+f1d8
#define ICON_FA_PAPERCLIP "\xef\x83\x86" // U+f0c6
#define ICON_FA_PARACHUTE_BOX "\xef\x93\x8d" // U+f4cd
#define ICON_FA_PARAGRAPH "\xef\x87\x9d" // U+f1dd
#define ICON_FA_PARKING "\xef\x95\x80" // U+f540
#define ICON_FA_PASSPORT "\xef\x96\xab" // U+f5ab
#define ICON_FA_PASTAFARIANISM "\xef\x99\xbb" // U+f67b
#define ICON_FA_PASTE "\xef\x83\xaa" // U+f0ea
#define ICON_FA_PAUSE "\xef\x81\x8c" // U+f04c
#define ICON_FA_PAUSE_CIRCLE "\xef\x8a\x8b" // U+f28b
#define ICON_FA_PAW "\xef\x86\xb0" // U+f1b0
#define ICON_FA_PEACE "\xef\x99\xbc" // U+f67c
#define ICON_FA_PEN "\xef\x8c\x84" // U+f304
#define ICON_FA_PEN_ALT "\xef\x8c\x85" // U+f305
#define ICON_FA_PEN_FANCY "\xef\x96\xac" // U+f5ac
#define ICON_FA_PEN_NIB "\xef\x96\xad" // U+f5ad
#define ICON_FA_PEN_SQUARE "\xef\x85\x8b" // U+f14b
#define ICON_FA_PENCIL_ALT "\xef\x8c\x83" // U+f303
#define ICON_FA_PENCIL_RULER "\xef\x96\xae" // U+f5ae
#define ICON_FA_PEOPLE_ARROWS "\xee\x81\xa8" // U+e068
#define ICON_FA_PEOPLE_CARRY "\xef\x93\x8e" // U+f4ce
#define ICON_FA_PEPPER_HOT "\xef\xa0\x96" // U+f816
#define ICON_FA_PERCENT "\xef\x8a\x95" // U+f295
#define ICON_FA_PERCENTAGE "\xef\x95\x81" // U+f541
#define ICON_FA_PERSON_BOOTH "\xef\x9d\x96" // U+f756
#define ICON_FA_PHONE "\xef\x82\x95" // U+f095
#define ICON_FA_PHONE_ALT "\xef\xa1\xb9" // U+f879
#define ICON_FA_PHONE_SLASH "\xef\x8f\x9d" // U+f3dd
#define ICON_FA_PHONE_SQUARE "\xef\x82\x98" // U+f098
#define ICON_FA_PHONE_SQUARE_ALT "\xef\xa1\xbb" // U+f87b
#define ICON_FA_PHONE_VOLUME "\xef\x8a\xa0" // U+f2a0
#define ICON_FA_PHOTO_VIDEO "\xef\xa1\xbc" // U+f87c
#define ICON_FA_PIGGY_BANK "\xef\x93\x93" // U+f4d3
#define ICON_FA_PILLS "\xef\x92\x84" // U+f484
#define ICON_FA_PIZZA_SLICE "\xef\xa0\x98" // U+f818
#define ICON_FA_PLACE_OF_WORSHIP "\xef\x99\xbf" // U+f67f
#define ICON_FA_PLANE "\xef\x81\xb2" // U+f072
#define ICON_FA_PLANE_ARRIVAL "\xef\x96\xaf" // U+f5af
#define ICON_FA_PLANE_DEPARTURE "\xef\x96\xb0" // U+f5b0
#define ICON_FA_PLANE_SLASH "\xee\x81\xa9" // U+e069
#define ICON_FA_PLAY "\xef\x81\x8b" // U+f04b
#define ICON_FA_PLAY_CIRCLE "\xef\x85\x84" // U+f144
#define ICON_FA_PLUG "\xef\x87\xa6" // U+f1e6
#define ICON_FA_PLUS "\xef\x81\xa7" // U+f067
#define ICON_FA_PLUS_CIRCLE "\xef\x81\x95" // U+f055
#define ICON_FA_PLUS_SQUARE "\xef\x83\xbe" // U+f0fe
#define ICON_FA_PODCAST "\xef\x8b\x8e" // U+f2ce
#define ICON_FA_POLL "\xef\x9a\x81" // U+f681
#define ICON_FA_POLL_H "\xef\x9a\x82" // U+f682
#define ICON_FA_POO "\xef\x8b\xbe" // U+f2fe
#define ICON_FA_POO_STORM "\xef\x9d\x9a" // U+f75a
#define ICON_FA_POOP "\xef\x98\x99" // U+f619
#define ICON_FA_PORTRAIT "\xef\x8f\xa0" // U+f3e0
#define ICON_FA_POUND_SIGN "\xef\x85\x94" // U+f154
#define ICON_FA_POWER_OFF "\xef\x80\x91" // U+f011
#define ICON_FA_PRAY "\xef\x9a\x83" // U+f683
#define ICON_FA_PRAYING_HANDS "\xef\x9a\x84" // U+f684
#define ICON_FA_PRESCRIPTION "\xef\x96\xb1" // U+f5b1
#define ICON_FA_PRESCRIPTION_BOTTLE "\xef\x92\x85" // U+f485
#define ICON_FA_PRESCRIPTION_BOTTLE_ALT "\xef\x92\x86" // U+f486
#define ICON_FA_PRINT "\xef\x80\xaf" // U+f02f
#define ICON_FA_PROCEDURES "\xef\x92\x87" // U+f487
#define ICON_FA_PROJECT_DIAGRAM "\xef\x95\x82" // U+f542
#define ICON_FA_PUMP_MEDICAL "\xee\x81\xaa" // U+e06a
#define ICON_FA_PUMP_SOAP "\xee\x81\xab" // U+e06b
#define ICON_FA_PUZZLE_PIECE "\xef\x84\xae" // U+f12e
#define ICON_FA_QRCODE "\xef\x80\xa9" // U+f029
#define ICON_FA_QUESTION "\xef\x84\xa8" // U+f128
#define ICON_FA_QUESTION_CIRCLE "\xef\x81\x99" // U+f059
#define ICON_FA_QUIDDITCH "\xef\x91\x98" // U+f458
#define ICON_FA_QUOTE_LEFT "\xef\x84\x8d" // U+f10d
#define ICON_FA_QUOTE_RIGHT "\xef\x84\x8e" // U+f10e
#define ICON_FA_QURAN "\xef\x9a\x87" // U+f687
#define ICON_FA_RADIATION "\xef\x9e\xb9" // U+f7b9
#define ICON_FA_RADIATION_ALT "\xef\x9e\xba" // U+f7ba
#define ICON_FA_RAINBOW "\xef\x9d\x9b" // U+f75b
#define ICON_FA_RANDOM "\xef\x81\xb4" // U+f074
#define ICON_FA_RECEIPT "\xef\x95\x83" // U+f543
#define ICON_FA_RECORD_VINYL "\xef\xa3\x99" // U+f8d9
#define ICON_FA_RECYCLE "\xef\x86\xb8" // U+f1b8
#define ICON_FA_REDO "\xef\x80\x9e" // U+f01e
#define ICON_FA_REDO_ALT "\xef\x8b\xb9" // U+f2f9
#define ICON_FA_REGISTERED "\xef\x89\x9d" // U+f25d
#define ICON_FA_REMOVE_FORMAT "\xef\xa1\xbd" // U+f87d
#define ICON_FA_REPLY "\xef\x8f\xa5" // U+f3e5
#define ICON_FA_REPLY_ALL "\xef\x84\xa2" // U+f122
#define ICON_FA_REPUBLICAN "\xef\x9d\x9e" // U+f75e
#define ICON_FA_RESTROOM "\xef\x9e\xbd" // U+f7bd
#define ICON_FA_RETWEET "\xef\x81\xb9" // U+f079
#define ICON_FA_RIBBON "\xef\x93\x96" // U+f4d6
#define ICON_FA_RING "\xef\x9c\x8b" // U+f70b
#define ICON_FA_ROAD "\xef\x80\x98" // U+f018
#define ICON_FA_ROBOT "\xef\x95\x84" // U+f544
#define ICON_FA_ROCKET "\xef\x84\xb5" // U+f135
#define ICON_FA_ROUTE "\xef\x93\x97" // U+f4d7
#define ICON_FA_RSS "\xef\x82\x9e" // U+f09e
#define ICON_FA_RSS_SQUARE "\xef\x85\x83" // U+f143
#define ICON_FA_RUBLE_SIGN "\xef\x85\x98" // U+f158
#define ICON_FA_RULER "\xef\x95\x85" // U+f545
#define ICON_FA_RULER_COMBINED "\xef\x95\x86" // U+f546
#define ICON_FA_RULER_HORIZONTAL "\xef\x95\x87" // U+f547
#define ICON_FA_RULER_VERTICAL "\xef\x95\x88" // U+f548
#define ICON_FA_RUNNING "\xef\x9c\x8c" // U+f70c
#define ICON_FA_RUPEE_SIGN "\xef\x85\x96" // U+f156
#define ICON_FA_SAD_CRY "\xef\x96\xb3" // U+f5b3
#define ICON_FA_SAD_TEAR "\xef\x96\xb4" // U+f5b4
#define ICON_FA_SATELLITE "\xef\x9e\xbf" // U+f7bf
#define ICON_FA_SATELLITE_DISH "\xef\x9f\x80" // U+f7c0
#define ICON_FA_SAVE "\xef\x83\x87" // U+f0c7
#define ICON_FA_SCHOOL "\xef\x95\x89" // U+f549
#define ICON_FA_SCREWDRIVER "\xef\x95\x8a" // U+f54a
#define ICON_FA_SCROLL "\xef\x9c\x8e" // U+f70e
#define ICON_FA_SD_CARD "\xef\x9f\x82" // U+f7c2
#define ICON_FA_SEARCH "\xef\x80\x82" // U+f002
#define ICON_FA_SEARCH_DOLLAR "\xef\x9a\x88" // U+f688
#define ICON_FA_SEARCH_LOCATION "\xef\x9a\x89" // U+f689
#define ICON_FA_SEARCH_MINUS "\xef\x80\x90" // U+f010
#define ICON_FA_SEARCH_PLUS "\xef\x80\x8e" // U+f00e
#define ICON_FA_SEEDLING "\xef\x93\x98" // U+f4d8
#define ICON_FA_SERVER "\xef\x88\xb3" // U+f233
#define ICON_FA_SHAPES "\xef\x98\x9f" // U+f61f
#define ICON_FA_SHARE "\xef\x81\xa4" // U+f064
#define ICON_FA_SHARE_ALT "\xef\x87\xa0" // U+f1e0
#define ICON_FA_SHARE_ALT_SQUARE "\xef\x87\xa1" // U+f1e1
#define ICON_FA_SHARE_SQUARE "\xef\x85\x8d" // U+f14d
#define ICON_FA_SHEKEL_SIGN "\xef\x88\x8b" // U+f20b
#define ICON_FA_SHIELD_ALT "\xef\x8f\xad" // U+f3ed
#define ICON_FA_SHIELD_VIRUS "\xee\x81\xac" // U+e06c
#define ICON_FA_SHIP "\xef\x88\x9a" // U+f21a
#define ICON_FA_SHIPPING_FAST "\xef\x92\x8b" // U+f48b
#define ICON_FA_SHOE_PRINTS "\xef\x95\x8b" // U+f54b
#define ICON_FA_SHOPPING_BAG "\xef\x8a\x90" // U+f290
#define ICON_FA_SHOPPING_BASKET "\xef\x8a\x91" // U+f291
#define ICON_FA_SHOPPING_CART "\xef\x81\xba" // U+f07a
#define ICON_FA_SHOWER "\xef\x8b\x8c" // U+f2cc
#define ICON_FA_SHUTTLE_VAN "\xef\x96\xb6" // U+f5b6
#define ICON_FA_SIGN "\xef\x93\x99" // U+f4d9
#define ICON_FA_SIGN_IN_ALT "\xef\x8b\xb6" // U+f2f6
#define ICON_FA_SIGN_LANGUAGE "\xef\x8a\xa7" // U+f2a7
#define ICON_FA_SIGN_OUT_ALT "\xef\x8b\xb5" // U+f2f5
#define ICON_FA_SIGNAL "\xef\x80\x92" // U+f012
#define ICON_FA_SIGNATURE "\xef\x96\xb7" // U+f5b7
#define ICON_FA_SIM_CARD "\xef\x9f\x84" // U+f7c4
#define ICON_FA_SINK "\xee\x81\xad" // U+e06d
#define ICON_FA_SITEMAP "\xef\x83\xa8" // U+f0e8
#define ICON_FA_SKATING "\xef\x9f\x85" // U+f7c5
#define ICON_FA_SKIING "\xef\x9f\x89" // U+f7c9
#define ICON_FA_SKIING_NORDIC "\xef\x9f\x8a" // U+f7ca
#define ICON_FA_SKULL "\xef\x95\x8c" // U+f54c
#define ICON_FA_SKULL_CROSSBONES "\xef\x9c\x94" // U+f714
#define ICON_FA_SLASH "\xef\x9c\x95" // U+f715
#define ICON_FA_SLEIGH "\xef\x9f\x8c" // U+f7cc
#define ICON_FA_SLIDERS_H "\xef\x87\x9e" // U+f1de
#define ICON_FA_SMILE "\xef\x84\x98" // U+f118
#define ICON_FA_SMILE_BEAM "\xef\x96\xb8" // U+f5b8
#define ICON_FA_SMILE_WINK "\xef\x93\x9a" // U+f4da
#define ICON_FA_SMOG "\xef\x9d\x9f" // U+f75f
#define ICON_FA_SMOKING "\xef\x92\x8d" // U+f48d
#define ICON_FA_SMOKING_BAN "\xef\x95\x8d" // U+f54d
#define ICON_FA_SMS "\xef\x9f\x8d" // U+f7cd
#define ICON_FA_SNOWBOARDING "\xef\x9f\x8e" // U+f7ce
#define ICON_FA_SNOWFLAKE "\xef\x8b\x9c" // U+f2dc
#define ICON_FA_SNOWMAN "\xef\x9f\x90" // U+f7d0
#define ICON_FA_SNOWPLOW "\xef\x9f\x92" // U+f7d2
#define ICON_FA_SOAP "\xee\x81\xae" // U+e06e
#define ICON_FA_SOCKS "\xef\x9a\x96" // U+f696
#define ICON_FA_SOLAR_PANEL "\xef\x96\xba" // U+f5ba
#define ICON_FA_SORT "\xef\x83\x9c" // U+f0dc
#define ICON_FA_SORT_ALPHA_DOWN "\xef\x85\x9d" // U+f15d
#define ICON_FA_SORT_ALPHA_DOWN_ALT "\xef\xa2\x81" // U+f881
#define ICON_FA_SORT_ALPHA_UP "\xef\x85\x9e" // U+f15e
#define ICON_FA_SORT_ALPHA_UP_ALT "\xef\xa2\x82" // U+f882
#define ICON_FA_SORT_AMOUNT_DOWN "\xef\x85\xa0" // U+f160
#define ICON_FA_SORT_AMOUNT_DOWN_ALT "\xef\xa2\x84" // U+f884
#define ICON_FA_SORT_AMOUNT_UP "\xef\x85\xa1" // U+f161
#define ICON_FA_SORT_AMOUNT_UP_ALT "\xef\xa2\x85" // U+f885
#define ICON_FA_SORT_DOWN "\xef\x83\x9d" // U+f0dd
#define ICON_FA_SORT_NUMERIC_DOWN "\xef\x85\xa2" // U+f162
#define ICON_FA_SORT_NUMERIC_DOWN_ALT "\xef\xa2\x86" // U+f886
#define ICON_FA_SORT_NUMERIC_UP "\xef\x85\xa3" // U+f163
#define ICON_FA_SORT_NUMERIC_UP_ALT "\xef\xa2\x87" // U+f887
#define ICON_FA_SORT_UP "\xef\x83\x9e" // U+f0de
#define ICON_FA_SPA "\xef\x96\xbb" // U+f5bb
#define ICON_FA_SPACE_SHUTTLE "\xef\x86\x97" // U+f197
#define ICON_FA_SPELL_CHECK "\xef\xa2\x91" // U+f891
#define ICON_FA_SPIDER "\xef\x9c\x97" // U+f717
#define ICON_FA_SPINNER "\xef\x84\x90" // U+f110
#define ICON_FA_SPLOTCH "\xef\x96\xbc" // U+f5bc
#define ICON_FA_SPRAY_CAN "\xef\x96\xbd" // U+f5bd
#define ICON_FA_SQUARE "\xef\x83\x88" // U+f0c8
#define ICON_FA_SQUARE_FULL "\xef\x91\x9c" // U+f45c
#define ICON_FA_SQUARE_ROOT_ALT "\xef\x9a\x98" // U+f698
#define ICON_FA_STAMP "\xef\x96\xbf" // U+f5bf
#define ICON_FA_STAR "\xef\x80\x85" // U+f005
#define ICON_FA_STAR_AND_CRESCENT "\xef\x9a\x99" // U+f699
#define ICON_FA_STAR_HALF "\xef\x82\x89" // U+f089
#define ICON_FA_STAR_HALF_ALT "\xef\x97\x80" // U+f5c0
#define ICON_FA_STAR_OF_DAVID "\xef\x9a\x9a" // U+f69a
#define ICON_FA_STAR_OF_LIFE "\xef\x98\xa1" // U+f621
#define ICON_FA_STEP_BACKWARD "\xef\x81\x88" // U+f048
#define ICON_FA_STEP_FORWARD "\xef\x81\x91" // U+f051
#define ICON_FA_STETHOSCOPE "\xef\x83\xb1" // U+f0f1
#define ICON_FA_STICKY_NOTE "\xef\x89\x89" // U+f249
#define ICON_FA_STOP "\xef\x81\x8d" // U+f04d
#define ICON_FA_STOP_CIRCLE "\xef\x8a\x8d" // U+f28d
#define ICON_FA_STOPWATCH "\xef\x8b\xb2" // U+f2f2
#define ICON_FA_STOPWATCH_20 "\xee\x81\xaf" // U+e06f
#define ICON_FA_STORE "\xef\x95\x8e" // U+f54e
#define ICON_FA_STORE_ALT "\xef\x95\x8f" // U+f54f
#define ICON_FA_STORE_ALT_SLASH "\xee\x81\xb0" // U+e070
#define ICON_FA_STORE_SLASH "\xee\x81\xb1" // U+e071
#define ICON_FA_STREAM "\xef\x95\x90" // U+f550
#define ICON_FA_STREET_VIEW "\xef\x88\x9d" // U+f21d
#define ICON_FA_STRIKETHROUGH "\xef\x83\x8c" // U+f0cc
#define ICON_FA_STROOPWAFEL "\xef\x95\x91" // U+f551
#define ICON_FA_SUBSCRIPT "\xef\x84\xac" // U+f12c
#define ICON_FA_SUBWAY "\xef\x88\xb9" // U+f239
#define ICON_FA_SUITCASE "\xef\x83\xb2" // U+f0f2
#define ICON_FA_SUITCASE_ROLLING "\xef\x97\x81" // U+f5c1
#define ICON_FA_SUN "\xef\x86\x85" // U+f185
#define ICON_FA_SUPERSCRIPT "\xef\x84\xab" // U+f12b
#define ICON_FA_SURPRISE "\xef\x97\x82" // U+f5c2
#define ICON_FA_SWATCHBOOK "\xef\x97\x83" // U+f5c3
#define ICON_FA_SWIMMER "\xef\x97\x84" // U+f5c4
#define ICON_FA_SWIMMING_POOL "\xef\x97\x85" // U+f5c5
#define ICON_FA_SYNAGOGUE "\xef\x9a\x9b" // U+f69b
#define ICON_FA_SYNC "\xef\x80\xa1" // U+f021
#define ICON_FA_SYNC_ALT "\xef\x8b\xb1" // U+f2f1
#define ICON_FA_SYRINGE "\xef\x92\x8e" // U+f48e
#define ICON_FA_TABLE "\xef\x83\x8e" // U+f0ce
#define ICON_FA_TABLE_TENNIS "\xef\x91\x9d" // U+f45d
#define ICON_FA_TABLET "\xef\x84\x8a" // U+f10a
#define ICON_FA_TABLET_ALT "\xef\x8f\xba" // U+f3fa
#define ICON_FA_TABLETS "\xef\x92\x90" // U+f490
#define ICON_FA_TACHOMETER_ALT "\xef\x8f\xbd" // U+f3fd
#define ICON_FA_TAG "\xef\x80\xab" // U+f02b
#define ICON_FA_TAGS "\xef\x80\xac" // U+f02c
#define ICON_FA_TAPE "\xef\x93\x9b" // U+f4db
#define ICON_FA_TASKS "\xef\x82\xae" // U+f0ae
#define ICON_FA_TAXI "\xef\x86\xba" // U+f1ba
#define ICON_FA_TEETH "\xef\x98\xae" // U+f62e
#define ICON_FA_TEETH_OPEN "\xef\x98\xaf" // U+f62f
#define ICON_FA_TEMPERATURE_HIGH "\xef\x9d\xa9" // U+f769
#define ICON_FA_TEMPERATURE_LOW "\xef\x9d\xab" // U+f76b
#define ICON_FA_TENGE "\xef\x9f\x97" // U+f7d7
#define ICON_FA_TERMINAL "\xef\x84\xa0" // U+f120
#define ICON_FA_TEXT_HEIGHT "\xef\x80\xb4" // U+f034
#define ICON_FA_TEXT_WIDTH "\xef\x80\xb5" // U+f035
#define ICON_FA_TH "\xef\x80\x8a" // U+f00a
#define ICON_FA_TH_LARGE "\xef\x80\x89" // U+f009
#define ICON_FA_TH_LIST "\xef\x80\x8b" // U+f00b
#define ICON_FA_THEATER_MASKS "\xef\x98\xb0" // U+f630
#define ICON_FA_THERMOMETER "\xef\x92\x91" // U+f491
#define ICON_FA_THERMOMETER_EMPTY "\xef\x8b\x8b" // U+f2cb
#define ICON_FA_THERMOMETER_FULL "\xef\x8b\x87" // U+f2c7
#define ICON_FA_THERMOMETER_HALF "\xef\x8b\x89" // U+f2c9
#define ICON_FA_THERMOMETER_QUARTER "\xef\x8b\x8a" // U+f2ca
#define ICON_FA_THERMOMETER_THREE_QUARTERS "\xef\x8b\x88" // U+f2c8
#define ICON_FA_THUMBS_DOWN "\xef\x85\xa5" // U+f165
#define ICON_FA_THUMBS_UP "\xef\x85\xa4" // U+f164
#define ICON_FA_THUMBTACK "\xef\x82\x8d" // U+f08d
#define ICON_FA_TICKET_ALT "\xef\x8f\xbf" // U+f3ff
#define ICON_FA_TIMES "\xef\x80\x8d" // U+f00d
#define ICON_FA_TIMES_CIRCLE "\xef\x81\x97" // U+f057
#define ICON_FA_TINT "\xef\x81\x83" // U+f043
#define ICON_FA_TINT_SLASH "\xef\x97\x87" // U+f5c7
#define ICON_FA_TIRED "\xef\x97\x88" // U+f5c8
#define ICON_FA_TOGGLE_OFF "\xef\x88\x84" // U+f204
#define ICON_FA_TOGGLE_ON "\xef\x88\x85" // U+f205
#define ICON_FA_TOILET "\xef\x9f\x98" // U+f7d8
#define ICON_FA_TOILET_PAPER "\xef\x9c\x9e" // U+f71e
#define ICON_FA_TOILET_PAPER_SLASH "\xee\x81\xb2" // U+e072
#define ICON_FA_TOOLBOX "\xef\x95\x92" // U+f552
#define ICON_FA_TOOLS "\xef\x9f\x99" // U+f7d9
#define ICON_FA_TOOTH "\xef\x97\x89" // U+f5c9
#define ICON_FA_TORAH "\xef\x9a\xa0" // U+f6a0
#define ICON_FA_TORII_GATE "\xef\x9a\xa1" // U+f6a1
#define ICON_FA_TRACTOR "\xef\x9c\xa2" // U+f722
#define ICON_FA_TRADEMARK "\xef\x89\x9c" // U+f25c
#define ICON_FA_TRAFFIC_LIGHT "\xef\x98\xb7" // U+f637
#define ICON_FA_TRAILER "\xee\x81\x81" // U+e041
#define ICON_FA_TRAIN "\xef\x88\xb8" // U+f238
#define ICON_FA_TRAM "\xef\x9f\x9a" // U+f7da
#define ICON_FA_TRANSGENDER "\xef\x88\xa4" // U+f224
#define ICON_FA_TRANSGENDER_ALT "\xef\x88\xa5" // U+f225
#define ICON_FA_TRASH "\xef\x87\xb8" // U+f1f8
#define ICON_FA_TRASH_ALT "\xef\x8b\xad" // U+f2ed
#define ICON_FA_TRASH_RESTORE "\xef\xa0\xa9" // U+f829
#define ICON_FA_TRASH_RESTORE_ALT "\xef\xa0\xaa" // U+f82a
#define ICON_FA_TREE "\xef\x86\xbb" // U+f1bb
#define ICON_FA_TROPHY "\xef\x82\x91" // U+f091
#define ICON_FA_TRUCK "\xef\x83\x91" // U+f0d1
#define ICON_FA_TRUCK_LOADING "\xef\x93\x9e" // U+f4de
#define ICON_FA_TRUCK_MONSTER "\xef\x98\xbb" // U+f63b
#define ICON_FA_TRUCK_MOVING "\xef\x93\x9f" // U+f4df
#define ICON_FA_TRUCK_PICKUP "\xef\x98\xbc" // U+f63c
#define ICON_FA_TSHIRT "\xef\x95\x93" // U+f553
#define ICON_FA_TTY "\xef\x87\xa4" // U+f1e4
#define ICON_FA_TV "\xef\x89\xac" // U+f26c
#define ICON_FA_UMBRELLA "\xef\x83\xa9" // U+f0e9
#define ICON_FA_UMBRELLA_BEACH "\xef\x97\x8a" // U+f5ca
#define ICON_FA_UNDERLINE "\xef\x83\x8d" // U+f0cd
#define ICON_FA_UNDO "\xef\x83\xa2" // U+f0e2
#define ICON_FA_UNDO_ALT "\xef\x8b\xaa" // U+f2ea
#define ICON_FA_UNIVERSAL_ACCESS "\xef\x8a\x9a" // U+f29a
#define ICON_FA_UNIVERSITY "\xef\x86\x9c" // U+f19c
#define ICON_FA_UNLINK "\xef\x84\xa7" // U+f127
#define ICON_FA_UNLOCK "\xef\x82\x9c" // U+f09c
#define ICON_FA_UNLOCK_ALT "\xef\x84\xbe" // U+f13e
#define ICON_FA_UPLOAD "\xef\x82\x93" // U+f093
#define ICON_FA_USER "\xef\x80\x87" // U+f007
#define ICON_FA_USER_ALT "\xef\x90\x86" // U+f406
#define ICON_FA_USER_ALT_SLASH "\xef\x93\xba" // U+f4fa
#define ICON_FA_USER_ASTRONAUT "\xef\x93\xbb" // U+f4fb
#define ICON_FA_USER_CHECK "\xef\x93\xbc" // U+f4fc
#define ICON_FA_USER_CIRCLE "\xef\x8a\xbd" // U+f2bd
#define ICON_FA_USER_CLOCK "\xef\x93\xbd" // U+f4fd
#define ICON_FA_USER_COG "\xef\x93\xbe" // U+f4fe
#define ICON_FA_USER_EDIT "\xef\x93\xbf" // U+f4ff
#define ICON_FA_USER_FRIENDS "\xef\x94\x80" // U+f500
#define ICON_FA_USER_GRADUATE "\xef\x94\x81" // U+f501
#define ICON_FA_USER_INJURED "\xef\x9c\xa8" // U+f728
#define ICON_FA_USER_LOCK "\xef\x94\x82" // U+f502
#define ICON_FA_USER_MD "\xef\x83\xb0" // U+f0f0
#define ICON_FA_USER_MINUS "\xef\x94\x83" // U+f503
#define ICON_FA_USER_NINJA "\xef\x94\x84" // U+f504
#define ICON_FA_USER_NURSE "\xef\xa0\xaf" // U+f82f
#define ICON_FA_USER_PLUS "\xef\x88\xb4" // U+f234
#define ICON_FA_USER_SECRET "\xef\x88\x9b" // U+f21b
#define ICON_FA_USER_SHIELD "\xef\x94\x85" // U+f505
#define ICON_FA_USER_SLASH "\xef\x94\x86" // U+f506
#define ICON_FA_USER_TAG "\xef\x94\x87" // U+f507
#define ICON_FA_USER_TIE "\xef\x94\x88" // U+f508
#define ICON_FA_USER_TIMES "\xef\x88\xb5" // U+f235
#define ICON_FA_USERS "\xef\x83\x80" // U+f0c0
#define ICON_FA_USERS_COG "\xef\x94\x89" // U+f509
#define ICON_FA_USERS_SLASH "\xee\x81\xb3" // U+e073
#define ICON_FA_UTENSIL_SPOON "\xef\x8b\xa5" // U+f2e5
#define ICON_FA_UTENSILS "\xef\x8b\xa7" // U+f2e7
#define ICON_FA_VECTOR_SQUARE "\xef\x97\x8b" // U+f5cb
#define ICON_FA_VENUS "\xef\x88\xa1" // U+f221
#define ICON_FA_VENUS_DOUBLE "\xef\x88\xa6" // U+f226
#define ICON_FA_VENUS_MARS "\xef\x88\xa8" // U+f228
#define ICON_FA_VEST "\xee\x82\x85" // U+e085
#define ICON_FA_VEST_PATCHES "\xee\x82\x86" // U+e086
#define ICON_FA_VIAL "\xef\x92\x92" // U+f492
#define ICON_FA_VIALS "\xef\x92\x93" // U+f493
#define ICON_FA_VIDEO "\xef\x80\xbd" // U+f03d
#define ICON_FA_VIDEO_SLASH "\xef\x93\xa2" // U+f4e2
#define ICON_FA_VIHARA "\xef\x9a\xa7" // U+f6a7
#define ICON_FA_VIRUS "\xee\x81\xb4" // U+e074
#define ICON_FA_VIRUS_SLASH "\xee\x81\xb5" // U+e075
#define ICON_FA_VIRUSES "\xee\x81\xb6" // U+e076
#define ICON_FA_VOICEMAIL "\xef\xa2\x97" // U+f897
#define ICON_FA_VOLLEYBALL_BALL "\xef\x91\x9f" // U+f45f
#define ICON_FA_VOLUME_DOWN "\xef\x80\xa7" // U+f027
#define ICON_FA_VOLUME_MUTE "\xef\x9a\xa9" // U+f6a9
#define ICON_FA_VOLUME_OFF "\xef\x80\xa6" // U+f026
#define ICON_FA_VOLUME_UP "\xef\x80\xa8" // U+f028
#define ICON_FA_VOTE_YEA "\xef\x9d\xb2" // U+f772
#define ICON_FA_VR_CARDBOARD "\xef\x9c\xa9" // U+f729
#define ICON_FA_WALKING "\xef\x95\x94" // U+f554
#define ICON_FA_WALLET "\xef\x95\x95" // U+f555
#define ICON_FA_WAREHOUSE "\xef\x92\x94" // U+f494
#define ICON_FA_WATER "\xef\x9d\xb3" // U+f773
#define ICON_FA_WAVE_SQUARE "\xef\xa0\xbe" // U+f83e
#define ICON_FA_WEIGHT "\xef\x92\x96" // U+f496
#define ICON_FA_WEIGHT_HANGING "\xef\x97\x8d" // U+f5cd
#define ICON_FA_WHEELCHAIR "\xef\x86\x93" // U+f193
#define ICON_FA_WIFI "\xef\x87\xab" // U+f1eb
#define ICON_FA_WIND "\xef\x9c\xae" // U+f72e
#define ICON_FA_WINDOW_CLOSE "\xef\x90\x90" // U+f410
#define ICON_FA_WINDOW_MAXIMIZE "\xef\x8b\x90" // U+f2d0
#define ICON_FA_WINDOW_MINIMIZE "\xef\x8b\x91" // U+f2d1
#define ICON_FA_WINDOW_RESTORE "\xef\x8b\x92" // U+f2d2
#define ICON_FA_WINE_BOTTLE "\xef\x9c\xaf" // U+f72f
#define ICON_FA_WINE_GLASS "\xef\x93\xa3" // U+f4e3
#define ICON_FA_WINE_GLASS_ALT "\xef\x97\x8e" // U+f5ce
#define ICON_FA_WON_SIGN "\xef\x85\x99" // U+f159
#define ICON_FA_WRENCH "\xef\x82\xad" // U+f0ad
#define ICON_FA_X_RAY "\xef\x92\x97" // U+f497
#define ICON_FA_YEN_SIGN "\xef\x85\x97" // U+f157
#define ICON_FA_YIN_YANG "\xef\x9a\xad" // U+f6ad
================================================
FILE: Source/External/imgui_tools/imgui_impl_glfw.cpp
================================================
// dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Issues:
// [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
// 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position.
// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX.
// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11.
// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend.
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API.
// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#include "imgui.h"
#include "imgui_impl_glfw.h"
// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
#endif
// GLFW
#include
#ifdef _WIN32
#undef APIENTRY
#define GLFW_EXPOSE_NATIVE_WIN32
#include // for glfwGetWin32Window()
#endif
#ifdef __APPLE__
#define GLFW_EXPOSE_NATIVE_COCOA
#include // for glfwGetCocoaWindow()
#endif
// We gather version tests as define in order to easily see which features are version-dependent.
#define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_HOVERED
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwSetWindowOpacity
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale
#define GLFW_HAS_VULKAN (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwCreateWindowSurface
#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwFocusWindow
#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW
#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorWorkarea
#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_COMBINED >= 3301) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
#else
#define GLFW_HAS_NEW_CURSORS (0)
#endif
#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
#else
#define GLFW_HAS_MOUSE_PASSTHROUGH (0)
#endif
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api
#define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName()
// GLFW data
enum GlfwClientApi
{
GlfwClientApi_Unknown,
GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan
};
struct ImGui_ImplGlfw_Data
{
GLFWwindow* Window;
GlfwClientApi ClientApi;
double Time;
GLFWwindow* MouseWindow;
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
ImVec2 LastValidMousePos;
GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST];
bool InstalledCallbacks;
bool WantUpdateMonitors;
#ifdef _WIN32
WNDPROC GlfwWndProc;
#endif
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
GLFWcursorposfun PrevUserCallbackCursorPos;
GLFWcursorenterfun PrevUserCallbackCursorEnter;
GLFWmousebuttonfun PrevUserCallbackMousebutton;
GLFWscrollfun PrevUserCallbackScroll;
GLFWkeyfun PrevUserCallbackKey;
GLFWcharfun PrevUserCallbackChar;
GLFWmonitorfun PrevUserCallbackMonitor;
ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
}
// Forward Declarations
static void ImGui_ImplGlfw_UpdateMonitors();
static void ImGui_ImplGlfw_InitPlatformInterface();
static void ImGui_ImplGlfw_ShutdownPlatformInterface();
// Functions
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
return glfwGetClipboardString((GLFWwindow*)user_data);
}
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
{
glfwSetClipboardString((GLFWwindow*)user_data, text);
}
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
{
switch (key)
{
case GLFW_KEY_TAB: return ImGuiKey_Tab;
case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
case GLFW_KEY_UP: return ImGuiKey_UpArrow;
case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
case GLFW_KEY_HOME: return ImGuiKey_Home;
case GLFW_KEY_END: return ImGuiKey_End;
case GLFW_KEY_INSERT: return ImGuiKey_Insert;
case GLFW_KEY_DELETE: return ImGuiKey_Delete;
case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
case GLFW_KEY_SPACE: return ImGuiKey_Space;
case GLFW_KEY_ENTER: return ImGuiKey_Enter;
case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
case GLFW_KEY_COMMA: return ImGuiKey_Comma;
case GLFW_KEY_MINUS: return ImGuiKey_Minus;
case GLFW_KEY_PERIOD: return ImGuiKey_Period;
case GLFW_KEY_SLASH: return ImGuiKey_Slash;
case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl;
case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl;
case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
case GLFW_KEY_MENU: return ImGuiKey_Menu;
case GLFW_KEY_0: return ImGuiKey_0;
case GLFW_KEY_1: return ImGuiKey_1;
case GLFW_KEY_2: return ImGuiKey_2;
case GLFW_KEY_3: return ImGuiKey_3;
case GLFW_KEY_4: return ImGuiKey_4;
case GLFW_KEY_5: return ImGuiKey_5;
case GLFW_KEY_6: return ImGuiKey_6;
case GLFW_KEY_7: return ImGuiKey_7;
case GLFW_KEY_8: return ImGuiKey_8;
case GLFW_KEY_9: return ImGuiKey_9;
case GLFW_KEY_A: return ImGuiKey_A;
case GLFW_KEY_B: return ImGuiKey_B;
case GLFW_KEY_C: return ImGuiKey_C;
case GLFW_KEY_D: return ImGuiKey_D;
case GLFW_KEY_E: return ImGuiKey_E;
case GLFW_KEY_F: return ImGuiKey_F;
case GLFW_KEY_G: return ImGuiKey_G;
case GLFW_KEY_H: return ImGuiKey_H;
case GLFW_KEY_I: return ImGuiKey_I;
case GLFW_KEY_J: return ImGuiKey_J;
case GLFW_KEY_K: return ImGuiKey_K;
case GLFW_KEY_L: return ImGuiKey_L;
case GLFW_KEY_M: return ImGuiKey_M;
case GLFW_KEY_N: return ImGuiKey_N;
case GLFW_KEY_O: return ImGuiKey_O;
case GLFW_KEY_P: return ImGuiKey_P;
case GLFW_KEY_Q: return ImGuiKey_Q;
case GLFW_KEY_R: return ImGuiKey_R;
case GLFW_KEY_S: return ImGuiKey_S;
case GLFW_KEY_T: return ImGuiKey_T;
case GLFW_KEY_U: return ImGuiKey_U;
case GLFW_KEY_V: return ImGuiKey_V;
case GLFW_KEY_W: return ImGuiKey_W;
case GLFW_KEY_X: return ImGuiKey_X;
case GLFW_KEY_Y: return ImGuiKey_Y;
case GLFW_KEY_Z: return ImGuiKey_Z;
case GLFW_KEY_F1: return ImGuiKey_F1;
case GLFW_KEY_F2: return ImGuiKey_F2;
case GLFW_KEY_F3: return ImGuiKey_F3;
case GLFW_KEY_F4: return ImGuiKey_F4;
case GLFW_KEY_F5: return ImGuiKey_F5;
case GLFW_KEY_F6: return ImGuiKey_F6;
case GLFW_KEY_F7: return ImGuiKey_F7;
case GLFW_KEY_F8: return ImGuiKey_F8;
case GLFW_KEY_F9: return ImGuiKey_F9;
case GLFW_KEY_F10: return ImGuiKey_F10;
case GLFW_KEY_F11: return ImGuiKey_F11;
case GLFW_KEY_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
static int ImGui_ImplGlfw_KeyToModifier(int key)
{
if (key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_RIGHT_CONTROL)
return GLFW_MOD_CONTROL;
if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT)
return GLFW_MOD_SHIFT;
if (key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT)
return GLFW_MOD_ALT;
if (key == GLFW_KEY_LEFT_SUPER || key == GLFW_KEY_RIGHT_SUPER)
return GLFW_MOD_SUPER;
return 0;
}
static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods)
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(ImGuiMod_Ctrl, (mods & GLFW_MOD_CONTROL) != 0);
io.AddKeyEvent(ImGuiMod_Shift, (mods & GLFW_MOD_SHIFT) != 0);
io.AddKeyEvent(ImGuiMod_Alt, (mods & GLFW_MOD_ALT) != 0);
io.AddKeyEvent(ImGuiMod_Super, (mods & GLFW_MOD_SUPER) != 0);
}
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackMousebutton != nullptr && window == bd->Window)
bd->PrevUserCallbackMousebutton(window, button, action, mods);
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
ImGuiIO& io = ImGui::GetIO();
if (button >= 0 && button < ImGuiMouseButton_COUNT)
io.AddMouseButtonEvent(button, action == GLFW_PRESS);
}
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackScroll != nullptr && window == bd->Window)
bd->PrevUserCallbackScroll(window, xoffset, yoffset);
ImGuiIO& io = ImGui::GetIO();
io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
}
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
{
#if GLFW_HAS_GETKEYNAME && !defined(__EMSCRIPTEN__)
// GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
// (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
// See https://github.com/glfw/glfw/issues/1502 for details.
// Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
// This won't cover edge cases but this is at least going to cover common cases.
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
return key;
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
const char* key_name = glfwGetKeyName(key, scancode);
glfwSetErrorCallback(prev_error_callback);
#if (GLFW_VERSION_COMBINED >= 3300) // Eat errors (see #5908)
(void)glfwGetError(NULL);
#endif
if (key_name && key_name[0] != 0 && key_name[1] == 0)
{
const char char_names[] = "`-=[]\\,;\'./";
const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 };
IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys));
if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); }
else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); }
else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); }
else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; }
}
// if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
#else
IM_UNUSED(scancode);
#endif
return key;
}
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackKey != nullptr && window == bd->Window)
bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
if (action != GLFW_PRESS && action != GLFW_RELEASE)
return;
// Workaround: X11 does not include current pressed/released modifier key in 'mods' flags. https://github.com/glfw/glfw/issues/1630
if (int keycode_to_mod = ImGui_ImplGlfw_KeyToModifier(keycode))
mods = (action == GLFW_PRESS) ? (mods | keycode_to_mod) : (mods & ~keycode_to_mod);
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows))
bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr;
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
ImGuiIO& io = ImGui::GetIO();
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
}
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackWindowFocus != nullptr && window == bd->Window)
bd->PrevUserCallbackWindowFocus(window, focused);
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(focused != 0);
}
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorPos != nullptr && window == bd->Window)
bd->PrevUserCallbackCursorPos(window, x, y);
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
int window_x, window_y;
glfwGetWindowPos(window, &window_x, &window_y);
x += window_x;
y += window_y;
}
io.AddMousePosEvent((float)x, (float)y);
bd->LastValidMousePos = ImVec2((float)x, (float)y);
}
// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorEnter != nullptr && window == bd->Window)
bd->PrevUserCallbackCursorEnter(window, entered);
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiIO& io = ImGui::GetIO();
if (entered)
{
bd->MouseWindow = window;
io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y);
}
else if (!entered && bd->MouseWindow == window)
{
bd->LastValidMousePos = io.MousePos;
bd->MouseWindow = nullptr;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
}
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackChar != nullptr && window == bd->Window)
bd->PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO();
io.AddInputCharacter(c);
}
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
bd->WantUpdateMonitors = true;
}
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!");
IM_ASSERT(bd->Window == window);
bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
bd->InstalledCallbacks = true;
}
void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!");
IM_ASSERT(bd->Window == window);
glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus);
glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter);
glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos);
glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton);
glfwSetScrollCallback(window, bd->PrevUserCallbackScroll);
glfwSetKeyCallback(window, bd->PrevUserCallbackKey);
glfwSetCharCallback(window, bd->PrevUserCallbackChar);
glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
bd->InstalledCallbacks = false;
bd->PrevUserCallbackWindowFocus = nullptr;
bd->PrevUserCallbackCursorEnter = nullptr;
bd->PrevUserCallbackCursorPos = nullptr;
bd->PrevUserCallbackMousebutton = nullptr;
bd->PrevUserCallbackScroll = nullptr;
bd->PrevUserCallbackKey = nullptr;
bd->PrevUserCallbackChar = nullptr;
bd->PrevUserCallbackMonitor = nullptr;
}
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
//printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED);
// Setup backend capabilities flags
ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = "imgui_impl_glfw";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
#endif
bd->Window = window;
bd->Time = 0.0;
bd->WantUpdateMonitors = true;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = bd->Window;
// Create mouse cursors
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
// Missing cursors will return nullptr and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
#if GLFW_HAS_NEW_CURSORS
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
#else
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
#endif
glfwSetErrorCallback(prev_error_callback);
#if (GLFW_VERSION_COMBINED >= 3300) // Eat errors (see #5785)
(void)glfwGetError(NULL);
#endif
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
if (install_callbacks)
ImGui_ImplGlfw_InstallCallbacks(window);
// Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
ImGui_ImplGlfw_UpdateMonitors();
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandle = (void*)bd->Window;
#ifdef _WIN32
main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window);
#elif defined(__APPLE__)
main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window);
#endif
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplGlfw_InitPlatformInterface();
bd->ClientApi = client_api;
return true;
}
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
}
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
}
bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
}
void ImGui_ImplGlfw_Shutdown()
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_ShutdownPlatformInterface();
if (bd->InstalledCallbacks)
ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
glfwDestroyCursor(bd->MouseCursors[cursor_n]);
io.BackendPlatformName = nullptr;
io.BackendPlatformUserData = nullptr;
IM_DELETE(bd);
}
static void ImGui_ImplGlfw_UpdateMouseData()
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
if (glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
{
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
return;
}
ImGuiID mouse_viewport_id = 0;
const ImVec2 mouse_pos_prev = io.MousePos;
for (int n = 0; n < platform_io.Viewports.Size; n++)
{
ImGuiViewport* viewport = platform_io.Viewports[n];
GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle;
#ifdef __EMSCRIPTEN__
const bool is_window_focused = true;
#else
const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
#endif
if (is_window_focused)
{
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
if (io.WantSetMousePos)
glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y));
// (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
if (bd->MouseWindow == nullptr)
{
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
int window_x, window_y;
glfwGetWindowPos(window, &window_x, &window_y);
mouse_x += window_x;
mouse_y += window_y;
}
bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
}
}
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
// - [X] GLFW >= 3.3 backend ON WINDOWS ONLY does correctly ignore viewports with the _NoInputs flag.
// - [!] GLFW <= 3.2 backend CANNOT correctly ignore viewports with the _NoInputs flag, and CANNOT reported Hovered Viewport because of mouse capture.
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
// by the backend, and use its flawed heuristic to guess the viewport behind.
// - [X] GLFW backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
// FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
// See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0;
#if GLFW_HAS_MOUSE_PASSTHROUGH
glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input);
#endif
if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input)
mouse_viewport_id = viewport->ID;
#else
// We cannot use bd->MouseWindow maintained from CursorEnter/Leave callbacks, because it is locked to the window capturing mouse.
#endif
}
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
io.AddMouseViewportEvent(mouse_viewport_id);
}
static void ImGui_ImplGlfw_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
for (int n = 0; n < platform_io.Viewports.Size; n++)
{
GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle;
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
else
{
// Show OS mouse cursor
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
}
// Update gamepad inputs
static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
static void ImGui_ImplGlfw_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
return;
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
#if GLFW_HAS_GAMEPAD_API
GLFWgamepadstate gamepad;
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
return;
#define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
#define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
#else
int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
if (axes_count == 0 || buttons_count == 0)
return;
#define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
#define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
#endif
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
#undef MAP_BUTTON
#undef MAP_ANALOG
}
static void ImGui_ImplGlfw_UpdateMonitors()
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
int monitors_count = 0;
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
platform_io.Monitors.resize(0);
for (int n = 0; n < monitors_count; n++)
{
ImGuiPlatformMonitor monitor;
int x, y;
glfwGetMonitorPos(glfw_monitors[n], &x, &y);
const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]);
monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y);
monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height);
#if GLFW_HAS_MONITOR_WORK_AREA
int w, h;
glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h);
if (w > 0 && h > 0) // Workaround a small GLFW issue reporting zero on monitor changes: https://github.com/glfw/glfw/pull/1761
{
monitor.WorkPos = ImVec2((float)x, (float)y);
monitor.WorkSize = ImVec2((float)w, (float)h);
}
#endif
#if GLFW_HAS_PER_MONITOR_DPI
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
float x_scale, y_scale;
glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale);
monitor.DpiScale = x_scale;
#endif
platform_io.Monitors.push_back(monitor);
}
bd->WantUpdateMonitors = false;
}
void ImGui_ImplGlfw_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplGlfw_InitForXXX()?");
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
glfwGetWindowSize(bd->Window, &w, &h);
glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h);
if (bd->WantUpdateMonitors)
ImGui_ImplGlfw_UpdateMonitors();
// Setup time step
double current_time = glfwGetTime();
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
bd->Time = current_time;
ImGui_ImplGlfw_UpdateMouseData();
ImGui_ImplGlfw_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplGlfw_UpdateGamepads();
}
//--------------------------------------------------------------------------------------------------------
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
//--------------------------------------------------------------------------------------------------------
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
struct ImGui_ImplGlfw_ViewportData
{
GLFWwindow* Window;
bool WindowOwned;
int IgnoreWindowPosEventFrame;
int IgnoreWindowSizeEventFrame;
ImGui_ImplGlfw_ViewportData() { Window = nullptr; WindowOwned = false; IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; }
~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == nullptr); }
};
static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window)
{
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
viewport->PlatformRequestClose = true;
}
// GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize().
// However: depending on the platform the callback may be invoked at different time:
// - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call
// - on Linux it is queued and invoked during glfwPollEvents()
// Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only
// ignore recent glfwSetWindowXXX() calls.
static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int)
{
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
{
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
{
bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowPosEventFrame + 1);
//data->IgnoreWindowPosEventFrame = -1;
if (ignore_event)
return;
}
viewport->PlatformRequestMove = true;
}
}
static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int)
{
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
{
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
{
bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowSizeEventFrame + 1);
//data->IgnoreWindowSizeEventFrame = -1;
if (ignore_event)
return;
}
viewport->PlatformRequestResize = true;
}
}
static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
viewport->PlatformUserData = vd;
// GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
// With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
glfwWindowHint(GLFW_VISIBLE, false);
glfwWindowHint(GLFW_FOCUSED, false);
#if GLFW_HAS_FOCUS_ON_SHOW
glfwWindowHint(GLFW_FOCUS_ON_SHOW, false);
#endif
glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true);
#if GLFW_HAS_WINDOW_TOPMOST
glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false);
#endif
GLFWwindow* share_window = (bd->ClientApi == GlfwClientApi_OpenGL) ? bd->Window : nullptr;
vd->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", nullptr, share_window);
vd->WindowOwned = true;
viewport->PlatformHandle = (void*)vd->Window;
#ifdef _WIN32
viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window);
#elif defined(__APPLE__)
viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(vd->Window);
#endif
glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
// Install GLFW callbacks for secondary viewports
glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback);
glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback);
glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback);
glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback);
glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback);
glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback);
glfwSetCharCallback(vd->Window, ImGui_ImplGlfw_CharCallback);
glfwSetWindowCloseCallback(vd->Window, ImGui_ImplGlfw_WindowCloseCallback);
glfwSetWindowPosCallback(vd->Window, ImGui_ImplGlfw_WindowPosCallback);
glfwSetWindowSizeCallback(vd->Window, ImGui_ImplGlfw_WindowSizeCallback);
if (bd->ClientApi == GlfwClientApi_OpenGL)
{
glfwMakeContextCurrent(vd->Window);
glfwSwapInterval(0);
}
}
static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
{
if (vd->WindowOwned)
{
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
::RemovePropA(hwnd, "IMGUI_VIEWPORT");
#endif
// Release any keys that were pressed in the window being destroyed and are still held down,
// because we will not receive any release events after window is destroyed.
for (int i = 0; i < IM_ARRAYSIZE(bd->KeyOwnerWindows); i++)
if (bd->KeyOwnerWindows[i] == vd->Window)
ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called.
glfwDestroyWindow(vd->Window);
}
vd->Window = nullptr;
IM_DELETE(vd);
}
viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
}
// We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs".
// In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!)
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
static LRESULT CALLBACK WndProcNoInputs(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (msg == WM_NCHITTEST)
{
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL).
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT");
if (viewport->Flags & ImGuiViewportFlags_NoInputs)
return HTTRANSPARENT;
}
return ::CallWindowProc(bd->GlfwWndProc, hWnd, msg, wParam, lParam);
}
#endif
static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
#if defined(_WIN32)
// GLFW hack: Hide icon from task bar
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
{
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
ex_style &= ~WS_EX_APPWINDOW;
ex_style |= WS_EX_TOOLWINDOW;
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
}
// GLFW hack: install hook for WM_NCHITTEST message handler
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport);
if (bd->GlfwWndProc == nullptr)
bd->GlfwWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WndProcNoInputs);
#endif
#if !GLFW_HAS_FOCUS_ON_SHOW
// GLFW hack: GLFW 3.2 has a bug where glfwShowWindow() also activates/focus the window.
// The fix was pushed to GLFW repository on 2018/01/09 and should be included in GLFW 3.3 via a GLFW_FOCUS_ON_SHOW window attribute.
// See https://github.com/glfw/glfw/issues/1189
// FIXME-VIEWPORT: Implement same work-around for Linux/OSX in the meanwhile.
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
{
::ShowWindow(hwnd, SW_SHOWNA);
return;
}
#endif
#endif
glfwShowWindow(vd->Window);
}
static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
int x = 0, y = 0;
glfwGetWindowPos(vd->Window, &x, &y);
return ImVec2((float)x, (float)y);
}
static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
vd->IgnoreWindowPosEventFrame = ImGui::GetFrameCount();
glfwSetWindowPos(vd->Window, (int)pos.x, (int)pos.y);
}
static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
int w = 0, h = 0;
glfwGetWindowSize(vd->Window, &w, &h);
return ImVec2((float)w, (float)h);
}
static void ImGui_ImplGlfw_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
#if __APPLE__ && !GLFW_HAS_OSX_WINDOW_POS_FIX
// Native OS windows are positioned from the bottom-left corner on macOS, whereas on other platforms they are
// positioned from the upper-left corner. GLFW makes an effort to convert macOS style coordinates, however it
// doesn't handle it when changing size. We are manually moving the window in order for changes of size to be based
// on the upper-left corner.
int x, y, width, height;
glfwGetWindowPos(vd->Window, &x, &y);
glfwGetWindowSize(vd->Window, &width, &height);
glfwSetWindowPos(vd->Window, x, y - height + size.y);
#endif
vd->IgnoreWindowSizeEventFrame = ImGui::GetFrameCount();
glfwSetWindowSize(vd->Window, (int)size.x, (int)size.y);
}
static void ImGui_ImplGlfw_SetWindowTitle(ImGuiViewport* viewport, const char* title)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
glfwSetWindowTitle(vd->Window, title);
}
static void ImGui_ImplGlfw_SetWindowFocus(ImGuiViewport* viewport)
{
#if GLFW_HAS_FOCUS_WINDOW
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
glfwFocusWindow(vd->Window);
#else
// FIXME: What are the effect of not having this function? At the moment imgui doesn't actually call SetWindowFocus - we set that up ahead, will answer that question later.
(void)viewport;
#endif
}
static bool ImGui_ImplGlfw_GetWindowFocus(ImGuiViewport* viewport)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
return glfwGetWindowAttrib(vd->Window, GLFW_FOCUSED) != 0;
}
static bool ImGui_ImplGlfw_GetWindowMinimized(ImGuiViewport* viewport)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
return glfwGetWindowAttrib(vd->Window, GLFW_ICONIFIED) != 0;
}
#if GLFW_HAS_WINDOW_ALPHA
static void ImGui_ImplGlfw_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
{
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
glfwSetWindowOpacity(vd->Window, alpha);
}
#endif
static void ImGui_ImplGlfw_RenderWindow(ImGuiViewport* viewport, void*)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
if (bd->ClientApi == GlfwClientApi_OpenGL)
glfwMakeContextCurrent(vd->Window);
}
static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
if (bd->ClientApi == GlfwClientApi_OpenGL)
{
glfwMakeContextCurrent(vd->Window);
glfwSwapBuffers(vd->Window);
}
}
//--------------------------------------------------------------------------------------------------------
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
//--------------------------------------------------------------------------------------------------------
// Avoid including so we can build without it
#if GLFW_HAS_VULKAN
#ifndef VULKAN_H_
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
#else
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
#endif
VK_DEFINE_HANDLE(VkInstance)
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
struct VkAllocationCallbacks;
enum VkResult { VK_RESULT_MAX_ENUM = 0x7FFFFFFF };
#endif // VULKAN_H_
extern "C" { extern GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); }
static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
IM_UNUSED(bd);
IM_ASSERT(bd->ClientApi == GlfwClientApi_Vulkan);
VkResult err = glfwCreateWindowSurface((VkInstance)vk_instance, vd->Window, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
return (int)err;
}
#endif // GLFW_HAS_VULKAN
static void ImGui_ImplGlfw_InitPlatformInterface()
{
// Register platform interface (will be coupled with a renderer interface)
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Platform_CreateWindow = ImGui_ImplGlfw_CreateWindow;
platform_io.Platform_DestroyWindow = ImGui_ImplGlfw_DestroyWindow;
platform_io.Platform_ShowWindow = ImGui_ImplGlfw_ShowWindow;
platform_io.Platform_SetWindowPos = ImGui_ImplGlfw_SetWindowPos;
platform_io.Platform_GetWindowPos = ImGui_ImplGlfw_GetWindowPos;
platform_io.Platform_SetWindowSize = ImGui_ImplGlfw_SetWindowSize;
platform_io.Platform_GetWindowSize = ImGui_ImplGlfw_GetWindowSize;
platform_io.Platform_SetWindowFocus = ImGui_ImplGlfw_SetWindowFocus;
platform_io.Platform_GetWindowFocus = ImGui_ImplGlfw_GetWindowFocus;
platform_io.Platform_GetWindowMinimized = ImGui_ImplGlfw_GetWindowMinimized;
platform_io.Platform_SetWindowTitle = ImGui_ImplGlfw_SetWindowTitle;
platform_io.Platform_RenderWindow = ImGui_ImplGlfw_RenderWindow;
platform_io.Platform_SwapBuffers = ImGui_ImplGlfw_SwapBuffers;
#if GLFW_HAS_WINDOW_ALPHA
platform_io.Platform_SetWindowAlpha = ImGui_ImplGlfw_SetWindowAlpha;
#endif
#if GLFW_HAS_VULKAN
platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface;
#endif
// Register main window handle (which is owned by the main application, not by us)
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
vd->Window = bd->Window;
vd->WindowOwned = false;
main_viewport->PlatformUserData = vd;
main_viewport->PlatformHandle = (void*)bd->Window;
}
static void ImGui_ImplGlfw_ShutdownPlatformInterface()
{
ImGui::DestroyPlatformWindows();
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
================================================
FILE: Source/External/imgui_tools/imgui_impl_glfw.h
================================================
// dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Issues:
// [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct GLFWwindow;
struct GLFWmonitor;
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// GLFW callbacks (installer)
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
// GLFW callbacks (individual callbacks to call if you didn't install callbacks)
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
================================================
FILE: Source/External/imgui_tools/imguizmo/GraphEditor.cpp
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui.h"
#include "imgui_internal.h"
#include
#include
#include
#include
#include "GraphEditor.h"
namespace GraphEditor {
static inline float Distance(const ImVec2& a, const ImVec2& b)
{
return sqrtf((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
static inline float sign(float v)
{
return (v >= 0.f) ? 1.f : -1.f;
}
static ImVec2 GetInputSlotPos(Delegate& delegate, const Node& node, SlotIndex slotIndex, float factor)
{
ImVec2 Size = node.mRect.GetSize() * factor;
size_t InputsCount = delegate.GetTemplate(node.mTemplateIndex).mInputCount;
return ImVec2(node.mRect.Min.x * factor,
node.mRect.Min.y * factor + Size.y * ((float)slotIndex + 1) / ((float)InputsCount + 1) + 8.f);
}
static ImVec2 GetOutputSlotPos(Delegate& delegate, const Node& node, SlotIndex slotIndex, float factor)
{
ImVec2 Size = node.mRect.GetSize() * factor;
size_t OutputsCount = delegate.GetTemplate(node.mTemplateIndex).mOutputCount;
return ImVec2(node.mRect.Min.x * factor + Size.x,
node.mRect.Min.y * factor + Size.y * ((float)slotIndex + 1) / ((float)OutputsCount + 1) + 8.f);
}
static ImRect GetNodeRect(const Node& node, float factor)
{
ImVec2 Size = node.mRect.GetSize() * factor;
return ImRect(node.mRect.Min * factor, node.mRect.Min * factor + Size);
}
static ImVec2 editingNodeSource;
static bool editingInput = false;
static ImVec2 captureOffset;
enum NodeOperation
{
NO_None,
NO_EditingLink,
NO_QuadSelecting,
NO_MovingNodes,
NO_EditInput,
NO_PanView,
};
static NodeOperation nodeOperation = NO_None;
static void HandleZoomScroll(ImRect regionRect, ViewState& viewState, const Options& options)
{
ImGuiIO& io = ImGui::GetIO();
if (regionRect.Contains(io.MousePos))
{
if (io.MouseWheel < -FLT_EPSILON)
{
viewState.mFactorTarget *= 1.f - options.mZoomRatio;
}
if (io.MouseWheel > FLT_EPSILON)
{
viewState.mFactorTarget *= 1.0f + options.mZoomRatio;
}
}
ImVec2 mouseWPosPre = (io.MousePos - ImGui::GetCursorScreenPos()) / viewState.mFactor;
viewState.mFactorTarget = ImClamp(viewState.mFactorTarget, options.mMinZoom, options.mMaxZoom);
viewState.mFactor = ImLerp(viewState.mFactor, viewState.mFactorTarget, options.mZoomLerpFactor);
ImVec2 mouseWPosPost = (io.MousePos - ImGui::GetCursorScreenPos()) / viewState.mFactor;
if (ImGui::IsMousePosValid())
{
viewState.mPosition += mouseWPosPost - mouseWPosPre;
}
}
void GraphEditorClear()
{
nodeOperation = NO_None;
}
static void FitNodes(Delegate& delegate, ViewState& viewState, const ImVec2 viewSize, bool selectedNodesOnly)
{
const size_t nodeCount = delegate.GetNodeCount();
if (!nodeCount)
{
return;
}
bool validNode = false;
ImVec2 min(FLT_MAX, FLT_MAX);
ImVec2 max(-FLT_MAX, -FLT_MAX);
for (NodeIndex nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
{
const Node& node = delegate.GetNode(nodeIndex);
if (selectedNodesOnly && !node.mSelected)
{
continue;
}
min = ImMin(min, node.mRect.Min);
min = ImMin(min, node.mRect.Max);
max = ImMax(max, node.mRect.Min);
max = ImMax(max, node.mRect.Max);
validNode = true;
}
if (!validNode)
{
return;
}
min -= viewSize * 0.05f;
max += viewSize * 0.05f;
ImVec2 nodesSize = max - min;
ImVec2 nodeCenter = (max + min) * 0.5f;
float ratioY = viewSize.y / nodesSize.y;
float ratioX = viewSize.x / nodesSize.x;
viewState.mFactor = viewState.mFactorTarget = ImMin(ImMin(ratioY, ratioX), 1.f);
viewState.mPosition = ImVec2(-nodeCenter.x, -nodeCenter.y) + (viewSize * 0.5f) / viewState.mFactorTarget;
}
static void DisplayLinks(Delegate& delegate,
ImDrawList* drawList,
const ImVec2 offset,
const float factor,
const ImRect regionRect,
NodeIndex hoveredNode,
const Options& options)
{
const size_t linkCount = delegate.GetLinkCount();
for (LinkIndex linkIndex = 0; linkIndex < linkCount; linkIndex++)
{
const auto link = delegate.GetLink(linkIndex);
const auto nodeInput = delegate.GetNode(link.mInputNodeIndex);
const auto nodeOutput = delegate.GetNode(link.mOutputNodeIndex);
ImVec2 p1 = offset + GetOutputSlotPos(delegate, nodeInput, link.mInputSlotIndex, factor);
ImVec2 p2 = offset + GetInputSlotPos(delegate, nodeOutput, link.mOutputSlotIndex, factor);
// con. view clipping
if ((p1.y < 0.f && p2.y < 0.f) || (p1.y > regionRect.Max.y && p2.y > regionRect.Max.y) ||
(p1.x < 0.f && p2.x < 0.f) || (p1.x > regionRect.Max.x && p2.x > regionRect.Max.x))
continue;
bool highlightCons = hoveredNode == link.mInputNodeIndex || hoveredNode == link.mOutputNodeIndex;
uint32_t col = delegate.GetTemplate(nodeInput.mTemplateIndex).mHeaderColor | (highlightCons ? 0xF0F0F0 : 0);
if (options.mDisplayLinksAsCurves)
{
// curves
drawList->AddBezierCubic(p1, p1 + ImVec2(50, 0) * factor, p2 + ImVec2(-50, 0) * factor, p2, 0xFF000000, options.mLineThickness * 1.5f * factor);
drawList->AddBezierCubic(p1, p1 + ImVec2(50, 0) * factor, p2 + ImVec2(-50, 0) * factor, p2, col, options.mLineThickness * 1.5f * factor);
/*
ImVec2 p10 = p1 + ImVec2(20.f * factor, 0.f);
ImVec2 p20 = p2 - ImVec2(20.f * factor, 0.f);
ImVec2 dif = p20 - p10;
ImVec2 p1a, p1b;
if (fabsf(dif.x) > fabsf(dif.y))
{
p1a = p10 + ImVec2(fabsf(fabsf(dif.x) - fabsf(dif.y)) * 0.5 * sign(dif.x), 0.f);
p1b = p1a + ImVec2(fabsf(dif.y) * sign(dif.x) , dif.y);
}
else
{
p1a = p10 + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(dif.x)) * 0.5 * sign(dif.y));
p1b = p1a + ImVec2(dif.x, fabsf(dif.x) * sign(dif.y));
}
drawList->AddLine(p1, p10, col, 3.f * factor);
drawList->AddLine(p10, p1a, col, 3.f * factor);
drawList->AddLine(p1a, p1b, col, 3.f * factor);
drawList->AddLine(p1b, p20, col, 3.f * factor);
drawList->AddLine(p20, p2, col, 3.f * factor);
*/
}
else
{
// straight lines
std::array pts;
int ptCount = 0;
ImVec2 dif = p2 - p1;
ImVec2 p1a, p1b;
const float limitx = 12.f * factor;
if (dif.x < limitx)
{
ImVec2 p10 = p1 + ImVec2(limitx, 0.f);
ImVec2 p20 = p2 - ImVec2(limitx, 0.f);
dif = p20 - p10;
p1a = p10 + ImVec2(0.f, dif.y * 0.5f);
p1b = p1a + ImVec2(dif.x, 0.f);
pts = { p1, p10, p1a, p1b, p20, p2 };
ptCount = 6;
}
else
{
if (fabsf(dif.y) < 1.f)
{
pts = { p1, (p1 + p2) * 0.5f, p2 };
ptCount = 3;
}
else
{
if (fabsf(dif.y) < 10.f)
{
if (fabsf(dif.x) > fabsf(dif.y))
{
p1a = p1 + ImVec2(fabsf(fabsf(dif.x) - fabsf(dif.y)) * 0.5f * sign(dif.x), 0.f);
p1b = p1a + ImVec2(fabsf(dif.y) * sign(dif.x), dif.y);
}
else
{
p1a = p1 + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(dif.x)) * 0.5f * sign(dif.y));
p1b = p1a + ImVec2(dif.x, fabsf(dif.x) * sign(dif.y));
}
}
else
{
if (fabsf(dif.x) > fabsf(dif.y))
{
float d = fabsf(dif.y) * sign(dif.x) * 0.5f;
p1a = p1 + ImVec2(d, dif.y * 0.5f);
p1b = p1a + ImVec2(fabsf(fabsf(dif.x) - fabsf(d) * 2.f) * sign(dif.x), 0.f);
}
else
{
float d = fabsf(dif.x) * sign(dif.y) * 0.5f;
p1a = p1 + ImVec2(dif.x * 0.5f, d);
p1b = p1a + ImVec2(0.f, fabsf(fabsf(dif.y) - fabsf(d) * 2.f) * sign(dif.y));
}
}
pts = { p1, p1a, p1b, p2 };
ptCount = 4;
}
}
float highLightFactor = factor * (highlightCons ? 2.0f : 1.f);
for (int pass = 0; pass < 2; pass++)
{
drawList->AddPolyline(pts.data(), ptCount, pass ? col : 0xFF000000, false, (pass ? options.mLineThickness : (options.mLineThickness * 1.5f)) * highLightFactor);
}
}
}
}
static void HandleQuadSelection(Delegate& delegate, ImDrawList* drawList, const ImVec2 offset, const float factor, ImRect contentRect, const Options& options)
{
if (!options.mAllowQuadSelection)
{
return;
}
ImGuiIO& io = ImGui::GetIO();
static ImVec2 quadSelectPos;
//auto& nodes = delegate->GetNodes();
auto nodeCount = delegate.GetNodeCount();
if (nodeOperation == NO_QuadSelecting && ImGui::IsWindowFocused())
{
const ImVec2 bmin = ImMin(quadSelectPos, io.MousePos);
const ImVec2 bmax = ImMax(quadSelectPos, io.MousePos);
drawList->AddRectFilled(bmin, bmax, options.mQuadSelection, 1.f);
drawList->AddRect(bmin, bmax, options.mQuadSelectionBorder, 1.f);
if (!io.MouseDown[0])
{
if (!io.KeyCtrl && !io.KeyShift)
{
for (size_t nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
{
delegate.SelectNode(nodeIndex, false);
}
}
nodeOperation = NO_None;
ImRect selectionRect(bmin, bmax);
for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
{
const auto node = delegate.GetNode(nodeIndex);
ImVec2 nodeRectangleMin = offset + node.mRect.Min * factor;
ImVec2 nodeRectangleMax = nodeRectangleMin + node.mRect.GetSize() * factor;
if (selectionRect.Overlaps(ImRect(nodeRectangleMin, nodeRectangleMax)))
{
if (io.KeyCtrl)
{
delegate.SelectNode(nodeIndex, false);
}
else
{
delegate.SelectNode(nodeIndex, true);
}
}
else
{
if (!io.KeyShift)
{
delegate.SelectNode(nodeIndex, false);
}
}
}
}
}
else if (nodeOperation == NO_None && io.MouseDown[0] && ImGui::IsWindowFocused() &&
contentRect.Contains(io.MousePos))
{
nodeOperation = NO_QuadSelecting;
quadSelectPos = io.MousePos;
}
}
static bool HandleConnections(ImDrawList* drawList,
NodeIndex nodeIndex,
const ImVec2 offset,
const float factor,
Delegate& delegate,
const Options& options,
bool bDrawOnly,
SlotIndex& inputSlotOver,
SlotIndex& outputSlotOver,
const bool inMinimap)
{
static NodeIndex editingNodeIndex;
static SlotIndex editingSlotIndex;
ImGuiIO& io = ImGui::GetIO();
const auto node = delegate.GetNode(nodeIndex);
const auto nodeTemplate = delegate.GetTemplate(node.mTemplateIndex);
const auto linkCount = delegate.GetLinkCount();
size_t InputsCount = nodeTemplate.mInputCount;
size_t OutputsCount = nodeTemplate.mOutputCount;
inputSlotOver = -1;
outputSlotOver = -1;
// draw/use inputs/outputs
bool hoverSlot = false;
for (int i = 0; i < 2; i++)
{
float closestDistance = FLT_MAX;
SlotIndex closestConn = -1;
ImVec2 closestTextPos;
ImVec2 closestPos;
const size_t slotCount[2] = {InputsCount, OutputsCount};
for (SlotIndex slotIndex = 0; slotIndex < slotCount[i]; slotIndex++)
{
const char** con = i ? nodeTemplate.mOutputNames : nodeTemplate.mInputNames;
const char* conText = (con && con[slotIndex]) ? con[slotIndex] : "";
ImVec2 p =
offset + (i ? GetOutputSlotPos(delegate, node, slotIndex, factor) : GetInputSlotPos(delegate, node, slotIndex, factor));
float distance = Distance(p, io.MousePos);
bool overCon = (nodeOperation == NO_None || nodeOperation == NO_EditingLink) &&
(distance < options.mNodeSlotRadius * 2.f) && (distance < closestDistance);
ImVec2 textSize;
textSize = ImGui::CalcTextSize(conText);
ImVec2 textPos =
p + ImVec2(-options.mNodeSlotRadius * (i ? -1.f : 1.f) * (overCon ? 3.f : 2.f) - (i ? 0 : textSize.x),
-textSize.y / 2);
ImRect nodeRect = GetNodeRect(node, factor);
if (!inMinimap && (overCon || (nodeRect.Contains(io.MousePos - offset) && closestConn == -1 &&
(editingInput == (i != 0)) && nodeOperation == NO_EditingLink)))
{
closestDistance = distance;
closestConn = slotIndex;
closestTextPos = textPos;
closestPos = p;
if (i)
{
outputSlotOver = slotIndex;
}
else
{
inputSlotOver = slotIndex;
}
}
else
{
const ImU32* slotColorSource = i ? nodeTemplate.mOutputColors : nodeTemplate.mInputColors;
const ImU32 slotColor = slotColorSource ? slotColorSource[slotIndex] : options.mDefaultSlotColor;
drawList->AddCircleFilled(p, options.mNodeSlotRadius, IM_COL32(0, 0, 0, 200));
drawList->AddCircleFilled(p, options.mNodeSlotRadius * 0.75f, slotColor);
if (!options.mDrawIONameOnHover)
{
drawList->AddText(io.FontDefault, 14, textPos + ImVec2(2, 2), IM_COL32(0, 0, 0, 255), conText);
drawList->AddText(io.FontDefault, 14, textPos, IM_COL32(150, 150, 150, 255), conText);
}
}
}
if (closestConn != -1)
{
const char** con = i ? nodeTemplate.mOutputNames : nodeTemplate.mInputNames;
const char* conText = (con && con[closestConn]) ? con[closestConn] : "";
const ImU32* slotColorSource = i ? nodeTemplate.mOutputColors : nodeTemplate.mInputColors;
const ImU32 slotColor = slotColorSource ? slotColorSource[closestConn] : options.mDefaultSlotColor;
hoverSlot = true;
drawList->AddCircleFilled(closestPos, options.mNodeSlotRadius * options.mNodeSlotHoverFactor * 0.75f, IM_COL32(0, 0, 0, 200));
drawList->AddCircleFilled(closestPos, options.mNodeSlotRadius * options.mNodeSlotHoverFactor, slotColor);
drawList->AddText(io.FontDefault, 16, closestTextPos + ImVec2(1, 1), IM_COL32(0, 0, 0, 255), conText);
drawList->AddText(io.FontDefault, 16, closestTextPos, IM_COL32(250, 250, 250, 255), conText);
bool inputToOutput = (!editingInput && !i) || (editingInput && i);
if (nodeOperation == NO_EditingLink && !io.MouseDown[0] && !bDrawOnly)
{
if (inputToOutput)
{
// check loopback
Link nl;
if (editingInput)
nl = Link{nodeIndex, closestConn, editingNodeIndex, editingSlotIndex};
else
nl = Link{editingNodeIndex, editingSlotIndex, nodeIndex, closestConn};
if (!delegate.AllowedLink(nl.mOutputNodeIndex, nl.mInputNodeIndex))
{
break;
}
bool alreadyExisting = false;
for (size_t linkIndex = 0; linkIndex < linkCount; linkIndex++)
{
const auto link = delegate.GetLink(linkIndex);
if (!memcmp(&link, &nl, sizeof(Link)))
{
alreadyExisting = true;
break;
}
}
if (!alreadyExisting)
{
for (int linkIndex = 0; linkIndex < linkCount; linkIndex++)
{
const auto link = delegate.GetLink(linkIndex);
if (link.mOutputNodeIndex == nl.mOutputNodeIndex && link.mOutputSlotIndex == nl.mOutputSlotIndex)
{
delegate.DelLink(linkIndex);
break;
}
}
delegate.AddLink(nl.mInputNodeIndex, nl.mInputSlotIndex, nl.mOutputNodeIndex, nl.mOutputSlotIndex);
}
}
}
// when ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() is uncommented, one can't click the node
// input/output when mouse is over the node itself.
if (nodeOperation == NO_None &&
/*ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() &&*/ io.MouseClicked[0] && !bDrawOnly)
{
nodeOperation = NO_EditingLink;
editingInput = i == 0;
editingNodeSource = closestPos;
editingNodeIndex = nodeIndex;
editingSlotIndex = closestConn;
if (editingInput)
{
// remove existing link
for (int linkIndex = 0; linkIndex < linkCount; linkIndex++)
{
const auto link = delegate.GetLink(linkIndex);
if (link.mOutputNodeIndex == nodeIndex && link.mOutputSlotIndex == closestConn)
{
delegate.DelLink(linkIndex);
break;
}
}
}
}
}
}
return hoverSlot;
}
static void DrawGrid(ImDrawList* drawList, ImVec2 windowPos, const ViewState& viewState, const ImVec2 canvasSize, ImU32 gridColor, ImU32 gridColor2, float gridSize)
{
float gridSpace = gridSize * viewState.mFactor;
int divx = static_cast(-viewState.mPosition.x / gridSize);
int divy = static_cast(-viewState.mPosition.y / gridSize);
for (float x = fmodf(viewState.mPosition.x * viewState.mFactor, gridSpace); x < canvasSize.x; x += gridSpace, divx ++)
{
bool tenth = !(divx % 10);
drawList->AddLine(ImVec2(x, 0.0f) + windowPos, ImVec2(x, canvasSize.y) + windowPos, tenth ? gridColor2 : gridColor);
}
for (float y = fmodf(viewState.mPosition.y * viewState.mFactor, gridSpace); y < canvasSize.y; y += gridSpace, divy ++)
{
bool tenth = !(divy % 10);
drawList->AddLine(ImVec2(0.0f, y) + windowPos, ImVec2(canvasSize.x, y) + windowPos, tenth ? gridColor2 : gridColor);
}
}
// return true if node is hovered
static bool DrawNode(ImDrawList* drawList,
NodeIndex nodeIndex,
const ImVec2 offset,
const float factor,
Delegate& delegate,
bool overInput,
const Options& options,
const bool inMinimap,
const ImRect& viewPort)
{
ImGuiIO& io = ImGui::GetIO();
const auto node = delegate.GetNode(nodeIndex);
IM_ASSERT((node.mRect.GetWidth() != 0.f) && (node.mRect.GetHeight() != 0.f) && "Nodes must have a non-zero rect.");
const auto nodeTemplate = delegate.GetTemplate(node.mTemplateIndex);
const ImVec2 nodeRectangleMin = offset + node.mRect.Min * factor;
const bool old_any_active = ImGui::IsAnyItemActive();
ImGui::SetCursorScreenPos(nodeRectangleMin);
const ImVec2 nodeSize = node.mRect.GetSize() * factor;
// test nested IO
drawList->ChannelsSetCurrent(1); // Background
const size_t InputsCount = nodeTemplate.mInputCount;
const size_t OutputsCount = nodeTemplate.mOutputCount;
/*
for (int i = 0; i < 2; i++)
{
const size_t slotCount[2] = {InputsCount, OutputsCount};
for (size_t slotIndex = 0; slotIndex < slotCount[i]; slotIndex++)
{
const char* con = i ? nodeTemplate.mOutputNames[slotIndex] : nodeTemplate.mInputNames[slotIndex];//node.mOutputs[slot_idx] : node->mInputs[slot_idx];
if (!delegate->IsIOPinned(nodeIndex, slot_idx, i == 1))
{
}
continue;
ImVec2 p = offset + (i ? GetOutputSlotPos(delegate, node, slotIndex, factor) : GetInputSlotPos(delegate, node, slotIndex, factor));
const float arc = 28.f * (float(i) * 0.3f + 1.0f) * (i ? 1.f : -1.f);
const float ofs = 0.f;
ImVec2 pts[3] = {p + ImVec2(arc + ofs, 0.f), p + ImVec2(0.f + ofs, -arc), p + ImVec2(0.f + ofs, arc)};
drawList->AddTriangleFilled(pts[0], pts[1], pts[2], i ? 0xFFAA5030 : 0xFF30AA50);
drawList->AddTriangle(pts[0], pts[1], pts[2], 0xFF000000, 2.f);
}
}
*/
ImGui::SetCursorScreenPos(nodeRectangleMin);
float maxHeight = ImMin(viewPort.Max.y, nodeRectangleMin.y + nodeSize.y) - nodeRectangleMin.y;
float maxWidth = ImMin(viewPort.Max.x, nodeRectangleMin.x + nodeSize.x) - nodeRectangleMin.x;
ImGui::InvisibleButton("node", ImVec2(maxWidth, maxHeight));
// must be called right after creating the control we want to be able to move
bool nodeMovingActive = ImGui::IsItemActive();
// Save the size of what we have emitted and whether any of the widgets are being used
bool nodeWidgetsActive = (!old_any_active && ImGui::IsAnyItemActive());
ImVec2 nodeRectangleMax = nodeRectangleMin + nodeSize;
bool nodeHovered = false;
if (ImGui::IsItemHovered() && nodeOperation == NO_None && !overInput)
{
nodeHovered = true;
}
if (ImGui::IsWindowFocused())
{
if ((nodeWidgetsActive || nodeMovingActive) && !inMinimap)
{
if (!node.mSelected)
{
if (!io.KeyShift)
{
const auto nodeCount = delegate.GetNodeCount();
for (size_t i = 0; i < nodeCount; i++)
{
delegate.SelectNode(i, false);
}
}
delegate.SelectNode(nodeIndex, true);
}
}
}
if (nodeMovingActive && io.MouseDown[0] && nodeHovered && !inMinimap)
{
if (nodeOperation != NO_MovingNodes)
{
nodeOperation = NO_MovingNodes;
}
}
const bool currentSelectedNode = node.mSelected;
const ImU32 node_bg_color = nodeHovered ? nodeTemplate.mBackgroundColorOver : nodeTemplate.mBackgroundColor;
drawList->AddRect(nodeRectangleMin,
nodeRectangleMax,
currentSelectedNode ? options.mSelectedNodeBorderColor : options.mNodeBorderColor,
options.mRounding,
ImDrawFlags_RoundCornersAll,
currentSelectedNode ? options.mBorderSelectionThickness : options.mBorderThickness);
ImVec2 imgPos = nodeRectangleMin + ImVec2(14, 25);
ImVec2 imgSize = nodeRectangleMax + ImVec2(-5, -5) - imgPos;
float imgSizeComp = std::min(imgSize.x, imgSize.y);
drawList->AddRectFilled(nodeRectangleMin, nodeRectangleMax, node_bg_color, options.mRounding);
/*float progress = delegate->NodeProgress(nodeIndex);
if (progress > FLT_EPSILON && progress < 1.f - FLT_EPSILON)
{
ImVec2 progressLineA = nodeRectangleMax - ImVec2(nodeSize.x - 2.f, 3.f);
ImVec2 progressLineB = progressLineA + ImVec2(nodeSize.x * factor - 4.f, 0.f);
drawList->AddLine(progressLineA, progressLineB, 0xFF400000, 3.f);
drawList->AddLine(progressLineA, ImLerp(progressLineA, progressLineB, progress), 0xFFFF0000, 3.f);
}*/
ImVec2 imgPosMax = imgPos + ImVec2(imgSizeComp, imgSizeComp);
//ImVec2 imageSize = delegate->GetEvaluationSize(nodeIndex);
/*float imageRatio = 1.f;
if (imageSize.x > 0.f && imageSize.y > 0.f)
{
imageRatio = imageSize.y / imageSize.x;
}
ImVec2 quadSize = imgPosMax - imgPos;
ImVec2 marge(0.f, 0.f);
if (imageRatio > 1.f)
{
marge.x = (quadSize.x - quadSize.y / imageRatio) * 0.5f;
}
else
{
marge.y = (quadSize.y - quadSize.y * imageRatio) * 0.5f;
}*/
//delegate->DrawNodeImage(drawList, ImRect(imgPos, imgPosMax), marge, nodeIndex);
drawList->AddRectFilled(nodeRectangleMin,
ImVec2(nodeRectangleMax.x, nodeRectangleMin.y + 20),
nodeTemplate.mHeaderColor, options.mRounding);
drawList->PushClipRect(nodeRectangleMin, ImVec2(nodeRectangleMax.x, nodeRectangleMin.y + 20), true);
drawList->AddText(nodeRectangleMin + ImVec2(2, 2), IM_COL32(0, 0, 0, 255), node.mName);
drawList->PopClipRect();
ImRect customDrawRect(nodeRectangleMin + ImVec2(options.mRounding, 20 + options.mRounding), nodeRectangleMax - ImVec2(options.mRounding, options.mRounding));
if (customDrawRect.Max.y > customDrawRect.Min.y && customDrawRect.Max.x > customDrawRect.Min.x)
{
delegate.CustomDraw(drawList, customDrawRect, nodeIndex);
}
/*
const ImTextureID bmpInfo = (ImTextureID)(uint64_t)delegate->GetBitmapInfo(nodeIndex).idx;
if (bmpInfo)
{
ImVec2 bmpInfoPos(nodeRectangleMax - ImVec2(26, 12));
ImVec2 bmpInfoSize(20, 20);
if (delegate->NodeIsCompute(nodeIndex))
{
drawList->AddImageQuad(bmpInfo,
bmpInfoPos,
bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f),
bmpInfoPos + bmpInfoSize,
bmpInfoPos + ImVec2(0., bmpInfoSize.y));
}
else if (delegate->NodeIs2D(nodeIndex))
{
drawList->AddImageQuad(bmpInfo,
bmpInfoPos,
bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f),
bmpInfoPos + bmpInfoSize,
bmpInfoPos + ImVec2(0., bmpInfoSize.y));
}
else if (delegate->NodeIsCubemap(nodeIndex))
{
drawList->AddImageQuad(bmpInfo,
bmpInfoPos + ImVec2(0., bmpInfoSize.y),
bmpInfoPos + bmpInfoSize,
bmpInfoPos + ImVec2(bmpInfoSize.x, 0.f),
bmpInfoPos);
}
}*/
return nodeHovered;
}
bool DrawMiniMap(ImDrawList* drawList, Delegate& delegate, ViewState& viewState, const Options& options, const ImVec2 windowPos, const ImVec2 canvasSize)
{
if (Distance(options.mMinimap.Min, options.mMinimap.Max) <= FLT_EPSILON)
{
return false;
}
const size_t nodeCount = delegate.GetNodeCount();
if (!nodeCount)
{
return false;
}
ImVec2 min(FLT_MAX, FLT_MAX);
ImVec2 max(-FLT_MAX, -FLT_MAX);
const ImVec2 margin(50, 50);
for (NodeIndex nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
{
const Node& node = delegate.GetNode(nodeIndex);
min = ImMin(min, node.mRect.Min - margin);
min = ImMin(min, node.mRect.Max + margin);
max = ImMax(max, node.mRect.Min - margin);
max = ImMax(max, node.mRect.Max + margin);
}
// add view in world space
const ImVec2 worldSizeView = canvasSize / viewState.mFactor;
const ImVec2 viewMin(-viewState.mPosition.x, -viewState.mPosition.y);
const ImVec2 viewMax = viewMin + worldSizeView;
min = ImMin(min, viewMin);
max = ImMax(max, viewMax);
const ImVec2 nodesSize = max - min;
const ImVec2 middleWorld = (min + max) * 0.5f;
const ImVec2 minScreen = windowPos + options.mMinimap.Min * canvasSize;
const ImVec2 maxScreen = windowPos + options.mMinimap.Max * canvasSize;
const ImVec2 viewSize = maxScreen - minScreen;
const ImVec2 middleScreen = (minScreen + maxScreen) * 0.5f;
const float ratioY = viewSize.y / nodesSize.y;
const float ratioX = viewSize.x / nodesSize.x;
const float factor = ImMin(ImMin(ratioY, ratioX), 1.f);
drawList->AddRectFilled(minScreen, maxScreen, IM_COL32(30, 30, 30, 200), 3, ImDrawFlags_RoundCornersAll);
for (NodeIndex nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
{
const Node& node = delegate.GetNode(nodeIndex);
const auto nodeTemplate = delegate.GetTemplate(node.mTemplateIndex);
ImRect rect = node.mRect;
rect.Min -= middleWorld;
rect.Min *= factor;
rect.Min += middleScreen;
rect.Max -= middleWorld;
rect.Max *= factor;
rect.Max += middleScreen;
drawList->AddRectFilled(rect.Min, rect.Max, nodeTemplate.mBackgroundColor, 1, ImDrawFlags_RoundCornersAll);
if (node.mSelected)
{
drawList->AddRect(rect.Min, rect.Max, options.mSelectedNodeBorderColor, 1, ImDrawFlags_RoundCornersAll);
}
}
// add view
ImVec2 viewMinScreen = (viewMin - middleWorld) * factor + middleScreen;
ImVec2 viewMaxScreen = (viewMax - middleWorld) * factor + middleScreen;
drawList->AddRectFilled(viewMinScreen, viewMaxScreen, IM_COL32(255, 255, 255, 32), 1, ImDrawFlags_RoundCornersAll);
drawList->AddRect(viewMinScreen, viewMaxScreen, IM_COL32(255, 255, 255, 128), 1, ImDrawFlags_RoundCornersAll);
ImGuiIO& io = ImGui::GetIO();
const bool mouseInMinimap = ImRect(minScreen, maxScreen).Contains(io.MousePos);
if (mouseInMinimap && io.MouseClicked[0])
{
const ImVec2 clickedRatio = (io.MousePos - minScreen) / viewSize;
const ImVec2 worldPosCenter = ImVec2(ImLerp(min.x, max.x, clickedRatio.x), ImLerp(min.y, max.y, clickedRatio.y));
ImVec2 worldPosViewMin = worldPosCenter - worldSizeView * 0.5;
ImVec2 worldPosViewMax = worldPosCenter + worldSizeView * 0.5;
if (worldPosViewMin.x < min.x)
{
worldPosViewMin.x = min.x;
worldPosViewMax.x = worldPosViewMin.x + worldSizeView.x;
}
if (worldPosViewMin.y < min.y)
{
worldPosViewMin.y = min.y;
worldPosViewMax.y = worldPosViewMin.y + worldSizeView.y;
}
if (worldPosViewMax.x > max.x)
{
worldPosViewMax.x = max.x;
worldPosViewMin.x = worldPosViewMax.x - worldSizeView.x;
}
if (worldPosViewMax.y > max.y)
{
worldPosViewMax.y = max.y;
worldPosViewMin.y = worldPosViewMax.y - worldSizeView.y;
}
viewState.mPosition = ImVec2(-worldPosViewMin.x, -worldPosViewMin.y);
}
return mouseInMinimap;
}
void Show(Delegate& delegate, const Options& options, ViewState& viewState, bool enabled, FitOnScreen* fit)
{
ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.f);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 0.f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.f);
const ImVec2 windowPos = ImGui::GetCursorScreenPos();
const ImVec2 canvasSize = ImGui::GetContentRegionAvail();
const ImVec2 scrollRegionLocalPos(0, 0);
ImRect regionRect(windowPos, windowPos + canvasSize);
HandleZoomScroll(regionRect, viewState, options);
ImVec2 offset = ImGui::GetCursorScreenPos() + viewState.mPosition * viewState.mFactor;
captureOffset = viewState.mPosition * viewState.mFactor;
//ImGui::InvisibleButton("GraphEditorButton", canvasSize);
ImGui::BeginChildFrame(71711, canvasSize);
ImGui::SetCursorPos(windowPos);
ImGui::BeginGroup();
ImGuiIO& io = ImGui::GetIO();
// Create our child canvas
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1, 1));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(30, 30, 30, 200));
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImGui::PushClipRect(regionRect.Min, regionRect.Max, true);
drawList->AddRectFilled(windowPos, windowPos + canvasSize, options.mBackgroundColor);
// Background or Display grid
if (options.mRenderGrid)
{
DrawGrid(drawList, windowPos, viewState, canvasSize, options.mGridColor, options.mGridColor2, options.mGridSize);
}
// Fit view
if (fit && ((*fit == Fit_AllNodes) || (*fit == Fit_SelectedNodes)))
{
FitNodes(delegate, viewState, canvasSize, (*fit == Fit_SelectedNodes));
}
if (enabled)
{
static NodeIndex hoveredNode = -1;
// Display links
drawList->ChannelsSplit(3);
// minimap
drawList->ChannelsSetCurrent(2); // minimap
const bool inMinimap = DrawMiniMap(drawList, delegate, viewState, options, windowPos, canvasSize);
// Focus rectangle
if (ImGui::IsWindowFocused())
{
drawList->AddRect(regionRect.Min, regionRect.Max, options.mFrameFocus, 1.f, 0, 2.f);
}
drawList->ChannelsSetCurrent(1); // Background
// Links
DisplayLinks(delegate, drawList, offset, viewState.mFactor, regionRect, hoveredNode, options);
// edit node link
if (nodeOperation == NO_EditingLink)
{
ImVec2 p1 = editingNodeSource;
ImVec2 p2 = io.MousePos;
drawList->AddLine(p1, p2, IM_COL32(200, 200, 200, 255), 3.0f);
}
// Display nodes
drawList->PushClipRect(regionRect.Min, regionRect.Max, true);
hoveredNode = -1;
SlotIndex inputSlotOver = -1;
SlotIndex outputSlotOver = -1;
NodeIndex nodeOver = -1;
const auto nodeCount = delegate.GetNodeCount();
for (int i = 0; i < 2; i++)
{
for (NodeIndex nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
{
//const auto* node = &nodes[nodeIndex];
const auto node = delegate.GetNode(nodeIndex);
if (node.mSelected != (i != 0))
{
continue;
}
// node view clipping
ImRect nodeRect = GetNodeRect(node, viewState.mFactor);
nodeRect.Min += offset;
nodeRect.Max += offset;
if (!regionRect.Overlaps(nodeRect))
{
continue;
}
ImGui::PushID((int)nodeIndex);
SlotIndex inputSlot = -1;
SlotIndex outputSlot = -1;
bool overInput = (!inMinimap) && HandleConnections(drawList, nodeIndex, offset, viewState.mFactor, delegate, options, false, inputSlot, outputSlot, inMinimap);
// shadow
/*
ImVec2 shadowOffset = ImVec2(30, 30);
ImVec2 shadowPivot = (nodeRect.Min + nodeRect.Max) /2.f;
ImVec2 shadowPointMiddle = shadowPivot + shadowOffset;
ImVec2 shadowPointTop = ImVec2(shadowPivot.x, nodeRect.Min.y) + shadowOffset;
ImVec2 shadowPointBottom = ImVec2(shadowPivot.x, nodeRect.Max.y) + shadowOffset;
ImVec2 shadowPointLeft = ImVec2(nodeRect.Min.x, shadowPivot.y) + shadowOffset;
ImVec2 shadowPointRight = ImVec2(nodeRect.Max.x, shadowPivot.y) + shadowOffset;
// top left
drawList->AddRectFilledMultiColor(nodeRect.Min + shadowOffset, shadowPointMiddle, IM_COL32(0 ,0, 0, 0), IM_COL32(0,0,0,0), IM_COL32(0, 0, 0, 255), IM_COL32(0, 0, 0, 0));
// top right
drawList->AddRectFilledMultiColor(shadowPointTop, shadowPointRight, IM_COL32(0 ,0, 0, 0), IM_COL32(0,0,0,0), IM_COL32(0, 0, 0, 0), IM_COL32(0, 0, 0, 255));
// bottom left
drawList->AddRectFilledMultiColor(shadowPointLeft, shadowPointBottom, IM_COL32(0 ,0, 0, 0), IM_COL32(0, 0, 0, 255), IM_COL32(0, 0, 0, 0), IM_COL32(0,0,0,0));
// bottom right
drawList->AddRectFilledMultiColor(shadowPointMiddle, nodeRect.Max + shadowOffset, IM_COL32(0, 0, 0, 255), IM_COL32(0 ,0, 0, 0), IM_COL32(0,0,0,0), IM_COL32(0, 0, 0, 0));
*/
if (DrawNode(drawList, nodeIndex, offset, viewState.mFactor, delegate, overInput, options, inMinimap, regionRect))
{
hoveredNode = nodeIndex;
}
HandleConnections(drawList, nodeIndex, offset, viewState.mFactor, delegate, options, true, inputSlot, outputSlot, inMinimap);
if (inputSlot != -1 || outputSlot != -1)
{
inputSlotOver = inputSlot;
outputSlotOver = outputSlot;
nodeOver = nodeIndex;
}
ImGui::PopID();
}
}
drawList->PopClipRect();
if (nodeOperation == NO_MovingNodes)
{
if (ImGui::IsMouseDragging(0, 1))
{
ImVec2 delta = io.MouseDelta / viewState.mFactor;
if (fabsf(delta.x) >= 1.f || fabsf(delta.y) >= 1.f)
{
delegate.MoveSelectedNodes(delta);
}
}
}
drawList->ChannelsSetCurrent(0);
// quad selection
if (!inMinimap)
{
HandleQuadSelection(delegate, drawList, offset, viewState.mFactor, regionRect, options);
}
drawList->ChannelsMerge();
// releasing mouse button means it's done in any operation
if (nodeOperation == NO_PanView)
{
if (!io.MouseDown[2])
{
nodeOperation = NO_None;
}
}
else if (nodeOperation != NO_None && !io.MouseDown[0])
{
nodeOperation = NO_None;
}
// right click
if (!inMinimap && nodeOperation == NO_None && regionRect.Contains(io.MousePos) &&
(ImGui::IsMouseClicked(1) /*|| (ImGui::IsWindowFocused() && ImGui::IsKeyPressedMap(ImGuiKey_Tab))*/))
{
delegate.RightClick(nodeOver, inputSlotOver, outputSlotOver);
}
// Scrolling
if (ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() && io.MouseClicked[2] && nodeOperation == NO_None)
{
nodeOperation = NO_PanView;
}
if (nodeOperation == NO_PanView)
{
viewState.mPosition += io.MouseDelta / viewState.mFactor;
}
}
ImGui::PopClipRect();
ImGui::PopStyleColor(1);
ImGui::PopStyleVar(2);
ImGui::EndGroup();
ImGui::EndChildFrame();
ImGui::PopStyleVar(3);
// change fit to none
if (fit)
{
*fit = Fit_None;
}
}
bool EditOptions(Options& options)
{
bool updated = false;
if (ImGui::CollapsingHeader("Colors", nullptr))
{
ImColor backgroundColor(options.mBackgroundColor);
ImColor gridColor(options.mGridColor);
ImColor selectedNodeBorderColor(options.mSelectedNodeBorderColor);
ImColor nodeBorderColor(options.mNodeBorderColor);
ImColor quadSelection(options.mQuadSelection);
ImColor quadSelectionBorder(options.mQuadSelectionBorder);
ImColor defaultSlotColor(options.mDefaultSlotColor);
ImColor frameFocus(options.mFrameFocus);
updated |= ImGui::ColorEdit4("Background", (float*)&backgroundColor);
updated |= ImGui::ColorEdit4("Grid", (float*)&gridColor);
updated |= ImGui::ColorEdit4("Selected Node Border", (float*)&selectedNodeBorderColor);
updated |= ImGui::ColorEdit4("Node Border", (float*)&nodeBorderColor);
updated |= ImGui::ColorEdit4("Quad Selection", (float*)&quadSelection);
updated |= ImGui::ColorEdit4("Quad Selection Border", (float*)&quadSelectionBorder);
updated |= ImGui::ColorEdit4("Default Slot", (float*)&defaultSlotColor);
updated |= ImGui::ColorEdit4("Frame when has focus", (float*)&frameFocus);
options.mBackgroundColor = backgroundColor;
options.mGridColor = gridColor;
options.mSelectedNodeBorderColor = selectedNodeBorderColor;
options.mNodeBorderColor = nodeBorderColor;
options.mQuadSelection = quadSelection;
options.mQuadSelectionBorder = quadSelectionBorder;
options.mDefaultSlotColor = defaultSlotColor;
options.mFrameFocus = frameFocus;
}
if (ImGui::CollapsingHeader("Options", nullptr))
{
updated |= ImGui::InputFloat4("Minimap", &options.mMinimap.Min.x);
updated |= ImGui::InputFloat("Line Thickness", &options.mLineThickness);
updated |= ImGui::InputFloat("Grid Size", &options.mGridSize);
updated |= ImGui::InputFloat("Rounding", &options.mRounding);
updated |= ImGui::InputFloat("Zoom Ratio", &options.mZoomRatio);
updated |= ImGui::InputFloat("Zoom Lerp Factor", &options.mZoomLerpFactor);
updated |= ImGui::InputFloat("Border Selection Thickness", &options.mBorderSelectionThickness);
updated |= ImGui::InputFloat("Border Thickness", &options.mBorderThickness);
updated |= ImGui::InputFloat("Slot Radius", &options.mNodeSlotRadius);
updated |= ImGui::InputFloat("Slot Hover Factor", &options.mNodeSlotHoverFactor);
updated |= ImGui::InputFloat2("Zoom min/max", &options.mMinZoom);
updated |= ImGui::InputFloat("Slot Hover Factor", &options.mSnap);
if (ImGui::RadioButton("Curved Links", options.mDisplayLinksAsCurves))
{
options.mDisplayLinksAsCurves = !options.mDisplayLinksAsCurves;
updated = true;
}
if (ImGui::RadioButton("Straight Links", !options.mDisplayLinksAsCurves))
{
options.mDisplayLinksAsCurves = !options.mDisplayLinksAsCurves;
updated = true;
}
updated |= ImGui::Checkbox("Allow Quad Selection", &options.mAllowQuadSelection);
updated |= ImGui::Checkbox("Render Grid", &options.mRenderGrid);
updated |= ImGui::Checkbox("Draw IO names on hover", &options.mDrawIONameOnHover);
}
return updated;
}
} // namespace
================================================
FILE: Source/External/imgui_tools/imguizmo/GraphEditor.h
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#pragma once
#include
#include
#include
#include "imgui.h"
#include "imgui_internal.h"
namespace GraphEditor {
typedef size_t NodeIndex;
typedef size_t SlotIndex;
typedef size_t LinkIndex;
typedef size_t TemplateIndex;
// Force the view to be respositionned and zoom to fit nodes with Show function.
// Parameter value will be changed to Fit_None by the function.
enum FitOnScreen
{
Fit_None,
Fit_AllNodes,
Fit_SelectedNodes
};
// Display options and colors
struct Options
{
ImRect mMinimap{{0.75f, 0.8f, 0.99f, 0.99f}}; // rectangle coordinates of minimap
ImU32 mBackgroundColor{ IM_COL32(40, 40, 40, 255) }; // full background color
ImU32 mGridColor{ IM_COL32(0, 0, 0, 60) }; // grid lines color
ImU32 mGridColor2{ IM_COL32(0, 0, 0, 160) }; // grid lines color every 10th
ImU32 mSelectedNodeBorderColor{ IM_COL32(255, 130, 30, 255) }; // node border color when it's selected
ImU32 mNodeBorderColor{ IM_COL32(100, 100, 100, 0) }; // node border color when it's not selected
ImU32 mQuadSelection{ IM_COL32(255, 32, 32, 64) }; // quad selection inside color
ImU32 mQuadSelectionBorder{ IM_COL32(255, 32, 32, 255) }; // quad selection border color
ImU32 mDefaultSlotColor{ IM_COL32(128, 128, 128, 255) }; // when no color is provided in node template, use this value
ImU32 mFrameFocus{ IM_COL32(64, 128, 255, 255) }; // rectangle border when graph editor has focus
float mLineThickness{ 5 }; // links width in pixels when zoom value is 1
float mGridSize{ 64.f }; // background grid size in pixels when zoom value is 1
float mRounding{ 3.f }; // rounding at node corners
float mZoomRatio{ 0.1f }; // factor per mouse wheel delta
float mZoomLerpFactor{ 0.25f }; // the smaller, the smoother
float mBorderSelectionThickness{ 6.f }; // thickness of selection border around nodes
float mBorderThickness{ 6.f }; // thickness of selection border around nodes
float mNodeSlotRadius{ 8.f }; // circle radius for inputs and outputs
float mNodeSlotHoverFactor{ 1.2f }; // increase size when hovering
float mMinZoom{ 0.2f }, mMaxZoom { 1.1f };
float mSnap{ 5.f };
bool mDisplayLinksAsCurves{ true }; // false is straight and 45deg lines
bool mAllowQuadSelection{ true }; // multiple selection using drag and drop
bool mRenderGrid{ true }; // grid or nothing
bool mDrawIONameOnHover{ true }; // only draw node input/output when hovering
};
// View state: scroll position and zoom factor
struct ViewState
{
ImVec2 mPosition{0.0f, 0.0f}; // scroll position
float mFactor{ 1.0f }; // current zoom factor
float mFactorTarget{ 1.0f }; // targeted zoom factor interpolated using Options.mZoomLerpFactor
};
struct Template
{
ImU32 mHeaderColor;
ImU32 mBackgroundColor;
ImU32 mBackgroundColorOver;
ImU8 mInputCount;
const char** mInputNames; // can be nullptr. No text displayed.
ImU32* mInputColors; // can be nullptr, default slot color will be used.
ImU8 mOutputCount;
const char** mOutputNames; // can be nullptr. No text displayed.
ImU32* mOutputColors; // can be nullptr, default slot color will be used.
};
struct Node
{
const char* mName;
TemplateIndex mTemplateIndex;
ImRect mRect;
bool mSelected{ false };
};
struct Link
{
NodeIndex mInputNodeIndex;
SlotIndex mInputSlotIndex;
NodeIndex mOutputNodeIndex;
SlotIndex mOutputSlotIndex;
};
struct Delegate
{
virtual bool AllowedLink(NodeIndex from, NodeIndex to) = 0;
virtual void SelectNode(NodeIndex nodeIndex, bool selected) = 0;
virtual void MoveSelectedNodes(const ImVec2 delta) = 0;
virtual void AddLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex) = 0;
virtual void DelLink(LinkIndex linkIndex) = 0;
// user is responsible for clipping
virtual void CustomDraw(ImDrawList* drawList, ImRect rectangle, NodeIndex nodeIndex) = 0;
// use mouse position to open context menu
// if nodeIndex != -1, right click happens on the specified node
virtual void RightClick(NodeIndex nodeIndex, SlotIndex slotIndexInput, SlotIndex slotIndexOutput) = 0;
virtual const size_t GetTemplateCount() = 0;
virtual const Template GetTemplate(TemplateIndex index) = 0;
virtual const size_t GetNodeCount() = 0;
virtual const Node GetNode(NodeIndex index) = 0;
virtual const size_t GetLinkCount() = 0;
virtual const Link GetLink(LinkIndex index) = 0;
};
void Show(Delegate& delegate, const Options& options, ViewState& viewState, bool enabled, FitOnScreen* fit = nullptr);
void GraphEditorClear();
bool EditOptions(Options& options);
} // namespace
================================================
FILE: Source/External/imgui_tools/imguizmo/ImCurveEdit.cpp
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "ImCurveEdit.h"
#include "imgui.h"
#include "imgui_internal.h"
#include
#include
#include
#if defined(_MSC_VER) || defined(__MINGW32__)
#include
#endif
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
#define _malloca(x) alloca(x)
#define _freea(x)
#endif
namespace ImCurveEdit
{
#ifndef IMGUI_DEFINE_MATH_OPERATORS
static ImVec2 operator+(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x + b.x, a.y + b.y);
}
static ImVec2 operator-(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x - b.x, a.y - b.y);
}
static ImVec2 operator*(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x * b.x, a.y * b.y);
}
static ImVec2 operator/(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x / b.x, a.y / b.y);
}
static ImVec2 operator*(const ImVec2& a, const float b) {
return ImVec2(a.x * b, a.y * b);
}
#endif
static float smoothstep(float edge0, float edge1, float x)
{
x = ImClamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return x * x * (3 - 2 * x);
}
static float distance(float x, float y, float x1, float y1, float x2, float y2)
{
float A = x - x1;
float B = y - y1;
float C = x2 - x1;
float D = y2 - y1;
float dot = A * C + B * D;
float len_sq = C * C + D * D;
float param = -1.f;
if (len_sq > FLT_EPSILON)
param = dot / len_sq;
float xx, yy;
if (param < 0.f) {
xx = x1;
yy = y1;
}
else if (param > 1.f) {
xx = x2;
yy = y2;
}
else {
xx = x1 + param * C;
yy = y1 + param * D;
}
float dx = x - xx;
float dy = y - yy;
return sqrtf(dx * dx + dy * dy);
}
static int DrawPoint(ImDrawList* draw_list, ImVec2 pos, const ImVec2 size, const ImVec2 offset, bool edited)
{
int ret = 0;
ImGuiIO& io = ImGui::GetIO();
static const ImVec2 localOffsets[4] = { ImVec2(1,0), ImVec2(0,1), ImVec2(-1,0), ImVec2(0,-1) };
ImVec2 offsets[4];
for (int i = 0; i < 4; i++)
{
offsets[i] = pos * size + localOffsets[i] * 4.5f + offset;
}
const ImVec2 center = pos * size + offset;
const ImRect anchor(center - ImVec2(5, 5), center + ImVec2(5, 5));
draw_list->AddConvexPolyFilled(offsets, 4, 0xFF000000);
if (anchor.Contains(io.MousePos))
{
ret = 1;
if (io.MouseDown[0])
ret = 2;
}
if (edited)
draw_list->AddPolyline(offsets, 4, 0xFFFFFFFF, true, 3.0f);
else if (ret)
draw_list->AddPolyline(offsets, 4, 0xFF80B0FF, true, 2.0f);
else
draw_list->AddPolyline(offsets, 4, 0xFF0080FF, true, 2.0f);
return ret;
}
int Edit(Delegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect, ImVector* selectedPoints)
{
static bool selectingQuad = false;
static ImVec2 quadSelection;
static int overCurve = -1;
static int movingCurve = -1;
static bool scrollingV = false;
static std::set selection;
static bool overSelectedPoint = false;
int ret = 0;
ImGuiIO& io = ImGui::GetIO();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushStyleColor(ImGuiCol_Border, 0);
ImGui::BeginChildFrame(id, size);
delegate.focused = ImGui::IsWindowFocused();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (clippingRect)
draw_list->PushClipRect(clippingRect->Min, clippingRect->Max, true);
const ImVec2 offset = ImGui::GetCursorScreenPos() + ImVec2(0.f, size.y);
const ImVec2 ssize(size.x, -size.y);
const ImRect container(offset + ImVec2(0.f, ssize.y), offset + ImVec2(ssize.x, 0.f));
ImVec2& min = delegate.GetMin();
ImVec2& max = delegate.GetMax();
// handle zoom and VScroll
if (container.Contains(io.MousePos))
{
if (fabsf(io.MouseWheel) > FLT_EPSILON)
{
const float r = (io.MousePos.y - offset.y) / ssize.y;
float ratioY = ImLerp(min.y, max.y, r);
auto scaleValue = [&](float v) {
v -= ratioY;
v *= (1.f - io.MouseWheel * 0.05f);
v += ratioY;
return v;
};
min.y = scaleValue(min.y);
max.y = scaleValue(max.y);
}
if (!scrollingV && ImGui::IsMouseDown(2))
{
scrollingV = true;
}
}
ImVec2 range = max - min + ImVec2(1.f, 0.f); // +1 because of inclusive last frame
const ImVec2 viewSize(size.x, -size.y);
const ImVec2 sizeOfPixel = ImVec2(1.f, 1.f) / viewSize;
const size_t curveCount = delegate.GetCurveCount();
if (scrollingV)
{
float deltaH = io.MouseDelta.y * range.y * sizeOfPixel.y;
min.y -= deltaH;
max.y -= deltaH;
if (!ImGui::IsMouseDown(2))
scrollingV = false;
}
draw_list->AddRectFilled(offset, offset + ssize, delegate.GetBackgroundColor());
auto pointToRange = [&](ImVec2 pt) { return (pt - min) / range; };
auto rangeToPoint = [&](ImVec2 pt) { return (pt * range) + min; };
draw_list->AddLine(ImVec2(-1.f, -min.y / range.y) * viewSize + offset, ImVec2(1.f, -min.y / range.y) * viewSize + offset, 0xFF000000, 1.5f);
bool overCurveOrPoint = false;
int localOverCurve = -1;
// make sure highlighted curve is rendered last
int* curvesIndex = (int*)_malloca(sizeof(int) * curveCount);
for (size_t c = 0; c < curveCount; c++)
curvesIndex[c] = int(c);
int highLightedCurveIndex = -1;
if (overCurve != -1 && curveCount)
{
ImSwap(curvesIndex[overCurve], curvesIndex[curveCount - 1]);
highLightedCurveIndex = overCurve;
}
for (size_t cur = 0; cur < curveCount; cur++)
{
int c = curvesIndex[cur];
if (!delegate.IsVisible(c))
continue;
const size_t ptCount = delegate.GetPointCount(c);
if (ptCount < 1)
continue;
CurveType curveType = delegate.GetCurveType(c);
if (curveType == CurveNone)
continue;
const ImVec2* pts = delegate.GetPoints(c);
uint32_t curveColor = delegate.GetCurveColor(c);
if ((c == highLightedCurveIndex && selection.empty() && !selectingQuad) || movingCurve == c)
curveColor = 0xFFFFFFFF;
for (size_t p = 0; p < ptCount - 1; p++)
{
const ImVec2 p1 = pointToRange(pts[p]);
const ImVec2 p2 = pointToRange(pts[p + 1]);
if (curveType == CurveSmooth || curveType == CurveLinear)
{
size_t subStepCount = (curveType == CurveSmooth) ? 20 : 2;
float step = 1.f / float(subStepCount - 1);
for (size_t substep = 0; substep < subStepCount - 1; substep++)
{
float t = float(substep) * step;
const ImVec2 sp1 = ImLerp(p1, p2, t);
const ImVec2 sp2 = ImLerp(p1, p2, t + step);
const float rt1 = smoothstep(p1.x, p2.x, sp1.x);
const float rt2 = smoothstep(p1.x, p2.x, sp2.x);
const ImVec2 pos1 = ImVec2(sp1.x, ImLerp(p1.y, p2.y, rt1)) * viewSize + offset;
const ImVec2 pos2 = ImVec2(sp2.x, ImLerp(p1.y, p2.y, rt2)) * viewSize + offset;
if (distance(io.MousePos.x, io.MousePos.y, pos1.x, pos1.y, pos2.x, pos2.y) < 8.f && !scrollingV)
{
localOverCurve = int(c);
overCurve = int(c);
overCurveOrPoint = true;
}
draw_list->AddLine(pos1, pos2, curveColor, 1.3f);
} // substep
}
else if (curveType == CurveDiscrete)
{
ImVec2 dp1 = p1 * viewSize + offset;
ImVec2 dp2 = ImVec2(p2.x, p1.y) * viewSize + offset;
ImVec2 dp3 = p2 * viewSize + offset;
draw_list->AddLine(dp1, dp2, curveColor, 1.3f);
draw_list->AddLine(dp2, dp3, curveColor, 1.3f);
if ((distance(io.MousePos.x, io.MousePos.y, dp1.x, dp1.y, dp3.x, dp1.y) < 8.f ||
distance(io.MousePos.x, io.MousePos.y, dp3.x, dp1.y, dp3.x, dp3.y) < 8.f)
/*&& localOverCurve == -1*/)
{
localOverCurve = int(c);
overCurve = int(c);
overCurveOrPoint = true;
}
}
} // point loop
for (size_t p = 0; p < ptCount; p++)
{
const int drawState = DrawPoint(draw_list, pointToRange(pts[p]), viewSize, offset, (selection.find({ int(c), int(p) }) != selection.end() && movingCurve == -1 && !scrollingV));
if (drawState && movingCurve == -1 && !selectingQuad)
{
overCurveOrPoint = true;
overSelectedPoint = true;
overCurve = -1;
if (drawState == 2)
{
if (!io.KeyShift && selection.find({ int(c), int(p) }) == selection.end())
selection.clear();
selection.insert({ int(c), int(p) });
}
}
}
} // curves loop
if (localOverCurve == -1)
overCurve = -1;
// move selection
static bool pointsMoved = false;
static ImVec2 mousePosOrigin;
static std::vector originalPoints;
if (overSelectedPoint && io.MouseDown[0])
{
if ((fabsf(io.MouseDelta.x) > 0.f || fabsf(io.MouseDelta.y) > 0.f) && !selection.empty())
{
if (!pointsMoved)
{
delegate.BeginEdit(0);
mousePosOrigin = io.MousePos;
originalPoints.resize(selection.size());
int index = 0;
for (auto& sel : selection)
{
const ImVec2* pts = delegate.GetPoints(sel.curveIndex);
originalPoints[index++] = pts[sel.pointIndex];
}
}
pointsMoved = true;
ret = 1;
auto prevSelection = selection;
int originalIndex = 0;
for (auto& sel : prevSelection)
{
const ImVec2 p = rangeToPoint(pointToRange(originalPoints[originalIndex]) + (io.MousePos - mousePosOrigin) * sizeOfPixel);
const int newIndex = delegate.EditPoint(sel.curveIndex, sel.pointIndex, p);
if (newIndex != sel.pointIndex)
{
selection.erase(sel);
selection.insert({ sel.curveIndex, newIndex });
}
originalIndex++;
}
}
}
if (overSelectedPoint && !io.MouseDown[0])
{
overSelectedPoint = false;
if (pointsMoved)
{
pointsMoved = false;
delegate.EndEdit();
}
}
// add point
if (overCurve != -1 && io.MouseDoubleClicked[0])
{
const ImVec2 np = rangeToPoint((io.MousePos - offset) / viewSize);
delegate.BeginEdit(overCurve);
delegate.AddPoint(overCurve, np);
delegate.EndEdit();
ret = 1;
}
// move curve
if (movingCurve != -1)
{
const size_t ptCount = delegate.GetPointCount(movingCurve);
const ImVec2* pts = delegate.GetPoints(movingCurve);
if (!pointsMoved)
{
mousePosOrigin = io.MousePos;
pointsMoved = true;
originalPoints.resize(ptCount);
for (size_t index = 0; index < ptCount; index++)
{
originalPoints[index] = pts[index];
}
}
if (ptCount >= 1)
{
for (size_t p = 0; p < ptCount; p++)
{
delegate.EditPoint(movingCurve, int(p), rangeToPoint(pointToRange(originalPoints[p]) + (io.MousePos - mousePosOrigin) * sizeOfPixel));
}
ret = 1;
}
if (!io.MouseDown[0])
{
movingCurve = -1;
pointsMoved = false;
delegate.EndEdit();
}
}
if (movingCurve == -1 && overCurve != -1 && ImGui::IsMouseClicked(0) && selection.empty() && !selectingQuad)
{
movingCurve = overCurve;
delegate.BeginEdit(overCurve);
}
// quad selection
if (selectingQuad)
{
const ImVec2 bmin = ImMin(quadSelection, io.MousePos);
const ImVec2 bmax = ImMax(quadSelection, io.MousePos);
draw_list->AddRectFilled(bmin, bmax, 0x40FF0000, 1.f);
draw_list->AddRect(bmin, bmax, 0xFFFF0000, 1.f);
const ImRect selectionQuad(bmin, bmax);
if (!io.MouseDown[0])
{
if (!io.KeyShift)
selection.clear();
// select everythnig is quad
for (size_t c = 0; c < curveCount; c++)
{
if (!delegate.IsVisible(c))
continue;
const size_t ptCount = delegate.GetPointCount(c);
if (ptCount < 1)
continue;
const ImVec2* pts = delegate.GetPoints(c);
for (size_t p = 0; p < ptCount; p++)
{
const ImVec2 center = pointToRange(pts[p]) * viewSize + offset;
if (selectionQuad.Contains(center))
selection.insert({ int(c), int(p) });
}
}
// done
selectingQuad = false;
}
}
if (!overCurveOrPoint && ImGui::IsMouseClicked(0) && !selectingQuad && movingCurve == -1 && !overSelectedPoint && container.Contains(io.MousePos))
{
selectingQuad = true;
quadSelection = io.MousePos;
}
if (clippingRect)
draw_list->PopClipRect();
ImGui::EndChildFrame();
ImGui::PopStyleVar();
ImGui::PopStyleColor(1);
if (selectedPoints)
{
selectedPoints->resize(int(selection.size()));
int index = 0;
for (auto& point : selection)
(*selectedPoints)[index++] = point;
}
return ret;
}
}
================================================
FILE: Source/External/imgui_tools/imguizmo/ImCurveEdit.h
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#pragma once
#include
#include "imgui.h"
struct ImRect;
namespace ImCurveEdit
{
enum CurveType
{
CurveNone,
CurveDiscrete,
CurveLinear,
CurveSmooth,
CurveBezier,
};
struct EditPoint
{
int curveIndex;
int pointIndex;
bool operator <(const EditPoint& other) const
{
if (curveIndex < other.curveIndex)
return true;
if (curveIndex > other.curveIndex)
return false;
if (pointIndex < other.pointIndex)
return true;
return false;
}
};
struct Delegate
{
bool focused = false;
virtual size_t GetCurveCount() = 0;
virtual bool IsVisible(size_t /*curveIndex*/) { return true; }
virtual CurveType GetCurveType(size_t /*curveIndex*/) const { return CurveLinear; }
virtual ImVec2& GetMin() = 0;
virtual ImVec2& GetMax() = 0;
virtual size_t GetPointCount(size_t curveIndex) = 0;
virtual uint32_t GetCurveColor(size_t curveIndex) = 0;
virtual ImVec2* GetPoints(size_t curveIndex) = 0;
virtual int EditPoint(size_t curveIndex, int pointIndex, ImVec2 value) = 0;
virtual void AddPoint(size_t curveIndex, ImVec2 value) = 0;
virtual unsigned int GetBackgroundColor() { return 0xFF202020; }
// handle undo/redo thru this functions
virtual void BeginEdit(int /*index*/) {}
virtual void EndEdit() {}
};
int Edit(Delegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect = NULL, ImVector* selectedPoints = NULL);
}
================================================
FILE: Source/External/imgui_tools/imguizmo/ImGradient.cpp
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "ImGradient.h"
#include "imgui.h"
#include "imgui_internal.h"
namespace ImGradient
{
#ifndef IMGUI_DEFINE_MATH_OPERATORS
static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); }
static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }
#endif
static int DrawPoint(ImDrawList* draw_list, ImVec4 color, const ImVec2 size, bool editing, ImVec2 pos)
{
ImGuiIO& io = ImGui::GetIO();
ImVec2 p1 = ImLerp(pos, ImVec2(pos + ImVec2(size.x - size.y, 0.f)), color.w) + ImVec2(3, 3);
ImVec2 p2 = ImLerp(pos + ImVec2(size.y, size.y), ImVec2(pos + size), color.w) - ImVec2(3, 3);
ImRect rc(p1, p2);
color.w = 1.f;
draw_list->AddRectFilled(p1, p2, ImColor(color));
if (editing)
draw_list->AddRect(p1, p2, 0xFFFFFFFF, 2.f, 15, 2.5f);
else
draw_list->AddRect(p1, p2, 0x80FFFFFF, 2.f, 15, 1.25f);
if (rc.Contains(io.MousePos))
{
if (io.MouseClicked[0])
return 2;
return 1;
}
return 0;
}
bool Edit(Delegate& delegate, const ImVec2& size, int& selection)
{
bool ret = false;
ImGuiIO& io = ImGui::GetIO();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::BeginChildFrame(137, size);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
const ImVec2 offset = ImGui::GetCursorScreenPos();
const ImVec4* pts = delegate.GetPoints();
static int currentSelection = -1;
static int movingPt = -1;
if (currentSelection >= int(delegate.GetPointCount()))
currentSelection = -1;
if (movingPt != -1)
{
ImVec4 current = pts[movingPt];
current.w += io.MouseDelta.x / size.x;
current.w = ImClamp(current.w, 0.f, 1.f);
delegate.EditPoint(movingPt, current);
ret = true;
if (!io.MouseDown[0])
movingPt = -1;
}
for (size_t i = 0; i < delegate.GetPointCount(); i++)
{
int ptSel = DrawPoint(draw_list, pts[i], size, i == currentSelection, offset);
if (ptSel == 2)
{
currentSelection = int(i);
ret = true;
}
if (ptSel == 1 && io.MouseDown[0] && movingPt == -1)
{
movingPt = int(i);
}
}
ImRect rc(offset, offset + size);
if (rc.Contains(io.MousePos) && io.MouseDoubleClicked[0])
{
float t = (io.MousePos.x - offset.x) / size.x;
delegate.AddPoint(delegate.GetPoint(t));
ret = true;
}
ImGui::EndChildFrame();
ImGui::PopStyleVar();
selection = currentSelection;
return ret;
}
}
================================================
FILE: Source/External/imgui_tools/imguizmo/ImGradient.h
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#pragma once
#include
struct ImVec4;
struct ImVec2;
namespace ImGradient
{
struct Delegate
{
virtual size_t GetPointCount() = 0;
virtual ImVec4* GetPoints() = 0;
virtual int EditPoint(int pointIndex, ImVec4 value) = 0;
virtual ImVec4 GetPoint(float t) = 0;
virtual void AddPoint(ImVec4 value) = 0;
};
bool Edit(Delegate& delegate, const ImVec2& size, int& selection);
}
================================================
FILE: Source/External/imgui_tools/imguizmo/ImGuizmo.cpp
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include "imgui.h"
#include "imgui_internal.h"
#include "ImGuizmo.h"
#if defined(_MSC_VER) || defined(__MINGW32__)
#include
#endif
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
#define _malloca(x) alloca(x)
#define _freea(x)
#endif
// includes patches for multiview from
// https://github.com/CedricGuillemet/ImGuizmo/issues/15
namespace IMGUIZMO_NAMESPACE
{
static const float ZPI = 3.14159265358979323846f;
static const float RAD2DEG = (180.f / ZPI);
static const float DEG2RAD = (ZPI / 180.f);
const float screenRotateSize = 0.06f;
// scale a bit so translate axis do not touch when in universal
const float rotationDisplayFactor = 1.2f;
static OPERATION operator&(OPERATION lhs, OPERATION rhs)
{
return static_cast(static_cast(lhs) & static_cast(rhs));
}
static bool operator!=(OPERATION lhs, int rhs)
{
return static_cast(lhs) != rhs;
}
static bool Intersects(OPERATION lhs, OPERATION rhs)
{
return (lhs & rhs) != 0;
}
// True if lhs contains rhs
static bool Contains(OPERATION lhs, OPERATION rhs)
{
return (lhs & rhs) == rhs;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// utility and math
void FPU_MatrixF_x_MatrixF(const float* a, const float* b, float* r)
{
r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
}
void Frustum(float left, float right, float bottom, float top, float znear, float zfar, float* m16)
{
float temp, temp2, temp3, temp4;
temp = 2.0f * znear;
temp2 = right - left;
temp3 = top - bottom;
temp4 = zfar - znear;
m16[0] = temp / temp2;
m16[1] = 0.0;
m16[2] = 0.0;
m16[3] = 0.0;
m16[4] = 0.0;
m16[5] = temp / temp3;
m16[6] = 0.0;
m16[7] = 0.0;
m16[8] = (right + left) / temp2;
m16[9] = (top + bottom) / temp3;
m16[10] = (-zfar - znear) / temp4;
m16[11] = -1.0f;
m16[12] = 0.0;
m16[13] = 0.0;
m16[14] = (-temp * zfar) / temp4;
m16[15] = 0.0;
}
void Perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar, float* m16)
{
float ymax, xmax;
ymax = znear * tanf(fovyInDegrees * DEG2RAD);
xmax = ymax * aspectRatio;
Frustum(-xmax, xmax, -ymax, ymax, znear, zfar, m16);
}
void Cross(const float* a, const float* b, float* r)
{
r[0] = a[1] * b[2] - a[2] * b[1];
r[1] = a[2] * b[0] - a[0] * b[2];
r[2] = a[0] * b[1] - a[1] * b[0];
}
float Dot(const float* a, const float* b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
void Normalize(const float* a, float* r)
{
float il = 1.f / (sqrtf(Dot(a, a)) + FLT_EPSILON);
r[0] = a[0] * il;
r[1] = a[1] * il;
r[2] = a[2] * il;
}
void LookAt(const float* eye, const float* at, const float* up, float* m16)
{
float X[3], Y[3], Z[3], tmp[3];
tmp[0] = eye[0] - at[0];
tmp[1] = eye[1] - at[1];
tmp[2] = eye[2] - at[2];
Normalize(tmp, Z);
Normalize(up, Y);
Cross(Y, Z, tmp);
Normalize(tmp, X);
Cross(Z, X, tmp);
Normalize(tmp, Y);
m16[0] = X[0];
m16[1] = Y[0];
m16[2] = Z[0];
m16[3] = 0.0f;
m16[4] = X[1];
m16[5] = Y[1];
m16[6] = Z[1];
m16[7] = 0.0f;
m16[8] = X[2];
m16[9] = Y[2];
m16[10] = Z[2];
m16[11] = 0.0f;
m16[12] = -Dot(X, eye);
m16[13] = -Dot(Y, eye);
m16[14] = -Dot(Z, eye);
m16[15] = 1.0f;
}
template T Clamp(T x, T y, T z) { return ((x < y) ? y : ((x > z) ? z : x)); }
template T max(T x, T y) { return (x > y) ? x : y; }
template T min(T x, T y) { return (x < y) ? x : y; }
template bool IsWithin(T x, T y, T z) { return (x >= y) && (x <= z); }
struct matrix_t;
struct vec_t
{
public:
float x, y, z, w;
void Lerp(const vec_t& v, float t)
{
x += (v.x - x) * t;
y += (v.y - y) * t;
z += (v.z - z) * t;
w += (v.w - w) * t;
}
void Set(float v) { x = y = z = w = v; }
void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) { x = _x; y = _y; z = _z; w = _w; }
vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }
vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }
vec_t& operator *= (const vec_t& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; }
vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; }
vec_t operator * (float f) const;
vec_t operator - () const;
vec_t operator - (const vec_t& v) const;
vec_t operator + (const vec_t& v) const;
vec_t operator * (const vec_t& v) const;
const vec_t& operator + () const { return (*this); }
float Length() const { return sqrtf(x * x + y * y + z * z); };
float LengthSq() const { return (x * x + y * y + z * z); };
vec_t Normalize() { (*this) *= (1.f / ( Length() > FLT_EPSILON ? Length() : FLT_EPSILON ) ); return (*this); }
vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }
vec_t Abs() const;
void Cross(const vec_t& v)
{
vec_t res;
res.x = y * v.z - z * v.y;
res.y = z * v.x - x * v.z;
res.z = x * v.y - y * v.x;
x = res.x;
y = res.y;
z = res.z;
w = 0.f;
}
void Cross(const vec_t& v1, const vec_t& v2)
{
x = v1.y * v2.z - v1.z * v2.y;
y = v1.z * v2.x - v1.x * v2.z;
z = v1.x * v2.y - v1.y * v2.x;
w = 0.f;
}
float Dot(const vec_t& v) const
{
return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w);
}
float Dot3(const vec_t& v) const
{
return (x * v.x) + (y * v.y) + (z * v.z);
}
void Transform(const matrix_t& matrix);
void Transform(const vec_t& s, const matrix_t& matrix);
void TransformVector(const matrix_t& matrix);
void TransformPoint(const matrix_t& matrix);
void TransformVector(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformVector(matrix); }
void TransformPoint(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformPoint(matrix); }
float& operator [] (size_t index) { return ((float*)&x)[index]; }
const float& operator [] (size_t index) const { return ((float*)&x)[index]; }
bool operator!=(const vec_t& other) const { return memcmp(this, &other, sizeof(vec_t)) != 0; }
};
vec_t makeVect(float _x, float _y, float _z = 0.f, float _w = 0.f) { vec_t res; res.x = _x; res.y = _y; res.z = _z; res.w = _w; return res; }
vec_t makeVect(ImVec2 v) { vec_t res; res.x = v.x; res.y = v.y; res.z = 0.f; res.w = 0.f; return res; }
vec_t vec_t::operator * (float f) const { return makeVect(x * f, y * f, z * f, w * f); }
vec_t vec_t::operator - () const { return makeVect(-x, -y, -z, -w); }
vec_t vec_t::operator - (const vec_t& v) const { return makeVect(x - v.x, y - v.y, z - v.z, w - v.w); }
vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); }
vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); }
vec_t vec_t::Abs() const { return makeVect(fabsf(x), fabsf(y), fabsf(z)); }
vec_t Normalized(const vec_t& v) { vec_t res; res = v; res.Normalize(); return res; }
vec_t Cross(const vec_t& v1, const vec_t& v2)
{
vec_t res;
res.x = v1.y * v2.z - v1.z * v2.y;
res.y = v1.z * v2.x - v1.x * v2.z;
res.z = v1.x * v2.y - v1.y * v2.x;
res.w = 0.f;
return res;
}
float Dot(const vec_t& v1, const vec_t& v2)
{
return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}
vec_t BuildPlan(const vec_t& p_point1, const vec_t& p_normal)
{
vec_t normal, res;
normal.Normalize(p_normal);
res.w = normal.Dot(p_point1);
res.x = normal.x;
res.y = normal.y;
res.z = normal.z;
return res;
}
struct matrix_t
{
public:
union
{
float m[4][4];
float m16[16];
struct
{
vec_t right, up, dir, position;
} v;
vec_t component[4];
};
operator float* () { return m16; }
operator const float* () const { return m16; }
void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); }
void Translation(const vec_t& vt)
{
v.right.Set(1.f, 0.f, 0.f, 0.f);
v.up.Set(0.f, 1.f, 0.f, 0.f);
v.dir.Set(0.f, 0.f, 1.f, 0.f);
v.position.Set(vt.x, vt.y, vt.z, 1.f);
}
void Scale(float _x, float _y, float _z)
{
v.right.Set(_x, 0.f, 0.f, 0.f);
v.up.Set(0.f, _y, 0.f, 0.f);
v.dir.Set(0.f, 0.f, _z, 0.f);
v.position.Set(0.f, 0.f, 0.f, 1.f);
}
void Scale(const vec_t& s) { Scale(s.x, s.y, s.z); }
matrix_t& operator *= (const matrix_t& mat)
{
matrix_t tmpMat;
tmpMat = *this;
tmpMat.Multiply(mat);
*this = tmpMat;
return *this;
}
matrix_t operator * (const matrix_t& mat) const
{
matrix_t matT;
matT.Multiply(*this, mat);
return matT;
}
void Multiply(const matrix_t& matrix)
{
matrix_t tmp;
tmp = *this;
FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this);
}
void Multiply(const matrix_t& m1, const matrix_t& m2)
{
FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this);
}
float GetDeterminant() const
{
return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] -
m[0][2] * m[1][1] * m[2][0] - m[0][1] * m[1][0] * m[2][2] - m[0][0] * m[1][2] * m[2][1];
}
float Inverse(const matrix_t& srcMatrix, bool affine = false);
void SetToIdentity()
{
v.right.Set(1.f, 0.f, 0.f, 0.f);
v.up.Set(0.f, 1.f, 0.f, 0.f);
v.dir.Set(0.f, 0.f, 1.f, 0.f);
v.position.Set(0.f, 0.f, 0.f, 1.f);
}
void Transpose()
{
matrix_t tmpm;
for (int l = 0; l < 4; l++)
{
for (int c = 0; c < 4; c++)
{
tmpm.m[l][c] = m[c][l];
}
}
(*this) = tmpm;
}
void RotationAxis(const vec_t& axis, float angle);
void OrthoNormalize()
{
v.right.Normalize();
v.up.Normalize();
v.dir.Normalize();
}
};
void vec_t::Transform(const matrix_t& matrix)
{
vec_t out;
out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + w * matrix.m[3][0];
out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + w * matrix.m[3][1];
out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + w * matrix.m[3][2];
out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + w * matrix.m[3][3];
x = out.x;
y = out.y;
z = out.z;
w = out.w;
}
void vec_t::Transform(const vec_t& s, const matrix_t& matrix)
{
*this = s;
Transform(matrix);
}
void vec_t::TransformPoint(const matrix_t& matrix)
{
vec_t out;
out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0];
out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1];
out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2];
out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3];
x = out.x;
y = out.y;
z = out.z;
w = out.w;
}
void vec_t::TransformVector(const matrix_t& matrix)
{
vec_t out;
out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0];
out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1];
out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2];
out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3];
x = out.x;
y = out.y;
z = out.z;
w = out.w;
}
float matrix_t::Inverse(const matrix_t& srcMatrix, bool affine)
{
float det = 0;
if (affine)
{
det = GetDeterminant();
float s = 1 / det;
m[0][0] = (srcMatrix.m[1][1] * srcMatrix.m[2][2] - srcMatrix.m[1][2] * srcMatrix.m[2][1]) * s;
m[0][1] = (srcMatrix.m[2][1] * srcMatrix.m[0][2] - srcMatrix.m[2][2] * srcMatrix.m[0][1]) * s;
m[0][2] = (srcMatrix.m[0][1] * srcMatrix.m[1][2] - srcMatrix.m[0][2] * srcMatrix.m[1][1]) * s;
m[1][0] = (srcMatrix.m[1][2] * srcMatrix.m[2][0] - srcMatrix.m[1][0] * srcMatrix.m[2][2]) * s;
m[1][1] = (srcMatrix.m[2][2] * srcMatrix.m[0][0] - srcMatrix.m[2][0] * srcMatrix.m[0][2]) * s;
m[1][2] = (srcMatrix.m[0][2] * srcMatrix.m[1][0] - srcMatrix.m[0][0] * srcMatrix.m[1][2]) * s;
m[2][0] = (srcMatrix.m[1][0] * srcMatrix.m[2][1] - srcMatrix.m[1][1] * srcMatrix.m[2][0]) * s;
m[2][1] = (srcMatrix.m[2][0] * srcMatrix.m[0][1] - srcMatrix.m[2][1] * srcMatrix.m[0][0]) * s;
m[2][2] = (srcMatrix.m[0][0] * srcMatrix.m[1][1] - srcMatrix.m[0][1] * srcMatrix.m[1][0]) * s;
m[3][0] = -(m[0][0] * srcMatrix.m[3][0] + m[1][0] * srcMatrix.m[3][1] + m[2][0] * srcMatrix.m[3][2]);
m[3][1] = -(m[0][1] * srcMatrix.m[3][0] + m[1][1] * srcMatrix.m[3][1] + m[2][1] * srcMatrix.m[3][2]);
m[3][2] = -(m[0][2] * srcMatrix.m[3][0] + m[1][2] * srcMatrix.m[3][1] + m[2][2] * srcMatrix.m[3][2]);
}
else
{
// transpose matrix
float src[16];
for (int i = 0; i < 4; ++i)
{
src[i] = srcMatrix.m16[i * 4];
src[i + 4] = srcMatrix.m16[i * 4 + 1];
src[i + 8] = srcMatrix.m16[i * 4 + 2];
src[i + 12] = srcMatrix.m16[i * 4 + 3];
}
// calculate pairs for first 8 elements (cofactors)
float tmp[12]; // temp array for pairs
tmp[0] = src[10] * src[15];
tmp[1] = src[11] * src[14];
tmp[2] = src[9] * src[15];
tmp[3] = src[11] * src[13];
tmp[4] = src[9] * src[14];
tmp[5] = src[10] * src[13];
tmp[6] = src[8] * src[15];
tmp[7] = src[11] * src[12];
tmp[8] = src[8] * src[14];
tmp[9] = src[10] * src[12];
tmp[10] = src[8] * src[13];
tmp[11] = src[9] * src[12];
// calculate first 8 elements (cofactors)
m16[0] = (tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]) - (tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]);
m16[1] = (tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]) - (tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]);
m16[2] = (tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]) - (tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]);
m16[3] = (tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]) - (tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]);
m16[4] = (tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]) - (tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]);
m16[5] = (tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]) - (tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]);
m16[6] = (tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]) - (tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]);
m16[7] = (tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]) - (tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]);
// calculate pairs for second 8 elements (cofactors)
tmp[0] = src[2] * src[7];
tmp[1] = src[3] * src[6];
tmp[2] = src[1] * src[7];
tmp[3] = src[3] * src[5];
tmp[4] = src[1] * src[6];
tmp[5] = src[2] * src[5];
tmp[6] = src[0] * src[7];
tmp[7] = src[3] * src[4];
tmp[8] = src[0] * src[6];
tmp[9] = src[2] * src[4];
tmp[10] = src[0] * src[5];
tmp[11] = src[1] * src[4];
// calculate second 8 elements (cofactors)
m16[8] = (tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]) - (tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]);
m16[9] = (tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]) - (tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]);
m16[10] = (tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]) - (tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]);
m16[11] = (tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]) - (tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]);
m16[12] = (tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]) - (tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]);
m16[13] = (tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]) - (tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]);
m16[14] = (tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]) - (tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]);
m16[15] = (tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]) - (tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]);
// calculate determinant
det = src[0] * m16[0] + src[1] * m16[1] + src[2] * m16[2] + src[3] * m16[3];
// calculate matrix inverse
float invdet = 1 / det;
for (int j = 0; j < 16; ++j)
{
m16[j] *= invdet;
}
}
return det;
}
void matrix_t::RotationAxis(const vec_t& axis, float angle)
{
float length2 = axis.LengthSq();
if (length2 < FLT_EPSILON)
{
SetToIdentity();
return;
}
vec_t n = axis * (1.f / sqrtf(length2));
float s = sinf(angle);
float c = cosf(angle);
float k = 1.f - c;
float xx = n.x * n.x * k + c;
float yy = n.y * n.y * k + c;
float zz = n.z * n.z * k + c;
float xy = n.x * n.y * k;
float yz = n.y * n.z * k;
float zx = n.z * n.x * k;
float xs = n.x * s;
float ys = n.y * s;
float zs = n.z * s;
m[0][0] = xx;
m[0][1] = xy + zs;
m[0][2] = zx - ys;
m[0][3] = 0.f;
m[1][0] = xy - zs;
m[1][1] = yy;
m[1][2] = yz + xs;
m[1][3] = 0.f;
m[2][0] = zx + ys;
m[2][1] = yz - xs;
m[2][2] = zz;
m[2][3] = 0.f;
m[3][0] = 0.f;
m[3][1] = 0.f;
m[3][2] = 0.f;
m[3][3] = 1.f;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
enum MOVETYPE
{
MT_NONE,
MT_MOVE_X,
MT_MOVE_Y,
MT_MOVE_Z,
MT_MOVE_YZ,
MT_MOVE_ZX,
MT_MOVE_XY,
MT_MOVE_SCREEN,
MT_ROTATE_X,
MT_ROTATE_Y,
MT_ROTATE_Z,
MT_ROTATE_SCREEN,
MT_SCALE_X,
MT_SCALE_Y,
MT_SCALE_Z,
MT_SCALE_XYZ
};
static bool IsTranslateType(int type)
{
return type >= MT_MOVE_X && type <= MT_MOVE_SCREEN;
}
static bool IsRotateType(int type)
{
return type >= MT_ROTATE_X && type <= MT_ROTATE_SCREEN;
}
static bool IsScaleType(int type)
{
return type >= MT_SCALE_X && type <= MT_SCALE_XYZ;
}
// Matches MT_MOVE_AB order
static const OPERATION TRANSLATE_PLANS[3] = { TRANSLATE_Y | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Y };
Style::Style()
{
// default values
TranslationLineThickness = 3.0f;
TranslationLineArrowSize = 6.0f;
RotationLineThickness = 2.0f;
RotationOuterLineThickness = 3.0f;
ScaleLineThickness = 3.0f;
ScaleLineCircleSize = 6.0f;
HatchedAxisLineThickness = 6.0f;
CenterCircleSize = 6.0f;
// initialize default colors
Colors[DIRECTION_X] = ImVec4(0.666f, 0.000f, 0.000f, 1.000f);
Colors[DIRECTION_Y] = ImVec4(0.000f, 0.666f, 0.000f, 1.000f);
Colors[DIRECTION_Z] = ImVec4(0.000f, 0.000f, 0.666f, 1.000f);
Colors[PLANE_X] = ImVec4(0.666f, 0.000f, 0.000f, 0.380f);
Colors[PLANE_Y] = ImVec4(0.000f, 0.666f, 0.000f, 0.380f);
Colors[PLANE_Z] = ImVec4(0.000f, 0.000f, 0.666f, 0.380f);
Colors[SELECTION] = ImVec4(1.000f, 0.500f, 0.062f, 0.541f);
Colors[INACTIVE] = ImVec4(0.600f, 0.600f, 0.600f, 0.600f);
Colors[TRANSLATION_LINE] = ImVec4(0.666f, 0.666f, 0.666f, 0.666f);
Colors[SCALE_LINE] = ImVec4(0.250f, 0.250f, 0.250f, 1.000f);
Colors[ROTATION_USING_BORDER] = ImVec4(1.000f, 0.500f, 0.062f, 1.000f);
Colors[ROTATION_USING_FILL] = ImVec4(1.000f, 0.500f, 0.062f, 0.500f);
Colors[HATCHED_AXIS_LINES] = ImVec4(0.000f, 0.000f, 0.000f, 0.500f);
Colors[TEXT] = ImVec4(1.000f, 1.000f, 1.000f, 1.000f);
Colors[TEXT_SHADOW] = ImVec4(0.000f, 0.000f, 0.000f, 1.000f);
}
struct Context
{
Context() : mbUsing(false), mbEnable(true), mbUsingBounds(false)
{
}
ImDrawList* mDrawList;
Style mStyle;
MODE mMode;
matrix_t mViewMat;
matrix_t mProjectionMat;
matrix_t mModel;
matrix_t mModelLocal; // orthonormalized model
matrix_t mModelInverse;
matrix_t mModelSource;
matrix_t mModelSourceInverse;
matrix_t mMVP;
matrix_t mMVPLocal; // MVP with full model matrix whereas mMVP's model matrix might only be translation in case of World space edition
matrix_t mViewProjection;
vec_t mModelScaleOrigin;
vec_t mCameraEye;
vec_t mCameraRight;
vec_t mCameraDir;
vec_t mCameraUp;
vec_t mRayOrigin;
vec_t mRayVector;
float mRadiusSquareCenter;
ImVec2 mScreenSquareCenter;
ImVec2 mScreenSquareMin;
ImVec2 mScreenSquareMax;
float mScreenFactor;
vec_t mRelativeOrigin;
bool mbUsing;
bool mbEnable;
bool mbMouseOver;
bool mReversed; // reversed projection matrix
// translation
vec_t mTranslationPlan;
vec_t mTranslationPlanOrigin;
vec_t mMatrixOrigin;
vec_t mTranslationLastDelta;
// rotation
vec_t mRotationVectorSource;
float mRotationAngle;
float mRotationAngleOrigin;
//vec_t mWorldToLocalAxis;
// scale
vec_t mScale;
vec_t mScaleValueOrigin;
vec_t mScaleLast;
float mSaveMousePosx;
// save axis factor when using gizmo
bool mBelowAxisLimit[3];
bool mBelowPlaneLimit[3];
float mAxisFactor[3];
// bounds stretching
vec_t mBoundsPivot;
vec_t mBoundsAnchor;
vec_t mBoundsPlan;
vec_t mBoundsLocalPivot;
int mBoundsBestAxis;
int mBoundsAxis[2];
bool mbUsingBounds;
matrix_t mBoundsMatrix;
//
int mCurrentOperation;
float mX = 0.f;
float mY = 0.f;
float mWidth = 0.f;
float mHeight = 0.f;
float mXMax = 0.f;
float mYMax = 0.f;
float mDisplayRatio = 1.f;
bool mIsOrthographic = false;
int mActualID = -1;
int mEditingID = -1;
OPERATION mOperation = OPERATION(-1);
bool mAllowAxisFlip = true;
float mGizmoSizeClipSpace = 0.1f;
};
static Context gContext;
static const vec_t directionUnary[3] = { makeVect(1.f, 0.f, 0.f), makeVect(0.f, 1.f, 0.f), makeVect(0.f, 0.f, 1.f) };
static const char* translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f",
"Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f",
"X : %5.3f Y : %5.3f Z : %5.3f" };
static const char* scaleInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "XYZ : %5.2f" };
static const char* rotationInfoMask[] = { "X : %5.2f deg %5.2f rad", "Y : %5.2f deg %5.2f rad", "Z : %5.2f deg %5.2f rad", "Screen : %5.2f deg %5.2f rad" };
static const int translationInfoIndex[] = { 0,0,0, 1,0,0, 2,0,0, 1,2,0, 0,2,0, 0,1,0, 0,1,2 };
static const float quadMin = 0.5f;
static const float quadMax = 0.8f;
static const float quadUV[8] = { quadMin, quadMin, quadMin, quadMax, quadMax, quadMax, quadMax, quadMin };
static const int halfCircleSegmentCount = 64;
static const float snapTension = 0.5f;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion);
static int GetRotateType(OPERATION op);
static int GetScaleType(OPERATION op);
Style& GetStyle()
{
return gContext.mStyle;
}
static ImU32 GetColorU32(int idx)
{
IM_ASSERT(idx < COLOR::COUNT);
return ImGui::ColorConvertFloat4ToU32(gContext.mStyle.Colors[idx]);
}
static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight))
{
vec_t trans;
trans.TransformPoint(worldPos, mat);
trans *= 0.5f / trans.w;
trans += makeVect(0.5f, 0.5f);
trans.y = 1.f - trans.y;
trans.x *= size.x;
trans.y *= size.y;
trans.x += position.x;
trans.y += position.y;
return ImVec2(trans.x, trans.y);
}
static void ComputeCameraRay(vec_t& rayOrigin, vec_t& rayDir, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight))
{
ImGuiIO& io = ImGui::GetIO();
matrix_t mViewProjInverse;
mViewProjInverse.Inverse(gContext.mViewMat * gContext.mProjectionMat);
const float mox = ((io.MousePos.x - position.x) / size.x) * 2.f - 1.f;
const float moy = (1.f - ((io.MousePos.y - position.y) / size.y)) * 2.f - 1.f;
const float zNear = gContext.mReversed ? (1.f - FLT_EPSILON) : 0.f;
const float zFar = gContext.mReversed ? 0.f : (1.f - FLT_EPSILON);
rayOrigin.Transform(makeVect(mox, moy, zNear, 1.f), mViewProjInverse);
rayOrigin *= 1.f / rayOrigin.w;
vec_t rayEnd;
rayEnd.Transform(makeVect(mox, moy, zFar, 1.f), mViewProjInverse);
rayEnd *= 1.f / rayEnd.w;
rayDir = Normalized(rayEnd - rayOrigin);
}
static float GetSegmentLengthClipSpace(const vec_t& start, const vec_t& end, const bool localCoordinates = false)
{
vec_t startOfSegment = start;
const matrix_t& mvp = localCoordinates ? gContext.mMVPLocal : gContext.mMVP;
startOfSegment.TransformPoint(mvp);
if (fabsf(startOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction
{
startOfSegment *= 1.f / startOfSegment.w;
}
vec_t endOfSegment = end;
endOfSegment.TransformPoint(mvp);
if (fabsf(endOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction
{
endOfSegment *= 1.f / endOfSegment.w;
}
vec_t clipSpaceAxis = endOfSegment - startOfSegment;
clipSpaceAxis.y /= gContext.mDisplayRatio;
float segmentLengthInClipSpace = sqrtf(clipSpaceAxis.x * clipSpaceAxis.x + clipSpaceAxis.y * clipSpaceAxis.y);
return segmentLengthInClipSpace;
}
static float GetParallelogram(const vec_t& ptO, const vec_t& ptA, const vec_t& ptB)
{
vec_t pts[] = { ptO, ptA, ptB };
for (unsigned int i = 0; i < 3; i++)
{
pts[i].TransformPoint(gContext.mMVP);
if (fabsf(pts[i].w) > FLT_EPSILON) // check for axis aligned with camera direction
{
pts[i] *= 1.f / pts[i].w;
}
}
vec_t segA = pts[1] - pts[0];
vec_t segB = pts[2] - pts[0];
segA.y /= gContext.mDisplayRatio;
segB.y /= gContext.mDisplayRatio;
vec_t segAOrtho = makeVect(-segA.y, segA.x);
segAOrtho.Normalize();
float dt = segAOrtho.Dot3(segB);
float surface = sqrtf(segA.x * segA.x + segA.y * segA.y) * fabsf(dt);
return surface;
}
inline vec_t PointOnSegment(const vec_t& point, const vec_t& vertPos1, const vec_t& vertPos2)
{
vec_t c = point - vertPos1;
vec_t V;
V.Normalize(vertPos2 - vertPos1);
float d = (vertPos2 - vertPos1).Length();
float t = V.Dot3(c);
if (t < 0.f)
{
return vertPos1;
}
if (t > d)
{
return vertPos2;
}
return vertPos1 + V * t;
}
static float IntersectRayPlane(const vec_t& rOrigin, const vec_t& rVector, const vec_t& plan)
{
const float numer = plan.Dot3(rOrigin) - plan.w;
const float denom = plan.Dot3(rVector);
if (fabsf(denom) < FLT_EPSILON) // normal is orthogonal to vector, cant intersect
{
return -1.0f;
}
return -(numer / denom);
}
static float DistanceToPlane(const vec_t& point, const vec_t& plan)
{
return plan.Dot3(point) + plan.w;
}
static bool IsInContextRect(ImVec2 p)
{
return IsWithin(p.x, gContext.mX, gContext.mXMax) && IsWithin(p.y, gContext.mY, gContext.mYMax);
}
static bool IsHoveringWindow()
{
ImGuiContext& g = *ImGui::GetCurrentContext();
ImGuiWindow* window = ImGui::FindWindowByName(gContext.mDrawList->_OwnerName);
if (g.HoveredWindow == window) // Mouse hovering drawlist window
return true;
if (g.HoveredWindow != NULL) // Any other window is hovered
return false;
if (ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max, false)) // Hovering drawlist window rect, while no other window is hovered (for _NoInputs windows)
return true;
return false;
}
void SetRect(float x, float y, float width, float height)
{
gContext.mX = x;
gContext.mY = y;
gContext.mWidth = width;
gContext.mHeight = height;
gContext.mXMax = gContext.mX + gContext.mWidth;
gContext.mYMax = gContext.mY + gContext.mXMax;
gContext.mDisplayRatio = width / height;
}
void SetOrthographic(bool isOrthographic)
{
gContext.mIsOrthographic = isOrthographic;
}
void SetDrawlist(ImDrawList* drawlist)
{
gContext.mDrawList = drawlist ? drawlist : ImGui::GetWindowDrawList();
}
void SetImGuiContext(ImGuiContext* ctx)
{
ImGui::SetCurrentContext(ctx);
}
void BeginFrame()
{
const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus;
#ifdef IMGUI_HAS_VIEWPORT
ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size);
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos);
#else
ImGuiIO& io = ImGui::GetIO();
ImGui::SetNextWindowSize(io.DisplaySize);
ImGui::SetNextWindowPos(ImVec2(0, 0));
#endif
ImGui::PushStyleColor(ImGuiCol_WindowBg, 0);
ImGui::PushStyleColor(ImGuiCol_Border, 0);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::Begin("gizmo", NULL, flags);
gContext.mDrawList = ImGui::GetWindowDrawList();
ImGui::End();
ImGui::PopStyleVar();
ImGui::PopStyleColor(2);
}
bool IsUsing()
{
return gContext.mbUsing || gContext.mbUsingBounds;
}
bool IsOver()
{
return (Intersects(gContext.mOperation, TRANSLATE) && GetMoveType(gContext.mOperation, NULL) != MT_NONE) ||
(Intersects(gContext.mOperation, ROTATE) && GetRotateType(gContext.mOperation) != MT_NONE) ||
(Intersects(gContext.mOperation, SCALE) && GetScaleType(gContext.mOperation) != MT_NONE) || IsUsing();
}
bool IsOver(OPERATION op)
{
if(IsUsing())
{
return true;
}
if(Intersects(op, SCALE) && GetScaleType(op) != MT_NONE)
{
return true;
}
if(Intersects(op, ROTATE) && GetRotateType(op) != MT_NONE)
{
return true;
}
if(Intersects(op, TRANSLATE) && GetMoveType(op, NULL) != MT_NONE)
{
return true;
}
return false;
}
void Enable(bool enable)
{
gContext.mbEnable = enable;
if (!enable)
{
gContext.mbUsing = false;
gContext.mbUsingBounds = false;
}
}
static void ComputeContext(const float* view, const float* projection, float* matrix, MODE mode)
{
gContext.mMode = mode;
gContext.mViewMat = *(matrix_t*)view;
gContext.mProjectionMat = *(matrix_t*)projection;
gContext.mbMouseOver = IsHoveringWindow();
gContext.mModelLocal = *(matrix_t*)matrix;
gContext.mModelLocal.OrthoNormalize();
if (mode == LOCAL)
{
gContext.mModel = gContext.mModelLocal;
}
else
{
gContext.mModel.Translation(((matrix_t*)matrix)->v.position);
}
gContext.mModelSource = *(matrix_t*)matrix;
gContext.mModelScaleOrigin.Set(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
gContext.mModelInverse.Inverse(gContext.mModel);
gContext.mModelSourceInverse.Inverse(gContext.mModelSource);
gContext.mViewProjection = gContext.mViewMat * gContext.mProjectionMat;
gContext.mMVP = gContext.mModel * gContext.mViewProjection;
gContext.mMVPLocal = gContext.mModelLocal * gContext.mViewProjection;
matrix_t viewInverse;
viewInverse.Inverse(gContext.mViewMat);
gContext.mCameraDir = viewInverse.v.dir;
gContext.mCameraEye = viewInverse.v.position;
gContext.mCameraRight = viewInverse.v.right;
gContext.mCameraUp = viewInverse.v.up;
// projection reverse
vec_t nearPos, farPos;
nearPos.Transform(makeVect(0, 0, 1.f, 1.f), gContext.mProjectionMat);
farPos.Transform(makeVect(0, 0, 2.f, 1.f), gContext.mProjectionMat);
gContext.mReversed = (nearPos.z/nearPos.w) > (farPos.z / farPos.w);
// compute scale from the size of camera right vector projected on screen at the matrix position
vec_t pointRight = viewInverse.v.right;
pointRight.TransformPoint(gContext.mViewProjection);
gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / (pointRight.x / pointRight.w - gContext.mMVP.v.position.x / gContext.mMVP.v.position.w);
vec_t rightViewInverse = viewInverse.v.right;
rightViewInverse.TransformVector(gContext.mModelInverse);
float rightLength = GetSegmentLengthClipSpace(makeVect(0.f, 0.f), rightViewInverse);
gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / rightLength;
ImVec2 centerSSpace = worldToPos(makeVect(0.f, 0.f), gContext.mMVP);
gContext.mScreenSquareCenter = centerSSpace;
gContext.mScreenSquareMin = ImVec2(centerSSpace.x - 10.f, centerSSpace.y - 10.f);
gContext.mScreenSquareMax = ImVec2(centerSSpace.x + 10.f, centerSSpace.y + 10.f);
ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector);
}
static void ComputeColors(ImU32* colors, int type, OPERATION operation)
{
if (gContext.mbEnable)
{
ImU32 selectionColor = GetColorU32(SELECTION);
switch (operation)
{
case TRANSLATE:
colors[0] = (type == MT_MOVE_SCREEN) ? selectionColor : IM_COL32_WHITE;
for (int i = 0; i < 3; i++)
{
colors[i + 1] = (type == (int)(MT_MOVE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
colors[i + 4] = (type == (int)(MT_MOVE_YZ + i)) ? selectionColor : GetColorU32(PLANE_X + i);
colors[i + 4] = (type == MT_MOVE_SCREEN) ? selectionColor : colors[i + 4];
}
break;
case ROTATE:
colors[0] = (type == MT_ROTATE_SCREEN) ? selectionColor : IM_COL32_WHITE;
for (int i = 0; i < 3; i++)
{
colors[i + 1] = (type == (int)(MT_ROTATE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
}
break;
case SCALEU:
case SCALE:
colors[0] = (type == MT_SCALE_XYZ) ? selectionColor : IM_COL32_WHITE;
for (int i = 0; i < 3; i++)
{
colors[i + 1] = (type == (int)(MT_SCALE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
}
break;
// note: this internal function is only called with three possible values for operation
default:
break;
}
}
else
{
ImU32 inactiveColor = GetColorU32(INACTIVE);
for (int i = 0; i < 7; i++)
{
colors[i] = inactiveColor;
}
}
}
static void ComputeTripodAxisAndVisibility(const int axisIndex, vec_t& dirAxis, vec_t& dirPlaneX, vec_t& dirPlaneY, bool& belowAxisLimit, bool& belowPlaneLimit, const bool localCoordinates = false)
{
dirAxis = directionUnary[axisIndex];
dirPlaneX = directionUnary[(axisIndex + 1) % 3];
dirPlaneY = directionUnary[(axisIndex + 2) % 3];
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
{
// when using, use stored factors so the gizmo doesn't flip when we translate
belowAxisLimit = gContext.mBelowAxisLimit[axisIndex];
belowPlaneLimit = gContext.mBelowPlaneLimit[axisIndex];
dirAxis *= gContext.mAxisFactor[axisIndex];
dirPlaneX *= gContext.mAxisFactor[(axisIndex + 1) % 3];
dirPlaneY *= gContext.mAxisFactor[(axisIndex + 2) % 3];
}
else
{
// new method
float lenDir = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis, localCoordinates);
float lenDirMinus = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirAxis, localCoordinates);
float lenDirPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneX, localCoordinates);
float lenDirMinusPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneX, localCoordinates);
float lenDirPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneY, localCoordinates);
float lenDirMinusPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneY, localCoordinates);
// For readability
bool & allowFlip = gContext.mAllowAxisFlip;
float mulAxis = (allowFlip && lenDir < lenDirMinus&& fabsf(lenDir - lenDirMinus) > FLT_EPSILON) ? -1.f : 1.f;
float mulAxisX = (allowFlip && lenDirPlaneX < lenDirMinusPlaneX&& fabsf(lenDirPlaneX - lenDirMinusPlaneX) > FLT_EPSILON) ? -1.f : 1.f;
float mulAxisY = (allowFlip && lenDirPlaneY < lenDirMinusPlaneY&& fabsf(lenDirPlaneY - lenDirMinusPlaneY) > FLT_EPSILON) ? -1.f : 1.f;
dirAxis *= mulAxis;
dirPlaneX *= mulAxisX;
dirPlaneY *= mulAxisY;
// for axis
float axisLengthInClipSpace = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis * gContext.mScreenFactor, localCoordinates);
float paraSurf = GetParallelogram(makeVect(0.f, 0.f, 0.f), dirPlaneX * gContext.mScreenFactor, dirPlaneY * gContext.mScreenFactor);
belowPlaneLimit = (paraSurf > 0.0025f);
belowAxisLimit = (axisLengthInClipSpace > 0.02f);
// and store values
gContext.mAxisFactor[axisIndex] = mulAxis;
gContext.mAxisFactor[(axisIndex + 1) % 3] = mulAxisX;
gContext.mAxisFactor[(axisIndex + 2) % 3] = mulAxisY;
gContext.mBelowAxisLimit[axisIndex] = belowAxisLimit;
gContext.mBelowPlaneLimit[axisIndex] = belowPlaneLimit;
}
}
static void ComputeSnap(float* value, float snap)
{
if (snap <= FLT_EPSILON)
{
return;
}
float modulo = fmodf(*value, snap);
float moduloRatio = fabsf(modulo) / snap;
if (moduloRatio < snapTension)
{
*value -= modulo;
}
else if (moduloRatio > (1.f - snapTension))
{
*value = *value - modulo + snap * ((*value < 0.f) ? -1.f : 1.f);
}
}
static void ComputeSnap(vec_t& value, const float* snap)
{
for (int i = 0; i < 3; i++)
{
ComputeSnap(&value[i], snap[i]);
}
}
static float ComputeAngleOnPlan()
{
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
vec_t perpendicularVector;
perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
perpendicularVector.Normalize();
float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -1.f, 1.f);
float angle = acosf(acosAngle);
angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;
return angle;
}
static void DrawRotationGizmo(OPERATION op, int type)
{
if(!Intersects(op, ROTATE))
{
return;
}
ImDrawList* drawList = gContext.mDrawList;
// colors
ImU32 colors[7];
ComputeColors(colors, type, ROTATE);
vec_t cameraToModelNormalized;
if (gContext.mIsOrthographic)
{
matrix_t viewInverse;
viewInverse.Inverse(*(matrix_t*)&gContext.mViewMat);
cameraToModelNormalized = -viewInverse.v.dir;
}
else
{
cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
}
cameraToModelNormalized.TransformVector(gContext.mModelInverse);
gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight;
bool hasRSC = Intersects(op, ROTATE_SCREEN);
for (int axis = 0; axis < 3; axis++)
{
if(!Intersects(op, static_cast(ROTATE_Z >> axis)))
{
continue;
}
const bool usingAxis = (gContext.mbUsing && type == MT_ROTATE_Z - axis);
const int circleMul = (hasRSC && !usingAxis ) ? 1 : 2;
ImVec2* circlePos = (ImVec2*)alloca(sizeof(ImVec2) * (circleMul * halfCircleSegmentCount + 1));
float angleStart = atan2f(cameraToModelNormalized[(4 - axis) % 3], cameraToModelNormalized[(3 - axis) % 3]) + ZPI * 0.5f;
for (int i = 0; i < circleMul * halfCircleSegmentCount + 1; i++)
{
float ng = angleStart + (float)circleMul * ZPI * ((float)i / (float)halfCircleSegmentCount);
vec_t axisPos = makeVect(cosf(ng), sinf(ng), 0.f);
vec_t pos = makeVect(axisPos[axis], axisPos[(axis + 1) % 3], axisPos[(axis + 2) % 3]) * gContext.mScreenFactor * rotationDisplayFactor;
circlePos[i] = worldToPos(pos, gContext.mMVP);
}
if (!gContext.mbUsing || usingAxis)
{
drawList->AddPolyline(circlePos, circleMul* halfCircleSegmentCount + 1, colors[3 - axis], false, gContext.mStyle.RotationLineThickness);
}
float radiusAxis = sqrtf((ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0])));
if (radiusAxis > gContext.mRadiusSquareCenter)
{
gContext.mRadiusSquareCenter = radiusAxis;
}
}
if(hasRSC && (!gContext.mbUsing || type == MT_ROTATE_SCREEN))
{
drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, gContext.mStyle.RotationOuterLineThickness);
}
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(type))
{
ImVec2 circlePos[halfCircleSegmentCount + 1];
circlePos[0] = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
for (unsigned int i = 1; i < halfCircleSegmentCount; i++)
{
float ng = gContext.mRotationAngle * ((float)(i - 1) / (float)(halfCircleSegmentCount - 1));
matrix_t rotateVectorMatrix;
rotateVectorMatrix.RotationAxis(gContext.mTranslationPlan, ng);
vec_t pos;
pos.TransformPoint(gContext.mRotationVectorSource, rotateVectorMatrix);
pos *= gContext.mScreenFactor * rotationDisplayFactor;
circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection);
}
drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, GetColorU32(ROTATION_USING_FILL));
drawList->AddPolyline(circlePos, halfCircleSegmentCount, GetColorU32(ROTATION_USING_BORDER), true, gContext.mStyle.RotationLineThickness);
ImVec2 destinationPosOnScreen = circlePos[1];
char tmps[512];
ImFormatString(tmps, sizeof(tmps), rotationInfoMask[type - MT_ROTATE_X], (gContext.mRotationAngle / ZPI) * 180.f, gContext.mRotationAngle);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
}
}
static void DrawHatchedAxis(const vec_t& axis)
{
if (gContext.mStyle.HatchedAxisLineThickness <= 0.0f)
{
return;
}
for (int j = 1; j < 10; j++)
{
ImVec2 baseSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2) * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2 + 1) * gContext.mScreenFactor, gContext.mMVP);
gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, GetColorU32(HATCHED_AXIS_LINES), gContext.mStyle.HatchedAxisLineThickness);
}
}
static void DrawScaleGizmo(OPERATION op, int type)
{
ImDrawList* drawList = gContext.mDrawList;
if(!Intersects(op, SCALE))
{
return;
}
// colors
ImU32 colors[7];
ComputeColors(colors, type, SCALE);
// draw
vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
{
scaleDisplay = gContext.mScale;
}
for (int i = 0; i < 3; i++)
{
if(!Intersects(op, static_cast(SCALE_X << i)))
{
continue;
}
const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);
if (!gContext.mbUsing || usingAxis)
{
vec_t dirPlaneX, dirPlaneY, dirAxis;
bool belowAxisLimit, belowPlaneLimit;
ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
// draw axis
if (belowAxisLimit)
{
bool hasTranslateOnAxis = Contains(op, static_cast(TRANSLATE_X << i));
float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVP);
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
{
ImU32 scaleLineColor = GetColorU32(SCALE_LINE);
drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, scaleLineColor, gContext.mStyle.ScaleLineThickness);
drawList->AddCircleFilled(worldDirSSpaceNoScale, gContext.mStyle.ScaleLineCircleSize, scaleLineColor);
}
if (!hasTranslateOnAxis || gContext.mbUsing)
{
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.ScaleLineThickness);
}
drawList->AddCircleFilled(worldDirSSpace, gContext.mStyle.ScaleLineCircleSize, colors[i + 1]);
if (gContext.mAxisFactor[i] < 0.f)
{
DrawHatchedAxis(dirAxis * scaleDisplay[i]);
}
}
}
}
// draw screen cirle
drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32);
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type))
{
//ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
/*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
dif.Normalize();
dif *= 5.f;
drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
*/
char tmps[512];
//vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
int componentInfoIndex = (type - MT_SCALE_X) * 3;
ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
}
}
static void DrawScaleUniveralGizmo(OPERATION op, int type)
{
ImDrawList* drawList = gContext.mDrawList;
if (!Intersects(op, SCALEU))
{
return;
}
// colors
ImU32 colors[7];
ComputeColors(colors, type, SCALEU);
// draw
vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
{
scaleDisplay = gContext.mScale;
}
for (int i = 0; i < 3; i++)
{
if (!Intersects(op, static_cast(SCALE_XU << i)))
{
continue;
}
const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);
if (!gContext.mbUsing || usingAxis)
{
vec_t dirPlaneX, dirPlaneY, dirAxis;
bool belowAxisLimit, belowPlaneLimit;
ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
// draw axis
if (belowAxisLimit)
{
bool hasTranslateOnAxis = Contains(op, static_cast(TRANSLATE_X << i));
float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
//ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
//ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVPLocal);
#if 0
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
{
drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, IM_COL32(0x40, 0x40, 0x40, 0xFF), 3.f);
drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, IM_COL32(0x40, 0x40, 0x40, 0xFF));
}
/*
if (!hasTranslateOnAxis || gContext.mbUsing)
{
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f);
}
*/
#endif
drawList->AddCircleFilled(worldDirSSpace, 12.f, colors[i + 1]);
}
}
}
// draw screen cirle
drawList->AddCircle(gContext.mScreenSquareCenter, 20.f, colors[0], 32, gContext.mStyle.CenterCircleSize);
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type))
{
//ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
/*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
dif.Normalize();
dif *= 5.f;
drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
*/
char tmps[512];
//vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
int componentInfoIndex = (type - MT_SCALE_X) * 3;
ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
}
}
static void DrawTranslationGizmo(OPERATION op, int type)
{
ImDrawList* drawList = gContext.mDrawList;
if (!drawList)
{
return;
}
if(!Intersects(op, TRANSLATE))
{
return;
}
// colors
ImU32 colors[7];
ComputeColors(colors, type, TRANSLATE);
const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
// draw
bool belowAxisLimit = false;
bool belowPlaneLimit = false;
for (int i = 0; i < 3; ++i)
{
vec_t dirPlaneX, dirPlaneY, dirAxis;
ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_X + i))
{
// draw axis
if (belowAxisLimit && Intersects(op, static_cast(TRANSLATE_X << i)))
{
ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace = worldToPos(dirAxis * gContext.mScreenFactor, gContext.mMVP);
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.TranslationLineThickness);
// Arrow head begin
ImVec2 dir(origin - worldDirSSpace);
float d = sqrtf(ImLengthSqr(dir));
dir /= d; // Normalize
dir *= gContext.mStyle.TranslationLineArrowSize;
ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector
ImVec2 a(worldDirSSpace + dir);
drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, a - ortogonalDir, colors[i + 1]);
// Arrow head end
if (gContext.mAxisFactor[i] < 0.f)
{
DrawHatchedAxis(dirAxis);
}
}
}
// draw plane
if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_YZ + i))
{
if (belowPlaneLimit && Contains(op, TRANSLATE_PLANS[i]))
{
ImVec2 screenQuadPts[4];
for (int j = 0; j < 4; ++j)
{
vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * quadUV[j * 2 + 1]) * gContext.mScreenFactor;
screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP);
}
drawList->AddPolyline(screenQuadPts, 4, GetColorU32(DIRECTION_X + i), true, 1.0f);
drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]);
}
}
}
drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32);
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(type))
{
ImU32 translationLineColor = GetColorU32(TRANSLATION_LINE);
ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
vec_t dif = { destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y, 0.f, 0.f };
dif.Normalize();
dif *= 5.f;
drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
char tmps[512];
vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
int componentInfoIndex = (type - MT_MOVE_X) * 3;
ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MT_MOVE_X], deltaInfo[translationInfoIndex[componentInfoIndex]], deltaInfo[translationInfoIndex[componentInfoIndex + 1]], deltaInfo[translationInfoIndex[componentInfoIndex + 2]]);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
}
}
static bool CanActivate()
{
if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive())
{
return true;
}
return false;
}
static void HandleAndDrawLocalBounds(const float* bounds, matrix_t* matrix, const float* snapValues, OPERATION operation)
{
ImGuiIO& io = ImGui::GetIO();
ImDrawList* drawList = gContext.mDrawList;
// compute best projection axis
vec_t axesWorldDirections[3];
vec_t bestAxisWorldDirection = { 0.0f, 0.0f, 0.0f, 0.0f };
int axes[3];
unsigned int numAxes = 1;
axes[0] = gContext.mBoundsBestAxis;
int bestAxis = axes[0];
if (!gContext.mbUsingBounds)
{
numAxes = 0;
float bestDot = 0.f;
for (int i = 0; i < 3; i++)
{
vec_t dirPlaneNormalWorld;
dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource);
dirPlaneNormalWorld.Normalize();
float dt = fabsf(Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld));
if (dt >= bestDot)
{
bestDot = dt;
bestAxis = i;
bestAxisWorldDirection = dirPlaneNormalWorld;
}
if (dt >= 0.1f)
{
axes[numAxes] = i;
axesWorldDirections[numAxes] = dirPlaneNormalWorld;
++numAxes;
}
}
}
if (numAxes == 0)
{
axes[0] = bestAxis;
axesWorldDirections[0] = bestAxisWorldDirection;
numAxes = 1;
}
else if (bestAxis != axes[0])
{
unsigned int bestIndex = 0;
for (unsigned int i = 0; i < numAxes; i++)
{
if (axes[i] == bestAxis)
{
bestIndex = i;
break;
}
}
int tempAxis = axes[0];
axes[0] = axes[bestIndex];
axes[bestIndex] = tempAxis;
vec_t tempDirection = axesWorldDirections[0];
axesWorldDirections[0] = axesWorldDirections[bestIndex];
axesWorldDirections[bestIndex] = tempDirection;
}
for (unsigned int axisIndex = 0; axisIndex < numAxes; ++axisIndex)
{
bestAxis = axes[axisIndex];
bestAxisWorldDirection = axesWorldDirections[axisIndex];
// corners
vec_t aabb[4];
int secondAxis = (bestAxis + 1) % 3;
int thirdAxis = (bestAxis + 2) % 3;
for (int i = 0; i < 4; i++)
{
aabb[i][3] = aabb[i][bestAxis] = 0.f;
aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)];
aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))];
}
// draw bounds
unsigned int anchorAlpha = gContext.mbEnable ? IM_COL32_BLACK : IM_COL32(0, 0, 0, 0x80);
matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection;
for (int i = 0; i < 4; i++)
{
ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP);
ImVec2 worldBound2 = worldToPos(aabb[(i + 1) % 4], boundsMVP);
if (!IsInContextRect(worldBound1) || !IsInContextRect(worldBound2))
{
continue;
}
float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2));
int stepCount = (int)(boundDistance / 10.f);
stepCount = min(stepCount, 1000);
for (int j = 0; j < stepCount; j++)
{
float stepLength = 1.f / (float)stepCount;
float t1 = (float)j * stepLength;
float t2 = (float)j * stepLength + stepLength * 0.5f;
ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1));
ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2));
//drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0, 0, 0, 0) + anchorAlpha, 3.f);
drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha, 2.f);
}
vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4]) * 0.5f;
ImVec2 midBound = worldToPos(midPoint, boundsMVP);
static const float AnchorBigRadius = 8.f;
static const float AnchorSmallRadius = 6.f;
bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius);
bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius);
int type = MT_NONE;
vec_t gizmoHitProportion;
if(Intersects(operation, TRANSLATE))
{
type = GetMoveType(operation, &gizmoHitProportion);
}
if(Intersects(operation, ROTATE) && type == MT_NONE)
{
type = GetRotateType(operation);
}
if(Intersects(operation, SCALE) && type == MT_NONE)
{
type = GetScaleType(operation);
}
if (type != MT_NONE)
{
overBigAnchor = false;
overSmallAnchor = false;
}
ImU32 selectionColor = GetColorU32(SELECTION);
unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha);
unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha);
drawList->AddCircleFilled(worldBound1, AnchorBigRadius, IM_COL32_BLACK);
drawList->AddCircleFilled(worldBound1, AnchorBigRadius - 1.2f, bigAnchorColor);
drawList->AddCircleFilled(midBound, AnchorSmallRadius, IM_COL32_BLACK);
drawList->AddCircleFilled(midBound, AnchorSmallRadius - 1.2f, smallAnchorColor);
int oppositeIndex = (i + 2) % 4;
// big anchor on corners
if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && CanActivate())
{
gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource);
gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource);
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
gContext.mBoundsBestAxis = bestAxis;
gContext.mBoundsAxis[0] = secondAxis;
gContext.mBoundsAxis[1] = thirdAxis;
gContext.mBoundsLocalPivot.Set(0.f);
gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis];
gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis];
gContext.mbUsingBounds = true;
gContext.mEditingID = gContext.mActualID;
gContext.mBoundsMatrix = gContext.mModelSource;
}
// small anchor on middle of segment
if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && CanActivate())
{
vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f;
gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource);
gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource);
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
gContext.mBoundsBestAxis = bestAxis;
int indices[] = { secondAxis , thirdAxis };
gContext.mBoundsAxis[0] = indices[i % 2];
gContext.mBoundsAxis[1] = -1;
gContext.mBoundsLocalPivot.Set(0.f);
gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
gContext.mbUsingBounds = true;
gContext.mEditingID = gContext.mActualID;
gContext.mBoundsMatrix = gContext.mModelSource;
}
}
if (gContext.mbUsingBounds && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
{
matrix_t scale;
scale.SetToIdentity();
// compute projected mouse position on plan
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan);
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
// compute a reference and delta vectors base on mouse move
vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs();
vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs();
// for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
for (int i = 0; i < 2; i++)
{
int axisIndex1 = gContext.mBoundsAxis[i];
if (axisIndex1 == -1)
{
continue;
}
float ratioAxis = 1.f;
vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex1].Abs();
float dtAxis = axisDir.Dot(referenceVector);
float boundSize = bounds[axisIndex1 + 3] - bounds[axisIndex1];
if (dtAxis > FLT_EPSILON)
{
ratioAxis = axisDir.Dot(deltaVector) / dtAxis;
}
if (snapValues)
{
float length = boundSize * ratioAxis;
ComputeSnap(&length, snapValues[axisIndex1]);
if (boundSize > FLT_EPSILON)
{
ratioAxis = length / boundSize;
}
}
scale.component[axisIndex1] *= ratioAxis;
}
// transform matrix
matrix_t preScale, postScale;
preScale.Translation(-gContext.mBoundsLocalPivot);
postScale.Translation(gContext.mBoundsLocalPivot);
matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix;
*matrix = res;
// info text
char tmps[512];
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z: %.2f"
, (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length()
, (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length()
, (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length()
);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
}
if (!io.MouseDown[0]) {
gContext.mbUsingBounds = false;
gContext.mEditingID = -1;
}
if (gContext.mbUsingBounds)
{
break;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
static int GetScaleType(OPERATION op)
{
if (gContext.mbUsing)
{
return MT_NONE;
}
ImGuiIO& io = ImGui::GetIO();
int type = MT_NONE;
// screen
if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&
io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&
Contains(op, SCALE))
{
type = MT_SCALE_XYZ;
}
// compute
for (int i = 0; i < 3 && type == MT_NONE; i++)
{
if(!Intersects(op, static_cast(SCALE_X << i)))
{
continue;
}
vec_t dirPlaneX, dirPlaneY, dirAxis;
bool belowAxisLimit, belowPlaneLimit;
ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
dirAxis.TransformVector(gContext.mModelLocal);
dirPlaneX.TransformVector(gContext.mModelLocal);
dirPlaneY.TransformVector(gContext.mModelLocal);
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModelLocal.v.position, dirAxis));
vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
const float startOffset = Contains(op, static_cast(TRANSLATE_X << i)) ? 1.0f : 0.1f;
const float endOffset = Contains(op, static_cast(TRANSLATE_X << i)) ? 1.4f : 1.0f;
const ImVec2 posOnPlanScreen = worldToPos(posOnPlan, gContext.mViewProjection);
const ImVec2 axisStartOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * startOffset, gContext.mViewProjection);
const ImVec2 axisEndOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * endOffset, gContext.mViewProjection);
vec_t closestPointOnAxis = PointOnSegment(makeVect(posOnPlanScreen), makeVect(axisStartOnScreen), makeVect(axisEndOnScreen));
if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size
{
type = MT_SCALE_X + i;
}
}
// universal
vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
float dist = deltaScreen.Length();
if (Contains(op, SCALEU) && dist >= 17.0f && dist < 23.0f)
{
type = MT_SCALE_XYZ;
}
for (int i = 0; i < 3 && type == MT_NONE; i++)
{
if (!Intersects(op, static_cast(SCALE_XU << i)))
{
continue;
}
vec_t dirPlaneX, dirPlaneY, dirAxis;
bool belowAxisLimit, belowPlaneLimit;
ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
// draw axis
if (belowAxisLimit)
{
bool hasTranslateOnAxis = Contains(op, static_cast(TRANSLATE_X << i));
float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
//ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
//ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale) * gContext.mScreenFactor, gContext.mMVPLocal);
float distance = sqrtf(ImLengthSqr(worldDirSSpace - io.MousePos));
if (distance < 12.f)
{
type = MT_SCALE_X + i;
}
}
}
return type;
}
static int GetRotateType(OPERATION op)
{
if (gContext.mbUsing)
{
return MT_NONE;
}
ImGuiIO& io = ImGui::GetIO();
int type = MT_NONE;
vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
float dist = deltaScreen.Length();
if (Intersects(op, ROTATE_SCREEN) && dist >= (gContext.mRadiusSquareCenter - 4.0f) && dist < (gContext.mRadiusSquareCenter + 4.0f))
{
type = MT_ROTATE_SCREEN;
}
const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir };
vec_t modelViewPos;
modelViewPos.TransformPoint(gContext.mModel.v.position, gContext.mViewMat);
for (int i = 0; i < 3 && type == MT_NONE; i++)
{
if(!Intersects(op, static_cast(ROTATE_X << i)))
{
continue;
}
// pickup plan
vec_t pickupPlan = BuildPlan(gContext.mModel.v.position, planNormals[i]);
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan);
const vec_t intersectWorldPos = gContext.mRayOrigin + gContext.mRayVector * len;
vec_t intersectViewPos;
intersectViewPos.TransformPoint(intersectWorldPos, gContext.mViewMat);
if (ImAbs(modelViewPos.z) - ImAbs(intersectViewPos.z) < -FLT_EPSILON)
{
continue;
}
const vec_t localPos = intersectWorldPos - gContext.mModel.v.position;
vec_t idealPosOnCircle = Normalized(localPos);
idealPosOnCircle.TransformVector(gContext.mModelInverse);
const ImVec2 idealPosOnCircleScreen = worldToPos(idealPosOnCircle * rotationDisplayFactor * gContext.mScreenFactor, gContext.mMVP);
//gContext.mDrawList->AddCircle(idealPosOnCircleScreen, 5.f, IM_COL32_WHITE);
const ImVec2 distanceOnScreen = idealPosOnCircleScreen - io.MousePos;
const float distance = makeVect(distanceOnScreen).Length();
if (distance < 8.f) // pixel size
{
type = MT_ROTATE_X + i;
}
}
return type;
}
static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion)
{
if(!Intersects(op, TRANSLATE) || gContext.mbUsing || !gContext.mbMouseOver)
{
return MT_NONE;
}
ImGuiIO& io = ImGui::GetIO();
int type = MT_NONE;
// screen
if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&
io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&
Contains(op, TRANSLATE))
{
type = MT_MOVE_SCREEN;
}
const vec_t screenCoord = makeVect(io.MousePos - ImVec2(gContext.mX, gContext.mY));
// compute
for (int i = 0; i < 3 && type == MT_NONE; i++)
{
vec_t dirPlaneX, dirPlaneY, dirAxis;
bool belowAxisLimit, belowPlaneLimit;
ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
dirAxis.TransformVector(gContext.mModel);
dirPlaneX.TransformVector(gContext.mModel);
dirPlaneY.TransformVector(gContext.mModel);
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, dirAxis));
vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
const ImVec2 axisStartOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor * 0.1f, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);
const ImVec2 axisEndOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);
vec_t closestPointOnAxis = PointOnSegment(screenCoord, makeVect(axisStartOnScreen), makeVect(axisEndOnScreen));
if ((closestPointOnAxis - screenCoord).Length() < 12.f && Intersects(op, static_cast(TRANSLATE_X << i))) // pixel size
{
type = MT_MOVE_X + i;
}
const float dx = dirPlaneX.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
const float dy = dirPlaneY.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
if (belowPlaneLimit && dx >= quadUV[0] && dx <= quadUV[4] && dy >= quadUV[1] && dy <= quadUV[3] && Contains(op, TRANSLATE_PLANS[i]))
{
type = MT_MOVE_YZ + i;
}
if (gizmoHitProportion)
{
*gizmoHitProportion = makeVect(dx, dy, 0.f);
}
}
return type;
}
static bool HandleTranslation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
{
if(!Intersects(op, TRANSLATE) || type != MT_NONE)
{
return false;
}
const ImGuiIO& io = ImGui::GetIO();
const bool applyRotationLocaly = gContext.mMode == LOCAL || type == MT_MOVE_SCREEN;
bool modified = false;
// move
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(gContext.mCurrentOperation))
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
const float signedLength = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
const float len = fabsf(signedLength); // near plan
const vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
// compute delta
const vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
vec_t delta = newOrigin - gContext.mModel.v.position;
// 1 axis constraint
if (gContext.mCurrentOperation >= MT_MOVE_X && gContext.mCurrentOperation <= MT_MOVE_Z)
{
const int axisIndex = gContext.mCurrentOperation - MT_MOVE_X;
const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex];
const float lengthOnAxis = Dot(axisValue, delta);
delta = axisValue * lengthOnAxis;
}
// snap
if (snap)
{
vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin;
if (applyRotationLocaly)
{
matrix_t modelSourceNormalized = gContext.mModelSource;
modelSourceNormalized.OrthoNormalize();
matrix_t modelSourceNormalizedInverse;
modelSourceNormalizedInverse.Inverse(modelSourceNormalized);
cumulativeDelta.TransformVector(modelSourceNormalizedInverse);
ComputeSnap(cumulativeDelta, snap);
cumulativeDelta.TransformVector(modelSourceNormalized);
}
else
{
ComputeSnap(cumulativeDelta, snap);
}
delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position;
}
if (delta != gContext.mTranslationLastDelta)
{
modified = true;
}
gContext.mTranslationLastDelta = delta;
// compute matrix & delta
matrix_t deltaMatrixTranslation;
deltaMatrixTranslation.Translation(delta);
if (deltaMatrix)
{
memcpy(deltaMatrix, deltaMatrixTranslation.m16, sizeof(float) * 16);
}
const matrix_t res = gContext.mModelSource * deltaMatrixTranslation;
*(matrix_t*)matrix = res;
if (!io.MouseDown[0])
{
gContext.mbUsing = false;
}
type = gContext.mCurrentOperation;
}
else
{
// find new possible way to move
vec_t gizmoHitProportion;
type = GetMoveType(op, &gizmoHitProportion);
if (type != MT_NONE)
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
}
if (CanActivate() && type != MT_NONE)
{
gContext.mbUsing = true;
gContext.mEditingID = gContext.mActualID;
gContext.mCurrentOperation = type;
vec_t movePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,
gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,
-gContext.mCameraDir };
vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
for (unsigned int i = 0; i < 3; i++)
{
vec_t orthoVector = Cross(movePlanNormal[i], cameraToModelNormalized);
movePlanNormal[i].Cross(orthoVector);
movePlanNormal[i].Normalize();
}
// pickup plan
gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_MOVE_X]);
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
gContext.mMatrixOrigin = gContext.mModel.v.position;
gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
}
}
return modified;
}
static bool HandleScale(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
{
if((!Intersects(op, SCALE) && !Intersects(op, SCALEU)) || type != MT_NONE || !gContext.mbMouseOver)
{
return false;
}
ImGuiIO& io = ImGui::GetIO();
bool modified = false;
if (!gContext.mbUsing)
{
// find new possible way to scale
type = GetScaleType(op);
if (type != MT_NONE)
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
}
if (CanActivate() && type != MT_NONE)
{
gContext.mbUsing = true;
gContext.mEditingID = gContext.mActualID;
gContext.mCurrentOperation = type;
const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.up, gContext.mModel.v.right, -gContext.mCameraDir };
// pickup plan
gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_SCALE_X]);
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
gContext.mMatrixOrigin = gContext.mModel.v.position;
gContext.mScale.Set(1.f, 1.f, 1.f);
gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
gContext.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
gContext.mSaveMousePosx = io.MousePos.x;
}
}
// scale
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(gContext.mCurrentOperation))
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
vec_t delta = newOrigin - gContext.mModelLocal.v.position;
// 1 axis constraint
if (gContext.mCurrentOperation >= MT_SCALE_X && gContext.mCurrentOperation <= MT_SCALE_Z)
{
int axisIndex = gContext.mCurrentOperation - MT_SCALE_X;
const vec_t& axisValue = *(vec_t*)&gContext.mModelLocal.m[axisIndex];
float lengthOnAxis = Dot(axisValue, delta);
delta = axisValue * lengthOnAxis;
vec_t baseVector = gContext.mTranslationPlanOrigin - gContext.mModelLocal.v.position;
float ratio = Dot(axisValue, baseVector + delta) / Dot(axisValue, baseVector);
gContext.mScale[axisIndex] = max(ratio, 0.001f);
}
else
{
float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f;
gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));
}
// snap
if (snap)
{
float scaleSnap[] = { snap[0], snap[0], snap[0] };
ComputeSnap(gContext.mScale, scaleSnap);
}
// no 0 allowed
for (int i = 0; i < 3; i++)
gContext.mScale[i] = max(gContext.mScale[i], 0.001f);
if (gContext.mScaleLast != gContext.mScale)
{
modified = true;
}
gContext.mScaleLast = gContext.mScale;
// compute matrix & delta
matrix_t deltaMatrixScale;
deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin);
matrix_t res = deltaMatrixScale * gContext.mModelLocal;
*(matrix_t*)matrix = res;
if (deltaMatrix)
{
vec_t deltaScale = gContext.mScale * gContext.mScaleValueOrigin;
vec_t originalScaleDivider;
originalScaleDivider.x = 1 / gContext.mModelScaleOrigin.x;
originalScaleDivider.y = 1 / gContext.mModelScaleOrigin.y;
originalScaleDivider.z = 1 / gContext.mModelScaleOrigin.z;
deltaScale = deltaScale * originalScaleDivider;
deltaMatrixScale.Scale(deltaScale);
memcpy(deltaMatrix, deltaMatrixScale.m16, sizeof(float) * 16);
}
if (!io.MouseDown[0])
{
gContext.mbUsing = false;
gContext.mScale.Set(1.f, 1.f, 1.f);
}
type = gContext.mCurrentOperation;
}
return modified;
}
static bool HandleRotation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
{
if(!Intersects(op, ROTATE) || type != MT_NONE || !gContext.mbMouseOver)
{
return false;
}
ImGuiIO& io = ImGui::GetIO();
bool applyRotationLocaly = gContext.mMode == LOCAL;
bool modified = false;
if (!gContext.mbUsing)
{
type = GetRotateType(op);
if (type != MT_NONE)
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
}
if (type == MT_ROTATE_SCREEN)
{
applyRotationLocaly = true;
}
if (CanActivate() && type != MT_NONE)
{
gContext.mbUsing = true;
gContext.mEditingID = gContext.mActualID;
gContext.mCurrentOperation = type;
const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir };
// pickup plan
if (applyRotationLocaly)
{
gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, rotatePlanNormal[type - MT_ROTATE_X]);
}
else
{
gContext.mTranslationPlan = BuildPlan(gContext.mModelSource.v.position, directionUnary[type - MT_ROTATE_X]);
}
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position;
gContext.mRotationVectorSource = Normalized(localPos);
gContext.mRotationAngleOrigin = ComputeAngleOnPlan();
}
}
// rotation
if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(gContext.mCurrentOperation))
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
gContext.mRotationAngle = ComputeAngleOnPlan();
if (snap)
{
float snapInRadian = snap[0] * DEG2RAD;
ComputeSnap(&gContext.mRotationAngle, snapInRadian);
}
vec_t rotationAxisLocalSpace;
rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);
rotationAxisLocalSpace.Normalize();
matrix_t deltaRotation;
deltaRotation.RotationAxis(rotationAxisLocalSpace, gContext.mRotationAngle - gContext.mRotationAngleOrigin);
if (gContext.mRotationAngle != gContext.mRotationAngleOrigin)
{
modified = true;
}
gContext.mRotationAngleOrigin = gContext.mRotationAngle;
matrix_t scaleOrigin;
scaleOrigin.Scale(gContext.mModelScaleOrigin);
if (applyRotationLocaly)
{
*(matrix_t*)matrix = scaleOrigin * deltaRotation * gContext.mModelLocal;
}
else
{
matrix_t res = gContext.mModelSource;
res.v.position.Set(0.f);
*(matrix_t*)matrix = res * deltaRotation;
((matrix_t*)matrix)->v.position = gContext.mModelSource.v.position;
}
if (deltaMatrix)
{
*(matrix_t*)deltaMatrix = gContext.mModelInverse * deltaRotation * gContext.mModel;
}
if (!io.MouseDown[0])
{
gContext.mbUsing = false;
gContext.mEditingID = -1;
}
type = gContext.mCurrentOperation;
}
return modified;
}
void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale)
{
matrix_t mat = *(matrix_t*)matrix;
scale[0] = mat.v.right.Length();
scale[1] = mat.v.up.Length();
scale[2] = mat.v.dir.Length();
mat.OrthoNormalize();
rotation[0] = RAD2DEG * atan2f(mat.m[1][2], mat.m[2][2]);
rotation[1] = RAD2DEG * atan2f(-mat.m[0][2], sqrtf(mat.m[1][2] * mat.m[1][2] + mat.m[2][2] * mat.m[2][2]));
rotation[2] = RAD2DEG * atan2f(mat.m[0][1], mat.m[0][0]);
translation[0] = mat.v.position.x;
translation[1] = mat.v.position.y;
translation[2] = mat.v.position.z;
}
void RecomposeMatrixFromComponents(const float* translation, const float* rotation, const float* scale, float* matrix)
{
matrix_t& mat = *(matrix_t*)matrix;
matrix_t rot[3];
for (int i = 0; i < 3; i++)
{
rot[i].RotationAxis(directionUnary[i], rotation[i] * DEG2RAD);
}
mat = rot[0] * rot[1] * rot[2];
float validScale[3];
for (int i = 0; i < 3; i++)
{
if (fabsf(scale[i]) < FLT_EPSILON)
{
validScale[i] = 0.001f;
}
else
{
validScale[i] = scale[i];
}
}
mat.v.right *= validScale[0];
mat.v.up *= validScale[1];
mat.v.dir *= validScale[2];
mat.v.position.Set(translation[0], translation[1], translation[2], 1.f);
}
void SetID(int id)
{
gContext.mActualID = id;
}
void AllowAxisFlip(bool value)
{
gContext.mAllowAxisFlip = value;
}
bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix, const float* snap, const float* localBounds, const float* boundsSnap)
{
// Scale is always local or matrix will be skewed when applying world scale or oriented matrix
ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode);
// set delta to identity
if (deltaMatrix)
{
((matrix_t*)deltaMatrix)->SetToIdentity();
}
// behind camera
vec_t camSpacePosition;
camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mMVP);
if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f)
{
return false;
}
// --
int type = MT_NONE;
bool manipulated = false;
if (gContext.mbEnable)
{
if (!gContext.mbUsingBounds)
{
manipulated = HandleTranslation(matrix, deltaMatrix, operation, type, snap) ||
HandleScale(matrix, deltaMatrix, operation, type, snap) ||
HandleRotation(matrix, deltaMatrix, operation, type, snap);
}
}
if (localBounds && !gContext.mbUsing)
{
HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap, operation);
}
gContext.mOperation = operation;
if (!gContext.mbUsingBounds)
{
DrawRotationGizmo(operation, type);
DrawTranslationGizmo(operation, type);
DrawScaleGizmo(operation, type);
DrawScaleUniveralGizmo(operation, type);
}
return manipulated;
}
void SetGizmoSizeClipSpace(float value)
{
gContext.mGizmoSizeClipSpace = value;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeFrustumPlanes(vec_t* frustum, const float* clip)
{
frustum[0].x = clip[3] - clip[0];
frustum[0].y = clip[7] - clip[4];
frustum[0].z = clip[11] - clip[8];
frustum[0].w = clip[15] - clip[12];
frustum[1].x = clip[3] + clip[0];
frustum[1].y = clip[7] + clip[4];
frustum[1].z = clip[11] + clip[8];
frustum[1].w = clip[15] + clip[12];
frustum[2].x = clip[3] + clip[1];
frustum[2].y = clip[7] + clip[5];
frustum[2].z = clip[11] + clip[9];
frustum[2].w = clip[15] + clip[13];
frustum[3].x = clip[3] - clip[1];
frustum[3].y = clip[7] - clip[5];
frustum[3].z = clip[11] - clip[9];
frustum[3].w = clip[15] - clip[13];
frustum[4].x = clip[3] - clip[2];
frustum[4].y = clip[7] - clip[6];
frustum[4].z = clip[11] - clip[10];
frustum[4].w = clip[15] - clip[14];
frustum[5].x = clip[3] + clip[2];
frustum[5].y = clip[7] + clip[6];
frustum[5].z = clip[11] + clip[10];
frustum[5].w = clip[15] + clip[14];
for (int i = 0; i < 6; i++)
{
frustum[i].Normalize();
}
}
void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount)
{
matrix_t viewInverse;
viewInverse.Inverse(*(matrix_t*)view);
struct CubeFace
{
float z;
ImVec2 faceCoordsScreen[4];
ImU32 color;
};
CubeFace* faces = (CubeFace*)_malloca(sizeof(CubeFace) * matrixCount * 6);
if (!faces)
{
return;
}
vec_t frustum[6];
matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection;
ComputeFrustumPlanes(frustum, viewProjection.m16);
int cubeFaceCount = 0;
for (int cube = 0; cube < matrixCount; cube++)
{
const float* matrix = &matrices[cube * 16];
matrix_t res = *(matrix_t*)matrix * *(matrix_t*)view * *(matrix_t*)projection;
for (int iFace = 0; iFace < 6; iFace++)
{
const int normalIndex = (iFace % 3);
const int perpXIndex = (normalIndex + 1) % 3;
const int perpYIndex = (normalIndex + 2) % 3;
const float invert = (iFace > 2) ? -1.f : 1.f;
const vec_t faceCoords[4] = { directionUnary[normalIndex] + directionUnary[perpXIndex] + directionUnary[perpYIndex],
directionUnary[normalIndex] + directionUnary[perpXIndex] - directionUnary[perpYIndex],
directionUnary[normalIndex] - directionUnary[perpXIndex] - directionUnary[perpYIndex],
directionUnary[normalIndex] - directionUnary[perpXIndex] + directionUnary[perpYIndex],
};
// clipping
/*
bool skipFace = false;
for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
{
vec_t camSpacePosition;
camSpacePosition.TransformPoint(faceCoords[iCoord] * 0.5f * invert, res);
if (camSpacePosition.z < 0.001f)
{
skipFace = true;
break;
}
}
if (skipFace)
{
continue;
}
*/
vec_t centerPosition, centerPositionVP;
centerPosition.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, *(matrix_t*)matrix);
centerPositionVP.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, res);
bool inFrustum = true;
for (int iFrustum = 0; iFrustum < 6; iFrustum++)
{
float dist = DistanceToPlane(centerPosition, frustum[iFrustum]);
if (dist < 0.f)
{
inFrustum = false;
break;
}
}
if (!inFrustum)
{
continue;
}
CubeFace& cubeFace = faces[cubeFaceCount];
// 3D->2D
//ImVec2 faceCoordsScreen[4];
for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
{
cubeFace.faceCoordsScreen[iCoord] = worldToPos(faceCoords[iCoord] * 0.5f * invert, res);
}
ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex);
cubeFace.color = directionColor | IM_COL32(0x80, 0x80, 0x80, 0);
cubeFace.z = centerPositionVP.z / centerPositionVP.w;
cubeFaceCount++;
}
}
qsort(faces, cubeFaceCount, sizeof(CubeFace), [](void const* _a, void const* _b) {
CubeFace* a = (CubeFace*)_a;
CubeFace* b = (CubeFace*)_b;
if (a->z < b->z)
{
return 1;
}
return -1;
});
// draw face with lighter color
for (int iFace = 0; iFace < cubeFaceCount; iFace++)
{
const CubeFace& cubeFace = faces[iFace];
gContext.mDrawList->AddConvexPolyFilled(cubeFace.faceCoordsScreen, 4, cubeFace.color);
}
_freea(faces);
}
void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize)
{
matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection;
vec_t frustum[6];
ComputeFrustumPlanes(frustum, viewProjection.m16);
matrix_t res = *(matrix_t*)matrix * viewProjection;
for (float f = -gridSize; f <= gridSize; f += 1.f)
{
for (int dir = 0; dir < 2; dir++)
{
vec_t ptA = makeVect(dir ? -gridSize : f, 0.f, dir ? f : -gridSize);
vec_t ptB = makeVect(dir ? gridSize : f, 0.f, dir ? f : gridSize);
bool visible = true;
for (int i = 0; i < 6; i++)
{
float dA = DistanceToPlane(ptA, frustum[i]);
float dB = DistanceToPlane(ptB, frustum[i]);
if (dA < 0.f && dB < 0.f)
{
visible = false;
break;
}
if (dA > 0.f && dB > 0.f)
{
continue;
}
if (dA < 0.f)
{
float len = fabsf(dA - dB);
float t = fabsf(dA) / len;
ptA.Lerp(ptB, t);
}
if (dB < 0.f)
{
float len = fabsf(dB - dA);
float t = fabsf(dB) / len;
ptB.Lerp(ptA, t);
}
}
if (visible)
{
ImU32 col = IM_COL32(0x80, 0x80, 0x80, 0xFF);
col = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? IM_COL32(0x90, 0x90, 0x90, 0xFF) : col;
col = (fabsf(f) < FLT_EPSILON) ? IM_COL32(0x40, 0x40, 0x40, 0xFF): col;
float thickness = 1.f;
thickness = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? 1.5f : thickness;
thickness = (fabsf(f) < FLT_EPSILON) ? 2.3f : thickness;
gContext.mDrawList->AddLine(worldToPos(ptA, res), worldToPos(ptB, res), col, thickness);
}
}
}
}
void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor)
{
// Scale is always local or matrix will be skewed when applying world scale or oriented matrix
ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode);
ViewManipulate(view, length, position, size, backgroundColor);
}
void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor)
{
static bool isDraging = false;
static bool isClicking = false;
static bool isInside = false;
static vec_t interpolationUp;
static vec_t interpolationDir;
static int interpolationFrames = 0;
const vec_t referenceUp = makeVect(0.f, 1.f, 0.f);
matrix_t svgView, svgProjection;
svgView = gContext.mViewMat;
svgProjection = gContext.mProjectionMat;
ImGuiIO& io = ImGui::GetIO();
gContext.mDrawList->AddRectFilled(position, position + size, backgroundColor);
matrix_t viewInverse;
viewInverse.Inverse(*(matrix_t*)view);
const vec_t camTarget = viewInverse.v.position - viewInverse.v.dir * length;
// view/projection matrices
const float distance = 3.f;
matrix_t cubeProjection, cubeView;
float fov = acosf(distance / (sqrtf(distance * distance + 3.f))) * RAD2DEG;
Perspective(fov / sqrtf(2.f), size.x / size.y, 0.01f, 1000.f, cubeProjection.m16);
vec_t dir = makeVect(viewInverse.m[2][0], viewInverse.m[2][1], viewInverse.m[2][2]);
vec_t up = makeVect(viewInverse.m[1][0], viewInverse.m[1][1], viewInverse.m[1][2]);
vec_t eye = dir * distance;
vec_t zero = makeVect(0.f, 0.f);
LookAt(&eye.x, &zero.x, &up.x, cubeView.m16);
// set context
gContext.mViewMat = cubeView;
gContext.mProjectionMat = cubeProjection;
ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector, position, size);
const matrix_t res = cubeView * cubeProjection;
// panels
static const ImVec2 panelPosition[9] = { ImVec2(0.75f,0.75f), ImVec2(0.25f, 0.75f), ImVec2(0.f, 0.75f),
ImVec2(0.75f, 0.25f), ImVec2(0.25f, 0.25f), ImVec2(0.f, 0.25f),
ImVec2(0.75f, 0.f), ImVec2(0.25f, 0.f), ImVec2(0.f, 0.f) };
static const ImVec2 panelSize[9] = { ImVec2(0.25f,0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f),
ImVec2(0.25f, 0.5f), ImVec2(0.5f, 0.5f), ImVec2(0.25f, 0.5f),
ImVec2(0.25f, 0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f) };
// tag faces
bool boxes[27]{};
static int overBox = -1;
for (int iPass = 0; iPass < 2; iPass++)
{
for (int iFace = 0; iFace < 6; iFace++)
{
const int normalIndex = (iFace % 3);
const int perpXIndex = (normalIndex + 1) % 3;
const int perpYIndex = (normalIndex + 2) % 3;
const float invert = (iFace > 2) ? -1.f : 1.f;
const vec_t indexVectorX = directionUnary[perpXIndex] * invert;
const vec_t indexVectorY = directionUnary[perpYIndex] * invert;
const vec_t boxOrigin = directionUnary[normalIndex] * -invert - indexVectorX - indexVectorY;
// plan local space
const vec_t n = directionUnary[normalIndex] * invert;
vec_t viewSpaceNormal = n;
vec_t viewSpacePoint = n * 0.5f;
viewSpaceNormal.TransformVector(cubeView);
viewSpaceNormal.Normalize();
viewSpacePoint.TransformPoint(cubeView);
const vec_t viewSpaceFacePlan = BuildPlan(viewSpacePoint, viewSpaceNormal);
// back face culling
if (viewSpaceFacePlan.w > 0.f)
{
continue;
}
const vec_t facePlan = BuildPlan(n * 0.5f, n);
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, facePlan);
vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len - (n * 0.5f);
float localx = Dot(directionUnary[perpXIndex], posOnPlan) * invert + 0.5f;
float localy = Dot(directionUnary[perpYIndex], posOnPlan) * invert + 0.5f;
// panels
const vec_t dx = directionUnary[perpXIndex];
const vec_t dy = directionUnary[perpYIndex];
const vec_t origin = directionUnary[normalIndex] - dx - dy;
for (int iPanel = 0; iPanel < 9; iPanel++)
{
vec_t boxCoord = boxOrigin + indexVectorX * float(iPanel % 3) + indexVectorY * float(iPanel / 3) + makeVect(1.f, 1.f, 1.f);
const ImVec2 p = panelPosition[iPanel] * 2.f;
const ImVec2 s = panelSize[iPanel] * 2.f;
ImVec2 faceCoordsScreen[4];
vec_t panelPos[4] = { dx * p.x + dy * p.y,
dx * p.x + dy * (p.y + s.y),
dx * (p.x + s.x) + dy * (p.y + s.y),
dx * (p.x + s.x) + dy * p.y };
for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
{
faceCoordsScreen[iCoord] = worldToPos((panelPos[iCoord] + origin) * 0.5f * invert, res, position, size);
}
const ImVec2 panelCorners[2] = { panelPosition[iPanel], panelPosition[iPanel] + panelSize[iPanel] };
bool insidePanel = localx > panelCorners[0].x && localx < panelCorners[1].x && localy > panelCorners[0].y && localy < panelCorners[1].y;
int boxCoordInt = int(boxCoord.x * 9.f + boxCoord.y * 3.f + boxCoord.z);
IM_ASSERT(boxCoordInt < 27);
boxes[boxCoordInt] |= insidePanel && (!isDraging) && gContext.mbMouseOver;
// draw face with lighter color
if (iPass)
{
ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex);
gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, (directionColor | IM_COL32(0x80, 0x80, 0x80, 0x80)) | (isInside ? IM_COL32(0x08, 0x08, 0x08, 0) : 0));
if (boxes[boxCoordInt])
{
gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, IM_COL32(0xF0, 0xA0, 0x60, 0x80));
if (io.MouseDown[0] && !isClicking && !isDraging) {
overBox = boxCoordInt;
isClicking = true;
isDraging = true;
}
}
}
}
}
}
if (interpolationFrames)
{
interpolationFrames--;
vec_t newDir = viewInverse.v.dir;
newDir.Lerp(interpolationDir, 0.2f);
newDir.Normalize();
vec_t newUp = viewInverse.v.up;
newUp.Lerp(interpolationUp, 0.3f);
newUp.Normalize();
newUp = interpolationUp;
vec_t newEye = camTarget + newDir * length;
LookAt(&newEye.x, &camTarget.x, &newUp.x, view);
}
isInside = gContext.mbMouseOver && ImRect(position, position + size).Contains(io.MousePos);
if (io.MouseDown[0] && (fabsf(io.MouseDelta[0]) || fabsf(io.MouseDelta[1])) && isClicking)
{
isClicking = false;
}
if (!io.MouseDown[0])
{
if (isClicking)
{
// apply new view direction
int cx = overBox / 9;
int cy = (overBox - cx * 9) / 3;
int cz = overBox % 3;
interpolationDir = makeVect(1.f - (float)cx, 1.f - (float)cy, 1.f - (float)cz);
interpolationDir.Normalize();
if (fabsf(Dot(interpolationDir, referenceUp)) > 1.0f - 0.01f)
{
vec_t right = viewInverse.v.right;
if (fabsf(right.x) > fabsf(right.z))
{
right.z = 0.f;
}
else
{
right.x = 0.f;
}
right.Normalize();
interpolationUp = Cross(interpolationDir, right);
interpolationUp.Normalize();
}
else
{
interpolationUp = referenceUp;
}
interpolationFrames = 40;
}
isClicking = false;
isDraging = false;
}
if (isDraging)
{
matrix_t rx, ry, roll;
rx.RotationAxis(referenceUp, -io.MouseDelta.x * 0.01f);
ry.RotationAxis(viewInverse.v.right, -io.MouseDelta.y * 0.01f);
roll = rx * ry;
vec_t newDir = viewInverse.v.dir;
newDir.TransformVector(roll);
newDir.Normalize();
// clamp
vec_t planDir = Cross(viewInverse.v.right, referenceUp);
planDir.y = 0.f;
planDir.Normalize();
float dt = Dot(planDir, newDir);
if (dt < 0.0f)
{
newDir += planDir * dt;
newDir.Normalize();
}
vec_t newEye = camTarget + newDir * length;
LookAt(&newEye.x, &camTarget.x, &referenceUp.x, view);
}
// restore view/projection because it was used to compute ray
ComputeContext(svgView.m16, svgProjection.m16, gContext.mModelSource.m16, gContext.mMode);
}
};
================================================
FILE: Source/External/imgui_tools/imguizmo/ImGuizmo.h
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -------------------------------------------------------------------------------------------
// History :
// 2019/11/03 View gizmo
// 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by source matrix scales. local/world rotation and translation fixed. Display message is incorrect (X: ... Y:...) in local mode.
// 2016/09/09 Hatched negative axis. Snapping. Documentation update.
// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved
// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results.
// 2016/08/31 First version
//
// -------------------------------------------------------------------------------------------
// Future (no order):
//
// - Multi view
// - display rotation/translation/scale infos in local/world space and not only local
// - finish local/world matrix application
// - OPERATION as bitmask
//
// -------------------------------------------------------------------------------------------
// Example
#if 0
void EditTransform(const Camera& camera, matrix_t& matrix)
{
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);
if (ImGui::IsKeyPressed(90))
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
if (ImGui::IsKeyPressed(69))
mCurrentGizmoOperation = ImGuizmo::ROTATE;
if (ImGui::IsKeyPressed(82)) // r Key
mCurrentGizmoOperation = ImGuizmo::SCALE;
if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
ImGui::SameLine();
if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
mCurrentGizmoOperation = ImGuizmo::ROTATE;
ImGui::SameLine();
if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
mCurrentGizmoOperation = ImGuizmo::SCALE;
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
ImGuizmo::DecomposeMatrixToComponents(matrix.m16, matrixTranslation, matrixRotation, matrixScale);
ImGui::InputFloat3("Tr", matrixTranslation, 3);
ImGui::InputFloat3("Rt", matrixRotation, 3);
ImGui::InputFloat3("Sc", matrixScale, 3);
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix.m16);
if (mCurrentGizmoOperation != ImGuizmo::SCALE)
{
if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
mCurrentGizmoMode = ImGuizmo::LOCAL;
ImGui::SameLine();
if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
mCurrentGizmoMode = ImGuizmo::WORLD;
}
static bool useSnap(false);
if (ImGui::IsKeyPressed(83))
useSnap = !useSnap;
ImGui::Checkbox("", &useSnap);
ImGui::SameLine();
vec_t snap;
switch (mCurrentGizmoOperation)
{
case ImGuizmo::TRANSLATE:
snap = config.mSnapTranslation;
ImGui::InputFloat3("Snap", &snap.x);
break;
case ImGuizmo::ROTATE:
snap = config.mSnapRotation;
ImGui::InputFloat("Angle Snap", &snap.x);
break;
case ImGuizmo::SCALE:
snap = config.mSnapScale;
ImGui::InputFloat("Scale Snap", &snap.x);
break;
}
ImGuiIO& io = ImGui::GetIO();
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
ImGuizmo::Manipulate(camera.mView.m16, camera.mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, matrix.m16, NULL, useSnap ? &snap.x : NULL);
}
#endif
#pragma once
#ifdef USE_IMGUI_API
#include "imconfig.h"
#endif
#ifndef IMGUI_API
#define IMGUI_API
#endif
#ifndef IMGUIZMO_NAMESPACE
#define IMGUIZMO_NAMESPACE ImGuizmo
#endif
namespace IMGUIZMO_NAMESPACE
{
// call inside your own window and before Manipulate() in order to draw gizmo to that window.
// Or pass a specific ImDrawList to draw to (e.g. ImGui::GetForegroundDrawList()).
IMGUI_API void SetDrawlist(ImDrawList* drawlist = nullptr);
// call BeginFrame right after ImGui_XXXX_NewFrame();
IMGUI_API void BeginFrame();
// this is necessary because when imguizmo is compiled into a dll, and imgui into another
// globals are not shared between them.
// More details at https://stackoverflow.com/questions/19373061/what-happens-to-global-and-static-variables-in-a-shared-library-when-it-is-dynam
// expose method to set imgui context
IMGUI_API void SetImGuiContext(ImGuiContext* ctx);
// return true if mouse cursor is over any gizmo control (axis, plan or screen component)
IMGUI_API bool IsOver();
// return true if mouse IsOver or if the gizmo is in moving state
IMGUI_API bool IsUsing();
// enable/disable the gizmo. Stay in the state until next call to Enable.
// gizmo is rendered with gray half transparent color when disabled
IMGUI_API void Enable(bool enable);
// helper functions for manualy editing translation/rotation/scale with an input float
// translation, rotation and scale float points to 3 floats each
// Angles are in degrees (more suitable for human editing)
// example:
// float matrixTranslation[3], matrixRotation[3], matrixScale[3];
// ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale);
// ImGui::InputFloat3("Tr", matrixTranslation, 3);
// ImGui::InputFloat3("Rt", matrixRotation, 3);
// ImGui::InputFloat3("Sc", matrixScale, 3);
// ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16);
//
// These functions have some numerical stability issues for now. Use with caution.
IMGUI_API void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale);
IMGUI_API void RecomposeMatrixFromComponents(const float* translation, const float* rotation, const float* scale, float* matrix);
IMGUI_API void SetRect(float x, float y, float width, float height);
// default is false
IMGUI_API void SetOrthographic(bool isOrthographic);
// Render a cube with face color corresponding to face normal. Usefull for debug/tests
IMGUI_API void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount);
IMGUI_API void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize);
// call it when you want a gizmo
// Needs view and projection matrices.
// matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional
// translation is applied in world space
enum OPERATION
{
TRANSLATE_X = (1u << 0),
TRANSLATE_Y = (1u << 1),
TRANSLATE_Z = (1u << 2),
ROTATE_X = (1u << 3),
ROTATE_Y = (1u << 4),
ROTATE_Z = (1u << 5),
ROTATE_SCREEN = (1u << 6),
SCALE_X = (1u << 7),
SCALE_Y = (1u << 8),
SCALE_Z = (1u << 9),
BOUNDS = (1u << 10),
SCALE_XU = (1u << 11),
SCALE_YU = (1u << 12),
SCALE_ZU = (1u << 13),
TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,
ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,
SCALE = SCALE_X | SCALE_Y | SCALE_Z,
SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
};
inline OPERATION operator|(OPERATION lhs, OPERATION rhs)
{
return static_cast(static_cast(lhs) | static_cast(rhs));
}
enum MODE
{
LOCAL,
WORLD
};
IMGUI_API bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix = NULL, const float* snap = NULL, const float* localBounds = NULL, const float* boundsSnap = NULL);
//
// Please note that this cubeview is patented by Autodesk : https://patents.google.com/patent/US7782319B2/en
// It seems to be a defensive patent in the US. I don't think it will bring troubles using it as
// other software are using the same mechanics. But just in case, you are now warned!
//
IMGUI_API void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor);
// use this version if you did not call Manipulate before and you are just using ViewManipulate
IMGUI_API void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor);
IMGUI_API void SetID(int id);
// return true if the cursor is over the operation's gizmo
IMGUI_API bool IsOver(OPERATION op);
IMGUI_API void SetGizmoSizeClipSpace(float value);
// Allow axis to flip
// When true (default), the guizmo axis flip for better visibility
// When false, they always stay along the positive world/local axis
IMGUI_API void AllowAxisFlip(bool value);
enum COLOR
{
DIRECTION_X, // directionColor[0]
DIRECTION_Y, // directionColor[1]
DIRECTION_Z, // directionColor[2]
PLANE_X, // planeColor[0]
PLANE_Y, // planeColor[1]
PLANE_Z, // planeColor[2]
SELECTION, // selectionColor
INACTIVE, // inactiveColor
TRANSLATION_LINE, // translationLineColor
SCALE_LINE,
ROTATION_USING_BORDER,
ROTATION_USING_FILL,
HATCHED_AXIS_LINES,
TEXT,
TEXT_SHADOW,
COUNT
};
struct Style
{
IMGUI_API Style();
float TranslationLineThickness; // Thickness of lines for translation gizmo
float TranslationLineArrowSize; // Size of arrow at the end of lines for translation gizmo
float RotationLineThickness; // Thickness of lines for rotation gizmo
float RotationOuterLineThickness; // Thickness of line surrounding the rotation gizmo
float ScaleLineThickness; // Thickness of lines for scale gizmo
float ScaleLineCircleSize; // Size of circle at the end of lines for scale gizmo
float HatchedAxisLineThickness; // Thickness of hatched axis lines
float CenterCircleSize; // Size of circle at the center of the translate/scale gizmo
ImVec4 Colors[COLOR::COUNT];
};
IMGUI_API Style& GetStyle();
}
================================================
FILE: Source/External/imgui_tools/imguizmo/ImSequencer.cpp
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "ImSequencer.h"
#include "imgui.h"
#include "imgui_internal.h"
#include
namespace ImSequencer
{
#ifndef IMGUI_DEFINE_MATH_OPERATORS
static ImVec2 operator+(const ImVec2& a, const ImVec2& b) {
return ImVec2(a.x + b.x, a.y + b.y);
}
#endif
static bool SequencerAddDelButton(ImDrawList* draw_list, ImVec2 pos, bool add = true)
{
ImGuiIO& io = ImGui::GetIO();
ImRect btnRect(pos, ImVec2(pos.x + 16, pos.y + 16));
bool overBtn = btnRect.Contains(io.MousePos);
bool containedClick = overBtn && btnRect.Contains(io.MouseClickedPos[0]);
bool clickedBtn = containedClick && io.MouseReleased[0];
int btnColor = overBtn ? 0xAAEAFFAA : 0x77A3B2AA;
if (containedClick && io.MouseDownDuration[0] > 0)
btnRect.Expand(2.0f);
float midy = pos.y + 16 / 2 - 0.5f;
float midx = pos.x + 16 / 2 - 0.5f;
draw_list->AddRect(btnRect.Min, btnRect.Max, btnColor, 4);
draw_list->AddLine(ImVec2(btnRect.Min.x + 3, midy), ImVec2(btnRect.Max.x - 3, midy), btnColor, 2);
if (add)
draw_list->AddLine(ImVec2(midx, btnRect.Min.y + 3), ImVec2(midx, btnRect.Max.y - 3), btnColor, 2);
return clickedBtn;
}
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions)
{
bool ret = false;
ImGuiIO& io = ImGui::GetIO();
int cx = (int)(io.MousePos.x);
int cy = (int)(io.MousePos.y);
static float framePixelWidth = 10.f;
static float framePixelWidthTarget = 10.f;
int legendWidth = 200;
static int movingEntry = -1;
static int movingPos = -1;
static int movingPart = -1;
int delEntry = -1;
int dupEntry = -1;
int ItemHeight = 20;
bool popupOpened = false;
int sequenceCount = sequence->GetItemCount();
if (!sequenceCount)
return false;
ImGui::BeginGroup();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
int firstFrameUsed = firstFrame ? *firstFrame : 0;
int controlHeight = sequenceCount * ItemHeight;
for (int i = 0; i < sequenceCount; i++)
controlHeight += int(sequence->GetCustomHeight(i));
int frameCount = ImMax(sequence->GetFrameMax() - sequence->GetFrameMin(), 1);
static bool MovingScrollBar = false;
static bool MovingCurrentFrame = false;
struct CustomDraw
{
int index;
ImRect customRect;
ImRect legendRect;
ImRect clippingRect;
ImRect legendClippingRect;
};
ImVector customDraws;
ImVector compactCustomDraws;
// zoom in/out
const int visibleFrameCount = (int)floorf((canvas_size.x - legendWidth) / framePixelWidth);
const float barWidthRatio = ImMin(visibleFrameCount / (float)frameCount, 1.f);
const float barWidthInPixels = barWidthRatio * (canvas_size.x - legendWidth);
ImRect regionRect(canvas_pos, canvas_pos + canvas_size);
static bool panningView = false;
static ImVec2 panningViewSource;
static int panningViewFrame;
if (ImGui::IsWindowFocused() && io.KeyAlt && io.MouseDown[2])
{
if (!panningView)
{
panningViewSource = io.MousePos;
panningView = true;
panningViewFrame = *firstFrame;
}
*firstFrame = panningViewFrame - int((io.MousePos.x - panningViewSource.x) / framePixelWidth);
*firstFrame = ImClamp(*firstFrame, sequence->GetFrameMin(), sequence->GetFrameMax() - visibleFrameCount);
}
if (panningView && !io.MouseDown[2])
{
panningView = false;
}
framePixelWidthTarget = ImClamp(framePixelWidthTarget, 0.1f, 50.f);
framePixelWidth = ImLerp(framePixelWidth, framePixelWidthTarget, 0.33f);
frameCount = sequence->GetFrameMax() - sequence->GetFrameMin();
if (visibleFrameCount >= frameCount && firstFrame)
*firstFrame = sequence->GetFrameMin();
// --
if (expanded && !*expanded)
{
ImGui::InvisibleButton("canvas", ImVec2(canvas_size.x - canvas_pos.x, (float)ItemHeight));
draw_list->AddRectFilled(canvas_pos, ImVec2(canvas_size.x + canvas_pos.x, canvas_pos.y + ItemHeight), 0xFF3D3837, 0);
char tmps[512];
ImFormatString(tmps, IM_ARRAYSIZE(tmps), sequence->GetCollapseFmt(), frameCount, sequenceCount);
draw_list->AddText(ImVec2(canvas_pos.x + 26, canvas_pos.y + 2), 0xFFFFFFFF, tmps);
}
else
{
bool hasScrollBar(true);
/*
int framesPixelWidth = int(frameCount * framePixelWidth);
if ((framesPixelWidth + legendWidth) >= canvas_size.x)
{
hasScrollBar = true;
}
*/
// test scroll area
ImVec2 headerSize(canvas_size.x, (float)ItemHeight);
ImVec2 scrollBarSize(canvas_size.x, 14.f);
ImGui::InvisibleButton("topBar", headerSize);
draw_list->AddRectFilled(canvas_pos, canvas_pos + headerSize, 0xFFFF0000, 0);
ImVec2 childFramePos = ImGui::GetCursorScreenPos();
ImVec2 childFrameSize(canvas_size.x, canvas_size.y - 8.f - headerSize.y - (hasScrollBar ? scrollBarSize.y : 0));
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
ImGui::BeginChildFrame(889, childFrameSize);
sequence->focused = ImGui::IsWindowFocused();
ImGui::InvisibleButton("contentBar", ImVec2(canvas_size.x, float(controlHeight)));
const ImVec2 contentMin = ImGui::GetItemRectMin();
const ImVec2 contentMax = ImGui::GetItemRectMax();
const ImRect contentRect(contentMin, contentMax);
const float contentHeight = contentMax.y - contentMin.y;
// full background
draw_list->AddRectFilled(canvas_pos, canvas_pos + canvas_size, 0xFF242424, 0);
// current frame top
ImRect topRect(ImVec2(canvas_pos.x + legendWidth, canvas_pos.y), ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + ItemHeight));
if (!MovingCurrentFrame && !MovingScrollBar && movingEntry == -1 && sequenceOptions & SEQUENCER_CHANGE_FRAME && currentFrame && *currentFrame >= 0 && topRect.Contains(io.MousePos) && io.MouseDown[0])
{
MovingCurrentFrame = true;
}
if (MovingCurrentFrame)
{
if (frameCount)
{
*currentFrame = (int)((io.MousePos.x - topRect.Min.x) / framePixelWidth) + firstFrameUsed;
if (*currentFrame < sequence->GetFrameMin())
*currentFrame = sequence->GetFrameMin();
if (*currentFrame >= sequence->GetFrameMax())
*currentFrame = sequence->GetFrameMax();
}
if (!io.MouseDown[0])
MovingCurrentFrame = false;
}
//header
draw_list->AddRectFilled(canvas_pos, ImVec2(canvas_size.x + canvas_pos.x, canvas_pos.y + ItemHeight), 0xFF3D3837, 0);
if (sequenceOptions & SEQUENCER_ADD)
{
if (SequencerAddDelButton(draw_list, ImVec2(canvas_pos.x + legendWidth - ItemHeight, canvas_pos.y + 2), true))
ImGui::OpenPopup("addEntry");
if (ImGui::BeginPopup("addEntry"))
{
for (int i = 0; i < sequence->GetItemTypeCount(); i++)
if (ImGui::Selectable(sequence->GetItemTypeName(i)))
{
sequence->Add(i);
*selectedEntry = sequence->GetItemCount() - 1;
}
ImGui::EndPopup();
popupOpened = true;
}
}
//header frame number and lines
int modFrameCount = 10;
int frameStep = 1;
while ((modFrameCount * framePixelWidth) < 150)
{
modFrameCount *= 2;
frameStep *= 2;
};
int halfModFrameCount = modFrameCount / 2;
auto drawLine = [&](int i, int regionHeight) {
bool baseIndex = ((i % modFrameCount) == 0) || (i == sequence->GetFrameMax() || i == sequence->GetFrameMin());
bool halfIndex = (i % halfModFrameCount) == 0;
int px = (int)canvas_pos.x + int(i * framePixelWidth) + legendWidth - int(firstFrameUsed * framePixelWidth);
int tiretStart = baseIndex ? 4 : (halfIndex ? 10 : 14);
int tiretEnd = baseIndex ? regionHeight : ItemHeight;
if (px <= (canvas_size.x + canvas_pos.x) && px >= (canvas_pos.x + legendWidth))
{
draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)tiretStart), ImVec2((float)px, canvas_pos.y + (float)tiretEnd - 1), 0xFF606060, 1);
draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)ItemHeight), ImVec2((float)px, canvas_pos.y + (float)regionHeight - 1), 0x30606060, 1);
}
if (baseIndex && px > (canvas_pos.x + legendWidth))
{
char tmps[512];
ImFormatString(tmps, IM_ARRAYSIZE(tmps), "%d", i);
draw_list->AddText(ImVec2((float)px + 3.f, canvas_pos.y), 0xFFBBBBBB, tmps);
}
};
auto drawLineContent = [&](int i, int /*regionHeight*/) {
int px = (int)canvas_pos.x + int(i * framePixelWidth) + legendWidth - int(firstFrameUsed * framePixelWidth);
int tiretStart = int(contentMin.y);
int tiretEnd = int(contentMax.y);
if (px <= (canvas_size.x + canvas_pos.x) && px >= (canvas_pos.x + legendWidth))
{
//draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)tiretStart), ImVec2((float)px, canvas_pos.y + (float)tiretEnd - 1), 0xFF606060, 1);
draw_list->AddLine(ImVec2(float(px), float(tiretStart)), ImVec2(float(px), float(tiretEnd)), 0x30606060, 1);
}
};
for (int i = sequence->GetFrameMin(); i <= sequence->GetFrameMax(); i += frameStep)
{
drawLine(i, ItemHeight);
}
drawLine(sequence->GetFrameMin(), ItemHeight);
drawLine(sequence->GetFrameMax(), ItemHeight);
/*
draw_list->AddLine(canvas_pos, ImVec2(canvas_pos.x, canvas_pos.y + controlHeight), 0xFF000000, 1);
draw_list->AddLine(ImVec2(canvas_pos.x, canvas_pos.y + ItemHeight), ImVec2(canvas_size.x, canvas_pos.y + ItemHeight), 0xFF000000, 1);
*/
// clip content
draw_list->PushClipRect(childFramePos, childFramePos + childFrameSize, true);
// draw item names in the legend rect on the left
size_t customHeight = 0;
for (int i = 0; i < sequenceCount; i++)
{
int type;
sequence->Get(i, NULL, NULL, &type, NULL);
ImVec2 tpos(contentMin.x + 3, contentMin.y + i * ItemHeight + 2 + customHeight);
draw_list->AddText(tpos, 0xFFFFFFFF, sequence->GetItemLabel(i));
if (sequenceOptions & SEQUENCER_DEL)
{
if (SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight + 2 - 10, tpos.y + 2), false))
delEntry = i;
if (SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight - ItemHeight + 2 - 10, tpos.y + 2), true))
dupEntry = i;
}
customHeight += sequence->GetCustomHeight(i);
}
// slots background
customHeight = 0;
for (int i = 0; i < sequenceCount; i++)
{
unsigned int col = (i & 1) ? 0xFF3A3636 : 0xFF413D3D;
size_t localCustomHeight = sequence->GetCustomHeight(i);
ImVec2 pos = ImVec2(contentMin.x + legendWidth, contentMin.y + ItemHeight * i + 1 + customHeight);
ImVec2 sz = ImVec2(canvas_size.x + canvas_pos.x, pos.y + ItemHeight - 1 + localCustomHeight);
if (!popupOpened && cy >= pos.y && cy < pos.y + (ItemHeight + localCustomHeight) && movingEntry == -1 && cx>contentMin.x && cx < contentMin.x + canvas_size.x)
{
col += 0x80201008;
pos.x -= legendWidth;
}
draw_list->AddRectFilled(pos, sz, col, 0);
customHeight += localCustomHeight;
}
draw_list->PushClipRect(childFramePos + ImVec2(float(legendWidth), 0.f), childFramePos + childFrameSize, true);
// vertical frame lines in content area
for (int i = sequence->GetFrameMin(); i <= sequence->GetFrameMax(); i += frameStep)
{
drawLineContent(i, int(contentHeight));
}
drawLineContent(sequence->GetFrameMin(), int(contentHeight));
drawLineContent(sequence->GetFrameMax(), int(contentHeight));
// selection
bool selected = selectedEntry && (*selectedEntry >= 0);
if (selected)
{
customHeight = 0;
for (int i = 0; i < *selectedEntry; i++)
customHeight += sequence->GetCustomHeight(i);
draw_list->AddRectFilled(ImVec2(contentMin.x, contentMin.y + ItemHeight * *selectedEntry + customHeight), ImVec2(contentMin.x + canvas_size.x, contentMin.y + ItemHeight * (*selectedEntry + 1) + customHeight), 0x801080FF, 1.f);
}
// slots
customHeight = 0;
for (int i = 0; i < sequenceCount; i++)
{
int* start, * end;
unsigned int color;
sequence->Get(i, &start, &end, NULL, &color);
size_t localCustomHeight = sequence->GetCustomHeight(i);
ImVec2 pos = ImVec2(contentMin.x + legendWidth - firstFrameUsed * framePixelWidth, contentMin.y + ItemHeight * i + 1 + customHeight);
ImVec2 slotP1(pos.x + *start * framePixelWidth, pos.y + 2);
ImVec2 slotP2(pos.x + *end * framePixelWidth + framePixelWidth, pos.y + ItemHeight - 2);
ImVec2 slotP3(pos.x + *end * framePixelWidth + framePixelWidth, pos.y + ItemHeight - 2 + localCustomHeight);
unsigned int slotColor = color | 0xFF000000;
unsigned int slotColorHalf = (color & 0xFFFFFF) | 0x40000000;
if (slotP1.x <= (canvas_size.x + contentMin.x) && slotP2.x >= (contentMin.x + legendWidth))
{
draw_list->AddRectFilled(slotP1, slotP3, slotColorHalf, 2);
draw_list->AddRectFilled(slotP1, slotP2, slotColor, 2);
}
if (ImRect(slotP1, slotP2).Contains(io.MousePos) && io.MouseDoubleClicked[0])
{
sequence->DoubleClick(i);
}
// Ensure grabbable handles
const float max_handle_width = slotP2.x - slotP1.x / 3.0f;
const float min_handle_width = ImMin(10.0f, max_handle_width);
const float handle_width = ImClamp(framePixelWidth / 2.0f, min_handle_width, max_handle_width);
ImRect rects[3] = { ImRect(slotP1, ImVec2(slotP1.x + handle_width, slotP2.y))
, ImRect(ImVec2(slotP2.x - handle_width, slotP1.y), slotP2)
, ImRect(slotP1, slotP2) };
const unsigned int quadColor[] = { 0xFFFFFFFF, 0xFFFFFFFF, slotColor + (selected ? 0 : 0x202020) };
if (movingEntry == -1 && (sequenceOptions & SEQUENCER_EDIT_STARTEND))// TODOFOCUS && backgroundRect.Contains(io.MousePos))
{
for (int j = 2; j >= 0; j--)
{
ImRect& rc = rects[j];
if (!rc.Contains(io.MousePos))
continue;
draw_list->AddRectFilled(rc.Min, rc.Max, quadColor[j], 2);
}
for (int j = 0; j < 3; j++)
{
ImRect& rc = rects[j];
if (!rc.Contains(io.MousePos))
continue;
if (!ImRect(childFramePos, childFramePos + childFrameSize).Contains(io.MousePos))
continue;
if (ImGui::IsMouseClicked(0) && !MovingScrollBar && !MovingCurrentFrame)
{
movingEntry = i;
movingPos = cx;
movingPart = j + 1;
sequence->BeginEdit(movingEntry);
break;
}
}
}
// custom draw
if (localCustomHeight > 0)
{
ImVec2 rp(canvas_pos.x, contentMin.y + ItemHeight * i + 1 + customHeight);
ImRect customRect(rp + ImVec2(legendWidth - (firstFrameUsed - sequence->GetFrameMin() - 0.5f) * framePixelWidth, float(ItemHeight)),
rp + ImVec2(legendWidth + (sequence->GetFrameMax() - firstFrameUsed - 0.5f + 2.f) * framePixelWidth, float(localCustomHeight + ItemHeight)));
ImRect clippingRect(rp + ImVec2(float(legendWidth), float(ItemHeight)), rp + ImVec2(canvas_size.x, float(localCustomHeight + ItemHeight)));
ImRect legendRect(rp + ImVec2(0.f, float(ItemHeight)), rp + ImVec2(float(legendWidth), float(localCustomHeight)));
ImRect legendClippingRect(canvas_pos + ImVec2(0.f, float(ItemHeight)), canvas_pos + ImVec2(float(legendWidth), float(localCustomHeight + ItemHeight)));
customDraws.push_back({ i, customRect, legendRect, clippingRect, legendClippingRect });
}
else
{
ImVec2 rp(canvas_pos.x, contentMin.y + ItemHeight * i + customHeight);
ImRect customRect(rp + ImVec2(legendWidth - (firstFrameUsed - sequence->GetFrameMin() - 0.5f) * framePixelWidth, float(0.f)),
rp + ImVec2(legendWidth + (sequence->GetFrameMax() - firstFrameUsed - 0.5f + 2.f) * framePixelWidth, float(ItemHeight)));
ImRect clippingRect(rp + ImVec2(float(legendWidth), float(0.f)), rp + ImVec2(canvas_size.x, float(ItemHeight)));
compactCustomDraws.push_back({ i, customRect, ImRect(), clippingRect, ImRect() });
}
customHeight += localCustomHeight;
}
// moving
if (/*backgroundRect.Contains(io.MousePos) && */movingEntry >= 0)
{
#if IMGUI_VERSION_NUM >= 18723
ImGui::SetNextFrameWantCaptureMouse(true);
#else
ImGui::CaptureMouseFromApp();
#endif
int diffFrame = int((cx - movingPos) / framePixelWidth);
if (std::abs(diffFrame) > 0)
{
int* start, * end;
sequence->Get(movingEntry, &start, &end, NULL, NULL);
if (selectedEntry)
*selectedEntry = movingEntry;
int& l = *start;
int& r = *end;
if (movingPart & 1)
l += diffFrame;
if (movingPart & 2)
r += diffFrame;
if (l < 0)
{
if (movingPart & 2)
r -= l;
l = 0;
}
if (movingPart & 1 && l > r)
l = r;
if (movingPart & 2 && r < l)
r = l;
movingPos += int(diffFrame * framePixelWidth);
}
if (!io.MouseDown[0])
{
// single select
if (!diffFrame && movingPart && selectedEntry)
{
*selectedEntry = movingEntry;
ret = true;
}
movingEntry = -1;
sequence->EndEdit();
}
}
// cursor
if (currentFrame && firstFrame && *currentFrame >= *firstFrame && *currentFrame <= sequence->GetFrameMax())
{
static const float cursorWidth = 8.f;
float cursorOffset = contentMin.x + legendWidth + (*currentFrame - firstFrameUsed) * framePixelWidth + framePixelWidth / 2 - cursorWidth * 0.5f;
draw_list->AddLine(ImVec2(cursorOffset, canvas_pos.y), ImVec2(cursorOffset, contentMax.y), 0xA02A2AFF, cursorWidth);
char tmps[512];
ImFormatString(tmps, IM_ARRAYSIZE(tmps), "%d", *currentFrame);
draw_list->AddText(ImVec2(cursorOffset + 10, canvas_pos.y + 2), 0xFF2A2AFF, tmps);
}
draw_list->PopClipRect();
draw_list->PopClipRect();
for (auto& customDraw : customDraws)
sequence->CustomDraw(customDraw.index, draw_list, customDraw.customRect, customDraw.legendRect, customDraw.clippingRect, customDraw.legendClippingRect);
for (auto& customDraw : compactCustomDraws)
sequence->CustomDrawCompact(customDraw.index, draw_list, customDraw.customRect, customDraw.clippingRect);
// copy paste
if (sequenceOptions & SEQUENCER_COPYPASTE)
{
ImRect rectCopy(ImVec2(contentMin.x + 100, canvas_pos.y + 2)
, ImVec2(contentMin.x + 100 + 30, canvas_pos.y + ItemHeight - 2));
bool inRectCopy = rectCopy.Contains(io.MousePos);
unsigned int copyColor = inRectCopy ? 0xFF1080FF : 0xFF000000;
draw_list->AddText(rectCopy.Min, copyColor, "Copy");
ImRect rectPaste(ImVec2(contentMin.x + 140, canvas_pos.y + 2)
, ImVec2(contentMin.x + 140 + 30, canvas_pos.y + ItemHeight - 2));
bool inRectPaste = rectPaste.Contains(io.MousePos);
unsigned int pasteColor = inRectPaste ? 0xFF1080FF : 0xFF000000;
draw_list->AddText(rectPaste.Min, pasteColor, "Paste");
if (inRectCopy && io.MouseReleased[0])
{
sequence->Copy();
}
if (inRectPaste && io.MouseReleased[0])
{
sequence->Paste();
}
}
//
ImGui::EndChildFrame();
ImGui::PopStyleColor();
if (hasScrollBar)
{
ImGui::InvisibleButton("scrollBar", scrollBarSize);
ImVec2 scrollBarMin = ImGui::GetItemRectMin();
ImVec2 scrollBarMax = ImGui::GetItemRectMax();
// ratio = number of frames visible in control / number to total frames
float startFrameOffset = ((float)(firstFrameUsed - sequence->GetFrameMin()) / (float)frameCount) * (canvas_size.x - legendWidth);
ImVec2 scrollBarA(scrollBarMin.x + legendWidth, scrollBarMin.y - 2);
ImVec2 scrollBarB(scrollBarMin.x + canvas_size.x, scrollBarMax.y - 1);
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF222222, 0);
ImRect scrollBarRect(scrollBarA, scrollBarB);
bool inScrollBar = scrollBarRect.Contains(io.MousePos);
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF101010, 8);
ImVec2 scrollBarC(scrollBarMin.x + legendWidth + startFrameOffset, scrollBarMin.y);
ImVec2 scrollBarD(scrollBarMin.x + legendWidth + barWidthInPixels + startFrameOffset, scrollBarMax.y - 2);
draw_list->AddRectFilled(scrollBarC, scrollBarD, (inScrollBar || MovingScrollBar) ? 0xFF606060 : 0xFF505050, 6);
ImRect barHandleLeft(scrollBarC, ImVec2(scrollBarC.x + 14, scrollBarD.y));
ImRect barHandleRight(ImVec2(scrollBarD.x - 14, scrollBarC.y), scrollBarD);
bool onLeft = barHandleLeft.Contains(io.MousePos);
bool onRight = barHandleRight.Contains(io.MousePos);
static bool sizingRBar = false;
static bool sizingLBar = false;
draw_list->AddRectFilled(barHandleLeft.Min, barHandleLeft.Max, (onLeft || sizingLBar) ? 0xFFAAAAAA : 0xFF666666, 6);
draw_list->AddRectFilled(barHandleRight.Min, barHandleRight.Max, (onRight || sizingRBar) ? 0xFFAAAAAA : 0xFF666666, 6);
ImRect scrollBarThumb(scrollBarC, scrollBarD);
static const float MinBarWidth = 44.f;
if (sizingRBar)
{
if (!io.MouseDown[0])
{
sizingRBar = false;
}
else
{
float barNewWidth = ImMax(barWidthInPixels + io.MouseDelta.x, MinBarWidth);
float barRatio = barNewWidth / barWidthInPixels;
framePixelWidthTarget = framePixelWidth = framePixelWidth / barRatio;
int newVisibleFrameCount = int((canvas_size.x - legendWidth) / framePixelWidthTarget);
int lastFrame = *firstFrame + newVisibleFrameCount;
if (lastFrame > sequence->GetFrameMax())
{
framePixelWidthTarget = framePixelWidth = (canvas_size.x - legendWidth) / float(sequence->GetFrameMax() - *firstFrame);
}
}
}
else if (sizingLBar)
{
if (!io.MouseDown[0])
{
sizingLBar = false;
}
else
{
if (fabsf(io.MouseDelta.x) > FLT_EPSILON)
{
float barNewWidth = ImMax(barWidthInPixels - io.MouseDelta.x, MinBarWidth);
float barRatio = barNewWidth / barWidthInPixels;
float previousFramePixelWidthTarget = framePixelWidthTarget;
framePixelWidthTarget = framePixelWidth = framePixelWidth / barRatio;
int newVisibleFrameCount = int(visibleFrameCount / barRatio);
int newFirstFrame = *firstFrame + newVisibleFrameCount - visibleFrameCount;
newFirstFrame = ImClamp(newFirstFrame, sequence->GetFrameMin(), ImMax(sequence->GetFrameMax() - visibleFrameCount, sequence->GetFrameMin()));
if (newFirstFrame == *firstFrame)
{
framePixelWidth = framePixelWidthTarget = previousFramePixelWidthTarget;
}
else
{
*firstFrame = newFirstFrame;
}
}
}
}
else
{
if (MovingScrollBar)
{
if (!io.MouseDown[0])
{
MovingScrollBar = false;
}
else
{
float framesPerPixelInBar = barWidthInPixels / (float)visibleFrameCount;
*firstFrame = int((io.MousePos.x - panningViewSource.x) / framesPerPixelInBar) - panningViewFrame;
*firstFrame = ImClamp(*firstFrame, sequence->GetFrameMin(), ImMax(sequence->GetFrameMax() - visibleFrameCount, sequence->GetFrameMin()));
}
}
else
{
if (scrollBarThumb.Contains(io.MousePos) && ImGui::IsMouseClicked(0) && firstFrame && !MovingCurrentFrame && movingEntry == -1)
{
MovingScrollBar = true;
panningViewSource = io.MousePos;
panningViewFrame = -*firstFrame;
}
if (!sizingRBar && onRight && ImGui::IsMouseClicked(0))
sizingRBar = true;
if (!sizingLBar && onLeft && ImGui::IsMouseClicked(0))
sizingLBar = true;
}
}
}
}
ImGui::EndGroup();
if (regionRect.Contains(io.MousePos))
{
bool overCustomDraw = false;
for (auto& custom : customDraws)
{
if (custom.customRect.Contains(io.MousePos))
{
overCustomDraw = true;
}
}
if (overCustomDraw)
{
}
else
{
#if 0
frameOverCursor = *firstFrame + (int)(visibleFrameCount * ((io.MousePos.x - (float)legendWidth - canvas_pos.x) / (canvas_size.x - legendWidth)));
//frameOverCursor = max(min(*firstFrame - visibleFrameCount / 2, frameCount - visibleFrameCount), 0);
/**firstFrame -= frameOverCursor;
*firstFrame *= framePixelWidthTarget / framePixelWidth;
*firstFrame += frameOverCursor;*/
if (io.MouseWheel < -FLT_EPSILON)
{
*firstFrame -= frameOverCursor;
*firstFrame = int(*firstFrame * 1.1f);
framePixelWidthTarget *= 0.9f;
*firstFrame += frameOverCursor;
}
if (io.MouseWheel > FLT_EPSILON)
{
*firstFrame -= frameOverCursor;
*firstFrame = int(*firstFrame * 0.9f);
framePixelWidthTarget *= 1.1f;
*firstFrame += frameOverCursor;
}
#endif
}
}
if (expanded)
{
if (SequencerAddDelButton(draw_list, ImVec2(canvas_pos.x + 2, canvas_pos.y + 2), !*expanded))
*expanded = !*expanded;
}
if (delEntry != -1)
{
sequence->Del(delEntry);
if (selectedEntry && (*selectedEntry == delEntry || *selectedEntry >= sequence->GetItemCount()))
*selectedEntry = -1;
}
if (dupEntry != -1)
{
sequence->Duplicate(dupEntry);
}
return ret;
}
}
================================================
FILE: Source/External/imgui_tools/imguizmo/ImSequencer.h
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#pragma once
#include
struct ImDrawList;
struct ImRect;
namespace ImSequencer
{
enum SEQUENCER_OPTIONS
{
SEQUENCER_EDIT_NONE = 0,
SEQUENCER_EDIT_STARTEND = 1 << 1,
SEQUENCER_CHANGE_FRAME = 1 << 3,
SEQUENCER_ADD = 1 << 4,
SEQUENCER_DEL = 1 << 5,
SEQUENCER_COPYPASTE = 1 << 6,
SEQUENCER_EDIT_ALL = SEQUENCER_EDIT_STARTEND | SEQUENCER_CHANGE_FRAME
};
struct SequenceInterface
{
bool focused = false;
virtual int GetFrameMin() const = 0;
virtual int GetFrameMax() const = 0;
virtual int GetItemCount() const = 0;
virtual void BeginEdit(int /*index*/) {}
virtual void EndEdit() {}
virtual int GetItemTypeCount() const { return 0; }
virtual const char* GetItemTypeName(int /*typeIndex*/) const { return ""; }
virtual const char* GetItemLabel(int /*index*/) const { return ""; }
virtual const char* GetCollapseFmt() const { return "%d Frames / %d entries"; }
virtual void Get(int index, int** start, int** end, int* type, unsigned int* color) = 0;
virtual void Add(int /*type*/) {}
virtual void Del(int /*index*/) {}
virtual void Duplicate(int /*index*/) {}
virtual void Copy() {}
virtual void Paste() {}
virtual size_t GetCustomHeight(int /*index*/) { return 0; }
virtual void DoubleClick(int /*index*/) {}
virtual void CustomDraw(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*legendRect*/, const ImRect& /*clippingRect*/, const ImRect& /*legendClippingRect*/) {}
virtual void CustomDrawCompact(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*clippingRect*/) {}
};
// return true if selection is made
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions);
}
================================================
FILE: Source/External/imgui_tools/imguizmo/ImZoomSlider.h
================================================
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#pragma once
namespace ImZoomSlider
{
typedef int ImGuiZoomSliderFlags;
enum ImGuiPopupFlags_
{
ImGuiZoomSliderFlags_None = 0,
ImGuiZoomSliderFlags_Vertical = 1,
ImGuiZoomSliderFlags_NoAnchors = 2,
ImGuiZoomSliderFlags_NoMiddleCarets = 4,
ImGuiZoomSliderFlags_NoWheel = 8,
};
template bool ImZoomSlider(const T lower, const T higher, T& viewLower, T& viewHigher, float wheelRatio = 0.01f, ImGuiZoomSliderFlags flags = ImGuiZoomSliderFlags_None)
{
bool interacted = false;
ImGuiIO& io = ImGui::GetIO();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
static const float handleSize = 12;
static const float roundRadius = 3.f;
static const char* controlName = "ImZoomSlider";
static bool movingScrollBarSvg = false;
static bool sizingRBarSvg = false;
static bool sizingLBarSvg = false;
static ImGuiID editingId = (ImGuiID)-1;
static float scrollingSource = 0.f;
static float saveViewLower;
static float saveViewHigher;
const bool isVertical = flags & ImGuiZoomSliderFlags_Vertical;
const ImVec2 canvasPos = ImGui::GetCursorScreenPos();
const ImVec2 canvasSize = ImGui::GetContentRegionAvail();
const float canvasSizeLength = isVertical ? ImGui::GetItemRectSize().y : canvasSize.x;
const ImVec2 scrollBarSize = isVertical ? ImVec2(14.f, canvasSizeLength) : ImVec2(canvasSizeLength, 14.f);
ImGui::InvisibleButton(controlName, scrollBarSize);
const ImGuiID currentId = ImGui::GetID(controlName);
const bool usingEditingId = currentId == editingId;
const bool canUseControl = usingEditingId || editingId == -1;
const bool movingScrollBar = usingEditingId ? movingScrollBarSvg : false;
const bool sizingRBar = usingEditingId ? sizingRBarSvg : false;
const bool sizingLBar = usingEditingId ? sizingLBarSvg : false;
const int componentIndex = isVertical ? 1 : 0;
const ImVec2 scrollBarMin = ImGui::GetItemRectMin();
const ImVec2 scrollBarMax = ImGui::GetItemRectMax();
const ImVec2 scrollBarA = ImVec2(scrollBarMin.x, scrollBarMin.y) - (isVertical ? ImVec2(2,0) : ImVec2(0,2));
const ImVec2 scrollBarB = isVertical ? ImVec2(scrollBarMax.x - 1.f, scrollBarMin.y + canvasSizeLength) : ImVec2(scrollBarMin.x + canvasSizeLength, scrollBarMax.y - 1.f);
const float scrollStart = ((viewLower - lower) / (higher - lower)) * canvasSizeLength + scrollBarMin[componentIndex];
const float scrollEnd = ((viewHigher - lower) / (higher - lower)) * canvasSizeLength + scrollBarMin[componentIndex];
const float screenSize = scrollEnd - scrollStart;
const ImVec2 scrollTopLeft = isVertical ? ImVec2(scrollBarMin.x, scrollStart) : ImVec2(scrollStart, scrollBarMin.y);
const ImVec2 scrollBottomRight = isVertical ? ImVec2(scrollBarMax.x - 2.f, scrollEnd) : ImVec2(scrollEnd, scrollBarMax.y - 2.f);
const bool inScrollBar = canUseControl && ImRect(scrollTopLeft, scrollBottomRight).Contains(io.MousePos);
const ImRect scrollBarRect(scrollBarA, scrollBarB);
const float deltaScreen = io.MousePos[componentIndex] - scrollingSource;
const float deltaView = ((higher - lower) / canvasSizeLength) * deltaScreen;
const uint32_t barColor = ImGui::GetColorU32((inScrollBar || movingScrollBar) ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
const float middleCoord = (scrollStart + scrollEnd) * 0.5f;
const bool insideControl = canUseControl && ImRect(scrollBarMin, scrollBarMax).Contains(io.MousePos);
const bool hasAnchors = !(flags & ImGuiZoomSliderFlags_NoAnchors);
const float viewMinSize = ((3.f * handleSize) / canvasSizeLength) * (higher - lower);
const auto ClipView = [lower, higher, &viewLower, &viewHigher]() {
if (viewLower < lower)
{
const float deltaClip = lower - viewLower;
viewLower += deltaClip;
viewHigher += deltaClip;
}
if (viewHigher > higher)
{
const float deltaClip = viewHigher - higher;
viewLower -= deltaClip;
viewHigher -= deltaClip;
}
};
bool onLeft = false;
bool onRight = false;
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF101010, roundRadius);
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF222222, 0);
draw_list->AddRectFilled(scrollTopLeft, scrollBottomRight, barColor, roundRadius);
if (!(flags & ImGuiZoomSliderFlags_NoMiddleCarets))
{
for (float i = 0.5f; i < 3.f; i += 1.f)
{
const float coordA = middleCoord - handleSize * 0.5f;
const float coordB = middleCoord + handleSize * 0.5f;
ImVec2 base = scrollBarMin;
base.x += scrollBarSize.x * 0.25f * i;
base.y += scrollBarSize.y * 0.25f * i;
if (isVertical)
{
draw_list->AddLine(ImVec2(base.x, coordA), ImVec2(base.x, coordB), ImGui::GetColorU32(ImGuiCol_SliderGrab));
}
else
{
draw_list->AddLine(ImVec2(coordA, base.y), ImVec2(coordB, base.y), ImGui::GetColorU32(ImGuiCol_SliderGrab));
}
}
}
// Mouse wheel
if (io.MouseClicked[0] && insideControl && !inScrollBar)
{
const float ratio = (io.MousePos[componentIndex] - scrollBarMin[componentIndex]) / (scrollBarMax[componentIndex] - scrollBarMin[componentIndex]);
const float size = (higher - lower);
const float halfViewSize = (viewHigher - viewLower) * 0.5f;
const float middle = ratio * size + lower;
viewLower = middle - halfViewSize;
viewHigher = middle + halfViewSize;
ClipView();
interacted = true;
}
if (!(flags & ImGuiZoomSliderFlags_NoWheel) && inScrollBar && fabsf(io.MouseWheel) > 0.f)
{
const float ratio = (io.MousePos[componentIndex] - scrollStart) / (scrollEnd - scrollStart);
const float amount = io.MouseWheel * wheelRatio * (viewHigher - viewLower);
viewLower -= ratio * amount;
viewHigher += (1.f - ratio) * amount;
ClipView();
interacted = true;
}
if (screenSize > handleSize * 2.f && hasAnchors)
{
const ImRect barHandleLeft(scrollTopLeft, isVertical ? ImVec2(scrollBottomRight.x, scrollTopLeft.y + handleSize) : ImVec2(scrollTopLeft.x + handleSize, scrollBottomRight.y));
const ImRect barHandleRight(isVertical ? ImVec2(scrollTopLeft.x, scrollBottomRight.y - handleSize) : ImVec2(scrollBottomRight.x - handleSize, scrollTopLeft.y), scrollBottomRight);
onLeft = barHandleLeft.Contains(io.MousePos);
onRight = barHandleRight.Contains(io.MousePos);
draw_list->AddRectFilled(barHandleLeft.Min, barHandleLeft.Max, ImGui::GetColorU32((onLeft || sizingLBar) ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), roundRadius);
draw_list->AddRectFilled(barHandleRight.Min, barHandleRight.Max, ImGui::GetColorU32((onRight || sizingRBar) ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), roundRadius);
}
if (sizingRBar)
{
if (!io.MouseDown[0])
{
sizingRBarSvg = false;
editingId = (ImGuiID)-1;
}
else
{
viewHigher = ImMin(saveViewHigher + deltaView, higher);
}
}
else if (sizingLBar)
{
if (!io.MouseDown[0])
{
sizingLBarSvg = false;
editingId = (ImGuiID)-1;
}
else
{
viewLower = ImMax(saveViewLower + deltaView, lower);
}
}
else
{
if (movingScrollBar)
{
if (!io.MouseDown[0])
{
movingScrollBarSvg = false;
editingId = (ImGuiID)-1;
}
else
{
viewLower = saveViewLower + deltaView;
viewHigher = saveViewHigher + deltaView;
ClipView();
}
}
else
{
if (inScrollBar && ImGui::IsMouseClicked(0))
{
movingScrollBarSvg = true;
scrollingSource = io.MousePos[componentIndex];
saveViewLower = viewLower;
saveViewHigher = viewHigher;
editingId = currentId;
}
if (!sizingRBar && onRight && ImGui::IsMouseClicked(0) && hasAnchors)
{
sizingRBarSvg = true;
editingId = currentId;
}
if (!sizingLBar && onLeft && ImGui::IsMouseClicked(0) && hasAnchors)
{
sizingLBarSvg = true;
editingId = currentId;
}
}
}
// minimal size check
if ((viewHigher - viewLower) < viewMinSize)
{
const float middle = (viewLower + viewHigher) * 0.5f;
viewLower = middle - viewMinSize * 0.5f;
viewHigher = middle + viewMinSize * 0.5f;
ClipView();
}
return movingScrollBar || sizingRBar || sizingLBar || interacted;
}
} // namespace
================================================
FILE: Source/External/imgui_tools/imnodes/imnodes.cpp
================================================
// the structure of this file:
//
// [SECTION] bezier curve helpers
// [SECTION] draw list helper
// [SECTION] ui state logic
// [SECTION] render helpers
// [SECTION] API implementation
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imnodes.h"
#include "imnodes_internal.h"
#include
// Check minimum ImGui version
#define MINIMUM_COMPATIBLE_IMGUI_VERSION 17400
#if IMGUI_VERSION_NUM < MINIMUM_COMPATIBLE_IMGUI_VERSION
#error "Minimum ImGui version requirement not met -- please use a newer version!"
#endif
#include
#include
#include
#include
#include // for fwrite, ssprintf, sscanf
#include
#include // strlen, strncmp
// Use secure CRT function variants to avoid MSVC compiler errors
#ifdef _MSC_VER
#define sscanf sscanf_s
#endif
ImNodesContext* GImNodes = NULL;
namespace IMNODES_NAMESPACE
{
namespace
{
// [SECTION] bezier curve helpers
struct CubicBezier
{
ImVec2 P0, P1, P2, P3;
int NumSegments;
};
inline ImVec2 EvalCubicBezier(
const float t,
const ImVec2& P0,
const ImVec2& P1,
const ImVec2& P2,
const ImVec2& P3)
{
// B(t) = (1-t)**3 p0 + 3(1 - t)**2 t P1 + 3(1-t)t**2 P2 + t**3 P3
const float u = 1.0f - t;
const float b0 = u * u * u;
const float b1 = 3 * u * u * t;
const float b2 = 3 * u * t * t;
const float b3 = t * t * t;
return ImVec2(
b0 * P0.x + b1 * P1.x + b2 * P2.x + b3 * P3.x,
b0 * P0.y + b1 * P1.y + b2 * P2.y + b3 * P3.y);
}
// Calculates the closest point along each bezier curve segment.
ImVec2 GetClosestPointOnCubicBezier(const int num_segments, const ImVec2& p, const CubicBezier& cb)
{
IM_ASSERT(num_segments > 0);
ImVec2 p_last = cb.P0;
ImVec2 p_closest;
float p_closest_dist = FLT_MAX;
float t_step = 1.0f / (float)num_segments;
for (int i = 1; i <= num_segments; ++i)
{
ImVec2 p_current = EvalCubicBezier(t_step * i, cb.P0, cb.P1, cb.P2, cb.P3);
ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
float dist = ImLengthSqr(p - p_line);
if (dist < p_closest_dist)
{
p_closest = p_line;
p_closest_dist = dist;
}
p_last = p_current;
}
return p_closest;
}
inline float GetDistanceToCubicBezier(
const ImVec2& pos,
const CubicBezier& cubic_bezier,
const int num_segments)
{
const ImVec2 point_on_curve = GetClosestPointOnCubicBezier(num_segments, pos, cubic_bezier);
const ImVec2 to_curve = point_on_curve - pos;
return ImSqrt(ImLengthSqr(to_curve));
}
inline ImRect GetContainingRectForCubicBezier(const CubicBezier& cb)
{
const ImVec2 min = ImVec2(ImMin(cb.P0.x, cb.P3.x), ImMin(cb.P0.y, cb.P3.y));
const ImVec2 max = ImVec2(ImMax(cb.P0.x, cb.P3.x), ImMax(cb.P0.y, cb.P3.y));
const float hover_distance = GImNodes->Style.LinkHoverDistance;
ImRect rect(min, max);
rect.Add(cb.P1);
rect.Add(cb.P2);
rect.Expand(ImVec2(hover_distance, hover_distance));
return rect;
}
inline CubicBezier GetCubicBezier(
ImVec2 start,
ImVec2 end,
const ImNodesAttributeType start_type,
const float line_segments_per_length)
{
IM_ASSERT(
(start_type == ImNodesAttributeType_Input) || (start_type == ImNodesAttributeType_Output));
if (start_type == ImNodesAttributeType_Input)
{
ImSwap(start, end);
}
const float link_length = ImSqrt(ImLengthSqr(end - start));
const ImVec2 offset = ImVec2(0.25f * link_length, 0.f);
CubicBezier cubic_bezier;
cubic_bezier.P0 = start;
cubic_bezier.P1 = start + offset;
cubic_bezier.P2 = end - offset;
cubic_bezier.P3 = end;
cubic_bezier.NumSegments = ImMax(static_cast(link_length * line_segments_per_length), 1);
return cubic_bezier;
}
inline float EvalImplicitLineEq(const ImVec2& p1, const ImVec2& p2, const ImVec2& p)
{
return (p2.y - p1.y) * p.x + (p1.x - p2.x) * p.y + (p2.x * p1.y - p1.x * p2.y);
}
inline int Sign(float val) { return int(val > 0.0f) - int(val < 0.0f); }
inline bool RectangleOverlapsLineSegment(const ImRect& rect, const ImVec2& p1, const ImVec2& p2)
{
// Trivial case: rectangle contains an endpoint
if (rect.Contains(p1) || rect.Contains(p2))
{
return true;
}
// Flip rectangle if necessary
ImRect flip_rect = rect;
if (flip_rect.Min.x > flip_rect.Max.x)
{
ImSwap(flip_rect.Min.x, flip_rect.Max.x);
}
if (flip_rect.Min.y > flip_rect.Max.y)
{
ImSwap(flip_rect.Min.y, flip_rect.Max.y);
}
// Trivial case: line segment lies to one particular side of rectangle
if ((p1.x < flip_rect.Min.x && p2.x < flip_rect.Min.x) ||
(p1.x > flip_rect.Max.x && p2.x > flip_rect.Max.x) ||
(p1.y < flip_rect.Min.y && p2.y < flip_rect.Min.y) ||
(p1.y > flip_rect.Max.y && p2.y > flip_rect.Max.y))
{
return false;
}
const int corner_signs[4] = {
Sign(EvalImplicitLineEq(p1, p2, flip_rect.Min)),
Sign(EvalImplicitLineEq(p1, p2, ImVec2(flip_rect.Max.x, flip_rect.Min.y))),
Sign(EvalImplicitLineEq(p1, p2, ImVec2(flip_rect.Min.x, flip_rect.Max.y))),
Sign(EvalImplicitLineEq(p1, p2, flip_rect.Max))};
int sum = 0;
int sum_abs = 0;
for (int i = 0; i < 4; ++i)
{
sum += corner_signs[i];
sum_abs += abs(corner_signs[i]);
}
// At least one corner of rectangle lies on a different side of line segment
return abs(sum) != sum_abs;
}
inline bool RectangleOverlapsBezier(const ImRect& rectangle, const CubicBezier& cubic_bezier)
{
ImVec2 current =
EvalCubicBezier(0.f, cubic_bezier.P0, cubic_bezier.P1, cubic_bezier.P2, cubic_bezier.P3);
const float dt = 1.0f / cubic_bezier.NumSegments;
for (int s = 0; s < cubic_bezier.NumSegments; ++s)
{
ImVec2 next = EvalCubicBezier(
static_cast((s + 1) * dt),
cubic_bezier.P0,
cubic_bezier.P1,
cubic_bezier.P2,
cubic_bezier.P3);
if (RectangleOverlapsLineSegment(rectangle, current, next))
{
return true;
}
current = next;
}
return false;
}
inline bool RectangleOverlapsLink(
const ImRect& rectangle,
const ImVec2& start,
const ImVec2& end,
const ImNodesAttributeType start_type)
{
// First level: simple rejection test via rectangle overlap:
ImRect lrect = ImRect(start, end);
if (lrect.Min.x > lrect.Max.x)
{
ImSwap(lrect.Min.x, lrect.Max.x);
}
if (lrect.Min.y > lrect.Max.y)
{
ImSwap(lrect.Min.y, lrect.Max.y);
}
if (rectangle.Overlaps(lrect))
{
// First, check if either one or both endpoinds are trivially contained
// in the rectangle
if (rectangle.Contains(start) || rectangle.Contains(end))
{
return true;
}
// Second level of refinement: do a more expensive test against the
// link
const CubicBezier cubic_bezier =
GetCubicBezier(start, end, start_type, GImNodes->Style.LinkLineSegmentsPerLength);
return RectangleOverlapsBezier(rectangle, cubic_bezier);
}
return false;
}
// [SECTION] coordinate space conversion helpers
inline ImVec2 ScreenSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v)
{
return v - GImNodes->CanvasOriginScreenSpace - editor.Panning;
}
inline ImRect ScreenSpaceToGridSpace(const ImNodesEditorContext& editor, const ImRect& r)
{
return ImRect(ScreenSpaceToGridSpace(editor, r.Min), ScreenSpaceToGridSpace(editor, r.Max));
}
inline ImVec2 GridSpaceToScreenSpace(const ImNodesEditorContext& editor, const ImVec2& v)
{
return v + GImNodes->CanvasOriginScreenSpace + editor.Panning;
}
inline ImVec2 GridSpaceToEditorSpace(const ImNodesEditorContext& editor, const ImVec2& v)
{
return v + editor.Panning;
}
inline ImVec2 EditorSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v)
{
return v - editor.Panning;
}
inline ImVec2 EditorSpaceToScreenSpace(const ImVec2& v)
{
return GImNodes->CanvasOriginScreenSpace + v;
}
inline ImVec2 MiniMapSpaceToGridSpace(const ImNodesEditorContext& editor, const ImVec2& v)
{
return (v - editor.MiniMapContentScreenSpace.Min) / editor.MiniMapScaling +
editor.GridContentBounds.Min;
}
inline ImVec2 ScreenSpaceToMiniMapSpace(const ImNodesEditorContext& editor, const ImVec2& v)
{
return (ScreenSpaceToGridSpace(editor, v) - editor.GridContentBounds.Min) *
editor.MiniMapScaling +
editor.MiniMapContentScreenSpace.Min;
}
inline ImRect ScreenSpaceToMiniMapSpace(const ImNodesEditorContext& editor, const ImRect& r)
{
return ImRect(
ScreenSpaceToMiniMapSpace(editor, r.Min), ScreenSpaceToMiniMapSpace(editor, r.Max));
}
// [SECTION] draw list helper
void ImDrawListGrowChannels(ImDrawList* draw_list, const int num_channels)
{
ImDrawListSplitter& splitter = draw_list->_Splitter;
if (splitter._Count == 1)
{
splitter.Split(draw_list, num_channels + 1);
return;
}
// NOTE: this logic has been lifted from ImDrawListSplitter::Split with slight modifications
// to allow nested splits. The main modification is that we only create new ImDrawChannel
// instances after splitter._Count, instead of over the whole splitter._Channels array like
// the regular ImDrawListSplitter::Split method does.
const int old_channel_capacity = splitter._Channels.Size;
// NOTE: _Channels is not resized down, and therefore _Count <= _Channels.size()!
const int old_channel_count = splitter._Count;
const int requested_channel_count = old_channel_count + num_channels;
if (old_channel_capacity < old_channel_count + num_channels)
{
splitter._Channels.resize(requested_channel_count);
}
splitter._Count = requested_channel_count;
for (int i = old_channel_count; i < requested_channel_count; ++i)
{
ImDrawChannel& channel = splitter._Channels[i];
// If we're inside the old capacity region of the array, we need to reuse the existing
// memory of the command and index buffers.
if (i < old_channel_capacity)
{
channel._CmdBuffer.resize(0);
channel._IdxBuffer.resize(0);
}
// Else, we need to construct new draw channels.
else
{
IM_PLACEMENT_NEW(&channel) ImDrawChannel();
}
{
ImDrawCmd draw_cmd;
draw_cmd.ClipRect = draw_list->_ClipRectStack.back();
draw_cmd.TextureId = draw_list->_TextureIdStack.back();
channel._CmdBuffer.push_back(draw_cmd);
}
}
}
void ImDrawListSplitterSwapChannels(
ImDrawListSplitter& splitter,
const int lhs_idx,
const int rhs_idx)
{
if (lhs_idx == rhs_idx)
{
return;
}
IM_ASSERT(lhs_idx >= 0 && lhs_idx < splitter._Count);
IM_ASSERT(rhs_idx >= 0 && rhs_idx < splitter._Count);
ImDrawChannel& lhs_channel = splitter._Channels[lhs_idx];
ImDrawChannel& rhs_channel = splitter._Channels[rhs_idx];
lhs_channel._CmdBuffer.swap(rhs_channel._CmdBuffer);
lhs_channel._IdxBuffer.swap(rhs_channel._IdxBuffer);
const int current_channel = splitter._Current;
if (current_channel == lhs_idx)
{
splitter._Current = rhs_idx;
}
else if (current_channel == rhs_idx)
{
splitter._Current = lhs_idx;
}
}
void DrawListSet(ImDrawList* window_draw_list)
{
GImNodes->CanvasDrawList = window_draw_list;
GImNodes->NodeIdxToSubmissionIdx.Clear();
GImNodes->NodeIdxSubmissionOrder.clear();
}
// The draw list channels are structured as follows. First we have our base channel, the canvas grid
// on which we render the grid lines in BeginNodeEditor(). The base channel is the reason
// draw_list_submission_idx_to_background_channel_idx offsets the index by one. Each BeginNode()
// call appends two new draw channels, for the node background and foreground. The node foreground
// is the channel into which the node's ImGui content is rendered. Finally, in EndNodeEditor() we
// append one last draw channel for rendering the selection box and the incomplete link on top of
// everything else.
//
// +----------+----------+----------+----------+----------+----------+
// | | | | | | |
// |canvas |node |node |... |... |click |
// |grid |background|foreground| | |interaction
// | | | | | | |
// +----------+----------+----------+----------+----------+----------+
// | |
// | submission idx |
// | |
// -----------------------
void DrawListAddNode(const int node_idx)
{
GImNodes->NodeIdxToSubmissionIdx.SetInt(
static_cast(node_idx), GImNodes->NodeIdxSubmissionOrder.Size);
GImNodes->NodeIdxSubmissionOrder.push_back(node_idx);
ImDrawListGrowChannels(GImNodes->CanvasDrawList, 2);
}
void DrawListAppendClickInteractionChannel()
{
// NOTE: don't use this function outside of EndNodeEditor. Using this before all nodes have been
// added will screw up the node draw order.
ImDrawListGrowChannels(GImNodes->CanvasDrawList, 1);
}
int DrawListSubmissionIdxToBackgroundChannelIdx(const int submission_idx)
{
// NOTE: the first channel is the canvas background, i.e. the grid
return 1 + 2 * submission_idx;
}
int DrawListSubmissionIdxToForegroundChannelIdx(const int submission_idx)
{
return DrawListSubmissionIdxToBackgroundChannelIdx(submission_idx) + 1;
}
void DrawListActivateClickInteractionChannel()
{
GImNodes->CanvasDrawList->_Splitter.SetCurrentChannel(
GImNodes->CanvasDrawList, GImNodes->CanvasDrawList->_Splitter._Count - 1);
}
void DrawListActivateCurrentNodeForeground()
{
const int foreground_channel_idx =
DrawListSubmissionIdxToForegroundChannelIdx(GImNodes->NodeIdxSubmissionOrder.Size - 1);
GImNodes->CanvasDrawList->_Splitter.SetCurrentChannel(
GImNodes->CanvasDrawList, foreground_channel_idx);
}
void DrawListActivateNodeBackground(const int node_idx)
{
const int submission_idx =
GImNodes->NodeIdxToSubmissionIdx.GetInt(static_cast(node_idx), -1);
// There is a discrepancy in the submitted node count and the rendered node count! Did you call
// one of the following functions
// * EditorContextMoveToNode
// * SetNodeScreenSpacePos
// * SetNodeGridSpacePos
// * SetNodeDraggable
// after the BeginNode/EndNode function calls?
IM_ASSERT(submission_idx != -1);
const int background_channel_idx = DrawListSubmissionIdxToBackgroundChannelIdx(submission_idx);
GImNodes->CanvasDrawList->_Splitter.SetCurrentChannel(
GImNodes->CanvasDrawList, background_channel_idx);
}
void DrawListSwapSubmissionIndices(const int lhs_idx, const int rhs_idx)
{
IM_ASSERT(lhs_idx != rhs_idx);
const int lhs_foreground_channel_idx = DrawListSubmissionIdxToForegroundChannelIdx(lhs_idx);
const int lhs_background_channel_idx = DrawListSubmissionIdxToBackgroundChannelIdx(lhs_idx);
const int rhs_foreground_channel_idx = DrawListSubmissionIdxToForegroundChannelIdx(rhs_idx);
const int rhs_background_channel_idx = DrawListSubmissionIdxToBackgroundChannelIdx(rhs_idx);
ImDrawListSplitterSwapChannels(
GImNodes->CanvasDrawList->_Splitter,
lhs_background_channel_idx,
rhs_background_channel_idx);
ImDrawListSplitterSwapChannels(
GImNodes->CanvasDrawList->_Splitter,
lhs_foreground_channel_idx,
rhs_foreground_channel_idx);
}
void DrawListSortChannelsByDepth(const ImVector& node_idx_depth_order)
{
if (GImNodes->NodeIdxToSubmissionIdx.Data.Size < 2)
{
return;
}
IM_ASSERT(node_idx_depth_order.Size == GImNodes->NodeIdxSubmissionOrder.Size);
int start_idx = node_idx_depth_order.Size - 1;
while (node_idx_depth_order[start_idx] == GImNodes->NodeIdxSubmissionOrder[start_idx])
{
if (--start_idx == 0)
{
// early out if submission order and depth order are the same
return;
}
}
// TODO: this is an O(N^2) algorithm. It might be worthwhile revisiting this to see if the time
// complexity can be reduced.
for (int depth_idx = start_idx; depth_idx > 0; --depth_idx)
{
const int node_idx = node_idx_depth_order[depth_idx];
// Find the current index of the node_idx in the submission order array
int submission_idx = -1;
for (int i = 0; i < GImNodes->NodeIdxSubmissionOrder.Size; ++i)
{
if (GImNodes->NodeIdxSubmissionOrder[i] == node_idx)
{
submission_idx = i;
break;
}
}
IM_ASSERT(submission_idx >= 0);
if (submission_idx == depth_idx)
{
continue;
}
for (int j = submission_idx; j < depth_idx; ++j)
{
DrawListSwapSubmissionIndices(j, j + 1);
ImSwap(GImNodes->NodeIdxSubmissionOrder[j], GImNodes->NodeIdxSubmissionOrder[j + 1]);
}
}
}
// [SECTION] ui state logic
ImVec2 GetScreenSpacePinCoordinates(
const ImRect& node_rect,
const ImRect& attribute_rect,
const ImNodesAttributeType type)
{
IM_ASSERT(type == ImNodesAttributeType_Input || type == ImNodesAttributeType_Output);
const float x = type == ImNodesAttributeType_Input
? (node_rect.Min.x - GImNodes->Style.PinOffset)
: (node_rect.Max.x + GImNodes->Style.PinOffset);
return ImVec2(x, 0.5f * (attribute_rect.Min.y + attribute_rect.Max.y));
}
ImVec2 GetScreenSpacePinCoordinates(const ImNodesEditorContext& editor, const ImPinData& pin)
{
const ImRect& parent_node_rect = editor.Nodes.Pool[pin.ParentNodeIdx].Rect;
return GetScreenSpacePinCoordinates(parent_node_rect, pin.AttributeRect, pin.Type);
}
bool MouseInCanvas()
{
// This flag should be true either when hovering or clicking something in the canvas.
const bool is_window_hovered_or_focused = ImGui::IsWindowHovered() || ImGui::IsWindowFocused();
return is_window_hovered_or_focused &&
GImNodes->CanvasRectScreenSpace.Contains(ImGui::GetMousePos());
}
void BeginNodeSelection(ImNodesEditorContext& editor, const int node_idx)
{
// Don't start selecting a node if we are e.g. already creating and dragging
// a new link! New link creation can happen when the mouse is clicked over
// a node, but within the hover radius of a pin.
if (editor.ClickInteraction.Type != ImNodesClickInteractionType_None)
{
return;
}
editor.ClickInteraction.Type = ImNodesClickInteractionType_Node;
// If the node is not already contained in the selection, then we want only
// the interaction node to be selected, effective immediately.
//
// If the multiple selection modifier is active, we want to add this node
// to the current list of selected nodes.
//
// Otherwise, we want to allow for the possibility of multiple nodes to be
// moved at once.
if (!editor.SelectedNodeIndices.contains(node_idx))
{
editor.SelectedLinkIndices.clear();
if (!GImNodes->MultipleSelectModifier)
{
editor.SelectedNodeIndices.clear();
}
editor.SelectedNodeIndices.push_back(node_idx);
// Ensure that individually selected nodes get rendered on top
ImVector& depth_stack = editor.NodeDepthOrder;
const int* const elem = depth_stack.find(node_idx);
IM_ASSERT(elem != depth_stack.end());
depth_stack.erase(elem);
depth_stack.push_back(node_idx);
}
// Deselect a previously-selected node
else if (GImNodes->MultipleSelectModifier)
{
const int* const node_ptr = editor.SelectedNodeIndices.find(node_idx);
editor.SelectedNodeIndices.erase(node_ptr);
// Don't allow dragging after deselecting
editor.ClickInteraction.Type = ImNodesClickInteractionType_None;
}
// To support snapping of multiple nodes, we need to store the offset of
// each node in the selection to the origin of the dragged node.
const ImVec2 ref_origin = editor.Nodes.Pool[node_idx].Origin;
editor.PrimaryNodeOffset =
ref_origin + GImNodes->CanvasOriginScreenSpace + editor.Panning - GImNodes->MousePos;
editor.SelectedNodeOffsets.clear();
for (int idx = 0; idx < editor.SelectedNodeIndices.Size; idx++)
{
const int node = editor.SelectedNodeIndices[idx];
const ImVec2 node_origin = editor.Nodes.Pool[node].Origin - ref_origin;
editor.SelectedNodeOffsets.push_back(node_origin);
}
}
void BeginLinkSelection(ImNodesEditorContext& editor, const int link_idx)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_Link;
// When a link is selected, clear all other selections, and insert the link
// as the sole selection.
editor.SelectedNodeIndices.clear();
editor.SelectedLinkIndices.clear();
editor.SelectedLinkIndices.push_back(link_idx);
}
void BeginLinkDetach(ImNodesEditorContext& editor, const int link_idx, const int detach_pin_idx)
{
const ImLinkData& link = editor.Links.Pool[link_idx];
ImClickInteractionState& state = editor.ClickInteraction;
state.Type = ImNodesClickInteractionType_LinkCreation;
state.LinkCreation.EndPinIdx.Reset();
state.LinkCreation.StartPinIdx =
detach_pin_idx == link.StartPinIdx ? link.EndPinIdx : link.StartPinIdx;
GImNodes->DeletedLinkIdx = link_idx;
}
void BeginLinkCreation(ImNodesEditorContext& editor, const int hovered_pin_idx)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_LinkCreation;
editor.ClickInteraction.LinkCreation.StartPinIdx = hovered_pin_idx;
editor.ClickInteraction.LinkCreation.EndPinIdx.Reset();
editor.ClickInteraction.LinkCreation.Type = ImNodesLinkCreationType_Standard;
GImNodes->ImNodesUIState |= ImNodesUIState_LinkStarted;
}
void BeginLinkInteraction(
ImNodesEditorContext& editor,
const int link_idx,
const ImOptionalIndex pin_idx = ImOptionalIndex())
{
// Check if we are clicking the link with the modifier pressed.
// This will in a link detach via clicking.
const bool modifier_pressed = GImNodes->Io.LinkDetachWithModifierClick.Modifier == NULL
? false
: *GImNodes->Io.LinkDetachWithModifierClick.Modifier;
if (modifier_pressed)
{
const ImLinkData& link = editor.Links.Pool[link_idx];
const ImPinData& start_pin = editor.Pins.Pool[link.StartPinIdx];
const ImPinData& end_pin = editor.Pins.Pool[link.EndPinIdx];
const ImVec2& mouse_pos = GImNodes->MousePos;
const float dist_to_start = ImLengthSqr(start_pin.Pos - mouse_pos);
const float dist_to_end = ImLengthSqr(end_pin.Pos - mouse_pos);
const int closest_pin_idx = dist_to_start < dist_to_end ? link.StartPinIdx : link.EndPinIdx;
editor.ClickInteraction.Type = ImNodesClickInteractionType_LinkCreation;
BeginLinkDetach(editor, link_idx, closest_pin_idx);
editor.ClickInteraction.LinkCreation.Type = ImNodesLinkCreationType_FromDetach;
}
else
{
if (pin_idx.HasValue())
{
const int hovered_pin_flags = editor.Pins.Pool[pin_idx.Value()].Flags;
// Check the 'click and drag to detach' case.
if (hovered_pin_flags & ImNodesAttributeFlags_EnableLinkDetachWithDragClick)
{
BeginLinkDetach(editor, link_idx, pin_idx.Value());
editor.ClickInteraction.LinkCreation.Type = ImNodesLinkCreationType_FromDetach;
}
else
{
BeginLinkCreation(editor, pin_idx.Value());
}
}
else
{
BeginLinkSelection(editor, link_idx);
}
}
}
static inline bool IsMiniMapHovered();
void BeginCanvasInteraction(ImNodesEditorContext& editor)
{
const bool any_ui_element_hovered =
GImNodes->HoveredNodeIdx.HasValue() || GImNodes->HoveredLinkIdx.HasValue() ||
GImNodes->HoveredPinIdx.HasValue() || ImGui::IsAnyItemHovered();
const bool mouse_not_in_canvas = !MouseInCanvas();
if (editor.ClickInteraction.Type != ImNodesClickInteractionType_None ||
any_ui_element_hovered || mouse_not_in_canvas)
{
return;
}
const bool started_panning = GImNodes->AltMouseClicked;
if (started_panning)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_Panning;
}
else if (GImNodes->LeftMouseClicked)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_BoxSelection;
editor.ClickInteraction.BoxSelector.Rect.Min =
ScreenSpaceToGridSpace(editor, GImNodes->MousePos);
}
}
void BoxSelectorUpdateSelection(ImNodesEditorContext& editor, ImRect box_rect)
{
// Invert box selector coordinates as needed
if (box_rect.Min.x > box_rect.Max.x)
{
ImSwap(box_rect.Min.x, box_rect.Max.x);
}
if (box_rect.Min.y > box_rect.Max.y)
{
ImSwap(box_rect.Min.y, box_rect.Max.y);
}
// Update node selection
editor.SelectedNodeIndices.clear();
// Test for overlap against node rectangles
for (int node_idx = 0; node_idx < editor.Nodes.Pool.size(); ++node_idx)
{
if (editor.Nodes.InUse[node_idx])
{
ImNodeData& node = editor.Nodes.Pool[node_idx];
if (box_rect.Overlaps(node.Rect))
{
editor.SelectedNodeIndices.push_back(node_idx);
}
}
}
// Update link selection
editor.SelectedLinkIndices.clear();
// Test for overlap against links
for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)
{
if (editor.Links.InUse[link_idx])
{
const ImLinkData& link = editor.Links.Pool[link_idx];
const ImPinData& pin_start = editor.Pins.Pool[link.StartPinIdx];
const ImPinData& pin_end = editor.Pins.Pool[link.EndPinIdx];
const ImRect& node_start_rect = editor.Nodes.Pool[pin_start.ParentNodeIdx].Rect;
const ImRect& node_end_rect = editor.Nodes.Pool[pin_end.ParentNodeIdx].Rect;
const ImVec2 start = GetScreenSpacePinCoordinates(
node_start_rect, pin_start.AttributeRect, pin_start.Type);
const ImVec2 end =
GetScreenSpacePinCoordinates(node_end_rect, pin_end.AttributeRect, pin_end.Type);
// Test
if (RectangleOverlapsLink(box_rect, start, end, pin_start.Type))
{
editor.SelectedLinkIndices.push_back(link_idx);
}
}
}
}
ImVec2 SnapOriginToGrid(ImVec2 origin)
{
if (GImNodes->Style.Flags & ImNodesStyleFlags_GridSnapping)
{
const float spacing = GImNodes->Style.GridSpacing;
const float spacing2 = spacing * 0.5f;
// Snap the origin to the nearest grid point in any direction
float modx = fmodf(fabsf(origin.x) + spacing2, spacing) - spacing2;
float mody = fmodf(fabsf(origin.y) + spacing2, spacing) - spacing2;
origin.x += (origin.x < 0.f) ? modx : -modx;
origin.y += (origin.y < 0.f) ? mody : -mody;
}
return origin;
}
void TranslateSelectedNodes(ImNodesEditorContext& editor)
{
if (GImNodes->LeftMouseDragging)
{
// If we have grid snap enabled, don't start moving nodes until we've moved the mouse
// slightly
const bool shouldTranslate = (GImNodes->Style.Flags & ImNodesStyleFlags_GridSnapping)
? ImGui::GetIO().MouseDragMaxDistanceSqr[0] > 5.0
: true;
const ImVec2 origin = SnapOriginToGrid(
GImNodes->MousePos - GImNodes->CanvasOriginScreenSpace - editor.Panning +
editor.PrimaryNodeOffset);
for (int i = 0; i < editor.SelectedNodeIndices.size(); ++i)
{
const ImVec2 node_rel = editor.SelectedNodeOffsets[i];
const int node_idx = editor.SelectedNodeIndices[i];
ImNodeData& node = editor.Nodes.Pool[node_idx];
if (node.Draggable && shouldTranslate)
{
node.Origin = origin + node_rel + editor.AutoPanningDelta;
}
}
}
}
struct LinkPredicate
{
bool operator()(const ImLinkData& lhs, const ImLinkData& rhs) const
{
// Do a unique compare by sorting the pins' addresses.
// This catches duplicate links, whether they are in the
// same direction or not.
// Sorting by pin index should have the uniqueness guarantees as sorting
// by id -- each unique id will get one slot in the link pool array.
int lhs_start = lhs.StartPinIdx;
int lhs_end = lhs.EndPinIdx;
int rhs_start = rhs.StartPinIdx;
int rhs_end = rhs.EndPinIdx;
if (lhs_start > lhs_end)
{
ImSwap(lhs_start, lhs_end);
}
if (rhs_start > rhs_end)
{
ImSwap(rhs_start, rhs_end);
}
return lhs_start == rhs_start && lhs_end == rhs_end;
}
};
ImOptionalIndex FindDuplicateLink(
const ImNodesEditorContext& editor,
const int start_pin_idx,
const int end_pin_idx)
{
ImLinkData test_link(0);
test_link.StartPinIdx = start_pin_idx;
test_link.EndPinIdx = end_pin_idx;
for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)
{
const ImLinkData& link = editor.Links.Pool[link_idx];
if (LinkPredicate()(test_link, link) && editor.Links.InUse[link_idx])
{
return ImOptionalIndex(link_idx);
}
}
return ImOptionalIndex();
}
bool ShouldLinkSnapToPin(
const ImNodesEditorContext& editor,
const ImPinData& start_pin,
const int hovered_pin_idx,
const ImOptionalIndex duplicate_link)
{
const ImPinData& end_pin = editor.Pins.Pool[hovered_pin_idx];
// The end pin must be in a different node
if (start_pin.ParentNodeIdx == end_pin.ParentNodeIdx)
{
return false;
}
// The end pin must be of a different type
if (start_pin.Type == end_pin.Type)
{
return false;
}
// The link to be created must not be a duplicate, unless it is the link which was created on
// snap. In that case we want to snap, since we want it to appear visually as if the created
// link remains snapped to the pin.
if (duplicate_link.HasValue() && !(duplicate_link == GImNodes->SnapLinkIdx))
{
return false;
}
return true;
}
void ClickInteractionUpdate(ImNodesEditorContext& editor)
{
switch (editor.ClickInteraction.Type)
{
case ImNodesClickInteractionType_BoxSelection:
{
editor.ClickInteraction.BoxSelector.Rect.Max =
ScreenSpaceToGridSpace(editor, GImNodes->MousePos);
ImRect box_rect = editor.ClickInteraction.BoxSelector.Rect;
box_rect.Min = GridSpaceToScreenSpace(editor, box_rect.Min);
box_rect.Max = GridSpaceToScreenSpace(editor, box_rect.Max);
BoxSelectorUpdateSelection(editor, box_rect);
const ImU32 box_selector_color = GImNodes->Style.Colors[ImNodesCol_BoxSelector];
const ImU32 box_selector_outline = GImNodes->Style.Colors[ImNodesCol_BoxSelectorOutline];
GImNodes->CanvasDrawList->AddRectFilled(box_rect.Min, box_rect.Max, box_selector_color);
GImNodes->CanvasDrawList->AddRect(box_rect.Min, box_rect.Max, box_selector_outline);
if (GImNodes->LeftMouseReleased)
{
ImVector& depth_stack = editor.NodeDepthOrder;
const ImVector& selected_idxs = editor.SelectedNodeIndices;
// Bump the selected node indices, in order, to the top of the depth stack.
// NOTE: this algorithm has worst case time complexity of O(N^2), if the node selection
// is ~ N (due to selected_idxs.contains()).
if ((selected_idxs.Size > 0) && (selected_idxs.Size < depth_stack.Size))
{
int num_moved = 0; // The number of indices moved. Stop after selected_idxs.Size
for (int i = 0; i < depth_stack.Size - selected_idxs.Size; ++i)
{
for (int node_idx = depth_stack[i]; selected_idxs.contains(node_idx);
node_idx = depth_stack[i])
{
depth_stack.erase(depth_stack.begin() + static_cast(i));
depth_stack.push_back(node_idx);
++num_moved;
}
if (num_moved == selected_idxs.Size)
{
break;
}
}
}
editor.ClickInteraction.Type = ImNodesClickInteractionType_None;
}
}
break;
case ImNodesClickInteractionType_Node:
{
TranslateSelectedNodes(editor);
if (GImNodes->LeftMouseReleased)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_None;
}
}
break;
case ImNodesClickInteractionType_Link:
{
if (GImNodes->LeftMouseReleased)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_None;
}
}
break;
case ImNodesClickInteractionType_LinkCreation:
{
const ImPinData& start_pin =
editor.Pins.Pool[editor.ClickInteraction.LinkCreation.StartPinIdx];
const ImOptionalIndex maybe_duplicate_link_idx =
GImNodes->HoveredPinIdx.HasValue()
? FindDuplicateLink(
editor,
editor.ClickInteraction.LinkCreation.StartPinIdx,
GImNodes->HoveredPinIdx.Value())
: ImOptionalIndex();
const bool should_snap =
GImNodes->HoveredPinIdx.HasValue() &&
ShouldLinkSnapToPin(
editor, start_pin, GImNodes->HoveredPinIdx.Value(), maybe_duplicate_link_idx);
// If we created on snap and the hovered pin is empty or changed, then we need signal that
// the link's state has changed.
const bool snapping_pin_changed =
editor.ClickInteraction.LinkCreation.EndPinIdx.HasValue() &&
!(GImNodes->HoveredPinIdx == editor.ClickInteraction.LinkCreation.EndPinIdx);
// Detach the link that was created by this link event if it's no longer in snap range
if (snapping_pin_changed && GImNodes->SnapLinkIdx.HasValue())
{
BeginLinkDetach(
editor,
GImNodes->SnapLinkIdx.Value(),
editor.ClickInteraction.LinkCreation.EndPinIdx.Value());
}
const ImVec2 start_pos = GetScreenSpacePinCoordinates(editor, start_pin);
// If we are within the hover radius of a receiving pin, snap the link
// endpoint to it
const ImVec2 end_pos = should_snap
? GetScreenSpacePinCoordinates(
editor, editor.Pins.Pool[GImNodes->HoveredPinIdx.Value()])
: GImNodes->MousePos;
const CubicBezier cubic_bezier = GetCubicBezier(
start_pos, end_pos, start_pin.Type, GImNodes->Style.LinkLineSegmentsPerLength);
#if IMGUI_VERSION_NUM < 18000
GImNodes->CanvasDrawList->AddBezierCurve(
#else
GImNodes->CanvasDrawList->AddBezierCubic(
#endif
cubic_bezier.P0,
cubic_bezier.P1,
cubic_bezier.P2,
cubic_bezier.P3,
GImNodes->Style.Colors[ImNodesCol_Link],
GImNodes->Style.LinkThickness,
cubic_bezier.NumSegments);
const bool link_creation_on_snap =
GImNodes->HoveredPinIdx.HasValue() &&
(editor.Pins.Pool[GImNodes->HoveredPinIdx.Value()].Flags &
ImNodesAttributeFlags_EnableLinkCreationOnSnap);
if (!should_snap)
{
editor.ClickInteraction.LinkCreation.EndPinIdx.Reset();
}
const bool create_link =
should_snap && (GImNodes->LeftMouseReleased || link_creation_on_snap);
if (create_link && !maybe_duplicate_link_idx.HasValue())
{
// Avoid send OnLinkCreated() events every frame if the snap link is not saved
// (only applies for EnableLinkCreationOnSnap)
if (!GImNodes->LeftMouseReleased &&
editor.ClickInteraction.LinkCreation.EndPinIdx == GImNodes->HoveredPinIdx)
{
break;
}
GImNodes->ImNodesUIState |= ImNodesUIState_LinkCreated;
editor.ClickInteraction.LinkCreation.EndPinIdx = GImNodes->HoveredPinIdx.Value();
}
if (GImNodes->LeftMouseReleased)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_None;
if (!create_link)
{
GImNodes->ImNodesUIState |= ImNodesUIState_LinkDropped;
}
}
}
break;
case ImNodesClickInteractionType_Panning:
{
const bool dragging = GImNodes->AltMouseDragging;
if (dragging)
{
editor.Panning += ImGui::GetIO().MouseDelta;
}
else
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_None;
}
}
break;
case ImNodesClickInteractionType_ImGuiItem:
{
if (GImNodes->LeftMouseReleased)
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_None;
}
}
case ImNodesClickInteractionType_None:
break;
default:
IM_ASSERT(!"Unreachable code!");
break;
}
}
void ResolveOccludedPins(const ImNodesEditorContext& editor, ImVector& occluded_pin_indices)
{
const ImVector& depth_stack = editor.NodeDepthOrder;
occluded_pin_indices.resize(0);
if (depth_stack.Size < 2)
{
return;
}
// For each node in the depth stack
for (int depth_idx = 0; depth_idx < (depth_stack.Size - 1); ++depth_idx)
{
const ImNodeData& node_below = editor.Nodes.Pool[depth_stack[depth_idx]];
// Iterate over the rest of the depth stack to find nodes overlapping the pins
for (int next_depth_idx = depth_idx + 1; next_depth_idx < depth_stack.Size;
++next_depth_idx)
{
const ImRect& rect_above = editor.Nodes.Pool[depth_stack[next_depth_idx]].Rect;
// Iterate over each pin
for (int idx = 0; idx < node_below.PinIndices.Size; ++idx)
{
const int pin_idx = node_below.PinIndices[idx];
const ImVec2& pin_pos = editor.Pins.Pool[pin_idx].Pos;
if (rect_above.Contains(pin_pos))
{
occluded_pin_indices.push_back(pin_idx);
}
}
}
}
}
ImOptionalIndex ResolveHoveredPin(
const ImObjectPool& pins,
const ImVector& occluded_pin_indices)
{
float smallest_distance = FLT_MAX;
ImOptionalIndex pin_idx_with_smallest_distance;
const float hover_radius_sqr = GImNodes->Style.PinHoverRadius * GImNodes->Style.PinHoverRadius;
for (int idx = 0; idx < pins.Pool.Size; ++idx)
{
if (!pins.InUse[idx])
{
continue;
}
if (occluded_pin_indices.contains(idx))
{
continue;
}
const ImVec2& pin_pos = pins.Pool[idx].Pos;
const float distance_sqr = ImLengthSqr(pin_pos - GImNodes->MousePos);
// TODO: GImNodes->Style.PinHoverRadius needs to be copied into pin data and the pin-local
// value used here. This is no longer called in BeginAttribute/EndAttribute scope and the
// detected pin might have a different hover radius than what the user had when calling
// BeginAttribute/EndAttribute.
if (distance_sqr < hover_radius_sqr && distance_sqr < smallest_distance)
{
smallest_distance = distance_sqr;
pin_idx_with_smallest_distance = idx;
}
}
return pin_idx_with_smallest_distance;
}
ImOptionalIndex ResolveHoveredNode(const ImVector& depth_stack)
{
if (GImNodes->NodeIndicesOverlappingWithMouse.size() == 0)
{
return ImOptionalIndex();
}
if (GImNodes->NodeIndicesOverlappingWithMouse.size() == 1)
{
return ImOptionalIndex(GImNodes->NodeIndicesOverlappingWithMouse[0]);
}
int largest_depth_idx = -1;
int node_idx_on_top = -1;
for (int i = 0; i < GImNodes->NodeIndicesOverlappingWithMouse.size(); ++i)
{
const int node_idx = GImNodes->NodeIndicesOverlappingWithMouse[i];
for (int depth_idx = 0; depth_idx < depth_stack.size(); ++depth_idx)
{
if (depth_stack[depth_idx] == node_idx && (depth_idx > largest_depth_idx))
{
largest_depth_idx = depth_idx;
node_idx_on_top = node_idx;
}
}
}
IM_ASSERT(node_idx_on_top != -1);
return ImOptionalIndex(node_idx_on_top);
}
ImOptionalIndex ResolveHoveredLink(
const ImObjectPool& links,
const ImObjectPool& pins)
{
float smallest_distance = FLT_MAX;
ImOptionalIndex link_idx_with_smallest_distance;
// There are two ways a link can be detected as "hovered".
// 1. The link is within hover distance to the mouse. The closest such link is selected as being
// hovered over.
// 2. If the link is connected to the currently hovered pin.
//
// The latter is a requirement for link detaching with drag click to work, as both a link and
// pin are required to be hovered over for the feature to work.
for (int idx = 0; idx < links.Pool.Size; ++idx)
{
if (!links.InUse[idx])
{
continue;
}
const ImLinkData& link = links.Pool[idx];
const ImPinData& start_pin = pins.Pool[link.StartPinIdx];
const ImPinData& end_pin = pins.Pool[link.EndPinIdx];
// If there is a hovered pin links can only be considered hovered if they use that pin
if (GImNodes->HoveredPinIdx.HasValue())
{
if (GImNodes->HoveredPinIdx == link.StartPinIdx ||
GImNodes->HoveredPinIdx == link.EndPinIdx)
{
return idx;
}
continue;
}
// TODO: the calculated CubicBeziers could be cached since we generate them again when
// rendering the links
const CubicBezier cubic_bezier = GetCubicBezier(
start_pin.Pos, end_pin.Pos, start_pin.Type, GImNodes->Style.LinkLineSegmentsPerLength);
// The distance test
{
const ImRect link_rect = GetContainingRectForCubicBezier(cubic_bezier);
// First, do a simple bounding box test against the box containing the link
// to see whether calculating the distance to the link is worth doing.
if (link_rect.Contains(GImNodes->MousePos))
{
const float distance = GetDistanceToCubicBezier(
GImNodes->MousePos, cubic_bezier, cubic_bezier.NumSegments);
// TODO: GImNodes->Style.LinkHoverDistance could be also copied into ImLinkData,
// since we're not calling this function in the same scope as ImNodes::Link(). The
// rendered/detected link might have a different hover distance than what the user
// had specified when calling Link()
if (distance < GImNodes->Style.LinkHoverDistance && distance < smallest_distance)
{
smallest_distance = distance;
link_idx_with_smallest_distance = idx;
}
}
}
}
return link_idx_with_smallest_distance;
}
// [SECTION] render helpers
inline ImRect GetItemRect() { return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); }
inline ImVec2 GetNodeTitleBarOrigin(const ImNodeData& node)
{
return node.Origin + node.LayoutStyle.Padding;
}
inline ImVec2 GetNodeContentOrigin(const ImNodeData& node)
{
const ImVec2 title_bar_height =
ImVec2(0.f, node.TitleBarContentRect.GetHeight() + 2.0f * node.LayoutStyle.Padding.y);
return node.Origin + title_bar_height + node.LayoutStyle.Padding;
}
inline ImRect GetNodeTitleRect(const ImNodeData& node)
{
ImRect expanded_title_rect = node.TitleBarContentRect;
expanded_title_rect.Expand(node.LayoutStyle.Padding);
return ImRect(
expanded_title_rect.Min,
expanded_title_rect.Min + ImVec2(node.Rect.GetWidth(), 0.f) +
ImVec2(0.f, expanded_title_rect.GetHeight()));
}
void DrawGrid(ImNodesEditorContext& editor, const ImVec2& canvas_size)
{
const ImVec2 offset = editor.Panning;
ImU32 line_color = GImNodes->Style.Colors[ImNodesCol_GridLine];
ImU32 line_color_prim = GImNodes->Style.Colors[ImNodesCol_GridLinePrimary];
bool draw_primary = GImNodes->Style.Flags & ImNodesStyleFlags_GridLinesPrimary;
for (float x = fmodf(offset.x, GImNodes->Style.GridSpacing); x < canvas_size.x;
x += GImNodes->Style.GridSpacing)
{
GImNodes->CanvasDrawList->AddLine(
EditorSpaceToScreenSpace(ImVec2(x, 0.0f)),
EditorSpaceToScreenSpace(ImVec2(x, canvas_size.y)),
offset.x - x == 0.f && draw_primary ? line_color_prim : line_color);
}
for (float y = fmodf(offset.y, GImNodes->Style.GridSpacing); y < canvas_size.y;
y += GImNodes->Style.GridSpacing)
{
GImNodes->CanvasDrawList->AddLine(
EditorSpaceToScreenSpace(ImVec2(0.0f, y)),
EditorSpaceToScreenSpace(ImVec2(canvas_size.x, y)),
offset.y - y == 0.f && draw_primary ? line_color_prim : line_color);
}
}
struct QuadOffsets
{
ImVec2 TopLeft, BottomLeft, BottomRight, TopRight;
};
QuadOffsets CalculateQuadOffsets(const float side_length)
{
const float half_side = 0.5f * side_length;
QuadOffsets offset;
offset.TopLeft = ImVec2(-half_side, half_side);
offset.BottomLeft = ImVec2(-half_side, -half_side);
offset.BottomRight = ImVec2(half_side, -half_side);
offset.TopRight = ImVec2(half_side, half_side);
return offset;
}
struct TriangleOffsets
{
ImVec2 TopLeft, BottomLeft, Right;
};
TriangleOffsets CalculateTriangleOffsets(const float side_length)
{
// Calculates the Vec2 offsets from an equilateral triangle's midpoint to
// its vertices. Here is how the left_offset and right_offset are
// calculated.
//
// For an equilateral triangle of side length s, the
// triangle's height, h, is h = s * sqrt(3) / 2.
//
// The length from the base to the midpoint is (1 / 3) * h. The length from
// the midpoint to the triangle vertex is (2 / 3) * h.
const float sqrt_3 = sqrtf(3.0f);
const float left_offset = -0.1666666666667f * sqrt_3 * side_length;
const float right_offset = 0.333333333333f * sqrt_3 * side_length;
const float vertical_offset = 0.5f * side_length;
TriangleOffsets offset;
offset.TopLeft = ImVec2(left_offset, vertical_offset);
offset.BottomLeft = ImVec2(left_offset, -vertical_offset);
offset.Right = ImVec2(right_offset, 0.f);
return offset;
}
void DrawPinShape(const ImVec2& pin_pos, const ImPinData& pin, const ImU32 pin_color)
{
static const int CIRCLE_NUM_SEGMENTS = 8;
switch (pin.Shape)
{
case ImNodesPinShape_Circle:
{
GImNodes->CanvasDrawList->AddCircle(
pin_pos,
GImNodes->Style.PinCircleRadius,
pin_color,
CIRCLE_NUM_SEGMENTS,
GImNodes->Style.PinLineThickness);
}
break;
case ImNodesPinShape_CircleFilled:
{
GImNodes->CanvasDrawList->AddCircleFilled(
pin_pos, GImNodes->Style.PinCircleRadius, pin_color, CIRCLE_NUM_SEGMENTS);
}
break;
case ImNodesPinShape_Quad:
{
const QuadOffsets offset = CalculateQuadOffsets(GImNodes->Style.PinQuadSideLength);
GImNodes->CanvasDrawList->AddQuad(
pin_pos + offset.TopLeft,
pin_pos + offset.BottomLeft,
pin_pos + offset.BottomRight,
pin_pos + offset.TopRight,
pin_color,
GImNodes->Style.PinLineThickness);
}
break;
case ImNodesPinShape_QuadFilled:
{
const QuadOffsets offset = CalculateQuadOffsets(GImNodes->Style.PinQuadSideLength);
GImNodes->CanvasDrawList->AddQuadFilled(
pin_pos + offset.TopLeft,
pin_pos + offset.BottomLeft,
pin_pos + offset.BottomRight,
pin_pos + offset.TopRight,
pin_color);
}
break;
case ImNodesPinShape_Triangle:
{
const TriangleOffsets offset =
CalculateTriangleOffsets(GImNodes->Style.PinTriangleSideLength);
GImNodes->CanvasDrawList->AddTriangle(
pin_pos + offset.TopLeft,
pin_pos + offset.BottomLeft,
pin_pos + offset.Right,
pin_color,
// NOTE: for some weird reason, the line drawn by AddTriangle is
// much thinner than the lines drawn by AddCircle or AddQuad.
// Multiplying the line thickness by two seemed to solve the
// problem at a few different thickness values.
2.f * GImNodes->Style.PinLineThickness);
}
break;
case ImNodesPinShape_TriangleFilled:
{
const TriangleOffsets offset =
CalculateTriangleOffsets(GImNodes->Style.PinTriangleSideLength);
GImNodes->CanvasDrawList->AddTriangleFilled(
pin_pos + offset.TopLeft,
pin_pos + offset.BottomLeft,
pin_pos + offset.Right,
pin_color);
}
break;
default:
IM_ASSERT(!"Invalid PinShape value!");
break;
}
}
void DrawPin(ImNodesEditorContext& editor, const int pin_idx)
{
ImPinData& pin = editor.Pins.Pool[pin_idx];
const ImRect& parent_node_rect = editor.Nodes.Pool[pin.ParentNodeIdx].Rect;
pin.Pos = GetScreenSpacePinCoordinates(parent_node_rect, pin.AttributeRect, pin.Type);
ImU32 pin_color = pin.ColorStyle.Background;
if (GImNodes->HoveredPinIdx == pin_idx)
{
pin_color = pin.ColorStyle.Hovered;
}
DrawPinShape(pin.Pos, pin, pin_color);
}
void DrawNode(ImNodesEditorContext& editor, const int node_idx)
{
const ImNodeData& node = editor.Nodes.Pool[node_idx];
ImGui::SetCursorPos(node.Origin + editor.Panning);
const bool node_hovered =
GImNodes->HoveredNodeIdx == node_idx &&
editor.ClickInteraction.Type != ImNodesClickInteractionType_BoxSelection;
ImU32 node_background = node.ColorStyle.Background;
ImU32 titlebar_background = node.ColorStyle.Titlebar;
if (editor.SelectedNodeIndices.contains(node_idx))
{
node_background = node.ColorStyle.BackgroundSelected;
titlebar_background = node.ColorStyle.TitlebarSelected;
}
else if (node_hovered)
{
node_background = node.ColorStyle.BackgroundHovered;
titlebar_background = node.ColorStyle.TitlebarHovered;
}
{
// node base
GImNodes->CanvasDrawList->AddRectFilled(
node.Rect.Min, node.Rect.Max, node_background, node.LayoutStyle.CornerRounding);
// title bar:
if (node.TitleBarContentRect.GetHeight() > 0.f)
{
ImRect title_bar_rect = GetNodeTitleRect(node);
#if IMGUI_VERSION_NUM < 18200
GImNodes->CanvasDrawList->AddRectFilled(
title_bar_rect.Min,
title_bar_rect.Max,
titlebar_background,
node.LayoutStyle.CornerRounding,
ImDrawCornerFlags_Top);
#else
GImNodes->CanvasDrawList->AddRectFilled(
title_bar_rect.Min,
title_bar_rect.Max,
titlebar_background,
node.LayoutStyle.CornerRounding,
ImDrawFlags_RoundCornersTop);
#endif
}
if ((GImNodes->Style.Flags & ImNodesStyleFlags_NodeOutline) != 0)
{
#if IMGUI_VERSION_NUM < 18200
GImNodes->CanvasDrawList->AddRect(
node.Rect.Min,
node.Rect.Max,
node.ColorStyle.Outline,
node.LayoutStyle.CornerRounding,
ImDrawCornerFlags_All,
node.LayoutStyle.BorderThickness);
#else
GImNodes->CanvasDrawList->AddRect(
node.Rect.Min,
node.Rect.Max,
node.ColorStyle.Outline,
node.LayoutStyle.CornerRounding,
ImDrawFlags_RoundCornersAll,
node.LayoutStyle.BorderThickness);
#endif
}
}
for (int i = 0; i < node.PinIndices.size(); ++i)
{
DrawPin(editor, node.PinIndices[i]);
}
if (node_hovered)
{
GImNodes->HoveredNodeIdx = node_idx;
}
}
void DrawLink(ImNodesEditorContext& editor, const int link_idx)
{
const ImLinkData& link = editor.Links.Pool[link_idx];
const ImPinData& start_pin = editor.Pins.Pool[link.StartPinIdx];
const ImPinData& end_pin = editor.Pins.Pool[link.EndPinIdx];
const CubicBezier cubic_bezier = GetCubicBezier(
start_pin.Pos, end_pin.Pos, start_pin.Type, GImNodes->Style.LinkLineSegmentsPerLength);
const bool link_hovered =
GImNodes->HoveredLinkIdx == link_idx &&
editor.ClickInteraction.Type != ImNodesClickInteractionType_BoxSelection;
if (link_hovered)
{
GImNodes->HoveredLinkIdx = link_idx;
}
// It's possible for a link to be deleted in begin_link_interaction. A user
// may detach a link, resulting in the link wire snapping to the mouse
// position.
//
// In other words, skip rendering the link if it was deleted.
if (GImNodes->DeletedLinkIdx == link_idx)
{
return;
}
ImU32 link_color = link.ColorStyle.Base;
if (editor.SelectedLinkIndices.contains(link_idx))
{
link_color = link.ColorStyle.Selected;
}
else if (link_hovered)
{
link_color = link.ColorStyle.Hovered;
}
#if IMGUI_VERSION_NUM < 18000
GImNodes->CanvasDrawList->AddBezierCurve(
#else
GImNodes->CanvasDrawList->AddBezierCubic(
#endif
cubic_bezier.P0,
cubic_bezier.P1,
cubic_bezier.P2,
cubic_bezier.P3,
link_color,
GImNodes->Style.LinkThickness,
cubic_bezier.NumSegments);
}
void BeginPinAttribute(
const int id,
const ImNodesAttributeType type,
const ImNodesPinShape shape,
const int node_idx)
{
// Make sure to call BeginNode() before calling
// BeginAttribute()
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);
GImNodes->CurrentScope = ImNodesScope_Attribute;
ImGui::BeginGroup();
ImGui::PushID(id);
ImNodesEditorContext& editor = EditorContextGet();
GImNodes->CurrentAttributeId = id;
const int pin_idx = ObjectPoolFindOrCreateIndex(editor.Pins, id);
GImNodes->CurrentPinIdx = pin_idx;
ImPinData& pin = editor.Pins.Pool[pin_idx];
pin.Id = id;
pin.ParentNodeIdx = node_idx;
pin.Type = type;
pin.Shape = shape;
pin.Flags = GImNodes->CurrentAttributeFlags;
pin.ColorStyle.Background = GImNodes->Style.Colors[ImNodesCol_Pin];
pin.ColorStyle.Hovered = GImNodes->Style.Colors[ImNodesCol_PinHovered];
}
void EndPinAttribute()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Attribute);
GImNodes->CurrentScope = ImNodesScope_Node;
ImGui::PopID();
ImGui::EndGroup();
if (ImGui::IsItemActive())
{
GImNodes->ActiveAttribute = true;
GImNodes->ActiveAttributeId = GImNodes->CurrentAttributeId;
}
ImNodesEditorContext& editor = EditorContextGet();
ImPinData& pin = editor.Pins.Pool[GImNodes->CurrentPinIdx];
ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];
pin.AttributeRect = GetItemRect();
node.PinIndices.push_back(GImNodes->CurrentPinIdx);
}
void Initialize(ImNodesContext* context)
{
context->CanvasOriginScreenSpace = ImVec2(0.0f, 0.0f);
context->CanvasRectScreenSpace = ImRect(ImVec2(0.f, 0.f), ImVec2(0.f, 0.f));
context->CurrentScope = ImNodesScope_None;
context->CurrentPinIdx = INT_MAX;
context->CurrentNodeIdx = INT_MAX;
context->DefaultEditorCtx = EditorContextCreate();
context->EditorCtx = context->DefaultEditorCtx;
context->CurrentAttributeFlags = ImNodesAttributeFlags_None;
context->AttributeFlagStack.push_back(GImNodes->CurrentAttributeFlags);
StyleColorsDark(&context->Style);
}
void Shutdown(ImNodesContext* ctx) { EditorContextFree(ctx->DefaultEditorCtx); }
// [SECTION] minimap
static inline bool IsMiniMapActive()
{
ImNodesEditorContext& editor = EditorContextGet();
return editor.MiniMapEnabled && editor.MiniMapSizeFraction > 0.0f;
}
static inline bool IsMiniMapHovered()
{
ImNodesEditorContext& editor = EditorContextGet();
return IsMiniMapActive() &&
ImGui::IsMouseHoveringRect(
editor.MiniMapRectScreenSpace.Min, editor.MiniMapRectScreenSpace.Max);
}
static inline void CalcMiniMapLayout()
{
ImNodesEditorContext& editor = EditorContextGet();
const ImVec2 offset = GImNodes->Style.MiniMapOffset;
const ImVec2 border = GImNodes->Style.MiniMapPadding;
const ImRect editor_rect = GImNodes->CanvasRectScreenSpace;
// Compute the size of the mini-map area
ImVec2 mini_map_size;
float mini_map_scaling;
{
const ImVec2 max_size =
ImFloor(editor_rect.GetSize() * editor.MiniMapSizeFraction - border * 2.0f);
const float max_size_aspect_ratio = max_size.x / max_size.y;
const ImVec2 grid_content_size = editor.GridContentBounds.IsInverted()
? max_size
: ImFloor(editor.GridContentBounds.GetSize());
const float grid_content_aspect_ratio = grid_content_size.x / grid_content_size.y;
mini_map_size = ImFloor(
grid_content_aspect_ratio > max_size_aspect_ratio
? ImVec2(max_size.x, max_size.x / grid_content_aspect_ratio)
: ImVec2(max_size.y * grid_content_aspect_ratio, max_size.y));
mini_map_scaling = mini_map_size.x / grid_content_size.x;
}
// Compute location of the mini-map
ImVec2 mini_map_pos;
{
ImVec2 align;
switch (editor.MiniMapLocation)
{
case ImNodesMiniMapLocation_BottomRight:
align.x = 1.0f;
align.y = 1.0f;
break;
case ImNodesMiniMapLocation_BottomLeft:
align.x = 0.0f;
align.y = 1.0f;
break;
case ImNodesMiniMapLocation_TopRight:
align.x = 1.0f;
align.y = 0.0f;
break;
case ImNodesMiniMapLocation_TopLeft: // [[fallthrough]]
default:
align.x = 0.0f;
align.y = 0.0f;
break;
}
const ImVec2 top_left_pos = editor_rect.Min + offset + border;
const ImVec2 bottom_right_pos = editor_rect.Max - offset - border - mini_map_size;
mini_map_pos = ImFloor(ImLerp(top_left_pos, bottom_right_pos, align));
}
editor.MiniMapRectScreenSpace =
ImRect(mini_map_pos - border, mini_map_pos + mini_map_size + border);
editor.MiniMapContentScreenSpace = ImRect(mini_map_pos, mini_map_pos + mini_map_size);
editor.MiniMapScaling = mini_map_scaling;
}
static void MiniMapDrawNode(ImNodesEditorContext& editor, const int node_idx)
{
const ImNodeData& node = editor.Nodes.Pool[node_idx];
const ImRect node_rect = ScreenSpaceToMiniMapSpace(editor, node.Rect);
// Round to near whole pixel value for corner-rounding to prevent visual glitches
const float mini_map_node_rounding =
floorf(node.LayoutStyle.CornerRounding * editor.MiniMapScaling);
ImU32 mini_map_node_background;
if (editor.ClickInteraction.Type == ImNodesClickInteractionType_None &&
ImGui::IsMouseHoveringRect(node_rect.Min, node_rect.Max))
{
mini_map_node_background = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundHovered];
// Run user callback when hovering a mini-map node
if (editor.MiniMapNodeHoveringCallback)
{
editor.MiniMapNodeHoveringCallback(node.Id, editor.MiniMapNodeHoveringCallbackUserData);
}
}
else if (editor.SelectedNodeIndices.contains(node_idx))
{
mini_map_node_background = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackgroundSelected];
}
else
{
mini_map_node_background = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeBackground];
}
const ImU32 mini_map_node_outline = GImNodes->Style.Colors[ImNodesCol_MiniMapNodeOutline];
GImNodes->CanvasDrawList->AddRectFilled(
node_rect.Min, node_rect.Max, mini_map_node_background, mini_map_node_rounding);
GImNodes->CanvasDrawList->AddRect(
node_rect.Min, node_rect.Max, mini_map_node_outline, mini_map_node_rounding);
}
static void MiniMapDrawLink(ImNodesEditorContext& editor, const int link_idx)
{
const ImLinkData& link = editor.Links.Pool[link_idx];
const ImPinData& start_pin = editor.Pins.Pool[link.StartPinIdx];
const ImPinData& end_pin = editor.Pins.Pool[link.EndPinIdx];
const CubicBezier cubic_bezier = GetCubicBezier(
ScreenSpaceToMiniMapSpace(editor, start_pin.Pos),
ScreenSpaceToMiniMapSpace(editor, end_pin.Pos),
start_pin.Type,
GImNodes->Style.LinkLineSegmentsPerLength / editor.MiniMapScaling);
// It's possible for a link to be deleted in begin_link_interaction. A user
// may detach a link, resulting in the link wire snapping to the mouse
// position.
//
// In other words, skip rendering the link if it was deleted.
if (GImNodes->DeletedLinkIdx == link_idx)
{
return;
}
const ImU32 link_color =
GImNodes->Style.Colors
[editor.SelectedLinkIndices.contains(link_idx) ? ImNodesCol_MiniMapLinkSelected
: ImNodesCol_MiniMapLink];
#if IMGUI_VERSION_NUM < 18000
GImNodes->CanvasDrawList->AddBezierCurve(
#else
GImNodes->CanvasDrawList->AddBezierCubic(
#endif
cubic_bezier.P0,
cubic_bezier.P1,
cubic_bezier.P2,
cubic_bezier.P3,
link_color,
GImNodes->Style.LinkThickness * editor.MiniMapScaling,
cubic_bezier.NumSegments);
}
static void MiniMapUpdate()
{
ImNodesEditorContext& editor = EditorContextGet();
ImU32 mini_map_background;
if (IsMiniMapHovered())
{
mini_map_background = GImNodes->Style.Colors[ImNodesCol_MiniMapBackgroundHovered];
}
else
{
mini_map_background = GImNodes->Style.Colors[ImNodesCol_MiniMapBackground];
}
// Create a child window bellow mini-map, so it blocks all mouse interaction on canvas.
int flags = ImGuiWindowFlags_NoBackground;
ImGui::SetCursorScreenPos(editor.MiniMapRectScreenSpace.Min);
ImGui::BeginChild("minimap", editor.MiniMapRectScreenSpace.GetSize(), false, flags);
const ImRect& mini_map_rect = editor.MiniMapRectScreenSpace;
// Draw minimap background and border
GImNodes->CanvasDrawList->AddRectFilled(
mini_map_rect.Min, mini_map_rect.Max, mini_map_background);
GImNodes->CanvasDrawList->AddRect(
mini_map_rect.Min, mini_map_rect.Max, GImNodes->Style.Colors[ImNodesCol_MiniMapOutline]);
// Clip draw list items to mini-map rect (after drawing background/outline)
GImNodes->CanvasDrawList->PushClipRect(
mini_map_rect.Min, mini_map_rect.Max, true /* intersect with editor clip-rect */);
// Draw links first so they appear under nodes, and we can use the same draw channel
for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)
{
if (editor.Links.InUse[link_idx])
{
MiniMapDrawLink(editor, link_idx);
}
}
for (int node_idx = 0; node_idx < editor.Nodes.Pool.size(); ++node_idx)
{
if (editor.Nodes.InUse[node_idx])
{
MiniMapDrawNode(editor, node_idx);
}
}
// Draw editor canvas rect inside mini-map
{
const ImU32 canvas_color = GImNodes->Style.Colors[ImNodesCol_MiniMapCanvas];
const ImU32 outline_color = GImNodes->Style.Colors[ImNodesCol_MiniMapCanvasOutline];
const ImRect rect = ScreenSpaceToMiniMapSpace(editor, GImNodes->CanvasRectScreenSpace);
GImNodes->CanvasDrawList->AddRectFilled(rect.Min, rect.Max, canvas_color);
GImNodes->CanvasDrawList->AddRect(rect.Min, rect.Max, outline_color);
}
// Have to pop mini-map clip rect
GImNodes->CanvasDrawList->PopClipRect();
bool mini_map_is_hovered = ImGui::IsWindowHovered();
ImGui::EndChild();
bool center_on_click = mini_map_is_hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left) &&
editor.ClickInteraction.Type == ImNodesClickInteractionType_None &&
!GImNodes->NodeIdxSubmissionOrder.empty();
if (center_on_click)
{
ImVec2 target = MiniMapSpaceToGridSpace(editor, ImGui::GetMousePos());
ImVec2 center = GImNodes->CanvasRectScreenSpace.GetSize() * 0.5f;
editor.Panning = ImFloor(center - target);
}
// Reset callback info after use
editor.MiniMapNodeHoveringCallback = NULL;
editor.MiniMapNodeHoveringCallbackUserData = NULL;
}
// [SECTION] selection helpers
template
void SelectObject(const ImObjectPool& objects, ImVector& selected_indices, const int id)
{
const int idx = ObjectPoolFind(objects, id);
IM_ASSERT(idx >= 0);
IM_ASSERT(selected_indices.find(idx) == selected_indices.end());
selected_indices.push_back(idx);
}
template
void ClearObjectSelection(
const ImObjectPool& objects,
ImVector& selected_indices,
const int id)
{
const int idx = ObjectPoolFind(objects, id);
IM_ASSERT(idx >= 0);
IM_ASSERT(selected_indices.find(idx) != selected_indices.end());
selected_indices.find_erase_unsorted(idx);
}
template
bool IsObjectSelected(const ImObjectPool& objects, ImVector& selected_indices, const int id)
{
const int idx = ObjectPoolFind(objects, id);
return selected_indices.find(idx) != selected_indices.end();
}
} // namespace
} // namespace IMNODES_NAMESPACE
// [SECTION] API implementation
ImNodesIO::EmulateThreeButtonMouse::EmulateThreeButtonMouse() : Modifier(NULL) {}
ImNodesIO::LinkDetachWithModifierClick::LinkDetachWithModifierClick() : Modifier(NULL) {}
ImNodesIO::MultipleSelectModifier::MultipleSelectModifier() : Modifier(NULL) {}
ImNodesIO::ImNodesIO()
: EmulateThreeButtonMouse(), LinkDetachWithModifierClick(),
AltMouseButton(ImGuiMouseButton_Middle), AutoPanningSpeed(1000.0f)
{
}
ImNodesStyle::ImNodesStyle()
: GridSpacing(24.f), NodeCornerRounding(4.f), NodePadding(8.f, 8.f), NodeBorderThickness(1.f),
LinkThickness(3.f), LinkLineSegmentsPerLength(0.1f), LinkHoverDistance(10.f),
PinCircleRadius(4.f), PinQuadSideLength(7.f), PinTriangleSideLength(9.5),
PinLineThickness(1.f), PinHoverRadius(10.f), PinOffset(0.f), MiniMapPadding(8.0f, 8.0f),
MiniMapOffset(4.0f, 4.0f), Flags(ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines),
Colors()
{
}
namespace IMNODES_NAMESPACE
{
ImNodesContext* CreateContext()
{
ImNodesContext* ctx = IM_NEW(ImNodesContext)();
if (GImNodes == NULL)
SetCurrentContext(ctx);
Initialize(ctx);
return ctx;
}
void DestroyContext(ImNodesContext* ctx)
{
if (ctx == NULL)
ctx = GImNodes;
Shutdown(ctx);
if (GImNodes == ctx)
SetCurrentContext(NULL);
IM_DELETE(ctx);
}
ImNodesContext* GetCurrentContext() { return GImNodes; }
void SetCurrentContext(ImNodesContext* ctx) { GImNodes = ctx; }
ImNodesEditorContext* EditorContextCreate()
{
void* mem = ImGui::MemAlloc(sizeof(ImNodesEditorContext));
new (mem) ImNodesEditorContext();
return (ImNodesEditorContext*)mem;
}
void EditorContextFree(ImNodesEditorContext* ctx)
{
ctx->~ImNodesEditorContext();
ImGui::MemFree(ctx);
}
void EditorContextSet(ImNodesEditorContext* ctx) { GImNodes->EditorCtx = ctx; }
ImVec2 EditorContextGetPanning()
{
const ImNodesEditorContext& editor = EditorContextGet();
return editor.Panning;
}
void EditorContextResetPanning(const ImVec2& pos)
{
ImNodesEditorContext& editor = EditorContextGet();
editor.Panning = pos;
}
void EditorContextMoveToNode(const int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);
editor.Panning.x = -node.Origin.x;
editor.Panning.y = -node.Origin.y;
}
void SetImGuiContext(ImGuiContext* ctx) { ImGui::SetCurrentContext(ctx); }
ImNodesIO& GetIO() { return GImNodes->Io; }
ImNodesStyle& GetStyle() { return GImNodes->Style; }
void StyleColorsDark(ImNodesStyle* dest)
{
if (dest == nullptr)
{
dest = &GImNodes->Style;
}
dest->Colors[ImNodesCol_NodeBackground] = IM_COL32(50, 50, 50, 255);
dest->Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(75, 75, 75, 255);
dest->Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(75, 75, 75, 255);
dest->Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255);
// title bar colors match ImGui's titlebg colors
dest->Colors[ImNodesCol_TitleBar] = IM_COL32(41, 74, 122, 255);
dest->Colors[ImNodesCol_TitleBarHovered] = IM_COL32(66, 150, 250, 255);
dest->Colors[ImNodesCol_TitleBarSelected] = IM_COL32(66, 150, 250, 255);
// link colors match ImGui's slider grab colors
dest->Colors[ImNodesCol_Link] = IM_COL32(61, 133, 224, 200);
dest->Colors[ImNodesCol_LinkHovered] = IM_COL32(66, 150, 250, 255);
dest->Colors[ImNodesCol_LinkSelected] = IM_COL32(66, 150, 250, 255);
// pin colors match ImGui's button colors
dest->Colors[ImNodesCol_Pin] = IM_COL32(53, 150, 250, 180);
dest->Colors[ImNodesCol_PinHovered] = IM_COL32(53, 150, 250, 255);
dest->Colors[ImNodesCol_BoxSelector] = IM_COL32(61, 133, 224, 30);
dest->Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(61, 133, 224, 150);
dest->Colors[ImNodesCol_GridBackground] = IM_COL32(40, 40, 50, 200);
dest->Colors[ImNodesCol_GridLine] = IM_COL32(200, 200, 200, 40);
dest->Colors[ImNodesCol_GridLinePrimary] = IM_COL32(240, 240, 240, 60);
// minimap colors
dest->Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 150);
dest->Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200);
dest->Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100);
dest->Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200);
dest->Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100);
dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered] = IM_COL32(200, 200, 200, 255);
dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] =
dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered];
dest->Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100);
dest->Colors[ImNodesCol_MiniMapLink] = dest->Colors[ImNodesCol_Link];
dest->Colors[ImNodesCol_MiniMapLinkSelected] = dest->Colors[ImNodesCol_LinkSelected];
dest->Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25);
dest->Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200);
}
void StyleColorsClassic(ImNodesStyle* dest)
{
if (dest == nullptr)
{
dest = &GImNodes->Style;
}
dest->Colors[ImNodesCol_NodeBackground] = IM_COL32(50, 50, 50, 255);
dest->Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(75, 75, 75, 255);
dest->Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(75, 75, 75, 255);
dest->Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255);
dest->Colors[ImNodesCol_TitleBar] = IM_COL32(69, 69, 138, 255);
dest->Colors[ImNodesCol_TitleBarHovered] = IM_COL32(82, 82, 161, 255);
dest->Colors[ImNodesCol_TitleBarSelected] = IM_COL32(82, 82, 161, 255);
dest->Colors[ImNodesCol_Link] = IM_COL32(255, 255, 255, 100);
dest->Colors[ImNodesCol_LinkHovered] = IM_COL32(105, 99, 204, 153);
dest->Colors[ImNodesCol_LinkSelected] = IM_COL32(105, 99, 204, 153);
dest->Colors[ImNodesCol_Pin] = IM_COL32(89, 102, 156, 170);
dest->Colors[ImNodesCol_PinHovered] = IM_COL32(102, 122, 179, 200);
dest->Colors[ImNodesCol_BoxSelector] = IM_COL32(82, 82, 161, 100);
dest->Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(82, 82, 161, 255);
dest->Colors[ImNodesCol_GridBackground] = IM_COL32(40, 40, 50, 200);
dest->Colors[ImNodesCol_GridLine] = IM_COL32(200, 200, 200, 40);
dest->Colors[ImNodesCol_GridLinePrimary] = IM_COL32(240, 240, 240, 60);
// minimap colors
dest->Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 100);
dest->Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200);
dest->Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100);
dest->Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200);
dest->Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100);
dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] =
dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered];
dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = IM_COL32(200, 200, 240, 255);
dest->Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100);
dest->Colors[ImNodesCol_MiniMapLink] = dest->Colors[ImNodesCol_Link];
dest->Colors[ImNodesCol_MiniMapLinkSelected] = dest->Colors[ImNodesCol_LinkSelected];
dest->Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25);
dest->Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200);
}
void StyleColorsLight(ImNodesStyle* dest)
{
if (dest == nullptr)
{
dest = &GImNodes->Style;
}
dest->Colors[ImNodesCol_NodeBackground] = IM_COL32(240, 240, 240, 255);
dest->Colors[ImNodesCol_NodeBackgroundHovered] = IM_COL32(240, 240, 240, 255);
dest->Colors[ImNodesCol_NodeBackgroundSelected] = IM_COL32(240, 240, 240, 255);
dest->Colors[ImNodesCol_NodeOutline] = IM_COL32(100, 100, 100, 255);
dest->Colors[ImNodesCol_TitleBar] = IM_COL32(248, 248, 248, 255);
dest->Colors[ImNodesCol_TitleBarHovered] = IM_COL32(209, 209, 209, 255);
dest->Colors[ImNodesCol_TitleBarSelected] = IM_COL32(209, 209, 209, 255);
// original imgui values: 66, 150, 250
dest->Colors[ImNodesCol_Link] = IM_COL32(66, 150, 250, 100);
// original imgui values: 117, 138, 204
dest->Colors[ImNodesCol_LinkHovered] = IM_COL32(66, 150, 250, 242);
dest->Colors[ImNodesCol_LinkSelected] = IM_COL32(66, 150, 250, 242);
// original imgui values: 66, 150, 250
dest->Colors[ImNodesCol_Pin] = IM_COL32(66, 150, 250, 160);
dest->Colors[ImNodesCol_PinHovered] = IM_COL32(66, 150, 250, 255);
dest->Colors[ImNodesCol_BoxSelector] = IM_COL32(90, 170, 250, 30);
dest->Colors[ImNodesCol_BoxSelectorOutline] = IM_COL32(90, 170, 250, 150);
dest->Colors[ImNodesCol_GridBackground] = IM_COL32(225, 225, 225, 255);
dest->Colors[ImNodesCol_GridLine] = IM_COL32(180, 180, 180, 100);
dest->Colors[ImNodesCol_GridLinePrimary] = IM_COL32(120, 120, 120, 100);
// minimap colors
dest->Colors[ImNodesCol_MiniMapBackground] = IM_COL32(25, 25, 25, 100);
dest->Colors[ImNodesCol_MiniMapBackgroundHovered] = IM_COL32(25, 25, 25, 200);
dest->Colors[ImNodesCol_MiniMapOutline] = IM_COL32(150, 150, 150, 100);
dest->Colors[ImNodesCol_MiniMapOutlineHovered] = IM_COL32(150, 150, 150, 200);
dest->Colors[ImNodesCol_MiniMapNodeBackground] = IM_COL32(200, 200, 200, 100);
dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] =
dest->Colors[ImNodesCol_MiniMapNodeBackgroundHovered];
dest->Colors[ImNodesCol_MiniMapNodeBackgroundSelected] = IM_COL32(200, 200, 240, 255);
dest->Colors[ImNodesCol_MiniMapNodeOutline] = IM_COL32(200, 200, 200, 100);
dest->Colors[ImNodesCol_MiniMapLink] = dest->Colors[ImNodesCol_Link];
dest->Colors[ImNodesCol_MiniMapLinkSelected] = dest->Colors[ImNodesCol_LinkSelected];
dest->Colors[ImNodesCol_MiniMapCanvas] = IM_COL32(200, 200, 200, 25);
dest->Colors[ImNodesCol_MiniMapCanvasOutline] = IM_COL32(200, 200, 200, 200);
}
void BeginNodeEditor()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
GImNodes->CurrentScope = ImNodesScope_Editor;
// Reset state from previous pass
ImNodesEditorContext& editor = EditorContextGet();
editor.AutoPanningDelta = ImVec2(0, 0);
editor.GridContentBounds = ImRect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
editor.MiniMapEnabled = false;
ObjectPoolReset(editor.Nodes);
ObjectPoolReset(editor.Pins);
ObjectPoolReset(editor.Links);
GImNodes->HoveredNodeIdx.Reset();
GImNodes->HoveredLinkIdx.Reset();
GImNodes->HoveredPinIdx.Reset();
GImNodes->DeletedLinkIdx.Reset();
GImNodes->SnapLinkIdx.Reset();
GImNodes->NodeIndicesOverlappingWithMouse.clear();
GImNodes->ImNodesUIState = ImNodesUIState_None;
GImNodes->MousePos = ImGui::GetIO().MousePos;
GImNodes->LeftMouseClicked = ImGui::IsMouseClicked(0);
GImNodes->LeftMouseReleased = ImGui::IsMouseReleased(0);
GImNodes->LeftMouseDragging = ImGui::IsMouseDragging(0, 0.0f);
GImNodes->AltMouseClicked =
(GImNodes->Io.EmulateThreeButtonMouse.Modifier != NULL &&
*GImNodes->Io.EmulateThreeButtonMouse.Modifier && GImNodes->LeftMouseClicked) ||
ImGui::IsMouseClicked(GImNodes->Io.AltMouseButton);
GImNodes->AltMouseDragging =
(GImNodes->Io.EmulateThreeButtonMouse.Modifier != NULL && GImNodes->LeftMouseDragging &&
(*GImNodes->Io.EmulateThreeButtonMouse.Modifier)) ||
ImGui::IsMouseDragging(GImNodes->Io.AltMouseButton, 0.0f);
GImNodes->AltMouseScrollDelta = ImGui::GetIO().MouseWheel;
GImNodes->MultipleSelectModifier =
(GImNodes->Io.MultipleSelectModifier.Modifier != NULL
? *GImNodes->Io.MultipleSelectModifier.Modifier
: ImGui::GetIO().KeyCtrl);
GImNodes->ActiveAttribute = false;
ImGui::BeginGroup();
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.f, 1.f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.f, 0.f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, GImNodes->Style.Colors[ImNodesCol_GridBackground]);
ImGui::BeginChild(
"scrolling_region",
ImVec2(0.f, 0.f),
true,
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoScrollWithMouse);
GImNodes->CanvasOriginScreenSpace = ImGui::GetCursorScreenPos();
// NOTE: we have to fetch the canvas draw list *after* we call
// BeginChild(), otherwise the ImGui UI elements are going to be
// rendered into the parent window draw list.
DrawListSet(ImGui::GetWindowDrawList());
{
const ImVec2 canvas_size = ImGui::GetWindowSize();
GImNodes->CanvasRectScreenSpace = ImRect(
EditorSpaceToScreenSpace(ImVec2(0.f, 0.f)), EditorSpaceToScreenSpace(canvas_size));
if (GImNodes->Style.Flags & ImNodesStyleFlags_GridLines)
{
DrawGrid(editor, canvas_size);
}
}
}
}
void EndNodeEditor()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);
GImNodes->CurrentScope = ImNodesScope_None;
ImNodesEditorContext& editor = EditorContextGet();
bool no_grid_content = editor.GridContentBounds.IsInverted();
if (no_grid_content)
{
editor.GridContentBounds = ScreenSpaceToGridSpace(editor, GImNodes->CanvasRectScreenSpace);
}
// Detect ImGui interaction first, because it blocks interaction with the rest of the UI
if (GImNodes->LeftMouseClicked && ImGui::IsAnyItemActive())
{
editor.ClickInteraction.Type = ImNodesClickInteractionType_ImGuiItem;
}
// Detect which UI element is being hovered over. Detection is done in a hierarchical fashion,
// because a UI element being hovered excludes any other as being hovered over.
// Don't do hovering detection for nodes/links/pins when interacting with the mini-map, since
// its an *overlay* with its own interaction behavior and must have precedence during mouse
// interaction.
if ((editor.ClickInteraction.Type == ImNodesClickInteractionType_None ||
editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation) &&
MouseInCanvas() && !IsMiniMapHovered())
{
// Pins needs some special care. We need to check the depth stack to see which pins are
// being occluded by other nodes.
ResolveOccludedPins(editor, GImNodes->OccludedPinIndices);
GImNodes->HoveredPinIdx = ResolveHoveredPin(editor.Pins, GImNodes->OccludedPinIndices);
if (!GImNodes->HoveredPinIdx.HasValue())
{
// Resolve which node is actually on top and being hovered using the depth stack.
GImNodes->HoveredNodeIdx = ResolveHoveredNode(editor.NodeDepthOrder);
}
// We don't check for hovered pins here, because if we want to detach a link by clicking and
// dragging, we need to have both a link and pin hovered.
if (!GImNodes->HoveredNodeIdx.HasValue())
{
GImNodes->HoveredLinkIdx = ResolveHoveredLink(editor.Links, editor.Pins);
}
}
for (int node_idx = 0; node_idx < editor.Nodes.Pool.size(); ++node_idx)
{
if (editor.Nodes.InUse[node_idx])
{
DrawListActivateNodeBackground(node_idx);
DrawNode(editor, node_idx);
}
}
// In order to render the links underneath the nodes, we want to first select the bottom draw
// channel.
GImNodes->CanvasDrawList->ChannelsSetCurrent(0);
for (int link_idx = 0; link_idx < editor.Links.Pool.size(); ++link_idx)
{
if (editor.Links.InUse[link_idx])
{
DrawLink(editor, link_idx);
}
}
// Render the click interaction UI elements (partial links, box selector) on top of everything
// else.
DrawListAppendClickInteractionChannel();
DrawListActivateClickInteractionChannel();
if (IsMiniMapActive())
{
CalcMiniMapLayout();
MiniMapUpdate();
}
// Handle node graph interaction
if (!IsMiniMapHovered())
{
if (GImNodes->LeftMouseClicked && GImNodes->HoveredLinkIdx.HasValue())
{
BeginLinkInteraction(editor, GImNodes->HoveredLinkIdx.Value(), GImNodes->HoveredPinIdx);
}
else if (GImNodes->LeftMouseClicked && GImNodes->HoveredPinIdx.HasValue())
{
BeginLinkCreation(editor, GImNodes->HoveredPinIdx.Value());
}
else if (GImNodes->LeftMouseClicked && GImNodes->HoveredNodeIdx.HasValue())
{
BeginNodeSelection(editor, GImNodes->HoveredNodeIdx.Value());
}
else if (
GImNodes->LeftMouseClicked || GImNodes->LeftMouseReleased ||
GImNodes->AltMouseClicked || GImNodes->AltMouseScrollDelta != 0.f)
{
BeginCanvasInteraction(editor);
}
bool should_auto_pan =
editor.ClickInteraction.Type == ImNodesClickInteractionType_BoxSelection ||
editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation ||
editor.ClickInteraction.Type == ImNodesClickInteractionType_Node;
if (should_auto_pan && !MouseInCanvas())
{
ImVec2 mouse = ImGui::GetMousePos();
ImVec2 center = GImNodes->CanvasRectScreenSpace.GetCenter();
ImVec2 direction = (center - mouse);
direction = direction * ImInvLength(direction, 0.0);
editor.AutoPanningDelta =
direction * ImGui::GetIO().DeltaTime * GImNodes->Io.AutoPanningSpeed;
editor.Panning += editor.AutoPanningDelta;
}
}
ClickInteractionUpdate(editor);
// At this point, draw commands have been issued for all nodes (and pins). Update the node pool
// to detect unused node slots and remove those indices from the depth stack before sorting the
// node draw commands by depth.
ObjectPoolUpdate(editor.Nodes);
ObjectPoolUpdate(editor.Pins);
DrawListSortChannelsByDepth(editor.NodeDepthOrder);
// After the links have been rendered, the link pool can be updated as well.
ObjectPoolUpdate(editor.Links);
// Finally, merge the draw channels
GImNodes->CanvasDrawList->ChannelsMerge();
// pop style
ImGui::EndChild(); // end scrolling region
ImGui::PopStyleColor(); // pop child window background color
ImGui::PopStyleVar(); // pop window padding
ImGui::PopStyleVar(); // pop frame padding
ImGui::EndGroup();
}
void MiniMap(
const float minimap_size_fraction,
const ImNodesMiniMapLocation location,
const ImNodesMiniMapNodeHoveringCallback node_hovering_callback,
const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data)
{
// Check that editor size fraction is sane; must be in the range (0, 1]
IM_ASSERT(minimap_size_fraction > 0.f && minimap_size_fraction <= 1.f);
// Remember to call before EndNodeEditor
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);
ImNodesEditorContext& editor = EditorContextGet();
editor.MiniMapEnabled = true;
editor.MiniMapSizeFraction = minimap_size_fraction;
editor.MiniMapLocation = location;
// Set node hovering callback information
editor.MiniMapNodeHoveringCallback = node_hovering_callback;
editor.MiniMapNodeHoveringCallbackUserData = node_hovering_callback_data;
// Actual drawing/updating of the MiniMap is done in EndNodeEditor so that
// mini map is draw over everything and all pin/link positions are updated
// correctly relative to their respective nodes. Hence, we must store some of
// of the state for the mini map in GImNodes for the actual drawing/updating
}
void BeginNode(const int node_id)
{
// Remember to call BeginNodeEditor before calling BeginNode
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);
GImNodes->CurrentScope = ImNodesScope_Node;
ImNodesEditorContext& editor = EditorContextGet();
const int node_idx = ObjectPoolFindOrCreateIndex(editor.Nodes, node_id);
GImNodes->CurrentNodeIdx = node_idx;
ImNodeData& node = editor.Nodes.Pool[node_idx];
node.ColorStyle.Background = GImNodes->Style.Colors[ImNodesCol_NodeBackground];
node.ColorStyle.BackgroundHovered = GImNodes->Style.Colors[ImNodesCol_NodeBackgroundHovered];
node.ColorStyle.BackgroundSelected = GImNodes->Style.Colors[ImNodesCol_NodeBackgroundSelected];
node.ColorStyle.Outline = GImNodes->Style.Colors[ImNodesCol_NodeOutline];
node.ColorStyle.Titlebar = GImNodes->Style.Colors[ImNodesCol_TitleBar];
node.ColorStyle.TitlebarHovered = GImNodes->Style.Colors[ImNodesCol_TitleBarHovered];
node.ColorStyle.TitlebarSelected = GImNodes->Style.Colors[ImNodesCol_TitleBarSelected];
node.LayoutStyle.CornerRounding = GImNodes->Style.NodeCornerRounding;
node.LayoutStyle.Padding = GImNodes->Style.NodePadding;
node.LayoutStyle.BorderThickness = GImNodes->Style.NodeBorderThickness;
// ImGui::SetCursorPos sets the cursor position, local to the current widget
// (in this case, the child object started in BeginNodeEditor). Use
// ImGui::SetCursorScreenPos to set the screen space coordinates directly.
ImGui::SetCursorPos(GridSpaceToEditorSpace(editor, GetNodeTitleBarOrigin(node)));
DrawListAddNode(node_idx);
DrawListActivateCurrentNodeForeground();
ImGui::PushID(node.Id);
ImGui::BeginGroup();
}
void EndNode()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);
GImNodes->CurrentScope = ImNodesScope_Editor;
ImNodesEditorContext& editor = EditorContextGet();
// The node's rectangle depends on the ImGui UI group size.
ImGui::EndGroup();
ImGui::PopID();
ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];
node.Rect = GetItemRect();
node.Rect.Expand(node.LayoutStyle.Padding);
editor.GridContentBounds.Add(node.Origin);
editor.GridContentBounds.Add(node.Origin + node.Rect.GetSize());
if (node.Rect.Contains(GImNodes->MousePos))
{
GImNodes->NodeIndicesOverlappingWithMouse.push_back(GImNodes->CurrentNodeIdx);
}
}
ImVec2 GetNodeDimensions(int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
const int node_idx = ObjectPoolFind(editor.Nodes, node_id);
IM_ASSERT(node_idx != -1); // invalid node_id
const ImNodeData& node = editor.Nodes.Pool[node_idx];
return node.Rect.GetSize();
}
void BeginNodeTitleBar()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);
ImGui::BeginGroup();
}
void EndNodeTitleBar()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);
ImGui::EndGroup();
ImNodesEditorContext& editor = EditorContextGet();
ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];
node.TitleBarContentRect = GetItemRect();
ImGui::ItemAdd(GetNodeTitleRect(node), ImGui::GetID("title_bar"));
ImGui::SetCursorPos(GridSpaceToEditorSpace(editor, GetNodeContentOrigin(node)));
}
void BeginInputAttribute(const int id, const ImNodesPinShape shape)
{
BeginPinAttribute(id, ImNodesAttributeType_Input, shape, GImNodes->CurrentNodeIdx);
}
void EndInputAttribute() { EndPinAttribute(); }
void BeginOutputAttribute(const int id, const ImNodesPinShape shape)
{
BeginPinAttribute(id, ImNodesAttributeType_Output, shape, GImNodes->CurrentNodeIdx);
}
void EndOutputAttribute() { EndPinAttribute(); }
void BeginStaticAttribute(const int id)
{
// Make sure to call BeginNode() before calling BeginAttribute()
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Node);
GImNodes->CurrentScope = ImNodesScope_Attribute;
GImNodes->CurrentAttributeId = id;
ImGui::BeginGroup();
ImGui::PushID(id);
}
void EndStaticAttribute()
{
// Make sure to call BeginNode() before calling BeginAttribute()
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Attribute);
GImNodes->CurrentScope = ImNodesScope_Node;
ImGui::PopID();
ImGui::EndGroup();
if (ImGui::IsItemActive())
{
GImNodes->ActiveAttribute = true;
GImNodes->ActiveAttributeId = GImNodes->CurrentAttributeId;
}
}
void PushAttributeFlag(const ImNodesAttributeFlags flag)
{
GImNodes->CurrentAttributeFlags |= flag;
GImNodes->AttributeFlagStack.push_back(GImNodes->CurrentAttributeFlags);
}
void PopAttributeFlag()
{
// PopAttributeFlag called without a matching PushAttributeFlag!
// The bottom value is always the default value, pushed in Initialize().
IM_ASSERT(GImNodes->AttributeFlagStack.size() > 1);
GImNodes->AttributeFlagStack.pop_back();
GImNodes->CurrentAttributeFlags = GImNodes->AttributeFlagStack.back();
}
void Link(const int id, const int start_attr_id, const int end_attr_id)
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_Editor);
ImNodesEditorContext& editor = EditorContextGet();
ImLinkData& link = ObjectPoolFindOrCreateObject(editor.Links, id);
link.Id = id;
link.StartPinIdx = ObjectPoolFindOrCreateIndex(editor.Pins, start_attr_id);
link.EndPinIdx = ObjectPoolFindOrCreateIndex(editor.Pins, end_attr_id);
link.ColorStyle.Base = GImNodes->Style.Colors[ImNodesCol_Link];
link.ColorStyle.Hovered = GImNodes->Style.Colors[ImNodesCol_LinkHovered];
link.ColorStyle.Selected = GImNodes->Style.Colors[ImNodesCol_LinkSelected];
// Check if this link was created by the current link event
if ((editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation &&
editor.Pins.Pool[link.EndPinIdx].Flags & ImNodesAttributeFlags_EnableLinkCreationOnSnap &&
editor.ClickInteraction.LinkCreation.StartPinIdx == link.StartPinIdx &&
editor.ClickInteraction.LinkCreation.EndPinIdx == link.EndPinIdx) ||
(editor.ClickInteraction.LinkCreation.StartPinIdx == link.EndPinIdx &&
editor.ClickInteraction.LinkCreation.EndPinIdx == link.StartPinIdx))
{
GImNodes->SnapLinkIdx = ObjectPoolFindOrCreateIndex(editor.Links, id);
}
}
void PushColorStyle(const ImNodesCol item, unsigned int color)
{
GImNodes->ColorModifierStack.push_back(ImNodesColElement(GImNodes->Style.Colors[item], item));
GImNodes->Style.Colors[item] = color;
}
void PopColorStyle()
{
IM_ASSERT(GImNodes->ColorModifierStack.size() > 0);
const ImNodesColElement elem = GImNodes->ColorModifierStack.back();
GImNodes->Style.Colors[elem.Item] = elem.Color;
GImNodes->ColorModifierStack.pop_back();
}
struct ImNodesStyleVarInfo
{
ImGuiDataType Type;
ImU32 Count;
ImU32 Offset;
void* GetVarPtr(ImNodesStyle* style) const { return (void*)((unsigned char*)style + Offset); }
};
static const ImNodesStyleVarInfo GStyleVarInfo[] = {
// ImNodesStyleVar_GridSpacing
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, GridSpacing)},
// ImNodesStyleVar_NodeCornerRounding
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, NodeCornerRounding)},
// ImNodesStyleVar_NodePadding
{ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImNodesStyle, NodePadding)},
// ImNodesStyleVar_NodeBorderThickness
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, NodeBorderThickness)},
// ImNodesStyleVar_LinkThickness
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, LinkThickness)},
// ImNodesStyleVar_LinkLineSegmentsPerLength
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, LinkLineSegmentsPerLength)},
// ImNodesStyleVar_LinkHoverDistance
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, LinkHoverDistance)},
// ImNodesStyleVar_PinCircleRadius
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinCircleRadius)},
// ImNodesStyleVar_PinQuadSideLength
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinQuadSideLength)},
// ImNodesStyleVar_PinTriangleSideLength
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinTriangleSideLength)},
// ImNodesStyleVar_PinLineThickness
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinLineThickness)},
// ImNodesStyleVar_PinHoverRadius
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinHoverRadius)},
// ImNodesStyleVar_PinOffset
{ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImNodesStyle, PinOffset)},
// ImNodesStyleVar_MiniMapPadding
{ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImNodesStyle, MiniMapPadding)},
// ImNodesStyleVar_MiniMapOffset
{ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImNodesStyle, MiniMapOffset)},
};
static const ImNodesStyleVarInfo* GetStyleVarInfo(ImNodesStyleVar idx)
{
IM_ASSERT(idx >= 0 && idx < ImNodesStyleVar_COUNT);
IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImNodesStyleVar_COUNT);
return &GStyleVarInfo[idx];
}
void PushStyleVar(const ImNodesStyleVar item, const float value)
{
const ImNodesStyleVarInfo* var_info = GetStyleVarInfo(item);
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
{
float& style_var = *(float*)var_info->GetVarPtr(&GImNodes->Style);
GImNodes->StyleModifierStack.push_back(ImNodesStyleVarElement(item, style_var));
style_var = value;
return;
}
IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
}
void PushStyleVar(const ImNodesStyleVar item, const ImVec2& value)
{
const ImNodesStyleVarInfo* var_info = GetStyleVarInfo(item);
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
{
ImVec2& style_var = *(ImVec2*)var_info->GetVarPtr(&GImNodes->Style);
GImNodes->StyleModifierStack.push_back(ImNodesStyleVarElement(item, style_var));
style_var = value;
return;
}
IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
}
void PopStyleVar(int count)
{
while (count > 0)
{
IM_ASSERT(GImNodes->StyleModifierStack.size() > 0);
const ImNodesStyleVarElement style_backup = GImNodes->StyleModifierStack.back();
GImNodes->StyleModifierStack.pop_back();
const ImNodesStyleVarInfo* var_info = GetStyleVarInfo(style_backup.Item);
void* style_var = var_info->GetVarPtr(&GImNodes->Style);
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
{
((float*)style_var)[0] = style_backup.FloatValue[0];
}
else if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
{
((float*)style_var)[0] = style_backup.FloatValue[0];
((float*)style_var)[1] = style_backup.FloatValue[1];
}
count--;
}
}
void SetNodeScreenSpacePos(const int node_id, const ImVec2& screen_space_pos)
{
ImNodesEditorContext& editor = EditorContextGet();
ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);
node.Origin = ScreenSpaceToGridSpace(editor, screen_space_pos);
}
void SetNodeEditorSpacePos(const int node_id, const ImVec2& editor_space_pos)
{
ImNodesEditorContext& editor = EditorContextGet();
ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);
node.Origin = EditorSpaceToGridSpace(editor, editor_space_pos);
}
void SetNodeGridSpacePos(const int node_id, const ImVec2& grid_pos)
{
ImNodesEditorContext& editor = EditorContextGet();
ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);
node.Origin = grid_pos;
}
void SetNodeDraggable(const int node_id, const bool draggable)
{
ImNodesEditorContext& editor = EditorContextGet();
ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);
node.Draggable = draggable;
}
ImVec2 GetNodeScreenSpacePos(const int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
const int node_idx = ObjectPoolFind(editor.Nodes, node_id);
IM_ASSERT(node_idx != -1);
ImNodeData& node = editor.Nodes.Pool[node_idx];
return GridSpaceToScreenSpace(editor, node.Origin);
}
ImVec2 GetNodeEditorSpacePos(const int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
const int node_idx = ObjectPoolFind(editor.Nodes, node_id);
IM_ASSERT(node_idx != -1);
ImNodeData& node = editor.Nodes.Pool[node_idx];
return GridSpaceToEditorSpace(editor, node.Origin);
}
ImVec2 GetNodeGridSpacePos(const int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
const int node_idx = ObjectPoolFind(editor.Nodes, node_id);
IM_ASSERT(node_idx != -1);
ImNodeData& node = editor.Nodes.Pool[node_idx];
return node.Origin;
}
void SnapNodeToGrid(int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
ImNodeData& node = ObjectPoolFindOrCreateObject(editor.Nodes, node_id);
node.Origin = SnapOriginToGrid(node.Origin);
}
bool IsEditorHovered() { return MouseInCanvas(); }
bool IsNodeHovered(int* const node_id)
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
IM_ASSERT(node_id != NULL);
const bool is_hovered = GImNodes->HoveredNodeIdx.HasValue();
if (is_hovered)
{
const ImNodesEditorContext& editor = EditorContextGet();
*node_id = editor.Nodes.Pool[GImNodes->HoveredNodeIdx.Value()].Id;
}
return is_hovered;
}
bool IsLinkHovered(int* const link_id)
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
IM_ASSERT(link_id != NULL);
const bool is_hovered = GImNodes->HoveredLinkIdx.HasValue();
if (is_hovered)
{
const ImNodesEditorContext& editor = EditorContextGet();
*link_id = editor.Links.Pool[GImNodes->HoveredLinkIdx.Value()].Id;
}
return is_hovered;
}
bool IsPinHovered(int* const attr)
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
IM_ASSERT(attr != NULL);
const bool is_hovered = GImNodes->HoveredPinIdx.HasValue();
if (is_hovered)
{
const ImNodesEditorContext& editor = EditorContextGet();
*attr = editor.Pins.Pool[GImNodes->HoveredPinIdx.Value()].Id;
}
return is_hovered;
}
int NumSelectedNodes()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
const ImNodesEditorContext& editor = EditorContextGet();
return editor.SelectedNodeIndices.size();
}
int NumSelectedLinks()
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
const ImNodesEditorContext& editor = EditorContextGet();
return editor.SelectedLinkIndices.size();
}
void GetSelectedNodes(int* node_ids)
{
IM_ASSERT(node_ids != NULL);
const ImNodesEditorContext& editor = EditorContextGet();
for (int i = 0; i < editor.SelectedNodeIndices.size(); ++i)
{
const int node_idx = editor.SelectedNodeIndices[i];
node_ids[i] = editor.Nodes.Pool[node_idx].Id;
}
}
void GetSelectedLinks(int* link_ids)
{
IM_ASSERT(link_ids != NULL);
const ImNodesEditorContext& editor = EditorContextGet();
for (int i = 0; i < editor.SelectedLinkIndices.size(); ++i)
{
const int link_idx = editor.SelectedLinkIndices[i];
link_ids[i] = editor.Links.Pool[link_idx].Id;
}
}
void ClearNodeSelection()
{
ImNodesEditorContext& editor = EditorContextGet();
editor.SelectedNodeIndices.clear();
}
void ClearNodeSelection(int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
ClearObjectSelection(editor.Nodes, editor.SelectedNodeIndices, node_id);
}
void ClearLinkSelection()
{
ImNodesEditorContext& editor = EditorContextGet();
editor.SelectedLinkIndices.clear();
}
void ClearLinkSelection(int link_id)
{
ImNodesEditorContext& editor = EditorContextGet();
ClearObjectSelection(editor.Links, editor.SelectedLinkIndices, link_id);
}
void SelectNode(int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
SelectObject(editor.Nodes, editor.SelectedNodeIndices, node_id);
}
void SelectLink(int link_id)
{
ImNodesEditorContext& editor = EditorContextGet();
SelectObject(editor.Links, editor.SelectedLinkIndices, link_id);
}
bool IsNodeSelected(int node_id)
{
ImNodesEditorContext& editor = EditorContextGet();
return IsObjectSelected(editor.Nodes, editor.SelectedNodeIndices, node_id);
}
bool IsLinkSelected(int link_id)
{
ImNodesEditorContext& editor = EditorContextGet();
return IsObjectSelected(editor.Links, editor.SelectedLinkIndices, link_id);
}
bool IsAttributeActive()
{
IM_ASSERT((GImNodes->CurrentScope & ImNodesScope_Node) != 0);
if (!GImNodes->ActiveAttribute)
{
return false;
}
return GImNodes->ActiveAttributeId == GImNodes->CurrentAttributeId;
}
bool IsAnyAttributeActive(int* const attribute_id)
{
IM_ASSERT((GImNodes->CurrentScope & (ImNodesScope_Node | ImNodesScope_Attribute)) == 0);
if (!GImNodes->ActiveAttribute)
{
return false;
}
if (attribute_id != NULL)
{
*attribute_id = GImNodes->ActiveAttributeId;
}
return true;
}
bool IsLinkStarted(int* const started_at_id)
{
// Call this function after EndNodeEditor()!
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
IM_ASSERT(started_at_id != NULL);
const bool is_started = (GImNodes->ImNodesUIState & ImNodesUIState_LinkStarted) != 0;
if (is_started)
{
const ImNodesEditorContext& editor = EditorContextGet();
const int pin_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;
*started_at_id = editor.Pins.Pool[pin_idx].Id;
}
return is_started;
}
bool IsLinkDropped(int* const started_at_id, const bool including_detached_links)
{
// Call this function after EndNodeEditor()!
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
const ImNodesEditorContext& editor = EditorContextGet();
const bool link_dropped =
(GImNodes->ImNodesUIState & ImNodesUIState_LinkDropped) != 0 &&
(including_detached_links ||
editor.ClickInteraction.LinkCreation.Type != ImNodesLinkCreationType_FromDetach);
if (link_dropped && started_at_id)
{
const int pin_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;
*started_at_id = editor.Pins.Pool[pin_idx].Id;
}
return link_dropped;
}
bool IsLinkCreated(
int* const started_at_pin_id,
int* const ended_at_pin_id,
bool* const created_from_snap)
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
IM_ASSERT(started_at_pin_id != NULL);
IM_ASSERT(ended_at_pin_id != NULL);
const bool is_created = (GImNodes->ImNodesUIState & ImNodesUIState_LinkCreated) != 0;
if (is_created)
{
const ImNodesEditorContext& editor = EditorContextGet();
const int start_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;
const int end_idx = editor.ClickInteraction.LinkCreation.EndPinIdx.Value();
const ImPinData& start_pin = editor.Pins.Pool[start_idx];
const ImPinData& end_pin = editor.Pins.Pool[end_idx];
if (start_pin.Type == ImNodesAttributeType_Output)
{
*started_at_pin_id = start_pin.Id;
*ended_at_pin_id = end_pin.Id;
}
else
{
*started_at_pin_id = end_pin.Id;
*ended_at_pin_id = start_pin.Id;
}
if (created_from_snap)
{
*created_from_snap =
editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation;
}
}
return is_created;
}
bool IsLinkCreated(
int* started_at_node_id,
int* started_at_pin_id,
int* ended_at_node_id,
int* ended_at_pin_id,
bool* created_from_snap)
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
IM_ASSERT(started_at_node_id != NULL);
IM_ASSERT(started_at_pin_id != NULL);
IM_ASSERT(ended_at_node_id != NULL);
IM_ASSERT(ended_at_pin_id != NULL);
const bool is_created = (GImNodes->ImNodesUIState & ImNodesUIState_LinkCreated) != 0;
if (is_created)
{
const ImNodesEditorContext& editor = EditorContextGet();
const int start_idx = editor.ClickInteraction.LinkCreation.StartPinIdx;
const int end_idx = editor.ClickInteraction.LinkCreation.EndPinIdx.Value();
const ImPinData& start_pin = editor.Pins.Pool[start_idx];
const ImNodeData& start_node = editor.Nodes.Pool[start_pin.ParentNodeIdx];
const ImPinData& end_pin = editor.Pins.Pool[end_idx];
const ImNodeData& end_node = editor.Nodes.Pool[end_pin.ParentNodeIdx];
if (start_pin.Type == ImNodesAttributeType_Output)
{
*started_at_pin_id = start_pin.Id;
*started_at_node_id = start_node.Id;
*ended_at_pin_id = end_pin.Id;
*ended_at_node_id = end_node.Id;
}
else
{
*started_at_pin_id = end_pin.Id;
*started_at_node_id = end_node.Id;
*ended_at_pin_id = start_pin.Id;
*ended_at_node_id = start_node.Id;
}
if (created_from_snap)
{
*created_from_snap =
editor.ClickInteraction.Type == ImNodesClickInteractionType_LinkCreation;
}
}
return is_created;
}
bool IsLinkDestroyed(int* const link_id)
{
IM_ASSERT(GImNodes->CurrentScope == ImNodesScope_None);
const bool link_destroyed = GImNodes->DeletedLinkIdx.HasValue();
if (link_destroyed)
{
const ImNodesEditorContext& editor = EditorContextGet();
const int link_idx = GImNodes->DeletedLinkIdx.Value();
*link_id = editor.Links.Pool[link_idx].Id;
}
return link_destroyed;
}
namespace
{
void NodeLineHandler(ImNodesEditorContext& editor, const char* const line)
{
int id;
int x, y;
if (sscanf(line, "[node.%i", &id) == 1)
{
const int node_idx = ObjectPoolFindOrCreateIndex(editor.Nodes, id);
GImNodes->CurrentNodeIdx = node_idx;
ImNodeData& node = editor.Nodes.Pool[node_idx];
node.Id = id;
}
else if (sscanf(line, "origin=%i,%i", &x, &y) == 2)
{
ImNodeData& node = editor.Nodes.Pool[GImNodes->CurrentNodeIdx];
node.Origin = SnapOriginToGrid(ImVec2((float)x, (float)y));
}
}
void EditorLineHandler(ImNodesEditorContext& editor, const char* const line)
{
(void)sscanf(line, "panning=%f,%f", &editor.Panning.x, &editor.Panning.y);
}
} // namespace
const char* SaveCurrentEditorStateToIniString(size_t* const data_size)
{
return SaveEditorStateToIniString(&EditorContextGet(), data_size);
}
const char* SaveEditorStateToIniString(
const ImNodesEditorContext* const editor_ptr,
size_t* const data_size)
{
IM_ASSERT(editor_ptr != NULL);
const ImNodesEditorContext& editor = *editor_ptr;
GImNodes->TextBuffer.clear();
// TODO: check to make sure that the estimate is the upper bound of element
GImNodes->TextBuffer.reserve(64 * editor.Nodes.Pool.size());
GImNodes->TextBuffer.appendf(
"[editor]\npanning=%i,%i\n", (int)editor.Panning.x, (int)editor.Panning.y);
for (int i = 0; i < editor.Nodes.Pool.size(); i++)
{
if (editor.Nodes.InUse[i])
{
const ImNodeData& node = editor.Nodes.Pool[i];
GImNodes->TextBuffer.appendf("\n[node.%d]\n", node.Id);
GImNodes->TextBuffer.appendf("origin=%i,%i\n", (int)node.Origin.x, (int)node.Origin.y);
}
}
if (data_size != NULL)
{
*data_size = GImNodes->TextBuffer.size();
}
return GImNodes->TextBuffer.c_str();
}
void LoadCurrentEditorStateFromIniString(const char* const data, const size_t data_size)
{
LoadEditorStateFromIniString(&EditorContextGet(), data, data_size);
}
void LoadEditorStateFromIniString(
ImNodesEditorContext* const editor_ptr,
const char* const data,
const size_t data_size)
{
if (data_size == 0u)
{
return;
}
ImNodesEditorContext& editor = editor_ptr == NULL ? EditorContextGet() : *editor_ptr;
char* buf = (char*)ImGui::MemAlloc(data_size + 1);
const char* buf_end = buf + data_size;
memcpy(buf, data, data_size);
buf[data_size] = 0;
void (*line_handler)(ImNodesEditorContext&, const char*);
line_handler = NULL;
char* line_end = NULL;
for (char* line = buf; line < buf_end; line = line_end + 1)
{
while (*line == '\n' || *line == '\r')
{
line++;
}
line_end = line;
while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
{
line_end++;
}
line_end[0] = 0;
if (*line == ';' || *line == '\0')
{
continue;
}
if (line[0] == '[' && line_end[-1] == ']')
{
line_end[-1] = 0;
if (strncmp(line + 1, "node", 4) == 0)
{
line_handler = NodeLineHandler;
}
else if (strcmp(line + 1, "editor") == 0)
{
line_handler = EditorLineHandler;
}
}
if (line_handler != NULL)
{
line_handler(editor, line);
}
}
ImGui::MemFree(buf);
}
void SaveCurrentEditorStateToIniFile(const char* const file_name)
{
SaveEditorStateToIniFile(&EditorContextGet(), file_name);
}
void SaveEditorStateToIniFile(const ImNodesEditorContext* const editor, const char* const file_name)
{
size_t data_size = 0u;
const char* data = SaveEditorStateToIniString(editor, &data_size);
FILE* file = ImFileOpen(file_name, "wt");
if (!file)
{
return;
}
fwrite(data, sizeof(char), data_size, file);
fclose(file);
}
void LoadCurrentEditorStateFromIniFile(const char* const file_name)
{
LoadEditorStateFromIniFile(&EditorContextGet(), file_name);
}
void LoadEditorStateFromIniFile(ImNodesEditorContext* const editor, const char* const file_name)
{
size_t data_size = 0u;
char* file_data = (char*)ImFileLoadToMemory(file_name, "rb", &data_size);
if (!file_data)
{
return;
}
LoadEditorStateFromIniString(editor, file_data, data_size);
ImGui::MemFree(file_data);
}
} // namespace IMNODES_NAMESPACE
================================================
FILE: Source/External/imgui_tools/imnodes/imnodes.h
================================================
#pragma once
#include
#include
#ifdef IMNODES_USER_CONFIG
#include IMNODES_USER_CONFIG
#endif
#ifndef IMNODES_NAMESPACE
#define IMNODES_NAMESPACE ImNodes
#endif
typedef int ImNodesCol; // -> enum ImNodesCol_
typedef int ImNodesStyleVar; // -> enum ImNodesStyleVar_
typedef int ImNodesStyleFlags; // -> enum ImNodesStyleFlags_
typedef int ImNodesPinShape; // -> enum ImNodesPinShape_
typedef int ImNodesAttributeFlags; // -> enum ImNodesAttributeFlags_
typedef int ImNodesMiniMapLocation; // -> enum ImNodesMiniMapLocation_
enum ImNodesCol_
{
ImNodesCol_NodeBackground = 0,
ImNodesCol_NodeBackgroundHovered,
ImNodesCol_NodeBackgroundSelected,
ImNodesCol_NodeOutline,
ImNodesCol_TitleBar,
ImNodesCol_TitleBarHovered,
ImNodesCol_TitleBarSelected,
ImNodesCol_Link,
ImNodesCol_LinkHovered,
ImNodesCol_LinkSelected,
ImNodesCol_Pin,
ImNodesCol_PinHovered,
ImNodesCol_BoxSelector,
ImNodesCol_BoxSelectorOutline,
ImNodesCol_GridBackground,
ImNodesCol_GridLine,
ImNodesCol_GridLinePrimary,
ImNodesCol_MiniMapBackground,
ImNodesCol_MiniMapBackgroundHovered,
ImNodesCol_MiniMapOutline,
ImNodesCol_MiniMapOutlineHovered,
ImNodesCol_MiniMapNodeBackground,
ImNodesCol_MiniMapNodeBackgroundHovered,
ImNodesCol_MiniMapNodeBackgroundSelected,
ImNodesCol_MiniMapNodeOutline,
ImNodesCol_MiniMapLink,
ImNodesCol_MiniMapLinkSelected,
ImNodesCol_MiniMapCanvas,
ImNodesCol_MiniMapCanvasOutline,
ImNodesCol_COUNT
};
enum ImNodesStyleVar_
{
ImNodesStyleVar_GridSpacing = 0,
ImNodesStyleVar_NodeCornerRounding,
ImNodesStyleVar_NodePadding,
ImNodesStyleVar_NodeBorderThickness,
ImNodesStyleVar_LinkThickness,
ImNodesStyleVar_LinkLineSegmentsPerLength,
ImNodesStyleVar_LinkHoverDistance,
ImNodesStyleVar_PinCircleRadius,
ImNodesStyleVar_PinQuadSideLength,
ImNodesStyleVar_PinTriangleSideLength,
ImNodesStyleVar_PinLineThickness,
ImNodesStyleVar_PinHoverRadius,
ImNodesStyleVar_PinOffset,
ImNodesStyleVar_MiniMapPadding,
ImNodesStyleVar_MiniMapOffset,
ImNodesStyleVar_COUNT
};
enum ImNodesStyleFlags_
{
ImNodesStyleFlags_None = 0,
ImNodesStyleFlags_NodeOutline = 1 << 0,
ImNodesStyleFlags_GridLines = 1 << 2,
ImNodesStyleFlags_GridLinesPrimary = 1 << 3,
ImNodesStyleFlags_GridSnapping = 1 << 4
};
enum ImNodesPinShape_
{
ImNodesPinShape_Circle,
ImNodesPinShape_CircleFilled,
ImNodesPinShape_Triangle,
ImNodesPinShape_TriangleFilled,
ImNodesPinShape_Quad,
ImNodesPinShape_QuadFilled
};
// This enum controls the way the attribute pins behave.
enum ImNodesAttributeFlags_
{
ImNodesAttributeFlags_None = 0,
// Allow detaching a link by left-clicking and dragging the link at a pin it is connected to.
// NOTE: the user has to actually delete the link for this to work. A deleted link can be
// detected by calling IsLinkDestroyed() after EndNodeEditor().
ImNodesAttributeFlags_EnableLinkDetachWithDragClick = 1 << 0,
// Visual snapping of an in progress link will trigger IsLink Created/Destroyed events. Allows
// for previewing the creation of a link while dragging it across attributes. See here for demo:
// https://github.com/Nelarius/imnodes/issues/41#issuecomment-647132113 NOTE: the user has to
// actually delete the link for this to work. A deleted link can be detected by calling
// IsLinkDestroyed() after EndNodeEditor().
ImNodesAttributeFlags_EnableLinkCreationOnSnap = 1 << 1
};
struct ImNodesIO
{
struct EmulateThreeButtonMouse
{
EmulateThreeButtonMouse();
// The keyboard modifier to use in combination with mouse left click to pan the editor view.
// Set to NULL by default. To enable this feature, set the modifier to point to a boolean
// indicating the state of a modifier. For example,
//
// ImNodes::GetIO().EmulateThreeButtonMouse.Modifier = &ImGui::GetIO().KeyAlt;
const bool* Modifier;
} EmulateThreeButtonMouse;
struct LinkDetachWithModifierClick
{
LinkDetachWithModifierClick();
// Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL
// by default. To enable the feature, set the modifier to point to a boolean indicating the
// state of a modifier. For example,
//
// ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;
//
// Left-clicking a link with this modifier pressed will detach that link. NOTE: the user has
// to actually delete the link for this to work. A deleted link can be detected by calling
// IsLinkDestroyed() after EndNodeEditor().
const bool* Modifier;
} LinkDetachWithModifierClick;
struct MultipleSelectModifier
{
MultipleSelectModifier();
// Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL
// by default. To enable the feature, set the modifier to point to a boolean indicating the
// state of a modifier. For example,
//
// ImNodes::GetIO().MultipleSelectModifier.Modifier = &ImGui::GetIO().KeyCtrl;
//
// Left-clicking a node with this modifier pressed will add the node to the list of
// currently selected nodes. If this value is NULL, the Ctrl key will be used.
const bool* Modifier;
} MultipleSelectModifier;
// Holding alt mouse button pans the node area, by default middle mouse button will be used
// Set based on ImGuiMouseButton values
int AltMouseButton;
// Panning speed when dragging an element and mouse is outside the main editor view.
float AutoPanningSpeed;
ImNodesIO();
};
struct ImNodesStyle
{
float GridSpacing;
float NodeCornerRounding;
ImVec2 NodePadding;
float NodeBorderThickness;
float LinkThickness;
float LinkLineSegmentsPerLength;
float LinkHoverDistance;
// The following variables control the look and behavior of the pins. The default size of each
// pin shape is balanced to occupy approximately the same surface area on the screen.
// The circle radius used when the pin shape is either ImNodesPinShape_Circle or
// ImNodesPinShape_CircleFilled.
float PinCircleRadius;
// The quad side length used when the shape is either ImNodesPinShape_Quad or
// ImNodesPinShape_QuadFilled.
float PinQuadSideLength;
// The equilateral triangle side length used when the pin shape is either
// ImNodesPinShape_Triangle or ImNodesPinShape_TriangleFilled.
float PinTriangleSideLength;
// The thickness of the line used when the pin shape is not filled.
float PinLineThickness;
// The radius from the pin's center position inside of which it is detected as being hovered
// over.
float PinHoverRadius;
// Offsets the pins' positions from the edge of the node to the outside of the node.
float PinOffset;
// Mini-map padding size between mini-map edge and mini-map content.
ImVec2 MiniMapPadding;
// Mini-map offset from the screen side.
ImVec2 MiniMapOffset;
// By default, ImNodesStyleFlags_NodeOutline and ImNodesStyleFlags_Gridlines are enabled.
ImNodesStyleFlags Flags;
// Set these mid-frame using Push/PopColorStyle. You can index this color array with with a
// ImNodesCol value.
unsigned int Colors[ImNodesCol_COUNT];
ImNodesStyle();
};
enum ImNodesMiniMapLocation_
{
ImNodesMiniMapLocation_BottomLeft,
ImNodesMiniMapLocation_BottomRight,
ImNodesMiniMapLocation_TopLeft,
ImNodesMiniMapLocation_TopRight,
};
struct ImGuiContext;
struct ImVec2;
struct ImNodesContext;
// An editor context corresponds to a set of nodes in a single workspace (created with a single
// Begin/EndNodeEditor pair)
//
// By default, the library creates an editor context behind the scenes, so using any of the imnodes
// functions doesn't require you to explicitly create a context.
struct ImNodesEditorContext;
// Callback type used to specify special behavior when hovering a node in the minimap
#ifndef ImNodesMiniMapNodeHoveringCallback
typedef void (*ImNodesMiniMapNodeHoveringCallback)(int, void*);
#endif
#ifndef ImNodesMiniMapNodeHoveringCallbackUserData
typedef void* ImNodesMiniMapNodeHoveringCallbackUserData;
#endif
namespace IMNODES_NAMESPACE
{
// Call this function if you are compiling imnodes in to a dll, separate from ImGui. Calling this
// function sets the GImGui global variable, which is not shared across dll boundaries.
void SetImGuiContext(ImGuiContext* ctx);
ImNodesContext* CreateContext();
void DestroyContext(ImNodesContext* ctx = NULL); // NULL = destroy current context
ImNodesContext* GetCurrentContext();
void SetCurrentContext(ImNodesContext* ctx);
ImNodesEditorContext* EditorContextCreate();
void EditorContextFree(ImNodesEditorContext*);
void EditorContextSet(ImNodesEditorContext*);
ImVec2 EditorContextGetPanning();
void EditorContextResetPanning(const ImVec2& pos);
void EditorContextMoveToNode(const int node_id);
ImNodesIO& GetIO();
// Returns the global style struct. See the struct declaration for default values.
ImNodesStyle& GetStyle();
// Style presets matching the dear imgui styles of the same name. If dest is NULL, the active
// context's ImNodesStyle instance will be used as the destination.
void StyleColorsDark(ImNodesStyle* dest = NULL); // on by default
void StyleColorsClassic(ImNodesStyle* dest = NULL);
void StyleColorsLight(ImNodesStyle* dest = NULL);
// The top-level function call. Call this before calling BeginNode/EndNode. Calling this function
// will result the node editor grid workspace being rendered.
void BeginNodeEditor();
void EndNodeEditor();
// Add a navigable minimap to the editor; call before EndNodeEditor after all
// nodes and links have been specified
void MiniMap(
const float minimap_size_fraction = 0.2f,
const ImNodesMiniMapLocation location = ImNodesMiniMapLocation_TopLeft,
const ImNodesMiniMapNodeHoveringCallback node_hovering_callback = NULL,
const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data = NULL);
// Use PushColorStyle and PopColorStyle to modify ImNodesStyle::Colors mid-frame.
void PushColorStyle(ImNodesCol item, unsigned int color);
void PopColorStyle();
void PushStyleVar(ImNodesStyleVar style_item, float value);
void PushStyleVar(ImNodesStyleVar style_item, const ImVec2& value);
void PopStyleVar(int count = 1);
// id can be any positive or negative integer, but INT_MIN is currently reserved for internal use.
void BeginNode(int id);
void EndNode();
ImVec2 GetNodeDimensions(int id);
// Place your node title bar content (such as the node title, using ImGui::Text) between the
// following function calls. These functions have to be called before adding any attributes, or the
// layout of the node will be incorrect.
void BeginNodeTitleBar();
void EndNodeTitleBar();
// Attributes are ImGui UI elements embedded within the node. Attributes can have pin shapes
// rendered next to them. Links are created between pins.
//
// The activity status of an attribute can be checked via the IsAttributeActive() and
// IsAnyAttributeActive() function calls. This is one easy way of checking for any changes made to
// an attribute's drag float UI, for instance.
//
// Each attribute id must be unique.
// Create an input attribute block. The pin is rendered on left side.
void BeginInputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);
void EndInputAttribute();
// Create an output attribute block. The pin is rendered on the right side.
void BeginOutputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);
void EndOutputAttribute();
// Create a static attribute block. A static attribute has no pin, and therefore can't be linked to
// anything. However, you can still use IsAttributeActive() and IsAnyAttributeActive() to check for
// attribute activity.
void BeginStaticAttribute(int id);
void EndStaticAttribute();
// Push a single AttributeFlags value. By default, only AttributeFlags_None is set.
void PushAttributeFlag(ImNodesAttributeFlags flag);
void PopAttributeFlag();
// Render a link between attributes.
// The attributes ids used here must match the ids used in Begin(Input|Output)Attribute function
// calls. The order of start_attr and end_attr doesn't make a difference for rendering the link.
void Link(int id, int start_attribute_id, int end_attribute_id);
// Enable or disable the ability to click and drag a specific node.
void SetNodeDraggable(int node_id, const bool draggable);
// The node's position can be expressed in three coordinate systems:
// * screen space coordinates, -- the origin is the upper left corner of the window.
// * editor space coordinates -- the origin is the upper left corner of the node editor window
// * grid space coordinates, -- the origin is the upper left corner of the node editor window,
// translated by the current editor panning vector (see EditorContextGetPanning() and
// EditorContextResetPanning())
// Use the following functions to get and set the node's coordinates in these coordinate systems.
void SetNodeScreenSpacePos(int node_id, const ImVec2& screen_space_pos);
void SetNodeEditorSpacePos(int node_id, const ImVec2& editor_space_pos);
void SetNodeGridSpacePos(int node_id, const ImVec2& grid_pos);
ImVec2 GetNodeScreenSpacePos(const int node_id);
ImVec2 GetNodeEditorSpacePos(const int node_id);
ImVec2 GetNodeGridSpacePos(const int node_id);
// If ImNodesStyleFlags_GridSnapping is enabled, snap the specified node's origin to the grid.
void SnapNodeToGrid(int node_id);
// Returns true if the current node editor canvas is being hovered over by the mouse, and is not
// blocked by any other windows.
bool IsEditorHovered();
// The following functions return true if a UI element is being hovered over by the mouse cursor.
// Assigns the id of the UI element being hovered over to the function argument. Use these functions
// after EndNodeEditor() has been called.
bool IsNodeHovered(int* node_id);
bool IsLinkHovered(int* link_id);
bool IsPinHovered(int* attribute_id);
// Use The following two functions to query the number of selected nodes or links in the current
// editor. Use after calling EndNodeEditor().
int NumSelectedNodes();
int NumSelectedLinks();
// Get the selected node/link ids. The pointer argument should point to an integer array with at
// least as many elements as the respective NumSelectedNodes/NumSelectedLinks function call
// returned.
void GetSelectedNodes(int* node_ids);
void GetSelectedLinks(int* link_ids);
// Clears the list of selected nodes/links. Useful if you want to delete a selected node or link.
void ClearNodeSelection();
void ClearLinkSelection();
// Use the following functions to add or remove individual nodes or links from the current editors
// selection. Note that all functions require the id to be an existing valid id for this editor.
// Select-functions has the precondition that the object is currently considered unselected.
// Clear-functions has the precondition that the object is currently considered selected.
// Preconditions listed above can be checked via IsNodeSelected/IsLinkSelected if not already
// known.
void SelectNode(int node_id);
void ClearNodeSelection(int node_id);
bool IsNodeSelected(int node_id);
void SelectLink(int link_id);
void ClearLinkSelection(int link_id);
bool IsLinkSelected(int link_id);
// Was the previous attribute active? This will continuously return true while the left mouse button
// is being pressed over the UI content of the attribute.
bool IsAttributeActive();
// Was any attribute active? If so, sets the active attribute id to the output function argument.
bool IsAnyAttributeActive(int* attribute_id = NULL);
// Use the following functions to query a change of state for an existing link, or new link. Call
// these after EndNodeEditor().
// Did the user start dragging a new link from a pin?
bool IsLinkStarted(int* started_at_attribute_id);
// Did the user drop the dragged link before attaching it to a pin?
// There are two different kinds of situations to consider when handling this event:
// 1) a link which is created at a pin and then dropped
// 2) an existing link which is detached from a pin and then dropped
// Use the including_detached_links flag to control whether this function triggers when the user
// detaches a link and drops it.
bool IsLinkDropped(int* started_at_attribute_id = NULL, bool including_detached_links = true);
// Did the user finish creating a new link?
bool IsLinkCreated(
int* started_at_attribute_id,
int* ended_at_attribute_id,
bool* created_from_snap = NULL);
bool IsLinkCreated(
int* started_at_node_id,
int* started_at_attribute_id,
int* ended_at_node_id,
int* ended_at_attribute_id,
bool* created_from_snap = NULL);
// Was an existing link detached from a pin by the user? The detached link's id is assigned to the
// output argument link_id.
bool IsLinkDestroyed(int* link_id);
// Use the following functions to write the editor context's state to a string, or directly to a
// file. The editor context is serialized in the INI file format.
const char* SaveCurrentEditorStateToIniString(size_t* data_size = NULL);
const char* SaveEditorStateToIniString(
const ImNodesEditorContext* editor,
size_t* data_size = NULL);
void LoadCurrentEditorStateFromIniString(const char* data, size_t data_size);
void LoadEditorStateFromIniString(ImNodesEditorContext* editor, const char* data, size_t data_size);
void SaveCurrentEditorStateToIniFile(const char* file_name);
void SaveEditorStateToIniFile(const ImNodesEditorContext* editor, const char* file_name);
void LoadCurrentEditorStateFromIniFile(const char* file_name);
void LoadEditorStateFromIniFile(ImNodesEditorContext* editor, const char* file_name);
} // namespace IMNODES_NAMESPACE
================================================
FILE: Source/External/imgui_tools/imnodes/imnodes_internal.h
================================================
#pragma once
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imnodes.h"
#include
#include
#include
// the structure of this file:
//
// [SECTION] internal enums
// [SECTION] internal data structures
// [SECTION] global and editor context structs
// [SECTION] object pool implementation
struct ImNodesContext;
extern ImNodesContext* GImNodes;
// [SECTION] internal enums
typedef int ImNodesScope;
typedef int ImNodesAttributeType;
typedef int ImNodesUIState;
typedef int ImNodesClickInteractionType;
typedef int ImNodesLinkCreationType;
enum ImNodesScope_
{
ImNodesScope_None = 1,
ImNodesScope_Editor = 1 << 1,
ImNodesScope_Node = 1 << 2,
ImNodesScope_Attribute = 1 << 3
};
enum ImNodesAttributeType_
{
ImNodesAttributeType_None,
ImNodesAttributeType_Input,
ImNodesAttributeType_Output
};
enum ImNodesUIState_
{
ImNodesUIState_None = 0,
ImNodesUIState_LinkStarted = 1 << 0,
ImNodesUIState_LinkDropped = 1 << 1,
ImNodesUIState_LinkCreated = 1 << 2
};
enum ImNodesClickInteractionType_
{
ImNodesClickInteractionType_Node,
ImNodesClickInteractionType_Link,
ImNodesClickInteractionType_LinkCreation,
ImNodesClickInteractionType_Panning,
ImNodesClickInteractionType_BoxSelection,
ImNodesClickInteractionType_ImGuiItem,
ImNodesClickInteractionType_None
};
enum ImNodesLinkCreationType_
{
ImNodesLinkCreationType_Standard,
ImNodesLinkCreationType_FromDetach
};
// [SECTION] internal data structures
// The object T must have the following interface:
//
// struct T
// {
// T();
//
// int id;
// };
template
struct ImObjectPool
{
ImVector Pool;
ImVector InUse;
ImVector FreeList;
ImGuiStorage IdMap;
ImObjectPool() : Pool(), InUse(), FreeList(), IdMap() {}
};
// Emulates std::optional using the sentinel value `INVALID_INDEX`.
struct ImOptionalIndex
{
ImOptionalIndex() : _Index(INVALID_INDEX) {}
ImOptionalIndex(const int value) : _Index(value) {}
// Observers
inline bool HasValue() const { return _Index != INVALID_INDEX; }
inline int Value() const
{
IM_ASSERT(HasValue());
return _Index;
}
// Modifiers
inline ImOptionalIndex& operator=(const int value)
{
_Index = value;
return *this;
}
inline void Reset() { _Index = INVALID_INDEX; }
inline bool operator==(const ImOptionalIndex& rhs) const { return _Index == rhs._Index; }
inline bool operator==(const int rhs) const { return _Index == rhs; }
inline bool operator!=(const ImOptionalIndex& rhs) const { return _Index != rhs._Index; }
inline bool operator!=(const int rhs) const { return _Index != rhs; }
static const int INVALID_INDEX = -1;
private:
int _Index;
};
struct ImNodeData
{
int Id;
ImVec2 Origin; // The node origin is in editor space
ImRect TitleBarContentRect;
ImRect Rect;
struct
{
ImU32 Background, BackgroundHovered, BackgroundSelected, Outline, Titlebar, TitlebarHovered,
TitlebarSelected;
} ColorStyle;
struct
{
float CornerRounding;
ImVec2 Padding;
float BorderThickness;
} LayoutStyle;
ImVector PinIndices;
bool Draggable;
ImNodeData(const int node_id)
: Id(node_id), Origin(0.0f, 0.0f), TitleBarContentRect(),
Rect(ImVec2(0.0f, 0.0f), ImVec2(0.0f, 0.0f)), ColorStyle(), LayoutStyle(), PinIndices(),
Draggable(true)
{
}
~ImNodeData() { Id = INT_MIN; }
};
struct ImPinData
{
int Id;
int ParentNodeIdx;
ImRect AttributeRect;
ImNodesAttributeType Type;
ImNodesPinShape Shape;
ImVec2 Pos; // screen-space coordinates
int Flags;
struct
{
ImU32 Background, Hovered;
} ColorStyle;
ImPinData(const int pin_id)
: Id(pin_id), ParentNodeIdx(), AttributeRect(), Type(ImNodesAttributeType_None),
Shape(ImNodesPinShape_CircleFilled), Pos(), Flags(ImNodesAttributeFlags_None),
ColorStyle()
{
}
};
struct ImLinkData
{
int Id;
int StartPinIdx, EndPinIdx;
struct
{
ImU32 Base, Hovered, Selected;
} ColorStyle;
ImLinkData(const int link_id) : Id(link_id), StartPinIdx(), EndPinIdx(), ColorStyle() {}
};
struct ImClickInteractionState
{
ImNodesClickInteractionType Type;
struct
{
int StartPinIdx;
ImOptionalIndex EndPinIdx;
ImNodesLinkCreationType Type;
} LinkCreation;
struct
{
ImRect Rect; // Coordinates in grid space
} BoxSelector;
ImClickInteractionState() : Type(ImNodesClickInteractionType_None) {}
};
struct ImNodesColElement
{
ImU32 Color;
ImNodesCol Item;
ImNodesColElement(const ImU32 c, const ImNodesCol s) : Color(c), Item(s) {}
};
struct ImNodesStyleVarElement
{
ImNodesStyleVar Item;
float FloatValue[2];
ImNodesStyleVarElement(const ImNodesStyleVar variable, const float value) : Item(variable)
{
FloatValue[0] = value;
}
ImNodesStyleVarElement(const ImNodesStyleVar variable, const ImVec2 value) : Item(variable)
{
FloatValue[0] = value.x;
FloatValue[1] = value.y;
}
};
// [SECTION] global and editor context structs
struct ImNodesEditorContext
{
ImObjectPool Nodes;
ImObjectPool Pins;
ImObjectPool Links;
ImVector NodeDepthOrder;
// ui related fields
ImVec2 Panning;
ImVec2 AutoPanningDelta;
// Minimum and maximum extents of all content in grid space. Valid after final
// ImNodes::EndNode() call.
ImRect GridContentBounds;
ImVector SelectedNodeIndices;
ImVector SelectedLinkIndices;
// Relative origins of selected nodes for snapping of dragged nodes
ImVector SelectedNodeOffsets;
// Offset of the primary node origin relative to the mouse cursor.
ImVec2 PrimaryNodeOffset;
ImClickInteractionState ClickInteraction;
// Mini-map state set by MiniMap()
bool MiniMapEnabled;
ImNodesMiniMapLocation MiniMapLocation;
float MiniMapSizeFraction;
ImNodesMiniMapNodeHoveringCallback MiniMapNodeHoveringCallback;
ImNodesMiniMapNodeHoveringCallbackUserData MiniMapNodeHoveringCallbackUserData;
// Mini-map state set during EndNodeEditor() call
ImRect MiniMapRectScreenSpace;
ImRect MiniMapContentScreenSpace;
float MiniMapScaling;
ImNodesEditorContext()
: Nodes(), Pins(), Links(), Panning(0.f, 0.f), SelectedNodeIndices(), SelectedLinkIndices(),
SelectedNodeOffsets(), PrimaryNodeOffset(0.f, 0.f), ClickInteraction(),
MiniMapEnabled(false), MiniMapSizeFraction(0.0f),
MiniMapNodeHoveringCallback(NULL), MiniMapNodeHoveringCallbackUserData(NULL),
MiniMapScaling(0.0f)
{
}
};
struct ImNodesContext
{
ImNodesEditorContext* DefaultEditorCtx;
ImNodesEditorContext* EditorCtx;
// Canvas draw list and helper state
ImDrawList* CanvasDrawList;
ImGuiStorage NodeIdxToSubmissionIdx;
ImVector NodeIdxSubmissionOrder;
ImVector NodeIndicesOverlappingWithMouse;
ImVector OccludedPinIndices;
// Canvas extents
ImVec2 CanvasOriginScreenSpace;
ImRect CanvasRectScreenSpace;
// Debug helpers
ImNodesScope CurrentScope;
// Configuration state
ImNodesIO Io;
ImNodesStyle Style;
ImVector ColorModifierStack;
ImVector StyleModifierStack;
ImGuiTextBuffer TextBuffer;
int CurrentAttributeFlags;
ImVector AttributeFlagStack;
// UI element state
int CurrentNodeIdx;
int CurrentPinIdx;
int CurrentAttributeId;
ImOptionalIndex HoveredNodeIdx;
ImOptionalIndex HoveredLinkIdx;
ImOptionalIndex HoveredPinIdx;
ImOptionalIndex DeletedLinkIdx;
ImOptionalIndex SnapLinkIdx;
// Event helper state
// TODO: this should be a part of a state machine, and not a member of the global struct.
// Unclear what parts of the code this relates to.
int ImNodesUIState;
int ActiveAttributeId;
bool ActiveAttribute;
// ImGui::IO cache
ImVec2 MousePos;
bool LeftMouseClicked;
bool LeftMouseReleased;
bool AltMouseClicked;
bool LeftMouseDragging;
bool AltMouseDragging;
float AltMouseScrollDelta;
bool MultipleSelectModifier;
};
namespace IMNODES_NAMESPACE
{
static inline ImNodesEditorContext& EditorContextGet()
{
// No editor context was set! Did you forget to call ImNodes::CreateContext()?
IM_ASSERT(GImNodes->EditorCtx != NULL);
return *GImNodes->EditorCtx;
}
// [SECTION] ObjectPool implementation
template
static inline int ObjectPoolFind(const ImObjectPool& objects, const int id)
{
const int index = objects.IdMap.GetInt(static_cast(id), -1);
return index;
}
template
static inline void ObjectPoolUpdate(ImObjectPool& objects)
{
for (int i = 0; i < objects.InUse.size(); ++i)
{
const int id = objects.Pool[i].Id;
if (!objects.InUse[i] && objects.IdMap.GetInt(id, -1) == i)
{
objects.IdMap.SetInt(id, -1);
objects.FreeList.push_back(i);
(objects.Pool.Data + i)->~T();
}
}
}
template<>
inline void ObjectPoolUpdate(ImObjectPool& nodes)
{
for (int i = 0; i < nodes.InUse.size(); ++i)
{
if (nodes.InUse[i])
{
nodes.Pool[i].PinIndices.clear();
}
else
{
const int id = nodes.Pool[i].Id;
if (nodes.IdMap.GetInt(id, -1) == i)
{
// Remove node idx form depth stack the first time we detect that this idx slot is
// unused
ImVector& depth_stack = EditorContextGet().NodeDepthOrder;
const int* const elem = depth_stack.find(i);
IM_ASSERT(elem != depth_stack.end());
depth_stack.erase(elem);
nodes.IdMap.SetInt(id, -1);
nodes.FreeList.push_back(i);
(nodes.Pool.Data + i)->~ImNodeData();
}
}
}
}
template
static inline void ObjectPoolReset(ImObjectPool& objects)
{
if (!objects.InUse.empty())
{
memset(objects.InUse.Data, 0, objects.InUse.size_in_bytes());
}
}
template
static inline int ObjectPoolFindOrCreateIndex(ImObjectPool& objects, const int id)
{
int index = objects.IdMap.GetInt(static_cast(id), -1);
// Construct new object
if (index == -1)
{
if (objects.FreeList.empty())
{
index = objects.Pool.size();
IM_ASSERT(objects.Pool.size() == objects.InUse.size());
const int new_size = objects.Pool.size() + 1;
objects.Pool.resize(new_size);
objects.InUse.resize(new_size);
}
else
{
index = objects.FreeList.back();
objects.FreeList.pop_back();
}
IM_PLACEMENT_NEW(objects.Pool.Data + index) T(id);
objects.IdMap.SetInt(static_cast(id), index);
}
// Flag it as used
objects.InUse[index] = true;
return index;
}
template<>
inline int ObjectPoolFindOrCreateIndex(ImObjectPool& nodes, const int node_id)
{
int node_idx = nodes.IdMap.GetInt(static_cast(node_id), -1);
// Construct new node
if (node_idx == -1)
{
if (nodes.FreeList.empty())
{
node_idx = nodes.Pool.size();
IM_ASSERT(nodes.Pool.size() == nodes.InUse.size());
const int new_size = nodes.Pool.size() + 1;
nodes.Pool.resize(new_size);
nodes.InUse.resize(new_size);
}
else
{
node_idx = nodes.FreeList.back();
nodes.FreeList.pop_back();
}
IM_PLACEMENT_NEW(nodes.Pool.Data + node_idx) ImNodeData(node_id);
nodes.IdMap.SetInt(static_cast(node_id), node_idx);
ImNodesEditorContext& editor = EditorContextGet();
editor.NodeDepthOrder.push_back(node_idx);
}
// Flag node as used
nodes.InUse[node_idx] = true;
return node_idx;
}
template
static inline T& ObjectPoolFindOrCreateObject(ImObjectPool& objects, const int id)
{
const int index = ObjectPoolFindOrCreateIndex(objects, id);
return objects.Pool[index];
}
} // namespace IMNODES_NAMESPACE
================================================
FILE: Source/External/imgui_tools/implot/implot.cpp
================================================
// MIT License
// Copyright (c) 2022 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ImPlot v0.14
/*
API BREAKING CHANGES
====================
Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot files.
You can read releases logs https://github.com/epezent/implot/releases for more details.
- 2022/06/19 (0.14) - The signature of ColormapScale has changed to accommodate a new ImPlotColormapScaleFlags parameter
- 2022/06/17 (0.14) - **IMPORTANT** All PlotX functions now take an ImPlotX_Flags `flags` parameter. Where applicable, it is located before the existing `offset` and `stride` parameters.
If you were providing offset and stride values, you will need to update your function call to include a `flags` value. If you fail to do this, you will likely see
unexpected results or crashes without a compiler warning since these three are all default args. We apologize for the inconvenience, but this was a necessary evil.
- PlotBarsH has been removed; use PlotBars + ImPlotBarsFlags_Horizontal instead
- PlotErrorBarsH has been removed; use PlotErrorBars + ImPlotErrorBarsFlags_Horizontal
- PlotHistogram/PlotHistogram2D signatures changed; `cumulative`, `density`, and `outliers` options now specified via ImPlotHistogramFlags
- PlotPieChart signature changed; `normalize` option now specified via ImPlotPieChartFlags
- PlotText signature changes; `vertical` option now specified via `ImPlotTextFlags_Vertical`
- `PlotVLines` and `PlotHLines` replaced with `PlotInfLines` (+ ImPlotInfLinesFlags_Horizontal )
- arguments of ImPlotGetter have been reversed to be consistent with other API callbacks
- SetupAxisScale + ImPlotScale have replaced ImPlotAxisFlags_LogScale and ImPlotAxisFlags_Time flags
- ImPlotFormatters should now return an int indicating the size written
- the signature of ImPlotGetter has been reversed so that void* user_data is the last argument and consistent with other callbacks
- 2021/10/19 (0.13) - MAJOR API OVERHAUL! See #168 and #272
- TRIVIAL RENAME:
- ImPlotLimits -> ImPlotRect
- ImPlotYAxis_ -> ImAxis_
- SetPlotYAxis -> SetAxis
- BeginDragDropTarget -> BeginDragDropTargetPlot
- BeginDragDropSource -> BeginDragDropSourcePlot
- ImPlotFlags_NoMousePos -> ImPlotFlags_NoMouseText
- SetNextPlotLimits -> SetNextAxesLimits
- SetMouseTextLocation -> SetupMouseText
- SIGNATURE MODIFIED:
- PixelsToPlot/PlotToPixels -> added optional X-Axis arg
- GetPlotMousePos -> added optional X-Axis arg
- GetPlotLimits -> added optional X-Axis arg
- GetPlotSelection -> added optional X-Axis arg
- DragLineX/Y/DragPoint -> now takes int id; removed labels (render with Annotation/Tag instead)
- REPLACED:
- IsPlotXAxisHovered/IsPlotXYAxisHovered -> IsAxisHovered(ImAxis)
- BeginDragDropTargetX/BeginDragDropTargetY -> BeginDragDropTargetAxis(ImAxis)
- BeginDragDropSourceX/BeginDragDropSourceY -> BeginDragDropSourceAxis(ImAxis)
- ImPlotCol_XAxis, ImPlotCol_YAxis1, etc. -> ImPlotCol_AxisText (push/pop this around SetupAxis to style individual axes)
- ImPlotCol_XAxisGrid, ImPlotCol_Y1AxisGrid -> ImPlotCol_AxisGrid (push/pop this around SetupAxis to style individual axes)
- SetNextPlotLimitsX/Y -> SetNextAxisLimits(ImAxis)
- LinkNextPlotLimits -> SetNextAxisLinks(ImAxis)
- FitNextPlotAxes -> SetNextAxisToFit(ImAxis)/SetNextAxesToFit
- SetLegendLocation -> SetupLegend
- ImPlotFlags_NoHighlight -> ImPlotLegendFlags_NoHighlight
- ImPlotOrientation -> ImPlotLegendFlags_Horizontal
- Annotate -> Annotation
- REMOVED:
- GetPlotQuery, SetPlotQuery, IsPlotQueried -> use DragRect
- SetNextPlotTicksX, SetNextPlotTicksY -> use SetupAxisTicks
- SetNextPlotFormatX, SetNextPlotFormatY -> use SetupAxisFormat
- AnnotateClamped -> use Annotation(bool clamp = true)
- OBSOLETED:
- BeginPlot (original signature) -> use simplified signature + Setup API
- 2021/07/30 (0.12) - The offset argument of `PlotXG` functions was been removed. Implement offsetting in your getter callback instead.
- 2021/03/08 (0.9) - SetColormap and PushColormap(ImVec4*) were removed. Use AddColormap for custom colormap support. LerpColormap was changed to SampleColormap.
ShowColormapScale was changed to ColormapScale and requires additional arguments.
- 2021/03/07 (0.9) - The signature of ShowColormapScale was modified to accept a ImVec2 size.
- 2021/02/28 (0.9) - BeginLegendDragDropSource was changed to BeginDragDropSourceItem with a number of other drag and drop improvements.
- 2021/01/18 (0.9) - The default behavior for opening context menus was change from double right-click to single right-click. ImPlotInputMap and related functions were moved
to implot_internal.h due to its immaturity.
- 2020/10/16 (0.8) - ImPlotStyleVar_InfoPadding was changed to ImPlotStyleVar_MousePosPadding
- 2020/09/10 (0.8) - The single array versions of PlotLine, PlotScatter, PlotStems, and PlotShaded were given additional arguments for x-scale and x0.
- 2020/09/07 (0.8) - Plotting functions which accept a custom getter function pointer have been post-fixed with a G (e.g. PlotLineG)
- 2020/09/06 (0.7) - Several flags under ImPlotFlags and ImPlotAxisFlags were inverted (e.g. ImPlotFlags_Legend -> ImPlotFlags_NoLegend) so that the default flagset
is simply 0. This more closely matches ImGui's style and makes it easier to enable non-default but commonly used flags (e.g. ImPlotAxisFlags_Time).
- 2020/08/28 (0.5) - ImPlotMarker_ can no longer be combined with bitwise OR, |. This features caused unecessary slow-down, and almost no one used it.
- 2020/08/25 (0.5) - ImPlotAxisFlags_Scientific was removed. Logarithmic axes automatically uses scientific notation.
- 2020/08/17 (0.5) - PlotText was changed so that text is centered horizontally and vertically about the desired point.
- 2020/08/16 (0.5) - An ImPlotContext must be explicitly created and destroyed now with `CreateContext` and `DestroyContext`. Previously, the context was statically initialized in this source file.
- 2020/06/13 (0.4) - The flags `ImPlotAxisFlag_Adaptive` and `ImPlotFlags_Cull` were removed. Both are now done internally by default.
- 2020/06/03 (0.3) - The signature and behavior of PlotPieChart was changed so that data with sum less than 1 can optionally be normalized. The label format can now be specified as well.
- 2020/06/01 (0.3) - SetPalette was changed to `SetColormap` for consistency with other plotting libraries. `RestorePalette` was removed. Use `SetColormap(ImPlotColormap_Default)`.
- 2020/05/31 (0.3) - Plot functions taking custom ImVec2* getters were removed. Use the ImPlotPoint* getter versions instead.
- 2020/05/29 (0.3) - The signature of ImPlotLimits::Contains was changed to take two doubles instead of ImVec2
- 2020/05/16 (0.2) - All plotting functions were reverted to being prefixed with "Plot" to maintain a consistent VerbNoun style. `Plot` was split into `PlotLine`
and `PlotScatter` (however, `PlotLine` can still be used to plot scatter points as `Plot` did before.). `Bar` is not `PlotBars`, to indicate
that multiple bars will be plotted.
- 2020/05/13 (0.2) - `ImMarker` was change to `ImPlotMarker` and `ImAxisFlags` was changed to `ImPlotAxisFlags`.
- 2020/05/11 (0.2) - `ImPlotFlags_Selection` was changed to `ImPlotFlags_BoxSelect`
- 2020/05/11 (0.2) - The namespace ImGui:: was replaced with ImPlot::. As a result, the following additional changes were made:
- Functions that were prefixed or decorated with the word "Plot" have been truncated. E.g., `ImGui::PlotBars` is now just `ImPlot::Bar`.
It should be fairly obvious what was what.
- Some functions have been given names that would have otherwise collided with the ImGui namespace. This has been done to maintain a consistent
style with ImGui. E.g., 'ImGui::PushPlotStyleVar` is now 'ImPlot::PushStyleVar'.
- 2020/05/10 (0.2) - The following function/struct names were changes:
- ImPlotRange -> ImPlotLimits
- GetPlotRange() -> GetPlotLimits()
- SetNextPlotRange -> SetNextPlotLimits
- SetNextPlotRangeX -> SetNextPlotLimitsX
- SetNextPlotRangeY -> SetNextPlotLimitsY
- 2020/05/10 (0.2) - Plot queries are pixel based by default. Query rects that maintain relative plot position have been removed. This was done to support multi-y-axis.
*/
#define IMGUI_DEFINE_MATH_OPERATORS
#include "implot.h"
#include "implot_internal.h"
#include
// Support for pre-1.82 versions. Users on 1.82+ can use 0 (default) flags to mean "all corners" but in order to support older versions we are more explicit.
#if (IMGUI_VERSION_NUM < 18102) && !defined(ImDrawFlags_RoundCornersAll)
#define ImDrawFlags_RoundCornersAll ImDrawCornerFlags_All
#endif
// Support for pre-1.89.7 versions.
#if (IMGUI_VERSION_NUM < 18966)
#define ImGuiButtonFlags_AllowOverlap ImGuiButtonFlags_AllowItemOverlap
#endif
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#endif
// Clang/GCC warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
#endif
// Global plot context
#ifndef GImPlot
ImPlotContext* GImPlot = nullptr;
#endif
//-----------------------------------------------------------------------------
// Struct Implementations
//-----------------------------------------------------------------------------
ImPlotInputMap::ImPlotInputMap() {
ImPlot::MapInputDefault(this);
}
ImPlotStyle::ImPlotStyle() {
LineWeight = 1;
Marker = ImPlotMarker_None;
MarkerSize = 4;
MarkerWeight = 1;
FillAlpha = 1;
ErrorBarSize = 5;
ErrorBarWeight = 1.5f;
DigitalBitHeight = 8;
DigitalBitGap = 4;
PlotBorderSize = 1;
MinorAlpha = 0.25f;
MajorTickLen = ImVec2(10,10);
MinorTickLen = ImVec2(5,5);
MajorTickSize = ImVec2(1,1);
MinorTickSize = ImVec2(1,1);
MajorGridSize = ImVec2(1,1);
MinorGridSize = ImVec2(1,1);
PlotPadding = ImVec2(10,10);
LabelPadding = ImVec2(5,5);
LegendPadding = ImVec2(10,10);
LegendInnerPadding = ImVec2(5,5);
LegendSpacing = ImVec2(5,0);
MousePosPadding = ImVec2(10,10);
AnnotationPadding = ImVec2(2,2);
FitPadding = ImVec2(0,0);
PlotDefaultSize = ImVec2(400,300);
PlotMinSize = ImVec2(200,150);
ImPlot::StyleColorsAuto(this);
Colormap = ImPlotColormap_Deep;
UseLocalTime = false;
Use24HourClock = false;
UseISO8601 = false;
}
//-----------------------------------------------------------------------------
// Style
//-----------------------------------------------------------------------------
namespace ImPlot {
const char* GetStyleColorName(ImPlotCol col) {
static const char* col_names[ImPlotCol_COUNT] = {
"Line",
"Fill",
"MarkerOutline",
"MarkerFill",
"ErrorBar",
"FrameBg",
"PlotBg",
"PlotBorder",
"LegendBg",
"LegendBorder",
"LegendText",
"TitleText",
"InlayText",
"AxisText",
"AxisGrid",
"AxisTick",
"AxisBg",
"AxisBgHovered",
"AxisBgActive",
"Selection",
"Crosshairs"
};
return col_names[col];
}
const char* GetMarkerName(ImPlotMarker marker) {
switch (marker) {
case ImPlotMarker_None: return "None";
case ImPlotMarker_Circle: return "Circle";
case ImPlotMarker_Square: return "Square";
case ImPlotMarker_Diamond: return "Diamond";
case ImPlotMarker_Up: return "Up";
case ImPlotMarker_Down: return "Down";
case ImPlotMarker_Left: return "Left";
case ImPlotMarker_Right: return "Right";
case ImPlotMarker_Cross: return "Cross";
case ImPlotMarker_Plus: return "Plus";
case ImPlotMarker_Asterisk: return "Asterisk";
default: return "";
}
}
ImVec4 GetAutoColor(ImPlotCol idx) {
ImVec4 col(0,0,0,1);
switch(idx) {
case ImPlotCol_Line: return col; // these are plot dependent!
case ImPlotCol_Fill: return col; // these are plot dependent!
case ImPlotCol_MarkerOutline: return col; // these are plot dependent!
case ImPlotCol_MarkerFill: return col; // these are plot dependent!
case ImPlotCol_ErrorBar: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_FrameBg: return ImGui::GetStyleColorVec4(ImGuiCol_FrameBg);
case ImPlotCol_PlotBg: return ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
case ImPlotCol_PlotBorder: return ImGui::GetStyleColorVec4(ImGuiCol_Border);
case ImPlotCol_LegendBg: return ImGui::GetStyleColorVec4(ImGuiCol_PopupBg);
case ImPlotCol_LegendBorder: return GetStyleColorVec4(ImPlotCol_PlotBorder);
case ImPlotCol_LegendText: return GetStyleColorVec4(ImPlotCol_InlayText);
case ImPlotCol_TitleText: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_InlayText: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_AxisText: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_AxisGrid: return GetStyleColorVec4(ImPlotCol_AxisText) * ImVec4(1,1,1,0.25f);
case ImPlotCol_AxisTick: return GetStyleColorVec4(ImPlotCol_AxisGrid);
case ImPlotCol_AxisBg: return ImVec4(0,0,0,0);
case ImPlotCol_AxisBgHovered: return ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
case ImPlotCol_AxisBgActive: return ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
case ImPlotCol_Selection: return ImVec4(1,1,0,1);
case ImPlotCol_Crosshairs: return GetStyleColorVec4(ImPlotCol_PlotBorder);
default: return col;
}
}
struct ImPlotStyleVarInfo {
ImGuiDataType Type;
ImU32 Count;
ImU32 Offset;
void* GetVarPtr(ImPlotStyle* style) const { return (void*)((unsigned char*)style + Offset); }
};
static const ImPlotStyleVarInfo GPlotStyleVarInfo[] =
{
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, LineWeight) }, // ImPlotStyleVar_LineWeight
{ ImGuiDataType_S32, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, Marker) }, // ImPlotStyleVar_Marker
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerSize) }, // ImPlotStyleVar_MarkerSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MarkerWeight) }, // ImPlotStyleVar_MarkerWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, FillAlpha) }, // ImPlotStyleVar_FillAlpha
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarSize) }, // ImPlotStyleVar_ErrorBarSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, ErrorBarWeight) }, // ImPlotStyleVar_ErrorBarWeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitHeight) }, // ImPlotStyleVar_DigitalBitHeight
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, DigitalBitGap) }, // ImPlotStyleVar_DigitalBitGap
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotBorderSize) }, // ImPlotStyleVar_PlotBorderSize
{ ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorAlpha) }, // ImPlotStyleVar_MinorAlpha
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorTickLen) }, // ImPlotStyleVar_MajorTickLen
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorTickLen) }, // ImPlotStyleVar_MinorTickLen
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorTickSize) }, // ImPlotStyleVar_MajorTickSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorTickSize) }, // ImPlotStyleVar_MinorTickSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MajorGridSize) }, // ImPlotStyleVar_MajorGridSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MinorGridSize) }, // ImPlotStyleVar_MinorGridSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotPadding) }, // ImPlotStyleVar_PlotPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LabelPadding) }, // ImPlotStyleVar_LabelPaddine
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendPadding) }, // ImPlotStyleVar_LegendPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendInnerPadding) }, // ImPlotStyleVar_LegendInnerPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, LegendSpacing) }, // ImPlotStyleVar_LegendSpacing
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, MousePosPadding) }, // ImPlotStyleVar_MousePosPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, AnnotationPadding) }, // ImPlotStyleVar_AnnotationPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, FitPadding) }, // ImPlotStyleVar_FitPadding
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotDefaultSize) }, // ImPlotStyleVar_PlotDefaultSize
{ ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImPlotStyle, PlotMinSize) } // ImPlotStyleVar_PlotMinSize
};
static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx) {
IM_ASSERT(idx >= 0 && idx < ImPlotStyleVar_COUNT);
IM_ASSERT(IM_ARRAYSIZE(GPlotStyleVarInfo) == ImPlotStyleVar_COUNT);
return &GPlotStyleVarInfo[idx];
}
//-----------------------------------------------------------------------------
// Generic Helpers
//-----------------------------------------------------------------------------
void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char *text_begin, const char* text_end) {
// the code below is based loosely on ImFont::RenderText
if (!text_end)
text_end = text_begin + strlen(text_begin);
ImGuiContext& g = *GImGui;
ImFont* font = g.Font;
// Align to be pixel perfect
pos.x = IM_FLOOR(pos.x);
pos.y = IM_FLOOR(pos.y);
const float scale = g.FontSize / font->FontSize;
const char* s = text_begin;
int chars_exp = (int)(text_end - s);
int chars_rnd = 0;
const int vtx_count_max = chars_exp * 4;
const int idx_count_max = chars_exp * 6;
DrawList->PrimReserve(idx_count_max, vtx_count_max);
while (s < text_end) {
unsigned int c = (unsigned int)*s;
if (c < 0x80) {
s += 1;
}
else {
s += ImTextCharFromUtf8(&c, s, text_end);
if (c == 0) // Malformed UTF-8?
break;
}
const ImFontGlyph * glyph = font->FindGlyph((ImWchar)c);
if (glyph == nullptr) {
continue;
}
DrawList->PrimQuadUV(pos + ImVec2(glyph->Y0, -glyph->X0) * scale, pos + ImVec2(glyph->Y0, -glyph->X1) * scale,
pos + ImVec2(glyph->Y1, -glyph->X1) * scale, pos + ImVec2(glyph->Y1, -glyph->X0) * scale,
ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V0),
ImVec2(glyph->U1, glyph->V1), ImVec2(glyph->U0, glyph->V1),
col);
pos.y -= glyph->AdvanceX * scale;
chars_rnd++;
}
// Give back unused vertices
int chars_skp = chars_exp-chars_rnd;
DrawList->PrimUnreserve(chars_skp*6, chars_skp*4);
}
void AddTextCentered(ImDrawList* DrawList, ImVec2 top_center, ImU32 col, const char* text_begin, const char* text_end) {
float txt_ht = ImGui::GetTextLineHeight();
const char* title_end = ImGui::FindRenderedTextEnd(text_begin, text_end);
ImVec2 text_size;
float y = 0;
while (const char* tmp = (const char*)memchr(text_begin, '\n', title_end-text_begin)) {
text_size = ImGui::CalcTextSize(text_begin,tmp,true);
DrawList->AddText(ImVec2(top_center.x - text_size.x * 0.5f, top_center.y+y),col,text_begin,tmp);
text_begin = tmp + 1;
y += txt_ht;
}
text_size = ImGui::CalcTextSize(text_begin,title_end,true);
DrawList->AddText(ImVec2(top_center.x - text_size.x * 0.5f, top_center.y+y),col,text_begin,title_end);
}
double NiceNum(double x, bool round) {
double f;
double nf;
int expv = (int)floor(ImLog10(x));
f = x / ImPow(10.0, (double)expv);
if (round)
if (f < 1.5)
nf = 1;
else if (f < 3)
nf = 2;
else if (f < 7)
nf = 5;
else
nf = 10;
else if (f <= 1)
nf = 1;
else if (f <= 2)
nf = 2;
else if (f <= 5)
nf = 5;
else
nf = 10;
return nf * ImPow(10.0, expv);
}
//-----------------------------------------------------------------------------
// Context Utils
//-----------------------------------------------------------------------------
void SetImGuiContext(ImGuiContext* ctx) {
ImGui::SetCurrentContext(ctx);
}
ImPlotContext* CreateContext() {
ImPlotContext* ctx = IM_NEW(ImPlotContext)();
Initialize(ctx);
if (GImPlot == nullptr)
SetCurrentContext(ctx);
return ctx;
}
void DestroyContext(ImPlotContext* ctx) {
if (ctx == nullptr)
ctx = GImPlot;
if (GImPlot == ctx)
SetCurrentContext(nullptr);
IM_DELETE(ctx);
}
ImPlotContext* GetCurrentContext() {
return GImPlot;
}
void SetCurrentContext(ImPlotContext* ctx) {
GImPlot = ctx;
}
#define IMPLOT_APPEND_CMAP(name, qual) ctx->ColormapData.Append(#name, name, sizeof(name)/sizeof(ImU32), qual)
#define IM_RGB(r,g,b) IM_COL32(r,g,b,255)
void Initialize(ImPlotContext* ctx) {
ResetCtxForNextPlot(ctx);
ResetCtxForNextAlignedPlots(ctx);
ResetCtxForNextSubplot(ctx);
const ImU32 Deep[] = {4289753676, 4283598045, 4285048917, 4283584196, 4289950337, 4284512403, 4291005402, 4287401100, 4285839820, 4291671396 };
const ImU32 Dark[] = {4280031972, 4290281015, 4283084621, 4288892568, 4278222847, 4281597951, 4280833702, 4290740727, 4288256409 };
const ImU32 Pastel[] = {4289639675, 4293119411, 4291161036, 4293184478, 4289124862, 4291624959, 4290631909, 4293712637, 4294111986 };
const ImU32 Paired[] = {4293119554, 4290017311, 4287291314, 4281114675, 4288256763, 4280031971, 4285513725, 4278222847, 4292260554, 4288298346, 4288282623, 4280834481};
const ImU32 Viridis[] = {4283695428, 4285867080, 4287054913, 4287455029, 4287526954, 4287402273, 4286883874, 4285579076, 4283552122, 4280737725, 4280674301 };
const ImU32 Plasma[] = {4287039501, 4288480321, 4289200234, 4288941455, 4287638193, 4286072780, 4284638433, 4283139314, 4281771772, 4280667900, 4280416752 };
const ImU32 Hot[] = {4278190144, 4278190208, 4278190271, 4278190335, 4278206719, 4278223103, 4278239231, 4278255615, 4283826175, 4289396735, 4294967295 };
const ImU32 Cool[] = {4294967040, 4294960666, 4294954035, 4294947661, 4294941030, 4294934656, 4294928025, 4294921651, 4294915020, 4294908646, 4294902015 };
const ImU32 Pink[] = {4278190154, 4282532475, 4284308894, 4285690554, 4286879686, 4287870160, 4288794330, 4289651940, 4291685869, 4293392118, 4294967295 };
const ImU32 Jet[] = {4289331200, 4294901760, 4294923520, 4294945280, 4294967040, 4289396565, 4283826090, 4278255615, 4278233855, 4278212095, 4278190335 };
const ImU32 Twilight[] = {IM_RGB(226,217,226),IM_RGB(166,191,202),IM_RGB(109,144,192),IM_RGB(95,88,176),IM_RGB(83,30,124),IM_RGB(47,20,54),IM_RGB(100,25,75),IM_RGB(159,60,80),IM_RGB(192,117,94),IM_RGB(208,179,158),IM_RGB(226,217,226)};
const ImU32 RdBu[] = {IM_RGB(103,0,31),IM_RGB(178,24,43),IM_RGB(214,96,77),IM_RGB(244,165,130),IM_RGB(253,219,199),IM_RGB(247,247,247),IM_RGB(209,229,240),IM_RGB(146,197,222),IM_RGB(67,147,195),IM_RGB(33,102,172),IM_RGB(5,48,97)};
const ImU32 BrBG[] = {IM_RGB(84,48,5),IM_RGB(140,81,10),IM_RGB(191,129,45),IM_RGB(223,194,125),IM_RGB(246,232,195),IM_RGB(245,245,245),IM_RGB(199,234,229),IM_RGB(128,205,193),IM_RGB(53,151,143),IM_RGB(1,102,94),IM_RGB(0,60,48)};
const ImU32 PiYG[] = {IM_RGB(142,1,82),IM_RGB(197,27,125),IM_RGB(222,119,174),IM_RGB(241,182,218),IM_RGB(253,224,239),IM_RGB(247,247,247),IM_RGB(230,245,208),IM_RGB(184,225,134),IM_RGB(127,188,65),IM_RGB(77,146,33),IM_RGB(39,100,25)};
const ImU32 Spectral[] = {IM_RGB(158,1,66),IM_RGB(213,62,79),IM_RGB(244,109,67),IM_RGB(253,174,97),IM_RGB(254,224,139),IM_RGB(255,255,191),IM_RGB(230,245,152),IM_RGB(171,221,164),IM_RGB(102,194,165),IM_RGB(50,136,189),IM_RGB(94,79,162)};
const ImU32 Greys[] = {IM_COL32_WHITE, IM_COL32_BLACK };
IMPLOT_APPEND_CMAP(Deep, true);
IMPLOT_APPEND_CMAP(Dark, true);
IMPLOT_APPEND_CMAP(Pastel, true);
IMPLOT_APPEND_CMAP(Paired, true);
IMPLOT_APPEND_CMAP(Viridis, false);
IMPLOT_APPEND_CMAP(Plasma, false);
IMPLOT_APPEND_CMAP(Hot, false);
IMPLOT_APPEND_CMAP(Cool, false);
IMPLOT_APPEND_CMAP(Pink, false);
IMPLOT_APPEND_CMAP(Jet, false);
IMPLOT_APPEND_CMAP(Twilight, false);
IMPLOT_APPEND_CMAP(RdBu, false);
IMPLOT_APPEND_CMAP(BrBG, false);
IMPLOT_APPEND_CMAP(PiYG, false);
IMPLOT_APPEND_CMAP(Spectral, false);
IMPLOT_APPEND_CMAP(Greys, false);
}
void ResetCtxForNextPlot(ImPlotContext* ctx) {
// end child window if it was made
if (ctx->ChildWindowMade)
ImGui::EndChild();
ctx->ChildWindowMade = false;
// reset the next plot/item data
ctx->NextPlotData.Reset();
ctx->NextItemData.Reset();
// reset labels
ctx->Annotations.Reset();
ctx->Tags.Reset();
// reset extents/fit
ctx->OpenContextThisFrame = false;
// reset digital plot items count
ctx->DigitalPlotItemCnt = 0;
ctx->DigitalPlotOffset = 0;
// nullify plot
ctx->CurrentPlot = nullptr;
ctx->CurrentItem = nullptr;
ctx->PreviousItem = nullptr;
}
void ResetCtxForNextAlignedPlots(ImPlotContext* ctx) {
ctx->CurrentAlignmentH = nullptr;
ctx->CurrentAlignmentV = nullptr;
}
void ResetCtxForNextSubplot(ImPlotContext* ctx) {
ctx->CurrentSubplot = nullptr;
ctx->CurrentAlignmentH = nullptr;
ctx->CurrentAlignmentV = nullptr;
}
//-----------------------------------------------------------------------------
// Plot Utils
//-----------------------------------------------------------------------------
ImPlotPlot* GetPlot(const char* title) {
ImGuiWindow* Window = GImGui->CurrentWindow;
const ImGuiID ID = Window->GetID(title);
return GImPlot->Plots.GetByKey(ID);
}
ImPlotPlot* GetCurrentPlot() {
return GImPlot->CurrentPlot;
}
void BustPlotCache() {
ImPlotContext& gp = *GImPlot;
gp.Plots.Clear();
gp.Subplots.Clear();
}
//-----------------------------------------------------------------------------
// Legend Utils
//-----------------------------------------------------------------------------
ImVec2 GetLocationPos(const ImRect& outer_rect, const ImVec2& inner_size, ImPlotLocation loc, const ImVec2& pad) {
ImVec2 pos;
if (ImHasFlag(loc, ImPlotLocation_West) && !ImHasFlag(loc, ImPlotLocation_East))
pos.x = outer_rect.Min.x + pad.x;
else if (!ImHasFlag(loc, ImPlotLocation_West) && ImHasFlag(loc, ImPlotLocation_East))
pos.x = outer_rect.Max.x - pad.x - inner_size.x;
else
pos.x = outer_rect.GetCenter().x - inner_size.x * 0.5f;
// legend reference point y
if (ImHasFlag(loc, ImPlotLocation_North) && !ImHasFlag(loc, ImPlotLocation_South))
pos.y = outer_rect.Min.y + pad.y;
else if (!ImHasFlag(loc, ImPlotLocation_North) && ImHasFlag(loc, ImPlotLocation_South))
pos.y = outer_rect.Max.y - pad.y - inner_size.y;
else
pos.y = outer_rect.GetCenter().y - inner_size.y * 0.5f;
pos.x = IM_ROUND(pos.x);
pos.y = IM_ROUND(pos.y);
return pos;
}
ImVec2 CalcLegendSize(ImPlotItemGroup& items, const ImVec2& pad, const ImVec2& spacing, bool vertical) {
// vars
const int nItems = items.GetLegendCount();
const float txt_ht = ImGui::GetTextLineHeight();
const float icon_size = txt_ht;
// get label max width
float max_label_width = 0;
float sum_label_width = 0;
for (int i = 0; i < nItems; ++i) {
const char* label = items.GetLegendLabel(i);
const float label_width = ImGui::CalcTextSize(label, nullptr, true).x;
max_label_width = label_width > max_label_width ? label_width : max_label_width;
sum_label_width += label_width;
}
// calc legend size
const ImVec2 legend_size = vertical ?
ImVec2(pad.x * 2 + icon_size + max_label_width, pad.y * 2 + nItems * txt_ht + (nItems - 1) * spacing.y) :
ImVec2(pad.x * 2 + icon_size * nItems + sum_label_width + (nItems - 1) * spacing.x, pad.y * 2 + txt_ht);
return legend_size;
}
int LegendSortingComp(const void* _a, const void* _b) {
ImPlotItemGroup* items = GImPlot->SortItems;
const int a = *(const int*)_a;
const int b = *(const int*)_b;
const char* label_a = items->GetLegendLabel(a);
const char* label_b = items->GetLegendLabel(b);
return strcmp(label_a,label_b);
}
bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool hovered, const ImVec2& pad, const ImVec2& spacing, bool vertical, ImDrawList& DrawList) {
// vars
const float txt_ht = ImGui::GetTextLineHeight();
const float icon_size = txt_ht;
const float icon_shrink = 2;
ImU32 col_txt = GetStyleColorU32(ImPlotCol_LegendText);
ImU32 col_txt_dis = ImAlphaU32(col_txt, 0.25f);
// render each legend item
float sum_label_width = 0;
bool any_item_hovered = false;
const int num_items = items.GetLegendCount();
if (num_items < 1)
return hovered;
// build render order
ImPlotContext& gp = *GImPlot;
ImVector& indices = gp.TempInt1;
indices.resize(num_items);
for (int i = 0; i < num_items; ++i)
indices[i] = i;
if (ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_Sort) && num_items > 1) {
gp.SortItems = &items;
qsort(indices.Data, num_items, sizeof(int), LegendSortingComp);
}
// render
for (int i = 0; i < num_items; ++i) {
const int idx = indices[i];
ImPlotItem* item = items.GetLegendItem(idx);
const char* label = items.GetLegendLabel(idx);
const float label_width = ImGui::CalcTextSize(label, nullptr, true).x;
const ImVec2 top_left = vertical ?
legend_bb.Min + pad + ImVec2(0, i * (txt_ht + spacing.y)) :
legend_bb.Min + pad + ImVec2(i * (icon_size + spacing.x) + sum_label_width, 0);
sum_label_width += label_width;
ImRect icon_bb;
icon_bb.Min = top_left + ImVec2(icon_shrink,icon_shrink);
icon_bb.Max = top_left + ImVec2(icon_size - icon_shrink, icon_size - icon_shrink);
ImRect label_bb;
label_bb.Min = top_left;
label_bb.Max = top_left + ImVec2(label_width + icon_size, icon_size);
ImU32 col_txt_hl;
ImU32 col_item = ImAlphaU32(item->Color,1);
ImRect button_bb(icon_bb.Min, label_bb.Max);
ImGui::KeepAliveID(item->ID);
bool item_hov = false;
bool item_hld = false;
bool item_clk = ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_NoButtons)
? false
: ImGui::ButtonBehavior(button_bb, item->ID, &item_hov, &item_hld);
if (item_clk)
item->Show = !item->Show;
const bool can_hover = (item_hov)
&& (!ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_NoHighlightItem)
|| !ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_NoHighlightAxis));
if (can_hover) {
item->LegendHoverRect.Min = icon_bb.Min;
item->LegendHoverRect.Max = label_bb.Max;
item->LegendHovered = true;
col_txt_hl = ImMixU32(col_txt, col_item, 64);
any_item_hovered = true;
}
else {
col_txt_hl = ImGui::GetColorU32(col_txt);
}
ImU32 col_icon;
if (item_hld)
col_icon = item->Show ? ImAlphaU32(col_item,0.5f) : ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.5f);
else if (item_hov)
col_icon = item->Show ? ImAlphaU32(col_item,0.75f) : ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.75f);
else
col_icon = item->Show ? col_item : col_txt_dis;
DrawList.AddRectFilled(icon_bb.Min, icon_bb.Max, col_icon);
const char* text_display_end = ImGui::FindRenderedTextEnd(label, nullptr);
if (label != text_display_end)
DrawList.AddText(top_left + ImVec2(icon_size, 0), item->Show ? col_txt_hl : col_txt_dis, label, text_display_end);
}
return hovered && !any_item_hovered;
}
//-----------------------------------------------------------------------------
// Locators
//-----------------------------------------------------------------------------
static const float TICK_FILL_X = 0.8f;
static const float TICK_FILL_Y = 1.0f;
void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
if (range.Min == range.Max)
return;
const int nMinor = 10;
const int nMajor = ImMax(2, (int)IM_ROUND(pixels / (vertical ? 300.0f : 400.0f)));
const double nice_range = NiceNum(range.Size() * 0.99, false);
const double interval = NiceNum(nice_range / (nMajor - 1), true);
const double graphmin = floor(range.Min / interval) * interval;
const double graphmax = ceil(range.Max / interval) * interval;
bool first_major_set = false;
int first_major_idx = 0;
const int idx0 = ticker.TickCount(); // ticker may have user custom ticks
ImVec2 total_size(0,0);
for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
// is this zero? combat zero formatting issues
if (major-interval < 0 && major+interval > 0)
major = 0;
if (range.Contains(major)) {
if (!first_major_set) {
first_major_idx = ticker.TickCount();
first_major_set = true;
}
total_size += ticker.AddTick(major, true, 0, true, formatter, formatter_data).LabelSize;
}
for (int i = 1; i < nMinor; ++i) {
double minor = major + i * interval / nMinor;
if (range.Contains(minor)) {
total_size += ticker.AddTick(minor, false, 0, true, formatter, formatter_data).LabelSize;
}
}
}
// prune if necessary
if ((!vertical && total_size.x > pixels*TICK_FILL_X) || (vertical && total_size.y > pixels*TICK_FILL_Y)) {
for (int i = first_major_idx-1; i >= idx0; i -= 2)
ticker.Ticks[i].ShowLabel = false;
for (int i = first_major_idx+1; i < ticker.TickCount(); i += 2)
ticker.Ticks[i].ShowLabel = false;
}
}
bool CalcLogarithmicExponents(const ImPlotRange& range, float pix, bool vertical, int& exp_min, int& exp_max, int& exp_step) {
if (range.Min * range.Max > 0) {
const int nMajor = vertical ? ImMax(2, (int)IM_ROUND(pix * 0.02f)) : ImMax(2, (int)IM_ROUND(pix * 0.01f)); // TODO: magic numbers
double log_min = ImLog10(ImAbs(range.Min));
double log_max = ImLog10(ImAbs(range.Max));
double log_a = ImMin(log_min,log_max);
double log_b = ImMax(log_min,log_max);
exp_step = ImMax(1,(int)(log_b - log_a) / nMajor);
exp_min = (int)log_a;
exp_max = (int)log_b;
if (exp_step != 1) {
while(exp_step % 3 != 0) exp_step++; // make step size multiple of three
while(exp_min % exp_step != 0) exp_min--; // decrease exp_min until exp_min + N * exp_step will be 0
}
return true;
}
return false;
}
void AddTicksLogarithmic(const ImPlotRange& range, int exp_min, int exp_max, int exp_step, ImPlotTicker& ticker, ImPlotFormatter formatter, void* data) {
const double sign = ImSign(range.Max);
for (int e = exp_min - exp_step; e < (exp_max + exp_step); e += exp_step) {
double major1 = sign*ImPow(10, (double)(e));
double major2 = sign*ImPow(10, (double)(e + 1));
double interval = (major2 - major1) / 9;
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
ticker.AddTick(major1, true, 0, true, formatter, data);
for (int j = 0; j < exp_step; ++j) {
major1 = sign*ImPow(10, (double)(e+j));
major2 = sign*ImPow(10, (double)(e+j+1));
interval = (major2 - major1) / 9;
for (int i = 1; i < (9 + (int)(j < (exp_step - 1))); ++i) {
double minor = major1 + i * interval;
if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
ticker.AddTick(minor, false, 0, false, formatter, data);
}
}
}
}
void Locator_Log10(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
int exp_min, exp_max, exp_step;
if (CalcLogarithmicExponents(range, pixels, vertical, exp_min, exp_max, exp_step))
AddTicksLogarithmic(range, exp_min, exp_max, exp_step, ticker, formatter, formatter_data);
}
float CalcSymLogPixel(double plt, const ImPlotRange& range, float pixels) {
double scaleToPixels = pixels / range.Size();
double scaleMin = TransformForward_SymLog(range.Min,nullptr);
double scaleMax = TransformForward_SymLog(range.Max,nullptr);
double s = TransformForward_SymLog(plt, nullptr);
double t = (s - scaleMin) / (scaleMax - scaleMin);
plt = range.Min + range.Size() * t;
return (float)(0 + scaleToPixels * (plt - range.Min));
}
void Locator_SymLog(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
if (range.Min >= -1 && range.Max <= 1) {
Locator_Default(ticker, range, pixels, vertical, formatter, formatter_data);
}
else if (range.Min * range.Max < 0) { // cross zero
const float pix_min = 0;
const float pix_max = pixels;
const float pix_p1 = CalcSymLogPixel(1, range, pixels);
const float pix_n1 = CalcSymLogPixel(-1, range, pixels);
int exp_min_p, exp_max_p, exp_step_p;
int exp_min_n, exp_max_n, exp_step_n;
CalcLogarithmicExponents(ImPlotRange(1,range.Max), ImAbs(pix_max-pix_p1),vertical,exp_min_p,exp_max_p,exp_step_p);
CalcLogarithmicExponents(ImPlotRange(range.Min,-1),ImAbs(pix_n1-pix_min),vertical,exp_min_n,exp_max_n,exp_step_n);
int exp_step = ImMax(exp_step_n, exp_step_p);
ticker.AddTick(0,true,0,true,formatter,formatter_data);
AddTicksLogarithmic(ImPlotRange(1,range.Max), exp_min_p,exp_max_p,exp_step,ticker,formatter,formatter_data);
AddTicksLogarithmic(ImPlotRange(range.Min,-1),exp_min_n,exp_max_n,exp_step,ticker,formatter,formatter_data);
}
else {
Locator_Log10(ticker, range, pixels, vertical, formatter, formatter_data);
}
}
void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTicker& ticker, ImPlotFormatter formatter, void* data) {
for (int i = 0; i < n; ++i) {
if (labels != nullptr)
ticker.AddTick(values[i], false, 0, true, labels[i]);
else
ticker.AddTick(values[i], false, 0, true, formatter, data);
}
}
//-----------------------------------------------------------------------------
// Time Ticks and Utils
//-----------------------------------------------------------------------------
// this may not be thread safe?
static const double TimeUnitSpans[ImPlotTimeUnit_COUNT] = {
0.000001,
0.001,
1,
60,
3600,
86400,
2629800,
31557600
};
inline ImPlotTimeUnit GetUnitForRange(double range) {
static double cutoffs[ImPlotTimeUnit_COUNT] = {0.001, 1, 60, 3600, 86400, 2629800, 31557600, IMPLOT_MAX_TIME};
for (int i = 0; i < ImPlotTimeUnit_COUNT; ++i) {
if (range <= cutoffs[i])
return (ImPlotTimeUnit)i;
}
return ImPlotTimeUnit_Yr;
}
inline int LowerBoundStep(int max_divs, const int* divs, const int* step, int size) {
if (max_divs < divs[0])
return 0;
for (int i = 1; i < size; ++i) {
if (max_divs < divs[i])
return step[i-1];
}
return step[size-1];
}
inline int GetTimeStep(int max_divs, ImPlotTimeUnit unit) {
if (unit == ImPlotTimeUnit_Ms || unit == ImPlotTimeUnit_Us) {
static const int step[] = {500,250,200,100,50,25,20,10,5,2,1};
static const int divs[] = {2,4,5,10,20,40,50,100,200,500,1000};
return LowerBoundStep(max_divs, divs, step, 11);
}
if (unit == ImPlotTimeUnit_S || unit == ImPlotTimeUnit_Min) {
static const int step[] = {30,15,10,5,1};
static const int divs[] = {2,4,6,12,60};
return LowerBoundStep(max_divs, divs, step, 5);
}
else if (unit == ImPlotTimeUnit_Hr) {
static const int step[] = {12,6,3,2,1};
static const int divs[] = {2,4,8,12,24};
return LowerBoundStep(max_divs, divs, step, 5);
}
else if (unit == ImPlotTimeUnit_Day) {
static const int step[] = {14,7,2,1};
static const int divs[] = {2,4,14,28};
return LowerBoundStep(max_divs, divs, step, 4);
}
else if (unit == ImPlotTimeUnit_Mo) {
static const int step[] = {6,3,2,1};
static const int divs[] = {2,4,6,12};
return LowerBoundStep(max_divs, divs, step, 4);
}
return 0;
}
ImPlotTime MkGmtTime(struct tm *ptm) {
ImPlotTime t;
#ifdef _WIN32
t.S = _mkgmtime(ptm);
#else
t.S = timegm(ptm);
#endif
if (t.S < 0)
t.S = 0;
return t;
}
tm* GetGmtTime(const ImPlotTime& t, tm* ptm)
{
#ifdef _WIN32
if (gmtime_s(ptm, &t.S) == 0)
return ptm;
else
return nullptr;
#else
return gmtime_r(&t.S, ptm);
#endif
}
ImPlotTime MkLocTime(struct tm *ptm) {
ImPlotTime t;
t.S = mktime(ptm);
if (t.S < 0)
t.S = 0;
return t;
}
tm* GetLocTime(const ImPlotTime& t, tm* ptm) {
#ifdef _WIN32
if (localtime_s(ptm, &t.S) == 0)
return ptm;
else
return nullptr;
#else
return localtime_r(&t.S, ptm);
#endif
}
inline ImPlotTime MkTime(struct tm *ptm) {
if (GetStyle().UseLocalTime)
return MkLocTime(ptm);
else
return MkGmtTime(ptm);
}
inline tm* GetTime(const ImPlotTime& t, tm* ptm) {
if (GetStyle().UseLocalTime)
return GetLocTime(t,ptm);
else
return GetGmtTime(t,ptm);
}
ImPlotTime MakeTime(int year, int month, int day, int hour, int min, int sec, int us) {
tm& Tm = GImPlot->Tm;
int yr = year - 1900;
if (yr < 0)
yr = 0;
sec = sec + us / 1000000;
us = us % 1000000;
Tm.tm_sec = sec;
Tm.tm_min = min;
Tm.tm_hour = hour;
Tm.tm_mday = day;
Tm.tm_mon = month;
Tm.tm_year = yr;
ImPlotTime t = MkTime(&Tm);
t.Us = us;
return t;
}
int GetYear(const ImPlotTime& t) {
tm& Tm = GImPlot->Tm;
GetTime(t, &Tm);
return Tm.tm_year + 1900;
}
ImPlotTime AddTime(const ImPlotTime& t, ImPlotTimeUnit unit, int count) {
tm& Tm = GImPlot->Tm;
ImPlotTime t_out = t;
switch(unit) {
case ImPlotTimeUnit_Us: t_out.Us += count; break;
case ImPlotTimeUnit_Ms: t_out.Us += count * 1000; break;
case ImPlotTimeUnit_S: t_out.S += count; break;
case ImPlotTimeUnit_Min: t_out.S += count * 60; break;
case ImPlotTimeUnit_Hr: t_out.S += count * 3600; break;
case ImPlotTimeUnit_Day: t_out.S += count * 86400; break;
case ImPlotTimeUnit_Mo: for (int i = 0; i < abs(count); ++i) {
GetTime(t_out, &Tm);
if (count > 0)
t_out.S += 86400 * GetDaysInMonth(Tm.tm_year + 1900, Tm.tm_mon);
else if (count < 0)
t_out.S -= 86400 * GetDaysInMonth(Tm.tm_year + 1900 - (Tm.tm_mon == 0 ? 1 : 0), Tm.tm_mon == 0 ? 11 : Tm.tm_mon - 1); // NOT WORKING
}
break;
case ImPlotTimeUnit_Yr: for (int i = 0; i < abs(count); ++i) {
if (count > 0)
t_out.S += 86400 * (365 + (int)IsLeapYear(GetYear(t_out)));
else if (count < 0)
t_out.S -= 86400 * (365 + (int)IsLeapYear(GetYear(t_out) - 1));
// this is incorrect if leap year and we are past Feb 28
}
break;
default: break;
}
t_out.RollOver();
return t_out;
}
ImPlotTime FloorTime(const ImPlotTime& t, ImPlotTimeUnit unit) {
ImPlotContext& gp = *GImPlot;
GetTime(t, &gp.Tm);
switch (unit) {
case ImPlotTimeUnit_S: return ImPlotTime(t.S, 0);
case ImPlotTimeUnit_Ms: return ImPlotTime(t.S, (t.Us / 1000) * 1000);
case ImPlotTimeUnit_Us: return t;
case ImPlotTimeUnit_Yr: gp.Tm.tm_mon = 0; // fall-through
case ImPlotTimeUnit_Mo: gp.Tm.tm_mday = 1; // fall-through
case ImPlotTimeUnit_Day: gp.Tm.tm_hour = 0; // fall-through
case ImPlotTimeUnit_Hr: gp.Tm.tm_min = 0; // fall-through
case ImPlotTimeUnit_Min: gp.Tm.tm_sec = 0; break;
default: return t;
}
return MkTime(&gp.Tm);
}
ImPlotTime CeilTime(const ImPlotTime& t, ImPlotTimeUnit unit) {
return AddTime(FloorTime(t, unit), unit, 1);
}
ImPlotTime RoundTime(const ImPlotTime& t, ImPlotTimeUnit unit) {
ImPlotTime t1 = FloorTime(t, unit);
ImPlotTime t2 = AddTime(t1,unit,1);
if (t1.S == t2.S)
return t.Us - t1.Us < t2.Us - t.Us ? t1 : t2;
return t.S - t1.S < t2.S - t.S ? t1 : t2;
}
ImPlotTime CombineDateTime(const ImPlotTime& date_part, const ImPlotTime& tod_part) {
ImPlotContext& gp = *GImPlot;
tm& Tm = gp.Tm;
GetTime(date_part, &gp.Tm);
int y = Tm.tm_year;
int m = Tm.tm_mon;
int d = Tm.tm_mday;
GetTime(tod_part, &gp.Tm);
Tm.tm_year = y;
Tm.tm_mon = m;
Tm.tm_mday = d;
ImPlotTime t = MkTime(&Tm);
t.Us = tod_part.Us;
return t;
}
// TODO: allow users to define these
static const char* MONTH_NAMES[] = {"January","February","March","April","May","June","July","August","September","October","November","December"};
static const char* WD_ABRVS[] = {"Su","Mo","Tu","We","Th","Fr","Sa"};
static const char* MONTH_ABRVS[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt, bool use_24_hr_clk) {
tm& Tm = GImPlot->Tm;
GetTime(t, &Tm);
const int us = t.Us % 1000;
const int ms = t.Us / 1000;
const int sec = Tm.tm_sec;
const int min = Tm.tm_min;
if (use_24_hr_clk) {
const int hr = Tm.tm_hour;
switch(fmt) {
case ImPlotTimeFmt_Us: return ImFormatString(buffer, size, ".%03d %03d", ms, us);
case ImPlotTimeFmt_SUs: return ImFormatString(buffer, size, ":%02d.%03d %03d", sec, ms, us);
case ImPlotTimeFmt_SMs: return ImFormatString(buffer, size, ":%02d.%03d", sec, ms);
case ImPlotTimeFmt_S: return ImFormatString(buffer, size, ":%02d", sec);
case ImPlotTimeFmt_MinSMs: return ImFormatString(buffer, size, ":%02d:%02d.%03d", min, sec, ms);
case ImPlotTimeFmt_HrMinSMs: return ImFormatString(buffer, size, "%02d:%02d:%02d.%03d", hr, min, sec, ms);
case ImPlotTimeFmt_HrMinS: return ImFormatString(buffer, size, "%02d:%02d:%02d", hr, min, sec);
case ImPlotTimeFmt_HrMin: return ImFormatString(buffer, size, "%02d:%02d", hr, min);
case ImPlotTimeFmt_Hr: return ImFormatString(buffer, size, "%02d:00", hr);
default: return 0;
}
}
else {
const char* ap = Tm.tm_hour < 12 ? "am" : "pm";
const int hr = (Tm.tm_hour == 0 || Tm.tm_hour == 12) ? 12 : Tm.tm_hour % 12;
switch(fmt) {
case ImPlotTimeFmt_Us: return ImFormatString(buffer, size, ".%03d %03d", ms, us);
case ImPlotTimeFmt_SUs: return ImFormatString(buffer, size, ":%02d.%03d %03d", sec, ms, us);
case ImPlotTimeFmt_SMs: return ImFormatString(buffer, size, ":%02d.%03d", sec, ms);
case ImPlotTimeFmt_S: return ImFormatString(buffer, size, ":%02d", sec);
case ImPlotTimeFmt_MinSMs: return ImFormatString(buffer, size, ":%02d:%02d.%03d", min, sec, ms);
case ImPlotTimeFmt_HrMinSMs: return ImFormatString(buffer, size, "%d:%02d:%02d.%03d%s", hr, min, sec, ms, ap);
case ImPlotTimeFmt_HrMinS: return ImFormatString(buffer, size, "%d:%02d:%02d%s", hr, min, sec, ap);
case ImPlotTimeFmt_HrMin: return ImFormatString(buffer, size, "%d:%02d%s", hr, min, ap);
case ImPlotTimeFmt_Hr: return ImFormatString(buffer, size, "%d%s", hr, ap);
default: return 0;
}
}
}
int FormatDate(const ImPlotTime& t, char* buffer, int size, ImPlotDateFmt fmt, bool use_iso_8601) {
tm& Tm = GImPlot->Tm;
GetTime(t, &Tm);
const int day = Tm.tm_mday;
const int mon = Tm.tm_mon + 1;
const int year = Tm.tm_year + 1900;
const int yr = year % 100;
if (use_iso_8601) {
switch (fmt) {
case ImPlotDateFmt_DayMo: return ImFormatString(buffer, size, "--%02d-%02d", mon, day);
case ImPlotDateFmt_DayMoYr: return ImFormatString(buffer, size, "%d-%02d-%02d", year, mon, day);
case ImPlotDateFmt_MoYr: return ImFormatString(buffer, size, "%d-%02d", year, mon);
case ImPlotDateFmt_Mo: return ImFormatString(buffer, size, "--%02d", mon);
case ImPlotDateFmt_Yr: return ImFormatString(buffer, size, "%d", year);
default: return 0;
}
}
else {
switch (fmt) {
case ImPlotDateFmt_DayMo: return ImFormatString(buffer, size, "%d/%d", mon, day);
case ImPlotDateFmt_DayMoYr: return ImFormatString(buffer, size, "%d/%d/%02d", mon, day, yr);
case ImPlotDateFmt_MoYr: return ImFormatString(buffer, size, "%s %d", MONTH_ABRVS[Tm.tm_mon], year);
case ImPlotDateFmt_Mo: return ImFormatString(buffer, size, "%s", MONTH_ABRVS[Tm.tm_mon]);
case ImPlotDateFmt_Yr: return ImFormatString(buffer, size, "%d", year);
default: return 0;
}
}
}
int FormatDateTime(const ImPlotTime& t, char* buffer, int size, ImPlotDateTimeSpec fmt) {
int written = 0;
if (fmt.Date != ImPlotDateFmt_None)
written += FormatDate(t, buffer, size, fmt.Date, fmt.UseISO8601);
if (fmt.Time != ImPlotTimeFmt_None) {
if (fmt.Date != ImPlotDateFmt_None)
buffer[written++] = ' ';
written += FormatTime(t, &buffer[written], size - written, fmt.Time, fmt.Use24HourClock);
}
return written;
}
inline float GetDateTimeWidth(ImPlotDateTimeSpec fmt) {
static const ImPlotTime t_max_width = MakeTime(2888, 12, 22, 12, 58, 58, 888888); // best guess at time that maximizes pixel width
char buffer[32];
FormatDateTime(t_max_width, buffer, 32, fmt);
return ImGui::CalcTextSize(buffer).x;
}
inline bool TimeLabelSame(const char* l1, const char* l2) {
size_t len1 = strlen(l1);
size_t len2 = strlen(l2);
size_t n = len1 < len2 ? len1 : len2;
return strcmp(l1 + len1 - n, l2 + len2 - n) == 0;
}
static const ImPlotDateTimeSpec TimeFormatLevel0[ImPlotTimeUnit_COUNT] = {
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_Us),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_SMs),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_S),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_HrMin),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_Hr),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMo, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_Mo, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_Yr, ImPlotTimeFmt_None)
};
static const ImPlotDateTimeSpec TimeFormatLevel1[ImPlotTimeUnit_COUNT] = {
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_HrMin),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_HrMinS),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_HrMin),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_HrMin),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_Yr, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_Yr, ImPlotTimeFmt_None)
};
static const ImPlotDateTimeSpec TimeFormatLevel1First[ImPlotTimeUnit_COUNT] = {
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_HrMinS),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_HrMinS),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_HrMin),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_HrMin),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_Yr, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_Yr, ImPlotTimeFmt_None)
};
static const ImPlotDateTimeSpec TimeFormatMouseCursor[ImPlotTimeUnit_COUNT] = {
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_Us),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_SUs),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_SMs),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_HrMinS),
ImPlotDateTimeSpec(ImPlotDateFmt_None, ImPlotTimeFmt_HrMin),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMo, ImPlotTimeFmt_Hr),
ImPlotDateTimeSpec(ImPlotDateFmt_DayMoYr, ImPlotTimeFmt_None),
ImPlotDateTimeSpec(ImPlotDateFmt_MoYr, ImPlotTimeFmt_None)
};
inline ImPlotDateTimeSpec GetDateTimeFmt(const ImPlotDateTimeSpec* ctx, ImPlotTimeUnit idx) {
ImPlotStyle& style = GetStyle();
ImPlotDateTimeSpec fmt = ctx[idx];
fmt.UseISO8601 = style.UseISO8601;
fmt.Use24HourClock = style.Use24HourClock;
return fmt;
}
void Locator_Time(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data) {
IM_ASSERT_USER_ERROR(vertical == false, "Cannot locate Time ticks on vertical axis!");
(void)vertical;
// get units for level 0 and level 1 labels
const ImPlotTimeUnit unit0 = GetUnitForRange(range.Size() / (pixels / 100)); // level = 0 (top)
const ImPlotTimeUnit unit1 = ImClamp(unit0 + 1, 0, ImPlotTimeUnit_COUNT-1); // level = 1 (bottom)
// get time format specs
const ImPlotDateTimeSpec fmt0 = GetDateTimeFmt(TimeFormatLevel0, unit0);
const ImPlotDateTimeSpec fmt1 = GetDateTimeFmt(TimeFormatLevel1, unit1);
const ImPlotDateTimeSpec fmtf = GetDateTimeFmt(TimeFormatLevel1First, unit1);
// min max times
const ImPlotTime t_min = ImPlotTime::FromDouble(range.Min);
const ImPlotTime t_max = ImPlotTime::FromDouble(range.Max);
// maximum allowable density of labels
const float max_density = 0.5f;
// book keeping
int last_major_offset = -1;
// formatter data
Formatter_Time_Data ftd;
ftd.UserFormatter = formatter;
ftd.UserFormatterData = formatter_data;
if (unit0 != ImPlotTimeUnit_Yr) {
// pixels per major (level 1) division
const float pix_per_major_div = pixels / (float)(range.Size() / TimeUnitSpans[unit1]);
// nominal pixels taken up by labels
const float fmt0_width = GetDateTimeWidth(fmt0);
const float fmt1_width = GetDateTimeWidth(fmt1);
const float fmtf_width = GetDateTimeWidth(fmtf);
// the maximum number of minor (level 0) labels that can fit between major (level 1) divisions
const int minor_per_major = (int)(max_density * pix_per_major_div / fmt0_width);
// the minor step size (level 0)
const int step = GetTimeStep(minor_per_major, unit0);
// generate ticks
ImPlotTime t1 = FloorTime(ImPlotTime::FromDouble(range.Min), unit1);
while (t1 < t_max) {
// get next major
const ImPlotTime t2 = AddTime(t1, unit1, 1);
// add major tick
if (t1 >= t_min && t1 <= t_max) {
// minor level 0 tick
ftd.Time = t1; ftd.Spec = fmt0;
ticker.AddTick(t1.ToDouble(), true, 0, true, Formatter_Time, &ftd);
// major level 1 tick
ftd.Time = t1; ftd.Spec = last_major_offset < 0 ? fmtf : fmt1;
ImPlotTick& tick_maj = ticker.AddTick(t1.ToDouble(), true, 1, true, Formatter_Time, &ftd);
const char* this_major = ticker.GetText(tick_maj);
if (last_major_offset >= 0 && TimeLabelSame(ticker.TextBuffer.Buf.Data + last_major_offset, this_major))
tick_maj.ShowLabel = false;
last_major_offset = tick_maj.TextOffset;
}
// add minor ticks up until next major
if (minor_per_major > 1 && (t_min <= t2 && t1 <= t_max)) {
ImPlotTime t12 = AddTime(t1, unit0, step);
while (t12 < t2) {
float px_to_t2 = (float)((t2 - t12).ToDouble()/range.Size()) * pixels;
if (t12 >= t_min && t12 <= t_max) {
ftd.Time = t12; ftd.Spec = fmt0;
ticker.AddTick(t12.ToDouble(), false, 0, px_to_t2 >= fmt0_width, Formatter_Time, &ftd);
if (last_major_offset < 0 && px_to_t2 >= fmt0_width && px_to_t2 >= (fmt1_width + fmtf_width) / 2) {
ftd.Time = t12; ftd.Spec = fmtf;
ImPlotTick& tick_maj = ticker.AddTick(t12.ToDouble(), true, 1, true, Formatter_Time, &ftd);
last_major_offset = tick_maj.TextOffset;
}
}
t12 = AddTime(t12, unit0, step);
}
}
t1 = t2;
}
}
else {
const ImPlotDateTimeSpec fmty = GetDateTimeFmt(TimeFormatLevel0, ImPlotTimeUnit_Yr);
const float label_width = GetDateTimeWidth(fmty);
const int max_labels = (int)(max_density * pixels / label_width);
const int year_min = GetYear(t_min);
const int year_max = GetYear(CeilTime(t_max, ImPlotTimeUnit_Yr));
const double nice_range = NiceNum((year_max - year_min)*0.99,false);
const double interval = NiceNum(nice_range / (max_labels - 1), true);
const int graphmin = (int)(floor(year_min / interval) * interval);
const int graphmax = (int)(ceil(year_max / interval) * interval);
const int step = (int)interval <= 0 ? 1 : (int)interval;
for (int y = graphmin; y < graphmax; y += step) {
ImPlotTime t = MakeTime(y);
if (t >= t_min && t <= t_max) {
ftd.Time = t; ftd.Spec = fmty;
ticker.AddTick(t.ToDouble(), true, 0, true, Formatter_Time, &ftd);
}
}
}
}
//-----------------------------------------------------------------------------
// Context Menu
//-----------------------------------------------------------------------------
template
bool DragFloat(const char*, F*, float, F, F) {
return false;
}
template <>
bool DragFloat(const char* label, double* v, float v_speed, double v_min, double v_max) {
return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, "%.3f", 1);
}
template <>
bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max) {
return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1);
}
inline void BeginDisabledControls(bool cond) {
if (cond) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f);
}
}
inline void EndDisabledControls(bool cond) {
if (cond) {
ImGui::PopItemFlag();
ImGui::PopStyleVar();
}
}
void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool /*time_allowed*/) {
ImGui::PushItemWidth(75);
bool always_locked = axis.IsRangeLocked() || axis.IsAutoFitting();
bool label = axis.HasLabel();
bool grid = axis.HasGridLines();
bool ticks = axis.HasTickMarks();
bool labels = axis.HasTickLabels();
double drag_speed = (axis.Range.Size() <= DBL_EPSILON) ? DBL_EPSILON * 1.0e+13 : 0.01 * axis.Range.Size(); // recover from almost equal axis limits.
if (axis.Scale == ImPlotScale_Time) {
ImPlotTime tmin = ImPlotTime::FromDouble(axis.Range.Min);
ImPlotTime tmax = ImPlotTime::FromDouble(axis.Range.Max);
BeginDisabledControls(always_locked);
ImGui::CheckboxFlags("##LockMin", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMin);
EndDisabledControls(always_locked);
ImGui::SameLine();
BeginDisabledControls(axis.IsLockedMin() || always_locked);
if (ImGui::BeginMenu("Min Time")) {
if (ShowTimePicker("mintime", &tmin)) {
if (tmin >= tmax)
tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
}
ImGui::Separator();
if (ShowDatePicker("mindate",&axis.PickerLevel,&axis.PickerTimeMin,&tmin,&tmax)) {
tmin = CombineDateTime(axis.PickerTimeMin, tmin);
if (tmin >= tmax)
tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
}
ImGui::EndMenu();
}
EndDisabledControls(axis.IsLockedMin() || always_locked);
BeginDisabledControls(always_locked);
ImGui::CheckboxFlags("##LockMax", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMax);
EndDisabledControls(always_locked);
ImGui::SameLine();
BeginDisabledControls(axis.IsLockedMax() || always_locked);
if (ImGui::BeginMenu("Max Time")) {
if (ShowTimePicker("maxtime", &tmax)) {
if (tmax <= tmin)
tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
}
ImGui::Separator();
if (ShowDatePicker("maxdate",&axis.PickerLevel,&axis.PickerTimeMax,&tmin,&tmax)) {
tmax = CombineDateTime(axis.PickerTimeMax, tmax);
if (tmax <= tmin)
tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
}
ImGui::EndMenu();
}
EndDisabledControls(axis.IsLockedMax() || always_locked);
}
else {
BeginDisabledControls(always_locked);
ImGui::CheckboxFlags("##LockMin", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMin);
EndDisabledControls(always_locked);
ImGui::SameLine();
BeginDisabledControls(axis.IsLockedMin() || always_locked);
double temp_min = axis.Range.Min;
if (DragFloat("Min", &temp_min, (float)drag_speed, -HUGE_VAL, axis.Range.Max - DBL_EPSILON)) {
axis.SetMin(temp_min,true);
if (equal_axis != nullptr)
equal_axis->SetAspect(axis.GetAspect());
}
EndDisabledControls(axis.IsLockedMin() || always_locked);
BeginDisabledControls(always_locked);
ImGui::CheckboxFlags("##LockMax", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMax);
EndDisabledControls(always_locked);
ImGui::SameLine();
BeginDisabledControls(axis.IsLockedMax() || always_locked);
double temp_max = axis.Range.Max;
if (DragFloat("Max", &temp_max, (float)drag_speed, axis.Range.Min + DBL_EPSILON, HUGE_VAL)) {
axis.SetMax(temp_max,true);
if (equal_axis != nullptr)
equal_axis->SetAspect(axis.GetAspect());
}
EndDisabledControls(axis.IsLockedMax() || always_locked);
}
ImGui::Separator();
ImGui::CheckboxFlags("Auto-Fit",(unsigned int*)&axis.Flags, ImPlotAxisFlags_AutoFit);
// TODO
// BeginDisabledControls(axis.IsTime() && time_allowed);
// ImGui::CheckboxFlags("Log Scale",(unsigned int*)&axis.Flags, ImPlotAxisFlags_LogScale);
// EndDisabledControls(axis.IsTime() && time_allowed);
// if (time_allowed) {
// BeginDisabledControls(axis.IsLog() || axis.IsSymLog());
// ImGui::CheckboxFlags("Time",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Time);
// EndDisabledControls(axis.IsLog() || axis.IsSymLog());
// }
ImGui::Separator();
ImGui::CheckboxFlags("Invert",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Invert);
ImGui::CheckboxFlags("Opposite",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Opposite);
ImGui::Separator();
BeginDisabledControls(axis.LabelOffset == -1);
if (ImGui::Checkbox("Label", &label))
ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoLabel);
EndDisabledControls(axis.LabelOffset == -1);
if (ImGui::Checkbox("Grid Lines", &grid))
ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoGridLines);
if (ImGui::Checkbox("Tick Marks", &ticks))
ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickMarks);
if (ImGui::Checkbox("Tick Labels", &labels))
ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickLabels);
}
bool ShowLegendContextMenu(ImPlotLegend& legend, bool visible) {
const float s = ImGui::GetFrameHeight();
bool ret = false;
if (ImGui::Checkbox("Show",&visible))
ret = true;
if (legend.CanGoInside)
ImGui::CheckboxFlags("Outside",(unsigned int*)&legend.Flags, ImPlotLegendFlags_Outside);
if (ImGui::RadioButton("H", ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal)))
legend.Flags |= ImPlotLegendFlags_Horizontal;
ImGui::SameLine();
if (ImGui::RadioButton("V", !ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal)))
legend.Flags &= ~ImPlotLegendFlags_Horizontal;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2,2));
if (ImGui::Button("NW",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_NorthWest; } ImGui::SameLine();
if (ImGui::Button("N", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_North; } ImGui::SameLine();
if (ImGui::Button("NE",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_NorthEast; }
if (ImGui::Button("W", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_West; } ImGui::SameLine();
if (ImGui::InvisibleButton("C", ImVec2(1.5f*s,s))) { } ImGui::SameLine();
if (ImGui::Button("E", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_East; }
if (ImGui::Button("SW",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_SouthWest; } ImGui::SameLine();
if (ImGui::Button("S", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_South; } ImGui::SameLine();
if (ImGui::Button("SE",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_SouthEast; }
ImGui::PopStyleVar();
return ret;
}
void ShowSubplotsContextMenu(ImPlotSubplot& subplot) {
if ((ImGui::BeginMenu("Linking"))) {
if (ImGui::MenuItem("Link Rows",nullptr,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkRows)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkRows);
if (ImGui::MenuItem("Link Cols",nullptr,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkCols)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkCols);
if (ImGui::MenuItem("Link All X",nullptr,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllX)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllX);
if (ImGui::MenuItem("Link All Y",nullptr,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllY)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllY);
ImGui::EndMenu();
}
if ((ImGui::BeginMenu("Settings"))) {
BeginDisabledControls(!subplot.HasTitle);
if (ImGui::MenuItem("Title",nullptr,subplot.HasTitle && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoTitle)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_NoTitle);
EndDisabledControls(!subplot.HasTitle);
if (ImGui::MenuItem("Resizable",nullptr,!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoResize)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_NoResize);
if (ImGui::MenuItem("Align",nullptr,!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoAlign)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_NoAlign);
if (ImGui::MenuItem("Share Items",nullptr,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems)))
ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems);
ImGui::EndMenu();
}
}
void ShowPlotContextMenu(ImPlotPlot& plot) {
ImPlotContext& gp = *GImPlot;
const bool owns_legend = gp.CurrentItems == &plot.Items;
const bool equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
char buf[16] = {};
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (!x_axis.Enabled || !x_axis.HasMenus())
continue;
ImGui::PushID(i);
ImFormatString(buf, sizeof(buf) - 1, i == 0 ? "X-Axis" : "X-Axis %d", i + 1);
if (ImGui::BeginMenu(x_axis.HasLabel() ? plot.GetAxisLabel(x_axis) : buf)) {
ShowAxisContextMenu(x_axis, equal ? x_axis.OrthoAxis : nullptr, false);
ImGui::EndMenu();
}
ImGui::PopID();
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (!y_axis.Enabled || !y_axis.HasMenus())
continue;
ImGui::PushID(i);
ImFormatString(buf, sizeof(buf) - 1, i == 0 ? "Y-Axis" : "Y-Axis %d", i + 1);
if (ImGui::BeginMenu(y_axis.HasLabel() ? plot.GetAxisLabel(y_axis) : buf)) {
ShowAxisContextMenu(y_axis, equal ? y_axis.OrthoAxis : nullptr, false);
ImGui::EndMenu();
}
ImGui::PopID();
}
ImGui::Separator();
if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoMenus)) {
if ((ImGui::BeginMenu("Legend"))) {
if (owns_legend) {
if (ShowLegendContextMenu(plot.Items.Legend, !ImHasFlag(plot.Flags, ImPlotFlags_NoLegend)))
ImFlipFlag(plot.Flags, ImPlotFlags_NoLegend);
}
else if (gp.CurrentSubplot != nullptr) {
if (ShowLegendContextMenu(gp.CurrentSubplot->Items.Legend, !ImHasFlag(gp.CurrentSubplot->Flags, ImPlotSubplotFlags_NoLegend)))
ImFlipFlag(gp.CurrentSubplot->Flags, ImPlotSubplotFlags_NoLegend);
}
ImGui::EndMenu();
}
}
if ((ImGui::BeginMenu("Settings"))) {
if (ImGui::MenuItem("Equal", nullptr, ImHasFlag(plot.Flags, ImPlotFlags_Equal)))
ImFlipFlag(plot.Flags, ImPlotFlags_Equal);
if (ImGui::MenuItem("Box Select",nullptr,!ImHasFlag(plot.Flags, ImPlotFlags_NoBoxSelect)))
ImFlipFlag(plot.Flags, ImPlotFlags_NoBoxSelect);
BeginDisabledControls(plot.TitleOffset == -1);
if (ImGui::MenuItem("Title",nullptr,plot.HasTitle()))
ImFlipFlag(plot.Flags, ImPlotFlags_NoTitle);
EndDisabledControls(plot.TitleOffset == -1);
if (ImGui::MenuItem("Mouse Position",nullptr,!ImHasFlag(plot.Flags, ImPlotFlags_NoMouseText)))
ImFlipFlag(plot.Flags, ImPlotFlags_NoMouseText);
if (ImGui::MenuItem("Crosshairs",nullptr,ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs)))
ImFlipFlag(plot.Flags, ImPlotFlags_Crosshairs);
ImGui::EndMenu();
}
if (gp.CurrentSubplot != nullptr && !ImHasFlag(gp.CurrentPlot->Flags, ImPlotSubplotFlags_NoMenus)) {
ImGui::Separator();
if ((ImGui::BeginMenu("Subplots"))) {
ShowSubplotsContextMenu(*gp.CurrentSubplot);
ImGui::EndMenu();
}
}
}
//-----------------------------------------------------------------------------
// Axis Utils
//-----------------------------------------------------------------------------
static inline int AxisPrecision(const ImPlotAxis& axis) {
const double range = axis.Ticker.TickCount() > 1 ? (axis.Ticker.Ticks[1].PlotPos - axis.Ticker.Ticks[0].PlotPos) : axis.Range.Size();
return Precision(range);
}
static inline double RoundAxisValue(const ImPlotAxis& axis, double value) {
return RoundTo(value, AxisPrecision(axis));
}
void LabelAxisValue(const ImPlotAxis& axis, double value, char* buff, int size, bool round) {
ImPlotContext& gp = *GImPlot;
// TODO: We shouldn't explicitly check that the axis is Time here. Ideally,
// Formatter_Time would handle the formatting for us, but the code below
// needs additional arguments which are not currently available in ImPlotFormatter
if (axis.Locator == Locator_Time) {
ImPlotTimeUnit unit = axis.Vertical
? GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetHeight() / 100)) // TODO: magic value!
: GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetWidth() / 100)); // TODO: magic value!
FormatDateTime(ImPlotTime::FromDouble(value), buff, size, GetDateTimeFmt(TimeFormatMouseCursor, unit));
}
else {
if (round)
value = RoundAxisValue(axis, value);
axis.Formatter(value, buff, size, axis.FormatterData);
}
}
void UpdateAxisColors(ImPlotAxis& axis) {
const ImVec4 col_grid = GetStyleColorVec4(ImPlotCol_AxisGrid);
axis.ColorMaj = ImGui::GetColorU32(col_grid);
axis.ColorMin = ImGui::GetColorU32(col_grid*ImVec4(1,1,1,GImPlot->Style.MinorAlpha));
axis.ColorTick = GetStyleColorU32(ImPlotCol_AxisTick);
axis.ColorTxt = GetStyleColorU32(ImPlotCol_AxisText);
axis.ColorBg = GetStyleColorU32(ImPlotCol_AxisBg);
axis.ColorHov = GetStyleColorU32(ImPlotCol_AxisBgHovered);
axis.ColorAct = GetStyleColorU32(ImPlotCol_AxisBgActive);
// axis.ColorHiLi = IM_COL32_BLACK_TRANS;
}
void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, ImPlotAlignmentData* align) {
ImPlotContext& gp = *GImPlot;
const float T = ImGui::GetTextLineHeight();
const float P = gp.Style.LabelPadding.y;
const float K = gp.Style.MinorTickLen.x;
int count_T = 0;
int count_B = 0;
float last_T = plot.AxesRect.Min.y;
float last_B = plot.AxesRect.Max.y;
for (int i = IMPLOT_NUM_X_AXES; i-- > 0;) { // FYI: can iterate forward
ImPlotAxis& axis = plot.XAxis(i);
if (!axis.Enabled)
continue;
const bool label = axis.HasLabel();
const bool ticks = axis.HasTickLabels();
const bool opp = axis.IsOpposite();
const bool time = axis.Scale == ImPlotScale_Time;
if (opp) {
if (count_T++ > 0)
pad_T += K + P;
if (label)
pad_T += T + P;
if (ticks)
pad_T += ImMax(T, axis.Ticker.MaxSize.y) + P + (time ? T + P : 0);
axis.Datum1 = plot.CanvasRect.Min.y + pad_T;
axis.Datum2 = last_T;
last_T = axis.Datum1;
}
else {
if (count_B++ > 0)
pad_B += K + P;
if (label)
pad_B += T + P;
if (ticks)
pad_B += ImMax(T, axis.Ticker.MaxSize.y) + P + (time ? T + P : 0);
axis.Datum1 = plot.CanvasRect.Max.y - pad_B;
axis.Datum2 = last_B;
last_B = axis.Datum1;
}
}
if (align) {
count_T = count_B = 0;
float delta_T, delta_B;
align->Update(pad_T,pad_B,delta_T,delta_B);
for (int i = IMPLOT_NUM_X_AXES; i-- > 0;) {
ImPlotAxis& axis = plot.XAxis(i);
if (!axis.Enabled)
continue;
if (axis.IsOpposite()) {
axis.Datum1 += delta_T;
axis.Datum2 += count_T++ > 1 ? delta_T : 0;
}
else {
axis.Datum1 -= delta_B;
axis.Datum2 -= count_B++ > 1 ? delta_B : 0;
}
}
}
}
void PadAndDatumAxesY(ImPlotPlot& plot, float& pad_L, float& pad_R, ImPlotAlignmentData* align) {
// [ pad_L ] [ pad_R ]
// .................CanvasRect................
// :TPWPK.PTPWP _____PlotRect____ PWPTP.KPWPT:
// :A # |- A # |- -| # A -| # A:
// :X | X | | X | x:
// :I # |- I # |- -| # I -| # I:
// :S | S | | S | S:
// :3 # |- 0 # |-_______________-| # 1 -| # 2:
// :.........................................:
//
// T = text height
// P = label padding
// K = minor tick length
// W = label width
ImPlotContext& gp = *GImPlot;
const float T = ImGui::GetTextLineHeight();
const float P = gp.Style.LabelPadding.x;
const float K = gp.Style.MinorTickLen.y;
int count_L = 0;
int count_R = 0;
float last_L = plot.AxesRect.Min.x;
float last_R = plot.AxesRect.Max.x;
for (int i = IMPLOT_NUM_Y_AXES; i-- > 0;) { // FYI: can iterate forward
ImPlotAxis& axis = plot.YAxis(i);
if (!axis.Enabled)
continue;
const bool label = axis.HasLabel();
const bool ticks = axis.HasTickLabels();
const bool opp = axis.IsOpposite();
if (opp) {
if (count_R++ > 0)
pad_R += K + P;
if (label)
pad_R += T + P;
if (ticks)
pad_R += axis.Ticker.MaxSize.x + P;
axis.Datum1 = plot.CanvasRect.Max.x - pad_R;
axis.Datum2 = last_R;
last_R = axis.Datum1;
}
else {
if (count_L++ > 0)
pad_L += K + P;
if (label)
pad_L += T + P;
if (ticks)
pad_L += axis.Ticker.MaxSize.x + P;
axis.Datum1 = plot.CanvasRect.Min.x + pad_L;
axis.Datum2 = last_L;
last_L = axis.Datum1;
}
}
plot.PlotRect.Min.x = plot.CanvasRect.Min.x + pad_L;
plot.PlotRect.Max.x = plot.CanvasRect.Max.x - pad_R;
if (align) {
count_L = count_R = 0;
float delta_L, delta_R;
align->Update(pad_L,pad_R,delta_L,delta_R);
for (int i = IMPLOT_NUM_Y_AXES; i-- > 0;) {
ImPlotAxis& axis = plot.YAxis(i);
if (!axis.Enabled)
continue;
if (axis.IsOpposite()) {
axis.Datum1 -= delta_R;
axis.Datum2 -= count_R++ > 1 ? delta_R : 0;
}
else {
axis.Datum1 += delta_L;
axis.Datum2 += count_L++ > 1 ? delta_L : 0;
}
}
}
}
//-----------------------------------------------------------------------------
// RENDERING
//-----------------------------------------------------------------------------
static inline void RenderGridLinesX(ImDrawList& DrawList, const ImPlotTicker& ticker, const ImRect& rect, ImU32 col_maj, ImU32 col_min, float size_maj, float size_min) {
const float density = ticker.TickCount() / rect.GetWidth();
ImVec4 col_min4 = ImGui::ColorConvertU32ToFloat4(col_min);
col_min4.w *= ImClamp(ImRemap(density, 0.1f, 0.2f, 1.0f, 0.0f), 0.0f, 1.0f);
col_min = ImGui::ColorConvertFloat4ToU32(col_min4);
for (int t = 0; t < ticker.TickCount(); t++) {
const ImPlotTick& xt = ticker.Ticks[t];
if (xt.PixelPos < rect.Min.x || xt.PixelPos > rect.Max.x)
continue;
if (xt.Level == 0) {
if (xt.Major)
DrawList.AddLine(ImVec2(xt.PixelPos, rect.Min.y), ImVec2(xt.PixelPos, rect.Max.y), col_maj, size_maj);
else if (density < 0.2f)
DrawList.AddLine(ImVec2(xt.PixelPos, rect.Min.y), ImVec2(xt.PixelPos, rect.Max.y), col_min, size_min);
}
}
}
static inline void RenderGridLinesY(ImDrawList& DrawList, const ImPlotTicker& ticker, const ImRect& rect, ImU32 col_maj, ImU32 col_min, float size_maj, float size_min) {
const float density = ticker.TickCount() / rect.GetHeight();
ImVec4 col_min4 = ImGui::ColorConvertU32ToFloat4(col_min);
col_min4.w *= ImClamp(ImRemap(density, 0.1f, 0.2f, 1.0f, 0.0f), 0.0f, 1.0f);
col_min = ImGui::ColorConvertFloat4ToU32(col_min4);
for (int t = 0; t < ticker.TickCount(); t++) {
const ImPlotTick& yt = ticker.Ticks[t];
if (yt.PixelPos < rect.Min.y || yt.PixelPos > rect.Max.y)
continue;
if (yt.Major)
DrawList.AddLine(ImVec2(rect.Min.x, yt.PixelPos), ImVec2(rect.Max.x, yt.PixelPos), col_maj, size_maj);
else if (density < 0.2f)
DrawList.AddLine(ImVec2(rect.Min.x, yt.PixelPos), ImVec2(rect.Max.x, yt.PixelPos), col_min, size_min);
}
}
static inline void RenderSelectionRect(ImDrawList& DrawList, const ImVec2& p_min, const ImVec2& p_max, const ImVec4& col) {
const ImU32 col_bg = ImGui::GetColorU32(col * ImVec4(1,1,1,0.25f));
const ImU32 col_bd = ImGui::GetColorU32(col);
DrawList.AddRectFilled(p_min, p_max, col_bg);
DrawList.AddRect(p_min, p_max, col_bd);
}
//-----------------------------------------------------------------------------
// Input Handling
//-----------------------------------------------------------------------------
static const float MOUSE_CURSOR_DRAG_THRESHOLD = 5.0f;
static const float BOX_SELECT_DRAG_THRESHOLD = 4.0f;
bool UpdateInput(ImPlotPlot& plot) {
bool changed = false;
ImPlotContext& gp = *GImPlot;
ImGuiIO& IO = ImGui::GetIO();
// BUTTON STATE -----------------------------------------------------------
const ImGuiButtonFlags plot_button_flags = ImGuiButtonFlags_AllowOverlap
| ImGuiButtonFlags_PressedOnClick
| ImGuiButtonFlags_PressedOnDoubleClick
| ImGuiButtonFlags_MouseButtonLeft
| ImGuiButtonFlags_MouseButtonRight
| ImGuiButtonFlags_MouseButtonMiddle;
const ImGuiButtonFlags axis_button_flags = ImGuiButtonFlags_FlattenChildren
| plot_button_flags;
const bool plot_clicked = ImGui::ButtonBehavior(plot.PlotRect,plot.ID,&plot.Hovered,&plot.Held,plot_button_flags);
#if (IMGUI_VERSION_NUM < 18966)
ImGui::SetItemAllowOverlap(); // Handled by ButtonBehavior()
#endif
if (plot_clicked) {
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoBoxSelect) && IO.MouseClicked[gp.InputMap.Select] && ImHasFlag(IO.KeyMods, gp.InputMap.SelectMod)) {
plot.Selecting = true;
plot.SelectStart = IO.MousePos;
plot.SelectRect = ImRect(0,0,0,0);
}
if (IO.MouseDoubleClicked[gp.InputMap.Fit]) {
plot.FitThisFrame = true;
for (int i = 0; i < ImAxis_COUNT; ++i)
plot.Axes[i].FitThisFrame = true;
}
}
const bool can_pan = IO.MouseDown[gp.InputMap.Pan] && ImHasFlag(IO.KeyMods, gp.InputMap.PanMod);
plot.Held = plot.Held && can_pan;
bool x_click[IMPLOT_NUM_X_AXES] = {false};
bool x_held[IMPLOT_NUM_X_AXES] = {false};
bool x_hov[IMPLOT_NUM_X_AXES] = {false};
bool y_click[IMPLOT_NUM_Y_AXES] = {false};
bool y_held[IMPLOT_NUM_Y_AXES] = {false};
bool y_hov[IMPLOT_NUM_Y_AXES] = {false};
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
ImPlotAxis& xax = plot.XAxis(i);
if (xax.Enabled) {
ImGui::KeepAliveID(xax.ID);
x_click[i] = ImGui::ButtonBehavior(xax.HoverRect,xax.ID,&xax.Hovered,&xax.Held,axis_button_flags);
if (x_click[i] && IO.MouseDoubleClicked[gp.InputMap.Fit])
plot.FitThisFrame = xax.FitThisFrame = true;
xax.Held = xax.Held && can_pan;
x_hov[i] = xax.Hovered || plot.Hovered;
x_held[i] = xax.Held || plot.Held;
}
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
ImPlotAxis& yax = plot.YAxis(i);
if (yax.Enabled) {
ImGui::KeepAliveID(yax.ID);
y_click[i] = ImGui::ButtonBehavior(yax.HoverRect,yax.ID,&yax.Hovered,&yax.Held,axis_button_flags);
if (y_click[i] && IO.MouseDoubleClicked[gp.InputMap.Fit])
plot.FitThisFrame = yax.FitThisFrame = true;
yax.Held = yax.Held && can_pan;
y_hov[i] = yax.Hovered || plot.Hovered;
y_held[i] = yax.Held || plot.Held;
}
}
// cancel due to DND activity
if (GImGui->DragDropActive || (IO.KeyMods == gp.InputMap.OverrideMod && gp.InputMap.OverrideMod != 0))
return false;
// STATE -------------------------------------------------------------------
const bool axis_equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
const bool any_x_hov = plot.Hovered || AnyAxesHovered(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
const bool any_x_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
const bool any_y_hov = plot.Hovered || AnyAxesHovered(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
const bool any_y_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
const bool any_hov = any_x_hov || any_y_hov;
const bool any_held = any_x_held || any_y_held;
const ImVec2 select_drag = ImGui::GetMouseDragDelta(gp.InputMap.Select);
const ImVec2 pan_drag = ImGui::GetMouseDragDelta(gp.InputMap.Pan);
const float select_drag_sq = ImLengthSqr(select_drag);
const float pan_drag_sq = ImLengthSqr(pan_drag);
const bool selecting = plot.Selecting && select_drag_sq > MOUSE_CURSOR_DRAG_THRESHOLD;
const bool panning = any_held && pan_drag_sq > MOUSE_CURSOR_DRAG_THRESHOLD;
// CONTEXT MENU -----------------------------------------------------------
if (IO.MouseReleased[gp.InputMap.Menu] && !plot.ContextLocked)
gp.OpenContextThisFrame = true;
if (selecting || panning)
plot.ContextLocked = true;
else if (!(IO.MouseDown[gp.InputMap.Menu] || IO.MouseReleased[gp.InputMap.Menu]))
plot.ContextLocked = false;
// DRAG INPUT -------------------------------------------------------------
if (any_held && !plot.Selecting) {
int drag_direction = 0;
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (x_held[i] && !x_axis.IsInputLocked()) {
drag_direction |= (1 << 1);
bool increasing = x_axis.IsInverted() ? IO.MouseDelta.x > 0 : IO.MouseDelta.x < 0;
if (IO.MouseDelta.x != 0 && !x_axis.IsPanLocked(increasing)) {
const double plot_l = x_axis.PixelsToPlot(plot.PlotRect.Min.x - IO.MouseDelta.x);
const double plot_r = x_axis.PixelsToPlot(plot.PlotRect.Max.x - IO.MouseDelta.x);
x_axis.SetMin(x_axis.IsInverted() ? plot_r : plot_l);
x_axis.SetMax(x_axis.IsInverted() ? plot_l : plot_r);
if (axis_equal && x_axis.OrthoAxis != nullptr)
x_axis.OrthoAxis->SetAspect(x_axis.GetAspect());
changed = true;
}
}
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (y_held[i] && !y_axis.IsInputLocked()) {
drag_direction |= (1 << 2);
bool increasing = y_axis.IsInverted() ? IO.MouseDelta.y < 0 : IO.MouseDelta.y > 0;
if (IO.MouseDelta.y != 0 && !y_axis.IsPanLocked(increasing)) {
const double plot_t = y_axis.PixelsToPlot(plot.PlotRect.Min.y - IO.MouseDelta.y);
const double plot_b = y_axis.PixelsToPlot(plot.PlotRect.Max.y - IO.MouseDelta.y);
y_axis.SetMin(y_axis.IsInverted() ? plot_t : plot_b);
y_axis.SetMax(y_axis.IsInverted() ? plot_b : plot_t);
if (axis_equal && y_axis.OrthoAxis != nullptr)
y_axis.OrthoAxis->SetAspect(y_axis.GetAspect());
changed = true;
}
}
}
if (IO.MouseDragMaxDistanceSqr[gp.InputMap.Pan] > MOUSE_CURSOR_DRAG_THRESHOLD) {
switch (drag_direction) {
case 0 : ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); break;
case (1 << 1) : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); break;
case (1 << 2) : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); break;
default : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); break;
}
}
}
// SCROLL INPUT -----------------------------------------------------------
if (any_hov && IO.MouseWheel != 0 && ImHasFlag(IO.KeyMods, gp.InputMap.ZoomMod)) {
float zoom_rate = gp.InputMap.ZoomRate;
if (IO.MouseWheel > 0)
zoom_rate = (-zoom_rate) / (1.0f + (2.0f * zoom_rate));
ImVec2 rect_size = plot.PlotRect.GetSize();
float tx = ImRemap(IO.MousePos.x, plot.PlotRect.Min.x, plot.PlotRect.Max.x, 0.0f, 1.0f);
float ty = ImRemap(IO.MousePos.y, plot.PlotRect.Min.y, plot.PlotRect.Max.y, 0.0f, 1.0f);
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& x_axis = plot.XAxis(i);
const bool equal_zoom = axis_equal && x_axis.OrthoAxis != nullptr;
const bool equal_locked = (equal_zoom != false) && x_axis.OrthoAxis->IsInputLocked();
if (x_hov[i] && !x_axis.IsInputLocked() && !equal_locked) {
float correction = (plot.Hovered && equal_zoom) ? 0.5f : 1.0f;
const double plot_l = x_axis.PixelsToPlot(plot.PlotRect.Min.x - rect_size.x * tx * zoom_rate * correction);
const double plot_r = x_axis.PixelsToPlot(plot.PlotRect.Max.x + rect_size.x * (1 - tx) * zoom_rate * correction);
x_axis.SetMin(x_axis.IsInverted() ? plot_r : plot_l);
x_axis.SetMax(x_axis.IsInverted() ? plot_l : plot_r);
if (axis_equal && x_axis.OrthoAxis != nullptr)
x_axis.OrthoAxis->SetAspect(x_axis.GetAspect());
changed = true;
}
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& y_axis = plot.YAxis(i);
const bool equal_zoom = axis_equal && y_axis.OrthoAxis != nullptr;
const bool equal_locked = equal_zoom && y_axis.OrthoAxis->IsInputLocked();
if (y_hov[i] && !y_axis.IsInputLocked() && !equal_locked) {
float correction = (plot.Hovered && equal_zoom) ? 0.5f : 1.0f;
const double plot_t = y_axis.PixelsToPlot(plot.PlotRect.Min.y - rect_size.y * ty * zoom_rate * correction);
const double plot_b = y_axis.PixelsToPlot(plot.PlotRect.Max.y + rect_size.y * (1 - ty) * zoom_rate * correction);
y_axis.SetMin(y_axis.IsInverted() ? plot_t : plot_b);
y_axis.SetMax(y_axis.IsInverted() ? plot_b : plot_t);
if (axis_equal && y_axis.OrthoAxis != nullptr)
y_axis.OrthoAxis->SetAspect(y_axis.GetAspect());
changed = true;
}
}
}
// BOX-SELECTION ----------------------------------------------------------
if (plot.Selecting) {
const ImVec2 d = plot.SelectStart - IO.MousePos;
const bool x_can_change = !ImHasFlag(IO.KeyMods,gp.InputMap.SelectHorzMod) && ImFabs(d.x) > 2;
const bool y_can_change = !ImHasFlag(IO.KeyMods,gp.InputMap.SelectVertMod) && ImFabs(d.y) > 2;
// confirm
if (IO.MouseReleased[gp.InputMap.Select]) {
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (!x_axis.IsInputLocked() && x_can_change) {
const double p1 = x_axis.PixelsToPlot(plot.SelectStart.x);
const double p2 = x_axis.PixelsToPlot(IO.MousePos.x);
x_axis.SetMin(ImMin(p1, p2));
x_axis.SetMax(ImMax(p1, p2));
changed = true;
}
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (!y_axis.IsInputLocked() && y_can_change) {
const double p1 = y_axis.PixelsToPlot(plot.SelectStart.y);
const double p2 = y_axis.PixelsToPlot(IO.MousePos.y);
y_axis.SetMin(ImMin(p1, p2));
y_axis.SetMax(ImMax(p1, p2));
changed = true;
}
}
if (x_can_change || y_can_change || (ImHasFlag(IO.KeyMods,gp.InputMap.SelectHorzMod) && ImHasFlag(IO.KeyMods,gp.InputMap.SelectVertMod)))
gp.OpenContextThisFrame = false;
plot.Selected = plot.Selecting = false;
}
// cancel
else if (IO.MouseReleased[gp.InputMap.SelectCancel]) {
plot.Selected = plot.Selecting = false;
gp.OpenContextThisFrame = false;
}
else if (ImLengthSqr(d) > BOX_SELECT_DRAG_THRESHOLD) {
// bad selection
if (plot.IsInputLocked()) {
ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
gp.OpenContextThisFrame = false;
plot.Selected = false;
}
else {
// TODO: Handle only min or max locked cases
const bool full_width = ImHasFlag(IO.KeyMods, gp.InputMap.SelectHorzMod) || AllAxesInputLocked(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
const bool full_height = ImHasFlag(IO.KeyMods, gp.InputMap.SelectVertMod) || AllAxesInputLocked(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
plot.SelectRect.Min.x = full_width ? plot.PlotRect.Min.x : ImMin(plot.SelectStart.x, IO.MousePos.x);
plot.SelectRect.Max.x = full_width ? plot.PlotRect.Max.x : ImMax(plot.SelectStart.x, IO.MousePos.x);
plot.SelectRect.Min.y = full_height ? plot.PlotRect.Min.y : ImMin(plot.SelectStart.y, IO.MousePos.y);
plot.SelectRect.Max.y = full_height ? plot.PlotRect.Max.y : ImMax(plot.SelectStart.y, IO.MousePos.y);
plot.SelectRect.Min -= plot.PlotRect.Min;
plot.SelectRect.Max -= plot.PlotRect.Min;
plot.Selected = true;
}
}
else {
plot.Selected = false;
}
}
return changed;
}
//-----------------------------------------------------------------------------
// Next Plot Data (Legacy)
//-----------------------------------------------------------------------------
void ApplyNextPlotData(ImAxis idx) {
ImPlotContext& gp = *GImPlot;
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
if (!axis.Enabled)
return;
double* npd_lmin = gp.NextPlotData.LinkedMin[idx];
double* npd_lmax = gp.NextPlotData.LinkedMax[idx];
bool npd_rngh = gp.NextPlotData.HasRange[idx];
ImPlotCond npd_rngc = gp.NextPlotData.RangeCond[idx];
ImPlotRange npd_rngv = gp.NextPlotData.Range[idx];
axis.LinkedMin = npd_lmin;
axis.LinkedMax = npd_lmax;
axis.PullLinks();
if (npd_rngh) {
if (!plot.Initialized || npd_rngc == ImPlotCond_Always)
axis.SetRange(npd_rngv);
}
axis.HasRange = npd_rngh;
axis.RangeCond = npd_rngc;
}
//-----------------------------------------------------------------------------
// Setup
//-----------------------------------------------------------------------------
void SetupAxis(ImAxis idx, const char* label, ImPlotAxisFlags flags) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
// get plot and axis
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
// set ID
axis.ID = plot.ID + idx + 1;
// check and set flags
if (plot.JustCreated || flags != axis.PreviousFlags)
axis.Flags = flags;
axis.PreviousFlags = flags;
// enable axis
axis.Enabled = true;
// set label
plot.SetAxisLabel(axis,label);
// cache colors
UpdateAxisColors(axis);
}
void SetupAxisLimits(ImAxis idx, double min_lim, double max_lim, ImPlotCond cond) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!"); // get plot and axis
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
if (!plot.Initialized || cond == ImPlotCond_Always)
axis.SetRange(min_lim, max_lim);
axis.HasRange = true;
axis.RangeCond = cond;
}
void SetupAxisFormat(ImAxis idx, const char* fmt) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.HasFormatSpec = fmt != nullptr;
if (fmt != nullptr)
ImStrncpy(axis.FormatSpec,fmt,sizeof(axis.FormatSpec));
}
void SetupAxisLinks(ImAxis idx, double* min_lnk, double* max_lnk) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.LinkedMin = min_lnk;
axis.LinkedMax = max_lnk;
axis.PullLinks();
}
void SetupAxisFormat(ImAxis idx, ImPlotFormatter formatter, void* data) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.Formatter = formatter;
axis.FormatterData = data;
}
void SetupAxisTicks(ImAxis idx, const double* values, int n_ticks, const char* const labels[], bool show_default) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.ShowDefaultTicks = show_default;
AddTicksCustom(values,
labels,
n_ticks,
axis.Ticker,
axis.Formatter ? axis.Formatter : Formatter_Default,
(axis.Formatter && axis.FormatterData) ? axis.FormatterData : axis.HasFormatSpec ? axis.FormatSpec : (void*)IMPLOT_LABEL_FORMAT);
}
void SetupAxisTicks(ImAxis idx, double v_min, double v_max, int n_ticks, const char* const labels[], bool show_default) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
n_ticks = n_ticks < 2 ? 2 : n_ticks;
FillRange(gp.TempDouble1, n_ticks, v_min, v_max);
SetupAxisTicks(idx, gp.TempDouble1.Data, n_ticks, labels, show_default);
}
void SetupAxisScale(ImAxis idx, ImPlotScale scale) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.Scale = scale;
switch (scale)
{
case ImPlotScale_Time:
axis.TransformForward = nullptr;
axis.TransformInverse = nullptr;
axis.TransformData = nullptr;
axis.Locator = Locator_Time;
axis.ConstraintRange = ImPlotRange(IMPLOT_MIN_TIME, IMPLOT_MAX_TIME);
axis.Ticker.Levels = 2;
break;
case ImPlotScale_Log10:
axis.TransformForward = TransformForward_Log10;
axis.TransformInverse = TransformInverse_Log10;
axis.TransformData = nullptr;
axis.Locator = Locator_Log10;
axis.ConstraintRange = ImPlotRange(DBL_MIN, INFINITY);
break;
case ImPlotScale_SymLog:
axis.TransformForward = TransformForward_SymLog;
axis.TransformInverse = TransformInverse_SymLog;
axis.TransformData = nullptr;
axis.Locator = Locator_SymLog;
axis.ConstraintRange = ImPlotRange(-INFINITY, INFINITY);
break;
default:
axis.TransformForward = nullptr;
axis.TransformInverse = nullptr;
axis.TransformData = nullptr;
axis.Locator = nullptr;
axis.ConstraintRange = ImPlotRange(-INFINITY, INFINITY);
break;
}
}
void SetupAxisScale(ImAxis idx, ImPlotTransform fwd, ImPlotTransform inv, void* data) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.Scale = IMPLOT_AUTO;
axis.TransformForward = fwd;
axis.TransformInverse = inv;
axis.TransformData = data;
}
void SetupAxisLimitsConstraints(ImAxis idx, double v_min, double v_max) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.ConstraintRange.Min = v_min;
axis.ConstraintRange.Max = v_max;
}
void SetupAxisZoomConstraints(ImAxis idx, double z_min, double z_max) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& axis = plot.Axes[idx];
IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
axis.ConstraintZoom.Min = z_min;
axis.ConstraintZoom.Max = z_max;
}
void SetupAxes(const char* x_label, const char* y_label, ImPlotAxisFlags x_flags, ImPlotAxisFlags y_flags) {
SetupAxis(ImAxis_X1, x_label, x_flags);
SetupAxis(ImAxis_Y1, y_label, y_flags);
}
void SetupAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond) {
SetupAxisLimits(ImAxis_X1, x_min, x_max, cond);
SetupAxisLimits(ImAxis_Y1, y_min, y_max, cond);
}
void SetupLegend(ImPlotLocation location, ImPlotLegendFlags flags) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
IM_ASSERT_USER_ERROR(gp.CurrentItems != nullptr,
"SetupLegend() needs to be called within an itemized context!");
ImPlotLegend& legend = gp.CurrentItems->Legend;
// check and set location
if (location != legend.PreviousLocation)
legend.Location = location;
legend.PreviousLocation = location;
// check and set flags
if (flags != legend.PreviousFlags)
legend.Flags = flags;
legend.PreviousFlags = flags;
}
void SetupMouseText(ImPlotLocation location, ImPlotMouseTextFlags flags) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr && !gp.CurrentPlot->SetupLocked,
"Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
gp.CurrentPlot->MouseTextLocation = location;
gp.CurrentPlot->MouseTextFlags = flags;
}
//-----------------------------------------------------------------------------
// SetNext
//-----------------------------------------------------------------------------
void SetNextAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot == nullptr, "SetNextAxisLimits() needs to be called before BeginPlot()!");
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
gp.NextPlotData.HasRange[axis] = true;
gp.NextPlotData.RangeCond[axis] = cond;
gp.NextPlotData.Range[axis].Min = v_min;
gp.NextPlotData.Range[axis].Max = v_max;
}
void SetNextAxisLinks(ImAxis axis, double* link_min, double* link_max) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot == nullptr, "SetNextAxisLinks() needs to be called before BeginPlot()!");
gp.NextPlotData.LinkedMin[axis] = link_min;
gp.NextPlotData.LinkedMax[axis] = link_max;
}
void SetNextAxisToFit(ImAxis axis) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot == nullptr, "SetNextAxisToFit() needs to be called before BeginPlot()!");
gp.NextPlotData.Fit[axis] = true;
}
void SetNextAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond) {
SetNextAxisLimits(ImAxis_X1, x_min, x_max, cond);
SetNextAxisLimits(ImAxis_Y1, y_min, y_max, cond);
}
void SetNextAxesToFit() {
for (int i = 0; i < ImAxis_COUNT; ++i)
SetNextAxisToFit(i);
}
//-----------------------------------------------------------------------------
// BeginPlot
//-----------------------------------------------------------------------------
bool BeginPlot(const char* title_id, const ImVec2& size, ImPlotFlags flags) {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot == nullptr, "Mismatched BeginPlot()/EndPlot()!");
// FRONT MATTER -----------------------------------------------------------
if (gp.CurrentSubplot != nullptr)
ImGui::PushID(gp.CurrentSubplot->CurrentIdx);
// get globals
ImGuiContext &G = *GImGui;
ImGuiWindow* Window = G.CurrentWindow;
// skip if needed
if (Window->SkipItems && !gp.CurrentSubplot) {
ResetCtxForNextPlot(GImPlot);
return false;
}
// ID and age (TODO: keep track of plot age in frames)
const ImGuiID ID = Window->GetID(title_id);
const bool just_created = gp.Plots.GetByKey(ID) == nullptr;
gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID);
ImPlotPlot &plot = *gp.CurrentPlot;
plot.ID = ID;
plot.Items.ID = ID - 1;
plot.JustCreated = just_created;
plot.SetupLocked = false;
// check flags
if (plot.JustCreated)
plot.Flags = flags;
else if (flags != plot.PreviousFlags)
plot.Flags = flags;
plot.PreviousFlags = flags;
// setup default axes
if (plot.JustCreated) {
SetupAxis(ImAxis_X1);
SetupAxis(ImAxis_Y1);
}
// reset axes
for (int i = 0; i < ImAxis_COUNT; ++i) {
plot.Axes[i].Reset();
UpdateAxisColors(plot.Axes[i]);
}
// ensure first axes enabled
plot.Axes[ImAxis_X1].Enabled = true;
plot.Axes[ImAxis_Y1].Enabled = true;
// set initial axes
plot.CurrentX = ImAxis_X1;
plot.CurrentY = ImAxis_Y1;
// process next plot data (legacy)
for (int i = 0; i < ImAxis_COUNT; ++i)
ApplyNextPlotData(i);
// capture scroll with a child region
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoChild)) {
ImVec2 child_size;
if (gp.CurrentSubplot != nullptr)
child_size = gp.CurrentSubplot->CellSize;
else
child_size = ImVec2(size.x == 0 ? gp.Style.PlotDefaultSize.x : size.x, size.y == 0 ? gp.Style.PlotDefaultSize.y : size.y);
ImGui::BeginChild(title_id, child_size, false, ImGuiWindowFlags_NoScrollbar);
Window = ImGui::GetCurrentWindow();
Window->ScrollMax.y = 1.0f;
gp.ChildWindowMade = true;
}
else {
gp.ChildWindowMade = false;
}
// clear text buffers
plot.ClearTextBuffer();
plot.SetTitle(title_id);
// set frame size
ImVec2 frame_size;
if (gp.CurrentSubplot != nullptr)
frame_size = gp.CurrentSubplot->CellSize;
else
frame_size = ImGui::CalcItemSize(size, gp.Style.PlotDefaultSize.x, gp.Style.PlotDefaultSize.y);
if (frame_size.x < gp.Style.PlotMinSize.x && (size.x < 0.0f || gp.CurrentSubplot != nullptr))
frame_size.x = gp.Style.PlotMinSize.x;
if (frame_size.y < gp.Style.PlotMinSize.y && (size.y < 0.0f || gp.CurrentSubplot != nullptr))
frame_size.y = gp.Style.PlotMinSize.y;
plot.FrameRect = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
ImGui::ItemSize(plot.FrameRect);
if (!ImGui::ItemAdd(plot.FrameRect, plot.ID, &plot.FrameRect) && !gp.CurrentSubplot) {
ResetCtxForNextPlot(GImPlot);
return false;
}
// setup items (or dont)
if (gp.CurrentItems == nullptr)
gp.CurrentItems = &plot.Items;
return true;
}
//-----------------------------------------------------------------------------
// SetupFinish
//-----------------------------------------------------------------------------
void SetupFinish() {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "SetupFinish needs to be called after BeginPlot!");
ImGuiContext& G = *GImGui;
ImDrawList& DrawList = *G.CurrentWindow->DrawList;
const ImGuiStyle& Style = G.Style;
ImPlotPlot &plot = *gp.CurrentPlot;
// lock setup
plot.SetupLocked = true;
// finalize axes and set default formatter/locator
for (int i = 0; i < ImAxis_COUNT; ++i) {
ImPlotAxis& axis = plot.Axes[i];
if (axis.Enabled) {
axis.Constrain();
if (!plot.Initialized && axis.CanInitFit())
plot.FitThisFrame = axis.FitThisFrame = true;
}
if (axis.Formatter == nullptr) {
axis.Formatter = Formatter_Default;
if (axis.HasFormatSpec)
axis.FormatterData = axis.FormatSpec;
else
axis.FormatterData = (void*)IMPLOT_LABEL_FORMAT;
}
if (axis.Locator == nullptr) {
axis.Locator = Locator_Default;
}
}
// setup nullptr orthogonal axes
const bool axis_equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
for (int ix = ImAxis_X1, iy = ImAxis_Y1; ix < ImAxis_Y1 || iy < ImAxis_COUNT; ++ix, ++iy) {
ImPlotAxis& x_axis = plot.Axes[ix];
ImPlotAxis& y_axis = plot.Axes[iy];
if (x_axis.Enabled && y_axis.Enabled) {
if (x_axis.OrthoAxis == nullptr)
x_axis.OrthoAxis = &y_axis;
if (y_axis.OrthoAxis == nullptr)
y_axis.OrthoAxis = &x_axis;
}
else if (x_axis.Enabled)
{
if (x_axis.OrthoAxis == nullptr && !axis_equal)
x_axis.OrthoAxis = &plot.Axes[ImAxis_Y1];
}
else if (y_axis.Enabled) {
if (y_axis.OrthoAxis == nullptr && !axis_equal)
y_axis.OrthoAxis = &plot.Axes[ImAxis_X1];
}
}
// canvas/axes bb
plot.CanvasRect = ImRect(plot.FrameRect.Min + gp.Style.PlotPadding, plot.FrameRect.Max - gp.Style.PlotPadding);
plot.AxesRect = plot.FrameRect;
// outside legend adjustments
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.Items.GetLegendCount() > 0 && ImHasFlag(plot.Items.Legend.Flags, ImPlotLegendFlags_Outside)) {
ImPlotLegend& legend = plot.Items.Legend;
const bool horz = ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal);
const ImVec2 legend_size = CalcLegendSize(plot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !horz);
const bool west = ImHasFlag(legend.Location, ImPlotLocation_West) && !ImHasFlag(legend.Location, ImPlotLocation_East);
const bool east = ImHasFlag(legend.Location, ImPlotLocation_East) && !ImHasFlag(legend.Location, ImPlotLocation_West);
const bool north = ImHasFlag(legend.Location, ImPlotLocation_North) && !ImHasFlag(legend.Location, ImPlotLocation_South);
const bool south = ImHasFlag(legend.Location, ImPlotLocation_South) && !ImHasFlag(legend.Location, ImPlotLocation_North);
if ((west && !horz) || (west && horz && !north && !south)) {
plot.CanvasRect.Min.x += (legend_size.x + gp.Style.LegendPadding.x);
plot.AxesRect.Min.x += (legend_size.x + gp.Style.PlotPadding.x);
}
if ((east && !horz) || (east && horz && !north && !south)) {
plot.CanvasRect.Max.x -= (legend_size.x + gp.Style.LegendPadding.x);
plot.AxesRect.Max.x -= (legend_size.x + gp.Style.PlotPadding.x);
}
if ((north && horz) || (north && !horz && !west && !east)) {
plot.CanvasRect.Min.y += (legend_size.y + gp.Style.LegendPadding.y);
plot.AxesRect.Min.y += (legend_size.y + gp.Style.PlotPadding.y);
}
if ((south && horz) || (south && !horz && !west && !east)) {
plot.CanvasRect.Max.y -= (legend_size.y + gp.Style.LegendPadding.y);
plot.AxesRect.Max.y -= (legend_size.y + gp.Style.PlotPadding.y);
}
}
// plot bb
float pad_top = 0, pad_bot = 0, pad_left = 0, pad_right = 0;
// (0) calc top padding form title
ImVec2 title_size(0.0f, 0.0f);
if (plot.HasTitle())
title_size = ImGui::CalcTextSize(plot.GetTitle(), nullptr, true);
if (title_size.x > 0) {
pad_top += title_size.y + gp.Style.LabelPadding.y;
plot.AxesRect.Min.y += gp.Style.PlotPadding.y + pad_top;
}
// (1) calc addition top padding and bot padding
PadAndDatumAxesX(plot,pad_top,pad_bot,gp.CurrentAlignmentH);
const float plot_height = plot.CanvasRect.GetHeight() - pad_top - pad_bot;
// (2) get y tick labels (needed for left/right pad)
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& axis = plot.YAxis(i);
if (axis.WillRender() && axis.ShowDefaultTicks) {
axis.Locator(axis.Ticker, axis.Range, plot_height, true, axis.Formatter, axis.FormatterData);
}
}
// (3) calc left/right pad
PadAndDatumAxesY(plot,pad_left,pad_right,gp.CurrentAlignmentV);
const float plot_width = plot.CanvasRect.GetWidth() - pad_left - pad_right;
// (4) get x ticks
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& axis = plot.XAxis(i);
if (axis.WillRender() && axis.ShowDefaultTicks) {
axis.Locator(axis.Ticker, axis.Range, plot_width, false, axis.Formatter, axis.FormatterData);
}
}
// (5) calc plot bb
plot.PlotRect = ImRect(plot.CanvasRect.Min + ImVec2(pad_left, pad_top), plot.CanvasRect.Max - ImVec2(pad_right, pad_bot));
// HOVER------------------------------------------------------------
// axes hover rect, pixel ranges
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
ImPlotAxis& xax = plot.XAxis(i);
xax.HoverRect = ImRect(ImVec2(plot.PlotRect.Min.x, ImMin(xax.Datum1,xax.Datum2)),
ImVec2(plot.PlotRect.Max.x, ImMax(xax.Datum1,xax.Datum2)));
xax.PixelMin = xax.IsInverted() ? plot.PlotRect.Max.x : plot.PlotRect.Min.x;
xax.PixelMax = xax.IsInverted() ? plot.PlotRect.Min.x : plot.PlotRect.Max.x;
xax.UpdateTransformCache();
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
ImPlotAxis& yax = plot.YAxis(i);
yax.HoverRect = ImRect(ImVec2(ImMin(yax.Datum1,yax.Datum2),plot.PlotRect.Min.y),
ImVec2(ImMax(yax.Datum1,yax.Datum2),plot.PlotRect.Max.y));
yax.PixelMin = yax.IsInverted() ? plot.PlotRect.Min.y : plot.PlotRect.Max.y;
yax.PixelMax = yax.IsInverted() ? plot.PlotRect.Max.y : plot.PlotRect.Min.y;
yax.UpdateTransformCache();
}
// Equal axis constraint. Must happen after we set Pixels
// constrain equal axes for primary x and y if not approximately equal
// constrains x to y since x pixel size depends on y labels width, and causes feedback loops in opposite case
if (axis_equal) {
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (x_axis.OrthoAxis == nullptr)
continue;
double xar = x_axis.GetAspect();
double yar = x_axis.OrthoAxis->GetAspect();
// edge case: user has set x range this frame, so fit y to x so that we honor their request for x range
// NB: because of feedback across several frames, the user's x request may not be perfectly honored
if (x_axis.HasRange)
x_axis.OrthoAxis->SetAspect(xar);
else if (!ImAlmostEqual(xar,yar) && !x_axis.OrthoAxis->IsInputLocked())
x_axis.SetAspect(yar);
}
}
// INPUT ------------------------------------------------------------------
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoInputs))
UpdateInput(plot);
// fit from FitNextPlotAxes or auto fit
for (int i = 0; i < ImAxis_COUNT; ++i) {
if (gp.NextPlotData.Fit[i] || plot.Axes[i].IsAutoFitting()) {
plot.FitThisFrame = true;
plot.Axes[i].FitThisFrame = true;
}
}
// RENDER -----------------------------------------------------------------
const float txt_height = ImGui::GetTextLineHeight();
// render frame
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoFrame))
ImGui::RenderFrame(plot.FrameRect.Min, plot.FrameRect.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, Style.FrameRounding);
// grid bg
DrawList.AddRectFilled(plot.PlotRect.Min, plot.PlotRect.Max, GetStyleColorU32(ImPlotCol_PlotBg));
// transform ticks
for (int i = 0; i < ImAxis_COUNT; i++) {
ImPlotAxis& axis = plot.Axes[i];
if (axis.WillRender()) {
for (int t = 0; t < axis.Ticker.TickCount(); t++) {
ImPlotTick& tk = axis.Ticker.Ticks[t];
tk.PixelPos = IM_ROUND(axis.PlotToPixels(tk.PlotPos));
}
}
}
// render grid (background)
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (x_axis.Enabled && x_axis.HasGridLines() && !x_axis.IsForeground())
RenderGridLinesX(DrawList, x_axis.Ticker, plot.PlotRect, x_axis.ColorMaj, x_axis.ColorMin, gp.Style.MajorGridSize.x, gp.Style.MinorGridSize.x);
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (y_axis.Enabled && y_axis.HasGridLines() && !y_axis.IsForeground())
RenderGridLinesY(DrawList, y_axis.Ticker, plot.PlotRect, y_axis.ColorMaj, y_axis.ColorMin, gp.Style.MajorGridSize.y, gp.Style.MinorGridSize.y);
}
// render x axis button, label, tick labels
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& ax = plot.XAxis(i);
if (!ax.Enabled)
continue;
if ((ax.Hovered || ax.Held) && !plot.Held && !ImHasFlag(ax.Flags, ImPlotAxisFlags_NoHighlight))
DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.Held ? ax.ColorAct : ax.ColorHov);
else if (ax.ColorHiLi != IM_COL32_BLACK_TRANS) {
DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorHiLi);
ax.ColorHiLi = IM_COL32_BLACK_TRANS;
}
else if (ax.ColorBg != IM_COL32_BLACK_TRANS) {
DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorBg);
}
const ImPlotTicker& tkr = ax.Ticker;
const bool opp = ax.IsOpposite();
if (ax.HasLabel()) {
const char* label = plot.GetAxisLabel(ax);
const ImVec2 label_size = ImGui::CalcTextSize(label);
const float label_offset = (ax.HasTickLabels() ? tkr.MaxSize.y + gp.Style.LabelPadding.y : 0.0f)
+ (tkr.Levels - 1) * (txt_height + gp.Style.LabelPadding.y)
+ gp.Style.LabelPadding.y;
const ImVec2 label_pos(plot.PlotRect.GetCenter().x - label_size.x * 0.5f,
opp ? ax.Datum1 - label_offset - label_size.y : ax.Datum1 + label_offset);
DrawList.AddText(label_pos, ax.ColorTxt, label);
}
if (ax.HasTickLabels()) {
for (int j = 0; j < tkr.TickCount(); ++j) {
const ImPlotTick& tk = tkr.Ticks[j];
const float datum = ax.Datum1 + (opp ? (-gp.Style.LabelPadding.y -txt_height -tk.Level * (txt_height + gp.Style.LabelPadding.y))
: gp.Style.LabelPadding.y + tk.Level * (txt_height + gp.Style.LabelPadding.y));
if (tk.ShowLabel && tk.PixelPos >= plot.PlotRect.Min.x - 1 && tk.PixelPos <= plot.PlotRect.Max.x + 1) {
ImVec2 start(tk.PixelPos - 0.5f * tk.LabelSize.x, datum);
DrawList.AddText(start, ax.ColorTxt, tkr.GetText(j));
}
}
}
}
// render y axis button, label, tick labels
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& ax = plot.YAxis(i);
if (!ax.Enabled)
continue;
if ((ax.Hovered || ax.Held) && !plot.Held && !ImHasFlag(ax.Flags, ImPlotAxisFlags_NoHighlight))
DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.Held ? ax.ColorAct : ax.ColorHov);
else if (ax.ColorHiLi != IM_COL32_BLACK_TRANS) {
DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorHiLi);
ax.ColorHiLi = IM_COL32_BLACK_TRANS;
}
else if (ax.ColorBg != IM_COL32_BLACK_TRANS) {
DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorBg);
}
const ImPlotTicker& tkr = ax.Ticker;
const bool opp = ax.IsOpposite();
if (ax.HasLabel()) {
const char* label = plot.GetAxisLabel(ax);
const ImVec2 label_size = CalcTextSizeVertical(label);
const float label_offset = (ax.HasTickLabels() ? tkr.MaxSize.x + gp.Style.LabelPadding.x : 0.0f)
+ gp.Style.LabelPadding.x;
const ImVec2 label_pos(opp ? ax.Datum1 + label_offset : ax.Datum1 - label_offset - label_size.x,
plot.PlotRect.GetCenter().y + label_size.y * 0.5f);
AddTextVertical(&DrawList, label_pos, ax.ColorTxt, label);
}
if (ax.HasTickLabels()) {
for (int j = 0; j < tkr.TickCount(); ++j) {
const ImPlotTick& tk = tkr.Ticks[j];
const float datum = ax.Datum1 + (opp ? gp.Style.LabelPadding.x : (-gp.Style.LabelPadding.x - tk.LabelSize.x));
if (tk.ShowLabel && tk.PixelPos >= plot.PlotRect.Min.y - 1 && tk.PixelPos <= plot.PlotRect.Max.y + 1) {
ImVec2 start(datum, tk.PixelPos - 0.5f * tk.LabelSize.y);
DrawList.AddText(start, ax.ColorTxt, tkr.GetText(j));
}
}
}
}
// clear legend (TODO: put elsewhere)
plot.Items.Legend.Reset();
// push ID to set item hashes (NB: !!!THIS PROBABLY NEEDS TO BE IN BEGIN PLOT!!!!)
ImGui::PushOverrideID(gp.CurrentItems->ID);
}
//-----------------------------------------------------------------------------
// EndPlot()
//-----------------------------------------------------------------------------
void EndPlot() {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "Mismatched BeginPlot()/EndPlot()!");
SetupLock();
ImGuiContext &G = *GImGui;
ImPlotPlot &plot = *gp.CurrentPlot;
ImGuiWindow * Window = G.CurrentWindow;
ImDrawList & DrawList = *Window->DrawList;
const ImGuiIO & IO = ImGui::GetIO();
// FINAL RENDER -----------------------------------------------------------
const bool render_border = gp.Style.PlotBorderSize > 0 && gp.Style.Colors[ImPlotCol_PlotBorder].w > 0;
const bool any_x_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
const bool any_y_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
ImGui::PushClipRect(plot.FrameRect.Min, plot.FrameRect.Max, true);
// render grid (foreground)
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (x_axis.Enabled && x_axis.HasGridLines() && x_axis.IsForeground())
RenderGridLinesX(DrawList, x_axis.Ticker, plot.PlotRect, x_axis.ColorMaj, x_axis.ColorMin, gp.Style.MajorGridSize.x, gp.Style.MinorGridSize.x);
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (y_axis.Enabled && y_axis.HasGridLines() && y_axis.IsForeground())
RenderGridLinesY(DrawList, y_axis.Ticker, plot.PlotRect, y_axis.ColorMaj, y_axis.ColorMin, gp.Style.MajorGridSize.y, gp.Style.MinorGridSize.y);
}
// render title
if (plot.HasTitle()) {
ImU32 col = GetStyleColorU32(ImPlotCol_TitleText);
AddTextCentered(&DrawList,ImVec2(plot.PlotRect.GetCenter().x, plot.CanvasRect.Min.y),col,plot.GetTitle());
}
// render x ticks
int count_B = 0, count_T = 0;
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
const ImPlotAxis& ax = plot.XAxis(i);
if (!ax.Enabled)
continue;
const ImPlotTicker& tkr = ax.Ticker;
const bool opp = ax.IsOpposite();
const bool aux = ((opp && count_T > 0)||(!opp && count_B > 0));
if (ax.HasTickMarks()) {
const float direction = opp ? 1.0f : -1.0f;
for (int j = 0; j < tkr.TickCount(); ++j) {
const ImPlotTick& tk = tkr.Ticks[j];
if (tk.Level != 0 || tk.PixelPos < plot.PlotRect.Min.x || tk.PixelPos > plot.PlotRect.Max.x)
continue;
const ImVec2 start(tk.PixelPos, ax.Datum1);
const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.x : gp.Style.MinorTickLen.x;
const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.x : gp.Style.MinorTickSize.x;
DrawList.AddLine(start, start + ImVec2(0,direction*len), ax.ColorTick, thk);
}
if (aux || !render_border)
DrawList.AddLine(ImVec2(plot.PlotRect.Min.x,ax.Datum1), ImVec2(plot.PlotRect.Max.x,ax.Datum1), ax.ColorTick, gp.Style.MinorTickSize.x);
}
count_B += !opp;
count_T += opp;
}
// render y ticks
int count_L = 0, count_R = 0;
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
const ImPlotAxis& ax = plot.YAxis(i);
if (!ax.Enabled)
continue;
const ImPlotTicker& tkr = ax.Ticker;
const bool opp = ax.IsOpposite();
const bool aux = ((opp && count_R > 0)||(!opp && count_L > 0));
if (ax.HasTickMarks()) {
const float direction = opp ? -1.0f : 1.0f;
for (int j = 0; j < tkr.TickCount(); ++j) {
const ImPlotTick& tk = tkr.Ticks[j];
if (tk.Level != 0 || tk.PixelPos < plot.PlotRect.Min.y || tk.PixelPos > plot.PlotRect.Max.y)
continue;
const ImVec2 start(ax.Datum1, tk.PixelPos);
const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y;
const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.y : gp.Style.MinorTickSize.y;
DrawList.AddLine(start, start + ImVec2(direction*len,0), ax.ColorTick, thk);
}
if (aux || !render_border)
DrawList.AddLine(ImVec2(ax.Datum1, plot.PlotRect.Min.y), ImVec2(ax.Datum1, plot.PlotRect.Max.y), ax.ColorTick, gp.Style.MinorTickSize.y);
}
count_L += !opp;
count_R += opp;
}
ImGui::PopClipRect();
// render annotations
PushPlotClipRect();
for (int i = 0; i < gp.Annotations.Size; ++i) {
const char* txt = gp.Annotations.GetText(i);
ImPlotAnnotation& an = gp.Annotations.Annotations[i];
const ImVec2 txt_size = ImGui::CalcTextSize(txt);
const ImVec2 size = txt_size + gp.Style.AnnotationPadding * 2;
ImVec2 pos = an.Pos;
if (an.Offset.x == 0)
pos.x -= size.x / 2;
else if (an.Offset.x > 0)
pos.x += an.Offset.x;
else
pos.x -= size.x - an.Offset.x;
if (an.Offset.y == 0)
pos.y -= size.y / 2;
else if (an.Offset.y > 0)
pos.y += an.Offset.y;
else
pos.y -= size.y - an.Offset.y;
if (an.Clamp)
pos = ClampLabelPos(pos, size, plot.PlotRect.Min, plot.PlotRect.Max);
ImRect rect(pos,pos+size);
if (an.Offset.x != 0 || an.Offset.y != 0) {
ImVec2 corners[4] = {rect.GetTL(), rect.GetTR(), rect.GetBR(), rect.GetBL()};
int min_corner = 0;
float min_len = FLT_MAX;
for (int c = 0; c < 4; ++c) {
float len = ImLengthSqr(an.Pos - corners[c]);
if (len < min_len) {
min_corner = c;
min_len = len;
}
}
DrawList.AddLine(an.Pos, corners[min_corner], an.ColorBg);
}
DrawList.AddRectFilled(rect.Min, rect.Max, an.ColorBg);
DrawList.AddText(pos + gp.Style.AnnotationPadding, an.ColorFg, txt);
}
// render selection
if (plot.Selected)
RenderSelectionRect(DrawList, plot.SelectRect.Min + plot.PlotRect.Min, plot.SelectRect.Max + plot.PlotRect.Min, GetStyleColorVec4(ImPlotCol_Selection));
// render crosshairs
if (ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs) && plot.Hovered && !(any_x_held || any_y_held) && !plot.Selecting && !plot.Items.Legend.Hovered) {
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
ImVec2 xy = IO.MousePos;
ImVec2 h1(plot.PlotRect.Min.x, xy.y);
ImVec2 h2(xy.x - 5, xy.y);
ImVec2 h3(xy.x + 5, xy.y);
ImVec2 h4(plot.PlotRect.Max.x, xy.y);
ImVec2 v1(xy.x, plot.PlotRect.Min.y);
ImVec2 v2(xy.x, xy.y - 5);
ImVec2 v3(xy.x, xy.y + 5);
ImVec2 v4(xy.x, plot.PlotRect.Max.y);
ImU32 col = GetStyleColorU32(ImPlotCol_Crosshairs);
DrawList.AddLine(h1, h2, col);
DrawList.AddLine(h3, h4, col);
DrawList.AddLine(v1, v2, col);
DrawList.AddLine(v3, v4, col);
}
// render mouse pos
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMouseText) && (plot.Hovered || ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_ShowAlways))) {
const bool no_aux = ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_NoAuxAxes);
const bool no_fmt = ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_NoFormat);
ImGuiTextBuffer& builder = gp.MousePosStringBuilder;
builder.Buf.shrink(0);
char buff[IMPLOT_LABEL_MAX_SIZE];
const int num_x = no_aux ? 1 : IMPLOT_NUM_X_AXES;
for (int i = 0; i < num_x; ++i) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (!x_axis.Enabled)
continue;
if (i > 0)
builder.append(", (");
double v = x_axis.PixelsToPlot(IO.MousePos.x);
if (no_fmt)
Formatter_Default(v,buff,IMPLOT_LABEL_MAX_SIZE,(void*)IMPLOT_LABEL_FORMAT);
else
LabelAxisValue(x_axis,v,buff,IMPLOT_LABEL_MAX_SIZE,true);
builder.append(buff);
if (i > 0)
builder.append(")");
}
builder.append(", ");
const int num_y = no_aux ? 1 : IMPLOT_NUM_Y_AXES;
for (int i = 0; i < num_y; ++i) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (!y_axis.Enabled)
continue;
if (i > 0)
builder.append(", (");
double v = y_axis.PixelsToPlot(IO.MousePos.y);
if (no_fmt)
Formatter_Default(v,buff,IMPLOT_LABEL_MAX_SIZE,(void*)IMPLOT_LABEL_FORMAT);
else
LabelAxisValue(y_axis,v,buff,IMPLOT_LABEL_MAX_SIZE,true);
builder.append(buff);
if (i > 0)
builder.append(")");
}
if (!builder.empty()) {
const ImVec2 size = ImGui::CalcTextSize(builder.c_str());
const ImVec2 pos = GetLocationPos(plot.PlotRect, size, plot.MouseTextLocation, gp.Style.MousePosPadding);
DrawList.AddText(pos, GetStyleColorU32(ImPlotCol_InlayText), builder.c_str());
}
}
PopPlotClipRect();
// axis side switch
if (!plot.Held) {
ImVec2 mouse_pos = ImGui::GetIO().MousePos;
ImRect trigger_rect = plot.PlotRect;
trigger_rect.Expand(-10);
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (ImHasFlag(x_axis.Flags, ImPlotAxisFlags_NoSideSwitch))
continue;
if (x_axis.Held && plot.PlotRect.Contains(mouse_pos)) {
const bool opp = ImHasFlag(x_axis.Flags, ImPlotAxisFlags_Opposite);
if (!opp) {
ImRect rect(plot.PlotRect.Min.x - 5, plot.PlotRect.Min.y - 5,
plot.PlotRect.Max.x + 5, plot.PlotRect.Min.y + 5);
if (mouse_pos.y < plot.PlotRect.Max.y - 10)
DrawList.AddRectFilled(rect.Min, rect.Max, x_axis.ColorHov);
if (rect.Contains(mouse_pos))
x_axis.Flags |= ImPlotAxisFlags_Opposite;
}
else {
ImRect rect(plot.PlotRect.Min.x - 5, plot.PlotRect.Max.y - 5,
plot.PlotRect.Max.x + 5, plot.PlotRect.Max.y + 5);
if (mouse_pos.y > plot.PlotRect.Min.y + 10)
DrawList.AddRectFilled(rect.Min, rect.Max, x_axis.ColorHov);
if (rect.Contains(mouse_pos))
x_axis.Flags &= ~ImPlotAxisFlags_Opposite;
}
}
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (ImHasFlag(y_axis.Flags, ImPlotAxisFlags_NoSideSwitch))
continue;
if (y_axis.Held && plot.PlotRect.Contains(mouse_pos)) {
const bool opp = ImHasFlag(y_axis.Flags, ImPlotAxisFlags_Opposite);
if (!opp) {
ImRect rect(plot.PlotRect.Max.x - 5, plot.PlotRect.Min.y - 5,
plot.PlotRect.Max.x + 5, plot.PlotRect.Max.y + 5);
if (mouse_pos.x > plot.PlotRect.Min.x + 10)
DrawList.AddRectFilled(rect.Min, rect.Max, y_axis.ColorHov);
if (rect.Contains(mouse_pos))
y_axis.Flags |= ImPlotAxisFlags_Opposite;
}
else {
ImRect rect(plot.PlotRect.Min.x - 5, plot.PlotRect.Min.y - 5,
plot.PlotRect.Min.x + 5, plot.PlotRect.Max.y + 5);
if (mouse_pos.x < plot.PlotRect.Max.x - 10)
DrawList.AddRectFilled(rect.Min, rect.Max, y_axis.ColorHov);
if (rect.Contains(mouse_pos))
y_axis.Flags &= ~ImPlotAxisFlags_Opposite;
}
}
}
}
// reset legend hovers
plot.Items.Legend.Hovered = false;
for (int i = 0; i < plot.Items.GetItemCount(); ++i)
plot.Items.GetItemByIndex(i)->LegendHovered = false;
// render legend
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.Items.GetLegendCount() > 0) {
ImPlotLegend& legend = plot.Items.Legend;
const bool legend_out = ImHasFlag(legend.Flags, ImPlotLegendFlags_Outside);
const bool legend_horz = ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal);
const ImVec2 legend_size = CalcLegendSize(plot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz);
const ImVec2 legend_pos = GetLocationPos(legend_out ? plot.FrameRect : plot.PlotRect,
legend_size,
legend.Location,
legend_out ? gp.Style.PlotPadding : gp.Style.LegendPadding);
legend.Rect = ImRect(legend_pos, legend_pos + legend_size);
// test hover
legend.Hovered = ImGui::IsWindowHovered() && legend.Rect.Contains(IO.MousePos);
if (legend_out)
ImGui::PushClipRect(plot.FrameRect.Min, plot.FrameRect.Max, true);
else
PushPlotClipRect();
ImU32 col_bg = GetStyleColorU32(ImPlotCol_LegendBg);
ImU32 col_bd = GetStyleColorU32(ImPlotCol_LegendBorder);
DrawList.AddRectFilled(legend.Rect.Min, legend.Rect.Max, col_bg);
DrawList.AddRect(legend.Rect.Min, legend.Rect.Max, col_bd);
bool legend_contextable = ShowLegendEntries(plot.Items, legend.Rect, legend.Hovered, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz, DrawList)
&& !ImHasFlag(legend.Flags, ImPlotLegendFlags_NoMenus);
// main ctx menu
if (gp.OpenContextThisFrame && legend_contextable && !ImHasFlag(plot.Flags, ImPlotFlags_NoMenus))
ImGui::OpenPopup("##LegendContext");
ImGui::PopClipRect();
if (ImGui::BeginPopup("##LegendContext")) {
ImGui::Text("Legend"); ImGui::Separator();
if (ShowLegendContextMenu(legend, !ImHasFlag(plot.Flags, ImPlotFlags_NoLegend)))
ImFlipFlag(plot.Flags, ImPlotFlags_NoLegend);
ImGui::EndPopup();
}
}
else {
plot.Items.Legend.Rect = ImRect();
}
// render border
if (render_border)
DrawList.AddRect(plot.PlotRect.Min, plot.PlotRect.Max, GetStyleColorU32(ImPlotCol_PlotBorder), 0, ImDrawFlags_RoundCornersAll, gp.Style.PlotBorderSize);
// render tags
for (int i = 0; i < gp.Tags.Size; ++i) {
ImPlotTag& tag = gp.Tags.Tags[i];
ImPlotAxis& axis = plot.Axes[tag.Axis];
if (!axis.Enabled || !axis.Range.Contains(tag.Value))
continue;
const char* txt = gp.Tags.GetText(i);
ImVec2 text_size = ImGui::CalcTextSize(txt);
ImVec2 size = text_size + gp.Style.AnnotationPadding * 2;
ImVec2 pos;
axis.Ticker.OverrideSizeLate(size);
float pix = IM_ROUND(axis.PlotToPixels(tag.Value));
if (axis.Vertical) {
if (axis.IsOpposite()) {
pos = ImVec2(axis.Datum1 + gp.Style.LabelPadding.x, pix - size.y * 0.5f);
DrawList.AddTriangleFilled(ImVec2(axis.Datum1,pix), pos, pos + ImVec2(0,size.y), tag.ColorBg);
}
else {
pos = ImVec2(axis.Datum1 - size.x - gp.Style.LabelPadding.x, pix - size.y * 0.5f);
DrawList.AddTriangleFilled(pos + ImVec2(size.x,0), ImVec2(axis.Datum1,pix), pos+size, tag.ColorBg);
}
}
else {
if (axis.IsOpposite()) {
pos = ImVec2(pix - size.x * 0.5f, axis.Datum1 - size.y - gp.Style.LabelPadding.y );
DrawList.AddTriangleFilled(pos + ImVec2(0,size.y), pos + size, ImVec2(pix,axis.Datum1), tag.ColorBg);
}
else {
pos = ImVec2(pix - size.x * 0.5f, axis.Datum1 + gp.Style.LabelPadding.y);
DrawList.AddTriangleFilled(pos, ImVec2(pix,axis.Datum1), pos + ImVec2(size.x, 0), tag.ColorBg);
}
}
DrawList.AddRectFilled(pos,pos+size,tag.ColorBg);
DrawList.AddText(pos+gp.Style.AnnotationPadding,tag.ColorFg,txt);
}
// FIT DATA --------------------------------------------------------------
const bool axis_equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
if (plot.FitThisFrame) {
for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
ImPlotAxis& x_axis = plot.XAxis(i);
if (x_axis.FitThisFrame) {
x_axis.ApplyFit(gp.Style.FitPadding.x);
if (axis_equal && x_axis.OrthoAxis != nullptr) {
double aspect = x_axis.GetAspect();
ImPlotAxis& y_axis = *x_axis.OrthoAxis;
if (y_axis.FitThisFrame) {
y_axis.ApplyFit(gp.Style.FitPadding.y);
y_axis.FitThisFrame = false;
aspect = ImMax(aspect, y_axis.GetAspect());
}
x_axis.SetAspect(aspect);
y_axis.SetAspect(aspect);
}
}
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
ImPlotAxis& y_axis = plot.YAxis(i);
if (y_axis.FitThisFrame) {
y_axis.ApplyFit(gp.Style.FitPadding.y);
if (axis_equal && y_axis.OrthoAxis != nullptr) {
double aspect = y_axis.GetAspect();
ImPlotAxis& x_axis = *y_axis.OrthoAxis;
if (x_axis.FitThisFrame) {
x_axis.ApplyFit(gp.Style.FitPadding.x);
x_axis.FitThisFrame = false;
aspect = ImMax(x_axis.GetAspect(), aspect);
}
x_axis.SetAspect(aspect);
y_axis.SetAspect(aspect);
}
}
}
plot.FitThisFrame = false;
}
// CONTEXT MENUS -----------------------------------------------------------
ImGui::PushOverrideID(plot.ID);
const bool can_ctx = gp.OpenContextThisFrame &&
!ImHasFlag(plot.Flags, ImPlotFlags_NoMenus) &&
!plot.Items.Legend.Hovered;
// main ctx menu
if (can_ctx && plot.Hovered)
ImGui::OpenPopup("##PlotContext");
if (ImGui::BeginPopup("##PlotContext")) {
ShowPlotContextMenu(plot);
ImGui::EndPopup();
}
// axes ctx menus
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
ImGui::PushID(i);
ImPlotAxis& x_axis = plot.XAxis(i);
if (can_ctx && x_axis.Hovered && x_axis.HasMenus())
ImGui::OpenPopup("##XContext");
if (ImGui::BeginPopup("##XContext")) {
ImGui::Text(x_axis.HasLabel() ? plot.GetAxisLabel(x_axis) : i == 0 ? "X-Axis" : "X-Axis %d", i + 1);
ImGui::Separator();
ShowAxisContextMenu(x_axis, axis_equal ? x_axis.OrthoAxis : nullptr, true);
ImGui::EndPopup();
}
ImGui::PopID();
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
ImGui::PushID(i);
ImPlotAxis& y_axis = plot.YAxis(i);
if (can_ctx && y_axis.Hovered && y_axis.HasMenus())
ImGui::OpenPopup("##YContext");
if (ImGui::BeginPopup("##YContext")) {
ImGui::Text(y_axis.HasLabel() ? plot.GetAxisLabel(y_axis) : i == 0 ? "Y-Axis" : "Y-Axis %d", i + 1);
ImGui::Separator();
ShowAxisContextMenu(y_axis, axis_equal ? y_axis.OrthoAxis : nullptr, false);
ImGui::EndPopup();
}
ImGui::PopID();
}
ImGui::PopID();
// LINKED AXES ------------------------------------------------------------
for (int i = 0; i < ImAxis_COUNT; ++i)
plot.Axes[i].PushLinks();
// CLEANUP ----------------------------------------------------------------
// remove items
if (gp.CurrentItems == &plot.Items)
gp.CurrentItems = nullptr;
// reset the plot items for the next frame
for (int i = 0; i < plot.Items.GetItemCount(); ++i) {
plot.Items.GetItemByIndex(i)->SeenThisFrame = false;
}
// mark the plot as initialized, i.e. having made it through one frame completely
plot.Initialized = true;
// Pop ImGui::PushID at the end of BeginPlot
ImGui::PopID();
// Reset context for next plot
ResetCtxForNextPlot(GImPlot);
// setup next subplot
if (gp.CurrentSubplot != nullptr) {
ImGui::PopID();
SubplotNextCell();
}
}
//-----------------------------------------------------------------------------
// BEGIN/END SUBPLOT
//-----------------------------------------------------------------------------
static const float SUBPLOT_BORDER_SIZE = 1.0f;
static const float SUBPLOT_SPLITTER_HALF_THICKNESS = 4.0f;
static const float SUBPLOT_SPLITTER_FEEDBACK_TIMER = 0.06f;
void SubplotSetCell(int row, int col) {
ImPlotContext& gp = *GImPlot;
ImPlotSubplot& subplot = *gp.CurrentSubplot;
if (row >= subplot.Rows || col >= subplot.Cols)
return;
float xoff = 0;
float yoff = 0;
for (int c = 0; c < col; ++c)
xoff += subplot.ColRatios[c];
for (int r = 0; r < row; ++r)
yoff += subplot.RowRatios[r];
const ImVec2 grid_size = subplot.GridRect.GetSize();
ImVec2 cpos = subplot.GridRect.Min + ImVec2(xoff*grid_size.x,yoff*grid_size.y);
cpos.x = IM_ROUND(cpos.x);
cpos.y = IM_ROUND(cpos.y);
ImGui::GetCurrentWindow()->DC.CursorPos = cpos;
// set cell size
subplot.CellSize.x = IM_ROUND(subplot.GridRect.GetWidth() * subplot.ColRatios[col]);
subplot.CellSize.y = IM_ROUND(subplot.GridRect.GetHeight() * subplot.RowRatios[row]);
// setup links
const bool lx = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllX);
const bool ly = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllY);
const bool lr = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkRows);
const bool lc = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkCols);
SetNextAxisLinks(ImAxis_X1, lx ? &subplot.ColLinkData[0].Min : lc ? &subplot.ColLinkData[col].Min : nullptr,
lx ? &subplot.ColLinkData[0].Max : lc ? &subplot.ColLinkData[col].Max : nullptr);
SetNextAxisLinks(ImAxis_Y1, ly ? &subplot.RowLinkData[0].Min : lr ? &subplot.RowLinkData[row].Min : nullptr,
ly ? &subplot.RowLinkData[0].Max : lr ? &subplot.RowLinkData[row].Max : nullptr);
// setup alignment
if (!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoAlign)) {
gp.CurrentAlignmentH = &subplot.RowAlignmentData[row];
gp.CurrentAlignmentV = &subplot.ColAlignmentData[col];
}
// set idx
if (ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ColMajor))
subplot.CurrentIdx = col * subplot.Rows + row;
else
subplot.CurrentIdx = row * subplot.Cols + col;
}
void SubplotSetCell(int idx) {
ImPlotContext& gp = *GImPlot;
ImPlotSubplot& subplot = *gp.CurrentSubplot;
if (idx >= subplot.Rows * subplot.Cols)
return;
int row = 0, col = 0;
if (ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ColMajor)) {
row = idx % subplot.Rows;
col = idx / subplot.Rows;
}
else {
row = idx / subplot.Cols;
col = idx % subplot.Cols;
}
return SubplotSetCell(row, col);
}
void SubplotNextCell() {
ImPlotContext& gp = *GImPlot;
ImPlotSubplot& subplot = *gp.CurrentSubplot;
SubplotSetCell(++subplot.CurrentIdx);
}
bool BeginSubplots(const char* title, int rows, int cols, const ImVec2& size, ImPlotSubplotFlags flags, float* row_sizes, float* col_sizes) {
IM_ASSERT_USER_ERROR(rows > 0 && cols > 0, "Invalid sizing arguments!");
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentSubplot == nullptr, "Mismatched BeginSubplots()/EndSubplots()!");
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems)
return false;
const ImGuiID ID = Window->GetID(title);
bool just_created = gp.Subplots.GetByKey(ID) == nullptr;
gp.CurrentSubplot = gp.Subplots.GetOrAddByKey(ID);
ImPlotSubplot& subplot = *gp.CurrentSubplot;
subplot.ID = ID;
subplot.Items.ID = ID - 1;
subplot.HasTitle = ImGui::FindRenderedTextEnd(title, nullptr) != title;
// push ID
ImGui::PushID(ID);
if (just_created)
subplot.Flags = flags;
else if (flags != subplot.PreviousFlags)
subplot.Flags = flags;
subplot.PreviousFlags = flags;
// check for change in rows and cols
if (subplot.Rows != rows || subplot.Cols != cols) {
subplot.RowAlignmentData.resize(rows);
subplot.RowLinkData.resize(rows);
subplot.RowRatios.resize(rows);
for (int r = 0; r < rows; ++r) {
subplot.RowAlignmentData[r].Reset();
subplot.RowLinkData[r] = ImPlotRange(0,1);
subplot.RowRatios[r] = 1.0f / rows;
}
subplot.ColAlignmentData.resize(cols);
subplot.ColLinkData.resize(cols);
subplot.ColRatios.resize(cols);
for (int c = 0; c < cols; ++c) {
subplot.ColAlignmentData[c].Reset();
subplot.ColLinkData[c] = ImPlotRange(0,1);
subplot.ColRatios[c] = 1.0f / cols;
}
}
// check incoming size requests
float row_sum = 0, col_sum = 0;
if (row_sizes != nullptr) {
row_sum = ImSum(row_sizes, rows);
for (int r = 0; r < rows; ++r)
subplot.RowRatios[r] = row_sizes[r] / row_sum;
}
if (col_sizes != nullptr) {
col_sum = ImSum(col_sizes, cols);
for (int c = 0; c < cols; ++c)
subplot.ColRatios[c] = col_sizes[c] / col_sum;
}
subplot.Rows = rows;
subplot.Cols = cols;
// calc plot frame sizes
ImVec2 title_size(0.0f, 0.0f);
if (!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoTitle))
title_size = ImGui::CalcTextSize(title, nullptr, true);
const float pad_top = title_size.x > 0.0f ? title_size.y + gp.Style.LabelPadding.y : 0;
const ImVec2 half_pad = gp.Style.PlotPadding/2;
const ImVec2 frame_size = ImGui::CalcItemSize(size, gp.Style.PlotDefaultSize.x, gp.Style.PlotDefaultSize.y);
subplot.FrameRect = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
subplot.GridRect.Min = subplot.FrameRect.Min + half_pad + ImVec2(0,pad_top);
subplot.GridRect.Max = subplot.FrameRect.Max - half_pad;
subplot.FrameHovered = subplot.FrameRect.Contains(ImGui::GetMousePos()) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows);
// outside legend adjustments (TODO: make function)
const bool share_items = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems);
if (share_items)
gp.CurrentItems = &subplot.Items;
if (share_items && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoLegend) && subplot.Items.GetLegendCount() > 0) {
ImPlotLegend& legend = subplot.Items.Legend;
const bool horz = ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal);
const ImVec2 legend_size = CalcLegendSize(subplot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !horz);
const bool west = ImHasFlag(legend.Location, ImPlotLocation_West) && !ImHasFlag(legend.Location, ImPlotLocation_East);
const bool east = ImHasFlag(legend.Location, ImPlotLocation_East) && !ImHasFlag(legend.Location, ImPlotLocation_West);
const bool north = ImHasFlag(legend.Location, ImPlotLocation_North) && !ImHasFlag(legend.Location, ImPlotLocation_South);
const bool south = ImHasFlag(legend.Location, ImPlotLocation_South) && !ImHasFlag(legend.Location, ImPlotLocation_North);
if ((west && !horz) || (west && horz && !north && !south))
subplot.GridRect.Min.x += (legend_size.x + gp.Style.LegendPadding.x);
if ((east && !horz) || (east && horz && !north && !south))
subplot.GridRect.Max.x -= (legend_size.x + gp.Style.LegendPadding.x);
if ((north && horz) || (north && !horz && !west && !east))
subplot.GridRect.Min.y += (legend_size.y + gp.Style.LegendPadding.y);
if ((south && horz) || (south && !horz && !west && !east))
subplot.GridRect.Max.y -= (legend_size.y + gp.Style.LegendPadding.y);
}
// render single background frame
ImGui::RenderFrame(subplot.FrameRect.Min, subplot.FrameRect.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, ImGui::GetStyle().FrameRounding);
// render title
if (title_size.x > 0.0f && !ImHasFlag(subplot.Flags, ImPlotFlags_NoTitle)) {
const ImU32 col = GetStyleColorU32(ImPlotCol_TitleText);
AddTextCentered(ImGui::GetWindowDrawList(),ImVec2(subplot.GridRect.GetCenter().x, subplot.GridRect.Min.y - pad_top + half_pad.y),col,title);
}
// render splitters
if (!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoResize)) {
ImDrawList& DrawList = *ImGui::GetWindowDrawList();
const ImU32 hov_col = ImGui::ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_SeparatorHovered]);
const ImU32 act_col = ImGui::ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_SeparatorActive]);
float xpos = subplot.GridRect.Min.x;
float ypos = subplot.GridRect.Min.y;
int separator = 1;
// bool pass = false;
for (int r = 0; r < subplot.Rows-1; ++r) {
ypos += subplot.RowRatios[r] * subplot.GridRect.GetHeight();
const ImGuiID sep_id = subplot.ID + separator;
ImGui::KeepAliveID(sep_id);
const ImRect sep_bb = ImRect(subplot.GridRect.Min.x, ypos-SUBPLOT_SPLITTER_HALF_THICKNESS, subplot.GridRect.Max.x, ypos+SUBPLOT_SPLITTER_HALF_THICKNESS);
bool sep_hov = false, sep_hld = false;
const bool sep_clk = ImGui::ButtonBehavior(sep_bb, sep_id, &sep_hov, &sep_hld, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick);
if ((sep_hov && G.HoveredIdTimer > SUBPLOT_SPLITTER_FEEDBACK_TIMER) || sep_hld) {
if (sep_clk && ImGui::IsMouseDoubleClicked(0)) {
float p = (subplot.RowRatios[r] + subplot.RowRatios[r+1])/2;
subplot.RowRatios[r] = subplot.RowRatios[r+1] = p;
}
if (sep_clk) {
subplot.TempSizes[0] = subplot.RowRatios[r];
subplot.TempSizes[1] = subplot.RowRatios[r+1];
}
if (sep_hld) {
float dp = ImGui::GetMouseDragDelta(0).y / subplot.GridRect.GetHeight();
if (subplot.TempSizes[0] + dp > 0.1f && subplot.TempSizes[1] - dp > 0.1f) {
subplot.RowRatios[r] = subplot.TempSizes[0] + dp;
subplot.RowRatios[r+1] = subplot.TempSizes[1] - dp;
}
}
DrawList.AddLine(ImVec2(IM_ROUND(subplot.GridRect.Min.x),IM_ROUND(ypos)),
ImVec2(IM_ROUND(subplot.GridRect.Max.x),IM_ROUND(ypos)),
sep_hld ? act_col : hov_col, SUBPLOT_BORDER_SIZE);
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
}
separator++;
}
for (int c = 0; c < subplot.Cols-1; ++c) {
xpos += subplot.ColRatios[c] * subplot.GridRect.GetWidth();
const ImGuiID sep_id = subplot.ID + separator;
ImGui::KeepAliveID(sep_id);
const ImRect sep_bb = ImRect(xpos-SUBPLOT_SPLITTER_HALF_THICKNESS, subplot.GridRect.Min.y, xpos+SUBPLOT_SPLITTER_HALF_THICKNESS, subplot.GridRect.Max.y);
bool sep_hov = false, sep_hld = false;
const bool sep_clk = ImGui::ButtonBehavior(sep_bb, sep_id, &sep_hov, &sep_hld, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick);
if ((sep_hov && G.HoveredIdTimer > SUBPLOT_SPLITTER_FEEDBACK_TIMER) || sep_hld) {
if (sep_clk && ImGui::IsMouseDoubleClicked(0)) {
float p = (subplot.ColRatios[c] + subplot.ColRatios[c+1])/2;
subplot.ColRatios[c] = subplot.ColRatios[c+1] = p;
}
if (sep_clk) {
subplot.TempSizes[0] = subplot.ColRatios[c];
subplot.TempSizes[1] = subplot.ColRatios[c+1];
}
if (sep_hld) {
float dp = ImGui::GetMouseDragDelta(0).x / subplot.GridRect.GetWidth();
if (subplot.TempSizes[0] + dp > 0.1f && subplot.TempSizes[1] - dp > 0.1f) {
subplot.ColRatios[c] = subplot.TempSizes[0] + dp;
subplot.ColRatios[c+1] = subplot.TempSizes[1] - dp;
}
}
DrawList.AddLine(ImVec2(IM_ROUND(xpos),IM_ROUND(subplot.GridRect.Min.y)),
ImVec2(IM_ROUND(xpos),IM_ROUND(subplot.GridRect.Max.y)),
sep_hld ? act_col : hov_col, SUBPLOT_BORDER_SIZE);
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
}
separator++;
}
}
// set outgoing sizes
if (row_sizes != nullptr) {
for (int r = 0; r < rows; ++r)
row_sizes[r] = subplot.RowRatios[r] * row_sum;
}
if (col_sizes != nullptr) {
for (int c = 0; c < cols; ++c)
col_sizes[c] = subplot.ColRatios[c] * col_sum;
}
// push styling
PushStyleColor(ImPlotCol_FrameBg, IM_COL32_BLACK_TRANS);
PushStyleVar(ImPlotStyleVar_PlotPadding, half_pad);
PushStyleVar(ImPlotStyleVar_PlotMinSize, ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize,0);
// set initial cursor pos
Window->DC.CursorPos = subplot.GridRect.Min;
// begin alignments
for (int r = 0; r < subplot.Rows; ++r)
subplot.RowAlignmentData[r].Begin();
for (int c = 0; c < subplot.Cols; ++c)
subplot.ColAlignmentData[c].Begin();
// clear legend data
subplot.Items.Legend.Reset();
// Setup first subplot
SubplotSetCell(0,0);
return true;
}
void EndSubplots() {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentSubplot != nullptr, "Mismatched BeginSubplots()/EndSubplots()!");
ImPlotSubplot& subplot = *gp.CurrentSubplot;
// set alignments
for (int r = 0; r < subplot.Rows; ++r)
subplot.RowAlignmentData[r].End();
for (int c = 0; c < subplot.Cols; ++c)
subplot.ColAlignmentData[c].End();
// pop styling
PopStyleColor();
PopStyleVar();
PopStyleVar();
ImGui::PopStyleVar();
// legend
subplot.Items.Legend.Hovered = false;
for (int i = 0; i < subplot.Items.GetItemCount(); ++i)
subplot.Items.GetItemByIndex(i)->LegendHovered = false;
// render legend
const bool share_items = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems);
ImDrawList& DrawList = *ImGui::GetWindowDrawList();
if (share_items && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoLegend) && subplot.Items.GetLegendCount() > 0) {
const bool legend_horz = ImHasFlag(subplot.Items.Legend.Flags, ImPlotLegendFlags_Horizontal);
const ImVec2 legend_size = CalcLegendSize(subplot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz);
const ImVec2 legend_pos = GetLocationPos(subplot.FrameRect, legend_size, subplot.Items.Legend.Location, gp.Style.PlotPadding);
subplot.Items.Legend.Rect = ImRect(legend_pos, legend_pos + legend_size);
subplot.Items.Legend.Hovered = subplot.FrameHovered && subplot.Items.Legend.Rect.Contains(ImGui::GetIO().MousePos);
ImGui::PushClipRect(subplot.FrameRect.Min, subplot.FrameRect.Max, true);
ImU32 col_bg = GetStyleColorU32(ImPlotCol_LegendBg);
ImU32 col_bd = GetStyleColorU32(ImPlotCol_LegendBorder);
DrawList.AddRectFilled(subplot.Items.Legend.Rect.Min, subplot.Items.Legend.Rect.Max, col_bg);
DrawList.AddRect(subplot.Items.Legend.Rect.Min, subplot.Items.Legend.Rect.Max, col_bd);
bool legend_contextable = ShowLegendEntries(subplot.Items, subplot.Items.Legend.Rect, subplot.Items.Legend.Hovered, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz, DrawList)
&& !ImHasFlag(subplot.Items.Legend.Flags, ImPlotLegendFlags_NoMenus);
if (legend_contextable && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoMenus) && ImGui::GetIO().MouseReleased[gp.InputMap.Menu])
ImGui::OpenPopup("##LegendContext");
ImGui::PopClipRect();
if (ImGui::BeginPopup("##LegendContext")) {
ImGui::Text("Legend"); ImGui::Separator();
if (ShowLegendContextMenu(subplot.Items.Legend, !ImHasFlag(subplot.Flags, ImPlotFlags_NoLegend)))
ImFlipFlag(subplot.Flags, ImPlotFlags_NoLegend);
ImGui::EndPopup();
}
}
else {
subplot.Items.Legend.Rect = ImRect();
}
// remove items
if (gp.CurrentItems == &subplot.Items)
gp.CurrentItems = nullptr;
// reset the plot items for the next frame (TODO: put this elswhere)
for (int i = 0; i < subplot.Items.GetItemCount(); ++i) {
subplot.Items.GetItemByIndex(i)->SeenThisFrame = false;
}
// pop id
ImGui::PopID();
// set DC back correctly
GImGui->CurrentWindow->DC.CursorPos = subplot.FrameRect.Min;
ImGui::Dummy(subplot.FrameRect.GetSize());
ResetCtxForNextSubplot(GImPlot);
}
//-----------------------------------------------------------------------------
// [SECTION] Plot Utils
//-----------------------------------------------------------------------------
void SetAxis(ImAxis axis) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "SetAxis() needs to be called between BeginPlot() and EndPlot()!");
IM_ASSERT_USER_ERROR(axis >= ImAxis_X1 && axis < ImAxis_COUNT, "Axis index out of bounds!");
IM_ASSERT_USER_ERROR(gp.CurrentPlot->Axes[axis].Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
SetupLock();
if (axis < ImAxis_Y1)
gp.CurrentPlot->CurrentX = axis;
else
gp.CurrentPlot->CurrentY = axis;
}
void SetAxes(ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "SetAxes() needs to be called between BeginPlot() and EndPlot()!");
IM_ASSERT_USER_ERROR(x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1, "X-Axis index out of bounds!");
IM_ASSERT_USER_ERROR(y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT, "Y-Axis index out of bounds!");
IM_ASSERT_USER_ERROR(gp.CurrentPlot->Axes[x_idx].Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
IM_ASSERT_USER_ERROR(gp.CurrentPlot->Axes[y_idx].Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
SetupLock();
gp.CurrentPlot->CurrentX = x_idx;
gp.CurrentPlot->CurrentY = y_idx;
}
ImPlotPoint PixelsToPlot(float x, float y, ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PixelsToPlot() needs to be called between BeginPlot() and EndPlot()!");
IM_ASSERT_USER_ERROR(x_idx == IMPLOT_AUTO || (x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1), "X-Axis index out of bounds!");
IM_ASSERT_USER_ERROR(y_idx == IMPLOT_AUTO || (y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT), "Y-Axis index out of bounds!");
SetupLock();
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& x_axis = x_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentX] : plot.Axes[x_idx];
ImPlotAxis& y_axis = y_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentY] : plot.Axes[y_idx];
return ImPlotPoint( x_axis.PixelsToPlot(x), y_axis.PixelsToPlot(y) );
}
ImPlotPoint PixelsToPlot(const ImVec2& pix, ImAxis x_idx, ImAxis y_idx) {
return PixelsToPlot(pix.x, pix.y, x_idx, y_idx);
}
ImVec2 PlotToPixels(double x, double y, ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PlotToPixels() needs to be called between BeginPlot() and EndPlot()!");
IM_ASSERT_USER_ERROR(x_idx == IMPLOT_AUTO || (x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1), "X-Axis index out of bounds!");
IM_ASSERT_USER_ERROR(y_idx == IMPLOT_AUTO || (y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT), "Y-Axis index out of bounds!");
SetupLock();
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& x_axis = x_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentX] : plot.Axes[x_idx];
ImPlotAxis& y_axis = y_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentY] : plot.Axes[y_idx];
return ImVec2( x_axis.PlotToPixels(x), y_axis.PlotToPixels(y) );
}
ImVec2 PlotToPixels(const ImPlotPoint& plt, ImAxis x_idx, ImAxis y_idx) {
return PlotToPixels(plt.x, plt.y, x_idx, y_idx);
}
ImVec2 GetPlotPos() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "GetPlotPos() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
return gp.CurrentPlot->PlotRect.Min;
}
ImVec2 GetPlotSize() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "GetPlotSize() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
return gp.CurrentPlot->PlotRect.GetSize();
}
ImPlotPoint GetPlotMousePos(ImAxis x_idx, ImAxis y_idx) {
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
return PixelsToPlot(ImGui::GetMousePos(), x_idx, y_idx);
}
ImPlotRect GetPlotLimits(ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "GetPlotLimits() needs to be called between BeginPlot() and EndPlot()!");
IM_ASSERT_USER_ERROR(x_idx == IMPLOT_AUTO || (x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1), "X-Axis index out of bounds!");
IM_ASSERT_USER_ERROR(y_idx == IMPLOT_AUTO || (y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT), "Y-Axis index out of bounds!");
SetupLock();
ImPlotPlot& plot = *gp.CurrentPlot;
ImPlotAxis& x_axis = x_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentX] : plot.Axes[x_idx];
ImPlotAxis& y_axis = y_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentY] : plot.Axes[y_idx];
ImPlotRect limits;
limits.X = x_axis.Range;
limits.Y = y_axis.Range;
return limits;
}
bool IsPlotHovered() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "IsPlotHovered() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
return gp.CurrentPlot->Hovered;
}
bool IsAxisHovered(ImAxis axis) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "IsPlotXAxisHovered() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
return gp.CurrentPlot->Axes[axis].Hovered;
}
bool IsSubplotsHovered() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentSubplot != nullptr, "IsSubplotsHovered() needs to be called between BeginSubplots() and EndSubplots()!");
return gp.CurrentSubplot->FrameHovered;
}
bool IsPlotSelected() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "IsPlotSelected() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
return gp.CurrentPlot->Selected;
}
ImPlotRect GetPlotSelection(ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "GetPlotSelection() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
ImPlotPlot& plot = *gp.CurrentPlot;
if (!plot.Selected)
return ImPlotRect(0,0,0,0);
ImPlotPoint p1 = PixelsToPlot(plot.SelectRect.Min + plot.PlotRect.Min, x_idx, y_idx);
ImPlotPoint p2 = PixelsToPlot(plot.SelectRect.Max + plot.PlotRect.Min, x_idx, y_idx);
ImPlotRect result;
result.X.Min = ImMin(p1.x, p2.x);
result.X.Max = ImMax(p1.x, p2.x);
result.Y.Min = ImMin(p1.y, p2.y);
result.Y.Max = ImMax(p1.y, p2.y);
return result;
}
void CancelPlotSelection() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "CancelPlotSelection() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
ImPlotPlot& plot = *gp.CurrentPlot;
if (plot.Selected)
plot.Selected = plot.Selecting = false;
}
void HideNextItem(bool hidden, ImPlotCond cond) {
ImPlotContext& gp = *GImPlot;
gp.NextItemData.HasHidden = true;
gp.NextItemData.Hidden = hidden;
gp.NextItemData.HiddenCond = cond;
}
//-----------------------------------------------------------------------------
// [SECTION] Plot Tools
//-----------------------------------------------------------------------------
void Annotation(double x, double y, const ImVec4& col, const ImVec2& offset, bool clamp, bool round) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "Annotation() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
char x_buff[IMPLOT_LABEL_MAX_SIZE];
char y_buff[IMPLOT_LABEL_MAX_SIZE];
ImPlotAxis& x_axis = gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentX];
ImPlotAxis& y_axis = gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentY];
LabelAxisValue(x_axis, x, x_buff, sizeof(x_buff), round);
LabelAxisValue(y_axis, y, y_buff, sizeof(y_buff), round);
Annotation(x,y,col,offset,clamp,"%s, %s",x_buff,y_buff);
}
void AnnotationV(double x, double y, const ImVec4& col, const ImVec2& offset, bool clamp, const char* fmt, va_list args) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "Annotation() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
ImVec2 pos = PlotToPixels(x,y,IMPLOT_AUTO,IMPLOT_AUTO);
ImU32 bg = ImGui::GetColorU32(col);
ImU32 fg = col.w == 0 ? GetStyleColorU32(ImPlotCol_InlayText) : CalcTextColor(col);
gp.Annotations.AppendV(pos, offset, bg, fg, clamp, fmt, args);
}
void Annotation(double x, double y, const ImVec4& col, const ImVec2& offset, bool clamp, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
AnnotationV(x,y,col,offset,clamp,fmt,args);
va_end(args);
}
void TagV(ImAxis axis, double v, const ImVec4& col, const char* fmt, va_list args) {
ImPlotContext& gp = *GImPlot;
SetupLock();
ImU32 bg = ImGui::GetColorU32(col);
ImU32 fg = col.w == 0 ? GetStyleColorU32(ImPlotCol_AxisText) : CalcTextColor(col);
gp.Tags.AppendV(axis,v,bg,fg,fmt,args);
}
void Tag(ImAxis axis, double v, const ImVec4& col, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
TagV(axis,v,col,fmt,args);
va_end(args);
}
void Tag(ImAxis axis, double v, const ImVec4& color, bool round) {
ImPlotContext& gp = *GImPlot;
SetupLock();
char buff[IMPLOT_LABEL_MAX_SIZE];
ImPlotAxis& ax = gp.CurrentPlot->Axes[axis];
LabelAxisValue(ax, v, buff, sizeof(buff), round);
Tag(axis,v,color,"%s",buff);
}
IMPLOT_API void TagX(double x, const ImVec4& color, bool round) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "TagX() needs to be called between BeginPlot() and EndPlot()!");
Tag(gp.CurrentPlot->CurrentX, x, color, round);
}
IMPLOT_API void TagX(double x, const ImVec4& color, const char* fmt, ...) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "TagX() needs to be called between BeginPlot() and EndPlot()!");
va_list args;
va_start(args, fmt);
TagV(gp.CurrentPlot->CurrentX,x,color,fmt,args);
va_end(args);
}
IMPLOT_API void TagXV(double x, const ImVec4& color, const char* fmt, va_list args) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "TagX() needs to be called between BeginPlot() and EndPlot()!");
TagV(gp.CurrentPlot->CurrentX, x, color, fmt, args);
}
IMPLOT_API void TagY(double y, const ImVec4& color, bool round) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "TagY() needs to be called between BeginPlot() and EndPlot()!");
Tag(gp.CurrentPlot->CurrentY, y, color, round);
}
IMPLOT_API void TagY(double y, const ImVec4& color, const char* fmt, ...) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "TagY() needs to be called between BeginPlot() and EndPlot()!");
va_list args;
va_start(args, fmt);
TagV(gp.CurrentPlot->CurrentY,y,color,fmt,args);
va_end(args);
}
IMPLOT_API void TagYV(double y, const ImVec4& color, const char* fmt, va_list args) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "TagY() needs to be called between BeginPlot() and EndPlot()!");
TagV(gp.CurrentPlot->CurrentY, y, color, fmt, args);
}
static const float DRAG_GRAB_HALF_SIZE = 4.0f;
bool DragPoint(int n_id, double* x, double* y, const ImVec4& col, float radius, ImPlotDragToolFlags flags) {
ImGui::PushID("#IMPLOT_DRAG_POINT");
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "DragPoint() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
FitPoint(ImPlotPoint(*x,*y));
}
const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, radius);
const ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
const ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
ImVec2 pos = PlotToPixels(*x,*y,IMPLOT_AUTO,IMPLOT_AUTO);
const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
ImRect rect(pos.x-grab_half_size,pos.y-grab_half_size,pos.x+grab_half_size,pos.y+grab_half_size);
bool hovered = false, held = false;
ImGui::KeepAliveID(id);
if (input)
ImGui::ButtonBehavior(rect,id,&hovered,&held);
bool dragging = false;
if (held && ImGui::IsMouseDragging(0)) {
*x = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
*y = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
dragging = true;
}
PushPlotClipRect();
ImDrawList& DrawList = *GetPlotDrawList();
if ((hovered || held) && show_curs)
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (dragging && no_delay)
pos = PlotToPixels(*x,*y,IMPLOT_AUTO,IMPLOT_AUTO);
DrawList.AddCircleFilled(pos, radius, col32);
PopPlotClipRect();
ImGui::PopID();
return dragging;
}
bool DragLineX(int n_id, double* value, const ImVec4& col, float thickness, ImPlotDragToolFlags flags) {
// ImGui::PushID("#IMPLOT_DRAG_LINE_X");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "DragLineX() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
FitPointX(*value);
}
const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, thickness/2);
float yt = gp.CurrentPlot->PlotRect.Min.y;
float yb = gp.CurrentPlot->PlotRect.Max.y;
float x = IM_ROUND(PlotToPixels(*value,0,IMPLOT_AUTO,IMPLOT_AUTO).x);
const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
ImRect rect(x-grab_half_size,yt,x+grab_half_size,yb);
bool hovered = false, held = false;
ImGui::KeepAliveID(id);
if (input)
ImGui::ButtonBehavior(rect,id,&hovered,&held);
if ((hovered || held) && show_curs)
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
float len = gp.Style.MajorTickLen.x;
ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
bool dragging = false;
if (held && ImGui::IsMouseDragging(0)) {
*value = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
dragging = true;
}
PushPlotClipRect();
ImDrawList& DrawList = *GetPlotDrawList();
if (dragging && no_delay)
x = IM_ROUND(PlotToPixels(*value,0,IMPLOT_AUTO,IMPLOT_AUTO).x);
DrawList.AddLine(ImVec2(x,yt), ImVec2(x,yb), col32, thickness);
DrawList.AddLine(ImVec2(x,yt), ImVec2(x,yt+len), col32, 3*thickness);
DrawList.AddLine(ImVec2(x,yb), ImVec2(x,yb-len), col32, 3*thickness);
PopPlotClipRect();
// ImGui::PopID();
return dragging;
}
bool DragLineY(int n_id, double* value, const ImVec4& col, float thickness, ImPlotDragToolFlags flags) {
ImGui::PushID("#IMPLOT_DRAG_LINE_Y");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "DragLineY() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
FitPointY(*value);
}
const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, thickness/2);
float xl = gp.CurrentPlot->PlotRect.Min.x;
float xr = gp.CurrentPlot->PlotRect.Max.x;
float y = IM_ROUND(PlotToPixels(0, *value,IMPLOT_AUTO,IMPLOT_AUTO).y);
const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
ImRect rect(xl,y-grab_half_size,xr,y+grab_half_size);
bool hovered = false, held = false;
ImGui::KeepAliveID(id);
if (input)
ImGui::ButtonBehavior(rect,id,&hovered,&held);
if ((hovered || held) && show_curs)
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
float len = gp.Style.MajorTickLen.y;
ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
bool dragging = false;
if (held && ImGui::IsMouseDragging(0)) {
*value = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
dragging = true;
}
PushPlotClipRect();
ImDrawList& DrawList = *GetPlotDrawList();
if (dragging && no_delay)
y = IM_ROUND(PlotToPixels(0, *value,IMPLOT_AUTO,IMPLOT_AUTO).y);
DrawList.AddLine(ImVec2(xl,y), ImVec2(xr,y), col32, thickness);
DrawList.AddLine(ImVec2(xl,y), ImVec2(xl+len,y), col32, 3*thickness);
DrawList.AddLine(ImVec2(xr,y), ImVec2(xr-len,y), col32, 3*thickness);
PopPlotClipRect();
ImGui::PopID();
return dragging;
}
bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_max, const ImVec4& col, ImPlotDragToolFlags flags) {
ImGui::PushID("#IMPLOT_DRAG_RECT");
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "DragRect() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
FitPoint(ImPlotPoint(*x_min,*y_min));
FitPoint(ImPlotPoint(*x_max,*y_max));
}
const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
bool h[] = {true,false,true,false};
double* x[] = {x_min,x_max,x_max,x_min};
double* y[] = {y_min,y_min,y_max,y_max};
ImVec2 p[4];
for (int i = 0; i < 4; ++i)
p[i] = PlotToPixels(*x[i],*y[i],IMPLOT_AUTO,IMPLOT_AUTO);
ImVec2 pc = PlotToPixels((*x_min+*x_max)/2,(*y_min+*y_max)/2,IMPLOT_AUTO,IMPLOT_AUTO);
ImRect rect(ImMin(p[0],p[2]),ImMax(p[0],p[2]));
ImRect rect_grab = rect; rect_grab.Expand(DRAG_GRAB_HALF_SIZE);
ImGuiMouseCursor cur[4];
if (show_curs) {
cur[0] = (rect.Min.x == p[0].x && rect.Min.y == p[0].y) || (rect.Max.x == p[0].x && rect.Max.y == p[0].y) ? ImGuiMouseCursor_ResizeNWSE : ImGuiMouseCursor_ResizeNESW;
cur[1] = cur[0] == ImGuiMouseCursor_ResizeNWSE ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
cur[2] = cur[1] == ImGuiMouseCursor_ResizeNWSE ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
cur[3] = cur[2] == ImGuiMouseCursor_ResizeNWSE ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
}
ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
color.w *= 0.25f;
ImU32 col32_a = ImGui::ColorConvertFloat4ToU32(color);
const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
bool dragging = false;
bool hovered = false, held = false;
ImRect b_rect(pc.x-DRAG_GRAB_HALF_SIZE,pc.y-DRAG_GRAB_HALF_SIZE,pc.x+DRAG_GRAB_HALF_SIZE,pc.y+DRAG_GRAB_HALF_SIZE);
ImGui::KeepAliveID(id);
if (input)
ImGui::ButtonBehavior(b_rect,id,&hovered,&held);
if ((hovered || held) && show_curs)
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
if (held && ImGui::IsMouseDragging(0)) {
for (int i = 0; i < 4; ++i) {
ImPlotPoint pp = PixelsToPlot(p[i] + ImGui::GetIO().MouseDelta,IMPLOT_AUTO,IMPLOT_AUTO);
*y[i] = pp.y;
*x[i] = pp.x;
}
dragging = true;
}
for (int i = 0; i < 4; ++i) {
// points
b_rect = ImRect(p[i].x-DRAG_GRAB_HALF_SIZE,p[i].y-DRAG_GRAB_HALF_SIZE,p[i].x+DRAG_GRAB_HALF_SIZE,p[i].y+DRAG_GRAB_HALF_SIZE);
ImGuiID p_id = id + i + 1;
ImGui::KeepAliveID(p_id);
if (input)
ImGui::ButtonBehavior(b_rect,p_id,&hovered,&held);
if ((hovered || held) && show_curs)
ImGui::SetMouseCursor(cur[i]);
if (held && ImGui::IsMouseDragging(0)) {
*x[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
*y[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
dragging = true;
}
// edges
ImVec2 e_min = ImMin(p[i],p[(i+1)%4]);
ImVec2 e_max = ImMax(p[i],p[(i+1)%4]);
b_rect = h[i] ? ImRect(e_min.x + DRAG_GRAB_HALF_SIZE, e_min.y - DRAG_GRAB_HALF_SIZE, e_max.x - DRAG_GRAB_HALF_SIZE, e_max.y + DRAG_GRAB_HALF_SIZE)
: ImRect(e_min.x - DRAG_GRAB_HALF_SIZE, e_min.y + DRAG_GRAB_HALF_SIZE, e_max.x + DRAG_GRAB_HALF_SIZE, e_max.y - DRAG_GRAB_HALF_SIZE);
ImGuiID e_id = id + i + 5;
ImGui::KeepAliveID(e_id);
if (input)
ImGui::ButtonBehavior(b_rect,e_id,&hovered,&held);
if ((hovered || held) && show_curs)
h[i] ? ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS) : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
if (held && ImGui::IsMouseDragging(0)) {
if (h[i])
*y[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
else
*x[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
dragging = true;
}
if (hovered && ImGui::IsMouseDoubleClicked(0))
{
ImPlotRect b = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO);
if (h[i])
*y[i] = ((y[i] == y_min && *y_min < *y_max) || (y[i] == y_max && *y_max < *y_min)) ? b.Y.Min : b.Y.Max;
else
*x[i] = ((x[i] == x_min && *x_min < *x_max) || (x[i] == x_max && *x_max < *x_min)) ? b.X.Min : b.X.Max;
dragging = true;
}
}
PushPlotClipRect();
ImDrawList& DrawList = *GetPlotDrawList();
if (dragging && no_delay) {
for (int i = 0; i < 4; ++i)
p[i] = PlotToPixels(*x[i],*y[i],IMPLOT_AUTO,IMPLOT_AUTO);
pc = PlotToPixels((*x_min+*x_max)/2,(*y_min+*y_max)/2,IMPLOT_AUTO,IMPLOT_AUTO);
rect = ImRect(ImMin(p[0],p[2]),ImMax(p[0],p[2]));
}
DrawList.AddRectFilled(rect.Min, rect.Max, col32_a);
DrawList.AddRect(rect.Min, rect.Max, col32);
if (input && (dragging || rect_grab.Contains(ImGui::GetMousePos()))) {
DrawList.AddCircleFilled(pc,DRAG_GRAB_HALF_SIZE,col32);
for (int i = 0; i < 4; ++i)
DrawList.AddCircleFilled(p[i],DRAG_GRAB_HALF_SIZE,col32);
}
PopPlotClipRect();
ImGui::PopID();
return dragging;
}
bool DragRect(int id, ImPlotRect* bounds, const ImVec4& col, ImPlotDragToolFlags flags) {
return DragRect(id, &bounds->X.Min, &bounds->Y.Min,&bounds->X.Max, &bounds->Y.Max, col, flags);
}
//-----------------------------------------------------------------------------
// [SECTION] Legend Utils and Tools
//-----------------------------------------------------------------------------
bool IsLegendEntryHovered(const char* label_id) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentItems != nullptr, "IsPlotItemHighlight() needs to be called within an itemized context!");
SetupLock();
ImGuiID id = ImGui::GetIDWithSeed(label_id, nullptr, gp.CurrentItems->ID);
ImPlotItem* item = gp.CurrentItems->GetItem(id);
return item && item->LegendHovered;
}
bool BeginLegendPopup(const char* label_id, ImGuiMouseButton mouse_button) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentItems != nullptr, "BeginLegendPopup() needs to be called within an itemized context!");
SetupLock();
ImGuiWindow* window = GImGui->CurrentWindow;
if (window->SkipItems)
return false;
ImGuiID id = ImGui::GetIDWithSeed(label_id, nullptr, gp.CurrentItems->ID);
if (ImGui::IsMouseReleased(mouse_button)) {
ImPlotItem* item = gp.CurrentItems->GetItem(id);
if (item && item->LegendHovered)
ImGui::OpenPopupEx(id);
}
return ImGui::BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
}
void EndLegendPopup() {
SetupLock();
ImGui::EndPopup();
}
void ShowAltLegend(const char* title_id, bool vertical, const ImVec2 size, bool interactable) {
ImPlotContext& gp = *GImPlot;
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems)
return;
ImDrawList &DrawList = *Window->DrawList;
ImPlotPlot* plot = GetPlot(title_id);
ImVec2 legend_size;
ImVec2 default_size = gp.Style.LegendPadding * 2;
if (plot != nullptr) {
legend_size = CalcLegendSize(plot->Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, vertical);
default_size = legend_size + gp.Style.LegendPadding * 2;
}
ImVec2 frame_size = ImGui::CalcItemSize(size, default_size.x, default_size.y);
ImRect bb_frame = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
ImGui::ItemSize(bb_frame);
if (!ImGui::ItemAdd(bb_frame, 0, &bb_frame))
return;
ImGui::RenderFrame(bb_frame.Min, bb_frame.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, G.Style.FrameRounding);
DrawList.PushClipRect(bb_frame.Min, bb_frame.Max, true);
if (plot != nullptr) {
const ImVec2 legend_pos = GetLocationPos(bb_frame, legend_size, 0, gp.Style.LegendPadding);
const ImRect legend_bb(legend_pos, legend_pos + legend_size);
interactable = interactable && bb_frame.Contains(ImGui::GetIO().MousePos);
// render legend box
ImU32 col_bg = GetStyleColorU32(ImPlotCol_LegendBg);
ImU32 col_bd = GetStyleColorU32(ImPlotCol_LegendBorder);
DrawList.AddRectFilled(legend_bb.Min, legend_bb.Max, col_bg);
DrawList.AddRect(legend_bb.Min, legend_bb.Max, col_bd);
// render entries
ShowLegendEntries(plot->Items, legend_bb, interactable, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, vertical, DrawList);
}
DrawList.PopClipRect();
}
//-----------------------------------------------------------------------------
// [SECTION] Drag and Drop Utils
//-----------------------------------------------------------------------------
bool BeginDragDropTargetPlot() {
SetupLock();
ImPlotContext& gp = *GImPlot;
ImRect rect = gp.CurrentPlot->PlotRect;
return ImGui::BeginDragDropTargetCustom(rect, gp.CurrentPlot->ID);
}
bool BeginDragDropTargetAxis(ImAxis axis) {
SetupLock();
ImPlotPlot& plot = *GImPlot->CurrentPlot;
ImPlotAxis& ax = plot.Axes[axis];
ImRect rect = ax.HoverRect;
rect.Expand(-3.5f);
return ImGui::BeginDragDropTargetCustom(rect, ax.ID);
}
bool BeginDragDropTargetLegend() {
SetupLock();
ImPlotItemGroup& items = *GImPlot->CurrentItems;
ImRect rect = items.Legend.Rect;
return ImGui::BeginDragDropTargetCustom(rect, items.ID);
}
void EndDragDropTarget() {
SetupLock();
ImGui::EndDragDropTarget();
}
bool BeginDragDropSourcePlot(ImGuiDragDropFlags flags) {
SetupLock();
ImPlotContext& gp = *GImPlot;
ImPlotPlot* plot = gp.CurrentPlot;
if (GImGui->IO.KeyMods == gp.InputMap.OverrideMod || GImGui->DragDropPayload.SourceId == plot->ID)
return ImGui::ItemAdd(plot->PlotRect, plot->ID) && ImGui::BeginDragDropSource(flags);
return false;
}
bool BeginDragDropSourceAxis(ImAxis idx, ImGuiDragDropFlags flags) {
SetupLock();
ImPlotContext& gp = *GImPlot;
ImPlotAxis& axis = gp.CurrentPlot->Axes[idx];
if (GImGui->IO.KeyMods == gp.InputMap.OverrideMod || GImGui->DragDropPayload.SourceId == axis.ID)
return ImGui::ItemAdd(axis.HoverRect, axis.ID) && ImGui::BeginDragDropSource(flags);
return false;
}
bool BeginDragDropSourceItem(const char* label_id, ImGuiDragDropFlags flags) {
SetupLock();
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentItems != nullptr, "BeginDragDropSourceItem() needs to be called within an itemized context!");
ImGuiID item_id = ImGui::GetIDWithSeed(label_id, nullptr, gp.CurrentItems->ID);
ImPlotItem* item = gp.CurrentItems->GetItem(item_id);
if (item != nullptr) {
return ImGui::ItemAdd(item->LegendHoverRect, item->ID) && ImGui::BeginDragDropSource(flags);
}
return false;
}
void EndDragDropSource() {
SetupLock();
ImGui::EndDragDropSource();
}
//-----------------------------------------------------------------------------
// [SECTION] Aligned Plots
//-----------------------------------------------------------------------------
bool BeginAlignedPlots(const char* group_id, bool vertical) {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentAlignmentH == nullptr && gp.CurrentAlignmentV == nullptr, "Mismatched BeginAlignedPlots()/EndAlignedPlots()!");
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems)
return false;
const ImGuiID ID = Window->GetID(group_id);
ImPlotAlignmentData* alignment = gp.AlignmentData.GetOrAddByKey(ID);
if (vertical)
gp.CurrentAlignmentV = alignment;
else
gp.CurrentAlignmentH = alignment;
if (alignment->Vertical != vertical)
alignment->Reset();
alignment->Vertical = vertical;
alignment->Begin();
return true;
}
void EndAlignedPlots() {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentAlignmentH != nullptr || gp.CurrentAlignmentV != nullptr, "Mismatched BeginAlignedPlots()/EndAlignedPlots()!");
ImPlotAlignmentData* alignment = gp.CurrentAlignmentH != nullptr ? gp.CurrentAlignmentH : (gp.CurrentAlignmentV != nullptr ? gp.CurrentAlignmentV : nullptr);
if (alignment)
alignment->End();
ResetCtxForNextAlignedPlots(GImPlot);
}
//-----------------------------------------------------------------------------
// [SECTION] Plot and Item Styling
//-----------------------------------------------------------------------------
ImPlotStyle& GetStyle() {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
return gp.Style;
}
void PushStyleColor(ImPlotCol idx, ImU32 col) {
ImPlotContext& gp = *GImPlot;
ImGuiColorMod backup;
backup.Col = (ImGuiCol)idx;
backup.BackupValue = gp.Style.Colors[idx];
gp.ColorModifiers.push_back(backup);
gp.Style.Colors[idx] = ImGui::ColorConvertU32ToFloat4(col);
}
void PushStyleColor(ImPlotCol idx, const ImVec4& col) {
ImPlotContext& gp = *GImPlot;
ImGuiColorMod backup;
backup.Col = (ImGuiCol)idx;
backup.BackupValue = gp.Style.Colors[idx];
gp.ColorModifiers.push_back(backup);
gp.Style.Colors[idx] = col;
}
void PopStyleColor(int count) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(count <= gp.ColorModifiers.Size, "You can't pop more modifiers than have been pushed!");
while (count > 0)
{
ImGuiColorMod& backup = gp.ColorModifiers.back();
gp.Style.Colors[backup.Col] = backup.BackupValue;
gp.ColorModifiers.pop_back();
count--;
}
}
void PushStyleVar(ImPlotStyleVar idx, float val) {
ImPlotContext& gp = *GImPlot;
const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx);
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) {
float* pvar = (float*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod((ImGuiStyleVar)idx, *pvar));
*pvar = val;
return;
}
IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
}
void PushStyleVar(ImPlotStyleVar idx, int val) {
ImPlotContext& gp = *GImPlot;
const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx);
if (var_info->Type == ImGuiDataType_S32 && var_info->Count == 1) {
int* pvar = (int*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod((ImGuiStyleVar)idx, *pvar));
*pvar = val;
return;
}
else if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) {
float* pvar = (float*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod((ImGuiStyleVar)idx, *pvar));
*pvar = (float)val;
return;
}
IM_ASSERT(0 && "Called PushStyleVar() int variant but variable is not a int!");
}
void PushStyleVar(ImPlotStyleVar idx, const ImVec2& val)
{
ImPlotContext& gp = *GImPlot;
const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx);
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
{
ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod((ImGuiStyleVar)idx, *pvar));
*pvar = val;
return;
}
IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
}
void PopStyleVar(int count) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(count <= gp.StyleModifiers.Size, "You can't pop more modifiers than have been pushed!");
while (count > 0) {
ImGuiStyleMod& backup = gp.StyleModifiers.back();
const ImPlotStyleVarInfo* info = GetPlotStyleVarInfo(backup.VarIdx);
void* data = info->GetVarPtr(&gp.Style);
if (info->Type == ImGuiDataType_Float && info->Count == 1) {
((float*)data)[0] = backup.BackupFloat[0];
}
else if (info->Type == ImGuiDataType_Float && info->Count == 2) {
((float*)data)[0] = backup.BackupFloat[0];
((float*)data)[1] = backup.BackupFloat[1];
}
else if (info->Type == ImGuiDataType_S32 && info->Count == 1) {
((int*)data)[0] = backup.BackupInt[0];
}
gp.StyleModifiers.pop_back();
count--;
}
}
//------------------------------------------------------------------------------
// [Section] Colormaps
//------------------------------------------------------------------------------
ImPlotColormap AddColormap(const char* name, const ImVec4* colormap, int size, bool qual) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(size > 1, "The colormap size must be greater than 1!");
IM_ASSERT_USER_ERROR(gp.ColormapData.GetIndex(name) == -1, "The colormap name has already been used!");
ImVector buffer;
buffer.resize(size);
for (int i = 0; i < size; ++i)
buffer[i] = ImGui::ColorConvertFloat4ToU32(colormap[i]);
return gp.ColormapData.Append(name, buffer.Data, size, qual);
}
ImPlotColormap AddColormap(const char* name, const ImU32* colormap, int size, bool qual) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(size > 1, "The colormap size must be greater than 1!");
IM_ASSERT_USER_ERROR(gp.ColormapData.GetIndex(name) == -1, "The colormap name has already be used!");
return gp.ColormapData.Append(name, colormap, size, qual);
}
int GetColormapCount() {
ImPlotContext& gp = *GImPlot;
return gp.ColormapData.Count;
}
const char* GetColormapName(ImPlotColormap colormap) {
ImPlotContext& gp = *GImPlot;
return gp.ColormapData.GetName(colormap);
}
ImPlotColormap GetColormapIndex(const char* name) {
ImPlotContext& gp = *GImPlot;
return gp.ColormapData.GetIndex(name);
}
void PushColormap(ImPlotColormap colormap) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(colormap >= 0 && colormap < gp.ColormapData.Count, "The colormap index is invalid!");
gp.ColormapModifiers.push_back(gp.Style.Colormap);
gp.Style.Colormap = colormap;
}
void PushColormap(const char* name) {
ImPlotContext& gp = *GImPlot;
ImPlotColormap idx = gp.ColormapData.GetIndex(name);
IM_ASSERT_USER_ERROR(idx != -1, "The colormap name is invalid!");
PushColormap(idx);
}
void PopColormap(int count) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(count <= gp.ColormapModifiers.Size, "You can't pop more modifiers than have been pushed!");
while (count > 0) {
const ImPlotColormap& backup = gp.ColormapModifiers.back();
gp.Style.Colormap = backup;
gp.ColormapModifiers.pop_back();
count--;
}
}
ImU32 NextColormapColorU32() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentItems != nullptr, "NextColormapColor() needs to be called between BeginPlot() and EndPlot()!");
int idx = gp.CurrentItems->ColormapIdx % gp.ColormapData.GetKeyCount(gp.Style.Colormap);
ImU32 col = gp.ColormapData.GetKeyColor(gp.Style.Colormap, idx);
gp.CurrentItems->ColormapIdx++;
return col;
}
ImVec4 NextColormapColor() {
return ImGui::ColorConvertU32ToFloat4(NextColormapColorU32());
}
int GetColormapSize(ImPlotColormap cmap) {
ImPlotContext& gp = *GImPlot;
cmap = cmap == IMPLOT_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
return gp.ColormapData.GetKeyCount(cmap);
}
ImU32 GetColormapColorU32(int idx, ImPlotColormap cmap) {
ImPlotContext& gp = *GImPlot;
cmap = cmap == IMPLOT_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
idx = idx % gp.ColormapData.GetKeyCount(cmap);
return gp.ColormapData.GetKeyColor(cmap, idx);
}
ImVec4 GetColormapColor(int idx, ImPlotColormap cmap) {
return ImGui::ColorConvertU32ToFloat4(GetColormapColorU32(idx,cmap));
}
ImU32 SampleColormapU32(float t, ImPlotColormap cmap) {
ImPlotContext& gp = *GImPlot;
cmap = cmap == IMPLOT_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
return gp.ColormapData.LerpTable(cmap, t);
}
ImVec4 SampleColormap(float t, ImPlotColormap cmap) {
return ImGui::ColorConvertU32ToFloat4(SampleColormapU32(t,cmap));
}
void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous) {
const int n = continuous ? size - 1 : size;
ImU32 col1, col2;
if (vert) {
const float step = bounds.GetHeight() / n;
ImRect rect(bounds.Min.x, bounds.Min.y, bounds.Max.x, bounds.Min.y + step);
for (int i = 0; i < n; ++i) {
if (reversed) {
col1 = colors[size-i-1];
col2 = continuous ? colors[size-i-2] : col1;
}
else {
col1 = colors[i];
col2 = continuous ? colors[i+1] : col1;
}
DrawList.AddRectFilledMultiColor(rect.Min, rect.Max, col1, col1, col2, col2);
rect.TranslateY(step);
}
}
else {
const float step = bounds.GetWidth() / n;
ImRect rect(bounds.Min.x, bounds.Min.y, bounds.Min.x + step, bounds.Max.y);
for (int i = 0; i < n; ++i) {
if (reversed) {
col1 = colors[size-i-1];
col2 = continuous ? colors[size-i-2] : col1;
}
else {
col1 = colors[i];
col2 = continuous ? colors[i+1] : col1;
}
DrawList.AddRectFilledMultiColor(rect.Min, rect.Max, col1, col2, col2, col1);
rect.TranslateX(step);
}
}
}
void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size, const char* format, ImPlotColormapScaleFlags flags, ImPlotColormap cmap) {
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems)
return;
const ImGuiID ID = Window->GetID(label);
ImVec2 label_size(0,0);
if (!ImHasFlag(flags, ImPlotColormapScaleFlags_NoLabel)) {
label_size = ImGui::CalcTextSize(label,nullptr,true);
}
ImPlotContext& gp = *GImPlot;
cmap = cmap == IMPLOT_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
ImVec2 frame_size = ImGui::CalcItemSize(size, 0, gp.Style.PlotDefaultSize.y);
if (frame_size.y < gp.Style.PlotMinSize.y && size.y < 0.0f)
frame_size.y = gp.Style.PlotMinSize.y;
ImPlotRange range(ImMin(scale_min,scale_max), ImMax(scale_min,scale_max));
gp.CTicker.Reset();
Locator_Default(gp.CTicker, range, frame_size.y, true, Formatter_Default, (void*)format);
const bool rend_label = label_size.x > 0;
const float txt_off = gp.Style.LabelPadding.x;
const float pad = txt_off + gp.CTicker.MaxSize.x + (rend_label ? txt_off + label_size.y : 0);
float bar_w = 20;
if (frame_size.x == 0)
frame_size.x = bar_w + pad + 2 * gp.Style.PlotPadding.x;
else {
bar_w = frame_size.x - (pad + 2 * gp.Style.PlotPadding.x);
if (bar_w < gp.Style.MajorTickLen.y)
bar_w = gp.Style.MajorTickLen.y;
}
ImDrawList &DrawList = *Window->DrawList;
ImRect bb_frame = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
ImGui::ItemSize(bb_frame);
if (!ImGui::ItemAdd(bb_frame, ID, &bb_frame))
return;
ImGui::RenderFrame(bb_frame.Min, bb_frame.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, G.Style.FrameRounding);
const bool opposite = ImHasFlag(flags, ImPlotColormapScaleFlags_Opposite);
const bool inverted = ImHasFlag(flags, ImPlotColormapScaleFlags_Invert);
const bool reversed = scale_min > scale_max;
float bb_grad_shift = opposite ? pad : 0;
ImRect bb_grad(bb_frame.Min + gp.Style.PlotPadding + ImVec2(bb_grad_shift, 0),
bb_frame.Min + ImVec2(bar_w + gp.Style.PlotPadding.x + bb_grad_shift,
frame_size.y - gp.Style.PlotPadding.y));
ImGui::PushClipRect(bb_frame.Min, bb_frame.Max, true);
const ImU32 col_text = ImGui::GetColorU32(ImGuiCol_Text);
const bool invert_scale = inverted ? (reversed ? false : true) : (reversed ? true : false);
const float y_min = invert_scale ? bb_grad.Max.y : bb_grad.Min.y;
const float y_max = invert_scale ? bb_grad.Min.y : bb_grad.Max.y;
RenderColorBar(gp.ColormapData.GetKeys(cmap), gp.ColormapData.GetKeyCount(cmap), DrawList, bb_grad, true, !inverted, !gp.ColormapData.IsQual(cmap));
for (int i = 0; i < gp.CTicker.TickCount(); ++i) {
const double y_pos_plt = gp.CTicker.Ticks[i].PlotPos;
const float y_pos = ImRemap((float)y_pos_plt, (float)range.Max, (float)range.Min, y_min, y_max);
const float tick_width = gp.CTicker.Ticks[i].Major ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y;
const float tick_thick = gp.CTicker.Ticks[i].Major ? gp.Style.MajorTickSize.y : gp.Style.MinorTickSize.y;
const float tick_t = (float)((y_pos_plt - scale_min) / (scale_max - scale_min));
const ImU32 tick_col = CalcTextColor(gp.ColormapData.LerpTable(cmap,tick_t));
if (y_pos < bb_grad.Max.y - 2 && y_pos > bb_grad.Min.y + 2) {
DrawList.AddLine(opposite ? ImVec2(bb_grad.Min.x+1, y_pos) : ImVec2(bb_grad.Max.x-1, y_pos),
opposite ? ImVec2(bb_grad.Min.x + tick_width, y_pos) : ImVec2(bb_grad.Max.x - tick_width, y_pos),
tick_col,
tick_thick);
}
const float txt_x = opposite ? bb_grad.Min.x - txt_off - gp.CTicker.Ticks[i].LabelSize.x : bb_grad.Max.x + txt_off;
const float txt_y = y_pos - gp.CTicker.Ticks[i].LabelSize.y * 0.5f;
DrawList.AddText(ImVec2(txt_x, txt_y), col_text, gp.CTicker.GetText(i));
}
if (rend_label) {
const float pos_x = opposite ? bb_frame.Min.x + gp.Style.PlotPadding.x : bb_grad.Max.x + 2 * txt_off + gp.CTicker.MaxSize.x;
const float pos_y = bb_grad.GetCenter().y + label_size.x * 0.5f;
const char* label_end = ImGui::FindRenderedTextEnd(label);
AddTextVertical(&DrawList,ImVec2(pos_x,pos_y),col_text,label,label_end);
}
DrawList.AddRect(bb_grad.Min, bb_grad.Max, GetStyleColorU32(ImPlotCol_PlotBorder));
ImGui::PopClipRect();
}
bool ColormapSlider(const char* label, float* t, ImVec4* out, const char* format, ImPlotColormap cmap) {
*t = ImClamp(*t,0.0f,1.0f);
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems)
return false;
ImPlotContext& gp = *GImPlot;
cmap = cmap == IMPLOT_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
const ImU32* keys = gp.ColormapData.GetKeys(cmap);
const int count = gp.ColormapData.GetKeyCount(cmap);
const bool qual = gp.ColormapData.IsQual(cmap);
const ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos;
const float w = ImGui::CalcItemWidth();
const float h = ImGui::GetFrameHeight();
const ImRect rect = ImRect(pos.x,pos.y,pos.x+w,pos.y+h);
RenderColorBar(keys,count,*ImGui::GetWindowDrawList(),rect,false,false,!qual);
const ImU32 grab = CalcTextColor(gp.ColormapData.LerpTable(cmap,*t));
// const ImU32 text = CalcTextColor(gp.ColormapData.LerpTable(cmap,0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBg,IM_COL32_BLACK_TRANS);
ImGui::PushStyleColor(ImGuiCol_FrameBgActive,IM_COL32_BLACK_TRANS);
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,ImVec4(1,1,1,0.1f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab,grab);
ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, grab);
ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize,2);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
const bool changed = ImGui::SliderFloat(label,t,0,1,format);
ImGui::PopStyleColor(5);
ImGui::PopStyleVar(2);
if (out != nullptr)
*out = ImGui::ColorConvertU32ToFloat4(gp.ColormapData.LerpTable(cmap,*t));
return changed;
}
bool ColormapButton(const char* label, const ImVec2& size_arg, ImPlotColormap cmap) {
ImGuiContext &G = *GImGui;
const ImGuiStyle& style = G.Style;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems)
return false;
ImPlotContext& gp = *GImPlot;
cmap = cmap == IMPLOT_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
const ImU32* keys = gp.ColormapData.GetKeys(cmap);
const int count = gp.ColormapData.GetKeyCount(cmap);
const bool qual = gp.ColormapData.IsQual(cmap);
const ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos;
const ImVec2 label_size = ImGui::CalcTextSize(label, nullptr, true);
ImVec2 size = ImGui::CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
const ImRect rect = ImRect(pos.x,pos.y,pos.x+size.x,pos.y+size.y);
RenderColorBar(keys,count,*ImGui::GetWindowDrawList(),rect,false,false,!qual);
const ImU32 text = CalcTextColor(gp.ColormapData.LerpTable(cmap,G.Style.ButtonTextAlign.x));
ImGui::PushStyleColor(ImGuiCol_Button,IM_COL32_BLACK_TRANS);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,ImVec4(1,1,1,0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,ImVec4(1,1,1,0.2f));
ImGui::PushStyleColor(ImGuiCol_Text,text);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,0);
const bool pressed = ImGui::Button(label,size);
ImGui::PopStyleColor(4);
ImGui::PopStyleVar(1);
return pressed;
}
//-----------------------------------------------------------------------------
// [Section] Miscellaneous
//-----------------------------------------------------------------------------
ImPlotInputMap& GetInputMap() {
IM_ASSERT_USER_ERROR(GImPlot != nullptr, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
return gp.InputMap;
}
void MapInputDefault(ImPlotInputMap* dst) {
ImPlotInputMap& map = dst ? *dst : GetInputMap();
map.Pan = ImGuiMouseButton_Left;
map.PanMod = ImGuiMod_None;
map.Fit = ImGuiMouseButton_Left;
map.Menu = ImGuiMouseButton_Right;
map.Select = ImGuiMouseButton_Right;
map.SelectMod = ImGuiMod_None;
map.SelectCancel = ImGuiMouseButton_Left;
map.SelectHorzMod = ImGuiMod_Alt;
map.SelectVertMod = ImGuiMod_Shift;
map.OverrideMod = ImGuiMod_Ctrl;
map.ZoomMod = ImGuiMod_None;
map.ZoomRate = 0.1f;
}
void MapInputReverse(ImPlotInputMap* dst) {
ImPlotInputMap& map = dst ? *dst : GetInputMap();
map.Pan = ImGuiMouseButton_Right;
map.PanMod = ImGuiMod_None;
map.Fit = ImGuiMouseButton_Left;
map.Menu = ImGuiMouseButton_Right;
map.Select = ImGuiMouseButton_Left;
map.SelectMod = ImGuiMod_None;
map.SelectCancel = ImGuiMouseButton_Right;
map.SelectHorzMod = ImGuiMod_Alt;
map.SelectVertMod = ImGuiMod_Shift;
map.OverrideMod = ImGuiMod_Ctrl;
map.ZoomMod = ImGuiMod_None;
map.ZoomRate = 0.1f;
}
//-----------------------------------------------------------------------------
// [Section] Miscellaneous
//-----------------------------------------------------------------------------
void ItemIcon(const ImVec4& col) {
ItemIcon(ImGui::ColorConvertFloat4ToU32(col));
}
void ItemIcon(ImU32 col) {
const float txt_size = ImGui::GetTextLineHeight();
ImVec2 size(txt_size-4,txt_size);
ImGuiWindow* window = ImGui::GetCurrentWindow();
ImVec2 pos = window->DC.CursorPos;
ImGui::GetWindowDrawList()->AddRectFilled(pos + ImVec2(0,2), pos + size - ImVec2(0,2), col);
ImGui::Dummy(size);
}
void ColormapIcon(ImPlotColormap cmap) {
ImPlotContext& gp = *GImPlot;
const float txt_size = ImGui::GetTextLineHeight();
ImVec2 size(txt_size-4,txt_size);
ImGuiWindow* window = ImGui::GetCurrentWindow();
ImVec2 pos = window->DC.CursorPos;
ImRect rect(pos+ImVec2(0,2),pos+size-ImVec2(0,2));
ImDrawList& DrawList = *ImGui::GetWindowDrawList();
RenderColorBar(gp.ColormapData.GetKeys(cmap),gp.ColormapData.GetKeyCount(cmap),DrawList,rect,false,false,!gp.ColormapData.IsQual(cmap));
ImGui::Dummy(size);
}
ImDrawList* GetPlotDrawList() {
return ImGui::GetWindowDrawList();
}
void PushPlotClipRect(float expand) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PushPlotClipRect() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
ImRect rect = gp.CurrentPlot->PlotRect;
rect.Expand(expand);
ImGui::PushClipRect(rect.Min, rect.Max, true);
}
void PopPlotClipRect() {
SetupLock();
ImGui::PopClipRect();
}
static void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
bool ShowStyleSelector(const char* label)
{
static int style_idx = -1;
if (ImGui::Combo(label, &style_idx, "Auto\0Classic\0Dark\0Light\0"))
{
switch (style_idx)
{
case 0: StyleColorsAuto(); break;
case 1: StyleColorsClassic(); break;
case 2: StyleColorsDark(); break;
case 3: StyleColorsLight(); break;
}
return true;
}
return false;
}
bool ShowColormapSelector(const char* label) {
ImPlotContext& gp = *GImPlot;
bool set = false;
if (ImGui::BeginCombo(label, gp.ColormapData.GetName(gp.Style.Colormap))) {
for (int i = 0; i < gp.ColormapData.Count; ++i) {
const char* name = gp.ColormapData.GetName(i);
if (ImGui::Selectable(name, gp.Style.Colormap == i)) {
gp.Style.Colormap = i;
ImPlot::BustItemCache();
set = true;
}
}
ImGui::EndCombo();
}
return set;
}
bool ShowInputMapSelector(const char* label) {
static int map_idx = -1;
if (ImGui::Combo(label, &map_idx, "Default\0Reversed\0"))
{
switch (map_idx)
{
case 0: MapInputDefault(); break;
case 1: MapInputReverse(); break;
}
return true;
}
return false;
}
void ShowStyleEditor(ImPlotStyle* ref) {
ImPlotContext& gp = *GImPlot;
ImPlotStyle& style = GetStyle();
static ImPlotStyle ref_saved_style;
// Default to using internal storage as reference
static bool init = true;
if (init && ref == nullptr)
ref_saved_style = style;
init = false;
if (ref == nullptr)
ref = &ref_saved_style;
if (ImPlot::ShowStyleSelector("Colors##Selector"))
ref_saved_style = style;
// Save/Revert button
if (ImGui::Button("Save Ref"))
*ref = ref_saved_style = style;
ImGui::SameLine();
if (ImGui::Button("Revert Ref"))
style = *ref;
ImGui::SameLine();
HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
"Use \"Export\" below to save them somewhere.");
if (ImGui::BeginTabBar("##StyleEditor")) {
if (ImGui::BeginTabItem("Variables")) {
ImGui::Text("Item Styling");
ImGui::SliderFloat("LineWeight", &style.LineWeight, 0.0f, 5.0f, "%.1f");
ImGui::SliderFloat("MarkerSize", &style.MarkerSize, 2.0f, 10.0f, "%.1f");
ImGui::SliderFloat("MarkerWeight", &style.MarkerWeight, 0.0f, 5.0f, "%.1f");
ImGui::SliderFloat("FillAlpha", &style.FillAlpha, 0.0f, 1.0f, "%.2f");
ImGui::SliderFloat("ErrorBarSize", &style.ErrorBarSize, 0.0f, 10.0f, "%.1f");
ImGui::SliderFloat("ErrorBarWeight", &style.ErrorBarWeight, 0.0f, 5.0f, "%.1f");
ImGui::SliderFloat("DigitalBitHeight", &style.DigitalBitHeight, 0.0f, 20.0f, "%.1f");
ImGui::SliderFloat("DigitalBitGap", &style.DigitalBitGap, 0.0f, 20.0f, "%.1f");
ImGui::Text("Plot Styling");
ImGui::SliderFloat("PlotBorderSize", &style.PlotBorderSize, 0.0f, 2.0f, "%.0f");
ImGui::SliderFloat("MinorAlpha", &style.MinorAlpha, 0.0f, 1.0f, "%.2f");
ImGui::SliderFloat2("MajorTickLen", (float*)&style.MajorTickLen, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("MinorTickLen", (float*)&style.MinorTickLen, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("MajorTickSize", (float*)&style.MajorTickSize, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat2("MinorTickSize", (float*)&style.MinorTickSize, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat2("MajorGridSize", (float*)&style.MajorGridSize, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat2("MinorGridSize", (float*)&style.MinorGridSize, 0.0f, 2.0f, "%.1f");
ImGui::SliderFloat2("PlotDefaultSize", (float*)&style.PlotDefaultSize, 0.0f, 1000, "%.0f");
ImGui::SliderFloat2("PlotMinSize", (float*)&style.PlotMinSize, 0.0f, 300, "%.0f");
ImGui::Text("Plot Padding");
ImGui::SliderFloat2("PlotPadding", (float*)&style.PlotPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LabelPadding", (float*)&style.LabelPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LegendPadding", (float*)&style.LegendPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LegendInnerPadding", (float*)&style.LegendInnerPadding, 0.0f, 10.0f, "%.0f");
ImGui::SliderFloat2("LegendSpacing", (float*)&style.LegendSpacing, 0.0f, 5.0f, "%.0f");
ImGui::SliderFloat2("MousePosPadding", (float*)&style.MousePosPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("AnnotationPadding", (float*)&style.AnnotationPadding, 0.0f, 5.0f, "%.0f");
ImGui::SliderFloat2("FitPadding", (float*)&style.FitPadding, 0, 0.2f, "%.2f");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Colors")) {
static int output_dest = 0;
static bool output_only_modified = false;
if (ImGui::Button("Export", ImVec2(75,0))) {
if (output_dest == 0)
ImGui::LogToClipboard();
else
ImGui::LogToTTY();
ImGui::LogText("ImVec4* colors = ImPlot::GetStyle().Colors;\n");
for (int i = 0; i < ImPlotCol_COUNT; i++) {
const ImVec4& col = style.Colors[i];
const char* name = ImPlot::GetStyleColorName(i);
if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) {
if (IsColorAuto(i))
ImGui::LogText("colors[ImPlotCol_%s]%*s= IMPLOT_AUTO_COL;\n",name,14 - (int)strlen(name), "");
else
ImGui::LogText("colors[ImPlotCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n",
name, 14 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
}
}
ImGui::LogFinish();
}
ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
static ImGuiTextFilter filter;
filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
static ImGuiColorEditFlags alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf;
if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
HelpMarker(
"In the color list:\n"
"Left-click on colored square to open color picker,\n"
"Right-click to open edit options menu.");
ImGui::Separator();
ImGui::PushItemWidth(-160);
for (int i = 0; i < ImPlotCol_COUNT; i++) {
const char* name = ImPlot::GetStyleColorName(i);
if (!filter.PassFilter(name))
continue;
ImGui::PushID(i);
ImVec4 temp = GetStyleColorVec4(i);
const bool is_auto = IsColorAuto(i);
if (!is_auto)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.25f);
if (ImGui::Button("Auto")) {
if (is_auto)
style.Colors[i] = temp;
else
style.Colors[i] = IMPLOT_AUTO_COL;
BustItemCache();
}
if (!is_auto)
ImGui::PopStyleVar();
ImGui::SameLine();
if (ImGui::ColorEdit4(name, &temp.x, ImGuiColorEditFlags_NoInputs | alpha_flags)) {
style.Colors[i] = temp;
BustItemCache();
}
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) {
ImGui::SameLine(175); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
ImGui::SameLine(); if (ImGui::Button("Revert")) {
style.Colors[i] = ref->Colors[i];
BustItemCache();
}
}
ImGui::PopID();
}
ImGui::PopItemWidth();
ImGui::Separator();
ImGui::Text("Colors that are set to Auto (i.e. IMPLOT_AUTO_COL) will\n"
"be automatically deduced from your ImGui style or the\n"
"current ImPlot Colormap. If you want to style individual\n"
"plot items, use Push/PopStyleColor around its function.");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Colormaps")) {
static int output_dest = 0;
if (ImGui::Button("Export", ImVec2(75,0))) {
if (output_dest == 0)
ImGui::LogToClipboard();
else
ImGui::LogToTTY();
int size = GetColormapSize();
const char* name = GetColormapName(gp.Style.Colormap);
ImGui::LogText("static const ImU32 %s_Data[%d] = {\n", name, size);
for (int i = 0; i < size; ++i) {
ImU32 col = GetColormapColorU32(i,gp.Style.Colormap);
ImGui::LogText(" %u%s\n", col, i == size - 1 ? "" : ",");
}
ImGui::LogText("};\nImPlotColormap %s = ImPlot::AddColormap(\"%s\", %s_Data, %d);", name, name, name, size);
ImGui::LogFinish();
}
ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
ImGui::SameLine();
static bool edit = false;
ImGui::Checkbox("Edit Mode",&edit);
// built-in/added
ImGui::Separator();
for (int i = 0; i < gp.ColormapData.Count; ++i) {
ImGui::PushID(i);
int size = gp.ColormapData.GetKeyCount(i);
bool selected = i == gp.Style.Colormap;
const char* name = GetColormapName(i);
if (!selected)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.25f);
if (ImGui::Button(name, ImVec2(100,0))) {
gp.Style.Colormap = i;
BustItemCache();
}
if (!selected)
ImGui::PopStyleVar();
ImGui::SameLine();
ImGui::BeginGroup();
if (edit) {
for (int c = 0; c < size; ++c) {
ImGui::PushID(c);
ImVec4 col4 = ImGui::ColorConvertU32ToFloat4(gp.ColormapData.GetKeyColor(i,c));
if (ImGui::ColorEdit4("",&col4.x,ImGuiColorEditFlags_NoInputs)) {
ImU32 col32 = ImGui::ColorConvertFloat4ToU32(col4);
gp.ColormapData.SetKeyColor(i,c,col32);
BustItemCache();
}
if ((c + 1) % 12 != 0 && c != size -1)
ImGui::SameLine();
ImGui::PopID();
}
}
else {
if (ImPlot::ColormapButton("##",ImVec2(-1,0),i))
edit = true;
}
ImGui::EndGroup();
ImGui::PopID();
}
static ImVector custom;
if (custom.Size == 0) {
custom.push_back(ImVec4(1,0,0,1));
custom.push_back(ImVec4(0,1,0,1));
custom.push_back(ImVec4(0,0,1,1));
}
ImGui::Separator();
ImGui::BeginGroup();
static char name[16] = "MyColormap";
if (ImGui::Button("+", ImVec2((100 - ImGui::GetStyle().ItemSpacing.x)/2,0)))
custom.push_back(ImVec4(0,0,0,1));
ImGui::SameLine();
if (ImGui::Button("-", ImVec2((100 - ImGui::GetStyle().ItemSpacing.x)/2,0)) && custom.Size > 2)
custom.pop_back();
ImGui::SetNextItemWidth(100);
ImGui::InputText("##Name",name,16,ImGuiInputTextFlags_CharsNoBlank);
static bool qual = true;
ImGui::Checkbox("Qualitative",&qual);
if (ImGui::Button("Add", ImVec2(100, 0)) && gp.ColormapData.GetIndex(name)==-1)
AddColormap(name,custom.Data,custom.Size,qual);
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
for (int c = 0; c < custom.Size; ++c) {
ImGui::PushID(c);
if (ImGui::ColorEdit4("##Col1", &custom[c].x, ImGuiColorEditFlags_NoInputs)) {
}
if ((c + 1) % 12 != 0)
ImGui::SameLine();
ImGui::PopID();
}
ImGui::EndGroup();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
void ShowUserGuide() {
ImGui::BulletText("Left-click drag within the plot area to pan X and Y axes.");
ImGui::Indent();
ImGui::BulletText("Left-click drag on axis labels to pan an individual axis.");
ImGui::Unindent();
ImGui::BulletText("Scroll in the plot area to zoom both X any Y axes.");
ImGui::Indent();
ImGui::BulletText("Scroll on axis labels to zoom an individual axis.");
ImGui::Unindent();
ImGui::BulletText("Right-click drag to box select data.");
ImGui::Indent();
ImGui::BulletText("Hold Alt to expand box selection horizontally.");
ImGui::BulletText("Hold Shift to expand box selection vertically.");
ImGui::BulletText("Left-click while box selecting to cancel the selection.");
ImGui::Unindent();
ImGui::BulletText("Double left-click to fit all visible data.");
ImGui::Indent();
ImGui::BulletText("Double left-click axis labels to fit the individual axis.");
ImGui::Unindent();
ImGui::BulletText("Right-click open the full plot context menu.");
ImGui::Indent();
ImGui::BulletText("Right-click axis labels to open an individual axis context menu.");
ImGui::Unindent();
ImGui::BulletText("Click legend label icons to show/hide plot items.");
}
void ShowTicksMetrics(const ImPlotTicker& ticker) {
ImGui::BulletText("Size: %d", ticker.TickCount());
ImGui::BulletText("MaxSize: [%f,%f]", ticker.MaxSize.x, ticker.MaxSize.y);
}
void ShowAxisMetrics(const ImPlotPlot& plot, const ImPlotAxis& axis) {
ImGui::BulletText("Label: %s", axis.LabelOffset == -1 ? "[none]" : plot.GetAxisLabel(axis));
ImGui::BulletText("Flags: 0x%08X", axis.Flags);
ImGui::BulletText("Range: [%f,%f]",axis.Range.Min, axis.Range.Max);
ImGui::BulletText("Pixels: %f", axis.PixelSize());
ImGui::BulletText("Aspect: %f", axis.GetAspect());
ImGui::BulletText(axis.OrthoAxis == nullptr ? "OrtherAxis: NULL" : "OrthoAxis: 0x%08X", axis.OrthoAxis->ID);
ImGui::BulletText("LinkedMin: %p", (void*)axis.LinkedMin);
ImGui::BulletText("LinkedMax: %p", (void*)axis.LinkedMax);
ImGui::BulletText("HasRange: %s", axis.HasRange ? "true" : "false");
ImGui::BulletText("Hovered: %s", axis.Hovered ? "true" : "false");
ImGui::BulletText("Held: %s", axis.Held ? "true" : "false");
if (ImGui::TreeNode("Transform")) {
ImGui::BulletText("PixelMin: %f", axis.PixelMin);
ImGui::BulletText("PixelMax: %f", axis.PixelMax);
ImGui::BulletText("ScaleToPixel: %f", axis.ScaleToPixel);
ImGui::BulletText("ScaleMax: %f", axis.ScaleMax);
ImGui::TreePop();
}
if (ImGui::TreeNode("Ticks")) {
ShowTicksMetrics(axis.Ticker);
ImGui::TreePop();
}
}
void ShowMetricsWindow(bool* p_popen) {
static bool show_plot_rects = false;
static bool show_axes_rects = false;
static bool show_axis_rects = false;
static bool show_canvas_rects = false;
static bool show_frame_rects = false;
static bool show_subplot_frame_rects = false;
static bool show_subplot_grid_rects = false;
ImDrawList& fg = *ImGui::GetForegroundDrawList();
ImPlotContext& gp = *GImPlot;
// ImGuiContext& g = *GImGui;
ImGuiIO& io = ImGui::GetIO();
ImGui::Begin("ImPlot Metrics", p_popen);
ImGui::Text("ImPlot " IMPLOT_VERSION);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::Text("Mouse Position: [%.0f,%.0f]", io.MousePos.x, io.MousePos.y);
ImGui::Separator();
if (ImGui::TreeNode("Tools")) {
if (ImGui::Button("Bust Plot Cache"))
BustPlotCache();
ImGui::SameLine();
if (ImGui::Button("Bust Item Cache"))
BustItemCache();
ImGui::Checkbox("Show Frame Rects", &show_frame_rects);
ImGui::Checkbox("Show Canvas Rects",&show_canvas_rects);
ImGui::Checkbox("Show Plot Rects", &show_plot_rects);
ImGui::Checkbox("Show Axes Rects", &show_axes_rects);
ImGui::Checkbox("Show Axis Rects", &show_axis_rects);
ImGui::Checkbox("Show Subplot Frame Rects", &show_subplot_frame_rects);
ImGui::Checkbox("Show Subplot Grid Rects", &show_subplot_grid_rects);
ImGui::TreePop();
}
const int n_plots = gp.Plots.GetBufSize();
const int n_subplots = gp.Subplots.GetBufSize();
// render rects
for (int p = 0; p < n_plots; ++p) {
ImPlotPlot* plot = gp.Plots.GetByIndex(p);
if (show_frame_rects)
fg.AddRect(plot->FrameRect.Min, plot->FrameRect.Max, IM_COL32(255,0,255,255));
if (show_canvas_rects)
fg.AddRect(plot->CanvasRect.Min, plot->CanvasRect.Max, IM_COL32(0,255,255,255));
if (show_plot_rects)
fg.AddRect(plot->PlotRect.Min, plot->PlotRect.Max, IM_COL32(255,255,0,255));
if (show_axes_rects)
fg.AddRect(plot->AxesRect.Min, plot->AxesRect.Max, IM_COL32(0,255,128,255));
if (show_axis_rects) {
for (int i = 0; i < ImAxis_COUNT; ++i) {
if (plot->Axes[i].Enabled)
fg.AddRect(plot->Axes[i].HoverRect.Min, plot->Axes[i].HoverRect.Max, IM_COL32(0,255,0,255));
}
}
}
for (int p = 0; p < n_subplots; ++p) {
ImPlotSubplot* subplot = gp.Subplots.GetByIndex(p);
if (show_subplot_frame_rects)
fg.AddRect(subplot->FrameRect.Min, subplot->FrameRect.Max, IM_COL32(255,0,0,255));
if (show_subplot_grid_rects)
fg.AddRect(subplot->GridRect.Min, subplot->GridRect.Max, IM_COL32(0,0,255,255));
}
if (ImGui::TreeNode("Plots","Plots (%d)", n_plots)) {
for (int p = 0; p < n_plots; ++p) {
// plot
ImPlotPlot& plot = *gp.Plots.GetByIndex(p);
ImGui::PushID(p);
if (ImGui::TreeNode("Plot", "Plot [0x%08X]", plot.ID)) {
int n_items = plot.Items.GetItemCount();
if (ImGui::TreeNode("Items", "Items (%d)", n_items)) {
for (int i = 0; i < n_items; ++i) {
ImPlotItem* item = plot.Items.GetItemByIndex(i);
ImGui::PushID(i);
if (ImGui::TreeNode("Item", "Item [0x%08X]", item->ID)) {
ImGui::Bullet(); ImGui::Checkbox("Show", &item->Show);
ImGui::Bullet();
ImVec4 temp = ImGui::ColorConvertU32ToFloat4(item->Color);
if (ImGui::ColorEdit4("Color",&temp.x, ImGuiColorEditFlags_NoInputs))
item->Color = ImGui::ColorConvertFloat4ToU32(temp);
ImGui::BulletText("NameOffset: %d",item->NameOffset);
ImGui::BulletText("Name: %s", item->NameOffset != -1 ? plot.Items.Legend.Labels.Buf.Data + item->NameOffset : "N/A");
ImGui::BulletText("Hovered: %s",item->LegendHovered ? "true" : "false");
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
char buff[16];
for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
ImFormatString(buff,16,"X-Axis %d", i+1);
if (plot.XAxis(i).Enabled && ImGui::TreeNode(buff, "X-Axis %d [0x%08X]", i+1, plot.XAxis(i).ID)) {
ShowAxisMetrics(plot, plot.XAxis(i));
ImGui::TreePop();
}
}
for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
ImFormatString(buff,16,"Y-Axis %d", i+1);
if (plot.YAxis(i).Enabled && ImGui::TreeNode(buff, "Y-Axis %d [0x%08X]", i+1, plot.YAxis(i).ID)) {
ShowAxisMetrics(plot, plot.YAxis(i));
ImGui::TreePop();
}
}
ImGui::BulletText("Title: %s", plot.HasTitle() ? plot.GetTitle() : "none");
ImGui::BulletText("Flags: 0x%08X", plot.Flags);
ImGui::BulletText("Initialized: %s", plot.Initialized ? "true" : "false");
ImGui::BulletText("Selecting: %s", plot.Selecting ? "true" : "false");
ImGui::BulletText("Selected: %s", plot.Selected ? "true" : "false");
ImGui::BulletText("Hovered: %s", plot.Hovered ? "true" : "false");
ImGui::BulletText("Held: %s", plot.Held ? "true" : "false");
ImGui::BulletText("LegendHovered: %s", plot.Items.Legend.Hovered ? "true" : "false");
ImGui::BulletText("ContextLocked: %s", plot.ContextLocked ? "true" : "false");
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Subplots","Subplots (%d)", n_subplots)) {
for (int p = 0; p < n_subplots; ++p) {
// plot
ImPlotSubplot& plot = *gp.Subplots.GetByIndex(p);
ImGui::PushID(p);
if (ImGui::TreeNode("Subplot", "Subplot [0x%08X]", plot.ID)) {
int n_items = plot.Items.GetItemCount();
if (ImGui::TreeNode("Items", "Items (%d)", n_items)) {
for (int i = 0; i < n_items; ++i) {
ImPlotItem* item = plot.Items.GetItemByIndex(i);
ImGui::PushID(i);
if (ImGui::TreeNode("Item", "Item [0x%08X]", item->ID)) {
ImGui::Bullet(); ImGui::Checkbox("Show", &item->Show);
ImGui::Bullet();
ImVec4 temp = ImGui::ColorConvertU32ToFloat4(item->Color);
if (ImGui::ColorEdit4("Color",&temp.x, ImGuiColorEditFlags_NoInputs))
item->Color = ImGui::ColorConvertFloat4ToU32(temp);
ImGui::BulletText("NameOffset: %d",item->NameOffset);
ImGui::BulletText("Name: %s", item->NameOffset != -1 ? plot.Items.Legend.Labels.Buf.Data + item->NameOffset : "N/A");
ImGui::BulletText("Hovered: %s",item->LegendHovered ? "true" : "false");
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
ImGui::BulletText("Flags: 0x%08X", plot.Flags);
ImGui::BulletText("FrameHovered: %s", plot.FrameHovered ? "true" : "false");
ImGui::BulletText("LegendHovered: %s", plot.Items.Legend.Hovered ? "true" : "false");
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Colormaps")) {
ImGui::BulletText("Colormaps: %d", gp.ColormapData.Count);
ImGui::BulletText("Memory: %d bytes", gp.ColormapData.Tables.Size * 4);
if (ImGui::TreeNode("Data")) {
for (int m = 0; m < gp.ColormapData.Count; ++m) {
if (ImGui::TreeNode(gp.ColormapData.GetName(m))) {
int count = gp.ColormapData.GetKeyCount(m);
int size = gp.ColormapData.GetTableSize(m);
bool qual = gp.ColormapData.IsQual(m);
ImGui::BulletText("Qualitative: %s", qual ? "true" : "false");
ImGui::BulletText("Key Count: %d", count);
ImGui::BulletText("Table Size: %d", size);
ImGui::Indent();
static float t = 0.5;
ImVec4 samp;
float wid = 32 * 10 - ImGui::GetFrameHeight() - ImGui::GetStyle().ItemSpacing.x;
ImGui::SetNextItemWidth(wid);
ImPlot::ColormapSlider("##Sample",&t,&samp,"%.3f",m);
ImGui::SameLine();
ImGui::ColorButton("Sampler",samp);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
for (int c = 0; c < size; ++c) {
ImVec4 col = ImGui::ColorConvertU32ToFloat4(gp.ColormapData.GetTableColor(m,c));
ImGui::PushID(m*1000+c);
ImGui::ColorButton("",col,0,ImVec2(10,10));
ImGui::PopID();
if ((c + 1) % 32 != 0 && c != size - 1)
ImGui::SameLine();
}
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::Unindent();
ImGui::TreePop();
}
}
ImGui::TreePop();
}
ImGui::TreePop();
}
ImGui::End();
}
bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime* t1, const ImPlotTime* t2) {
ImGui::PushID(id);
ImGui::BeginGroup();
ImGuiStyle& style = ImGui::GetStyle();
ImVec4 col_txt = style.Colors[ImGuiCol_Text];
ImVec4 col_dis = style.Colors[ImGuiCol_TextDisabled];
ImVec4 col_btn = style.Colors[ImGuiCol_Button];
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
const float ht = ImGui::GetFrameHeight();
ImVec2 cell_size(ht*1.25f,ht);
char buff[32];
bool clk = false;
tm& Tm = GImPlot->Tm;
const int min_yr = 1970;
const int max_yr = 2999;
// t1 parts
int t1_mo = 0; int t1_md = 0; int t1_yr = 0;
if (t1 != nullptr) {
GetTime(*t1,&Tm);
t1_mo = Tm.tm_mon;
t1_md = Tm.tm_mday;
t1_yr = Tm.tm_year + 1900;
}
// t2 parts
int t2_mo = 0; int t2_md = 0; int t2_yr = 0;
if (t2 != nullptr) {
GetTime(*t2,&Tm);
t2_mo = Tm.tm_mon;
t2_md = Tm.tm_mday;
t2_yr = Tm.tm_year + 1900;
}
// day widget
if (*level == 0) {
*t = FloorTime(*t, ImPlotTimeUnit_Day);
GetTime(*t, &Tm);
const int this_year = Tm.tm_year + 1900;
const int last_year = this_year - 1;
const int next_year = this_year + 1;
const int this_mon = Tm.tm_mon;
const int last_mon = this_mon == 0 ? 11 : this_mon - 1;
const int next_mon = this_mon == 11 ? 0 : this_mon + 1;
const int days_this_mo = GetDaysInMonth(this_year, this_mon);
const int days_last_mo = GetDaysInMonth(this_mon == 0 ? last_year : this_year, last_mon);
ImPlotTime t_first_mo = FloorTime(*t,ImPlotTimeUnit_Mo);
GetTime(t_first_mo,&Tm);
const int first_wd = Tm.tm_wday;
// month year
ImFormatString(buff, 32, "%s %d", MONTH_NAMES[this_mon], this_year);
if (ImGui::Button(buff))
*level = 1;
ImGui::SameLine(5*cell_size.x);
BeginDisabledControls(this_year <= min_yr && this_mon == 0);
if (ImGui::ArrowButtonEx("##Up",ImGuiDir_Up,cell_size))
*t = AddTime(*t, ImPlotTimeUnit_Mo, -1);
EndDisabledControls(this_year <= min_yr && this_mon == 0);
ImGui::SameLine();
BeginDisabledControls(this_year >= max_yr && this_mon == 11);
if (ImGui::ArrowButtonEx("##Down",ImGuiDir_Down,cell_size))
*t = AddTime(*t, ImPlotTimeUnit_Mo, 1);
EndDisabledControls(this_year >= max_yr && this_mon == 11);
// render weekday abbreviations
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
for (int i = 0; i < 7; ++i) {
ImGui::Button(WD_ABRVS[i],cell_size);
if (i != 6) { ImGui::SameLine(); }
}
ImGui::PopItemFlag();
// 0 = last mo, 1 = this mo, 2 = next mo
int mo = first_wd > 0 ? 0 : 1;
int day = mo == 1 ? 1 : days_last_mo - first_wd + 1;
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 7; ++j) {
if (mo == 0 && day > days_last_mo) {
mo = 1;
day = 1;
}
else if (mo == 1 && day > days_this_mo) {
mo = 2;
day = 1;
}
const int now_yr = (mo == 0 && this_mon == 0) ? last_year : ((mo == 2 && this_mon == 11) ? next_year : this_year);
const int now_mo = mo == 0 ? last_mon : (mo == 1 ? this_mon : next_mon);
const int now_md = day;
const bool off_mo = mo == 0 || mo == 2;
const bool t1_or_t2 = (t1 != nullptr && t1_mo == now_mo && t1_yr == now_yr && t1_md == now_md) ||
(t2 != nullptr && t2_mo == now_mo && t2_yr == now_yr && t2_md == now_md);
if (off_mo)
ImGui::PushStyleColor(ImGuiCol_Text, col_dis);
if (t1_or_t2) {
ImGui::PushStyleColor(ImGuiCol_Button, col_btn);
ImGui::PushStyleColor(ImGuiCol_Text, col_txt);
}
ImGui::PushID(i*7+j);
ImFormatString(buff,32,"%d",day);
if (now_yr == min_yr-1 || now_yr == max_yr+1) {
ImGui::Dummy(cell_size);
}
else if (ImGui::Button(buff,cell_size) && !clk) {
*t = MakeTime(now_yr, now_mo, now_md);
clk = true;
}
ImGui::PopID();
if (t1_or_t2)
ImGui::PopStyleColor(2);
if (off_mo)
ImGui::PopStyleColor();
if (j != 6)
ImGui::SameLine();
day++;
}
}
}
// month widget
else if (*level == 1) {
*t = FloorTime(*t, ImPlotTimeUnit_Mo);
GetTime(*t, &Tm);
int this_yr = Tm.tm_year + 1900;
ImFormatString(buff, 32, "%d", this_yr);
if (ImGui::Button(buff))
*level = 2;
BeginDisabledControls(this_yr <= min_yr);
ImGui::SameLine(5*cell_size.x);
if (ImGui::ArrowButtonEx("##Up",ImGuiDir_Up,cell_size))
*t = AddTime(*t, ImPlotTimeUnit_Yr, -1);
EndDisabledControls(this_yr <= min_yr);
ImGui::SameLine();
BeginDisabledControls(this_yr >= max_yr);
if (ImGui::ArrowButtonEx("##Down",ImGuiDir_Down,cell_size))
*t = AddTime(*t, ImPlotTimeUnit_Yr, 1);
EndDisabledControls(this_yr >= max_yr);
// ImGui::Dummy(cell_size);
cell_size.x *= 7.0f/4.0f;
cell_size.y *= 7.0f/3.0f;
int mo = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
const bool t1_or_t2 = (t1 != nullptr && t1_yr == this_yr && t1_mo == mo) ||
(t2 != nullptr && t2_yr == this_yr && t2_mo == mo);
if (t1_or_t2)
ImGui::PushStyleColor(ImGuiCol_Button, col_btn);
if (ImGui::Button(MONTH_ABRVS[mo],cell_size) && !clk) {
*t = MakeTime(this_yr, mo);
*level = 0;
}
if (t1_or_t2)
ImGui::PopStyleColor();
if (j != 3)
ImGui::SameLine();
mo++;
}
}
}
else if (*level == 2) {
*t = FloorTime(*t, ImPlotTimeUnit_Yr);
int this_yr = GetYear(*t);
int yr = this_yr - this_yr % 20;
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImFormatString(buff,32,"%d-%d",yr,yr+19);
ImGui::Button(buff);
ImGui::PopItemFlag();
ImGui::SameLine(5*cell_size.x);
BeginDisabledControls(yr <= min_yr);
if (ImGui::ArrowButtonEx("##Up",ImGuiDir_Up,cell_size))
*t = MakeTime(yr-20);
EndDisabledControls(yr <= min_yr);
ImGui::SameLine();
BeginDisabledControls(yr + 20 >= max_yr);
if (ImGui::ArrowButtonEx("##Down",ImGuiDir_Down,cell_size))
*t = MakeTime(yr+20);
EndDisabledControls(yr+ 20 >= max_yr);
// ImGui::Dummy(cell_size);
cell_size.x *= 7.0f/4.0f;
cell_size.y *= 7.0f/5.0f;
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 4; ++j) {
const bool t1_or_t2 = (t1 != nullptr && t1_yr == yr) || (t2 != nullptr && t2_yr == yr);
if (t1_or_t2)
ImGui::PushStyleColor(ImGuiCol_Button, col_btn);
ImFormatString(buff,32,"%d",yr);
if (yr<1970||yr>3000) {
ImGui::Dummy(cell_size);
}
else if (ImGui::Button(buff,cell_size)) {
*t = MakeTime(yr);
*level = 1;
}
if (t1_or_t2)
ImGui::PopStyleColor();
if (j != 3)
ImGui::SameLine();
yr++;
}
}
}
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::EndGroup();
ImGui::PopID();
return clk;
}
bool ShowTimePicker(const char* id, ImPlotTime* t) {
ImPlotContext& gp = *GImPlot;
ImGui::PushID(id);
tm& Tm = gp.Tm;
GetTime(*t,&Tm);
static const char* nums[] = { "00","01","02","03","04","05","06","07","08","09",
"10","11","12","13","14","15","16","17","18","19",
"20","21","22","23","24","25","26","27","28","29",
"30","31","32","33","34","35","36","37","38","39",
"40","41","42","43","44","45","46","47","48","49",
"50","51","52","53","54","55","56","57","58","59"};
static const char* am_pm[] = {"am","pm"};
bool hour24 = gp.Style.Use24HourClock;
int hr = hour24 ? Tm.tm_hour : ((Tm.tm_hour == 0 || Tm.tm_hour == 12) ? 12 : Tm.tm_hour % 12);
int min = Tm.tm_min;
int sec = Tm.tm_sec;
int ap = Tm.tm_hour < 12 ? 0 : 1;
bool changed = false;
ImVec2 spacing = ImGui::GetStyle().ItemSpacing;
spacing.x = 0;
float width = ImGui::CalcTextSize("888").x;
float height = ImGui::GetFrameHeight();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, spacing);
ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize,2.0f);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0,0,0,0));
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered));
ImGui::SetNextItemWidth(width);
if (ImGui::BeginCombo("##hr",nums[hr],ImGuiComboFlags_NoArrowButton)) {
const int ia = hour24 ? 0 : 1;
const int ib = hour24 ? 24 : 13;
for (int i = ia; i < ib; ++i) {
if (ImGui::Selectable(nums[i],i==hr)) {
hr = i;
changed = true;
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
ImGui::Text(":");
ImGui::SameLine();
ImGui::SetNextItemWidth(width);
if (ImGui::BeginCombo("##min",nums[min],ImGuiComboFlags_NoArrowButton)) {
for (int i = 0; i < 60; ++i) {
if (ImGui::Selectable(nums[i],i==min)) {
min = i;
changed = true;
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
ImGui::Text(":");
ImGui::SameLine();
ImGui::SetNextItemWidth(width);
if (ImGui::BeginCombo("##sec",nums[sec],ImGuiComboFlags_NoArrowButton)) {
for (int i = 0; i < 60; ++i) {
if (ImGui::Selectable(nums[i],i==sec)) {
sec = i;
changed = true;
}
}
ImGui::EndCombo();
}
if (!hour24) {
ImGui::SameLine();
if (ImGui::Button(am_pm[ap],ImVec2(0,height))) {
ap = 1 - ap;
changed = true;
}
}
ImGui::PopStyleColor(3);
ImGui::PopStyleVar(2);
ImGui::PopID();
if (changed) {
if (!hour24)
hr = hr % 12 + ap * 12;
Tm.tm_hour = hr;
Tm.tm_min = min;
Tm.tm_sec = sec;
*t = MkTime(&Tm);
}
return changed;
}
void StyleColorsAuto(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
style->MinorAlpha = 0.25f;
colors[ImPlotCol_Line] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_ErrorBar] = IMPLOT_AUTO_COL;
colors[ImPlotCol_FrameBg] = IMPLOT_AUTO_COL;
colors[ImPlotCol_PlotBg] = IMPLOT_AUTO_COL;
colors[ImPlotCol_PlotBorder] = IMPLOT_AUTO_COL;
colors[ImPlotCol_LegendBg] = IMPLOT_AUTO_COL;
colors[ImPlotCol_LegendBorder] = IMPLOT_AUTO_COL;
colors[ImPlotCol_LegendText] = IMPLOT_AUTO_COL;
colors[ImPlotCol_TitleText] = IMPLOT_AUTO_COL;
colors[ImPlotCol_InlayText] = IMPLOT_AUTO_COL;
colors[ImPlotCol_PlotBorder] = IMPLOT_AUTO_COL;
colors[ImPlotCol_AxisText] = IMPLOT_AUTO_COL;
colors[ImPlotCol_AxisGrid] = IMPLOT_AUTO_COL;
colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL;
colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL;
colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL;
colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Selection] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Crosshairs] = IMPLOT_AUTO_COL;
}
void StyleColorsClassic(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
style->MinorAlpha = 0.5f;
colors[ImPlotCol_Line] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_ErrorBar] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
colors[ImPlotCol_PlotBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.35f);
colors[ImPlotCol_PlotBorder] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
colors[ImPlotCol_LegendBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
colors[ImPlotCol_LegendBorder] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
colors[ImPlotCol_LegendText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_TitleText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_InlayText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_AxisText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_AxisGrid] = ImVec4(0.90f, 0.90f, 0.90f, 0.25f);
colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_Selection] = ImVec4(0.97f, 0.97f, 0.39f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(0.50f, 0.50f, 0.50f, 0.75f);
}
void StyleColorsDark(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
style->MinorAlpha = 0.25f;
colors[ImPlotCol_Line] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_ErrorBar] = IMPLOT_AUTO_COL;
colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
colors[ImPlotCol_PlotBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
colors[ImPlotCol_PlotBorder] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
colors[ImPlotCol_LegendBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImPlotCol_LegendBorder] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
colors[ImPlotCol_LegendText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_TitleText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_InlayText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_AxisText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_Selection] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f);
}
void StyleColorsLight(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
style->MinorAlpha = 1.0f;
colors[ImPlotCol_Line] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_ErrorBar] = IMPLOT_AUTO_COL;
colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_PlotBg] = ImVec4(0.42f, 0.57f, 1.00f, 0.13f);
colors[ImPlotCol_PlotBorder] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImPlotCol_LegendBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
colors[ImPlotCol_LegendBorder] = ImVec4(0.82f, 0.82f, 0.82f, 0.80f);
colors[ImPlotCol_LegendText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_TitleText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_InlayText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_AxisText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_AxisTick] = ImVec4(0.00f, 0.00f, 0.00f, 0.25f);
colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO
colors[ImPlotCol_Selection] = ImVec4(0.82f, 0.64f, 0.03f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
}
//-----------------------------------------------------------------------------
// [SECTION] Obsolete Functions/Types
//-----------------------------------------------------------------------------
#ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
bool BeginPlot(const char* title, const char* x_label, const char* y1_label, const ImVec2& size,
ImPlotFlags flags, ImPlotAxisFlags x_flags, ImPlotAxisFlags y1_flags, ImPlotAxisFlags y2_flags, ImPlotAxisFlags y3_flags,
const char* y2_label, const char* y3_label)
{
if (!BeginPlot(title, size, flags))
return false;
SetupAxis(ImAxis_X1, x_label, x_flags);
SetupAxis(ImAxis_Y1, y1_label, y1_flags);
if (ImHasFlag(flags, ImPlotFlags_YAxis2))
SetupAxis(ImAxis_Y2, y2_label, y2_flags);
if (ImHasFlag(flags, ImPlotFlags_YAxis3))
SetupAxis(ImAxis_Y3, y3_label, y3_flags);
return true;
}
#endif
} // namespace ImPlot
================================================
FILE: Source/External/imgui_tools/implot/implot.h
================================================
// MIT License
// Copyright (c) 2022 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ImPlot v0.14
// Table of Contents:
//
// [SECTION] Macros and Defines
// [SECTION] Enums and Types
// [SECTION] Callbacks
// [SECTION] Contexts
// [SECTION] Begin/End Plot
// [SECTION] Begin/End Subplot
// [SECTION] Setup
// [SECTION] SetNext
// [SECTION] Plot Items
// [SECTION] Plot Tools
// [SECTION] Plot Utils
// [SECTION] Legend Utils
// [SECTION] Drag and Drop
// [SECTION] Styling
// [SECTION] Colormaps
// [SECTION] Input Mapping
// [SECTION] Miscellaneous
// [SECTION] Demo
// [SECTION] Obsolete API
#pragma once
#include "imgui.h"
//-----------------------------------------------------------------------------
// [SECTION] Macros and Defines
//-----------------------------------------------------------------------------
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
// Using ImPlot via a shared library is not recommended, because we don't guarantee
// backward nor forward ABI compatibility and also function call overhead. If you
// do use ImPlot as a DLL, be sure to call SetImGuiContext (see Miscellanous section).
#ifndef IMPLOT_API
#define IMPLOT_API
#endif
// ImPlot version string.
#define IMPLOT_VERSION "0.14"
// Indicates variable should deduced automatically.
#define IMPLOT_AUTO -1
// Special color used to indicate that a color should be deduced automatically.
#define IMPLOT_AUTO_COL ImVec4(0,0,0,-1)
// Macro for templated plotting functions; keeps header clean.
#define IMPLOT_TMP template IMPLOT_API
//-----------------------------------------------------------------------------
// [SECTION] Enums and Types
//-----------------------------------------------------------------------------
// Forward declarations
struct ImPlotContext; // ImPlot context (opaque struct, see implot_internal.h)
// Enums/Flags
typedef int ImAxis; // -> enum ImAxis_
typedef int ImPlotFlags; // -> enum ImPlotFlags_
typedef int ImPlotAxisFlags; // -> enum ImPlotAxisFlags_
typedef int ImPlotSubplotFlags; // -> enum ImPlotSubplotFlags_
typedef int ImPlotLegendFlags; // -> enum ImPlotLegendFlags_
typedef int ImPlotMouseTextFlags; // -> enum ImPlotMouseTextFlags_
typedef int ImPlotDragToolFlags; // -> ImPlotDragToolFlags_
typedef int ImPlotColormapScaleFlags; // -> ImPlotColormapScaleFlags_
typedef int ImPlotItemFlags; // -> ImPlotItemFlags_
typedef int ImPlotLineFlags; // -> ImPlotLineFlags_
typedef int ImPlotScatterFlags; // -> ImPlotScatterFlags
typedef int ImPlotStairsFlags; // -> ImPlotStairsFlags_
typedef int ImPlotShadedFlags; // -> ImPlotShadedFlags_
typedef int ImPlotBarsFlags; // -> ImPlotBarsFlags_
typedef int ImPlotBarGroupsFlags; // -> ImPlotBarGroupsFlags_
typedef int ImPlotErrorBarsFlags; // -> ImPlotErrorBarsFlags_
typedef int ImPlotStemsFlags; // -> ImPlotStemsFlags_
typedef int ImPlotInfLinesFlags; // -> ImPlotInfLinesFlags_
typedef int ImPlotPieChartFlags; // -> ImPlotPieChartFlags_
typedef int ImPlotHeatmapFlags; // -> ImPlotHeatmapFlags_
typedef int ImPlotHistogramFlags; // -> ImPlotHistogramFlags_
typedef int ImPlotDigitalFlags; // -> ImPlotDigitalFlags_
typedef int ImPlotImageFlags; // -> ImPlotImageFlags_
typedef int ImPlotTextFlags; // -> ImPlotTextFlags_
typedef int ImPlotDummyFlags; // -> ImPlotDummyFlags_
typedef int ImPlotCond; // -> enum ImPlotCond_
typedef int ImPlotCol; // -> enum ImPlotCol_
typedef int ImPlotStyleVar; // -> enum ImPlotStyleVar_
typedef int ImPlotScale; // -> enum ImPlotScale_
typedef int ImPlotMarker; // -> enum ImPlotMarker_
typedef int ImPlotColormap; // -> enum ImPlotColormap_
typedef int ImPlotLocation; // -> enum ImPlotLocation_
typedef int ImPlotBin; // -> enum ImPlotBin_
// Axis indices. The values assigned may change; NEVER hardcode these.
enum ImAxis_ {
// horizontal axes
ImAxis_X1 = 0, // enabled by default
ImAxis_X2, // disabled by default
ImAxis_X3, // disabled by default
// vertical axes
ImAxis_Y1, // enabled by default
ImAxis_Y2, // disabled by default
ImAxis_Y3, // disabled by default
// bookeeping
ImAxis_COUNT
};
// Options for plots (see BeginPlot).
enum ImPlotFlags_ {
ImPlotFlags_None = 0, // default
ImPlotFlags_NoTitle = 1 << 0, // the plot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MyPlot")
ImPlotFlags_NoLegend = 1 << 1, // the legend will not be displayed
ImPlotFlags_NoMouseText = 1 << 2, // the mouse position, in plot coordinates, will not be displayed inside of the plot
ImPlotFlags_NoInputs = 1 << 3, // the user will not be able to interact with the plot
ImPlotFlags_NoMenus = 1 << 4, // the user will not be able to open context menus
ImPlotFlags_NoBoxSelect = 1 << 5, // the user will not be able to box-select
ImPlotFlags_NoChild = 1 << 6, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications)
ImPlotFlags_NoFrame = 1 << 7, // the ImGui frame will not be rendered
ImPlotFlags_Equal = 1 << 8, // x and y axes pairs will be constrained to have the same units/pixel
ImPlotFlags_Crosshairs = 1 << 9, // the default mouse cursor will be replaced with a crosshair when hovered
ImPlotFlags_CanvasOnly = ImPlotFlags_NoTitle | ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMouseText
};
// Options for plot axes (see SetupAxis).
enum ImPlotAxisFlags_ {
ImPlotAxisFlags_None = 0, // default
ImPlotAxisFlags_NoLabel = 1 << 0, // the axis label will not be displayed (axis labels are also hidden if the supplied string name is nullptr)
ImPlotAxisFlags_NoGridLines = 1 << 1, // no grid lines will be displayed
ImPlotAxisFlags_NoTickMarks = 1 << 2, // no tick marks will be displayed
ImPlotAxisFlags_NoTickLabels = 1 << 3, // no text labels will be displayed
ImPlotAxisFlags_NoInitialFit = 1 << 4, // axis will not be initially fit to data extents on the first rendered frame
ImPlotAxisFlags_NoMenus = 1 << 5, // the user will not be able to open context menus with right-click
ImPlotAxisFlags_NoSideSwitch = 1 << 6, // the user will not be able to switch the axis side by dragging it
ImPlotAxisFlags_NoHighlight = 1 << 7, // the axis will not have its background highlighted when hovered or held
ImPlotAxisFlags_Opposite = 1 << 8, // axis ticks and labels will be rendered on the conventionally opposite side (i.e, right or top)
ImPlotAxisFlags_Foreground = 1 << 9, // grid lines will be displayed in the foreground (i.e. on top of data) instead of the background
ImPlotAxisFlags_Invert = 1 << 10, // the axis will be inverted
ImPlotAxisFlags_AutoFit = 1 << 11, // axis will be auto-fitting to data extents
ImPlotAxisFlags_RangeFit = 1 << 12, // axis will only fit points if the point is in the visible range of the **orthogonal** axis
ImPlotAxisFlags_PanStretch = 1 << 13, // panning in a locked or constrained state will cause the axis to stretch if possible
ImPlotAxisFlags_LockMin = 1 << 14, // the axis minimum value will be locked when panning/zooming
ImPlotAxisFlags_LockMax = 1 << 15, // the axis maximum value will be locked when panning/zooming
ImPlotAxisFlags_Lock = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax,
ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels,
ImPlotAxisFlags_AuxDefault = ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_Opposite
};
// Options for subplots (see BeginSubplot)
enum ImPlotSubplotFlags_ {
ImPlotSubplotFlags_None = 0, // default
ImPlotSubplotFlags_NoTitle = 1 << 0, // the subplot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MySubplot")
ImPlotSubplotFlags_NoLegend = 1 << 1, // the legend will not be displayed (only applicable if ImPlotSubplotFlags_ShareItems is enabled)
ImPlotSubplotFlags_NoMenus = 1 << 2, // the user will not be able to open context menus with right-click
ImPlotSubplotFlags_NoResize = 1 << 3, // resize splitters between subplot cells will be not be provided
ImPlotSubplotFlags_NoAlign = 1 << 4, // subplot edges will not be aligned vertically or horizontally
ImPlotSubplotFlags_ShareItems = 1 << 5, // items across all subplots will be shared and rendered into a single legend entry
ImPlotSubplotFlags_LinkRows = 1 << 6, // link the y-axis limits of all plots in each row (does not apply to auxiliary axes)
ImPlotSubplotFlags_LinkCols = 1 << 7, // link the x-axis limits of all plots in each column (does not apply to auxiliary axes)
ImPlotSubplotFlags_LinkAllX = 1 << 8, // link the x-axis limits in every plot in the subplot (does not apply to auxiliary axes)
ImPlotSubplotFlags_LinkAllY = 1 << 9, // link the y-axis limits in every plot in the subplot (does not apply to auxiliary axes)
ImPlotSubplotFlags_ColMajor = 1 << 10 // subplots are added in column major order instead of the default row major order
};
// Options for legends (see SetupLegend)
enum ImPlotLegendFlags_ {
ImPlotLegendFlags_None = 0, // default
ImPlotLegendFlags_NoButtons = 1 << 0, // legend icons will not function as hide/show buttons
ImPlotLegendFlags_NoHighlightItem = 1 << 1, // plot items will not be highlighted when their legend entry is hovered
ImPlotLegendFlags_NoHighlightAxis = 1 << 2, // axes will not be highlighted when legend entries are hovered (only relevant if x/y-axis count > 1)
ImPlotLegendFlags_NoMenus = 1 << 3, // the user will not be able to open context menus with right-click
ImPlotLegendFlags_Outside = 1 << 4, // legend will be rendered outside of the plot area
ImPlotLegendFlags_Horizontal = 1 << 5, // legend entries will be displayed horizontally
ImPlotLegendFlags_Sort = 1 << 6, // legend entries will be displayed in alphabetical order
};
// Options for mouse hover text (see SetupMouseText)
enum ImPlotMouseTextFlags_ {
ImPlotMouseTextFlags_None = 0, // default
ImPlotMouseTextFlags_NoAuxAxes = 1 << 0, // only show the mouse position for primary axes
ImPlotMouseTextFlags_NoFormat = 1 << 1, // axes label formatters won't be used to render text
ImPlotMouseTextFlags_ShowAlways = 1 << 2, // always display mouse position even if plot not hovered
};
// Options for DragPoint, DragLine, DragRect
enum ImPlotDragToolFlags_ {
ImPlotDragToolFlags_None = 0, // default
ImPlotDragToolFlags_NoCursors = 1 << 0, // drag tools won't change cursor icons when hovered or held
ImPlotDragToolFlags_NoFit = 1 << 1, // the drag tool won't be considered for plot fits
ImPlotDragToolFlags_NoInputs = 1 << 2, // lock the tool from user inputs
ImPlotDragToolFlags_Delayed = 1 << 3, // tool rendering will be delayed one frame; useful when applying position-constraints
};
// Flags for ColormapScale
enum ImPlotColormapScaleFlags_ {
ImPlotColormapScaleFlags_None = 0, // default
ImPlotColormapScaleFlags_NoLabel = 1 << 0, // the colormap axis label will not be displayed
ImPlotColormapScaleFlags_Opposite = 1 << 1, // render the colormap label and tick labels on the opposite side
ImPlotColormapScaleFlags_Invert = 1 << 2, // invert the colormap bar and axis scale (this only affects rendering; if you only want to reverse the scale mapping, make scale_min > scale_max)
};
// Flags for ANY PlotX function
enum ImPlotItemFlags_ {
ImPlotItemFlags_None = 0,
ImPlotItemFlags_NoLegend = 1 << 0, // the item won't have a legend entry displayed
ImPlotItemFlags_NoFit = 1 << 1, // the item won't be considered for plot fits
};
// Flags for PlotLine
enum ImPlotLineFlags_ {
ImPlotLineFlags_None = 0, // default
ImPlotLineFlags_Segments = 1 << 10, // a line segment will be rendered from every two consecutive points
ImPlotLineFlags_Loop = 1 << 11, // the last and first point will be connected to form a closed loop
ImPlotLineFlags_SkipNaN = 1 << 12, // NaNs values will be skipped instead of rendered as missing data
ImPlotLineFlags_NoClip = 1 << 13, // markers (if displayed) on the edge of a plot will not be clipped
ImPlotLineFlags_Shaded = 1 << 14, // a filled region between the line and horizontal origin will be rendered; use PlotShaded for more advanced cases
};
// Flags for PlotScatter
enum ImPlotScatterFlags_ {
ImPlotScatterFlags_None = 0, // default
ImPlotScatterFlags_NoClip = 1 << 10, // markers on the edge of a plot will not be clipped
};
// Flags for PlotStairs
enum ImPlotStairsFlags_ {
ImPlotStairsFlags_None = 0, // default
ImPlotStairsFlags_PreStep = 1 << 10, // the y value is continued constantly to the left from every x position, i.e. the interval (x[i-1], x[i]] has the value y[i]
ImPlotStairsFlags_Shaded = 1 << 11 // a filled region between the stairs and horizontal origin will be rendered; use PlotShaded for more advanced cases
};
// Flags for PlotShaded (placeholder)
enum ImPlotShadedFlags_ {
ImPlotShadedFlags_None = 0 // default
};
// Flags for PlotBars
enum ImPlotBarsFlags_ {
ImPlotBarsFlags_None = 0, // default
ImPlotBarsFlags_Horizontal = 1 << 10, // bars will be rendered horizontally on the current y-axis
};
// Flags for PlotBarGroups
enum ImPlotBarGroupsFlags_ {
ImPlotBarGroupsFlags_None = 0, // default
ImPlotBarGroupsFlags_Horizontal = 1 << 10, // bar groups will be rendered horizontally on the current y-axis
ImPlotBarGroupsFlags_Stacked = 1 << 11, // items in a group will be stacked on top of each other
};
// Flags for PlotErrorBars
enum ImPlotErrorBarsFlags_ {
ImPlotErrorBarsFlags_None = 0, // default
ImPlotErrorBarsFlags_Horizontal = 1 << 10, // error bars will be rendered horizontally on the current y-axis
};
// Flags for PlotStems
enum ImPlotStemsFlags_ {
ImPlotStemsFlags_None = 0, // default
ImPlotStemsFlags_Horizontal = 1 << 10, // stems will be rendered horizontally on the current y-axis
};
// Flags for PlotInfLines
enum ImPlotInfLinesFlags_ {
ImPlotInfLinesFlags_None = 0, // default
ImPlotInfLinesFlags_Horizontal = 1 << 10 // lines will be rendered horizontally on the current y-axis
};
// Flags for PlotPieChart
enum ImPlotPieChartFlags_ {
ImPlotPieChartFlags_None = 0, // default
ImPlotPieChartFlags_Normalize = 1 << 10 // force normalization of pie chart values (i.e. always make a full circle if sum < 0)
};
// Flags for PlotHeatmap
enum ImPlotHeatmapFlags_ {
ImPlotHeatmapFlags_None = 0, // default
ImPlotHeatmapFlags_ColMajor = 1 << 10, // data will be read in column major order
};
// Flags for PlotHistogram and PlotHistogram2D
enum ImPlotHistogramFlags_ {
ImPlotHistogramFlags_None = 0, // default
ImPlotHistogramFlags_Horizontal = 1 << 10, // histogram bars will be rendered horizontally (not supported by PlotHistogram2D)
ImPlotHistogramFlags_Cumulative = 1 << 11, // each bin will contain its count plus the counts of all previous bins (not supported by PlotHistogram2D)
ImPlotHistogramFlags_Density = 1 << 12, // counts will be normalized, i.e. the PDF will be visualized, or the CDF will be visualized if Cumulative is also set
ImPlotHistogramFlags_NoOutliers = 1 << 13, // exclude values outside the specifed histogram range from the count toward normalizing and cumulative counts
ImPlotHistogramFlags_ColMajor = 1 << 14 // data will be read in column major order (not supported by PlotHistogram)
};
// Flags for PlotDigital (placeholder)
enum ImPlotDigitalFlags_ {
ImPlotDigitalFlags_None = 0 // default
};
// Flags for PlotImage (placeholder)
enum ImPlotImageFlags_ {
ImPlotImageFlags_None = 0 // default
};
// Flags for PlotText
enum ImPlotTextFlags_ {
ImPlotTextFlags_None = 0, // default
ImPlotTextFlags_Vertical = 1 << 10 // text will be rendered vertically
};
// Flags for PlotDummy (placeholder)
enum ImPlotDummyFlags_ {
ImPlotDummyFlags_None = 0 // default
};
// Represents a condition for SetupAxisLimits etc. (same as ImGuiCond, but we only support a subset of those enums)
enum ImPlotCond_
{
ImPlotCond_None = ImGuiCond_None, // No condition (always set the variable), same as _Always
ImPlotCond_Always = ImGuiCond_Always, // No condition (always set the variable)
ImPlotCond_Once = ImGuiCond_Once, // Set the variable once per runtime session (only the first call will succeed)
};
// Plot styling colors.
enum ImPlotCol_ {
// item styling colors
ImPlotCol_Line, // plot line/outline color (defaults to next unused color in current colormap)
ImPlotCol_Fill, // plot fill color for bars (defaults to the current line color)
ImPlotCol_MarkerOutline, // marker outline color (defaults to the current line color)
ImPlotCol_MarkerFill, // marker fill color (defaults to the current line color)
ImPlotCol_ErrorBar, // error bar color (defaults to ImGuiCol_Text)
// plot styling colors
ImPlotCol_FrameBg, // plot frame background color (defaults to ImGuiCol_FrameBg)
ImPlotCol_PlotBg, // plot area background color (defaults to ImGuiCol_WindowBg)
ImPlotCol_PlotBorder, // plot area border color (defaults to ImGuiCol_Border)
ImPlotCol_LegendBg, // legend background color (defaults to ImGuiCol_PopupBg)
ImPlotCol_LegendBorder, // legend border color (defaults to ImPlotCol_PlotBorder)
ImPlotCol_LegendText, // legend text color (defaults to ImPlotCol_InlayText)
ImPlotCol_TitleText, // plot title text color (defaults to ImGuiCol_Text)
ImPlotCol_InlayText, // color of text appearing inside of plots (defaults to ImGuiCol_Text)
ImPlotCol_AxisText, // axis label and tick lables color (defaults to ImGuiCol_Text)
ImPlotCol_AxisGrid, // axis grid color (defaults to 25% ImPlotCol_AxisText)
ImPlotCol_AxisTick, // axis tick color (defaults to AxisGrid)
ImPlotCol_AxisBg, // background color of axis hover region (defaults to transparent)
ImPlotCol_AxisBgHovered, // axis hover color (defaults to ImGuiCol_ButtonHovered)
ImPlotCol_AxisBgActive, // axis active color (defaults to ImGuiCol_ButtonActive)
ImPlotCol_Selection, // box-selection color (defaults to yellow)
ImPlotCol_Crosshairs, // crosshairs color (defaults to ImPlotCol_PlotBorder)
ImPlotCol_COUNT
};
// Plot styling variables.
enum ImPlotStyleVar_ {
// item styling variables
ImPlotStyleVar_LineWeight, // float, plot item line weight in pixels
ImPlotStyleVar_Marker, // int, marker specification
ImPlotStyleVar_MarkerSize, // float, marker size in pixels (roughly the marker's "radius")
ImPlotStyleVar_MarkerWeight, // float, plot outline weight of markers in pixels
ImPlotStyleVar_FillAlpha, // float, alpha modifier applied to all plot item fills
ImPlotStyleVar_ErrorBarSize, // float, error bar whisker width in pixels
ImPlotStyleVar_ErrorBarWeight, // float, error bar whisker weight in pixels
ImPlotStyleVar_DigitalBitHeight, // float, digital channels bit height (at 1) in pixels
ImPlotStyleVar_DigitalBitGap, // float, digital channels bit padding gap in pixels
// plot styling variables
ImPlotStyleVar_PlotBorderSize, // float, thickness of border around plot area
ImPlotStyleVar_MinorAlpha, // float, alpha multiplier applied to minor axis grid lines
ImPlotStyleVar_MajorTickLen, // ImVec2, major tick lengths for X and Y axes
ImPlotStyleVar_MinorTickLen, // ImVec2, minor tick lengths for X and Y axes
ImPlotStyleVar_MajorTickSize, // ImVec2, line thickness of major ticks
ImPlotStyleVar_MinorTickSize, // ImVec2, line thickness of minor ticks
ImPlotStyleVar_MajorGridSize, // ImVec2, line thickness of major grid lines
ImPlotStyleVar_MinorGridSize, // ImVec2, line thickness of minor grid lines
ImPlotStyleVar_PlotPadding, // ImVec2, padding between widget frame and plot area, labels, or outside legends (i.e. main padding)
ImPlotStyleVar_LabelPadding, // ImVec2, padding between axes labels, tick labels, and plot edge
ImPlotStyleVar_LegendPadding, // ImVec2, legend padding from plot edges
ImPlotStyleVar_LegendInnerPadding, // ImVec2, legend inner padding from legend edges
ImPlotStyleVar_LegendSpacing, // ImVec2, spacing between legend entries
ImPlotStyleVar_MousePosPadding, // ImVec2, padding between plot edge and interior info text
ImPlotStyleVar_AnnotationPadding, // ImVec2, text padding around annotation labels
ImPlotStyleVar_FitPadding, // ImVec2, additional fit padding as a percentage of the fit extents (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y)
ImPlotStyleVar_PlotDefaultSize, // ImVec2, default size used when ImVec2(0,0) is passed to BeginPlot
ImPlotStyleVar_PlotMinSize, // ImVec2, minimum size plot frame can be when shrunk
ImPlotStyleVar_COUNT
};
// Axis scale
enum ImPlotScale_ {
ImPlotScale_Linear = 0, // default linear scale
ImPlotScale_Time, // date/time scale
ImPlotScale_Log10, // base 10 logartithmic scale
ImPlotScale_SymLog, // symmetric log scale
};
// Marker specifications.
enum ImPlotMarker_ {
ImPlotMarker_None = -1, // no marker
ImPlotMarker_Circle, // a circle marker (default)
ImPlotMarker_Square, // a square maker
ImPlotMarker_Diamond, // a diamond marker
ImPlotMarker_Up, // an upward-pointing triangle marker
ImPlotMarker_Down, // an downward-pointing triangle marker
ImPlotMarker_Left, // an leftward-pointing triangle marker
ImPlotMarker_Right, // an rightward-pointing triangle marker
ImPlotMarker_Cross, // a cross marker (not fillable)
ImPlotMarker_Plus, // a plus marker (not fillable)
ImPlotMarker_Asterisk, // a asterisk marker (not fillable)
ImPlotMarker_COUNT
};
// Built-in colormaps
enum ImPlotColormap_ {
ImPlotColormap_Deep = 0, // a.k.a. seaborn deep (qual=true, n=10) (default)
ImPlotColormap_Dark = 1, // a.k.a. matplotlib "Set1" (qual=true, n=9 )
ImPlotColormap_Pastel = 2, // a.k.a. matplotlib "Pastel1" (qual=true, n=9 )
ImPlotColormap_Paired = 3, // a.k.a. matplotlib "Paired" (qual=true, n=12)
ImPlotColormap_Viridis = 4, // a.k.a. matplotlib "viridis" (qual=false, n=11)
ImPlotColormap_Plasma = 5, // a.k.a. matplotlib "plasma" (qual=false, n=11)
ImPlotColormap_Hot = 6, // a.k.a. matplotlib/MATLAB "hot" (qual=false, n=11)
ImPlotColormap_Cool = 7, // a.k.a. matplotlib/MATLAB "cool" (qual=false, n=11)
ImPlotColormap_Pink = 8, // a.k.a. matplotlib/MATLAB "pink" (qual=false, n=11)
ImPlotColormap_Jet = 9, // a.k.a. MATLAB "jet" (qual=false, n=11)
ImPlotColormap_Twilight = 10, // a.k.a. matplotlib "twilight" (qual=false, n=11)
ImPlotColormap_RdBu = 11, // red/blue, Color Brewer (qual=false, n=11)
ImPlotColormap_BrBG = 12, // brown/blue-green, Color Brewer (qual=false, n=11)
ImPlotColormap_PiYG = 13, // pink/yellow-green, Color Brewer (qual=false, n=11)
ImPlotColormap_Spectral = 14, // color spectrum, Color Brewer (qual=false, n=11)
ImPlotColormap_Greys = 15, // white/black (qual=false, n=2 )
};
// Used to position items on a plot (e.g. legends, labels, etc.)
enum ImPlotLocation_ {
ImPlotLocation_Center = 0, // center-center
ImPlotLocation_North = 1 << 0, // top-center
ImPlotLocation_South = 1 << 1, // bottom-center
ImPlotLocation_West = 1 << 2, // center-left
ImPlotLocation_East = 1 << 3, // center-right
ImPlotLocation_NorthWest = ImPlotLocation_North | ImPlotLocation_West, // top-left
ImPlotLocation_NorthEast = ImPlotLocation_North | ImPlotLocation_East, // top-right
ImPlotLocation_SouthWest = ImPlotLocation_South | ImPlotLocation_West, // bottom-left
ImPlotLocation_SouthEast = ImPlotLocation_South | ImPlotLocation_East // bottom-right
};
// Enums for different automatic histogram binning methods (k = bin count or w = bin width)
enum ImPlotBin_ {
ImPlotBin_Sqrt = -1, // k = sqrt(n)
ImPlotBin_Sturges = -2, // k = 1 + log2(n)
ImPlotBin_Rice = -3, // k = 2 * cbrt(n)
ImPlotBin_Scott = -4, // w = 3.49 * sigma / cbrt(n)
};
// Double precision version of ImVec2 used by ImPlot. Extensible by end users.
struct ImPlotPoint {
double x, y;
ImPlotPoint() { x = y = 0.0; }
ImPlotPoint(double _x, double _y) { x = _x; y = _y; }
ImPlotPoint(const ImVec2& p) { x = p.x; y = p.y; }
double operator[] (size_t idx) const { return (&x)[idx]; }
double& operator[] (size_t idx) { return (&x)[idx]; }
#ifdef IMPLOT_POINT_CLASS_EXTRA
IMPLOT_POINT_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h
// to convert back and forth between your math types and ImPlotPoint.
#endif
};
// Range defined by a min/max value.
struct ImPlotRange {
double Min, Max;
ImPlotRange() { Min = 0; Max = 0; }
ImPlotRange(double _min, double _max) { Min = _min; Max = _max; }
bool Contains(double value) const { return value >= Min && value <= Max; }
double Size() const { return Max - Min; }
double Clamp(double value) const { return (value < Min) ? Min : (value > Max) ? Max : value; }
};
// Combination of two range limits for X and Y axes. Also an AABB defined by Min()/Max().
struct ImPlotRect {
ImPlotRange X, Y;
ImPlotRect() { }
ImPlotRect(double x_min, double x_max, double y_min, double y_max) { X.Min = x_min; X.Max = x_max; Y.Min = y_min; Y.Max = y_max; }
bool Contains(const ImPlotPoint& p) const { return Contains(p.x, p.y); }
bool Contains(double x, double y) const { return X.Contains(x) && Y.Contains(y); }
ImPlotPoint Size() const { return ImPlotPoint(X.Size(), Y.Size()); }
ImPlotPoint Clamp(const ImPlotPoint& p) { return Clamp(p.x, p.y); }
ImPlotPoint Clamp(double x, double y) { return ImPlotPoint(X.Clamp(x),Y.Clamp(y)); }
ImPlotPoint Min() const { return ImPlotPoint(X.Min, Y.Min); }
ImPlotPoint Max() const { return ImPlotPoint(X.Max, Y.Max); }
};
// Plot style structure
struct ImPlotStyle {
// item styling variables
float LineWeight; // = 1, item line weight in pixels
int Marker; // = ImPlotMarker_None, marker specification
float MarkerSize; // = 4, marker size in pixels (roughly the marker's "radius")
float MarkerWeight; // = 1, outline weight of markers in pixels
float FillAlpha; // = 1, alpha modifier applied to plot fills
float ErrorBarSize; // = 5, error bar whisker width in pixels
float ErrorBarWeight; // = 1.5, error bar whisker weight in pixels
float DigitalBitHeight; // = 8, digital channels bit height (at y = 1.0f) in pixels
float DigitalBitGap; // = 4, digital channels bit padding gap in pixels
// plot styling variables
float PlotBorderSize; // = 1, line thickness of border around plot area
float MinorAlpha; // = 0.25 alpha multiplier applied to minor axis grid lines
ImVec2 MajorTickLen; // = 10,10 major tick lengths for X and Y axes
ImVec2 MinorTickLen; // = 5,5 minor tick lengths for X and Y axes
ImVec2 MajorTickSize; // = 1,1 line thickness of major ticks
ImVec2 MinorTickSize; // = 1,1 line thickness of minor ticks
ImVec2 MajorGridSize; // = 1,1 line thickness of major grid lines
ImVec2 MinorGridSize; // = 1,1 line thickness of minor grid lines
ImVec2 PlotPadding; // = 10,10 padding between widget frame and plot area, labels, or outside legends (i.e. main padding)
ImVec2 LabelPadding; // = 5,5 padding between axes labels, tick labels, and plot edge
ImVec2 LegendPadding; // = 10,10 legend padding from plot edges
ImVec2 LegendInnerPadding; // = 5,5 legend inner padding from legend edges
ImVec2 LegendSpacing; // = 5,0 spacing between legend entries
ImVec2 MousePosPadding; // = 10,10 padding between plot edge and interior mouse location text
ImVec2 AnnotationPadding; // = 2,2 text padding around annotation labels
ImVec2 FitPadding; // = 0,0 additional fit padding as a percentage of the fit extents (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y)
ImVec2 PlotDefaultSize; // = 400,300 default size used when ImVec2(0,0) is passed to BeginPlot
ImVec2 PlotMinSize; // = 200,150 minimum size plot frame can be when shrunk
// style colors
ImVec4 Colors[ImPlotCol_COUNT]; // Array of styling colors. Indexable with ImPlotCol_ enums.
// colormap
ImPlotColormap Colormap; // The current colormap. Set this to either an ImPlotColormap_ enum or an index returned by AddColormap.
// settings/flags
bool UseLocalTime; // = false, axis labels will be formatted for your timezone when ImPlotAxisFlag_Time is enabled
bool UseISO8601; // = false, dates will be formatted according to ISO 8601 where applicable (e.g. YYYY-MM-DD, YYYY-MM, --MM-DD, etc.)
bool Use24HourClock; // = false, times will be formatted using a 24 hour clock
IMPLOT_API ImPlotStyle();
};
// Support for legacy versions
#if (IMGUI_VERSION_NUM < 18716) // Renamed in 1.88
#define ImGuiMod_None 0
#define ImGuiMod_Ctrl ImGuiKeyModFlags_Ctrl
#define ImGuiMod_Shift ImGuiKeyModFlags_Shift
#define ImGuiMod_Alt ImGuiKeyModFlags_Alt
#define ImGuiMod_Super ImGuiKeyModFlags_Super
#elif (IMGUI_VERSION_NUM < 18823) // Renamed in 1.89, sorry
#define ImGuiMod_None 0
#define ImGuiMod_Ctrl ImGuiModFlags_Ctrl
#define ImGuiMod_Shift ImGuiModFlags_Shift
#define ImGuiMod_Alt ImGuiModFlags_Alt
#define ImGuiMod_Super ImGuiModFlags_Super
#endif
// Input mapping structure. Default values listed. See also MapInputDefault, MapInputReverse.
struct ImPlotInputMap {
ImGuiMouseButton Pan; // LMB enables panning when held,
int PanMod; // none optional modifier that must be held for panning/fitting
ImGuiMouseButton Fit; // LMB initiates fit when double clicked
ImGuiMouseButton Select; // RMB begins box selection when pressed and confirms selection when released
ImGuiMouseButton SelectCancel; // LMB cancels active box selection when pressed; cannot be same as Select
int SelectMod; // none optional modifier that must be held for box selection
int SelectHorzMod; // Alt expands active box selection horizontally to plot edge when held
int SelectVertMod; // Shift expands active box selection vertically to plot edge when held
ImGuiMouseButton Menu; // RMB opens context menus (if enabled) when clicked
int OverrideMod; // Ctrl when held, all input is ignored; used to enable axis/plots as DND sources
int ZoomMod; // none optional modifier that must be held for scroll wheel zooming
float ZoomRate; // 0.1f zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click); make negative to invert
IMPLOT_API ImPlotInputMap();
};
//-----------------------------------------------------------------------------
// [SECTION] Callbacks
//-----------------------------------------------------------------------------
// Callback signature for axis tick label formatter.
typedef int (*ImPlotFormatter)(double value, char* buff, int size, void* user_data);
// Callback signature for data getter.
typedef ImPlotPoint (*ImPlotGetter)(int idx, void* user_data);
// Callback signature for axis transform.
typedef double (*ImPlotTransform)(double value, void* user_data);
namespace ImPlot {
//-----------------------------------------------------------------------------
// [SECTION] Contexts
//-----------------------------------------------------------------------------
// Creates a new ImPlot context. Call this after ImGui::CreateContext.
IMPLOT_API ImPlotContext* CreateContext();
// Destroys an ImPlot context. Call this before ImGui::DestroyContext. nullptr = destroy current context.
IMPLOT_API void DestroyContext(ImPlotContext* ctx = nullptr);
// Returns the current ImPlot context. nullptr if no context has ben set.
IMPLOT_API ImPlotContext* GetCurrentContext();
// Sets the current ImPlot context.
IMPLOT_API void SetCurrentContext(ImPlotContext* ctx);
// Sets the current **ImGui** context. This is ONLY necessary if you are compiling
// ImPlot as a DLL (not recommended) separate from your ImGui compilation. It
// sets the global variable GImGui, which is not shared across DLL boundaries.
// See GImGui documentation in imgui.cpp for more details.
IMPLOT_API void SetImGuiContext(ImGuiContext* ctx);
//-----------------------------------------------------------------------------
// [SECTION] Begin/End Plot
//-----------------------------------------------------------------------------
// Starts a 2D plotting context. If this function returns true, EndPlot() MUST
// be called! You are encouraged to use the following convention:
//
// if (BeginPlot(...)) {
// PlotLine(...);
// ...
// EndPlot();
// }
//
// Important notes:
//
// - #title_id must be unique to the current ImGui ID scope. If you need to avoid ID
// collisions or don't want to display a title in the plot, use double hashes
// (e.g. "MyPlot##HiddenIdText" or "##NoTitle").
// - #size is the **frame** size of the plot widget, not the plot area. The default
// size of plots (i.e. when ImVec2(0,0)) can be modified in your ImPlotStyle.
IMPLOT_API bool BeginPlot(const char* title_id, const ImVec2& size=ImVec2(-1,0), ImPlotFlags flags=0);
// Only call EndPlot() if BeginPlot() returns true! Typically called at the end
// of an if statement conditioned on BeginPlot(). See example above.
IMPLOT_API void EndPlot();
//-----------------------------------------------------------------------------
// [SECTION] Begin/End Subplots
//-----------------------------------------------------------------------------
// Starts a subdivided plotting context. If the function returns true,
// EndSubplots() MUST be called! Call BeginPlot/EndPlot AT MOST [rows*cols]
// times in between the begining and end of the subplot context. Plots are
// added in row major order.
//
// Example:
//
// if (BeginSubplots("My Subplot",2,3,ImVec2(800,400)) {
// for (int i = 0; i < 6; ++i) {
// if (BeginPlot(...)) {
// ImPlot::PlotLine(...);
// ...
// EndPlot();
// }
// }
// EndSubplots();
// }
//
// Produces:
//
// [0] | [1] | [2]
// ----|-----|----
// [3] | [4] | [5]
//
// Important notes:
//
// - #title_id must be unique to the current ImGui ID scope. If you need to avoid ID
// collisions or don't want to display a title in the plot, use double hashes
// (e.g. "MySubplot##HiddenIdText" or "##NoTitle").
// - #rows and #cols must be greater than 0.
// - #size is the size of the entire grid of subplots, not the individual plots
// - #row_ratios and #col_ratios must have AT LEAST #rows and #cols elements,
// respectively. These are the sizes of the rows and columns expressed in ratios.
// If the user adjusts the dimensions, the arrays are updated with new ratios.
//
// Important notes regarding BeginPlot from inside of BeginSubplots:
//
// - The #title_id parameter of _BeginPlot_ (see above) does NOT have to be
// unique when called inside of a subplot context. Subplot IDs are hashed
// for your convenience so you don't have call PushID or generate unique title
// strings. Simply pass an empty string to BeginPlot unless you want to title
// each subplot.
// - The #size parameter of _BeginPlot_ (see above) is ignored when inside of a
// subplot context. The actual size of the subplot will be based on the
// #size value you pass to _BeginSubplots_ and #row/#col_ratios if provided.
IMPLOT_API bool BeginSubplots(const char* title_id,
int rows,
int cols,
const ImVec2& size,
ImPlotSubplotFlags flags = 0,
float* row_ratios = nullptr,
float* col_ratios = nullptr);
// Only call EndSubplots() if BeginSubplots() returns true! Typically called at the end
// of an if statement conditioned on BeginSublots(). See example above.
IMPLOT_API void EndSubplots();
//-----------------------------------------------------------------------------
// [SECTION] Setup
//-----------------------------------------------------------------------------
// The following API allows you to setup and customize various aspects of the
// current plot. The functions should be called immediately after BeginPlot
// and before any other API calls. Typical usage is as follows:
// if (BeginPlot(...)) { 1) begin a new plot
// SetupAxis(ImAxis_X1, "My X-Axis"); 2) make Setup calls
// SetupAxis(ImAxis_Y1, "My Y-Axis");
// SetupLegend(ImPlotLocation_North);
// ...
// SetupFinish(); 3) [optional] explicitly finish setup
// PlotLine(...); 4) plot items
// ...
// EndPlot(); 5) end the plot
// }
//
// Important notes:
//
// - Always call Setup code at the top of your BeginPlot conditional statement.
// - Setup is locked once you start plotting or explicitly call SetupFinish.
// Do NOT call Setup code after you begin plotting or after you make
// any non-Setup API calls (e.g. utils like PlotToPixels also lock Setup)
// - Calling SetupFinish is OPTIONAL, but probably good practice. If you do not
// call it yourself, then the first subsequent plotting or utility function will
// call it for you.
// Enables an axis or sets the label and/or flags for an existing axis. Leave #label = nullptr for no label.
IMPLOT_API void SetupAxis(ImAxis axis, const char* label=nullptr, ImPlotAxisFlags flags=0);
// Sets an axis range limits. If ImPlotCond_Always is used, the axes limits will be locked.
IMPLOT_API void SetupAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond = ImPlotCond_Once);
// Links an axis range limits to external values. Set to nullptr for no linkage. The pointer data must remain valid until EndPlot.
IMPLOT_API void SetupAxisLinks(ImAxis axis, double* link_min, double* link_max);
// Sets the format of numeric axis labels via formater specifier (default="%g"). Formated values will be double (i.e. use %f).
IMPLOT_API void SetupAxisFormat(ImAxis axis, const char* fmt);
// Sets the format of numeric axis labels via formatter callback. Given #value, write a label into #buff. Optionally pass user data.
IMPLOT_API void SetupAxisFormat(ImAxis axis, ImPlotFormatter formatter, void* data=nullptr);
// Sets an axis' ticks and optionally the labels. To keep the default ticks, set #keep_default=true.
IMPLOT_API void SetupAxisTicks(ImAxis axis, const double* values, int n_ticks, const char* const labels[]=nullptr, bool keep_default=false);
// Sets an axis' ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true.
IMPLOT_API void SetupAxisTicks(ImAxis axis, double v_min, double v_max, int n_ticks, const char* const labels[]=nullptr, bool keep_default=false);
// Sets an axis' scale using built-in options.
IMPLOT_API void SetupAxisScale(ImAxis axis, ImPlotScale scale);
// Sets an axis' scale using user supplied forward and inverse transfroms.
IMPLOT_API void SetupAxisScale(ImAxis axis, ImPlotTransform forward, ImPlotTransform inverse, void* data=nullptr);
// Sets an axis' limits constraints.
IMPLOT_API void SetupAxisLimitsConstraints(ImAxis axis, double v_min, double v_max);
// Sets an axis' zoom constraints.
IMPLOT_API void SetupAxisZoomConstraints(ImAxis axis, double z_min, double z_max);
// Sets the label and/or flags for primary X and Y axes (shorthand for two calls to SetupAxis).
IMPLOT_API void SetupAxes(const char* x_label, const char* y_label, ImPlotAxisFlags x_flags=0, ImPlotAxisFlags y_flags=0);
// Sets the primary X and Y axes range limits. If ImPlotCond_Always is used, the axes limits will be locked (shorthand for two calls to SetupAxisLimits).
IMPLOT_API void SetupAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond = ImPlotCond_Once);
// Sets up the plot legend.
IMPLOT_API void SetupLegend(ImPlotLocation location, ImPlotLegendFlags flags=0);
// Set the location of the current plot's mouse position text (default = South|East).
IMPLOT_API void SetupMouseText(ImPlotLocation location, ImPlotMouseTextFlags flags=0);
// Explicitly finalize plot setup. Once you call this, you cannot make anymore Setup calls for the current plot!
// Note that calling this function is OPTIONAL; it will be called by the first subsequent setup-locking API call.
IMPLOT_API void SetupFinish();
//-----------------------------------------------------------------------------
// [SECTION] SetNext
//-----------------------------------------------------------------------------
// Though you should default to the `Setup` API above, there are some scenarios
// where (re)configuring a plot or axis before `BeginPlot` is needed (e.g. if
// using a preceding button or slider widget to change the plot limits). In
// this case, you can use the `SetNext` API below. While this is not as feature
// rich as the Setup API, most common needs are provided. These functions can be
// called anwhere except for inside of `Begin/EndPlot`. For example:
// if (ImGui::Button("Center Plot"))
// ImPlot::SetNextPlotLimits(-1,1,-1,1);
// if (ImPlot::BeginPlot(...)) {
// ...
// ImPlot::EndPlot();
// }
//
// Important notes:
//
// - You must still enable non-default axes with SetupAxis for these functions
// to work properly.
// Sets an upcoming axis range limits. If ImPlotCond_Always is used, the axes limits will be locked.
IMPLOT_API void SetNextAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond = ImPlotCond_Once);
// Links an upcoming axis range limits to external values. Set to nullptr for no linkage. The pointer data must remain valid until EndPlot!
IMPLOT_API void SetNextAxisLinks(ImAxis axis, double* link_min, double* link_max);
// Set an upcoming axis to auto fit to its data.
IMPLOT_API void SetNextAxisToFit(ImAxis axis);
// Sets the upcoming primary X and Y axes range limits. If ImPlotCond_Always is used, the axes limits will be locked (shorthand for two calls to SetupAxisLimits).
IMPLOT_API void SetNextAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond = ImPlotCond_Once);
// Sets all upcoming axes to auto fit to their data.
IMPLOT_API void SetNextAxesToFit();
//-----------------------------------------------------------------------------
// [SECTION] Plot Items
//-----------------------------------------------------------------------------
// The main plotting API is provied below. Call these functions between
// Begin/EndPlot and after any Setup API calls. Each plots data on the current
// x and y axes, which can be changed with `SetAxis/Axes`.
//
// The templated functions are explicitly instantiated in implot_items.cpp.
// They are not intended to be used generically with custom types. You will get
// a linker error if you try! All functions support the following scalar types:
//
// float, double, ImS8, ImU8, ImS16, ImU16, ImS32, ImU32, ImS64, ImU64
//
//
// If you need to plot custom or non-homogenous data you have a few options:
//
// 1. If your data is a simple struct/class (e.g. Vector2f), you can use striding.
// This is the most performant option if applicable.
//
// struct Vector2f { float X, Y; };
// ...
// Vector2f data[42];
// ImPlot::PlotLine("line", &data[0].x, &data[0].y, 42, 0, 0, sizeof(Vector2f));
//
// 2. Write a custom getter C function or C++ lambda and pass it and optionally your data to
// an ImPlot function post-fixed with a G (e.g. PlotScatterG). This has a slight performance
// cost, but probably not enough to worry about unless your data is very large. Examples:
//
// ImPlotPoint MyDataGetter(void* data, int idx) {
// MyData* my_data = (MyData*)data;
// ImPlotPoint p;
// p.x = my_data->GetTime(idx);
// p.y = my_data->GetValue(idx);
// return p
// }
// ...
// auto my_lambda = [](int idx, void*) {
// double t = idx / 999.0;
// return ImPlotPoint(t, 0.5+0.5*std::sin(2*PI*10*t));
// };
// ...
// if (ImPlot::BeginPlot("MyPlot")) {
// MyData my_data;
// ImPlot::PlotScatterG("scatter", MyDataGetter, &my_data, my_data.Size());
// ImPlot::PlotLineG("line", my_lambda, nullptr, 1000);
// ImPlot::EndPlot();
// }
//
// NB: All types are converted to double before plotting. You may lose information
// if you try plotting extremely large 64-bit integral types. Proceed with caution!
// Plots a standard 2D line plot.
IMPLOT_TMP void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotLineFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotLineFlags flags=0);
// Plots a standard 2D scatter plot. Default marker is ImPlotMarker_Circle.
IMPLOT_TMP void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotScatterFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, ImPlotScatterFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotScatterFlags flags=0);
// Plots a a stairstep graph. The y value is continued constantly to the right from every x position, i.e. the interval [x[i], x[i+1]) has the value y[i]
IMPLOT_TMP void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotStairsFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, ImPlotStairsFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_API void PlotStairsG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotStairsFlags flags=0);
// Plots a shaded (filled) region between two lines, or a line and a horizontal reference. Set yref to +/-INFINITY for infinite fill extents.
IMPLOT_TMP void PlotShaded(const char* label_id, const T* values, int count, double yref=0, double xscale=1, double xstart=0, ImPlotShadedFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double yref=0, ImPlotShadedFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, ImPlotShadedFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_API void PlotShadedG(const char* label_id, ImPlotGetter getter1, void* data1, ImPlotGetter getter2, void* data2, int count, ImPlotShadedFlags flags=0);
// Plots a bar graph. Vertical by default. #bar_size and #shift are in plot units.
IMPLOT_TMP void PlotBars(const char* label_id, const T* values, int count, double bar_size=0.67, double shift=0, ImPlotBarsFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, ImPlotBarsFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_API void PlotBarsG(const char* label_id, ImPlotGetter getter, void* data, int count, double bar_size, ImPlotBarsFlags flags=0);
// Plots a group of bars. #values is a row-major matrix with #item_count rows and #group_count cols. #label_ids should have #item_count elements.
IMPLOT_TMP void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_size=0.67, double shift=0, ImPlotBarGroupsFlags flags=0);
// Plots vertical error bar. The label_id should be the same as the label_id of the associated line or bar plot.
IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, ImPlotErrorBarsFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, ImPlotErrorBarsFlags flags=0, int offset=0, int stride=sizeof(T));
// Plots stems. Vertical by default.
IMPLOT_TMP void PlotStems(const char* label_id, const T* values, int count, double ref=0, double scale=1, double start=0, ImPlotStemsFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_TMP void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref=0, ImPlotStemsFlags flags=0, int offset=0, int stride=sizeof(T));
// Plots infinite vertical or horizontal lines (e.g. for references or asymptotes).
IMPLOT_TMP void PlotInfLines(const char* label_id, const T* values, int count, ImPlotInfLinesFlags flags=0, int offset=0, int stride=sizeof(T));
// Plots a pie chart. Center and radius are in plot units. #label_fmt can be set to nullptr for no labels.
IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* label_fmt="%.1f", double angle0=90, ImPlotPieChartFlags flags=0);
// Plots a 2D heatmap chart. Values are expected to be in row-major order by default. Leave #scale_min and scale_max both at 0 for automatic color scaling, or set them to a predefined range. #label_fmt can be set to nullptr for no labels.
IMPLOT_TMP void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min=0, double scale_max=0, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1), ImPlotHeatmapFlags flags=0);
// Plots a horizontal histogram. #bins can be a positive integer or an ImPlotBin_ method. If #range is left unspecified, the min/max of #values will be used as the range.
// Otherwise, outlier values outside of the range are not binned. The largest bin count or density is returned.
IMPLOT_TMP double PlotHistogram(const char* label_id, const T* values, int count, int bins=ImPlotBin_Sturges, double bar_scale=1.0, ImPlotRange range=ImPlotRange(), ImPlotHistogramFlags flags=0);
// Plots two dimensional, bivariate histogram as a heatmap. #x_bins and #y_bins can be a positive integer or an ImPlotBin. If #range is left unspecified, the min/max of
// #xs an #ys will be used as the ranges. Otherwise, outlier values outside of range are not binned. The largest bin count or density is returned.
IMPLOT_TMP double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins=ImPlotBin_Sturges, int y_bins=ImPlotBin_Sturges, ImPlotRect range=ImPlotRect(), ImPlotHistogramFlags flags=0);
// Plots digital data. Digital plots do not respond to y drag or zoom, and are always referenced to the bottom of the plot.
IMPLOT_TMP void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, ImPlotDigitalFlags flags=0, int offset=0, int stride=sizeof(T));
IMPLOT_API void PlotDigitalG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotDigitalFlags flags=0);
// Plots an axis-aligned image. #bounds_min/bounds_max are in plot coordinates (y-up) and #uv0/uv1 are in texture coordinates (y-down).
IMPLOT_API void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImVec2& uv0=ImVec2(0,0), const ImVec2& uv1=ImVec2(1,1), const ImVec4& tint_col=ImVec4(1,1,1,1), ImPlotImageFlags flags=0);
// Plots a centered text label at point x,y with an optional pixel offset. Text color can be changed with ImPlot::PushStyleColor(ImPlotCol_InlayText, ...).
IMPLOT_API void PlotText(const char* text, double x, double y, const ImVec2& pix_offset=ImVec2(0,0), ImPlotTextFlags flags=0);
// Plots a dummy item (i.e. adds a legend entry colored by ImPlotCol_Line)
IMPLOT_API void PlotDummy(const char* label_id, ImPlotDummyFlags flags=0);
//-----------------------------------------------------------------------------
// [SECTION] Plot Tools
//-----------------------------------------------------------------------------
// The following can be used to render interactive elements and/or annotations.
// Like the item plotting functions above, they apply to the current x and y
// axes, which can be changed with `SetAxis/SetAxes`.
// Shows a draggable point at x,y. #col defaults to ImGuiCol_Text.
IMPLOT_API bool DragPoint(int id, double* x, double* y, const ImVec4& col, float size = 4, ImPlotDragToolFlags flags=0);
// Shows a draggable vertical guide line at an x-value. #col defaults to ImGuiCol_Text.
IMPLOT_API bool DragLineX(int id, double* x, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags=0);
// Shows a draggable horizontal guide line at a y-value. #col defaults to ImGuiCol_Text.
IMPLOT_API bool DragLineY(int id, double* y, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags=0);
// Shows a draggable and resizeable rectangle.
IMPLOT_API bool DragRect(int id, double* x1, double* y1, double* x2, double* y2, const ImVec4& col, ImPlotDragToolFlags flags=0);
// Shows an annotation callout at a chosen point. Clamping keeps annotations in the plot area. Annotations are always rendered on top.
IMPLOT_API void Annotation(double x, double y, const ImVec4& col, const ImVec2& pix_offset, bool clamp, bool round = false);
IMPLOT_API void Annotation(double x, double y, const ImVec4& col, const ImVec2& pix_offset, bool clamp, const char* fmt, ...) IM_FMTARGS(6);
IMPLOT_API void AnnotationV(double x, double y, const ImVec4& col, const ImVec2& pix_offset, bool clamp, const char* fmt, va_list args) IM_FMTLIST(6);
// Shows a x-axis tag at the specified coordinate value.
IMPLOT_API void TagX(double x, const ImVec4& col, bool round = false);
IMPLOT_API void TagX(double x, const ImVec4& col, const char* fmt, ...) IM_FMTARGS(3);
IMPLOT_API void TagXV(double x, const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(3);
// Shows a y-axis tag at the specified coordinate value.
IMPLOT_API void TagY(double y, const ImVec4& col, bool round = false);
IMPLOT_API void TagY(double y, const ImVec4& col, const char* fmt, ...) IM_FMTARGS(3);
IMPLOT_API void TagYV(double y, const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(3);
//-----------------------------------------------------------------------------
// [SECTION] Plot Utils
//-----------------------------------------------------------------------------
// Select which axis/axes will be used for subsequent plot elements.
IMPLOT_API void SetAxis(ImAxis axis);
IMPLOT_API void SetAxes(ImAxis x_axis, ImAxis y_axis);
// Convert pixels to a position in the current plot's coordinate system. Passing IMPLOT_AUTO uses the current axes.
IMPLOT_API ImPlotPoint PixelsToPlot(const ImVec2& pix, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
IMPLOT_API ImPlotPoint PixelsToPlot(float x, float y, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
// Convert a position in the current plot's coordinate system to pixels. Passing IMPLOT_AUTO uses the current axes.
IMPLOT_API ImVec2 PlotToPixels(const ImPlotPoint& plt, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
IMPLOT_API ImVec2 PlotToPixels(double x, double y, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
// Get the current Plot position (top-left) in pixels.
IMPLOT_API ImVec2 GetPlotPos();
// Get the curent Plot size in pixels.
IMPLOT_API ImVec2 GetPlotSize();
// Returns the mouse position in x,y coordinates of the current plot. Passing IMPLOT_AUTO uses the current axes.
IMPLOT_API ImPlotPoint GetPlotMousePos(ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
// Returns the current plot axis range.
IMPLOT_API ImPlotRect GetPlotLimits(ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
// Returns true if the plot area in the current plot is hovered.
IMPLOT_API bool IsPlotHovered();
// Returns true if the axis label area in the current plot is hovered.
IMPLOT_API bool IsAxisHovered(ImAxis axis);
// Returns true if the bounding frame of a subplot is hovered.
IMPLOT_API bool IsSubplotsHovered();
// Returns true if the current plot is being box selected.
IMPLOT_API bool IsPlotSelected();
// Returns the current plot box selection bounds. Passing IMPLOT_AUTO uses the current axes.
IMPLOT_API ImPlotRect GetPlotSelection(ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
// Cancels a the current plot box selection.
IMPLOT_API void CancelPlotSelection();
// Hides or shows the next plot item (i.e. as if it were toggled from the legend).
// Use ImPlotCond_Always if you need to forcefully set this every frame.
IMPLOT_API void HideNextItem(bool hidden = true, ImPlotCond cond = ImPlotCond_Once);
// Use the following around calls to Begin/EndPlot to align l/r/t/b padding.
// Consider using Begin/EndSubplots first. They are more feature rich and
// accomplish the same behaviour by default. The functions below offer lower
// level control of plot alignment.
// Align axis padding over multiple plots in a single row or column. #group_id must
// be unique. If this function returns true, EndAlignedPlots() must be called.
IMPLOT_API bool BeginAlignedPlots(const char* group_id, bool vertical = true);
// Only call EndAlignedPlots() if BeginAlignedPlots() returns true!
IMPLOT_API void EndAlignedPlots();
//-----------------------------------------------------------------------------
// [SECTION] Legend Utils
//-----------------------------------------------------------------------------
// Begin a popup for a legend entry.
IMPLOT_API bool BeginLegendPopup(const char* label_id, ImGuiMouseButton mouse_button=1);
// End a popup for a legend entry.
IMPLOT_API void EndLegendPopup();
// Returns true if a plot item legend entry is hovered.
IMPLOT_API bool IsLegendEntryHovered(const char* label_id);
//-----------------------------------------------------------------------------
// [SECTION] Drag and Drop
//-----------------------------------------------------------------------------
// Turns the current plot's plotting area into a drag and drop target. Don't forget to call EndDragDropTarget!
IMPLOT_API bool BeginDragDropTargetPlot();
// Turns the current plot's X-axis into a drag and drop target. Don't forget to call EndDragDropTarget!
IMPLOT_API bool BeginDragDropTargetAxis(ImAxis axis);
// Turns the current plot's legend into a drag and drop target. Don't forget to call EndDragDropTarget!
IMPLOT_API bool BeginDragDropTargetLegend();
// Ends a drag and drop target (currently just an alias for ImGui::EndDragDropTarget).
IMPLOT_API void EndDragDropTarget();
// NB: By default, plot and axes drag and drop *sources* require holding the Ctrl modifier to initiate the drag.
// You can change the modifier if desired. If ImGuiMod_None is provided, the axes will be locked from panning.
// Turns the current plot's plotting area into a drag and drop source. You must hold Ctrl. Don't forget to call EndDragDropSource!
IMPLOT_API bool BeginDragDropSourcePlot(ImGuiDragDropFlags flags=0);
// Turns the current plot's X-axis into a drag and drop source. You must hold Ctrl. Don't forget to call EndDragDropSource!
IMPLOT_API bool BeginDragDropSourceAxis(ImAxis axis, ImGuiDragDropFlags flags=0);
// Turns an item in the current plot's legend into drag and drop source. Don't forget to call EndDragDropSource!
IMPLOT_API bool BeginDragDropSourceItem(const char* label_id, ImGuiDragDropFlags flags=0);
// Ends a drag and drop source (currently just an alias for ImGui::EndDragDropSource).
IMPLOT_API void EndDragDropSource();
//-----------------------------------------------------------------------------
// [SECTION] Styling
//-----------------------------------------------------------------------------
// Styling colors in ImPlot works similarly to styling colors in ImGui, but
// with one important difference. Like ImGui, all style colors are stored in an
// indexable array in ImPlotStyle. You can permanently modify these values through
// GetStyle().Colors, or temporarily modify them with Push/Pop functions below.
// However, by default all style colors in ImPlot default to a special color
// IMPLOT_AUTO_COL. The behavior of this color depends upon the style color to
// which it as applied:
//
// 1) For style colors associated with plot items (e.g. ImPlotCol_Line),
// IMPLOT_AUTO_COL tells ImPlot to color the item with the next unused
// color in the current colormap. Thus, every item will have a different
// color up to the number of colors in the colormap, at which point the
// colormap will roll over. For most use cases, you should not need to
// set these style colors to anything but IMPLOT_COL_AUTO; you are
// probably better off changing the current colormap. However, if you
// need to explicitly color a particular item you may either Push/Pop
// the style color around the item in question, or use the SetNextXXXStyle
// API below. If you permanently set one of these style colors to a specific
// color, or forget to call Pop, then all subsequent items will be styled
// with the color you set.
//
// 2) For style colors associated with plot styling (e.g. ImPlotCol_PlotBg),
// IMPLOT_AUTO_COL tells ImPlot to set that color from color data in your
// **ImGuiStyle**. The ImGuiCol_ that these style colors default to are
// detailed above, and in general have been mapped to produce plots visually
// consistent with your current ImGui style. Of course, you are free to
// manually set these colors to whatever you like, and further can Push/Pop
// them around individual plots for plot-specific styling (e.g. coloring axes).
// Provides access to plot style structure for permanant modifications to colors, sizes, etc.
IMPLOT_API ImPlotStyle& GetStyle();
// Style plot colors for current ImGui style (default).
IMPLOT_API void StyleColorsAuto(ImPlotStyle* dst = nullptr);
// Style plot colors for ImGui "Classic".
IMPLOT_API void StyleColorsClassic(ImPlotStyle* dst = nullptr);
// Style plot colors for ImGui "Dark".
IMPLOT_API void StyleColorsDark(ImPlotStyle* dst = nullptr);
// Style plot colors for ImGui "Light".
IMPLOT_API void StyleColorsLight(ImPlotStyle* dst = nullptr);
// Use PushStyleX to temporarily modify your ImPlotStyle. The modification
// will last until the matching call to PopStyleX. You MUST call a pop for
// every push, otherwise you will leak memory! This behaves just like ImGui.
// Temporarily modify a style color. Don't forget to call PopStyleColor!
IMPLOT_API void PushStyleColor(ImPlotCol idx, ImU32 col);
IMPLOT_API void PushStyleColor(ImPlotCol idx, const ImVec4& col);
// Undo temporary style color modification(s). Undo multiple pushes at once by increasing count.
IMPLOT_API void PopStyleColor(int count = 1);
// Temporarily modify a style variable of float type. Don't forget to call PopStyleVar!
IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, float val);
// Temporarily modify a style variable of int type. Don't forget to call PopStyleVar!
IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, int val);
// Temporarily modify a style variable of ImVec2 type. Don't forget to call PopStyleVar!
IMPLOT_API void PushStyleVar(ImPlotStyleVar idx, const ImVec2& val);
// Undo temporary style variable modification(s). Undo multiple pushes at once by increasing count.
IMPLOT_API void PopStyleVar(int count = 1);
// The following can be used to modify the style of the next plot item ONLY. They do
// NOT require calls to PopStyleX. Leave style attributes you don't want modified to
// IMPLOT_AUTO or IMPLOT_AUTO_COL. Automatic styles will be deduced from the current
// values in your ImPlotStyle or from Colormap data.
// Set the line color and weight for the next item only.
IMPLOT_API void SetNextLineStyle(const ImVec4& col = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO);
// Set the fill color for the next item only.
IMPLOT_API void SetNextFillStyle(const ImVec4& col = IMPLOT_AUTO_COL, float alpha_mod = IMPLOT_AUTO);
// Set the marker style for the next item only.
IMPLOT_API void SetNextMarkerStyle(ImPlotMarker marker = IMPLOT_AUTO, float size = IMPLOT_AUTO, const ImVec4& fill = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO, const ImVec4& outline = IMPLOT_AUTO_COL);
// Set the error bar style for the next item only.
IMPLOT_API void SetNextErrorBarStyle(const ImVec4& col = IMPLOT_AUTO_COL, float size = IMPLOT_AUTO, float weight = IMPLOT_AUTO);
// Gets the last item primary color (i.e. its legend icon color)
IMPLOT_API ImVec4 GetLastItemColor();
// Returns the null terminated string name for an ImPlotCol.
IMPLOT_API const char* GetStyleColorName(ImPlotCol idx);
// Returns the null terminated string name for an ImPlotMarker.
IMPLOT_API const char* GetMarkerName(ImPlotMarker idx);
//-----------------------------------------------------------------------------
// [SECTION] Colormaps
//-----------------------------------------------------------------------------
// Item styling is based on colormaps when the relevant ImPlotCol_XXX is set to
// IMPLOT_AUTO_COL (default). Several built-in colormaps are available. You can
// add and then push/pop your own colormaps as well. To permanently set a colormap,
// modify the Colormap index member of your ImPlotStyle.
// Colormap data will be ignored and a custom color will be used if you have done one of the following:
// 1) Modified an item style color in your ImPlotStyle to anything other than IMPLOT_AUTO_COL.
// 2) Pushed an item style color using PushStyleColor().
// 3) Set the next item style with a SetNextXXXStyle function.
// Add a new colormap. The color data will be copied. The colormap can be used by pushing either the returned index or the
// string name with PushColormap. The colormap name must be unique and the size must be greater than 1. You will receive
// an assert otherwise! By default colormaps are considered to be qualitative (i.e. discrete). If you want to create a
// continuous colormap, set #qual=false. This will treat the colors you provide as keys, and ImPlot will build a linearly
// interpolated lookup table. The memory footprint of this table will be exactly ((size-1)*255+1)*4 bytes.
IMPLOT_API ImPlotColormap AddColormap(const char* name, const ImVec4* cols, int size, bool qual=true);
IMPLOT_API ImPlotColormap AddColormap(const char* name, const ImU32* cols, int size, bool qual=true);
// Returns the number of available colormaps (i.e. the built-in + user-added count).
IMPLOT_API int GetColormapCount();
// Returns a null terminated string name for a colormap given an index. Returns nullptr if index is invalid.
IMPLOT_API const char* GetColormapName(ImPlotColormap cmap);
// Returns an index number for a colormap given a valid string name. Returns -1 if name is invalid.
IMPLOT_API ImPlotColormap GetColormapIndex(const char* name);
// Temporarily switch to one of the built-in (i.e. ImPlotColormap_XXX) or user-added colormaps (i.e. a return value of AddColormap). Don't forget to call PopColormap!
IMPLOT_API void PushColormap(ImPlotColormap cmap);
// Push a colormap by string name. Use built-in names such as "Default", "Deep", "Jet", etc. or a string you provided to AddColormap. Don't forget to call PopColormap!
IMPLOT_API void PushColormap(const char* name);
// Undo temporary colormap modification(s). Undo multiple pushes at once by increasing count.
IMPLOT_API void PopColormap(int count = 1);
// Returns the next color from the current colormap and advances the colormap for the current plot.
// Can also be used with no return value to skip colors if desired. You need to call this between Begin/EndPlot!
IMPLOT_API ImVec4 NextColormapColor();
// Colormap utils. If cmap = IMPLOT_AUTO (default), the current colormap is assumed.
// Pass an explicit colormap index (built-in or user-added) to specify otherwise.
// Returns the size of a colormap.
IMPLOT_API int GetColormapSize(ImPlotColormap cmap = IMPLOT_AUTO);
// Returns a color from a colormap given an index >= 0 (modulo will be performed).
IMPLOT_API ImVec4 GetColormapColor(int idx, ImPlotColormap cmap = IMPLOT_AUTO);
// Sample a color from the current colormap given t between 0 and 1.
IMPLOT_API ImVec4 SampleColormap(float t, ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a vertical color scale with linear spaced ticks using the specified color map. Use double hashes to hide label (e.g. "##NoLabel"). If scale_min > scale_max, the scale to color mapping will be reversed.
IMPLOT_API void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0), const char* format = "%g", ImPlotColormapScaleFlags flags = 0, ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a horizontal slider with a colormap gradient background. Optionally returns the color sampled at t in [0 1].
IMPLOT_API bool ColormapSlider(const char* label, float* t, ImVec4* out = nullptr, const char* format = "", ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a button with a colormap gradient brackground.
IMPLOT_API bool ColormapButton(const char* label, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO);
// When items in a plot sample their color from a colormap, the color is cached and does not change
// unless explicitly overriden. Therefore, if you change the colormap after the item has already been plotted,
// item colors will NOT update. If you need item colors to resample the new colormap, then use this
// function to bust the cached colors. If #plot_title_id is nullptr, then every item in EVERY existing plot
// will be cache busted. Otherwise only the plot specified by #plot_title_id will be busted. For the
// latter, this function must be called in the same ImGui ID scope that the plot is in. You should rarely if ever
// need this function, but it is available for applications that require runtime colormap swaps (e.g. Heatmaps demo).
IMPLOT_API void BustColorCache(const char* plot_title_id = nullptr);
//-----------------------------------------------------------------------------
// [SECTION] Input Mapping
//-----------------------------------------------------------------------------
// Provides access to input mapping structure for permanant modifications to controls for pan, select, etc.
IMPLOT_API ImPlotInputMap& GetInputMap();
// Default input mapping: pan = LMB drag, box select = RMB drag, fit = LMB double click, context menu = RMB click, zoom = scroll.
IMPLOT_API void MapInputDefault(ImPlotInputMap* dst = nullptr);
// Reverse input mapping: pan = RMB drag, box select = LMB drag, fit = LMB double click, context menu = RMB click, zoom = scroll.
IMPLOT_API void MapInputReverse(ImPlotInputMap* dst = nullptr);
//-----------------------------------------------------------------------------
// [SECTION] Miscellaneous
//-----------------------------------------------------------------------------
// Render icons similar to those that appear in legends (nifty for data lists).
IMPLOT_API void ItemIcon(const ImVec4& col);
IMPLOT_API void ItemIcon(ImU32 col);
IMPLOT_API void ColormapIcon(ImPlotColormap cmap);
// Get the plot draw list for custom rendering to the current plot area. Call between Begin/EndPlot.
IMPLOT_API ImDrawList* GetPlotDrawList();
// Push clip rect for rendering to current plot area. The rect can be expanded or contracted by #expand pixels. Call between Begin/EndPlot.
IMPLOT_API void PushPlotClipRect(float expand=0);
// Pop plot clip rect. Call between Begin/EndPlot.
IMPLOT_API void PopPlotClipRect();
// Shows ImPlot style selector dropdown menu.
IMPLOT_API bool ShowStyleSelector(const char* label);
// Shows ImPlot colormap selector dropdown menu.
IMPLOT_API bool ShowColormapSelector(const char* label);
// Shows ImPlot input map selector dropdown menu.
IMPLOT_API bool ShowInputMapSelector(const char* label);
// Shows ImPlot style editor block (not a window).
IMPLOT_API void ShowStyleEditor(ImPlotStyle* ref = nullptr);
// Add basic help/info block for end users (not a window).
IMPLOT_API void ShowUserGuide();
// Shows ImPlot metrics/debug information window.
IMPLOT_API void ShowMetricsWindow(bool* p_popen = nullptr);
//-----------------------------------------------------------------------------
// [SECTION] Demo
//-----------------------------------------------------------------------------
// Shows the ImPlot demo window (add implot_demo.cpp to your sources!)
IMPLOT_API void ShowDemoWindow(bool* p_open = nullptr);
} // namespace ImPlot
//-----------------------------------------------------------------------------
// [SECTION] Obsolete API
//-----------------------------------------------------------------------------
// The following functions will be removed! Keep your copy of implot up to date!
// Occasionally set '#define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS' to stay ahead.
// If you absolutely must use these functions and do not want to receive compiler
// warnings, set '#define IMPLOT_DISABLE_OBSOLETE_WARNINGS'.
#ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#ifndef IMPLOT_DISABLE_DEPRECATED_WARNINGS
#if __cplusplus > 201402L
#define IMPLOT_DEPRECATED(method) [[deprecated]] method
#elif defined( __GNUC__ ) && !defined( __INTEL_COMPILER ) && ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) )
#define IMPLOT_DEPRECATED(method) method __attribute__( ( deprecated ) )
#elif defined( _MSC_VER )
#define IMPLOT_DEPRECATED(method) __declspec(deprecated) method
#else
#define IMPLOT_DEPRECATED(method) method
#endif
#else
#define IMPLOT_DEPRECATED(method) method
#endif
enum ImPlotFlagsObsolete_ {
ImPlotFlags_YAxis2 = 1 << 20,
ImPlotFlags_YAxis3 = 1 << 21,
};
namespace ImPlot {
// OBSOLETED in v0.13 -> PLANNED REMOVAL in v1.0
IMPLOT_DEPRECATED( IMPLOT_API bool BeginPlot(const char* title_id,
const char* x_label, // = nullptr,
const char* y_label, // = nullptr,
const ImVec2& size = ImVec2(-1,0),
ImPlotFlags flags = ImPlotFlags_None,
ImPlotAxisFlags x_flags = 0,
ImPlotAxisFlags y_flags = 0,
ImPlotAxisFlags y2_flags = ImPlotAxisFlags_AuxDefault,
ImPlotAxisFlags y3_flags = ImPlotAxisFlags_AuxDefault,
const char* y2_label = nullptr,
const char* y3_label = nullptr) );
} // namespace ImPlot
#endif
================================================
FILE: Source/External/imgui_tools/implot/implot_demo.cpp
================================================
// MIT License
// Copyright (c) 2022 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ImPlot v0.14
// We define this so that the demo does not accidentally use deprecated API
#ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#endif
#include "implot.h"
#include
#include
#include
#include
#ifdef _MSC_VER
#define sprintf sprintf_s
#endif
#ifndef PI
#define PI 3.14159265358979323846
#endif
#define CHECKBOX_FLAG(flags, flag) ImGui::CheckboxFlags(#flag, (unsigned int*)&flags, flag)
// Encapsulates examples for customizing ImPlot.
namespace MyImPlot {
// Example for Custom Data and Getters section.
struct Vector2f {
Vector2f(float _x, float _y) { x = _x; y = _y; }
float x, y;
};
// Example for Custom Data and Getters section.
struct WaveData {
double X, Amp, Freq, Offset;
WaveData(double x, double amp, double freq, double offset) { X = x; Amp = amp; Freq = freq; Offset = offset; }
};
ImPlotPoint SineWave(int idx, void* wave_data);
ImPlotPoint SawWave(int idx, void* wave_data);
ImPlotPoint Spiral(int idx, void* wave_data);
// Example for Tables section.
void Sparkline(const char* id, const float* values, int count, float min_v, float max_v, int offset, const ImVec4& col, const ImVec2& size);
// Example for Custom Plotters and Tooltips section.
void PlotCandlestick(const char* label_id, const double* xs, const double* opens, const double* closes, const double* lows, const double* highs, int count, bool tooltip = true, float width_percent = 0.25f, ImVec4 bullCol = ImVec4(0,1,0,1), ImVec4 bearCol = ImVec4(1,0,0,1));
// Example for Custom Styles section.
void StyleSeaborn();
} // namespace MyImPlot
namespace ImPlot {
template
inline T RandomRange(T min, T max) {
T scale = rand() / (T) RAND_MAX;
return min + scale * ( max - min );
}
ImVec4 RandomColor() {
ImVec4 col;
col.x = RandomRange(0.0f,1.0f);
col.y = RandomRange(0.0f,1.0f);
col.z = RandomRange(0.0f,1.0f);
col.w = 1.0f;
return col;
}
double RandomGauss() {
static double V1, V2, S;
static int phase = 0;
double X;
if(phase == 0) {
do {
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while(S >= 1 || S == 0);
X = V1 * sqrt(-2 * log(S) / S);
} else
X = V2 * sqrt(-2 * log(S) / S);
phase = 1 - phase;
return X;
}
template
struct NormalDistribution {
NormalDistribution(double mean, double sd) {
for (int i = 0; i < N; ++i)
Data[i] = RandomGauss()*sd + mean;
}
double Data[N];
};
// utility structure for realtime plot
struct ScrollingBuffer {
int MaxSize;
int Offset;
ImVector Data;
ScrollingBuffer(int max_size = 2000) {
MaxSize = max_size;
Offset = 0;
Data.reserve(MaxSize);
}
void AddPoint(float x, float y) {
if (Data.size() < MaxSize)
Data.push_back(ImVec2(x,y));
else {
Data[Offset] = ImVec2(x,y);
Offset = (Offset + 1) % MaxSize;
}
}
void Erase() {
if (Data.size() > 0) {
Data.shrink(0);
Offset = 0;
}
}
};
// utility structure for realtime plot
struct RollingBuffer {
float Span;
ImVector Data;
RollingBuffer() {
Span = 10.0f;
Data.reserve(2000);
}
void AddPoint(float x, float y) {
float xmod = fmodf(x, Span);
if (!Data.empty() && xmod < Data.back().x)
Data.shrink(0);
Data.push_back(ImVec2(xmod, y));
}
};
// Huge data used by Time Formatting example (~500 MB allocation!)
struct HugeTimeData {
HugeTimeData(double min) {
Ts = new double[Size];
Ys = new double[Size];
for (int i = 0; i < Size; ++i) {
Ts[i] = min + i;
Ys[i] = GetY(Ts[i]);
}
}
~HugeTimeData() { delete[] Ts; delete[] Ys; }
static double GetY(double t) {
return 0.5 + 0.25 * sin(t/86400/12) + 0.005 * sin(t/3600);
}
double* Ts;
double* Ys;
static const int Size = 60*60*24*366;
};
//-----------------------------------------------------------------------------
// [SECTION] Demo Functions
//-----------------------------------------------------------------------------
void Demo_Help() {
ImGui::Text("ABOUT THIS DEMO:");
ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
ImGui::BulletText("The \"Tools\" menu above gives access to: Style Editors (ImPlot/ImGui)\n"
"and Metrics (general purpose Dear ImGui debugging tool).");
ImGui::Separator();
ImGui::Text("PROGRAMMER GUIDE:");
ImGui::BulletText("See the ShowDemoWindow() code in implot_demo.cpp. <- you are here!");
ImGui::BulletText("If you see visual artifacts, do one of the following:");
ImGui::Indent();
ImGui::BulletText("Handle ImGuiBackendFlags_RendererHasVtxOffset for 16-bit indices in your backend.");
ImGui::BulletText("Or, enable 32-bit indices in imconfig.h.");
ImGui::BulletText("Your current configuration is:");
ImGui::Indent();
ImGui::BulletText("ImDrawIdx: %d-bit", (int)(sizeof(ImDrawIdx) * 8));
ImGui::BulletText("ImGuiBackendFlags_RendererHasVtxOffset: %s", (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ? "True" : "False");
ImGui::Unindent();
ImGui::Unindent();
ImGui::Separator();
ImGui::Text("USER GUIDE:");
ShowUserGuide();
}
//-----------------------------------------------------------------------------
void ButtonSelector(const char* label, ImGuiMouseButton* b) {
ImGui::PushID(label);
if (ImGui::RadioButton("LMB",*b == ImGuiMouseButton_Left))
*b = ImGuiMouseButton_Left;
ImGui::SameLine();
if (ImGui::RadioButton("RMB",*b == ImGuiMouseButton_Right))
*b = ImGuiMouseButton_Right;
ImGui::SameLine();
if (ImGui::RadioButton("MMB",*b == ImGuiMouseButton_Middle))
*b = ImGuiMouseButton_Middle;
ImGui::PopID();
}
void ModSelector(const char* label, int* k) {
ImGui::PushID(label);
ImGui::CheckboxFlags("Ctrl", (unsigned int*)k, ImGuiMod_Ctrl); ImGui::SameLine();
ImGui::CheckboxFlags("Shift", (unsigned int*)k, ImGuiMod_Shift); ImGui::SameLine();
ImGui::CheckboxFlags("Alt", (unsigned int*)k, ImGuiMod_Alt); ImGui::SameLine();
ImGui::CheckboxFlags("Super", (unsigned int*)k, ImGuiMod_Super);
ImGui::PopID();
}
void InputMapping(const char* label, ImGuiMouseButton* b, int* k) {
ImGui::LabelText("##","%s",label);
if (b != nullptr) {
ImGui::SameLine(100);
ButtonSelector(label,b);
}
if (k != nullptr) {
ImGui::SameLine(300);
ModSelector(label,k);
}
}
void ShowInputMapping() {
ImPlotInputMap& map = ImPlot::GetInputMap();
InputMapping("Pan",&map.Pan,&map.PanMod);
InputMapping("Fit",&map.Fit,nullptr);
InputMapping("Select",&map.Select,&map.SelectMod);
InputMapping("SelectHorzMod",nullptr,&map.SelectHorzMod);
InputMapping("SelectVertMod",nullptr,&map.SelectVertMod);
InputMapping("SelectCancel",&map.SelectCancel,nullptr);
InputMapping("Menu",&map.Menu,nullptr);
InputMapping("OverrideMod",nullptr,&map.OverrideMod);
InputMapping("ZoomMod",nullptr,&map.ZoomMod);
ImGui::SliderFloat("ZoomRate",&map.ZoomRate,-1,1);
}
void Demo_Config() {
ImGui::ShowFontSelector("Font");
ImGui::ShowStyleSelector("ImGui Style");
ImPlot::ShowStyleSelector("ImPlot Style");
ImPlot::ShowColormapSelector("ImPlot Colormap");
ImPlot::ShowInputMapSelector("Input Map");
ImGui::Separator();
ImGui::Checkbox("Use Local Time", &ImPlot::GetStyle().UseLocalTime);
ImGui::Checkbox("Use ISO 8601", &ImPlot::GetStyle().UseISO8601);
ImGui::Checkbox("Use 24 Hour Clock", &ImPlot::GetStyle().Use24HourClock);
ImGui::Separator();
if (ImPlot::BeginPlot("Preview")) {
static double now = (double)time(nullptr);
ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_Time);
ImPlot::SetupAxisLimits(ImAxis_X1, now, now + 24*3600);
for (int i = 0; i < 10; ++i) {
double x[2] = {now, now + 24*3600};
double y[2] = {0,i/9.0};
ImGui::PushID(i);
ImPlot::PlotLine("##Line",x,y,2);
ImGui::PopID();
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_LinePlots() {
static float xs1[1001], ys1[1001];
for (int i = 0; i < 1001; ++i) {
xs1[i] = i * 0.001f;
ys1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
}
static double xs2[20], ys2[20];
for (int i = 0; i < 20; ++i) {
xs2[i] = i * 1/19.0f;
ys2[i] = xs2[i] * xs2[i];
}
if (ImPlot::BeginPlot("Line Plots")) {
ImPlot::SetupAxes("x","y");
ImPlot::PlotLine("f(x)", xs1, ys1, 1001);
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
ImPlot::PlotLine("g(x)", xs2, ys2, 20,ImPlotLineFlags_Segments);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_FilledLinePlots() {
static double xs1[101], ys1[101], ys2[101], ys3[101];
srand(0);
for (int i = 0; i < 101; ++i) {
xs1[i] = (float)i;
ys1[i] = RandomRange(400.0,450.0);
ys2[i] = RandomRange(275.0,350.0);
ys3[i] = RandomRange(150.0,225.0);
}
static bool show_lines = true;
static bool show_fills = true;
static float fill_ref = 0;
static int shade_mode = 0;
static ImPlotShadedFlags flags = 0;
ImGui::Checkbox("Lines",&show_lines); ImGui::SameLine();
ImGui::Checkbox("Fills",&show_fills);
if (show_fills) {
ImGui::SameLine();
if (ImGui::RadioButton("To -INF",shade_mode == 0))
shade_mode = 0;
ImGui::SameLine();
if (ImGui::RadioButton("To +INF",shade_mode == 1))
shade_mode = 1;
ImGui::SameLine();
if (ImGui::RadioButton("To Ref",shade_mode == 2))
shade_mode = 2;
if (shade_mode == 2) {
ImGui::SameLine();
ImGui::SetNextItemWidth(100);
ImGui::DragFloat("##Ref",&fill_ref, 1, -100, 500);
}
}
if (ImPlot::BeginPlot("Stock Prices")) {
ImPlot::SetupAxes("Days","Price");
ImPlot::SetupAxesLimits(0,100,0,500);
if (show_fills) {
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
ImPlot::PlotShaded("Stock 1", xs1, ys1, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, flags);
ImPlot::PlotShaded("Stock 2", xs1, ys2, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, flags);
ImPlot::PlotShaded("Stock 3", xs1, ys3, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref, flags);
ImPlot::PopStyleVar();
}
if (show_lines) {
ImPlot::PlotLine("Stock 1", xs1, ys1, 101);
ImPlot::PlotLine("Stock 2", xs1, ys2, 101);
ImPlot::PlotLine("Stock 3", xs1, ys3, 101);
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_ShadedPlots() {
static float xs[1001], ys[1001], ys1[1001], ys2[1001], ys3[1001], ys4[1001];
srand(0);
for (int i = 0; i < 1001; ++i) {
xs[i] = i * 0.001f;
ys[i] = 0.25f + 0.25f * sinf(25 * xs[i]) * sinf(5 * xs[i]) + RandomRange(-0.01f, 0.01f);
ys1[i] = ys[i] + RandomRange(0.1f, 0.12f);
ys2[i] = ys[i] - RandomRange(0.1f, 0.12f);
ys3[i] = 0.75f + 0.2f * sinf(25 * xs[i]);
ys4[i] = 0.75f + 0.1f * cosf(25 * xs[i]);
}
static float alpha = 0.25f;
ImGui::DragFloat("Alpha",&alpha,0.01f,0,1);
if (ImPlot::BeginPlot("Shaded Plots")) {
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha);
ImPlot::PlotShaded("Uncertain Data",xs,ys1,ys2,1001);
ImPlot::PlotLine("Uncertain Data", xs, ys, 1001);
ImPlot::PlotShaded("Overlapping",xs,ys3,ys4,1001);
ImPlot::PlotLine("Overlapping",xs,ys3,1001);
ImPlot::PlotLine("Overlapping",xs,ys4,1001);
ImPlot::PopStyleVar();
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_ScatterPlots() {
srand(0);
static float xs1[100], ys1[100];
for (int i = 0; i < 100; ++i) {
xs1[i] = i * 0.01f;
ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
}
static float xs2[50], ys2[50];
for (int i = 0; i < 50; i++) {
xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX);
ys2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX);
}
if (ImPlot::BeginPlot("Scatter Plot")) {
ImPlot::PlotScatter("Data 1", xs1, ys1, 100);
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 6, ImPlot::GetColormapColor(1), IMPLOT_AUTO, ImPlot::GetColormapColor(1));
ImPlot::PlotScatter("Data 2", xs2, ys2, 50);
ImPlot::PopStyleVar();
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_StairstepPlots() {
static float ys1[21], ys2[21];
for (int i = 0; i < 21; ++i) {
ys1[i] = 0.75f + 0.2f * sinf(10 * i * 0.05f);
ys2[i] = 0.25f + 0.2f * sinf(10 * i * 0.05f);
}
static ImPlotStairsFlags flags = 0;
CHECKBOX_FLAG(flags, ImPlotStairsFlags_Shaded);
if (ImPlot::BeginPlot("Stairstep Plot")) {
ImPlot::SetupAxes("x","f(x)");
ImPlot::SetupAxesLimits(0,1,0,1);
ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(0.5f,0.5f,0.5f,1.0f));
ImPlot::PlotLine("##1",ys1,21,0.05f);
ImPlot::PlotLine("##2",ys2,21,0.05f);
ImPlot::PopStyleColor();
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f);
ImPlot::PlotStairs("Post Step (default)", ys1, 21, 0.05f, 0, flags);
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f);
ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, flags|ImPlotStairsFlags_PreStep);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_BarPlots() {
static ImS8 data[10] = {1,2,3,4,5,6,7,8,9,10};
if (ImPlot::BeginPlot("Bar Plot")) {
ImPlot::PlotBars("Vertical",data,10,0.7,1);
ImPlot::PlotBars("Horizontal",data,10,0.4,1,ImPlotBarsFlags_Horizontal);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_BarGroups() {
static ImS8 data[30] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90, // midterm
80, 62, 56, 99, 55, 78, 88, 78, 90, 100, // final
80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; // course
static const char* ilabels[] = {"Midterm Exam","Final Exam","Course Grade"};
static const char* glabels[] = {"S1","S2","S3","S4","S5","S6","S7","S8","S9","S10"};
static const double positions[] = {0,1,2,3,4,5,6,7,8,9};
static int items = 3;
static int groups = 10;
static float size = 0.67f;
static ImPlotBarGroupsFlags flags = 0;
static bool horz = false;
ImGui::CheckboxFlags("Stacked", (unsigned int*)&flags, ImPlotBarGroupsFlags_Stacked);
ImGui::SameLine();
ImGui::Checkbox("Horizontal",&horz);
ImGui::SliderInt("Items",&items,1,3);
ImGui::SliderFloat("Size",&size,0,1);
if (ImPlot::BeginPlot("Bar Group")) {
ImPlot::SetupLegend(ImPlotLocation_East, ImPlotLegendFlags_Outside);
if (horz) {
ImPlot::SetupAxes("Score","Student",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit);
ImPlot::SetupAxisTicks(ImAxis_Y1,positions, groups, glabels);
ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,flags|ImPlotBarGroupsFlags_Horizontal);
}
else {
ImPlot::SetupAxes("Student","Score",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit);
ImPlot::SetupAxisTicks(ImAxis_X1,positions, groups, glabels);
ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,flags);
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_BarStacks() {
static ImPlotColormap Liars = -1;
if (Liars == -1) {
static const ImU32 Liars_Data[6] = { 4282515870, 4282609140, 4287357182, 4294630301, 4294945280, 4294921472 };
Liars = ImPlot::AddColormap("Liars", Liars_Data, 6);
}
static bool diverging = true;
ImGui::Checkbox("Diverging",&diverging);
static const char* politicians[] = {"Trump","Bachman","Cruz","Gingrich","Palin","Santorum","Walker","Perry","Ryan","McCain","Rubio","Romney","Rand Paul","Christie","Biden","Kasich","Sanders","J Bush","H Clinton","Obama"};
static int data_reg[] = {18,26,7,14,10,8,6,11,4,4,3,8,6,8,6,5,0,3,1,2, // Pants on Fire
43,36,30,21,30,27,25,17,11,22,15,16,16,17,12,12,14,6,13,12, // False
16,13,28,22,15,21,15,18,30,17,24,18,13,10,14,15,17,22,14,12, // Mostly False
17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True
5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True
1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True
static const char* labels_reg[] = {"Pants on Fire","False","Mostly False","Half True","Mostly True","True"};
static int data_div[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Pants on Fire (dummy, to order legend logically)
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // False (dummy, to order legend logically)
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Mostly False (dummy, to order legend logically)
-16,-13,-28,-22,-15,-21,-15,-18,-30,-17,-24,-18,-13,-10,-14,-15,-17,-22,-14,-12, // Mostly False
-43,-36,-30,-21,-30,-27,-25,-17,-11,-22,-15,-16,-16,-17,-12,-12,-14,-6,-13,-12, // False
-18,-26,-7,-14,-10,-8,-6,-11,-4,-4,-3,-8,-6,-8,-6,-5,0,-3,-1,-2, // Pants on Fire
17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True
5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True
1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True
static const char* labels_div[] = {"Pants on Fire","False","Mostly False","Mostly False","False","Pants on Fire","Half True","Mostly True","True"};
ImPlot::PushColormap(Liars);
if (ImPlot::BeginPlot("PolitiFact: Who Lies More?",ImVec2(-1,400),ImPlotFlags_NoMouseText)) {
ImPlot::SetupLegend(ImPlotLocation_South, ImPlotLegendFlags_Outside|ImPlotLegendFlags_Horizontal);
ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_Invert);
ImPlot::SetupAxisTicks(ImAxis_Y1,0,19,20,politicians,false);
if (diverging)
ImPlot::PlotBarGroups(labels_div,data_div,9,20,0.75,0,ImPlotBarGroupsFlags_Stacked|ImPlotBarGroupsFlags_Horizontal);
else
ImPlot::PlotBarGroups(labels_reg,data_reg,6,20,0.75,0,ImPlotBarGroupsFlags_Stacked|ImPlotBarGroupsFlags_Horizontal);
ImPlot::EndPlot();
}
ImPlot::PopColormap();
}
//-----------------------------------------------------------------------------
void Demo_ErrorBars() {
static float xs[5] = {1,2,3,4,5};
static float bar[5] = {1,2,5,3,4};
static float lin1[5] = {8,8,9,7,8};
static float lin2[5] = {6,7,6,9,6};
static float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f};
static float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f};
static float err3[5] = {0.09f, 0.14f, 0.09f, 0.12f, 0.16f};
static float err4[5] = {0.02f, 0.08f, 0.15f, 0.05f, 0.2f};
if (ImPlot::BeginPlot("##ErrorBars")) {
ImPlot::SetupAxesLimits(0, 6, 0, 10);
ImPlot::PlotBars("Bar", xs, bar, 5, 0.5f);
ImPlot::PlotErrorBars("Bar", xs, bar, err1, 5);
ImPlot::SetNextErrorBarStyle(ImPlot::GetColormapColor(1), 0);
ImPlot::PlotErrorBars("Line", xs, lin1, err1, err2, 5);
ImPlot::SetNextMarkerStyle(ImPlotMarker_Square);
ImPlot::PlotLine("Line", xs, lin1, 5);
ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImPlot::GetColormapColor(2));
ImPlot::PlotErrorBars("Scatter", xs, lin2, err2, 5);
ImPlot::PlotErrorBars("Scatter", xs, lin2, err3, err4, 5, ImPlotErrorBarsFlags_Horizontal);
ImPlot::PopStyleColor();
ImPlot::PlotScatter("Scatter", xs, lin2, 5);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_StemPlots() {
static double xs[51], ys1[51], ys2[51];
for (int i = 0; i < 51; ++i) {
xs[i] = i * 0.02;
ys1[i] = 1.0 + 0.5 * sin(25*xs[i])*cos(2*xs[i]);
ys2[i] = 0.5 + 0.25 * sin(10*xs[i]) * sin(xs[i]);
}
if (ImPlot::BeginPlot("Stem Plots")) {
ImPlot::SetupAxisLimits(ImAxis_X1,0,1.0);
ImPlot::SetupAxisLimits(ImAxis_Y1,0,1.6);
ImPlot::PlotStems("Stems 1",xs,ys1,51);
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
ImPlot::PlotStems("Stems 2", xs, ys2,51);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_InfiniteLines() {
static double vals[] = {0.25, 0.5, 0.75};
if (ImPlot::BeginPlot("##Infinite")) {
ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoInitialFit,ImPlotAxisFlags_NoInitialFit);
ImPlot::PlotInfLines("Vertical",vals,3);
ImPlot::PlotInfLines("Horizontal",vals,3,ImPlotInfLinesFlags_Horizontal);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_PieCharts() {
static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"};
static float data1[] = {0.15f, 0.30f, 0.2f, 0.05f};
static ImPlotPieChartFlags flags = 0;
ImGui::SetNextItemWidth(250);
ImGui::DragFloat4("Values", data1, 0.01f, 0, 1);
if ((data1[0] + data1[1] + data1[2] + data1[3]) < 1) {
ImGui::SameLine();
CHECKBOX_FLAG(flags,ImPlotPieChartFlags_Normalize);
}
if (ImPlot::BeginPlot("##Pie1", ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) {
ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
ImPlot::SetupAxesLimits(0, 1, 0, 1);
ImPlot::PlotPieChart(labels1, data1, 4, 0.5, 0.5, 0.4, "%.2f", 90, flags);
ImPlot::EndPlot();
}
ImGui::SameLine();
static const char* labels2[] = {"A","B","C","D","E"};
static int data2[] = {1,1,2,3,5};
ImPlot::PushColormap(ImPlotColormap_Pastel);
if (ImPlot::BeginPlot("##Pie2", ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) {
ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
ImPlot::SetupAxesLimits(0, 1, 0, 1);
ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, "%.0f", 180, flags);
ImPlot::EndPlot();
}
ImPlot::PopColormap();
}
//-----------------------------------------------------------------------------
void Demo_Heatmaps() {
static float values1[7][7] = {{0.8f, 2.4f, 2.5f, 3.9f, 0.0f, 4.0f, 0.0f},
{2.4f, 0.0f, 4.0f, 1.0f, 2.7f, 0.0f, 0.0f},
{1.1f, 2.4f, 0.8f, 4.3f, 1.9f, 4.4f, 0.0f},
{0.6f, 0.0f, 0.3f, 0.0f, 3.1f, 0.0f, 0.0f},
{0.7f, 1.7f, 0.6f, 2.6f, 2.2f, 6.2f, 0.0f},
{1.3f, 1.2f, 0.0f, 0.0f, 0.0f, 3.2f, 5.1f},
{0.1f, 2.0f, 0.0f, 1.4f, 0.0f, 1.9f, 6.3f}};
static float scale_min = 0;
static float scale_max = 6.3f;
static const char* xlabels[] = {"C1","C2","C3","C4","C5","C6","C7"};
static const char* ylabels[] = {"R1","R2","R3","R4","R5","R6","R7"};
static ImPlotColormap map = ImPlotColormap_Viridis;
if (ImPlot::ColormapButton(ImPlot::GetColormapName(map),ImVec2(225,0),map)) {
map = (map + 1) % ImPlot::GetColormapCount();
// We bust the color cache of our plots so that item colors will
// resample the new colormap in the event that they have already
// been created. See documentation in implot.h.
BustColorCache("##Heatmap1");
BustColorCache("##Heatmap2");
}
ImGui::SameLine();
ImGui::LabelText("##Colormap Index", "%s", "Change Colormap");
ImGui::SetNextItemWidth(225);
ImGui::DragFloatRange2("Min / Max",&scale_min, &scale_max, 0.01f, -20, 20);
static ImPlotHeatmapFlags hm_flags = 0;
ImGui::CheckboxFlags("Column Major", (unsigned int*)&hm_flags, ImPlotHeatmapFlags_ColMajor);
static ImPlotAxisFlags axes_flags = ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks;
ImPlot::PushColormap(map);
if (ImPlot::BeginPlot("##Heatmap1",ImVec2(225,225),ImPlotFlags_NoLegend|ImPlotFlags_NoMouseText)) {
ImPlot::SetupAxes(nullptr, nullptr, axes_flags, axes_flags);
ImPlot::SetupAxisTicks(ImAxis_X1,0 + 1.0/14.0, 1 - 1.0/14.0, 7, xlabels);
ImPlot::SetupAxisTicks(ImAxis_Y1,1 - 1.0/14.0, 0 + 1.0/14.0, 7, ylabels);
ImPlot::PlotHeatmap("heat",values1[0],7,7,scale_min,scale_max,"%g",ImPlotPoint(0,0),ImPlotPoint(1,1),hm_flags);
ImPlot::EndPlot();
}
ImGui::SameLine();
ImPlot::ColormapScale("##HeatScale",scale_min, scale_max, ImVec2(60,225));
ImGui::SameLine();
const int size = 80;
static double values2[size*size];
srand((unsigned int)(ImGui::GetTime()*1000000));
for (int i = 0; i < size*size; ++i)
values2[i] = RandomRange(0.0,1.0);
if (ImPlot::BeginPlot("##Heatmap2",ImVec2(225,225))) {
ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
ImPlot::SetupAxesLimits(-1,1,-1,1);
ImPlot::PlotHeatmap("heat1",values2,size,size,0,1,nullptr);
ImPlot::PlotHeatmap("heat2",values2,size,size,0,1,nullptr, ImPlotPoint(-1,-1), ImPlotPoint(0,0));
ImPlot::EndPlot();
}
ImPlot::PopColormap();
}
//-----------------------------------------------------------------------------
void Demo_Histogram() {
static ImPlotHistogramFlags hist_flags = ImPlotHistogramFlags_Density;
static int bins = 50;
static double mu = 5;
static double sigma = 2;
ImGui::SetNextItemWidth(200);
if (ImGui::RadioButton("Sqrt",bins==ImPlotBin_Sqrt)) { bins = ImPlotBin_Sqrt; } ImGui::SameLine();
if (ImGui::RadioButton("Sturges",bins==ImPlotBin_Sturges)) { bins = ImPlotBin_Sturges; } ImGui::SameLine();
if (ImGui::RadioButton("Rice",bins==ImPlotBin_Rice)) { bins = ImPlotBin_Rice; } ImGui::SameLine();
if (ImGui::RadioButton("Scott",bins==ImPlotBin_Scott)) { bins = ImPlotBin_Scott; } ImGui::SameLine();
if (ImGui::RadioButton("N Bins",bins>=0)) { bins = 50; }
if (bins>=0) {
ImGui::SameLine();
ImGui::SetNextItemWidth(200);
ImGui::SliderInt("##Bins", &bins, 1, 100);
}
ImGui::CheckboxFlags("Horizontal", (unsigned int*)&hist_flags, ImPlotHistogramFlags_Horizontal);
ImGui::SameLine();
ImGui::CheckboxFlags("Density", (unsigned int*)&hist_flags, ImPlotHistogramFlags_Density);
ImGui::SameLine();
ImGui::CheckboxFlags("Cumulative", (unsigned int*)&hist_flags, ImPlotHistogramFlags_Cumulative);
static bool range = false;
ImGui::Checkbox("Range", &range);
static float rmin = -3;
static float rmax = 13;
if (range) {
ImGui::SameLine();
ImGui::SetNextItemWidth(200);
ImGui::DragFloat2("##Range",&rmin,0.1f,-3,13);
ImGui::SameLine();
ImGui::CheckboxFlags("Exclude Outliers", (unsigned int*)&hist_flags, ImPlotHistogramFlags_NoOutliers);
}
static NormalDistribution<10000> dist(mu, sigma);
static double x[100];
static double y[100];
if (hist_flags & ImPlotHistogramFlags_Density) {
for (int i = 0; i < 100; ++i) {
x[i] = -3 + 16 * (double)i/99.0;
y[i] = exp( - (x[i]-mu)*(x[i]-mu) / (2*sigma*sigma)) / (sigma * sqrt(2*3.141592653589793238));
}
if (hist_flags & ImPlotHistogramFlags_Cumulative) {
for (int i = 1; i < 100; ++i)
y[i] += y[i-1];
for (int i = 0; i < 100; ++i)
y[i] /= y[99];
}
}
if (ImPlot::BeginPlot("##Histograms")) {
ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit);
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL,0.5f);
ImPlot::PlotHistogram("Empirical", dist.Data, 10000, bins, 1.0, range ? ImPlotRange(rmin,rmax) : ImPlotRange(), hist_flags);
if ((hist_flags & ImPlotHistogramFlags_Density) && !(hist_flags & ImPlotHistogramFlags_NoOutliers)) {
if (hist_flags & ImPlotHistogramFlags_Horizontal)
ImPlot::PlotLine("Theoretical",y,x,100);
else
ImPlot::PlotLine("Theoretical",x,y,100);
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_Histogram2D() {
static int count = 50000;
static int xybins[2] = {100,100};
static ImPlotHistogramFlags hist_flags = 0;
ImGui::SliderInt("Count",&count,100,100000);
ImGui::SliderInt2("Bins",xybins,1,500);
ImGui::SameLine();
ImGui::CheckboxFlags("Density", (unsigned int*)&hist_flags, ImPlotHistogramFlags_Density);
static NormalDistribution<100000> dist1(1, 2);
static NormalDistribution<100000> dist2(1, 1);
double max_count = 0;
ImPlotAxisFlags flags = ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_Foreground;
ImPlot::PushColormap("Hot");
if (ImPlot::BeginPlot("##Hist2D",ImVec2(ImGui::GetContentRegionAvail().x-100-ImGui::GetStyle().ItemSpacing.x,0))) {
ImPlot::SetupAxes(nullptr, nullptr, flags, flags);
ImPlot::SetupAxesLimits(-6,6,-6,6);
max_count = ImPlot::PlotHistogram2D("Hist2D",dist1.Data,dist2.Data,count,xybins[0],xybins[1],ImPlotRect(-6,6,-6,6), hist_flags);
ImPlot::EndPlot();
}
ImGui::SameLine();
ImPlot::ColormapScale(hist_flags & ImPlotHistogramFlags_Density ? "Density" : "Count",0,max_count,ImVec2(100,0));
ImPlot::PopColormap();
}
//-----------------------------------------------------------------------------
void Demo_DigitalPlots() {
ImGui::BulletText("Digital plots do not respond to Y drag and zoom, so that");
ImGui::Indent();
ImGui::Text("you can drag analog plots over the rising/falling digital edge.");
ImGui::Unindent();
static bool paused = false;
static ScrollingBuffer dataDigital[2];
static ScrollingBuffer dataAnalog[2];
static bool showDigital[2] = {true, false};
static bool showAnalog[2] = {true, false};
char label[32];
ImGui::Checkbox("digital_0", &showDigital[0]); ImGui::SameLine();
ImGui::Checkbox("digital_1", &showDigital[1]); ImGui::SameLine();
ImGui::Checkbox("analog_0", &showAnalog[0]); ImGui::SameLine();
ImGui::Checkbox("analog_1", &showAnalog[1]);
static float t = 0;
if (!paused) {
t += ImGui::GetIO().DeltaTime;
//digital signal values
if (showDigital[0])
dataDigital[0].AddPoint(t, sinf(2*t) > 0.45);
if (showDigital[1])
dataDigital[1].AddPoint(t, sinf(2*t) < 0.45);
//Analog signal values
if (showAnalog[0])
dataAnalog[0].AddPoint(t, sinf(2*t));
if (showAnalog[1])
dataAnalog[1].AddPoint(t, cosf(2*t));
}
if (ImPlot::BeginPlot("##Digital")) {
ImPlot::SetupAxisLimits(ImAxis_X1, t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
ImPlot::SetupAxisLimits(ImAxis_Y1, -1, 1);
for (int i = 0; i < 2; ++i) {
if (showDigital[i] && dataDigital[i].Data.size() > 0) {
snprintf(label, sizeof(label), "digital_%d", i);
ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), 0, dataDigital[i].Offset, 2 * sizeof(float));
}
}
for (int i = 0; i < 2; ++i) {
if (showAnalog[i]) {
snprintf(label, sizeof(label), "analog_%d", i);
if (dataAnalog[i].Data.size() > 0)
ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), 0, dataAnalog[i].Offset, 2 * sizeof(float));
}
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_Images() {
ImGui::BulletText("Below we are displaying the font texture, which is the only texture we have\naccess to in this demo.");
ImGui::BulletText("Use the 'ImTextureID' type as storage to pass pointers or identifiers to your\nown texture data.");
ImGui::BulletText("See ImGui Wiki page 'Image Loading and Displaying Examples'.");
static ImVec2 bmin(0,0);
static ImVec2 bmax(1,1);
static ImVec2 uv0(0,0);
static ImVec2 uv1(1,1);
static ImVec4 tint(1,1,1,1);
ImGui::SliderFloat2("Min", &bmin.x, -2, 2, "%.1f");
ImGui::SliderFloat2("Max", &bmax.x, -2, 2, "%.1f");
ImGui::SliderFloat2("UV0", &uv0.x, -2, 2, "%.1f");
ImGui::SliderFloat2("UV1", &uv1.x, -2, 2, "%.1f");
ImGui::ColorEdit4("Tint",&tint.x);
if (ImPlot::BeginPlot("##image")) {
ImPlot::PlotImage("my image",ImGui::GetIO().Fonts->TexID, bmin, bmax, uv0, uv1, tint);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_RealtimePlots() {
ImGui::BulletText("Move your mouse to change the data!");
ImGui::BulletText("This example assumes 60 FPS. Higher FPS requires larger buffer size.");
static ScrollingBuffer sdata1, sdata2;
static RollingBuffer rdata1, rdata2;
ImVec2 mouse = ImGui::GetMousePos();
static float t = 0;
t += ImGui::GetIO().DeltaTime;
sdata1.AddPoint(t, mouse.x * 0.0005f);
rdata1.AddPoint(t, mouse.x * 0.0005f);
sdata2.AddPoint(t, mouse.y * 0.0005f);
rdata2.AddPoint(t, mouse.y * 0.0005f);
static float history = 10.0f;
ImGui::SliderFloat("History",&history,1,30,"%.1f s");
rdata1.Span = history;
rdata2.Span = history;
static ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels;
if (ImPlot::BeginPlot("##Scrolling", ImVec2(-1,150))) {
ImPlot::SetupAxes(nullptr, nullptr, flags, flags);
ImPlot::SetupAxisLimits(ImAxis_X1,t - history, t, ImGuiCond_Always);
ImPlot::SetupAxisLimits(ImAxis_Y1,0,1);
ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL,0.5f);
ImPlot::PlotShaded("Mouse X", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), -INFINITY, 0, sdata1.Offset, 2 * sizeof(float));
ImPlot::PlotLine("Mouse Y", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), 0, sdata2.Offset, 2*sizeof(float));
ImPlot::EndPlot();
}
if (ImPlot::BeginPlot("##Rolling", ImVec2(-1,150))) {
ImPlot::SetupAxes(nullptr, nullptr, flags, flags);
ImPlot::SetupAxisLimits(ImAxis_X1,0,history, ImGuiCond_Always);
ImPlot::SetupAxisLimits(ImAxis_Y1,0,1);
ImPlot::PlotLine("Mouse X", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 0, 2 * sizeof(float));
ImPlot::PlotLine("Mouse Y", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 0, 2 * sizeof(float));
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_MarkersAndText() {
static float mk_size = ImPlot::GetStyle().MarkerSize;
static float mk_weight = ImPlot::GetStyle().MarkerWeight;
ImGui::DragFloat("Marker Size",&mk_size,0.1f,2.0f,10.0f,"%.2f px");
ImGui::DragFloat("Marker Weight", &mk_weight,0.05f,0.5f,3.0f,"%.2f px");
if (ImPlot::BeginPlot("##MarkerStyles", ImVec2(-1,0), ImPlotFlags_CanvasOnly)) {
ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
ImPlot::SetupAxesLimits(0, 10, 0, 12);
ImS8 xs[2] = {1,4};
ImS8 ys[2] = {10,11};
// filled markers
for (int m = 0; m < ImPlotMarker_COUNT; ++m) {
ImGui::PushID(m);
ImPlot::SetNextMarkerStyle(m, mk_size, IMPLOT_AUTO_COL, mk_weight);
ImPlot::PlotLine("##Filled", xs, ys, 2);
ImGui::PopID();
ys[0]--; ys[1]--;
}
xs[0] = 6; xs[1] = 9; ys[0] = 10; ys[1] = 11;
// open markers
for (int m = 0; m < ImPlotMarker_COUNT; ++m) {
ImGui::PushID(m);
ImPlot::SetNextMarkerStyle(m, mk_size, ImVec4(0,0,0,0), mk_weight);
ImPlot::PlotLine("##Open", xs, ys, 2);
ImGui::PopID();
ys[0]--; ys[1]--;
}
ImPlot::PlotText("Filled Markers", 2.5f, 6.0f);
ImPlot::PlotText("Open Markers", 7.5f, 6.0f);
ImPlot::PushStyleColor(ImPlotCol_InlayText, ImVec4(1,0,1,1));
ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, ImVec2(0,0), ImPlotTextFlags_Vertical);
ImPlot::PopStyleColor();
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_NaNValues() {
static bool include_nan = true;
static ImPlotLineFlags flags = 0;
float data1[5] = {0.0f,0.25f,0.5f,0.75f,1.0f};
float data2[5] = {0.0f,0.25f,0.5f,0.75f,1.0f};
if (include_nan)
data1[2] = NAN;
ImGui::Checkbox("Include NaN",&include_nan);
ImGui::SameLine();
ImGui::CheckboxFlags("Skip NaN", (unsigned int*)&flags, ImPlotLineFlags_SkipNaN);
if (ImPlot::BeginPlot("##NaNValues")) {
ImPlot::SetNextMarkerStyle(ImPlotMarker_Square);
ImPlot::PlotLine("line", data1, data2, 5, flags);
ImPlot::PlotBars("bars", data1, 5);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_LogScale() {
static double xs[1001], ys1[1001], ys2[1001], ys3[1001];
for (int i = 0; i < 1001; ++i) {
xs[i] = i*0.1f;
ys1[i] = sin(xs[i]) + 1;
ys2[i] = log(xs[i]);
ys3[i] = pow(10.0, xs[i]);
}
if (ImPlot::BeginPlot("Log Plot", ImVec2(-1,0))) {
ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_Log10);
ImPlot::SetupAxesLimits(0.1, 100, 0, 10);
ImPlot::PlotLine("f(x) = x", xs, xs, 1001);
ImPlot::PlotLine("f(x) = sin(x)+1", xs, ys1, 1001);
ImPlot::PlotLine("f(x) = log(x)", xs, ys2, 1001);
ImPlot::PlotLine("f(x) = 10^x", xs, ys3, 21);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_SymmetricLogScale() {
static double xs[1001], ys1[1001], ys2[1001];
for (int i = 0; i < 1001; ++i) {
xs[i] = i*0.1f-50;
ys1[i] = sin(xs[i]);
ys2[i] = i*0.002 - 1;
}
if (ImPlot::BeginPlot("SymLog Plot", ImVec2(-1,0))) {
ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_SymLog);
ImPlot::PlotLine("f(x) = a*x+b",xs,ys2,1001);
ImPlot::PlotLine("f(x) = sin(x)",xs,ys1,1001);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_TimeScale() {
static double t_min = 1609459200; // 01/01/2021 @ 12:00:00am (UTC)
static double t_max = 1640995200; // 01/01/2022 @ 12:00:00am (UTC)
ImGui::BulletText("When ImPlotAxisFlags_Time is enabled on the X-Axis, values are interpreted as\n"
"UNIX timestamps in seconds and axis labels are formated as date/time.");
ImGui::BulletText("By default, labels are in UTC time but can be set to use local time instead.");
ImGui::Checkbox("Local Time",&ImPlot::GetStyle().UseLocalTime);
ImGui::SameLine();
ImGui::Checkbox("ISO 8601",&ImPlot::GetStyle().UseISO8601);
ImGui::SameLine();
ImGui::Checkbox("24 Hour Clock",&ImPlot::GetStyle().Use24HourClock);
static HugeTimeData* data = nullptr;
if (data == nullptr) {
ImGui::SameLine();
if (ImGui::Button("Generate Huge Data (~500MB!)")) {
static HugeTimeData sdata(t_min);
data = &sdata;
}
}
if (ImPlot::BeginPlot("##Time", ImVec2(-1,0))) {
ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_Time);
ImPlot::SetupAxesLimits(t_min,t_max,0,1);
if (data != nullptr) {
// downsample our data
int downsample = (int)ImPlot::GetPlotLimits().X.Size() / 1000 + 1;
int start = (int)(ImPlot::GetPlotLimits().X.Min - t_min);
start = start < 0 ? 0 : start > HugeTimeData::Size - 1 ? HugeTimeData::Size - 1 : start;
int end = (int)(ImPlot::GetPlotLimits().X.Max - t_min) + 1000;
end = end < 0 ? 0 : end > HugeTimeData::Size - 1 ? HugeTimeData::Size - 1 : end;
int size = (end - start)/downsample;
// plot it
ImPlot::PlotLine("Time Series", &data->Ts[start], &data->Ys[start], size, 0, 0, sizeof(double)*downsample);
}
// plot time now
double t_now = (double)time(nullptr);
double y_now = HugeTimeData::GetY(t_now);
ImPlot::PlotScatter("Now",&t_now,&y_now,1);
ImPlot::Annotation(t_now,y_now,ImPlot::GetLastItemColor(),ImVec2(10,10),false,"Now");
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
static inline double TransformForward_Sqrt(double v, void*) {
return sqrt(v);
}
static inline double TransformInverse_Sqrt(double v, void*) {
return v*v;
}
void Demo_CustomScale() {
static float v[100];
for (int i = 0; i < 100; ++i) {
v[i] = i*0.01f;
}
if (ImPlot::BeginPlot("Sqrt")) {
ImPlot::SetupAxis(ImAxis_X1, "Linear");
ImPlot::SetupAxis(ImAxis_Y1, "Sqrt");
ImPlot::SetupAxisScale(ImAxis_Y1, TransformForward_Sqrt, TransformInverse_Sqrt);
ImPlot::SetupAxisLimitsConstraints(ImAxis_Y1, 0, INFINITY);
ImPlot::PlotLine("##data",v,v,100);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_MultipleAxes() {
static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001];
for (int i = 0; i < 1001; ++i) {
xs[i] = (i*0.1f);
xs2[i] = xs[i] + 10.0f;
ys1[i] = sinf(xs[i]) * 3 + 1;
ys2[i] = cosf(xs[i]) * 0.2f + 0.5f;
ys3[i] = sinf(xs[i]+0.5f) * 100 + 200;
}
static bool x2_axis = true;
static bool y2_axis = true;
static bool y3_axis = true;
ImGui::Checkbox("X-Axis 2", &x2_axis);
ImGui::SameLine();
ImGui::Checkbox("Y-Axis 2", &y2_axis);
ImGui::SameLine();
ImGui::Checkbox("Y-Axis 3", &y3_axis);
ImGui::BulletText("You can drag axes to the opposite side of the plot.");
ImGui::BulletText("Hover over legend items to see which axis they are plotted on.");
if (ImPlot::BeginPlot("Multi-Axis Plot", ImVec2(-1,0))) {
ImPlot::SetupAxes("X-Axis 1", "Y-Axis 1");
ImPlot::SetupAxesLimits(0, 100, 0, 10);
if (x2_axis) {
ImPlot::SetupAxis(ImAxis_X2, "X-Axis 2",ImPlotAxisFlags_AuxDefault);
ImPlot::SetupAxisLimits(ImAxis_X2, 0, 100);
}
if (y2_axis) {
ImPlot::SetupAxis(ImAxis_Y2, "Y-Axis 2",ImPlotAxisFlags_AuxDefault);
ImPlot::SetupAxisLimits(ImAxis_Y2, 0, 1);
}
if (y3_axis) {
ImPlot::SetupAxis(ImAxis_Y3, "Y-Axis 3",ImPlotAxisFlags_AuxDefault);
ImPlot::SetupAxisLimits(ImAxis_Y3, 0, 300);
}
ImPlot::PlotLine("f(x) = x", xs, xs, 1001);
if (x2_axis) {
ImPlot::SetAxes(ImAxis_X2, ImAxis_Y1);
ImPlot::PlotLine("f(x) = sin(x)*3+1", xs2, ys1, 1001);
}
if (y2_axis) {
ImPlot::SetAxes(ImAxis_X1, ImAxis_Y2);
ImPlot::PlotLine("f(x) = cos(x)*.2+.5", xs, ys2, 1001);
}
if (y3_axis) {
ImPlot::SetAxes(ImAxis_X2, ImAxis_Y3);
ImPlot::PlotLine("f(x) = sin(x+.5)*100+200 ", xs2, ys3, 1001);
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_LinkedAxes() {
static ImPlotRect lims(0,1,0,1);
static bool linkx = true, linky = true;
int data[2] = {0,1};
ImGui::Checkbox("Link X", &linkx);
ImGui::SameLine();
ImGui::Checkbox("Link Y", &linky);
ImGui::DragScalarN("Limits",ImGuiDataType_Double,&lims.X.Min,4,0.01f);
if (BeginAlignedPlots("AlignedGroup")) {
if (ImPlot::BeginPlot("Plot A")) {
ImPlot::SetupAxisLinks(ImAxis_X1, linkx ? &lims.X.Min : nullptr, linkx ? &lims.X.Max : nullptr);
ImPlot::SetupAxisLinks(ImAxis_Y1, linky ? &lims.Y.Min : nullptr, linky ? &lims.Y.Max : nullptr);
ImPlot::PlotLine("Line",data,2);
ImPlot::EndPlot();
}
if (ImPlot::BeginPlot("Plot B")) {
ImPlot::SetupAxisLinks(ImAxis_X1, linkx ? &lims.X.Min : nullptr, linkx ? &lims.X.Max : nullptr);
ImPlot::SetupAxisLinks(ImAxis_Y1, linky ? &lims.Y.Min : nullptr, linky ? &lims.Y.Max : nullptr);
ImPlot::PlotLine("Line",data,2);
ImPlot::EndPlot();
}
ImPlot::EndAlignedPlots();
}
}
//-----------------------------------------------------------------------------
void Demo_AxisConstraints() {
static float constraints[4] = {-10,10,1,20};
static ImPlotAxisFlags flags;
ImGui::DragFloat2("Limits Constraints", &constraints[0], 0.01f);
ImGui::DragFloat2("Zoom Constraints", &constraints[2], 0.01f);
CHECKBOX_FLAG(flags, ImPlotAxisFlags_PanStretch);
if (ImPlot::BeginPlot("##AxisConstraints",ImVec2(-1,0))) {
ImPlot::SetupAxes("X","Y",flags,flags);
ImPlot::SetupAxesLimits(-1,1,-1,1);
ImPlot::SetupAxisLimitsConstraints(ImAxis_X1,constraints[0], constraints[1]);
ImPlot::SetupAxisZoomConstraints(ImAxis_X1,constraints[2], constraints[3]);
ImPlot::SetupAxisLimitsConstraints(ImAxis_Y1,constraints[0], constraints[1]);
ImPlot::SetupAxisZoomConstraints(ImAxis_Y1,constraints[2], constraints[3]);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_EqualAxes() {
ImGui::BulletText("Equal constraint applies to axis pairs (e.g ImAxis_X1/Y1, ImAxis_X2/Y2)");
static double xs1[360], ys1[360];
for (int i = 0; i < 360; ++i) {
double angle = i * 2 * PI / 359.0;
xs1[i] = cos(angle); ys1[i] = sin(angle);
}
float xs2[] = {-1,0,1,0,-1};
float ys2[] = {0,1,0,-1,0};
if (ImPlot::BeginPlot("##EqualAxes",ImVec2(-1,0),ImPlotFlags_Equal)) {
ImPlot::SetupAxis(ImAxis_X2, nullptr, ImPlotAxisFlags_AuxDefault);
ImPlot::SetupAxis(ImAxis_Y2, nullptr, ImPlotAxisFlags_AuxDefault);
ImPlot::PlotLine("Circle",xs1,ys1,360);
ImPlot::SetAxes(ImAxis_X2, ImAxis_Y2);
ImPlot::PlotLine("Diamond",xs2,ys2,5);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_AutoFittingData() {
ImGui::BulletText("The Y-axis has been configured to auto-fit to only the data visible in X-axis range.");
ImGui::BulletText("Zoom and pan the X-axis. Disable Stems to see a difference in fit.");
ImGui::BulletText("If ImPlotAxisFlags_RangeFit is disabled, the axis will fit ALL data.");
static ImPlotAxisFlags xflags = ImPlotAxisFlags_None;
static ImPlotAxisFlags yflags = ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_RangeFit;
ImGui::TextUnformatted("X: "); ImGui::SameLine();
ImGui::CheckboxFlags("ImPlotAxisFlags_AutoFit##X", (unsigned int*)&xflags, ImPlotAxisFlags_AutoFit); ImGui::SameLine();
ImGui::CheckboxFlags("ImPlotAxisFlags_RangeFit##X", (unsigned int*)&xflags, ImPlotAxisFlags_RangeFit);
ImGui::TextUnformatted("Y: "); ImGui::SameLine();
ImGui::CheckboxFlags("ImPlotAxisFlags_AutoFit##Y", (unsigned int*)&yflags, ImPlotAxisFlags_AutoFit); ImGui::SameLine();
ImGui::CheckboxFlags("ImPlotAxisFlags_RangeFit##Y", (unsigned int*)&yflags, ImPlotAxisFlags_RangeFit);
static double data[101];
srand(0);
for (int i = 0; i < 101; ++i)
data[i] = 1 + sin(i/10.0f);
if (ImPlot::BeginPlot("##DataFitting")) {
ImPlot::SetupAxes("X","Y",xflags,yflags);
ImPlot::PlotLine("Line",data,101);
ImPlot::PlotStems("Stems",data,101);
ImPlot::EndPlot();
};
}
//-----------------------------------------------------------------------------
ImPlotPoint SinewaveGetter(int i, void* data) {
float f = *(float*)data;
return ImPlotPoint(i,sinf(f*i));
}
void Demo_SubplotsSizing() {
static ImPlotSubplotFlags flags = ImPlotSubplotFlags_None;
ImGui::CheckboxFlags("ImPlotSubplotFlags_NoResize", (unsigned int*)&flags, ImPlotSubplotFlags_NoResize);
ImGui::CheckboxFlags("ImPlotSubplotFlags_NoTitle", (unsigned int*)&flags, ImPlotSubplotFlags_NoTitle);
static int rows = 3;
static int cols = 3;
ImGui::SliderInt("Rows",&rows,1,5);
ImGui::SliderInt("Cols",&cols,1,5);
static float rratios[] = {5,1,1,1,1,1};
static float cratios[] = {5,1,1,1,1,1};
ImGui::DragScalarN("Row Ratios",ImGuiDataType_Float,rratios,rows,0.01f,nullptr);
ImGui::DragScalarN("Col Ratios",ImGuiDataType_Float,cratios,cols,0.01f,nullptr);
if (ImPlot::BeginSubplots("My Subplots", rows, cols, ImVec2(-1,400), flags, rratios, cratios)) {
for (int i = 0; i < rows*cols; ++i) {
if (ImPlot::BeginPlot("",ImVec2(),ImPlotFlags_NoLegend)) {
ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations);
float fi = 0.01f * (i+1);
ImPlot::SetNextLineStyle(SampleColormap((float)i/(float)(rows*cols-1),ImPlotColormap_Jet));
ImPlot::PlotLineG("data",SinewaveGetter,&fi,1000);
ImPlot::EndPlot();
}
}
ImPlot::EndSubplots();
}
}
//-----------------------------------------------------------------------------
void Demo_SubplotItemSharing() {
static ImPlotSubplotFlags flags = ImPlotSubplotFlags_ShareItems;
ImGui::CheckboxFlags("ImPlotSubplotFlags_ShareItems", (unsigned int*)&flags, ImPlotSubplotFlags_ShareItems);
ImGui::CheckboxFlags("ImPlotSubplotFlags_ColMajor", (unsigned int*)&flags, ImPlotSubplotFlags_ColMajor);
ImGui::BulletText("Drag and drop items from the legend onto plots (except for 'common')");
static int rows = 2;
static int cols = 3;
static int id[] = {0,1,2,3,4,5};
static int curj = -1;
if (ImPlot::BeginSubplots("##ItemSharing", rows, cols, ImVec2(-1,400), flags)) {
for (int i = 0; i < rows*cols; ++i) {
if (ImPlot::BeginPlot("")) {
float fc = 0.01f;
ImPlot::PlotLineG("common",SinewaveGetter,&fc,1000);
for (int j = 0; j < 6; ++j) {
if (id[j] == i) {
char label[8];
float fj = 0.01f * (j+2);
snprintf(label, sizeof(label), "data%d", j);
ImPlot::PlotLineG(label,SinewaveGetter,&fj,1000);
if (ImPlot::BeginDragDropSourceItem(label)) {
curj = j;
ImGui::SetDragDropPayload("MY_DND",nullptr,0);
ImPlot::ItemIcon(GetLastItemColor()); ImGui::SameLine();
ImGui::TextUnformatted(label);
ImPlot::EndDragDropSource();
}
}
}
if (ImPlot::BeginDragDropTargetPlot()) {
if (ImGui::AcceptDragDropPayload("MY_DND"))
id[curj] = i;
ImPlot::EndDragDropTarget();
}
ImPlot::EndPlot();
}
}
ImPlot::EndSubplots();
}
}
//-----------------------------------------------------------------------------
void Demo_SubplotAxisLinking() {
static ImPlotSubplotFlags flags = ImPlotSubplotFlags_LinkRows | ImPlotSubplotFlags_LinkCols;
ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkRows", (unsigned int*)&flags, ImPlotSubplotFlags_LinkRows);
ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkCols", (unsigned int*)&flags, ImPlotSubplotFlags_LinkCols);
ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkAllX", (unsigned int*)&flags, ImPlotSubplotFlags_LinkAllX);
ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkAllY", (unsigned int*)&flags, ImPlotSubplotFlags_LinkAllY);
static int rows = 2;
static int cols = 2;
if (ImPlot::BeginSubplots("##AxisLinking", rows, cols, ImVec2(-1,400), flags)) {
for (int i = 0; i < rows*cols; ++i) {
if (ImPlot::BeginPlot("")) {
ImPlot::SetupAxesLimits(0,1000,-1,1);
float fc = 0.01f;
ImPlot::PlotLineG("common",SinewaveGetter,&fc,1000);
ImPlot::EndPlot();
}
}
ImPlot::EndSubplots();
}
}
//-----------------------------------------------------------------------------
void Demo_LegendOptions() {
static ImPlotLocation loc = ImPlotLocation_East;
ImGui::CheckboxFlags("North", (unsigned int*)&loc, ImPlotLocation_North); ImGui::SameLine();
ImGui::CheckboxFlags("South", (unsigned int*)&loc, ImPlotLocation_South); ImGui::SameLine();
ImGui::CheckboxFlags("West", (unsigned int*)&loc, ImPlotLocation_West); ImGui::SameLine();
ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlotLocation_East);
static ImPlotLegendFlags flags = 0;
CHECKBOX_FLAG(flags, ImPlotLegendFlags_Horizontal);
CHECKBOX_FLAG(flags, ImPlotLegendFlags_Outside);
CHECKBOX_FLAG(flags, ImPlotLegendFlags_Sort);
ImGui::SliderFloat2("LegendPadding", (float*)&GetStyle().LegendPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LegendInnerPadding", (float*)&GetStyle().LegendInnerPadding, 0.0f, 10.0f, "%.0f");
ImGui::SliderFloat2("LegendSpacing", (float*)&GetStyle().LegendSpacing, 0.0f, 5.0f, "%.0f");
if (ImPlot::BeginPlot("##Legend",ImVec2(-1,0))) {
ImPlot::SetupLegend(loc, flags);
static MyImPlot::WaveData data1(0.001, 0.2, 4, 0.2);
static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.4);
static MyImPlot::WaveData data3(0.001, 0.2, 4, 0.6);
static MyImPlot::WaveData data4(0.001, 0.2, 4, 0.8);
static MyImPlot::WaveData data5(0.001, 0.2, 4, 1.0);
ImPlot::PlotLineG("Item B", MyImPlot::SawWave, &data1, 1000); // "Item B" added to legend
ImPlot::PlotLineG("Item A##IDText", MyImPlot::SawWave, &data2, 1000); // "Item A" added to legend, text after ## used for ID only
ImPlot::PlotLineG("##NotListed", MyImPlot::SawWave, &data3, 1000); // plotted, but not added to legend
ImPlot::PlotLineG("Item C", MyImPlot::SawWave, &data4, 1000); // "Item C" added to legend
ImPlot::PlotLineG("Item C", MyImPlot::SawWave, &data5, 1000); // combined with previous "Item C"
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_DragPoints() {
ImGui::BulletText("Click and drag each point.");
static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None;
ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine();
ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine();
ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs);
ImPlotAxisFlags ax_flags = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoTickMarks;
if (ImPlot::BeginPlot("##Bezier",ImVec2(-1,0),ImPlotFlags_CanvasOnly)) {
ImPlot::SetupAxes(nullptr,nullptr,ax_flags,ax_flags);
ImPlot::SetupAxesLimits(0,1,0,1);
static ImPlotPoint P[] = {ImPlotPoint(.05f,.05f), ImPlotPoint(0.2,0.4), ImPlotPoint(0.8,0.6), ImPlotPoint(.95f,.95f)};
ImPlot::DragPoint(0,&P[0].x,&P[0].y, ImVec4(0,0.9f,0,1),4,flags);
ImPlot::DragPoint(1,&P[1].x,&P[1].y, ImVec4(1,0.5f,1,1),4,flags);
ImPlot::DragPoint(2,&P[2].x,&P[2].y, ImVec4(0,0.5f,1,1),4,flags);
ImPlot::DragPoint(3,&P[3].x,&P[3].y, ImVec4(0,0.9f,0,1),4,flags);
static ImPlotPoint B[100];
for (int i = 0; i < 100; ++i) {
double t = i / 99.0;
double u = 1 - t;
double w1 = u*u*u;
double w2 = 3*u*u*t;
double w3 = 3*u*t*t;
double w4 = t*t*t;
B[i] = ImPlotPoint(w1*P[0].x + w2*P[1].x + w3*P[2].x + w4*P[3].x, w1*P[0].y + w2*P[1].y + w3*P[2].y + w4*P[3].y);
}
ImPlot::SetNextLineStyle(ImVec4(1,0.5f,1,1));
ImPlot::PlotLine("##h1",&P[0].x, &P[0].y, 2, 0, 0, sizeof(ImPlotPoint));
ImPlot::SetNextLineStyle(ImVec4(0,0.5f,1,1));
ImPlot::PlotLine("##h2",&P[2].x, &P[2].y, 2, 0, 0, sizeof(ImPlotPoint));
ImPlot::SetNextLineStyle(ImVec4(0,0.9f,0,1), 2);
ImPlot::PlotLine("##bez",&B[0].x, &B[0].y, 100, 0, 0, sizeof(ImPlotPoint));
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_DragLines() {
ImGui::BulletText("Click and drag the horizontal and vertical lines.");
static double x1 = 0.2;
static double x2 = 0.8;
static double y1 = 0.25;
static double y2 = 0.75;
static double f = 0.1;
static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None;
ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine();
ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine();
ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs);
if (ImPlot::BeginPlot("##lines",ImVec2(-1,0))) {
ImPlot::SetupAxesLimits(0,1,0,1);
ImPlot::DragLineX(0,&x1,ImVec4(1,1,1,1),1,flags);
ImPlot::DragLineX(1,&x2,ImVec4(1,1,1,1),1,flags);
ImPlot::DragLineY(2,&y1,ImVec4(1,1,1,1),1,flags);
ImPlot::DragLineY(3,&y2,ImVec4(1,1,1,1),1,flags);
double xs[1000], ys[1000];
for (int i = 0; i < 1000; ++i) {
xs[i] = (x2+x1)/2+fabs(x2-x1)*(i/1000.0f - 0.5f);
ys[i] = (y1+y2)/2+fabs(y2-y1)/2*sin(f*i/10);
}
ImPlot::PlotLine("Interactive Data", xs, ys, 1000);
ImPlot::DragLineY(120482,&f,ImVec4(1,0.5f,1,1),1,flags);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_DragRects() {
static float x_data[512];
static float y_data1[512];
static float y_data2[512];
static float y_data3[512];
static float sampling_freq = 44100;
static float freq = 500;
for (size_t i = 0; i < 512; ++i) {
const float t = i / sampling_freq;
x_data[i] = t;
const float arg = 2 * 3.14f * freq * t;
y_data1[i] = sinf(arg);
y_data2[i] = y_data1[i] * -0.6f + sinf(2 * arg) * 0.4f;
y_data3[i] = y_data2[i] * -0.6f + sinf(3 * arg) * 0.4f;
}
ImGui::BulletText("Click and drag the edges, corners, and center of the rect.");
static ImPlotRect rect(0.0025,0.0045,0,0.5);
static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None;
ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine();
ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine();
ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs);
if (ImPlot::BeginPlot("##Main",ImVec2(-1,150))) {
ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoTickLabels,ImPlotAxisFlags_NoTickLabels);
ImPlot::SetupAxesLimits(0,0.01,-1,1);
ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
ImPlot::PlotLine("Signal 3", x_data, y_data3, 512);
ImPlot::DragRect(0,&rect.X.Min,&rect.Y.Min,&rect.X.Max,&rect.Y.Max,ImVec4(1,0,1,1),flags);
ImPlot::EndPlot();
}
if (ImPlot::BeginPlot("##rect",ImVec2(-1,150), ImPlotFlags_CanvasOnly)) {
ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations);
ImPlot::SetupAxesLimits(rect.X.Min, rect.X.Max, rect.Y.Min, rect.Y.Max, ImGuiCond_Always);
ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
ImPlot::PlotLine("Signal 3", x_data, y_data3, 512);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
ImPlotPoint FindCentroid(const ImVector& data, const ImPlotRect& bounds, int& cnt) {
cnt = 0;
ImPlotPoint avg;
ImPlotRect bounds_fixed;
bounds_fixed.X.Min = bounds.X.Min < bounds.X.Max ? bounds.X.Min : bounds.X.Max;
bounds_fixed.X.Max = bounds.X.Min < bounds.X.Max ? bounds.X.Max : bounds.X.Min;
bounds_fixed.Y.Min = bounds.Y.Min < bounds.Y.Max ? bounds.Y.Min : bounds.Y.Max;
bounds_fixed.Y.Max = bounds.Y.Min < bounds.Y.Max ? bounds.Y.Max : bounds.Y.Min;
for (int i = 0; i < data.size(); ++i) {
if (bounds_fixed.Contains(data[i].x, data[i].y)) {
avg.x += data[i].x;
avg.y += data[i].y;
cnt++;
}
}
if (cnt > 0) {
avg.x = avg.x / cnt;
avg.y = avg.y / cnt;
}
return avg;
}
//-----------------------------------------------------------------------------
void Demo_Querying() {
static ImVector data;
static ImVector rects;
static ImPlotRect limits, select;
static bool init = true;
if (init) {
for (int i = 0; i < 50; ++i)
{
double x = RandomRange(0.1, 0.9);
double y = RandomRange(0.1, 0.9);
data.push_back(ImPlotPoint(x,y));
}
init = false;
}
ImGui::BulletText("Box select and left click mouse to create a new query rect.");
ImGui::BulletText("Ctrl + click in the plot area to draw points.");
if (ImGui::Button("Clear Queries"))
rects.shrink(0);
if (ImPlot::BeginPlot("##Centroid")) {
ImPlot::SetupAxesLimits(0,1,0,1);
if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) {
ImPlotPoint pt = ImPlot::GetPlotMousePos();
data.push_back(pt);
}
ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 0, 2 * sizeof(double));
if (ImPlot::IsPlotSelected()) {
select = ImPlot::GetPlotSelection();
int cnt;
ImPlotPoint centroid = FindCentroid(data,select,cnt);
if (cnt > 0) {
ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,6);
ImPlot::PlotScatter("Centroid", ¢roid.x, ¢roid.y, 1);
}
if (ImGui::IsMouseClicked(ImPlot::GetInputMap().SelectCancel)) {
CancelPlotSelection();
rects.push_back(select);
}
}
for (int i = 0; i < rects.size(); ++i) {
int cnt;
ImPlotPoint centroid = FindCentroid(data,rects[i],cnt);
if (cnt > 0) {
ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,6);
ImPlot::PlotScatter("Centroid", ¢roid.x, ¢roid.y, 1);
}
ImPlot::DragRect(i,&rects[i].X.Min,&rects[i].Y.Min,&rects[i].X.Max,&rects[i].Y.Max,ImVec4(1,0,1,1));
}
limits = ImPlot::GetPlotLimits();
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_Annotations() {
static bool clamp = false;
ImGui::Checkbox("Clamp",&clamp);
if (ImPlot::BeginPlot("##Annotations")) {
ImPlot::SetupAxesLimits(0,2,0,1);
static float p[] = {0.25f, 0.25f, 0.75f, 0.75f, 0.25f};
ImPlot::PlotScatter("##Points",&p[0],&p[1],4);
ImVec4 col = GetLastItemColor();
ImPlot::Annotation(0.25,0.25,col,ImVec2(-15,15),clamp,"BL");
ImPlot::Annotation(0.75,0.25,col,ImVec2(15,15),clamp,"BR");
ImPlot::Annotation(0.75,0.75,col,ImVec2(15,-15),clamp,"TR");
ImPlot::Annotation(0.25,0.75,col,ImVec2(-15,-15),clamp,"TL");
ImPlot::Annotation(0.5,0.5,col,ImVec2(0,0),clamp,"Center");
ImPlot::Annotation(1.25,0.75,ImVec4(0,1,0,1),ImVec2(0,0),clamp);
float bx[] = {1.2f,1.5f,1.8f};
float by[] = {0.25f, 0.5f, 0.75f};
ImPlot::PlotBars("##Bars",bx,by,3,0.2);
for (int i = 0; i < 3; ++i)
ImPlot::Annotation(bx[i],by[i],ImVec4(0,0,0,0),ImVec2(0,-5),clamp,"B[%d]=%.2f",i,by[i]);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_Tags() {
static bool show = true;
ImGui::Checkbox("Show Tags",&show);
if (ImPlot::BeginPlot("##Tags")) {
ImPlot::SetupAxis(ImAxis_X2);
ImPlot::SetupAxis(ImAxis_Y2);
if (show) {
ImPlot::TagX(0.25, ImVec4(1,1,0,1));
ImPlot::TagY(0.75, ImVec4(1,1,0,1));
static double drag_tag = 0.25;
ImPlot::DragLineY(0,&drag_tag,ImVec4(1,0,0,1),1,ImPlotDragToolFlags_NoFit);
ImPlot::TagY(drag_tag, ImVec4(1,0,0,1), "Drag");
SetAxes(ImAxis_X2, ImAxis_Y2);
ImPlot::TagX(0.5, ImVec4(0,1,1,1), "%s", "MyTag");
ImPlot::TagY(0.5, ImVec4(0,1,1,1), "Tag: %d", 42);
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_DragAndDrop() {
ImGui::BulletText("Drag/drop items from the left column.");
ImGui::BulletText("Drag/drop items between plots.");
ImGui::Indent();
ImGui::BulletText("Plot 1 Targets: Plot, Y-Axes, Legend");
ImGui::BulletText("Plot 1 Sources: Legend Item Labels");
ImGui::BulletText("Plot 2 Targets: Plot, X-Axis, Y-Axis");
ImGui::BulletText("Plot 2 Sources: Plot, X-Axis, Y-Axis (hold Ctrl)");
ImGui::Unindent();
// convenience struct to manage DND items; do this however you like
struct MyDndItem {
int Idx;
int Plt;
ImAxis Yax;
char Label[16];
ImVector Data;
ImVec4 Color;
MyDndItem() {
static int i = 0;
Idx = i++;
Plt = 0;
Yax = ImAxis_Y1;
snprintf(Label, sizeof(Label), "%02d Hz", Idx+1);
Color = RandomColor();
Data.reserve(1001);
for (int k = 0; k < 1001; ++k) {
float t = k * 1.0f / 999;
Data.push_back(ImVec2(t, 0.5f + 0.5f * sinf(2*3.14f*t*(Idx+1))));
}
}
void Reset() { Plt = 0; Yax = ImAxis_Y1; }
};
const int k_dnd = 20;
static MyDndItem dnd[k_dnd];
static MyDndItem* dndx = nullptr; // for plot 2
static MyDndItem* dndy = nullptr; // for plot 2
// child window to serve as initial source for our DND items
ImGui::BeginChild("DND_LEFT",ImVec2(100,400));
if (ImGui::Button("Reset Data")) {
for (int k = 0; k < k_dnd; ++k)
dnd[k].Reset();
dndx = dndy = nullptr;
}
for (int k = 0; k < k_dnd; ++k) {
if (dnd[k].Plt > 0)
continue;
ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
ImGui::Selectable(dnd[k].Label, false, 0, ImVec2(100, 0));
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
ImGui::SetDragDropPayload("MY_DND", &k, sizeof(int));
ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
ImGui::TextUnformatted(dnd[k].Label);
ImGui::EndDragDropSource();
}
}
ImGui::EndChild();
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
int i = *(int*)payload->Data; dnd[i].Reset();
}
ImGui::EndDragDropTarget();
}
ImGui::SameLine();
ImGui::BeginChild("DND_RIGHT",ImVec2(-1,400));
// plot 1 (time series)
ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoHighlight;
if (ImPlot::BeginPlot("##DND1", ImVec2(-1,195))) {
ImPlot::SetupAxis(ImAxis_X1, nullptr, flags|ImPlotAxisFlags_Lock);
ImPlot::SetupAxis(ImAxis_Y1, "[drop here]", flags);
ImPlot::SetupAxis(ImAxis_Y2, "[drop here]", flags|ImPlotAxisFlags_Opposite);
ImPlot::SetupAxis(ImAxis_Y3, "[drop here]", flags|ImPlotAxisFlags_Opposite);
for (int k = 0; k < k_dnd; ++k) {
if (dnd[k].Plt == 1 && dnd[k].Data.size() > 0) {
ImPlot::SetAxis(dnd[k].Yax);
ImPlot::SetNextLineStyle(dnd[k].Color);
ImPlot::PlotLine(dnd[k].Label, &dnd[k].Data[0].x, &dnd[k].Data[0].y, dnd[k].Data.size(), 0, 0, 2 * sizeof(float));
// allow legend item labels to be DND sources
if (ImPlot::BeginDragDropSourceItem(dnd[k].Label)) {
ImGui::SetDragDropPayload("MY_DND", &k, sizeof(int));
ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
ImGui::TextUnformatted(dnd[k].Label);
ImPlot::EndDragDropSource();
}
}
}
// allow the main plot area to be a DND target
if (ImPlot::BeginDragDropTargetPlot()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = ImAxis_Y1;
}
ImPlot::EndDragDropTarget();
}
// allow each y-axis to be a DND target
for (int y = ImAxis_Y1; y <= ImAxis_Y3; ++y) {
if (ImPlot::BeginDragDropTargetAxis(y)) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = y;
}
ImPlot::EndDragDropTarget();
}
}
// allow the legend to be a DND target
if (ImPlot::BeginDragDropTargetLegend()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = ImAxis_Y1;
}
ImPlot::EndDragDropTarget();
}
ImPlot::EndPlot();
}
// plot 2 (Lissajous)
if (ImPlot::BeginPlot("##DND2", ImVec2(-1,195))) {
ImPlot::PushStyleColor(ImPlotCol_AxisBg, dndx != nullptr ? dndx->Color : ImPlot::GetStyle().Colors[ImPlotCol_AxisBg]);
ImPlot::SetupAxis(ImAxis_X1, dndx == nullptr ? "[drop here]" : dndx->Label, flags);
ImPlot::PushStyleColor(ImPlotCol_AxisBg, dndy != nullptr ? dndy->Color : ImPlot::GetStyle().Colors[ImPlotCol_AxisBg]);
ImPlot::SetupAxis(ImAxis_Y1, dndy == nullptr ? "[drop here]" : dndy->Label, flags);
ImPlot::PopStyleColor(2);
if (dndx != nullptr && dndy != nullptr) {
ImVec4 mixed((dndx->Color.x + dndy->Color.x)/2,(dndx->Color.y + dndy->Color.y)/2,(dndx->Color.z + dndy->Color.z)/2,(dndx->Color.w + dndy->Color.w)/2);
ImPlot::SetNextLineStyle(mixed);
ImPlot::PlotLine("##dndxy", &dndx->Data[0].y, &dndy->Data[0].y, dndx->Data.size(), 0, 0, 2 * sizeof(float));
}
// allow the x-axis to be a DND target
if (ImPlot::BeginDragDropTargetAxis(ImAxis_X1)) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
int i = *(int*)payload->Data; dndx = &dnd[i];
}
ImPlot::EndDragDropTarget();
}
// allow the x-axis to be a DND source
if (dndx != nullptr && ImPlot::BeginDragDropSourceAxis(ImAxis_X1)) {
ImGui::SetDragDropPayload("MY_DND", &dndx->Idx, sizeof(int));
ImPlot::ItemIcon(dndx->Color); ImGui::SameLine();
ImGui::TextUnformatted(dndx->Label);
ImPlot::EndDragDropSource();
}
// allow the y-axis to be a DND target
if (ImPlot::BeginDragDropTargetAxis(ImAxis_Y1)) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
int i = *(int*)payload->Data; dndy = &dnd[i];
}
ImPlot::EndDragDropTarget();
}
// allow the y-axis to be a DND source
if (dndy != nullptr && ImPlot::BeginDragDropSourceAxis(ImAxis_Y1)) {
ImGui::SetDragDropPayload("MY_DND", &dndy->Idx, sizeof(int));
ImPlot::ItemIcon(dndy->Color); ImGui::SameLine();
ImGui::TextUnformatted(dndy->Label);
ImPlot::EndDragDropSource();
}
// allow the plot area to be a DND target
if (ImPlot::BeginDragDropTargetPlot()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
int i = *(int*)payload->Data; dndx = dndy = &dnd[i];
}
}
// allow the plot area to be a DND source
if (ImPlot::BeginDragDropSourcePlot()) {
ImGui::TextUnformatted("Yes, you can\ndrag this!");
ImPlot::EndDragDropSource();
}
ImPlot::EndPlot();
}
ImGui::EndChild();
}
//-----------------------------------------------------------------------------
void Demo_Tables() {
#ifdef IMGUI_HAS_TABLE
static ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV |
ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable;
static bool anim = true;
static int offset = 0;
ImGui::BulletText("Plots can be used inside of ImGui tables as another means of creating subplots.");
ImGui::Checkbox("Animate",&anim);
if (anim)
offset = (offset + 1) % 100;
if (ImGui::BeginTable("##table", 3, flags, ImVec2(-1,0))) {
ImGui::TableSetupColumn("Electrode", ImGuiTableColumnFlags_WidthFixed, 75.0f);
ImGui::TableSetupColumn("Voltage", ImGuiTableColumnFlags_WidthFixed, 75.0f);
ImGui::TableSetupColumn("EMG Signal");
ImGui::TableHeadersRow();
ImPlot::PushColormap(ImPlotColormap_Cool);
for (int row = 0; row < 10; row++) {
ImGui::TableNextRow();
static float data[100];
srand(row);
for (int i = 0; i < 100; ++i)
data[i] = RandomRange(0.0f,10.0f);
ImGui::TableSetColumnIndex(0);
ImGui::Text("EMG %d", row);
ImGui::TableSetColumnIndex(1);
ImGui::Text("%.3f V", data[offset]);
ImGui::TableSetColumnIndex(2);
ImGui::PushID(row);
MyImPlot::Sparkline("##spark",data,100,0,11.0f,offset,ImPlot::GetColormapColor(row),ImVec2(-1, 35));
ImGui::PopID();
}
ImPlot::PopColormap();
ImGui::EndTable();
}
#else
ImGui::BulletText("You need to merge the ImGui 'tables' branch for this section.");
#endif
}
//-----------------------------------------------------------------------------
void Demo_OffsetAndStride() {
static const int k_circles = 11;
static const int k_points_per = 50;
static const int k_size = 2 * k_points_per * k_circles;
static double interleaved_data[k_size];
for (int p = 0; p < k_points_per; ++p) {
for (int c = 0; c < k_circles; ++c) {
double r = (double)c / (k_circles - 1) * 0.2 + 0.2;
interleaved_data[p*2*k_circles + 2*c + 0] = 0.5 + r * cos((double)p/k_points_per * 6.28);
interleaved_data[p*2*k_circles + 2*c + 1] = 0.5 + r * sin((double)p/k_points_per * 6.28);
}
}
static int offset = 0;
ImGui::BulletText("Offsetting is useful for realtime plots (see above) and circular buffers.");
ImGui::BulletText("Striding is useful for interleaved data (e.g. audio) or plotting structs.");
ImGui::BulletText("Here, all circle data is stored in a single interleaved buffer:");
ImGui::BulletText("[c0.x0 c0.y0 ... cn.x0 cn.y0 c0.x1 c0.y1 ... cn.x1 cn.y1 ... cn.xm cn.ym]");
ImGui::BulletText("The offset value indicates which circle point index is considered the first.");
ImGui::BulletText("Offsets can be negative and/or larger than the actual data count.");
ImGui::SliderInt("Offset", &offset, -2*k_points_per, 2*k_points_per);
if (ImPlot::BeginPlot("##strideoffset",ImVec2(-1,0),ImPlotFlags_Equal)) {
ImPlot::PushColormap(ImPlotColormap_Jet);
char buff[32];
for (int c = 0; c < k_circles; ++c) {
snprintf(buff, sizeof(buff), "Circle %d", c);
ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, 0, offset, 2*k_circles*sizeof(double));
}
ImPlot::EndPlot();
ImPlot::PopColormap();
}
// offset++; uncomment for animation!
}
//-----------------------------------------------------------------------------
void Demo_CustomDataAndGetters() {
ImGui::BulletText("You can plot custom structs using the stride feature.");
ImGui::BulletText("Most plotters can also be passed a function pointer for getting data.");
ImGui::Indent();
ImGui::BulletText("You can optionally pass user data to be given to your getter function.");
ImGui::BulletText("C++ lambdas can be passed as function pointers as well!");
ImGui::Unindent();
MyImPlot::Vector2f vec2_data[2] = { MyImPlot::Vector2f(0,0), MyImPlot::Vector2f(1,1) };
if (ImPlot::BeginPlot("##Custom Data")) {
// custom structs using stride example:
ImPlot::PlotLine("Vector2f", &vec2_data[0].x, &vec2_data[0].y, 2, 0, 0, sizeof(MyImPlot::Vector2f) /* or sizeof(float) * 2 */);
// custom getter example 1:
ImPlot::PlotLineG("Spiral", MyImPlot::Spiral, nullptr, 1000);
// custom getter example 2:
static MyImPlot::WaveData data1(0.001, 0.2, 2, 0.75);
static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25);
ImPlot::PlotLineG("Waves", MyImPlot::SineWave, &data1, 1000);
ImPlot::PlotLineG("Waves", MyImPlot::SawWave, &data2, 1000);
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
ImPlot::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000);
ImPlot::PopStyleVar();
// you can also pass C++ lambdas:
// auto lamda = [](void* data, int idx) { ... return ImPlotPoint(x,y); };
// ImPlot::PlotLine("My Lambda", lambda, data, 1000);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
int MetricFormatter(double value, char* buff, int size, void* data) {
const char* unit = (const char*)data;
static double v[] = {1000000000,1000000,1000,1,0.001,0.000001,0.000000001};
static const char* p[] = {"G","M","k","","m","u","n"};
if (value == 0) {
return snprintf(buff,size,"0 %s", unit);
}
for (int i = 0; i < 7; ++i) {
if (fabs(value) >= v[i]) {
return snprintf(buff,size,"%g %s%s",value/v[i],p[i],unit);
}
}
return snprintf(buff,size,"%g %s%s",value/v[6],p[6],unit);
}
void Demo_TickLabels() {
static bool custom_fmt = true;
static bool custom_ticks = false;
static bool custom_labels = true;
ImGui::Checkbox("Show Custom Format", &custom_fmt);
ImGui::SameLine();
ImGui::Checkbox("Show Custom Ticks", &custom_ticks);
if (custom_ticks) {
ImGui::SameLine();
ImGui::Checkbox("Show Custom Labels", &custom_labels);
}
const double pi = 3.14;
const char* pi_str[] = {"PI"};
static double yticks[] = {100,300,700,900};
static const char* ylabels[] = {"One","Three","Seven","Nine"};
static double yticks_aux[] = {0.2,0.4,0.6};
static const char* ylabels_aux[] = {"A","B","C","D","E","F"};
if (ImPlot::BeginPlot("##Ticks")) {
ImPlot::SetupAxesLimits(2.5,5,0,1000);
ImPlot::SetupAxis(ImAxis_Y2, nullptr, ImPlotAxisFlags_AuxDefault);
ImPlot::SetupAxis(ImAxis_Y3, nullptr, ImPlotAxisFlags_AuxDefault);
if (custom_fmt) {
ImPlot::SetupAxisFormat(ImAxis_X1, "%g ms");
ImPlot::SetupAxisFormat(ImAxis_Y1, MetricFormatter, (void*)"Hz");
ImPlot::SetupAxisFormat(ImAxis_Y2, "%g dB");
ImPlot::SetupAxisFormat(ImAxis_Y3, MetricFormatter, (void*)"m");
}
if (custom_ticks) {
ImPlot::SetupAxisTicks(ImAxis_X1, &pi,1,custom_labels ? pi_str : nullptr, true);
ImPlot::SetupAxisTicks(ImAxis_Y1, yticks, 4, custom_labels ? ylabels : nullptr, false);
ImPlot::SetupAxisTicks(ImAxis_Y2, yticks_aux, 3, custom_labels ? ylabels_aux : nullptr, false);
ImPlot::SetupAxisTicks(ImAxis_Y3, 0, 1, 6, custom_labels ? ylabels_aux : nullptr, false);
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_CustomStyles() {
ImPlot::PushColormap(ImPlotColormap_Deep);
// normally you wouldn't change the entire style each frame
ImPlotStyle backup = ImPlot::GetStyle();
MyImPlot::StyleSeaborn();
if (ImPlot::BeginPlot("seaborn style")) {
ImPlot::SetupAxes( "x-axis", "y-axis");
ImPlot::SetupAxesLimits(-0.5f, 9.5f, 0, 10);
unsigned int lin[10] = {8,8,9,7,8,8,8,9,7,8};
unsigned int bar[10] = {1,2,5,3,4,1,2,5,3,4};
unsigned int dot[10] = {7,6,6,7,8,5,6,5,8,7};
ImPlot::PlotBars("Bars", bar, 10, 0.5f);
ImPlot::PlotLine("Line", lin, 10);
ImPlot::NextColormapColor(); // skip green
ImPlot::PlotScatter("Scatter", dot, 10);
ImPlot::EndPlot();
}
ImPlot::GetStyle() = backup;
ImPlot::PopColormap();
}
//-----------------------------------------------------------------------------
void Demo_CustomRendering() {
if (ImPlot::BeginPlot("##CustomRend")) {
ImVec2 cntr = ImPlot::PlotToPixels(ImPlotPoint(0.5f, 0.5f));
ImVec2 rmin = ImPlot::PlotToPixels(ImPlotPoint(0.25f, 0.75f));
ImVec2 rmax = ImPlot::PlotToPixels(ImPlotPoint(0.75f, 0.25f));
ImPlot::PushPlotClipRect();
ImPlot::GetPlotDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20);
ImPlot::GetPlotDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255));
ImPlot::PopPlotClipRect();
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_LegendPopups() {
ImGui::BulletText("You can implement legend context menus to inject per-item controls and widgets.");
ImGui::BulletText("Right click the legend label/icon to edit custom item attributes.");
static float frequency = 0.1f;
static float amplitude = 0.5f;
static ImVec4 color = ImVec4(1,1,0,1);
static float alpha = 1.0f;
static bool line = false;
static float thickness = 1;
static bool markers = false;
static bool shaded = false;
static float vals[101];
for (int i = 0; i < 101; ++i)
vals[i] = amplitude * sinf(frequency * i);
if (ImPlot::BeginPlot("Right Click the Legend")) {
ImPlot::SetupAxesLimits(0,100,-1,1);
// rendering logic
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha);
if (!line) {
ImPlot::SetNextFillStyle(color);
ImPlot::PlotBars("Right Click Me", vals, 101);
}
else {
if (markers) ImPlot::SetNextMarkerStyle(ImPlotMarker_Square);
ImPlot::SetNextLineStyle(color, thickness);
ImPlot::PlotLine("Right Click Me", vals, 101);
if (shaded) ImPlot::PlotShaded("Right Click Me",vals,101);
}
ImPlot::PopStyleVar();
// custom legend context menu
if (ImPlot::BeginLegendPopup("Right Click Me")) {
ImGui::SliderFloat("Frequency",&frequency,0,1,"%0.2f");
ImGui::SliderFloat("Amplitude",&litude,0,1,"%0.2f");
ImGui::Separator();
ImGui::ColorEdit3("Color",&color.x);
ImGui::SliderFloat("Transparency",&alpha,0,1,"%.2f");
ImGui::Checkbox("Line Plot", &line);
if (line) {
ImGui::SliderFloat("Thickness", &thickness, 0, 5);
ImGui::Checkbox("Markers", &markers);
ImGui::Checkbox("Shaded",&shaded);
}
ImPlot::EndLegendPopup();
}
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
void Demo_ColormapWidgets() {
static int cmap = ImPlotColormap_Viridis;
if (ImPlot::ColormapButton("Button",ImVec2(0,0),cmap)) {
cmap = (cmap + 1) % ImPlot::GetColormapCount();
}
static float t = 0.5f;
static ImVec4 col;
ImGui::ColorButton("##Display",col,ImGuiColorEditFlags_NoInputs);
ImGui::SameLine();
ImPlot::ColormapSlider("Slider", &t, &col, "%.3f", cmap);
ImPlot::ColormapIcon(cmap); ImGui::SameLine(); ImGui::Text("Icon");
static ImPlotColormapScaleFlags flags = 0;
static float scale[2] = {0, 100};
ImPlot::ColormapScale("Scale",scale[0],scale[1],ImVec2(0,0),"%g dB",flags,cmap);
ImGui::InputFloat2("Scale",scale);
CHECKBOX_FLAG(flags, ImPlotColormapScaleFlags_NoLabel);
CHECKBOX_FLAG(flags, ImPlotColormapScaleFlags_Opposite);
CHECKBOX_FLAG(flags, ImPlotColormapScaleFlags_Invert);
}
//-----------------------------------------------------------------------------
void Demo_CustomPlottersAndTooltips() {
ImGui::BulletText("You can create custom plotters or extend ImPlot using implot_internal.h.");
double dates[] = {1546300800,1546387200,1546473600,1546560000,1546819200,1546905600,1546992000,1547078400,1547164800,1547424000,1547510400,1547596800,1547683200,1547769600,1547942400,1548028800,1548115200,1548201600,1548288000,1548374400,1548633600,1548720000,1548806400,1548892800,1548979200,1549238400,1549324800,1549411200,1549497600,1549584000,1549843200,1549929600,1550016000,1550102400,1550188800,1550361600,1550448000,1550534400,1550620800,1550707200,1550793600,1551052800,1551139200,1551225600,1551312000,1551398400,1551657600,1551744000,1551830400,1551916800,1552003200,1552262400,1552348800,1552435200,1552521600,1552608000,1552867200,1552953600,1553040000,1553126400,1553212800,1553472000,1553558400,1553644800,1553731200,1553817600,1554076800,1554163200,1554249600,1554336000,1554422400,1554681600,1554768000,1554854400,1554940800,1555027200,1555286400,1555372800,1555459200,1555545600,1555632000,1555891200,1555977600,1556064000,1556150400,1556236800,1556496000,1556582400,1556668800,1556755200,1556841600,1557100800,1557187200,1557273600,1557360000,1557446400,1557705600,1557792000,1557878400,1557964800,1558051200,1558310400,1558396800,1558483200,1558569600,1558656000,1558828800,1558915200,1559001600,1559088000,1559174400,1559260800,1559520000,1559606400,1559692800,1559779200,1559865600,1560124800,1560211200,1560297600,1560384000,1560470400,1560729600,1560816000,1560902400,1560988800,1561075200,1561334400,1561420800,1561507200,1561593600,1561680000,1561939200,1562025600,1562112000,1562198400,1562284800,1562544000,1562630400,1562716800,1562803200,1562889600,1563148800,1563235200,1563321600,1563408000,1563494400,1563753600,1563840000,1563926400,1564012800,1564099200,1564358400,1564444800,1564531200,1564617600,1564704000,1564963200,1565049600,1565136000,1565222400,1565308800,1565568000,1565654400,1565740800,1565827200,1565913600,1566172800,1566259200,1566345600,1566432000,1566518400,1566777600,1566864000,1566950400,1567036800,1567123200,1567296000,1567382400,1567468800,1567555200,1567641600,1567728000,1567987200,1568073600,1568160000,1568246400,1568332800,1568592000,1568678400,1568764800,1568851200,1568937600,1569196800,1569283200,1569369600,1569456000,1569542400,1569801600,1569888000,1569974400,1570060800,1570147200,1570406400,1570492800,1570579200,1570665600,1570752000,1571011200,1571097600,1571184000,1571270400,1571356800,1571616000,1571702400,1571788800,1571875200,1571961600};
double opens[] = {1284.7,1319.9,1318.7,1328,1317.6,1321.6,1314.3,1325,1319.3,1323.1,1324.7,1321.3,1323.5,1322,1281.3,1281.95,1311.1,1315,1314,1313.1,1331.9,1334.2,1341.3,1350.6,1349.8,1346.4,1343.4,1344.9,1335.6,1337.9,1342.5,1337,1338.6,1337,1340.4,1324.65,1324.35,1349.5,1371.3,1367.9,1351.3,1357.8,1356.1,1356,1347.6,1339.1,1320.6,1311.8,1314,1312.4,1312.3,1323.5,1319.1,1327.2,1332.1,1320.3,1323.1,1328,1330.9,1338,1333,1335.3,1345.2,1341.1,1332.5,1314,1314.4,1310.7,1314,1313.1,1315,1313.7,1320,1326.5,1329.2,1314.2,1312.3,1309.5,1297.4,1293.7,1277.9,1295.8,1295.2,1290.3,1294.2,1298,1306.4,1299.8,1302.3,1297,1289.6,1302,1300.7,1303.5,1300.5,1303.2,1306,1318.7,1315,1314.5,1304.1,1294.7,1293.7,1291.2,1290.2,1300.4,1284.2,1284.25,1301.8,1295.9,1296.2,1304.4,1323.1,1340.9,1341,1348,1351.4,1351.4,1343.5,1342.3,1349,1357.6,1357.1,1354.7,1361.4,1375.2,1403.5,1414.7,1433.2,1438,1423.6,1424.4,1418,1399.5,1435.5,1421.25,1434.1,1412.4,1409.8,1412.2,1433.4,1418.4,1429,1428.8,1420.6,1441,1460.4,1441.7,1438.4,1431,1439.3,1427.4,1431.9,1439.5,1443.7,1425.6,1457.5,1451.2,1481.1,1486.7,1512.1,1515.9,1509.2,1522.3,1513,1526.6,1533.9,1523,1506.3,1518.4,1512.4,1508.8,1545.4,1537.3,1551.8,1549.4,1536.9,1535.25,1537.95,1535.2,1556,1561.4,1525.6,1516.4,1507,1493.9,1504.9,1506.5,1513.1,1506.5,1509.7,1502,1506.8,1521.5,1529.8,1539.8,1510.9,1511.8,1501.7,1478,1485.4,1505.6,1511.6,1518.6,1498.7,1510.9,1510.8,1498.3,1492,1497.7,1484.8,1494.2,1495.6,1495.6,1487.5,1491.1,1495.1,1506.4};
double highs[] = {1284.75,1320.6,1327,1330.8,1326.8,1321.6,1326,1328,1325.8,1327.1,1326,1326,1323.5,1322.1,1282.7,1282.95,1315.8,1316.3,1314,1333.2,1334.7,1341.7,1353.2,1354.6,1352.2,1346.4,1345.7,1344.9,1340.7,1344.2,1342.7,1342.1,1345.2,1342,1350,1324.95,1330.75,1369.6,1374.3,1368.4,1359.8,1359,1357,1356,1353.4,1340.6,1322.3,1314.1,1316.1,1312.9,1325.7,1323.5,1326.3,1336,1332.1,1330.1,1330.4,1334.7,1341.1,1344.2,1338.8,1348.4,1345.6,1342.8,1334.7,1322.3,1319.3,1314.7,1316.6,1316.4,1315,1325.4,1328.3,1332.2,1329.2,1316.9,1312.3,1309.5,1299.6,1296.9,1277.9,1299.5,1296.2,1298.4,1302.5,1308.7,1306.4,1305.9,1307,1297.2,1301.7,1305,1305.3,1310.2,1307,1308,1319.8,1321.7,1318.7,1316.2,1305.9,1295.8,1293.8,1293.7,1304.2,1302,1285.15,1286.85,1304,1302,1305.2,1323,1344.1,1345.2,1360.1,1355.3,1363.8,1353,1344.7,1353.6,1358,1373.6,1358.2,1369.6,1377.6,1408.9,1425.5,1435.9,1453.7,1438,1426,1439.1,1418,1435,1452.6,1426.65,1437.5,1421.5,1414.1,1433.3,1441.3,1431.4,1433.9,1432.4,1440.8,1462.3,1467,1443.5,1444,1442.9,1447,1437.6,1440.8,1445.7,1447.8,1458.2,1461.9,1481.8,1486.8,1522.7,1521.3,1521.1,1531.5,1546.1,1534.9,1537.7,1538.6,1523.6,1518.8,1518.4,1514.6,1540.3,1565,1554.5,1556.6,1559.8,1541.9,1542.9,1540.05,1558.9,1566.2,1561.9,1536.2,1523.8,1509.1,1506.2,1532.2,1516.6,1519.7,1515,1519.5,1512.1,1524.5,1534.4,1543.3,1543.3,1542.8,1519.5,1507.2,1493.5,1511.4,1525.8,1522.2,1518.8,1515.3,1518,1522.3,1508,1501.5,1503,1495.5,1501.1,1497.9,1498.7,1492.1,1499.4,1506.9,1520.9};
double lows[] = {1282.85,1315,1318.7,1309.6,1317.6,1312.9,1312.4,1319.1,1319,1321,1318.1,1321.3,1319.9,1312,1280.5,1276.15,1308,1309.9,1308.5,1312.3,1329.3,1333.1,1340.2,1347,1345.9,1338,1340.8,1335,1332,1337.9,1333,1336.8,1333.2,1329.9,1340.4,1323.85,1324.05,1349,1366.3,1351.2,1349.1,1352.4,1350.7,1344.3,1338.9,1316.3,1308.4,1306.9,1309.6,1306.7,1312.3,1315.4,1319,1327.2,1317.2,1320,1323,1328,1323,1327.8,1331.7,1335.3,1336.6,1331.8,1311.4,1310,1309.5,1308,1310.6,1302.8,1306.6,1313.7,1320,1322.8,1311,1312.1,1303.6,1293.9,1293.5,1291,1277.9,1294.1,1286,1289.1,1293.5,1296.9,1298,1299.6,1292.9,1285.1,1288.5,1296.3,1297.2,1298.4,1298.6,1302,1300.3,1312,1310.8,1301.9,1292,1291.1,1286.3,1289.2,1289.9,1297.4,1283.65,1283.25,1292.9,1295.9,1290.8,1304.2,1322.7,1336.1,1341,1343.5,1345.8,1340.3,1335.1,1341.5,1347.6,1352.8,1348.2,1353.7,1356.5,1373.3,1398,1414.7,1427,1416.4,1412.7,1420.1,1396.4,1398.8,1426.6,1412.85,1400.7,1406,1399.8,1404.4,1415.5,1417.2,1421.9,1415,1413.7,1428.1,1434,1435.7,1427.5,1429.4,1423.9,1425.6,1427.5,1434.8,1422.3,1412.1,1442.5,1448.8,1468.2,1484.3,1501.6,1506.2,1498.6,1488.9,1504.5,1518.3,1513.9,1503.3,1503,1506.5,1502.1,1503,1534.8,1535.3,1541.4,1528.6,1525.6,1535.25,1528.15,1528,1542.6,1514.3,1510.7,1505.5,1492.1,1492.9,1496.8,1493.1,1503.4,1500.9,1490.7,1496.3,1505.3,1505.3,1517.9,1507.4,1507.1,1493.3,1470.5,1465,1480.5,1501.7,1501.4,1493.3,1492.1,1505.1,1495.7,1478,1487.1,1480.8,1480.6,1487,1488.3,1484.8,1484,1490.7,1490.4,1503.1};
double closes[] = {1283.35,1315.3,1326.1,1317.4,1321.5,1317.4,1323.5,1319.2,1321.3,1323.3,1319.7,1325.1,1323.6,1313.8,1282.05,1279.05,1314.2,1315.2,1310.8,1329.1,1334.5,1340.2,1340.5,1350,1347.1,1344.3,1344.6,1339.7,1339.4,1343.7,1337,1338.9,1340.1,1338.7,1346.8,1324.25,1329.55,1369.6,1372.5,1352.4,1357.6,1354.2,1353.4,1346,1341,1323.8,1311.9,1309.1,1312.2,1310.7,1324.3,1315.7,1322.4,1333.8,1319.4,1327.1,1325.8,1330.9,1325.8,1331.6,1336.5,1346.7,1339.2,1334.7,1313.3,1316.5,1312.4,1313.4,1313.3,1312.2,1313.7,1319.9,1326.3,1331.9,1311.3,1313.4,1309.4,1295.2,1294.7,1294.1,1277.9,1295.8,1291.2,1297.4,1297.7,1306.8,1299.4,1303.6,1302.2,1289.9,1299.2,1301.8,1303.6,1299.5,1303.2,1305.3,1319.5,1313.6,1315.1,1303.5,1293,1294.6,1290.4,1291.4,1302.7,1301,1284.15,1284.95,1294.3,1297.9,1304.1,1322.6,1339.3,1340.1,1344.9,1354,1357.4,1340.7,1342.7,1348.2,1355.1,1355.9,1354.2,1362.1,1360.1,1408.3,1411.2,1429.5,1430.1,1426.8,1423.4,1425.1,1400.8,1419.8,1432.9,1423.55,1412.1,1412.2,1412.8,1424.9,1419.3,1424.8,1426.1,1423.6,1435.9,1440.8,1439.4,1439.7,1434.5,1436.5,1427.5,1432.2,1433.3,1441.8,1437.8,1432.4,1457.5,1476.5,1484.2,1519.6,1509.5,1508.5,1517.2,1514.1,1527.8,1531.2,1523.6,1511.6,1515.7,1515.7,1508.5,1537.6,1537.2,1551.8,1549.1,1536.9,1529.4,1538.05,1535.15,1555.9,1560.4,1525.5,1515.5,1511.1,1499.2,1503.2,1507.4,1499.5,1511.5,1513.4,1515.8,1506.2,1515.1,1531.5,1540.2,1512.3,1515.2,1506.4,1472.9,1489,1507.9,1513.8,1512.9,1504.4,1503.9,1512.8,1500.9,1488.7,1497.6,1483.5,1494,1498.3,1494.1,1488.1,1487.5,1495.7,1504.7,1505.3};
static bool tooltip = true;
ImGui::Checkbox("Show Tooltip", &tooltip);
ImGui::SameLine();
static ImVec4 bullCol = ImVec4(0.000f, 1.000f, 0.441f, 1.000f);
static ImVec4 bearCol = ImVec4(0.853f, 0.050f, 0.310f, 1.000f);
ImGui::SameLine(); ImGui::ColorEdit4("##Bull", &bullCol.x, ImGuiColorEditFlags_NoInputs);
ImGui::SameLine(); ImGui::ColorEdit4("##Bear", &bearCol.x, ImGuiColorEditFlags_NoInputs);
ImPlot::GetStyle().UseLocalTime = false;
if (ImPlot::BeginPlot("Candlestick Chart",ImVec2(-1,0))) {
ImPlot::SetupAxes(nullptr,nullptr,0,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_RangeFit);
ImPlot::SetupAxesLimits(1546300800, 1571961600, 1250, 1600);
ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_Time);
ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 1546300800, 1571961600);
ImPlot::SetupAxisZoomConstraints(ImAxis_X1, 60*60*24*14, 1571961600-1546300800);
ImPlot::SetupAxisFormat(ImAxis_Y1, "$%.0f");
MyImPlot::PlotCandlestick("GOOGL",dates, opens, closes, lows, highs, 218, tooltip, 0.25f, bullCol, bearCol);
ImPlot::EndPlot();
}
}
//-----------------------------------------------------------------------------
// DEMO WINDOW
//-----------------------------------------------------------------------------
void DemoHeader(const char* label, void(*demo)()) {
if (ImGui::TreeNodeEx(label)) {
demo();
ImGui::TreePop();
}
}
void ShowDemoWindow(bool* p_open) {
static bool show_implot_metrics = false;
static bool show_implot_style_editor = false;
static bool show_imgui_metrics = false;
static bool show_imgui_style_editor = false;
static bool show_imgui_demo = false;
if (show_implot_metrics) {
ImPlot::ShowMetricsWindow(&show_implot_metrics);
}
if (show_implot_style_editor) {
ImGui::SetNextWindowSize(ImVec2(415,762), ImGuiCond_Appearing);
ImGui::Begin("Style Editor (ImPlot)", &show_implot_style_editor);
ImPlot::ShowStyleEditor();
ImGui::End();
}
if (show_imgui_style_editor) {
ImGui::Begin("Style Editor (ImGui)", &show_imgui_style_editor);
ImGui::ShowStyleEditor();
ImGui::End();
}
if (show_imgui_metrics) {
ImGui::ShowMetricsWindow(&show_imgui_metrics);
}
if (show_imgui_demo) {
ImGui::ShowDemoWindow(&show_imgui_demo);
}
ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(600, 750), ImGuiCond_FirstUseEver);
ImGui::Begin("ImPlot Demo", p_open, ImGuiWindowFlags_MenuBar);
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Metrics", nullptr, &show_implot_metrics);
ImGui::MenuItem("Style Editor", nullptr, &show_implot_style_editor);
ImGui::Separator();
ImGui::MenuItem("ImGui Metrics", nullptr, &show_imgui_metrics);
ImGui::MenuItem("ImGui Style Editor", nullptr, &show_imgui_style_editor);
ImGui::MenuItem("ImGui Demo", nullptr, &show_imgui_demo);
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
//-------------------------------------------------------------------------
ImGui::Text("ImPlot says hello. (%s)", IMPLOT_VERSION);
// display warning about 16-bit indices
static bool showWarning = sizeof(ImDrawIdx)*8 == 16 && (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) == false;
if (showWarning) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1,1,0,1));
ImGui::TextWrapped("WARNING: ImDrawIdx is 16-bit and ImGuiBackendFlags_RendererHasVtxOffset is false. Expect visual glitches and artifacts! See README for more information.");
ImGui::PopStyleColor();
}
ImGui::Spacing();
if (ImGui::BeginTabBar("ImPlotDemoTabs")) {
if (ImGui::BeginTabItem("Plots")) {
DemoHeader("Line Plots", Demo_LinePlots);
DemoHeader("Filled Line Plots", Demo_FilledLinePlots);
DemoHeader("Shaded Plots##", Demo_ShadedPlots);
DemoHeader("Scatter Plots", Demo_ScatterPlots);
DemoHeader("Realtime Plots", Demo_RealtimePlots);
DemoHeader("Stairstep Plots", Demo_StairstepPlots);
DemoHeader("Bar Plots", Demo_BarPlots);
DemoHeader("Bar Groups", Demo_BarGroups);
DemoHeader("Bar Stacks", Demo_BarStacks);
DemoHeader("Error Bars", Demo_ErrorBars);
DemoHeader("Stem Plots##", Demo_StemPlots);
DemoHeader("Infinite Lines", Demo_InfiniteLines);
DemoHeader("Pie Charts", Demo_PieCharts);
DemoHeader("Heatmaps", Demo_Heatmaps);
DemoHeader("Histogram", Demo_Histogram);
DemoHeader("Histogram 2D", Demo_Histogram2D);
DemoHeader("Digital Plots", Demo_DigitalPlots);
DemoHeader("Images", Demo_Images);
DemoHeader("Markers and Text", Demo_MarkersAndText);
DemoHeader("NaN Values", Demo_NaNValues);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Subplots")) {
DemoHeader("Sizing", Demo_SubplotsSizing);
DemoHeader("Item Sharing", Demo_SubplotItemSharing);
DemoHeader("Axis Linking", Demo_SubplotAxisLinking);
DemoHeader("Tables", Demo_Tables);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Axes")) {
DemoHeader("Log Scale", Demo_LogScale);
DemoHeader("Symmetric Log Scale", Demo_SymmetricLogScale);
DemoHeader("Time Scale", Demo_TimeScale);
DemoHeader("Custom Scale", Demo_CustomScale);
DemoHeader("Multiple Axes", Demo_MultipleAxes);
DemoHeader("Tick Labels", Demo_TickLabels);
DemoHeader("Linked Axes", Demo_LinkedAxes);
DemoHeader("Axis Constraints", Demo_AxisConstraints);
DemoHeader("Equal Axes", Demo_EqualAxes);
DemoHeader("Auto-Fitting Data", Demo_AutoFittingData);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Tools")) {
DemoHeader("Offset and Stride", Demo_OffsetAndStride);
DemoHeader("Drag Points", Demo_DragPoints);
DemoHeader("Drag Lines", Demo_DragLines);
DemoHeader("Drag Rects", Demo_DragRects);
DemoHeader("Querying", Demo_Querying);
DemoHeader("Annotations", Demo_Annotations);
DemoHeader("Tags", Demo_Tags);
DemoHeader("Drag and Drop", Demo_DragAndDrop);
DemoHeader("Legend Options", Demo_LegendOptions);
DemoHeader("Legend Popups", Demo_LegendPopups);
DemoHeader("Colormap Widgets", Demo_ColormapWidgets);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Custom")) {
DemoHeader("Custom Styles", Demo_CustomStyles);
DemoHeader("Custom Data and Getters", Demo_CustomDataAndGetters);
DemoHeader("Custom Rendering", Demo_CustomRendering);
DemoHeader("Custom Plotters and Tooltips", Demo_CustomPlottersAndTooltips);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Config")) {
Demo_Config();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Help")) {
Demo_Help();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
ImGui::End();
}
} // namespace ImPlot
namespace MyImPlot {
ImPlotPoint SineWave(int idx, void* data) {
WaveData* wd = (WaveData*)data;
double x = idx * wd->X;
return ImPlotPoint(x, wd->Offset + wd->Amp * sin(2 * 3.14 * wd->Freq * x));
}
ImPlotPoint SawWave(int idx, void* data) {
WaveData* wd = (WaveData*)data;
double x = idx * wd->X;
return ImPlotPoint(x, wd->Offset + wd->Amp * (-2 / 3.14 * atan(cos(3.14 * wd->Freq * x) / sin(3.14 * wd->Freq * x))));
}
ImPlotPoint Spiral(int idx, void*) {
float r = 0.9f; // outer radius
float a = 0; // inner radius
float b = 0.05f; // increment per rev
float n = (r - a) / b; // number of revolutions
double th = 2 * n * 3.14; // angle
float Th = float(th * idx / (1000 - 1));
return ImPlotPoint(0.5f+(a + b*Th / (2.0f * (float) 3.14))*cos(Th),
0.5f + (a + b*Th / (2.0f * (float)3.14))*sin(Th));
}
void Sparkline(const char* id, const float* values, int count, float min_v, float max_v, int offset, const ImVec4& col, const ImVec2& size) {
ImPlot::PushStyleVar(ImPlotStyleVar_PlotPadding, ImVec2(0,0));
if (ImPlot::BeginPlot(id,size,ImPlotFlags_CanvasOnly|ImPlotFlags_NoChild)) {
ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations);
ImPlot::SetupAxesLimits(0, count - 1, min_v, max_v, ImGuiCond_Always);
ImPlot::SetNextLineStyle(col);
ImPlot::SetNextFillStyle(col, 0.25);
ImPlot::PlotLine(id, values, count, 1, 0, ImPlotLineFlags_Shaded, offset);
ImPlot::EndPlot();
}
ImPlot::PopStyleVar();
}
void StyleSeaborn() {
ImPlotStyle& style = ImPlot::GetStyle();
ImVec4* colors = style.Colors;
colors[ImPlotCol_Line] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Fill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerOutline] = IMPLOT_AUTO_COL;
colors[ImPlotCol_MarkerFill] = IMPLOT_AUTO_COL;
colors[ImPlotCol_ErrorBar] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_PlotBg] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f);
colors[ImPlotCol_PlotBorder] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImPlotCol_LegendBg] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f);
colors[ImPlotCol_LegendBorder] = ImVec4(0.80f, 0.81f, 0.85f, 1.00f);
colors[ImPlotCol_LegendText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_TitleText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_InlayText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_AxisText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_AxisBgHovered] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f);
colors[ImPlotCol_AxisBgActive] = ImVec4(0.92f, 0.92f, 0.95f, 0.75f);
colors[ImPlotCol_Selection] = ImVec4(1.00f, 0.65f, 0.00f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(0.23f, 0.10f, 0.64f, 0.50f);
style.LineWeight = 1.5;
style.Marker = ImPlotMarker_None;
style.MarkerSize = 4;
style.MarkerWeight = 1;
style.FillAlpha = 1.0f;
style.ErrorBarSize = 5;
style.ErrorBarWeight = 1.5f;
style.DigitalBitHeight = 8;
style.DigitalBitGap = 4;
style.PlotBorderSize = 0;
style.MinorAlpha = 1.0f;
style.MajorTickLen = ImVec2(0,0);
style.MinorTickLen = ImVec2(0,0);
style.MajorTickSize = ImVec2(0,0);
style.MinorTickSize = ImVec2(0,0);
style.MajorGridSize = ImVec2(1.2f,1.2f);
style.MinorGridSize = ImVec2(1.2f,1.2f);
style.PlotPadding = ImVec2(12,12);
style.LabelPadding = ImVec2(5,5);
style.LegendPadding = ImVec2(5,5);
style.MousePosPadding = ImVec2(5,5);
style.PlotMinSize = ImVec2(300,225);
}
} // namespaece MyImPlot
// WARNING:
//
// You can use "implot_internal.h" to build custom plotting fuctions or extend ImPlot.
// However, note that forward compatibility of this file is not guaranteed and the
// internal API is subject to change. At some point we hope to bring more of this
// into the public API and expose the necessary building blocks to fully support
// custom plotters. For now, proceed at your own risk!
#include "implot_internal.h"
namespace MyImPlot {
template
int BinarySearch(const T* arr, int l, int r, T x) {
if (r >= l) {
int mid = l + (r - l) / 2;
if (arr[mid] == x)
return mid;
if (arr[mid] > x)
return BinarySearch(arr, l, mid - 1, x);
return BinarySearch(arr, mid + 1, r, x);
}
return -1;
}
void PlotCandlestick(const char* label_id, const double* xs, const double* opens, const double* closes, const double* lows, const double* highs, int count, bool tooltip, float width_percent, ImVec4 bullCol, ImVec4 bearCol) {
// get ImGui window DrawList
ImDrawList* draw_list = ImPlot::GetPlotDrawList();
// calc real value width
double half_width = count > 1 ? (xs[1] - xs[0]) * width_percent : width_percent;
// custom tool
if (ImPlot::IsPlotHovered() && tooltip) {
ImPlotPoint mouse = ImPlot::GetPlotMousePos();
mouse.x = ImPlot::RoundTime(ImPlotTime::FromDouble(mouse.x), ImPlotTimeUnit_Day).ToDouble();
float tool_l = ImPlot::PlotToPixels(mouse.x - half_width * 1.5, mouse.y).x;
float tool_r = ImPlot::PlotToPixels(mouse.x + half_width * 1.5, mouse.y).x;
float tool_t = ImPlot::GetPlotPos().y;
float tool_b = tool_t + ImPlot::GetPlotSize().y;
ImPlot::PushPlotClipRect();
draw_list->AddRectFilled(ImVec2(tool_l, tool_t), ImVec2(tool_r, tool_b), IM_COL32(128,128,128,64));
ImPlot::PopPlotClipRect();
// find mouse location index
int idx = BinarySearch(xs, 0, count - 1, mouse.x);
// render tool tip (won't be affected by plot clip rect)
if (idx != -1) {
ImGui::BeginTooltip();
char buff[32];
ImPlot::FormatDate(ImPlotTime::FromDouble(xs[idx]),buff,32,ImPlotDateFmt_DayMoYr,ImPlot::GetStyle().UseISO8601);
ImGui::Text("Day: %s", buff);
ImGui::Text("Open: $%.2f", opens[idx]);
ImGui::Text("Close: $%.2f", closes[idx]);
ImGui::Text("Low: $%.2f", lows[idx]);
ImGui::Text("High: $%.2f", highs[idx]);
ImGui::EndTooltip();
}
}
// begin plot item
if (ImPlot::BeginItem(label_id)) {
// override legend icon color
ImPlot::GetCurrentItem()->Color = IM_COL32(64,64,64,255);
// fit data if requested
if (ImPlot::FitThisFrame()) {
for (int i = 0; i < count; ++i) {
ImPlot::FitPoint(ImPlotPoint(xs[i], lows[i]));
ImPlot::FitPoint(ImPlotPoint(xs[i], highs[i]));
}
}
// render data
for (int i = 0; i < count; ++i) {
ImVec2 open_pos = ImPlot::PlotToPixels(xs[i] - half_width, opens[i]);
ImVec2 close_pos = ImPlot::PlotToPixels(xs[i] + half_width, closes[i]);
ImVec2 low_pos = ImPlot::PlotToPixels(xs[i], lows[i]);
ImVec2 high_pos = ImPlot::PlotToPixels(xs[i], highs[i]);
ImU32 color = ImGui::GetColorU32(opens[i] > closes[i] ? bearCol : bullCol);
draw_list->AddLine(low_pos, high_pos, color);
draw_list->AddRectFilled(open_pos, close_pos, color);
}
// end plot item
ImPlot::EndItem();
}
}
} // namespace MyImplot
================================================
FILE: Source/External/imgui_tools/implot/implot_internal.h
================================================
// MIT License
// Copyright (c) 2022 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ImPlot v0.14
// You may use this file to debug, understand or extend ImPlot features but we
// don't provide any guarantee of forward compatibility!
//-----------------------------------------------------------------------------
// [SECTION] Header Mess
//-----------------------------------------------------------------------------
#pragma once
#include
#include "imgui_internal.h"
#ifndef IMPLOT_VERSION
#error Must include implot.h before implot_internal.h
#endif
// Support for pre-1.84 versions. ImPool's GetSize() -> GetBufSize()
#if (IMGUI_VERSION_NUM < 18303)
#define GetBufSize GetSize
#endif
//-----------------------------------------------------------------------------
// [SECTION] Constants
//-----------------------------------------------------------------------------
// Constants can be changed unless stated otherwise. We may move some of these
// to ImPlotStyleVar_ over time.
// Mimimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS)
#define IMPLOT_MIN_TIME 0
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS)
#define IMPLOT_MAX_TIME 32503680000
// Default label format for axis labels
#define IMPLOT_LABEL_FORMAT "%g"
// Max character size for tick labels
#define IMPLOT_LABEL_MAX_SIZE 32
//-----------------------------------------------------------------------------
// [SECTION] Macros
//-----------------------------------------------------------------------------
#define IMPLOT_NUM_X_AXES ImAxis_Y1
#define IMPLOT_NUM_Y_AXES (ImAxis_COUNT - IMPLOT_NUM_X_AXES)
// Split ImU32 color into RGB components [0 255]
#define IM_COL32_SPLIT_RGB(col,r,g,b) \
ImU32 r = ((col >> IM_COL32_R_SHIFT) & 0xFF); \
ImU32 g = ((col >> IM_COL32_G_SHIFT) & 0xFF); \
ImU32 b = ((col >> IM_COL32_B_SHIFT) & 0xFF);
//-----------------------------------------------------------------------------
// [SECTION] Forward Declarations
//-----------------------------------------------------------------------------
struct ImPlotTick;
struct ImPlotAxis;
struct ImPlotAxisColor;
struct ImPlotItem;
struct ImPlotLegend;
struct ImPlotPlot;
struct ImPlotNextPlotData;
struct ImPlotTicker;
//-----------------------------------------------------------------------------
// [SECTION] Context Pointer
//-----------------------------------------------------------------------------
#ifndef GImPlot
extern IMPLOT_API ImPlotContext* GImPlot; // Current implicit context pointer
#endif
//-----------------------------------------------------------------------------
// [SECTION] Generic Helpers
//-----------------------------------------------------------------------------
// Computes the common (base-10) logarithm
static inline float ImLog10(float x) { return log10f(x); }
static inline double ImLog10(double x) { return log10(x); }
static inline float ImSinh(float x) { return sinhf(x); }
static inline double ImSinh(double x) { return sinh(x); }
static inline float ImAsinh(float x) { return asinhf(x); }
static inline double ImAsinh(double x) { return asinh(x); }
// Returns true if a flag is set
template
static inline bool ImHasFlag(TSet set, TFlag flag) { return (set & flag) == flag; }
// Flips a flag in a flagset
template
static inline void ImFlipFlag(TSet& set, TFlag flag) { ImHasFlag(set, flag) ? set &= ~flag : set |= flag; }
// Linearly remaps x from [x0 x1] to [y0 y1].
template
static inline T ImRemap(T x, T x0, T x1, T y0, T y1) { return y0 + (x - x0) * (y1 - y0) / (x1 - x0); }
// Linear rempas x from [x0 x1] to [0 1]
template
static inline T ImRemap01(T x, T x0, T x1) { return (x - x0) / (x1 - x0); }
// Returns always positive modulo (assumes r != 0)
static inline int ImPosMod(int l, int r) { return (l % r + r) % r; }
// Returns true if val is NAN
static inline bool ImNan(double val) { return isnan(val); }
// Returns true if val is NAN or INFINITY
static inline bool ImNanOrInf(double val) { return !(val >= -DBL_MAX && val <= DBL_MAX) || ImNan(val); }
// Turns NANs to 0s
static inline double ImConstrainNan(double val) { return ImNan(val) ? 0 : val; }
// Turns infinity to floating point maximums
static inline double ImConstrainInf(double val) { return val >= DBL_MAX ? DBL_MAX : val <= -DBL_MAX ? - DBL_MAX : val; }
// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?)
static inline double ImConstrainLog(double val) { return val <= 0 ? 0.001f : val; }
// Turns numbers less than 0 to zero
static inline double ImConstrainTime(double val) { return val < IMPLOT_MIN_TIME ? IMPLOT_MIN_TIME : (val > IMPLOT_MAX_TIME ? IMPLOT_MAX_TIME : val); }
// True if two numbers are approximately equal using units in the last place.
static inline bool ImAlmostEqual(double v1, double v2, int ulp = 2) { return ImAbs(v1-v2) < DBL_EPSILON * ImAbs(v1+v2) * ulp || ImAbs(v1-v2) < DBL_MIN; }
// Finds min value in an unsorted array
template
static inline T ImMinArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] < m) { m = values[i]; } } return m; }
// Finds the max value in an unsorted array
template
static inline T ImMaxArray(const T* values, int count) { T m = values[0]; for (int i = 1; i < count; ++i) { if (values[i] > m) { m = values[i]; } } return m; }
// Finds the min and max value in an unsorted array
template
static inline void ImMinMaxArray(const T* values, int count, T* min_out, T* max_out) {
T Min = values[0]; T Max = values[0];
for (int i = 1; i < count; ++i) {
if (values[i] < Min) { Min = values[i]; }
if (values[i] > Max) { Max = values[i]; }
}
*min_out = Min; *max_out = Max;
}
// Finds the sim of an array
template
static inline T ImSum(const T* values, int count) {
T sum = 0;
for (int i = 0; i < count; ++i)
sum += values[i];
return sum;
}
// Finds the mean of an array
template
static inline double ImMean(const T* values, int count) {
double den = 1.0 / count;
double mu = 0;
for (int i = 0; i < count; ++i)
mu += (double)values[i] * den;
return mu;
}
// Finds the sample standard deviation of an array
template
static inline double ImStdDev(const T* values, int count) {
double den = 1.0 / (count - 1.0);
double mu = ImMean(values, count);
double x = 0;
for (int i = 0; i < count; ++i)
x += ((double)values[i] - mu) * ((double)values[i] - mu) * den;
return sqrt(x);
}
// Mix color a and b by factor s in [0 256]
static inline ImU32 ImMixU32(ImU32 a, ImU32 b, ImU32 s) {
#ifdef IMPLOT_MIX64
const ImU32 af = 256-s;
const ImU32 bf = s;
const ImU64 al = (a & 0x00ff00ff) | (((ImU64)(a & 0xff00ff00)) << 24);
const ImU64 bl = (b & 0x00ff00ff) | (((ImU64)(b & 0xff00ff00)) << 24);
const ImU64 mix = (al * af + bl * bf);
return ((mix >> 32) & 0xff00ff00) | ((mix & 0xff00ff00) >> 8);
#else
const ImU32 af = 256-s;
const ImU32 bf = s;
const ImU32 al = (a & 0x00ff00ff);
const ImU32 ah = (a & 0xff00ff00) >> 8;
const ImU32 bl = (b & 0x00ff00ff);
const ImU32 bh = (b & 0xff00ff00) >> 8;
const ImU32 ml = (al * af + bl * bf);
const ImU32 mh = (ah * af + bh * bf);
return (mh & 0xff00ff00) | ((ml & 0xff00ff00) >> 8);
#endif
}
// Lerp across an array of 32-bit collors given t in [0.0 1.0]
static inline ImU32 ImLerpU32(const ImU32* colors, int size, float t) {
int i1 = (int)((size - 1 ) * t);
int i2 = i1 + 1;
if (i2 == size || size == 1)
return colors[i1];
float den = 1.0f / (size - 1);
float t1 = i1 * den;
float t2 = i2 * den;
float tr = ImRemap01(t, t1, t2);
return ImMixU32(colors[i1], colors[i2], (ImU32)(tr*256));
}
// Set alpha channel of 32-bit color from float in range [0.0 1.0]
static inline ImU32 ImAlphaU32(ImU32 col, float alpha) {
return col & ~((ImU32)((1.0f-alpha)*255)<
static inline bool ImOverlaps(T min_a, T max_a, T min_b, T max_b) {
return min_a <= max_b && min_b <= max_a;
}
//-----------------------------------------------------------------------------
// [SECTION] ImPlot Enums
//-----------------------------------------------------------------------------
typedef int ImPlotTimeUnit; // -> enum ImPlotTimeUnit_
typedef int ImPlotDateFmt; // -> enum ImPlotDateFmt_
typedef int ImPlotTimeFmt; // -> enum ImPlotTimeFmt_
enum ImPlotTimeUnit_ {
ImPlotTimeUnit_Us, // microsecond
ImPlotTimeUnit_Ms, // millisecond
ImPlotTimeUnit_S, // second
ImPlotTimeUnit_Min, // minute
ImPlotTimeUnit_Hr, // hour
ImPlotTimeUnit_Day, // day
ImPlotTimeUnit_Mo, // month
ImPlotTimeUnit_Yr, // year
ImPlotTimeUnit_COUNT
};
enum ImPlotDateFmt_ { // default [ ISO 8601 ]
ImPlotDateFmt_None = 0,
ImPlotDateFmt_DayMo, // 10/3 [ --10-03 ]
ImPlotDateFmt_DayMoYr, // 10/3/91 [ 1991-10-03 ]
ImPlotDateFmt_MoYr, // Oct 1991 [ 1991-10 ]
ImPlotDateFmt_Mo, // Oct [ --10 ]
ImPlotDateFmt_Yr // 1991 [ 1991 ]
};
enum ImPlotTimeFmt_ { // default [ 24 Hour Clock ]
ImPlotTimeFmt_None = 0,
ImPlotTimeFmt_Us, // .428 552 [ .428 552 ]
ImPlotTimeFmt_SUs, // :29.428 552 [ :29.428 552 ]
ImPlotTimeFmt_SMs, // :29.428 [ :29.428 ]
ImPlotTimeFmt_S, // :29 [ :29 ]
ImPlotTimeFmt_MinSMs, // 21:29.428 [ 21:29.428 ]
ImPlotTimeFmt_HrMinSMs, // 7:21:29.428pm [ 19:21:29.428 ]
ImPlotTimeFmt_HrMinS, // 7:21:29pm [ 19:21:29 ]
ImPlotTimeFmt_HrMin, // 7:21pm [ 19:21 ]
ImPlotTimeFmt_Hr // 7pm [ 19:00 ]
};
//-----------------------------------------------------------------------------
// [SECTION] Callbacks
//-----------------------------------------------------------------------------
typedef void (*ImPlotLocator)(ImPlotTicker& ticker, const ImPlotRange& range, float pixels, bool vertical, ImPlotFormatter formatter, void* formatter_data);
//-----------------------------------------------------------------------------
// [SECTION] Structs
//-----------------------------------------------------------------------------
// Combined date/time format spec
struct ImPlotDateTimeSpec {
ImPlotDateTimeSpec() {}
ImPlotDateTimeSpec(ImPlotDateFmt date_fmt, ImPlotTimeFmt time_fmt, bool use_24_hr_clk = false, bool use_iso_8601 = false) {
Date = date_fmt;
Time = time_fmt;
UseISO8601 = use_iso_8601;
Use24HourClock = use_24_hr_clk;
}
ImPlotDateFmt Date;
ImPlotTimeFmt Time;
bool UseISO8601;
bool Use24HourClock;
};
// Two part timestamp struct.
struct ImPlotTime {
time_t S; // second part
int Us; // microsecond part
ImPlotTime() { S = 0; Us = 0; }
ImPlotTime(time_t s, int us = 0) { S = s + us / 1000000; Us = us % 1000000; }
void RollOver() { S = S + Us / 1000000; Us = Us % 1000000; }
double ToDouble() const { return (double)S + (double)Us / 1000000.0; }
static ImPlotTime FromDouble(double t) { return ImPlotTime((time_t)t, (int)(t * 1000000 - floor(t) * 1000000)); }
};
static inline ImPlotTime operator+(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return ImPlotTime(lhs.S + rhs.S, lhs.Us + rhs.Us); }
static inline ImPlotTime operator-(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return ImPlotTime(lhs.S - rhs.S, lhs.Us - rhs.Us); }
static inline bool operator==(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs.S == rhs.S && lhs.Us == rhs.Us; }
static inline bool operator<(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs.S == rhs.S ? lhs.Us < rhs.Us : lhs.S < rhs.S; }
static inline bool operator>(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return rhs < lhs; }
static inline bool operator<=(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs < rhs || lhs == rhs; }
static inline bool operator>=(const ImPlotTime& lhs, const ImPlotTime& rhs)
{ return lhs > rhs || lhs == rhs; }
// Colormap data storage
struct ImPlotColormapData {
ImVector Keys;
ImVector KeyCounts;
ImVector KeyOffsets;
ImVector Tables;
ImVector TableSizes;
ImVector