aboutsummaryrefslogtreecommitdiff
path: root/tools/ArtistTools/source/BlastPlugin/SampleBase/ui
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2017-02-24 09:32:20 -0800
committerBryan Galdrikian <[email protected]>2017-02-24 09:32:20 -0800
commite1bf674c16e3c8472b29574159c789cd3f0c64e0 (patch)
tree9f0cfce09c71a2c27ff19589fcad6cd83504477c /tools/ArtistTools/source/BlastPlugin/SampleBase/ui
parentfirst commit (diff)
downloadblast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.tar.xz
blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.zip
Updating to [email protected] and [email protected] with a new directory structure.
NvBlast folder is gone, files have been moved to top level directory. README is changed to reflect this.
Diffstat (limited to 'tools/ArtistTools/source/BlastPlugin/SampleBase/ui')
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.cpp621
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.h106
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.cpp294
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.h129
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.cpp158
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.h62
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.cpp1210
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.h124
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.cpp445
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.h82
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.cpp583
-rw-r--r--tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.h25
12 files changed, 3839 insertions, 0 deletions
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.cpp b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.cpp
new file mode 100644
index 0000000..e56a124
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.cpp
@@ -0,0 +1,621 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include "CommonUIController.h"
+
+#include "Renderer.h"
+#include "BlastController.h"
+#include "DamageToolController.h"
+#include "SceneController.h"
+#include "SampleController.h"
+#include "PhysXController.h"
+#include "SampleProfiler.h"
+
+#include "PxVisualizationParameter.h"
+#include "PxScene.h"
+
+#include <imgui.h>
+#include "imgui_impl_dx11.h"
+#include "UIHelpers.h"
+
+#include <cstdio>
+#include <inttypes.h>
+
+
+inline float memorySizeOutput(const char*& prefix, float value)
+{
+ for (prefix = "\0\0k\0M\0G\0T\0P\0E"; value >= 1024 && *prefix != 'E'; value /= 1024, prefix += 2);
+ return value;
+}
+
+CommonUIController::CommonUIController()
+{
+}
+
+HRESULT CommonUIController::DeviceCreated(ID3D11Device* pDevice)
+{
+ DeviceManager* manager = GetDeviceManager();
+ ID3D11DeviceContext* pd3dDeviceContext;
+ pDevice->GetImmediateContext(&pd3dDeviceContext);
+ ImGui_ImplDX11_Init(manager->GetHWND(), pDevice, pd3dDeviceContext);
+
+ ImGuiStyle& style = ImGui::GetStyle();
+ style.WindowRounding = 8.0f;
+ style.ScrollbarRounding = 8.0f;
+ style.FrameRounding = 8.0f;
+ //style.IndentSpacing = 20;
+ int mainColor[3] = { 110, 110, 110 }; // previous green one { 50, 110, 30 }
+ style.Colors[ImGuiCol_TitleBg] = ImColor(mainColor[0], mainColor[1], mainColor[2], 62);
+ style.Colors[ImGuiCol_TitleBgCollapsed] = ImColor(mainColor[0], mainColor[1], mainColor[2], 52);
+ style.Colors[ImGuiCol_TitleBgActive] = ImColor(mainColor[0], mainColor[1], mainColor[2], 87);
+ style.Colors[ImGuiCol_Header] = ImColor(mainColor[0], mainColor[1], mainColor[2], 52);
+ style.Colors[ImGuiCol_HeaderHovered] = ImColor(mainColor[0], mainColor[1], mainColor[2], 92);
+ style.Colors[ImGuiCol_HeaderActive] = ImColor(mainColor[0], mainColor[1], mainColor[2], 72);
+ style.Colors[ImGuiCol_ScrollbarBg] = ImColor(mainColor[0], mainColor[1], mainColor[2], 12);
+ style.Colors[ImGuiCol_ScrollbarGrab] = ImColor(mainColor[0], mainColor[1], mainColor[2], 52);
+ style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImColor(mainColor[0], mainColor[1], mainColor[2], 92);
+ style.Colors[ImGuiCol_ScrollbarGrabActive] = ImColor(mainColor[0], mainColor[1], mainColor[2], 72);
+ style.Colors[ImGuiCol_Button] = ImColor(40, 100, 80, 30);
+ style.Colors[ImGuiCol_ButtonHovered] = ImColor(40, 100, 80, 100);
+ style.Colors[ImGuiCol_ButtonActive] = ImColor(40, 100, 80, 70);
+ style.Colors[ImGuiCol_PopupBg] = ImColor(10, 23, 18, 230);
+ style.Colors[ImGuiCol_TextSelectedBg] = ImColor(10, 23, 18, 180);
+ style.Colors[ImGuiCol_FrameBg] = ImColor(70, 70, 70, 30);
+ style.Colors[ImGuiCol_FrameBgHovered] = ImColor(70, 70, 70, 70);
+ style.Colors[ImGuiCol_FrameBgActive] = ImColor(70, 70, 70, 50);
+ style.Colors[ImGuiCol_ComboBg] = ImColor(20, 20, 20, 252);
+
+ return S_OK;
+}
+
+void CommonUIController::DeviceDestroyed()
+{
+ ImGui_ImplDX11_Shutdown();
+}
+
+extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+LRESULT CommonUIController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PX_UNUSED(hWnd);
+ PX_UNUSED(wParam);
+ PX_UNUSED(lParam);
+
+ ImGui_ImplDX11_WndProcHandler(hWnd, uMsg, wParam, lParam);
+
+ if (uMsg == WM_KEYDOWN && !ImGui::GetIO().WantCaptureKeyboard)
+ {
+ int iKeyPressed = static_cast<int>(wParam);
+ switch (iKeyPressed)
+ {
+ case 'P':
+ {
+ getPhysXController().setPaused(!getPhysXController().isPaused());
+ break;
+ }
+ case 'O':
+ {
+ getRenderer().setWireframeMode(!getRenderer().getWireframeMode());
+ break;
+ }
+ case 'I':
+ {
+ getBlastController().debugRenderMode = (BlastFamily::DebugRenderMode)(((int)getBlastController().debugRenderMode + 1) % BlastFamily::DebugRenderMode::DEBUG_RENDER_MODES_COUNT);
+ break;
+ }
+ case VK_F5:
+ {
+ getRenderer().reloadShaders();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (ImGui::GetIO().WantCaptureMouse)
+ return 0;
+
+ return 1;
+}
+
+void CommonUIController::Animate(double fElapsedTimeSeconds)
+{
+ m_dt = (float)fElapsedTimeSeconds;
+}
+
+void CommonUIController::Render(ID3D11Device*, ID3D11DeviceContext*, ID3D11RenderTargetView*, ID3D11DepthStencilView*)
+{
+ ImGui_ImplDX11_NewFrame();
+ drawUI();
+ ImGui::Render();
+}
+
+void CommonUIController::addDelayedCall(const char* title, const char* message, std::function<void()> func, float delay)
+{
+ DelayedCall call = { func, title, message, delay, delay };
+ m_delayedCalls.emplace(call);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IMGUI UI
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+void CommonUIController::drawUI()
+{
+ const float padding = 8.0f;
+ ImGui::SetNextWindowPos(ImVec2(padding, padding), ImGuiSetCond_Once/*ImGuiSetCond_FirstUseEver*/);
+ ImGui::SetNextWindowSize(ImVec2(420, getRenderer().getScreenHeight() - 2 * padding), ImGuiSetCond_Once/*ImGuiSetCond_FirstUseEver*/);
+ ImGui::SetNextWindowCollapsed(false, ImGuiSetCond_Once);
+ ImGui::Begin("New Shiny UI", 0, ImGuiWindowFlags_NoTitleBar);
+ {
+ ImGui::PushItemWidth(ImGui::GetWindowSize().x * 0.5f);
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Scene
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Scene"))
+ {
+ getSceneController().drawUI();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Blast
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Blast"))
+ {
+ getBlastController().drawUI();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Damage Tool
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Damage Tool"))
+ {
+ getDamageToolController().drawUI();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Stats
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Stats"))
+ {
+ BlastController& blastController = getBlastController();
+
+ const char* prefix;
+ float sizeVal;
+
+ // FPS
+ double averageTime = GetDeviceManager()->GetAverageFrameTime();
+ float fps = (averageTime > 0) ? 1.0 / averageTime : 0.0;
+ float frameMs = 1000.0f / fps;
+ ImGui::Text("Frame Time %.3f ms (%.1f FPS)", frameMs, fps);
+
+ static PlotLinesInstance<> fpsPlot;
+ fpsPlot.plot("FPS", frameMs, "ms/frame", 0.0f, 100.0f);
+
+ // Render stats
+ ImGui::PushStyleColor(ImGuiCol_Text, ImColor(0xFF, 0x3B, 0xD8, 0xFF));
+ ImGui::Text("Draw Calls (Opaque/Transparent): %d/%d", getRenderer().getVisibleOpaqueRenderablesCount(), getRenderer().getVisibleTransparentRenderablesCount());
+ ImGui::PopStyleColor();
+
+ // Blast stats
+ const BlastTimers& timers = blastController.getLastBlastTimers();
+
+ ImGui::Text("Simulation Time: %.2f ms ", getPhysXController().getLastSimulationTime() * 1000);
+ ImGui::Text("Actor Count: %d", blastController.getActorCount());
+ ImGui::Text("Visible Chunk Count: %d", blastController.getTotalVisibleChunkCount());
+
+ getManager()->getSceneController().drawStatsUI();
+
+ sizeVal = memorySizeOutput(prefix, (float)blastController.getFamilySize());
+ ImGui::Text("Family Size: %.3g %sB", sizeVal, prefix);
+ sizeVal = memorySizeOutput(prefix, (float)blastController.getBlastAssetsSize());
+ ImGui::Text("Blast asset Data size: %.3g %sB", sizeVal, prefix);
+
+ //ImGui::Text(" Last Blast Extern Time: %8.3f ms", timers.mLastExternalTime * 1000);
+// ImGui::Text(" Last Damage Time: %8.3f ms", timers.blastDamage * 1000);
+#if NV_PROFILE
+ ImGui::Text("Last Material Time: %8.3f ms", timers.blastDamageMaterial * 1000);
+ ImGui::Text("Last Fracture Time: %8.3f ms", timers.blastDamageFracture * 1000);
+#endif
+// ImGui::Text("Last Physics Split Time: %.3f ms", timers.physicsSplit * 1000);
+#if NV_PROFILE
+ ImGui::Text("Last Island Time: %8.3f ms", timers.blastSplitIsland * 1000);
+ ImGui::Text("Last Partition Time: %8.3f ms", timers.blastSplitPartition * 1000);
+ ImGui::Text("Last Visibility Time: %8.3f ms", timers.blastSplitVisibility * 1000);
+#endif
+
+#if NV_PROFILE
+ // Sample Profiler
+ static bool s_showProfilerWindow = false;
+ if (ImGui::Button("Code Profiler"))
+ {
+ s_showProfilerWindow = !s_showProfilerWindow;
+ }
+ if (s_showProfilerWindow)
+ {
+ drawCodeProfiler(&s_showProfilerWindow);
+ }
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Application
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Application"))
+ {
+ // Paused
+ bool isPaused = getPhysXController().isPaused();
+ if (ImGui::Checkbox("Pause (P)", &isPaused))
+ {
+ getPhysXController().setPaused(isPaused);
+ }
+
+ // Reload Shaders
+ if (ImGui::Button("Reload Shaders (F5)"))
+ {
+ getRenderer().reloadShaders();
+ }
+
+ // ImGui Test Window (just in case)
+ static bool s_showTestWindow = false;
+ if (ImGui::Button("ImGui Test Window"))
+ {
+ s_showTestWindow = !s_showTestWindow;
+ }
+ if (s_showTestWindow)
+ {
+ ImGui::ShowTestWindow();
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Debug Render
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Debug Render"))
+ {
+ // WireFrame
+ bool wireFrameEnabled = getRenderer().getWireframeMode();
+ if (ImGui::Checkbox("WireFrame (O)", &wireFrameEnabled))
+ {
+ getRenderer().setWireframeMode(wireFrameEnabled);
+ }
+
+ // - - - - - - - -
+ ImGui::Spacing();
+
+ // Blast Debug Render Mode
+ const char* debugRenderItems[] =
+ {
+ "Disabled", // DEBUG_RENDER_DISABLED
+ "Health Graph", // DEBUG_RENDER_HEALTH_GRAPH
+ "Centroids", // DEBUG_RENDER_CENTROIDS
+ "Health Graph + Centroids", // DEBUG_RENDER_HEALTH_GRAPH_CENTROIDS
+ "Joints", // DEBUG_RENDER_JOINTS
+ "Stress Graph", // DEBUG_RENDER_STRESS_GRAPH
+ "Stress Graph + Nodes Impulses", // DEBUG_RENDER_STRESS_GRAPH_NODES_IMPULSES
+ "Stress Graph + Bonds Impulses" // DEBUG_RENDER_STRESS_GRAPH_BONDS_IMPULSES
+ };
+ ImGui::Combo("Blast Debug Render Mode (I)", (int*)&getBlastController().debugRenderMode, debugRenderItems, IM_ARRAYSIZE(debugRenderItems), -1);
+
+ // Blast Debug Render Scale
+ ImGui::DragFloat("Blast Debug Render Scale", &getBlastController().debugRenderScale, 0.01f, 0.0f, 10.0f, "%.3f", 4.0f);
+
+ // - - - - - - - -
+ ImGui::Spacing();
+
+ // PhysX Debug Render
+ if (ImGui::TreeNode("PhysX Debug Render"))
+ {
+ auto addParam = [&](physx::PxVisualizationParameter::Enum param, const char* uiName)
+ {
+ bool enabled = getPhysXController().getPhysXScene().getVisualizationParameter(param) != 0;
+ if (ImGui::Checkbox(uiName, &enabled))
+ {
+ getPhysXController().getPhysXScene().setVisualizationParameter(param, enabled ? 1.0f : 0.0f);
+ }
+ };
+
+ addParam(PxVisualizationParameter::eSCALE, "Scale");
+ addParam(PxVisualizationParameter::eBODY_AXES, "Body Axes");
+ addParam(PxVisualizationParameter::eWORLD_AXES, "World Axes");
+ addParam(PxVisualizationParameter::eBODY_MASS_AXES, "Body Mass Axes");
+ addParam(PxVisualizationParameter::eBODY_LIN_VELOCITY, "Body Lin Velocity");
+ addParam(PxVisualizationParameter::eBODY_ANG_VELOCITY, "Body Ang Velocity");
+ addParam(PxVisualizationParameter::eBODY_JOINT_GROUPS, "Body Joint");
+ addParam(PxVisualizationParameter::eCONTACT_POINT, "Contact Point");
+ addParam(PxVisualizationParameter::eCONTACT_NORMAL, "Contact Normal");
+ addParam(PxVisualizationParameter::eCONTACT_ERROR, "Contact Error");
+ addParam(PxVisualizationParameter::eCONTACT_FORCE, "Contact Force");
+ addParam(PxVisualizationParameter::eACTOR_AXES, "Actor Axes");
+ addParam(PxVisualizationParameter::eCOLLISION_AABBS, "Collision AABBs");
+ addParam(PxVisualizationParameter::eCOLLISION_SHAPES, "Collision Shapes");
+ addParam(PxVisualizationParameter::eCOLLISION_AXES, "Collision Axes");
+ addParam(PxVisualizationParameter::eCOLLISION_COMPOUNDS, "Collision Compounds");
+ addParam(PxVisualizationParameter::eCOLLISION_FNORMALS, "Collision FNormals");
+ addParam(PxVisualizationParameter::eCOLLISION_EDGES, "Collision Edges");
+ addParam(PxVisualizationParameter::eCOLLISION_STATIC, "Collision Static");
+ addParam(PxVisualizationParameter::eCOLLISION_DYNAMIC, "Collision Dynamic");
+ //addParam(PxVisualizationParameter::eDEPRECATED_COLLISION_PAIRS, "Collision Pairs");
+ addParam(PxVisualizationParameter::eJOINT_LOCAL_FRAMES, "Joint Local Frames");
+ addParam(PxVisualizationParameter::eJOINT_LIMITS, "Joint Limits");
+ //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_POSITION, "PS Position");
+ //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_VELOCITY, "PS Velocity");
+ //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_COLLISION_NORMAL, "PS Collision Normal");
+ //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_BOUNDS, "PS Bounds");
+ //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_GRID, "PS Grid");
+ //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_BROADPHASE_BOUNDS, "PS Broadphase Bounds");
+ //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_MAX_MOTION_DISTANCE, "PS Max Motion Distance");
+ addParam(PxVisualizationParameter::eCULL_BOX, "Cull Box");
+ //addParam(PxVisualizationParameter::eCLOTH_VERTICAL, "Cloth Vertical");
+ //addParam(PxVisualizationParameter::eCLOTH_HORIZONTAL, "Cloth Horizontal");
+ //addParam(PxVisualizationParameter::eCLOTH_BENDING, "Cloth Bending");
+ //addParam(PxVisualizationParameter::eCLOTH_SHEARING, "Cloth Shearing");
+ //addParam(PxVisualizationParameter::eCLOTH_VIRTUAL_PARTICLES, "Cloth Virtual Particles");
+ addParam(PxVisualizationParameter::eMBP_REGIONS, "MBP Regions");
+
+ ImGui::TreePop();
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // PhysX
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("PhysX"))
+ {
+ // PhysX
+ getPhysXController().drawUI();
+
+ // GPU
+ getSampleController().drawPhysXGpuUI();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Renderer
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Renderer"))
+ {
+ getRenderer().drawUI();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Hints
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (ImGui::CollapsingHeader("Hints / Help"))
+ {
+ ImGui::BulletText("Rotate camera - RMB");
+ ImGui::BulletText("Move camera - WASDQE(SHIFT)");
+ ImGui::BulletText("Play/Pause - P");
+ ImGui::BulletText("Reload shaders - F5");
+ ImGui::BulletText("Wireframe - O");
+ ImGui::BulletText("Blast Debug Render - I");
+ ImGui::BulletText("Apply damage - LMB");
+ ImGui::BulletText("Damage radius - +/-/wheel");
+ ImGui::BulletText("Damage profile - 1-9");
+ ImGui::BulletText("Explosive - X");
+ ImGui::BulletText("Throw cube - F");
+ ImGui::BulletText("Restart - R");
+ }
+
+ ImGui::PopItemWidth();
+ }
+ ImGui::End();
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Mode Text
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ {
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4());
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0));
+
+ const char* text = getDamageToolController().isDamageMode() ? "DAMAGE MODE (PRESS SPACE)" : "DRAG MODE (PRESS SPACE)";
+ ImVec2 size = ImGui::CalcTextSize(text);
+ ImGui::SetNextWindowPos(ImVec2((getRenderer().getScreenWidth() - size.x) / 2, 0));
+ ImGui::Begin("Mode Text", 0, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar);
+ ImGui::Text(text);
+ ImGui::End();
+
+ ImGui::PopStyleVar();
+ ImGui::PopStyleColor();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // FPS
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ {
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4());
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
+
+ double averageTime = GetDeviceManager()->GetAverageFrameTime();
+ float fps = (averageTime > 0) ? 1.0 / averageTime : 0.0;
+ static char buf[32];
+ std::sprintf(buf, "%.1f FPS", fps);
+ ImVec2 size = ImGui::CalcTextSize(buf);
+
+ size.x += 20.0;
+ ImGui::SetNextWindowSize(size);
+ ImGui::SetNextWindowPos(ImVec2(getRenderer().getScreenWidth() - size.x, 0));
+ ImGui::Begin("FPS", 0, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar);
+ ImGui::Text(buf);
+ ImGui::End();
+
+ ImGui::PopStyleVar();
+ ImGui::PopStyleColor();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Loading overlay
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ if (!m_delayedCalls.empty())
+ {
+ DelayedCall& call = m_delayedCalls.front();
+ if (call.delay > 0)
+ {
+ const int height = 50;
+ const char* message = call.message;
+ const float alpha = PxClamp(lerp(0.0f, 1.0f, (call.delayTotal - call.delay) * 10.0f), 0.0f, 1.0f);
+
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, ImColor(0, 0, 0, 200));
+ ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
+ ImGui::SetNextWindowPosCenter();
+ ImVec2 size = ImGui::CalcTextSize(message);
+ int width = std::max<float>(200, size.x) + 50;
+ ImGui::SetNextWindowSize(ImVec2(width, height));
+ ImGui::Begin(call.title, 0, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar);
+ ImGui::SetCursorPos(ImVec2((width - size.x) * 0.5f, (height - size.y) * 0.5f));
+ ImGui::Text(message);
+ ImGui::End();
+ ImGui::PopStyleVar();
+ ImGui::PopStyleColor();
+
+ call.delay -= PxClamp(m_dt, 0.0f, 0.1f);
+ }
+ else
+ {
+ call.func();
+ m_delayedCalls.pop();
+ }
+ }
+}
+
+
+void CommonUIController::drawCodeProfiler(bool* open)
+{
+ ImGuiWindowFlags window_flags = 0;
+ const float padding = 8.0f;
+ const float width = 550;
+ const float height = 580;
+ ImGui::SetNextWindowPos(ImVec2(getRenderer().getScreenWidth() - width - padding, padding), ImGuiSetCond_Once/*ImGuiSetCond_FirstUseEver*/);
+ ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiSetCond_Once);
+ if (!ImGui::Begin("Code Profiler", open, window_flags))
+ {
+ // Early out if the window is collapsed, as an optimization.
+ ImGui::End();
+ return;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Control/Main Bar
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ {
+ if (ImGui::Button("Reset"))
+ {
+ PROFILER_INIT();
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("Dump To File (profile.txt)"))
+ {
+ SampleProfilerDumpToFile("profile.txt");
+ }
+ ImGui::SameLine();
+ ImGui::Text("Profiler overhead: %2.3f ms", SampleProfilerGetOverhead().count() * 0.001f);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Legend
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ {
+ ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing();
+ ImGui::Text("Legend: name | calls | time | max time");
+ ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Stats Tree
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ ImGui::SetNextTreeNodeOpen(true, ImGuiSetCond_Once);
+ float plotMS = 0.0f;
+ float plotMaxMS = 0.0f;
+ const char* plotName = nullptr;
+ if (ImGui::TreeNode("Root"))
+ {
+ auto treeIt = SampleProfilerCreateTreeIterator();
+ if (treeIt)
+ {
+ uint32_t depth = 1;
+ uint32_t openeDepth = 1;
+ while (!treeIt->isDone())
+ {
+ const auto data = treeIt->data();
+
+ while (data->depth < depth)
+ {
+ ImGui::TreePop();
+ depth--;
+ }
+
+ const uint32_t maxLen = 30;
+ auto hash = data->hash;
+ static uint64_t selectedNodeHash = 0;
+ if (selectedNodeHash == hash)
+ {
+ plotMS = data->time.count() * 0.001f;
+ plotMaxMS = data->maxTime.count() * 0.001f;
+ plotName = data->name;
+ }
+ if (ImGui::TreeNodeEx(data->name, data->hasChilds ? 0 : ImGuiTreeNodeFlags_Leaf, "%-*.*s | %d | %2.3f ms | %2.3f ms",
+ maxLen, maxLen, data->name, data->calls, data->time.count() * 0.001f, data->maxTime.count() * 0.001f))
+ {
+ depth++;
+ treeIt->next();
+ }
+ else
+ {
+ treeIt->next();
+ while (!treeIt->isDone() && treeIt->data()->depth > depth)
+ treeIt->next();
+ }
+
+ if (ImGui::IsItemClicked())
+ {
+ selectedNodeHash = hash;
+ }
+ }
+
+ while (depth > 0)
+ {
+ ImGui::TreePop();
+ depth--;
+ }
+
+ treeIt->release();
+ }
+ else
+ {
+ ImGui::Text("Profiler Is Broken. Begin/End Mismatch.");
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // Selected Item Plot
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ {
+ ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing();
+ if (plotName)
+ {
+ static PlotLinesInstance<> selectedNodePlot;
+ selectedNodePlot.plot("", plotMS, plotName, 0.0f, plotMaxMS);
+ }
+ else
+ {
+ ImGui::Text("Select item to plot.");
+ }
+ }
+
+ ImGui::End();
+} \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.h b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.h
new file mode 100644
index 0000000..da62674
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.h
@@ -0,0 +1,106 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#ifndef COMMON_UI_CONTROLLER_H
+#define COMMON_UI_CONTROLLER_H
+
+#include "SampleManager.h"
+#include <DirectXMath.h>
+#include <string>
+#include <list>
+#include <queue>
+#include <functional>
+
+
+class Renderer;
+class PhysXController;
+class BlastController;
+
+
+class CommonUIController : public ISampleController
+{
+ public:
+ CommonUIController();
+ virtual ~CommonUIController() {};
+
+ virtual HRESULT DeviceCreated(ID3D11Device* pDevice);
+ virtual void DeviceDestroyed();
+ virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual void Animate(double fElapsedTimeSeconds);
+ virtual void Render(ID3D11Device*, ID3D11DeviceContext*, ID3D11RenderTargetView*, ID3D11DepthStencilView*);
+
+ void addDelayedCall(std::function<void()> func, const char* message)
+ {
+ addDelayedCall("PLEASE WAIT...", message, func);
+ }
+
+ void addPopupMessage(const char* title, const char* message, float duration = 2.f)
+ {
+ addDelayedCall(title, message, [] {}, duration);
+ }
+
+ private:
+ void addDelayedCall(const char* title, const char* message, std::function<void()> func, float delay = 0.1f);
+
+ void drawUI();
+ void drawCodeProfiler(bool*);
+
+
+ //////// used controllers ////////
+
+ Renderer& getRenderer() const
+ {
+ return getManager()->getRenderer();
+ }
+
+ PhysXController& getPhysXController() const
+ {
+ return getManager()->getPhysXController();
+ }
+
+ BlastController&getBlastController() const
+ {
+ return getManager()->getBlastController();
+ }
+
+ DamageToolController& getDamageToolController() const
+ {
+ return getManager()->getDamageToolController();
+ }
+
+ SceneController& getSceneController() const
+ {
+ return getManager()->getSceneController();
+ }
+
+ SampleController& getSampleController() const
+ {
+ return getManager()->getSampleController();
+ }
+
+
+ //////// internal data ////////
+
+ struct DelayedCall
+ {
+ std::function<void()> func;
+ const char* title;
+ const char* message;
+ float delay;
+ float delayTotal;
+ };
+
+ std::queue<DelayedCall> m_delayedCalls;
+
+ float m_dt;
+
+};
+
+#endif \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.cpp b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.cpp
new file mode 100644
index 0000000..fba1227
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.cpp
@@ -0,0 +1,294 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include "DamageToolController.h"
+#include "RenderUtils.h"
+#include "BlastController.h"
+#include "Renderer.h"
+#include "PhysXController.h"
+#include "SampleProfiler.h"
+
+#include <imgui.h>
+
+#include "NvBlastTkActor.h"
+#include "NvBlastExtDamageShaders.h"
+#include "NvBlastExtPxActor.h"
+
+#include "PxRigidDynamic.h"
+#include "PxScene.h"
+
+
+using namespace Nv::Blast;
+using namespace physx;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Setup
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+const DirectX::XMFLOAT4 PICK_POINTER_ACTIVE_COLOR(1.0f, 0.f, 0.f, 0.6f);
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+DamageToolController::DamageToolController()
+ : m_damageRadius(5.0f), m_compressiveDamage(1.0f), m_pickPointerColor(1.0f, 1.0f, 1.0f, 0.4f),
+ m_pickPointerRenderMaterial(nullptr), m_pickPointerRenderable(nullptr), m_explosiveImpulse(100), m_damageProfile(0), m_stressForceFactor(1.0f)
+{
+ // Damage functions
+ auto radialDamageExecute = [&](const Damager* damager, ExtPxActor* actor, PxVec3 position, PxVec3 normal)
+ {
+ NvBlastExtRadialDamageDesc desc =
+ {
+ m_compressiveDamage,
+ { position.x, position.y, position.z },
+ m_damageRadius,
+ m_damageRadius + 2.0f
+ };
+
+ actor->getTkActor().damage(damager->program, &desc, sizeof(desc));
+ };
+ auto shearDamageExecute = [&](const Damager* damager, ExtPxActor* actor, PxVec3 position, PxVec3 normal)
+ {
+ PxVec3 force = -2 * normal;
+
+ NvBlastExtShearDamageDesc desc =
+ {
+ { force.x, force.y, force.z },
+ { position.x, position.y, position.z }
+ };
+
+ actor->getTkActor().damage(damager->program, &desc, sizeof(desc));
+ };
+ auto stressDamageExecute = [&](const Damager* damager, ExtPxActor* actor, PxVec3 position, PxVec3 normal)
+ {
+ PxVec3 force = -m_stressForceFactor * normal * actor->getPhysXActor().getMass();
+
+ getBlastController().stressDamage(actor, position, force);
+ };
+
+ // Damage Tools:
+ {
+ Damager dam;
+ dam.uiName = "Radial Damage (Falloff)";
+ dam.program = NvBlastDamageProgram { NvBlastExtFalloffGraphShader, NvBlastExtFalloffSubgraphShader };
+ dam.pointerColor = DirectX::XMFLOAT4(1.0f, 1.0f, 1.0f, 0.4f);
+ dam.executeFunction = radialDamageExecute;
+ m_armory.push_back(dam);
+ }
+ {
+ Damager dam;
+ dam.uiName = "Radial Damage (Cutter)";
+ dam.program = NvBlastDamageProgram { NvBlastExtCutterGraphShader, NvBlastExtCutterSubgraphShader };
+ dam.pointerColor = DirectX::XMFLOAT4(0.5f, 0.5f, 1.0f, 0.4f);
+ dam.executeFunction = radialDamageExecute;
+ m_armory.push_back(dam);
+ }
+
+ {
+ Damager dam;
+ dam.uiName = "Shear Damage";
+ dam.program = NvBlastDamageProgram { NvBlastExtShearGraphShader, NvBlastExtShearSubgraphShader };
+ dam.pointerColor = DirectX::XMFLOAT4(0.5f, 1.0f, 0.5f, 0.4f);
+ dam.executeFunction = shearDamageExecute;
+ m_armory.push_back(dam);
+ }
+
+ {
+ Damager dam;
+ dam.uiName = "Stress Damage";
+ dam.program = { nullptr, nullptr };
+ dam.pointerColor = DirectX::XMFLOAT4(0.5f, 0.5f, 1.0f, 0.4f);
+ dam.executeFunction = stressDamageExecute;
+ m_armory.push_back(dam);
+ }
+
+ for (const Damager& d : m_armory)
+ {
+ m_armoryNames.push_back(d.uiName);
+ }
+}
+
+DamageToolController::~DamageToolController()
+{
+}
+
+void DamageToolController::onSampleStart()
+{
+ // pick pointer
+// Add By Lixu Begin
+ m_pickPointerRenderMaterial = new RenderMaterial("", getRenderer().getResourceManager(), "physx_primitive_transparent", "", RenderMaterial::BLEND_ALPHA_BLENDING);
+// Add By Lixu End
+ IRenderMesh* mesh = getRenderer().getPrimitiveRenderMesh(PrimitiveRenderMeshType::Sphere);
+ m_pickPointerRenderable = getRenderer().createRenderable(*mesh, *m_pickPointerRenderMaterial);
+ m_pickPointerRenderable->setScale(PxVec3(m_damageRadius));
+
+ // default tool
+ setDamageProfile(0);
+
+ // start with damage mode by default
+ setDamageMode(true);
+}
+
+void DamageToolController::onInitialize()
+{
+}
+
+
+void DamageToolController::onSampleStop()
+{
+ getRenderer().removeRenderable(m_pickPointerRenderable);
+ SAFE_DELETE(m_pickPointerRenderMaterial);
+}
+
+void DamageToolController::Animate(double dt)
+{
+ PROFILER_SCOPED_FUNCTION();
+
+ m_pickPointerColor = XMFLOAT4Lerp(m_pickPointerColor, m_armory[m_damageProfile].pointerColor, dt * 5.0f);
+ m_pickPointerRenderable->setColor(m_pickPointerColor);
+}
+
+
+LRESULT DamageToolController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PROFILER_SCOPED_FUNCTION();
+
+ if (uMsg == WM_LBUTTONDOWN || uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONUP)
+ {
+ float mouseX = (short)LOWORD(lParam) / getRenderer().getScreenWidth();
+ float mouseY = (short)HIWORD(lParam) / getRenderer().getScreenHeight();
+ bool press = uMsg == WM_LBUTTONDOWN;
+
+ // damage mode
+ if (m_damageMode && m_pickPointerRenderable)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxRaycastHit hit; hit.shape = NULL;
+ PxRaycastBuffer hit1;
+ getPhysXController().getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION | PxHitFlag::eNORMAL);
+ hit = hit1.block;
+
+ if (hit.shape)
+ {
+ PxRigidActor* actor = hit.actor;
+ m_pickPointerRenderable->setHidden(false);
+ m_pickPointerRenderable->setTransform(PxTransform(hit.position));
+
+ if (press)
+ {
+ damage(hit.position, hit.normal);
+ m_pickPointerColor = PICK_POINTER_ACTIVE_COLOR;
+ }
+ }
+ else
+ {
+ m_pickPointerRenderable->setHidden(true);
+ }
+ }
+ }
+
+ if (uMsg == WM_MOUSEWHEEL)
+ {
+ int delta = int((short)HIWORD(wParam)) / WHEEL_DELTA;
+ changeDamageRadius(delta * 0.3f);
+ }
+
+ if (uMsg == WM_KEYDOWN)
+ {
+ int iKeyPressed = static_cast<int>(wParam);
+ if (iKeyPressed == VK_OEM_PLUS)
+ {
+ changeDamageRadius(0.2f);
+ }
+ else if (iKeyPressed == VK_OEM_MINUS)
+ {
+ changeDamageRadius(-0.2f);
+ }
+ else if (iKeyPressed >= '1' && iKeyPressed <= '9')
+ {
+ uint32_t num = PxClamp<uint32_t>(iKeyPressed - '1', 0, (uint32_t)m_armory.size() - 1);
+ setDamageProfile(num);
+ }
+ else if (iKeyPressed == VK_SPACE)
+ {
+ setDamageMode(!isDamageMode());
+ }
+
+ }
+
+ return 1;
+}
+
+void DamageToolController::drawUI()
+{
+ ImGui::DragFloat("Compressive Damage", &m_compressiveDamage, 0.05f);
+ ImGui::DragFloat("Explosive Impulse", &m_explosiveImpulse);
+ ImGui::DragFloat("Damage Radius (Mouse WH)", &m_damageRadius);
+ ImGui::DragFloat("Stress Damage Force", &m_stressForceFactor);
+
+ // - - - - - - - -
+ ImGui::Spacing();
+
+ // Armory
+ if (ImGui::Combo("Damage Profile", (int*)&m_damageProfile, m_armoryNames.data(), (int)m_armoryNames.size(), -1))
+ {
+ setDamageProfile(m_damageProfile);
+ }
+}
+
+
+void DamageToolController::setDamageMode(bool enabled)
+{
+ m_damageMode = enabled;
+
+ getPhysXController().setDraggingEnabled(!m_damageMode);
+
+ if (!m_damageMode)
+ {
+ m_pickPointerRenderable->setHidden(true);
+ }
+}
+
+
+void DamageToolController::setDamageProfile(uint32_t profile)
+{
+ m_damageProfile = profile;
+}
+
+
+void DamageToolController::changeDamageRadius(float dr)
+{
+ m_damageRadius += dr;
+ m_damageRadius = PxMax(1.0f, m_damageRadius);
+ m_pickPointerRenderable->setScale(PxVec3(m_damageRadius));
+}
+
+
+void DamageToolController::damage(physx::PxVec3 position, physx::PxVec3 normal)
+{
+ auto damageFunction = [&](ExtPxActor* actor)
+ {
+ auto t0 = actor->getPhysXActor().getGlobalPose();
+ PxTransform t(t0.getInverse());
+ PxVec3 localNormal = t.rotate(normal);
+ PxVec3 localPosition = t.transform(position);
+ Damager& damager = m_armory[m_damageProfile];
+ damager.execute(actor, localPosition, localNormal);
+ };
+
+ this->getBlastController().blast(position, m_damageRadius, m_explosiveImpulse, damageFunction);
+
+}
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.h b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.h
new file mode 100644
index 0000000..b6712f2
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.h
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#ifndef DAMAGE_TOOL_CONTROLLER_H
+#define DAMAGE_TOOL_CONTROLLER_H
+
+#include "SampleManager.h"
+#include "NvBlastTypes.h"
+#include <DirectXMath.h>
+#include <functional>
+#include "PxVec3.h"
+
+
+class Renderable;
+class RenderMaterial;
+
+namespace Nv
+{
+namespace Blast
+{
+class ExtPxActor;
+}
+}
+
+
+
+class DamageToolController : public ISampleController
+{
+public:
+ DamageToolController();
+ virtual ~DamageToolController();
+
+ virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual void Animate(double dt);
+ void drawUI();
+
+
+ virtual void onInitialize();
+ virtual void onSampleStart();
+ virtual void onSampleStop();
+
+ bool isDamageMode() const
+ {
+ return m_damageMode;
+ }
+
+// Add By Lixu Begin
+ Renderable* getPickPointer()
+ {
+ return m_pickPointerRenderable;
+ }
+// Add By Lixu End
+
+private:
+ DamageToolController& operator= (DamageToolController&);
+
+
+ //////// private methods ////////
+
+ void damage(physx::PxVec3 position, physx::PxVec3 normal);
+
+ void setDamageProfile(uint32_t profile);
+ uint32_t getDamageProfile() const
+ {
+ return m_damageProfile;
+ }
+
+ void changeDamageRadius(float dr);
+
+ void setDamageMode(bool enabled);
+
+
+ //////// used controllers ////////
+
+ Renderer& getRenderer() const
+ {
+ return getManager()->getRenderer();
+ }
+
+ PhysXController& getPhysXController() const
+ {
+ return getManager()->getPhysXController();
+ }
+
+ BlastController& getBlastController() const
+ {
+ return getManager()->getBlastController();
+ }
+
+
+ //////// internal data ////////
+
+ Renderable* m_pickPointerRenderable;
+ RenderMaterial* m_pickPointerRenderMaterial;
+ DirectX::XMFLOAT4 m_pickPointerColor;
+
+ float m_damageRadius;
+ float m_compressiveDamage;
+ float m_explosiveImpulse;
+ float m_stressForceFactor;
+ uint32_t m_damageProfile;
+
+ struct Damager
+ {
+ const char* uiName;
+ NvBlastDamageProgram program;
+ DirectX::XMFLOAT4 pointerColor;
+ std::function<void(const Damager* damager, Nv::Blast::ExtPxActor* actor, physx::PxVec3 position, physx::PxVec3 normal)> executeFunction;
+
+ void execute(Nv::Blast::ExtPxActor* actor, physx::PxVec3 position, physx::PxVec3 normal)
+ {
+ executeFunction(this, actor, position, normal);
+ }
+ };
+
+ std::vector<Damager> m_armory;
+ std::vector<const char*> m_armoryNames;
+
+ bool m_damageMode;
+};
+
+#endif \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.cpp b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.cpp
new file mode 100644
index 0000000..244f121
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.cpp
@@ -0,0 +1,158 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include "EditionToolController.h"
+#include "BlastController.h"
+#include "Renderer.h"
+#include "PhysXController.h"
+#include "SampleProfiler.h"
+#include "PxRigidDynamic.h"
+#include "PxScene.h"
+#include "NvBlastExtPxManager.h"
+#include "SceneController.h"
+#include "NvBlastExtPxActor.h"
+#include "GlobalSettings.h"
+using namespace Nv::Blast;
+using namespace physx;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Setup
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+EditionToolController::EditionToolController()
+{
+}
+
+EditionToolController::~EditionToolController()
+{
+}
+
+void EditionToolController::onSampleStart()
+{
+}
+
+void EditionToolController::onInitialize()
+{
+}
+
+
+void EditionToolController::onSampleStop()
+{
+}
+
+void EditionToolController::Animate(double dt)
+{
+ PROFILER_SCOPED_FUNCTION();
+}
+
+
+LRESULT EditionToolController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PROFILER_SCOPED_FUNCTION();
+
+ if (uMsg == WM_LBUTTONDOWN || uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONUP)
+ {
+ float mouseX = (short)LOWORD(lParam) / getRenderer().getScreenWidth();
+ float mouseY = (short)HIWORD(lParam) / getRenderer().getScreenHeight();
+ bool press = uMsg == WM_LBUTTONDOWN;
+
+ if (uMsg == WM_LBUTTONUP)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxRaycastHit hit; hit.shape = NULL;
+ PxRaycastBuffer hit1;
+ getPhysXController().getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION | PxHitFlag::eNORMAL);
+ hit = hit1.block;
+
+ PxRigidActor* actor = NULL;
+ if (hit.shape)
+ {
+ actor = hit.actor;
+ }
+ fracture(actor);
+ }
+ }
+
+ return 1;
+}
+
+void EditionToolController::drawUI()
+{
+}
+
+void EditionToolController::fracture(PxActor* actor)
+{
+ if (NULL == actor)
+ {
+ return;
+ }
+
+ BlastController& blastController = getBlastController();
+ std::vector<BlastFamilyPtr>& families = blastController.getFamilies();
+ if (families.size() == 0)
+ {
+ return;
+ }
+
+ ExtPxActor* extActor = NULL;
+ PxRigidDynamic* rigidDynamic = actor->is<PxRigidDynamic>();
+ if (NULL != rigidDynamic)
+ {
+ extActor = blastController.getExtPxManager().getActorFromPhysXActor(*rigidDynamic);
+ }
+ if (NULL == extActor)
+ {
+ return;
+ }
+
+ uint32_t chunkCount = extActor->getChunkCount();
+ if (chunkCount <= 0)
+ {
+ return;
+ }
+
+ BlastFamilyPtr pBlastFamily = NULL;
+ std::vector<BlastFamilyPtr>::iterator it = families.begin();
+ for (; it != families.end(); it++)
+ {
+ BlastFamilyPtr f = *it;
+ if (f->find(extActor))
+ {
+ pBlastFamily = f;
+ break;
+ }
+ }
+ if (NULL == pBlastFamily)
+ {
+ return;
+ }
+
+ const uint32_t* chunkIndices = extActor->getChunkIndices();
+
+ const BlastAsset& blastAsset = pBlastFamily->getBlastAsset();
+ const BlastAsset* pBlastAsset = &blastAsset;
+
+ SceneController& sceneController = getManager()->getSceneController();
+ AssetList::ModelAsset desc;
+ sceneController.GetAssetDesc(pBlastAsset, desc);
+
+ std::string assetname = desc.id;
+ GlobalSettings& globalSettings = GlobalSettings::Inst();
+ getManager()->fractureAsset(globalSettings.m_projectFileDir, assetname, pBlastAsset, chunkIndices[0]);
+ getManager()->addModelAsset(globalSettings.m_projectFileDir, assetname, desc.isSkinned, desc.transform, false);
+} \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.h b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.h
new file mode 100644
index 0000000..b1e88d1
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.h
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#ifndef EDITION_TOOL_CONTROLLER_H
+#define EDITION_TOOL_CONTROLLER_H
+
+#include "SampleManager.h"
+
+namespace physx
+{
+ class PxActor;
+}
+
+class EditionToolController : public ISampleController
+{
+public:
+ EditionToolController();
+ virtual ~EditionToolController();
+
+ virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual void Animate(double dt);
+ void drawUI();
+
+ virtual void onInitialize();
+ virtual void onSampleStart();
+ virtual void onSampleStop();
+
+ void fracture(physx::PxActor* actor);
+
+private:
+ EditionToolController& operator= (EditionToolController&);
+
+ //////// private methods ////////
+
+ //////// used controllers ////////
+
+ Renderer& getRenderer() const
+ {
+ return getManager()->getRenderer();
+ }
+
+ PhysXController& getPhysXController() const
+ {
+ return getManager()->getPhysXController();
+ }
+
+ BlastController& getBlastController() const
+ {
+ return getManager()->getBlastController();
+ }
+
+ //////// internal data ////////
+};
+
+#endif // EDITION_TOOL_CONTROLLER_H \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.cpp b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.cpp
new file mode 100644
index 0000000..ff0ffa9
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.cpp
@@ -0,0 +1,1210 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include "GizmoToolController.h"
+#include "RenderUtils.h"
+#include "BlastController.h"
+#include "SelectionToolController.h"
+#include "Renderer.h"
+#include "PhysXController.h"
+#include "SampleProfiler.h"
+
+#include <imgui.h>
+
+#include "NvBlastTkActor.h"
+#include "NvBlastExtDamageShaders.h"
+
+#include "PxRigidDynamic.h"
+#include "PxScene.h"
+#include <AppMainWindow.h>
+
+
+using namespace Nv::Blast;
+using namespace physx;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Setup
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+const DirectX::XMFLOAT4 X_DIRECTION_COLOR_F = DirectX::XMFLOAT4(1, 0, 0, 1);
+const DirectX::XMFLOAT4 Y_DIRECTION_COLOR_F = DirectX::XMFLOAT4(0, 1, 0, 1);
+const DirectX::XMFLOAT4 Z_DIRECTION_COLOR_F = DirectX::XMFLOAT4(0, 0, 1, 1);
+const DirectX::XMFLOAT4 HIGHLIGHT_COLOR_F = DirectX::XMFLOAT4(1, 1, 0, 1);
+
+const physx::PxU32 X_DIRECTION_COLOR_U = XMFLOAT4ToU32Color(X_DIRECTION_COLOR_F);
+const physx::PxU32 Y_DIRECTION_COLOR_U = XMFLOAT4ToU32Color(Y_DIRECTION_COLOR_F);
+const physx::PxU32 Z_DIRECTION_COLOR_U = XMFLOAT4ToU32Color(Z_DIRECTION_COLOR_F);
+const physx::PxU32 HIGHLIGHT_COLOR_U = XMFLOAT4ToU32Color(HIGHLIGHT_COLOR_F);
+
+const float defaultAxisLength = 10.0;
+const float defaultAxisModifier = -1.0;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+GizmoToolController::GizmoToolController()
+{
+ m_bGizmoFollowed = false;
+
+ int segment = 36;
+ double span = PxTwoPi / segment;
+ PxVec3* vertex = new PxVec3[segment];
+
+ for (int i = 0; i < segment; i++)
+ {
+ vertex[i].x = 0;
+ vertex[i].y = 10 * PxSin(i * span);
+ vertex[i].z = 10 * PxCos(i * span);
+ }
+ // x
+ for (int i = 0; i < segment - 1; i++)
+ {
+ m_CircleRenderData.push_back(PxDebugLine(vertex[i], vertex[i + 1], X_DIRECTION_COLOR_U));
+ }
+ m_CircleRenderData.push_back(PxDebugLine(vertex[segment - 1], vertex[0], X_DIRECTION_COLOR_U));
+
+ for (int i = 0; i < segment; i++)
+ {
+ vertex[i].x = 10 * PxCos(i * span);
+ vertex[i].y = 0;
+ vertex[i].z = 10 * PxSin(i * span);
+ }
+ // y
+ for (int i = 0; i < segment - 1; i++)
+ {
+ m_CircleRenderData.push_back(PxDebugLine(vertex[i], vertex[i + 1], Y_DIRECTION_COLOR_U));
+ }
+ m_CircleRenderData.push_back(PxDebugLine(vertex[segment - 1], vertex[0], Y_DIRECTION_COLOR_U));
+
+ for (int i = 0; i < segment; i++)
+ {
+ vertex[i].x = 10 * PxCos(i * span);
+ vertex[i].y = 10 * PxSin(i * span);
+ vertex[i].z = 0;
+ }
+ // z
+ for (int i = 0; i < segment - 1; i++)
+ {
+ m_CircleRenderData.push_back(PxDebugLine(vertex[i], vertex[i + 1], Z_DIRECTION_COLOR_U));
+ }
+ m_CircleRenderData.push_back(PxDebugLine(vertex[segment - 1], vertex[0], Z_DIRECTION_COLOR_U));
+
+ delete[] vertex;
+ vertex = NULL;
+
+ resetPos();
+}
+
+GizmoToolController::~GizmoToolController()
+{
+}
+
+void GizmoToolController::onSampleStart()
+{
+ m_AxisRenderMaterial = new RenderMaterial("", getRenderer().getResourceManager(), "physx_primitive_transparent");
+
+ IRenderMesh* coneMesh = getRenderer().getPrimitiveRenderMesh(PrimitiveRenderMeshType::Cone);
+ m_AxisConeRenderable[AT_X] = getRenderer().createRenderable(*coneMesh, *m_AxisRenderMaterial);
+ m_AxisConeRenderable[AT_Y] = getRenderer().createRenderable(*coneMesh, *m_AxisRenderMaterial);
+ m_AxisConeRenderable[AT_Z] = getRenderer().createRenderable(*coneMesh, *m_AxisRenderMaterial);
+ m_AxisConeRenderable[AT_X]->setColor(X_DIRECTION_COLOR_F);
+ m_AxisConeRenderable[AT_Y]->setColor(Y_DIRECTION_COLOR_F);
+ m_AxisConeRenderable[AT_Z]->setColor(Z_DIRECTION_COLOR_F);
+ m_AxisConeRenderable[AT_X]->setScale(PxVec3(0.5, 1, 0.5));
+ m_AxisConeRenderable[AT_Y]->setScale(PxVec3(0.5, 1, 0.5));
+ m_AxisConeRenderable[AT_Z]->setScale(PxVec3(0.5, 1, 0.5));
+ m_AxisConeRenderable[AT_X]->setHidden(true);
+ m_AxisConeRenderable[AT_Y]->setHidden(true);
+ m_AxisConeRenderable[AT_Z]->setHidden(true);
+
+ IRenderMesh* boxMesh = getRenderer().getPrimitiveRenderMesh(PrimitiveRenderMeshType::Box);
+ m_AxisBoxRenderable[AT_X] = getRenderer().createRenderable(*boxMesh, *m_AxisRenderMaterial);
+ m_AxisBoxRenderable[AT_Y] = getRenderer().createRenderable(*boxMesh, *m_AxisRenderMaterial);
+ m_AxisBoxRenderable[AT_Z] = getRenderer().createRenderable(*boxMesh, *m_AxisRenderMaterial);
+ m_AxisBoxRenderable[AT_X]->setColor(X_DIRECTION_COLOR_F);
+ m_AxisBoxRenderable[AT_Y]->setColor(Y_DIRECTION_COLOR_F);
+ m_AxisBoxRenderable[AT_Z]->setColor(Z_DIRECTION_COLOR_F);
+ m_AxisBoxRenderable[AT_X]->setScale(PxVec3(0.5, 0.5, 0.5));
+ m_AxisBoxRenderable[AT_Y]->setScale(PxVec3(0.5, 0.5, 0.5));
+ m_AxisBoxRenderable[AT_Z]->setScale(PxVec3(0.5, 0.5, 0.5));
+ m_AxisBoxRenderable[AT_X]->setHidden(true);
+ m_AxisBoxRenderable[AT_Y]->setHidden(true);
+ m_AxisBoxRenderable[AT_Z]->setHidden(true);
+
+ m_Axis[AT_X] = PxVec3(defaultAxisLength, 0.0, 0.0);
+ m_Axis[AT_Y] = PxVec3(0.0, defaultAxisLength, 0.0);
+ m_Axis[AT_Z] = PxVec3(0.0, 0.0, defaultAxisLength);
+}
+
+void GizmoToolController::onInitialize()
+{
+}
+
+
+void GizmoToolController::onSampleStop()
+{
+}
+
+void GizmoToolController::Animate(double dt)
+{
+ PROFILER_SCOPED_FUNCTION();
+
+ if (NULL == m_CurrentActor)
+ {
+ m_AxisConeRenderable[AT_X]->setHidden(true);
+ m_AxisConeRenderable[AT_Y]->setHidden(true);
+ m_AxisConeRenderable[AT_Z]->setHidden(true);
+ m_AxisBoxRenderable[AT_X]->setHidden(true);
+ m_AxisBoxRenderable[AT_Y]->setHidden(true);
+ m_AxisBoxRenderable[AT_Z]->setHidden(true);
+
+ return;
+ }
+
+ bool isTranslation = m_GizmoToolMode == GTM_Translate;
+ bool isScale = m_GizmoToolMode == GTM_Scale;
+ bool isRotation = m_GizmoToolMode == GTM_Rotation;
+ bool isLocal = AppMainWindow::Inst().m_bGizmoWithLocal;
+
+ bool showLine = isTranslation || isScale || (isRotation && isLocal);
+ bool showCone = isTranslation || (isRotation && isLocal);
+ bool showBox = isScale;
+ bool showCircle = isRotation;
+
+ m_AxisConeRenderable[AT_X]->setHidden(!isTranslation);
+ m_AxisConeRenderable[AT_Y]->setHidden(!isTranslation);
+ m_AxisConeRenderable[AT_Z]->setHidden(!isTranslation);
+ m_AxisBoxRenderable[AT_X]->setHidden(!isScale);
+ m_AxisBoxRenderable[AT_Y]->setHidden(!isScale);
+ m_AxisBoxRenderable[AT_Z]->setHidden(!isScale);
+
+ if (showLine)
+ {
+ if (m_bNeedResetPos)
+ {
+ m_AxisRenderBuffer.clear();
+ m_AxisRenderBuffer.m_lines.push_back(PxDebugLine(m_TargetPos, m_TargetPos + m_Axis[AT_X] * defaultAxisModifier, X_DIRECTION_COLOR_U));
+ m_AxisRenderBuffer.m_lines.push_back(PxDebugLine(m_TargetPos, m_TargetPos + m_Axis[AT_Y], Y_DIRECTION_COLOR_U));
+ m_AxisRenderBuffer.m_lines.push_back(PxDebugLine(m_TargetPos, m_TargetPos + m_Axis[AT_Z], Z_DIRECTION_COLOR_U));
+ }
+
+ if (m_bNeedResetColor)
+ {
+ if (m_AxisSelected == AT_X)
+ {
+ m_AxisRenderBuffer.m_lines[0].color0 = HIGHLIGHT_COLOR_U;
+ m_AxisRenderBuffer.m_lines[0].color1 = HIGHLIGHT_COLOR_U;
+ }
+ else
+ {
+ m_AxisRenderBuffer.m_lines[0].color0 = X_DIRECTION_COLOR_U;
+ m_AxisRenderBuffer.m_lines[0].color1 = X_DIRECTION_COLOR_U;
+ }
+ if (m_AxisSelected == AT_Y)
+ {
+ m_AxisRenderBuffer.m_lines[1].color0 = HIGHLIGHT_COLOR_U;
+ m_AxisRenderBuffer.m_lines[1].color1 = HIGHLIGHT_COLOR_U;
+ }
+ else
+ {
+ m_AxisRenderBuffer.m_lines[1].color0 = Y_DIRECTION_COLOR_U;
+ m_AxisRenderBuffer.m_lines[1].color1 = Y_DIRECTION_COLOR_U;
+ }
+ if (m_AxisSelected == AT_Z)
+ {
+ m_AxisRenderBuffer.m_lines[2].color0 = HIGHLIGHT_COLOR_U;
+ m_AxisRenderBuffer.m_lines[2].color1 = HIGHLIGHT_COLOR_U;
+ }
+ else
+ {
+ m_AxisRenderBuffer.m_lines[2].color0 = Z_DIRECTION_COLOR_U;
+ m_AxisRenderBuffer.m_lines[2].color1 = Z_DIRECTION_COLOR_U;
+ }
+ }
+
+ getRenderer().queueRenderBuffer(&m_AxisRenderBuffer);
+ }
+
+ if (showCone)
+ {
+ if (m_bNeedResetPos)
+ {
+ PxTransform transform;
+
+ transform.p = m_TargetPos + m_Axis[AT_X] * defaultAxisModifier;
+ transform.q = CalDirectionQuat(AT_X);
+ m_AxisConeRenderable[AT_X]->setTransform(transform);
+
+ transform.p = m_TargetPos + m_Axis[AT_Y];
+ transform.q = CalDirectionQuat(AT_Y);
+ m_AxisConeRenderable[AT_Y]->setTransform(transform);
+
+ transform.p = m_TargetPos + m_Axis[AT_Z];
+ transform.q = CalDirectionQuat(AT_Z);
+ m_AxisConeRenderable[AT_Z]->setTransform(transform);
+ }
+
+ if (m_bNeedResetColor)
+ {
+ if (m_AxisSelected == AT_X)
+ {
+ m_AxisConeRenderable[AT_X]->setColor(HIGHLIGHT_COLOR_F);
+ }
+ else
+ {
+ m_AxisConeRenderable[AT_X]->setColor(X_DIRECTION_COLOR_F);
+ }
+ if (m_AxisSelected == AT_Y)
+ {
+ m_AxisConeRenderable[AT_Y]->setColor(HIGHLIGHT_COLOR_F);
+ }
+ else
+ {
+ m_AxisConeRenderable[AT_Y]->setColor(Y_DIRECTION_COLOR_F);
+ }
+ if (m_AxisSelected == AT_Z)
+ {
+ m_AxisConeRenderable[AT_Z]->setColor(HIGHLIGHT_COLOR_F);
+ }
+ else
+ {
+ m_AxisConeRenderable[AT_Z]->setColor(Z_DIRECTION_COLOR_F);
+ }
+ }
+ }
+
+ if (showBox)
+ {
+ if (m_bNeedResetPos)
+ {
+ PxTransform transform;
+
+ transform.p = m_TargetPos + m_Axis[AT_X] * defaultAxisModifier;
+ transform.q = CalDirectionQuat(AT_X);
+ m_AxisBoxRenderable[AT_X]->setTransform(transform);
+
+ transform.p = m_TargetPos + m_Axis[AT_Y];
+ transform.q = CalDirectionQuat(AT_Y);
+ m_AxisBoxRenderable[AT_Y]->setTransform(transform);
+
+ transform.p = m_TargetPos + m_Axis[AT_Z];
+ transform.q = CalDirectionQuat(AT_Z);
+ m_AxisBoxRenderable[AT_Z]->setTransform(transform);
+ }
+
+ if (m_bNeedResetColor)
+ {
+ if (m_AxisSelected == AT_X)
+ {
+ m_AxisBoxRenderable[AT_X]->setColor(HIGHLIGHT_COLOR_F);
+ }
+ else
+ {
+ m_AxisBoxRenderable[AT_X]->setColor(X_DIRECTION_COLOR_F);
+ }
+ if (m_AxisSelected == AT_Y)
+ {
+ m_AxisBoxRenderable[AT_Y]->setColor(HIGHLIGHT_COLOR_F);
+ }
+ else
+ {
+ m_AxisBoxRenderable[AT_Y]->setColor(Y_DIRECTION_COLOR_F);
+ }
+ if (m_AxisSelected == AT_Z)
+ {
+ m_AxisBoxRenderable[AT_Z]->setColor(HIGHLIGHT_COLOR_F);
+ }
+ else
+ {
+ m_AxisBoxRenderable[AT_Z]->setColor(Z_DIRECTION_COLOR_F);
+ }
+ }
+ }
+
+ if (showCircle)
+ {
+ if (m_bNeedResetPos)
+ {
+ PxQuat q = CalConvertQuat();
+
+ m_CircleRenderBuffer.clear();
+ std::vector<PxDebugLine>::iterator it;
+ for (it = m_CircleRenderData.begin(); it != m_CircleRenderData.end(); it++)
+ {
+ PxDebugLine line = (*it);
+
+ line.pos0 = q.rotate(line.pos0);
+ line.pos1 = q.rotate(line.pos1);
+
+ line.pos0 += m_TargetPos;
+ line.pos1 += m_TargetPos;
+
+ m_CircleRenderBuffer.m_lines.push_back(line);
+ }
+ }
+
+ if (m_bNeedResetColor)
+ {
+ std::vector<PxDebugLine>& datas = m_CircleRenderData;
+ std::vector<PxDebugLine>& lines = m_CircleRenderBuffer.m_lines;
+ int linesize = lines.size();
+ int linesize_per_axis = linesize / 3;
+ float multiply;
+ physx::PxU32 color;
+
+ if (m_AxisSelected == AT_X)
+ {
+ for (int l = 0; l < linesize_per_axis; l++)
+ {
+ multiply = 1.0 * (l + 1) / linesize_per_axis;
+ color = XMFLOAT4ToU32Color(DirectX::XMFLOAT4(multiply, multiply, 0, 1));
+ lines[l].color0 = color;
+ lines[l].color1 = color;
+ }
+ }
+ else
+ {
+ for (int l = 0; l < linesize_per_axis; l++)
+ {
+ multiply = 1.0 * (l + 1) / linesize_per_axis;
+ color = XMFLOAT4ToU32Color(DirectX::XMFLOAT4(multiply, 0, 0, 1));
+ lines[l].color0 = color;
+ lines[l].color1 = color;
+ }
+ }
+ if (m_AxisSelected == AT_Y)
+ {
+ for (int l = linesize_per_axis; l < linesize_per_axis * 2; l++)
+ {
+ multiply = 1.0 * (l + 1 - linesize_per_axis) / linesize_per_axis;
+ color = XMFLOAT4ToU32Color(DirectX::XMFLOAT4(multiply, multiply, 0, 1));
+ lines[l].color0 = color;
+ lines[l].color1 = color;
+ }
+ }
+ else
+ {
+ for (int l = linesize_per_axis; l < linesize_per_axis * 2; l++)
+ {
+ multiply = 1.0 * (l + 1 - linesize_per_axis) / linesize_per_axis;
+ color = XMFLOAT4ToU32Color(DirectX::XMFLOAT4(0, multiply, 0, 1));
+ lines[l].color0 = color;
+ lines[l].color1 = color;
+ }
+ }
+ if (m_AxisSelected == AT_Z)
+ {
+ for (int l = linesize_per_axis * 2; l < linesize; l++)
+ {
+ multiply = 1.0 * (l + 1 - linesize_per_axis * 2) / linesize_per_axis;
+ color = XMFLOAT4ToU32Color(DirectX::XMFLOAT4(multiply, multiply, 0, 1));
+ lines[l].color0 = color;
+ lines[l].color1 = color;
+ }
+ }
+ else
+ {
+ for (int l = linesize_per_axis * 2; l < linesize; l++)
+ {
+ multiply = 1.0 * (l + 1 - linesize_per_axis * 2) / linesize_per_axis;
+ color = XMFLOAT4ToU32Color(DirectX::XMFLOAT4(0, 0, multiply, 1));
+ lines[l].color0 = color;
+ lines[l].color1 = color;
+ }
+ }
+ }
+
+ getRenderer().queueRenderBuffer(&m_CircleRenderBuffer);
+ }
+
+ m_bNeedResetPos = false;
+ m_bNeedResetColor = false;
+}
+
+#include "PxPhysics.h"
+#include "cooking/PxCooking.h"
+LRESULT GizmoToolController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PROFILER_SCOPED_FUNCTION();
+
+ if (uMsg == WM_LBUTTONDOWN || uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONUP)
+ {
+ float mouseX = (short)LOWORD(lParam) / getRenderer().getScreenWidth();
+ float mouseY = (short)HIWORD(lParam) / getRenderer().getScreenHeight();
+ bool press = uMsg == WM_LBUTTONDOWN;
+
+ if (m_GizmoToolMode == GTM_Translate)
+ {
+ if (uMsg == WM_LBUTTONDOWN)
+ {
+ if (m_AxisSelected == AT_Num)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxRaycastHit hit; hit.shape = NULL;
+ PxRaycastBuffer hit1;
+ getPhysXController().getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION | PxHitFlag::eNORMAL);
+ hit = hit1.block;
+
+ if (hit.shape)
+ {
+ PxRigidActor* actor = hit.actor;
+ PxRigidDynamic* rigidDynamic = actor->is<PxRigidDynamic>();
+ if (NULL != rigidDynamic)
+ {
+ m_CurrentActor = actor;
+ getSelectionToolController().pointSelect(m_CurrentActor);
+
+ PxTransform gp = m_CurrentActor->getGlobalPose();
+
+ m_TargetPos = gp.p;
+ m_Axis[AT_X] = gp.q.rotate(PxVec3(defaultAxisLength, 0, 0));
+ m_Axis[AT_Y] = gp.q.rotate(PxVec3(0, defaultAxisLength, 0));
+ m_Axis[AT_Z] = gp.q.rotate(PxVec3(0, 0, defaultAxisLength));
+
+ m_bNeedResetPos = true;
+ }
+ else
+ {
+ m_CurrentActor = NULL;
+ getSelectionToolController().clearSelect();
+ }
+ }
+ }
+ else
+ {
+ m_bGizmoFollowed = (m_CurrentActor != NULL);
+ }
+ }
+ else if (uMsg == WM_MOUSEMOVE)
+ {
+ if (m_bGizmoFollowed)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxVec3 axis = m_Axis[m_AxisSelected];
+ axis = axis.getNormalized();
+ PxVec3 samplepoint = eyePos + pickDir;
+ PxVec3 normal = m_LastEyeRay.cross(axis);
+ normal = normal.getNormalized();
+ PxVec3 foot;
+ GetFootFromPointToPlane(samplepoint, eyePos, normal, foot);
+ PxVec3 direction = foot - eyePos;
+ direction = direction.getNormalized();
+ PxVec3 target;
+ GetIntersectBetweenLines(m_LastFoot, axis, eyePos, direction, target);
+ PxVec3 delta = target - m_LastFoot;
+
+ m_LastEyeRay = direction;
+ m_LastFoot = target;
+
+ PxTransform gp_old = m_CurrentActor->getGlobalPose();
+ PxTransform gp_new(gp_old.p + delta, gp_old.q);;
+ m_CurrentActor->setGlobalPose(gp_new);
+
+ m_TargetPos = gp_new.p;
+
+ bool local = AppMainWindow::Inst().m_bGizmoWithLocal;
+ if (local)
+ {
+ uint32_t shapesCount = m_CurrentActor->getNbShapes();
+ if (shapesCount > 0)
+ {
+ PxTransform gp_newInv = gp_new.getInverse();
+
+ PxTransform lp_old;
+ PxTransform lp_new;
+
+ std::vector<PxShape*> shapes(shapesCount);
+ m_CurrentActor->getShapes(&shapes[0], shapesCount);
+ getPhysXController().getPhysXScene().removeActor(*m_CurrentActor);
+ for (uint32_t i = 0; i < shapesCount; i++)
+ {
+ PxShape* shape = shapes[i];
+
+ m_CurrentActor->detachShape(*shape);
+
+ lp_old = shape->getLocalPose();
+ lp_new = gp_newInv * gp_old * lp_old;
+ shape->setLocalPose(lp_new);
+
+ m_CurrentActor->attachShape(*shape);
+ }
+ getPhysXController().getPhysXScene().addActor(*m_CurrentActor);
+ }
+ }
+
+ m_bNeedResetPos = true;
+ m_bNeedResetColor = true;
+ }
+ else if(m_CurrentActor != NULL)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ m_LastEyeRay = pickDir;
+
+ // get axis which intersect with this eye ray
+ AxisType as = AT_Num;
+ {
+ double distanceMin = PX_MAX_F32;
+ double tolerance = 1;
+ int line_index = -1;
+ PxVec3 foot;
+ std::vector<PxDebugLine>& lines = m_AxisRenderBuffer.m_lines;
+ int linesize = lines.size();
+ for (int l = 0; l < linesize; l++)
+ {
+ PxVec3 start = lines[l].pos0;
+ PxVec3 end = lines[l].pos1;
+ PxVec3 dir = end - start;
+ double length = dir.magnitude();
+ // separate the line to 10 segment
+ double delta = length * 0.1;
+ for (int segment = 0; segment <= 10; segment++)
+ {
+ PxVec3 vertex = start + 0.1 * segment * dir;
+ double distance = DistanceFromPointToLine(vertex, eyePos, pickDir, foot);
+
+ if (distance < distanceMin)
+ {
+ distanceMin = distance;
+ line_index = l;
+ m_LastFoot = foot;
+ }
+ }
+ }
+ if (distanceMin < tolerance)
+ {
+ int axis_index = line_index * 3 / linesize;
+ as = (AxisType)axis_index;
+ }
+ }
+ setAxisSelected(as);
+ }
+ }
+ else if (uMsg == WM_LBUTTONUP)
+ {
+ m_bNeedResetPos = true;
+ m_bNeedResetColor = true;
+ m_bGizmoFollowed = false;
+ }
+ }
+ else if (m_GizmoToolMode == GTM_Scale)
+ {
+ if (uMsg == WM_LBUTTONDOWN)
+ {
+ if (m_AxisSelected == AT_Num)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxRaycastHit hit; hit.shape = NULL;
+ PxRaycastBuffer hit1;
+ getPhysXController().getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION | PxHitFlag::eNORMAL);
+ hit = hit1.block;
+
+ if (hit.shape)
+ {
+ PxRigidActor* actor = hit.actor;
+ PxRigidDynamic* rigidDynamic = actor->is<PxRigidDynamic>();
+ if (NULL != rigidDynamic)
+ {
+ m_CurrentActor = actor;
+ getSelectionToolController().pointSelect(m_CurrentActor);
+
+ PxTransform gp = m_CurrentActor->getGlobalPose();
+
+ m_TargetPos = gp.p;
+ m_Axis[AT_X] = gp.q.rotate(PxVec3(defaultAxisLength, 0, 0));
+ m_Axis[AT_Y] = gp.q.rotate(PxVec3(0, defaultAxisLength, 0));
+ m_Axis[AT_Z] = gp.q.rotate(PxVec3(0, 0, defaultAxisLength));
+
+ m_bNeedResetPos = true;
+ }
+ else
+ {
+ m_CurrentActor = NULL;
+ getSelectionToolController().clearSelect();
+ }
+ }
+ }
+ else
+ {
+ m_bGizmoFollowed = (m_CurrentActor != NULL);
+ m_LastAxis[AT_X] = m_Axis[AT_X].getNormalized();
+ m_LastAxis[AT_Y] = m_Axis[AT_Y].getNormalized();
+ m_LastAxis[AT_Z] = m_Axis[AT_Z].getNormalized();
+ }
+ }
+ else if (uMsg == WM_MOUSEMOVE)
+ {
+ if (m_bGizmoFollowed)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxVec3 axis = m_LastAxis[m_AxisSelected];
+ PxVec3 samplepoint = eyePos + pickDir;
+ PxVec3 normal = m_LastEyeRay.cross(axis);
+ normal = normal.getNormalized();
+ PxVec3 foot;
+ GetFootFromPointToPlane(samplepoint, eyePos, normal, foot);
+ PxVec3 direction = foot - eyePos;
+ direction = direction.getNormalized();
+ PxVec3 target;
+ GetIntersectBetweenLines(m_LastFoot, axis, eyePos, direction, target);
+ PxVec3 delta = target - m_LastFoot;
+
+ if (m_AxisSelected == AT_X)
+ {
+ delta *= defaultAxisModifier;
+ }
+ m_Axis[m_AxisSelected] = m_LastAxis[m_AxisSelected] * defaultAxisLength + delta;
+
+ bool isShift = (GetAsyncKeyState(VK_SHIFT) && 0x8000);
+ if (isShift)
+ {
+ float length = m_Axis[m_AxisSelected].magnitude();
+ m_Axis[AT_X] = m_LastAxis[AT_X] * length;
+ m_Axis[AT_Y] = m_LastAxis[AT_Y] * length;
+ m_Axis[AT_Z] = m_LastAxis[AT_Z] * length;
+ }
+
+ ScaleActor(false);
+
+ m_bNeedResetPos = true;
+ m_bNeedResetColor = true;
+ }
+ else if (m_CurrentActor != NULL)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ m_LastEyeRay = pickDir;
+
+ // get axis which intersect with this eye ray
+ AxisType as = AT_Num;
+ {
+ double distanceMin = PX_MAX_F32;
+ double tolerance = 1;
+ int line_index = -1;
+ std::vector<PxDebugLine>& lines = m_AxisRenderBuffer.m_lines;
+ int linesize = lines.size();
+ PxVec3 foot;
+ for (int l = 0; l < linesize; l++)
+ {
+ PxVec3 vertex = lines[l].pos1;
+ double distance = DistanceFromPointToLine(vertex, eyePos, pickDir, foot);
+
+ if (distance < distanceMin)
+ {
+ distanceMin = distance;
+ line_index = l;
+ m_LastFoot = foot;
+ }
+ }
+ if (distanceMin < tolerance)
+ {
+ as = (AxisType)line_index;
+ }
+ }
+ setAxisSelected(as);
+ }
+ }
+ else if (uMsg == WM_LBUTTONUP)
+ {
+ if (m_AxisSelected != AT_Num)
+ {
+ if (NULL != m_CurrentActor)
+ {
+ ScaleActor(true);
+ }
+
+ m_Axis[AT_X] = m_LastAxis[AT_X] * defaultAxisLength;
+ m_Axis[AT_Y] = m_LastAxis[AT_Y] * defaultAxisLength;
+ m_Axis[AT_Z] = m_LastAxis[AT_Z] * defaultAxisLength;
+ }
+
+ m_bNeedResetPos = true;
+ m_bNeedResetColor = true;
+ m_bGizmoFollowed = false;
+ }
+ }
+ else if (m_GizmoToolMode == GTM_Rotation)
+ {
+ if (uMsg == WM_LBUTTONDOWN)
+ {
+ if (m_AxisSelected == AT_Num)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxRaycastHit hit; hit.shape = NULL;
+ PxRaycastBuffer hit1;
+ getPhysXController().getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION | PxHitFlag::eNORMAL);
+ hit = hit1.block;
+
+ if (hit.shape)
+ {
+ PxRigidActor* actor = hit.actor;
+ PxRigidDynamic* rigidDynamic = actor->is<PxRigidDynamic>();
+ if (NULL != rigidDynamic)
+ {
+ m_CurrentActor = actor;
+ getSelectionToolController().pointSelect(m_CurrentActor);
+
+ PxTransform gp = m_CurrentActor->getGlobalPose();
+
+ m_TargetPos = gp.p;
+ m_Axis[AT_X] = gp.q.rotate(PxVec3(defaultAxisLength, 0, 0));
+ m_Axis[AT_Y] = gp.q.rotate(PxVec3(0, defaultAxisLength, 0));
+ m_Axis[AT_Z] = gp.q.rotate(PxVec3(0, 0, defaultAxisLength));
+
+ m_bNeedResetPos = true;
+ }
+ else
+ {
+ m_CurrentActor = NULL;
+ getSelectionToolController().clearSelect();
+ }
+ }
+ }
+ else
+ {
+ m_bGizmoFollowed = (m_CurrentActor != NULL);
+ }
+ }
+ else if (uMsg == WM_MOUSEMOVE)
+ {
+ if (m_bGizmoFollowed)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxVec3 planenormal = m_Axis[m_AxisSelected];
+ planenormal = planenormal.getNormalized();
+
+ PxVec3 from, to;
+ CalPlaneLineIntersectPoint(from, planenormal, m_TargetPos, m_LastEyeRay, eyePos);
+ CalPlaneLineIntersectPoint(to, planenormal, m_TargetPos, pickDir, eyePos);
+ from = from - m_TargetPos;
+ to = to - m_TargetPos;
+ from = from.getNormalized();
+ to = to.getNormalized();
+ float cosangle = from.dot(to);
+ float angle = PxAcos(cosangle);
+ PxVec3 cross = from.cross(to);
+ cross = cross.getNormalized();
+
+ PxQuat q(angle, cross);
+ if (m_AxisSelected == AT_X)
+ {
+ m_Axis[AT_Y] = q.rotate(m_Axis[AT_Y]);
+ m_Axis[AT_Z] = q.rotate(m_Axis[AT_Z]);
+ }
+ else if (m_AxisSelected == AT_Y)
+ {
+ m_Axis[AT_X] = q.rotate(m_Axis[AT_X]);
+ m_Axis[AT_Z] = q.rotate(m_Axis[AT_Z]);
+ }
+ else if (m_AxisSelected == AT_Z)
+ {
+ m_Axis[AT_X] = q.rotate(m_Axis[AT_X]);
+ m_Axis[AT_Y] = q.rotate(m_Axis[AT_Y]);
+ }
+
+ m_LastEyeRay = pickDir;
+
+ PxTransform gp_old = m_CurrentActor->getGlobalPose();
+ PxTransform gp_new = PxTransform(gp_old.p, CalConvertQuat());
+ m_CurrentActor->setGlobalPose(gp_new);
+
+ bool local = AppMainWindow::Inst().m_bGizmoWithLocal;
+ if (local)
+ {
+ uint32_t shapesCount = m_CurrentActor->getNbShapes();
+ if (shapesCount > 0)
+ {
+ PxTransform gp_newInv = gp_new.getInverse();
+
+ PxTransform lp_old;
+ PxTransform lp_new;
+
+ std::vector<PxShape*> shapes(shapesCount);
+ m_CurrentActor->getShapes(&shapes[0], shapesCount);
+ getPhysXController().getPhysXScene().removeActor(*m_CurrentActor);
+ for (uint32_t i = 0; i < shapesCount; i++)
+ {
+ PxShape* shape = shapes[i];
+
+ m_CurrentActor->detachShape(*shape);
+
+ lp_old = shape->getLocalPose();
+ lp_new = gp_newInv * gp_old * lp_old;
+ shape->setLocalPose(lp_new);
+
+ m_CurrentActor->attachShape(*shape);
+ }
+ getPhysXController().getPhysXScene().addActor(*m_CurrentActor);
+ }
+ }
+
+ m_bNeedResetPos = true;
+ m_bNeedResetColor = true;
+ }
+ else if (m_CurrentActor != NULL)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ m_LastEyeRay = pickDir;
+
+ // get axis which intersect with this eye ray
+ AxisType as = AT_Num;
+ {
+ double distanceMin = PX_MAX_F32;
+ double tolerance = 1;
+ int line_index = -1;
+ std::vector<PxDebugLine>& lines = m_CircleRenderBuffer.m_lines;
+ int linesize = lines.size();
+ PxVec3 foot;
+ for (int l = 0; l < linesize; l++)
+ {
+ PxVec3 vertex = lines[l].pos0;
+ double distance = DistanceFromPointToLine(vertex, eyePos, pickDir, foot);
+
+ if (distance < distanceMin)
+ {
+ distanceMin = distance;
+ line_index = l;
+ m_LastFoot = foot;
+ }
+ }
+ if (distanceMin < tolerance)
+ {
+ int axis_index = line_index * 3 / linesize;
+ as = (AxisType)axis_index;
+ }
+ }
+ setAxisSelected(as);
+ }
+ }
+ else if (uMsg == WM_LBUTTONUP)
+ {
+ m_bNeedResetPos = true;
+ m_bNeedResetColor = true;
+ m_bGizmoFollowed = false;
+ }
+ }
+ }
+
+ return 1;
+}
+
+void GizmoToolController::drawUI()
+{
+}
+
+void GizmoToolController::setGizmoToolMode(GizmoToolMode mode)
+{
+ if (mode == m_GizmoToolMode)
+ {
+ return;
+ }
+
+ m_GizmoToolMode = mode;
+
+ m_bNeedResetPos = true;
+ m_bNeedResetColor = true;
+}
+
+void GizmoToolController::setAxisSelected(AxisType type)
+{
+ if (type == m_AxisSelected)
+ {
+ return;
+ }
+
+ m_AxisSelected = type;
+ m_bNeedResetColor = true;
+}
+
+void GizmoToolController::showAxisRenderables(bool show)
+{
+ bool isTranslate = m_GizmoToolMode == GTM_Translate;
+ bool isScale = m_GizmoToolMode == GTM_Scale;
+
+ m_AxisConeRenderable[AT_X]->setHidden(!show || !isTranslate);
+ m_AxisConeRenderable[AT_Y]->setHidden(!show || !isTranslate);
+ m_AxisConeRenderable[AT_Z]->setHidden(!show || !isTranslate);
+ m_AxisBoxRenderable[AT_X]->setHidden(!show || !isScale);
+ m_AxisBoxRenderable[AT_Y]->setHidden(!show || !isScale);
+ m_AxisBoxRenderable[AT_Z]->setHidden(!show || !isScale);
+}
+
+void GizmoToolController::resetPos()
+{
+ m_TargetPos = PxVec3(-100, -100, -100);
+ m_bNeedResetPos = true;
+
+ m_AxisSelected = AT_Num;
+ m_bNeedResetColor = true;
+
+ m_CurrentActor = NULL;
+}
+
+bool GizmoToolController::CalPlaneLineIntersectPoint(PxVec3& result, PxVec3 planeNormal, PxVec3 planePoint, PxVec3 linedirection, PxVec3 linePoint)
+{
+ float dot = planeNormal.dot(linedirection);
+ if (dot == 0)
+ {
+ return false;
+ }
+ else
+ {
+ float t = ((planePoint[0] - linePoint[0]) * planeNormal[0] +
+ (planePoint[1] - linePoint[1]) * planeNormal[1] +
+ (planePoint[2] - linePoint[2]) * planeNormal[2]) / dot;
+ result = linePoint + linedirection * t;
+ }
+ return true;
+}
+
+float GizmoToolController::DistanceFromPointToLine(PxVec3& point, PxVec3& origin, PxVec3& direction, PxVec3& foot)
+{
+ direction = direction.getNormalized();
+ PxVec3 sub = point - origin;
+ float t = direction.dot(sub);
+ foot = origin + direction * t;
+ PxVec3 dis = point - foot;
+ return dis.magnitude();
+}
+
+bool GizmoToolController::GetFootFromPointToPlane(PxVec3& point, PxVec3& origin, PxVec3& normal, PxVec3& foot)
+{
+ return CalPlaneLineIntersectPoint(foot, normal, origin, normal, point);
+}
+
+bool GizmoToolController::GetIntersectBetweenLines(PxVec3& origin1, PxVec3& direction1, PxVec3& origin2, PxVec3& direction2, PxVec3& intersect)
+{
+ PxVec3 normal1 = direction1.cross(direction2);
+ PxVec3 normal2 = normal1.cross(direction1);
+ normal2 = normal2.getNormalized();
+ return CalPlaneLineIntersectPoint(intersect, normal2, origin1, direction2, origin2);
+}
+
+PxQuat GizmoToolController::CalDirectionQuat(AxisType type)
+{
+ PxVec3 origin(0, 1, 0);
+ PxVec3 target = m_Axis[type];
+ if (type == AT_X)
+ {
+ target *= defaultAxisModifier;
+ }
+ target = target.getNormalized();
+ PxVec3 cross = origin.cross(target);
+ cross = cross.getNormalized();
+ float cos = origin.dot(target);
+ float angle = PxAcos(cos);
+ PxQuat q(angle, cross);
+ return q;
+}
+
+PxQuat GizmoToolController::CalConvertQuat()
+{
+ PxVec3 x_origin(1, 0, 0);
+ PxVec3 y_origin(0, 1, 0);
+ PxVec3 z_origin(0, 0, 1);
+
+ PxVec3 x_target = m_Axis[AT_X];
+ PxVec3 y_target = m_Axis[AT_Y];
+ x_target = x_target.getNormalized();
+ y_target = y_target.getNormalized();
+
+ PxVec3 x_cross = x_origin.cross(x_target);
+ x_cross = x_cross.getNormalized();
+ float x_cos = x_origin.dot(x_target);
+ float x_angle = PxAcos(x_cos);
+ PxQuat x_quat(x_angle, x_cross);
+
+ PxVec3 y_interval = x_quat.rotate(y_origin);
+
+ PxVec3 y_cross = y_interval.cross(y_target);
+ y_cross = y_cross.getNormalized();
+ float y_cos = y_interval.dot(y_target);
+ float y_angle = PxAcos(y_cos);
+ PxQuat y_quat(y_angle, y_cross);
+
+ PxQuat q = y_quat * x_quat;
+ return q;
+}
+
+void GizmoToolController::ScaleActor(bool replace)
+{
+ if (NULL == m_CurrentActor)
+ {
+ return;
+ }
+ ExtPxActor* extActor = NULL;
+ PxRigidDynamic* rigidDynamic = m_CurrentActor->is<PxRigidDynamic>();
+ if (NULL != rigidDynamic)
+ {
+ extActor = getBlastController().getExtPxManager().getActorFromPhysXActor(*rigidDynamic);
+ }
+ if (NULL == extActor)
+ {
+ return;
+ }
+
+ std::vector<BlastFamilyPtr>& families = getBlastController().getFamilies();
+ if (families.size() == 0)
+ {
+ return;
+ }
+
+ BlastFamilyPtr pBlastFamily = NULL;
+ std::vector<BlastFamilyPtr>::iterator it = families.begin();
+ for (; it != families.end(); it++)
+ {
+ BlastFamilyPtr f = *it;
+ if (f->find(extActor))
+ {
+ pBlastFamily = f;
+ break;
+ }
+ }
+ if (NULL == pBlastFamily)
+ {
+ return;
+ }
+
+ float multiply = m_Axis[m_AxisSelected].magnitude() / defaultAxisLength;
+ if (m_Axis[m_AxisSelected].dot(m_LastAxis[m_AxisSelected]) < 0)
+ {
+ multiply = -multiply;
+ }
+ PxVec3 delta(1, 1, 1);
+ bool isShift = (GetAsyncKeyState(VK_SHIFT) && 0x8000);
+ if (isShift)
+ {
+ delta *= multiply;
+ }
+ else
+ {
+ delta[m_AxisSelected] = multiply;
+ }
+ PxMat44 scale = PxMat44(PxVec4(delta, 1));
+
+ bool isLocal = AppMainWindow::Inst().m_bGizmoWithLocal;
+ if (!isLocal)
+ {
+ PxTransform gp = m_CurrentActor->getGlobalPose();
+ uint32_t shapesCount = m_CurrentActor->getNbShapes();
+ if (shapesCount > 0)
+ {
+ std::vector<PxShape*> shapes(shapesCount);
+ m_CurrentActor->getShapes(&shapes[0], shapesCount);
+ PxShape* shape = shapes[0];
+ PxTransform lp = shape->getLocalPose();
+ gp = gp * lp;
+ }
+ PxMat44 world = PxMat44(gp);
+ PxMat44 worldInv = world.inverseRT();
+ scale = world * scale * worldInv;
+ }
+
+ pBlastFamily->setActorScale(*extActor, scale, replace);
+
+ if (!replace)
+ {
+ return;
+ }
+
+ uint32_t shapesCount = m_CurrentActor->getNbShapes();
+ if (shapesCount == 0)
+ {
+ return;
+ }
+
+ std::vector<PxShape*> shapes(shapesCount);
+ m_CurrentActor->getShapes(&shapes[0], shapesCount);
+
+ getPhysXController().getPhysXScene().removeActor(*m_CurrentActor);
+
+ for (uint32_t i = 0; i < shapesCount; i++)
+ {
+ PxShape* shape = shapes[i];
+
+ PxConvexMeshGeometry mesh;
+ bool valid = shape->getConvexMeshGeometry(mesh);
+ if (!valid)
+ {
+ continue;
+ }
+
+ PxConvexMesh* pMesh = mesh.convexMesh;
+ if (NULL == pMesh)
+ {
+ continue;
+ }
+
+ PxU32 numVertex = pMesh->getNbVertices();
+ if (numVertex == 0)
+ {
+ continue;
+ }
+
+ const PxVec3* pVertex = pMesh->getVertices();
+ PxVec3* pVertexNew = new PxVec3[numVertex];
+ for (PxU32 v = 0; v < numVertex; v++)
+ {
+ pVertexNew[v] = scale.transform(pVertex[v]);
+ }
+
+ PxConvexMeshDesc convexMeshDesc;
+ convexMeshDesc.points.count = numVertex;
+ convexMeshDesc.points.data = pVertexNew;
+ convexMeshDesc.points.stride = sizeof(PxVec3);
+ convexMeshDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
+ PxPhysics& physics = getManager()->getPhysXController().getPhysics();
+ PxCooking& cooking = getManager()->getPhysXController().getCooking();
+ PxConvexMesh* convexMesh = cooking.createConvexMesh(convexMeshDesc, physics.getPhysicsInsertionCallback());
+ if (NULL == convexMesh)
+ {
+ delete[] pVertexNew;
+ continue;
+ }
+
+ mesh.convexMesh = convexMesh;
+
+ m_CurrentActor->detachShape(*shape);
+ shape->setGeometry(mesh);
+ m_CurrentActor->attachShape(*shape);
+
+ pMesh->release();
+ delete[] pVertexNew;
+ }
+
+ getPhysXController().getPhysXScene().addActor(*m_CurrentActor);
+} \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.h b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.h
new file mode 100644
index 0000000..215cde5
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.h
@@ -0,0 +1,124 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#ifndef GIZMO_TOOL_CONTROLLER_H
+#define GIZMO_TOOL_CONTROLLER_H
+
+#include "SampleManager.h"
+#include "DebugRenderBuffer.h"
+#include "NvBlastExtPxManager.h"
+
+class Renderable;
+class RenderMaterial;
+
+namespace Nv
+{
+namespace Blast
+{
+class ExtPhysicsActor;
+}
+}
+
+enum AxisType
+{
+ AT_X = 0,
+ AT_Y = 1,
+ AT_Z = 2,
+ AT_Num
+};
+
+enum GizmoToolMode
+{
+ GTM_Translate = 0,
+ GTM_Scale,
+ GTM_Rotation
+};
+
+class GizmoToolController : public ISampleController
+{
+public:
+ GizmoToolController();
+ virtual ~GizmoToolController();
+
+ virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual void Animate(double dt);
+ void drawUI();
+
+ virtual void onInitialize();
+ virtual void onSampleStart();
+ virtual void onSampleStop();
+
+ void setGizmoToolMode(GizmoToolMode mode);
+ void setAxisSelected(AxisType type);
+ void showAxisRenderables(bool show);
+ void resetPos();
+
+private:
+ GizmoToolController& operator= (GizmoToolController&);
+
+ //////// private methods ////////
+
+ bool CalPlaneLineIntersectPoint(PxVec3& result, PxVec3 planeNormal, PxVec3 planePoint, PxVec3 linedirection, PxVec3 linePoint);
+ float DistanceFromPointToLine(PxVec3& point, PxVec3& origin, PxVec3& direction, PxVec3& foot);
+ bool GetFootFromPointToPlane(PxVec3& point, PxVec3& origin, PxVec3& normal, PxVec3& foot);
+ bool GetIntersectBetweenLines(PxVec3& origin1, PxVec3& direction1, PxVec3& origin2, PxVec3& direction2, PxVec3& intersect);
+ PxQuat CalDirectionQuat(AxisType type);
+ PxQuat CalConvertQuat();
+ void ScaleActor(bool replace);
+ //////// used controllers ////////
+
+ Renderer& getRenderer() const
+ {
+ return getManager()->getRenderer();
+ }
+
+ PhysXController& getPhysXController() const
+ {
+ return getManager()->getPhysXController();
+ }
+
+ BlastController& getBlastController() const
+ {
+ return getManager()->getBlastController();
+ }
+
+ SelectionToolController& getSelectionToolController() const
+ {
+ return getManager()->getSelectionToolController();
+ }
+
+ //////// internal data ////////
+
+ GizmoToolMode m_GizmoToolMode;
+
+ bool m_bGizmoFollowed;
+ PxVec3 m_LastEyeRay;
+ PxVec3 m_LastFoot;
+ PxVec3 m_LastAxis[AT_Num];
+
+ PxRigidActor* m_CurrentActor;
+
+ bool m_bNeedResetPos;
+ bool m_bNeedResetColor;
+
+ PxVec3 m_TargetPos;
+ PxVec3 m_Axis[AT_Num];
+ AxisType m_AxisSelected;
+ Renderable* m_AxisConeRenderable[AT_Num];
+ Renderable* m_AxisBoxRenderable[AT_Num];
+
+ RenderMaterial* m_AxisRenderMaterial;
+ DebugRenderBuffer m_AxisRenderBuffer;
+
+ std::vector<PxDebugLine> m_CircleRenderData;
+ DebugRenderBuffer m_CircleRenderBuffer;
+};
+
+#endif // GIZMO_TOOL_CONTROLLER_H \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.cpp b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.cpp
new file mode 100644
index 0000000..02a511f
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.cpp
@@ -0,0 +1,445 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include "SelectionToolController.h"
+#include "RenderUtils.h"
+#include "BlastController.h"
+#include "Renderer.h"
+#include "PhysXController.h"
+#include "SampleProfiler.h"
+
+#include <imgui.h>
+
+#include "NvBlastTkActor.h"
+#include "NvBlastExtDamageShaders.h"
+
+#include "PxRigidDynamic.h"
+#include "PxScene.h"
+#include "BlastSceneTree.h"
+
+using namespace Nv::Blast;
+using namespace physx;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Setup
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+SelectionToolController::SelectionToolController()
+{
+ m_bRectSelecting = false;
+}
+
+SelectionToolController::~SelectionToolController()
+{
+}
+
+void SelectionToolController::onSampleStart()
+{
+}
+
+void SelectionToolController::onInitialize()
+{
+}
+
+
+void SelectionToolController::onSampleStop()
+{
+}
+
+void SelectionToolController::Animate(double dt)
+{
+ PROFILER_SCOPED_FUNCTION();
+
+ if (m_bRectSelecting)
+ {
+ getRenderer().queueRenderBuffer(&m_RectRenderBuffer);
+ }
+}
+
+
+LRESULT SelectionToolController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PROFILER_SCOPED_FUNCTION();
+
+ if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP)
+ {
+ float mouseX = (short)LOWORD(lParam) / getRenderer().getScreenWidth();
+ float mouseY = (short)HIWORD(lParam) / getRenderer().getScreenHeight();
+ bool press = uMsg == WM_LBUTTONDOWN;
+
+ if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN)
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+
+ m_RectSelectScreenPos.x = mouseX;
+ m_RectSelectScreenPos.y = mouseY;
+ m_RectSelectSpaceDir = pickDir.getNormalized();
+
+ m_RectRenderBuffer.clear();
+ m_bRectSelecting = true;
+ }
+ else if (uMsg == WM_MOUSEMOVE)
+ {
+ if (m_bRectSelecting)
+ {
+ PxVec3 eyePos, pickDir[3];
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir[0]);
+ getPhysXController().getEyePoseAndPickDir(m_RectSelectScreenPos.x, mouseY, eyePos, pickDir[1]);
+ getPhysXController().getEyePoseAndPickDir(mouseX, m_RectSelectScreenPos.y, eyePos, pickDir[2]);
+ pickDir[0] = pickDir[0].getNormalized();
+ pickDir[1] = pickDir[1].getNormalized();
+ pickDir[2] = pickDir[2].getNormalized();
+
+ PxVec3 lefttop, leftbottom, righttop, rightbottom;
+
+ if (mouseX > m_RectSelectScreenPos.x) // right
+ {
+ if (mouseY > m_RectSelectScreenPos.y) // top
+ {
+ leftbottom = m_RectSelectSpaceDir;
+ righttop = pickDir[0];
+ lefttop = pickDir[2];
+ rightbottom = pickDir[1];
+ }
+ else // bottom
+ {
+ leftbottom = pickDir[1];
+ righttop = pickDir[2];
+ lefttop = m_RectSelectSpaceDir;
+ rightbottom = pickDir[0];
+ }
+ }
+ else // left
+ {
+ if (mouseY > m_RectSelectScreenPos.y) // top
+ {
+ leftbottom = pickDir[2];
+ righttop = pickDir[1];
+ lefttop = pickDir[0];
+ rightbottom = m_RectSelectSpaceDir;
+ }
+ else // bottom
+ {
+ leftbottom = pickDir[0];
+ righttop = m_RectSelectSpaceDir;
+ lefttop = pickDir[2];
+ rightbottom = pickDir[1];
+ }
+ }
+
+ float multiply = 10; // in order to draw line
+ lefttop = eyePos + lefttop * multiply;
+ righttop = eyePos + righttop * multiply;
+ leftbottom = eyePos + leftbottom * multiply;
+ rightbottom = eyePos + rightbottom * multiply;
+
+ m_RectRenderBuffer.clear();
+
+ DirectX::XMFLOAT4 LINE_COLOR(1.0f, 0.0f, 0.0f, 1.0f);
+ m_RectRenderBuffer.m_lines.push_back(PxDebugLine(lefttop, leftbottom, XMFLOAT4ToU32Color(LINE_COLOR)));
+ m_RectRenderBuffer.m_lines.push_back(PxDebugLine(lefttop, righttop, XMFLOAT4ToU32Color(LINE_COLOR)));
+ m_RectRenderBuffer.m_lines.push_back(PxDebugLine(righttop, rightbottom, XMFLOAT4ToU32Color(LINE_COLOR)));
+ m_RectRenderBuffer.m_lines.push_back(PxDebugLine(leftbottom, rightbottom, XMFLOAT4ToU32Color(LINE_COLOR)));
+ }
+ }
+ else if (uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP)
+ {
+ if (uMsg == WM_RBUTTONUP && m_actorsSelected.size() > 1)
+ {
+ return 1;
+ }
+
+ if (m_bRectSelecting)
+ {
+ bool isShift = (GetAsyncKeyState(VK_SHIFT) && 0x8000);
+ bool isCtrl = (GetAsyncKeyState(VK_CONTROL) && 0x8000);
+
+ SelectMode selectMode = SM_RESET;
+ if (isShift && isCtrl)
+ {
+ selectMode = SM_REMAIN;
+ }
+ else if (isShift)
+ {
+ selectMode = SM_ADD;
+ }
+ else if (isCtrl)
+ {
+ selectMode = SM_SUB;
+ }
+
+ int width = getRenderer().getScreenWidth();
+ int height = getRenderer().getScreenHeight();
+ int deltaX = (mouseX - m_RectSelectScreenPos.x) * width;
+ int deltaY = (mouseY - m_RectSelectScreenPos.y) * height;
+ float distance = deltaX * deltaX + deltaY * deltaY;
+ // rect select mode
+ if (distance > 1)
+ {
+ PxVec3 eyePos, pickDir[3];
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir[0]);
+ getPhysXController().getEyePoseAndPickDir(m_RectSelectScreenPos.x, mouseY, eyePos, pickDir[1]);
+ getPhysXController().getEyePoseAndPickDir(mouseX, m_RectSelectScreenPos.y, eyePos, pickDir[2]);
+ pickDir[0] = pickDir[0].getNormalized();
+ pickDir[1] = pickDir[1].getNormalized();
+ pickDir[2] = pickDir[2].getNormalized();
+
+ PxVec3 lefttop, leftbottom, righttop, rightbottom;
+
+ if (mouseX > m_RectSelectScreenPos.x) // right
+ {
+ if (mouseY > m_RectSelectScreenPos.y) // top
+ {
+ leftbottom = m_RectSelectSpaceDir;
+ righttop = pickDir[0];
+ lefttop = pickDir[2];
+ rightbottom = pickDir[1];
+ }
+ else // bottom
+ {
+ leftbottom = pickDir[1];
+ righttop = pickDir[2];
+ lefttop = m_RectSelectSpaceDir;
+ rightbottom = pickDir[0];
+ }
+ }
+ else // left
+ {
+ if (mouseY > m_RectSelectScreenPos.y) // top
+ {
+ leftbottom = pickDir[2];
+ righttop = pickDir[1];
+ lefttop = pickDir[0];
+ rightbottom = m_RectSelectSpaceDir;
+ }
+ else // bottom
+ {
+ leftbottom = pickDir[0];
+ righttop = m_RectSelectSpaceDir;
+ lefttop = pickDir[2];
+ rightbottom = pickDir[1];
+ }
+ }
+
+ rectSelect(eyePos, lefttop, leftbottom, righttop, rightbottom, selectMode);
+ }
+ // point select mode
+ else
+ {
+ PxVec3 eyePos, pickDir;
+ getPhysXController().getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir);
+ pickDir = pickDir.getNormalized();
+
+ PxRaycastHit hit; hit.shape = NULL;
+ PxRaycastBuffer hit1;
+ getPhysXController().getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION | PxHitFlag::eNORMAL);
+ hit = hit1.block;
+
+ PxRigidActor* actor = NULL;
+ if (hit.shape)
+ {
+ actor = hit.actor;
+ }
+ pointSelect(actor, selectMode);
+ }
+ }
+
+ BlastSceneTree::ins()->updateChunkItemSelection();
+ m_RectRenderBuffer.clear();
+ m_bRectSelecting = false;
+ }
+ }
+
+ return 1;
+}
+
+void SelectionToolController::drawUI()
+{
+}
+
+void SelectionToolController::pointSelect(PxActor* actor, SelectMode selectMode)
+{
+ ExtPxActor* extActor = NULL;
+ if (NULL != actor)
+ {
+ PxRigidDynamic* rigidDynamic = actor->is<PxRigidDynamic>();
+ if (NULL != rigidDynamic)
+ {
+ extActor = getBlastController().getExtPxManager().getActorFromPhysXActor(*rigidDynamic);
+ }
+ }
+
+ if (selectMode == SM_RESET)
+ {
+ clearSelect();
+
+ if (NULL != extActor)
+ {
+ setActorSelected(*extActor, true);
+ m_actorsSelected.emplace(extActor);
+ }
+ }
+ else if (selectMode == SM_ADD)
+ {
+ if (NULL != extActor)
+ {
+ setActorSelected(*extActor, true);
+ m_actorsSelected.emplace(extActor);
+ }
+ }
+ else if (selectMode == SM_SUB)
+ {
+ if (NULL != extActor)
+ {
+ setActorSelected(*extActor, false);
+ m_actorsSelected.erase(extActor);
+ }
+ }
+}
+
+#include "PxPhysics.h"
+#include "cooking/PxCooking.h"
+
+class RectSelectionCallback : public PxOverlapCallback
+{
+public:
+ RectSelectionCallback(ExtPxManager& physicsManager, std::set<ExtPxActor*>& actorBuffer)
+ : m_physicsManager(physicsManager), m_actorBuffer(actorBuffer), PxOverlapCallback(m_hitBuffer, sizeof(m_hitBuffer) / sizeof(m_hitBuffer[0])) {}
+
+ PxAgain processTouches(const PxOverlapHit* buffer, PxU32 nbHits)
+ {
+ for (PxU32 i = 0; i < nbHits; ++i)
+ {
+ PxRigidDynamic* rigidDynamic = buffer[i].actor->is<PxRigidDynamic>();
+ if (rigidDynamic)
+ {
+ ExtPxActor* actor = m_physicsManager.getActorFromPhysXActor(*rigidDynamic);
+ if (actor != nullptr)
+ {
+ m_actorBuffer.insert(actor);
+ }
+ }
+ }
+ return true;
+ }
+
+private:
+ ExtPxManager& m_physicsManager;
+ std::set<ExtPxActor*>& m_actorBuffer;
+ PxOverlapHit m_hitBuffer[1000];
+};
+
+void SelectionToolController::rectSelect(PxVec3 eyePos, PxVec3 lefttop, PxVec3 leftbottom, PxVec3 righttop, PxVec3 rightbottom, SelectMode selectMode)
+{
+ std::set<ExtPxActor*> actorsToSelect;
+
+ float nearClip = 1;
+ PxVec3 nearlefttop = lefttop * nearClip;
+ PxVec3 nearrighttop = righttop * nearClip;
+ PxVec3 nearleftbottom = leftbottom * nearClip;
+ PxVec3 nearrightbottom = rightbottom * nearClip;
+
+ float farClip = 1000;
+ PxVec3 farlefttop = lefttop * farClip;
+ PxVec3 farrighttop = righttop * farClip;
+ PxVec3 farleftbottom = leftbottom * farClip;
+ PxVec3 farrightbottom = rightbottom * farClip;
+
+ PxVec3 vertices[8] =
+ {
+ nearlefttop, nearrighttop, nearleftbottom, nearrightbottom,
+ farlefttop, farrighttop, farleftbottom, farrightbottom
+ };
+ PxConvexMeshDesc convexMeshDesc;
+ convexMeshDesc.points.count = 8;
+ convexMeshDesc.points.data = vertices;
+ convexMeshDesc.points.stride = sizeof(PxVec3);
+ convexMeshDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
+ PxPhysics& physics = getManager()->getPhysXController().getPhysics();
+ PxCooking& cooking = getManager()->getPhysXController().getCooking();
+ PxConvexMesh* convexMesh = cooking.createConvexMesh(convexMeshDesc, physics.getPhysicsInsertionCallback());
+ if (NULL != convexMesh)
+ {
+ RectSelectionCallback overlapCallback(getBlastController().getExtPxManager(), actorsToSelect);
+ getManager()->getPhysXController().getPhysXScene().overlap(PxConvexMeshGeometry(convexMesh), PxTransform(eyePos), overlapCallback);
+ convexMesh->release();
+ }
+
+ if (selectMode == SM_RESET)
+ {
+ clearSelect();
+
+ for (ExtPxActor* actor : actorsToSelect)
+ {
+ setActorSelected(*actor, true);
+ m_actorsSelected.emplace(actor);
+ }
+ }
+ else if (selectMode == SM_ADD)
+ {
+ for (ExtPxActor* actor : actorsToSelect)
+ {
+ setActorSelected(*actor, true);
+ m_actorsSelected.emplace(actor);
+ }
+ }
+ else if (selectMode == SM_SUB)
+ {
+ for (ExtPxActor* actor : actorsToSelect)
+ {
+ setActorSelected(*actor, false);
+ m_actorsSelected.erase(actor);
+ }
+ }
+}
+
+void SelectionToolController::clearSelect()
+{
+ for (ExtPxActor* actor : m_actorsSelected)
+ {
+ setActorSelected(*actor, false);
+ }
+
+ m_actorsSelected.clear();
+ SampleManager::ins()->clearChunksSelected();
+}
+
+void SelectionToolController::setActorSelected(const ExtPxActor& actor, bool selected)
+{
+ std::vector<BlastFamilyPtr>& families = getBlastController().getFamilies();
+ if (families.size() == 0)
+ {
+ return;
+ }
+
+ BlastFamilyPtr pBlastFamily = NULL;
+ std::vector<BlastFamilyPtr>::iterator it = families.begin();
+ for (; it != families.end(); it++)
+ {
+ BlastFamilyPtr f = *it;
+ if (f->find((ExtPxActor*)&actor))
+ {
+ pBlastFamily = f;
+ break;
+ }
+ }
+ if (NULL == pBlastFamily)
+ {
+ return;
+ }
+
+ pBlastFamily->setActorSelected(actor, selected);
+} \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.h b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.h
new file mode 100644
index 0000000..5261b90
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.h
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#ifndef SELECTION_TOOL_CONTROLLER_H
+#define SELECTION_TOOL_CONTROLLER_H
+
+#include "SampleManager.h"
+#include "PxVec2.h"
+#include "PxVec3.h"
+#include "DebugRenderBuffer.h"
+#include "BlastFamily.h"
+#include "NvBlastExtPxManager.h"
+class Renderable;
+class RenderMaterial;
+
+namespace Nv
+{
+namespace Blast
+{
+class ExtPxActor;
+}
+}
+
+class SelectionToolController : public ISampleController
+{
+public:
+ SelectionToolController();
+ virtual ~SelectionToolController();
+
+ virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual void Animate(double dt);
+ void drawUI();
+
+ virtual void onInitialize();
+ virtual void onSampleStart();
+ virtual void onSampleStop();
+
+ void pointSelect(PxActor* actor, SelectMode selectMode = SM_RESET);
+ void rectSelect(PxVec3 eyePos, PxVec3 lefttop, PxVec3 leftbottom, PxVec3 righttop, PxVec3 rightbottom, SelectMode selectMode = SM_RESET);
+ void clearSelect();
+
+private:
+ SelectionToolController& operator= (SelectionToolController&);
+
+ //////// private methods ////////
+
+ //////// used controllers ////////
+
+ Renderer& getRenderer() const
+ {
+ return getManager()->getRenderer();
+ }
+
+ PhysXController& getPhysXController() const
+ {
+ return getManager()->getPhysXController();
+ }
+
+ BlastController& getBlastController() const
+ {
+ return getManager()->getBlastController();
+ }
+
+ //////// internal data ////////
+
+ PxVec2 m_RectSelectScreenPos;
+ PxVec3 m_RectSelectSpaceDir;
+ bool m_bRectSelecting;
+ DebugRenderBuffer m_RectRenderBuffer;
+
+ void setActorSelected(const ExtPxActor& actor, bool selected);
+ std::set<ExtPxActor*> m_actorsSelected;
+};
+
+#endif // SELECTION_TOOL_CONTROLLER_H \ No newline at end of file
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.cpp b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.cpp
new file mode 100644
index 0000000..11f66f0
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.cpp
@@ -0,0 +1,583 @@
+// ImGui Win32 + DirectX11 binding
+// In this binding, ImTextureID is used to store a 'ID3D11ShaderResourceView*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
+// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
+// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
+// https://github.com/ocornut/imgui
+
+#include <imgui.h>
+#include "imgui_impl_dx11.h"
+
+// DirectX
+#include <d3d11.h>
+#include <d3dcompiler.h>
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
+
+// Data
+static INT64 g_Time = 0;
+static INT64 g_TicksPerSecond = 0;
+
+static HWND g_hWnd = 0;
+static ID3D11Device* g_pd3dDevice = NULL;
+static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
+static ID3D11Buffer* g_pVB = NULL;
+static ID3D11Buffer* g_pIB = NULL;
+static ID3D10Blob * g_pVertexShaderBlob = NULL;
+static ID3D11VertexShader* g_pVertexShader = NULL;
+static ID3D11InputLayout* g_pInputLayout = NULL;
+static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
+static ID3D10Blob * g_pPixelShaderBlob = NULL;
+static ID3D11PixelShader* g_pPixelShader = NULL;
+static ID3D11SamplerState* g_pFontSampler = NULL;
+static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
+static ID3D11RasterizerState* g_pRasterizerState = NULL;
+static ID3D11BlendState* g_pBlendState = NULL;
+static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
+static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
+
+struct VERTEX_CONSTANT_BUFFER
+{
+ float mvp[4][4];
+};
+
+// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
+// If text or lines are blurry when integrating ImGui in your engine:
+// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
+void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data)
+{
+ ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
+
+ // Create and grow vertex/index buffers if needed
+ if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
+ g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
+ return;
+ }
+ if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
+ g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
+ return;
+ }
+
+ // Copy and convert all vertices into a single contiguous buffer
+ D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
+ if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
+ return;
+ if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
+ return;
+ ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
+ ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ memcpy(vtx_dst, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert));
+ memcpy(idx_dst, &cmd_list->IdxBuffer[0], cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx));
+ vtx_dst += cmd_list->VtxBuffer.size();
+ idx_dst += cmd_list->IdxBuffer.size();
+ }
+ ctx->Unmap(g_pVB, 0);
+ ctx->Unmap(g_pIB, 0);
+
+ // Setup orthographic projection matrix into our constant buffer
+ {
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
+ return;
+ VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
+ float L = 0.0f;
+ float R = ImGui::GetIO().DisplaySize.x;
+ float B = ImGui::GetIO().DisplaySize.y;
+ float T = 0.0f;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
+ ctx->Unmap(g_pVertexConstantBuffer, 0);
+ }
+
+ // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
+ struct BACKUP_DX11_STATE
+ {
+ UINT ScissorRectsCount, ViewportsCount;
+ D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ ID3D11RasterizerState* RS;
+ ID3D11BlendState* BlendState;
+ FLOAT BlendFactor[4];
+ UINT SampleMask;
+ UINT StencilRef;
+ ID3D11DepthStencilState* DepthStencilState;
+ ID3D11ShaderResourceView* PSShaderResource;
+ ID3D11SamplerState* PSSampler;
+ ID3D11PixelShader* PS;
+ ID3D11VertexShader* VS;
+ UINT PSInstancesCount, VSInstancesCount;
+ ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
+ D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
+ ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
+ UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
+ DXGI_FORMAT IndexBufferFormat;
+ ID3D11InputLayout* InputLayout;
+ };
+ BACKUP_DX11_STATE old;
+ old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
+ ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
+ ctx->RSGetState(&old.RS);
+ ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
+ ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
+ ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
+ ctx->PSGetSamplers(0, 1, &old.PSSampler);
+ old.PSInstancesCount = old.VSInstancesCount = 256;
+ ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
+ ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
+ ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
+ ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
+ ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
+ ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
+ ctx->IAGetInputLayout(&old.InputLayout);
+
+ // Setup viewport
+ D3D11_VIEWPORT vp;
+ memset(&vp, 0, sizeof(D3D11_VIEWPORT));
+ vp.Width = ImGui::GetIO().DisplaySize.x;
+ vp.Height = ImGui::GetIO().DisplaySize.y;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = vp.TopLeftY = 0.0f;
+ ctx->RSSetViewports(1, &vp);
+
+ // Bind shader and vertex buffers
+ unsigned int stride = sizeof(ImDrawVert);
+ unsigned int offset = 0;
+ ctx->IASetInputLayout(g_pInputLayout);
+ ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
+ ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
+ ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ ctx->VSSetShader(g_pVertexShader, NULL, 0);
+ ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
+ ctx->PSSetShader(g_pPixelShader, NULL, 0);
+ ctx->PSSetSamplers(0, 1, &g_pFontSampler);
+
+ // Setup render state
+ const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
+ ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
+ ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
+ ctx->RSSetState(g_pRasterizerState);
+
+ // Render command lists
+ int vtx_offset = 0;
+ int idx_offset = 0;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback)
+ {
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ const D3D11_RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w };
+ ctx->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->TextureId);
+ ctx->RSSetScissorRects(1, &r);
+ ctx->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset);
+ }
+ idx_offset += pcmd->ElemCount;
+ }
+ vtx_offset += cmd_list->VtxBuffer.size();
+ }
+
+ // Restore modified DX state
+ ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
+ ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
+ ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
+ ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
+ ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
+ ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
+ ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
+ ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
+ for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
+ ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
+ ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
+ for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
+ ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
+ ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
+ ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
+ ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
+}
+
+IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ io.MouseDown[0] = true;
+ return true;
+ case WM_LBUTTONUP:
+ io.MouseDown[0] = false;
+ return true;
+ case WM_RBUTTONDOWN:
+ io.MouseDown[1] = true;
+ return true;
+ case WM_RBUTTONUP:
+ io.MouseDown[1] = false;
+ return true;
+ case WM_MBUTTONDOWN:
+ io.MouseDown[2] = true;
+ return true;
+ case WM_MBUTTONUP:
+ io.MouseDown[2] = false;
+ return true;
+ case WM_MOUSEWHEEL:
+ io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f;
+ return true;
+ case WM_MOUSEMOVE:
+ io.MousePos.x = (signed short)(lParam);
+ io.MousePos.y = (signed short)(lParam >> 16);
+ return true;
+ case WM_KEYDOWN:
+ if (wParam < 256)
+ io.KeysDown[wParam] = 1;
+ return true;
+ case WM_KEYUP:
+ if (wParam < 256)
+ io.KeysDown[wParam] = 0;
+ return true;
+ case WM_CHAR:
+ // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
+ if (wParam > 0 && wParam < 0x10000)
+ io.AddInputCharacter((unsigned short)wParam);
+ return true;
+ }
+ return 0;
+}
+
+static void ImGui_ImplDX11_CreateFontsTexture()
+{
+ // Build texture atlas
+ ImGuiIO& io = ImGui::GetIO();
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+
+ // Upload texture to graphics system
+ {
+ D3D11_TEXTURE2D_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Width = width;
+ desc.Height = height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ ID3D11Texture2D *pTexture = NULL;
+ D3D11_SUBRESOURCE_DATA subResource;
+ subResource.pSysMem = pixels;
+ subResource.SysMemPitch = desc.Width * 4;
+ subResource.SysMemSlicePitch = 0;
+ g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
+
+ // Create texture view
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ ZeroMemory(&srvDesc, sizeof(srvDesc));
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = desc.MipLevels;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
+ pTexture->Release();
+ }
+
+ // Store our identifier
+ io.Fonts->TexID = (void *)g_pFontTextureView;
+
+ // Create texture sampler
+ {
+ D3D11_SAMPLER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.MipLODBias = 0.f;
+ desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ desc.MinLOD = 0.f;
+ desc.MaxLOD = 0.f;
+ g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
+ }
+}
+
+bool ImGui_ImplDX11_CreateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return false;
+ if (g_pFontSampler)
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+
+ // By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
+ // If you would like to use this DX11 sample code but remove this dependency you can:
+ // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [prefered solution]
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // See https://github.com/ocornut/imgui/pull/638 for sources and details.
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(b0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, NULL);
+ if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ return false;
+ if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
+ return false;
+
+ // Create the input layout
+ D3D11_INPUT_ELEMENT_DESC local_layout[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+ if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
+ return false;
+
+ // Create the constant buffer
+ {
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
+ }
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ sampler sampler0;\
+ Texture2D texture0;\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, NULL);
+ if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ return false;
+ if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
+ return false;
+ }
+
+ // Create the blending setup
+ {
+ D3D11_BLEND_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.AlphaToCoverageEnable = false;
+ desc.RenderTarget[0].BlendEnable = true;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
+ }
+
+ // Create the rasterizer state
+ {
+ D3D11_RASTERIZER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.FillMode = D3D11_FILL_SOLID;
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.ScissorEnable = true;
+ desc.DepthClipEnable = true;
+ g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
+ }
+
+ // Create depth-stencil State
+ {
+ D3D11_DEPTH_STENCIL_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.DepthEnable = false;
+ desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
+ desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
+ desc.StencilEnable = false;
+ desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
+ desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
+ desc.BackFace = desc.FrontFace;
+ g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
+ }
+
+ ImGui_ImplDX11_CreateFontsTexture();
+
+ return true;
+}
+
+void ImGui_ImplDX11_InvalidateDeviceObjects()
+{
+ if (!g_pd3dDevice)
+ return;
+
+ if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
+ if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = 0; }
+ if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
+ if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
+
+ if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
+ if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
+ if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
+ if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
+ if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; }
+ if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
+ if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
+ if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
+ if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; }
+}
+
+bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context)
+{
+ g_hWnd = (HWND)hwnd;
+ g_pd3dDevice = device;
+ g_pd3dDeviceContext = device_context;
+
+ if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond))
+ return false;
+ if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time))
+ return false;
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime.
+ io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
+ io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
+ io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
+ io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
+ io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
+ io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
+ io.KeyMap[ImGuiKey_Home] = VK_HOME;
+ io.KeyMap[ImGuiKey_End] = VK_END;
+ io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
+ io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
+ io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
+ io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
+ io.KeyMap[ImGuiKey_A] = 'A';
+ io.KeyMap[ImGuiKey_C] = 'C';
+ io.KeyMap[ImGuiKey_V] = 'V';
+ io.KeyMap[ImGuiKey_X] = 'X';
+ io.KeyMap[ImGuiKey_Y] = 'Y';
+ io.KeyMap[ImGuiKey_Z] = 'Z';
+
+ io.RenderDrawListsFn = ImGui_ImplDX11_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer.
+ io.ImeWindowHandle = g_hWnd;
+
+ return true;
+}
+
+void ImGui_ImplDX11_Shutdown()
+{
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+ ImGui::Shutdown();
+ g_pd3dDevice = NULL;
+ g_pd3dDeviceContext = NULL;
+ g_hWnd = (HWND)0;
+}
+
+void ImGui_ImplDX11_NewFrame()
+{
+ if (!g_pFontSampler)
+ ImGui_ImplDX11_CreateDeviceObjects();
+
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ RECT rect;
+ GetClientRect(g_hWnd, &rect);
+ io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
+
+ // Setup time step
+ INT64 current_time;
+ QueryPerformanceCounter((LARGE_INTEGER *)&current_time);
+ io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
+ g_Time = current_time;
+
+ // Read keyboard modifiers inputs
+ io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
+ io.KeyAlt = (GetKeyState(VK_MENU) & 0x8000) != 0;
+ io.KeySuper = false;
+ // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events
+ // io.MousePos : filled by WM_MOUSEMOVE events
+ // io.MouseDown : filled by WM_*BUTTON* events
+ // io.MouseWheel : filled by WM_MOUSEWHEEL events
+
+ // Hide OS mouse cursor if ImGui is drawing it
+ SetCursor(io.MouseDrawCursor ? NULL : LoadCursor(NULL, IDC_ARROW));
+
+ // Start the frame
+ ImGui::NewFrame();
+}
diff --git a/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.h b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.h
new file mode 100644
index 0000000..7d6f710
--- /dev/null
+++ b/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.h
@@ -0,0 +1,25 @@
+// ImGui Win32 + DirectX11 binding
+// In this binding, ImTextureID is used to store a 'ID3D11ShaderResourceView*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
+// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
+// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
+// https://github.com/ocornut/imgui
+
+struct ID3D11Device;
+struct ID3D11DeviceContext;
+
+IMGUI_API bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context);
+IMGUI_API void ImGui_ImplDX11_Shutdown();
+IMGUI_API void ImGui_ImplDX11_NewFrame();
+
+// Use if you want to reset your rendering device without losing ImGui state.
+IMGUI_API void ImGui_ImplDX11_InvalidateDeviceObjects();
+IMGUI_API bool ImGui_ImplDX11_CreateDeviceObjects();
+
+// Handler for Win32 messages, update mouse/keyboard data.
+// You may or not need this for your implementation, but it can serve as reference for handling inputs.
+// Commented out to avoid dragging dependencies on <windows.h> types. You can copy the extern declaration in your code.
+/*
+IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+*/