diff options
| author | Bryan Galdrikian <[email protected]> | 2017-02-21 12:07:59 -0800 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2017-02-21 12:07:59 -0800 |
| commit | 446ce137c6823ba9eff273bdafdaf266287c7c98 (patch) | |
| tree | d20aab3e2ed08d7b3ca71c2f40db6a93ea00c459 /NvBlast/tools/ArtistTools/source/BlastPlugin | |
| download | blast-1.0.0-beta.tar.xz blast-1.0.0-beta.zip | |
first commitv1.0.0-beta
Diffstat (limited to 'NvBlast/tools/ArtistTools/source/BlastPlugin')
137 files changed, 29334 insertions, 0 deletions
diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/BlastPlugin.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/BlastPlugin.cpp new file mode 100644 index 0000000..78aa6d0 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/BlastPlugin.cpp @@ -0,0 +1,1736 @@ +#include <QtCore/QtPlugin> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtWidgets/QMenuBar> +#include <QtWidgets/QToolBar> +#include <QtWidgets/QTabWidget> +#include <QtWidgets/QAction> +#include <QtWidgets/QMessageBox> +#include <QtWidgets/QFileDialog> +#include <QtGui/QDesktopServices> +#include <QtWidgets/QPushButton> +#include <QtCore/QVariant> +#include <QtWidgets/QApplication> +#include <QtWidgets/QButtonGroup> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QComboBox> +#include <QtWidgets/QFrame> +#include <QtWidgets/QGridLayout> +#include <QtWidgets/QHBoxLayout> +#include <QtWidgets/QHeaderView> +#include <QtWidgets/QLabel> +#include <QtWidgets/QSpacerItem> +#include <QtWidgets/QVBoxLayout> +#include <QtWidgets/QWidget> + +#include "PluginBlast.h" +#include "BlastPlugin.h" +#include "SlideSpinBox.h" +#include "Utils.h" +#include "CorelibUtils.h" +#include "Settings.h" +#include "GlobalSettings.h" +#include "SimpleScene.h" +#include "Camera.h" +#include "Light.h" +#include "ProjectParams.h" +#include "FoundationHolder.h" +#include "AppMainWindow.h" +#include "ViewerOutput.h" +#include "ExpandablePanel.h" +#include "DisplayMeshesPanel.h" +#include "PluginBlast.h" +#include "BlastToolbar.h" +#include "MaterialLibraryPanel.h" +#include "MaterialAssignmentsPanel.h" +#include "FileReferencesPanel.h" +#include "GeneralPanel.h" +#include "BlastCompositePanel.h" +#include "BlastSceneTree.h" +#include "FiltersDockWidget.h" +#include "DefaultDamagePanel.h" +#include "FiltersDockWidget.h" +#include "FractureCutoutSettingsPanel.h" +#include "FractureGeneralPanel.h" +#include "FractureShellCutSettingsPanel.h" +#include "FractureSliceSettingsPanel.h" +#include "FractureVisualizersPanel.h" +#include "FractureVoronoiSettingsPanel.h" +#include "SupportPanel.h" +#include "BlastSceneTree.h" +#include "FiltersDockWidget.h" + +// A singleton, sort of... To pass the events from WindowProc to the object. +DeviceManager* g_DeviceManagerInstance = NULL; + +HWND g_hWnd = 0; + +DeviceManager* GetDeviceManager() +{ + return g_DeviceManagerInstance; +} + +QString BlastPlugin::GetPluginName() +{ + return BlastPluginName; +} + +bool BlastPlugin::CoreLib_RunApp() +{ + return true; +} + +bool BlastPlugin::LoadRenderPlugin(std::string api) +{ + return PluginBlast::Create(api); +} + +bool BlastPlugin::GetBoneNames(std::vector<std::string>& BoneNames) +{ + return true; +} + +bool BlastPlugin::MainToolbar_updateValues() +{ + return true; +} + +bool BlastPlugin::CurveEditor_updateValues(int _paramId, float* _values) +{ + return true; +} + +bool BlastPlugin::CurveEditor_onUpdateValues(int _paramId, float* _values) +{ + return true; +} + +bool BlastPlugin::DisplayMeshesPanel_updateValues() +{ + return true; +} +bool BlastPlugin::DisplayMeshesPanel_EmitToggleSignal(unsigned int id, bool visible) +{ + return true; +} + +bool BlastPlugin::Camera_LoadParameters(void* ptr, Camera* pCamera) +{ + nvidia::parameterized::BlastProjectParametersNS::Camera_Type* param = + static_cast<nvidia::parameterized::BlastProjectParametersNS::Camera_Type*>(ptr); + + pCamera->_zup = param->flags == 1; + pCamera->_fov = param->fov; + pCamera->_aspectRatio = param->aspectRatio; + pCamera->_znear = param->znear; + pCamera->_zfar = param->zfar; + pCamera->_isPerspective = param->isPerspective; + memcpy(&pCamera->_eye, ¶m->eye, sizeof(pCamera->_eye)); + memcpy(&pCamera->_at, ¶m->at, sizeof(pCamera->_at)); + pCamera->_lookDistance = param->lookDistance; + memcpy(&pCamera->_orientation, ¶m->orientation, sizeof(pCamera->_orientation)); + memcpy(&pCamera->_viewMatrix, ¶m->viewMatrix, sizeof(pCamera->_viewMatrix)); + memcpy(&pCamera->_projectionMatrix, ¶m->projectionMatrix, sizeof(pCamera->_projectionMatrix)); + + return true; +} + +bool BlastPlugin::Camera_SaveParameters(void * ptr, Camera* pCamera) +{ + nvidia::parameterized::BlastProjectParametersNS::Camera_Type* outParam = + static_cast<nvidia::parameterized::BlastProjectParametersNS::Camera_Type*>(ptr); + + outParam->flags = (pCamera->_zup ? 1 : 2); + outParam->fov = pCamera->_fov; + outParam->aspectRatio = pCamera->_aspectRatio; + outParam->znear = pCamera->_znear; + outParam->zfar = pCamera->_zfar; + outParam->width = 0; + outParam->height = 0; + outParam->isPerspective = pCamera->_isPerspective; + memcpy(&outParam->eye, &pCamera->_eye, sizeof(outParam->eye)); + memcpy(&outParam->at, &pCamera->_at, sizeof(outParam->at)); + outParam->lookDistance = pCamera->_lookDistance; + memcpy(&outParam->orientation, &pCamera->_orientation, sizeof(outParam->orientation)); + memcpy(&outParam->viewMatrix, &pCamera->_viewMatrix, sizeof(outParam->viewMatrix)); + memcpy(&outParam->projectionMatrix, &pCamera->_projectionMatrix, sizeof(outParam->projectionMatrix)); + return true; +} + +bool BlastPlugin::Gamepad_ToggleSimulation() +{ + return true; +} + +bool BlastPlugin::Gamepad_LoadSamples(QString fn) +{ + return true; +} + +bool BlastPlugin::Gamepad_ResetScene() +{ + return true; +} + +bool BlastPlugin::Gamepad_StartAnimation() +{ + return true; +} + +bool BlastPlugin::GamepadHandler_ShowHair() +{ + return true; +} + +bool BlastPlugin::GamepadHandler_SpinWindStrength(float windStrength) +{ + return true; +} + +bool BlastPlugin::Gamepad_ResetAnimation() +{ + return true; +} + +bool BlastPlugin::Gamepad_PlayPauseAnimation() +{ + return true; +} + +bool BlastPlugin::Light_loadParameters(NvParameterized::Handle& handle, Light* pLight) +{ + if (pLight == nullptr) + return false; + + NvParameterized::NvParameters* params = static_cast<NvParameterized::NvParameters*>(handle.getInterface()); + size_t offset = 0; + nvidia::parameterized::BlastProjectParametersNS::Light_Type* param = nullptr; + params->getVarPtr(handle, (void*&)param, offset); + + pLight->m_enable = param->enable; + pLight->m_useShadows = param->useShadows; + pLight->m_visualize = param->visualize; + pLight->m_intensity = param->intensity; + + memcpy(&pLight->m_color, ¶m->color, sizeof(atcore_float3)); + + atcore_float3 axisX, axisY, axisZ, lightPos; + memcpy(&axisX, ¶m->lightAxisX, sizeof(atcore_float3)); + memcpy(&axisY, ¶m->lightAxisY, sizeof(atcore_float3)); + memcpy(&axisZ, ¶m->lightAxisZ, sizeof(atcore_float3)); + memcpy(&lightPos, ¶m->lightPos, sizeof(atcore_float3)); + + pLight->SetShadowMapResolution(param->shadowMapResolution); + + pLight->m_lightCamera.SetEye(lightPos); + pLight->m_lightCamera.SetViewMatrix(axisX, axisY, axisZ); + pLight->m_lightCamera.BuildViewMatrix(); + return true; +} + +bool BlastPlugin::Light_saveParameters(NvParameterized::Handle& handle, Light* pLight) +{ + if (pLight == nullptr) + return false; + + NvParameterized::NvParameters* params = static_cast<NvParameterized::NvParameters*>(handle.getInterface()); + size_t offset = 0; + nvidia::parameterized::BlastProjectParametersNS::Light_Type* param = nullptr; + params->getVarPtr(handle, (void*&)param, offset); + memset((void*)param, 0, sizeof(nvidia::parameterized::BlastProjectParametersNS::Light_Type)); + + param->enable = pLight->m_enable; + param->useShadows = pLight->m_useShadows; + param->visualize = pLight->m_visualize; + param->intensity = pLight->m_intensity; + + param->shadowMapResolution = pLight->m_shadowMapResolutionIndex; + + memcpy(¶m->color, &pLight->m_color, sizeof(atcore_float3)); + + { + atcore_float3 axisX = pLight->m_lightCamera.GetXAxis(); + atcore_float3 axisY = pLight->m_lightCamera.GetYAxis(); + atcore_float3 axisZ = pLight->m_lightCamera.GetZAxis(); + atcore_float3 lightPos = pLight->m_lightCamera.GetEye(); + + memcpy(¶m->lightAxisX, &axisX, sizeof(atcore_float3)); + memcpy(¶m->lightAxisY, &axisY, sizeof(atcore_float3)); + memcpy(¶m->lightAxisZ, &axisZ, sizeof(atcore_float3)); + memcpy(¶m->lightPos, &lightPos, sizeof(atcore_float3)); + } + return true; +} + +bool BlastPlugin::SimpleScene_SimpleScene() +{ + return true; +} + + +#include "Timer.h" +Timer g_fpsTimer; + +#include "D3DWidget.h" +#include "SampleManager.h" + +#include <QtWidgets/QShortcut> + +bool BlastPlugin::SimpleScene_Initialize(int backdoor) +{ + if (!CreateProjectParamsContext()) + return false; + + D3DWidget* d3dWidget = AppMainWindow::Inst().GetRenderWidget(); + g_hWnd = (HWND)d3dWidget->winId(); + + RECT rc; + GetClientRect((HWND)g_hWnd, &rc); + int wBuf = rc.right - rc.left; + int hBuf = rc.bottom - rc.top; + + DeviceCreationParameters deviceParams; + deviceParams.swapChainFormat = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + deviceParams.swapChainSampleCount = 4; + deviceParams.startFullscreen = false; + deviceParams.hWnd = g_hWnd; + deviceParams.backBufferWidth = wBuf; + deviceParams.backBufferHeight = hBuf; +#if defined(DEBUG) | defined(_DEBUG) + deviceParams.createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG; +#endif + deviceParams.featureLevel = D3D_FEATURE_LEVEL_11_0; + + DeviceManager* pDeviceManager = new DeviceManager; + //pDeviceManager->CreateWindowDeviceAndSwapChain(deviceParams); + RenderPlugin* pPlugin = RenderPlugin::Instance(); + D3DHandles handles; + pDeviceManager->SetWindowHandle(g_hWnd); + pDeviceManager->SetWindowDeviceAndSwapChain(pPlugin->GetDeviceHandles(handles)); + g_DeviceManagerInstance = pDeviceManager; + SimpleScene::Inst()->SetDeviceManager(pDeviceManager); + + SampleManager* pSampleManager = new SampleManager(pDeviceManager); + SimpleScene::Inst()->SetSampleManager(pSampleManager); + + // post build will copy samples\resources to bin\resources. If debug in VS, need set working directory to binary's folder + + pSampleManager->init(); + + QShortcut* shortCut; + + shortCut = new QShortcut(QKeySequence(Qt::Key_K), d3dWidget); + connect(shortCut, SIGNAL(activated()), this, SLOT(shortcut_damagetool())); + + shortCut = new QShortcut(QKeySequence(Qt::Key_Q), d3dWidget); + connect(shortCut, SIGNAL(activated()), this, SLOT(shortcut_selecttool())); + + shortCut = new QShortcut(QKeySequence(Qt::Key_W), d3dWidget); + connect(shortCut, SIGNAL(activated()), this, SLOT(shortcut_Translate())); + shortCut = new QShortcut(QKeySequence(Qt::Key_E), d3dWidget); + connect(shortCut, SIGNAL(activated()), this, SLOT(shortcut_Rotation())); + shortCut = new QShortcut(QKeySequence(Qt::Key_R), d3dWidget); + connect(shortCut, SIGNAL(activated()), this, SLOT(shortcut_Scale())); + + shortCut = new QShortcut(QKeySequence(Qt::Key_L), d3dWidget); + connect(shortCut, SIGNAL(activated()), this, SLOT(shortcut_edittool())); + + _chunkContextMenu = new QMenu(); + action_Make_Support = new QAction(tr("Make Support"), d3dWidget); + _chunkContextMenu->addAction(action_Make_Support); + connect(action_Make_Support, SIGNAL(triggered()), this, SLOT(slot_Make_Support())); + + action_Make_Static_Support = new QAction(tr("Make Static Support"), d3dWidget); + _chunkContextMenu->addAction(action_Make_Static_Support); + connect(action_Make_Static_Support, SIGNAL(triggered()), this, SLOT(slot_Make_Static_Support())); + + action_Remove_Support = new QAction(tr("Remove Support"), d3dWidget); + _chunkContextMenu->addAction(action_Remove_Support); + connect(action_Remove_Support, SIGNAL(triggered()), this, SLOT(slot_Remove_Support())); + + _bondContextMenu = new QMenu(); + action_Bond_Chunks = new QAction(tr("Bond Chunks"), d3dWidget); + _bondContextMenu->addAction(action_Bond_Chunks); + connect(action_Bond_Chunks, SIGNAL(triggered()), this, SLOT(slot_Bond_Chunks())); + + action_Bond_Chunks_with_Joints = new QAction(tr("Bond Chunks With Joints"), d3dWidget); + _bondContextMenu->addAction(action_Bond_Chunks_with_Joints); + connect(action_Bond_Chunks_with_Joints, SIGNAL(triggered()), this, SLOT(slot_Bond_Chunks_with_Joints())); + + action_Remove_all_Bonds = new QAction(tr("Remove All Bonds"), d3dWidget); + _bondContextMenu->addAction(action_Remove_all_Bonds); + connect(action_Remove_all_Bonds, SIGNAL(triggered()), this, SLOT(slot_Remove_all_Bonds())); + + return true; +} +bool BlastPlugin::SimpleScene_Shutdown() +{ + SampleManager& sm = SimpleScene::Inst()->GetSampleManager(); + sm.free(); + //SimpleScene::Inst()->SetSampleManager(NV_NULL); + + ReleaseProjectParamsContext(); + + g_DeviceManagerInstance = NV_NULL; + + return true; +} + +//#include "SceneController.h" +bool BlastPlugin::SimpleScene_Clear() +{ + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.clearScene(); +// SceneController& sceneController = sampleManager.getSceneController(); +// sceneController.ClearScene(); + + BlastProject::ins().clear(); + + return true; +} + +bool BlastPlugin::SimpleScene_Draw_DX12() +{ + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +#include <Stats.h> +namespace +{ + Stats g_StatsCPU; + Stats g_StatsGPU; + + Stats g_FrameStatsCPU; + Stats g_FrameStatsGPU; +} + +////////////////////////////////////////////////////////////////////////////// +void BlastPlugin::ResetFrameTimer() +{ + g_StatsCPU.reset(); + g_StatsGPU.reset(); +} + +void BlastPlugin::DrawHUD() +{ + GlobalSettings& globalSettings = GlobalSettings::Inst(); + + if (!globalSettings.m_showHUD) + return; + + // finish frame timer + g_FrameStatsCPU.add(g_StatsCPU); + g_FrameStatsGPU.add(g_StatsGPU); + + wchar_t sz[1000]; + + RenderInterface::TxtHelperBegin(); + RenderInterface::TxtHelperSetInsertionPos(2, 0); + RenderInterface::TxtHelperSetForegroundColor(1.0f, 1.0f, 1.0f, 1.0f); + + if (RenderInterface::GetDeviceInfoString(sz)) + RenderInterface::TxtHelperDrawTextLine(sz); + + { + // const NvHair::BuildInfo& buildInfo = GetHairSDK()->getBuildInfo(); + + // char releaseVersion[NvHair::BuildInfo::VERSION_BUFFER_SIZE]; + // buildInfo.m_versionToStringFunc(buildInfo.m_releaseVersion, releaseVersion); + + swprintf_s(sz, 1000, L"Lib build: %S Release version: %S\n", "n.a.", "1.0.0"); + RenderInterface::TxtHelperDrawTextLine(sz); + } + + swprintf_s(sz, 1000, L"Current frame time %3.2f[%d-%d:%2.2f]\n", + globalSettings.m_frameTime, + (int)globalSettings.m_frameStartTime, + (int)globalSettings.m_frameEndTime, + globalSettings.m_animationSpeed); + + RenderInterface::TxtHelperDrawTextLine(sz); + + bool computeProfile = globalSettings.m_computeProfile; + + //FurCharacter& character = SimpleScene::Inst()->GetFurCharacter(); + //std::vector<HairInstance*> validInstances; + //character.GetValidHairInstances(validInstances); + + if (globalSettings.m_computeStatistics && globalSettings.m_showHUD) + { + + //for (int i = 0; i < validInstances.size(); i++) + //{ + // HairInstance* pHairInstance = validInstances[i]; + + // NvHair::Stats& hairStats = pHairInstance->m_hairStats; + + // int totalHairs = hairStats.m_numHairs; + // int totalFaces = hairStats.m_numFaces; + + // float averageNumCVsPerHair = hairStats.m_averageNumCvsPerHair; + // float averageDensity = hairStats.m_averageDensity; + // float averageHairsPerFace = hairStats.m_averageHairsPerFace; + // float distanceLODFactor = hairStats.m_distanceLodFactor; + // float detailLODFactor = hairStats.m_detailLodFactor; + // float camDistance = hairStats.m_camDistance; + + // int m = pHairInstance->getDescriptor().m_splineMultiplier; + // float vertsPerHair = m * (averageNumCVsPerHair - 1.0f) + 1; + // float totalLines = totalHairs * vertsPerHair; + + // const char* hairName = pHairInstance->m_assetName.c_str(); + // std::wstring hairNameW; + // std::copy(hairName, hairName + strlen(hairName), back_inserter(hairNameW)); + + // swprintf_s(sz, 1000, L"Asset Name (%s), %d hairs, %d faces, %.1f lines", + // hairNameW.c_str(), totalHairs, totalFaces, totalLines); + // RenderInterface::TxtHelperDrawTextLine(sz); + + // swprintf_s(sz, 1000, L" average density %.2f, avg hairs per face %.2f, avg CVs per hair %2.1f, avg render vertices per hair %3.1f", + // averageDensity, averageHairsPerFace, averageNumCVsPerHair, vertsPerHair); + // RenderInterface::TxtHelperDrawTextLine(sz); + + // swprintf_s(sz, 1000, L" distance LOD Factor: %.2f, detail LOD Factor: %.2f, camera distance: %.2f", + // distanceLODFactor, detailLODFactor, camDistance); + // RenderInterface::TxtHelperDrawTextLine(sz); + //} + } + + if (globalSettings.m_showFPS) + { + static double fps = 0; + static double lastFrames = GlobalSettings::Inst().m_renderFrameCnt; + Timer& g_fpsTimer = SimpleScene::Inst()->GetTimer(); + static double lastFpsTime = g_fpsTimer.GetTimeInSeconds(); + static int numFrames = 1; + + static Stats lastStatsCPU; + static Stats lastStatsGPU; + + Stats& statsGPU = g_FrameStatsGPU; + Stats& statsCPU = g_FrameStatsCPU; + + double currentFpsTime = g_fpsTimer.GetTimeInSeconds(); + if ((currentFpsTime - lastFpsTime) > 1.0) + { + double currentFrames = GlobalSettings::Inst().m_renderFrameCnt; + numFrames = currentFrames - lastFrames; + + fps = numFrames / (currentFpsTime - lastFpsTime); + + lastFrames = currentFrames; + lastFpsTime = currentFpsTime; + + lastStatsGPU = statsGPU; + lastStatsCPU = statsCPU; + + lastStatsGPU.average((float)numFrames); + lastStatsCPU.average((float)numFrames); + + statsGPU.reset(); + statsCPU.reset(); + } + + if (globalSettings.m_computeProfile) + { + swprintf_s(sz, 1000, L"Render time (GPU/CPU): Total %.2f/%.2fms, Hair %.2f/%.2fms, Mesh %.2f/%.2fms, Shadow %.2f/%.2fms, Stats %.2f/%.2fms", + lastStatsGPU.m_totalRenderTime, lastStatsCPU.m_totalRenderTime, + lastStatsGPU.m_hairRenderTime, lastStatsCPU.m_hairRenderTime, + lastStatsGPU.m_meshRenderTime, lastStatsCPU.m_meshRenderTime, + lastStatsGPU.m_shadowRenderTime, lastStatsCPU.m_shadowRenderTime, + lastStatsGPU.m_hairStatsTime, lastStatsCPU.m_hairStatsTime); + + RenderInterface::TxtHelperDrawTextLine(sz); + + swprintf_s(sz, 1000, L"Update time (GPU/CPU): Total %.2f/%.2fms, Hair Update %.2f/%.2fms, Mesh Skinning %.2f/%.2fms, Sim %.2f/%.2fms", + lastStatsGPU.m_totalUpdateTime, lastStatsCPU.m_totalUpdateTime, + lastStatsGPU.m_hairSkinningTime, lastStatsCPU.m_hairSkinningTime, + lastStatsGPU.m_meshSkinningTime, lastStatsCPU.m_meshSkinningTime, + lastStatsGPU.m_hairSimulationTime, lastStatsCPU.m_hairSimulationTime); + RenderInterface::TxtHelperDrawTextLine(sz); + + { + float cpuMeshTime = lastStatsCPU.m_meshRenderTime + lastStatsCPU.m_meshSkinningTime; + float gpuMeshTime = lastStatsGPU.m_meshRenderTime + lastStatsGPU.m_meshSkinningTime; + + float cpuHairTime = lastStatsCPU.m_totalRenderTime + lastStatsCPU.m_totalUpdateTime - cpuMeshTime; + float gpuHairTime = lastStatsGPU.m_totalRenderTime + lastStatsGPU.m_totalUpdateTime - gpuMeshTime; + + float gpuFPS = 1000.0f / gpuHairTime; + RenderInterface::TxtHelperSetForegroundColor(0.2f, 1.0f, 0.2f, 1.0f); + swprintf_s(sz, 1000, L"Hair: GPU Fps %.2f, GPU time %.2fms, CPU time %.2fms", + gpuFPS, gpuHairTime, cpuHairTime); + RenderInterface::TxtHelperDrawTextLine(sz); + } + + float gpuTime = lastStatsGPU.m_totalRenderTime + lastStatsGPU.m_totalUpdateTime; + float gpuFPS = 1000.0f / gpuTime; + RenderInterface::TxtHelperSetForegroundColor(1.0f, 0.5f, 0.5f, 1.0f); + swprintf_s(sz, 1000, L"Total: GPU Fps %.2f, GPU time %.2fms, CPU time %.2fms", + gpuFPS, + lastStatsGPU.m_totalRenderTime + lastStatsGPU.m_totalUpdateTime, + lastStatsCPU.m_totalRenderTime + lastStatsCPU.m_totalUpdateTime + ); + RenderInterface::TxtHelperDrawTextLine(sz); + + } + else + { + swprintf_s(sz, 1000, L"Fps %.2f", fps); + RenderInterface::TxtHelperDrawTextLine(sz); + } + } + + RenderInterface::TxtHelperEnd(); +} + +bool BlastPlugin::SimpleScene_Draw_DX11() +{ + BlastPlugin::DrawHUD(); + return true; +} + +bool BlastPlugin::SimpleScene_FitCamera(atcore_float3& center, atcore_float3& extents) +{ + return true; +} +bool BlastPlugin::SimpleScene_DrawGround() +{ + return true; +} +bool BlastPlugin::SimpleScene_DrawWind() +{ + return true; +} +bool BlastPlugin::SimpleScene_DrawAxis() +{ + return true; +} + +#include <Shlwapi.h> +#include <FbxUtil.h> +#include <MeshData.h> +#include <PxVec2.h> +#include <SourceAssetOpenDlg.h> +bool BlastPlugin::SimpleScene_LoadSceneFromFbx(const char* d, const char* f) +{ + SourceAssetOpenDlg dlg(false, &AppMainWindow::Inst()); + int res = dlg.exec(); + if (res != QDialog::Accepted || dlg.getFile().isEmpty()) + return false; + + QFileInfo fileInfo(dlg.getFile()); + std::string dir = QDir::toNativeSeparators(fileInfo.absoluteDir().absolutePath()).toLocal8Bit(); + std::string fbxName = fileInfo.fileName().toLocal8Bit(); + + GlobalSettings& globalSettings = GlobalSettings::Inst(); + + char fbxFilePath[MAX_PATH]; + + float sceneUnit = globalSettings.getSceneUnitInCentimeters(); + + PathCombineA(fbxFilePath, dir.c_str(), fbxName.c_str()); + + AppMainWindow::Inst().setProgress("Initializing FBX loader", 0); + FbxUtil::Initialize(fbxFilePath, sceneUnit); + + char rootBoneName[MAX_PATH]; + int upAxis = 0; + + FbxUtil::GetGlobalSettings( + &globalSettings.m_frameStartTime, + &globalSettings.m_frameEndTime, + &globalSettings.m_animationFps, + &upAxis, rootBoneName); + + if (upAxis == 1) + SimpleScene::Inst()->ResetUpDir(false); + else if (upAxis = 2) + SimpleScene::Inst()->ResetUpDir(true); + + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + + int numMeshes = 0; + char* meshNames = 0; + char* skinned = 0; + FbxUtil::GetMeshInfo(&numMeshes, &meshNames, &skinned); + if (numMeshes > 1) + { + //return false; + } + + // to do later when numMeshes is more than one + numMeshes = 1; + + for (int i = 0; i < numMeshes; i++) + { + const char* meshName = meshNames + i * 128; + + MeshDesc meshDesc; + FbxUtil::CreateMeshDescriptor(meshName, meshDesc); + + MeshMaterial* materials = 0; + int numMaterials = 0; + FbxUtil::GetMeshMaterials(meshName, &numMaterials, &materials); + + SkinData skinData; + FbxUtil::InitializeSkinData(meshName, skinData); + + meshDesc.UpdateNormal(false); + + std::vector<physx::PxVec3> positions; + std::vector<physx::PxVec3> normals; + std::vector<physx::PxVec2> uv; + std::vector<unsigned int> indices; + + for (uint32_t i = 0; i < meshDesc.m_NumVertices; ++i) + { + atcore_float3 pos = meshDesc.m_pVertices[i]; + atcore_float3 vertexNormal = meshDesc.m_pVertexNormals[i]; + atcore_float2 texcoord = meshDesc.m_pTexCoords[i]; + + positions.push_back(physx::PxVec3(pos.x, pos.y, pos.z)); + normals.push_back(physx::PxVec3(vertexNormal.x, vertexNormal.y, vertexNormal.z)); + uv.push_back(physx::PxVec2(texcoord.x, texcoord.y)); + } + + for (uint32_t i = 0; i < meshDesc.m_NumTriangles; ++i) + { + indices.push_back(meshDesc.m_pIndices[i * 3 + 0]); + indices.push_back(meshDesc.m_pIndices[i * 3 + 1]); + indices.push_back(meshDesc.m_pIndices[i * 3 + 2]); + } + + sampleManager.createAsset(meshName, positions, normals, uv, indices); + + physx::PxTransform t(physx::PxIdentity); + { + QVector3D Position = dlg.getPosition(); + t.p = physx::PxVec3(Position.x(), Position.y(), Position.z()); + + QVector3D RotationAxis = dlg.getRotationAxis(); + physx::PxVec3 Axis = physx::PxVec3(RotationAxis.x(), RotationAxis.y(), RotationAxis.z()); + Axis = Axis.getNormalized(); + float RotationDegree = dlg.getRotationDegree(); + float DEGREE_TO_RAD = acos(-1.0) / 180.0; + RotationDegree = RotationDegree * DEGREE_TO_RAD; + t.q = physx::PxQuat(RotationDegree, Axis); + } + sampleManager.addModelAsset(meshName, dlg.getSkinned(), t, !dlg.isAppend()); + } + + FbxUtil::Release(); + + globalSettings.m_sceneLoaded = true; + globalSettings.m_animationIndex = 1; + globalSettings.m_firstFrame = true; + + globalSettings.resetAnimation(); + + return true; +} + +bool BlastPlugin::SimpleScene_LoadProject(const char* dir, const char* file) +{ + GlobalSettings& globalSettings = GlobalSettings::Inst(); + SimpleScene* pScene = SimpleScene::Inst(); + nvidia::parameterized::BlastProjectParametersNS::ParametersStruct params; + if (!ProjectParamsLoad(globalSettings.getAbsoluteFilePath().c_str(), pScene)) + return false; + + return true; +} +bool BlastPlugin::SimpleScene_SaveProject(const char* dir, const char* file) +{ + GlobalSettings& globalSettings = GlobalSettings::Inst(); + SimpleScene* pScene = SimpleScene::Inst(); + + QString saveFilePath = globalSettings.getAbsoluteFilePath().c_str(); + QString tempFilePath = utils::GetTempFilePath().c_str(); + if (ProjectParamsSave(tempFilePath.toUtf8().data(), pScene)) + { + if (!utils::RenameFile(tempFilePath.toUtf8().data(), saveFilePath.toUtf8().data(), true /* overwrite */)) + { + return false; + } + pScene->SetProjectModified(false); + return true; + } + + return false; +} +bool BlastPlugin::SimpleScene_LoadParameters(NvParameterized::Interface* iface) +{ + nvidia::parameterized::BlastProjectParameters* params = static_cast<nvidia::parameterized::BlastProjectParameters*>(iface); + + nvidia::parameterized::BlastProjectParametersNS::ParametersStruct& srcDesc = params->parameters(); + copy(BlastProject::ins().getParams(), srcDesc); + + for (int i = 0; i < srcDesc.blast.blastAssets.arraySizes[0]; ++i) + { + BPPAsset& asset = srcDesc.blast.blastAssets.buf[i]; + QFileInfo fileInfo(asset.path.buf); + QByteArray tmp = fileInfo.baseName().toUtf8(); + const char* fileName = tmp.data(); + physx::PxTransform t(physx::PxIdentity); + BPPAssetInstance* instance = BlastProject::ins().getAssetInstance(asset.path.buf, 0); + if (instance != nullptr) + { + nvidia::NvVec3& postion = instance->transform.position; + nvidia::NvVec4& rotation = instance->transform.rotation; + t.p = physx::PxVec3(postion.x, postion.y, postion.z); + t.q = physx::PxQuat(rotation.x, rotation.y, rotation.z, rotation.w); + } + SimpleScene::Inst()->GetSampleManager().addModelAsset(fileName, false, t, true); + } + + SimpleScene* pScene = SimpleScene::Inst(); + + if (pScene->m_pCamera) + { + pScene->m_pCamera->LoadParameters(&srcDesc.camera); + } + + pScene->LoadCameraBookmarks(iface); + + if (pScene->m_pWindCamera) + { + pScene->m_pWindCamera->LoadParameters(&srcDesc.windCamera); + } + + GlobalSettings& globalSettings = GlobalSettings::Inst(); + + // Load scene settings + globalSettings.m_repeatAnimation = srcDesc.scene.repeatAnimation; + globalSettings.m_animationSpeed = srcDesc.scene.animationSpeed; + globalSettings.m_showGrid = srcDesc.scene.showGrid; + globalSettings.m_showAxis = srcDesc.scene.showAxis; + globalSettings.m_zup = srcDesc.scene.upAxis == 1; + globalSettings.m_sceneUnitIndex = srcDesc.scene.sceneUnitIndex; + + // Load render settings + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle("renderer", handle) == NvParameterized::ERROR_NONE) + { + globalSettings.m_computeStatistics = srcDesc.renderer.showStatistics; + globalSettings.m_showGraphicsMesh = srcDesc.renderer.showGraphicsMesh; + globalSettings.m_useLighting = srcDesc.renderer.useLighting; + globalSettings.m_showSkinnedMeshOnly = srcDesc.renderer.showSkinnedMeshOnly; + globalSettings.m_renderFps = srcDesc.renderer.renderFps; + globalSettings.m_simulationFps = srcDesc.renderer.simulationFps; + + Light::LoadParameters(handle); + } + + //// Load fbx paths + //if (iface->getParameterHandle("fbxFilePaths", handle) == NvParameterized::ERROR_NONE) + //{ + // int arraySize; + // handle.getArraySize(arraySize); + // char** strArray = new char*[arraySize]; + // handle.getParamStringArray(strArray, arraySize); + // for (int idx = 0; idx < arraySize; ++idx) + // { + // pScene->LoadSceneFromFbx( + // globalSettings.m_projectFileDir.c_str(), + // strArray[idx]); + // } + // delete[] strArray; + //} + + //// get fur character mesh setting + //if (false == pScene->GetFurCharacter().LoadMeshParameters(handle)) + // return false; + + //// Load apx paths (hair instances) + //if (iface->getParameterHandle("apxFilePaths", handle) == NvParameterized::ERROR_NONE) + //{ + // if (false == pScene->GetFurCharacter().LoadHairParameters(handle)) + // return false; + //} + + BlastProject::ins().loadUserPreset(); + return true; +} +bool BlastPlugin::SimpleScene_SaveParameters(NvParameterized::Interface* iface) +{ + nvidia::parameterized::BlastProjectParameters* params = static_cast<nvidia::parameterized::BlastProjectParameters*>(iface); + nvidia::parameterized::BlastProjectParametersNS::ParametersStruct& targetDesc = params->parameters(); + memset(&targetDesc, sizeof(BPParams), 0); + BPParams& srcParams = BlastProject::ins().getParams(); + copy(targetDesc, srcParams); + + SimpleScene* pScene = SimpleScene::Inst(); + + if (pScene->m_pCamera) + pScene->m_pCamera->SaveParameters(&targetDesc.camera); + + pScene->SaveCameraBookmarks(iface); + + if (pScene->m_pWindCamera) + pScene->m_pWindCamera->SaveParameters(&targetDesc.windCamera); + + // Save scene settings + GlobalSettings& globalSettings = GlobalSettings::Inst(); + + targetDesc.scene.repeatAnimation = globalSettings.m_repeatAnimation; + targetDesc.scene.animationSpeed = globalSettings.m_animationSpeed; + targetDesc.scene.showGrid = globalSettings.m_showGrid; + targetDesc.scene.showAxis = globalSettings.m_showAxis; + targetDesc.scene.upAxis = (globalSettings.m_zup) ? 1 : 2; + targetDesc.scene.sceneUnitIndex = globalSettings.m_sceneUnitIndex; + + // Save render settings + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle("renderer", handle) == NvParameterized::ERROR_NONE) + { + targetDesc.renderer.renderFps = globalSettings.m_renderFps; + targetDesc.renderer.simulationFps = globalSettings.m_simulationFps; + targetDesc.renderer.showStatistics = globalSettings.m_computeStatistics; + targetDesc.renderer.showGraphicsMesh = globalSettings.m_showGraphicsMesh; + targetDesc.renderer.useLighting = globalSettings.m_useLighting; + targetDesc.renderer.showSkinnedMeshOnly = globalSettings.m_showSkinnedMeshOnly; + + Light::SaveParameters(handle); + } + + //if (iface->getParameterHandle("renderer.textureFilePath", handle) == NvParameterized::ERROR_NONE) + //{ + // std::string textureFilePath = globalSettings.getRelativePath(globalSettings.m_backgroundTextureFilePath.c_str()); + // handle.setParamString(textureFilePath.c_str()); + //} + + //// save hair path + //if (iface->getParameterHandle("apxFilePaths", handle) == NvParameterized::ERROR_NONE) + // character.SaveHairParameters(handle); + + return true; +} + +bool BlastPlugin::SimpleScene_LoadCameraBookmarks(NvParameterized::Interface* iface) +{ + return true; +} + +bool BlastPlugin::SimpleScene_SaveCameraBookmarks(NvParameterized::Interface* iface) +{ + SimpleScene* pScene = SimpleScene::Inst(); + + nvidia::parameterized::BlastProjectParameters* params = static_cast<nvidia::parameterized::BlastProjectParameters*>(iface); + nvidia::parameterized::BlastProjectParametersNS::ParametersStruct& srcDesc = params->parameters(); + nvidia::parameterized::BlastProjectParametersNS::CameraBookmark_DynamicArray1D_Type& bookmarks = srcDesc.cameraBookmarks; + + NvParameterized::Handle cameraBookmarksHandle(iface); + if (iface->getParameterHandle("cameraBookmarks", cameraBookmarksHandle) != NvParameterized::ERROR_NONE) + return false; + + int numCameraBookmarks = pScene->m_cameraBookmarks.size(); + cameraBookmarksHandle.resizeArray(numCameraBookmarks); + + for (int idx = 0; idx < numCameraBookmarks; ++idx) + { + NvParameterized::Handle cameraBookmarkHandle(cameraBookmarksHandle); + if (cameraBookmarksHandle.getChildHandle(idx, cameraBookmarkHandle) == NvParameterized::ERROR_NONE) + { + NvParameterized::Handle tempHandle(cameraBookmarkHandle); + CameraBookmark& bookmark = pScene->m_cameraBookmarks[idx]; + + if (ParamGetChild(cameraBookmarkHandle, tempHandle, "name")) + { + tempHandle.setParamString(bookmark.name.toStdString().c_str()); + } + + bookmark.camera.SaveParameters((void*)&(bookmarks.buf[idx].camera)); + } + } + + return true; +} + +bool BlastPlugin::D3DWidget_resizeEvent(QResizeEvent* e) +{ + DeviceManager& deviceManager = SimpleScene::Inst()->GetDeviceManager(); + + int w = e->size().width(); + int h = e->size().height(); + WPARAM wParam = MAKEWPARAM(w, h); + LPARAM lParam = MAKELPARAM(w, h); + deviceManager.MsgProc(g_hWnd, WM_SIZE, wParam, lParam); + + return true; +} + +bool BlastPlugin::D3DWidget_paintEvent(QPaintEvent* e) +{ + SampleManager& pSampleManager = SimpleScene::Inst()->GetSampleManager(); + pSampleManager.run(); + + if (pSampleManager.m_bNeedRefreshTree) + { + _blastSceneTree->updateValues(); + pSampleManager.m_bNeedRefreshTree = false; + } + + return true; +} + +bool BlastPlugin::D3DWidget_mousePressEvent(QMouseEvent* e) +{ + UINT uMsg = WM_LBUTTONDOWN; + if (e->button() == Qt::RightButton) + { + uMsg = WM_RBUTTONDOWN; + } + else if (e->button() == Qt::MidButton) + { + uMsg = WM_MBUTTONDOWN; + } + + int x = e->x(); + int y = e->y(); + WPARAM wParam = MAKEWPARAM(x, y); + LPARAM lParam = MAKELPARAM(x, y); + + DeviceManager& deviceManager = SimpleScene::Inst()->GetDeviceManager(); + deviceManager.MsgProc(g_hWnd, uMsg, wParam, lParam); + + return true; +} + +bool BlastPlugin::D3DWidget_mouseReleaseEvent(QMouseEvent* e) +{ + UINT uMsg = WM_LBUTTONUP; + if (e->button() == Qt::RightButton) + { + uMsg = WM_RBUTTONUP; + } + else if (e->button() == Qt::MidButton) + { + uMsg = WM_MBUTTONUP; + } + + int x = e->x(); + int y = e->y(); + WPARAM wParam = MAKEWPARAM(x, y); + LPARAM lParam = MAKELPARAM(x, y); + + DeviceManager& deviceManager = SimpleScene::Inst()->GetDeviceManager(); + deviceManager.MsgProc(g_hWnd, uMsg, wParam, lParam); + + return true; +} + +bool BlastPlugin::D3DWidget_mouseMoveEvent(QMouseEvent* e) +{ + DeviceManager& deviceManager = SimpleScene::Inst()->GetDeviceManager(); + + int x = e->x(); + int y = e->y(); + WPARAM wParam = MAKEWPARAM(x, y); + LPARAM lParam = MAKELPARAM(x, y); + deviceManager.MsgProc(g_hWnd, WM_MOUSEMOVE, wParam, lParam); + + return true; +} + +bool BlastPlugin::D3DWidget_wheelEvent(QWheelEvent * e) +{ + DeviceManager& deviceManager = SimpleScene::Inst()->GetDeviceManager(); + + int delta = e->delta(); + WPARAM wParam = MAKEWPARAM(delta, delta); + LPARAM lParam = MAKELPARAM(delta, delta); + deviceManager.MsgProc(g_hWnd, WM_MOUSEWHEEL, wParam, lParam); + + return true; +} + +bool BlastPlugin::D3DWidget_keyPressEvent(QKeyEvent* e) +{ return true; } +bool BlastPlugin::D3DWidget_keyReleaseEvent(QKeyEvent* e) +{ return true; } +bool BlastPlugin::D3DWidget_dragEnterEvent(QDragEnterEvent *e) +{ return true; } +bool BlastPlugin::D3DWidget_dragMoveEvent(QDragMoveEvent *e) +{ return true; } +bool BlastPlugin::D3DWidget_dragLeaveEvent(QDragLeaveEvent *e) +{ return true; } +bool BlastPlugin::D3DWidget_dropEvent(QDropEvent *e) +{ return true; } + +bool BlastPlugin::D3DWidget_contextMenuEvent(QContextMenuEvent *e) +{ + QPoint pos = QCursor::pos(); + + std::map<BlastAsset*, std::vector<uint32_t>> selectedAssetChunks = SampleManager::ins()->getSelectedChunks(); + if (1 == selectedAssetChunks.size()) + { + std::map<BlastAsset*, std::vector<uint32_t>>::iterator itr = selectedAssetChunks.begin(); + BlastAsset* asset = itr->first; + std::vector<uint32_t> selectChunks = itr->second; + + std::vector<BlastChunkNode*> chunkNodes = BlastTreeData::ins().getChunkNodeByBlastChunk(asset, selectChunks); + if (1 == chunkNodes.size()) + { + _chunkContextMenu->exec(pos); + } + else if (1 < chunkNodes.size()) + { + bool allSupportChunk = true; + for (size_t i = 0; i < chunkNodes.size(); ++i) + { + BlastChunkNode* chunkNode = chunkNodes[i]; + if (eChunk != chunkNode->getType()) + { + allSupportChunk = false; + break; + } + } + + if (allSupportChunk) + { + _bondContextMenu->exec(QCursor::pos()); + } + } + } + e->accept(); + return true; +} + +#ifdef NV_ARTISTTOOLS +bool BlastPlugin::D3D11Shaders_InitializeShadersD3D11(std::map<int, D3D11RenderShader*>& ShaderMap) +{ + return PluginBlast::Instance()->D3D11Shaders_InitializeShadersD3D11(ShaderMap); +} +#endif // NV_ARTISTTOOLS + +bool BlastPlugin::AppMainWindow_AppMainWindow() +{ + _mainToolbar = 0; + _materialLibraryPanel = 0; + _materialAssignmentsPanel = 0; + _fileReferencesPanel = 0; + _generalPanel = 0; + _defaultDamagePanel = 0; + _fractureCutoutSettingsPanel = 0; + _fractureGeneralPanel = 0; + _fractureShellCutSettingPanel = 0; + _fractureSliceSettingsPanel = 0; + _fractureVisualizersPanel = 0; + _fractureVoronoiSettingsPanel = 0; + _supportPanel = 0; + _blastSceneTree = 0; + _filtersDockWidget = 0; + + return true; +} + +bool BlastPlugin::AppMainWindow_InitMenuItems(QMenuBar* pMenuBar) +{ + QMenu *pMenu = pMenuBar->addMenu("&Blast"); + QAction *act; + + act = new QAction("Open project file", this); + act->setShortcut(QKeySequence::Open); + connect(act, SIGNAL(triggered()), this, SLOT(menu_openProject())); + pMenu->addAction(act); + + act = new QAction("Save project file", this); + act->setShortcut(QKeySequence::Save); + connect(act, SIGNAL(triggered()), this, SLOT(menu_saveProject())); + pMenu->addAction(act); + + act = new QAction("Save project file as...", this); + connect(act, SIGNAL(triggered()), this, SLOT(menu_saveProjectAs())); + pMenu->addAction(act); + + pMenu->addSeparator(); + + return true; +} + +bool BlastPlugin::AppMainWindow_InitMainTab(QWidget *displayScrollAreaContents, QVBoxLayout *displayScrollAreaLayout, int idx) +{ + ExpandablePanel* panel = new ExpandablePanel(displayScrollAreaContents); + displayScrollAreaLayout->insertWidget(idx++, panel); + panel->SetTitle("Display Mesh Materials"); + + return true; +} + +bool BlastPlugin::AppMainWindow_InitPluginTab(QTabWidget* sideBarTab) +{ + { + QWidget *tabMaterial; + QGridLayout *gridLayoutMaterial; + QFrame *materialEditorArea; + QVBoxLayout *materialEditorAreaLayout; + QScrollArea *materialScrollArea; + QWidget *materialScrollAreaContents; + QVBoxLayout *materialScrollAreaLayout; + QSpacerItem *verticalSpacerMaterial; + + tabMaterial = new QWidget(); + tabMaterial->setObjectName(QStringLiteral("tabMaterial")); + gridLayoutMaterial = new QGridLayout(tabMaterial); + gridLayoutMaterial->setSpacing(6); + gridLayoutMaterial->setContentsMargins(11, 11, 11, 11); + gridLayoutMaterial->setObjectName(QStringLiteral("gridLayoutMaterial")); + gridLayoutMaterial->setContentsMargins(0, 0, 0, 0); + materialEditorArea = new QFrame(tabMaterial); + materialEditorArea->setObjectName(QStringLiteral("materialEditorArea")); + materialEditorAreaLayout = new QVBoxLayout(materialEditorArea); + materialEditorAreaLayout->setSpacing(6); + materialEditorAreaLayout->setContentsMargins(11, 11, 11, 11); + materialEditorAreaLayout->setObjectName(QStringLiteral("materialEditorAreaLayout")); + materialEditorAreaLayout->setContentsMargins(2, 2, 2, 2); + + gridLayoutMaterial->addWidget(materialEditorArea, 1, 0, 1, 1); + + materialScrollArea = new QScrollArea(tabMaterial); + materialScrollArea->setObjectName(QStringLiteral("materialScrollArea")); + materialScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + materialScrollArea->setWidgetResizable(true); + materialScrollAreaContents = new QWidget(); + materialScrollAreaContents->setObjectName(QStringLiteral("materialScrollAreaContents")); + materialScrollAreaContents->setGeometry(QRect(0, 0, 359, 481)); + materialScrollAreaLayout = new QVBoxLayout(materialScrollAreaContents); + materialScrollAreaLayout->setSpacing(3); + materialScrollAreaLayout->setContentsMargins(11, 11, 11, 11); + materialScrollAreaLayout->setObjectName(QStringLiteral("materialScrollAreaLayout")); + materialScrollAreaLayout->setContentsMargins(2, 2, 2, 2); + verticalSpacerMaterial = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + materialScrollAreaLayout->addItem(verticalSpacerMaterial); + + materialScrollArea->setWidget(materialScrollAreaContents); + + gridLayoutMaterial->addWidget(materialScrollArea, 0, 0, 1, 1); + + sideBarTab->addTab(tabMaterial, QString()); + + sideBarTab->setTabText(sideBarTab->indexOf(tabMaterial), QApplication::translate("AppMainWindowClass", "Materials", 0)); + + ExpandablePanel* panel = 0; + int pannelCnt = 0; + + panel = new ExpandablePanel(materialScrollAreaContents); + _materialLibraryPanel = new MaterialLibraryPanel(panel); + panel->AddContent(_materialLibraryPanel); + materialScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Material Library"); + + panel = new ExpandablePanel(materialScrollAreaContents); + _materialAssignmentsPanel = new MaterialAssignmentsPanel(panel); + panel->AddContent(_materialAssignmentsPanel); + materialScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Material Assignments"); + } + + { + QWidget *tabBlast; + QGridLayout *gridLayout; + QFrame *blastMaterialEditorArea; + QVBoxLayout *blastMaterialEditorAreaLayout; + QScrollArea *blastScrollArea; + QWidget *blastScrollAreaContents; + QVBoxLayout *blastScrollAreaLayout; + QSpacerItem *verticalSpacer; + + tabBlast = new QWidget(); + tabBlast->setObjectName(QStringLiteral("tabBlast")); + gridLayout = new QGridLayout(tabBlast); + gridLayout->setSpacing(6); + gridLayout->setContentsMargins(11, 11, 11, 11); + gridLayout->setObjectName(QStringLiteral("gridLayout")); + gridLayout->setContentsMargins(0, 0, 0, 0); + blastMaterialEditorArea = new QFrame(tabBlast); + blastMaterialEditorArea->setObjectName(QStringLiteral("blastMaterialEditorArea")); + blastMaterialEditorAreaLayout = new QVBoxLayout(blastMaterialEditorArea); + blastMaterialEditorAreaLayout->setSpacing(6); + blastMaterialEditorAreaLayout->setContentsMargins(11, 11, 11, 11); + blastMaterialEditorAreaLayout->setObjectName(QStringLiteral("blastMaterialEditorAreaLayout")); + blastMaterialEditorAreaLayout->setContentsMargins(2, 2, 2, 2); + + gridLayout->addWidget(blastMaterialEditorArea, 1, 0, 1, 1); + + blastScrollArea = new QScrollArea(tabBlast); + blastScrollArea->setObjectName(QStringLiteral("blastScrollArea")); + blastScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + blastScrollArea->setWidgetResizable(true); + blastScrollAreaContents = new QWidget(); + blastScrollAreaContents->setObjectName(QStringLiteral("blastScrollAreaContents")); + blastScrollAreaContents->setGeometry(QRect(0, 0, 359, 481)); + blastScrollAreaLayout = new QVBoxLayout(blastScrollAreaContents); + blastScrollAreaLayout->setSpacing(3); + blastScrollAreaLayout->setContentsMargins(11, 11, 11, 11); + blastScrollAreaLayout->setObjectName(QStringLiteral("blastScrollAreaLayout")); + blastScrollAreaLayout->setContentsMargins(2, 2, 2, 2); + verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + blastScrollAreaLayout->addItem(verticalSpacer); + + blastScrollArea->setWidget(blastScrollAreaContents); + + gridLayout->addWidget(blastScrollArea, 0, 0, 1, 1); + + sideBarTab->addTab(tabBlast, QString()); + + sideBarTab->setTabText(sideBarTab->indexOf(tabBlast), QApplication::translate("AppMainWindowClass", "Blast", 0)); + + ExpandablePanel* panel = 0; + int pannelCnt = 0; + + panel = new ExpandablePanel(blastScrollAreaContents); + _fileReferencesPanel = new FileReferencesPanel(panel); + panel->AddContent(_fileReferencesPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("File References"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _generalPanel = new GeneralPanel(panel); + panel->AddContent(_generalPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("General"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _supportPanel = new SupportPanel(panel); + panel->AddContent(_supportPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Support"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _blastCompositePanel = new BlastCompositePanel(panel); + panel->AddContent(_blastCompositePanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Blast Composite"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _fractureGeneralPanel = new FractureGeneralPanel(panel); + panel->AddContent(_fractureGeneralPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Fracture General"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _fractureCutoutSettingsPanel = new FractureCutoutSettingsPanel(panel); + panel->AddContent(_fractureCutoutSettingsPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Cutout Projection Settings"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _fractureShellCutSettingPanel = new FractureShellCutSettingsPanel(panel); + panel->AddContent(_fractureShellCutSettingPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Shell Cut Settings"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _fractureSliceSettingsPanel = new FractureSliceSettingsPanel(panel); + panel->AddContent(_fractureSliceSettingsPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Slice Settings"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _fractureVoronoiSettingsPanel = new FractureVoronoiSettingsPanel(panel); + panel->AddContent(_fractureVoronoiSettingsPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Voronoi Settings"); + + panel = new ExpandablePanel(blastScrollAreaContents); + _fractureVisualizersPanel = new FractureVisualizersPanel(panel); + panel->AddContent(_fractureVisualizersPanel); + blastScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Visualizers"); + } + + { + QWidget *tabDamage; + QGridLayout *gridLayoutDamage; + QFrame *damageEditorArea; + QVBoxLayout *damageEditorAreaLayout; + QScrollArea *damageScrollArea; + QWidget *damageScrollAreaContents; + QVBoxLayout *damageScrollAreaLayout; + QSpacerItem *verticalSpacerDamage; + + tabDamage = new QWidget(); + tabDamage->setObjectName(QStringLiteral("tabDamage")); + gridLayoutDamage = new QGridLayout(tabDamage); + gridLayoutDamage->setSpacing(6); + gridLayoutDamage->setContentsMargins(11, 11, 11, 11); + gridLayoutDamage->setObjectName(QStringLiteral("gridLayoutDamage")); + gridLayoutDamage->setContentsMargins(0, 0, 0, 0); + damageEditorArea = new QFrame(tabDamage); + damageEditorArea->setObjectName(QStringLiteral("damageEditorArea")); + damageEditorAreaLayout = new QVBoxLayout(damageEditorArea); + damageEditorAreaLayout->setSpacing(6); + damageEditorAreaLayout->setContentsMargins(11, 11, 11, 11); + damageEditorAreaLayout->setObjectName(QStringLiteral("damageEditorAreaLayout")); + damageEditorAreaLayout->setContentsMargins(2, 2, 2, 2); + + gridLayoutDamage->addWidget(damageEditorArea, 1, 0, 1, 1); + + damageScrollArea = new QScrollArea(tabDamage); + damageScrollArea->setObjectName(QStringLiteral("damageScrollArea")); + damageScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + damageScrollArea->setWidgetResizable(true); + damageScrollAreaContents = new QWidget(); + damageScrollAreaContents->setObjectName(QStringLiteral("damageScrollAreaContents")); + damageScrollAreaContents->setGeometry(QRect(0, 0, 359, 481)); + damageScrollAreaLayout = new QVBoxLayout(damageScrollAreaContents); + damageScrollAreaLayout->setSpacing(3); + damageScrollAreaLayout->setContentsMargins(11, 11, 11, 11); + damageScrollAreaLayout->setObjectName(QStringLiteral("damageScrollAreaLayout")); + damageScrollAreaLayout->setContentsMargins(2, 2, 2, 2); + verticalSpacerDamage = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + damageScrollAreaLayout->addItem(verticalSpacerDamage); + + damageScrollArea->setWidget(damageScrollAreaContents); + + gridLayoutDamage->addWidget(damageScrollArea, 0, 0, 1, 1); + + sideBarTab->addTab(tabDamage, QString()); + + sideBarTab->setTabText(sideBarTab->indexOf(tabDamage), QApplication::translate("AppMainWindowClass", "Damage", 0)); + + ExpandablePanel* panel = 0; + int pannelCnt = 0; + + panel = new ExpandablePanel(damageScrollAreaContents); + _defaultDamagePanel = new DefaultDamagePanel(panel); + panel->AddContent(_defaultDamagePanel); + damageScrollAreaLayout->insertWidget(pannelCnt++, panel); + panel->SetTitle("Default Damage"); + } + + return true; +} + +bool BlastPlugin::AppMainWindow_InitUI() +{ + AppMainWindow* mainWindow = &AppMainWindow::Inst(); + _mainToolbar = new BlastToolbar(mainWindow); + _mainToolbar->setAllowedAreas(Qt::TopDockWidgetArea); + _mainToolbar->setFeatures(_mainToolbar->features()&~QDockWidget::DockWidgetClosable); + mainWindow->addDockWidget(Qt::TopDockWidgetArea, _mainToolbar); + + _filtersDockWidget = new FiltersDockWidget(mainWindow); + _filtersDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea); + _filtersDockWidget->setFeatures(_filtersDockWidget->features()&~QDockWidget::DockWidgetClosable); + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, _filtersDockWidget); + + _blastSceneTree = new BlastSceneTree(mainWindow); + _blastSceneTree->setAllowedAreas(Qt::LeftDockWidgetArea); + _blastSceneTree->setFeatures(_blastSceneTree->features()&~QDockWidget::DockWidgetClosable); + _blastSceneTree->addObserver(_defaultDamagePanel); + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, _blastSceneTree); + return true; +} + +bool BlastPlugin::AppMainWindow_updateUI() +{ + if (_mainToolbar) + _mainToolbar->updateValues(); + + if (_filtersDockWidget) + _filtersDockWidget->updateValues(); + + if (_blastSceneTree) + _blastSceneTree->updateValues(); + + if (_materialLibraryPanel) + _materialLibraryPanel->updateValues(); + + if (_materialAssignmentsPanel) + _materialAssignmentsPanel->updateValues(); + + if (_fileReferencesPanel) + _fileReferencesPanel->updateValues(); + + if (_generalPanel) + _generalPanel->updateValues(); + + if (_blastCompositePanel) + _blastCompositePanel->updateValues(); + + if (_fractureCutoutSettingsPanel) + _fractureCutoutSettingsPanel->updateValues(); + + if (_fractureGeneralPanel) + _fractureGeneralPanel->updateValues(); + + if (_fractureShellCutSettingPanel) + _fractureShellCutSettingPanel->updateValues(); + + if (_fractureSliceSettingsPanel) + _fractureSliceSettingsPanel->updateValues(); + + if (_fractureVisualizersPanel) + _fractureVisualizersPanel->updateValues(); + + if (_fractureVoronoiSettingsPanel) + _fractureVoronoiSettingsPanel->updateValues(); + + if (_supportPanel) + _supportPanel->updateValues(); + + if (_defaultDamagePanel) + _defaultDamagePanel->updateValues(); + return true; +} + +bool BlastPlugin::AppMainWindow_updatePluginUI() +{ + return true; +} + +bool BlastPlugin::AppMainWindow_processDragAndDrop(QString fname) +{ + return true; +} + +bool BlastPlugin::AppMainWindow_closeEvent(QCloseEvent *event) +{ + if (!menu_saveProject()) + { + return false; + } + + return true; +} + + +bool BlastPlugin::AppMainWindow_InitToolbar(QWidget *pQWidget, QVBoxLayout* pLayout) +{ + //_mainToolbar = new BlastToolbar(pQWidget); + //pLayout->insertWidget(0, _mainToolbar); +// connect(_mainToolbar->getUI().btnFileOpen, SIGNAL(clicked()), this, SLOT(menu_openProject())); + + return true; +} + +bool BlastPlugin::AppMainWindow_shortcut_expert(bool mode) +{ + if (_mainToolbar) + _mainToolbar->setVisible(mode); + + return true; +} + +bool BlastPlugin::AppMainWindow_updateMainToolbar() +{ + if (_mainToolbar) + _mainToolbar->updateValues(); + + return true; +} + +bool BlastPlugin::AppMainWindow_menu_about() +{ + return true; +} + +bool BlastPlugin::AppMainWindow_menu_opendoc() +{ + QString appDir = QApplication::applicationDirPath(); + QString docsFile = QFileInfo(appDir + "/../../docs/User_Guide/Nvidia Blast.chm").absoluteFilePath(); + + QUrl docsUrl = QUrl::fromLocalFile(docsFile); + QUrl url = QUrl::fromUserInput(QString("http://docs.nvidia.com/gameworks/content/artisttools/blast/index.html")); + QDesktopServices::openUrl(url); + + return true; +} + +#if USE_CURVE_EDITOR +#include "CurveEditorMainWindow.h" + +bool BlastPlugin::AppMainWindow_UpdateCurveEditor() +{ + return true; +} +bool BlastPlugin::AppMainWindow_ShowCurveEditor(int paramId) +{ + return true; +} +bool BlastPlugin::AppMainWindow_onCurveAttributeChanged(nvidia::CurveEditor::CurveAttribute* attribute) +{ + return true; +} +bool BlastPlugin::AppMainWindow_onColorAttributeChanged(nvidia::CurveEditor::ColorAttribute* attribute) +{ + return true; +} +bool BlastPlugin::AppMainWindow_onReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute* attribute, bool reloadColorTex, int selectedCtrlPntIndex) +{ + return true; +} +#endif + +bool BlastPlugin::menu_openProject() +{ + AppMainWindow& window = AppMainWindow::Inst(); + QString lastDir = window._lastFilePath; + QString fileName = QFileDialog::getOpenFileName(&window, "Open Blast Project File", lastDir, "Blast Project File (*.blastProj)"); + + return window.openProject(fileName); +} + +bool BlastPlugin::menu_saveProject() +{ + char message[1024]; + + std::string projectFilePath = GlobalSettings::Inst().getAbsoluteFilePath(); + std::string projectFileName = GlobalSettings::Inst().m_projectFileName; + if (projectFileName != "") + { + if (SimpleScene::Inst()->SaveProject( + GlobalSettings::Inst().m_projectFileDir.c_str(), + GlobalSettings::Inst().m_projectFileName.c_str() + ) == false) + { + QMessageBox messageBox; + + sprintf(message, "Project file %s could not be saved!", (const char*)projectFilePath.c_str()); + messageBox.critical(0, "Error", message); + messageBox.setFixedSize(500, 200); + char message[1024]; + sprintf(message, "Failed to save project file(\"%s\")", (const char*)projectFilePath.c_str()); + viewer_err(message); + return false; + } + + sprintf(message, "Project file %s was saved.", (const char*)projectFilePath.c_str()); + + /* + QMessageBox messageBox; + messageBox.information(0, "Info", message); + messageBox.setFixedSize(500,200); + */ + viewer_msg(message); + return true; + } + else + { + return menu_saveProjectAs(); + } + return false; +} + +bool BlastPlugin::menu_saveProjectAs() +{ + AppMainWindow& window = AppMainWindow::Inst(); + + char message[1024]; + + QString lastDir = window._lastFilePath; + QString fileName = QFileDialog::getSaveFileName(&window, "Save Blast Project File", lastDir, "Blast Project File (*.blastProj)"); + if (!fileName.isEmpty()) + { + QFileInfo fileInfo(fileName); + QByteArray dir = QDir::toNativeSeparators(fileInfo.absoluteDir().absolutePath()).toLocal8Bit(); + QByteArray file = fileInfo.fileName().toLocal8Bit(); + + if (SimpleScene::Inst()->SaveProject(dir, file) == false) + { + QMessageBox messageBox; + sprintf(message, "Project file %s could not be saved!", (const char*)file); + messageBox.critical(0, "Error", message); + messageBox.setFixedSize(500, 200); + return false; + } + + sprintf(message, "Project file %s was saved.", (const char*)file); + + /* + QMessageBox messageBox; + messageBox.information(0, "Info", message); + messageBox.setFixedSize(500,200); + */ + + viewer_msg(message); + + window._lastFilePath = fileInfo.absoluteDir().absolutePath(); + return true; + } + return false; +} + +bool BlastPlugin::shortcut_damagetool() +{ + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Damage); + return true; +} + +bool BlastPlugin::shortcut_selecttool() +{ + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Select); + return true; +} + +bool BlastPlugin::shortcut_Translate() +{ + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Translate); + return true; +} + +bool BlastPlugin::shortcut_Rotation() +{ + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Rotation); + return true; +} + +bool BlastPlugin::shortcut_Scale() +{ + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Scale); + return true; +} + +bool BlastPlugin::shortcut_edittool() +{ + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Edit); + return true; +} + +bool BlastPlugin::slot_Make_Support() +{ + BlastSceneTree::ins()->makeSupport(); + return true; +} + +bool BlastPlugin::slot_Make_Static_Support() +{ + BlastSceneTree::ins()->makeStaticSupport(); + return true; +} + +bool BlastPlugin::slot_Remove_Support() +{ + BlastSceneTree::ins()->removeSupport(); + return true; +} + +bool BlastPlugin::slot_Bond_Chunks() +{ + BlastSceneTree::ins()->bondChunks(); + return true; +} + +bool BlastPlugin::slot_Bond_Chunks_with_Joints() +{ + BlastSceneTree::ins()->bondChunksWithJoints(); + return true; +} + +bool BlastPlugin::slot_Remove_all_Bonds() +{ + BlastSceneTree::ins()->removeAllBonds(); + return true; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/BlastPlugin.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/BlastPlugin.h new file mode 100644 index 0000000..21a5499 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/BlastPlugin.h @@ -0,0 +1,192 @@ +#ifndef BLASTPLUGIN_H +#define BLASTPLUGIN_H + +#include <QtCore/QObject> +#include <QtCore/QtPlugin> +#include "PluginInterface.h" +#include "UIGlobal.h" + +class QMenu; +class QAction; +class QDoubleSpinBox; +class QComboBox; +class QCheckBox; +class QVBoxLayout; +class BlastToolbar; +class FileReferencesPanel; +class GeneralPanel; +class BlastCompositePanel; +class DefaultDamagePanel; +class MaterialLibraryPanel; +class MaterialAssignmentsPanel; +class FractureCutoutSettingsPanel; +class FractureGeneralPanel; +class FractureShellCutSettingsPanel; +class FractureSliceSettingsPanel; +class FractureVisualizersPanel; +class FractureVoronoiSettingsPanel; +class SupportPanel; +class BlastSceneTree; +class FiltersDockWidget; + +class Camera; +class Light; +namespace NvParameterized +{ + class Interface; + class Handle; +} +class D3D11RenderShader; + +#define BlastPluginName "BlastPlugin" + +class BlastPlugin : public QObject, public PluginInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID PluginInterface_iid FILE "blastplugin.json") + Q_INTERFACES(PluginInterface) + +public: + virtual QString GetPluginName(); + + virtual bool CoreLib_RunApp(); + + virtual bool LoadRenderPlugin(std::string api); + + virtual bool GetBoneNames(std::vector<std::string>& BoneNames); + + virtual bool MainToolbar_updateValues(); + + virtual bool CurveEditor_updateValues(int _paramId, float* _values); + virtual bool CurveEditor_onUpdateValues(int _paramId, float* _values); + + virtual bool DisplayMeshesPanel_updateValues(); + virtual bool DisplayMeshesPanel_EmitToggleSignal(unsigned int id, bool visible); + + virtual bool Camera_LoadParameters(void* ptr, Camera* pCamera); + virtual bool Camera_SaveParameters(void * ptr, Camera* pCamera); + + virtual bool Gamepad_ToggleSimulation(); + virtual bool Gamepad_LoadSamples(QString fn); + virtual bool Gamepad_ResetScene(); + virtual bool Gamepad_StartAnimation(); + virtual bool GamepadHandler_ShowHair(); + virtual bool GamepadHandler_SpinWindStrength(float windStrength); + virtual bool Gamepad_ResetAnimation(); + virtual bool Gamepad_PlayPauseAnimation(); + + virtual bool Light_loadParameters(NvParameterized::Handle& handle, Light* pLight); + virtual bool Light_saveParameters(NvParameterized::Handle& handle, Light* pLight); + + virtual bool SimpleScene_SimpleScene(); + virtual bool SimpleScene_Initialize(int backdoor); + virtual bool SimpleScene_Shutdown(); + virtual bool SimpleScene_Clear(); + virtual bool SimpleScene_Draw_DX12(); + virtual bool SimpleScene_Draw_DX11(); + virtual bool SimpleScene_FitCamera(atcore_float3& center, atcore_float3& extents); + virtual bool SimpleScene_DrawGround(); + virtual bool SimpleScene_DrawWind(); + virtual bool SimpleScene_DrawAxis(); + virtual bool SimpleScene_LoadSceneFromFbx(const char* dir, const char* fbxName); + virtual bool SimpleScene_LoadProject(const char* dir, const char* file); + virtual bool SimpleScene_SaveProject(const char* dir, const char* file); + virtual bool SimpleScene_LoadParameters(NvParameterized::Interface* iface); + virtual bool SimpleScene_SaveParameters(NvParameterized::Interface* iface); + virtual bool SimpleScene_LoadCameraBookmarks(NvParameterized::Interface* iface); + virtual bool SimpleScene_SaveCameraBookmarks(NvParameterized::Interface* iface); + + virtual bool D3DWidget_resizeEvent(QResizeEvent* e); + virtual bool D3DWidget_paintEvent(QPaintEvent* e); + virtual bool D3DWidget_mousePressEvent(QMouseEvent* e); + virtual bool D3DWidget_mouseReleaseEvent(QMouseEvent* e); + virtual bool D3DWidget_mouseMoveEvent(QMouseEvent* e); + virtual bool D3DWidget_wheelEvent(QWheelEvent * e); + virtual bool D3DWidget_keyPressEvent(QKeyEvent* e); + virtual bool D3DWidget_keyReleaseEvent(QKeyEvent* e); + virtual bool D3DWidget_dragEnterEvent(QDragEnterEvent *e); + virtual bool D3DWidget_dragMoveEvent(QDragMoveEvent *e); + virtual bool D3DWidget_dragLeaveEvent(QDragLeaveEvent *e); + virtual bool D3DWidget_dropEvent(QDropEvent *e); + virtual bool D3DWidget_contextMenuEvent(QContextMenuEvent *e); + + virtual bool D3D11Shaders_InitializeShadersD3D11(std::map<int, D3D11RenderShader*>& ShaderMap); + + virtual bool AppMainWindow_AppMainWindow(); + virtual bool AppMainWindow_InitMenuItems(QMenuBar* pMenuBar); + virtual bool AppMainWindow_InitMainTab(QWidget *displayScrollAreaContents, QVBoxLayout *displayScrollAreaLayout, int idx); + virtual bool AppMainWindow_InitPluginTab(QTabWidget* pTabWidget); + virtual bool AppMainWindow_InitUI(); + virtual bool AppMainWindow_updateUI(); + virtual bool AppMainWindow_updatePluginUI(); + virtual bool AppMainWindow_processDragAndDrop(QString fname); + virtual bool AppMainWindow_closeEvent(QCloseEvent *event); + virtual bool AppMainWindow_InitToolbar(QWidget *pQWidget, QVBoxLayout* pLayout); + virtual bool AppMainWindow_shortcut_expert(bool mode); + virtual bool AppMainWindow_updateMainToolbar(); + + virtual bool AppMainWindow_menu_about(); + virtual bool AppMainWindow_menu_opendoc(); +#if USE_CURVE_EDITOR + virtual bool AppMainWindow_UpdateCurveEditor(); + virtual bool AppMainWindow_ShowCurveEditor(int paramId); + virtual bool AppMainWindow_onCurveAttributeChanged(nvidia::CurveEditor::CurveAttribute* attribute); + virtual bool AppMainWindow_onColorAttributeChanged(nvidia::CurveEditor::ColorAttribute* attribute); + virtual bool AppMainWindow_onReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute* attribute, bool reloadColorTex, int selectedCtrlPntIndex); +#endif + BlastToolbar* GetMainToolbar() { return _mainToolbar; } + +public: + static void DrawHUD(); + + ///////////////////////////////////////////////////////////////////// + // profiler and timer + static void ResetFrameTimer(); + +public slots: + bool menu_openProject(); + bool menu_saveProject(); + bool menu_saveProjectAs(); + bool shortcut_damagetool(); + bool shortcut_selecttool(); + bool shortcut_Translate(); + bool shortcut_Rotation(); + bool shortcut_Scale(); + bool shortcut_edittool(); + + bool slot_Make_Support(); + bool slot_Make_Static_Support(); + bool slot_Remove_Support(); + bool slot_Bond_Chunks(); + bool slot_Bond_Chunks_with_Joints(); + bool slot_Remove_all_Bonds(); + +private: + BlastToolbar* _mainToolbar; + MaterialLibraryPanel* _materialLibraryPanel; + MaterialAssignmentsPanel* _materialAssignmentsPanel; + FileReferencesPanel* _fileReferencesPanel; + GeneralPanel* _generalPanel; + BlastCompositePanel* _blastCompositePanel; + DefaultDamagePanel* _defaultDamagePanel; + FractureCutoutSettingsPanel* _fractureCutoutSettingsPanel; + FractureGeneralPanel* _fractureGeneralPanel; + FractureShellCutSettingsPanel* _fractureShellCutSettingPanel; + FractureSliceSettingsPanel* _fractureSliceSettingsPanel; + FractureVisualizersPanel* _fractureVisualizersPanel; + FractureVoronoiSettingsPanel* _fractureVoronoiSettingsPanel; + SupportPanel* _supportPanel; + BlastSceneTree* _blastSceneTree; + FiltersDockWidget* _filtersDockWidget; + + QMenu* _chunkContextMenu; + QMenu* _bondContextMenu; + QAction* action_Make_Support; + QAction* action_Make_Static_Support; + QAction* action_Remove_Support; + QAction* action_Bond_Chunks; + QAction* action_Bond_Chunks_with_Joints; + QAction* action_Remove_all_Bonds; +}; + +#endif // HAIRWORKSPLUGIN_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/FoundationHolder.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/FoundationHolder.h new file mode 100644 index 0000000..5ec7868 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/FoundationHolder.h @@ -0,0 +1,138 @@ +// This code contains NVIDIA Confidential Information and is disclosed +// under the Mutual Non-Disclosure Agreement. +// +// Notice +// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES +// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless +// expressly authorized by NVIDIA. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2013 NVIDIA Corporation. All rights reserved. +// +// NVIDIA Corporation and its licensors retain all intellectual property and proprietary +// rights in and to this software and 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. +// + +#pragma once + +#include "NvErrorCallback.h" +#include "NsGlobals.h" +#include "NsVersionNumber.h" + +class DefaultErrorCallback : public nvidia::NvErrorCallback +{ +public: + DefaultErrorCallback(void) + { + } + + virtual void reportError(nvidia::NvErrorCode::Enum code, const char* message, const char* file, int line) + { + NV_UNUSED(code); + printf("PhysX: %s : %s : %d\r\n", message, file, line); + } +private: +}; + +class DefaultAllocator : public nvidia::NvAllocatorCallback +{ +public: + DefaultAllocator(void) + { + } + + ~DefaultAllocator(void) + { + } + + virtual void* allocate(size_t size, const char* typeName, const char* filename, int line) + { + NV_UNUSED(typeName); + NV_UNUSED(filename); + NV_UNUSED(line); + void *ret = ::_aligned_malloc(size, 16); + return ret; + } + + virtual void deallocate(void* ptr) + { + ::_aligned_free(ptr); + } +private: +}; + + +#if 0 +class FoundationHolder +{ + NvFoundation* mFoundation; + FoundationHolder() + :mFoundation(nullptr) + { + } + + ~FoundationHolder() + { + if (mFoundation) + { + // to-do + // we should release foundation. but Hair SDK could release it first. + //mFoundation->release(); + mFoundation = nullptr; + } + } + +public: + + static NvFoundation* GetFoundation() + { + static FoundationHolder fh; + if (fh.mFoundation == nullptr) + { + static DefaultAllocator sDefaultAllocator; + static DefaultErrorCallback sDefaultErrorCallback; + fh.mFoundation = NvCreateFoundation(NV_FOUNDATION_VERSION, sDefaultAllocator, sDefaultErrorCallback); + assert(fh.mFoundation != nullptr); + } + return fh.mFoundation; + } +}; + +#else + +class FoundationHolder +{ + bool m_isInitialized; + public: + static void GetFoundation() + { + static FoundationHolder s_holder; + if (!s_holder.m_isInitialized) + { + static DefaultAllocator sDefaultAllocator; + static DefaultErrorCallback sDefaultErrorCallback; + nvidia::shdfnd::initializeSharedFoundation(NV_FOUNDATION_VERSION, sDefaultAllocator, sDefaultErrorCallback); + + s_holder.m_isInitialized = true; + } + } + ~FoundationHolder() + { + //nvidia::terminateSharedFoundation(); + } +}; + +#endif diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/ProjectParams.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/ProjectParams.cpp new file mode 100644 index 0000000..36d78cc --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/ProjectParams.cpp @@ -0,0 +1,2162 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and 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. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved. + +#include "NvParameterized.h" +#include "XmlSerializer.h" +#include "NsFileBuffer.h" +#include "NvTraits.h" +#include "NsMemoryBuffer.h" + +#include "BlastProjectParameters.h" +#include "SimpleScene.h" +#include "ProjectParams.h" + +#include "NvErrorCallback.h" +#include "NsGlobals.h" +#include "NsVersionNumber.h" +#include <QtXml\QtXml> +#include <QtWidgets/QMessageBox> +#include "AppMainWindow.h" +#include "FoundationHolder.h" + +using namespace nvidia; +using namespace nvidia::parameterized; + + +struct ProjectParamsContext* g_projectParamsContext = nullptr; +const char* USER_PRESET_PATH = ".\\BlastUserPreset.userPreset"; + +struct ProjectParamsContext +{ + //NvFoundation* mFoundation; + NvParameterized::Traits* mTraits; + BlastProjectParametersFactory* mBlastProjectParametersFactory; +}; + +void freeString(NvParameterized::DummyStringStruct& str) +{ + delete[] str.buf; + str.buf = nullptr; +} + +void freeBlast(BPPGraphicsMesh& data) +{ + freeString(data.name); +} + +void freeBlast(BPPChunk& data) +{ + freeString(data.name); + freeString(data.asset); +} + +void freeBlast(BPPBond& data) +{ + freeString(data.name); + freeString(data.asset); +} + +void freeBlast(BPPAsset& data) +{ + freeString(data.path); +} + +void freeBlast(BPPAssetInstance& data) +{ + freeString(data.name); + freeString(data.source); +} + +void freeBlast(BPPComposite& data) +{ + freeString(data.composite); + + freeBlast(data.blastAssetInstances); + freeBlast(data.landmarks); +} + +void freeBlast(BPPBlast& data) +{ + freeString(data.fileReferences.fbxSourceAsset); + freeString(data.fileReferences.fbx); + freeString(data.fileReferences.blast); + freeString(data.fileReferences.collision); + + freeBlast(data.composite); + freeBlast(data.blastAssets); + freeBlast(data.chunks); + freeBlast(data.bonds); +} + +void freeBlast(BPPLandmark& data) +{ + freeString(data.name); +} + +void freeBlast(BPPStringArray& data) +{ + for (int i = 0; i < data.arraySizes[0]; ++i) + { + freeString(data.buf[i]); + } + + delete[] data.buf; + data.buf = nullptr; + data.arraySizes[0] = 0; +} + +void freeBlast(BPPGraphicsMeshArray& data) +{ + for (int i = 0; i < data.arraySizes[0]; ++i) + { + freeBlast(data.buf[i]); + } + + delete[] data.buf; + data.buf = nullptr; + data.arraySizes[0] = 0; +} + +void freeBlast(BPPChunkArray& data) +{ + for (int i = 0; i < data.arraySizes[0]; ++i) + { + freeBlast(data.buf[i]); + } + + delete[] data.buf; + data.buf = nullptr; + data.arraySizes[0] = 0; +} + +void freeBlast(BPPBondArray& data) +{ + for (int i = 0; i < data.arraySizes[0]; ++i) + { + freeBlast(data.buf[i]); + } + + delete[] data.buf; + data.buf = nullptr; + data.arraySizes[0] = 0; +} + +void freeBlast(BPPAssetArray& data) +{ + for (int i = 0; i < data.arraySizes[0]; ++i) + { + freeBlast(data.buf[i]); + } + + delete[] data.buf; + data.buf = nullptr; + data.arraySizes[0] = 0; +} + +void freeBlast(BPPAssetInstanceArray& data) +{ + for (int i = 0; i < data.arraySizes[0]; ++i) + { + freeBlast(data.buf[i]); + } + + delete[] data.buf; + data.buf = nullptr; + data.arraySizes[0] = 0; +} + +void freeBlast(BPPLandmarkArray& data) +{ + for (int i = 0; i < data.arraySizes[0]; ++i) + { + freeBlast(data.buf[i]); + } + + delete[] data.buf; + data.buf = nullptr; + data.arraySizes[0] = 0; +} + +void copy(NvParameterized::DummyStringStruct& dest, const char* source) +{ + delete[] dest.buf; + dest.buf = nullptr; + //dest.isAllocated = false; + + if (source != nullptr) + { + dest.buf = new char[strlen(source) + 1]; + strcpy(const_cast<char*>(dest.buf), source); + //dest.isAllocated = true; + } +} + +void copy(NvParameterized::DummyStringStruct& dest, NvParameterized::DummyStringStruct& source) +{ + copy(dest, source.buf); +} + +void copy(BPPStringArray& dest, BPPStringArray& source) +{ + { + for (int i = 0; i < dest.arraySizes[0]; ++i) + { + delete[] dest.buf[i].buf; + } + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + } + + + if (source.arraySizes[0] > 0) + { + dest.buf = new NvParameterized::DummyStringStruct[source.arraySizes[0]]; + + for (int i = 0; i < source.arraySizes[0]; ++i) + { + NvParameterized::DummyStringStruct& destItem = dest.buf[i]; + NvParameterized::DummyStringStruct& sourceItem = source.buf[i]; + + destItem.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPGraphicsMaterialArray& dest, BPPGraphicsMaterialArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPGraphicsMaterial[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPGraphicsMaterial& destItem = dest.buf[i]; + BPPGraphicsMaterial& sourceItem = source.buf[i]; + + init(destItem); + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPGraphicsMeshArray& dest, BPPGraphicsMeshArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPGraphicsMesh[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPGraphicsMesh& destItem = dest.buf[i]; + BPPGraphicsMesh& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + + copy(destItem.name, sourceItem.name); + destItem.visible = sourceItem.visible; + copy(destItem.materialAssignments, sourceItem.materialAssignments); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPBookmarkArray& dest, BPPBookmarkArray& source) +{ + { + int count = dest.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + delete[] dest.buf[i].name.buf; + } + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + } + + { + int count = source.arraySizes[0]; + dest.arraySizes[0] = count; + if (count > 0) + { + dest.buf = new BPPCameraBookmark[count]; + for (int i = 0; i < count; ++i) + { + BPPCameraBookmark& destItem = dest.buf[i]; + BPPCameraBookmark& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + + copy(destItem.name, sourceItem.name); + destItem.camera = sourceItem.camera; + } + } + } +} + +void copy(BPPLightArray& dest, BPPLightArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPLight[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPLight& destItem = dest.buf[i]; + BPPLight& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + + copy(destItem.name, sourceItem.name); + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPChunkArray& dest, BPPChunkArray& source) +{ + freeBlast(dest); + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPChunk[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPChunk& destItem = dest.buf[i]; + BPPChunk& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + destItem.asset.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPBondArray& dest, BPPBondArray& source) +{ + freeBlast(dest); + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPBond[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPBond& destItem = dest.buf[i]; + BPPBond& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + destItem.asset.buf = nullptr; + destItem.support.healthMask.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPProjectileArray& dest, BPPProjectileArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPProjectile[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPProjectile& destItem = dest.buf[i]; + BPPProjectile& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPAssetArray& dest, BPPAssetArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPAsset[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPAsset& destItem = dest.buf[i]; + BPPAsset& sourceItem = source.buf[i]; + + destItem.path.buf = nullptr; + destItem.activePreset.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPAssetInstanceArray& dest, BPPAssetInstanceArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPAssetInstance[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPAssetInstance& destItem = dest.buf[i]; + BPPAssetInstance& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + destItem.source.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPLandmarkArray& dest, BPPLandmarkArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPLandmark[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPLandmark& destItem = dest.buf[i]; + BPPLandmark& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPU32Array& dest, BPPU32Array& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new uint32_t[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + uint32_t& destItem = dest.buf[i]; + uint32_t& sourceItem = source.buf[i]; + + destItem = sourceItem; + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPFilterPresetArray& dest, BPPFilterPresetArray& source) +{ + delete[] dest.buf; + dest.buf = nullptr; + dest.arraySizes[0] = 0; + + if (source.arraySizes[0] > 0) + { + dest.buf = new BPPFilterPreset[source.arraySizes[0]]; + for (int i = 0; i < source.arraySizes[0]; ++i) + { + BPPFilterPreset& destItem = dest.buf[i]; + BPPFilterPreset& sourceItem = source.buf[i]; + + destItem.name.buf = nullptr; + destItem.depthFilters.buf = nullptr; + + copy(destItem, sourceItem); + } + dest.arraySizes[0] = source.arraySizes[0]; + } +} + +void copy(BPPLight& dest, BPPLight& source) +{ + copy(dest.name, source.name); + dest.enable = source.enable; + dest.useShadows = source.useShadows; + dest.lockToRoot = source.lockToRoot; + dest.visualize = source.visualize; + dest.type = source.type; + dest.shadowMapResolution = source.shadowMapResolution; + dest.color = source.color; + dest.diffuseColor = source.diffuseColor; + dest.ambientColor = source.ambientColor; + dest.specularColor = source.specularColor; + dest.intensity = source.intensity; + dest.distance = source.distance; + dest.spotFalloffStart = source.spotFalloffStart; + dest.spotFalloffEnd = source.spotFalloffEnd; + dest.lightAxisX = source.lightAxisX; + dest.lightAxisY = source.lightAxisY; + dest.lightAxisZ = source.lightAxisZ; + dest.lightPos = source.lightPos; +} + +void copy(BPPGraphicsMaterial& dest, BPPGraphicsMaterial& source) +{ + copy(dest.name, source.name); + dest.useTextures = source.useTextures; + copy(dest.diffuseTextureFilePath, source.diffuseTextureFilePath); + copy(dest.specularTextureFilePath, source.specularTextureFilePath); + copy(dest.normalTextureFilePath, source.normalTextureFilePath); + dest.diffuseColor = source.diffuseColor; + dest.specularColor = source.specularColor; + dest.specularShininess = source.specularShininess; +} + +void copy(BPPGraphicsMesh& dest, BPPGraphicsMesh& source) +{ + copy(dest.name, source.name); + dest.visible = source.visible; + copy(dest.materialAssignments, source.materialAssignments); +} + +void copy(BPPMaterialAssignments& dest, BPPMaterialAssignments& source) +{ + dest.materialIndexes[0] = source.materialIndexes[0]; + dest.materialIndexes[1] = source.materialIndexes[1]; + dest.materialIndexes[2] = source.materialIndexes[2]; + dest.materialIndexes[3] = source.materialIndexes[3]; +} + +void copy(BPPProjectile& dest, BPPProjectile& source) +{ + copy(dest.name, source.name); + dest.visible = source.visible; +} + +void copy(BPPSupportStructure& dest, BPPSupportStructure& source) +{ + copy(dest.healthMask, source.healthMask); + dest.bondStrength = source.bondStrength; + dest.enableJoint = source.enableJoint; +} + +void copy(BPPChunk& dest, BPPChunk& source) +{ + dest.ID = source.ID; + dest.parentID = source.parentID; + copy(dest.name, source.name); + copy(dest.asset, source.asset); + dest.visible = source.visible; + dest.support = source.support; + dest.staticFlag = source.staticFlag; +} + +void copy(BPPBond& dest, BPPBond& source) +{ + copy(dest.name, source.name); + copy(dest.asset, source.asset); + dest.visible = source.visible; + dest.fromChunk = source.fromChunk; + dest.toChunk = source.toChunk; + copy(dest.support, source.support); +} + +void copy(BPPLandmark& dest, BPPLandmark& source) +{ + copy(dest.name, source.name); + dest.visible = source.visible; + dest.enable = source.enable; + dest.radius = source.radius; +} + +void copy(BPPRenderer& dest, BPPRenderer& source) +{ + dest.renderFps = source.renderFps; + dest.frameStartTime = source.frameStartTime; + dest.frameEndTime = source.frameEndTime; + dest.animationFps = source.animationFps; + dest.animate = source.animate; + dest.simulate = source.simulate; + dest.resetSimulationOnLoop = source.resetSimulationOnLoop; + dest.simulationFps = source.simulationFps; + dest.showGraphicsMesh = source.showGraphicsMesh; + dest.visualizeGrowthMesh = source.visualizeGrowthMesh; + dest.visualizeLight = source.visualizeLight; + dest.visualizeWind = source.visualizeWind; + dest.showStatistics = source.showStatistics; + dest.renderStyle = source.renderStyle; + dest.colorizeOption = source.colorizeOption; + dest.showWireframe = source.showWireframe; + dest.lockRootBone = source.lockRootBone; + dest.controlTextureOption = source.controlTextureOption; + dest.useLighting = source.useLighting; + dest.showSkinnedMeshOnly = source.showSkinnedMeshOnly; + dest.lightDir = source.lightDir; + dest.ambientColor = source.ambientColor; + dest.windDir = source.windDir; + dest.windStrength = source.windStrength; + dest.lightIntensity = source.lightIntensity; + dest.gravityDir = source.gravityDir; + dest.gravityScale = source.gravityScale; + + copy(dest.textureFilePath, source.textureFilePath); + copy(dest.lights, source.lights); +} + +void copy(BPPStressSolver& dest, BPPStressSolver& source) +{ + dest.solverMode = source.solverMode; + dest.linearFactor = source.linearFactor; + dest.angularFactor = source.angularFactor; + dest.meanError = source.meanError; + dest.varianceError = source.varianceError; + dest.bondsPerFrame = source.bondsPerFrame; + dest.bondsIterations = source.bondsIterations; +} + +void copy(BPPAsset& dest, BPPAsset& source) +{ + copy(dest.path, source.path); + dest.visible = source.visible; + dest.stressSolver = source.stressSolver; + copy(dest.activePreset, source.activePreset); + dest.defaultDamage = source.defaultDamage; +} + +void copy(BPPAssetInstance& dest, BPPAssetInstance& source) +{ + copy(dest.name, source.name); + dest.visible = source.visible; + copy(dest.source, source.source); + dest.transform = source.transform; +} + +void copy(BPPComposite& dest, BPPComposite& source) +{ + copy(dest.composite, source.composite); + dest.visible = source.visible; + copy(dest.blastAssetInstances, source.blastAssetInstances); + dest.bondThreshold = source.bondThreshold; + dest.bondStrength = source.bondStrength; + copy(dest.landmarks, source.landmarks); +} + +void copy(BPPBlast& dest, BPPBlast& source) +{ + copy(dest.fileReferences.fbxSourceAsset, source.fileReferences.fbxSourceAsset); + copy(dest.fileReferences.fbx, source.fileReferences.fbx); + copy(dest.fileReferences.blast, source.fileReferences.blast); + copy(dest.fileReferences.collision, source.fileReferences.collision); + + copy(dest.composite, source.composite); + copy(dest.blastAssets, source.blastAssets); + copy(dest.chunks, source.chunks); + copy(dest.bonds, source.bonds); + copy(dest.projectiles, source.projectiles); + copy(dest.graphicsMeshes, source.graphicsMeshes); + + copy(dest.userPreset, source.userPreset); + copy(dest.healthMask, source.healthMask); +} + +void copy(BPPFilter& dest, BPPFilter& source) +{ + dest.activeFilter = source.activeFilter; + copy(dest.filters, source.filters); +} + +void copy(BPPVoronoi& dest, BPPVoronoi& source) +{ + dest.numSites = source.numSites; + dest.siteGeneration = source.siteGeneration; + dest.gridSize = source.gridSize; + dest.gridScale = source.gridScale; + dest.amplitude = source.amplitude; + + dest.frequency = source.frequency; + copy(dest.paintMasks, source.paintMasks); + dest.activePaintMask = source.activePaintMask; + copy(dest.meshCutters, source.meshCutters); + dest.activeMeshCutter = source.activeMeshCutter; + dest.fractureInsideCutter = source.fractureInsideCutter; + dest.fractureOutsideCutter = source.fractureOutsideCutter; + copy(dest.textureSites, source.textureSites); + dest.numTextureSites = source.numTextureSites; +} + +void copy(BPPCutoutProjection& dest, BPPCutoutProjection& source) +{ + copy(dest.textures, source.textures); + dest.cutoutType = source.cutoutType; + dest.pixelThreshold = source.pixelThreshold; + dest.tiled = source.tiled; + dest.invertU = source.invertU; + dest.invertV = source.invertV; +} + +void copy(BPPFracture& dest, BPPFracture& source) +{ + dest.activeFractureMethod = source.activeFractureMethod; + dest.general = source.general; + dest.visualization = source.visualization; + dest.shellCut = source.shellCut; + copy(dest.voronoi, source.voronoi); + dest.slice = source.slice; + copy(dest.cutoutProjection, source.cutoutProjection); +} + +void copy(BPPFilterPreset& dest, BPPFilterPreset& source) +{ + copy(dest.name, source.name); + copy(dest.depthFilters, source.depthFilters); +} + +void copy(BPParams& dest, BPParams& source) +{ + dest.camera = source.camera; + copy(dest.cameraBookmarks, source.cameraBookmarks); + dest.lightCamera = source.camera; + dest.windCamera = source.camera; + copy(dest.graphicsMaterials, source.graphicsMaterials); + dest.scene = source.scene; + copy(dest.renderer, source.renderer); + copy(dest.blast, source.blast); + copy(dest.filter, source.filter); + copy(dest.fracture, source.fracture); + + copy(dest.blast.userPreset, USER_PRESET_PATH); +} + +void merge(BPPChunkArray& dest, BPPChunkArray& source) +{ + if (source.arraySizes[0] > 0) + { + BPPChunk* oriDestArray = dest.buf; + int oriCount = dest.arraySizes[0]; + int srcCount = source.arraySizes[0]; + dest.buf = new BPPChunk[oriCount + srcCount]; + int i = 0; + for (; i < oriCount; ++i) + { + BPPChunk& destItem = dest.buf[i]; + BPPChunk& oriItem = oriDestArray[i]; + + destItem.name.buf = nullptr; + destItem.asset.buf = nullptr; + copy(destItem, oriItem); + } + for (int j = 0; j < srcCount; ++j, ++i) + { + BPPChunk& destItem = dest.buf[i]; + BPPChunk& sourceItem = source.buf[j]; + + destItem.name.buf = nullptr; + destItem.asset.buf = nullptr; + copy(destItem, sourceItem); + } + for (int m = 0; m < oriCount; ++m) + { + freeBlast(oriDestArray[m]); + } + delete[] oriDestArray; + dest.arraySizes[0] = oriCount + srcCount; + } +} + +void merge(BPPBondArray& dest, BPPBondArray& source) +{ + if (source.arraySizes[0] > 0) + { + BPPBond* oriDestArray = dest.buf; + int oriCount = dest.arraySizes[0]; + int srcCount = source.arraySizes[0]; + dest.buf = new BPPBond[oriCount + srcCount]; + int i = 0; + for (; i < oriCount; ++i) + { + BPPBond& destItem = dest.buf[i]; + BPPBond& oriItem = oriDestArray[i]; + + destItem.name.buf = nullptr; + destItem.asset.buf = nullptr; + destItem.support.healthMask.buf = nullptr; + copy(destItem, oriItem); + } + for (int j = 0; j < srcCount; ++j, ++i) + { + BPPBond& destItem = dest.buf[i]; + BPPBond& sourceItem = source.buf[j]; + + destItem.name.buf = nullptr; + destItem.asset.buf = nullptr; + destItem.support.healthMask.buf = nullptr; + copy(destItem, sourceItem); + } + for (int m = 0; m < oriCount; ++m) + { + freeBlast(oriDestArray[m]); + } + delete[] oriDestArray; + dest.arraySizes[0] = oriCount + srcCount; + } +} + +void init(BPPStressSolver& param) +{ + param.solverMode = -1; + param.linearFactor = 0; + param.angularFactor = 0; + param.meanError = 0; + param.varianceError = 0; + param.bondsPerFrame = 0; + param.bondsIterations = 0; +} + +void init(BPPGraphicsMaterial& param) +{ + param.name.buf = nullptr; + param.useTextures = false; + param.diffuseTextureFilePath.buf = nullptr; + param.specularTextureFilePath.buf = nullptr; + param.normalTextureFilePath.buf = nullptr; + param.specularShininess = 0.0; +} + +void init(BPParams& params) +{ + //memset(¶ms, sizeof(BPParams), 0); + + //params.cameraBookmarks.buf = nullptr; + //for (int i = 0; i < 4; ++i) + // params.renderer.lights.buf[i].name.buf = +} + +StressSolverUserPreset::StressSolverUserPreset(const char* inName) + : name(inName) +{ + name = name; + stressSolver.solverMode = -1; + stressSolver.linearFactor = 0; + stressSolver.angularFactor = 0; + stressSolver.meanError = 0; + stressSolver.varianceError = 0; + stressSolver.bondsPerFrame = 0; + stressSolver.bondsIterations = 0; +} + +BlastProject& BlastProject::ins() +{ + static BlastProject _ins; + return _ins; +} + +BlastProject::~BlastProject() +{ + delete[] _projectParams.cameraBookmarks.buf; +} + +void BlastProject::clear() +{ + freeBlast(_projectParams.blast); +} + +bool BlastProject::isGraphicsMaterialNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPGraphicsMaterialArray& theArray = _projectParams.graphicsMaterials; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + BPPGraphicsMaterial& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.name.buf, name) == 0) + return true; + } + return false; +} + +BPPGraphicsMaterial* BlastProject::addGraphicsMaterial(const char* name, const char* diffuseTexture) +{ + if (name == nullptr || strlen(name) == 0) + return nullptr; + + BPPGraphicsMaterialArray& theArray = _projectParams.graphicsMaterials; + BPPGraphicsMaterial* oldBuf = theArray.buf; + theArray.buf = new BPPGraphicsMaterial[theArray.arraySizes[0] + 1]; + + int i = 0; + for (; i < theArray.arraySizes[0]; ++i) + { + BPPGraphicsMaterial& newItem = theArray.buf[i]; + BPPGraphicsMaterial& oldItem = oldBuf[i]; + newItem.useTextures = false; + newItem.name.buf = nullptr; + newItem.diffuseTextureFilePath.buf = nullptr; + newItem.specularTextureFilePath.buf = nullptr; + newItem.normalTextureFilePath.buf = nullptr; + newItem.specularShininess = 0.0; + copy(newItem, oldItem); + } + + BPPGraphicsMaterial& newItem = theArray.buf[i]; + newItem.name.buf = nullptr; + newItem.useTextures = false; + newItem.diffuseTextureFilePath.buf = nullptr; + newItem.specularTextureFilePath.buf = nullptr; + newItem.normalTextureFilePath.buf = nullptr; + newItem.specularShininess = 0.0; + copy(newItem.name, name); + if (diffuseTexture != nullptr) + { + copy(newItem.diffuseTextureFilePath, diffuseTexture); + } + theArray.arraySizes[0] += 1; + + delete[] oldBuf; + + return &newItem; +} + +void BlastProject::removeGraphicsMaterial(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isGraphicsMaterialNameExist(name)) + return; + + BPPGraphicsMaterialArray& theArray = _projectParams.graphicsMaterials; + BPPGraphicsMaterial* oldBuf = theArray.buf; + + theArray.buf = new BPPGraphicsMaterial[theArray.arraySizes[0] - 1]; + int index = 0; + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(oldBuf[i].name.buf, name) != 0) + { + BPPGraphicsMaterial& newItem = theArray.buf[index++]; + BPPGraphicsMaterial& oldItem = oldBuf[i]; + newItem.useTextures = false; + newItem.name.buf = nullptr; + newItem.diffuseTextureFilePath.buf = nullptr; + newItem.specularTextureFilePath.buf = nullptr; + newItem.normalTextureFilePath.buf = nullptr; + copy(newItem, oldItem); + } + } + theArray.arraySizes[0] -= 1; + delete[] oldBuf; +} + +void BlastProject::renameGraphicsMaterial(const char* oldName, const char* newName) +{ + if (oldName == nullptr || newName == nullptr) + return; + + BPPGraphicsMaterialArray& theArray = _projectParams.graphicsMaterials; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(theArray.buf[i].name.buf, oldName) == 0) + { + copy(theArray.buf[i].name, newName); + return; + } + } +} + +std::vector<BPPAsset*> BlastProject::getSelectedBlastAssets(void) +{ + std::vector<BPPAsset*> assets; + return assets; +} + +bool BlastProject::isAssetInstanceNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPAssetInstanceArray& theArray = _projectParams.blast.composite.blastAssetInstances; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + BPPAssetInstance& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.name.buf, name) == 0) + return true; + } + return false; +} + +BPPAssetInstance* BlastProject::getAssetInstance(const char* assetPath, int instanceIndex) +{ + if (assetPath == nullptr || strlen(assetPath) == 0 || instanceIndex < 0) + { + return nullptr; + } + + BPPAssetInstanceArray& instanceArray = _projectParams.blast.composite.blastAssetInstances; + if (instanceIndex < instanceArray.arraySizes[0]) + { + BPPAssetInstance& assetInstance = instanceArray.buf[instanceIndex]; + if (nvidia::shdfnd::strcmp(assetPath, assetInstance.source.buf) == 0) + return &assetInstance; + } + + return nullptr; +} + +BPPAssetInstance* BlastProject::addAssetInstance(int blastAssetIndex, const char* instanceName) +{ + if (instanceName == nullptr) + return nullptr; + + BPPAssetArray& assetArray = _projectParams.blast.blastAssets; + if (blastAssetIndex < 0 && blastAssetIndex > assetArray.arraySizes[0]) + return nullptr; + + BPPComposite& composite = _projectParams.blast.composite; + BPPAssetInstanceArray& theArray = composite.blastAssetInstances; + + BPPAssetInstance* oldBuf = theArray.buf; + theArray.buf = new BPPAssetInstance[theArray.arraySizes[0] + 1]; + + int i = 0; + for (; i < theArray.arraySizes[0]; ++i) + { + BPPAssetInstance& newItem = theArray.buf[i]; + BPPAssetInstance& oldItem = oldBuf[i]; + + newItem.name.buf = nullptr; + newItem.source.buf = nullptr; + copy(newItem, oldItem); + } + + BPPAssetInstance& newItem = theArray.buf[i]; + newItem.name.buf = nullptr; + newItem.source.buf = nullptr; + copy(newItem.name, instanceName); + copy(newItem.source, assetArray.buf[blastAssetIndex].path); + newItem.visible = true; + + delete[] oldBuf; + + return &newItem; +} + +void BlastProject::removeAssetInstance(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isAssetInstanceNameExist(name)) + return; + + BPPAssetInstanceArray& theArray = _projectParams.blast.composite.blastAssetInstances; + BPPAssetInstance* oldBuf = theArray.buf; + + theArray.buf = new BPPAssetInstance[theArray.arraySizes[0] - 1]; + int index = 0; + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(oldBuf[i].name.buf, name) != 0) + { + BPPAssetInstance& newItem = theArray.buf[index++]; + BPPAssetInstance& oldItem = oldBuf[i]; + newItem.name.buf = nullptr; + newItem.source.buf = nullptr; + copy(newItem, oldItem); + } + } + theArray.arraySizes[0] -= 1; + delete[] oldBuf; +} + +BPPChunk* BlastProject::getChunk(BPPAsset& asset, int id) +{ + BPPChunkArray& chunkArray = _projectParams.blast.chunks; + + int count = chunkArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPChunk& chunk = chunkArray.buf[i]; + if (chunk.ID == id && (nvidia::shdfnd::strcmp(chunk.asset.buf, asset.path.buf) == 0)) + return &chunk; + } + + return nullptr; +} + +std::vector<BPPChunk*> BlastProject::getChildrenChunks(BPPAsset& asset, int parentID) +{ + std::vector<BPPChunk*> chunks; + + BPPChunkArray& chunkArray = _projectParams.blast.chunks; + + int count = chunkArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPChunk& chunk = chunkArray.buf[i]; + if (chunk.parentID == parentID && (nvidia::shdfnd::strcmp(chunk.asset.buf, asset.path.buf) == 0)) + chunks.push_back(&chunk); + } + + return chunks; +} + +std::vector<BPPChunk*> BlastProject::getChildrenChunks(BPPAsset& asset) +{ + std::vector<BPPChunk*> chunks; + + BPPChunkArray& chunkArray = _projectParams.blast.chunks; + + int count = chunkArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPChunk& chunk = chunkArray.buf[i]; + if (nvidia::shdfnd::strcmp(chunk.asset.buf, asset.path.buf) == 0) + chunks.push_back(&chunk); + } + + return chunks; +} + +std::vector<BPPBond*> BlastProject::getBondsByChunk(BPPAsset& asset, int chunkID) +{ + std::vector<BPPBond*> bonds; + BPPBondArray& bondArray = _projectParams.blast.bonds; + int count = bondArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPBond& bond = bondArray.buf[i]; + if ((nvidia::shdfnd::strcmp(bond.asset.buf, asset.path.buf) == 0)) + { + if (bond.fromChunk == chunkID) + bonds.push_back(&bond); + else if (bond.toChunk == chunkID) + bonds.push_back(&bond); + } + } + + return bonds; +} + +bool BlastProject::isLandmarkNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPLandmarkArray& theArray = _projectParams.blast.composite.landmarks; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + BPPLandmark& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.name.buf, name) == 0) + return true; + } + return false; +} + +BPPLandmark* BlastProject::addLandmark(const char* name) +{ + if (name == nullptr) + return nullptr; + + BPPLandmarkArray& theArray = _projectParams.blast.composite.landmarks; + BPPLandmark* oldBuf = theArray.buf; + theArray.buf = new BPPLandmark[theArray.arraySizes[0] + 1]; + + int i = 0; + for (; i < theArray.arraySizes[0]; ++i) + { + BPPLandmark& newItem = theArray.buf[i]; + BPPLandmark& oldItem = oldBuf[i]; + + newItem.name.buf = nullptr; + copy(newItem, oldItem); + } + + BPPLandmark& newItem = theArray.buf[i]; + newItem.name.buf = nullptr; + copy(newItem.name, name); + newItem.visible = true; + newItem.enable = true; + newItem.radius = 0.0; + theArray.arraySizes[0] += 1; + + delete[] oldBuf; + + return &newItem; +} + +void BlastProject::removeLandmark(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isLandmarkNameExist(name)) + return ; + + BPPLandmarkArray& theArray = _projectParams.blast.composite.landmarks; + BPPLandmark* oldBuf = theArray.buf; + + theArray.buf = new BPPLandmark[theArray.arraySizes[0] - 1]; + int index = 0; + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(oldBuf[i].name.buf, name) != 0) + { + BPPLandmark& newItem = theArray.buf[index++]; + BPPLandmark& oldItem = oldBuf[i]; + newItem.name.buf = nullptr; + copy(newItem, oldItem); + } + } + theArray.arraySizes[0] -= 1; + delete[] oldBuf; +} + +BPPLandmark* BlastProject::getLandmark(const char* name) +{ + if (name == nullptr) + return nullptr; + + BPPLandmarkArray& theArray = _projectParams.blast.composite.landmarks; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(theArray.buf[i].name.buf, name) == 0) + return &theArray.buf[i]; + } + + return nullptr; +} + +void BlastProject::renameLandmark(const char* oldName, const char* newName) +{ + if (oldName == nullptr || newName == nullptr) + return ; + + BPPLandmarkArray& theArray = _projectParams.blast.composite.landmarks; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(theArray.buf[i].name.buf, oldName) == 0) + { + copy(theArray.buf[i].name, newName); + return; + } + } +} + +bool BlastProject::isUserPresetNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + for (size_t i = 0; i < _userPresets.size(); ++i) + { + StressSolverUserPreset& item = _userPresets[i]; + if (item.name == name) + return true; + } + + return false; +} + +std::vector<StressSolverUserPreset>& BlastProject::getUserPresets() +{ + return _userPresets; +} + +void BlastProject::addUserPreset(const char* name) +{ + _userPresets.push_back(StressSolverUserPreset(name)); +} + +void BlastProject::saveUserPreset() +{ + QFile file(_projectParams.blast.userPreset.buf); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + return; + } + QTextStream out(&file); + + QDomDocument xmlDoc; + QDomElement rootElm = xmlDoc.createElement(QObject::tr("UserPreSet")); + xmlDoc.appendChild(rootElm); + + for (size_t i = 0; i < _userPresets.size(); ++i) + { + _saveStressSolverPreset(rootElm, _userPresets[i]); + } + + // 4 is count of indent + xmlDoc.save(out, 4); +} + +void BlastProject::loadUserPreset() +{ + QFile file(_projectParams.blast.userPreset.buf); + + if (!file.open(QIODevice::ReadOnly)) + { + return; + } + + QDomDocument xmlDoc; + if (!xmlDoc.setContent(&file)) + { + file.close(); + return; + } + file.close(); + + if (xmlDoc.isNull() || xmlDoc.documentElement().tagName() != QObject::tr("UserPreSet")) + { + QMessageBox::warning(&AppMainWindow::Inst(), QObject::tr("Warning"), QObject::tr("The file you selected is empty or not a blast user preset file.")); + return; + } + + QDomNodeList elms = xmlDoc.documentElement().elementsByTagName(QObject::tr("StressSolverPreset")); + for (int i = 0; i < elms.count(); ++i) + { + StressSolverUserPreset preset(""); + _userPresets.push_back(preset); + _loadStressSolverPreset(elms.at(i).toElement(), _userPresets[i]); + } + +} + +bool BlastProject::isFilterPresetNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPFilterPresetArray& theArray = _projectParams.filter.filters; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + BPPFilterPreset& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.name.buf, name) == 0) + return true; + } + return false; +} + +std::vector<BPPFilterPreset*> BlastProject::getFilterPresets() +{ + std::vector<BPPFilterPreset*> presets; + return presets; +} + +void BlastProject::addFilterPreset(const char* name) +{ + if (name == nullptr) + return; + + BPPFilterPresetArray& theArray = _projectParams.filter.filters; + BPPFilterPreset* oldBuf = theArray.buf; + theArray.buf = new BPPFilterPreset[theArray.arraySizes[0] + 1]; + + int i = 0; + for (; i < theArray.arraySizes[0]; ++i) + { + BPPFilterPreset& newItem = theArray.buf[i]; + BPPFilterPreset& oldItem = oldBuf[i]; + + newItem.name.buf = nullptr; + newItem.depthFilters.buf = nullptr; + newItem.depthFilters.arraySizes[0] = 0; + copy(newItem, oldItem); + } + + BPPFilterPreset& newItem = theArray.buf[i]; + newItem.name.buf = nullptr; + newItem.depthFilters.buf = nullptr; + newItem.depthFilters.arraySizes[0] = 0; + copy(newItem.name, name); + theArray.arraySizes[0] += 1; + + delete[] oldBuf; +} + +void BlastProject::removeFilterPreset(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isFilterPresetNameExist(name)) + return; + + BPPFilterPresetArray& theArray = _projectParams.filter.filters; + BPPFilterPreset* oldBuf = theArray.buf; + + theArray.buf = new BPPFilterPreset[theArray.arraySizes[0] - 1]; + int index = 0; + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(oldBuf[i].name.buf, name) != 0) + { + BPPFilterPreset& newItem = theArray.buf[index++]; + BPPFilterPreset& oldItem = oldBuf[i]; + newItem.name.buf = nullptr; + newItem.depthFilters.buf = nullptr; + newItem.depthFilters.arraySizes[0] = 0; + copy(newItem, oldItem); + } + } + theArray.arraySizes[0] -= 1; + delete[] oldBuf; +} + +BPPFilterPreset* BlastProject::getFilterPreset(const char* name) +{ + if (name == nullptr) + return nullptr; + + BPPFilterPresetArray& theArray = _projectParams.filter.filters; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(theArray.buf[i].name.buf, name) == 0) + return &theArray.buf[i]; + } + + return nullptr; +} + +void BlastProject::renameFilterPreset(const char* oldName, const char* newName) +{ + if (oldName == nullptr || newName == nullptr) + return; + + BPPFilterPresetArray& theArray = _projectParams.filter.filters; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(theArray.buf[i].name.buf, oldName) == 0) + { + copy(theArray.buf[i].name, newName); + return; + } + } +} + +void BlastProject::addFilterDepth(const char* filterName, int depth) +{ + if (filterName == nullptr || depth < 0) + return; + + BPPFilterPresetArray& theArray = _projectParams.filter.filters; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(theArray.buf[i].name.buf, filterName) == 0) + { + BPPU32Array& depthArray = theArray.buf[i].depthFilters; + for (int j = 0; j < depthArray.arraySizes[0]; ++j) + { + if (depthArray.buf[j] == depth) + return; + } + + uint32_t* oldBuf = depthArray.buf; + depthArray.buf = new uint32_t[theArray.arraySizes[0] + 1]; + + int m = 0, n = 0; + for (; n < depthArray.arraySizes[0];) + { + if (oldBuf[n] < depth) + { + depthArray.buf[m++] = oldBuf[n++]; + } + else + { + if (m == n) + depthArray.buf[m++] = depth; + else + depthArray.buf[m++] = oldBuf[n++]; + } + } + + if (m == n) + { + depthArray.buf[m] = depth; + } + depthArray.arraySizes[0] += 1; + return; + } + } +} + +void BlastProject::removeFilterDepth(const char* filterName, int depth) +{ + if (filterName == nullptr || depth < 0) + return; + + BPPFilterPresetArray& theArray = _projectParams.filter.filters; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(theArray.buf[i].name.buf, filterName) == 0) + { + bool foundDepth = false; + BPPU32Array& depthArray = theArray.buf[i].depthFilters; + for (int j = 0; j < depthArray.arraySizes[0]; ++j) + { + if (depthArray.buf[j] == depth) + { + foundDepth = true; + break; + } + } + + if (!foundDepth) + return; + + uint32_t* oldBuf = depthArray.buf; + depthArray.buf = new uint32_t[theArray.arraySizes[0] - 1]; + + int m = 0, n = 0; + for (; n < depthArray.arraySizes[0];) + { + if (oldBuf[n] != depth) + { + depthArray.buf[m++] = oldBuf[n++]; + } + else + { + depthArray.buf[m] = depthArray.buf[n++]; + } + } + + depthArray.arraySizes[0] -= 1; + return; + } + } +} + +bool BlastProject::isCutoutTextureNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.cutoutProjection.textures; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + NvParameterized::DummyStringStruct& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.buf, name) == 0) + return true; + } + return false; +} + +void BlastProject::addCutoutTexture(const char* name) +{ + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.cutoutProjection.textures; + _addStringItem(theArray, name); +} + +void BlastProject::removeCutoutTexture(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isCutoutTextureNameExist(name)) + return; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.cutoutProjection.textures; + _removeStringItem(theArray, name); +} + +bool BlastProject::isPaintMaskNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.paintMasks; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + NvParameterized::DummyStringStruct& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.buf, name) == 0) + return true; + } + return false; +} + +void BlastProject::addPaintMasks(const char* name) +{ + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.paintMasks; + _addStringItem(theArray, name); +} + +void BlastProject::removePaintMasks(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isPaintMaskNameExist(name)) + return; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.paintMasks; + _removeStringItem(theArray, name); +} + +bool BlastProject::isMeshCutterNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.meshCutters; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + NvParameterized::DummyStringStruct& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.buf, name) == 0) + return true; + } + return false; +} + +void BlastProject::addMeshCutter(const char* name) +{ + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.meshCutters; + _addStringItem(theArray, name); +} + +void BlastProject::removeMeshCutter(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isMeshCutterNameExist(name)) + return; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.meshCutters; + _removeStringItem(theArray, name); +} + +bool BlastProject::isVoronoiTextureNameExist(const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return false; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.textureSites; + + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + NvParameterized::DummyStringStruct& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.buf, name) == 0) + return true; + } + return false; +} + +void BlastProject::addVoronoiTexture(const char* name) +{ + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.textureSites; + _addStringItem(theArray, name); +} + +void BlastProject::removeVoronoiTexture(const char* name) +{ + if (name == nullptr || strlen(name) == 0 || !isVoronoiTextureNameExist(name)) + return; + + BPPStringArray& theArray = BlastProject::ins().getParams().fracture.voronoi.textureSites; + _removeStringItem(theArray, name); +} + +BlastProject::BlastProject() +{ + _projectParams.cameraBookmarks.buf = nullptr; + _projectParams.cameraBookmarks.arraySizes[0] = 0; + + _projectParams.graphicsMaterials.buf = nullptr; + _projectParams.graphicsMaterials.arraySizes[0] = 0; + + _projectParams.renderer.textureFilePath.buf = nullptr; + + _projectParams.renderer.lights.buf = new BPPLight[4]; + _projectParams.renderer.lights.arraySizes[0] = 4; + + for (int i = 0; i < 4; ++i) + { + _projectParams.renderer.lights.buf[i].name.buf = nullptr; + } + + _projectParams.blast.fileReferences.blast.buf = nullptr; + _projectParams.blast.fileReferences.fbx.buf = nullptr; + _projectParams.blast.fileReferences.fbxSourceAsset.buf = nullptr; + _projectParams.blast.fileReferences.collision.buf = nullptr; + + _projectParams.blast.composite.composite.buf = nullptr; + _projectParams.blast.composite.blastAssetInstances.buf = nullptr; + _projectParams.blast.composite.blastAssetInstances.arraySizes[0] = 0; + + _projectParams.blast.composite.landmarks.buf = nullptr; + _projectParams.blast.composite.landmarks.arraySizes[0] = 0; + + _projectParams.blast.blastAssets.buf = nullptr; + _projectParams.blast.blastAssets.arraySizes[0] = 0; + + _projectParams.blast.projectiles.buf = nullptr; + _projectParams.blast.projectiles.arraySizes[0] = 0; + + _projectParams.blast.graphicsMeshes.buf = nullptr; + _projectParams.blast.graphicsMeshes.arraySizes[0] = 0; + + _projectParams.blast.userPreset.buf = nullptr; + _projectParams.blast.healthMask.buf = nullptr; + + _projectParams.filter.filters.buf = nullptr; + _projectParams.filter.filters.arraySizes[0] = 0; + + _projectParams.fracture.voronoi.paintMasks.buf = nullptr; + _projectParams.fracture.voronoi.paintMasks.arraySizes[0] = 0; + + _projectParams.fracture.voronoi.meshCutters.buf = nullptr; + _projectParams.fracture.voronoi.meshCutters.arraySizes[0] = 0; + + _projectParams.fracture.voronoi.textureSites.buf = nullptr; + _projectParams.fracture.voronoi.textureSites.arraySizes[0] = 0; + + _projectParams.fracture.cutoutProjection.textures.buf = nullptr; + _projectParams.fracture.cutoutProjection.textures.arraySizes[0] = 0; +} + +void BlastProject::_saveStressSolverPreset(QDomElement& parentElm, StressSolverUserPreset& stressSolverUserPreset) +{ + QDomElement newElm = parentElm.ownerDocument().createElement(QObject::tr("StressSolverPreset")); + parentElm.appendChild(newElm); + newElm.setAttribute(QObject::tr("Name"), stressSolverUserPreset.name.c_str()); + _saveStressSolver(newElm, stressSolverUserPreset.stressSolver); +} + +void BlastProject::_saveStressSolver(QDomElement& parentElm, BPPStressSolver& stressSolver) +{ + QDomElement newElm = parentElm.ownerDocument().createElement(QObject::tr("StressSolver")); + parentElm.appendChild(newElm); + newElm.setAttribute(QObject::tr("SolverMode"), stressSolver.solverMode); + newElm.setAttribute(QObject::tr("LinearFactor"), stressSolver.linearFactor); + newElm.setAttribute(QObject::tr("AngularFactor"), stressSolver.angularFactor); + newElm.setAttribute(QObject::tr("MeanError"), stressSolver.meanError); + newElm.setAttribute(QObject::tr("VarianceError"), stressSolver.varianceError); + newElm.setAttribute(QObject::tr("BondsPerFrame"), stressSolver.bondsPerFrame); + newElm.setAttribute(QObject::tr("BondsIterations"), stressSolver.bondsIterations); +} + +void BlastProject::_loadStressSolverPreset(QDomElement& parentElm, StressSolverUserPreset& stressSolverUserPreset) +{ + stressSolverUserPreset.name = parentElm.attribute(QObject::tr("Name")).toUtf8().data(); + + QDomElement stressSolverElm = parentElm.firstChildElement(QObject::tr("StressSolver")); + _loadStressSolver(stressSolverElm, stressSolverUserPreset.stressSolver); +} + +void BlastProject::_loadStressSolver(QDomElement& parentElm, BPPStressSolver& stressSolver) +{ + stressSolver.solverMode = parentElm.attribute(QObject::tr("SolverMode")).toInt(); + stressSolver.linearFactor = parentElm.attribute(QObject::tr("LinearFactor")).toFloat(); + stressSolver.angularFactor = parentElm.attribute(QObject::tr("AngularFactor")).toFloat(); + stressSolver.meanError = parentElm.attribute(QObject::tr("MeanError")).toFloat(); + stressSolver.varianceError = parentElm.attribute(QObject::tr("VarianceError")).toFloat(); + stressSolver.bondsPerFrame = parentElm.attribute(QObject::tr("BondsPerFrame")).toUInt(); + stressSolver.bondsIterations = parentElm.attribute(QObject::tr("BondsIterations")).toUInt(); +} + +void BlastProject::_addStringItem(BPPStringArray& theArray, const char* name) +{ + if (name == nullptr) + return; + + NvParameterized::DummyStringStruct* oldBuf = theArray.buf; + theArray.buf = new NvParameterized::DummyStringStruct[theArray.arraySizes[0] + 1]; + + int i = 0; + for (; i < theArray.arraySizes[0]; ++i) + { + NvParameterized::DummyStringStruct& newItem = theArray.buf[i]; + NvParameterized::DummyStringStruct& oldItem = oldBuf[i]; + newItem.buf = nullptr; + copy(newItem, oldItem); + } + + NvParameterized::DummyStringStruct& newItem = theArray.buf[i]; + newItem.buf = nullptr; + copy(newItem, name); + theArray.arraySizes[0] += 1; + + delete[] oldBuf; +} + +void BlastProject::_removeStringItem(BPPStringArray& theArray, const char* name) +{ + if (name == nullptr || strlen(name) == 0) + return; + + bool nameExist = false; + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + NvParameterized::DummyStringStruct& item = theArray.buf[i]; + if (nvidia::shdfnd::strcmp(item.buf, name) == 0) + { + nameExist = true; + break; + } + } + + if (!nameExist) + return; + + NvParameterized::DummyStringStruct* oldBuf = theArray.buf; + + theArray.buf = new NvParameterized::DummyStringStruct[theArray.arraySizes[0] - 1]; + int index = 0; + for (int i = 0; i < theArray.arraySizes[0]; ++i) + { + if (nvidia::shdfnd::strcmp(oldBuf[i].buf, name) != 0) + { + NvParameterized::DummyStringStruct& newItem = theArray.buf[index++]; + NvParameterized::DummyStringStruct& oldItem = oldBuf[i]; + newItem.buf = nullptr; + copy(newItem, oldItem); + } + } + theArray.arraySizes[0] -= 1; + delete[] oldBuf; +} + +static bool LoadParamVec2Array(NvParameterized::Interface* iface, + const char* paramName, + nvidia::NvVec2** outValue) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + int arraySize; + handle.getArraySize(arraySize); + *outValue = new nvidia::NvVec2[arraySize]; + handle.getParamVec2Array((nvidia::NvVec2*)*outValue, arraySize); + return true; + } + return false; +} + +static bool LoadParamVec3Array(NvParameterized::Interface* iface, + const char* paramName, + nvidia::NvVec3** outValue) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + int arraySize; + handle.getArraySize(arraySize); + *outValue = new nvidia::NvVec3[arraySize]; + handle.getParamVec3Array((nvidia::NvVec3*)*outValue, arraySize); + return true; + } + return false; +} + +static bool LoadParamVec4Array(NvParameterized::Interface* iface, + const char* paramName, + nvidia::NvVec4** outValue) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + int arraySize; + handle.getArraySize(arraySize); + *outValue = new nvidia::NvVec4[arraySize]; + handle.getParamVec4Array((nvidia::NvVec4*)*outValue, arraySize); + return true; + } + return false; +} + +static bool LoadParamU8Array(NvParameterized::Interface* iface, + const char* paramName, + NvUInt8** outValue) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + int arraySize; + handle.getArraySize(arraySize); + *outValue = new NvUInt8[arraySize]; + handle.getParamU8Array((NvUInt8*)*outValue, arraySize); + return true; + } + return false; +} + +static bool LoadParamU32Array(NvParameterized::Interface* iface, + const char* paramName, + NvUInt32** outValue) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + int arraySize; + handle.getArraySize(arraySize); + *outValue = new NvUInt32[arraySize]; + handle.getParamU32Array((NvUInt32*)*outValue, arraySize); + return true; + } + return false; +} + +static bool LoadParamString(NvParameterized::Interface* iface, + const char* paramName, + char* outString) +{ + if (outString == NV_NULL) + { + return false; + } + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + const char* var; + handle.getParamString(var); + if (var) + { + strcpy(outString, var); + } + else + { + outString[0] = '\0'; + } + return true; + } + return false; +} + +static bool SaveParamVec2Array(NvParameterized::Interface* iface, + const char* paramName, + const nvidia::NvVec2* value, + int arraySize) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + handle.resizeArray(arraySize); + handle.setParamVec2Array((nvidia::NvVec2*)value, arraySize); + return true; + } + return false; +} + +static bool SaveParamVec3Array(NvParameterized::Interface* iface, + const char* paramName, + const nvidia::NvVec3* value, + int arraySize) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + handle.resizeArray(arraySize); + handle.setParamVec3Array((nvidia::NvVec3*)value, arraySize); + return true; + } + return false; +} + +static bool SaveParamVec4Array(NvParameterized::Interface* iface, + const char* paramName, + const nvidia::NvVec4* value, + int arraySize) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + handle.resizeArray(arraySize); + handle.setParamVec4Array((nvidia::NvVec4*)value, arraySize); + return true; + } + return false; +} + +static bool SaveParamU8Array(NvParameterized::Interface* iface, + const char* paramName, + const NvUInt8* value, + int arraySize) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + handle.resizeArray(arraySize); + handle.setParamU8Array((NvUInt8*)value, arraySize); + return true; + } + return false; +} + +static bool SaveParamU32Array(NvParameterized::Interface* iface, + const char* paramName, + const NvUInt32* value, + int arraySize) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + handle.resizeArray(arraySize); + handle.setParamU32Array((NvUInt32*)value, arraySize); + return true; + } + return false; +} + +static bool SaveParamString(NvParameterized::Interface* iface, + const char* paramName, + const char* inString) +{ + NvParameterized::Handle handle(iface); + if (iface->getParameterHandle(paramName, handle) == NvParameterized::ERROR_NONE) + { + handle.setParamString(inString); + return true; + } + return false; +} + +bool CreateProjectParamsContext() +{ + FoundationHolder::GetFoundation(); + + ProjectParamsContext* context = new ProjectParamsContext; + g_projectParamsContext = context; + if (context == nullptr) + return false; + + //context->mFoundation = FoundationHolder::GetFoundation(); + //assert(context->mFoundation != NV_NULL); + context->mTraits = NvParameterized::createTraits(); + context->mBlastProjectParametersFactory = new BlastProjectParametersFactory; + context->mTraits->registerFactory(*context->mBlastProjectParametersFactory); + return true; +} + +void ReleaseProjectParamsContext() +{ + g_projectParamsContext->mTraits->release(); + delete g_projectParamsContext->mBlastProjectParametersFactory; + delete g_projectParamsContext; +} + +bool ProjectParamsLoad(const char* filePath, + SimpleScene* scene) +{ + if (g_projectParamsContext == NV_NULL) return false; + NvFileBuf* stream = new NvFileBufferBase(filePath, NvFileBuf::OPEN_READ_ONLY); + if (!stream || !stream->isOpen()) + { + // file open error + if (stream) stream->release(); + return false; + } + NvParameterized::Serializer::DeserializedData data; + NvParameterized::Serializer::ErrorType serError = NvParameterized::Serializer::ERROR_NONE; + NvParameterized::XmlSerializer serializer(g_projectParamsContext->mTraits); + bool isUpdated; + serError = serializer.deserialize(*stream, data, isUpdated); + if (data.size() < 1) + { + if (stream) stream->release(); + return false; + } + + scene->Clear(); + + for (int idx = 0; idx < (int)data.size(); ++idx) { + NvParameterized::Interface* iface = data[idx]; + if (::strcmp(iface->className(), BlastProjectParameters::staticClassName()) == 0) + { + scene->LoadParameters(iface); + } + } + stream->release(); + return true; +} + +bool ProjectParamsSave(const char* filePath, + SimpleScene* scene) +{ + if (g_projectParamsContext == NV_NULL) return false; + NvParameterized::XmlSerializer serializer(g_projectParamsContext->mTraits); + NvFileBuf* stream = new NvFileBufferBase(filePath, NvFileBuf::OPEN_WRITE_ONLY); + if (!stream || !stream->isOpen()) + { + // file open error + if (stream) stream->release(); + return false; + } + NvParameterized::Traits* traits = g_projectParamsContext->mTraits; + int numObjects = 0; + const int kMaxObjects = 1; + NvParameterized::Interface* objects[kMaxObjects]; + + if (1) + { + BlastProjectParameters* params = new BlastProjectParameters(traits); + objects[numObjects++] = params; + NvParameterized::Interface* iface = static_cast<NvParameterized::Interface*>(params); + scene->SaveParameters(iface); + } + + NV_ASSERT(numObjects <= kMaxObjects); + NvParameterized::Serializer::ErrorType serError = NvParameterized::Serializer::ERROR_NONE; + bool isUpdate = false; + serError = serializer.serialize(*stream, (const NvParameterized::Interface**)&objects[0], numObjects, isUpdate); + //for (int idx = 0; idx < numObjects; ++idx) + //{ + // delete objects[idx]; + //} + stream->release(); + return true; +} + +// Utility function to get the child parameter handle from the parent handle. +bool ParamGetChild(NvParameterized::Handle& parentHandle, NvParameterized::Handle& outChildHandle, const char* childName) +{ + if (parentHandle.getChildHandle(parentHandle.getInterface(), childName, outChildHandle) == NvParameterized::ERROR_NONE) + { + return true; + } + return false; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/ProjectParams.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/ProjectParams.h new file mode 100644 index 0000000..fa7adf7 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Parameters/ProjectParams.h @@ -0,0 +1,210 @@ +#pragma once + +#include "BlastProjectParameters.h" +#include <QtCore/QVector> + +class QDomElement; + +typedef nvidia::parameterized::BlastProjectParametersNS::ParametersStruct BPParams; +typedef nvidia::parameterized::BlastProjectParametersNS::GraphicsMaterial_Type BPPGraphicsMaterial; +typedef nvidia::parameterized::BlastProjectParametersNS::MaterialAssignments_Type BPPMaterialAssignments; +typedef nvidia::parameterized::BlastProjectParametersNS::GraphicsMesh_Type BPPGraphicsMesh; +typedef nvidia::parameterized::BlastProjectParametersNS::Light_Type BPPLight; +typedef nvidia::parameterized::BlastProjectParametersNS::Camera_Type BPPCamera; +typedef nvidia::parameterized::BlastProjectParametersNS::CameraBookmark_Type BPPCameraBookmark; +typedef nvidia::parameterized::BlastProjectParametersNS::Scene_Type BPPScene; +typedef nvidia::parameterized::BlastProjectParametersNS::Renderer_Type BPPRenderer; +typedef nvidia::parameterized::BlastProjectParametersNS::BlastFileReferences_Type BPPFileReferences; +typedef nvidia::parameterized::BlastProjectParametersNS::StressSolver_Type BPPStressSolver; +typedef nvidia::parameterized::BlastProjectParametersNS::SupportStructure_Type BPPSupportStructure; +typedef nvidia::parameterized::BlastProjectParametersNS::Bond_Type BPPBond; +typedef nvidia::parameterized::BlastProjectParametersNS::Chunk_Type BPPChunk; +typedef nvidia::parameterized::BlastProjectParametersNS::DefaultDamage_Type BPPDefaultDamage; +typedef nvidia::parameterized::BlastProjectParametersNS::BlastAsset_Type BPPAsset; +typedef nvidia::parameterized::BlastProjectParametersNS::BlastAssetInstance_Type BPPAssetInstance; +typedef nvidia::parameterized::BlastProjectParametersNS::Projectile_Type BPPProjectile; +typedef nvidia::parameterized::BlastProjectParametersNS::Landmark_Type BPPLandmark; +typedef nvidia::parameterized::BlastProjectParametersNS::BlastComposite_Type BPPComposite; +typedef nvidia::parameterized::BlastProjectParametersNS::Blast_Type BPPBlast; +typedef nvidia::parameterized::BlastProjectParametersNS::FractureGeneral_Type BPPFractureGeneral; +typedef nvidia::parameterized::BlastProjectParametersNS::FractureVisualization_Type BPPFractureVisualization; +typedef nvidia::parameterized::BlastProjectParametersNS::ShellCut_Type BPPShellCut; +typedef nvidia::parameterized::BlastProjectParametersNS::Voronoi_Type BPPVoronoi; +typedef nvidia::parameterized::BlastProjectParametersNS::Slice_Type BPPSlice; +typedef nvidia::parameterized::BlastProjectParametersNS::CutoutProjection_Type BPPCutoutProjection; +typedef nvidia::parameterized::BlastProjectParametersNS::Fracture_Type BPPFracture; +typedef nvidia::parameterized::BlastProjectParametersNS::FilterPreset_Type BPPFilterPreset; +typedef nvidia::parameterized::BlastProjectParametersNS::Filter_Type BPPFilter; + +typedef nvidia::parameterized::BlastProjectParametersNS::CameraBookmark_DynamicArray1D_Type BPPBookmarkArray; +typedef nvidia::parameterized::BlastProjectParametersNS::STRING_DynamicArray1D_Type BPPStringArray; +typedef nvidia::parameterized::BlastProjectParametersNS::GraphicsMaterial_DynamicArray1D_Type BPPGraphicsMaterialArray; +typedef nvidia::parameterized::BlastProjectParametersNS::GraphicsMesh_DynamicArray1D_Type BPPGraphicsMeshArray; +typedef nvidia::parameterized::BlastProjectParametersNS::Light_DynamicArray1D_Type BPPLightArray; +typedef nvidia::parameterized::BlastProjectParametersNS::Chunk_DynamicArray1D_Type BPPChunkArray; +typedef nvidia::parameterized::BlastProjectParametersNS::Bond_DynamicArray1D_Type BPPBondArray; +typedef nvidia::parameterized::BlastProjectParametersNS::Projectile_DynamicArray1D_Type BPPProjectileArray; +typedef nvidia::parameterized::BlastProjectParametersNS::BlastAsset_DynamicArray1D_Type BPPAssetArray; +typedef nvidia::parameterized::BlastProjectParametersNS::BlastAssetInstance_DynamicArray1D_Type BPPAssetInstanceArray; +typedef nvidia::parameterized::BlastProjectParametersNS::Landmark_DynamicArray1D_Type BPPLandmarkArray; +typedef nvidia::parameterized::BlastProjectParametersNS::FilterPreset_DynamicArray1D_Type BPPFilterPresetArray; +typedef nvidia::parameterized::BlastProjectParametersNS::U32_DynamicArray1D_Type BPPU32Array; + +void freeString(NvParameterized::DummyStringStruct& str); +void freeBlast(BPPGraphicsMesh& data); +void freeBlast(BPPChunk& data); +void freeBlast(BPPBond& data); +void freeBlast(BPPAsset& data); +void freeBlast(BPPAssetInstance& data); +void freeBlast(BPPComposite& data); +void freeBlast(BPPBlast& data); +void freeBlast(BPPLandmark& data); + +void freeBlast(BPPStringArray& data); +void freeBlast(BPPGraphicsMeshArray& data); +void freeBlast(BPPChunkArray& data); +void freeBlast(BPPBondArray& data); +void freeBlast(BPPAssetArray& data); +void freeBlast(BPPAssetInstanceArray& data); +void freeBlast(BPPLandmarkArray& data); + +void copy(NvParameterized::DummyStringStruct& dest, const char* source); +void copy(NvParameterized::DummyStringStruct& dest, NvParameterized::DummyStringStruct& source); +void copy(BPPStringArray& dest, BPPStringArray& source); +void copy(BPPGraphicsMaterialArray& dest, BPPGraphicsMaterialArray& source); +void copy(BPPGraphicsMeshArray& dest, BPPGraphicsMeshArray& source); +void copy(BPPBookmarkArray& dest, BPPBookmarkArray& source); +void copy(BPPLightArray& dest, BPPLightArray& source); +void copy(BPPChunkArray& dest, BPPChunkArray& source); +void copy(BPPBondArray& dest, BPPBondArray& source); +void copy(BPPProjectileArray& dest, BPPProjectileArray& source); +void copy(BPPAssetArray& dest, BPPAssetArray& source); +void copy(BPPAssetInstanceArray& dest, BPPAssetInstanceArray& source); +void copy(BPPLandmarkArray& dest, BPPLandmarkArray& source); +void copy(BPPU32Array& dest, BPPU32Array& source); +void copy(BPPFilterPresetArray& dest, BPPFilterPresetArray& source); + +void copy(BPPLight& dest, BPPLight& source); +void copy(BPPRenderer& dest, BPPRenderer& source); +void copy(BPPGraphicsMaterial& dest, BPPGraphicsMaterial& source); +void copy(BPPGraphicsMesh& dest, BPPGraphicsMesh& source); +void copy(BPPMaterialAssignments& dest, BPPMaterialAssignments& source); +void copy(BPPChunk& dest, BPPChunk& source); +void copy(BPPBond& dest, BPPBond& source); +void copy(BPPProjectile& dest, BPPProjectile& source); +void copy(BPPSupportStructure& dest, BPPSupportStructure& source); +void copy(BPPLandmark& dest, BPPLandmark& source); +void copy(BPPStressSolver& dest, BPPStressSolver& source); +void copy(BPPAsset& dest, BPPAsset& source); +void copy(BPPAssetInstance& dest, BPPAssetInstance& source); +void copy(BPPComposite& dest, BPPComposite& source); +void copy(BPPBlast& dest, BPPBlast& source); +void copy(BPPFilter& dest, BPPFilter& source); +void copy(BPPVoronoi& dest, BPPVoronoi& source); +void copy(BPPCutoutProjection& dest, BPPCutoutProjection& source); +void copy(BPPFracture& dest, BPPFracture& source); +void copy(BPPFilterPreset& dest, BPPFilterPreset& source); +void copy(BPParams& dest, BPParams& source); + +void merge(BPPChunkArray& dest, BPPChunkArray& source); +void merge(BPPBondArray& dest, BPPBondArray& source); + +void init(BPPStressSolver& param); +void init(BPPGraphicsMaterial& param); +void init(BPParams& params); + +struct StressSolverUserPreset +{ + StressSolverUserPreset(const char* inName); + std::string name; + BPPStressSolver stressSolver; +}; + +class BlastProject +{ +public: + + static BlastProject& ins(); + ~BlastProject(); + + BPParams& getParams() { return _projectParams; } + + void clear(); + + bool isGraphicsMaterialNameExist(const char* name); + BPPGraphicsMaterial* addGraphicsMaterial(const char* name, const char* diffuseTexture); + void removeGraphicsMaterial(const char* name); + void renameGraphicsMaterial(const char* oldName, const char* newName); + + std::vector<BPPAsset*> getSelectedBlastAssets(void); + + bool isAssetInstanceNameExist(const char* name); + BPPAssetInstance* getAssetInstance(const char* assetPath, int instanceIndex); + BPPAssetInstance* addAssetInstance(int blastAssetIndex, const char* instanceName); + void removeAssetInstance(const char* name); + + BPPChunk* getChunk(BPPAsset& asset, int id); + std::vector<BPPChunk*> getChildrenChunks(BPPAsset& asset, int parentID); + std::vector<BPPChunk*> getChildrenChunks(BPPAsset& asset); + std::vector<BPPBond*> getBondsByChunk(BPPAsset& asset, int chunkID); + + bool isLandmarkNameExist(const char* name); + BPPLandmark* addLandmark(const char* name); + void removeLandmark(const char* name); + BPPLandmark* getLandmark(const char* name); + void renameLandmark(const char* oldName, const char* newName); + + bool isUserPresetNameExist(const char* name); + std::vector<StressSolverUserPreset>& getUserPresets(); + void addUserPreset(const char* name); + void saveUserPreset(); + void loadUserPreset(); + + bool isFilterPresetNameExist(const char* name); + std::vector<BPPFilterPreset*> getFilterPresets(); + void addFilterPreset(const char* name); + void removeFilterPreset(const char* name); + BPPFilterPreset* getFilterPreset(const char* name); + void renameFilterPreset(const char* oldName, const char* newName); + void addFilterDepth(const char* filterName, int depth); + void removeFilterDepth(const char* filterName, int depth); + + bool isCutoutTextureNameExist(const char* name); + void addCutoutTexture(const char* name); + void removeCutoutTexture(const char* name); + + bool isPaintMaskNameExist(const char* name); + void addPaintMasks(const char* name); + void removePaintMasks(const char* name); + + bool isMeshCutterNameExist(const char* name); + void addMeshCutter(const char* name); + void removeMeshCutter(const char* name); + + bool isVoronoiTextureNameExist(const char* name); + void addVoronoiTexture(const char* name); + void removeVoronoiTexture(const char* name); + +private: + BlastProject(); + void _saveStressSolverPreset(QDomElement& parentElm, StressSolverUserPreset& stressSolverUserPreset); + void _saveStressSolver(QDomElement& parentElm, BPPStressSolver& stressSolver); + void _loadStressSolverPreset(QDomElement& parentElm, StressSolverUserPreset& stressSolverUserPreset); + void _loadStressSolver(QDomElement& parentElm, BPPStressSolver& stressSolver); + + void _addStringItem(BPPStringArray& theArray, const char* name); + void _removeStringItem(BPPStringArray& theArray, const char* name); + +private: + BPParams _projectParams; + std::vector<StressSolverUserPreset> _userPresets; +}; + +bool CreateProjectParamsContext(); +void ReleaseProjectParamsContext(); +bool ProjectParamsLoad(const char* filePath, + class SimpleScene* scene); +bool ProjectParamsSave(const char* filePath, + class SimpleScene* scene); + +bool ParamGetChild(NvParameterized::Handle& parentHandle, NvParameterized::Handle& outChildHandle, const char* childName); diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D11/PluginBlastDx11.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D11/PluginBlastDx11.cpp new file mode 100644 index 0000000..1c37502 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D11/PluginBlastDx11.cpp @@ -0,0 +1,23 @@ +#include "PluginBlastDx11.h" +#include "D3D11RenderShader.h" +#include "D3D11RenderInterface.h" +#include "LightShaderParam.h" + +PluginBlast* CreateRenderBlast(void) +{ + return new PluginBlastDx11; +} + +PluginBlastDx11::PluginBlastDx11() +{ +} + +PluginBlastDx11::~PluginBlastDx11() +{ +} + +// D3D11Shaders +bool PluginBlastDx11::D3D11Shaders_InitializeShadersD3D11(std::map<int, D3D11RenderShader*>& ShaderMap) +{ + return true; +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D11/PluginBlastDx11.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D11/PluginBlastDx11.h new file mode 100644 index 0000000..ed9dbe1 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D11/PluginBlastDx11.h @@ -0,0 +1,16 @@ +#pragma once + +#include "PluginBlast.h" + +extern "C" PLUGINBTRENDER_EXPORT PluginBlast* CreateRenderBlast(void); + +class PluginBlastDx11 : public PluginBlast +{ +public: + PluginBlastDx11(); + ~PluginBlastDx11(); + + // D3D11Shaders + virtual bool D3D11Shaders_InitializeShadersD3D11(std::map<int, D3D11RenderShader*>& ShaderMap); +}; + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D12/PluginBlastDx12.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D12/PluginBlastDx12.cpp new file mode 100644 index 0000000..670f17b --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D12/PluginBlastDx12.cpp @@ -0,0 +1,20 @@ +#include "PluginBlastDx12.h" + +PluginBlast* CreateRenderBlast(void) +{ + return new PluginBlastDx12; +} + +PluginBlastDx12::PluginBlastDx12() +{ +} + +PluginBlastDx12::~PluginBlastDx12() +{ +} + +// D3D11Shaders +bool PluginBlastDx12::D3D11Shaders_InitializeShadersD3D11(std::map<int, D3D11RenderShader*>& ShaderMap) +{ + return true; +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D12/PluginBlastDx12.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D12/PluginBlastDx12.h new file mode 100644 index 0000000..fab6b4e --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/D3D12/PluginBlastDx12.h @@ -0,0 +1,16 @@ +#pragma once + +#include "PluginBlast.h" + +extern "C" PLUGINBTRENDER_EXPORT PluginBlast* CreateRenderBlast(void); + +class PluginBlastDx12 : public PluginBlast +{ +public: + PluginBlastDx12(); + ~PluginBlastDx12(); + + // D3D11Shaders + virtual bool D3D11Shaders_InitializeShadersD3D11(std::map<int, D3D11RenderShader*>& ShaderMap); +}; + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/Interface/PluginBlast.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/Interface/PluginBlast.cpp new file mode 100644 index 0000000..3a9c9c9 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/Interface/PluginBlast.cpp @@ -0,0 +1,69 @@ +#include "PluginBlast.h" + +PluginBlast* g_Plugin = nullptr; + +PluginBlast::PluginBlast() +{ +} + +PluginBlast::~PluginBlast() +{ +} + +typedef PluginBlast*(*Func)(void); + +bool PluginBlast::Create(std::string strApi) +{ + if ("" == strApi) + return false; + + std::string pluginDll = ""; + HMODULE module = NULL; + Func CreateFunc = NULL; + +#ifdef NV_ARTISTTOOLS + pluginDll = "RenderBlast"; +#else + pluginDll = "FurRender"; +#endif + + pluginDll.append(strApi); + +#ifdef _WIN64 + pluginDll.append(".win64"); +#else + pluginDll.append(".win32"); +#endif + +#ifdef _DEBUG + pluginDll.append(".d"); +#else +#endif + + pluginDll.append(".dll"); + + module = LoadLibraryA(pluginDll.c_str()); + if (NULL == module) + return false; + + CreateFunc = (Func)GetProcAddress(module, "CreateRenderBlast"); + if (NULL == CreateFunc) + return false; + + g_Plugin = CreateFunc(); + return (NULL != g_Plugin); +} + +PluginBlast* PluginBlast::Instance() +{ + return g_Plugin; +} + +void PluginBlast::Destroy() +{ + if (nullptr == g_Plugin) + return; + + delete g_Plugin; + g_Plugin = nullptr; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/Interface/PluginBlast.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/Interface/PluginBlast.h new file mode 100644 index 0000000..a67fd89 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Render/Interface/PluginBlast.h @@ -0,0 +1,21 @@ +#pragma once + +#include "RenderPlugin.h" +#include "blastplugin_global.h" + +class PLUGINBT_EXPORT PluginBlast +{ +public: + static bool Create(std::string api); + static PluginBlast* Instance(); + static void Destroy(); + + ~PluginBlast(); + + // D3D11Shaders + virtual bool D3D11Shaders_InitializeShadersD3D11(std::map<int, D3D11RenderShader*>& ShaderMap) = 0; + +protected: + PluginBlast(); +}; + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/Sample.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/Sample.h new file mode 100644 index 0000000..c9fa503 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/Sample.h @@ -0,0 +1,95 @@ +/* +* 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 SAMPLE_H +#define SAMPLE_H + +#include "PxTransform.h" +#include <string> +#include <vector> + + +struct AssetList +{ + struct BoxAsset + { + BoxAsset() : staticHeight(-std::numeric_limits<float>().infinity()), + jointAllBonds(false), extents(20, 20, 20) + {} + + struct Level + { + Level() :x(0), y(0), z(0), isSupport(0) {}; + + int x, y, z; + bool isSupport; + }; + + std::string id; + std::string name; + physx::PxVec3 extents; + float staticHeight; + bool jointAllBonds; + std::vector<Level> levels; + }; + + struct ModelAsset + { + ModelAsset() : isSkinned(false), transform(physx::PxIdentity) + {} + + std::string id; + std::string file; + std::string name; + physx::PxTransform transform; + bool isSkinned; + }; + + struct CompositeAsset + { + CompositeAsset() : transform(physx::PxIdentity) + {} + + struct AssetRef + { + std::string id; + physx::PxTransform transform; + }; + + struct Joint + { + int32_t assetIndices[2]; + uint32_t chunkIndices[2]; + physx::PxVec3 attachPositions[2]; + }; + + std::string id; + std::string name; + physx::PxTransform transform; + std::vector<AssetRef> assetRefs; + std::vector<Joint> joints; + }; + + std::vector<ModelAsset> models; + std::vector<CompositeAsset> composites; + std::vector<BoxAsset> boxes; +}; + +struct SampleConfig +{ + std::wstring sampleName; + std::string assetsFile; + std::vector<std::string> additionalResourcesDir; + AssetList additionalAssetList; +}; + +int runSample(const SampleConfig& config); + +#endif //SAMPLE_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAsset.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAsset.cpp new file mode 100644 index 0000000..01f8fd6 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAsset.cpp @@ -0,0 +1,60 @@ +/* +* 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 "BlastAsset.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastTkAsset.h" +#include <map> + +BlastAsset::BlastAsset(Renderer& renderer) + : m_renderer(renderer) +{ +} + +void BlastAsset::validate() +{ +} + +size_t BlastAsset::getBlastAssetSize() const +{ + return m_pxAsset->getTkAsset().getDataSize(); +} + +std::vector<uint32_t> BlastAsset::getChunkIndexesByDepth(uint32_t depth) const +{ + const TkAsset& tkAsset = m_pxAsset->getTkAsset(); + const NvBlastChunk* pNvBlastChunk = tkAsset.getChunks(); + uint32_t chunkCount = tkAsset.getChunkCount(); + + std::map<uint32_t, uint32_t> indexDepthMap; + indexDepthMap.insert(std::make_pair(0, 0)); + for (size_t i = 1; i < chunkCount; ++i) + { + int depth = 0; + const NvBlastChunk* curChunk = pNvBlastChunk + i; + while (-1 != curChunk->parentChunkIndex) + { + ++depth; + curChunk = pNvBlastChunk + curChunk->parentChunkIndex; + } + indexDepthMap.insert(std::make_pair(i, depth)); + } + + std::vector<uint32_t> indexes; + for (std::map<uint32_t, uint32_t>::iterator itr = indexDepthMap.begin(); itr != indexDepthMap.end(); ++itr) + { + if (itr->second == depth) + { + indexes.push_back(itr->first); + } + } + + return indexes; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAsset.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAsset.h new file mode 100644 index 0000000..b2e2f38 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAsset.h @@ -0,0 +1,99 @@ +/* +* 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 BLAST_ASSET_H +#define BLAST_ASSET_H + +#include <memory> +#include <vector> +#include "PxTransform.h" +#include "NvBlastTypes.h" + +using namespace physx; + +class Renderer; +class BlastFamily; +class PhysXController; + +namespace Nv +{ +namespace Blast +{ +class ExtPxFamily; +class ExtPxAsset; +class ExtPxManager; +class TkGroup; +} +} + +using namespace Nv::Blast; + +// Add By Lixu Begin +typedef BlastFamily* BlastFamilyPtr; +// Add By Lixu End + + +class BlastAsset +{ +public: + //////// ctor //////// + + BlastAsset(Renderer& renderer); + virtual ~BlastAsset() {} + + + //////// desc //////// + + /** + Descriptor with actor initial settings. + */ + struct ActorDesc + { + NvBlastID id; + PxTransform transform; + TkGroup* group; + }; + + + //////// abstract //////// + + virtual BlastFamilyPtr createFamily(PhysXController& physXConroller, ExtPxManager& pxManager, const ActorDesc& desc) = 0; + + + //////// data getters //////// + + const ExtPxAsset* getPxAsset() const + { + return m_pxAsset; + } + + size_t getBlastAssetSize() const; + + std::vector<uint32_t> getChunkIndexesByDepth(uint32_t depth) const; + +protected: + //////// internal operations //////// + + void validate(); + + + //////// input data //////// + + Renderer& m_renderer; + + + //////// internal data //////// + + ExtPxAsset* m_pxAsset; +}; + + + +#endif //BLAST_ASSET_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetBoxes.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetBoxes.cpp new file mode 100644 index 0000000..dfa0138 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetBoxes.cpp @@ -0,0 +1,84 @@ +/* +* 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 "BlastAssetBoxes.h" +#include "BlastFamilyBoxes.h" +#include "NvBlastExtPxAsset.h" +#include "PxPhysics.h" +#include "cooking/PxCooking.h" + + +BlastAssetBoxes::BlastAssetBoxes(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const Desc& desc) + : BlastAsset(renderer) +{ + // generate boxes slices procedurally + CubeAssetGenerator::generate(m_generatorAsset, desc.generatorSettings); + + // asset desc / tk asset + ExtPxAssetDesc assetDesc; + assetDesc.chunkDescs = &m_generatorAsset.solverChunks[0]; + assetDesc.chunkCount = (uint32_t)m_generatorAsset.solverChunks.size(); + assetDesc.bondDescs = m_generatorAsset.solverBonds.size() > 0 ? &m_generatorAsset.solverBonds[0] : nullptr; + assetDesc.bondCount = (uint32_t)m_generatorAsset.solverBonds.size(); + std::vector<uint8_t> bondFlags(assetDesc.bondCount); + std::fill(bondFlags.begin(), bondFlags.end(), desc.jointAllBonds ? 1 : 0); + assetDesc.bondFlags = bondFlags.data(); + + // box convex + PxVec3 vertices[8] = { { -1, -1, -1 }, { -1, -1, 1 }, { -1, 1, -1 }, { -1, 1, 1 }, { 1, -1, -1 }, { 1, -1, 1 }, { 1, 1, -1 }, { 1, 1, 1 } }; + PxConvexMeshDesc convexMeshDesc; + convexMeshDesc.points.count = 8; + convexMeshDesc.points.data = vertices; + convexMeshDesc.points.stride = sizeof(PxVec3); + convexMeshDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX; + m_boxMesh = cooking.createConvexMesh(convexMeshDesc, physics.getPhysicsInsertionCallback()); + + // prepare chunks + const uint32_t chunkCount = (uint32_t)m_generatorAsset.solverChunks.size(); + std::vector<ExtPxAssetDesc::ChunkDesc> pxChunks(chunkCount); + std::vector<ExtPxAssetDesc::SubchunkDesc> pxSubchunks; + pxSubchunks.reserve(chunkCount); + for (uint32_t i = 0; i < m_generatorAsset.solverChunks.size(); i++) + { + uint32_t chunkID = m_generatorAsset.solverChunks[i].userData; + GeneratorAsset::BlastChunkCube& cube = m_generatorAsset.chunks[chunkID]; + PxVec3 position = *reinterpret_cast<PxVec3*>(&cube.position); + PxVec3 extents = *reinterpret_cast<PxVec3*>(&cube.extents); + ExtPxAssetDesc::ChunkDesc& chunk = pxChunks[chunkID]; + ExtPxAssetDesc::SubchunkDesc subchunk = + { + PxTransform(position), + PxConvexMeshGeometry(m_boxMesh, PxMeshScale(extents / 2)) + }; + pxSubchunks.push_back(subchunk); + chunk.subchunks = &pxSubchunks.back(); + chunk.subchunkCount = 1; + chunk.isStatic = (position.y - (extents.y - desc.generatorSettings.extents.y) / 2) <= desc.staticHeight; + } + + // create asset + assetDesc.pxChunks = pxChunks.data(); + m_pxAsset = ExtPxAsset::create(assetDesc, framework); + + validate(); +} + + +BlastAssetBoxes::~BlastAssetBoxes() +{ + m_boxMesh->release(); + m_pxAsset->release(); +} + + +BlastFamilyPtr BlastAssetBoxes::createFamily(PhysXController& physXConroller, ExtPxManager& pxManager, const ActorDesc& desc) +{ + return BlastFamilyPtr(new BlastFamilyBoxes(physXConroller, pxManager, m_renderer, *this, desc)); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetBoxes.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetBoxes.h new file mode 100644 index 0000000..518e93d --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetBoxes.h @@ -0,0 +1,56 @@ +/* +* 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 BLAST_ASSET_BOXES_H +#define BLAST_ASSET_BOXES_H + +#include "BlastAsset.h" +#include "AssetGenerator.h" +#include "PxConvexMesh.h" + + +namespace physx +{ +class PxPhysics; +class PxCooking; +} + +namespace Nv +{ +namespace Blast +{ +class TkFramework; +} +} + + +class BlastAssetBoxes : public BlastAsset +{ +public: + struct Desc + { + CubeAssetGenerator::Settings generatorSettings; + float staticHeight; + bool jointAllBonds; + }; + + BlastAssetBoxes(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const Desc& desc); + virtual ~BlastAssetBoxes(); + + BlastFamilyPtr createFamily(PhysXController& physXConroller, ExtPxManager& pxManager, const ActorDesc& desc); + +private: + PxConvexMesh* m_boxMesh; + GeneratorAsset m_generatorAsset; +}; + + + +#endif //BLAST_ASSET_BOXES_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModel.cpp new file mode 100644 index 0000000..c42215e --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModel.cpp @@ -0,0 +1,64 @@ +/* +* 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 "BlastAssetModel.h" +#include "Renderer.h" +#include "BlastController.h" +#include "Utils.h" +#include "ResourceManager.h" +#include "PsFileBuffer.h" +#include "NvBlastExtPxAsset.h" +#include <sstream> + + +BlastAssetModel::BlastAssetModel(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const char* modelName) + : BlastAsset(renderer) +{ + ResourceManager& resourceManager = m_renderer.getResourceManager(); + + // Physics Asset + std::ostringstream blastFileName; + blastFileName << modelName << ".bpxa"; + std::string path; + if (resourceManager.findFile(blastFileName.str(), path)) + { + PsFileBuffer fileBuf(path.c_str(), PxFileBuf::OPEN_READ_ONLY); + m_pxAsset = ExtPxAsset::deserialize(fileBuf, framework, physics); + ASSERT_PRINT(m_pxAsset != nullptr, "can't load bpxa file"); + } + else + { + ASSERT_PRINT(false, "wrong blastFilename"); + } + + // load obj file + std::ostringstream objFileName; + objFileName << modelName << ".obj"; + if (resourceManager.findFile(objFileName.str(), path)) + { + m_model = BlastModel::loadFromFileTinyLoader(path.c_str()); + if (!m_model) + { + ASSERT_PRINT(false, "obj load failed"); + } + } + else + { + ASSERT_PRINT(false, "wrong objFileName"); + } + + validate(); +} + + +BlastAssetModel::~BlastAssetModel() +{ + m_pxAsset->release(); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModel.h new file mode 100644 index 0000000..8132911 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModel.h @@ -0,0 +1,57 @@ +/* +* 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 BLAST_ASSET_MODEL_H +#define BLAST_ASSET_MODEL_H + +#include "BlastAsset.h" +#include "BlastModel.h" + + +namespace physx +{ +class PxPhysics; +class PxCooking; +} + +namespace Nv +{ +namespace Blast +{ +class TkFramework; +} +} + + +class BlastAssetModel : public BlastAsset +{ +public: + //////// ctor //////// + + BlastAssetModel(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const char* modelName); + virtual ~BlastAssetModel(); + + + //////// data getters //////// + + const BlastModel& getModel() const + { +// Add By Lixu Begin + return *m_model; +// Add By Lixu End + } + +private: + //////// private internal data //////// + + BlastModelPtr m_model; +}; + +#endif //BLAST_ASSET_MODEL_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSimple.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSimple.cpp new file mode 100644 index 0000000..56c7441 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSimple.cpp @@ -0,0 +1,56 @@ +/* +* 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 "BlastAssetModelSimple.h" +#include "BlastFamilyModelSimple.h" +#include "CustomRenderMesh.h" +#include "Renderer.h" + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// BlastAssetModelSimple +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BlastAssetModelSimple::BlastAssetModelSimple(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const char* modelName) + : BlastAssetModel(framework, physics, cooking, renderer, modelName) +{ + // prepare materials +// Add By Lixu Begin + for (const BlastModel::Material& material : getModel().materials) + { + if (material.diffuseTexture.empty()) + m_renderMaterials.push_back(RenderMaterial::getDefaultRenderMaterial()); + else + m_renderMaterials.push_back(new RenderMaterial(material.name.c_str(), renderer.getResourceManager(), "model_simple_textured_ex", material.diffuseTexture.c_str())); + } +// Add By Lixu End + validate(); +} + + +BlastAssetModelSimple::~BlastAssetModelSimple() +{ + // release materials + for (RenderMaterial* r : m_renderMaterials) + { + if (r == RenderMaterial::getDefaultRenderMaterial()) + { + continue; + } + SAFE_DELETE(r); + } +} + + +BlastFamilyPtr BlastAssetModelSimple::createFamily(PhysXController& physXConroller, ExtPxManager& pxManager, const ActorDesc& desc) +{ + return BlastFamilyPtr(new BlastFamilyModelSimple(physXConroller, pxManager, m_renderer, *this, desc)); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSimple.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSimple.h new file mode 100644 index 0000000..7e61616 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSimple.h @@ -0,0 +1,47 @@ +/* +* 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 BLAST_ASSET_MODEL_SIMPLE_H +#define BLAST_ASSET_MODEL_SIMPLE_H + +#include "BlastAssetModel.h" + + +class RenderMaterial; + +class BlastAssetModelSimple : public BlastAssetModel +{ +public: + //////// ctor //////// + + BlastAssetModelSimple(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const char* modelName); + virtual ~BlastAssetModelSimple(); + + + //////// interface implementation //////// + + virtual BlastFamilyPtr createFamily(PhysXController& physXConroller, ExtPxManager& pxManager, const ActorDesc& desc); + + + //////// data getters //////// + + const std::vector<RenderMaterial*>& getRenderMaterials() const + { + return m_renderMaterials; + } + + +private: + //////// private internal data //////// + + std::vector<RenderMaterial*> m_renderMaterials; +}; + +#endif //BLAST_ASSET_MODEL_SIMPLE_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSkinned.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSkinned.cpp new file mode 100644 index 0000000..5cf3a0d --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSkinned.cpp @@ -0,0 +1,47 @@ +/* +* 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 "BlastAssetModelSkinned.h" +#include "BlastFamilyModelSkinned.h" +#include "RenderMaterial.h" +#include "Renderer.h" + + +BlastAssetModelSkinned::BlastAssetModelSkinned(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const char* modelName) + : BlastAssetModel(framework, physics, cooking, renderer, modelName) +{ +// Add By Lixu Begin + int index = 0; + char materialName[50]; + for (const BlastModel::Material& material : getModel().materials) + { + sprintf(materialName, "%s_Material%d", modelName, index++); + + if (material.diffuseTexture.empty()) + m_renderMaterials.push_back(new RenderMaterial(modelName, renderer.getResourceManager(), "model_skinned")); + else + m_renderMaterials.push_back(new RenderMaterial(modelName, renderer.getResourceManager(), "model_skinned_textured", material.diffuseTexture.c_str())); + } +// Add By Lixu End + validate(); +} + +BlastAssetModelSkinned::~BlastAssetModelSkinned() +{ + for (RenderMaterial* r : m_renderMaterials) + { + SAFE_DELETE(r); + } +} + +BlastFamilyPtr BlastAssetModelSkinned::createFamily(PhysXController& physXConroller, ExtPxManager& pxManager, const ActorDesc& desc) +{ + return BlastFamilyPtr(new BlastFamilyModelSkinned(physXConroller, pxManager, m_renderer, *this, desc)); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSkinned.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSkinned.h new file mode 100644 index 0000000..149c8e8 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastAssetModelSkinned.h @@ -0,0 +1,46 @@ +/* +* 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 BLAST_ASSET_MODEL_SKINNED_H +#define BLAST_ASSET_MODEL_SKINNED_H + +#include "BlastAssetModel.h" + +class RenderMaterial; + +class BlastAssetModelSkinned : public BlastAssetModel +{ +public: + //////// ctor //////// + + BlastAssetModelSkinned(TkFramework& framework, PxPhysics& physics, PxCooking& cooking, Renderer& renderer, const char* modelName); + virtual ~BlastAssetModelSkinned(); + + + //////// interface implementation //////// + + BlastFamilyPtr createFamily(PhysXController& physXConroller, ExtPxManager& pxManager, const ActorDesc& desc); + + + //////// public getter //////// + + const std::vector<RenderMaterial*>& getRenderMaterials() const + { + return m_renderMaterials; + } + + +private: + //////// internal data //////// + + std::vector<RenderMaterial*> m_renderMaterials; +}; + +#endif //BLAST_ASSET_MODEL_SKINNED_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastController.cpp new file mode 100644 index 0000000..4061931 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastController.cpp @@ -0,0 +1,555 @@ +/* +* 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 "BlastController.h" +#include "BlastFamily.h" +#include "BlastAsset.h" +#include "BlastReplay.h" +#include "PhysXController.h" +#include "SampleTime.h" +#include "SampleProfiler.h" +#include "Utils.h" +#include "Renderer.h" + +#include "NvBlast.h" +#include "NvBlastExtPxManager.h" +#include "NvBlastExtPxFamily.h" +#include "NvBlastExtPxActor.h" + +#include "NvBlastTkFramework.h" + +#include "PsString.h" +#include "PxTaskManager.h" +#include "PxDefaultCpuDispatcher.h" +#include "PxRigidBody.h" +#include "PxScene.h" +#include "PxRigidDynamic.h" +#include "PxDistanceJoint.h" + +#include <sstream> +#include <numeric> +#include <cstdlib> + +#include "imgui.h" + +// Add By Lixu Begin +#include "BlastSceneTree.h" +// Add By Lixu End + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AllocatorCallback +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class BlastAllocatorCallback : public PxAllocatorCallback +{ +public: + virtual void* allocate(size_t size, const char* typeName, const char* filename, int line) override + { + NV_UNUSED(typeName); + NV_UNUSED(filename); + NV_UNUSED(line); + return malloc(size); + } + + virtual void deallocate(void* ptr) override + { + free(ptr); + } +}; +BlastAllocatorCallback g_allocatorCallback; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ErrorCallback +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class BlastErrorCallback : public PxErrorCallback +{ +public: + virtual void reportError(PxErrorCode::Enum code, const char* msg, const char* file, int line) override + { + std::stringstream str; + str << "NvBlastTk "; + bool critical = false; + switch (code) + { + case PxErrorCode::eNO_ERROR: critical = false; break; + case PxErrorCode::eDEBUG_INFO: str << "[Debug Info]"; critical = false; break; + case PxErrorCode::eDEBUG_WARNING: str << "[Debug Warning]"; critical = false; break; + case PxErrorCode::eINVALID_PARAMETER: str << "[Invalid Parameter]"; critical = true; break; + case PxErrorCode::eINVALID_OPERATION: str << "[Invalid Operation]"; critical = true; break; + case PxErrorCode::eOUT_OF_MEMORY: str << "[Out of] Memory"; critical = true; break; + case PxErrorCode::eINTERNAL_ERROR: str << "[Internal Error]"; critical = true; break; + case PxErrorCode::eABORT: str << "[Abort]"; critical = true; break; + case PxErrorCode::ePERF_WARNING: str << "[Perf Warning]"; critical = false; break; + default: PX_ALWAYS_ASSERT(); + } + str << file << "(" << line << "): " << msg << "\n"; + + std::string message = str.str(); + shdfnd::printString(message.c_str()); + PX_ASSERT_WITH_MESSAGE(!critical, message.c_str()); + } +}; +BlastErrorCallback g_errorCallback; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Joint creation +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static physx::PxJoint* createPxJointCallback(ExtPxActor* actor0, const physx::PxTransform& localFrame0, ExtPxActor* actor1, const physx::PxTransform& localFrame1, physx::PxPhysics& physics, TkJoint& joint) +{ + PxDistanceJoint* pxJoint = PxDistanceJointCreate(physics, actor0 ? &actor0->getPhysXActor() : nullptr, localFrame0, actor1 ? &actor1->getPhysXActor() : nullptr, localFrame1); + pxJoint->setMaxDistance(1.0f); + return pxJoint; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Controller +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BlastController::BlastController() +: m_eventCallback(nullptr), debugRenderMode(BlastFamily::DEBUG_RENDER_DISABLED), m_impactDamageEnabled(true), +m_impactDamageToStressEnabled(false), m_rigidBodyLimitEnabled(true), m_rigidBodyLimit(40000), m_blastAssetsSize(0), debugRenderScale(0.01f) +{ + m_extImpactDamageManagerSettings.fragility = 500.0f; + + m_impactDamageToStressFactor = 0.01f; + m_draggingToStressFactor = 100.0f; +} + + +BlastController::~BlastController() +{ +} + +void BlastController::reinitialize() +{ + onSampleStop(); + onSampleStart(); +} + +void BlastController::onSampleStart() +{ + TkFrameworkDesc desc; + desc.allocatorCallback = &g_allocatorCallback; + desc.errorCallback = &g_errorCallback; + m_tkFramework = NvBlastTkFrameworkCreate(desc); + + m_replay = new BlastReplay(); + + m_taskManager = PxTaskManager::createTaskManager(g_errorCallback, getPhysXController().getCPUDispatcher(), 0); + + TkGroupDesc gdesc; + gdesc.pxTaskManager = m_taskManager; + m_tkGroup = m_tkFramework->createGroup(gdesc); + + m_extPxManager = ExtPxManager::create(getPhysXController().getPhysics(), *m_tkFramework, createPxJointCallback); + m_extPxManager->setActorCountLimit(m_rigidBodyLimitEnabled ? m_rigidBodyLimit : 0); + m_extImpactDamageManager = ExtImpactDamageManager::create(m_extPxManager, m_extImpactDamageManagerSettings); + m_eventCallback = new EventCallback(m_extImpactDamageManager); + + setImpactDamageEnabled(m_impactDamageEnabled, true); +} + + +void BlastController::onSampleStop() +{ + removeAllFamilies(); + + m_extImpactDamageManager->release(); + m_extPxManager->release(); + SAFE_DELETE(m_eventCallback); + + m_tkGroup->release(); + + delete m_replay; + + m_tkFramework->release(); + + m_taskManager->release(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Impact damage +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::setImpactDamageEnabled(bool enabled, bool forceUpdate) +{ + if (m_impactDamageEnabled != enabled || forceUpdate) + { + m_impactDamageEnabled = enabled; + getPhysXController().getPhysXScene().setSimulationEventCallback(m_impactDamageEnabled ? m_eventCallback : nullptr); + refreshImpactDamageSettings(); + } +} + +bool BlastController::customImpactDamageFunction(void* data, ExtPxActor* actor, physx::PxShape* shape, physx::PxVec3 position, physx::PxVec3 force) +{ + return reinterpret_cast<BlastController*>(data)->stressDamage(actor, position, force); +} + +bool BlastController::stressDamage(ExtPxActor *actor, physx::PxVec3 position, physx::PxVec3 force) +{ + if (actor->getTkActor().getGraphNodeCount() > 1) + { + void* userData = actor->getFamily().userData; + if (userData) + { + ExtStressSolver* solver = reinterpret_cast<ExtStressSolver*>(userData); + solver->applyImpulse(*actor, position, force * m_impactDamageToStressFactor); + return true; + } + } + + return false; +} + +void BlastController::refreshImpactDamageSettings() +{ + m_extImpactDamageManagerSettings.damageFunction = m_impactDamageToStressEnabled ? customImpactDamageFunction : nullptr; + m_extImpactDamageManagerSettings.damageFunctionData = this; + m_extImpactDamageManager->setSettings(m_extImpactDamageManagerSettings); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Stress +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::updateDraggingStress() +{ + auto physxController = getPhysXController(); + auto actor = physxController.getDraggingActor(); + if (actor) + { + ExtPxActor* pxActor = m_extPxManager->getActorFromPhysXActor(*actor); + if (pxActor && pxActor->getTkActor().getGraphNodeCount() > 1 && pxActor->getPhysXActor().getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC) + { + void* userData = pxActor->getFamily().userData; + if (userData) + { + ExtStressSolver* solver = reinterpret_cast<ExtStressSolver*>(userData); + PxTransform t(pxActor->getPhysXActor().getGlobalPose().getInverse()); + PxVec3 dragVector = t.rotate(physxController.getDragVector()); + const float factor = dragVector.magnitudeSquared() * m_draggingToStressFactor; + solver->applyImpulse(*pxActor, physxController.getDragActorHookLocalPoint(), dragVector.getNormalized() * factor); + } + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Stats +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +uint32_t BlastController::getActorCount() const +{ + return std::accumulate(m_families.begin(), m_families.end(), (uint32_t)0, [](uint32_t sum, const BlastFamilyPtr& a) + { + return sum += a->getActorCount(); + }); +} + +uint32_t BlastController::getTotalVisibleChunkCount() const +{ + return std::accumulate(m_families.begin(), m_families.end(), (uint32_t)0, [](uint32_t sum, const BlastFamilyPtr& a) + { + return sum += a->getTotalVisibleChunkCount(); + }); +} + +size_t BlastController::getFamilySize() const +{ + return std::accumulate(m_families.begin(), m_families.end(), (size_t)0, [](size_t sum, const BlastFamilyPtr& a) + { + return sum += a->getFamilySize(); + }); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Time +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const double Time::s_secondsPerTick = Time::getTickDuration(); + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Controller events +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::Animate(double dt) +{ + PROFILER_SCOPED_FUNCTION(); + + PROFILER_BEGIN("Apply Impact Damage"); + m_extImpactDamageManager->applyDamage(); + PROFILER_END(); + + updateDraggingStress(); + + m_replay->update(); + + Time blastTime; + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (m_families[i]) + { + m_families[i]->updatePreSplit(dt); + } + } + + fillDebugRender(); + + PROFILER_BEGIN("Tk Group Process/Sync"); + m_tkGroup->process(); + m_tkGroup->sync(true); + PROFILER_END(); + + TkGroupStats gstats; + m_tkGroup->getStats(gstats); + + this->m_lastBlastTimers.blastDamageMaterial = NvBlastTicksToSeconds(gstats.timers.material); + this->m_lastBlastTimers.blastDamageFracture = NvBlastTicksToSeconds(gstats.timers.fracture); + this->m_lastBlastTimers.blastSplitIsland = NvBlastTicksToSeconds(gstats.timers.island); + this->m_lastBlastTimers.blastSplitPartition = NvBlastTicksToSeconds(gstats.timers.partition); + this->m_lastBlastTimers.blastSplitVisibility = NvBlastTicksToSeconds(gstats.timers.visibility); + + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (m_families[i]) + { + m_families[i]->updateAfterSplit(dt); + } + } + +// Add By Lixu Begin + BlastSceneTree* pBlastSceneTree = BlastSceneTree::ins(); + bool needUpdateUI = false; + + std::map<BlastAsset*, std::vector<BlastFamily*>>& AssetFamiliesMap = getManager()->getAssetFamiliesMap(); + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator itAsset; + std::vector<BlastFamily*>::iterator itFamily; + uint32_t assetIndex = 0; + for (itAsset = AssetFamiliesMap.begin(); itAsset != AssetFamiliesMap.end(); itAsset++) + { + std::vector<BlastFamily*>& BlastFamilies = itAsset->second; + for (itFamily = BlastFamilies.begin(); itFamily != BlastFamilies.end(); itFamily++) + { + BlastFamily* pFamily = *itFamily; + + std::map<uint32_t, bool>& VisibleChangedChunks = pFamily->getVisibleChangedChunks(); + std::map<uint32_t, bool>::iterator itChunk; + for (itChunk = VisibleChangedChunks.begin(); itChunk != VisibleChangedChunks.end(); itChunk++) + { + pBlastSceneTree->updateVisible(assetIndex, itChunk->first, itChunk->second); + } + pFamily->clearVisibleChangedChunks(); + + needUpdateUI = needUpdateUI || VisibleChangedChunks.size() > 0; + } + + assetIndex++; + } + + if (needUpdateUI) + { + pBlastSceneTree->updateValues(false); + } +// Add By Lixu End +} + + +void BlastController::drawUI() +{ + // impact damage + bool impactEnabled = getImpactDamageEnabled(); + if (ImGui::Checkbox("Impact Damage", &impactEnabled)) + { + setImpactDamageEnabled(impactEnabled); + } + + if (ImGui::DragFloat("Fragility", &m_extImpactDamageManagerSettings.fragility)) + { + refreshImpactDamageSettings(); + } + + if (ImGui::Checkbox("Impact Damage To Stress Solver", &m_impactDamageToStressEnabled)) + { + refreshImpactDamageSettings(); + } + + ImGui::DragFloat("Impact Damage To Stress Factor", &m_impactDamageToStressFactor, 0.001f, 0.0f, 1000.0f, "%.4f"); + ImGui::DragFloat("Dragging To Stress Factor", &m_draggingToStressFactor, 0.1f, 0.0f, 1000.0f, "%.3f"); + + ImGui::Checkbox("Limit Rigid Body Count", &m_rigidBodyLimitEnabled); + if (m_rigidBodyLimitEnabled) + { + ImGui::DragInt("Rigid Body Limit", (int*)&m_rigidBodyLimit, 100, 1000, 100000); + } + m_extPxManager->setActorCountLimit(m_rigidBodyLimitEnabled ? m_rigidBodyLimit : 0); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// actor management +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BlastFamilyPtr BlastController::spawnFamily(BlastAsset* blastAsset, const BlastAsset::ActorDesc& desc) +{ + BlastFamilyPtr actor = blastAsset->createFamily(getPhysXController(), *m_extPxManager, desc); + m_families.push_back(actor); + recalculateAssetsSize(); + m_replay->addFamily(&actor->getFamily()->getTkFamily()); + return actor; +} + +void BlastController::removeFamily(BlastFamilyPtr actor) +{ + m_replay->removeFamily(&actor->getFamily()->getTkFamily()); + m_families.erase(std::remove(m_families.begin(), m_families.end(), actor), m_families.end()); + recalculateAssetsSize(); + getPhysXController().resetDragging(); +// Add By Lixu Begin + delete actor; +// Add By Lixu End +} + +void BlastController::removeAllFamilies() +{ + while (!m_families.empty()) + { + removeFamily(m_families.back()); + } + m_replay->reset(); +} + +// Add By Lixu Begin +#include "SceneController.h" +// Add By Lixu End +void BlastController::recalculateAssetsSize() +{ + +// Add By Lixu Begin + std::map<BlastAsset*, std::vector<BlastFamily*>>& AssetFamiliesMap = getManager()->getAssetFamiliesMap(); + std::map<BlastAsset*, AssetList::ModelAsset>& AssetDescMap = getManager()->getAssetDescMap(); + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator it; + for (it = AssetFamiliesMap.begin(); it != AssetFamiliesMap.end(); it++) + { + std::vector<BlastFamily*>& fs = it->second; + fs.clear(); + } + AssetFamiliesMap.clear(); + AssetDescMap.clear(); + + SceneController& sceneController = getManager()->getSceneController(); + int familiesSize = m_families.size(); + for (int i = 0; i < familiesSize; i++) + { + BlastFamilyPtr pBlastFamily = m_families[i]; + BlastAsset* pBlastAsset = (BlastAsset*)&pBlastFamily->getBlastAsset(); + AssetFamiliesMap[pBlastAsset].push_back(&*m_families[i]); + if (AssetDescMap.find(pBlastAsset) == AssetDescMap.end()) + { + AssetList::ModelAsset desc; + if (sceneController.GetAssetDesc(pBlastAsset, desc)) + { + AssetDescMap[pBlastAsset] = desc; + } + } + + AssetList::ModelAsset& m = AssetDescMap[pBlastAsset]; + pBlastFamily->initTransform(m.transform); + } +// Add By Lixu End + + std::set<const BlastAsset*> uniquedAssets; + m_blastAssetsSize = 0; + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (uniquedAssets.find(&m_families[i]->getBlastAsset()) == uniquedAssets.end()) + { + m_blastAssetsSize += m_families[i]->getBlastAsset().getBlastAssetSize(); + uniquedAssets.insert(&m_families[i]->getBlastAsset()); + } + } +} + +void BlastController::blast(PxVec3 worldPos, float damageRadius, float explosiveImpulse, std::function<void(ExtPxActor*)> damageFunction) +{ + PROFILER_SCOPED_FUNCTION(); + + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (m_families[i]) + { + m_families[i]->blast(worldPos, damageRadius, explosiveImpulse, damageFunction); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// context/log +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::blastLog(int type, const char* msg, const char* file, int line) +{ + std::stringstream str; + bool critical = false; + switch (type) + { + case NvBlastMessage::Error: str << "[NvBlast ERROR] "; critical = true; break; + case NvBlastMessage::Warning: str << "[NvBlast WARNING] "; critical = true; break; + case NvBlastMessage::Info: str << "[NvBlast INFO] "; critical = false; break; + case NvBlastMessage::Debug: str << "[NvBlast DEBUG] "; critical = false; break; + } + str << file << "(" << line << "): " << msg << "\n"; + + std::string message = str.str(); + shdfnd::printString(message.c_str()); + PX_ASSERT_WITH_MESSAGE(!critical, message.c_str()); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// debug render +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::fillDebugRender() +{ + PROFILER_SCOPED_FUNCTION(); + + m_debugRenderBuffer.clear(); + + if (debugRenderMode != BlastFamily::DEBUG_RENDER_DISABLED) + { + getPhysXController().getPhysXScene().setVisualizationParameter(PxVisualizationParameter::eSCALE, 1); + for (uint32_t i = 0; i < m_families.size(); ++i) + { + m_families[i]->fillDebugRender(m_debugRenderBuffer, debugRenderMode, debugRenderScale); + } + } + else + { + getPhysXController().getPhysXScene().setVisualizationParameter(PxVisualizationParameter::eSCALE, 0); + } + + getRenderer().queueRenderBuffer(&m_debugRenderBuffer); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastController.h new file mode 100644 index 0000000..98f5c24 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastController.h @@ -0,0 +1,246 @@ +/* +* 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 BLAST_CONTROLLER_H +#define BLAST_CONTROLLER_H + +#include "SampleManager.h" +#include "BlastFamily.h" +#include "DebugRenderBuffer.h" +#include "PxSimulationEventCallback.h" +#include "NvBlastExtImpactDamageManager.h" + +using namespace physx; + +class BlastAsset; +class BlastReplay; + +namespace physx +{ +class PxTaskManager; +} +namespace Nv +{ +namespace Blast +{ +class TkFramework; +} +} + + +struct BlastTimers +{ + double blastDamageMaterial; + double blastDamageFracture; + double blastSplitIsland; + double blastSplitPartition; + double blastSplitVisibility; +}; + +/** +Blast Controller. Entry point for all blast related code, keeps blast actors and controls them. +*/ +class BlastController : public ISampleController +{ +public: + //////// ctor //////// + + BlastController(); + virtual ~BlastController(); + + void reinitialize(); + + //////// controller callbacks //////// + + virtual void onSampleStart(); + virtual void onSampleStop(); + + virtual void Animate(double dt); + void drawUI(); + + + //////// public API //////// + + void blast(PxVec3 worldPos, float damageRadius, float explosiveImpulse, std::function<void(ExtPxActor*)> damageFunction); + + bool stressDamage(ExtPxActor *actor, PxVec3 position, PxVec3 force); + + BlastFamilyPtr spawnFamily(BlastAsset* blastAsset, const BlastAsset::ActorDesc& desc); + void removeFamily(BlastFamilyPtr actor); + void removeAllFamilies(); + + + //////// public static //////// + + static void blastLog(int type, const char* msg, const char* file, int line); + + + //////// public getters/setters //////// + + TkFramework& getTkFramework() const + { + return *m_tkFramework; + } + + TkGroup* getTkGroup() const + { + return m_tkGroup; + } + + ExtPxManager& getExtPxManager() const + { + return *m_extPxManager; + } + + ExtImpactDamageManager* getExtImpactDamageManager() const + { + return m_extImpactDamageManager; + } + + BlastReplay* getReplay() const + { + return m_replay; + } + + uint32_t getActorCount() const; + + uint32_t getTotalVisibleChunkCount() const; + + size_t getFamilySize() const; + + size_t getBlastAssetsSize() const + { + return m_blastAssetsSize; + } + + const BlastTimers& getLastBlastTimers() const + { + return m_lastBlastTimers; + } + + bool getImpactDamageEnabled() const + { + return m_impactDamageEnabled; + } + + void setImpactDamageEnabled(bool enabled, bool forceUpdate = false); + + ExtStressSolverSettings& getStressSolverSettings() + { + return m_extStressSolverSettings; + } + +// Add By Lixu Begin + std::vector<BlastFamilyPtr>& getFamilies() + { + return m_families; + } +// Add By Lixu End + + float getLastStressDelta() const; + + //////// public variables for UI //////// + + BlastFamily::DebugRenderMode debugRenderMode; + float debugRenderScale; + + + //////// Filter shader enum //////// + + enum FilterDataAttributes + { + SUPPRESS_CONTACT_NOTIFY = 1, + }; + +private: + //////// impact damage event callback //////// + + class EventCallback : public PxSimulationEventCallback + { + public: + EventCallback(ExtImpactDamageManager* manager) : m_manager(manager) {} + + // implemented + virtual void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs) + { + m_manager->onContact(pairHeader, pairs, nbPairs); + } + + private: + // unused + void onConstraintBreak(PxConstraintInfo*, PxU32) {} + void onWake(PxActor**, PxU32) {} + void onSleep(PxActor**, PxU32) {} + void onTrigger(PxTriggerPair*, PxU32) {} + void onAdvance(const PxRigidBody*const*, const PxTransform*, const PxU32) {} + + // data + ExtImpactDamageManager* m_manager; + }; + + + //////// private methods //////// + + void updateDraggingStress(); + + void refreshImpactDamageSettings(); + + void fillDebugRender(); + + void recalculateAssetsSize(); + + static bool customImpactDamageFunction(void* data, ExtPxActor* actor, PxShape* shape, PxVec3 position, PxVec3 force); + + + //////// used controllers //////// + + Renderer& getRenderer() const + { + return getManager()->getRenderer(); + } + + PhysXController& getPhysXController() const + { + return getManager()->getPhysXController(); + } + + + //////// internal data //////// + + PxTaskManager* m_taskManager; + TkFramework* m_tkFramework; + TkGroup* m_tkGroup; + ExtPxManager* m_extPxManager; + ExtImpactDamageManager* m_extImpactDamageManager; + ExtImpactSettings m_extImpactDamageManagerSettings; + EventCallback* m_eventCallback; + ExtStressSolverSettings m_extStressSolverSettings; + + std::vector<BlastFamilyPtr> m_families; + DebugRenderBuffer m_debugRenderBuffer; + + bool m_impactDamageEnabled; + bool m_impactDamageToStressEnabled; + + float m_impactDamageToStressFactor; + float m_draggingToStressFactor; + + bool m_rigidBodyLimitEnabled; + uint32_t m_rigidBodyLimit; + + BlastReplay* m_replay; + + BlastTimers m_lastBlastTimers; + + size_t m_blastAssetsSize; +}; + + +#endif diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamily.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamily.cpp new file mode 100644 index 0000000..f947cbd --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamily.cpp @@ -0,0 +1,588 @@ +/* +* 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 "BlastFamily.h" +#include "SampleProfiler.h" +#include "PhysXController.h" +#include "RenderUtils.h" +#include "SampleTime.h" +#include "UIHelpers.h" + +#include "NvBlast.h" +#include "NvBlastTkFamily.h" +#include "NvBlastTkActor.h" +#include "NvBlastTkAsset.h" +#include "NvBlastTkJoint.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastExtPxActor.h" +#include "NvBlastExtPxFamily.h" +#include "NvBlastExtPxManager.h" + +#include "PxRigidDynamic.h" +#include "PxScene.h" +#include "PxJoint.h" + + +const float RIGIDBODY_DENSITY = 2000.0f; + +const float BlastFamily::BOND_HEALTH_MAX = 1.0f; + +BlastFamily::BlastFamily(PhysXController& physXController, ExtPxManager& pxManager, const BlastAsset& blastAsset) + : m_physXController(physXController) + , m_pxManager(pxManager) + , m_blastAsset(blastAsset) + , m_listener(this) + , m_totalVisibleChunkCount(0) + , m_stressSolver(nullptr) +{ + m_settings.stressSolverEnabled = false; + m_settings.stressDamageEnabled = false; + + m_settings.material = { 3.0f, 0.1f, 0.2f, 1.5f + 1e-5f, 0.95f };; +} + +BlastFamily::~BlastFamily() +{ + if (m_stressSolver) + { + m_stressSolver->release(); + } + + m_pxFamily->unsubscribe(m_listener); + + m_pxFamily->release(); +} + +void BlastFamily::initialize(const BlastAsset::ActorDesc& desc) +{ + ExtPxFamilyDesc familyDesc; + familyDesc.actorDesc.initialBondHealths = nullptr; + familyDesc.actorDesc.initialSupportChunkHealths = nullptr; + familyDesc.actorDesc.uniformInitialBondHealth = BOND_HEALTH_MAX; + familyDesc.actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + familyDesc.group = desc.group; + familyDesc.pxAsset = m_blastAsset.getPxAsset(); + m_pxFamily = m_pxManager.createFamily(familyDesc); + + m_tkFamily = &m_pxFamily->getTkFamily(); + m_tkFamily->setID(desc.id); + m_tkFamily->setMaterial(&m_settings.material); + + m_familySize = NvBlastFamilyGetSize(m_tkFamily->getFamilyLL(), nullptr); + + m_pxFamily->subscribe(m_listener); + + ExtPxSpawnSettings spawnSettings = { + &m_physXController.getPhysXScene(), + m_physXController.getDefaultMaterial(), + RIGIDBODY_DENSITY + }; + m_pxFamily->spawn(desc.transform, PxVec3(1.0f), spawnSettings); + + reloadStressSolver(); +} + +void BlastFamily::updatePreSplit(float dt) +{ + PROFILER_BEGIN("Stress Solver"); + // update stress + m_stressSolveTime = 0; + if (m_stressSolver) + { + Time t; + m_stressSolver->update(m_settings.stressDamageEnabled); + m_stressSolveTime += t.getElapsedSeconds(); + } + PROFILER_END(); + + // collect potential actors to health update + m_actorsToUpdateHealth.clear(); + for (const ExtPxActor* actor : m_actors) + { + if (actor->getTkActor().isPending()) + { + m_actorsToUpdateHealth.emplace(actor); + } + } +} + +void BlastFamily::updateAfterSplit(float dt) +{ + PROFILER_BEGIN("Actor Health Update"); + for (const ExtPxActor* actor : m_actors) + { + onActorUpdate(*actor); + + // update health if neccessary + if (m_actorsToUpdateHealth.find(actor) != m_actorsToUpdateHealth.end()) + { + onActorHealthUpdate(*actor); + } + } + PROFILER_END(); + + PROFILER_BEGIN("Actor Misc Update"); + onUpdate(); + PROFILER_END(); + + m_pxFamily->postSplitUpdate(); +} + +void BlastFamily::processActorCreated(ExtPxFamily&, ExtPxActor& actor) +{ + m_totalVisibleChunkCount += actor.getChunkCount(); + m_actors.emplace(&actor); + + onActorCreated(actor); + onActorHealthUpdate(actor); +} + +void BlastFamily::processActorDestroyed(ExtPxFamily&, ExtPxActor& actor) +{ + m_totalVisibleChunkCount -= actor.getChunkCount(); + m_physXController.notifyRigidDynamicDestroyed(&actor.getPhysXActor()); + + onActorDestroyed(actor); + + m_actors.erase(m_actors.find(&actor)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Data Helpers +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +uint32_t BlastFamily::getActorCount() const +{ + return (uint32_t)m_tkFamily->getActorCount(); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// UI +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastFamily::drawUI() +{ + // Blast Material + ImGui::Spacing(); + ImGui::Text("Blast Material:"); + ImGui::DragFloat("singleChunkThreshold", &m_settings.material.singleChunkThreshold); + ImGui::DragFloat("graphChunkThreshold", &m_settings.material.graphChunkThreshold); + ImGui::DragFloat("bondNormalThreshold", &m_settings.material.bondNormalThreshold); + ImGui::DragFloat("bondTangentialThreshold", &m_settings.material.bondTangentialThreshold); + ImGui::DragFloat("damageAttenuation", &m_settings.material.damageAttenuation); + + ImGui::Spacing(); + + // Stress Solver Settings + if (ImGui::Checkbox("Stress Solver Enabled", &m_settings.stressSolverEnabled)) + { + reloadStressSolver(); + } + + if (m_settings.stressSolverEnabled) + { + // Settings + bool changed = false; + + changed |= ImGui::DragInt("Bond Iterations Per Frame", (int*)&m_settings.stressSolverSettings.bondIterationsPerFrame, 100, 0, 500000); + changed |= ImGui::DragFloat("Stress Linear Factor", &m_settings.stressSolverSettings.stressLinearFactor, 0.00001f, 0.0f, 10.0f, "%.6f"); + changed |= ImGui::DragFloat("Stress Angular Factor", &m_settings.stressSolverSettings.stressAngularFactor, 0.00001f, 0.0f, 10.0f, "%.6f"); + changed |= ImGui::SliderInt("Graph Reduction Level", (int*)&m_settings.stressSolverSettings.graphReductionLevel, 0, 32); + if (changed) + { + refreshStressSolverSettings(); + } + + ImGui::Checkbox("Stress Damage Enabled", &m_settings.stressDamageEnabled); + + if (ImGui::Button("Recalculate Stress")) + { + resetStress(); + } + } +} + +void BlastFamily::drawStatsUI() +{ + ImGui::PushStyleColor(ImGuiCol_Text, ImColor(10, 255, 10, 255)); + const ExtStressSolver* stressSolver = m_stressSolver; + if (stressSolver) + { + const float errorLinear = stressSolver->getStressErrorLinear(); + const float errorAngular = stressSolver->getStressErrorAngular(); + + ImGui::Text("Stress Bond Count: %d", stressSolver->getBondCount()); + ImGui::Text("Stress Iterations: %d (+%d)", stressSolver->getIterationCount(), stressSolver->getIterationsPerFrame()); + ImGui::Text("Stress Frames: %d", stressSolver->getFrameCount()); + ImGui::Text("Stress Error Lin / Ang: %.4f / %.4f", errorLinear, errorAngular); + ImGui::Text("Stress Solve Time: %.3f ms", m_stressSolveTime * 1000); + + // plot errors + { + static float scale = 1.0f; + scale = stressSolver->getFrameCount() <= 1 ? 1.0f : scale; + scale = std::max<float>(scale, errorLinear); + scale = std::max<float>(scale, errorAngular); + + static PlotLinesInstance<> linearErrorPlot; + linearErrorPlot.plot("Stress Linear Error", errorLinear, "error/frame", 0.0f, 1.0f * scale); + static PlotLinesInstance<> angularErrorPlot; + angularErrorPlot.plot("Stress Angular Error", errorAngular, "error/frame", 0.0f, 1.0f * scale); + } + } + else + { + ImGui::Text("No Stress Solver"); + } + ImGui::PopStyleColor(); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Stress Solver +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastFamily::setSettings(const Settings& settings) +{ + bool reloadStressSolverNeeded = (m_settings.stressSolverEnabled != settings.stressSolverEnabled); + + m_settings = settings; + refreshStressSolverSettings(); + + if (reloadStressSolverNeeded) + { + reloadStressSolver(); + } + + m_tkFamily->setMaterial(&m_settings.material); +} + +void BlastFamily::refreshStressSolverSettings() +{ + if (m_stressSolver) + { + m_stressSolver->setSettings(m_settings.stressSolverSettings); + } +} + +void BlastFamily::resetStress() +{ + m_stressSolver->reset(); +} + +void BlastFamily::reloadStressSolver() +{ + if (m_stressSolver) + { + m_stressSolver->release(); + m_stressSolver = nullptr; + } + + if (m_settings.stressSolverEnabled) + { + m_stressSolver = ExtStressSolver::create(*m_pxFamily, m_settings.stressSolverSettings); + m_pxFamily->userData = m_stressSolver; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// debug render +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const DirectX::XMFLOAT4 BOND_NORMAL_COLOR(0.0f, 0.8f, 1.0f, 1.0f); +const DirectX::XMFLOAT4 BOND_INVISIBLE_COLOR(0.65f, 0.16f, 0.16f, 1.0f); +const DirectX::XMFLOAT4 BOND_IMPULSE_LINEAR_COLOR(0.0f, 1.0f, 0.0f, 1.0f); +const DirectX::XMFLOAT4 BOND_IMPULSE_ANGULAR_COLOR(1.0f, 0.0f, 0.0f, 1.0f); +const DirectX::XMFLOAT4 JOINT_COLOR(0.5f, 0.6f, 7.0f, 1.0f); + + +inline void pushCentroid(std::vector<PxDebugLine>& lines, PxVec3 pos, PxU32 color, const float& area, const PxVec3& normal) +{ + // draw square of area 'area' rotated by normal + { + // build world rotation + PxVec3 n0(0, 0, 1); + PxVec3 n1 = normal; + PxVec3 axis = n0.cross(n1); + float d = n0.dot(n1); + PxQuat q(axis.x, axis.y, axis.z, 1.f + d); + q.normalize(); + float e = PxSqrt(1.0f / 2.0f); + float r = PxSqrt(area); + + // transform all 4 square points + PxTransform t(pos, q); + PxVec3 p0 = t.transform(PxVec3(-e, e, 0) * r); + PxVec3 p1 = t.transform(PxVec3( e, e, 0) * r); + PxVec3 p2 = t.transform(PxVec3( e, -e, 0) * r); + PxVec3 p3 = t.transform(PxVec3(-e, -e, 0) * r); + + // push square edges + lines.push_back(PxDebugLine(p0, p1, color)); + lines.push_back(PxDebugLine(p3, p2, color)); + lines.push_back(PxDebugLine(p1, p2, color)); + lines.push_back(PxDebugLine(p0, p3, color)); + } + + // draw normal + lines.push_back(PxDebugLine(pos, pos + normal * 0.5f, XMFLOAT4ToU32Color(BOND_NORMAL_COLOR))); +} + +inline DirectX::XMFLOAT4 bondHealthColor(float healthFraction) +{ + const DirectX::XMFLOAT4 BOND_HEALTHY_COLOR(0.0f, 1.0f, 0.0f, 1.0f); + const DirectX::XMFLOAT4 BOND_MID_COLOR(1.0f, 1.0f, 0.0f, 1.0f); + const DirectX::XMFLOAT4 BOND_BROKEN_COLOR(1.0f, 0.0f, 0.0f, 1.0f); + + return healthFraction < 0.5 ? XMFLOAT4Lerp(BOND_BROKEN_COLOR, BOND_MID_COLOR, 2.0f * healthFraction) : XMFLOAT4Lerp(BOND_MID_COLOR, BOND_HEALTHY_COLOR, 2.0f * healthFraction - 1.0f); +} + +void BlastFamily::fillDebugRender(DebugRenderBuffer& debugRenderBuffer, DebugRenderMode mode, float renderScale) +{ + const NvBlastChunk* chunks = m_tkFamily->getAsset()->getChunks(); + const NvBlastBond* bonds = m_tkFamily->getAsset()->getBonds(); + const NvBlastSupportGraph graph = m_tkFamily->getAsset()->getGraph(); + + for (const ExtPxActor* pxActor : m_actors) + { + TkActor& actor = pxActor->getTkActor(); + uint32_t lineStartIndex = (uint32_t)debugRenderBuffer.m_lines.size(); + + uint32_t nodeCount = actor.getGraphNodeCount(); + if (nodeCount == 0) // subsupport chunks don't have graph nodes + continue; + + std::vector<uint32_t> nodes(actor.getGraphNodeCount()); + actor.getGraphNodeIndices(nodes.data(), static_cast<uint32_t>(nodes.size())); + + if (DEBUG_RENDER_HEALTH_GRAPH <= mode && mode <= DEBUG_RENDER_HEALTH_GRAPH_CENTROIDS) + { + const float* bondHealths = actor.getBondHealths(); + + const ExtPxChunk* pxChunks = m_blastAsset.getPxAsset()->getChunks(); + + for (uint32_t node0 : nodes) + { + const uint32_t chunkIndex0 = graph.chunkIndices[node0]; + const NvBlastChunk& blastChunk0 = chunks[chunkIndex0]; + const ExtPxChunk& assetChunk0 = pxChunks[chunkIndex0]; + + for (uint32_t adjacencyIndex = graph.adjacencyPartition[node0]; adjacencyIndex < graph.adjacencyPartition[node0 + 1]; adjacencyIndex++) + { + uint32_t node1 = graph.adjacentNodeIndices[adjacencyIndex]; + const uint32_t chunkIndex1 = graph.chunkIndices[node1]; + const NvBlastChunk& blastChunk1 = chunks[chunkIndex1]; + const ExtPxChunk& assetChunk1 = pxChunks[chunkIndex1]; + if (node0 > node1) + continue; + + bool invisibleBond = assetChunk0.subchunkCount == 0 || assetChunk1.subchunkCount == 0; + + // health + uint32_t bondIndex = graph.adjacentBondIndices[adjacencyIndex]; + float healthVal = PxClamp(bondHealths[bondIndex] / BOND_HEALTH_MAX, 0.0f, 1.0f); + + DirectX::XMFLOAT4 color = bondHealthColor(healthVal); + + const NvBlastBond& solverBond = bonds[bondIndex]; + const PxVec3& centroid = reinterpret_cast<const PxVec3&>(solverBond.centroid); + + // centroid + if (mode == DEBUG_RENDER_HEALTH_GRAPH_CENTROIDS || mode == DEBUG_RENDER_CENTROIDS) + { + const PxVec3& normal = reinterpret_cast<const PxVec3&>(solverBond.normal); + pushCentroid(debugRenderBuffer.m_lines, centroid, XMFLOAT4ToU32Color(invisibleBond ? BOND_INVISIBLE_COLOR : color), solverBond.area, normal.getNormalized()); + } + + // chunk connection (bond) + if ((mode == DEBUG_RENDER_HEALTH_GRAPH || mode == DEBUG_RENDER_HEALTH_GRAPH_CENTROIDS) && !invisibleBond) + { + const PxVec3& c0 = reinterpret_cast<const PxVec3&>(blastChunk0.centroid); + const PxVec3& c1 = reinterpret_cast<const PxVec3&>(blastChunk1.centroid); + debugRenderBuffer.m_lines.push_back(PxDebugLine(c0, c1, XMFLOAT4ToU32Color(color))); + } + } + } + } + + // stress + if (DEBUG_RENDER_STRESS_GRAPH <= mode && mode <= DEBUG_RENDER_STRESS_GRAPH_BONDS_IMPULSES) + { + if (m_stressSolver) + { + m_stressSolver->fillDebugRender(nodes, debugRenderBuffer.m_lines, (ExtStressSolver::DebugRenderMode)(mode - DEBUG_RENDER_STRESS_GRAPH), renderScale); + } + } + + // transform all added lines from local to global + PxTransform localToGlobal = pxActor->getPhysXActor().getGlobalPose(); + for (uint32_t i = lineStartIndex; i < debugRenderBuffer.m_lines.size(); i++) + { + PxDebugLine& line = debugRenderBuffer.m_lines[i]; + line.pos0 = localToGlobal.transform(line.pos0); + line.pos1 = localToGlobal.transform(line.pos1); + } + } + + // joints debug render + if (mode == DEBUG_RENDER_JOINTS) + { + for (const ExtPxActor* pxActor : m_actors) + { + TkActor& actor = pxActor->getTkActor(); + const uint32_t jointCount = actor.getJointCount(); + if (jointCount > 0) + { + std::vector<TkJoint*> joints(jointCount); + actor.getJoints(joints.data(), jointCount); + for (auto joint : joints) + { + PxJoint* pxJoint = reinterpret_cast<PxJoint*>(joint->userData); + if (pxJoint) + { + PxRigidActor *actor0, *actor1; + pxJoint->getActors(actor0, actor1); + auto lp0 = pxJoint->getLocalPose(PxJointActorIndex::eACTOR0); + auto lp1 = pxJoint->getLocalPose(PxJointActorIndex::eACTOR1); + PxVec3 p0 = actor0 ? actor0->getGlobalPose().transform(lp0).p : lp0.p; + PxVec3 p1 = actor1 ? actor1->getGlobalPose().transform(lp1).p : lp1.p; + debugRenderBuffer.m_lines.push_back(PxDebugLine(p0, p1, XMFLOAT4ToU32Color(JOINT_COLOR))); + } + } + } + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// action!!! +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class BlastOverlapCallback : public PxOverlapCallback +{ +public: + BlastOverlapCallback(ExtPxManager& pxManager, std::set<ExtPxActor*>& actorBuffer) + : m_pxManager(pxManager), 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_pxManager.getActorFromPhysXActor(*rigidDynamic); + if (actor != nullptr) + { + m_actorBuffer.insert(actor); + } + } + } + return true; + } + +private: + ExtPxManager& m_pxManager; + std::set<ExtPxActor*>& m_actorBuffer; + PxOverlapHit m_hitBuffer[1000]; +}; + +void BlastFamily::blast(PxVec3 worldPos, float damageRadius, float explosiveImpulse, std::function<void(ExtPxActor*)> damageFunction) +{ +// Add By Lixu Begin + const ExtPxAsset* pExtPxAsset = m_blastAsset.getPxAsset(); + const TkAsset& tkAsset = pExtPxAsset->getTkAsset(); + uint32_t bondCount = tkAsset.getBondCount(); + if (bondCount == 0) + { + return; + } +// Add By Lixu End + + std::set<ExtPxActor*> actorsToDamage; +#if 1 + BlastOverlapCallback overlapCallback(m_pxManager, actorsToDamage); + m_physXController.getPhysXScene().overlap(PxSphereGeometry(damageRadius), PxTransform(worldPos), overlapCallback); +#else + for (std::map<NvBlastActor*, PhysXController::Actor*>::iterator it = m_actorsMap.begin(); it != m_actorsMap.end(); it++) + { + actorsToDamage.insert(it->first); + } +#endif + + for (auto actor : actorsToDamage) + { + damageFunction(actor); + } + + if (explosiveImpulse > 0.0f) + { + explode(worldPos, damageRadius, explosiveImpulse); + } +} + + +class ExplodeOverlapCallback : public PxOverlapCallback +{ +public: + ExplodeOverlapCallback(PxVec3 worldPos, float radius, float explosiveImpulse) + : m_worldPos(worldPos) + , m_radius(radius) + , m_explosiveImpulse(explosiveImpulse) + , PxOverlapCallback(m_hitBuffer, sizeof(m_hitBuffer) / sizeof(m_hitBuffer[0])) {} + + PxAgain processTouches(const PxOverlapHit* buffer, PxU32 nbHits) + { + for (PxU32 i = 0; i < nbHits; ++i) + { + PxRigidActor* actor = buffer[i].actor; + PxRigidDynamic* rigidDynamic = actor->is<PxRigidDynamic>(); + if (rigidDynamic && !(rigidDynamic->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC)) + { + if (m_actorBuffer.find(rigidDynamic) == m_actorBuffer.end()) + { + m_actorBuffer.insert(rigidDynamic); + PxVec3 dr = rigidDynamic->getGlobalPose().transform(rigidDynamic->getCMassLocalPose()).p - m_worldPos; + float distance = dr.magnitude(); + float factor = PxClamp(1.0f - (distance * distance) / (m_radius * m_radius), 0.0f, 1.0f); + float impulse = factor * m_explosiveImpulse * RIGIDBODY_DENSITY; + PxVec3 vel = dr.getNormalized() * impulse / rigidDynamic->getMass(); + rigidDynamic->setLinearVelocity(rigidDynamic->getLinearVelocity() + vel); + } + } + } + return true; + } + +private: + PxOverlapHit m_hitBuffer[1000]; + float m_explosiveImpulse; + std::set<PxRigidDynamic*> m_actorBuffer; + PxVec3 m_worldPos; + float m_radius; +}; + +void BlastFamily::explode(PxVec3 worldPos, float damageRadius, float explosiveImpulse) +{ + ExplodeOverlapCallback overlapCallback(worldPos, damageRadius, explosiveImpulse); + m_physXController.getPhysXScene().overlap(PxSphereGeometry(damageRadius), PxTransform(worldPos), overlapCallback); + +} + +// Add By Lixu Begin +bool BlastFamily::find(ExtPxActor* actor) +{ + std::set<ExtPxActor*>::iterator it = m_actors.find(actor); + return it != m_actors.end(); +} +// Add By Lixu End diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamily.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamily.h new file mode 100644 index 0000000..b4611a9 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamily.h @@ -0,0 +1,224 @@ +/* +* 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 BLAST_FAMILY_H +#define BLAST_FAMILY_H + +#include "BlastAsset.h" +#include "NvBlastExtPxListener.h" +#include "NvBlastExtStressSolver.h" +#include "NvBlastExtDamageShaders.h" +#include <functional> +#include <set> +#include <map> + + +class DebugRenderBuffer; +// Add By Lixu Begin +class RenderMaterial; +// Add By Lixu End + +namespace Nv +{ +namespace Blast +{ +class TkFamily; +class ExtPxManager; +} +} + + +/** +BlastFamily class represents 1 spawned BlastAsset, contains and manipulates all physx/blast actors spawned by fracturing it. +Abstract class, internal actor management functions are implementation dependent and so pure virtual. +*/ +class BlastFamily +{ +public: + + //////// public API //////// + + void blast(PxVec3 worldPos, float damageRadius, float explosiveImpulse, std::function<void(ExtPxActor*)> damageFunction); + void explode(PxVec3 worldPos, float damageRadius, float explosiveImpulse); + + void updatePreSplit(float dt); + void updateAfterSplit(float dt); + + void drawUI(); + void drawStatsUI(); + +// Add By Lixu Begin + bool find(ExtPxActor* actor); + virtual void setActorSelected(const ExtPxActor& actor, bool selected) {} + virtual std::vector<uint32_t> getSelectedChunks() { return std::vector<uint32_t>(); } + virtual void clearChunksSelected() {} + virtual void setChunkSelected(uint32_t chunk, bool selected) {} + virtual void setChunkSelected(std::vector<uint32_t> depths, bool selected) {} + virtual bool getChunkSelected(uint32_t chunk) { return false; } + virtual void setActorScale(const ExtPxActor& actor, PxMat44& scale, bool replace) {} + virtual bool isChunkVisible(uint32_t chunkIndex) { return false; } + virtual void setChunkVisible(uint32_t chunkIndex, bool bVisible) {} + virtual void setChunkVisible(std::vector<uint32_t> depths, bool bVisible) {} + virtual void initTransform(physx::PxTransform t) {} + std::map<uint32_t, bool>& getVisibleChangedChunks() { return m_VisibleChangedChunks; } + void clearVisibleChangedChunks() { m_VisibleChangedChunks.clear(); } + virtual void getMaterial(RenderMaterial** ppRenderMaterial, bool externalSurface) {} + virtual void setMaterial(RenderMaterial* pRenderMaterial, bool externalSurface) {} +// Add By Lixu End + + enum DebugRenderMode + { + DEBUG_RENDER_DISABLED, + DEBUG_RENDER_HEALTH_GRAPH, + DEBUG_RENDER_CENTROIDS, + DEBUG_RENDER_HEALTH_GRAPH_CENTROIDS, + DEBUG_RENDER_JOINTS, + DEBUG_RENDER_STRESS_GRAPH, + DEBUG_RENDER_STRESS_GRAPH_NODES_IMPULSES, + DEBUG_RENDER_STRESS_GRAPH_BONDS_IMPULSES, + + // count + DEBUG_RENDER_MODES_COUNT + }; + + void fillDebugRender(DebugRenderBuffer& debugRenderBuffer, DebugRenderMode mode, float renderScale); + + + //////// public getters //////// + + const ExtPxFamily* getFamily() const + { + return m_pxFamily; + } + + uint32_t getActorCount() const; + + uint32_t getTotalVisibleChunkCount() const + { + return m_totalVisibleChunkCount; + } + + size_t getFamilySize() const + { + return m_familySize; + } + + const BlastAsset& getBlastAsset() + { + return m_blastAsset; + } + + void resetStress(); + + void refreshStressSolverSettings(); + + void reloadStressSolver(); + + + //////// consts //////// + + static const float BOND_HEALTH_MAX; + + + //////// settings //////// + + struct Settings + { + bool stressSolverEnabled; + ExtStressSolverSettings stressSolverSettings; + bool stressDamageEnabled; + NvBlastExtMaterial material; + }; + + void setSettings(const Settings& settings); + + const Settings& getSettings() const + { + return m_settings; + } + + + //////// dtor //////// + + virtual ~BlastFamily(); + +protected: + + //////// ctor //////// + + BlastFamily(PhysXController& physXController, ExtPxManager& pxManager, const BlastAsset& blastAsset); + + void initialize(const BlastAsset::ActorDesc& desc); + + + //////// internal virtual callbacks //////// + + virtual void onActorCreated(const ExtPxActor& actor) = 0; + virtual void onActorUpdate(const ExtPxActor& actor) = 0; + virtual void onActorDestroyed(const ExtPxActor& actor) = 0; + virtual void onActorHealthUpdate(const ExtPxActor& pxActor) {}; + + virtual void onUpdate() {} + + + //////// protected data //////// + + PhysXController& m_physXController; + ExtPxManager& m_pxManager; + const BlastAsset& m_blastAsset; + std::map<uint32_t, bool> m_VisibleChangedChunks; + +private: + + //////// physics listener //////// + + class PxManagerListener : public ExtPxListener + { + public: + PxManagerListener(BlastFamily* family) : m_family(family) {} + + virtual void onActorCreated(ExtPxFamily& family, ExtPxActor& actor) + { + m_family->processActorCreated(family, actor); + + } + + virtual void onActorDestroyed(ExtPxFamily& family, ExtPxActor& actor) + { + m_family->processActorDestroyed(family, actor); + } + private: + BlastFamily* m_family; + }; + + friend class PxManagerListener; + + //////// private methods //////// + + void processActorCreated(ExtPxFamily&, ExtPxActor& actor); + void processActorDestroyed(ExtPxFamily&, ExtPxActor& actor); + + + //////// private data //////// + + TkFamily* m_tkFamily; + ExtPxFamily* m_pxFamily; + PxManagerListener m_listener; + Settings m_settings; + size_t m_familySize; + uint32_t m_totalVisibleChunkCount; + ExtStressSolver* m_stressSolver; + double m_stressSolveTime; + std::set<ExtPxActor*> m_actors; + std::set<const ExtPxActor*> m_actorsToUpdateHealth; +}; + + +#endif //BLAST_FAMILY_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyBoxes.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyBoxes.cpp new file mode 100644 index 0000000..e8b7b27 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyBoxes.cpp @@ -0,0 +1,92 @@ +/* +* 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 "BlastFamilyBoxes.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastExtPxActor.h" +#include "BlastAssetBoxes.h" +#include "Renderer.h" +#include "PhysXController.h" +#include "RenderUtils.h" +#include "PxRigidDynamic.h" + +using namespace physx; + + +BlastFamilyBoxes::BlastFamilyBoxes(PhysXController& physXController, ExtPxManager& pxManager, Renderer& renderer, const BlastAssetBoxes& blastAsset, const BlastAsset::ActorDesc& desc) + : BlastFamily(physXController, pxManager, blastAsset), m_renderer(renderer) +{ + // prepare renderables + IRenderMesh* boxRenderMesh = renderer.getPrimitiveRenderMesh(PrimitiveRenderMeshType::Box); + RenderMaterial* primitiveRenderMaterial = physXController.getPrimitiveRenderMaterial(); + + const ExtPxAsset* pxAsset = m_blastAsset.getPxAsset(); + const uint32_t chunkCount = pxAsset->getChunkCount(); + const ExtPxChunk* chunks = pxAsset->getChunks(); + const ExtPxSubchunk* subChunks = pxAsset->getSubchunks(); + m_chunkRenderables.resize(chunkCount); + for (uint32_t i = 0; i < chunkCount; i++) + { + Renderable* renderable = renderer.createRenderable(*boxRenderMesh, *primitiveRenderMaterial); + renderable->setHidden(true); + renderable->setScale(subChunks[chunks[i].firstSubchunkIndex].geometry.scale.scale); + m_chunkRenderables[i] = renderable; + } + + // initialize in position + initialize(desc); +} + +BlastFamilyBoxes::~BlastFamilyBoxes() +{ + for (uint32_t i = 0; i < m_chunkRenderables.size(); i++) + { + m_renderer.removeRenderable(m_chunkRenderables[i]); + } +} + +void BlastFamilyBoxes::onActorCreated(const ExtPxActor& actor) +{ + DirectX::XMFLOAT4 color = getRandomPastelColor(); + + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + const uint32_t chunkIndex = chunkIndices[i]; + m_chunkRenderables[chunkIndex]->setHidden(false); + m_chunkRenderables[chunkIndex]->setColor(color); + } +} + +void BlastFamilyBoxes::onActorUpdate(const ExtPxActor& actor) +{ + const ExtPxChunk* chunks = m_blastAsset.getPxAsset()->getChunks(); + const ExtPxSubchunk* subChunks = m_blastAsset.getPxAsset()->getSubchunks(); + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + const uint32_t chunkIndex = chunkIndices[i]; + m_chunkRenderables[chunkIndex]->setTransform(actor.getPhysXActor().getGlobalPose() * subChunks[chunks[chunkIndex].firstSubchunkIndex].transform); + } +} + +void BlastFamilyBoxes::onActorDestroyed(const ExtPxActor& actor) +{ + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + m_chunkRenderables[chunkIndices[i]]->setHidden(true); + } + +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyBoxes.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyBoxes.h new file mode 100644 index 0000000..1f70451 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyBoxes.h @@ -0,0 +1,37 @@ +/* +* 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 BLAST_FAMILY_BOXES +#define BLAST_FAMILY_BOXES + +#include "BlastFamily.h" + +class BlastAssetBoxes; +class Renderable; + + +class BlastFamilyBoxes : public BlastFamily +{ +public: + BlastFamilyBoxes(PhysXController& physXController, ExtPxManager& pxManager, Renderer& renderer, const BlastAssetBoxes& blastAsset, const BlastAsset::ActorDesc& desc); + virtual ~BlastFamilyBoxes(); + +protected: + virtual void onActorCreated(const ExtPxActor& actor); + virtual void onActorUpdate(const ExtPxActor& actor); + virtual void onActorDestroyed(const ExtPxActor& actor); + +private: + Renderer& m_renderer; + std::vector<Renderable*> m_chunkRenderables; +}; + + +#endif //BLAST_FAMILY_BOXES
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSimple.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSimple.cpp new file mode 100644 index 0000000..54df3cd --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSimple.cpp @@ -0,0 +1,638 @@ +/* +* 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 "BlastFamilyModelSimple.h" +#include "RenderUtils.h" +#include "DeviceManager.h" +#include "Renderer.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastExtPxActor.h" +#include "NvBlastTkActor.h" +#include "NvBlastTkAsset.h" +#include "PxRigidDynamic.h" + +using namespace physx; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SimpleRenderMesh +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SimpleRenderMesh : public IRenderMesh +{ +public: + SimpleRenderMesh(const SimpleMesh* mesh) : m_mesh(mesh) + { + m_device = GetDeviceManager()->GetDevice(); + + m_inputDesc.push_back({ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + m_inputDesc.push_back({ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + m_inputDesc.push_back({ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + m_inputDesc.push_back({ "TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + + m_numVertices = static_cast<uint32_t>(mesh->vertices.size()); + m_numFaces = static_cast<uint32_t>(mesh->indices.size()); + + // VB + { + D3D11_SUBRESOURCE_DATA vertexBufferData; + ZeroMemory(&vertexBufferData, sizeof(vertexBufferData)); + vertexBufferData.pSysMem = mesh->vertices.data(); + + D3D11_BUFFER_DESC bufferDesc; + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.ByteWidth = sizeof(SimpleMesh::Vertex) * m_numVertices; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + V(m_device->CreateBuffer(&bufferDesc, &vertexBufferData, &m_vertexBuffer)); + } + + // Health Buffer + { + // fill with 1.0f initially + std::vector<float> healths(mesh->vertices.size()); + std::fill(healths.begin(), healths.end(), 1.0f); + + D3D11_SUBRESOURCE_DATA vertexBufferData; + ZeroMemory(&vertexBufferData, sizeof(vertexBufferData)); + vertexBufferData.pSysMem = healths.data(); + + D3D11_BUFFER_DESC bufferDesc; + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.ByteWidth = (uint32_t)(sizeof(float) * m_numVertices); + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + + V(m_device->CreateBuffer(&bufferDesc, &vertexBufferData, &m_healthBuffer)); + } + + // IB + if (m_numFaces) + { + D3D11_SUBRESOURCE_DATA indexBufferData; + + ZeroMemory(&indexBufferData, sizeof(indexBufferData)); + indexBufferData.pSysMem = mesh->indices.data(); + + D3D11_BUFFER_DESC bufferDesc; + + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc.ByteWidth = sizeof(uint16_t) * m_numFaces; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + V(m_device->CreateBuffer(&bufferDesc, &indexBufferData, &m_indexBuffer)); + } + } + + ~SimpleRenderMesh() + { + SAFE_RELEASE(m_healthBuffer); + SAFE_RELEASE(m_vertexBuffer); + SAFE_RELEASE(m_indexBuffer); + } + + + void render(ID3D11DeviceContext& context) const + { + context.IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + UINT strides[2] = { sizeof(SimpleMesh::Vertex), sizeof(uint32_t) }; + UINT offsets[2] = { 0 }; + ID3D11Buffer* buffers[2] = { m_vertexBuffer, m_healthBuffer }; + context.IASetVertexBuffers(0, 2, buffers, strides, offsets); + + + context.IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R16_UINT, 0); + + if (m_indexBuffer) + context.DrawIndexed(m_numFaces, 0, 0); + else + context.Draw(m_numVertices, 0); + } + + const std::vector<D3D11_INPUT_ELEMENT_DESC>& getInputElementDesc() const { return m_inputDesc; } + + const SimpleMesh* getMesh() { return m_mesh; } + + void updateHealths(const std::vector<float>& healths) + { + ID3D11DeviceContext* context; + m_device->GetImmediateContext(&context); + + // update buffer + { + D3D11_MAPPED_SUBRESOURCE mappedRead; + V(context->Map(m_healthBuffer, 0, D3D11_MAP_WRITE_DISCARD, NULL, &mappedRead)); + memcpy(mappedRead.pData, healths.data(), sizeof(float) * healths.size()); + context->Unmap(m_healthBuffer, 0); + } + + } + +// Add By Lixu Begin + void setScale(PxMat44 scale, bool replace) + { + std::vector<SimpleMesh::Vertex> newVertex(m_numVertices); + for (int v = 0; v < m_numVertices; v++) + { + newVertex[v] = m_mesh->vertices[v]; + newVertex[v].position = scale.transform(newVertex[v].position); + } + + D3D11_SUBRESOURCE_DATA vertexBufferData; + ZeroMemory(&vertexBufferData, sizeof(vertexBufferData)); + vertexBufferData.pSysMem = newVertex.data(); + + D3D11_BUFFER_DESC bufferDesc; + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.ByteWidth = sizeof(SimpleMesh::Vertex) * m_numVertices; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + ID3D11Buffer* pBuffer = m_vertexBuffer; + V(m_device->CreateBuffer(&bufferDesc, &vertexBufferData, &m_vertexBuffer)); + if (NULL != pBuffer) + { + pBuffer->Release(); + pBuffer = NULL; + } + + if (replace) + { + memcpy((void*)m_mesh->vertices.data(), newVertex.data(), bufferDesc.ByteWidth); + } + } +// Add By Lixu End + +private: + + ID3D11Device* m_device; + + ID3D11Buffer* m_vertexBuffer; + ID3D11Buffer* m_healthBuffer; + ID3D11Buffer* m_indexBuffer; + uint32_t m_numFaces; + uint32_t m_numVertices; + + std::vector<D3D11_INPUT_ELEMENT_DESC> m_inputDesc; + + const SimpleMesh* m_mesh; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// BlastFamilyModelSimple +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BlastFamilyModelSimple::BlastFamilyModelSimple(PhysXController& physXController, ExtPxManager& pxManager, Renderer& renderer, const BlastAssetModelSimple& blastAsset, const BlastAsset::ActorDesc& desc) + : BlastFamily(physXController, pxManager, blastAsset), m_renderer(renderer) +{ + // materials + auto materials = blastAsset.getRenderMaterials(); + + // model + const BlastModel& model = blastAsset.getModel(); + + // create render mesh for every BlastModel::Chunk::Mesh and renderable with it + const std::vector<BlastModel::Chunk>& modelChunks = model.chunks; + m_chunks.resize(modelChunks.size()); + for (uint32_t chunkIndex = 0; chunkIndex < modelChunks.size(); chunkIndex++) + { + const std::vector<BlastModel::Chunk::Mesh>& meshes = modelChunks[chunkIndex].meshes; + std::vector<SimpleRenderMesh*>& renderMeshes = m_chunks[chunkIndex].renderMeshes; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; +// Add By Lixu Begin + std::vector<Renderable*>& ex_Renderables = m_chunks[chunkIndex].ex_Renderables; + ex_Renderables.clear(); + std::vector<Renderable*>& in_Renderables = m_chunks[chunkIndex].in_Renderables; + in_Renderables.clear(); +// Add By Lixu End + renderMeshes.resize(meshes.size()); + renderables.resize(meshes.size()); + for (uint32_t i = 0; i < meshes.size(); i++) + { + renderMeshes[i] = new SimpleRenderMesh(&meshes[i].mesh); + + uint32_t materialIndex = model.chunks[chunkIndex].meshes[i].materialIndex; + Renderable* renderable = renderer.createRenderable(*renderMeshes[i], *materials[materialIndex]); + renderable->setHidden(true); + renderables[i] = renderable; +// Add By Lixu Begin + if (materialIndex == 0) + { + ex_Renderables.push_back(renderable); + } + else if (materialIndex == 1) + { + in_Renderables.push_back(renderable); + } +// Add By Lixu End + } + } + + // initialize in position + initialize(desc); +} + +BlastFamilyModelSimple::~BlastFamilyModelSimple() +{ + // release all chunks + for (uint32_t chunkIndex = 0; chunkIndex < m_chunks.size(); chunkIndex++) + { + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (uint32_t i = 0; i < m_chunks[chunkIndex].renderables.size(); i++) + { + m_renderer.removeRenderable(m_chunks[chunkIndex].renderables[i]); + SAFE_DELETE(m_chunks[chunkIndex].renderMeshes[i]); + } + } +} + +void BlastFamilyModelSimple::onActorCreated(const ExtPxActor& actor) +{ + // separate color for every material + std::vector<DirectX::XMFLOAT4> colors; + + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + uint32_t chunkIndex = chunkIndices[i]; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (uint32_t r = 0; r < renderables.size(); r++) + { + if (colors.size() <= r) + colors.push_back(getRandomPastelColor()); + + renderables[r]->setHidden(false); + renderables[r]->setColor(colors[r]); + + m_VisibleChangedChunks[chunkIndex] = true; + } + } +} + +void BlastFamilyModelSimple::onActorUpdate(const ExtPxActor& actor) +{ +// Add By Lixu Begin + uint32_t shapesCount = actor.getPhysXActor().getNbShapes(); + PxTransform lp; + if (shapesCount > 0) + { + std::vector<PxShape*> shapes(shapesCount); + actor.getPhysXActor().getShapes(&shapes[0], shapesCount); + PxShape* shape = shapes[0]; + lp = shape->getLocalPose(); + } +// Add By Lixu End + + const ExtPxChunk* chunks = m_blastAsset.getPxAsset()->getChunks(); + const ExtPxSubchunk* subChunks = m_blastAsset.getPxAsset()->getSubchunks(); + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + uint32_t chunkIndex = chunkIndices[i]; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { +// Add By Lixu Begin + r->setTransform(actor.getPhysXActor().getGlobalPose() * lp * subChunks[chunks[chunkIndex].firstSubchunkIndex].transform); +// Add By Lixu End + } + } +} + +void BlastFamilyModelSimple::onActorDestroyed(const ExtPxActor& actor) +{ + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + uint32_t chunkIndex = chunkIndices[i]; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { + r->setHidden(true); + + m_VisibleChangedChunks[chunkIndex] = false; + } + } +} + +void BlastFamilyModelSimple::onActorHealthUpdate(const ExtPxActor& actor) +{ + TkActor& tkActor = actor.getTkActor(); + const TkAsset* tkAsset = tkActor.getAsset(); + + const float* bondHealths = tkActor.getBondHealths(); + uint32_t nodeCount = tkActor.getGraphNodeCount(); + if (nodeCount == 0) // subsupport chunks don't have graph nodes + return; + + std::vector<uint32_t> nodes(tkActor.getGraphNodeCount()); + tkActor.getGraphNodeIndices(nodes.data(), static_cast<uint32_t>(nodes.size())); + + const NvBlastChunk* chunks = tkAsset->getChunks(); + const NvBlastBond* bonds = tkAsset->getBonds(); + + const NvBlastSupportGraph graph = tkAsset->getGraph(); + + std::vector<float> healthBuffer; + + for (uint32_t node0 : nodes) + { + uint32_t chunkIndex = graph.chunkIndices[node0]; + + if (chunkIndex >= m_chunks.size()) + continue; + + std::vector<SimpleRenderMesh*>& meshes = m_chunks[chunkIndex].renderMeshes; + const auto& renderables = m_chunks[chunkIndex].renderables; + for (uint32_t i = 0; i < meshes.size(); ++i) + { + if(renderables[i]->isHidden()) + continue; + + SimpleRenderMesh* renderMesh = meshes[i]; + + const SimpleMesh* mesh = renderMesh->getMesh(); + healthBuffer.resize(mesh->vertices.size()); + + for (uint32_t vertexIndex = 0; vertexIndex < mesh->vertices.size(); vertexIndex++) + { + PxVec3 position = mesh->vertices[vertexIndex].position; + float health = 0.0f; + float healthDenom = 0.0f; + + for (uint32_t adjacencyIndex = graph.adjacencyPartition[node0]; adjacencyIndex < graph.adjacencyPartition[node0 + 1]; adjacencyIndex++) + { + uint32_t node1 = graph.adjacentNodeIndices[adjacencyIndex]; + uint32_t bondIndex = graph.adjacentBondIndices[adjacencyIndex]; + float bondHealth = PxClamp(bondHealths[bondIndex] / BOND_HEALTH_MAX, 0.0f, 1.0f); + const NvBlastBond& solverBond = bonds[bondIndex]; + const PxVec3& centroid = reinterpret_cast<const PxVec3&>(solverBond.centroid); + + float factor = 1.0f / (centroid - position).magnitudeSquared(); + + health += bondHealth * factor; + healthDenom += factor; + } + + healthBuffer[vertexIndex] = healthDenom > 0.0f ? health / healthDenom : 1.0f; + } + + renderMesh->updateHealths(healthBuffer); + } + } +} + +// Add By Lixu Begin +void BlastFamilyModelSimple::setActorSelected(const ExtPxActor& actor, bool selected) +{ + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + uint32_t chunkIndex = chunkIndices[i]; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { + r->setSelected(selected); + } + } +} + +void BlastFamilyModelSimple::setChunkSelected(uint32_t chunk, bool selected) +{ + if (chunk > m_chunks.size()) + return; + + std::vector<Renderable*>& renderables = m_chunks[chunk].renderables; + for (Renderable* r : renderables) + { + r->setSelected(select); + } +} + +void BlastFamilyModelSimple::setChunkSelected(std::vector<uint32_t> depths, bool selected) +{ + for (size_t i = 0; i < depths.size(); ++i) + { + const std::vector<uint32_t> indexes = m_blastAsset.getChunkIndexesByDepth(depths[i]); + for (size_t j = 0; j < indexes.size(); ++j) + { + setChunkSelected(indexes[j], selected); + } + } +} + +void BlastFamilyModelSimple::clearChunksSelected() +{ + size_t count = m_chunks.size(); + for (size_t chunkIndex = 0; chunkIndex < count; ++chunkIndex) + { + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { + r->setSelected(false); + } + } +} + +bool BlastFamilyModelSimple::getChunkSelected(uint32_t chunk) +{ + if (chunk > m_chunks.size()) + return false; + + std::vector<Renderable*>& renderables = m_chunks[chunk].renderables; + for (Renderable* r : renderables) + { + for (Renderable* r : renderables) + { + if (r->isSelected()) + { + return true; + } + } + } + + return false; +} + +std::vector<uint32_t> BlastFamilyModelSimple::getSelectedChunks() +{ + std::vector<uint32_t> selectedChunks; + size_t count = m_chunks.size(); + for (size_t chunkIndex = 0; chunkIndex < count; ++chunkIndex) + { + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { + if (r->isSelected()) + { + selectedChunks.push_back(chunkIndex); + break; + } + } + } + return selectedChunks; +} + +void BlastFamilyModelSimple::setActorScale(const ExtPxActor& actor, PxMat44& scale, bool replace) +{ + const uint32_t* chunkIndices = actor.getChunkIndices(); + uint32_t chunkCount = actor.getChunkCount(); + for (uint32_t i = 0; i < chunkCount; i++) + { + uint32_t chunkIndex = chunkIndices[i]; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { + r->setMeshScale(scale, replace); + } + } +} + +bool BlastFamilyModelSimple::isChunkVisible(uint32_t chunkIndex) +{ + if (chunkIndex < 0 || chunkIndex >= m_chunks.size()) + { + return false; + } + + bool bVisible = false; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + if (renderables.size() > 0) + { + bVisible = !renderables[0]->isHidden(); + } + return bVisible; +} + +void BlastFamilyModelSimple::setChunkVisible(uint32_t chunkIndex, bool bVisible) +{ + if (chunkIndex < 0 || chunkIndex >= m_chunks.size()) + { + return; + } + + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { + r->setHidden(!bVisible); + } +} + +void BlastFamilyModelSimple::setChunkVisible(std::vector<uint32_t> depths, bool bVisible) +{ + for (size_t i = 0; i < depths.size(); ++i) + { + const std::vector<uint32_t> indexes = m_blastAsset.getChunkIndexesByDepth(depths[i]); + for (size_t j = 0; j < indexes.size(); ++j) + { + setChunkVisible(indexes[j], bVisible); + } + } +} + +void BlastFamilyModelSimple::initTransform(physx::PxTransform t) +{ + int chunkSize = m_chunks.size(); + for (int i = 0; i < chunkSize; i++) + { + std::vector<Renderable*>& renderables = m_chunks[i].renderables; + for (Renderable* r : renderables) + { + r->setTransform(t); + } + } +} + +void BlastFamilyModelSimple::getMaterial(RenderMaterial** ppRenderMaterial, bool externalSurface) +{ + *ppRenderMaterial = nullptr; + + int chunkSize = m_chunks.size(); + if (chunkSize == 0) + { + return; + } + + if (externalSurface) + { + for (int i = 0; i < chunkSize; i++) + { + std::vector<Renderable*>& renderables = m_chunks[i].ex_Renderables; + if (renderables.size() > 0) + { + RenderMaterial& m = renderables[0]->getMaterial(); + *ppRenderMaterial = &m; + return; + } + } + } + else + { + for (int i = 0; i < chunkSize; i++) + { + std::vector<Renderable*>& renderables = m_chunks[i].in_Renderables; + if (renderables.size() > 0) + { + RenderMaterial& m = renderables[0]->getMaterial(); + *ppRenderMaterial = &m; + return; + } + } + } +} + +void BlastFamilyModelSimple::setMaterial(RenderMaterial* pRenderMaterial, bool externalSurface) +{ + RenderMaterial* p = pRenderMaterial; + if (p == nullptr) + { + p = RenderMaterial::getDefaultRenderMaterial(); + } + + int chunkSize = m_chunks.size(); + if (externalSurface) + { + for (int i = 0; i < chunkSize; i++) + { + std::vector<Renderable*>& renderables = m_chunks[i].ex_Renderables; + for (Renderable* r : renderables) + { + r->setMaterial(*p); + } + } + } + else + { + for (int i = 0; i < chunkSize; i++) + { + std::vector<Renderable*>& renderables = m_chunks[i].in_Renderables; + for (Renderable* r : renderables) + { + r->setMaterial(*p); + } + } + } +} +// Add By Lixu End
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSimple.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSimple.h new file mode 100644 index 0000000..ed51133 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSimple.h @@ -0,0 +1,72 @@ +/* +* 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 BLAST_FAMILY_MODEL_SIMPLE_H +#define BLAST_FAMILY_MODEL_SIMPLE_H + +#include "BlastFamily.h" +#include "BlastAssetModelSimple.h" + +class SimpleRenderMesh; +class Renderable; +class Renderer; + +class BlastFamilyModelSimple : public BlastFamily +{ +public: + //////// ctor //////// + + BlastFamilyModelSimple(PhysXController& physXController, ExtPxManager& pxManager, Renderer& renderer, const BlastAssetModelSimple& blastAsset, const BlastAsset::ActorDesc& desc); + virtual ~BlastFamilyModelSimple(); + +// Add By Lixu Begin + virtual void setActorSelected(const ExtPxActor& actor, bool selected); + virtual void clearChunksSelected(); + virtual void setChunkSelected(uint32_t chunk, bool selected); + virtual void setChunkSelected(std::vector<uint32_t> depths, bool selected); + virtual bool getChunkSelected(uint32_t chunk); + virtual std::vector<uint32_t> getSelectedChunks(); + virtual void setActorScale(const ExtPxActor& actor, PxMat44& scale, bool replace); + virtual bool isChunkVisible(uint32_t chunkIndex); + virtual void setChunkVisible(uint32_t chunkIndex, bool bVisible); + virtual void setChunkVisible(std::vector<uint32_t> depths, bool bVisible); + virtual void initTransform(physx::PxTransform t); + virtual void getMaterial(RenderMaterial** ppRenderMaterial, bool externalSurface); + virtual void setMaterial(RenderMaterial* pRenderMaterial, bool externalSurface); +// Add By Lixu End + +protected: + //////// abstract implementation //////// + + virtual void onActorCreated(const ExtPxActor& actor); + virtual void onActorUpdate(const ExtPxActor& actor); + virtual void onActorDestroyed(const ExtPxActor& actor); + virtual void onActorHealthUpdate(const ExtPxActor& pxActor); + +private: + //////// internal data //////// + + Renderer& m_renderer; + + struct Chunk + { + std::vector<SimpleRenderMesh*> renderMeshes; + std::vector<Renderable*> renderables; +// Add By Lixu Begin + std::vector<Renderable*> ex_Renderables; + std::vector<Renderable*> in_Renderables; +// Add By Lixu End + }; + + std::vector<Chunk> m_chunks; +}; + + +#endif //BLAST_FAMILY_MODEL_SIMPLE_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSkinned.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSkinned.cpp new file mode 100644 index 0000000..c0731d5 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSkinned.cpp @@ -0,0 +1,167 @@ +/* +* 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 "BlastFamilyModelSkinned.h" +#include "RenderUtils.h" +#include "Renderer.h" +#include "SkinnedRenderMesh.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastExtPxActor.h" +#include "NvBlastTkActor.h" +#include "PxRigidDynamic.h" + +using namespace physx; + +BlastFamilyModelSkinned::BlastFamilyModelSkinned(PhysXController& physXController, ExtPxManager& pxManager, Renderer& renderer, const BlastAssetModelSkinned& blastAsset, const BlastAsset::ActorDesc& desc) + : BlastFamily(physXController, pxManager, blastAsset), m_renderer(renderer), m_visibleActorsDirty(true) +{ + // materials + auto materials = blastAsset.getRenderMaterials(); + + const BlastModel& model = blastAsset.getModel(); + + // finalize (create) sub model + auto finalizeSubModelFunction = [&](SubModel* subModel, std::vector<const SimpleMesh*>& subModelMeshes, RenderMaterial& renderMaterial) + { + subModel->skinnedRenderMesh = new SkinnedRenderMesh(subModelMeshes); + subModel->renderable = renderer.createRenderable(*subModel->skinnedRenderMesh, renderMaterial); + subModel->renderable->setColor(getRandomPastelColor()); + }; + + // create at least one submodel per every material (if mesh count is too high, more then one sub model per material to be created) + SubModel* subModel = nullptr; + std::vector<const SimpleMesh*> subModelMeshes; + subModelMeshes.reserve(model.chunks.size()); + for (uint32_t materialIndex = 0; materialIndex < model.materials.size(); materialIndex++) + { + for (uint32_t chunkIndex = 0; chunkIndex < model.chunks.size(); chunkIndex++) + { + const BlastModel::Chunk& chunk = model.chunks[chunkIndex]; + for (const BlastModel::Chunk::Mesh& mesh : chunk.meshes) + { + if (mesh.materialIndex == materialIndex) + { + // init new submodel? + if (subModel == nullptr) + { + m_subModels.push_back(SubModel()); + subModel = &m_subModels.back(); + subModel->chunkIdToBoneMap.resize(model.chunks.size()); + std::fill(subModel->chunkIdToBoneMap.begin(), subModel->chunkIdToBoneMap.end(), SubModel::INVALID_BONE_ID); + subModelMeshes.clear(); + } + + // add mesh to map and list + subModel->chunkIdToBoneMap[chunkIndex] = (uint32_t)subModelMeshes.size(); + subModelMeshes.push_back(&(mesh.mesh)); + + // mesh reached limit? + if (subModelMeshes.size() == SkinnedRenderMesh::MeshesCountMax) + { + finalizeSubModelFunction(subModel, subModelMeshes, *materials[materialIndex]); + subModel = nullptr; + } + } + } + } + + // finalize subModel for this material + if (subModel && subModelMeshes.size() > 0) + { + finalizeSubModelFunction(subModel, subModelMeshes, *materials[materialIndex]); + subModel = nullptr; + } + } + + // reserve for scratch + m_visibleBones.reserve(model.chunks.size()); + m_visibleBoneTransforms.reserve(model.chunks.size()); + + // initialize in position + initialize(desc); +} + +BlastFamilyModelSkinned::~BlastFamilyModelSkinned() +{ + for (uint32_t subModelIndex = 0; subModelIndex < m_subModels.size(); subModelIndex++) + { + m_renderer.removeRenderable(m_subModels[subModelIndex].renderable); + SAFE_DELETE(m_subModels[subModelIndex].skinnedRenderMesh); + } +} + +void BlastFamilyModelSkinned::onActorCreated(const ExtPxActor& actor) +{ + m_visibleActors.insert(&actor); + m_visibleActorsDirty = true; +} + +void BlastFamilyModelSkinned::onActorUpdate(const ExtPxActor& actor) +{ +} + +void BlastFamilyModelSkinned::onActorDestroyed(const ExtPxActor& actor) +{ + m_visibleActors.erase(&actor); + m_visibleActorsDirty = true; +} + +void BlastFamilyModelSkinned::onUpdate() +{ + // visible actors changed this frame? + if (m_visibleActorsDirty) + { + for (const SubModel& model : m_subModels) + { + // pass visible chunks list to render mesh + m_visibleBones.clear(); + for (const ExtPxActor* actor : m_visibleActors) + { + const uint32_t* chunkIndices = actor->getChunkIndices(); + uint32_t chunkCount = actor->getChunkCount(); + for (uint32_t i = 0; i < chunkCount; ++i) + { + uint32_t chunkIndex = chunkIndices[i]; + uint32_t boneIndex = model.chunkIdToBoneMap[chunkIndex]; + if (boneIndex != SubModel::INVALID_BONE_ID) + { + m_visibleBones.push_back(boneIndex); + } + } + } + model.skinnedRenderMesh->updateVisibleMeshes(m_visibleBones); + } + + m_visibleActorsDirty = false; + } + + // update and pass chunk transforms + const ExtPxChunk* chunks = m_blastAsset.getPxAsset()->getChunks(); + const ExtPxSubchunk* subChunks = m_blastAsset.getPxAsset()->getSubchunks(); + for (const SubModel& model : m_subModels) + { + m_visibleBoneTransforms.clear(); + for (const ExtPxActor* actor : m_visibleActors) + { + const uint32_t* chunkIndices = actor->getChunkIndices(); + uint32_t chunkCount = actor->getChunkCount(); + for (uint32_t i = 0; i < chunkCount; ++i) + { + uint32_t chunkIndex = chunkIndices[i]; + uint32_t boneIndex = model.chunkIdToBoneMap[chunkIndex]; + if (boneIndex != SubModel::INVALID_BONE_ID) + { + m_visibleBoneTransforms.push_back(PxMat44(actor->getPhysXActor().getGlobalPose() * subChunks[chunks[chunkIndex].firstSubchunkIndex].transform)); + } + } + } + model.skinnedRenderMesh->updateVisibleMeshTransforms(m_visibleBoneTransforms); + } +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSkinned.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSkinned.h new file mode 100644 index 0000000..aeb9353 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFamilyModelSkinned.h @@ -0,0 +1,63 @@ +/* +* 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 BLAST_FAMILY_MODEL_SKINNED_H +#define BLAST_FAMILY_MODEL_SKINNED_H + +#include "BlastFamily.h" +#include "BlastAssetModelSkinned.h" + +class SkinnedRenderMesh; +class Renderable; + +class BlastFamilyModelSkinned : public BlastFamily +{ +public: + //////// ctor //////// + + BlastFamilyModelSkinned(PhysXController& physXController, ExtPxManager& pxManager, Renderer& renderer, const BlastAssetModelSkinned& blastAsset, const BlastAsset::ActorDesc& desc); + virtual ~BlastFamilyModelSkinned(); + +protected: + //////// abstract implementation //////// + + virtual void onActorCreated(const ExtPxActor& actor); + virtual void onActorUpdate(const ExtPxActor& actor); + virtual void onActorDestroyed(const ExtPxActor& actor); + + virtual void onUpdate(); + +private: + //////// internal data //////// + + Renderer& m_renderer; + + struct SubModel + { + static const uint32_t INVALID_BONE_ID = ~(uint32_t)0; + + Renderable* renderable = nullptr; + SkinnedRenderMesh* skinnedRenderMesh = nullptr; + std::vector<uint32_t> chunkIdToBoneMap; + }; + std::vector<SubModel> m_subModels; + + std::set<const ExtPxActor*> m_visibleActors; + bool m_visibleActorsDirty; + + //////// scratch buffers //////// + + std::vector<uint32_t> m_visibleBones; + std::vector<PxMat44> m_visibleBoneTransforms; + +}; + + +#endif //BLAST_FAMILY_MODEL_SKINNED_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFractureTool.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFractureTool.cpp new file mode 100644 index 0000000..aa738b9 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFractureTool.cpp @@ -0,0 +1,171 @@ +/* +* 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 "BlastFractureTool.h" +#include <BlastAssetModel.h> +#include <BlastAsset.h> +#include <NvBlastExtPxAsset.h> +#include <NvBlastTkAsset.h> + +void BlastFractureTool::free() +{ + std::vector<Nv::Blast::Mesh*>::iterator it; + for (it = chunkMeshes.begin(); it != chunkMeshes.end(); it++) + { + delete (*it); + (*it) = nullptr; + } + chunkMeshes.clear(); +} + +void BlastFractureTool::setSourceAsset(const BlastAsset* pBlastAsset) +{ + free(); + + BlastAssetModel* pBlastAssetModel = (BlastAssetModel*)pBlastAsset; + const BlastModel& blastModel = pBlastAssetModel->getModel(); + const std::vector<BlastModel::Chunk>& chunks = blastModel.chunks; + int chunkSize = chunks.size(); + if (chunkSize == 0) + { + return; + } + + chunkMeshes.resize(chunkSize, nullptr); + for (int cs = 0; cs < chunkSize; cs++) + { + const BlastModel::Chunk& chunk = chunks[cs]; + const std::vector<BlastModel::Chunk::Mesh>& meshes = chunk.meshes; + int meshSize = meshes.size(); + + if (meshSize == 0) + { + continue; + } + + std::vector<physx::PxVec3> positions; + std::vector<physx::PxVec3> normals; + std::vector<physx::PxVec2> uv; + std::vector<uint32_t> ind; + std::vector<int> faceBreakPoint; + std::vector<uint32_t> materialIndexes; + uint16_t curIndex = 0; + for (int ms = 0; ms < meshSize; ms++) + { + const BlastModel::Chunk::Mesh& mesh = meshes[ms]; + materialIndexes.push_back(mesh.materialIndex); + const SimpleMesh& simpleMesh = mesh.mesh; + const std::vector<SimpleMesh::Vertex>& vertices = simpleMesh.vertices; + const std::vector<uint16_t>& indices = simpleMesh.indices; + + int NumVertices = vertices.size(); + for (uint32_t i = 0; i < NumVertices; ++i) + { + positions.push_back(physx::PxVec3(vertices[i].position.x, vertices[i].position.y, vertices[i].position.z)); + normals.push_back(physx::PxVec3(vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z)); + uv.push_back(physx::PxVec2(vertices[i].uv.x, vertices[i].uv.y)); + } + int NumIndices = indices.size(); + for (uint32_t i = 0; i < NumIndices; ++i) + { + ind.push_back(indices[i] + curIndex); + } + curIndex += NumIndices; + faceBreakPoint.push_back(NumIndices / 3); + } + + PxVec3* nr = (!normals.empty()) ? normals.data() : 0; + PxVec2* uvp = (!uv.empty()) ? uv.data() : 0; + Nv::Blast::Mesh* pMesh = new Nv::Blast::Mesh( + positions.data(), nr, uvp, static_cast<uint32_t>(positions.size()), + ind.data(), static_cast<uint32_t>(ind.size())); + + int curFaceIndex = 0; + int curFaceBreakPoint = faceBreakPoint[curFaceIndex]; + uint32_t curMaterialIndex = materialIndexes[curFaceIndex]; + for (int fc = 0; fc < pMesh->getFacetCount(); fc++) + { + if (fc >= curFaceBreakPoint) + { + curFaceIndex++; + curFaceBreakPoint += faceBreakPoint[curFaceIndex]; + curMaterialIndex = materialIndexes[curFaceIndex]; + } + + pMesh->getFacet(fc)->userData = curMaterialIndex; + } + + chunkMeshes[cs] = pMesh; + } + + const ExtPxAsset* pExtPxAsset = pBlastAsset->getPxAsset(); + const TkAsset& tkAsset = pExtPxAsset->getTkAsset(); + + std::vector<int32_t> parentIds; + parentIds.resize(chunkSize); + parentIds.assign(chunkSize, -1); + { + const NvBlastChunk* pNvBlastChunk = tkAsset.getChunks(); + for (uint32_t i = 0; i < chunkSize; ++i) + { + parentIds[i] = pNvBlastChunk[i].parentChunkIndex; + } + } + std::vector<bool> isLeafs; + isLeafs.resize(chunkSize); + isLeafs.assign(chunkSize, false); + { + const NvBlastSupportGraph supportGraph = tkAsset.getGraph(); + for (uint32_t i = 0; i < supportGraph.nodeCount; ++i) + { + const uint32_t chunkIndex = supportGraph.chunkIndices[i]; + isLeafs[chunkIndex] = true; + } + } + + setSourceMesh(chunkMeshes[0]); + + mChunkData.resize(chunkSize); + mChunkData[0].parent = parentIds[0]; + mChunkData[0].isLeaf = isLeafs[0]; + mChunkData[0].chunkId = 0; + Nv::Blast::Mesh* mesh = nullptr; + for (int cs = 1; cs < chunkSize; cs++) + { + if (chunkMeshes[cs] == nullptr) + continue; + mChunkData[cs].meshData = new Nv::Blast::Mesh(*chunkMeshes[cs]); + mChunkData[cs].parent = parentIds[cs]; + mChunkData[cs].chunkId = cs; + mChunkData[cs].isLeaf = isLeafs[cs]; + + mesh = mChunkData[cs].meshData; + Nv::Blast::Vertex* verticesBuffer = mesh->getVertices(); + for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i) + { + verticesBuffer[i].p = (verticesBuffer[i].p - mOffset) * (1.0f / mScaleFactor); + } + mesh->getBoundingBox().minimum = (mesh->getBoundingBox().minimum - mOffset) * (1.0f / mScaleFactor); + mesh->getBoundingBox().maximum = (mesh->getBoundingBox().maximum - mOffset) * (1.0f / mScaleFactor); + for (uint32_t i = 0; i < mesh->getFacetCount(); ++i) + { + mesh->getFacet(i)->userData = chunkMeshes[cs]->getFacet(i)->userData; + } + } +} + +Nv::Blast::Mesh* BlastFractureTool::getSourceMesh(int32_t chunkId) +{ + if (chunkId < 0 || chunkId >= chunkMeshes.size()) + { + return nullptr; + } + return chunkMeshes[chunkId]; +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFractureTool.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFractureTool.h new file mode 100644 index 0000000..b50ccf3 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastFractureTool.h @@ -0,0 +1,41 @@ +/* +* 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 BLAST_FRACTURETOOL_H +#define BLAST_FRACTURETOOL_H + +#include "NvBlastExtAuthoringFractureTool.h" + +class BlastAsset; +namespace Nv +{ + namespace Blast + { + class Mesh; + } +} + +class BlastFractureTool : public Nv::Blast::FractureTool +{ +public: + BlastFractureTool(NvBlastLog logCallback = nullptr) : FractureTool(logCallback) {} + ~BlastFractureTool() { free(); } + + void setSourceAsset(const BlastAsset* pBlastAsset); + + Nv::Blast::Mesh* getSourceMesh(int32_t chunkId); + +private: + void free(); + + std::vector<Nv::Blast::Mesh*> chunkMeshes; +}; + +#endif //BLAST_FRACTURETOOL_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastModel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastModel.cpp new file mode 100644 index 0000000..d231a6c --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastModel.cpp @@ -0,0 +1,167 @@ +/* +* 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 "BlastModel.h" + +// Add By Lixu Begin +//#define TINYOBJLOADER_IMPLEMENTATION +// Add By Lixu End +#include "tiny_obj_loader.h" + + +using namespace physx; + +BlastModelPtr BlastModel::loadFromFileTinyLoader(const char* path) +{ +// Add By Lixu Begin + BlastModel* model = new BlastModel(); +// Add By Lixu End + + std::vector<tinyobj::shape_t> shapes; + std::vector<tinyobj::material_t> mats; + std::string err; + std::string mtlPath; + for (size_t i = strnlen(path, 255) - 1; i >= 0; --i) + { + if (path[i] == '\\') + { + mtlPath.resize(i + 2, 0); + strncpy(&mtlPath[0], path, i + 1); + break; + } + } + + + bool ret = tinyobj::LoadObj(shapes, mats, err, path, mtlPath.data()); + + // can't load? + if (!ret) + return false; + + // one submodel per material + uint32_t materialsCount = (uint32_t)mats.size(); + model->materials.resize(materialsCount); + + // fill submodel materials + for (uint32_t i = 0; i < materialsCount; i++) + { + tinyobj::material_t *pMaterial = &mats[i]; + + if (!pMaterial->diffuse_texname.empty()) + { +// Add By Lixu Begin + model->materials[i].name = pMaterial->name; +// Add By Lixu End + model->materials[i].diffuseTexture = pMaterial->diffuse_texname; + } + } + + // estimate + model->chunks.reserve(shapes.size() / materialsCount + 1); + + if (shapes.size() > 0) + { + uint32_t meshIndex = 0; + for (uint32_t m = 0; m < shapes.size(); m++) + { + tinyobj::shape_t& pMesh = shapes[m]; + uint32_t materialIndex; + uint32_t chunkIndex; + sscanf(pMesh.name.data(), "%d_%d", &chunkIndex, &materialIndex); + if (model->chunks.size() <= chunkIndex) + { + model->chunks.resize(chunkIndex + 1); + } + model->chunks[chunkIndex].meshes.push_back(Chunk::Mesh()); + Chunk::Mesh& mesh = model->chunks[chunkIndex].meshes.back(); + + mesh.materialIndex = materialIndex; + SimpleMesh& chunkMesh = mesh.mesh; + + PxVec3 emin(FLT_MAX, FLT_MAX, FLT_MAX); + PxVec3 emax(FLT_MIN, FLT_MIN, FLT_MIN); + + + + // create an index buffer + chunkMesh.indices.resize(pMesh.mesh.indices.size()); + + // Check if all faces are triangles + bool allTriangles = true; + for (uint32_t i = 0; i < pMesh.mesh.num_vertices.size(); ++i) + { + if (pMesh.mesh.num_vertices[i] != 3) + { + allTriangles = false; + break; + } + } + + if (pMesh.mesh.indices.size() > 0 && allTriangles) + { + for (uint32_t i = 0; i < pMesh.mesh.indices.size(); i += 3) + { + chunkMesh.indices[i] = (uint16_t)pMesh.mesh.indices[i + 2]; + chunkMesh.indices[i + 1] = (uint16_t)pMesh.mesh.indices[i + 1]; + chunkMesh.indices[i + 2] = (uint16_t)pMesh.mesh.indices[i]; + } + } + // create vertex buffer + chunkMesh.vertices.resize(pMesh.mesh.positions.size() / 3); + // copy positions + uint32_t indexer = 0; + for (uint32_t i = 0; i < pMesh.mesh.positions.size() / 3; i++) + { + chunkMesh.vertices[i].position.x = pMesh.mesh.positions[indexer]; + chunkMesh.vertices[i].position.y = pMesh.mesh.positions[indexer + 1]; + chunkMesh.vertices[i].position.z = pMesh.mesh.positions[indexer + 2]; + indexer += 3; + // calc min/max + emin = emin.minimum(chunkMesh.vertices[i].position); + emax = emax.maximum(chunkMesh.vertices[i].position); + } + + // copy normals + if (pMesh.mesh.normals.size() > 0) + { + indexer = 0; + for (uint32_t i = 0; i < pMesh.mesh.normals.size() / 3; i++) + { + chunkMesh.vertices[i].normal.x = pMesh.mesh.normals[indexer]; + chunkMesh.vertices[i].normal.y = pMesh.mesh.normals[indexer + 1]; + chunkMesh.vertices[i].normal.z = pMesh.mesh.normals[indexer + 2]; + + indexer += 3; + } + } + + // copy uv + if (pMesh.mesh.texcoords.size() > 0) + { + indexer = 0; + for (uint32_t i = 0; i < pMesh.mesh.texcoords.size() / 2; i++) + { + chunkMesh.vertices[i].uv.x = pMesh.mesh.texcoords[indexer]; + chunkMesh.vertices[i].uv.y = pMesh.mesh.texcoords[indexer + 1]; + indexer += 2; + } + } + + // assign extents + chunkMesh.extents = (emax - emin) * 0.5f; + + // get the center + chunkMesh.center = emin + chunkMesh.extents; + + } + } + + return model; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastModel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastModel.h new file mode 100644 index 0000000..683a343 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastModel.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2016-2017, 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 BLAST_MODEL_H +#define BLAST_MODEL_H + +#include "Mesh.h" +#include <vector> +#include <memory> + + +class BlastModel; +// Add By Lixu Begin +typedef BlastModel* BlastModelPtr; +// Add By Lixu End + +/** +BlastModel struct represents graphic model. +Now only loading from .obj file is supported. +Can have >=0 materials +Every chunk can have multiple meshes (1 for every material) +*/ +class BlastModel +{ +public: + struct Material + { +// Add By Lixu Begin + std::string name; +// Add By Lixu End + std::string diffuseTexture; + }; + + struct Chunk + { + struct Mesh + { + uint32_t materialIndex; + SimpleMesh mesh; + }; + + std::vector<Mesh> meshes; + }; + + std::vector<Material> materials; + std::vector<Chunk> chunks; + + static BlastModelPtr loadFromFileTinyLoader(const char* path); +private: + BlastModel() {} +}; + +#endif // ifndef BLAST_MODEL_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastReplay.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastReplay.cpp new file mode 100644 index 0000000..13d2b33 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastReplay.cpp @@ -0,0 +1,160 @@ +/* +* 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 "BlastReplay.h" +#include "NvBlastTk.h" +#include "NvBlastExtPxManager.h" +#include "NvBlastExtPxFamily.h" +#include "SampleProfiler.h" + + +using namespace std::chrono; + +BlastReplay::BlastReplay() : m_sync(nullptr) +{ + m_sync = ExtSync::create(); + reset(); +} + +BlastReplay::~BlastReplay() +{ + m_sync->release(); + clearBuffer(); +} + +void BlastReplay::addFamily(TkFamily* family) +{ + family->addListener(*m_sync); +} + +void BlastReplay::removeFamily(TkFamily* family) +{ + family->removeListener(*m_sync); +} + +void BlastReplay::startRecording(ExtPxManager& manager, bool syncFamily, bool syncPhysics) +{ + if (isRecording()) + return; + + m_sync->releaseSyncBuffer(); + + if (syncFamily || syncPhysics) + { + std::vector<ExtPxFamily*> families(manager.getFamilyCount()); + manager.getFamilies(families.data(), (uint32_t)families.size()); + for (ExtPxFamily* family : families) + { + if (syncPhysics) + { + m_sync->syncFamily(*family); + } + else if (syncFamily) + { + m_sync->syncFamily(family->getTkFamily()); + } + } + } + + m_isRecording = true; +} + +void BlastReplay::stopRecording() +{ + if (!isRecording()) + return; + + const ExtSyncEvent*const* buffer; + uint32_t size; + m_sync->acquireSyncBuffer(buffer, size); + + clearBuffer(); + m_buffer.resize(size); + for (uint32_t i = 0; i < size; ++i) + { + m_buffer[i] = buffer[i]->clone(); + } + + // TODO: sort by ts ? make sure? + //m_buffer.sort + + m_sync->releaseSyncBuffer(); + + m_isRecording = false; +} + +void BlastReplay::startPlayback(ExtPxManager& manager, TkGroup* group) +{ + if (isPlaying() || !hasRecord()) + return; + + m_isPlaying = true; + m_startTime = steady_clock::now(); + m_nextEventIndex = 0; + m_firstEventTs = m_buffer[0]->timestamp; + m_pxManager = &manager; + m_group = group; +} + +void BlastReplay::stopPlayback() +{ + if (!isPlaying()) + return; + + m_isPlaying = false; + m_pxManager = nullptr; + m_group = nullptr; +} + +void BlastReplay::update() +{ + if (isPlaying()) + { + PROFILER_SCOPED_FUNCTION(); + + auto now = steady_clock::now(); + auto mil = duration_cast<milliseconds>((now - m_startTime)); + bool stop = true; + while (m_nextEventIndex < m_buffer.size()) + { + const ExtSyncEvent* e = m_buffer[m_nextEventIndex]; + auto t = e->timestamp - m_firstEventTs; + if (t < (uint64_t)mil.count()) + { + m_sync->applySyncBuffer(m_pxManager->getFramework(), &e, 1, m_group, m_pxManager); + m_nextEventIndex++; + } + else + { + stop = false; + break; + } + } + + if (stop) + stopPlayback(); + } +} + +void BlastReplay::reset() +{ + m_isPlaying = false; + m_isRecording = false; + m_sync->releaseSyncBuffer(); +} + +void BlastReplay::clearBuffer() +{ + for (auto e : m_buffer) + { + e->release(); + } + m_buffer.clear(); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastReplay.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastReplay.h new file mode 100644 index 0000000..a85c996 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/blast/BlastReplay.h @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2016-2017, 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 BLAST_REPLAY_H +#define BLAST_REPLAY_H + +#include "NvBlastExtSync.h" +#include <chrono> + +using namespace Nv::Blast; + +class BlastReplay +{ +public: + BlastReplay(); + ~BlastReplay(); + + bool isRecording() const + { + return m_isRecording; + } + + bool isPlaying() const + { + return m_isPlaying; + } + + bool hasRecord() const + { + return m_buffer.size() > 0; + } + + size_t getEventCount() const + { + return isRecording() ? m_sync->getSyncBufferSize() : m_buffer.size(); + } + + uint32_t getCurrentEventIndex() const + { + return m_nextEventIndex; + } + + void addFamily(TkFamily* family); + void removeFamily(TkFamily* family); + + void startRecording(ExtPxManager& manager, bool syncFamily, bool syncPhysics); + void stopRecording(); + void startPlayback(ExtPxManager& manager, TkGroup* group); + void stopPlayback(); + void update(); + void reset(); + +private: + void clearBuffer(); + + ExtPxManager* m_pxManager; + TkGroup* m_group; + std::chrono::steady_clock::time_point m_startTime; + uint64_t m_firstEventTs; + uint32_t m_nextEventIndex; + bool m_isRecording; + bool m_isPlaying; + ExtSync* m_sync; + std::vector<ExtSyncEvent*> m_buffer; +}; + + +#endif // ifndef BLAST_REPLAY_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/Application.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/Application.cpp new file mode 100644 index 0000000..955d841 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/Application.cpp @@ -0,0 +1,66 @@ +/* +* 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 "Application.h" +#include <DirectXMath.h> +#include "XInput.h" +#include "DXUTMisc.h" + + +Application::Application(DeviceManager* pDeviceManager) +{ + m_deviceManager = pDeviceManager; +} + +void Application::addControllerToFront(IApplicationController* controller) +{ + m_controllers.push_back(controller); + m_deviceManager->AddControllerToFront(controller); +} + +int Application::init() +{ + // FirstPersonCamera uses this timer, without it it will be FPS-dependent + DXUTGetGlobalTimer()->Start(); + + m_deviceManager->DeviceCreated(); + m_deviceManager->BackBufferResized(); + + for (auto it = m_controllers.begin(); it != m_controllers.end(); it++) + (*it)->onInitialize(); + + for (auto it = m_controllers.begin(); it != m_controllers.end(); it++) + (*it)->onSampleStart(); + + m_deviceManager->SetVsyncEnabled(false); + + return 0; +} + +int Application::run() +{ + m_deviceManager->MessageLoop(); + + return 0; +} + +int Application::free() +{ + for (auto it = m_controllers.rbegin(); it != m_controllers.rend(); it++) + (*it)->onSampleStop(); + + for (auto it = m_controllers.rbegin(); it != m_controllers.rend(); it++) + (*it)->onTerminate(); + + //m_deviceManager->Shutdown(); // destructor will call this function + delete m_deviceManager; + + return 0; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/Application.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/Application.h new file mode 100644 index 0000000..f0e0601 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/Application.h @@ -0,0 +1,57 @@ +/* +* 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 APPLICATION_H +#define APPLICATION_H + +#include <DeviceManager.h> +#include <vector> +#include <string> + +/** +ISampleController adds more onstart and onstop callbacks to IVisualController +*/ +class IApplicationController : public IVisualController +{ + public: + virtual void onInitialize() {} + virtual void onSampleStart() {} + virtual void onSampleStop() {} + virtual void onTerminate() {} +}; + + +/** +Main manager which runs sample. +You have to add controllers to it which will receive all the start, animate, render etc. callbacks. +*/ +class Application +{ +public: + Application(DeviceManager* pDeviceManager); + void addControllerToFront(IApplicationController* controller); + + const std::vector<IApplicationController*>& getControllers() const + { + return m_controllers; + } + + int init(); + int run(); + int free(); + +private: + DeviceManager* m_deviceManager; + std::vector<IApplicationController*> m_controllers; +// std::wstring m_sampleName; +}; + + +#endif //APPLICATION_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/DeviceManager.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/DeviceManager.cpp new file mode 100644 index 0000000..b29fb86 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/DeviceManager.cpp @@ -0,0 +1,801 @@ +// TAGRELEASE: PUBLIC + +#include "DeviceManager.h" +#include <WinUser.h> +#include <Windows.h> +#include <assert.h> +#include <sstream> +#include <algorithm> +#include <vector> + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } +#endif + +#undef min +#undef max + +namespace +{ + bool IsNvDeviceID(UINT id) + { + return id == 0x10DE; + } + + // Find an adapter whose name contains the given string. + IDXGIAdapter* FindAdapter(const WCHAR* targetName, bool& isNv) + { + IDXGIAdapter* targetAdapter = NULL; + IDXGIFactory* IDXGIFactory_0001 = NULL; + HRESULT hres = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&IDXGIFactory_0001); + if (hres != S_OK) + { + printf("ERROR in CreateDXGIFactory, %s@%d.\nFor more info, get log from debug D3D runtime: (1) Install DX SDK, and enable Debug D3D from DX Control Panel Utility. (2) Install and start DbgView. (3) Try running the program again.\n",__FILE__,__LINE__); + return targetAdapter; + } + + // changed by Junma Lixu + std::vector<IDXGIAdapter*> adapters; + // check current adapter first. EnumAdapters could fail on some device + IDXGIAdapter* pAdapter = nullptr; + ID3D11Device* pD3dDevice = nullptr; + ID3D11DeviceContext* pD3dDeviceContext = nullptr; + DWORD createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG; + D3D_FEATURE_LEVEL fl; + // This following code is the robust way to get all possible feature levels while handling DirectX 11.0 systems: + // please read https://blogs.msdn.microsoft.com/chuckw/2014/02/05/anatomy-of-direct3d-11-create-device/ + D3D_FEATURE_LEVEL lvl[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 }; + HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, + createDeviceFlags, lvl, _countof(lvl), + D3D11_SDK_VERSION, &pD3dDevice, &fl, &pD3dDeviceContext); + if (pD3dDevice) + { + IDXGIDevice* dxgiDevice = nullptr; + hr = pD3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice)); + if (SUCCEEDED(hr)) + { + hr = dxgiDevice->GetAdapter(&pAdapter); + if (pAdapter) + { + adapters.push_back(pAdapter); + } + SAFE_RELEASE(dxgiDevice); + } + SAFE_RELEASE(pD3dDeviceContext); + SAFE_RELEASE(pD3dDevice); + } + + // Enum Adapters + unsigned int adapterNo = 0; + while (SUCCEEDED(hres = IDXGIFactory_0001->EnumAdapters(adapterNo, (IDXGIAdapter**)&pAdapter))) + { + adapters.push_back(pAdapter); + adapterNo++; + } + if (wcslen(targetName) != 0) + { + // find the adapter with specified name + for (int i = 0; i < adapters.size(); ++i) + { + IDXGIAdapter* pAdapter = adapters[i]; + DXGI_ADAPTER_DESC aDesc; + pAdapter->GetDesc(&aDesc); + std::wstring aName = aDesc.Description; + if (aName.find(targetName) != std::string::npos) + { + targetAdapter = pAdapter; + isNv = IsNvDeviceID(aDesc.VendorId); + } + } + } + else + { + // no name specified, find one NV adapter + for (int i = 0; i < adapters.size(); ++i) + { + IDXGIAdapter* pAdapter = adapters[i]; + DXGI_ADAPTER_DESC aDesc; + pAdapter->GetDesc(&aDesc); + std::wstring aName = aDesc.Description; + if (IsNvDeviceID(aDesc.VendorId)) + { + targetAdapter = pAdapter; + isNv = true; + } + } + } + if (targetAdapter == nullptr) + targetAdapter = adapters[0]; + for (int i = 0; i < adapters.size(); ++i) + { + IDXGIAdapter* pAdapter = adapters[i]; + if (pAdapter != targetAdapter) + { + pAdapter->Release(); + } + } + + if (IDXGIFactory_0001) + IDXGIFactory_0001->Release(); + + return targetAdapter; + } + + // Adjust window rect so that it is centred on the given adapter. Clamps to fit if it's too big. + RECT MoveWindowOntoAdapter(IDXGIAdapter* targetAdapter, const RECT& rect) + { + assert(targetAdapter != NULL); + + RECT result = rect; + HRESULT hres = S_OK; + unsigned int outputNo = 0; + while (SUCCEEDED(hres)) + { + IDXGIOutput* pOutput = NULL; + hres = targetAdapter->EnumOutputs(outputNo++, &pOutput); + + if (SUCCEEDED(hres) && pOutput) + { + DXGI_OUTPUT_DESC OutputDesc; + pOutput->GetDesc( &OutputDesc ); + const RECT desktop = OutputDesc.DesktopCoordinates; + const int centreX = (int) desktop.left + (int)(desktop.right - desktop.left) / 2; + const int centreY = (int) desktop.top + (int)(desktop.bottom - desktop.top) / 2; + const int winW = rect.right - rect.left; + const int winH = rect.bottom - rect.top; + int left = centreX - winW/2; + int right = left + winW; + int top = centreY - winH/2; + int bottom = top + winH; + result.left = std::max(left, (int) desktop.left); + result.right = std::min(right, (int) desktop.right); + result.bottom = std::min(bottom, (int) desktop.bottom); + result.top = std::max(top, (int) desktop.top); + pOutput->Release(); + + // If there is more than one output, go with the first found. Multi-monitor support could go here. + break; + } + } + return result; + } +} + +HRESULT +DeviceManager::CreateWindowDeviceAndSwapChain(const DeviceCreationParameters& params) +{ + IDXGIAdapter* targetAdapter = FindAdapter(params.adapterNameSubstring, m_IsNvidia); + if (targetAdapter) + { + RECT rect = { 0, 0, params.backBufferWidth, params.backBufferHeight }; + rect = MoveWindowOntoAdapter(targetAdapter, rect); + } + else + { + return E_FAIL; + } + + HRESULT hr = E_FAIL; + + m_hWnd = params.hWnd; + + RECT clientRect; + GetClientRect(m_hWnd, &clientRect); + UINT width = clientRect.right - clientRect.left; + UINT height = clientRect.bottom - clientRect.top; + + ZeroMemory(&m_SwapChainDesc, sizeof(m_SwapChainDesc)); + m_SwapChainDesc.BufferCount = params.swapChainBufferCount; + m_SwapChainDesc.BufferDesc.Width = width; + m_SwapChainDesc.BufferDesc.Height = height; + m_SwapChainDesc.BufferDesc.Format = params.swapChainFormat; + m_SwapChainDesc.BufferDesc.RefreshRate.Numerator = params.refreshRate; + m_SwapChainDesc.BufferDesc.RefreshRate.Denominator = 0; + m_SwapChainDesc.BufferUsage = params.swapChainUsage; + m_SwapChainDesc.OutputWindow = m_hWnd; + m_SwapChainDesc.SampleDesc.Count = params.swapChainSampleCount; + m_SwapChainDesc.SampleDesc.Quality = params.swapChainSampleQuality; + m_SwapChainDesc.Windowed = !params.startFullscreen; + m_SwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + + // The D3D documentation says that if adapter is non-null, driver type must be unknown. Why not put + // this logic in the CreateDevice fns then?!? + const D3D_DRIVER_TYPE dType = (targetAdapter)? D3D_DRIVER_TYPE_UNKNOWN: params.driverType; + + hr = D3D11CreateDeviceAndSwapChain( + targetAdapter, // pAdapter + dType, // DriverType + NULL, // Software + params.createDeviceFlags, // Flags + ¶ms.featureLevel, // pFeatureLevels + 1, // FeatureLevels + D3D11_SDK_VERSION, // SDKVersion + &m_SwapChainDesc, // pSwapChainDesc + &m_SwapChain, // ppSwapChain + &m_Device, // ppDevice + NULL, // pFeatureLevel + &m_ImmediateContext // ppImmediateContext + ); + + if (targetAdapter) + targetAdapter->Release(); + + if(FAILED(hr)) + return hr; + + m_DepthStencilDesc.ArraySize = 1; + m_DepthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + m_DepthStencilDesc.CPUAccessFlags = 0; + m_DepthStencilDesc.Format = params.depthStencilFormat; + m_DepthStencilDesc.Width = width; + m_DepthStencilDesc.Height = height; + m_DepthStencilDesc.MipLevels = 1; + m_DepthStencilDesc.MiscFlags = 0; + m_DepthStencilDesc.SampleDesc.Count = params.swapChainSampleCount; + m_DepthStencilDesc.SampleDesc.Quality = 0; + m_DepthStencilDesc.Usage = D3D11_USAGE_DEFAULT; + + hr = CreateRenderTargetAndDepthStencil(); + + return hr; +} + +void +DeviceManager::Shutdown() +{ + if(m_SwapChain && GetWindowState() == kWindowFullscreen) + m_SwapChain->SetFullscreenState(false, NULL); + + DeviceDestroyed(); + + // changed by Junma Lixu + //SAFE_RELEASE(m_BackBufferRTV); + //SAFE_RELEASE(m_DepthStencilDSV); + //SAFE_RELEASE(m_DepthStencilBuffer); + +// g_DeviceManagerInstance = NULL; + + // changed by Junma Lixu + //SAFE_RELEASE(m_ImmediateContext); + //SAFE_RELEASE(m_SwapChain); + +#if defined(DEBUG) || defined(_DEBUG) + ID3D11Debug * d3dDebug = nullptr; + if (nullptr != m_Device) + { + ID3D11DeviceContext* pCtx; + m_Device->GetImmediateContext(&pCtx); + pCtx->ClearState(); + pCtx->Flush(); + pCtx->Release(); + if (SUCCEEDED(m_Device->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void**>(&d3dDebug)))) + { + d3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL); + d3dDebug->Release(); + } + } +#endif + + // changed by Junma Lixu + //SAFE_RELEASE(m_Device); + + if(m_hWnd) + { + DestroyWindow(m_hWnd); + m_hWnd = NULL; + } +} + +HRESULT +DeviceManager::CreateRenderTargetAndDepthStencil() +{ + HRESULT hr; + + ID3D11Texture2D *backBuffer = NULL; + hr = m_SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBuffer); + if (FAILED(hr)) + return hr; + + hr = m_Device->CreateRenderTargetView(backBuffer, NULL, &m_BackBufferRTV); + backBuffer->Release(); + if (FAILED(hr)) + return hr; + + if(m_DepthStencilDesc.Format != DXGI_FORMAT_UNKNOWN) + { + hr = m_Device->CreateTexture2D(&m_DepthStencilDesc, NULL, &m_DepthStencilBuffer); + if (FAILED(hr)) + return hr; + + hr = m_Device->CreateDepthStencilView(m_DepthStencilBuffer, NULL, &m_DepthStencilDSV); + if (FAILED(hr)) + return hr; + } + + return S_OK; +} + +#include "SimpleScene.h" +#include "RenderInterface.h" + +void +DeviceManager::MessageLoop() +{ + LARGE_INTEGER newTime; + QueryPerformanceCounter(&newTime); + + double elapsedSeconds = (m_FixedFrameInterval >= 0) + ? m_FixedFrameInterval + : (double)(newTime.QuadPart - previousTime.QuadPart) / (double)perfFreq.QuadPart; + + if (m_SwapChain && GetWindowState() != kWindowMinimized) + { + Animate(elapsedSeconds); + // changed by Junma Lixu + CoreLib* pCore = CoreLib::Inst(); + RenderInterface::SwitchToDX11(); + pCore->SimpleScene_Draw_DX11(); + Render(); + RenderInterface::FlushDX11(); + RenderInterface::PresentRenderWindow(); + //m_SwapChain->Present(m_SyncInterval, 0); + Sleep(0); + } + else + { + // Release CPU resources when idle + Sleep(1); + } + + { + m_vFrameTimes.push_back(elapsedSeconds); + double timeSum = 0; + for (auto it = m_vFrameTimes.begin(); it != m_vFrameTimes.end(); it++) + timeSum += *it; + + if (timeSum > m_AverageTimeUpdateInterval) + { + m_AverageFrameTime = timeSum / (double)m_vFrameTimes.size(); + m_vFrameTimes.clear(); + } + } + + previousTime = newTime; +} + +LRESULT +DeviceManager::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DESTROY: + case WM_CLOSE: + PostQuitMessage(0); + return 0; + + case WM_SYSKEYDOWN: + if(wParam == VK_F4) + { + PostQuitMessage(0); + return 0; + } + break; + + case WM_ENTERSIZEMOVE: + m_InSizingModalLoop = true; + m_NewWindowSize.cx = m_SwapChainDesc.BufferDesc.Width; + m_NewWindowSize.cy = m_SwapChainDesc.BufferDesc.Height; + break; + + case WM_EXITSIZEMOVE: + m_InSizingModalLoop = false; + ResizeSwapChain(); + break; + + case WM_SIZE: + // Ignore the WM_SIZE event if there is no device, + // or if the window has been minimized (size == 0), + // or if it has been restored to the previous size (this part is tested inside ResizeSwapChain) + if (m_Device && (lParam != 0)) + { + m_NewWindowSize.cx = LOWORD(lParam); + m_NewWindowSize.cy = HIWORD(lParam); + + if(!m_InSizingModalLoop) + ResizeSwapChain(); + } + } + + if( uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST ) + { + // processing messages front-to-back + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + if((*it)->IsEnabled()) + { + // for kb/mouse messages, 0 means the message has been handled + if(0 == (*it)->MsgProc(hWnd, uMsg, wParam, lParam)) + return 0; + } + } + } + + if (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST) + { + return 0; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +void +DeviceManager::ResizeSwapChain() +{ + // changed by Junma Lixu + RenderPlugin* pPlugin = RenderPlugin::Instance(); + D3DHandles handles; + SetWindowDeviceAndSwapChain(pPlugin->GetDeviceHandles(handles)); + BackBufferResized(); + return; + + if (m_NewWindowSize.cx == (LONG)m_SwapChainDesc.BufferDesc.Width && + m_NewWindowSize.cy == (LONG)m_SwapChainDesc.BufferDesc.Height) + return; + + m_SwapChainDesc.BufferDesc.Width = m_NewWindowSize.cx; + m_SwapChainDesc.BufferDesc.Height = m_NewWindowSize.cy; + + ID3D11RenderTargetView *nullRTV = NULL; + m_ImmediateContext->OMSetRenderTargets(1, &nullRTV, NULL); + SAFE_RELEASE(m_BackBufferRTV); + SAFE_RELEASE(m_DepthStencilDSV); + SAFE_RELEASE(m_DepthStencilBuffer); + + if (m_SwapChain) + { + // Resize the swap chain + m_SwapChain->ResizeBuffers(m_SwapChainDesc.BufferCount, m_SwapChainDesc.BufferDesc.Width, + m_SwapChainDesc.BufferDesc.Height, m_SwapChainDesc.BufferDesc.Format, + m_SwapChainDesc.Flags); + + m_DepthStencilDesc.Width = m_NewWindowSize.cx; + m_DepthStencilDesc.Height = m_NewWindowSize.cy; + + CreateRenderTargetAndDepthStencil(); + + BackBufferResized(); + } +} + +void +DeviceManager::Render() +{ + D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (float)m_SwapChainDesc.BufferDesc.Width, (float)m_SwapChainDesc.BufferDesc.Height, 0.0f, 1.0f }; + + // rendering back-to-front + for(auto it = m_vControllers.rbegin(); it != m_vControllers.rend(); it++) + { + if((*it)->IsEnabled()) + { + m_ImmediateContext->OMSetRenderTargets(1, &m_BackBufferRTV, m_DepthStencilDSV); + m_ImmediateContext->RSSetViewports(1, &viewport); + + (*it)->Render(m_Device, m_ImmediateContext, m_BackBufferRTV, m_DepthStencilDSV); + } + } + + m_ImmediateContext->OMSetRenderTargets(0, NULL, NULL); +} + +void +DeviceManager::Animate(double fElapsedTimeSeconds) +{ + // front-to-back, but the order shouldn't matter + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + if((*it)->IsEnabled()) + { + (*it)->Animate(fElapsedTimeSeconds); + } + } +} + +void +DeviceManager::DeviceCreated() +{ + // creating resources front-to-back + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + (*it)->DeviceCreated(m_Device); + } +} + +void +DeviceManager::DeviceDestroyed() +{ + // releasing resources back-to-front + for(auto it = m_vControllers.rbegin(); it != m_vControllers.rend(); it++) + { + (*it)->DeviceDestroyed(); + } +} + +void +DeviceManager::BackBufferResized() +{ + if(m_SwapChain == NULL) + return; + + DXGI_SURFACE_DESC backSD; + backSD.Format = m_SwapChainDesc.BufferDesc.Format; + backSD.Width = m_SwapChainDesc.BufferDesc.Width; + backSD.Height = m_SwapChainDesc.BufferDesc.Height; + backSD.SampleDesc = m_SwapChainDesc.SampleDesc; + + for(auto it = m_vControllers.begin(); it != m_vControllers.end(); it++) + { + (*it)->BackBufferResized(m_Device, &backSD); + } +} + +HRESULT +DeviceManager::ChangeBackBufferFormat(DXGI_FORMAT format, UINT sampleCount) +{ + HRESULT hr = E_FAIL; + + if((format == DXGI_FORMAT_UNKNOWN || format == m_SwapChainDesc.BufferDesc.Format) && + (sampleCount == 0 || sampleCount == m_SwapChainDesc.SampleDesc.Count)) + return S_FALSE; + + if(m_Device) + { + bool fullscreen = (GetWindowState() == kWindowFullscreen); + if(fullscreen) + m_SwapChain->SetFullscreenState(false, NULL); + + IDXGISwapChain* newSwapChain = NULL; + DXGI_SWAP_CHAIN_DESC newSwapChainDesc = m_SwapChainDesc; + + if(format != DXGI_FORMAT_UNKNOWN) + newSwapChainDesc.BufferDesc.Format = format; + if(sampleCount != 0) + newSwapChainDesc.SampleDesc.Count = sampleCount; + + IDXGIAdapter* pDXGIAdapter = GetDXGIAdapter(); + + IDXGIFactory* pDXGIFactory = NULL; + pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&pDXGIFactory)); + + hr = pDXGIFactory->CreateSwapChain(m_Device, &newSwapChainDesc, &newSwapChain); + + pDXGIFactory->Release(); + pDXGIAdapter->Release(); + + if (FAILED(hr)) + { + if(fullscreen) + m_SwapChain->SetFullscreenState(true, NULL); + + return hr; + } + + SAFE_RELEASE(m_BackBufferRTV); + SAFE_RELEASE(m_SwapChain); + SAFE_RELEASE(m_DepthStencilBuffer); + SAFE_RELEASE(m_DepthStencilDSV); + + m_SwapChain = newSwapChain; + m_SwapChainDesc = newSwapChainDesc; + + m_DepthStencilDesc.SampleDesc.Count = sampleCount; + + if(fullscreen) + m_SwapChain->SetFullscreenState(true, NULL); + + CreateRenderTargetAndDepthStencil(); + BackBufferResized(); + } + + return S_OK; +} + +void +DeviceManager::AddControllerToFront(IVisualController* pController) +{ + m_vControllers.remove(pController); + m_vControllers.push_front(pController); +} + +void +DeviceManager::AddControllerToBack(IVisualController* pController) +{ + m_vControllers.remove(pController); + m_vControllers.push_back(pController); +} + +void +DeviceManager::RemoveController(IVisualController* pController) +{ + m_vControllers.remove(pController); +} + +HRESULT +DeviceManager::ResizeWindow(int width, int height) +{ + if(m_SwapChain == NULL) + return E_FAIL; + + RECT rect; + GetWindowRect(m_hWnd, &rect); + + ShowWindow(m_hWnd, SW_RESTORE); + + if(!MoveWindow(m_hWnd, rect.left, rect.top, width, height, true)) + return E_FAIL; + + // No need to call m_SwapChain->ResizeBackBuffer because MoveWindow will send WM_SIZE, which calls that function. + + return S_OK; +} + +#define WINDOW_STYLE_NORMAL (WS_OVERLAPPEDWINDOW | WS_VISIBLE) +#define WINDOW_STYLE_FULLSCREEN (WS_POPUP | WS_SYSMENU | WS_VISIBLE) + +HRESULT +DeviceManager::EnterFullscreenMode(int width, int height) +{ + if(m_SwapChain == NULL) + return E_FAIL; + + if(GetWindowState() == kWindowFullscreen) + return S_FALSE; + + if(width <= 0 || height <= 0) + { + width = m_SwapChainDesc.BufferDesc.Width; + height = m_SwapChainDesc.BufferDesc.Height; + } + + SetWindowLong(m_hWnd, GWL_STYLE, WINDOW_STYLE_FULLSCREEN); + MoveWindow(m_hWnd, 0, 0, width, height, true); + + HRESULT hr = m_SwapChain->SetFullscreenState(true, NULL); + + if(FAILED(hr)) + { + SetWindowLong(m_hWnd, GWL_STYLE, WINDOW_STYLE_NORMAL); + return hr; + } + + UpdateWindow(m_hWnd); + m_SwapChain->GetDesc(&m_SwapChainDesc); + + return S_OK; +} + +HRESULT +DeviceManager::LeaveFullscreenMode(int windowWidth, int windowHeight) +{ + if(m_SwapChain == NULL) + return E_FAIL; + + if(GetWindowState() != kWindowFullscreen) + return S_FALSE; + + HRESULT hr = m_SwapChain->SetFullscreenState(false, NULL); + if(FAILED(hr)) return hr; + + SetWindowLong(m_hWnd, GWL_STYLE, WINDOW_STYLE_NORMAL); + + if(windowWidth <= 0 || windowHeight <= 0) + { + windowWidth = m_SwapChainDesc.BufferDesc.Width; + windowHeight = m_SwapChainDesc.BufferDesc.Height; + } + + RECT rect = { 0, 0, windowWidth, windowHeight }; + AdjustWindowRect(&rect, WINDOW_STYLE_NORMAL, FALSE); + MoveWindow(m_hWnd, 0, 0, rect.right - rect.left, rect.bottom - rect.top, true); + UpdateWindow(m_hWnd); + + m_SwapChain->GetDesc(&m_SwapChainDesc); + + return S_OK; +} + +HRESULT +DeviceManager::ToggleFullscreen() +{ + if(GetWindowState() == kWindowFullscreen) + return LeaveFullscreenMode(); + else + return EnterFullscreenMode(); +} + +DeviceManager::WindowState +DeviceManager::GetWindowState() +{ + if(m_SwapChain && !m_SwapChainDesc.Windowed) + return kWindowFullscreen; + + if(m_hWnd == INVALID_HANDLE_VALUE) + return kWindowNone; + + if(IsZoomed(m_hWnd)) + return kWindowMaximized; + + if(IsIconic(m_hWnd)) + return kWindowMinimized; + + return kWindowNormal; +} + +HRESULT +DeviceManager::GetDisplayResolution(int& width, int& height) +{ + if(m_hWnd != INVALID_HANDLE_VALUE) + { + HMONITOR monitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTOPRIMARY); + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + + if(GetMonitorInfo(monitor, &info)) + { + width = info.rcMonitor.right - info.rcMonitor.left; + height = info.rcMonitor.bottom - info.rcMonitor.top; + return S_OK; + } + } + + return E_FAIL; +} + +IDXGIAdapter* +DeviceManager::GetDXGIAdapter() +{ + if(!m_Device) + return NULL; + + IDXGIDevice* pDXGIDevice = NULL; + m_Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDXGIDevice)); + + IDXGIAdapter* pDXGIAdapter = NULL; + pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&pDXGIAdapter)); + + pDXGIDevice->Release(); + + return pDXGIAdapter; +} + +// added by Junma Lixu +void +DeviceManager::SetWindowHandle(HWND hWnd) +{ + m_hWnd = hWnd; +} + +HRESULT +DeviceManager::SetWindowDeviceAndSwapChain(D3DHandles& deviceHandles) +{ + ID3D11Device* pDevice = (ID3D11Device*)(deviceHandles.pDevice); + ID3D11DeviceContext* pImmediateContext = (ID3D11DeviceContext*)(deviceHandles.pDeviceContext); + if (pDevice == nullptr || pImmediateContext == nullptr) + { + return E_FAIL; + } + + m_Device = pDevice; + m_ImmediateContext = pImmediateContext; + m_SwapChain = deviceHandles.pDXGISwapChain; + HRESULT res0 = m_SwapChain->GetDesc(&m_SwapChainDesc); + assert(m_SwapChainDesc.OutputWindow == m_hWnd); + + m_BackBufferRTV = (ID3D11RenderTargetView*)deviceHandles.pD3D11RenderTargetView; + m_DepthStencilBuffer = (ID3D11Texture2D*)deviceHandles.pD3D11DepthBuffer; + m_DepthStencilDSV = (ID3D11DepthStencilView*)deviceHandles.pD3D11DepthStencilView; + m_DepthStencilBuffer->GetDesc(&m_DepthStencilDesc); + //m_DepthStencilDSV->GetDesc(&); + return S_OK; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/DeviceManager.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/DeviceManager.h new file mode 100644 index 0000000..bd6f7e2 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/DeviceManager.h @@ -0,0 +1,179 @@ +// TAGRELEASE: PUBLIC + +#pragma once +#include <Windows.h> +#include <DXGI.h> +#include <D3D11.h> +#include <list> +// added by Junma Lixu +#include "RenderPlugin.h" + +struct DeviceCreationParameters +{ + bool startMaximized; + bool startFullscreen; + int backBufferWidth; + int backBufferHeight; + int refreshRate; + int swapChainBufferCount; + DXGI_FORMAT swapChainFormat; + DXGI_FORMAT depthStencilFormat; + DXGI_USAGE swapChainUsage; + int swapChainSampleCount; + int swapChainSampleQuality; + UINT createDeviceFlags; + D3D_DRIVER_TYPE driverType; + D3D_FEATURE_LEVEL featureLevel; + HWND hWnd; + + // For use in the case of multiple adapters. If this is non-null, device creation will try to match + // the given string against an adapter name. If the specified string exists as a sub-string of the + // adapter name, the device and window will be created on that adapter. Case sensitive. + const WCHAR* adapterNameSubstring; + + DeviceCreationParameters() + : startMaximized(false) + , startFullscreen(false) + , backBufferWidth(1280) + , backBufferHeight(720) + , refreshRate(0) + , swapChainBufferCount(1) + , swapChainFormat(DXGI_FORMAT_R8G8B8A8_UNORM) + , depthStencilFormat(DXGI_FORMAT_D24_UNORM_S8_UINT) + , swapChainUsage(DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT) + , swapChainSampleCount(1) + , swapChainSampleQuality(0) + , createDeviceFlags(0) + , driverType(D3D_DRIVER_TYPE_HARDWARE) + , featureLevel(D3D_FEATURE_LEVEL_11_0) + , adapterNameSubstring(L"") + , hWnd(0) + { } +}; + +#pragma warning(push) +#pragma warning(disable: 4100) // unreferenced formal parameter +class IVisualController +{ +private: + bool m_Enabled; +public: + IVisualController() : m_Enabled(true) { } + + virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return 1; } + virtual void Render(ID3D11Device* pDevice, ID3D11DeviceContext* pDeviceContext, ID3D11RenderTargetView* pRTV, ID3D11DepthStencilView* pDSV) { } + virtual void Animate(double fElapsedTimeSeconds) { } + virtual HRESULT DeviceCreated(ID3D11Device* pDevice) { return S_OK; } + virtual void DeviceDestroyed() { } + virtual void BackBufferResized(ID3D11Device* pDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc) { } + + virtual void EnableController() { m_Enabled = true; } + virtual void DisableController() { m_Enabled = false; } + virtual bool IsEnabled() { return m_Enabled; } +}; +#pragma warning(pop) + +struct D3DHandles; + +class DeviceManager +{ +public: + enum WindowState + { + kWindowNone, + kWindowNormal, + kWindowMinimized, + kWindowMaximized, + kWindowFullscreen + }; + +protected: + ID3D11Device* m_Device; + ID3D11DeviceContext* m_ImmediateContext; + IDXGISwapChain* m_SwapChain; + ID3D11RenderTargetView* m_BackBufferRTV; + ID3D11Texture2D* m_DepthStencilBuffer; + ID3D11DepthStencilView* m_DepthStencilDSV; + DXGI_SWAP_CHAIN_DESC m_SwapChainDesc; + D3D11_TEXTURE2D_DESC m_DepthStencilDesc; + bool m_IsNvidia; + HWND m_hWnd; + std::list<IVisualController*> m_vControllers; + std::wstring m_WindowTitle; + double m_FixedFrameInterval; + UINT m_SyncInterval; + std::list<double> m_vFrameTimes; + double m_AverageFrameTime; + double m_AverageTimeUpdateInterval; + bool m_InSizingModalLoop; + SIZE m_NewWindowSize; + LARGE_INTEGER perfFreq, previousTime; +private: + HRESULT CreateRenderTargetAndDepthStencil(); + void ResizeSwapChain(); +public: + + DeviceManager() + : m_Device(NULL) + , m_ImmediateContext(NULL) + , m_SwapChain(NULL) + , m_BackBufferRTV(NULL) + , m_DepthStencilBuffer(NULL) + , m_DepthStencilDSV(NULL) + , m_IsNvidia(false) + , m_hWnd(NULL) + , m_WindowTitle(L"") + , m_FixedFrameInterval(-1) + , m_SyncInterval(0) + , m_AverageFrameTime(0) + , m_AverageTimeUpdateInterval(0.5) + , m_InSizingModalLoop(false) + { + QueryPerformanceFrequency(&perfFreq); + QueryPerformanceCounter(&previousTime); + } + + virtual ~DeviceManager() + { Shutdown(); } + + virtual HRESULT CreateWindowDeviceAndSwapChain(const DeviceCreationParameters& params); + virtual HRESULT ChangeBackBufferFormat(DXGI_FORMAT format, UINT sampleCount); + virtual HRESULT ResizeWindow(int width, int height); + virtual HRESULT EnterFullscreenMode(int width = 0, int height = 0); + virtual HRESULT LeaveFullscreenMode(int windowWidth = 0, int windowHeight = 0); + virtual HRESULT ToggleFullscreen(); + + virtual void Shutdown(); + virtual void MessageLoop(); + virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + virtual void Render(); + virtual void Animate(double fElapsedTimeSeconds); + virtual void DeviceCreated(); + virtual void DeviceDestroyed(); + virtual void BackBufferResized(); + + void AddControllerToFront(IVisualController* pController); + void AddControllerToBack(IVisualController* pController); + void RemoveController(IVisualController* pController); + + void SetFixedFrameInterval(double seconds) { m_FixedFrameInterval = seconds; } + void DisableFixedFrameInterval() { m_FixedFrameInterval = -1; } + + bool IsNvidia() const { return m_IsNvidia; } + HWND GetHWND() { return m_hWnd; } + ID3D11Device* GetDevice() { return m_Device; } + WindowState GetWindowState(); + bool GetVsyncEnabled() { return m_SyncInterval > 0; } + void SetVsyncEnabled(bool enabled) { m_SyncInterval = enabled ? 1 : 0; } + HRESULT GetDisplayResolution(int& width, int& height); + IDXGIAdapter* GetDXGIAdapter(); + double GetAverageFrameTime() { return m_AverageFrameTime; } + void SetAverageTimeUpdateInterval(double value) { m_AverageTimeUpdateInterval = value; } + + // added by Junma Lixu + void SetWindowHandle(HWND hWnd); + virtual HRESULT SetWindowDeviceAndSwapChain(D3DHandles& pDeviceHandles); +}; + + +DeviceManager* GetDeviceManager(); diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleController.cpp new file mode 100644 index 0000000..163b3b4 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleController.cpp @@ -0,0 +1,63 @@ +/* +* 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 "SampleController.h" +#include "SceneController.h" +#include "CommonUIController.h" +#include "BlastController.h" +#include "PhysXController.h" + +#include "imgui.h" + +SampleController::SampleController() +{ +} + +SampleController::~SampleController() +{ +} + +void SampleController::onSampleStart() +{ + // start with GPU physics by default + setUseGPUPhysics(true); +} + + +void SampleController::setUseGPUPhysics(bool useGPUPhysics) +{ + if (!getPhysXController().getGPUPhysicsAvailable()) + { + useGPUPhysics = false; + } + + if (getPhysXController().getUseGPUPhysics() == useGPUPhysics) + { + return; + } + + int assetNum = getSceneController().releaseAll(); + + getPhysXController().setUseGPUPhysics(useGPUPhysics); + getBlastController().reinitialize(); + + getSceneController().spawnAsset(assetNum); +} + + +void SampleController::drawPhysXGpuUI() +{ + // GPU Physics + bool useGPU = getPhysXController().getUseGPUPhysics(); + if (ImGui::Checkbox("Use GPU Physics", &useGPU)) + { + getCommonUIController().addDelayedCall([=]() { setUseGPUPhysics(useGPU); }, "Loading..."); + } +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleController.h new file mode 100644 index 0000000..a52c2fe --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleController.h @@ -0,0 +1,57 @@ +/* +* 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 SAMPLE_CONTROLLER_H +#define SAMPLE_CONTROLLER_H + +#include "SampleManager.h" + +class SampleController : public ISampleController +{ +public: + SampleController(); + virtual ~SampleController(); + + virtual void onSampleStart(); + void drawPhysXGpuUI(); + +private: + SampleController& operator= (SampleController&); + + + //////// used controllers //////// + + PhysXController& getPhysXController() const + { + return getManager()->getPhysXController(); + } + + BlastController& getBlastController() const + { + return getManager()->getBlastController(); + } + + SceneController& getSceneController() const + { + return getManager()->getSceneController(); + } + + CommonUIController& getCommonUIController() const + { + return getManager()->getCommonUIController(); + } + + + //////// private methods //////// + + void setUseGPUPhysics(bool useGPUPhysics); +}; + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleManager.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleManager.cpp new file mode 100644 index 0000000..2e13687 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleManager.cpp @@ -0,0 +1,1267 @@ +/* +* 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 "NvBlastExtAuthoringTypes.h" +#include "NvBlastExtAuthoringFractureTool.h" +#include "NvBlastExtAuthoringBondGenerator.h" +#include "NvBlastIndexFns.h" + +#include "SampleManager.h" + +#include "Utils.h" + +#include "Renderer.h" +#include "PhysXController.h" +#include "BlastController.h" +#include "CommonUIController.h" +#include "DamageToolController.h" +#include "SelectionToolController.h" +#include "GizmoToolController.h" +#include "EditionToolController.h" +#include "SceneController.h" +#include "SampleController.h" + +#include "tclap/CmdLine.h" +#include "PxPhysics.h" +#include "PsFileBuffer.h" +#include "NvBlast.h" +#include "NvBlastExtAuthoringCollisionBuilder.h" +#include "NvBlastExtPxAsset.h" +#include "BlastFractureTool.h" +#include <set> +#include "MaterialLibraryPanel.h" +#include "MaterialAssignmentsPanel.h" + +using namespace physx; + +physx::PxFoundation* foundation = nullptr; +physx::PxPhysics* physics = nullptr; +physx::PxCooking* cooking = nullptr; +Nv::Blast::ExtPxManager* physicsManager = nullptr; +SampleManager* sSampleManager = nullptr; + +class SimpleRandomGenerator : public RandomGeneratorBase +{ +public: + SimpleRandomGenerator() { + remember = false; + }; + + virtual float getRandomValue() + { + float r = (float)rand(); + r = r / RAND_MAX; + return r; + } + + virtual float getExponential(float lambda) + { + return -1.0f / lambda * log(1 - getRandomValue()); + } + + virtual void seed(int32_t seed) + { + srand(seed); + } + + virtual ~SimpleRandomGenerator() {}; + +private: + bool remember; +}; +static SimpleRandomGenerator sRandomGenerator; + +void loggingCallback(int type, const char* msg, const char* file, int line) +{ + (void)type; + + std::cout << msg << " FILE:" << file << " Line: " << line << "\n"; +} + +void buildPxChunks(const std::vector<std::vector<Triangle>>& chunkGeometry, std::vector<ExtPxAssetDesc::ChunkDesc>& pxChunks, + std::vector<ExtPxAssetDesc::SubchunkDesc>& pxSubchunks) +{ + ConvexMeshBuilder collisionBuilder(cooking, &physics->getPhysicsInsertionCallback()); + + pxChunks.resize(chunkGeometry.size()); + pxSubchunks.resize(chunkGeometry.size()); + + for (uint32_t i = 0; i < chunkGeometry.size(); ++i) + { + std::vector<physx::PxVec3> vertices; + for (uint32_t p = 0; p < chunkGeometry[i].size(); ++p) + { + vertices.push_back(chunkGeometry[i][p].a.p); + vertices.push_back(chunkGeometry[i][p].b.p); + vertices.push_back(chunkGeometry[i][p].c.p); + } + pxSubchunks[i].transform = physx::PxTransform(physx::PxIdentity); + pxSubchunks[i].geometry = physx::PxConvexMeshGeometry(collisionBuilder.buildConvexMesh(vertices)); + pxChunks[i].isStatic = false; + pxChunks[i].subchunkCount = 1; + pxChunks[i].subchunks = &pxSubchunks[i]; + } + + // only effect when chunk is support + pxChunks[0].isStatic = true; +} + +void saveFractureToObj(std::vector<std::vector<Triangle> > chunksGeometry, std::string name, std::string path) +{ + MaterialAssignmentsPanel* pMaterialAssignmentsPanel = MaterialAssignmentsPanel::ins(); + std::vector<std::string> materialNames; + std::vector<std::string> materialPaths; + pMaterialAssignmentsPanel->getMaterialNameAndPaths(materialNames, materialPaths); + + uint32_t submeshCount = 2; + // export materials (mtl file) + { + std::ostringstream mtlFilePath; + mtlFilePath << path << name << ".mtl"; + FILE* f = fopen(mtlFilePath.str().c_str(), "w"); + if (!f) + return; + + for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex) + { + fprintf(f, "newmtl %s\n", materialNames[submeshIndex].c_str()); + fprintf(f, "\tmap_Kd %s\n", materialPaths[submeshIndex].c_str()); + fprintf(f, "\n"); + } + + fclose(f); + } + + { + std::ostringstream objFilePath; + objFilePath << path << name << ".obj"; + FILE* outStream = fopen(objFilePath.str().c_str(), "w"); + + fprintf(outStream, "mtllib %s.mtl\n", name.c_str()); + fprintf(outStream, "o frac \n"); + + + for (uint32_t vc = 0; vc < chunksGeometry.size(); ++vc) + { + std::vector<Triangle>& chunk = chunksGeometry[vc]; + for (uint32_t i = 0; i < chunk.size(); ++i) + { + fprintf(outStream, "v %lf %lf %lf\n", chunk[i].a.p.x, chunk[i].a.p.y, chunk[i].a.p.z); + fprintf(outStream, "v %lf %lf %lf\n", chunk[i].b.p.x, chunk[i].b.p.y, chunk[i].b.p.z); + fprintf(outStream, "v %lf %lf %lf\n", chunk[i].c.p.x, chunk[i].c.p.y, chunk[i].c.p.z); + } + + for (uint32_t i = 0; i < chunk.size(); ++i) + { + fprintf(outStream, "vt %lf %lf \n", chunk[i].a.uv[0].x, chunk[i].a.uv[0].y); + fprintf(outStream, "vt %lf %lf \n", chunk[i].b.uv[0].x, chunk[i].b.uv[0].y); + fprintf(outStream, "vt %lf %lf \n", chunk[i].c.uv[0].x, chunk[i].c.uv[0].y); + } + + for (uint32_t i = 0; i < chunk.size(); ++i) + { + fprintf(outStream, "vn %lf %lf %lf\n", chunk[i].a.n.x, chunk[i].a.n.y, chunk[i].a.n.z); + fprintf(outStream, "vn %lf %lf %lf\n", chunk[i].b.n.x, chunk[i].b.n.y, chunk[i].b.n.z); + fprintf(outStream, "vn %lf %lf %lf\n", chunk[i].c.n.x, chunk[i].c.n.y, chunk[i].c.n.z); + } + } + int indx = 1; + for (uint32_t vc = 0; vc < chunksGeometry.size(); ++vc) + { + fprintf(outStream, "g %d_%d \n", vc, 0); + fprintf(outStream, "usemtl %s\n", materialNames[0].c_str()); + int totalSize = chunksGeometry[vc].size(); + std::vector<int> internalSurfaces; + for (uint32_t i = 0; i < totalSize; ++i) + { + if (chunksGeometry[vc][i].userInfo != 0) + { + internalSurfaces.push_back(indx++); + internalSurfaces.push_back(indx++); + internalSurfaces.push_back(indx++); + continue; + } + fprintf(outStream, "f %d/%d/%d ", indx, indx, indx); + indx++; + fprintf(outStream, "%d/%d/%d ", indx, indx, indx); + indx++; + fprintf(outStream, "%d/%d/%d \n", indx, indx, indx); + indx++; + } + int internalSize = internalSurfaces.size(); + if (internalSize > 0) + { + fprintf(outStream, "g %d_%d \n", vc, 1); + fprintf(outStream, "usemtl %s\n", materialNames[1].c_str()); + int isIndex; + for (uint32_t is = 0; is < internalSize;) + { + isIndex = internalSurfaces[is++]; + fprintf(outStream, "f %d/%d/%d ", isIndex, isIndex, isIndex); + isIndex = internalSurfaces[is++]; + fprintf(outStream, "%d/%d/%d ", isIndex, isIndex, isIndex); + isIndex = internalSurfaces[is++]; + fprintf(outStream, "%d/%d/%d \n", isIndex, isIndex, isIndex); + } + } + } + fclose(outStream); + } +} + +void FractureExecutor::setSourceMesh(Nv::Blast::Mesh* mesh) +{ + assert(m_fractureTool); + m_sourMesh = mesh; + m_fractureTool->setSourceMesh(mesh); +} + +void FractureExecutor::setSourceAsset(const BlastAsset* blastAsset) +{ + assert(m_fractureTool); + m_fractureTool->setSourceAsset(blastAsset); + m_sourMesh = nullptr; +} + +VoronoiFractureExecutor::VoronoiFractureExecutor() +: m_cellsCount(5) +{ + if (sSampleManager) + m_fractureTool = sSampleManager->m_fTool; +} + +void VoronoiFractureExecutor::setCellsCount(uint32_t cellsCount) +{ + m_cellsCount = cellsCount; +} + +bool VoronoiFractureExecutor::execute() +{ + Nv::Blast::Mesh* mesh = nullptr; + if (m_sourMesh) + { + mesh = m_sourMesh; + } + else + { + mesh = m_fractureTool->getSourceMesh(m_chunkId); + } + // Prevent crash Junma Added By Lixu + if (mesh == nullptr) + return false; + + VoronoiSitesGenerator stGenerator(mesh, (m_randomGenerator == nullptr ? &sRandomGenerator : m_randomGenerator)); + stGenerator.uniformlyGenerateSitesInMesh(m_cellsCount); + m_fractureTool->voronoiFracturing(m_chunkId, stGenerator.getVoronoiSites(), false); + m_fractureTool->finalizeFracturing(); + + return sSampleManager->postProcessCurrentAsset(); +} + +SliceFractureExecutor::SliceFractureExecutor() +: m_config(new Nv::Blast::SlicingConfiguration()) +{ + if (sSampleManager) + m_fractureTool = sSampleManager->m_fTool; +} + +void SliceFractureExecutor::applyNoise(float amplitude, float frequency, int32_t octaves, float falloff, int32_t relaxIterations, float relaxFactor, int32_t seed) +{ + m_fractureTool->applyNoise(amplitude, frequency, octaves, falloff, relaxIterations, relaxFactor, seed); +} + +void SliceFractureExecutor::applyConfig(int32_t xSlices, int32_t ySlices, int32_t zSlices, float offsetVariations, float angleVariations) +{ + m_config->x_slices = xSlices; + m_config->y_slices = ySlices; + m_config->z_slices = zSlices; + m_config->offset_variations = offsetVariations; + m_config->angle_variations = angleVariations; +} + +bool SliceFractureExecutor::execute() +{ + m_fractureTool->slicing(m_chunkId, *m_config, false, (m_randomGenerator == nullptr ? &sRandomGenerator : m_randomGenerator)); + m_fractureTool->finalizeFracturing(); + return sSampleManager->postProcessCurrentAsset(); +} + +static VoronoiFractureExecutor sVoronoiFracture; + +SampleManager* SampleManager::ins() +{ + return sSampleManager; +} + +SampleManager::SampleManager(DeviceManager* pDeviceManager) +{ + sSampleManager = this; + m_bNeedConfig = false; + m_bNeedRefreshTree = false; + + m_renderer = new Renderer(); + m_physXController = new PhysXController(ExtImpactDamageManager::FilterShader); + m_blastController = new BlastController(); + m_sceneController = new SceneController(); + m_damageToolController = new DamageToolController(); + m_selectionToolController = new SelectionToolController(); + m_gizmoToolController = new GizmoToolController(); + m_editionToolController = new EditionToolController(); + m_sampleController = new SampleController(); +// m_commonUIController = new CommonUIController(); + + m_pApplication = new Application(pDeviceManager); + + Application& app = *m_pApplication; + + app.addControllerToFront(m_renderer); + app.addControllerToFront(m_physXController); + app.addControllerToFront(m_blastController); + app.addControllerToFront(m_sceneController); + app.addControllerToFront(m_damageToolController); + app.addControllerToFront(m_selectionToolController); + app.addControllerToFront(m_gizmoToolController); + app.addControllerToFront(m_editionToolController); + app.addControllerToFront(m_sampleController); +// app.addControllerToFront(m_commonUIController); + + for (IApplicationController* c : app.getControllers()) + { + (static_cast<ISampleController*>(c))->setManager(this); + } + + m_config.sampleName = L""; + m_config.assetsFile = ""; + + m_config.additionalResourcesDir.clear(); + m_config.additionalResourcesDir.push_back("../resources"); + m_config.additionalResourcesDir.push_back("../../../../bin/resources"); + + m_config.additionalAssetList.models.clear(); + m_config.additionalAssetList.boxes.clear(); + m_config.additionalAssetList.composites.clear(); + + m_fTool = new BlastFractureTool(loggingCallback); + m_fractureExecutor = nullptr; + + setFractureExecutor(&sVoronoiFracture); + + m_pCurBlastAsset = nullptr; + m_nCurFamilyIndex = -1; +} + +SampleManager::~SampleManager() +{ + delete m_renderer; + delete m_physXController; + delete m_blastController; + delete m_sceneController; + delete m_damageToolController; + delete m_selectionToolController; + delete m_gizmoToolController; + delete m_editionToolController; + delete m_sampleController; + delete m_fTool; +// delete m_commonUIController; +} + +int SampleManager::init() +{ + Application& app = *m_pApplication; + app.init(); + + m_ToolType = BTT_Num; + setBlastToolType(BTT_Edit); + + return 0; +} + +int SampleManager::run() +{ + if (m_bNeedConfig) + { + getSceneController().onSampleStop(); + getSceneController().onSampleStart(); + + _setSourceAsset(); + + m_bNeedConfig = false; + m_bNeedRefreshTree = true; + } + + Application& app = *m_pApplication; + app.run(); + + std::vector<std::string>::iterator itStr; + std::vector<Renderable*>::iterator itRenderable; + for (itStr = m_NeedDeleteRenderMaterials.begin(); itStr != m_NeedDeleteRenderMaterials.end(); itStr++) + { + std::string materialName = *itStr; + RenderMaterial* pRenderMaterial = m_RenderMaterialMap[materialName]; + std::vector<Renderable*>& renderables = pRenderMaterial->getRelatedRenderables(); + for (itRenderable = renderables.begin(); itRenderable != renderables.end(); itRenderable++) + { + Renderable* pRenderable = *itRenderable; + pRenderable->setMaterial(*RenderMaterial::getDefaultRenderMaterial()); + } + + removeRenderMaterial(materialName); + } + m_NeedDeleteRenderMaterials.clear(); + + MaterialLibraryPanel::ins()->deleteMaterials(); + + return 0; +} + +int SampleManager::free() +{ + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator it; + for (it = m_AssetFamiliesMap.begin(); it != m_AssetFamiliesMap.end(); it++) + { + std::vector<BlastFamily*>& fs = it->second; + fs.clear(); + } + m_AssetFamiliesMap.clear(); + m_AssetDescMap.clear(); + + Application& app = *m_pApplication; + app.free(); + + /* + std::vector<AssetList::ModelAsset>& modelAssets = m_config.additionalAssetList.models; + std::vector<AssetList::ModelAsset>::iterator it; + char filename[50]; + for (it = modelAssets.begin(); it != modelAssets.end(); it++) + { + AssetList::ModelAsset& m = *it; + + sprintf(filename, "../../../../bin/resources/models/%s.bpxa", m.id.c_str()); + DeleteFileA(filename); + + sprintf(filename, "../../../../bin/resources/models/%s.mtl", m.id.c_str()); + DeleteFileA(filename); + + sprintf(filename, "../../../../bin/resources/models/%s.obj", m.id.c_str()); + DeleteFileA(filename); + } + */ + + return 0; +} + +void SampleManager::addModelAsset(std::string file, bool isSkinned, physx::PxTransform transform, bool clear) +{ + if (clear) + { + m_config.additionalAssetList.models.clear(); + } + else + { + std::vector<AssetList::ModelAsset>& modelAssets = m_config.additionalAssetList.models; + std::vector<AssetList::ModelAsset>::iterator it = modelAssets.begin(); + for (; it != modelAssets.end(); it++) + { + AssetList::ModelAsset& m = *it; + if (m.id == file) + { + modelAssets.erase(it); + break; + } + } + } + + AssetList::ModelAsset modelAsset; + modelAsset.name = file; + modelAsset.id = file; + modelAsset.file = file; + modelAsset.isSkinned = isSkinned; + modelAsset.transform = transform; + + m_config.additionalAssetList.models.push_back(modelAsset); + + m_bNeedConfig = true; +} + +bool SampleManager::createAsset( + std::string assetName, + std::vector<physx::PxVec3>& positions, + std::vector<physx::PxVec3>& normals, + std::vector<physx::PxVec2>& uv, + std::vector<unsigned int>& indices, + bool fracture) +{ + PhysXController& pc = getPhysXController(); + BlastController& bc = getBlastController(); + + physics = &pc.getPhysics(); + foundation = &physics->getFoundation(); + cooking = &pc.getCooking(); + physicsManager = &bc.getExtPxManager(); + + std::vector<Nv::Blast::Mesh* > meshes; + PxVec3* nr = (!normals.empty()) ? normals.data() : 0; + PxVec2* uvp = (!uv.empty()) ? uv.data() : 0; + Nv::Blast::Mesh* sourceMesh = new Nv::Blast::Mesh(positions.data(), nr, uvp, static_cast<uint32_t>(positions.size()), + indices.data(), static_cast<uint32_t>(indices.size())); + meshes.push_back(sourceMesh); + + m_fractureExecutor->setSourceMesh(sourceMesh); + if (fracture) + { + m_fractureExecutor->execute(); + m_fractureExecutor = &sVoronoiFracture; + } + else + { + m_fTool->finalizeFracturing(); + } + + std::string outDir = "../../../../bin/resources/models/"; + _createAsset(assetName, outDir, meshes); + + delete sourceMesh; + sourceMesh = 0; + + m_bNeedConfig = true; + + return true; +} + +bool SampleManager::createAsset( + const std::string& assetName, + const std::vector<Nv::Blast::Mesh* >& meshes, + bool fracture) +{ + PhysXController& pc = getPhysXController(); + BlastController& bc = getBlastController(); + + physics = &pc.getPhysics(); + foundation = &physics->getFoundation(); + cooking = &pc.getCooking(); + physicsManager = &bc.getExtPxManager(); + + if (meshes.size() == 1) + { + Nv::Blast::Mesh* sourceMesh = meshes[0]; + m_fractureExecutor->setSourceMesh(sourceMesh); + if (fracture) + { + m_fractureExecutor->execute(); + m_fractureExecutor = &sVoronoiFracture; + } + else + { + m_fTool->finalizeFracturing(); + } + } + + std::string outDir = "../../../../bin/resources/models/"; + _createAsset(assetName, outDir, meshes); + + m_bNeedConfig = true; + + return true; +} + +bool SampleManager::saveAsset() +{ + if (m_pCurBlastAsset == nullptr) + { + return false; + } + + AssetList::ModelAsset& desc = m_AssetDescMap[m_pCurBlastAsset]; + + PhysXController& pc = getPhysXController(); + BlastController& bc = getBlastController(); + physics = &pc.getPhysics(); + foundation = &physics->getFoundation(); + cooking = &pc.getCooking(); + physicsManager = &bc.getExtPxManager(); + + std::string outDir = "../../../../bin/resources/models/"; + + std::ostringstream outBlastFilePathStream; + outBlastFilePathStream << outDir << desc.name << ".bpxa"; + std::string outBlastFilePath = outBlastFilePathStream.str(); + const ExtPxAsset* asset = m_pCurBlastAsset->getPxAsset(); + if (asset == nullptr) + { + return false; + } + physx::PsFileBuffer fileBuf(outBlastFilePath.c_str(), physx::PxFileBuf::OPEN_WRITE_ONLY); + if (!asset->serialize(fileBuf, *cooking)) + { + return false; + } + fileBuf.close(); + + m_fTool->setSourceAsset(m_pCurBlastAsset); + m_fTool->finalizeFracturing(); + + size_t nChunkListSize = m_fTool->getChunkList().size(); + std::vector<std::vector<Triangle> > chunkMeshes(nChunkListSize); + std::vector<bool> isSupport(nChunkListSize); + for (uint32_t i = 0; i < nChunkListSize; ++i) + { + m_fTool->getBaseMesh(i, chunkMeshes[i]); + isSupport[i] = m_fTool->getChunkList()[i].isLeaf; + } + + BlastBondGenerator bondGenerator(cooking, &physics->getPhysicsInsertionCallback()); + BondGenerationConfig cnf; + cnf.bondMode = BondGenerationConfig::AVERAGE; + std::vector<NvBlastChunkDesc> chunkDesc; + std::vector<NvBlastBondDesc> bondDescs; + bondGenerator.buildDescFromInternalFracture(m_fTool, isSupport, bondDescs, chunkDesc); + const uint32_t chunkCount = static_cast<uint32_t>(chunkDesc.size()); + const uint32_t bondCount = static_cast<uint32_t>(bondDescs.size()); + if (bondCount == 0) + { + std::cout << "Can't create bonds descriptors..." << std::endl; + } + + std::vector<uint32_t> chunkReorderInvMap; + { + std::vector<uint32_t> chunkReorderMap(chunkCount); + std::vector<char> scratch(chunkCount * sizeof(NvBlastChunkDesc)); + NvBlastEnsureAssetExactSupportCoverage(chunkDesc.data(), chunkCount, scratch.data(), loggingCallback); + NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), chunkDesc.data(), chunkCount, scratch.data(), loggingCallback); + NvBlastApplyAssetDescChunkReorderMapInplace(chunkDesc.data(), chunkCount, bondDescs.data(), bondCount, chunkReorderMap.data(), scratch.data(), loggingCallback); + chunkReorderInvMap.resize(chunkReorderMap.size()); + Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<unsigned int>(chunkReorderMap.size())); + } + + std::vector<std::vector<Triangle>> resultGeometry(chunkMeshes.size()); + for (uint32_t i = 0; i < chunkMeshes.size(); ++i) + { + uint32_t chunkIndex = chunkReorderInvMap[i]; + resultGeometry[chunkIndex] = chunkMeshes[i]; + } + + saveFractureToObj(resultGeometry, desc.name, outDir); + + std::string saveInfo = outBlastFilePath + " saved successfully\n"; + output(saveInfo.c_str()); + + return true; +} + +bool SampleManager::fractureAsset(std::string& assetName, const BlastAsset* pBlastAsset, int32_t chunkId) +{ + PhysXController& pc = getPhysXController(); + BlastController& bc = getBlastController(); + + physics = &pc.getPhysics(); + foundation = &physics->getFoundation(); + cooking = &pc.getCooking(); + physicsManager = &bc.getExtPxManager(); + + m_fractureExecutor->setSourceAsset(pBlastAsset); + m_fractureExecutor->setTargetChunk(chunkId); + m_fractureExecutor->execute(); + m_fractureExecutor = &sVoronoiFracture; + + std::string outDir = "../../../../bin/resources/models/"; + + std::ostringstream outBlastFilePathStream; + outBlastFilePathStream << outDir << assetName << ".bpxa"; + std::string outBlastFilePath = outBlastFilePathStream.str(); + + std::vector<NvBlastChunkDesc> chunkDesc; + std::vector<NvBlastBondDesc> bondDescs; + std::vector<std::vector<Triangle> > chunkMeshes; + std::vector<bool> isSupport; + + size_t nChunkListSize = m_fTool->getChunkList().size(); + chunkMeshes.resize(nChunkListSize); + isSupport.resize(nChunkListSize); + for (uint32_t i = 0; i < nChunkListSize; ++i) + { + m_fTool->getBaseMesh(i, chunkMeshes[i]); + isSupport[i] = m_fTool->getChunkList()[i].isLeaf; + } + + BlastBondGenerator bondGenerator(cooking, &physics->getPhysicsInsertionCallback()); + + BondGenerationConfig cnf; + cnf.bondMode = BondGenerationConfig::AVERAGE; + bondGenerator.buildDescFromInternalFracture(m_fTool, isSupport, bondDescs, chunkDesc); + + const uint32_t chunkCount = static_cast<uint32_t>(chunkDesc.size()); + const uint32_t bondCount = static_cast<uint32_t>(bondDescs.size()); + if (bondCount == 0) + { + std::cout << "Can't create bonds descriptors..." << std::endl; + } + + // order chunks, build map + std::vector<uint32_t> chunkReorderInvMap; + { + std::vector<uint32_t> chunkReorderMap(chunkCount); + std::vector<char> scratch(chunkCount * sizeof(NvBlastChunkDesc)); + NvBlastEnsureAssetExactSupportCoverage(chunkDesc.data(), chunkCount, scratch.data(), loggingCallback); + NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), chunkDesc.data(), chunkCount, scratch.data(), loggingCallback); + NvBlastApplyAssetDescChunkReorderMapInplace(chunkDesc.data(), chunkCount, bondDescs.data(), bondCount, chunkReorderMap.data(), scratch.data(), loggingCallback); + chunkReorderInvMap.resize(chunkReorderMap.size()); + Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<unsigned int>(chunkReorderMap.size())); + } + + // get result geometry + std::vector<std::vector<Triangle>> resultGeometry(chunkMeshes.size()); + for (uint32_t i = 0; i < chunkMeshes.size(); ++i) + { + uint32_t chunkIndex = chunkReorderInvMap[i]; + resultGeometry[chunkIndex] = chunkMeshes[i]; + } + + // prepare physics data (convexes) + std::vector<ExtPxAssetDesc::ChunkDesc> pxChunks(chunkCount); + std::vector<ExtPxAssetDesc::SubchunkDesc> pxSubchunks; + buildPxChunks(resultGeometry, pxChunks, pxSubchunks); + + // build and serialize ExtPhysicsAsset + ExtPxAssetDesc descriptor; + descriptor.bondCount = bondCount; + descriptor.bondDescs = bondDescs.data(); + descriptor.chunkCount = chunkCount; + descriptor.chunkDescs = chunkDesc.data(); + descriptor.bondFlags = nullptr; + descriptor.pxChunks = pxChunks.data(); + ExtPxAsset* asset = ExtPxAsset::create(descriptor, bc.getTkFramework()); + if (asset == nullptr) + { + return false; + } + + physx::PsFileBuffer fileBuf(outBlastFilePath.c_str(), physx::PxFileBuf::OPEN_WRITE_ONLY); + if (!asset->serialize(fileBuf, *cooking)) + { + return false; + } + fileBuf.close(); + asset->release(); + + saveFractureToObj(resultGeometry, assetName, outDir); + + m_bNeedConfig = true; + + return true; +} + +bool SampleManager::postProcessCurrentAsset() +{ + std::vector<AssetList::ModelAsset>& models = m_config.additionalAssetList.models; + if (models.size() < 0) + { + return true; + } + + std::string assetName = models.at(models.size() - 1).file; + std::string outDir = "../../../../bin/resources/models/"; + std::vector<Nv::Blast::Mesh* > meshes; + _createAsset(assetName, outDir, meshes); + + m_bNeedConfig = true; + + return true; +} + +std::vector<uint32_t> SampleManager::getCurrentSelectedChunks() +{ + std::vector<uint32_t> selectedChunks; + std::vector<BlastFamilyPtr>& spFamilies = m_blastController->getFamilies(); + if (spFamilies.size() > 0) + { + return spFamilies.back()->getSelectedChunks(); + } + return selectedChunks; +} + +std::map<BlastAsset*, std::vector<uint32_t>> SampleManager::getSelectedChunks() +{ + std::map<BlastAsset*, std::vector<uint32_t>> selectedChunks; + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator itrBlast = m_AssetFamiliesMap.begin(); + for (; itrBlast != m_AssetFamiliesMap.end(); ++itrBlast) + { + std::set<uint32_t> assetChunks; + std::vector<BlastFamily*>& families = itrBlast->second; + std::vector<BlastFamily*>::iterator itrFamily = families.begin(); + for (; itrFamily != families.end(); ++itrFamily) + { + std::vector<uint32_t> familyChunks = (*itrFamily)->getSelectedChunks(); + for (std::vector<uint32_t>::iterator itrChunk = familyChunks.begin(); itrChunk != familyChunks.end(); ++itrChunk) + { + assetChunks.insert(*itrChunk); + } + } + + if (assetChunks.size() == 0) + continue; + + std::vector<uint32_t> vecAssetChunks; + for (std::set<uint32_t>::iterator itrChunk = assetChunks.begin(); itrChunk != assetChunks.end(); ++itrChunk) + { + vecAssetChunks.push_back(*itrChunk); + } + + selectedChunks.insert(std::make_pair(itrBlast->first, vecAssetChunks)); + } + + return selectedChunks; +} + +void SampleManager::clearChunksSelected() +{ + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator itr = m_AssetFamiliesMap.begin(); + for (; itr != m_AssetFamiliesMap.end(); ++itr) + { + BlastAsset* pBlastAsset = itr->first; + std::vector<BlastFamily*>& fs = itr->second; + + for (BlastFamily* f : fs) + { + f->clearChunksSelected(); + } + } +} + +void SampleManager::setChunkSelected(std::vector<uint32_t> depths, bool selected) +{ + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator itrBlast = m_AssetFamiliesMap.begin(); + for (; itrBlast != m_AssetFamiliesMap.end(); ++itrBlast) + { + std::vector<BlastFamily*>& families = itrBlast->second; + std::vector<BlastFamily*>::iterator itrFamily = families.begin(); + for (; itrFamily != families.end(); ++itrFamily) + { + (*itrFamily)->setChunkSelected(depths, selected); + } + } +} + +void SampleManager::setChunkVisible(std::vector<uint32_t> depths, bool bVisible) +{ + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator itrBlast = m_AssetFamiliesMap.begin(); + for (; itrBlast != m_AssetFamiliesMap.end(); ++itrBlast) + { + std::vector<BlastFamily*>& families = itrBlast->second; + std::vector<BlastFamily*>::iterator itrFamily = families.begin(); + for (; itrFamily != families.end(); ++itrFamily) + { + (*itrFamily)->setChunkVisible(depths, bVisible); + } + } +} + +void SampleManager::setFractureExecutor(FractureExecutor* executor) +{ + m_fractureExecutor = executor; + if (executor) + { + executor->m_fractureTool = m_fTool; + if (executor->m_randomGenerator == nullptr) + executor->m_randomGenerator = &sRandomGenerator; + } +} + +void SampleManager::setBlastToolType(BlastToolType type) +{ + if (m_ToolType == type) + { + getPhysXController().setPaused(type != BTT_Damage); + return; + } + + // refresh selection + bool needClear = true; + bool currentGizmo = (m_ToolType >= BTT_Translate && m_ToolType <= BTT_Rotation); + bool switchToGizmo = (type >= BTT_Translate && type <= BTT_Rotation); + if (currentGizmo && switchToGizmo) + { + needClear = false; + } + if (needClear) + { + getSelectionToolController().clearSelect(); + getGizmoToolController().resetPos(); + } + + getDamageToolController().getPickPointer()->setHidden(type != BTT_Damage); + getGizmoToolController().showAxisRenderables(switchToGizmo); + getPhysXController().setPaused(type != BTT_Damage); + + getDamageToolController().DisableController(); + getSelectionToolController().DisableController(); + getGizmoToolController().DisableController(); + getEditionToolController().DisableController(); + + switch (type) + { + case BTT_Damage: + { + getDamageToolController().EnableController(); + } + break; + case BTT_Drag: + { + getDamageToolController().EnableController(); + } + break; + case BTT_Select: + { + getSelectionToolController().EnableController(); + } + break; + case BTT_Translate: + { + getGizmoToolController().EnableController(); + getGizmoToolController().setGizmoToolMode(GTM_Translate); + } + break; + case BTT_Scale: + { + getGizmoToolController().EnableController(); + getGizmoToolController().setGizmoToolMode(GTM_Scale); + } + break; + case BTT_Rotation: + { + getGizmoToolController().EnableController(); + getGizmoToolController().setGizmoToolMode(GTM_Rotation); + } + break; + case BTT_Edit: + { + getEditionToolController().EnableController(); + } + break; + default: + break; + } + + m_ToolType = type; +} + +#include <ViewerOutput.h> +void SampleManager::output(const char* str) +{ + viewer_msg("%s", str); +} + +void SampleManager::output(float value) +{ + viewer_msg("%f", value); +} + +void SampleManager::output(physx::PxVec3& vec) +{ + viewer_msg("%f,%f,%f", vec.x, vec.y, vec.z); +} + +void SampleManager::clearScene() +{ + getSceneController().ClearScene(); + m_config.sampleName.clear(); + m_config.assetsFile.clear(); + //m_config.additionalResourcesDir.clear(); + m_config.additionalAssetList.models.clear(); + m_config.additionalAssetList.composites.clear(); + m_config.additionalAssetList.boxes.clear(); + + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator it; + for (it = m_AssetFamiliesMap.begin(); it != m_AssetFamiliesMap.end(); it++) + { + std::vector<BlastFamily*>& fs = it->second; + fs.clear(); + } + m_AssetFamiliesMap.clear(); + m_AssetDescMap.clear(); +} + +bool SampleManager::_createAsset( + const std::string& assetName, + const std::string& outDir, + const std::vector<Nv::Blast::Mesh* >& meshes) +{ + PhysXController& pc = getPhysXController(); + BlastController& bc = getBlastController(); + + physics = &pc.getPhysics(); + foundation = &physics->getFoundation(); + cooking = &pc.getCooking(); + physicsManager = &bc.getExtPxManager(); + TkFramework& tk = bc.getTkFramework(); + + std::ostringstream outBlastFilePathStream; + outBlastFilePathStream << outDir << assetName << ".bpxa"; + std::string outBlastFilePath = outBlastFilePathStream.str(); + + std::vector<NvBlastChunkDesc> chunkDesc; + std::vector<NvBlastBondDesc> bondDescs; + std::vector<std::vector<Triangle> > chunkMeshes; + std::vector<bool> isSupport; + + if (meshes.size() <= 1) + { + size_t nChunkListSize = m_fTool->getChunkList().size(); + chunkMeshes.resize(nChunkListSize); + isSupport.resize(nChunkListSize); + for (uint32_t i = 0; i < nChunkListSize; ++i) + { + m_fTool->getBaseMesh(i, chunkMeshes[i]); + isSupport[i] = m_fTool->getChunkList()[i].isLeaf; + } + } + // If there are more than one mesh, then it seems that it prefractured, lets consider first mesh in meshes as depth 0, other meshes as depth 1 chunks + // we should just build Blast descriptors for such input. + else + { + chunkMeshes.resize(meshes.size()); + std::vector<PxVec3> chunkCentroids(meshes.size(), PxVec3(0, 0, 0)); + + for (uint32_t i = 0; i < meshes.size(); ++i) + { + std::vector<Triangle>& chunk = chunkMeshes[i]; + + Vertex* vbf = meshes[i]->getVertices(); + Edge* ebf = meshes[i]->getEdges(); + + for (uint32_t fc = 0; fc < meshes[i]->getFacetCount(); ++fc) + { + Facet* f = meshes[i]->getFacet(fc); + Triangle tr; + tr.a = vbf[ebf[f->firstEdgeNumber].s]; + tr.b = vbf[ebf[f->firstEdgeNumber + 1].s]; + tr.c = vbf[ebf[f->firstEdgeNumber + 2].s]; + chunk.push_back(tr); + + chunkCentroids[i] += tr.a.p + tr.b.p + tr.c.p; + } + + chunkCentroids[i] *= 1.0f / (3 * meshes[i]->getFacetCount()); + } + + isSupport.resize(chunkMeshes.size()); + chunkDesc.resize(chunkMeshes.size()); + isSupport[0] = false; + + chunkDesc[0].centroid[0] = chunkCentroids[0].x; + chunkDesc[0].centroid[1] = chunkCentroids[0].y; + chunkDesc[0].centroid[2] = chunkCentroids[0].z; + chunkDesc[0].parentChunkIndex = UINT32_MAX; + + for (uint32_t i = 1; i < chunkDesc.size(); ++i) + { + chunkDesc[i].parentChunkIndex = 0; + chunkDesc[i].flags = NvBlastChunkDesc::SupportFlag; + chunkDesc[i].centroid[0] = chunkCentroids[i].x; + chunkDesc[i].centroid[1] = chunkCentroids[i].y; + chunkDesc[i].centroid[2] = chunkCentroids[i].z; + isSupport[i] = true; + } + } + + BlastBondGenerator bondGenerator(cooking, &physics->getPhysicsInsertionCallback()); + + BondGenerationConfig cnf; + cnf.bondMode = BondGenerationConfig::AVERAGE; + + if (meshes.size() > 1) + { + bondGenerator.bondsFromPrefractured(chunkMeshes, isSupport, bondDescs, cnf); + } + else + { + bondGenerator.buildDescFromInternalFracture(m_fTool, isSupport, bondDescs, chunkDesc); + } + + const uint32_t chunkCount = static_cast<uint32_t>(chunkDesc.size()); + const uint32_t bondCount = static_cast<uint32_t>(bondDescs.size()); + if (bondCount == 0) + { + std::cout << "Can't create bonds descriptors..." << std::endl; + } + + // order chunks, build map + std::vector<uint32_t> chunkReorderInvMap; + { + std::vector<uint32_t> chunkReorderMap(chunkCount); + std::vector<char> scratch(chunkCount * sizeof(NvBlastChunkDesc)); + NvBlastEnsureAssetExactSupportCoverage(chunkDesc.data(), chunkCount, scratch.data(), loggingCallback); + NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), chunkDesc.data(), chunkCount, scratch.data(), loggingCallback); + NvBlastApplyAssetDescChunkReorderMapInplace(chunkDesc.data(), chunkCount, bondDescs.data(), bondCount, chunkReorderMap.data(), scratch.data(), loggingCallback); + chunkReorderInvMap.resize(chunkReorderMap.size()); + Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<unsigned int>(chunkReorderMap.size())); + } + + // get result geometry + std::vector<std::vector<Triangle>> resultGeometry(chunkMeshes.size()); + for (uint32_t i = 0; i < chunkMeshes.size(); ++i) + { + uint32_t chunkIndex = chunkReorderInvMap[i]; + resultGeometry[chunkIndex] = chunkMeshes[i]; + } + + // prepare physics data (convexes) + std::vector<ExtPxAssetDesc::ChunkDesc> pxChunks(chunkCount); + std::vector<ExtPxAssetDesc::SubchunkDesc> pxSubchunks; + buildPxChunks(resultGeometry, pxChunks, pxSubchunks); + + // build and serialize ExtPhysicsAsset + ExtPxAssetDesc descriptor; + descriptor.bondCount = bondCount; + descriptor.bondDescs = bondDescs.data(); + descriptor.chunkCount = chunkCount; + descriptor.chunkDescs = chunkDesc.data(); + descriptor.bondFlags = nullptr; + descriptor.pxChunks = pxChunks.data(); + ExtPxAsset* asset = ExtPxAsset::create(descriptor, tk); + if (asset == nullptr) + { + return false; + } + + physx::PsFileBuffer fileBuf(outBlastFilePath.c_str(), physx::PxFileBuf::OPEN_WRITE_ONLY); + if (!asset->serialize(fileBuf, *cooking)) + { + return false; + } + fileBuf.close(); + asset->release(); + + saveFractureToObj(resultGeometry, assetName, outDir); + + m_bNeedConfig = true; + + return true; +} + +void SampleManager::_setSourceAsset() +{ + std::vector<BlastFamilyPtr>& families = m_blastController->getFamilies(); + if (families.size() > 0) + { + BlastFamilyPtr spLastFamily = families.back(); + + m_fTool->setSourceAsset(&(spLastFamily->getBlastAsset())); + } +} + +void SampleManager::addRenderMaterial(RenderMaterial* pRenderMaterial) +{ + if (pRenderMaterial == nullptr) + { + return; + } + + std::string materialName = pRenderMaterial->getMaterialName(); + if (materialName.empty()) + { + return; + } + + m_RenderMaterialMap[materialName] = pRenderMaterial; + + std::string textureFileName = pRenderMaterial->getTextureFileName(); + MaterialLibraryPanel::ins()->addMaterial(materialName, textureFileName); +} + +void SampleManager::removeRenderMaterial(std::string name) +{ + if (name.empty()) + { + return; + } + + std::map<std::string, RenderMaterial*>::iterator it = m_RenderMaterialMap.find(name); + if (it != m_RenderMaterialMap.end()) + { + m_RenderMaterialMap.erase(it); + MaterialLibraryPanel::ins()->removeMaterial(name); + } +} + +void SampleManager::deleteRenderMaterial(std::string name) +{ + if (name.empty()) + { + return; + } + + m_NeedDeleteRenderMaterials.push_back(name); +} + +void SampleManager::renameRenderMaterial(std::string oldName, std::string newName) +{ + if (oldName.empty() || newName.empty()) + { + return; + } + + std::map<std::string, RenderMaterial*>::iterator it = m_RenderMaterialMap.find(oldName); + if (it != m_RenderMaterialMap.end()) + { + RenderMaterial* pRenderMaterial = it->second; + m_RenderMaterialMap.erase(it); + pRenderMaterial->setMaterialName(newName); + m_RenderMaterialMap[newName] = pRenderMaterial; + } +} + +void SampleManager::getCurrentSelectedInstance(BlastAsset** ppBlastAsset, int& index) +{ + *ppBlastAsset = m_pCurBlastAsset; + index = m_nCurFamilyIndex; +} + +void SampleManager::setCurrentSelectedInstance(BlastAsset* pBlastAsset, int index) +{ + m_pCurBlastAsset = pBlastAsset; + m_nCurFamilyIndex = index; + + MaterialAssignmentsPanel::ins()->updateValues(); +} + +void SampleManager::getMaterialForCurrentFamily(RenderMaterial** ppRenderMaterial, bool externalSurface) +{ + if (m_pCurBlastAsset == nullptr || m_nCurFamilyIndex < 0) + { + return; + } + + std::vector<BlastFamily*>& fs = m_AssetFamiliesMap[m_pCurBlastAsset]; + int fsSize = fs.size(); + if (fsSize == 0 || fsSize < m_nCurFamilyIndex) + { + return; + } + + BlastFamily* pBlastFamily = fs[m_nCurFamilyIndex]; + pBlastFamily->getMaterial(ppRenderMaterial, externalSurface); +} + +void SampleManager::setMaterialForCurrentFamily(RenderMaterial* pRenderMaterial, bool externalSurface) +{ + if (m_pCurBlastAsset == nullptr || m_nCurFamilyIndex < 0) + { + return; + } + + std::vector<BlastFamily*>& fs = m_AssetFamiliesMap[m_pCurBlastAsset]; + int fsSize = fs.size(); + if (fsSize == 0 || fsSize < m_nCurFamilyIndex) + { + return; + } + + BlastFamily* pBlastFamily = fs[m_nCurFamilyIndex]; + pBlastFamily->setMaterial(pRenderMaterial, externalSurface); +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleManager.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleManager.h new file mode 100644 index 0000000..e0b0ac9 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/core/SampleManager.h @@ -0,0 +1,302 @@ +/* +* 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 SAMPLE_MANAGER_H +#define SAMPLE_MANAGER_H + +#include "Application.h" +#include "Sample.h" +#include <map> + +class SampleManager; +class BlastFractureTool; +class BlastAsset; +class BlastFamily; +class RenderMaterial; +namespace Nv +{ +namespace Blast +{ + class Mesh; + class RandomGeneratorBase; + class VoronoiSitesGenerator; + struct SlicingConfiguration; +} +} + +class ISampleController : public IApplicationController +{ +public: + + void setManager(SampleManager* manager) + { + m_manager = manager; + } +protected: + + SampleManager* getManager() const + { + return m_manager; + } + +private: + SampleManager* m_manager; +}; + +class FractureExecutor +{ + friend class SampleManager; +public: + FractureExecutor() + : m_fractureTool(0) + , m_chunkId(-1) + , m_randomGenerator(nullptr) + , m_sourMesh(nullptr) + { + } + + virtual bool execute() = 0; + void setSourceMesh(Nv::Blast::Mesh* mesh); + void setSourceAsset(const BlastAsset* blastAsset); + void setTargetChunk(uint32_t chunkId) { m_chunkId = chunkId; } + void setRandomGenerator(Nv::Blast::RandomGeneratorBase* randomGenerator) { m_randomGenerator = randomGenerator; } +protected: + BlastFractureTool* m_fractureTool; + uint32_t m_chunkId; + Nv::Blast::RandomGeneratorBase* m_randomGenerator; + Nv::Blast::Mesh* m_sourMesh; +}; + +class VoronoiFractureExecutor : public FractureExecutor +{ +public: + VoronoiFractureExecutor(); + void setCellsCount(uint32_t cellsCount); + + virtual bool execute(); + +private: + uint32_t m_cellsCount; +}; + +class SliceFractureExecutor : public FractureExecutor +{ +public: + SliceFractureExecutor(); + void applyNoise(float amplitude, float frequency, int32_t octaves, float falloff, int32_t relaxIterations, float relaxFactor, int32_t seed = 0); + void applyConfig(int32_t xSlices, int32_t ySlices, int32_t zSlices, float offsetVariations, float angleVariations); + + virtual bool execute(); + +private: + Nv::Blast::SlicingConfiguration* m_config; +}; + +enum BlastToolType +{ + BTT_Damage = 0, + BTT_Drag, + BTT_Select, + BTT_Translate, + BTT_Scale, + BTT_Rotation, + BTT_Edit, + BTT_Num +}; + +enum SelectMode +{ + SM_RESET = 0, + SM_ADD, + SM_SUB, + SM_REMAIN, +}; + +class Renderer; +class PhysXController; +class BlastController; +class SceneController; +class DamageToolController; +class SelectionToolController; +class GizmoToolController; +class EditionToolController; +class SampleController; +class CommonUIController; +class SimpleRandomGenerator; + +/** +*/ +class SampleManager +{ + friend class VoronoiFractureExecutor; + friend class SliceFractureExecutor; + public: + static SampleManager* ins(); + SampleManager(DeviceManager* pDeviceManager); + ~SampleManager(); + + int init(); + int run(); + int free(); + + void addModelAsset(std::string file, bool isSkinned, physx::PxTransform transform, bool clear = true); + + bool createAsset( + std::string assetName, + std::vector<physx::PxVec3>& positions, + std::vector<physx::PxVec3>& normals, + std::vector<physx::PxVec2>& uv, + std::vector<unsigned int>& indices, + bool fracture = false); + + bool createAsset( + const std::string& assetName, + const std::vector<Nv::Blast::Mesh* >& meshes, + bool fracture = false); + + bool saveAsset(); + bool fractureAsset(std::string& assetName, const BlastAsset* blastAsset, int32_t chunkId); + + bool postProcessCurrentAsset(); + + Renderer& getRenderer() + { + return *m_renderer; + } + + PhysXController& getPhysXController() const + { + return *m_physXController; + } + + BlastController& getBlastController() const + { + return *m_blastController; + } + + SceneController& getSceneController() const + { + return *m_sceneController; + } + + DamageToolController& getDamageToolController() const + { + return *m_damageToolController; + } + + SelectionToolController& getSelectionToolController() const + { + return *m_selectionToolController; + } + + GizmoToolController& getGizmoToolController() const + { + return *m_gizmoToolController; + } + + EditionToolController& getEditionToolController() const + { + return *m_editionToolController; + } + + SampleController& getSampleController() const + { + return *m_sampleController; + } + + CommonUIController& getCommonUIController() const + { + return *m_commonUIController; + } + + const SampleConfig& getConfig() const + { + return m_config; + } + + std::vector<uint32_t> getCurrentSelectedChunks(); + std::map<BlastAsset*, std::vector<uint32_t>> getSelectedChunks(); + void clearChunksSelected(); + void setChunkSelected(std::vector<uint32_t> depths, bool selected); + void setChunkVisible(std::vector<uint32_t> depths, bool bVisible); + + void setFractureExecutor(FractureExecutor* executor); + + void setBlastToolType(BlastToolType type); + + void output(const char* str); + void output(float value); + void output(physx::PxVec3& vec); + + void clearScene(); + + std::map<BlastAsset*, std::vector<BlastFamily*>>& getAssetFamiliesMap() + { + return m_AssetFamiliesMap; + } + std::map<BlastAsset*, AssetList::ModelAsset>& getAssetDescMap() + { + return m_AssetDescMap; + } + + std::map<std::string, RenderMaterial*>& getRenderMaterials(){ return m_RenderMaterialMap; } + void addRenderMaterial(RenderMaterial* pRenderMaterial); + void removeRenderMaterial(std::string name); + void deleteRenderMaterial(std::string name); + void renameRenderMaterial(std::string oldName, std::string newName); + + bool m_bNeedRefreshTree; + + void getCurrentSelectedInstance(BlastAsset** ppBlastAsset, int& index); + void setCurrentSelectedInstance(BlastAsset* pBlastAsset, int index); + void getMaterialForCurrentFamily(RenderMaterial** ppRenderMaterial, bool externalSurface); + void setMaterialForCurrentFamily(RenderMaterial* pRenderMaterial, bool externalSurface); + +private: + bool _createAsset( + const std::string& assetName, + const std::string& outDir, + const std::vector<Nv::Blast::Mesh* >& meshes); + + void _setSourceAsset(); + +private: + Renderer* m_renderer; + PhysXController* m_physXController; + BlastController* m_blastController; + SceneController* m_sceneController; + DamageToolController* m_damageToolController; + SelectionToolController* m_selectionToolController; + GizmoToolController* m_gizmoToolController; + EditionToolController* m_editionToolController; + SampleController* m_sampleController; + CommonUIController* m_commonUIController; + + SampleConfig m_config; + + Application* m_pApplication; + BlastToolType m_ToolType; + + BlastFractureTool* m_fTool; + FractureExecutor* m_fractureExecutor; + + std::map<BlastAsset*, std::vector<BlastFamily*>> m_AssetFamiliesMap; + std::map<BlastAsset*, AssetList::ModelAsset> m_AssetDescMap; + std::map<std::string, RenderMaterial*> m_RenderMaterialMap; + std::vector<std::string> m_NeedDeleteRenderMaterials; + + BlastAsset* m_pCurBlastAsset; + int m_nCurFamilyIndex; + + bool m_bNeedConfig; +}; + + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/physx/PhysXController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/physx/PhysXController.cpp new file mode 100644 index 0000000..5146914 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/physx/PhysXController.cpp @@ -0,0 +1,825 @@ +/* + * 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 "PhysXController.h" +#include "RenderMaterial.h" +#include "ResourceManager.h" +#include "Renderer.h" + +#include "XInput.h" +#include "DXUTMisc.h" +#include "DXUTCamera.h" +#include "ConvexRenderMesh.h" +#include "RenderUtils.h" +#include "SampleProfiler.h" +#include "NvBlastProfiler.h" + +#include "PxPhysicsVersion.h" +#include "PxPvdTransport.h" +#include "PxDefaultCpuDispatcher.h" +#include "PxPhysics.h" +#include "PxScene.h" +#include "PxCooking.h" +#include "PxGpu.h" +#include "PxSimpleFactory.h" +#include "PxRigidBodyExt.h" +#include "PxRigidDynamic.h" +#include "PxRigidStatic.h" +#include "PxMaterial.h" +#include "PxFoundationVersion.h" +#include "PxMath.h" + +#include <imgui.h> +#include <chrono> + +using namespace std::chrono; + +#define PVD_TO_FILE 0 + +const DirectX::XMFLOAT4 PLANE_COLOR(1.0f, 1.0f, 1.0f, 1.0f); +const DirectX::XMFLOAT4 HOOK_LINE_COLOR(1.0f, 1.0f, 1.0f, 1.0f); +const float DEFAULT_FIXED_TIMESTEP = 1.0f / 60.0f; + +PhysXController::PhysXController(PxSimulationFilterShader filterShader) +: m_filterShader(filterShader) +, m_gpuPhysicsAvailable(true) +, m_useGPUPhysics(true) +, m_lastSimulationTime(0) +, m_paused(false) +, m_draggingActor(nullptr) +, m_draggingEnabled(true) +, m_draggingTryReconnect(false) +, m_perfWriter(NULL) +, m_fixedTimeStep(DEFAULT_FIXED_TIMESTEP) +, m_timeAccumulator(0) +, m_useFixedTimeStep(true) +, m_maxSubstepCount(1) +{ + QueryPerformanceFrequency(&m_performanceFreq); + +// Add By Lixu Begin + m_bForce = true; +// Add By Lixu End +} + +PhysXController::~PhysXController() +{ +} + +void PhysXController::onInitialize() +{ + initPhysX(); + initPhysXPrimitives(); +} + +void PhysXController::onTerminate() +{ + releasePhysXPrimitives(); + releasePhysX(); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PhysX init/release +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void PhysXController::initPhysX() +{ + m_foundation = PxCreateFoundation(PX_FOUNDATION_VERSION, m_allocator, m_errorCallback); + + m_pvd = PxCreatePvd(*m_foundation); + + NvBlastProfilerSetCallback(m_pvd); + NvBlastProfilerEnablePlatform(false); + NvBlastProfilerSetDetail(NvBlastProfilerDetail::LOW); + + PxTolerancesScale scale; + + m_physics = PxCreatePhysics(PX_PHYSICS_VERSION, *m_foundation, scale, true, m_pvd); + + PxCookingParams cookingParams(scale); + cookingParams.buildGPUData = true; + m_cooking = PxCreateCooking(PX_PHYSICS_VERSION, m_physics->getFoundation(), cookingParams); + + PxCudaContextManagerDesc ctxMgrDesc; + m_cudaContext = PxCreateCudaContextManager(m_physics->getFoundation(), ctxMgrDesc); + if (m_cudaContext && !m_cudaContext->contextIsValid()) + { + m_cudaContext->release(); + m_cudaContext = NULL; + } + + PxSceneDesc sceneDesc(m_physics->getTolerancesScale()); + sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); + m_dispatcher = PxDefaultCpuDispatcherCreate(4); + sceneDesc.cpuDispatcher = m_dispatcher; + sceneDesc.gpuDispatcher = m_cudaContext != NULL ? m_cudaContext->getGpuDispatcher() : NULL; + sceneDesc.filterShader = m_filterShader; + sceneDesc.flags |= PxSceneFlag::eENABLE_STABILIZATION; + sceneDesc.flags |= PxSceneFlag::eENABLE_PCM; + if (sceneDesc.gpuDispatcher == nullptr) + { + m_gpuPhysicsAvailable = false; + m_useGPUPhysics = false; + } + if (m_useGPUPhysics) + { + sceneDesc.flags |= PxSceneFlag::eENABLE_GPU_DYNAMICS; + sceneDesc.broadPhaseType = PxBroadPhaseType::eGPU; + + sceneDesc.gpuDynamicsConfig.constraintBufferCapacity *= 4; + sceneDesc.gpuDynamicsConfig.contactBufferCapacity *= 4; + sceneDesc.gpuDynamicsConfig.contactStreamSize *= 4; + sceneDesc.gpuDynamicsConfig.forceStreamCapacity *= 4; + sceneDesc.gpuDynamicsConfig.foundLostPairsCapacity *= 4; + sceneDesc.gpuDynamicsConfig.patchStreamSize *= 4; + sceneDesc.gpuDynamicsConfig.tempBufferCapacity *= 4; + + } + m_physicsScene = m_physics->createScene(sceneDesc); + + m_defaultMaterial = m_physics->createMaterial(0.8f, 0.7f, 0.1f); + + PxPvdSceneClient* pvdClient = m_physicsScene->getScenePvdClient(); + if(pvdClient) + { + pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS, true); + pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_CONTACTS, true); + pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true); + } + + m_physicsScene->setVisualizationParameter(PxVisualizationParameter::eSCALE, 0); + +#if NV_DEBUG || NV_CHECKED || NV_PROFILE + PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate("localhost", 5425, 10); + if (transport) + { + m_pvd->connect(*transport, +#if NV_DEBUG || NV_CHECKED + PxPvdInstrumentationFlag::eALL +#else + PxPvdInstrumentationFlag::ePROFILE +#endif + ); + } +#endif +} + +void PhysXController::releasePhysX() +{ + m_defaultMaterial->release(); + m_physicsScene->release(); + if (m_cudaContext) + m_cudaContext->release(); + m_dispatcher->release(); + m_physics->release(); + if (m_pvd) + { + PxPvdTransport* transport = m_pvd->getTransport(); + m_pvd->release(); + if (transport) + transport->release(); + } + m_cooking->release(); + m_foundation->release(); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// GPU toggle +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void PhysXController::setUseGPUPhysics(bool useGPUPhysics) +{ + if (!m_gpuPhysicsAvailable) + { + useGPUPhysics = false; + } + + if (m_useGPUPhysics == useGPUPhysics) + { + return; + } + + onTerminate(); + + m_useGPUPhysics = useGPUPhysics; + + onInitialize(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PhysX wrappers +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +PxRigidDynamic* PhysXController::createRigidDynamic(const PxTransform& transform) +{ + return m_physics->createRigidDynamic(transform); +} + +void PhysXController::releaseRigidDynamic(PxRigidDynamic* rigidDynamic) +{ + notifyRigidDynamicDestroyed(rigidDynamic); + + m_physXActorsToRemove.push_back(rigidDynamic); +} + +void PhysXController::notifyRigidDynamicDestroyed(PxRigidDynamic* rigidDynamic) +{ + if (m_draggingActor == rigidDynamic) + { + m_draggingActor = nullptr; + m_draggingTryReconnect = true; + } +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Controller events +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void PhysXController::Animate(double dt) +{ + PROFILER_SCOPED_FUNCTION(); + +// Add By Lixu Begin + if (m_paused && !m_bForce) + return; + if (m_bForce) + { + m_paused = true; + m_bForce = false; + } +// Add By Lixu End + + // slower physics if fps is too low + dt = PxClamp(dt, 0.0, 0.033333); + + updateDragging(dt); + + { + PROFILER_SCOPED("PhysX simulate"); + steady_clock::time_point start = steady_clock::now(); + if (m_useFixedTimeStep) + { + m_timeAccumulator += dt; + m_substepCount = (uint32_t)std::floor(m_timeAccumulator / m_fixedTimeStep); + m_timeAccumulator -= m_fixedTimeStep * m_substepCount; + m_substepCount = m_maxSubstepCount > 0 ? physx::PxClamp<uint32_t>(m_substepCount, 0, m_maxSubstepCount) : m_substepCount; + for (uint32_t i = 0; i < m_substepCount; ++i) + { + PROFILER_SCOPED("PhysX simulate (substep)"); + m_physicsScene->simulate(m_fixedTimeStep); + m_physicsScene->fetchResults(true); + } + } + else + { + m_substepCount = 1; + m_physicsScene->simulate(dt); + m_physicsScene->fetchResults(true); + } + m_lastSimulationTime = duration_cast<microseconds>(steady_clock::now() - start).count() * 0.000001; + } + + PROFILER_BEGIN("Debug Render Buffer"); + getRenderer().queueRenderBuffer(&m_physicsScene->getRenderBuffer()); + PROFILER_END(); + + updateActorTransforms(); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Dragging +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void PhysXController::setDraggingEnabled(bool enabled) +{ + m_draggingEnabled = enabled; + + if (!m_draggingEnabled) + { + m_draggingActor = nullptr; + } +} + +void PhysXController::updateDragging(double dt) +{ + PROFILER_SCOPED_FUNCTION(); + + // If dragging actor was recently removed we try to reconnect to new one once, using previous hook world point. + // Often it is removed because it was split into smaller chunks (actors), so we wont to stay connected for nicer user experience. + if (m_draggingActor == nullptr && m_draggingTryReconnect) + { + class OverlapCallback : public PxOverlapBufferN<32> + { + public: + OverlapCallback() : hitActor(nullptr) {} + + PxAgain processTouches(const PxOverlapHit* buffer, PxU32 nbHits) + { + for (PxU32 i = 0; i < nbHits; ++i) + { + PxRigidDynamic* rigidDynamic = buffer[i].actor->is<PxRigidDynamic>(); + if (rigidDynamic) + { + hitActor = rigidDynamic; + break; + } + } + return true; + } + + PxRigidDynamic* hitActor; + }; + + OverlapCallback overlapCallback; + PxSphereGeometry sphere(0.15f); + bool isHit = getPhysXScene().overlap(sphere, PxTransform(m_draggingActorLastHookWorldPoint), overlapCallback, PxQueryFilterData(PxQueryFlag::eDYNAMIC)); + if (isHit && overlapCallback.hitActor) + { + m_draggingActor = overlapCallback.hitActor; + } + + m_draggingTryReconnect = false; + } + + // Update dragging force and debug render (line) + if (m_draggingEnabled && m_draggingActor != NULL) + { + const float DRAGGING_FORCE_FACTOR = 10.0f; + const float DRAGGING_VELOCITY_FACTOR = 2.0f; + PxVec3 attractionPoint = m_dragAttractionPoint; + PxVec3 hookPoint = m_draggingActor->getGlobalPose().transform(m_draggingActorHookLocalPoint); + m_draggingActorLastHookWorldPoint = hookPoint; + m_dragVector = (m_dragAttractionPoint - hookPoint); + PxVec3 dragVeloctiy = (m_dragVector * DRAGGING_FORCE_FACTOR - DRAGGING_VELOCITY_FACTOR * m_draggingActor->getLinearVelocity()) * dt; + PxRigidBodyExt::addForceAtLocalPos(*m_draggingActor, dragVeloctiy * m_draggingActor->getMass(), m_draggingActorHookLocalPoint, PxForceMode::eIMPULSE, true); + + // debug render line + m_dragDebugRenderBuffer.clear(); + m_dragDebugRenderBuffer.m_lines.push_back(PxDebugLine(attractionPoint, hookPoint, XMFLOAT4ToU32Color(HOOK_LINE_COLOR))); + getRenderer().queueRenderBuffer(&m_dragDebugRenderBuffer); + } +} + +void PhysXController::resetDragging() +{ + m_draggingActor = nullptr; +} + + +LRESULT PhysXController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PROFILER_SCOPED_FUNCTION(); + + if (m_draggingEnabled && (uMsg == WM_LBUTTONDOWN || uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONUP)) + { + float mouseX = (short)LOWORD(lParam) / getRenderer().getScreenWidth(); + float mouseY = (short)HIWORD(lParam) / getRenderer().getScreenHeight(); + + PxVec3 eyePos, pickDir; + getEyePoseAndPickDir(mouseX, mouseY, eyePos, pickDir); + pickDir = pickDir.getNormalized(); + + if (uMsg == WM_LBUTTONDOWN) + { + if (pickDir.magnitude() > 0) + { + PxRaycastHit hit; + PxRaycastBuffer rcBuffer(&hit, 1); + bool isHit = getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, rcBuffer, PxHitFlag::ePOSITION, PxQueryFilterData(PxQueryFlag::eDYNAMIC)); + if (isHit) + { + m_dragDistance = (eyePos - hit.position).magnitude(); + m_draggingActor = hit.actor->is<PxRigidDynamic>(); + m_draggingActorHookLocalPoint = m_draggingActor->getGlobalPose().getInverse().transform(hit.position); + m_draggingActor->setLinearVelocity(PxVec3(0, 0, 0)); + m_draggingActor->setAngularVelocity(PxVec3(0, 0, 0)); + m_dragAttractionPoint = hit.position; + } + } + } + else if (uMsg == WM_MOUSEMOVE) + { + PxRaycastHit hit; + PxRaycastBuffer rcBuffer(&hit, 1); + bool isHit = getPhysXScene().raycast(eyePos, pickDir, PX_MAX_F32, rcBuffer, PxHitFlag::ePOSITION, PxQueryFilterData(PxQueryFlag::eSTATIC)); + if (isHit) + { + m_dragDistance = PxMin(m_dragDistance, (eyePos - hit.position).magnitude()); + } + + m_dragAttractionPoint = eyePos + pickDir * m_dragDistance; + } + else if (uMsg == WM_LBUTTONUP) + { + m_draggingActor = NULL; + } + } + + return 1; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// UI +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void PhysXController::drawUI() +{ + ImGui::Checkbox("Use Fixed Timestep", &m_useFixedTimeStep); + if (m_useFixedTimeStep) + { + ImGui::InputFloat("Fixed Timestep", &m_fixedTimeStep); + ImGui::InputInt("Max Substep Count", &m_maxSubstepCount); + } + + ImGui::Text("Substep Count: %d", m_substepCount); + ImGui::Text("Simulation Time (total): %4.2f ms", getLastSimulationTime() * 1000); + ImGui::Text("Simulation Time (substep): %4.2f ms", m_substepCount > 0 ? (getLastSimulationTime() / m_substepCount) * 1000 : 0.0); +} + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PhysX Primitive +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void PhysXController::initPhysXPrimitives() +{ + // physx primitive render materials + { +// Add By Lixu Begin + m_physXPrimitiveRenderMaterial = new RenderMaterial("", getRenderer().getResourceManager(), "physx_primitive", ""); + m_physXPlaneRenderMaterial = new RenderMaterial("", getRenderer().getResourceManager(), "physx_primitive_plane", ""); + m_physXPrimitiveTransparentRenderMaterial = new RenderMaterial("", getRenderer().getResourceManager(), "physx_primitive_transparent", "", RenderMaterial::BLEND_ALPHA_BLENDING); +// Add By Lixu End + } + + // create plane + Actor* plane = spawnPhysXPrimitivePlane(PxPlane(PxVec3(0, 1, 0).getNormalized(), 0)); + plane->setColor(PLANE_COLOR); +} + +void PhysXController::releasePhysXPrimitives() +{ + // remove all actors + for (std::set<Actor*>::iterator it = m_actors.begin(); it != m_actors.end(); it++) + { + delete (*it); + } + m_actors.clear(); + + // remove all materials + SAFE_DELETE(m_physXPrimitiveRenderMaterial); + SAFE_DELETE(m_physXPlaneRenderMaterial); + SAFE_DELETE(m_physXPrimitiveTransparentRenderMaterial); + + // remove all convex render meshes + for (auto it = m_convexRenderMeshes.begin(); it != m_convexRenderMeshes.end(); it++) + { + SAFE_DELETE((*it).second); + } + m_convexRenderMeshes.clear(); +} + +void PhysXController::updateActorTransforms() +{ + PROFILER_SCOPED_FUNCTION(); + + for (std::set<Actor*>::iterator it = m_actors.begin(); it != m_actors.end(); it++) + { + (*it)->update(); + } +} + +PhysXController::Actor* PhysXController::spawnPhysXPrimitiveBox(const PxTransform& position, PxVec3 extents, float density) +{ + PxBoxGeometry geom = PxBoxGeometry(extents); + PxRigidDynamic* actor = PxCreateDynamic(*m_physics, position, geom, *m_defaultMaterial, density); + + return spawnPhysXPrimitive(actor); +} + +PhysXController::Actor* PhysXController::spawnPhysXPrimitivePlane(const PxPlane& plane) +{ + PxRigidStatic* actor = PxCreatePlane(*m_physics, plane, *m_defaultMaterial); + PhysXController::Actor* p = spawnPhysXPrimitive(actor, true, true); + return p; +} + +PhysXController::Actor* PhysXController::spawnPhysXPrimitive(PxRigidActor* actor, bool addToScene, bool ownPxActor) +{ + if (addToScene) + { + m_physicsScene->addActor(*actor); + } + + Actor* a = new Actor(this, actor, ownPxActor); + + m_actors.emplace(a); + + return a; +} + +void PhysXController::removePhysXPrimitive(Actor* actor) +{ + if (m_actors.find(actor) == m_actors.end()) + return; + + m_actors.erase(actor); + + if (!actor->ownsPxActor()) + { + m_physXActorsToRemove.push_back(actor->getActor()); + } + + if (m_draggingActor == actor->getActor()) + { + m_draggingActor = nullptr; + } + + delete actor; +} + +void PhysXController::removeUnownedPhysXActors() +{ + if (m_physXActorsToRemove.size()) + { + m_physicsScene->removeActors(&m_physXActorsToRemove[0], (PxU32)m_physXActorsToRemove.size()); + for (size_t i = 0; i < m_physXActorsToRemove.size(); ++i) + { + m_physXActorsToRemove[i]->release(); + } + m_physXActorsToRemove.resize(0); + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Actor +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +PhysXController::Actor::Actor(PhysXController* controller, PxRigidActor* actor, bool ownPxActor) : + m_controller(controller), + m_ownPxActor(ownPxActor), + m_hidden(false) +{ + m_actor = actor; + + uint32_t shapesCount = actor->getNbShapes(); + m_shapes.resize(shapesCount); + actor->getShapes(&m_shapes[0], shapesCount); + + m_renderables.resize(m_shapes.size()); + for (uint32_t i = 0; i < m_shapes.size(); i++) + { + PxShape* shape = m_shapes[i]; + IRenderMesh* mesh = m_controller->getRenderMeshForShape(shape); + RenderMaterial* material = shape->getGeometryType() == PxGeometryType::ePLANE ? m_controller->m_physXPlaneRenderMaterial : m_controller->m_physXPrimitiveRenderMaterial; + m_renderables[i] = m_controller->getRenderer().createRenderable(*mesh, *material); + m_renderables[i]->setScale(m_controller->getMeshScaleForShape(shape)); + } +} + +PhysXController::Actor::~Actor() +{ + for (uint32_t i = 0; i < m_renderables.size(); i++) + { + m_controller->getRenderer().removeRenderable(m_renderables[i]); + } + if (m_ownPxActor) + { + m_actor->release(); + } +} + +void PhysXController::Actor::setColor(DirectX::XMFLOAT4 color) +{ + m_color = color; + + for (uint32_t i = 0; i < m_renderables.size(); i++) + { + m_renderables[i]->setColor(color); + } +} + +void PhysXController::Actor::setHidden(bool hidden) +{ + m_hidden = hidden; + + for (uint32_t i = 0; i < m_renderables.size(); i++) + { + m_renderables[i]->setHidden(hidden); + } +} + +void PhysXController::Actor::update() +{ + for (uint32_t i = 0; i < m_renderables.size(); i++) + { + m_renderables[i]->setTransform(m_actor->getGlobalPose() * m_shapes[i]->getLocalPose()); + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PhysX Shapes Renderer +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +IRenderMesh* PhysXController::getConvexRenderMesh(const PxConvexMesh* mesh) +{ + auto it = m_convexRenderMeshes.find(mesh); + if (it != m_convexRenderMeshes.end()) + { + return (*it).second; + } + else + { + ConvexRenderMesh* renderMesh = new ConvexRenderMesh(mesh); + m_convexRenderMeshes[mesh] = renderMesh; + return renderMesh; + } +} + +IRenderMesh* PhysXController::getRenderMeshForShape(const PxShape* shape) +{ + switch (shape->getGeometryType()) + { + case PxGeometryType::eBOX: + return getRenderer().getPrimitiveRenderMesh(PrimitiveRenderMeshType::Box); + case PxGeometryType::ePLANE: + return getRenderer().getPrimitiveRenderMesh(PrimitiveRenderMeshType::Plane); + case PxGeometryType::eSPHERE: + return getRenderer().getPrimitiveRenderMesh(PrimitiveRenderMeshType::Sphere); + case PxGeometryType::eCONVEXMESH: + { + PxConvexMeshGeometry geom; + shape->getConvexMeshGeometry(geom); + return getConvexRenderMesh(geom.convexMesh); + } + default: + PX_ALWAYS_ASSERT_MESSAGE("Unsupported PxGeometryType"); + return NULL; + } +} + +PxVec3 PhysXController::getMeshScaleForShape(const PxShape* shape) +{ + switch (shape->getGeometryType()) + { + case PxGeometryType::eBOX: + { + PxBoxGeometry boxGeom; + shape->getBoxGeometry(boxGeom); + return boxGeom.halfExtents; + } + case PxGeometryType::ePLANE: + { + return PxVec3(1, 2000, 2000); + } + case PxGeometryType::eSPHERE: + { + PxSphereGeometry sphereGeom; + shape->getSphereGeometry(sphereGeom); + return PxVec3(sphereGeom.radius, sphereGeom.radius, sphereGeom.radius); + } + case PxGeometryType::eCONVEXMESH: + { + PxConvexMeshGeometry convexGeom; + shape->getConvexMeshGeometry(convexGeom); + return convexGeom.scale.scale; // maybe incorrect because of rotation not used + } + default: + return PxVec3(1, 1, 1); + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Utils +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +PxVec3 unproject(PxMat44& proj, PxMat44& view, float x, float y) +{ + PxVec4 screenPoint(x, y, 0, 1); + PxVec4 viewPoint = PxVec4(x / proj[0][0], y / proj[1][1], 1, 1); + PxVec4 nearPoint = view.inverseRT().transform(viewPoint); + if (nearPoint.w) + nearPoint *= 1.0f / nearPoint.w; + return PxVec3(nearPoint.x, nearPoint.y, nearPoint.z); +} + + +void PhysXController::getEyePoseAndPickDir(float mouseX, float mouseY, PxVec3& eyePos, PxVec3& pickDir) +{ + PxMat44 view = XMMATRIXToPxMat44(getRenderer().getCamera().GetViewMatrix()); + PxMat44 proj = XMMATRIXToPxMat44(getRenderer().getCamera().GetProjMatrix()); + + PxMat44 eyeTransform = view.inverseRT(); + eyePos = eyeTransform.getPosition(); + PxVec3 nearPos = unproject(proj, view, mouseX * 2 - 1, 1 - mouseY * 2); + pickDir = nearPos - eyePos; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Add By Lixu Begin +#include "PxExtensionsAPI.h" +#include "PxDefaultStreams.h" +#include "PxCollectionExt.h" +// export collision as RepX. In exported file, it includes collisions as convexMesh. But for Rigidbodies, it will only export those exists. +// if export as file A before damaging, it exports all of the chunks as convexMeshes. And Chunk 0 as Dynamic rigid body. +// if export as file B after damaging and fracturing in the middle of simulation, it exports all of the chunks as convexMeshes. And the existing chunks as dynamic rigid bodies. +bool PhysXController::ExportCollisionRepX(const char* fname, physx::PxPhysics* pSDK, physx::PxScene* pScene, bool asBinary) +{ + if ((pSDK == NULL) || (pScene == NULL) || (fname == NULL)) + return false; + + int count = pSDK->getNbScenes(); + assert(count == 1); + + physx::PxSerializationRegistry* psr = physx::PxSerialization::createSerializationRegistry(*pSDK); + + physx::PxCollection* collectionSdk = physx::PxCollectionExt::createCollection(*pSDK); + PX_ASSERT(collectionSdk); + + physx::PxCollection* collectionScene = physx::PxCollectionExt::createCollection(*pScene); + PX_ASSERT(collectionScene); + + collectionSdk->add(*collectionScene); + physx::PxSerialization::complete(*collectionSdk, *psr, NULL, true); + + physx::PxDefaultFileOutputStream theStream(fname); + bool exportNames = true; + bool bExportOk = false; + if (asBinary) + bExportOk = physx::PxSerialization::serializeCollectionToBinary(theStream, *collectionSdk, *psr, NULL, exportNames); + else + bExportOk = physx::PxSerialization::serializeCollectionToXml(theStream, *collectionSdk, *psr); + + if (!bExportOk) + { + std::string warning = "Fail to save scene: "; + warning += fname; + warning += "!"; + MessageBoxA(NULL, warning.c_str(), "", MB_OK | MB_ICONWARNING); + bExportOk = false; + } + + collectionScene->release(); + collectionSdk->release(); + + psr->release(); + + return bExportOk; +} + +// we have to clear those convexMeshes when init scene. if not, they increase. +void PhysXController::ClearOldCOllisions() +{ + physx::PxU32 size = m_physics->getNbShapes(); + if (size > 0) + { + physx::PxShape** pShapes = new physx::PxShape*[size]; + memset(pShapes, 0, size); // clear + physx::PxU32 count = m_physics->getShapes(pShapes, size); + for (physx::PxU32 i = 0; i < count; i++) + { + physx::PxShape& shape = *pShapes[i]; + PxGeometryType::Enum type = shape.getGeometryType(); + if (type == PxGeometryType::eCONVEXMESH) + shape.release(); + } + delete[] pShapes; + size = m_physics->getNbShapes(); + } + // release convexMesh + size = m_physics->getNbConvexMeshes(); + if (size > 0) + { + physx::PxConvexMesh** pConvex = new physx::PxConvexMesh*[size]; + memset(pConvex, 0, size); // clear + physx::PxU32 count = m_physics->getConvexMeshes(pConvex, size); + for (physx::PxU32 i = 0; i < count; i++) + { + pConvex[i]->release(); + } + delete[] pConvex; + size = m_physics->getNbConvexMeshes(); + } +} +// Add By Lixu Begin diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/physx/PhysXController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/physx/PhysXController.h new file mode 100644 index 0000000..2473526 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/physx/PhysXController.h @@ -0,0 +1,296 @@ +/* +* 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 PHYSX_CONTROLLER_H +#define PHYSX_CONTROLLER_H + +#include "SampleManager.h" +#include <DirectXMath.h> +#include "DebugRenderBuffer.h" +#include "PxFiltering.h" +#include "PxDefaultAllocator.h" +#include "PxDefaultErrorCallback.h" +#include <set> +#include <map> + + +using namespace physx; + +class PerformanceDataWriter; +class RenderMaterial; +class Renderable; +class IRenderMesh; + +namespace physx +{ +class PxCpuDispatcher; +class PxFoundation; +class PxDefaultAllocator; +class PxDefaultErrorCallback; +class PxPhysics; +class PxCooking; +class PxPvd; +class PxCudaContextManager; +class PxDefaultCpuDispatcher; +} + + +/** +SampleController which manages all the PhysX related work: +1. initialization, scene updates, release. +2. it can create update and render physx primitives. They are represented by PhysXController::Actor, see public API. +3. provides ability to drag actors by mouse or other similar input + +NOTE: this class does too much, probably should be split in a few smaller ones. +*/ +class PhysXController : public ISampleController +{ + public: + + //////// Actor //////// + + class Actor + { + public: + + Actor(PhysXController* controller, PxRigidActor* actor, bool ownPxActor = true); + ~Actor(); + + void setColor(DirectX::XMFLOAT4 color); + DirectX::XMFLOAT4 getColor() const { return m_color; } + + bool isHidden() { return m_hidden; } + void setHidden(bool hidden); + + void update(); + PxRigidActor* getActor() const { return m_actor; } + + bool ownsPxActor() const { return m_ownPxActor; } + + private: + PhysXController* m_controller; + PxRigidActor* m_actor; + std::vector<PxShape*> m_shapes; + + std::vector<Renderable*> m_renderables; + DirectX::XMFLOAT4 m_color; + + bool m_hidden; + bool m_ownPxActor; + }; + + + //////// ctor //////// + + PhysXController(PxSimulationFilterShader filterShader); + virtual ~PhysXController(); + + + //////// virtual callbacks //////// + + virtual void onInitialize(); + virtual void onTerminate(); + + virtual void Animate(double dt); + + virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + + //////// public API //////// + + void getEyePoseAndPickDir(float mouseX, float mouseY, PxVec3& eyePos, PxVec3& pickDir); + + // wrappers to physx calls + PxRigidDynamic* createRigidDynamic(const PxTransform& transform); + void releaseRigidDynamic(PxRigidDynamic*); + + Actor* spawnPhysXPrimitiveBox(const PxTransform& position, PxVec3 extents = PxVec3(1, 1, 1), float density = 2000.0f); + Actor* spawnPhysXPrimitivePlane(const PxPlane& plane); + Actor* spawnPhysXPrimitive(PxRigidActor* actor, bool addToScene = true, bool ownPxActor = true); + void removePhysXPrimitive(Actor*); + + IRenderMesh* getConvexRenderMesh(const PxConvexMesh* mesh); + IRenderMesh* getRenderMeshForShape(const PxShape* shape); + PxVec3 getMeshScaleForShape(const PxShape* shape); + + void removeUnownedPhysXActors(); + + bool isPaused() const + { + return m_paused; + } + + void setPaused(bool paused) + { + m_paused = paused; + } + + void setDraggingEnabled(bool enabled); + bool getDraggingEnabled() const { return m_draggingEnabled; } + void resetDragging(); + + void notifyRigidDynamicDestroyed(PxRigidDynamic*); + + void drawUI(); + + //////// public getters //////// + + double getLastSimulationTime() const + { + return m_lastSimulationTime; + } + + RenderMaterial* getPrimitiveRenderMaterial() + { + return m_physXPrimitiveRenderMaterial; + } + +// Add By Lixu Begin + bool ExportCollisionRepX(const char* fname, physx::PxPhysics* pSDK, physx::PxScene* pScene, bool asBinary); + void ClearOldCOllisions(); + RenderMaterial* getFBXRenderMaterial() + { + return m_physXPlaneRenderMaterial; + } + bool m_bForce; +// Add By Lixu End + + PxPhysics& getPhysics() const + { + return *m_physics; + } + + PxScene& getPhysXScene() const + { + return *m_physicsScene; + } + + PxMaterial* getDefaultMaterial() const + { + return m_defaultMaterial; + } + + PxCooking& getCooking() const + { + return *m_cooking; + } + + PxDefaultCpuDispatcher* getCPUDispatcher() const + { + return m_dispatcher; + } + + void setPerformanceWriter(PerformanceDataWriter* perfWriter) + { + m_perfWriter = perfWriter; + } + + bool getGPUPhysicsAvailable() const + { + return m_gpuPhysicsAvailable; + } + + void setUseGPUPhysics(bool useGPUPhysics); + + bool getUseGPUPhysics() const + { + return m_useGPUPhysics; + } + + const PxVec3& getDragActorHookLocalPoint() const + { + return m_draggingActorHookLocalPoint; + } + + const PxVec3& getDragVector() const + { + return m_dragVector; + } + + PxRigidDynamic* getDraggingActor() const + { + return m_draggingActor; + } + + private: + //////// internal methods //////// + + void initPhysX(); + void releasePhysX(); + + void initPhysXPrimitives(); + void releasePhysXPrimitives(); + void updateActorTransforms(); + void updateDragging(double dt); + + + //////// used controllers //////// + + Renderer& getRenderer() const + { + return getManager()->getRenderer(); + } + + + //////// internal data //////// + + // PhysX + PxFoundation* m_foundation; + PxDefaultAllocator m_allocator; + PxDefaultErrorCallback m_errorCallback; + PxPhysics* m_physics; + PxCooking* m_cooking; + PxPvd* m_pvd; + PxCudaContextManager* m_cudaContext; + PxDefaultCpuDispatcher* m_dispatcher; + PxMaterial* m_defaultMaterial; + PxSimulationFilterShader m_filterShader; + PxScene* m_physicsScene; + + // PhysX API related + std::vector<PxActor*> m_physXActorsToRemove; + + // primitives/actors + std::set<Actor*> m_actors; + std::map<const PxConvexMesh*, IRenderMesh*> m_convexRenderMeshes; + RenderMaterial* m_physXPrimitiveRenderMaterial; + RenderMaterial* m_physXPlaneRenderMaterial; + RenderMaterial* m_physXPrimitiveTransparentRenderMaterial; + + // simulation + bool m_gpuPhysicsAvailable; + bool m_useGPUPhysics; + double m_lastSimulationTime; + LARGE_INTEGER m_performanceFreq; + bool m_paused; + bool m_useFixedTimeStep; + float m_fixedTimeStep; + float m_timeAccumulator; + uint32_t m_substepCount; + int32_t m_maxSubstepCount; + + // dragging + bool m_draggingEnabled; + PxRigidDynamic* m_draggingActor; + PxVec3 m_draggingActorHookLocalPoint; + PxVec3 m_dragAttractionPoint; + PxVec3 m_dragVector; + float m_dragDistance; + DebugRenderBuffer m_dragDebugRenderBuffer; + PxVec3 m_draggingActorLastHookWorldPoint; + bool m_draggingTryReconnect; + + // Performance writer + PerformanceDataWriter* m_perfWriter; + + +}; + +#endif diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ConvexRenderMesh.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ConvexRenderMesh.cpp new file mode 100644 index 0000000..074cc2d --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ConvexRenderMesh.cpp @@ -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. +*/ + +#include "ConvexRenderMesh.h" +#include "Renderer.h" +#include "PxConvexMesh.h" + + +struct Vertex +{ + PxVec3 position; + PxVec3 normal; +}; + +ConvexRenderMesh::ConvexRenderMesh(const PxConvexMesh* mesh) +{ + const uint32_t nbPolygons = mesh->getNbPolygons(); + const uint8_t* indexBuffer = mesh->getIndexBuffer(); + const PxVec3* meshVertices = mesh->getVertices(); + + uint32_t nbVerts = 0; + uint32_t nbFaces = 0; + + for (uint32_t i = 0; i < nbPolygons; i++) + { + PxHullPolygon data; + mesh->getPolygonData(i, data); + uint32_t nbPolyVerts = data.mNbVerts; + nbVerts += nbPolyVerts; + nbFaces += (nbPolyVerts - 2) * 3; + } + + std::vector<Vertex> vertices; + std::vector<uint16_t> faces; + + vertices.resize(nbVerts); + faces.resize(nbFaces); + + uint32_t vertCounter = 0; + uint32_t facesCounter = 0; + for (uint32_t i = 0; i < nbPolygons; i++) + { + PxHullPolygon data; + mesh->getPolygonData(i, data); + + PxVec3 normal(data.mPlane[0], data.mPlane[1], data.mPlane[2]); + + uint32_t vI0 = vertCounter; + for (uint32_t vI = 0; vI < data.mNbVerts; vI++) + { + vertices[vertCounter].position = meshVertices[indexBuffer[data.mIndexBase + vI]]; + vertices[vertCounter].normal = normal; + vertCounter++; + } + + for (uint32_t vI = 1; vI < uint32_t(data.mNbVerts) - 1; vI++) + { + faces[facesCounter++] = uint16_t(vI0); + faces[facesCounter++] = uint16_t(vI0 + vI + 1); + faces[facesCounter++] = uint16_t(vI0 + vI); + } + } + + std::vector<D3D11_INPUT_ELEMENT_DESC> layout; + layout.push_back({ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + layout.push_back({ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + + initialize(vertices.data(), (uint32_t)vertices.size(), sizeof(Vertex), layout, faces.data(), nbFaces); +} + + +ConvexRenderMesh::~ConvexRenderMesh() +{ +} + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ConvexRenderMesh.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ConvexRenderMesh.h new file mode 100644 index 0000000..dfe8d8f --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ConvexRenderMesh.h @@ -0,0 +1,34 @@ +/* +* 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 CONVEX_RENDER_MESH_H +#define CONVEX_RENDER_MESH_H + +#include "CustomRenderMesh.h" + +namespace physx +{ +class PxConvexMesh; +} + + +/** +PxConvexMesh render mesh +(this class relates to PhysX more then to Renderer) +*/ +class ConvexRenderMesh : public CustomRenderMesh +{ +public: + ConvexRenderMesh(const PxConvexMesh* mesh); + virtual ~ConvexRenderMesh(); +}; + + +#endif //CONVEX_RENDER_MESH_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/CustomRenderMesh.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/CustomRenderMesh.cpp new file mode 100644 index 0000000..61ae9e0 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/CustomRenderMesh.cpp @@ -0,0 +1,96 @@ +/* +* 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 "CustomRenderMesh.h" + + +CustomRenderMesh::CustomRenderMesh() + : m_indexBuffer(nullptr) +{ +} + +CustomRenderMesh::CustomRenderMesh(const void* vertices, uint32_t numVertices, uint32_t vertexSize, std::vector<D3D11_INPUT_ELEMENT_DESC>& inputDesc, const uint16_t* faces, uint32_t numFaces) + : m_indexBuffer(nullptr) +{ + initialize(vertices, numVertices, vertexSize, inputDesc, faces, numFaces); +} + +void CustomRenderMesh::initialize(const void* vertices, uint32_t numVertices, uint32_t vertexSize, std::vector<D3D11_INPUT_ELEMENT_DESC>& inputDesc, const uint16_t* faces, uint32_t numFaces) +{ + ID3D11Device* device = GetDeviceManager()->GetDevice(); + + m_inputDesc = inputDesc; + m_numVertices = numVertices; + m_vertexSize = vertexSize; + m_numFaces = numFaces; + + // VB + { + D3D11_SUBRESOURCE_DATA vertexBufferData; + + ZeroMemory(&vertexBufferData, sizeof(vertexBufferData)); + vertexBufferData.pSysMem = vertices; + + D3D11_BUFFER_DESC bufferDesc; + + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.ByteWidth = vertexSize * numVertices; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + V(device->CreateBuffer(&bufferDesc, &vertexBufferData, &m_vertexBuffer)); + } + + // IB + if (faces != nullptr) + { + D3D11_SUBRESOURCE_DATA indexBufferData; + + ZeroMemory(&indexBufferData, sizeof(indexBufferData)); + indexBufferData.pSysMem = faces; + + D3D11_BUFFER_DESC bufferDesc; + + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc.ByteWidth = sizeof(uint16_t) * numFaces; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + V(device->CreateBuffer(&bufferDesc, &indexBufferData, &m_indexBuffer)); + } +} + +CustomRenderMesh::~CustomRenderMesh() +{ + SAFE_RELEASE(m_vertexBuffer); + SAFE_RELEASE(m_indexBuffer); +} + + +void CustomRenderMesh::render(ID3D11DeviceContext& context) const +{ + context.IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + UINT strides[1] = { m_vertexSize }; + UINT offsets[1] = { 0 }; + context.IASetVertexBuffers(0, 1, &m_vertexBuffer, strides, offsets); + + context.IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R16_UINT, 0); + + if (m_indexBuffer) + context.DrawIndexed(m_numFaces, 0, 0); + else + context.Draw(m_numVertices, 0); +} + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/CustomRenderMesh.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/CustomRenderMesh.h new file mode 100644 index 0000000..b0ddea1 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/CustomRenderMesh.h @@ -0,0 +1,41 @@ +/* +* 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 CUSTOM_RENDER_MESH_H +#define CUSTOM_RENDER_MESH_H + +#include "Renderable.h" + + +class CustomRenderMesh : public IRenderMesh +{ +public: + const std::vector<D3D11_INPUT_ELEMENT_DESC>& getInputElementDesc() const { return m_inputDesc; } + void render(ID3D11DeviceContext& context) const; + + CustomRenderMesh(const void* vertices, uint32_t numVertices, uint32_t vertexSize, std::vector<D3D11_INPUT_ELEMENT_DESC>& inputDesc, const uint16_t* faces = nullptr, uint32_t numFaces = 0); + virtual ~CustomRenderMesh(); + +protected: + CustomRenderMesh(); + void initialize(const void* vertices, uint32_t numVertices, uint32_t vertexSize, std::vector<D3D11_INPUT_ELEMENT_DESC>& inputDesc, const uint16_t* faces, uint32_t numFaces); + +private: + ID3D11Buffer* m_vertexBuffer; + ID3D11Buffer* m_indexBuffer; + uint32_t m_numFaces; + uint32_t m_numVertices; + uint32_t m_vertexSize; + + std::vector<D3D11_INPUT_ELEMENT_DESC> m_inputDesc; +}; + + +#endif //CUSTOM_RENDER_MESH_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/DebugRenderBuffer.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/DebugRenderBuffer.h new file mode 100644 index 0000000..7810733 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/DebugRenderBuffer.h @@ -0,0 +1,50 @@ +/* +* 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 DEBUGRENDERBUFFER_H +#define DEBUGRENDERBUFFER_H + +#include "PxRenderBuffer.h" +#include <vector> + +using namespace physx; + + +/** +Simple PxRenderBuffer implementation for easy debug primitives adding +*/ +class DebugRenderBuffer : public PxRenderBuffer +{ +public: + ~DebugRenderBuffer() {} + + virtual PxU32 getNbPoints() const { return 0; } + virtual const PxDebugPoint* getPoints() const { return nullptr; } + + virtual PxU32 getNbLines() const { return static_cast<PxU32>(m_lines.size()); } + virtual const PxDebugLine* getLines() const { return m_lines.data(); } + + virtual PxU32 getNbTriangles() const { return 0; } + virtual const PxDebugTriangle* getTriangles() const { return nullptr; } + + virtual PxU32 getNbTexts() const { return 0; } + virtual const PxDebugText* getTexts() const { return nullptr; } + + virtual void append(const PxRenderBuffer& other) {} + virtual void clear() + { + m_lines.clear(); + } + + std::vector<PxDebugLine> m_lines; +}; + + +#endif //DEBUGRENDERBUFFER_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Mesh.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Mesh.cpp new file mode 100644 index 0000000..cdf63f2 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Mesh.cpp @@ -0,0 +1,13 @@ +/* +* 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 "Mesh.h" + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Mesh.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Mesh.h new file mode 100644 index 0000000..b10f0d6 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Mesh.h @@ -0,0 +1,54 @@ +/* +* 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 MESH_H +#define MESH_H + +#include <vector> +#include "PxVec2.h" +#include "PxVec3.h" + +// Add By Lixu Begin +class MeshBase +// Add By Lixu End +{ + virtual uint32_t getVertexStride() = 0; + // ... TBD +}; + +/** +SimpleMesh: position + normal + uv +We use only this type everywhere, once other versions will be required we should generalize Mesh and refactor code. +*/ +// Add By Lixu Begin +class SimpleMesh : public MeshBase +// Add By Lixu End +{ +public: + + class Vertex + { + public: + physx::PxVec3 position; + physx::PxVec3 normal; + physx::PxVec2 uv; + }; + + virtual uint32_t getVertexStride() { return sizeof(Vertex); } + + std::vector<Vertex> vertices; + std::vector<uint16_t> indices; + + physx::PxVec3 extents; + physx::PxVec3 center; +}; + + +#endif //MESH_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/PrimitiveRenderMesh.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/PrimitiveRenderMesh.cpp new file mode 100644 index 0000000..06c7616 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/PrimitiveRenderMesh.cpp @@ -0,0 +1,284 @@ +/* +* 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 "PrimitiveRenderMesh.h" +#include "Renderer.h" + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Base Mesh internal class +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +PrimitiveRenderMesh::PrimitiveRenderMesh(const float v[], UINT numVertices) +{ + std::vector<D3D11_INPUT_ELEMENT_DESC> layout; + layout.push_back({ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + layout.push_back({ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + + initialize(v, numVertices, sizeof(float) * 6, layout, nullptr, 0); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Box Mesh +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const float boxVertices[] = +{ + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, + + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, + + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, + + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f +}; + +BoxRenderMesh::BoxRenderMesh() : PrimitiveRenderMesh(boxVertices, sizeof(boxVertices) / (6 * sizeof(boxVertices[0]))) {} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Plane Mesh +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const float planeSize = 1.0f; // we use scaling instead +const float planeTilesCount = 1000.0f; + +const float planeVertices[] = +{ + 0, planeSize, planeSize, 1.0f, 0.0f, 0.0f, planeTilesCount, planeTilesCount, + 0, planeSize, -planeSize, 1.0f, 0.0f, 0.0f, planeTilesCount, -planeTilesCount, + 0, -planeSize, -planeSize, 1.0f, 0.0f, 0.0f, -planeTilesCount, -planeTilesCount, + 0, -planeSize, -planeSize, 1.0f, 0.0f, 0.0f, -planeTilesCount, -planeTilesCount, + 0, -planeSize, planeSize, 1.0f, 0.0f, 0.0f, -planeTilesCount, planeTilesCount, + 0, planeSize, planeSize, 1.0f, 0.0f, 0.0f, planeTilesCount, planeTilesCount +}; + +PlaneRenderMesh::PlaneRenderMesh() +{ + std::vector<D3D11_INPUT_ELEMENT_DESC> layout; + layout.push_back({ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + layout.push_back({ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + layout.push_back({ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + + initialize(planeVertices, sizeof(planeVertices) / (8 * sizeof(planeVertices[0])), sizeof(float) * 8, layout, nullptr, 0); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sphere Mesh +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +const uint32_t g_numSlices = 8; // along lines of longitude +const uint32_t g_numStacks = 16; // along lines of latitude + +const uint32_t g_numSphereVertices = (g_numSlices * 2 + 1)*(g_numStacks + 1); +const uint32_t g_numSphereIndices = g_numSlices * 2 * g_numStacks * 6; + +const uint32_t g_numConeVertices = (g_numSlices * 2 + 1) * 2; +const uint32_t g_numConeIndices = g_numSlices * 2 * 6; + +PxVec3 g_spherePositions[g_numSphereVertices]; +uint16_t g_sphereIndices[g_numSphereIndices]; + +void generateSphereMesh(uint16_t slices, uint16_t stacks, PxVec3* positions, uint16_t* indices) +{ + const PxF32 thetaStep = PxPi / stacks; + const PxF32 phiStep = PxTwoPi / (slices * 2); + + PxF32 theta = 0.0f; + + // generate vertices + for (uint16_t y = 0; y <= stacks; ++y) + { + PxF32 phi = 0.0f; + + PxF32 cosTheta = PxCos(theta); + PxF32 sinTheta = PxSin(theta); + + for (uint16_t x = 0; x <= slices * 2; ++x) + { + PxF32 cosPhi = PxCos(phi); + PxF32 sinPhi = PxSin(phi); + + PxVec3 p(cosPhi*sinTheta, cosTheta, sinPhi*sinTheta); + + // write vertex + *(positions++) = p; + + phi += phiStep; + } + + theta += thetaStep; + } + + const uint16_t numRingQuads = 2 * slices; + const uint16_t numRingVerts = 2 * slices + 1; + + // add faces + for (uint16_t y = 0; y < stacks; ++y) + { + for (uint16_t i = 0; i < numRingQuads; ++i) + { + // add a quad + *(indices++) = (y + 0)*numRingVerts + i; + *(indices++) = (y + 1)*numRingVerts + i; + *(indices++) = (y + 1)*numRingVerts + i + 1; + + *(indices++) = (y + 1)*numRingVerts + i + 1; + *(indices++) = (y + 0)*numRingVerts + i + 1; + *(indices++) = (y + 0)*numRingVerts + i; + } + } +} + + +struct SphereVertex +{ + PxVec3 position; + PxVec3 normal; +}; + +SphereRenderMesh::SphereRenderMesh() +{ + generateSphereMesh(g_numSlices, g_numStacks, g_spherePositions, g_sphereIndices); + + std::vector<SphereVertex> vertices; + for (uint32_t i = 0; i < g_numSphereVertices; i++) + { + vertices.push_back({ g_spherePositions[i], g_spherePositions[i] }); + } + + std::vector<D3D11_INPUT_ELEMENT_DESC> layout; + layout.push_back({ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + layout.push_back({ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + + initialize(vertices.data(), (uint32_t)vertices.size(), sizeof(SphereVertex), layout, g_sphereIndices, g_numSphereIndices); +} + + +SphereRenderMesh::~SphereRenderMesh() +{ +} + +// Add By Lixu Begin +const float coneVertices[] = +{ + 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f,//top + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f,//left bottom + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f,//left top + + 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,//top + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//right top + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f,//right bottom + + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f,//top + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f,//left top + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f,//right top + + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,//top + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,//right bottom + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,//left bottom + + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f,//left top + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f,//right bottom + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f,//right top + + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f,//right bottom + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f,//left top + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f,//left bottom +}; + +ConeRenderMesh::ConeRenderMesh() : PrimitiveRenderMesh(coneVertices, sizeof(coneVertices) / (6 * sizeof(coneVertices[0]))) {} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FBX Mesh class +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include <AnimUtil.h> +#include <PxVec2.h> +#include <vector> + +struct FBXVertex +{ + PxVec3 position; + PxVec3 normal; + PxVec2 uv; +}; + +FBXRenderMesh::FBXRenderMesh(MeshDesc* pMeshData) +{ + std::vector<D3D11_INPUT_ELEMENT_DESC> layout; + layout.push_back({ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + layout.push_back({ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + layout.push_back({ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + + std::vector<FBXVertex> vertices; + std::vector<uint16_t> indices; + + for (uint32_t i = 0; i < pMeshData->m_NumVertices; ++i) + { + atcore_float3 pos = pMeshData->m_pVertices[i]; + atcore_float3 vertexNormal = pMeshData->m_pVertexNormals[i]; + atcore_float2 texcoord = pMeshData->m_pTexCoords[i]; + + FBXVertex newVertex; + newVertex.position = physx::PxVec3(pos.x, pos.y, pos.z); + newVertex.normal = physx::PxVec3(vertexNormal.x, vertexNormal.y, vertexNormal.z); + newVertex.uv = physx::PxVec2(texcoord.x, texcoord.y); + + vertices.push_back(newVertex); + } + + for (uint32_t i = 0; i < pMeshData->m_NumTriangles; ++i) + { + indices.push_back(pMeshData->m_pIndices[i * 3 + 0]); + indices.push_back(pMeshData->m_pIndices[i * 3 + 1]); + indices.push_back(pMeshData->m_pIndices[i * 3 + 2]); + } + + initialize(vertices.data(), (uint32_t)vertices.size(), sizeof(FBXVertex), layout, indices.data(), (uint32_t)indices.size()); +} +// Add By Lixu End
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/PrimitiveRenderMesh.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/PrimitiveRenderMesh.h new file mode 100644 index 0000000..0f3f345 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/PrimitiveRenderMesh.h @@ -0,0 +1,81 @@ +/* +* 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 PRIMITIVE_RENDER_MESH_H +#define PRIMITIVE_RENDER_MESH_H + +#include "Utils.h" +#include <DirectXMath.h> + +#include <vector> +#include "Renderable.h" +#include "CustomRenderMesh.h" + + +class PrimitiveRenderMesh : public CustomRenderMesh +{ +protected: + PrimitiveRenderMesh(const float v[], UINT numVertices); +}; + +class BoxRenderMesh : public PrimitiveRenderMesh +{ +public: + BoxRenderMesh(); +}; + + +class PlaneRenderMesh : public CustomRenderMesh +{ +public: + PlaneRenderMesh(); +}; + + +class SphereRenderMesh : public CustomRenderMesh +{ +public: + SphereRenderMesh(); + virtual ~SphereRenderMesh(); +}; + + +// Add By Lixu Begin +class ConeRenderMesh : public PrimitiveRenderMesh +{ +public: + ConeRenderMesh(); +}; + +class MeshDesc; + +class FBXRenderMesh : public CustomRenderMesh +{ +public: + FBXRenderMesh(MeshDesc* pMeshData); +}; +// Add By Lixu End + + +struct PrimitiveRenderMeshType +{ + enum Enum + { + Box, + Plane, + Sphere, +// Add By Lixu Begin + Cone, +// Add By Lixu End + Count + }; +}; + +#endif //PRIMITIVE_RENDER_MESH_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderMaterial.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderMaterial.cpp new file mode 100644 index 0000000..1b90f8f --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderMaterial.cpp @@ -0,0 +1,277 @@ +/* +* 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 "RenderMaterial.h" +#include <DirectXMath.h> +#include "ShaderUtils.h" +#include "Renderer.h" +#include "SampleManager.h" + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// RenderMaterial +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +RenderMaterial::RenderMaterial(const char* materialName, ResourceManager& resourceCallback, const char* shaderFileName, + const char* textureFileName, BlendMode blendMode) +{ +// Add By Lixu Begin + mMaterialName = materialName; + mTextureFileName = textureFileName; + SampleManager::ins()->addRenderMaterial(this); +// Add By Lixu End + + this->initialize(resourceCallback, shaderFileName, textureFileName, blendMode); +} + +void RenderMaterial::initialize(ResourceManager& resourceCallback, const char* shaderFileName, const char* textureFileName, BlendMode blendMode) +{ + std::vector<std::string> v; + v.push_back(shaderFileName); + initialize(resourceCallback, v, textureFileName, blendMode); +} + +void RenderMaterial::initialize(ResourceManager& resourceCallback, std::vector<std::string> shaderFileNames, const char* textureFileName, BlendMode blendMode) +{ + mTextureSRV = nullptr; + mTexture = nullptr; + mBlendState = nullptr; + + for (uint32_t i = 0; i < shaderFileNames.size(); i++) + { + const ShaderFileResource* resource = resourceCallback.requestShaderFile(shaderFileNames[i].c_str()); + if (resource) + { + std::string shaderFilePath = resource->path; + mShaderFilePathes.push_back(shaderFilePath); + } + } + mShaderGroups.reserve(mShaderFilePathes.size()); + + if (!mTextureFileName.empty()) + { + mTexture = resourceCallback.requestTexture(mTextureFileName.c_str()); + } + + setBlending(blendMode); + + reload(); +} + +void RenderMaterial::releaseReloadableResources() +{ + for (std::vector<ShaderGroup*>::iterator it = mShaderGroups.begin(); it != mShaderGroups.end(); it++) + { + delete *it; + } + mShaderGroups.clear(); + +// Add By Lixu Begin + for (std::map<const IRenderMesh*, Instance*>::iterator it = mRenderMeshToInstanceMap.begin(); + it != mRenderMeshToInstanceMap.end(); it++) + { + delete it->second; + } + mRenderMeshToInstanceMap.clear(); +// Add By Lixu End + + SAFE_RELEASE(mTextureSRV); +} + +RenderMaterial::~RenderMaterial() +{ +// Add By Lixu Begin + SampleManager::ins()->removeRenderMaterial(mMaterialName); +// Add By Lixu End + + releaseReloadableResources(); + SAFE_RELEASE(mBlendState); +} + +void RenderMaterial::setBlending(BlendMode blendMode) +{ + mBlendMode = blendMode; + + SAFE_RELEASE(mBlendState); + + D3D11_BLEND_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + + switch (blendMode) + { + case BLEND_NONE: + desc.RenderTarget[0].BlendEnable = FALSE; + desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + break; + case BLEND_ALPHA_BLENDING: + desc.AlphaToCoverageEnable = FALSE; + desc.IndependentBlendEnable = TRUE; + desc.RenderTarget[0].BlendEnable = TRUE; + desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + break; + case BLEND_ADDITIVE: // actually, is's additive by alpha + desc.AlphaToCoverageEnable = FALSE; + desc.IndependentBlendEnable = TRUE; + desc.RenderTarget[0].BlendEnable = TRUE; + desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; + desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; + desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + break; + default: + PX_ALWAYS_ASSERT_MESSAGE("Unknown blend mode"); + } + + ID3D11Device* device = GetDeviceManager()->GetDevice(); + V(device->CreateBlendState(&desc, &mBlendState)); +} + +void RenderMaterial::reload() +{ + releaseReloadableResources(); + + // load shaders + ID3D11Device* device = GetDeviceManager()->GetDevice(); + + for (std::vector<std::string>::iterator it = mShaderFilePathes.begin(); it != mShaderFilePathes.end(); it++) + { + const char* shaderFilePath = (*it).c_str(); + ShaderGroup* shaderGroup = new ShaderGroup(); + V(createShaderFromFile(device, shaderFilePath, "VS", &(shaderGroup->vs), shaderGroup->buffer)); + createShaderFromFile(device, shaderFilePath, "PS", &shaderGroup->ps); + createShaderFromFile(device, shaderFilePath, "GS", &shaderGroup->gs); + mShaderGroups.push_back(shaderGroup); + } + + // load texture + if (mTexture) + { + V(DirectX::CreateShaderResourceView(device, mTexture->image.GetImages(), mTexture->image.GetImageCount(), + mTexture->metaData, &mTextureSRV)); + } +} + + + +RenderMaterial::InstancePtr RenderMaterial::getMaterialInstance(const IRenderMesh* mesh) +{ + // look in cache + auto it = mRenderMeshToInstanceMap.find(mesh); + if (it != mRenderMeshToInstanceMap.end()) + { +// Add By Lixu Begin + /* + if (!(*it).second.expired()) + { + return (*it).second.lock(); + } + */ + return it->second; +// Add By Lixu End + } + + // create new + const std::vector<D3D11_INPUT_ELEMENT_DESC>& descs = mesh->getInputElementDesc(); + RenderMaterial::InstancePtr instance = getMaterialInstance(&descs[0], (uint32_t)descs.size()); + mRenderMeshToInstanceMap[mesh] = instance; + return instance; +} + +RenderMaterial::InstancePtr RenderMaterial::getMaterialInstance(const D3D11_INPUT_ELEMENT_DESC* elementDescs, uint32_t numElements) +{ + ID3D11Device* device = GetDeviceManager()->GetDevice(); + + for (uint32_t i = 0; i < mShaderGroups.size(); i++) + { + if (mShaderGroups[i]->buffer == NULL) + continue; + + ID3D11InputLayout* inputLayout = NULL; + device->CreateInputLayout(elementDescs, numElements, mShaderGroups[i]->buffer->GetBufferPointer(), mShaderGroups[i]->buffer->GetBufferSize(), &inputLayout); + + if (inputLayout) + { + RenderMaterial::InstancePtr materialInstance(new Instance(*this, inputLayout, i)); + return materialInstance; + } + } + PX_ALWAYS_ASSERT(); + return NULL; +} + +void RenderMaterial::Instance::bind(ID3D11DeviceContext& context, uint32_t slot, bool depthStencilOnly) +{ + mMaterial.mShaderGroups[mShaderNum]->Set(&context, !depthStencilOnly); + + context.OMSetBlendState(mMaterial.mBlendState, nullptr, 0xFFFFFFFF); + context.PSSetShaderResources(slot, 1, &(mMaterial.mTextureSRV)); + context.IASetInputLayout(mInputLayout); +} + +bool RenderMaterial::Instance::isValid() +{ + return mMaterial.mShaderGroups.size() > 0 && mMaterial.mShaderGroups[mShaderNum]->IsValid(); +} + +// Add By Lixu Begin +void RenderMaterial::setTextureFileName(std::string textureFileName) +{ + if (mTextureFileName == textureFileName) + { + return; + } + + mTextureFileName = textureFileName; + mTexture = nullptr; + SAFE_RELEASE(mTextureSRV); + + if (mTextureFileName.empty()) + { + return; + } + + std::string searchDir = mTextureFileName; + size_t ind = searchDir.find_last_of('/'); + if (ind > 0) + searchDir = searchDir.substr(0, ind); + + ResourceManager* pResourceManager = ResourceManager::ins(); + pResourceManager->addSearchDir(searchDir.c_str()); + mTexture = pResourceManager->requestTexture(mTextureFileName.c_str()); + if (mTexture == nullptr) + { + return; + } + + ID3D11Device* device = GetDeviceManager()->GetDevice(); + DirectX::CreateShaderResourceView(device, mTexture->image.GetImages(), mTexture->image.GetImageCount(), + mTexture->metaData, &mTextureSRV); +} + +RenderMaterial* g_DefaultRenderMaterial = nullptr; +RenderMaterial* RenderMaterial::getDefaultRenderMaterial() +{ + if (g_DefaultRenderMaterial == nullptr) + { + ResourceManager* pResourceManager = ResourceManager::ins(); + g_DefaultRenderMaterial = new RenderMaterial("", *pResourceManager, "model_simple_ex"); + } + return g_DefaultRenderMaterial; +} +// Add By Lixu End
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderMaterial.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderMaterial.h new file mode 100644 index 0000000..912a81a --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderMaterial.h @@ -0,0 +1,132 @@ +/* +* 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 RENDER_MATERIAL_H +#define RENDER_MATERIAL_H + +#include "Utils.h" +#include "DirectXTex.h" + +#include <string> +#include <vector> +#include <list> +#include <map> +#include <memory> + + +class IRenderMesh; +class ResourceManager; +struct TextureResource; +class Renderable; + + +class RenderMaterial +{ + public: + + enum BlendMode + { + BLEND_NONE, + BLEND_ALPHA_BLENDING, + BLEND_ADDITIVE + }; + + RenderMaterial(const char* materialName, ResourceManager& resourceProvider, const char* shaderFileName, const char* textureFileName = "", BlendMode blendMode = BLEND_NONE); + ~RenderMaterial(); + + void setBlending(BlendMode blendMode); + BlendMode getBlending() const { return mBlendMode; } + + void reload(); + + class Instance + { + public: + Instance(RenderMaterial& material, ID3D11InputLayout* inputLayout, uint32_t shaderNum = 0) : mMaterial(material), mInputLayout(inputLayout), mShaderNum(shaderNum) {} + ~Instance() { SAFE_RELEASE(mInputLayout); } + + bool isValid(); + void bind(ID3D11DeviceContext& context, uint32_t slot, bool depthStencilOnly = false); + RenderMaterial& getMaterial() const { return mMaterial; } + private: + RenderMaterial& mMaterial; + ID3D11InputLayout* mInputLayout; + uint32_t mShaderNum; + }; + +// Add By Lixu Begin + typedef Instance* InstancePtr; + std::string getMaterialName(){ return mMaterialName; } + void setMaterialName(std::string materialName){ mMaterialName = materialName; } + std::string getTextureFileName(){ return mTextureFileName; } + void setTextureFileName(std::string textureFileName); + void addRelatedRenderable(Renderable* pRenderable){ mRelatedRenderables.push_back(pRenderable); } + std::vector<Renderable*>& getRelatedRenderables(){ return mRelatedRenderables; } + static RenderMaterial* getDefaultRenderMaterial(); +// Add By Lixu End + + InstancePtr getMaterialInstance(const IRenderMesh* mesh); + InstancePtr getMaterialInstance(const D3D11_INPUT_ELEMENT_DESC* elementDescs, uint32_t numElements); + + private: + void initialize(ResourceManager& resourceCallback, const char* shaderFileName, const char* textureFileName, BlendMode blendMode); + void initialize(ResourceManager&resourceProvider, std::vector<std::string> shaderFileNames, const char* textureFileName, BlendMode blendMode); + + void releaseReloadableResources(); + + std::string mMaterialName; + std::string mShaderFileName; + std::string mTextureFileName; + + struct ShaderGroup + { + ShaderGroup() : vs(nullptr), gs(nullptr), ps(nullptr), buffer(nullptr) + { + } + ~ShaderGroup() + { + Release(); + } + void Release() + { + SAFE_RELEASE(vs); + SAFE_RELEASE(gs); + SAFE_RELEASE(ps); + SAFE_RELEASE(buffer); + } + void Set(ID3D11DeviceContext* c, bool setPixelShader = true) + { + c->VSSetShader(vs, nullptr, 0); + c->GSSetShader(gs, nullptr, 0); + c->PSSetShader(setPixelShader ? ps : nullptr, nullptr, 0); + } + bool IsValid() + { + return vs != nullptr; + } + ID3D11VertexShader* vs; + ID3D11GeometryShader* gs; + ID3D11PixelShader* ps; + ID3DBlob* buffer; + }; + +// Add By Lixu Begin + std::map<const IRenderMesh*, Instance*> mRenderMeshToInstanceMap; + std::vector<Renderable*> mRelatedRenderables; +// Add By Lixu End + const TextureResource* mTexture; + ID3D11ShaderResourceView* mTextureSRV; + std::vector<std::string> mShaderFilePathes; + std::vector<ShaderGroup*> mShaderGroups; + ID3D11BlendState* mBlendState; + BlendMode mBlendMode; +}; + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderUtils.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderUtils.h new file mode 100644 index 0000000..12df9f2 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RenderUtils.h @@ -0,0 +1,78 @@ +/* +* 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 RENDER_UTILS_H +#define RENDER_UTILS_H + +#include "DirectXTex.h" +#include <DirectXMath.h> +#include "PxMat44.h" +#include "PxVec3.h" +#include "PxVec4.h" + +static DirectX::XMFLOAT4 getRandomPastelColor() +{ + float r = ((double)rand() / (RAND_MAX)) * 0.5f + 0.5f; + float g = ((double)rand() / (RAND_MAX)) * 0.5f + 0.5f; + float b = ((double)rand() / (RAND_MAX)) * 0.5f + 0.5f; + return DirectX::XMFLOAT4(r, g, b, 1.0f); +} + +static physx::PxMat44 XMMATRIXToPxMat44(const DirectX::XMMATRIX& mat) +{ + physx::PxMat44 m; + memcpy(const_cast<float*>(m.front()), &mat.r[0], 4 * 4 * sizeof(float)); + return m; +} + +static DirectX::XMMATRIX PxMat44ToXMMATRIX(const physx::PxMat44& mat) +{ + return DirectX::XMMATRIX(mat.front()); +} + +static physx::PxVec4 XMVECTORToPxVec4(const DirectX::XMVECTOR& vec) +{ + DirectX::XMFLOAT4 f; + DirectX::XMStoreFloat4(&f, vec); + return physx::PxVec4(f.x, f.y, f.z, f.w); +} + +static physx::PxVec3 XMFLOAT3ToPxVec3(const DirectX::XMFLOAT3& vec) +{ + return physx::PxVec3(vec.x, vec.y, vec.z); +} + +static physx::PxVec4 XMFLOAT4ToPxVec4(const DirectX::XMFLOAT4& vec) +{ + return physx::PxVec4(vec.x, vec.y, vec.z, vec.w); +} + +static uint32_t XMFLOAT4ToU32Color(const DirectX::XMFLOAT4& color) +{ + uint32_t c = 0; + c |= (int)(color.w * 255); c <<= 8; + c |= (int)(color.z * 255); c <<= 8; + c |= (int)(color.y * 255); c <<= 8; + c |= (int)(color.x * 255); + return c; +} + +static DirectX::XMFLOAT4 XMFLOAT4Lerp(const DirectX::XMFLOAT4 v0, const DirectX::XMFLOAT4 v1, float val) +{ + DirectX::XMFLOAT4 v( + v0.x * (1 - val) + v1.x * val, + v0.y * (1 - val) + v1.y * val, + v0.z * (1 - val) + v1.z * val, + v0.w * (1 - val) + v1.w * val + ); + return v; +} + +#endif //RENDER_UTILS_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderable.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderable.cpp new file mode 100644 index 0000000..51569b7 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderable.cpp @@ -0,0 +1,55 @@ +/* +* 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 "Renderable.h" +#include "Renderer.h" +#include "RenderUtils.h" + +const DirectX::XMFLOAT4 DEFAULT_COLOR(0.5f, 0.5f, 0.5f, 1.0f); + +Renderable::Renderable(IRenderMesh& mesh, RenderMaterial& material) : m_mesh(mesh), m_scale(1, 1, 1), m_color(DEFAULT_COLOR), m_hidden(false), m_transform(PxIdentity) +// Add By Lixu Begin +, m_selected(false) +// Add By Lixu End +{ + setMaterial(material); +} + +void Renderable::setMaterial(RenderMaterial& material) +{ + material.addRelatedRenderable(this); + m_materialInstance = material.getMaterialInstance(&m_mesh); +} + +void Renderable::render(Renderer& renderer, bool depthStencilOnly) const +{ + if (!m_materialInstance->isValid()) + { + PX_ALWAYS_ASSERT(); + return; + } + + m_materialInstance->bind(*renderer.m_context, 0, depthStencilOnly); + + // setup object CB + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + renderer.m_context->Map(renderer.m_objectCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + Renderer::CBObject* objectBuffer = (Renderer::CBObject*)mappedResource.pData; + objectBuffer->world = PxMat44ToXMMATRIX(getModelMatrix()); + objectBuffer->color = getColor(); +// Add By Lixu Begin + objectBuffer->selected = m_selected ? 1.0 : -1.0; +// Add By Lixu End + renderer.m_context->Unmap(renderer.m_objectCB, 0); + } + + m_mesh.render(*renderer.m_context); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderable.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderable.h new file mode 100644 index 0000000..9e38e4f --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderable.h @@ -0,0 +1,151 @@ +/* +* 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 RENDERABLE_H +#define RENDERABLE_H + +#include "RenderMaterial.h" +#include <DirectXMath.h> +#include "PxMat44.h" +#include "PxVec3.h" +#include "PxVec4.h" + +using namespace physx; + +class Renderer; + +/** +RenderMesh interface, used by Renderable +*/ +class IRenderMesh +{ +public: + virtual ~IRenderMesh() {} + virtual const std::vector<D3D11_INPUT_ELEMENT_DESC>& getInputElementDesc() const = 0; + virtual void render(ID3D11DeviceContext& context) const = 0; +// Add By Lixu Begin + virtual void setScale(PxMat44 scale, bool replace) {}; +// Add By Lixu End +}; + +/** +Renderable, represents single object renderer by Renderer. +Basically Renderable = RenderMaterial + RenderMesh +*/ +class Renderable +{ +public: + //////// public API //////// + + void setMaterial(RenderMaterial& material); + + PxMat44 getModelMatrix() const + { + return PxMat44(m_transform) * PxMat44(PxVec4(m_scale, 1)); + } + + void setTransform(PxTransform& transform) + { + m_transform = transform; + } + + const PxTransform& getTransform() const + { + return m_transform; + } + + void setScale(PxVec3 scale) + { + m_scale = scale; + } + + const PxVec3& getScale() const + { + return m_scale; + } + + void setColor(DirectX::XMFLOAT4 color) + { + m_color = color; + } + DirectX::XMFLOAT4 getColor() const + { + return m_color; + } + + void setHidden(bool hidden) + { + m_hidden = hidden; + } + + bool isHidden() const + { + return m_hidden; + } + +// Add By Lixu Begin + void setSelected(bool selected) + { + m_selected = selected; + } + + bool isSelected() const + { + return m_selected; + } + + void setMeshScale(PxMat44 scale, bool replace) + { + m_mesh.setScale(scale, replace); + } +// Add By Lixu End + + bool isTransparent() const + { + return !(m_materialInstance->getMaterial().getBlending() == RenderMaterial::BLEND_NONE); + } + + RenderMaterial& getMaterial() const { return m_materialInstance->getMaterial(); } + +private: + //////// methods used by Renderer //////// + + friend class Renderer; + + void render(Renderer& renderer) const + { + render(renderer, false); + } + + void renderDepthStencilOnly(Renderer& renderer) const + { + render(renderer, true); + } + + Renderable(IRenderMesh& mesh, RenderMaterial& material); + + void render(Renderer& renderer, bool depthStencilOnly) const; + + + //////// internal data //////// + + DirectX::XMFLOAT4 m_color; + PxTransform m_transform; + PxVec3 m_scale; + + RenderMaterial::InstancePtr m_materialInstance; + IRenderMesh& m_mesh; + bool m_hidden; +// Add By Lixu Begin + bool m_selected; +// Add By Lixu End +}; + +#endif //RENDERABLE_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderer.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderer.cpp new file mode 100644 index 0000000..49b1669 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderer.cpp @@ -0,0 +1,736 @@ +/* +* 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 "Renderer.h" +#include "RenderUtils.h" +#include "UIHelpers.h" +#include "SampleProfiler.h" + +#include "PxRenderBuffer.h" + +#include <set> + + +const float CAMERA_CLIP_NEAR = 1.0f; +const float CAMERA_CLIP_FAR = 1000.00f; + +const float CLEAR_SCENE_COLOR[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Renderer +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +Renderer::Renderer() +: m_cameraCB(nullptr) +, m_worldCB(nullptr) +, m_objectCB(nullptr) +, m_RSState(nullptr) +, m_opaqueRenderDSState(nullptr) +, m_transparencyRenderDSState(nullptr) +, m_DSTexture(nullptr) +, m_DSView(nullptr) +, m_DSTextureSRV(nullptr) +, m_pointSampler(nullptr) +, m_linearSampler(nullptr) +, m_wireframeMode(false) +, m_debugPrimitiveVB(nullptr) +, m_debugPrimitiveVBVerticesCount(0) +, m_shadowEnabled(true) +, m_HBAOEnabled(true) +, m_visibleOpaqueRenderablesCount(0) +, m_visibleTransparentRenderablesCount(0) +{ + m_worldCBData.ambientColor = DirectX::XMFLOAT3(0.21f, 0.21f, 0.22f); + m_worldCBData.pointLightColor = DirectX::XMFLOAT3(1.0f, 1.0f, 1.0f); + m_worldCBData.pointLightPos = DirectX::XMFLOAT3(0.0f, 30.0f, 12.0f); + m_worldCBData.dirLightColor = DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f); + m_worldCBData.dirLightDir = DirectX::XMFLOAT3(-0.08f, -0.34f, -0.91f); + m_worldCBData.specularPower = 140.0f; + m_worldCBData.specularIntensity = 0.4f; + + toggleCameraSpeed(false); +} + +Renderer::~Renderer() +{ +} + +void Renderer::initializeDefaultRSState() +{ + SAFE_RELEASE(m_RSState); + D3D11_RASTERIZER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); +// Add By Lixu Begin + desc.CullMode = D3D11_CULL_NONE; +// Add By Lixu End + desc.FillMode = m_wireframeMode ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID; + desc.AntialiasedLineEnable = FALSE; + desc.DepthBias = 0; + desc.DepthBiasClamp = 0; + desc.DepthClipEnable = TRUE; + desc.FrontCounterClockwise = FALSE; + desc.MultisampleEnable = TRUE; + desc.ScissorEnable = FALSE; + desc.SlopeScaledDepthBias = 0; + + V(m_device->CreateRasterizerState(&desc, &m_RSState)); +} + +HRESULT Renderer::DeviceCreated(ID3D11Device* device) +{ + m_device = device; + + // Camera constant buffer + { + D3D11_BUFFER_DESC buffer_desc; + ZeroMemory(&buffer_desc, sizeof(buffer_desc)); + buffer_desc.Usage = D3D11_USAGE_DYNAMIC; + buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + buffer_desc.ByteWidth = sizeof(CBCamera); + _ASSERT((buffer_desc.ByteWidth % 16) == 0); + + V(device->CreateBuffer(&buffer_desc, nullptr, &m_cameraCB)); + } + + // World constant buffer + { + D3D11_BUFFER_DESC buffer_desc; + ZeroMemory(&buffer_desc, sizeof(buffer_desc)); + buffer_desc.Usage = D3D11_USAGE_DYNAMIC; + buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + buffer_desc.ByteWidth = sizeof(CBWorld); + _ASSERT((buffer_desc.ByteWidth % 16) == 0); + + V(device->CreateBuffer(&buffer_desc, nullptr, &m_worldCB)); + } + + // Object constant buffer + { + D3D11_BUFFER_DESC buffer_desc; + ZeroMemory(&buffer_desc, sizeof(buffer_desc)); + buffer_desc.Usage = D3D11_USAGE_DYNAMIC; + buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + buffer_desc.ByteWidth = sizeof(CBObject); + _ASSERT((buffer_desc.ByteWidth % 16) == 0); + + V(device->CreateBuffer(&buffer_desc, nullptr, &m_objectCB)); + } + + // Opaque Render Depth-Stencil state + { + D3D11_DEPTH_STENCIL_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.StencilEnable = FALSE; + desc.DepthEnable = TRUE; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + + V(device->CreateDepthStencilState(&desc, &m_opaqueRenderDSState)); + } + + // Transparency Render Depth-Stencil state + { + D3D11_DEPTH_STENCIL_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.StencilEnable = FALSE; + desc.DepthEnable = TRUE; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + + V(device->CreateDepthStencilState(&desc, &m_transparencyRenderDSState)); + } + + // Linear 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_CLAMP; + desc.MaxAnisotropy = 1; + desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + desc.MinLOD = 0; + desc.MaxLOD = D3D11_FLOAT32_MAX; + V(device->CreateSamplerState(&desc, &m_linearSampler)); + } + + // Point sampler + { + D3D11_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + desc.MaxAnisotropy = 1; + desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + desc.MinLOD = 0; + desc.MaxLOD = D3D11_FLOAT32_MAX; + V(device->CreateSamplerState(&desc, &m_pointSampler)); + } + + // Rasterizer state + initializeDefaultRSState(); + + // init primitive render meshes + for (uint32_t i = 0; i < PrimitiveRenderMeshType::Count; i++) + { + m_primitiveRenderMeshes[i] = nullptr; + } + + // init shadows + ID3D11DeviceContext* pd3dDeviceContext; + m_device->GetImmediateContext(&pd3dDeviceContext); + m_shadow.createResources(m_device, pd3dDeviceContext, &m_camera); + + // init hbao + m_HBAO.createResources(m_device); + + return S_OK; +} + +void Renderer::DeviceDestroyed() +{ + SAFE_RELEASE(m_cameraCB); + SAFE_RELEASE(m_worldCB); + SAFE_RELEASE(m_objectCB); + SAFE_RELEASE(m_RSState); + SAFE_RELEASE(m_opaqueRenderDSState); + SAFE_RELEASE(m_transparencyRenderDSState); + SAFE_RELEASE(m_pointSampler); + SAFE_RELEASE(m_linearSampler); + SAFE_RELEASE(m_debugPrimitiveVB); + SAFE_RELEASE(m_DSTexture); + SAFE_RELEASE(m_DSView); + SAFE_RELEASE(m_DSTextureSRV); + + for (uint32_t i = 0; i < PrimitiveRenderMeshType::Count; i++) + { + SAFE_DELETE(m_primitiveRenderMeshes[i]); + } +} + +void Renderer::onInitialize() +{ + // search paths + m_resourceManager.addSearchDir("..\\..\\samples\\resources"); + m_resourceManager.addSearchDir("..\\..\\..\\samples\\resources"); + for (const std::string& d : getManager()->getConfig().additionalResourcesDir) + { + m_resourceManager.addSearchDir(d.c_str()); + } + + // debug primitive render material and input layout + { + m_debugPrimitiveRenderMaterial = new RenderMaterial("", m_resourceManager, "debug_primitive", ""); + + D3D11_INPUT_ELEMENT_DESC layout[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 } + }; + + m_debugPrimitiveRenderMaterialInstance = m_debugPrimitiveRenderMaterial->getMaterialInstance(layout, ARRAYSIZE(layout)); + } +} + +void Renderer::onTerminate() +{ + SAFE_DELETE(m_debugPrimitiveRenderMaterial); +} + +void Renderer::BackBufferResized(ID3D11Device* /*device*/, const DXGI_SURFACE_DESC* sd) +{ + // Setup the camera's projection parameters + m_screenWidth = sd->Width; + m_screenHeight = sd->Height; + float fAspectRatio = m_screenWidth / m_screenHeight; + m_camera.SetProjParams(DirectX::XM_PIDIV4, fAspectRatio, CAMERA_CLIP_NEAR, CAMERA_CLIP_FAR); + + SAFE_RELEASE(m_DSTexture); + SAFE_RELEASE(m_DSView); + SAFE_RELEASE(m_DSTextureSRV); + + // create a new Depth-Stencil texture + { + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = sd->Width; + desc.Height = sd->Height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R32_TYPELESS; // Use a typeless type here so that it can be both depth-stencil and shader resource. + desc.SampleDesc.Count = sd->SampleDesc.Count; + desc.SampleDesc.Quality = sd->SampleDesc.Quality; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + V(m_device->CreateTexture2D(&desc, NULL, &m_DSTexture)); + } + + // create Depth-Stencil view + { + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.ViewDimension = sd->SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; + desc.Format = DXGI_FORMAT_D32_FLOAT; // Make the view see this as D32_FLOAT instead of typeless + desc.Texture2D.MipSlice = 0; + V(m_device->CreateDepthStencilView(m_DSTexture, &desc, &m_DSView)); + } + + // create Depth-Stencil shader resource view + { + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Format = DXGI_FORMAT_R32_FLOAT; // Make the shaders see this as R32_FLOAT instead of typeless + desc.ViewDimension = sd->SampleDesc.Count > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipLevels = 1; + desc.Texture2D.MostDetailedMip = 0; + V(m_device->CreateShaderResourceView(m_DSTexture, &desc, &m_DSTextureSRV)); + } + + // setup viewport + m_viewport.Width = (FLOAT)sd->Width; + m_viewport.Height = (FLOAT)sd->Height; + m_viewport.MinDepth = 0; + m_viewport.MaxDepth = 1; + m_viewport.TopLeftX = 0; + m_viewport.TopLeftY = 0; + + // setup shadows + m_shadow.setScreenResolution(0, sd->Width, sd->Height, sd->SampleDesc.Count, nullptr); +} + +void Renderer::setAllConstantBuffers(ID3D11DeviceContext* ctx) +{ + ID3D11Buffer* cbs[3] = { m_cameraCB, m_worldCB, m_objectCB }; + ctx->VSSetConstantBuffers(0, 3, cbs); + ctx->GSSetConstantBuffers(0, 3, cbs); + ctx->PSSetConstantBuffers(0, 3, cbs); +} + +void Renderer::Render(ID3D11Device* /*device*/, ID3D11DeviceContext* ctx, ID3D11RenderTargetView* pRTV, + ID3D11DepthStencilView*) +{ + PROFILER_SCOPED_FUNCTION(); + + m_context = ctx; + + ctx->ClearRenderTargetView(pRTV, CLEAR_SCENE_COLOR); + ctx->ClearDepthStencilView(m_DSView, D3D11_CLEAR_DEPTH, 1.0, 0); + ctx->RSSetViewports(1, &m_viewport); + + // needed matrices + DirectX::XMMATRIX viewMatrix = m_camera.GetViewMatrix(); + DirectX::XMMATRIX projMatrix = m_camera.GetProjMatrix(); + DirectX::XMMATRIX projMatrixInv = DirectX::XMMatrixInverse(NULL, projMatrix); + DirectX::XMMATRIX viewProjMatrix = viewMatrix * projMatrix; + + // Fill Camera constant buffer + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + ctx->Map(m_cameraCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + CBCamera* cameraBuffer = (CBCamera*)mappedResource.pData; + cameraBuffer->viewProjection = viewProjMatrix; + cameraBuffer->projectionInv = projMatrixInv; + DirectX::XMStoreFloat3(&(cameraBuffer->viewPos), m_camera.GetEyePt()); + ctx->Unmap(m_cameraCB, 0); + } + + // Fill World constant buffer + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + ctx->Map(m_worldCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + CBWorld* worldBuffer = (CBWorld*)mappedResource.pData; + memcpy(worldBuffer, &m_worldCBData, sizeof(m_worldCBData)); + //worldBuffer->ambientColor = m_CBWorldData.ambientColor; + //worldBuffer->pointLightPos = m_CBWorldData.pointLightPos; + //worldBuffer->pointLightColor = m_CBWorldData.pointLightColor; + //worldBuffer->dirLightDir = m_CBWorldData.dirLightDir; + //worldBuffer->specularPower = m_CBWorldData.specularPower; + //worldBuffer->dirLightColor = m_CBWorldData.dirLightColor; + //worldBuffer->specularIntensity = m_CBWorldData.specularIntensity; + ctx->Unmap(m_worldCB, 0); + } + + ctx->RSSetState(m_RSState); + ctx->PSSetSamplers(0, 1, &m_linearSampler); + ctx->PSSetSamplers(1, 1, &m_pointSampler); + + + if (m_shadowEnabled) + { + // render depth only + { + ctx->OMSetRenderTargets(0, nullptr, m_DSView); + ctx->OMSetDepthStencilState(m_opaqueRenderDSState, 0xFF); + + // set constants buffers + setAllConstantBuffers(ctx); + + for (auto it = m_renderables.begin(); it != m_renderables.end(); it++) + { + if (!(*it)->isTransparent() && !(*it)->isHidden()) + (*it)->renderDepthStencilOnly(*this); + } + } + + // render shadow map + m_shadow.renderShadowMaps(this); + + // render shadow buffer + ctx->OMSetRenderTargets(0, nullptr, nullptr); + m_shadow.renderShadowBuffer(m_DSTextureSRV, nullptr); + } + + // Opaque render + { + ctx->RSSetViewports(1, &m_viewport); + ctx->RSSetState(m_RSState); + ctx->OMSetRenderTargets(1, &pRTV, m_DSView); + ctx->OMSetDepthStencilState(m_opaqueRenderDSState, 0xFF); + + // set constants buffers + setAllConstantBuffers(ctx); + + // Fill Camera constant buffer + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + ctx->Map(m_cameraCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + CBCamera* cameraBuffer = (CBCamera*)mappedResource.pData; + cameraBuffer->viewProjection = viewProjMatrix; + cameraBuffer->projectionInv = projMatrixInv; + DirectX::XMStoreFloat3(&(cameraBuffer->viewPos), m_camera.GetEyePt()); + ctx->Unmap(m_cameraCB, 0); + } + + // Render opaque renderables + m_visibleOpaqueRenderablesCount = 0; + for (auto it = m_renderables.begin(); it != m_renderables.end(); it++) + { + if (!(*it)->isTransparent() && !(*it)->isHidden()) + { + (*it)->render(*this); + m_visibleOpaqueRenderablesCount++; + } + } + } + + // modulate shadows + if (m_shadowEnabled) + { + m_shadow.modulateShadowBuffer(pRTV); + } + + // render AO + if (m_HBAOEnabled) + { + m_HBAO.renderAO(m_context, pRTV, m_DSTextureSRV, projMatrix); + } + + ctx->RSSetViewports(1, &m_viewport); + + // render debug render buffers + while (m_queuedRenderBuffers.size() > 0) + { + render(m_queuedRenderBuffers.back()); + m_queuedRenderBuffers.pop_back(); + } + + // Transparency render + ctx->OMSetRenderTargets(1, &pRTV, m_DSView); + ctx->OMSetDepthStencilState(m_transparencyRenderDSState, 0xFF); + + // depth as SRV isn't used now (uncommenting will produce a warning, probably need readonly depth?) + //ctx->PSSetShaderResources(1, 1, &mDSTextureSRV); + + // Render transparent renderables + m_visibleTransparentRenderablesCount = 0; + for (auto it = m_renderables.begin(); it != m_renderables.end(); it++) + { + if ((*it)->isTransparent() && !(*it)->isHidden()) + { + (*it)->render(*this); + m_visibleTransparentRenderablesCount++; + } + } + + // shadows debug render + if (0) + { + m_shadow.displayMapFrustums(pRTV, m_DSView); + } + + // Reset RT and SRV state + ID3D11ShaderResourceView* nullAttach[16] = { nullptr }; + ctx->PSSetShaderResources(0, 16, nullAttach); + ctx->OMSetRenderTargets(0, nullptr, nullptr); +} + +LRESULT Renderer::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PX_UNUSED(hWnd); + PX_UNUSED(wParam); + PX_UNUSED(lParam); + + if (uMsg == WM_KEYDOWN || uMsg == WM_KEYUP) + { + // Camera overspeed event + int iKeyPressed = static_cast<int>(wParam); + if (iKeyPressed == VK_SHIFT) + { + toggleCameraSpeed(uMsg == WM_KEYDOWN); + } + } + + // Camera events + return m_camera.HandleMessages(hWnd, uMsg, wParam, lParam); +} + +void Renderer::Animate(double fElapsedTimeSeconds) +{ + PROFILER_SCOPED_FUNCTION(); + + m_camera.FrameMove((float)fElapsedTimeSeconds); +} + +void Renderer::renderDepthOnly(DirectX::XMMATRIX* viewProjectionSubstitute) +{ + // Fill Camera constant buffer + if (viewProjectionSubstitute) + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + m_context->Map(m_cameraCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + CBCamera* cameraBuffer = (CBCamera*)mappedResource.pData; + cameraBuffer->viewProjection = *viewProjectionSubstitute; + m_context->Unmap(m_cameraCB, 0); + } + + // set constants buffers + setAllConstantBuffers(m_context); + + // render + for (auto it = m_renderables.begin(); it != m_renderables.end(); it++) + { + if (!(*it)->isTransparent() && !(*it)->isHidden()) + (*it)->renderDepthStencilOnly(*this); + } +} + +void Renderer::render(const PxRenderBuffer* renderBuffer) +{ + // points + uint32_t pointsCount = renderBuffer->getNbPoints(); + if (pointsCount > 0) + { + RenderDebugVertex* verts = new RenderDebugVertex[pointsCount]; + const PxDebugPoint* points = renderBuffer->getPoints(); + for (uint32_t i = 0; i < pointsCount; i++) + { + verts[i].mPos = points[i].pos; + verts[i].mColor = points[i].color; + } + + renderDebugPrimitive(verts, pointsCount, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + delete[] verts; + } + + // lines + uint32_t linesCount = renderBuffer->getNbLines(); + if (linesCount > 0) + { + RenderDebugVertex* verts = new RenderDebugVertex[linesCount * 2]; + const PxDebugLine* lines = renderBuffer->getLines(); + for (uint32_t i = 0; i < linesCount; i++) + { + verts[i * 2].mPos = lines[i].pos0; + verts[i * 2].mColor = lines[i].color0; + verts[i * 2 + 1].mPos = lines[i].pos1; + verts[i * 2 + 1].mColor = lines[i].color1; + } + + renderDebugPrimitive(verts, linesCount * 2, D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + delete[] verts; + } + + // triangles + uint32_t trianglesCount = renderBuffer->getNbTriangles(); + if (trianglesCount > 0) + { + RenderDebugVertex* verts = new RenderDebugVertex[trianglesCount * 3]; + const PxDebugTriangle* triangles = renderBuffer->getTriangles(); + for (uint32_t i = 0; i < trianglesCount; i++) + { + verts[i * 3].mPos = triangles[i].pos0; + verts[i * 3].mColor = triangles[i].color0; + verts[i * 3 + 1].mPos = triangles[i].pos1; + verts[i * 3 + 1].mColor = triangles[i].color1; + verts[i * 3 + 2].mPos = triangles[i].pos2; + verts[i * 3 + 2].mColor = triangles[i].color2; + } + + renderDebugPrimitive(verts, trianglesCount * 3, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + delete[] verts; + } + + // texts? + // .... +} + +void Renderer::renderDebugPrimitive(const Renderer::RenderDebugVertex *vertices, uint32_t verticesCount, D3D11_PRIMITIVE_TOPOLOGY topology) +{ + m_context->IASetPrimitiveTopology(topology); + + m_debugPrimitiveRenderMaterialInstance->bind(*m_context, 0); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + m_context->Map(m_objectCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + CBObject* objectBuffer = (CBObject*)mappedResource.pData; + + objectBuffer->world = PxMat44ToXMMATRIX(PxMat44(PxIdentity)); + + m_context->Unmap(m_objectCB, 0); + + if (m_debugPrimitiveVBVerticesCount < verticesCount) + { + m_debugPrimitiveVBVerticesCount = verticesCount; + SAFE_RELEASE(m_debugPrimitiveVB); + + D3D11_BUFFER_DESC bufferDesc; + + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.ByteWidth = sizeof(Renderer::RenderDebugVertex) * m_debugPrimitiveVBVerticesCount; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + + V(m_device->CreateBuffer(&bufferDesc, NULL, &m_debugPrimitiveVB)); + } + + CD3D11_BOX box(0, 0, 0, (LONG)(sizeof(Renderer::RenderDebugVertex) * verticesCount), 1, 1); + m_context->UpdateSubresource(m_debugPrimitiveVB, 0, &box, vertices, 0, 0); + + ID3D11Buffer* pBuffers[1] = { m_debugPrimitiveVB }; + UINT strides[1] = { sizeof(RenderDebugVertex) }; + UINT offsets[1] = { 0 }; + m_context->IASetVertexBuffers(0, 1, pBuffers, strides, offsets); + + m_context->Draw(verticesCount, 0); +} + +IRenderMesh* Renderer::getPrimitiveRenderMesh(PrimitiveRenderMeshType::Enum type) +{ + if (m_primitiveRenderMeshes[type] == NULL) + { + switch (type) + { + case PrimitiveRenderMeshType::Box: + m_primitiveRenderMeshes[type] = new BoxRenderMesh(); + break; + case PrimitiveRenderMeshType::Plane: + m_primitiveRenderMeshes[type] = new PlaneRenderMesh(); + break; + case PrimitiveRenderMeshType::Sphere: + m_primitiveRenderMeshes[type] = new SphereRenderMesh(); + break; +// Add By Lixu Begin + case PrimitiveRenderMeshType::Cone: + m_primitiveRenderMeshes[type] = new ConeRenderMesh(); + break; +// Add By Lixu End + default: + PX_ALWAYS_ASSERT_MESSAGE("Unsupported PxGeometryType"); + return NULL; + } + } + + return m_primitiveRenderMeshes[type]; +} + + +Renderable* Renderer::createRenderable(IRenderMesh& mesh, RenderMaterial& material) +{ + Renderable* renderable = new Renderable(mesh, material); + m_renderables.emplace(renderable); + return renderable; +} + +void Renderer::removeRenderable(Renderable* r) +{ + m_renderables.erase(m_renderables.find(r)); + delete r; +} + +void Renderer::toggleCameraSpeed(bool overspeed) +{ + m_camera.SetScalers(0.002f, overspeed ? 150.f : 25.f); +} + +void Renderer::reloadShaders() +{ + // iterate Renderables materials and call reload() + std::set<RenderMaterial*> materials; + for (auto it = m_renderables.begin(); it != m_renderables.end(); it++) + { + materials.emplace(&((*it)->getMaterial())); + } + for (std::set<RenderMaterial*>::iterator it = materials.begin(); it != materials.end(); it++) + { + (*it)->reload(); + } +} + +void Renderer::drawUI() +{ + // Lighting + if (ImGui::TreeNode("Lighting")) + { + ImGui::ColorEdit3("Ambient Color", &(m_worldCBData.ambientColor.x)); + ImGui::ColorEdit3("Point Light Color", &(m_worldCBData.pointLightColor.x)); + ImGui::DragFloat3("Point Light Pos", &(m_worldCBData.pointLightPos.x)); + ImGui::ColorEdit3("Dir Light Color", &(m_worldCBData.dirLightColor.x)); + ImGui_DragFloat3Dir("Dir Light Dir", &(m_worldCBData.dirLightDir.x)); + ImGui::DragFloat("Specular Power", &(m_worldCBData.specularPower), 1.0f, 1.0f, 500.0f); + ImGui::DragFloat("Specular Intensity", &(m_worldCBData.specularIntensity), 0.01f, 0.0f, 2.0f); + + ImGui::TreePop(); + } + + // Shadow + if (ImGui::TreeNode("Shadow")) + { + ImGui::Checkbox("Shadows Enabled", &m_shadowEnabled); + if (m_shadowEnabled) + { + m_shadow.drawUI(); + } + + ImGui::TreePop(); + } + + // HBAO+ + if (ImGui::TreeNode("HBAO+")) + { + ImGui::Checkbox("HBAO Enabled", &(m_HBAOEnabled)); + if (m_HBAOEnabled) + { + m_HBAO.drawUI(); + } + + ImGui::TreePop(); + } +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderer.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderer.h new file mode 100644 index 0000000..58662a6 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/Renderer.h @@ -0,0 +1,251 @@ +/* +* 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 RENDERER_H +#define RENDERER_H + +#include "RenderMaterial.h" +#include <DirectXMath.h> +#include "XInput.h" +#include "DXUTMisc.h" +#include "DXUTCamera.h" +#include "SampleManager.h" +#include "Utils.h" +#include "ResourceManager.h" +#include "PrimitiveRenderMesh.h" +#include "RendererShadow.h" +#include "RendererHBAO.h" +#include <unordered_set> + +class CFirstPersonCamera; +class PhysXPrimitive; +class RenderDebugImpl; + +namespace physx +{ +class PxRenderBuffer; +} + + +/** +3D World Renderer +- use createRenderable() to add objects to render. +- use queueRenderBuffer() every frame to render debug primitives. +- contains ResourceManager to search for file and load resources. +- contains RendererShadow and RendererHBAO, use them through getters to control shadows. +*/ +class Renderer : public ISampleController +{ + friend class Renderable; + + public: + //////// ctor //////// + + Renderer(); + ~Renderer(); + + + //////// public API //////// + + void reloadShaders(); + + bool getWireframeMode() + { + return m_wireframeMode; + } + + void setWireframeMode(bool enabled) + { + if(m_wireframeMode != enabled) + { + m_wireframeMode = enabled; + initializeDefaultRSState(); + } + } + + IRenderMesh* getPrimitiveRenderMesh(PrimitiveRenderMeshType::Enum type); + + Renderable* createRenderable(IRenderMesh& mesh, RenderMaterial& material); + void removeRenderable(Renderable* r); + + void drawUI(); + + + //////// public getters //////// + + float getScreenWidth() const + { + return m_screenWidth; + } + + float getScreenHeight() const + { + return m_screenHeight; + } + + void queueRenderBuffer(const PxRenderBuffer* buffer) + { + m_queuedRenderBuffers.push_back(buffer); + } + + ResourceManager& getResourceManager() + { + return m_resourceManager; + } + + uint32_t getVisibleOpaqueRenderablesCount() + { + return m_visibleOpaqueRenderablesCount; + } + + uint32_t getVisibleTransparentRenderablesCount() + { + return m_visibleTransparentRenderablesCount; + } + + CFirstPersonCamera& getCamera() + { + return m_camera; + } + + + //////// public 'internal' methods //////// + + // for internal usage (used by RenderShadows) + void renderDepthOnly(DirectX::XMMATRIX* viewProjectionSubstitute); + + protected: + + //////// controller callbacks //////// + + 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 onInitialize(); + virtual void onTerminate(); + virtual void BackBufferResized(ID3D11Device* pDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc); + virtual void Render(ID3D11Device* /*device*/, ID3D11DeviceContext* ctx, ID3D11RenderTargetView* pRTV, + ID3D11DepthStencilView* pDSV); + + private: + + //////// internal methods //////// + + struct RenderDebugVertex + { + PxVec3 mPos; + uint32_t mColor; + }; + + void render(const PxRenderBuffer* renderBuffer); + void render(Renderable* renderable); + void renderDebugPrimitive(const RenderDebugVertex *vertices, uint32_t verticesCount, D3D11_PRIMITIVE_TOPOLOGY topology); + void initializeDefaultRSState(); + void setAllConstantBuffers(ID3D11DeviceContext* ctx); + void toggleCameraSpeed(bool overspeed); + + + //////// constant buffers //////// + + struct CBCamera + { + DirectX::XMMATRIX viewProjection; + DirectX::XMMATRIX projectionInv; + DirectX::XMFLOAT3 viewPos; + float unusedPad; + }; + struct CBWorld + { + DirectX::XMFLOAT3 ambientColor; + float unusedPad1; + DirectX::XMFLOAT3 pointLightPos; + float unusedPad2; + DirectX::XMFLOAT3 pointLightColor; + float unusedPad3; + DirectX::XMFLOAT3 dirLightDir; + float specularPower; + DirectX::XMFLOAT3 dirLightColor; + float specularIntensity; // TODO: actually it's per object property + }; + struct CBObject + { + DirectX::XMMATRIX world; + DirectX::XMFLOAT4 color; +// Add By Lixu Begin + float selected; +// Add By Lixu End + }; + + + //////// internal data //////// + + // camera + CFirstPersonCamera m_camera; + float m_screenWidth; + float m_screenHeight; + + // resources + ResourceManager m_resourceManager; + + // additional render modules(libs) + RendererShadow m_shadow; + bool m_shadowEnabled; + RendererHBAO m_HBAO; + bool m_HBAOEnabled; + + // DX11 common + ID3D11Device* m_device; + ID3D11DeviceContext* m_context; + D3D11_VIEWPORT m_viewport; + + // DX11 states + ID3D11RasterizerState* m_RSState; + ID3D11DepthStencilState* m_opaqueRenderDSState; + ID3D11DepthStencilState* m_transparencyRenderDSState; + + // DX11 samplers + ID3D11SamplerState* m_pointSampler; + ID3D11SamplerState* m_linearSampler; + + // Depth Buffer + ID3D11Texture2D* m_DSTexture; + ID3D11DepthStencilView* m_DSView; + ID3D11ShaderResourceView* m_DSTextureSRV; + + // Constant Buffers + ID3D11Buffer* m_cameraCB; + ID3D11Buffer* m_worldCB; + CBWorld m_worldCBData; + ID3D11Buffer* m_objectCB; + + // toggles (options) + bool m_wireframeMode; + + // renderables + std::unordered_set<Renderable*> m_renderables; + + // primitive meshes cache + IRenderMesh* m_primitiveRenderMeshes[PrimitiveRenderMeshType::Count]; + + // stats + uint32_t m_visibleOpaqueRenderablesCount; + uint32_t m_visibleTransparentRenderablesCount; + + // Debug Render + RenderMaterial* m_debugPrimitiveRenderMaterial; + RenderMaterial::InstancePtr m_debugPrimitiveRenderMaterialInstance; + ID3D11Buffer* m_debugPrimitiveVB; + uint32_t m_debugPrimitiveVBVerticesCount; + std::vector<const PxRenderBuffer*> m_queuedRenderBuffers; +}; + + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererHBAO.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererHBAO.cpp new file mode 100644 index 0000000..5e20a49 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererHBAO.cpp @@ -0,0 +1,81 @@ +/* +* 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 "RendererHBAO.h" +#include "Renderer.h" +#include "imgui.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Renderer HBAO (wrapper for hbao+) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +RendererHBAO::RendererHBAO() +{ + m_SSAOContext = NULL; + + // default parameters + m_SSAOParameters.Radius = 2.0f; +} + + +RendererHBAO::~RendererHBAO() +{ + releaseResources(); +} + + +void RendererHBAO::createResources(ID3D11Device *pd3dDevice) +{ + GFSDK_SSAO_Status status; + status = GFSDK_SSAO_CreateContext_D3D11(pd3dDevice, &m_SSAOContext, nullptr); + assert(status == GFSDK_SSAO_OK); +} + + +void RendererHBAO::releaseResources() +{ + if (m_SSAOContext != NULL) + { + m_SSAOContext->Release(); + } +} + + +void RendererHBAO::renderAO(ID3D11DeviceContext *pd3dDeviceContext, ID3D11RenderTargetView* pRTV, ID3D11ShaderResourceView* pDepthSRV, DirectX::XMMATRIX& projMatrix) +{ + GFSDK_SSAO_InputData_D3D11 InputData; + InputData.DepthData.pFullResDepthTextureSRV = pDepthSRV; + InputData.DepthData.DepthTextureType = GFSDK_SSAO_HARDWARE_DEPTHS; + InputData.DepthData.MetersToViewSpaceUnits = 1.0f; + InputData.DepthData.ProjectionMatrix.Data = GFSDK_SSAO_Float4x4(reinterpret_cast<const GFSDK_SSAO_FLOAT*>(&(projMatrix.r[0]))); + InputData.DepthData.ProjectionMatrix.Layout = GFSDK_SSAO_ROW_MAJOR_ORDER; + + GFSDK_SSAO_Output_D3D11 Output; + Output.pRenderTargetView = pRTV;// m_pSceneRTs->ColorRTV; + Output.Blend.Mode = GFSDK_SSAO_MULTIPLY_RGB; + + m_SSAOContext->RenderAO(pd3dDeviceContext, InputData, m_SSAOParameters, Output); +} + + +void RendererHBAO::drawUI() +{ + ImGui::DragFloat("Radius", &(m_SSAOParameters.Radius), 0.05f, 0.0f, 100.0f); + ImGui::DragFloat("Bias", &(m_SSAOParameters.Bias), 0.01f, 0.0f, 0.5f); + ImGui::DragFloat("NearAO", &(m_SSAOParameters.NearAO), 0.01f, 1.0f, 4.0f); + ImGui::DragFloat("FarAO", &(m_SSAOParameters.FarAO), 0.01, 1.0f, 4.0f); + ImGui::DragFloat("PowerExponent", &(m_SSAOParameters.PowerExponent), 0.01f, 1.0f, 8.0f); + ImGui::Checkbox("ForegroundAO Enabled", (bool*)&(m_SSAOParameters.ForegroundAO.Enable)); + ImGui::DragFloat("ForegroundAO ViewDepth", &(m_SSAOParameters.ForegroundAO.ForegroundViewDepth), 0.01f, 0.0f, 100.0f); + ImGui::Checkbox("BackgroundAO Enabled", (bool*)&(m_SSAOParameters.BackgroundAO.Enable)); + ImGui::DragFloat("BackgroundAO ViewDepth", &(m_SSAOParameters.BackgroundAO.BackgroundViewDepth), 0.01f, 0.0f, 100.0f); +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererHBAO.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererHBAO.h new file mode 100644 index 0000000..2478628 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererHBAO.h @@ -0,0 +1,40 @@ +/* +* 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 RENDERER_HBAO_H +#define RENDERER_HBAO_H + +#include <DirectXMath.h> +#include "GFSDK_SSAO.h" + + +class Renderer; + +class RendererHBAO +{ +public: + RendererHBAO(); + ~RendererHBAO(); + + void createResources(ID3D11Device *pd3dDevice); + void renderAO(ID3D11DeviceContext *pd3dDeviceContext, ID3D11RenderTargetView* pRTV, ID3D11ShaderResourceView* pDepthSRV, DirectX::XMMATRIX& projMatrix); + + void drawUI(); + +private: + void releaseResources(); + + GFSDK_SSAO_Parameters m_SSAOParameters; + + GFSDK_SSAO_Context_D3D11* m_SSAOContext; +}; + + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererShadow.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererShadow.cpp new file mode 100644 index 0000000..28a79e5 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererShadow.cpp @@ -0,0 +1,417 @@ +/* +* 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 "RendererShadow.h" + +#include "XInput.h" +#include "DXUTMisc.h" +#include "DXUTCamera.h" +#include "Renderer.h" +#include "UIHelpers.h" + +#define CASCADES 1 + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Renderer Shadows (wrapper for shadow_lib) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const float DEFAULT_LIGHT_SIZE = 3.0f; +const DirectX::XMFLOAT3 DEFAULT_LIGHT_POS(-25, 25, 25); +const DirectX::XMFLOAT3 DEFAULT_LIGHT_LOOK_AT(0, 0, 0); +const DirectX::XMFLOAT3 DEFAULT_SHADOW_COLOR(0.25f, 0.25f, 0.25f); + +RendererShadow::RendererShadow() +{ + m_shadowLibContext = NULL; + + m_PCSSEnabled = false; + m_lightSize = DEFAULT_LIGHT_SIZE; + m_lightPos = DEFAULT_LIGHT_POS; + m_lightLookAt = DEFAULT_LIGHT_LOOK_AT; + m_shadowColor = DEFAULT_SHADOW_COLOR; + + m_worldSpaceBBox0.x = m_worldSpaceBBox0.y = m_worldSpaceBBox0.z = -100; + m_worldSpaceBBox1.x = m_worldSpaceBBox1.y = m_worldSpaceBBox1.z = 100; + + // Penumbra params + m_PCSSParams.fMaxThreshold = 80.0f; + m_PCSSParams.fMaxClamp = 40.0f; + m_PCSSParams.fMinSizePercent = 3.0f; + m_PCSSParams.fMinWeightExponent = 5.0f; + m_PCSSParams.fMinWeightThresholdPercent = 20.0f; + + m_softShadowTestScale = 0.002f; + + memset(&m_shadowBufferSRV, 0, sizeof(m_shadowBufferSRV)); + + m_shadowMapHandle = NULL; + m_shadowBufferHandle = NULL; +} + + +RendererShadow::~RendererShadow() +{ + ReleaseResources(); +} + + +void RendererShadow::createResources(ID3D11Device *pd3dDevice, ID3D11DeviceContext* context, CFirstPersonCamera* camera) +{ + m_camera = camera; + +#if !CASCADES + uint32_t shadowMapScale = 5; + uint32_t shadowMapWidth = 1024; + uint32_t shadowMapHeight = 1024; + + // SM Desc + m_SMDesc.eViewType = GFSDK_ShadowLib_ViewType_Single; + m_SMDesc.eMapType = GFSDK_ShadowLib_MapType_Texture; +#else + + uint32_t shadowMapScale = 5; + uint32_t shadowMapWidth = 1024; + uint32_t shadowMapHeight = 1024; + + // SM Desc + m_SMDesc.eViewType = GFSDK_ShadowLib_ViewType_Cascades_2; + m_SMDesc.eMapType = GFSDK_ShadowLib_MapType_TextureArray; +#endif + + m_SMDesc.uResolutionWidth = shadowMapWidth * shadowMapScale; + m_SMDesc.uResolutionHeight = shadowMapHeight * shadowMapScale; + m_SMDesc.uArraySize = m_SMDesc.eViewType; + + for (int j = 0; j < GFSDK_ShadowLib_ViewType_Cascades_4; j++) + { + m_SMDesc.ViewLocation[j].uMapID = j; + m_SMDesc.ViewLocation[j].v2Origin.x = 0; + m_SMDesc.ViewLocation[j].v2Origin.y = 0; + m_SMDesc.ViewLocation[j].v2Dimension.x = shadowMapWidth * shadowMapScale; + m_SMDesc.ViewLocation[j].v2Dimension.y = shadowMapHeight * shadowMapScale; + } + + + // SM Render Params + m_SMRenderParams.iDepthBias = 1000; + m_SMRenderParams.fSlopeScaledDepthBias = 8; + + // SB Render Params + m_SBRenderParams.eTechniqueType = GFSDK_ShadowLib_TechniqueType_PCSS; + m_SBRenderParams.eQualityType = GFSDK_ShadowLib_QualityType_High; + + // DLL version + GFSDK_ShadowLib_Version DLLVersion; + GFSDK_ShadowLib_Status retCode = GFSDK_ShadowLib_GetDLLVersion(&DLLVersion); + + // Header version + GFSDK_ShadowLib_Version headerVersion; + headerVersion.uMajor = GFSDK_SHADOWLIB_MAJOR_VERSION; + headerVersion.uMinor = GFSDK_SHADOWLIB_MINOR_VERSION; + + // Do they match? + if (DLLVersion.uMajor == headerVersion.uMajor && DLLVersion.uMinor == headerVersion.uMinor) + { + GFSDK_ShadowLib_DeviceContext deviceAndContext; + deviceAndContext.pD3DDevice = pd3dDevice; + deviceAndContext.pDeviceContext = context; + + retCode = GFSDK_ShadowLib_Create(&headerVersion, &m_shadowLibContext, &deviceAndContext, NULL); + + if (retCode != GFSDK_ShadowLib_Status_Ok) assert(false); + } + else + { + assert(false); + } +} + + +void RendererShadow::ReleaseResources() +{ + SAFE_RELEASE(m_downsampledShadowMap.pTexture); + SAFE_RELEASE(m_downsampledShadowMap.pSRV); + SAFE_RELEASE(m_downsampledShadowMap.pRTV); + + if (m_shadowLibContext != NULL) + { + m_shadowLibContext->Destroy(); + m_shadowLibContext = NULL; + } +} + + +void RendererShadow::setScreenResolution(float FovyRad, UINT Width, UINT Height, UINT uSampleCount, ID3D11DepthStencilView* pReadOnlyDSV) +{ + changeShadowSettings(Width, Height, uSampleCount, pReadOnlyDSV); +} + + +void RendererShadow::changeShadowSettings(UINT Width, UINT Height, UINT uSampleCount, ID3D11DepthStencilView* pReadOnlyDSV) +{ + m_SBDesc.uResolutionWidth = Width; + m_SBDesc.uResolutionHeight = Height; + m_SBDesc.uSampleCount = uSampleCount; + m_SBDesc.ReadOnlyDSV.pDSV = pReadOnlyDSV; + + reloadBuffers(); +} + +void RendererShadow::reloadBuffers() +{ + { + m_shadowLibContext->RemoveMap(&m_shadowMapHandle); + + if (m_SMDesc.eMapType == GFSDK_ShadowLib_MapType_Texture && + m_SMDesc.eViewType == GFSDK_ShadowLib_ViewType_Single && + m_SBRenderParams.eTechniqueType == GFSDK_ShadowLib_TechniqueType_PCSS) + { + m_SMDesc.bDownsample = true; + } + + m_shadowLibContext->AddMap(&m_SMDesc, &m_shadowMapHandle); + } + + if (m_SMDesc.eMapType == GFSDK_ShadowLib_MapType_Texture && m_SMDesc.eViewType == GFSDK_ShadowLib_ViewType_Single) + { + m_downsampledShadowMap.uWidth = m_SMDesc.uResolutionWidth >> 1; + m_downsampledShadowMap.uHeight = m_SMDesc.uResolutionHeight >> 1; + m_downsampledShadowMap.uSampleCount = 1; + m_downsampledShadowMap.Format = DXGI_FORMAT_R32_FLOAT; + SAFE_RELEASE(m_downsampledShadowMap.pTexture); + SAFE_RELEASE(m_downsampledShadowMap.pSRV); + SAFE_RELEASE(m_downsampledShadowMap.pRTV); + m_shadowLibContext->DevModeCreateTexture2D(&m_downsampledShadowMap); + } + + m_shadowLibContext->RemoveBuffer(&m_shadowBufferHandle); + m_shadowLibContext->AddBuffer(&m_SBDesc, &m_shadowBufferHandle); +} + + + +//-------------------------------------------------------------------------------------- +// Data passed to the shadow map render function +//-------------------------------------------------------------------------------------- +struct ShadowMapRenderFunctionParams +{ + Renderer* renderer; +}; +static ShadowMapRenderFunctionParams s_RenderParams; + +//-------------------------------------------------------------------------------------- +// Shadow map render function +//-------------------------------------------------------------------------------------- +static void ShadowMapRenderFunction(void* pParams, gfsdk_float4x4* pViewProj) +{ + ShadowMapRenderFunctionParams* pRP = (ShadowMapRenderFunctionParams*)pParams; + + DirectX::XMMATRIX viewProjection; + memcpy(&viewProjection, &pViewProj->_11, sizeof(gfsdk_float4x4)); + + pRP->renderer->renderDepthOnly(&viewProjection); +} + +void RendererShadow::renderShadowMaps(Renderer* renderer) +{ + // select technique + GFSDK_ShadowLib_TechniqueType technique = m_SBRenderParams.eTechniqueType; + m_SBRenderParams.eTechniqueType = m_PCSSEnabled ? GFSDK_ShadowLib_TechniqueType_PCSS : GFSDK_ShadowLib_TechniqueType_PCF; + if (technique != m_SBRenderParams.eTechniqueType) + reloadBuffers(); + + + DirectX::XMMATRIX viewMatrix = m_camera->GetViewMatrix(); + DirectX::XMMATRIX projMatrix = m_camera->GetProjMatrix(); + + memcpy(&m_SMRenderParams.m4x4EyeViewMatrix, &viewMatrix.r[0], sizeof(gfsdk_float4x4)); + memcpy(&m_SMRenderParams.m4x4EyeProjectionMatrix, &projMatrix.r[0], sizeof(gfsdk_float4x4)); + + // TODO: (better world space bbox needed) + m_SMRenderParams.v3WorldSpaceBBox[0] = m_worldSpaceBBox0; + m_SMRenderParams.v3WorldSpaceBBox[1] = m_worldSpaceBBox1; + + m_SMRenderParams.LightDesc.eLightType = GFSDK_ShadowLib_LightType_Directional; + memcpy(&m_SMRenderParams.LightDesc.v3LightPos, &m_lightPos.x, sizeof(gfsdk_float3)); + memcpy(&m_SMRenderParams.LightDesc.v3LightLookAt, &m_lightLookAt.x, sizeof(gfsdk_float3)); + m_SMRenderParams.LightDesc.fLightSize = m_lightSize; + m_SMRenderParams.LightDesc.bLightFalloff = false; + + // Scene specific setup for the shadow map phase that follows + s_RenderParams.renderer = renderer; + m_SMRenderParams.fnpDrawFunction = GFSDK_ShadowLib_FunctionPointer(ShadowMapRenderFunction); + m_SMRenderParams.pDrawFunctionParams = &s_RenderParams; + + // render shadow map + m_shadowLibContext->RenderMap(m_shadowMapHandle, &m_SMRenderParams); +} + + +void RendererShadow::renderShadowBuffer(ID3D11ShaderResourceView* pDepthStencilSRV, ID3D11ShaderResourceView* pResolvedDepthStencilSRV) +{ + if (m_SBRenderParams.eTechniqueType == GFSDK_ShadowLib_TechniqueType_PCSS && + m_SMDesc.eMapType == GFSDK_ShadowLib_MapType_Texture && + m_SMDesc.eViewType == GFSDK_ShadowLib_ViewType_Single) + { + m_tempResources.pDownsampledShadowMap = &m_downsampledShadowMap; + m_shadowLibContext->SetTempResources(&m_tempResources); + } + + m_SBRenderParams.PCSSPenumbraParams = m_PCSSParams; + m_SBRenderParams.fSoftShadowTestScale = m_softShadowTestScale; + + m_shadowLibContext->ClearBuffer(m_shadowBufferHandle); + + m_SBRenderParams.DepthBufferDesc.DepthStencilSRV.pSRV = pDepthStencilSRV; + + m_shadowLibContext->RenderBuffer(m_shadowMapHandle, m_shadowBufferHandle, &m_SBRenderParams); + + m_shadowLibContext->FinalizeBuffer(m_shadowBufferHandle, &m_shadowBufferSRV); +} + + +void RendererShadow::modulateShadowBuffer(ID3D11RenderTargetView* pOutputRTV) +{ + GFSDK_ShadowLib_RenderTargetView ColorRTV; + ColorRTV.pRTV = pOutputRTV; + + gfsdk_float3 v3ShadowColor = { m_shadowColor.x, m_shadowColor.y, m_shadowColor.z }; + m_shadowLibContext->ModulateBuffer(m_shadowBufferHandle, &ColorRTV, v3ShadowColor, GFSDK_ShadowLib_ModulateBufferMask_RGB); +} + + +void RendererShadow::displayShadowMaps(ID3D11RenderTargetView* pOutputRTV, UINT Width, UINT Height) +{ + GFSDK_ShadowLib_RenderTargetView ColorRTV; + ColorRTV.pRTV = pOutputRTV; + + float fMapResW = (float)m_SMDesc.uResolutionWidth; + float fMapResH = (float)m_SMDesc.uResolutionHeight; + + float fWidthScale = Width / ((float)m_SMDesc.uArraySize * fMapResW); + fWidthScale = (fWidthScale > 1.0f) ? (1.0f) : (fWidthScale); + + float fOneFifth = (float)Height / (5.0f); + float fHeightScale = fOneFifth / fMapResH; + fHeightScale = (fHeightScale > 1.0f) ? (1.0f) : (fHeightScale); + + float fScale = (fHeightScale < fWidthScale) ? (fHeightScale) : (fWidthScale); + + fMapResW = floorf(fMapResW * fScale); + fMapResH = floorf(fMapResH * fScale); + + for (unsigned int j = 0; j < (unsigned int)m_SMDesc.uArraySize; j++) + { + m_shadowLibContext->DevModeDisplayMap(m_shadowBufferHandle, + &ColorRTV, + m_shadowMapHandle, + j, + j * (unsigned int)fMapResW + j, + Height - (unsigned int)fMapResH, + fScale); + } +} + + +void RendererShadow::displayMapFrustums(ID3D11RenderTargetView* pOutputRTV, ID3D11DepthStencilView* pDSV) +{ + gfsdk_float3 v3Color; + v3Color.x = 1.0f; + v3Color.y = 0.0f; + v3Color.z = 0.0f; + + GFSDK_ShadowLib_RenderTargetView ColorRTV; + ColorRTV.pRTV = pOutputRTV; + + GFSDK_ShadowLib_DepthStencilView DSV; + DSV.pDSV = pDSV; + + unsigned int NumViews; + NumViews = m_SMDesc.eViewType; + + for (unsigned int j = 0; j < NumViews; j++) + { + switch (j) + { + case 0: + v3Color.x = 1.0f; + v3Color.y = 0.0f; + v3Color.z = 0.0f; + break; + case 1: + v3Color.x = 0.0f; + v3Color.y = 1.0f; + v3Color.z = 0.0f; + break; + case 2: + v3Color.x = 0.0f; + v3Color.y = 0.0f; + v3Color.z = 1.0f; + break; + case 3: + v3Color.x = 1.0f; + v3Color.y = 1.0f; + v3Color.z = 0.0f; + break; + } + + m_shadowLibContext->DevModeDisplayMapFrustum(m_shadowBufferHandle, + &ColorRTV, + &DSV, + m_shadowMapHandle, + j, + v3Color); + } +} + + +void RendererShadow::displayShadowBuffer(ID3D11RenderTargetView* pOutputRTV) +{ + gfsdk_float2 v2Scale; + v2Scale.x = 1.0f; + v2Scale.y = 1.0f; + + GFSDK_ShadowLib_RenderTargetView ColorRTV; + ColorRTV.pRTV = pOutputRTV; + + m_shadowLibContext->DevModeDisplayBuffer(m_shadowBufferHandle, + &ColorRTV, + v2Scale, + NULL); +} + + +void RendererShadow::toggleDisplayCascades(bool bToggle) +{ + m_shadowLibContext->DevModeToggleDebugCascadeShader(m_shadowBufferHandle, + bToggle); +} + + +void RendererShadow::drawUI() +{ + ImGui::Checkbox("PCSS", &m_PCSSEnabled); + ImGui::ColorEdit3("Shadow Color", &(m_shadowColor.x)); + ImGui::DragFloat("Light Size", &m_lightSize, 0.05f, 0.0f, 100.0f); + ImGui::DragFloat3("Light Position", &(m_lightPos.x)); + ImGui_DragFloat3Dir("Light LookAt", &(m_lightLookAt.x)); + ImGui::DragFloat("SoftShadowTestScale", &(m_softShadowTestScale), 0.0001f, 0.0f, 10.0f); + if (m_PCSSEnabled) + { + ImGui::DragFloat("PCSS: fMaxClamp", &(m_PCSSParams.fMaxClamp), 0.001f, 0.0f, 100.0f); + ImGui::DragFloat("PCSS: fMaxThreshold", &(m_PCSSParams.fMaxThreshold), 0.001f, 0.0f, 100.0f); + ImGui::DragFloat("PCSS: fMinSizePercent", &(m_PCSSParams.fMinSizePercent), 0.001f, 0.0f, 100.0f); + ImGui::DragFloat("PCSS: fMinWeightExponent", &(m_PCSSParams.fMinWeightExponent), 0.001f, 0.0f, 100.0f); + ImGui::DragFloat("PCSS: fMinWeightThresholdPercent", &(m_PCSSParams.fMinWeightThresholdPercent), 0.001f, 0.0f, 100.0f); + ImGui::DragFloat("PCSS: fBlockerSearchDitherPercent", &(m_PCSSParams.fBlockerSearchDitherPercent), 0.001f, 0.0f, 100.0f); + ImGui::DragFloat("PCSS: fFilterDitherPercent", &(m_PCSSParams.fFilterDitherPercent), 0.001f, 0.0f, 100.0f); + } +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererShadow.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererShadow.h new file mode 100644 index 0000000..cc81c67 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/RendererShadow.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 RENDERER_SHADOW_H +#define RENDERER_SHADOW_H + +#include <DirectXMath.h> +#include "Utils.h" +#include "gfsdk_shadowlib.h" + +#include <string> + + +class CFirstPersonCamera; +class Renderer; + +class RendererShadow +{ +public: + RendererShadow(); + ~RendererShadow(); + + void createResources(ID3D11Device *pd3dDevice, ID3D11DeviceContext* context, CFirstPersonCamera* camera); + + void setScreenResolution(float FovyRad, UINT Width, UINT Height, UINT uSampleCount, ID3D11DepthStencilView* pReadOnlyDSV); + void changeShadowSettings(UINT Width, UINT Height, UINT uSampleCount, ID3D11DepthStencilView* pReadOnlyDSV); + void renderShadowMaps(Renderer* renderer); + void renderShadowBuffer(ID3D11ShaderResourceView* pDepthStencilSRV, ID3D11ShaderResourceView* pResolvedDepthStencilSRV); + void modulateShadowBuffer(ID3D11RenderTargetView* pOutputRTV); + void displayShadowMaps(ID3D11RenderTargetView* pOutputRTV, UINT Width, UINT Height); + void displayMapFrustums(ID3D11RenderTargetView* pOutputRTV, ID3D11DepthStencilView* pDSV); + void displayShadowBuffer(ID3D11RenderTargetView* pOutputRTV); + void toggleDisplayCascades(bool bToggle); + + + void drawUI(); + +private: + void reloadBuffers(); + void ReleaseResources(); + + + GFSDK_ShadowLib_Context* m_shadowLibContext; + + GFSDK_ShadowLib_ShaderResourceView m_shadowBufferSRV; + + GFSDK_ShadowLib_Map* m_shadowMapHandle; + GFSDK_ShadowLib_MapDesc m_SMDesc; + GFSDK_ShadowLib_BufferDesc m_SBDesc; + GFSDK_ShadowLib_MapRenderParams m_SMRenderParams; + + GFSDK_ShadowLib_Buffer* m_shadowBufferHandle; + GFSDK_ShadowLib_BufferRenderParams m_SBRenderParams; + + GFSDK_ShadowLib_TempResources m_tempResources; + GFSDK_ShadowLib_Texture2D m_downsampledShadowMap; + + CFirstPersonCamera* m_camera; + + // params + bool m_PCSSEnabled; + float m_lightSize; + DirectX::XMFLOAT3 m_lightPos; + DirectX::XMFLOAT3 m_lightLookAt; + DirectX::XMFLOAT3 m_shadowColor; + GFSDK_ShadowLib_PCSSPenumbraParams m_PCSSParams; + float m_softShadowTestScale; + + gfsdk_float3 m_worldSpaceBBox0; + gfsdk_float3 m_worldSpaceBBox1; + +}; + + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ResourceManager.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ResourceManager.cpp new file mode 100644 index 0000000..a051f96 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ResourceManager.cpp @@ -0,0 +1,246 @@ +/* +* 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 "ResourceManager.h" +#include "PxAssert.h" +#include "PsString.h" +#include "Utils.h" + +#include <windows.h> + + +using namespace physx; + +#define PATH_MAX_LEN 512 + +// Add By Lixu Begin +ResourceManager* pResourceManager = nullptr; +ResourceManager* ResourceManager::ins() +{ + return pResourceManager; +} +// Add By Lixu End + +ResourceManager::ResourceManager() +{ + // search for root folder by default + addSearchDir("."); + +// Add By Lixu Begin + pResourceManager = this; +// Add By Lixu End +} + +const ShaderFileResource* ResourceManager::requestShaderFile(const char* name) +{ + const Resource* resource = requestResource(eSHADER_FILE, name); + return resource != nullptr ? static_cast<const ShaderFileResource*>(resource) : nullptr; +} + +const TextureResource* ResourceManager::requestTexture(const char* name) +{ + const Resource* resource = requestResource(eTEXTURE, name); + return resource != nullptr ? static_cast<const TextureResource*>(resource) : nullptr; +} + +const Resource* ResourceManager::requestResource(ResourceType type, const char* name) +{ + // search in loaded + std::pair<ResourceType, std::string> key(type, name); + auto val = m_loadedResources.find(key); + if (val != m_loadedResources.end()) + { + return val->second.get(); + } + + std::shared_ptr<Resource> resource; + if (type == eSHADER_FILE) + { + char path[PATH_MAX_LEN]; + const char* exts[] = { "hlsl" }; + if (findFile(name, std::vector<const char*>(exts, exts + sizeof(exts) / sizeof(exts[0])), path)) + { + resource = std::shared_ptr<Resource>(new ShaderFileResource(path)); + } + else + { + PX_ALWAYS_ASSERT_MESSAGE(name); + } + } + else if (type == eTEXTURE) + { + char path[PATH_MAX_LEN]; +// Add By Lixu Begin + const char* exts[] = { "dds", "tga", "jpg", "png" }; +// Add By Lixu End + if (findFile(name, std::vector<const char*>(exts, exts + sizeof(exts) / sizeof(exts[0])), path)) + { + std::shared_ptr<TextureResource> textureResource(new TextureResource()); + WCHAR wPath[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, path, -1, wPath, MAX_PATH); + wPath[MAX_PATH - 1] = 0; + + const char* ext = strext(path); + if (::strcmp(ext, "dds") == 0) + { + V(DirectX::LoadFromDDSFile(wPath, DirectX::DDS_FLAGS_NONE, &textureResource->metaData, + textureResource->image)); + } + else if (::strcmp(ext, "tga") == 0) + { + V(DirectX::LoadFromTGAFile(wPath, &textureResource->metaData, + textureResource->image)); + } +// Add By Lixu Begin + else if (::strcmp(ext, "jpg") == 0) + { + V(DirectX::LoadFromWICFile(wPath, DirectX::TEX_FILTER_DEFAULT | DirectX::WIC_FLAGS_ALL_FRAMES, &textureResource->metaData, + textureResource->image)); + } + else if (::strcmp(ext, "png") == 0) + { + V(DirectX::LoadFromWICFile(wPath, DirectX::TEX_FILTER_DEFAULT | DirectX::WIC_FLAGS_ALL_FRAMES, &textureResource->metaData, + textureResource->image)); + } +// Add By Lixu End + else + { + PX_ALWAYS_ASSERT_MESSAGE("Unsupported texture extension"); + } + resource = textureResource; + } + } + + if (resource.get()) + { + m_loadedResources.emplace(key, resource); + return resource.get(); + } + else + { + PX_ALWAYS_ASSERT_MESSAGE(name); + return nullptr; + } +} + +bool dirExists(const char* dir) +{ + DWORD ftyp = GetFileAttributesA(dir); + if (ftyp == INVALID_FILE_ATTRIBUTES) + return false; // something is wrong with path! + + if (ftyp & FILE_ATTRIBUTE_DIRECTORY) + return true; // this is a directory! + + return false; // this is not a directory! +} + +bool ResourceManager::addSearchDir(const char* dir, bool recursive) +{ + if (dirExists(dir)) + { + m_searchDirs.push_back(SearchDir(dir, recursive)); + return true; + } + return false; +} + + +ResourceManager::~ResourceManager() +{ +} + + +bool ResourceManager::findFileInDir(std::string fileNameFull, const char* path, bool recursive, char* foundPath) +{ + WIN32_FIND_DATAA ffd; + char tmp[PATH_MAX_LEN]; + shdfnd::snprintf(tmp, sizeof(tmp), "%s\\*", path); + HANDLE hFind = FindFirstFileA(tmp, &ffd); + + if(INVALID_HANDLE_VALUE == hFind) + { + return NULL; + } + + do + { + if (0 == shdfnd::strcmp(".", ffd.cFileName) || 0 == shdfnd::strcmp("..", ffd.cFileName)) + continue; + + if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + shdfnd::snprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName); + if(findFileInDir(fileNameFull, tmp, recursive, foundPath)) + return true; + } + else if (shdfnd::stricmp(ffd.cFileName, fileNameFull.c_str()) == 0) + { + shdfnd::snprintf(foundPath, PATH_MAX_LEN, "%s\\%s", path, ffd.cFileName); + return true; + } + } while(FindNextFileA(hFind, &ffd) != 0); + // release handle + FindClose(hFind); + return false; +} + +bool ResourceManager::findFile(std::string fileName, const std::vector<const char*>& exts, char* foundPath) +{ + std::string fileNameOnly = fileName; + size_t ind = fileNameOnly.find_last_of('/'); + if (ind > 0) + fileNameOnly = fileNameOnly.substr(ind + 1); + +// Add By Lixu Begin + std::string fileDir = "."; + size_t fl = fileName.length(); + if (ind >= 0 && ind < fl) + fileDir = fileName.substr(0, ind); + if (findFileInDir(fileNameOnly.c_str(), fileDir.c_str(), true, foundPath)) + return true; +// Add By Lixu End + + for(size_t i = 0; i < m_searchDirs.size(); i++) + { + const SearchDir& searchDir = m_searchDirs[i]; + + for(size_t j = 0; j < exts.size(); j++) + { + const char* ext = exts[j]; + const uint32_t fileMaxLen = 128; + char fileNameFull[fileMaxLen] = { 0 }; + + physx::shdfnd::snprintf(fileNameFull, fileMaxLen, "%s.%s", fileNameOnly.c_str(), ext); + if(findFileInDir(fileNameFull, searchDir.path.c_str(), searchDir.recursive, foundPath)) + return true; + } + + if (findFileInDir(fileNameOnly.c_str(), searchDir.path.c_str(), searchDir.recursive, foundPath)) + return true; + } + return false; +} + +bool ResourceManager::findFile(std::string fileName, std::string& foundPath) +{ + std::vector<const char*> exts; + char path[PATH_MAX_LEN]; + if (findFile(fileName, exts, path)) + { + foundPath = path; + return true; + } + else + { + return false; + } +} + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ResourceManager.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ResourceManager.h new file mode 100644 index 0000000..0378438 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ResourceManager.h @@ -0,0 +1,97 @@ +/* +* 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 RESOURCE_MANAGER_H +#define RESOURCE_MANAGER_H + +#include <vector> +#include <string> +#include <map> +#include <memory> +#include "DirectXTex.h" + + +struct Resource +{ +private: + Resource& operator = (const Resource&); +}; + + +struct ShaderFileResource : public Resource +{ + ShaderFileResource(const std::string& p) : path(p) {} + std::string path; +}; + + +struct TextureResource : public Resource +{ + DirectX::TexMetadata metaData; + DirectX::ScratchImage image; +}; + + +/** +ResourceManager used to look for files in provided dirs (see addSearchDir). Also it loads resources and caches them. +*/ +class ResourceManager +{ +public: + //////// ctor //////// + + ResourceManager(); + ~ResourceManager(); + +// Add By Lixu Begin + static ResourceManager* ins(); +// Add By Lixu End + + //////// public API //////// + + bool addSearchDir(const char* dir, bool recursive = true); + + const ShaderFileResource* requestShaderFile(const char* name); + + const TextureResource* requestTexture(const char* name); + + bool findFile(std::string fileName, std::string& foundPath); + + bool findFile(std::string fileName, const std::vector<const char*>& exts, char* foundPath); + + +private: + //////// internal methods //////// + + enum ResourceType + { + eSHADER_FILE, + eTEXTURE + }; + + const Resource* requestResource(ResourceType type, const char* name); + + bool findFileInDir(std::string fileNameFull, const char* path, bool recursive, char* foundPath); + + struct SearchDir + { + SearchDir(std::string path_, bool recursive_) : path(path_), recursive(recursive_) {} + + std::string path; + bool recursive; + }; + + + //////// internal data //////// + + std::vector<SearchDir> m_searchDirs; + std::map<std::pair<ResourceType, std::string>, std::shared_ptr<Resource>> m_loadedResources; +}; +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ShaderUtils.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ShaderUtils.h new file mode 100644 index 0000000..778c811 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/ShaderUtils.h @@ -0,0 +1,99 @@ +/* +* 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 SHADER_UTILS_H +#define SHADER_UTILS_H + +#include "Utils.h" +#include <d3dcompiler.h> + + +static HRESULT CompileShaderFromFile(const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, + ID3DBlob** ppBlobOut) +{ + HRESULT hr = S_OK; + ID3DBlob* pErrorBlob = NULL; + + WCHAR wFileName[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, szFileName, -1, wFileName, MAX_PATH); + wFileName[MAX_PATH - 1] = 0; + hr = D3DCompileFromFile(wFileName, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, szEntryPoint, szShaderModel, D3D10_SHADER_ENABLE_STRICTNESS, 0, + ppBlobOut, &pErrorBlob); + if(FAILED(hr)) + { + OutputDebugStringA((char*)pErrorBlob->GetBufferPointer()); + SAFE_RELEASE(pErrorBlob); + return hr; + } + SAFE_RELEASE(pErrorBlob); + + return S_OK; +} + +static HRESULT createShader(ID3D11Device* pDev, const void* pData, size_t len, ID3D11VertexShader** ppShd, bool) +{ + return pDev->CreateVertexShader(pData, len, nullptr, ppShd); +} + +static HRESULT createShader(ID3D11Device* pDev, const void* pData, size_t len, ID3D11GeometryShader** ppShd, + bool forceFast) +{ + PX_UNUSED(forceFast); + return pDev->CreateGeometryShader(pData, len, nullptr, ppShd); +} + +static HRESULT createShader(ID3D11Device* pDev, const void* pData, size_t len, ID3D11PixelShader** ppShd, bool) +{ + return pDev->CreatePixelShader(pData, len, nullptr, ppShd); +} + +static const char* shaderModel(ID3D11VertexShader**) +{ + return "vs_5_0"; +} + +static const char* shaderModel(ID3D11GeometryShader**) +{ + return "gs_5_0"; +} + +static const char* shaderModel(ID3D11PixelShader**) +{ + return "ps_5_0"; +} + +// Give back the shader buffer blob for use in CreateVertexLayout. Caller must release the blob. +template <class S> +static HRESULT createShaderFromFile(ID3D11Device* pDev, const char* szFileName, LPCSTR szEntryPoint, S** ppShd, + ID3DBlob*& pShaderBuffer, bool forceFast = false) +{ + HRESULT hr = CompileShaderFromFile(szFileName, szEntryPoint, shaderModel(ppShd), &pShaderBuffer); + if(SUCCEEDED(hr) && pShaderBuffer) + { + const void* shaderBufferData = pShaderBuffer->GetBufferPointer(); + const UINT shaderBufferSize = pShaderBuffer->GetBufferSize(); + createShader(pDev, shaderBufferData, shaderBufferSize, ppShd, forceFast); + } + return hr; +} + +// Overloaded, same as above but don't give back the shader buffer blob. +template <class S> +static HRESULT createShaderFromFile(ID3D11Device* pDev, const char* szFileName, LPCSTR szEntryPoint, S** ppShd, + bool forceFast = false) +{ + ID3DBlob* pShaderBuffer = NULL; + HRESULT hr = createShaderFromFile(pDev, szFileName, szEntryPoint, ppShd, pShaderBuffer, forceFast); + SAFE_RELEASE(pShaderBuffer); + return hr; +} + + +#endif //SHADER_UTILS_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/SkinnedRenderMesh.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/SkinnedRenderMesh.cpp new file mode 100644 index 0000000..c575d6c --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/SkinnedRenderMesh.cpp @@ -0,0 +1,217 @@ +/* +* 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 "SkinnedRenderMesh.h" +#include "Renderer.h" + +SkinnedRenderMesh::SkinnedRenderMesh(const std::vector<const SimpleMesh*>& meshes) +{ + PX_ASSERT_WITH_MESSAGE(meshes.size() <= MeshesCountMax, "meshes.size() have to be <= SkinnedRenderMesh::MeshesCountMax"); + + m_device = GetDeviceManager()->GetDevice(); + + // input element desc setup + m_inputDesc.push_back({ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + m_inputDesc.push_back({ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + m_inputDesc.push_back({ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + m_inputDesc.push_back({ "TEXCOORD", 1, DXGI_FORMAT_R32_UINT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }); + + // reserve VB + uint32_t verticesTotal = 0; + std::for_each(meshes.begin(), meshes.end(), [&](const SimpleMesh* c) { verticesTotal += (uint32_t)c->vertices.size(); }); + std::vector<SimpleMesh::Vertex> vertexBuffer; + vertexBuffer.reserve(verticesTotal); + + // reserve IB + uint32_t indicesTotal = 0; + std::for_each(meshes.begin(), meshes.end(), [&](const SimpleMesh* c) { indicesTotal += (uint32_t)c->indices.size(); }); + m_indices.reserve(indicesTotal); + + // fill VB, IB, MeshInfo + m_meshesInfo.resize(meshes.size()); + for (uint32_t meshIndex = 0; meshIndex < meshes.size(); ++meshIndex) + { + const SimpleMesh* mesh = meshes[meshIndex]; + MeshInfo& meshInfo = m_meshesInfo[meshIndex]; + + meshInfo.firstVertex = (uint32_t)vertexBuffer.size(); + vertexBuffer.insert(vertexBuffer.end(), mesh->vertices.begin(), mesh->vertices.end()); + meshInfo.verticesCount = (uint32_t)mesh->vertices.size(); + + meshInfo.firstIndex = (uint32_t)m_indices.size(); + uint32_t indexOffset = meshInfo.firstVertex; + for (uint32_t index : mesh->indices) + { + m_indices.push_back((uint32_t)index + indexOffset); + } + meshInfo.indicesCount = (uint32_t)mesh->indices.size(); + } + + // vertex buffer + { + D3D11_SUBRESOURCE_DATA vertexBufferData; + + ZeroMemory(&vertexBufferData, sizeof(vertexBufferData)); + vertexBufferData.pSysMem = vertexBuffer.data(); + + D3D11_BUFFER_DESC bufferDesc; + + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.ByteWidth = (uint32_t)(sizeof(SimpleMesh::Vertex) * vertexBuffer.size()); + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + V(m_device->CreateBuffer(&bufferDesc, &vertexBufferData, &m_vertexBuffer)); + } + + // bone index buffer + { + D3D11_BUFFER_DESC bufferDesc; + + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.ByteWidth = (uint32_t)(sizeof(uint32_t) * vertexBuffer.size()); + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + + V(m_device->CreateBuffer(&bufferDesc, nullptr, &m_boneIndexBuffer)); + } + + // index buffer + { + D3D11_BUFFER_DESC bufferDesc; + + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc.ByteWidth = (uint32_t)(sizeof(uint32_t) * m_indices.size()); + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + + V(m_device->CreateBuffer(&bufferDesc, nullptr, &m_indexBuffer)); + } + + // bone texture + { + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = 4; + desc.Height = (uint32_t)meshes.size(); + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + V(m_device->CreateTexture2D(&desc, nullptr, &m_boneTexture)); + } + + // bone texture SRV + { + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipLevels = 1; + desc.Texture2D.MostDetailedMip = 0; + V(m_device->CreateShaderResourceView(m_boneTexture, &desc, &m_boneTextureSRV)); + } +} + +SkinnedRenderMesh::~SkinnedRenderMesh() +{ + SAFE_RELEASE(m_vertexBuffer); + SAFE_RELEASE(m_boneIndexBuffer); + SAFE_RELEASE(m_indexBuffer); + SAFE_RELEASE(m_boneTexture); + SAFE_RELEASE(m_boneTextureSRV); +} + +void SkinnedRenderMesh::updateVisibleMeshes(const std::vector<uint32_t>& visibleMeshes) +{ + ID3D11DeviceContext* context; + m_device->GetImmediateContext(&context); + + // update bone index buffer + { + D3D11_MAPPED_SUBRESOURCE mappedRead; + V(context->Map(m_boneIndexBuffer, 0, D3D11_MAP_WRITE_DISCARD, NULL, &mappedRead)); + + uint32_t* boneIndexBuffer = (uint32_t*)mappedRead.pData; + for (uint32_t i = 0; i < visibleMeshes.size(); ++i) + { + const MeshInfo& info = m_meshesInfo[visibleMeshes[i]]; + for (uint32_t v = info.firstVertex; v < info.firstVertex + info.verticesCount; ++v) + { + boneIndexBuffer[v] = i; + } + } + + context->Unmap(m_boneIndexBuffer, 0); + } + + // update index buffer + { + D3D11_MAPPED_SUBRESOURCE mappedRead; + V(context->Map(m_indexBuffer, 0, D3D11_MAP_WRITE_DISCARD, NULL, &mappedRead)); + + uint32_t* indexBuffer = (uint32_t*)mappedRead.pData; + uint32_t indexCount = 0; + for (uint32_t meshIndex : visibleMeshes) + { + const MeshInfo& info = m_meshesInfo[meshIndex]; + memcpy(indexBuffer + indexCount, &m_indices[info.firstIndex], info.indicesCount * sizeof(uint32_t)); + indexCount += info.indicesCount; + } + context->Unmap(m_indexBuffer, 0); + m_indexCount = indexCount; + PX_ASSERT(m_indexCount % 3 == 0); + } +} + +void SkinnedRenderMesh::updateVisibleMeshTransforms(std::vector<PxMat44>& transforms) +{ + ID3D11DeviceContext* context; + m_device->GetImmediateContext(&context); + + // update bone transform texture + { + D3D11_MAPPED_SUBRESOURCE mappedRead; + V(context->Map(m_boneTexture, 0, D3D11_MAP_WRITE_DISCARD, NULL, &mappedRead)); + for (uint32_t i = 0; i < transforms.size(); ++i) + { + std::memcpy((uint8_t*)mappedRead.pData + i * mappedRead.RowPitch, &transforms[i], sizeof(PxMat44)); + } + context->Unmap(m_boneTexture, 0); + } +} + +void SkinnedRenderMesh::render(ID3D11DeviceContext& context) const +{ + context.IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + UINT strides[2] = { sizeof(SimpleMesh::Vertex), sizeof(uint32_t) }; + UINT offsets[2] = { 0 }; + ID3D11Buffer* buffers[2] = { m_vertexBuffer, m_boneIndexBuffer }; + context.IASetVertexBuffers(0, 2, buffers, strides, offsets); + + context.IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0); + + context.VSSetShaderResources(1, 1, &m_boneTextureSRV); + + context.DrawIndexed(m_indexCount, 0, 0); +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/SkinnedRenderMesh.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/SkinnedRenderMesh.h new file mode 100644 index 0000000..2f690d8 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/renderer/SkinnedRenderMesh.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 SKINNED_RENDER_MESH_H +#define SKINNED_RENDER_MESH_H + +#include "Utils.h" +#include <DirectXMath.h> + +#include <vector> +#include "Renderable.h" +#include "Mesh.h" + +/** +SkinnedRenderMesh: + bonde indices are passed as vertex input, + bone transforms are stored in texture + max bone meshes count: SkinnedRenderMesh::MeshesCountMax +*/ +class SkinnedRenderMesh : public IRenderMesh +{ +public: + //////// ctor //////// + + SkinnedRenderMesh(const std::vector<const SimpleMesh*>& meshes); + ~SkinnedRenderMesh(); + + + //////// const //////// + + static const uint32_t MeshesCountMax = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + + //////// public API //////// + + void updateVisibleMeshes(const std::vector<uint32_t>& visibleMeshes); + void updateVisibleMeshTransforms(std::vector<PxMat44>& transforms); + + + //////// IRenderMesh implementation //////// + + virtual const std::vector<D3D11_INPUT_ELEMENT_DESC>& getInputElementDesc() const { return m_inputDesc; } + virtual void render(ID3D11DeviceContext& context) const; + +private: + //////// internal data //////// + + struct MeshInfo + { + uint32_t firstIndex; + uint32_t indicesCount; + + uint32_t firstVertex; + uint32_t verticesCount; + }; + + std::vector<D3D11_INPUT_ELEMENT_DESC> m_inputDesc; + + ID3D11Device* m_device; + + ID3D11Buffer* m_vertexBuffer; + ID3D11Buffer* m_boneIndexBuffer; + ID3D11Buffer* m_indexBuffer; + ID3D11Texture2D* m_boneTexture; + ID3D11ShaderResourceView* m_boneTextureSRV; + + uint32_t m_indexCount; + + std::vector<MeshInfo> m_meshesInfo; + std::vector<uint32_t> m_indices; +}; + + + +#endif //SKINNED_RENDER_MESH_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SampleAssetListParser.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SampleAssetListParser.cpp new file mode 100644 index 0000000..00cf4df --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SampleAssetListParser.cpp @@ -0,0 +1,272 @@ +/* +* 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 "SampleAssetListParser.h" +#include <PsFastXml.h> +#include "Sample.h" +#include "PxVec4.h" +#include "PxInputDataFromPxFileBuf.h" + + +using namespace physx; + + +const float DEGREE_TO_RAD = acos(-1.0) / 180.0; + +class AssetListParser : public physx::shdfnd::FastXml::Callback +{ +public: + AssetListParser(AssetList& assetList): m_assetList(assetList){} +protected: + + // encountered a comment in the XML + virtual bool processComment(const char* /*comment*/) + { + return true; + } + + virtual bool processClose(const char* elementName, unsigned int /*depth*/, bool& /*isError*/) + { + if (::strcmp(elementName, "Box") == 0) + { + m_assetList.boxes.push_back(m_boxTemp); + m_boxTemp = AssetList::BoxAsset(); + } + else if (::strcmp(elementName, "Composite") == 0) + { + m_assetList.composites.push_back(m_compositeTemp); + m_compositeTemp = AssetList::CompositeAsset(); + } + return true; + } + + // return true to continue processing the XML document, false to skip. + virtual bool processElement(const char* elementName, // name of the element + const char* elementData, // element data, null if none + const physx::shdfnd::FastXml::AttributePairs& attr, + int /*lineno*/) // line number in the source XML file + { + if (::strcmp(elementName, "Model") == 0) + { + m_assetList.models.resize(m_assetList.models.size() + 1); + auto& model = m_assetList.models.back(); + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "id") == 0) + { + model.id = std::string(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "file") == 0) + { + model.file = std::string(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "name") == 0) + { + model.name = std::string(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "isSkinned") == 0) + { + std::string str = attr.getValue(i); + if (::strcmp(&str[0], "true") == 0) + { + model.isSkinned = true; + } + } + } + + model.transform = parseTransform(attr); + + if (model.name.empty()) + { + model.name = model.file; + } + if (model.id.empty()) + { + model.id = model.name; + } + } + else if (::strcmp(elementName, "Box") == 0) + { + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "id") == 0) + { + m_boxTemp.id = std::string(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "name") == 0) + { + m_boxTemp.name = std::string(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "staticHeight") == 0) + { + std::string str = attr.getValue(i); + sscanf(&str[0], "%f", &m_boxTemp.staticHeight); + } + else if (::strcmp(attr.getKey(i), "jointAllBonds") == 0) + { + std::string str = attr.getValue(i); + if (::strcmp(&str[0], "true") == 0) + { + m_boxTemp.jointAllBonds = true; + } + } + else if (::strcmp(attr.getKey(i), "extents") == 0) + { + std::string str = attr.getValue(i); + sscanf(&str[0], "%f %f %f", &m_boxTemp.extents.x, &m_boxTemp.extents.y, &m_boxTemp.extents.z); + } + } + + if (m_boxTemp.id.empty()) + { + m_boxTemp.id = m_boxTemp.name; + } + } + else if (::strcmp(elementName, "Level") == 0) + { + m_boxTemp.levels.push_back(AssetList::BoxAsset::Level()); + auto& level = m_boxTemp.levels.back(); + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "slices") == 0) + { + std::string str = attr.getValue(i); + sscanf(&str[0], "%d %d %d", &level.x, &level.y, &level.z); + } + if (::strcmp(attr.getKey(i), "isSupport") == 0) + { + std::string str = attr.getValue(i); + if (::strcmp(&str[0], "true") == 0) + { + level.isSupport = true; + } + } + } + } + else if (::strcmp(elementName, "Composite") == 0) + { + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "id") == 0) + { + m_compositeTemp.id = std::string(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "name") == 0) + { + m_compositeTemp.name = std::string(attr.getValue(i)); + } + } + m_compositeTemp.transform = parseTransform(attr); + + if (m_compositeTemp.id.empty()) + { + m_compositeTemp.id = m_compositeTemp.name; + } + } + else if (::strcmp(elementName, "AssetRef") == 0) + { + m_compositeTemp.assetRefs.push_back(AssetList::CompositeAsset::AssetRef()); + AssetList::CompositeAsset::AssetRef& assetRef = m_compositeTemp.assetRefs.back(); + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "id") == 0) + { + assetRef.id = attr.getValue(i); + } + } + assetRef.transform = parseTransform(attr); + } + else if (::strcmp(elementName, "Joint") == 0) + { + m_compositeTemp.joints.push_back(AssetList::CompositeAsset::Joint()); + AssetList::CompositeAsset::Joint& joint = m_compositeTemp.joints.back(); + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "asset0") == 0) + { + joint.assetIndices[0] = std::stoi(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "asset1") == 0) + { + joint.assetIndices[1] = std::stoi(attr.getValue(i)); + } + if (::strcmp(attr.getKey(i), "chunk0") == 0) + { + joint.chunkIndices[0] = std::stoi(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "chunk1") == 0) + { + joint.chunkIndices[1] = std::stoi(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "position0") == 0) + { + joint.attachPositions[0] = parsePosition(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "position1") == 0) + { + joint.attachPositions[1] = parsePosition(attr.getValue(i)); + } + } + } + return true; + } + +private: + PxTransform parseTransform(const physx::shdfnd::FastXml::AttributePairs& attr) + { + PxTransform transform(PxIdentity); + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "position") == 0) + { + transform.p = parsePosition(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "rotation") == 0) + { + transform.q = parseRotation(attr.getValue(i)); + } + } + return transform; + } + + PxVec3 parsePosition(const char* value) + { + PxVec3 ps; + sscanf(value, "%f %f %f", &ps.x, &ps.y, &ps.z); + return ps; + } + + PxQuat parseRotation(const char* value) + { + PxVec4 ps; + sscanf(value, "%f %f %f %f", &ps.x, &ps.y, &ps.z, &ps.w); + ps.w = ps.w * DEGREE_TO_RAD; + return PxQuat(ps.w, PxVec3(ps.x, ps.y, ps.z).getNormalized());; + } + + AssetList::BoxAsset m_boxTemp; + AssetList::CompositeAsset m_compositeTemp; + AssetList& m_assetList; +}; + + +void parseAssetList(AssetList& assetList, std::string filepath) +{ + physx::PsFileBuffer fileBuffer(filepath.c_str(), physx::general_PxIOStream2::PxFileBuf::OPEN_READ_ONLY); + if (!fileBuffer.isOpen()) + { + return; + } + PxInputDataFromPxFileBuf inputData(fileBuffer); + AssetListParser parser(assetList); + physx::shdfnd::FastXml* xml = physx::shdfnd::createFastXml(&parser); + xml->processXml(inputData, false); + xml->release(); +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SampleAssetListParser.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SampleAssetListParser.h new file mode 100644 index 0000000..b6303ec --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SampleAssetListParser.h @@ -0,0 +1,20 @@ +/* +* 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 SAMPLEASSETLISTPARSER_H +#define SAMPLEASSETLISTPARSER_H + +#include <string> + +struct AssetList; + +void parseAssetList(AssetList& assetList, std::string filepath); + +#endif // SAMPLEASSETLISTPARSER_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SceneController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SceneController.cpp new file mode 100644 index 0000000..2466304 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SceneController.cpp @@ -0,0 +1,1510 @@ +/* +* 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 "SceneController.h" +#include "RenderUtils.h" +#include "Utils.h" + +#include "BlastAssetBoxes.h" +#include "BlastAssetModelSimple.h" +#include "BlastAssetModelSkinned.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastExtPxFamily.h" +#include "NvBlastExtPxManager.h" + +#include "SampleAssetListParser.h" +#include "BlastReplay.h" +#include "Renderer.h" + +#include "BlastController.h" +#include "CommonUIController.h" +#include "PhysXController.h" + +#include "PxRigidDynamic.h" +#include <PsFastXml.h> +#include "PxInputDataFromPxFileBuf.h" + +#include <algorithm> +#include <imgui.h> +#include <sstream> +#include <tuple> + + + +//////// Simple hash function //////// +static NvBlastID generateIDFromString(const char* str) +{ + uint32_t h[4] = { 5381, 5381, 5381, 5381 }; + int i = 0; + for (const char* ptr = str; *ptr; i = ((i + 1) & 3), ++ptr) + { + h[i] = ((h[i] << 5) + h[i]) ^ static_cast<uint32_t>(*ptr); + } + return *reinterpret_cast<NvBlastID*>(h); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Scenes Setup +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const DirectX::XMFLOAT4 PICK_POINTER_ACTIVE_COLOR(1.0f, 0.f, 0.f, 0.6f); +const float RIGIDBODY_DENSITY = 2000.0f; + + +class SingleSceneAsset; + +class SceneAsset +{ +public: + SceneAsset() : spawnCount(0) {} + virtual ~SceneAsset() {} + + void initialize(Scene* scene) + { + m_scene = scene; + } + + virtual const char* getID() const = 0; + virtual const char* getName() const = 0; + + virtual void load() = 0; + virtual void unload() = 0; + virtual bool isLoaded() const = 0; + virtual void spawn(PxVec3 shift) = 0; + + virtual ImVec4 getUIColor() const + { + return ImGui::GetStyle().Colors[ImGuiCol_Text]; + } + + uint32_t spawnCount; +protected: + Scene* m_scene; +}; + + +class SceneActor +{ +public: + virtual ~SceneActor() {} + virtual const char* getName() const = 0; + virtual const char* getSubname(int subindex) const { return nullptr; } + virtual ImVec4 getUIColor() const = 0; + virtual void drawUI(int subindex) {} + virtual void drawStatsUI(int subindex) {} + virtual uint32_t getSubactorCount() const { return 0; } + virtual PxVec3 getSpawnShift() const { return PxVec3(PxZero); } + virtual void reload() {} + virtual void removeSubactor(int subindex) {} +}; + + +class Scene +{ +public: + struct ActorIndex + { + int index; + int subindex; + + ActorIndex() { reset(); } + ActorIndex(int i, int s) : index(i), subindex(s) {} + + bool operator==(const ActorIndex& other) const + { + return index == other.index && subindex == other.subindex; + } + + void reset() + { + index = -1; + subindex = -1; + } + }; + + Scene(Renderer& renderer, PhysXController& physXController, BlastController& blastController, CommonUIController& commonUIController) : + m_renderer(renderer), m_physXController(physXController), m_blastController(blastController), m_commonUIController(commonUIController) + { + } + + ~Scene() + { + removeAllSceneActors(); + + for (uint32_t i = 0; i < m_assets.size(); i++) + { + SAFE_DELETE(m_assets[i]); + } + m_assets.clear(); + m_assetsByID.clear(); + m_tkAssetMap.clear(); + } + + void addAsset(SceneAsset* asset) + { + m_assets.push_back(asset); + asset->initialize(this); + m_assetsByID[asset->getID()] = asset; + } + +// Add By Lixu Begin + std::vector<SceneAsset*>& getAssets() + { + return m_assets; + } + + std::vector<SceneActor*>& getActors() + { + return m_sceneActors; + } +// Add By Lixu End + + void drawUI() + { + /////////////////////////////////////////////////////////////////////////////////////////// + // Assets Selection + /////////////////////////////////////////////////////////////////////////////////////////// + { + static int mode = 0; + ImGui::RadioButton("Replace", &mode, 0); ImGui::SameLine(); + ImGui::RadioButton("Append", &mode, 1); + + ImGui::ListBoxHeader("Assets", (int)m_assets.size()); + for (uint32_t i = 0; i < m_assets.size(); ++i) + { + ImVec4 color = m_assets[i]->getUIColor(); + color.w = color.w * (m_assets[i]->isLoaded() ? 1.0f : 0.5f); + ImGui::PushStyleColor(ImGuiCol_Text, color); + if (ImGui::Selectable(m_assets[i]->getName(), m_lastSpawnedAsset == i)) + { + m_lastSpawnedAsset = i; + if (mode == 0) + { + removeAllSceneActors(); + } + m_commonUIController.addDelayedCall([=]() { spawnAsset(m_lastSpawnedAsset); }, "Loading Asset"); + } + ImGui::PopStyleColor(); + } + ImGui::ListBoxFooter(); + } + + ImGui::Spacing(); + ImGui::Separator(); + + /////////////////////////////////////////////////////////////////////////////////////////// + // Actors Selection + /////////////////////////////////////////////////////////////////////////////////////////// + { + // actor's list + { + int itemCount = 0; + for (size_t i = 0; i < m_sceneActors.size(); ++i) + { + itemCount += 1 + m_sceneActors[i]->getSubactorCount(); + } + + ImGui::ListBoxHeader("Scene Actors", itemCount); + for (int i = 0; i < (int)m_sceneActors.size(); ++i) + { + ImVec4 color = m_sceneActors[i]->getUIColor(); + ImGui::PushStyleColor(ImGuiCol_Text, color); + + const bool isSelected = (m_selectedActor.index == i); + + ImGui::PushID(i); + if (ImGui::Selectable(m_sceneActors[i]->getName(), isSelected && m_selectedActor.subindex == -1)) + { + setSelectedActor(i); + } + + for (int s = 0; s < (int)m_sceneActors[i]->getSubactorCount(); ++s) + { + ImGui::PushID(s); + if (ImGui::Selectable(m_sceneActors[i]->getSubname(s), isSelected && m_selectedActor.subindex == s)) + { + setSelectedActor(i, s); + } + ImGui::PopID(); + } + + ImGui::PopID(); + ImGui::PopStyleColor(); + } + ImGui::ListBoxFooter(); + } + + SceneActor* selectedActor = getSelectedActor(); + if (selectedActor) + { + if (ImGui::Button("Remove")) + { + removeSceneActor(m_selectedActor); + } + + ImGui::SameLine(); + + if (ImGui::Button("Reload")) + { + selectedActor->reload(); + } + + ImGui::SameLine(); + } + + if (ImGui::Button("Remove All")) + { + removeAllSceneActors(); + } + ImGui::SameLine(); + if (ImGui::Button("Reload All (R)")) + { + reloadAllActors(); + } + } + + ImGui::Spacing(); + ImGui::Spacing(); + + /////////////////////////////////////////////////////////////////////////////////////////// + // Selected Actor + /////////////////////////////////////////////////////////////////////////////////////////// + { + SceneActor* selectedActor = getSelectedActor(); + if (selectedActor) + { + ImGui::Text("Selected Actor: "); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, ImColor(40, 200, 80, 255)); + ImGui::Text(m_selectedActor.subindex >= 0 ? selectedActor->getSubname(m_selectedActor.subindex) : selectedActor->getName()); + ImGui::PopStyleColor(); + + ImGui::Spacing(); + + selectedActor->drawUI(m_selectedActor.subindex); + } + else + { + ImGui::Text("No Selected Actor"); + } + } + } + + void drawStatsUI() + { + SceneActor* selectedActor = getSelectedActor(); + if (selectedActor) + { + selectedActor->drawStatsUI(m_selectedActor.subindex); + } + } + + void spawnAsset(int32_t num) + { + m_lastSpawnedAsset = physx::PxClamp<int32_t>(num, -1, (uint32_t)m_assets.size() - 1); + + if (m_lastSpawnedAsset < 0) + { + return; + } + + PxVec3 shift(PxZero); +// Add By Lixu Begin + /* + for (SceneActor* a : m_sceneActors) + { + shift += a->getSpawnShift(); + } + */ +// Add By Lixu End + + SceneAsset* asset = m_assets[m_lastSpawnedAsset]; + asset->spawn(shift); + } + + void addSceneActor(SceneActor* actor) + { + m_sceneActors.push_back(actor); + if (!getSelectedActor()) + { + setSelectedActor((uint32_t)m_sceneActors.size() - 1); + } + } + + void removeSceneActor(ActorIndex actorIndex) + { + SceneActor* actor = getActorByIndex(actorIndex.index); + if (actorIndex.subindex < 0) + { + delete actor; + m_sceneActors.erase(std::remove(m_sceneActors.begin(), m_sceneActors.end(), actor)); + } + else + { + actor->removeSubactor(actorIndex.subindex); + + if (actor->getSubactorCount() == 0) + { + removeSceneActor(ActorIndex(actorIndex.index, -1)); + return; + } + } + + SceneActor* selectedActor = getActorByIndex(m_selectedActor.index); + if (selectedActor == nullptr) + { + if (!m_sceneActors.empty()) + { + setSelectedActor((uint32_t)m_sceneActors.size() - 1); + } + } + else + { + int subactorCount = selectedActor->getSubactorCount(); + if (m_selectedActor.subindex >= subactorCount || (m_selectedActor.subindex < 0 && subactorCount > 0)) + { + setSelectedActor(m_selectedActor.index, subactorCount - 1); + } + } + } + + void removeAllSceneActors() + { + for (SceneActor* a : m_sceneActors) + { + delete a; + } + m_sceneActors.clear(); + setSelectedActor(-1); + } + + void setSelectedActor(int index, int subindex = -1) + { + m_selectedActor.index = physx::PxClamp<int32_t>(index, -1, (uint32_t)m_sceneActors.size() - 1); + m_selectedActor.subindex = subindex; + } + + SceneActor* getSelectedActor() const + { + return getActorByIndex(m_selectedActor.index); + } + + SceneActor* getActorByIndex(int index) const + { + return (index >= 0 && index < (int)m_sceneActors.size()) ? m_sceneActors[index] : nullptr; + } + + int releaseAll() + { + removeAllSceneActors(); + + for (size_t i = 0; i < m_assets.size(); ++i) + { + m_assets[i]->unload(); + } + + const int currentAsset = m_lastSpawnedAsset; + m_lastSpawnedAsset = -1; + return currentAsset; + } + + void reloadAllActors() + { + for (SceneActor* a : m_sceneActors) + { + a->reload(); + } + } + + void registerTkAsset(const TkAsset& tkAsset, SingleSceneAsset* asset) + { + m_tkAssetMap[&tkAsset] = asset; + } + + void unregisterTkAsset(const TkAsset& tkAsset) + { + m_tkAssetMap.erase(&tkAsset); + } + + SingleSceneAsset* findSingleSceneAsset(const TkAsset& tkAsset) + { + auto entry = m_tkAssetMap.find(&tkAsset); + return entry != m_tkAssetMap.end() ? entry->second : nullptr; + } + + SceneAsset* findSceneAsset(const std::string& id) + { + auto entry = m_assetsByID.find(id); + return entry != m_assetsByID.end() ? entry->second : nullptr; + } + + + //////// used controllers //////// + + Renderer& getRenderer() const + { + return m_renderer; + } + + PhysXController& getPhysXController() const + { + return m_physXController; + } + + BlastController& getBlastController() const + { + return m_blastController; + } + + CommonUIController& getCommonUIController() const + { + return m_commonUIController; + } + +private: + + Renderer& m_renderer; + PhysXController& m_physXController; + BlastController& m_blastController; + CommonUIController& m_commonUIController; + + std::vector<SceneAsset*> m_assets; + std::vector<SceneActor*> m_sceneActors; + std::map<const TkAsset*, SingleSceneAsset*> m_tkAssetMap; + std::map<std::string, SceneAsset*> m_assetsByID; + + int m_lastSpawnedAsset; + + ActorIndex m_selectedActor; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Assets +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SingleSceneActor; + +class SingleSceneAsset : public SceneAsset +{ +public: + SingleSceneAsset() : m_asset(nullptr) {} + virtual ~SingleSceneAsset() { unload(); } + + virtual void spawn(PxVec3 shift) override; + + virtual void load() override + { + if (!m_asset) + { + m_asset = createAsset(); + m_scene->registerTkAsset(m_asset->getPxAsset()->getTkAsset(), this); + } + } + + virtual void unload() override + { + if (m_asset) + { + m_scene->unregisterTkAsset(m_asset->getPxAsset()->getTkAsset()); + delete m_asset; + m_asset = nullptr; + } + } + + virtual bool isLoaded() const override + { + return m_asset != nullptr; + } + + BlastAsset* getAsset() const + { + return m_asset; + } + + virtual PxTransform getInitialTransform() = 0; + +protected: + virtual BlastAsset* createAsset() = 0; + +private: + BlastAsset* m_asset; +}; + + +class ModelSceneAsset : public SingleSceneAsset +{ +public: + ModelSceneAsset() {} + + virtual const char* getID() const override{ return desc.id.c_str(); } + virtual const char* getName() const override { return desc.name.c_str(); } + + AssetList::ModelAsset desc; + + virtual PxTransform getInitialTransform() { return desc.transform; } +}; + + +class SimpleModelSceneAsset : public ModelSceneAsset +{ +public: + virtual BlastAsset* createAsset() + { + return new BlastAssetModelSimple(m_scene->getBlastController().getTkFramework(), m_scene->getPhysXController().getPhysics(), + m_scene->getPhysXController().getCooking(), m_scene->getRenderer(), desc.file.c_str()); + } + + virtual ImVec4 getUIColor() const override + { + return ImColor(255, 255, 200, 255); + } +}; + + +class SkinnedModelSceneAsset : public ModelSceneAsset +{ +public: + virtual BlastAsset* createAsset() + { + return new BlastAssetModelSkinned(m_scene->getBlastController().getTkFramework(), m_scene->getPhysXController().getPhysics(), + m_scene->getPhysXController().getCooking(), m_scene->getRenderer(), desc.file.c_str()); + } + + virtual ImVec4 getUIColor() const override + { + return ImColor(255, 200, 255, 255); + } +}; + + +class BoxesSceneAsset : public SingleSceneAsset +{ +public: + BoxesSceneAsset(const AssetList::BoxAsset& d) : desc(d) + { + for (uint32_t lv = 0; lv < desc.levels.size(); ++lv) + { + const AssetList::BoxAsset::Level& level = desc.levels[lv]; + NvBlastChunkDesc::Flags fl = (level.isSupport) ? NvBlastChunkDesc::Flags::SupportFlag : NvBlastChunkDesc::Flags::NoFlags; + assetDesc.generatorSettings.depths.push_back({ GeneratorAsset::Vec3(level.x, level.y, level.z), fl }); + } + assetDesc.generatorSettings.extents = GeneratorAsset::Vec3(desc.extents.x, desc.extents.y, desc.extents.z); + assetDesc.staticHeight = desc.staticHeight; + assetDesc.jointAllBonds = desc.jointAllBonds; + } + + virtual ImVec4 getUIColor() const override + { + return ImColor(255, 200, 200, 255); + } + + virtual const char* getID() const override { return desc.id.c_str(); } + virtual const char* getName() const override { return desc.name.c_str(); } + + + AssetList::BoxAsset desc; + BlastAssetBoxes::Desc assetDesc; + + virtual BlastAsset* createAsset() + { + return new BlastAssetBoxes(m_scene->getBlastController().getTkFramework(), m_scene->getPhysXController().getPhysics(), + m_scene->getPhysXController().getCooking(), m_scene->getRenderer(), assetDesc); + } + + virtual PxTransform getInitialTransform() { return PxTransform(PxVec3(0, assetDesc.generatorSettings.extents.y / 2, 0)); } +}; + + +class CompositeSceneAsset : public SceneAsset +{ +public: + CompositeSceneAsset(const AssetList::CompositeAsset& desc) + : m_desc(desc) + { + } + + virtual ~CompositeSceneAsset() { unload(); } + + virtual ImVec4 getUIColor() const override + { + return ImColor(200, 255, 255, 255); + } + + virtual const char* getID() const override { return m_desc.id.c_str(); } + virtual const char* getName() const override { return m_desc.name.c_str(); } + + virtual void spawn(PxVec3 shift) override; + + virtual void load() override + { + if (!isLoaded()) + { + // load dependent assets + for (const auto& assetRef : m_desc.assetRefs) + { + SceneAsset* asset = m_scene->findSceneAsset(assetRef.id); + if (asset) + { + asset->load(); + m_sceneAssets.push_back(static_cast<SingleSceneAsset*>(asset)); + } + else + { + m_scene->getCommonUIController().addPopupMessage("Error", "Wrong asset dependency on composite"); + m_sceneAssets.clear(); + return; + } + } + + // check joints + for (const auto& joint : m_desc.joints) + { + bool ok = (joint.assetIndices[0] >= 0 || joint.assetIndices[1] >= 0); + for (char k = 0; k < 2 && ok; ++k) + { + if (joint.assetIndices[k] < 0) + continue; + ok &= (joint.assetIndices[k] < (int32_t)m_sceneAssets.size()); + if (!ok) + break; + ok &= joint.chunkIndices[k] < m_sceneAssets[joint.assetIndices[k]]->getAsset()->getPxAsset()->getTkAsset().getChunkCount(); + } + if (!ok) + { + m_scene->getCommonUIController().addPopupMessage("Error", "Wrong joint on composite"); + m_sceneAssets.clear(); + return; + } + } + } + } + + virtual void unload() override + { + m_sceneAssets.clear(); + } + + virtual bool isLoaded() const override + { + return !m_sceneAssets.empty(); + } + + virtual PxTransform getInitialTransform() + { + return m_desc.transform; + } + + const AssetList::CompositeAsset& getDesc() const + { + return m_desc; + } + + const std::vector<SingleSceneAsset*>& getSceneAssets() const + { + return m_sceneAssets; + } + +private: + AssetList::CompositeAsset m_desc; + std::vector<SingleSceneAsset*> m_sceneAssets; +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Scene Actors +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SingleSceneActor : public SceneActor +{ +public: + SingleSceneActor(Scene& scene, SingleSceneAsset* asset, PxVec3 shift) + : m_scene(scene) + , m_asset(asset) + , m_shift(shift) + { + m_index = m_asset->spawnCount++; + spawn(); + } + + SingleSceneActor::~SingleSceneActor() + { + remove(); + } + + virtual const char* getName() const override + { + return m_name.c_str(); + } + + virtual const char* getSubname(int) const override + { + return nullptr; + } + + virtual ImVec4 getUIColor() const override + { + return m_asset->getUIColor(); + } + + virtual void drawUI(int) override + { + m_actor->drawUI(); + } + + virtual void drawStatsUI(int) override + { + m_actor->drawStatsUI(); + } + + virtual PxVec3 getSpawnShift() const override + { + return PxVec3(-20, 0, 0); + } + + virtual void reload() override + { + auto settings = m_actor->getSettings(); + remove(); + spawn(); + m_actor->setSettings(settings); + } + +private: + void remove() + { + m_scene.getBlastController().removeFamily(m_actor); + m_actor = nullptr; + } + + void spawn() + { + std::ostringstream str; + str << m_asset->getName(); + if (m_index) + str << " (" << m_index << ")"; + m_name = str.str(); + + PxTransform pose = m_asset->getInitialTransform(); + pose.p += m_shift; + + BlastAsset::ActorDesc actorDesc = { + actorDesc.id = generateIDFromString(m_name.c_str()), + pose, + m_scene.getBlastController().getTkGroup() + }; + + m_actor = m_scene.getBlastController().spawnFamily(m_asset->getAsset(), actorDesc); + } + + Scene& m_scene; + BlastFamilyPtr m_actor; + SingleSceneAsset* m_asset; + PxVec3 m_shift; + uint32_t m_index; + std::string m_name; +}; + +class CompositeSceneActor : public SceneActor +{ +public: + CompositeSceneActor(Scene& scene, CompositeSceneAsset* asset, PxVec3 shift) + : m_scene(scene) + , m_asset(asset) + , m_shift(shift) + { + m_index = m_asset->spawnCount++; + spawn(); + } + + CompositeSceneActor::~CompositeSceneActor() + { + remove(); + } + + virtual uint32_t getSubactorCount() const + { + return (uint32_t)m_actors.size(); + } + + virtual const char* getName() const override + { + return m_name.c_str(); + } + + virtual const char* getSubname(int subindex) const override + { + return m_actors[subindex].name.c_str(); + } + + virtual ImVec4 getUIColor() const override + { + return m_asset->getUIColor(); + } + + virtual void drawUI(int subindex) override + { + if (subindex >= 0) + { + m_actors[subindex].actor->drawUI(); + } + else + { + ImGui::Text("Select subactor to edit settings."); + } + } + + virtual void drawStatsUI(int subindex) override + { + if (subindex >= 0) + { + m_actors[subindex].actor->drawStatsUI(); + } + } + + virtual PxVec3 getSpawnShift() const override + { + return PxVec3(-20, 0, 0); + } + + virtual void reload() override + { + std::map<uint32_t, BlastFamily::Settings> settings; + for (uint32_t i = 0; i < m_actors.size(); ++i) + { + settings[m_actors[i].initialIndex] = m_actors[i].actor->getSettings(); + } + remove(); + spawn(); + for (uint32_t i = 0; i < m_actors.size(); ++i) + { + if (settings.find(i) != settings.end()) + { + m_actors[i].actor->setSettings(settings[i]); + } + } + } + + virtual void removeSubactor(int subindex) + { + if (subindex >= 0 && subindex < (int)m_actors.size()) + { + m_scene.getBlastController().removeFamily(m_actors[subindex].actor); + m_actors[subindex] = m_actors.back(); + m_actors.resize(m_actors.size() - 1); + } + } + +private: + void remove() + { + for (uint32_t i = 0; i < m_actors.size(); ++i) + { + m_scene.getBlastController().removeFamily(m_actors[i].actor); + } + m_actors.clear(); + } + + void spawn() + { + std::ostringstream str; + str << m_asset->getName(); + if (m_index) + str << " (" << m_index << ")"; + m_name = str.str(); + + const AssetList::CompositeAsset& assetDesc = m_asset->getDesc(); + const std::vector<SingleSceneAsset*>& sceneAssets = m_asset->getSceneAssets(); + + const uint32_t actorCount = (uint32_t)sceneAssets.size(); + m_actors.resize(actorCount); + + for (uint32_t i = 0; i < actorCount; ++i) + { + std::ostringstream str; + str << " -> " << i << "." << sceneAssets[i]->getName(); + m_actors[i].name = str.str(); + } + + ExtPxManager& pxManager = m_scene.getBlastController().getExtPxManager(); + for (uint32_t i = 0; i < actorCount; ++i) + { + PxTransform pose = m_asset->getInitialTransform(); + pose.p += m_shift; + pose = assetDesc.assetRefs[i].transform.transform(pose); + + BlastAsset::ActorDesc actorDesc = { + generateIDFromString(m_actors[i].name.c_str()), + pose, + m_scene.getBlastController().getTkGroup() + }; + m_actors[i].actor = m_scene.getBlastController().spawnFamily(sceneAssets[i]->getAsset(), actorDesc); + m_actors[i].initialIndex = i; + } + + for (const auto& joint : assetDesc.joints) + { + TkJointDesc jointDesc; + for (char k = 0; k < 2; ++k) + { + jointDesc.attachPositions[k] = joint.attachPositions[k]; + jointDesc.chunkIndices[k] = joint.chunkIndices[k]; + jointDesc.families[k] = (joint.assetIndices[k] < 0) ? nullptr : &m_actors[joint.assetIndices[k]].actor->getFamily()->getTkFamily(); + } + TkJoint* joint = pxManager.getFramework().createJoint(jointDesc); + if (joint) + { + pxManager.createJoint(*joint); + } + else + { + m_scene.getCommonUIController().addPopupMessage("Error", "Some joints can't be created"); + } + } + } + + struct Subactor + { + BlastFamilyPtr actor; + uint32_t initialIndex; + std::string name; + }; + + Scene& m_scene; + std::vector<Subactor> m_actors; + CompositeSceneAsset* m_asset; + PxVec3 m_shift; + uint32_t m_index; + std::string m_name; +}; + +class PhysXSceneActor : public SceneActor +{ +public: + PhysXSceneActor(PhysXController& physXController, PhysXController::Actor* actor, const char* name) + : m_physXController(physXController) + , m_actor(actor) + , m_name(name) + { + } + + PhysXSceneActor::~PhysXSceneActor() + { + m_physXController.removePhysXPrimitive(m_actor); + } + + virtual const char* getName() const override + { + return m_name; + } + + virtual ImVec4 getUIColor() const override + { + return ImColor(255, 100, 100, 255); + } + + +private: + PhysXController& m_physXController; + PhysXController::Actor* m_actor; + const char* m_name; + +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Assets Implementation +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void SingleSceneAsset::spawn(PxVec3 shift) +{ + load(); + SingleSceneActor* actor = new SingleSceneActor(*m_scene, this, shift); + m_scene->addSceneActor(actor); +} + +void CompositeSceneAsset::spawn(PxVec3 shift) +{ + load(); + if (isLoaded()) + { + CompositeSceneActor* actor = new CompositeSceneActor(*m_scene, this, shift); + m_scene->addSceneActor(actor); + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PackmanConfigParser +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class PackmanConfigParser : public physx::shdfnd::FastXml::Callback +{ +public: + std::vector<std::pair<std::string, std::string>> dependencies; + +protected: + + // encountered a comment in the XML + virtual bool processComment(const char* /*comment*/) + { + return true; + } + + virtual bool processClose(const char* elementName, unsigned int /*depth*/, bool& /*isError*/) + { + return true; + } + + // return true to continue processing the XML document, false to skip. + virtual bool processElement(const char* elementName, // name of the element + const char* elementData, // element data, null if none + const physx::shdfnd::FastXml::AttributePairs& attr, + int /*lineno*/) // line number in the source XML file + { + if (::strcmp(elementName, "dependency") == 0) + { + dependencies.resize(dependencies.size() + 1); + for (int i = 0; i < attr.getNbAttr(); ++i) + { + if (::strcmp(attr.getKey(i), "name") == 0) + { + dependencies.back().first = std::string(attr.getValue(i)); + } + else if (::strcmp(attr.getKey(i), "version") == 0) + { + dependencies.back().second = std::string(attr.getValue(i)); + } + } + } + return true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Controller +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +SceneController::SceneController() : m_cubeScale(1.0f) +{ + m_scene = NULL; +} + +SceneController::~SceneController() +{ +} + +void SceneController::onSampleStart() +{ + // setup camera + CFirstPersonCamera* camera = &getRenderer().getCamera(); + DirectX::XMVECTORF32 lookAtPt = { 0, 10, 0, 0 }; + DirectX::XMVECTORF32 eyePt = { 0, 20, 60, 0 }; + camera->SetViewParams(eyePt, lookAtPt); + camera->SetRotateButtons(false, false, true, false); + camera->SetEnablePositionMovement(true); + + // setup scene + m_scene = new Scene(getRenderer(), getPhysXController(), getBlastController(), getCommonUIController()); + + const SampleConfig& config = getManager()->getConfig(); + + // add packman repo to search dirs + bool packmanResourcesAdded = false; + if (const char* packmanPath = std::getenv("PM_PACKAGES_ROOT")) + { + const char* RESOURCES_CONFIG_FILE = "resources.xml"; + + std::string path; + if (getRenderer().getResourceManager().findFile(RESOURCES_CONFIG_FILE, path)) + { + physx::PsFileBuffer fileBuffer(path.c_str(), physx::general_PxIOStream2::PxFileBuf::OPEN_READ_ONLY); + if (fileBuffer.isOpen()) + { + PxInputDataFromPxFileBuf inputData(fileBuffer); + PackmanConfigParser parser; + physx::shdfnd::FastXml* xml = physx::shdfnd::createFastXml(&parser); + xml->processXml(inputData, false); + xml->release(); + for (auto& dep : parser.dependencies) + { + std::stringstream ss; + ss << packmanPath << "\\" << dep.first << "\\" << dep.second; + if (getRenderer().getResourceManager().addSearchDir(ss.str().c_str())) + { + packmanResourcesAdded = true; + } + } + } + } + } + if (!packmanResourcesAdded) + { + getManager()->getCommonUIController().addPopupMessage("Error", "BlastSampleResources package wasn't found. Consider running download_sample_resources.bat in root folder.", 5.0f); + } + + // parse asset file + AssetList assetList; + if (!config.assetsFile.empty()) + { + std::string path; + if (getRenderer().getResourceManager().findFile(config.assetsFile, path)) + { + parseAssetList(assetList, path); + } + } + + // add both asset file and asset list from config + addAssets(config.additionalAssetList, packmanResourcesAdded); + addAssets(assetList, packmanResourcesAdded); + +// Add By Lixu Begin + int size = m_scene->getAssets().size(); + for (int i = 0; i < size; i++) + { + spawnAsset(i); + } +// Add By Lixu End +} + +void SceneController::addAssets(const AssetList& assetList, bool loadModels) +{ + if (loadModels) + { + for (const auto& model : assetList.models) + { + ModelSceneAsset* asset; + if (!model.isSkinned) + { + asset = new SimpleModelSceneAsset(); + } + else + { + asset = new SkinnedModelSceneAsset(); + } + asset->desc = model; + m_scene->addAsset(asset); + } + + for (const auto& composite : assetList.composites) + { + m_scene->addAsset(new CompositeSceneAsset(composite)); + } + } + + for (const auto& box : assetList.boxes) + { + BoxesSceneAsset* asset = new BoxesSceneAsset(box); + m_scene->addAsset(asset); + } +} + +void SceneController::onInitialize() +{ + +} + +void SceneController::onSampleStop() +{ + if (NULL != m_scene) + { + delete m_scene; + m_scene = nullptr; + } +} + +void SceneController::onTerminate() +{ +} + +void SceneController::Animate(double dt) +{ +} + +LRESULT SceneController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_KEYDOWN) + { + int iKeyPressed = static_cast<int>(wParam); + switch (iKeyPressed) + { + case 'R': + m_scene->reloadAllActors(); + return 0; + case 'F': + throwCube(); + return 0; + default: + break; + } + } + + return 1; +} + +void SceneController::drawUI() +{ + /////////////////////////////////////////////////////////////////////////////////////////// + // Scene UI + /////////////////////////////////////////////////////////////////////////////////////////// + + m_scene->drawUI(); + + + ImGui::Spacing(); + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Spacing(); + ImGui::Spacing(); + + /////////////////////////////////////////////////////////////////////////////////////////// + // Replay + /////////////////////////////////////////////////////////////////////////////////////////// + { + ImGui::Text("Replay Control:"); + + BlastReplay* replay = getBlastController().getReplay(); + if (replay->isRecording()) + { + auto getAnimStr = []() + { + const uint32_t count = 5; + const uint64_t periodMS = 150; + static char str[count + 1] = ""; + for (uint32_t i = 0; i < count; i++) + { + uint64_t ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); + str[i] = (i == (ts % (periodMS * count)) / periodMS) ? '*' : ' '; + } + return str; + }; + ImGui::Text("State: Recording [%s] | Events: %d", getAnimStr(), replay->getEventCount()); + + if (ImGui::Button("Stop Recording")) + { + replay->stopRecording(); + } + } + else if (replay->isPlaying()) + { + ImGui::Text("State: Playing | Events: %d / %d", replay->getCurrentEventIndex(), replay->getEventCount()); + + if (ImGui::Button("Stop Playing")) + { + replay->stopPlayback(); + } + } + else + { + ImGui::Text("State: Idle | Events: %d", replay->getEventCount()); + + static bool syncFamilies = true; + static bool syncPhysics = true; + + ImGui::Checkbox("Sync Initial Actors", &syncFamilies); + if (ImGui::Checkbox("Sync Initial Transforms", &syncPhysics)) + { + syncFamilies = syncPhysics; + } + + if (ImGui::Button("Start Recording")) + { + replay->startRecording(getBlastController().getExtPxManager(), syncFamilies, syncPhysics); + } + + if (replay->hasRecord()) + { + static bool reload = false; + if (ImGui::Button("Start Playback")) + { + if (reload) + m_scene->reloadAllActors(); + replay->startPlayback(getBlastController().getExtPxManager(), getBlastController().getTkGroup()); + } + ImGui::SameLine(); + ImGui::Checkbox("Reload Scene On Playback", &reload); + } + } + } + + ImGui::Spacing(); + ImGui::Spacing(); + ImGui::Separator(); + + /////////////////////////////////////////////////////////////////////////////////////////// + // Cube + /////////////////////////////////////////////////////////////////////////////////////////// + { + ImGui::Text("Thrown Cube Params (F)"); + ImGui::DragFloat("Cube Size", &m_cubeScale, 1.0f, 0.0f, 100.0f); + } + +} + +void SceneController::drawStatsUI() +{ + m_scene->drawStatsUI(); +} + +void SceneController::throwCube() +{ + const float CUBE_VELOCITY = 100; + const float CUBE_DENSITY = 20000.0f; + + CFirstPersonCamera* camera = &getRenderer().getCamera(); + PxVec3 eyePos = XMVECTORToPxVec4(camera->GetEyePt()).getXYZ(); + PxVec3 lookAtPos = XMVECTORToPxVec4(camera->GetLookAtPt()).getXYZ(); + PhysXController::Actor* cube = getPhysXController().spawnPhysXPrimitiveBox(PxTransform(eyePos), PxVec3(m_cubeScale, m_cubeScale, m_cubeScale), CUBE_DENSITY); + PxRigidDynamic* rigidDynamic = cube->getActor()->is<PxRigidDynamic>(); + cube->setColor(DirectX::XMFLOAT4(1, 0, 0, 1)); + + PxVec3 dir = (lookAtPos - eyePos).getNormalized(); + rigidDynamic->setLinearVelocity(dir * CUBE_VELOCITY); + +// Add By Lixu Begin + std::string validname = ""; + if (m_ReusedNames.size() > 0) + { + validname = m_ReusedNames.back(); + m_ReusedNames.pop_back(); + } + else + { + int projectilesSize = m_Projectiles.size(); + char cubename[10]; + sprintf(cubename, "Cube_%d", projectilesSize); + validname = cubename; + } + cube->setColor(DirectX::XMFLOAT4(1, 1, 1, 1)); + PhysXSceneActor* p = new PhysXSceneActor(getPhysXController(), cube, validname.c_str()); + m_UsedNames.push_back(validname); + m_Projectiles.push_back(p); + m_scene->addSceneActor(p); + + getManager()->m_bNeedRefreshTree = true; +// Add By Lixu End +} + +void SceneController::spawnAsset(int32_t num) +{ + m_scene->spawnAsset(num); +} + +int SceneController::releaseAll() +{ + return m_scene->releaseAll(); +} + +// Add By Lixu Begin +void SceneController::addProjectile() +{ + throwCube(); +} + +void SceneController::clearProjectile() +{ + std::vector<PhysXSceneActor*>::iterator it; + for (it = m_Projectiles.begin(); it != m_Projectiles.end(); it++) + { + std::vector<SceneActor*>& actors = m_scene->getActors(); + std::map<SceneActor*, int> ActorIndexMap; + int actorSize = actors.size(); + for (int i = 0; i < actorSize; i++) + { + ActorIndexMap[actors[i]] = i; + } + + m_scene->removeSceneActor(Scene::ActorIndex(ActorIndexMap[*it], -1)); + } + m_Projectiles.clear(); + m_UsedNames.clear(); + m_ReusedNames.clear(); +} + +void SceneController::ResetScene() +{ + clearProjectile(); + m_scene->reloadAllActors(); + getManager()->m_bNeedRefreshTree = true; +} + +void SceneController::ClearScene() +{ + clearProjectile(); + m_scene->releaseAll(); + // Add By Lixu Begin + PhysXController& pc = getPhysXController(); + pc.ClearOldCOllisions(); + // Add By Lixu End +} + +bool SceneController::GetAssetDesc(const BlastAsset* asset, AssetList::ModelAsset& desc) +{ + SampleManager* pSampleManager = getManager(); + SampleConfig* config = (SampleConfig*)&(pSampleManager->getConfig()); + std::vector<AssetList::ModelAsset>& modelAssets = config->additionalAssetList.models; + std::vector<AssetList::ModelAsset>::iterator itModelAssets; + std::vector<SceneAsset*>& sceneAssets = m_scene->getAssets(); + std::vector<SceneAsset*>::iterator itSceneAssets; + + bool find = false; + for (itSceneAssets = sceneAssets.begin(); itSceneAssets != sceneAssets.end(); itSceneAssets++) + { + SceneAsset* sceneAsset = *itSceneAssets; + std::string id = sceneAsset->getID(); + for (itModelAssets = modelAssets.begin(); itModelAssets != modelAssets.end(); itModelAssets++) + { + AssetList::ModelAsset& modelAsset = *itModelAssets; + if (modelAsset.id == id) + { + if (!modelAsset.isSkinned) + { + SimpleModelSceneAsset* pSimpleModelSceneAsset = (SimpleModelSceneAsset*)sceneAsset; + if (pSimpleModelSceneAsset->getAsset() == asset) + { + desc = modelAsset; + find = true; + break; + } + } + else + { + SkinnedModelSceneAsset* pSkinnedModelSceneAsset = (SkinnedModelSceneAsset*)sceneAsset; + if (pSkinnedModelSceneAsset->getAsset() == asset) + { + desc = modelAsset; + find = true; + break; + } + } + } + } + + if (find) + { + break; + } + } + + return find; +} + +void SceneController::GetProjectilesNames(std::vector<std::string>& projectilesNames) +{ + projectilesNames.clear(); + std::vector<std::string>::iterator it = m_UsedNames.begin(); + for (; it != m_UsedNames.end(); it++) + { + projectilesNames.push_back(*it); + } +} +// Add By Lixu End
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SceneController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SceneController.h new file mode 100644 index 0000000..82f08d8 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/scene/SceneController.h @@ -0,0 +1,99 @@ +/* +* 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 SCENE_CONTROLLER_H +#define SCENE_CONTROLLER_H + +#include "SampleManager.h" +#include <map> + + +class CFirstPersonCamera; +class BlastAssetBoxes; +class SceneActor; +class BlastAsset; +class SingleSceneAsset; +class Scene; +// Add By Lixu Begin +class PhysXSceneActor; +// Add By Lixu End +class SceneController : public ISampleController +{ +public: + + SceneController(); + virtual ~SceneController(); + + virtual LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + virtual void Animate(double dt); + void drawUI(); + void drawStatsUI(); + + virtual void onInitialize(); + virtual void onSampleStart(); + virtual void onSampleStop(); + virtual void onTerminate(); + + // commands + int releaseAll(); + void spawnAsset(int32_t); + +// Add By Lixu Begin + void addProjectile(); + void clearProjectile(); + void ResetScene(); + void ClearScene(); + bool GetAssetDesc(const BlastAsset* asset, AssetList::ModelAsset& desc); + void GetProjectilesNames(std::vector<std::string>& projectilesNames); +// Add By Lixu End + +private: + void addAssets(const AssetList& assetList, bool loadModels = true); + void throwCube(); + + SceneController& operator= (SceneController&); + + //////// used controllers //////// + + Renderer& getRenderer() const + { + return getManager()->getRenderer(); + } + + PhysXController& getPhysXController() const + { + return getManager()->getPhysXController(); + } + + BlastController& getBlastController() const + { + return getManager()->getBlastController(); + } + + CommonUIController& getCommonUIController() const + { + return getManager()->getCommonUIController(); + } + + + //////// internal data //////// + + Scene* m_scene; + + float m_cubeScale; + +// Add By Lixu Begin + std::vector<std::string> m_UsedNames; + std::vector<std::string> m_ReusedNames; + std::vector<PhysXSceneActor*> m_Projectiles; +// Add By Lixu End +}; + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.cpp new file mode 100644 index 0000000..e56a124 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/CommonUIController.h new file mode 100644 index 0000000..da62674 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.cpp new file mode 100644 index 0000000..fba1227 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/DamageToolController.h new file mode 100644 index 0000000..b6712f2 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.cpp new file mode 100644 index 0000000..b02044b --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.cpp @@ -0,0 +1,156 @@ +/* +* 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" +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; + getManager()->fractureAsset(assetname, pBlastAsset, chunkIndices[0]); + getManager()->addModelAsset(assetname, desc.isSkinned, desc.transform, false); +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/EditionToolController.h new file mode 100644 index 0000000..b1e88d1 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.cpp new file mode 100644 index 0000000..ff0ffa9 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/GizmoToolController.h new file mode 100644 index 0000000..215cde5 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.cpp new file mode 100644 index 0000000..02a511f --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/SelectionToolController.h new file mode 100644 index 0000000..5261b90 --- /dev/null +++ b/NvBlast/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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.cpp new file mode 100644 index 0000000..11f66f0 --- /dev/null +++ b/NvBlast/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 *)¤t_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/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/ui/imgui_impl_dx11.h new file mode 100644 index 0000000..7d6f710 --- /dev/null +++ b/NvBlast/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); +*/ diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/PxInputDataFromPxFileBuf.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/PxInputDataFromPxFileBuf.h new file mode 100644 index 0000000..dfa8260 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/PxInputDataFromPxFileBuf.h @@ -0,0 +1,51 @@ +/* +* 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 PXINPUTDATAFROMPXFILEBUF_H +#define PXINPUTDATAFROMPXFILEBUF_H + +#include <PsFileBuffer.h> + + +// Copied from APEX +class PxInputDataFromPxFileBuf : public physx::PxInputData +{ +public: + PxInputDataFromPxFileBuf(physx::PxFileBuf& fileBuf) : mFileBuf(fileBuf) {} + + // physx::PxInputData interface + virtual uint32_t getLength() const + { + return mFileBuf.getFileLength(); + } + + virtual void seek(uint32_t offset) + { + mFileBuf.seekRead(offset); + } + + virtual uint32_t tell() const + { + return mFileBuf.tellRead(); + } + + // physx::PxInputStream interface + virtual uint32_t read(void* dest, uint32_t count) + { + return mFileBuf.read(dest, count); + } + + PX_NOCOPY(PxInputDataFromPxFileBuf) +private: + physx::PxFileBuf& mFileBuf; +}; + + +#endif //PXINPUTDATAFROMPXFILEBUF_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleProfiler.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleProfiler.cpp new file mode 100644 index 0000000..4df23fd --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleProfiler.cpp @@ -0,0 +1,223 @@ +/* +* 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 "SampleProfiler.h" +#include <map> +#include <iostream> +#include <fstream> +#include <stack> + +using namespace std::chrono; + +struct ProfileData +{ + steady_clock::time_point start; + + microseconds time; + microseconds prevTime; + microseconds maxTime; + uint32_t calls; + uint32_t prevCalls; + + ProfileData() : time(0), prevTime(0), maxTime(0), calls(0), prevCalls(0) + {} +}; + +struct Node +{ + ProfileData data; + std::map<const char*, Node> childs; + Node* parent; +}; + +static std::map<const char*, Node> s_roots; +static Node* s_currentNode; +static bool s_beginEndMismatch; +static microseconds s_overhead; +static microseconds s_prevOverhead; + +void SampleProfilerInit() +{ + s_roots.clear(); + s_currentNode = nullptr; + s_beginEndMismatch = false; + s_overhead = microseconds(); +} + +void SampleProfilerBegin(const char* name) +{ + auto start = steady_clock::now(); + { + Node* parent = s_currentNode; + if (s_currentNode == nullptr) + { + s_currentNode = &s_roots[name]; + } + else + { + s_currentNode = &s_currentNode->childs[name]; + } + s_currentNode->parent = parent; + s_currentNode->data.calls++; + s_currentNode->data.start = steady_clock::now(); + } + s_overhead += duration_cast<microseconds>(steady_clock::now() - start); +} + +void SampleProfilerEnd() +{ + auto start = steady_clock::now(); + { + if (s_currentNode) + { + auto& data = s_currentNode->data; + data.time += duration_cast<microseconds>(steady_clock::now() - data.start); + data.maxTime = data.time > data.maxTime ? data.time : data.maxTime; + s_currentNode = s_currentNode->parent; + } + else + { + s_beginEndMismatch = true; + } + } + s_overhead += duration_cast<microseconds>(steady_clock::now() - start); +} + +struct SampleProfilerTreeIteratorImpl final : public SampleProfilerTreeIterator +{ + struct StackNode + { + Node* node; + const char* name; + }; + + SampleProfilerTreeIteratorImpl(std::map<const char*, Node>& roots) + { + for (auto& root : roots) + { + m_stack.emplace(StackNode { &root.second, root.first }); + } + + next(); + } + + virtual const Data* data() const override + { + return m_valid ? &m_data : nullptr; + } + + Node* node() + { + return m_node; + } + + virtual bool isDone() const + { + return !m_valid; + } + + virtual void next() + { + if (!m_stack.empty()) + { + auto& e = m_stack.top(); + m_stack.pop(); + m_node = e.node; + m_data.depth = 0; + m_data.hash = (uint64_t)m_node; + for (const Node* p = m_node; p != nullptr; p = p->parent) + { + m_data.depth++; + } + m_data.name = e.name; + m_data.calls = m_node->data.prevCalls; + m_data.time = m_node->data.prevTime; + m_data.maxTime = m_node->data.maxTime; + m_data.hasChilds = !m_node->childs.empty(); + + for (auto it = m_node->childs.rbegin(); it != m_node->childs.rend(); ++it) + { + m_stack.emplace(StackNode { &(*it).second, (*it).first }); + } + m_valid = true; + } + else + { + m_valid = false; + } + } + + virtual void release() + { + delete this; + } + + bool m_valid; + Data m_data; + Node* m_node; + std::stack<StackNode > m_stack; +}; + +void SampleProfilerReset() +{ + for (SampleProfilerTreeIteratorImpl it(s_roots); !it.isDone(); it.next()) + { + auto& data = it.node()->data; + data.prevTime = data.time; + data.prevCalls = data.calls; + data.time = microseconds(); + data.calls = 0; + } + s_currentNode = nullptr; + s_beginEndMismatch = false; + s_prevOverhead = s_overhead; + s_overhead = microseconds(); +} + +bool SampleProfilerIsValid() +{ + return !s_beginEndMismatch; +} + +microseconds SampleProfilerGetOverhead() +{ + return s_prevOverhead; +} + +SampleProfilerTreeIterator* SampleProfilerCreateTreeIterator() +{ + return SampleProfilerIsValid() ? new SampleProfilerTreeIteratorImpl(s_roots) : nullptr; +} + +void SampleProfilerDumpToFile(const char* path) +{ + std::ofstream myfile(path, std::ios_base::out); + if (myfile.is_open()) + { + if (s_beginEndMismatch) + { + myfile << "Error: Begin/End Mismatch.\n"; + } + else + { + myfile << "[Root]\n"; + for(SampleProfilerTreeIteratorImpl it(s_roots); !it.isDone(); it.next()) + { + auto data = it.data(); + for (uint32_t i = 0; i < data->depth; ++i) + myfile << "\t"; + myfile << data->name << " --> calls: " << data->calls << ", total: " << data->time.count() * 0.001 << "ms\n"; + } + } + + myfile.close(); + } +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleProfiler.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleProfiler.h new file mode 100644 index 0000000..1ea3663 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleProfiler.h @@ -0,0 +1,79 @@ +/* +* 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 SAMPLEPROFILER_H +#define SAMPLEPROFILER_H + +#include <chrono> + +#if NV_PROFILE + +void SampleProfilerInit(); +void SampleProfilerBegin(const char* name); +void SampleProfilerEnd(); +void SampleProfilerReset(); + +struct SampleProfilerScoped +{ + SampleProfilerScoped(const char* name) + { + SampleProfilerBegin(name); + } + + ~SampleProfilerScoped() + { + SampleProfilerEnd(); + } +}; + +#define PROFILER_INIT() SampleProfilerInit() +#define PROFILER_BEGIN(x) SampleProfilerBegin(x) +#define PROFILER_END() SampleProfilerEnd() +#define PROFILER_SCOPED(x) SampleProfilerScoped __scopedProfiler__(x) +#define PROFILER_SCOPED_FUNCTION() SampleProfilerScoped __scopedProfiler__(__FUNCTION__) +#define PROFILER_RESET() SampleProfilerReset() + +#else + +#define PROFILER_INIT() +#define PROFILER_BEGIN(x) +#define PROFILER_END() +#define PROFILER_SCOPED(x) +#define PROFILER_SCOPED_FUNCTION() +#define PROFILER_RESET() + +#endif + +void SampleProfilerDumpToFile(const char* path); +bool SampleProfilerIsValid(); +std::chrono::microseconds SampleProfilerGetOverhead(); + +struct SampleProfilerTreeIterator +{ + struct Data + { + uint64_t hash; + const char* name; + bool hasChilds; + uint32_t depth; + std::chrono::microseconds time; + std::chrono::microseconds maxTime; + uint32_t calls; + }; + + virtual const Data* data() const = 0; + virtual bool isDone() const = 0; + virtual void next() = 0; + virtual void release() = 0; +}; + +SampleProfilerTreeIterator* SampleProfilerCreateTreeIterator(); + +#endif //SAMPLEPROFILER_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleTime.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleTime.h new file mode 100644 index 0000000..c62ced2 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/SampleTime.h @@ -0,0 +1,58 @@ +/* +* 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 SAMPLE_TIME_H +#define SAMPLE_TIME_H + +#include <stdint.h> + +class Time +{ +public: + Time() : m_lastTickCount(getTimeTicks()) {} + + double Time::getElapsedSeconds() + { + const int64_t lastTickCount = m_lastTickCount; + m_lastTickCount = getTimeTicks(); + return (m_lastTickCount - lastTickCount) * s_secondsPerTick; + } + + double Time::peekElapsedSeconds() const + { + return (getTimeTicks() - m_lastTickCount) * s_secondsPerTick; + } + + double Time::getLastTime() const + { + return m_lastTickCount * s_secondsPerTick; + } + +private: + static double getTickDuration() + { + LARGE_INTEGER a; + QueryPerformanceFrequency(&a); + return 1.0 / (double)a.QuadPart; + } + + int64_t getTimeTicks() const + { + LARGE_INTEGER a; + QueryPerformanceCounter(&a); + return a.QuadPart; + } + + int64_t m_lastTickCount; + static const double s_secondsPerTick; +}; + + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/UIHelpers.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/UIHelpers.h new file mode 100644 index 0000000..b23eb84 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/UIHelpers.h @@ -0,0 +1,56 @@ +/* +* 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 UI_HELPERS_H +#define UI_HELPERS_H + +#include "imgui.h" +#include "PxVec3.h" + + +static void ImGui_DragFloat3Dir(const char* label, float v[3]) +{ + if (ImGui::Button("Normalize")) + { + ((physx::PxVec3*)v)->normalize(); + } + ImGui::SameLine(); + ImGui::DragFloat3(label, v); +}; + + +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) + +template<int valuesCount = 90> +class PlotLinesInstance +{ +public: + PlotLinesInstance() + { + memset(m_values, 0, sizeof(float) * valuesCount); + } + + void plot(const char* label, float newValue, const char* overlay_text, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 80)) + { + for (; ImGui::GetTime() > m_time + 1.0f / 60.0f; m_time += 1.0f / 60.0f) + { + m_values[m_offset] = newValue; + m_offset = (m_offset + 1) % valuesCount; + } + ImGui::PlotLines(label, m_values, valuesCount, m_offset, overlay_text, scale_min, scale_max, graph_size); + } + +private: + float m_values[valuesCount]; + int m_offset; + float m_time = ImGui::GetTime(); +}; + +#endif //UI_HELPERS_H
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/Utils.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/Utils.cpp new file mode 100644 index 0000000..a271137 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/Utils.cpp @@ -0,0 +1,13 @@ +#include "Utils.h" + +#include <string> +#include <cstdarg> + +HRESULT messagebox_printf(const char* caption, UINT mb_type, const char* format, ...) +{ + va_list args; + va_start(args, format); + char formatted_text[512]; + _vsnprintf(formatted_text, 512, format, args); + return MessageBoxA(nullptr, formatted_text, caption, mb_type); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/Utils.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/Utils.h new file mode 100644 index 0000000..5d4addc --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/SampleBase/utils/Utils.h @@ -0,0 +1,91 @@ +#ifndef UTILS_H +#define UTILS_H + +#include <DeviceManager.h> +#include <assert.h> + +#include "PxPreprocessor.h" + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MACROS +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef V_RETURN +#define V_RETURN(x) \ + { \ + hr = (x); \ + if(FAILED(hr)) \ + { \ + return hr; \ + } \ + } +#endif + +#ifndef V +#define V(x) \ + { \ + HRESULT hr = (x); \ + _ASSERT(SUCCEEDED(hr)); \ + } +#endif + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) \ + { \ + if(p) \ + { \ + (p)->Release(); \ + (p) = NULL; \ + } \ + } +#endif + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) \ + { \ + if(p) \ + { \ + delete (p); \ + (p) = NULL; \ + } \ + } +#endif + +#define ASSERT_PRINT(cond, format, ...) \ + if(!(cond)) \ + { \ + messagebox_printf("Assertion Failed!", MB_OK | MB_ICONERROR, #cond "\n" format, __VA_ARGS__); \ + assert(cond); \ + } + +HRESULT messagebox_printf(const char* caption, UINT mb_type, const char* format, ...); + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static const char* strext(const char* str) +{ + const char* ext = NULL; // by default no extension found! + while (str) + { + str = strchr(str, '.'); + if (str) + { + str++; + ext = str; + } + } + return ext; +} + +static inline float lerp(float a, float b, float t) { return a + (b - a) * t; } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastCompositePanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastCompositePanel.cpp new file mode 100644 index 0000000..b42a4f5 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastCompositePanel.cpp @@ -0,0 +1,306 @@ +#include "BlastCompositePanel.h" +#include "ui_BlastCompositePanel.h" +#include "ProjectParams.h" +#include <QtCore/QFileInfo> +#include <QtWidgets/QInputDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QMessageBox> + +BlastCompositePanel::BlastCompositePanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::BlastCompositePanel), + _selectedAsset(-1) +{ + ui->setupUi(this); + + ui->btnRemoveAsset->setEnabled(false); + ui->btnModifyLandmark->setEnabled(false); + ui->btnRemoveLandmark->setEnabled(false); +} + +BlastCompositePanel::~BlastCompositePanel() +{ + delete ui; +} + +void BlastCompositePanel::updateValues() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPComposite& composite = projectParams.blast.composite; + + ui->lineEditComposite->setText(composite.composite.buf); + + _updateAssetComboBox(); + + _updateAssetInstanceListWidget(); + + ui->spinBoxBondByThreshold->setValue(composite.bondThreshold); + ui->spinBoxNewBondStrength->setValue(composite.bondStrength); + + _updateLandmarkListWidget(); + + ui->checkBoxEnableLandmark->setChecked(false); + ui->spinBoxLandmarkRadius->setValue(false); +} + +void BlastCompositePanel::on_btnCollapse_clicked() +{ + +} + +void BlastCompositePanel::on_btnSave_clicked() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPComposite& composite = projectParams.blast.composite; + + QByteArray tmp = ui->lineEditComposite->text().toUtf8(); + copy(composite.composite, tmp.data()); +} + +void BlastCompositePanel::on_comboBoxAsset_currentIndexChanged(int index) +{ + _selectedAsset = index; +} + +void BlastCompositePanel::on_btnAddAsset_clicked() +{ + bool ok = false; + QString name = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input name for new blast instance:"), + QLineEdit::Normal, + "", + &ok); + bool nameExist = BlastProject::ins().isAssetInstanceNameExist(name.toUtf8().data()); + if (ok && !name.isEmpty() && !nameExist) + { + BlastProject::ins().addAssetInstance(_selectedAsset, name.toUtf8().data()); + _updateAssetInstanceListWidget(); + ui->listWidgetBlastAsset->setCurrentRow(ui->listWidgetBlastAsset->count() - 1); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && name.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new preset!"); + } +} + +void BlastCompositePanel::on_btnRemoveAsset_clicked() +{ + QList<QListWidgetItem*> items = ui->listWidgetBlastAsset->selectedItems(); + BlastProject::ins().removeAssetInstance(items.at(0)->text().toUtf8().data()); +} + +void BlastCompositePanel::on_listWidgetBlastAsset_itemSelectionChanged() +{ + QList<QListWidgetItem*> items = ui->listWidgetBlastAsset->selectedItems(); + if (items.count() > 0) + ui->btnRemoveAsset->setEnabled(true); + else + ui->btnRemoveAsset->setEnabled(false); +} + +void BlastCompositePanel::on_spinBoxBondByThreshold_valueChanged(double arg1) +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPComposite& composite = projectParams.blast.composite; + composite.bondThreshold = arg1; +} + +void BlastCompositePanel::on_spinBoxNewBondStrength_valueChanged(double arg1) +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPComposite& composite = projectParams.blast.composite; + composite.bondStrength = arg1; +} + +void BlastCompositePanel::on_btnAddLandmark_clicked() +{ + bool ok = false; + QString name = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input name for new landmark:"), + QLineEdit::Normal, + "", + &ok); + bool nameExist = BlastProject::ins().isLandmarkNameExist(name.toUtf8().data()); + if (ok && !name.isEmpty() && !nameExist) + { + BlastProject::ins().addLandmark(name.toUtf8().data()); + _updateLandmarkListWidget(); + ui->listWidgetLandmark->setCurrentRow(ui->listWidgetLandmark->count() - 1); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && name.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new landmark!"); + } +} + +void BlastCompositePanel::on_btnModifyLandmark_clicked() +{ + QList<QListWidgetItem*> items = ui->listWidgetLandmark->selectedItems(); + QByteArray tem = items.at(0)->text().toUtf8(); + const char* oldName = tem.data(); + + bool ok = false; + QString newName = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input new name for the selected landmark:"), + QLineEdit::Normal, + oldName, + &ok); + bool nameExist = BlastProject::ins().isLandmarkNameExist(newName.toUtf8().data()); + if (ok && !newName.isEmpty() && !nameExist) + { + int selectIndex = ui->listWidgetLandmark->currentRow(); + BlastProject::ins().renameLandmark(oldName, newName.toUtf8().data()); + _updateLandmarkListWidget(); + ui->listWidgetLandmark->setCurrentRow(selectIndex); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && newName.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new landmark!"); + } +} + +void BlastCompositePanel::on_btnRemoveLandmark_clicked() +{ + QList<QListWidgetItem*> items = ui->listWidgetLandmark->selectedItems(); + QByteArray tem = items.at(0)->text().toUtf8(); + const char* name = tem.data(); + BlastProject::ins().removeLandmark(name); + _updateLandmarkListWidget(); +} + +void BlastCompositePanel::on_listWidgetLandmark_itemSelectionChanged() +{ + _updateLandmarkUIs(); +} + +void BlastCompositePanel::on_checkBoxEnableLandmark_stateChanged(int arg1) +{ + QList<QListWidgetItem*> items = ui->listWidgetLandmark->selectedItems(); + + int count = items.count(); + for (int i = 0; i < count; ++i) + { + BPPLandmark* landmark = BlastProject::ins().getLandmark(items.at(0)->text().toUtf8().data()); + if (landmark != nullptr) + { + landmark->enable = ui->checkBoxEnableLandmark->isChecked(); + } + } +} + +void BlastCompositePanel::on_spinBoxLandmarkRadius_valueChanged(double arg1) +{ + QList<QListWidgetItem*> items = ui->listWidgetLandmark->selectedItems(); + + int count = items.count(); + for (int i = 0; i < count; ++i) + { + BPPLandmark* landmark = BlastProject::ins().getLandmark(items.at(0)->text().toUtf8().data()); + if (landmark != nullptr) + { + landmark->radius = ui->spinBoxLandmarkRadius->value(); + } + } +} + +void BlastCompositePanel::_updateAssetComboBox() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPAssetArray& blastAssetArray = projectParams.blast.blastAssets; + BPPComposite& composite = projectParams.blast.composite; + + ui->comboBoxAsset->clear(); + int countAssets = blastAssetArray.arraySizes[0]; + if (countAssets > 0) + { + QStringList assets; + for (int i = 0; i < countAssets; ++i) + { + QFileInfo fileInfo(blastAssetArray.buf[i].path.buf); + assets.append(fileInfo.baseName()); + } + ui->comboBoxAsset->addItems(assets); + } + else + { + ui->btnAddAsset->setEnabled(false); + ui->btnRemoveAsset->setEnabled(false); + } +} + +void BlastCompositePanel::_updateAssetInstanceListWidget() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPComposite& composite = projectParams.blast.composite; + + ui->listWidgetBlastAsset->clear(); + int countAssetInstances = composite.blastAssetInstances.arraySizes[0]; + if (countAssetInstances > 0) + { + QStringList assetInstances; + + for (int i = 0; i < countAssetInstances; ++i) + { + assetInstances.append(composite.blastAssetInstances.buf[i].name.buf); + } + ui->listWidgetBlastAsset->addItems(assetInstances); + } +} + +void BlastCompositePanel::_updateLandmarkListWidget() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPComposite& composite = projectParams.blast.composite; + + ui->listWidgetLandmark->clear(); + int countJoints = composite.landmarks.arraySizes[0]; + if (countJoints > 0) + { + QStringList landmarks; + + for (int i = 0; i < countJoints; ++i) + { + landmarks.append(composite.landmarks.buf[i].name.buf); + } + ui->listWidgetLandmark->addItems(landmarks); + } +} + +void BlastCompositePanel::_updateLandmarkUIs() +{ + QList<QListWidgetItem*> items = ui->listWidgetLandmark->selectedItems(); + + if (items.count() > 0) + { + BPPLandmark* landmark = BlastProject::ins().getLandmark(items.at(0)->text().toUtf8().data()); + if (landmark != nullptr) + { + ui->btnModifyLandmark->setEnabled(true); + ui->btnRemoveLandmark->setEnabled(true); + ui->checkBoxEnableLandmark->setChecked(landmark->enable); + ui->spinBoxLandmarkRadius->setValue(landmark->radius); + } + } + else + { + ui->btnModifyLandmark->setEnabled(false); + ui->btnRemoveLandmark->setEnabled(false); + ui->checkBoxEnableLandmark->setChecked(false); + ui->spinBoxLandmarkRadius->setValue(0.0f); + } +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastCompositePanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastCompositePanel.h new file mode 100644 index 0000000..b4e5bcf --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastCompositePanel.h @@ -0,0 +1,59 @@ +#ifndef BLASTCOMPOSITEPANEL_H +#define BLASTCOMPOSITEPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class BlastCompositePanel; +} + +class BlastCompositePanel : public QWidget +{ + Q_OBJECT + +public: + explicit BlastCompositePanel(QWidget *parent = 0); + ~BlastCompositePanel(); + void updateValues(); + +private slots: + void on_btnCollapse_clicked(); + + void on_btnSave_clicked(); + + void on_comboBoxAsset_currentIndexChanged(int index); + + void on_btnAddAsset_clicked(); + + void on_btnRemoveAsset_clicked(); + + void on_listWidgetBlastAsset_itemSelectionChanged(); + + void on_spinBoxBondByThreshold_valueChanged(double arg1); + + void on_spinBoxNewBondStrength_valueChanged(double arg1); + + void on_btnAddLandmark_clicked(); + + void on_btnModifyLandmark_clicked(); + + void on_btnRemoveLandmark_clicked(); + + void on_listWidgetLandmark_itemSelectionChanged(); + + void on_checkBoxEnableLandmark_stateChanged(int arg1); + + void on_spinBoxLandmarkRadius_valueChanged(double arg1); + +private: + void _updateAssetComboBox(); + void _updateAssetInstanceListWidget(); + void _updateLandmarkListWidget(); + void _updateLandmarkUIs(); + +private: + Ui::BlastCompositePanel *ui; + int _selectedAsset; +}; + +#endif // BLASTCOMPOSITEPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastSceneTree.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastSceneTree.cpp new file mode 100644 index 0000000..64a7c2f --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastSceneTree.cpp @@ -0,0 +1,1804 @@ +#include "BlastSceneTree.h" +#include <QtWidgets/QMessageBox> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QMenu> +#include <QtCore/QFileInfo> +#include <assert.h> +#include "ProjectParams.h" +#include <SimpleScene.h> +#include <BlastController.h> +#include <SceneController.h> +#include <NvBlastExtPxAsset.h> +#include <NvBlastTkAsset.h> +#include <NvBlastAsset.h> +#include <BlastFamilyModelSimple.h> + +bool isChunkVisible(std::vector<BlastFamily*>& fs, uint32_t chunkIndex) +{ + int fsSize = fs.size(); + if (fsSize == 0) + { + return false; + } + + bool visible = false; + for (int i = 0; i < fsSize; i++) + { + if (fs[i]->isChunkVisible(chunkIndex)) + { + visible = true; + break; + } + } + return visible; +} + +void setChunkVisible(std::vector<BlastFamily*>& fs, uint32_t chunkIndex, bool visible) +{ + int fsSize = fs.size(); + if (fsSize == 0) + { + return; + } + + for (int i = 0; i < fsSize; i++) + { + fs[i]->setChunkVisible(chunkIndex, visible); + } +} + +void setChunkSelected(std::vector<BlastFamily*>& fs, uint32_t chunkIndex, bool selected) +{ + int fsSize = fs.size(); + if (fsSize == 0) + { + return; + } + + for (int i = 0; i < fsSize; i++) + { + fs[i]->setChunkSelected(chunkIndex, selected); + } +} + +void BlastChunkNode::setVisible(bool val) +{ + BPPChunk* pBPPChunk = (BPPChunk*)_data; + pBPPChunk->visible = val; + + BlastAsset* pBlastAsset = (BlastAsset*)_assetPtr; + + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + + std::map<BlastAsset*, std::vector<BlastFamily*>>& AssetFamiliesMap = sampleManager.getAssetFamiliesMap(); + std::vector<BlastFamily*>& fs = AssetFamiliesMap[pBlastAsset]; + + setChunkVisible(fs, pBPPChunk->ID, val); +} + +void BlastChunkNode::setSelected(bool val) +{ + BPPChunk* pBPPChunk = (BPPChunk*)_data; + pBPPChunk->visible = val; + + BlastAsset* pBlastAsset = (BlastAsset*)_assetPtr; + + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + + std::map<BlastAsset*, std::vector<BlastFamily*>>& AssetFamiliesMap = sampleManager.getAssetFamiliesMap(); + std::vector<BlastFamily*>& fs = AssetFamiliesMap[pBlastAsset]; + + setChunkSelected(fs, pBPPChunk->ID, val); +} + +void BlastAssetInstanceNode::setSelected(bool val) +{ + BPPAssetInstance* pBPPAssetInstance = (BPPAssetInstance*)_data; + std::string name = pBPPAssetInstance->name; + + std::string strAsset = name.substr(0, name.find_first_of("_")); + BlastAsset* pBlastAsset = nullptr; + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + std::map<BlastAsset*, AssetList::ModelAsset>& AssetDescMap = sampleManager.getAssetDescMap(); + std::map<BlastAsset*, AssetList::ModelAsset>::iterator itAssetDescMap; + for (itAssetDescMap = AssetDescMap.begin(); + itAssetDescMap != AssetDescMap.end(); itAssetDescMap++) + { + AssetList::ModelAsset& model = itAssetDescMap->second; + if (model.name == strAsset) + { + pBlastAsset = itAssetDescMap->first; + break; + } + } + + std::string strIndex = name.substr(name.find_last_of("_") + 1); + int nIndex = atoi(strIndex.c_str()); + + sampleManager.setCurrentSelectedInstance(pBlastAsset, nIndex); +} + +BlastTreeData& BlastTreeData::ins() +{ + static BlastTreeData _ins; + return _ins; +} + +bool BlastTreeData::isChild(BlastChunkNode* parent, BlastChunkNode* child) +{ + if (parent == nullptr || child == nullptr) + return false; + + BlastNode* curParent = child->getParent(); + while (eChunk == curParent->getType() && curParent != nullptr) + { + if (curParent == parent) + return true; + curParent = curParent->getParent(); + } + + return false; +} + +std::vector<BlastChunkNode*> BlastTreeData::getTopChunkNodes(std::vector<BlastChunkNode*>& nodes) +{ + std::vector<BlastChunkNode*> result; + + for (size_t i = 0; i < nodes.size(); ++i) + { + bool isCurNodeTop = true; + for (size_t j = 0; j < nodes.size(); ++j) + { + if (i != j && isChild(nodes[i], nodes[j])) + { + isCurNodeTop = false; + break; + } + } + + if (isCurNodeTop) + { + result.push_back(nodes[i]); + } + } + + return result; +} + +bool BlastTreeData::isRoot(BlastChunkNode* node) +{ + if (node == nullptr || node->getParent() == nullptr) + return false; + + return eAsset == node->getParent()->getType(); +} + +bool BlastTreeData::isLeaf(BlastChunkNode* node) +{ + if (node == nullptr) + return false; + + for (BlastNode* curNode : node->children) + { + if (eChunk == curNode->getType()) + return false; + } + + return true; +} + +void removeChunkNodeSupport(BlastChunkNode* node) +{ + if (node == nullptr) + return; + + BPPChunk* chunk = static_cast<BPPChunk*>(node->getData()); + chunk->support = false; + + for (BlastNode* curNode : node->children) + { + if (eChunk == curNode->getType()) + { + removeChunkNodeSupport((BlastChunkNode*)curNode); + } + } +} + +void BlastTreeData::makeSupport(BlastChunkNode* node) +{ + if (node == nullptr) + return; + BPPChunk* chunk = static_cast<BPPChunk*>(node->getData()); + chunk->staticFlag = false; + chunk->support = true; + + for (BlastNode* curNode : node->children) + { + if (eChunk == curNode->getType()) + { + removeChunkNodeSupport((BlastChunkNode*)curNode); + } + } +} + +void BlastTreeData::makeStaticSupport(BlastChunkNode* node) +{ + if (node == nullptr) + return; + BPPChunk* chunk = static_cast<BPPChunk*>(node->getData()); + chunk->staticFlag = true; + chunk->support = true; + + for (BlastNode* curNode : node->children) + { + if (eChunk == curNode->getType()) + { + removeChunkNodeSupport((BlastChunkNode*)curNode); + } + } +} + +void BlastTreeData::removeSupport(BlastChunkNode* node) +{ + if (node == nullptr) + return; + + if (isLeaf(node)) + return; + + BPPChunk* chunk = static_cast<BPPChunk*>(node->getData()); + chunk->support = false; + chunk->staticFlag = false; + + for (BlastNode* curNode : node->children) + { + if (eChunk == curNode->getType()) + { + BPPChunk* curChunk = static_cast<BPPChunk*>(curNode->getData()); + curChunk->support = true; + } + } +} + +BlastNode* BlastTreeData::getBlastNodeByProjectData(void* data) +{ + std::map<void*, BlastNode*>::iterator itr = _blastProjectDataToNodeMap.find(data); + if (itr != _blastProjectDataToNodeMap.end()) + return itr->second; + + return nullptr; +} + +struct ChunkSupport +{ + ChunkSupport() + { + m_bSupport = false; + } + + bool m_bSupport; +}; + +struct BondChunkIndices +{ + BondChunkIndices() + { + chunkIndices[0] = -1; + chunkIndices[1] = -1; + } + + void SetIndices(uint32_t chunkIndex0, uint32_t chunkIndex1) + { + if (chunkIndex0 < chunkIndex1) + { + chunkIndices[0] = chunkIndex0; + chunkIndices[1] = chunkIndex1; + } + else + { + chunkIndices[0] = chunkIndex1; + chunkIndices[1] = chunkIndex0; + } + } + + uint32_t chunkIndices[2]; +}; + +void BlastTreeData::update() +{ + _freeBlastNode(); + + BPPBlast& blast = BlastProject::ins().getParams().blast; + std::vector<BlastAsset*> BlastAssetVec; + { + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + + std::map<BlastAsset*, std::vector<BlastFamily*>>& AssetFamiliesMap = sampleManager.getAssetFamiliesMap(); + std::map<BlastAsset*, AssetList::ModelAsset>& AssetDescMap = sampleManager.getAssetDescMap(); + + BlastController& blastController = sampleManager.getBlastController(); + SceneController& sceneController = sampleManager.getSceneController(); + + std::vector<BlastFamilyPtr>& families = blastController.getFamilies(); + int familiesSize = families.size(); + + std::map<BlastAsset*, AssetList::ModelAsset>::iterator it; + for (it = AssetDescMap.begin(); it != AssetDescMap.end(); it++) + { + BlastAssetVec.push_back(it->first); + } + int modelAssetsSize = AssetDescMap.size(); + + std::vector<std::string> projectilesNames; + sceneController.GetProjectilesNames(projectilesNames); + + // compoistie + { + BPPComposite& composite = blast.composite; + composite.composite.buf = nullptr; + composite.visible = true; + + copy(composite.composite, "BlastComposite"); + + // asset instance array + { + BPPAssetInstanceArray& instanceArray = composite.blastAssetInstances; + instanceArray.arraySizes[0] = familiesSize; + if (familiesSize > 0) + { + instanceArray.buf = new BPPAssetInstance[familiesSize]; + int curInstanceIndex = 0; + char instancename[50]; + std::map<BlastAsset*, std::vector<BlastFamily*>>::iterator itAssetFamiliesMap; + for (itAssetFamiliesMap = AssetFamiliesMap.begin(); + itAssetFamiliesMap != AssetFamiliesMap.end(); itAssetFamiliesMap++) + { + BlastAsset* pBlastAsset = itAssetFamiliesMap->first; + std::vector<BlastFamily*>& fs = itAssetFamiliesMap->second; + int fsSize = fs.size(); + for (int i = 0; i < fsSize; i++) + { + BPPAssetInstance& instance = instanceArray.buf[curInstanceIndex]; + instance.name.buf = nullptr; + instance.source.buf = nullptr; + instance.visible = true; + + AssetList::ModelAsset desc = AssetDescMap[pBlastAsset]; + sprintf(instancename, "%s_Instance_%d", desc.name.c_str(), i); + copy(instance.name, instancename); + + std::string assetFilePath = SampleManager::ins()->getConfig().additionalResourcesDir.back() + "/models/" + desc.file + ".bpxa"; + sprintf(instancename, "%s", assetFilePath.c_str()); + copy(instance.source, instancename); + + PxVec3 p = desc.transform.p; + PxQuat q = desc.transform.q; + instanceArray.buf[curInstanceIndex].transform.position = nvidia::NvVec3(p.x, p.y, p.z); + instanceArray.buf[curInstanceIndex].transform.rotation = nvidia::NvVec4(q.x, q.y, q.z, q.w); + + curInstanceIndex++; + } + } + } + } + + // landmark array + if (0) + { + BPPLandmarkArray& landmarkArray = composite.landmarks; + landmarkArray.buf = new BPPLandmark[2]; + landmarkArray.arraySizes[0] = 2; + landmarkArray.buf[0].name.buf = nullptr; + landmarkArray.buf[1].name.buf = nullptr; + + copy(landmarkArray.buf[0].name, "Landmark_1"); + copy(landmarkArray.buf[1].name, "Landmark_2"); + } + } + + // asset array + { + BPPAssetArray& assetArray = blast.blastAssets; + assetArray.arraySizes[0] = modelAssetsSize; + if (modelAssetsSize > 0) + { + assetArray.buf = new BPPAsset[modelAssetsSize]; + int curAssetIndex = 0; + + blast.chunks.buf = nullptr; + blast.chunks.arraySizes[0] = 0; + blast.bonds.buf = nullptr; + blast.bonds.arraySizes[0] = 0; + + std::map<BlastAsset*, AssetList::ModelAsset>::iterator itAssetDescMap; + for (itAssetDescMap = AssetDescMap.begin(); + itAssetDescMap != AssetDescMap.end(); itAssetDescMap++) + { + BlastAsset* pBlastAsset = itAssetDescMap->first; + AssetList::ModelAsset& desc = itAssetDescMap->second; + std::vector<BlastFamily*>& fs = AssetFamiliesMap[pBlastAsset]; + + BPPAsset& asset = assetArray.buf[curAssetIndex]; + asset.path.buf = nullptr; + asset.activePreset.buf = nullptr; + std::string assetFilePath = SampleManager::ins()->getConfig().additionalResourcesDir.back() + "/models/" + desc.file + ".bpxa"; + copy(asset.path, assetFilePath.c_str()); + + const ExtPxAsset* pExtPxAsset = pBlastAsset->getPxAsset(); + const ExtPxChunk* pExtPxChunk = pExtPxAsset->getChunks(); + + const TkAsset& tkAsset = pExtPxAsset->getTkAsset(); + uint32_t chunkCount = tkAsset.getChunkCount(); + const NvBlastChunk* pNvBlastChunk = tkAsset.getChunks(); + uint32_t bondCount = tkAsset.getBondCount(); + const NvBlastBond* pNvBlastBond = tkAsset.getBonds(); + + const NvBlastSupportGraph supportGraph = tkAsset.getGraph(); + uint32_t* chunkIndices = supportGraph.chunkIndices; + uint32_t* adjacencyPartition = supportGraph.adjacencyPartition; + uint32_t* adjacentNodeIndices = supportGraph.adjacentNodeIndices; + uint32_t* adjacentBondIndices = supportGraph.adjacentBondIndices; + + ChunkSupport* pSupport = new ChunkSupport[chunkCount]; + BondChunkIndices* pBCIndices = new BondChunkIndices[bondCount]; + + for (uint32_t node0 = 0; node0 < supportGraph.nodeCount; ++node0) + { + const uint32_t chunkIndex0 = supportGraph.chunkIndices[node0]; + + pSupport[chunkIndex0].m_bSupport = true; + + for (uint32_t adjacencyIndex = adjacencyPartition[node0]; adjacencyIndex < adjacencyPartition[node0 + 1]; adjacencyIndex++) + { + uint32_t node1 = supportGraph.adjacentNodeIndices[adjacencyIndex]; + + // add this condition if you don't want to iterate all bonds twice + if (node0 > node1) + continue; + + const uint32_t chunkIndex1 = supportGraph.chunkIndices[node1]; + + uint32_t bondIndex = supportGraph.adjacentBondIndices[adjacencyIndex]; + + pBCIndices[bondIndex].SetIndices(chunkIndex0, chunkIndex1); + } + } + + // chunks + { + BPPChunkArray curArray; + curArray.buf = new BPPChunk[chunkCount]; + curArray.arraySizes[0] = chunkCount; + char chunkname[10]; + for (int cc = 0; cc < chunkCount; ++cc) + { + BPPChunk& chunk = curArray.buf[cc]; + chunk.name.buf = nullptr; + chunk.asset.buf = nullptr; + + std::vector<uint32_t> parentChunkIndexes; + parentChunkIndexes.push_back(cc); + uint32_t parentChunkIndex = cc; + while ((parentChunkIndex = pNvBlastChunk[parentChunkIndex].parentChunkIndex) != -1) + { + parentChunkIndexes.push_back(parentChunkIndex); + } + + std::string strChunkName = "Chunk"; + for (int pcIndex = parentChunkIndexes.size() - 1; pcIndex >= 0; pcIndex--) + { + sprintf(chunkname, "_%d", parentChunkIndexes[pcIndex]); + strChunkName += chunkname; + } + copy(chunk.name, strChunkName.c_str()); + + copy(chunk.asset, asset.path); + chunk.ID = cc; + chunk.parentID = pNvBlastChunk[cc].parentChunkIndex; + chunk.staticFlag = pExtPxChunk[cc].isStatic; + chunk.visible = isChunkVisible(fs, cc); + chunk.support = pSupport[cc].m_bSupport; + } + + merge(blast.chunks, curArray); + freeBlast(curArray); + } + + // bonds + { + BPPBondArray curArray; + curArray.buf = new BPPBond[bondCount]; + curArray.arraySizes[0] = bondCount; + char bondname[10]; + bool visible; + for (int bc = 0; bc < bondCount; ++bc) + { + BPPBond& bond = curArray.buf[bc]; + bond.name.buf = nullptr; + bond.asset.buf = nullptr; + + visible = isChunkVisible(fs, pBCIndices[bc].chunkIndices[0]) + || isChunkVisible(fs, pBCIndices[bc].chunkIndices[1]); + bond.visible = visible; + bond.support.healthMask.buf = nullptr; // ? + bond.fromChunk = pBCIndices[bc].chunkIndices[0]; + bond.toChunk = pBCIndices[bc].chunkIndices[1]; + + sprintf(bondname, "Bond_%d_%d", bond.fromChunk, bond.toChunk); + copy(bond.name, bondname); + copy(bond.asset, asset.path); + } + + merge(blast.bonds, curArray); + freeBlast(curArray); + } + + delete[] pSupport; + pSupport = nullptr; + delete[] pBCIndices; + pBCIndices = nullptr; + + curAssetIndex++; + } + } + } + + // projectile + { + BPPProjectileArray& projectileArray = blast.projectiles; + int BPPProjectileSize = projectilesNames.size(); + projectileArray.arraySizes[0] = BPPProjectileSize; + if (BPPProjectileSize > 0) + { + projectileArray.buf = new BPPProjectile[BPPProjectileSize]; + for (int i = 0; i < BPPProjectileSize; i++) + { + projectileArray.buf[i].name.buf = nullptr; + copy(projectileArray.buf[i].name, projectilesNames[i].c_str()); + projectileArray.buf[i].visible = true; + } + } + } + + // graphics meshes + if (0) + { + BPPGraphicsMeshArray& graphicsMeshArray = blast.graphicsMeshes; + graphicsMeshArray.buf = new BPPGraphicsMesh[3]; + graphicsMeshArray.arraySizes[0] = 3; + graphicsMeshArray.buf[0].name.buf = nullptr; + copy(graphicsMeshArray.buf[0].name, "SurfaceMesh1"); + graphicsMeshArray.buf[0].visible = true; + + graphicsMeshArray.buf[1].name.buf = nullptr; + copy(graphicsMeshArray.buf[1].name, "SurfaceMesh2"); + graphicsMeshArray.buf[1].visible = true; + + graphicsMeshArray.buf[2].name.buf = nullptr; + copy(graphicsMeshArray.buf[2].name, "DisplayMesh1"); + graphicsMeshArray.buf[2].visible = true; + } + } + + BPPAssetArray& assetArray = blast.blastAssets; + + int count = assetArray.arraySizes[0]; + for (int c = 0; c < count; ++c) + { + BPPAsset& asset = assetArray.buf[c]; + QFileInfo fileInfo(asset.path.buf); + BlastAssetNode* assetNode = new BlastAssetNode(fileInfo.baseName().toUtf8().data(), asset); + _assets.push_back(assetNode); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)&asset, assetNode)); + + // get the firlst level chunks whose parentID is -1 + std::vector<BPPChunk*> childChunks = BlastProject::ins().getChildrenChunks(asset, -1); + + for (size_t i = 0; i < childChunks.size(); ++i) + { + BPPChunk& chunk = *(childChunks[i]); + BlastChunkNode* chunkNode = new BlastChunkNode(chunk.name.buf, chunk, BlastAssetVec[c]); + assetNode->children.push_back(chunkNode); + chunkNode->setParent(assetNode); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)&chunk, chunkNode)); + _addChunkNode(chunk, asset, chunkNode, BlastAssetVec[c]); + } + } + + BPPComposite& composite = blast.composite; + _composite = new BlastCompositeNode(composite.composite.buf, composite); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)&composite, _composite)); + BPPAssetInstanceArray& assetInstanceArray = composite.blastAssetInstances; + count = assetInstanceArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPAssetInstance& blastAssetInstance = composite.blastAssetInstances.buf[i]; + BlastAssetInstanceNode* blastAssetInstanceNode = new BlastAssetInstanceNode(blastAssetInstance.name.buf, blastAssetInstance); + _composite->children.push_back(blastAssetInstanceNode); + blastAssetInstanceNode->setParent(_composite); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)&blastAssetInstance, blastAssetInstanceNode)); + } + + BPPLandmarkArray& landmarkArray = composite.landmarks; + count = landmarkArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPLandmark& landmark = composite.landmarks.buf[i]; + BlastLandmarkNode* landmarkNode = new BlastLandmarkNode(landmark.name.buf, landmark); + _composite->children.push_back(landmarkNode); + landmarkNode->setParent(_composite); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)&landmark, landmarkNode)); + } + + BPPProjectileArray& projectileArray = blast.projectiles; + count = projectileArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPProjectile& projectile = projectileArray.buf[i]; + BlastProjectileNode* projectileNode = new BlastProjectileNode(projectile.name.buf, projectile); + _projectiles.push_back(projectileNode); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)&projectile, projectileNode)); + } + + BPPGraphicsMeshArray& graphicsMeshArray = blast.graphicsMeshes; + count = graphicsMeshArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPGraphicsMesh& graphicsMesh = graphicsMeshArray.buf[i]; + BlastGraphicsMeshNode* projectileNode = new BlastGraphicsMeshNode(graphicsMesh.name.buf, graphicsMesh); + _graphicsMeshes.push_back(projectileNode); + } +} + +void BlastTreeData::updateVisible(uint32_t assetIndex, uint32_t chunkIndex, bool visible) +{ + BPPBlast& blast = BlastProject::ins().getParams().blast; + BPPAssetArray& assetArray = blast.blastAssets; + if (assetIndex < assetArray.arraySizes[0]) + { + BPPAsset& asset = assetArray.buf[assetIndex]; + + std::vector<BPPChunk*> childChunks = BlastProject::ins().getChildrenChunks(asset); + if (chunkIndex < childChunks.size()) + { + BPPChunk& chunk = *(childChunks[chunkIndex]); + chunk.visible = visible; + } + } +} + + +BlastChunkNode* findChunkNode(BlastChunkNode* chunkNode, uint32_t chunkIndex) +{ + if (chunkNode == nullptr) + return nullptr; + + if (((BPPChunk*)chunkNode->getData())->ID == chunkIndex) + return chunkNode; + + std::vector<BlastNode*>& children = chunkNode->children; + for (size_t i = 0; i < children.size(); ++i) + { + BlastNode* node = children[i]; + if (node->getType() == eChunk) + { + BlastChunkNode* chunkNode = findChunkNode(static_cast<BlastChunkNode*>(node), chunkIndex); + if (chunkNode) + { + return chunkNode; + } + else + continue; + } + + else + continue; + } + + return nullptr; +} + +std::vector<BlastChunkNode*> BlastTreeData::getChunkNodeByBlastChunk(const BlastAsset* asset, const std::vector<uint32_t>& chunkIndexes) +{ + std::vector<BlastChunkNode*> chunkNodes; + if (asset == nullptr || chunkIndexes.size() == 0) + { + return chunkNodes; + } + + BlastAssetNode* assetNode = _getAssetNode(asset); + if (assetNode) + { + std::vector<BlastNode*>& children = assetNode->children; + for (BlastNode* node : children) + { + if (node->getType() == eChunk) + { + for (uint32_t chunkId : chunkIndexes) + { + BlastChunkNode* chunkNode = findChunkNode(static_cast<BlastChunkNode*>(node), chunkId); + if (chunkNode) + { + chunkNodes.push_back(chunkNode); + } + } + } + } + } + + return chunkNodes; +} + +bool isCompleteSupport(BlastChunkNode* node) +{ + if (node == nullptr) + return false; + + if (node->isSupport()) + return true; + + const std::vector<BlastNode*>& children = node->children; + for (BlastNode* curNode : children) + { + if (eChunk == curNode->getType()) + { + BlastChunkNode* chunkNode = (BlastChunkNode*)curNode; + if (0 == chunkNode->children.size()) + { + if (!chunkNode->isSupport()) + return false; + } + + if (!isCompleteSupport(chunkNode)) + return false; + } + } + + return true; +} + +bool BlastTreeData::isCompleteSupportAsset(const BlastAsset* asset) +{ + BlastAssetNode* assetNode = _getAssetNode(asset); + return isCompleteSupportAsset(assetNode); +} + +bool BlastTreeData::isCompleteSupportAsset(const BlastAssetNode* node) +{ + if (node == nullptr) + return false; + + const std::vector<BlastNode*>& children = node->children; + for (BlastNode* curNode : children) + { + if (eChunk == curNode->getType()) + { + BlastChunkNode* chunkNode = (BlastChunkNode*)curNode; + if (!isCompleteSupport(chunkNode)) + return false; + } + } + + return true; +} + +bool BlastTreeData::isOverlapSupportAsset(const BlastAsset* asset) +{ + BlastAssetNode* assetNode = _getAssetNode(asset); + return isOverlapSupportAsset(assetNode); +} + +bool isOverlapSupport(BlastChunkNode* node) +{ + if (node == nullptr) + return false; + + bool isParentSupport = node->isSupport(); + + const std::vector<BlastNode*>& children = node->children; + for (BlastNode* curNode : children) + { + if (eChunk == curNode->getType()) + { + BlastChunkNode* chunkNode = (BlastChunkNode*)curNode; + if (0 == chunkNode->children.size()) + { + if (isParentSupport && chunkNode->isSupport()) + return true; + } + + if (isParentSupport && isOverlapSupport(chunkNode)) + return true; + } + } + + return false; +} + +bool BlastTreeData::isOverlapSupportAsset(const BlastAssetNode* node) +{ + if (node == nullptr) + return false; + + const std::vector<BlastNode*>& children = node->children; + for (BlastNode* curNode : children) + { + if (eChunk == curNode->getType()) + { + BlastChunkNode* chunkNode = (BlastChunkNode*)curNode; + if (isOverlapSupport(chunkNode)) + return true; + } + } + + return false; +} + +BlastTreeData::BlastTreeData() +{ + +} + +void BlastTreeData::_addChunkNode(const BPPChunk& parentData, BPPAsset& asset, BlastChunkNode* parentNode, void* assetPtr) +{ + if (parentNode != nullptr) + { + std::vector<BPPBond*> bonds = BlastProject::ins().getBondsByChunk(asset, parentData.ID); + for (size_t i = 0; i < bonds.size(); ++i) + { + BPPBond* bond = bonds[i]; + BlastBondNode* bondNode = new BlastBondNode(bond->name.buf, *bond); + parentNode->children.push_back(bondNode); + bondNode->setParent(parentNode); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)bond, bondNode)); + } + + std::vector<BPPChunk*> childChunks = BlastProject::ins().getChildrenChunks(asset, parentData.ID); + + for (size_t i = 0; i < childChunks.size(); ++i) + { + BPPChunk& chunk = *(childChunks[i]); + BlastChunkNode* chunkNode = new BlastChunkNode(chunk.name.buf, chunk, assetPtr); + parentNode->children.push_back(chunkNode); + chunkNode->setParent(parentNode); + _blastProjectDataToNodeMap.insert(std::make_pair((void*)&chunk, chunkNode)); + _addChunkNode(chunk, asset, chunkNode, assetPtr); + } + } +} + +void freeChunkNode(BlastChunkNode* chunkNode) +{ + if (chunkNode == nullptr) + return; + + std::vector<BlastNode*>& children = chunkNode->children; + for (size_t i = 0; i < children.size(); ++i) + { + BlastNode* node = children[i]; + if (node->getType() == eChunk) + freeChunkNode(static_cast<BlastChunkNode*>(node)); + else + { + delete node; + node = nullptr; + } + } + + delete chunkNode; + chunkNode = nullptr; +} + +void BlastTreeData::_freeBlastNode() +{ + if (_composite) + { + size_t count = _composite->children.size(); + for (size_t i = 0; i < count; ++i) + { + delete _composite->children[i]; + } + delete _composite; + _composite = nullptr; + } + + size_t count = _assets.size(); + for (size_t i = 0; i < count; ++i) + { + std::vector<BlastNode*>& children = _assets[i]->children; + for (size_t j = 0; j < children.size(); ++j) + { + freeChunkNode(static_cast<BlastChunkNode*>(children[j])); + } + delete _assets[i]; + } + _assets.clear(); + + count = _projectiles.size(); + for (size_t i = 0; i < count; ++i) + { + delete _projectiles[i]; + } + _projectiles.clear(); + + count = _graphicsMeshes.size(); + for (size_t i = 0; i < count; ++i) + { + delete _graphicsMeshes[i]; + } + _graphicsMeshes.clear(); + + _blastProjectDataToNodeMap.clear(); +} + +BlastAssetNode* BlastTreeData::_getAssetNode(const BlastAsset* asset) +{ + std::map<BlastAsset*, AssetList::ModelAsset>& assetDescMap = SampleManager::ins()->getAssetDescMap(); + std::map<BlastAsset*, AssetList::ModelAsset>::iterator itrAssetDesc = assetDescMap.find(const_cast<BlastAsset*>(asset)); + + BlastAssetNode* foundAssetNode = nullptr; + for (BlastAssetNode* assetNode : _assets) + { + if (itrAssetDesc->second.name == assetNode->name) + { + foundAssetNode = assetNode; + break; + } + } + + return foundAssetNode; +} + +VisualButton::VisualButton(QWidget* parent, BlastNode* blastItem) + : QWidget(parent) + , _button(new QPushButton(parent)) + , _blastItem(blastItem) +{ + connect(_button, SIGNAL(toggled(bool)), this, SLOT(on_visualbility_toggled(bool))); + _button->setCheckable(true); + _button->setChecked(blastItem->getVisible()); + if (blastItem->getVisible()) + _button->setIcon(QIcon(":/AppMainWindow/images/visibilityToggle_visible.png")); + else + _button->setIcon(QIcon(":/AppMainWindow/images/visibilityToggle_notVisible.png")); + _button->setFixedSize(20, 20); + this->setLayoutDirection(Qt::RightToLeft); + this->setLayout(new QHBoxLayout); + this->layout()->setMargin(0); + this->layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + this->layout()->addWidget(_button); +} + +void VisualButton::on_visualbility_toggled(bool checked) +{ + if (checked) + { + _button->setIcon(QIcon(":/AppMainWindow/images/visibilityToggle_visible.png")); + } + else + { + _button->setIcon(QIcon(":/AppMainWindow/images/visibilityToggle_notVisible.png")); + } + + if (_blastItem) + { + _blastItem->setVisible(checked); + } +} + +void VisualButton::_updateBlast(bool visible) +{ + EBlastNodeType type = _blastItem->getType(); + + switch (type) + { + case eBond: + ((BPPBond*)_blastItem->getData())->visible = visible; + break; + case eChunk: + ((BPPChunk*)_blastItem->getData())->visible = visible; + break; + case eAsset: + ((BPPAsset*)_blastItem->getData())->visible = visible; + break; + case eProjectile: + ((BPPBond*)_blastItem->getData())->visible = visible; + break; + case eGraphicsMesh: + ((BPPGraphicsMesh*)_blastItem->getData())->visible = visible; + break; + case eAssetInstance: + ((BPPAssetInstance*)_blastItem->getData())->visible = visible; + break; + case eLandmark: + ((BPPLandmark*)_blastItem->getData())->visible = visible; + break; + case eComposite: + ((BPPComposite*)_blastItem->getData())->visible = visible; + break; + default: + break; + } +} + +static BlastSceneTree* sBlastSceneTree = nullptr; +BlastSceneTree* BlastSceneTree::ins() +{ + return sBlastSceneTree; +} + +BlastSceneTree::BlastSceneTree(QWidget *parent) + : QDockWidget(parent) +{ + ui.setupUi(this); + _updateData = true; + sBlastSceneTree = this; + + ui.blastSceneTree->setStyleSheet("QTreeWidget::item{height:24px}"); + ui.blastSceneTree->setColumnWidth(0, 260); + ui.blastSceneTree->setColumnWidth(1, 20); + + ui.blastSceneTree->setContextMenuPolicy(Qt::CustomContextMenu); + + _treeChunkContextMenu = new QMenu(this); + _makeSupportAction = new QAction(tr("Make Support"), this); + _treeChunkContextMenu->addAction(_makeSupportAction); + connect(_makeSupportAction, SIGNAL(triggered()), this, SLOT(onMakeSupportMenuItemClicked())); + + _makeStaticSupportAction = new QAction(tr("Make Static Support"), this); + _treeChunkContextMenu->addAction(_makeStaticSupportAction); + connect(_makeStaticSupportAction, SIGNAL(triggered()), this, SLOT(onMakeStaticSupportMenuItemClicked())); + + _removeSupportAction = new QAction(tr("Remove Support"), this); + _treeChunkContextMenu->addAction(_removeSupportAction); + connect(_removeSupportAction, SIGNAL(triggered()), this, SLOT(onRemoveSupportMenuItemClicked())); + + _treeBondContextMenu = new QMenu(this); + _bondChunksAction = new QAction(tr("Bond Chunks"), this); + _treeBondContextMenu->addAction(_bondChunksAction); + connect(_bondChunksAction, SIGNAL(triggered()), this, SLOT(onBondChunksMenuItemClicked())); + + _bondChunksWithJointsAction = new QAction(tr("Bond Chunks With Joints"), this); + _treeBondContextMenu->addAction(_bondChunksWithJointsAction); + connect(_bondChunksWithJointsAction, SIGNAL(triggered()), this, SLOT(onBondChunksWithJointsMenuItemClicked())); + + _removeAllBondsAction = new QAction(tr("Remove All Bonds"), this); + _treeBondContextMenu->addAction(_removeAllBondsAction); + connect(_removeAllBondsAction, SIGNAL(triggered()), this, SLOT(onRemoveAllBondsMenuItemClicked())); +} + +BlastSceneTree::~BlastSceneTree() +{ + +} + +void BlastSceneTree::updateValues(bool updataData) +{ + if (updataData) + { + BlastTreeData::ins().update(); + } + + _updateTreeUIs(); +} + +void BlastSceneTree::dataSelected(std::vector<BlastNode*> selections) +{ + for (size_t i = 0; i < selections.size(); ++i) + { + _selectTreeItem(selections[i]); + } +} + +void BlastSceneTree::addObserver(ISceneObserver* observer) +{ + std::vector<ISceneObserver*>::iterator itr = std::find(_observers.begin(), _observers.end(), observer); + if (itr == _observers.end()) + { + _observers.push_back(observer); + } +} + +void BlastSceneTree::removeObserver(ISceneObserver* observer) +{ + std::vector<ISceneObserver*>::iterator itr = std::find(_observers.begin(), _observers.end(), observer); + _observers.erase(itr); +} + +void BlastSceneTree::updateVisible(uint32_t assetIndex, uint32_t chunkIndex, bool visible) +{ + BlastTreeData::ins().updateVisible(assetIndex, chunkIndex, visible); +} + +void BlastSceneTree::updateChunkItemSelection() +{ + _updateData = false; + + ui.blastSceneTree->clearSelection(); + BlastTreeData& treeData = BlastTreeData::ins(); + std::vector<BlastChunkNode*> chunkNodes; + + std::map<BlastAsset*, std::vector<uint32_t>> selectedChunks = SampleManager::ins()->getSelectedChunks(); + std::map<BlastAsset*, std::vector<uint32_t>>::iterator itrAssetSelectedChunks = selectedChunks.begin(); + for (; itrAssetSelectedChunks != selectedChunks.end(); ++itrAssetSelectedChunks) + { + std::vector<BlastChunkNode*> aseetNodes = treeData.getChunkNodeByBlastChunk(itrAssetSelectedChunks->first, itrAssetSelectedChunks->second); + chunkNodes.insert(chunkNodes.end(), aseetNodes.begin(), aseetNodes.end()); + } + + for (BlastChunkNode* node : chunkNodes) + { + _selectTreeItem(node); + } + + _updateData = true; +} + +void BlastSceneTree::makeSupport() +{ + std::vector<BlastChunkNode*> selectedChunkNodes; + QList<QTreeWidgetItem*> selectedItems = ui.blastSceneTree->selectedItems(); + for (int i = 0; i < selectedItems.size(); ++i) + { + QMap<QTreeWidgetItem*, BlastNode*>::iterator itr = _treeItemDataMap.find(selectedItems.at(i)); + + if (eChunk == itr.value()->getType()) + { + selectedChunkNodes.push_back((BlastChunkNode*)itr.value()); + } + } + + std::vector<BlastChunkNode*> topChunkNodes = BlastTreeData::getTopChunkNodes(selectedChunkNodes); + for (size_t i = 0; i < topChunkNodes.size(); ++i) + { + BlastChunkNode* chunkNode = topChunkNodes[i]; + BlastTreeData::makeSupport(chunkNode); + } + + _updateChunkTreeItems(); +} + +void BlastSceneTree::makeStaticSupport() +{ + std::vector<BlastChunkNode*> selectedChunkNodes; + QList<QTreeWidgetItem*> selectedItems = ui.blastSceneTree->selectedItems(); + for (int i = 0; i < selectedItems.size(); ++i) + { + QMap<QTreeWidgetItem*, BlastNode*>::iterator itr = _treeItemDataMap.find(selectedItems.at(i)); + + if (eChunk == itr.value()->getType()) + { + selectedChunkNodes.push_back((BlastChunkNode*)itr.value()); + } + } + + std::vector<BlastChunkNode*> topChunkNodes = BlastTreeData::getTopChunkNodes(selectedChunkNodes); + for (size_t i = 0; i < topChunkNodes.size(); ++i) + { + BlastChunkNode* chunkNode = topChunkNodes[i]; + BlastTreeData::makeStaticSupport(chunkNode); + } + + _updateChunkTreeItems(); +} + +void BlastSceneTree::removeSupport() +{ + std::vector<BlastChunkNode*> selectedChunkNodes; + QList<QTreeWidgetItem*> selectedItems = ui.blastSceneTree->selectedItems(); + for (int i = 0; i < selectedItems.size(); ++i) + { + QMap<QTreeWidgetItem*, BlastNode*>::iterator itr = _treeItemDataMap.find(selectedItems.at(i)); + + if (eChunk == itr.value()->getType()) + { + selectedChunkNodes.push_back((BlastChunkNode*)itr.value()); + } + } + + std::vector<BlastChunkNode*> topChunkNodes = BlastTreeData::getTopChunkNodes(selectedChunkNodes); + for (size_t i = 0; i < topChunkNodes.size(); ++i) + { + BlastChunkNode* chunkNode = topChunkNodes[i]; + BlastTreeData::removeSupport(chunkNode); + } + + _updateChunkTreeItems(); +} + +void BlastSceneTree::bondChunks() +{ + +} + +void BlastSceneTree::bondChunksWithJoints() +{ + +} + +void BlastSceneTree::removeAllBonds() +{ + +} + +void BlastSceneTree::on_btnAsset_clicked() +{ + QMessageBox::information(NULL, "test", "on_btnAsset_clicked"); +} + +void BlastSceneTree::on_assetComposite_clicked() +{ + QMessageBox::information(NULL, "test", "on_assetComposite_clicked"); +} + +void BlastSceneTree::on_btnChunk_clicked() +{ + QMessageBox::information(NULL, "test", "on_btnChunk_clicked"); +} + +void BlastSceneTree::on_btnBond_clicked() +{ + QMessageBox::information(NULL, "test", "on_btnBond_clicked"); +} + +void BlastSceneTree::on_btnProjectile_clicked() +{ + QMessageBox::information(NULL, "test", "on_btnProjectile_clicked"); +} + +void BlastSceneTree::on_blastSceneTree_customContextMenuRequested(const QPoint &pos) +{ + QList<QTreeWidgetItem*> items = ui.blastSceneTree->selectedItems(); + + if (items.count() == 1) + { + QTreeWidgetItem* curItem = items.at(0); + + QMap<QTreeWidgetItem*, BlastNode*>::iterator itr = _treeItemDataMap.find(curItem); + if (itr != _treeItemDataMap.end()) + { + if (eChunk == itr.value()->getType() || eBond == itr.value()->getType()) + { + _treeChunkContextMenu->exec(QCursor::pos()); + } + } + } + else if (items.count() > 1) + { + bool allSupportChunk = true; + for (int i = 0; i < items.count(); ++i) + { + QMap<QTreeWidgetItem*, BlastNode*>::iterator itr = _treeItemDataMap.find(items.at(i)); + if (itr != _treeItemDataMap.end()) + { + if (eChunk != itr.value()->getType()) + { + allSupportChunk = false; + break; + } + } + } + + if (allSupportChunk) + { + _treeBondContextMenu->exec(QCursor::pos()); + } + } + +} + +void BlastSceneTree::on_blastSceneTree_itemSelectionChanged() +{ + if (!_updateData) + return; + + SampleManager::ins()->clearChunksSelected(); + + QList<QTreeWidgetItem*> selectedItems = ui.blastSceneTree->selectedItems(); + std::vector<BlastNode*> nodes; + for (int i = 0; i < selectedItems.count(); ++i) + { + QMap<QTreeWidgetItem*, BlastNode*>::iterator itr = _treeItemDataMap.find(selectedItems.at(i)); + if (itr != _treeItemDataMap.end()) + { + nodes.push_back(itr.value()); + + BlastNode* node = itr.value(); + if (eChunk == node->getType()) + { + ((BlastChunkNode*)node)->setSelected(true); + } + else if (eAssetInstance == node->getType()) + { + ((BlastAssetInstanceNode*)node)->setSelected(true); + } + } + } + + for (size_t i = 0; i < _observers.size(); ++i) + { + _observers[i]->dataSelected(nodes); + } +} + +void BlastSceneTree::onMakeSupportMenuItemClicked() +{ + makeSupport(); +} + +void BlastSceneTree::onMakeStaticSupportMenuItemClicked() +{ + makeStaticSupport(); +} + +void BlastSceneTree::onRemoveSupportMenuItemClicked() +{ + removeSupport(); +} + +void BlastSceneTree::onBondChunksMenuItemClicked() +{ + bondChunks(); +} + +void BlastSceneTree::onBondChunksWithJointsMenuItemClicked() +{ + bondChunksWithJoints(); +} + +void BlastSceneTree::onRemoveAllBondsMenuItemClicked() +{ + removeAllBonds(); +} + +void BlastSceneTree::_updateTreeUIs() +{ + ui.blastSceneTree->clear(); + _treeItemDataMap.clear(); + _treeDataItemMap.clear(); + + BlastCompositeNode* compositeNode = BlastTreeData::ins().getCompsiteNode(); + if (compositeNode != nullptr) + { + QTreeWidgetItem* compositeTreeWidgetItem = new QTreeWidgetItem(ui.blastSceneTree); + compositeTreeWidgetItem->setText(0, compositeNode->name.c_str()); + compositeTreeWidgetItem->setIcon(0, QIcon(":/AppMainWindow/images/AssetComposite.png")); + VisualButton* btn = new VisualButton(this, compositeNode); + ui.blastSceneTree->setItemWidget(compositeTreeWidgetItem, 1, btn); + _treeItemDataMap.insert(compositeTreeWidgetItem, compositeNode); + _treeDataItemMap.insert(compositeNode, compositeTreeWidgetItem); + + size_t count = compositeNode->children.size(); + for (size_t i = 0; i < count; ++i) + { + BlastNode* assetInstanceNode = compositeNode->children[i]; + QTreeWidgetItem* assetInstanceWidgetItem = new QTreeWidgetItem(compositeTreeWidgetItem); + assetInstanceWidgetItem->setText(0, assetInstanceNode->name.c_str()); + if (assetInstanceNode->getType() == eAssetInstance) + assetInstanceWidgetItem->setIcon(0, QIcon(":/AppMainWindow/images/Asset.png")); + VisualButton* btn = new VisualButton(this, assetInstanceNode); + ui.blastSceneTree->setItemWidget(assetInstanceWidgetItem, 1, btn); + _treeItemDataMap.insert(assetInstanceWidgetItem, assetInstanceNode); + _treeDataItemMap.insert(assetInstanceNode, assetInstanceWidgetItem); + } + } + + std::vector<BlastAssetNode*>& assets = BlastTreeData::ins().getAssetNodes(); + size_t count = assets.size(); + for (size_t i = 0; i < count; ++i) + { + BlastAssetNode* assetNode = assets[i]; + + QTreeWidgetItem* assetTreeWidgetItem = new QTreeWidgetItem(ui.blastSceneTree); + assetTreeWidgetItem->setText(0, assetNode->name.c_str()); + assetTreeWidgetItem->setIcon(0, QIcon(":/AppMainWindow/images/Asset.png")); + VisualButton* btn = new VisualButton(this, assetNode); + ui.blastSceneTree->setItemWidget(assetTreeWidgetItem, 1, btn); + _treeItemDataMap.insert(assetTreeWidgetItem, assetNode); + _treeDataItemMap.insert(assetNode, assetTreeWidgetItem); + + _addChunkUI(assetNode, assetTreeWidgetItem); + } + + std::vector<BlastProjectileNode*>& projectiles = BlastTreeData::ins().getProjectileNodes(); + count = projectiles.size(); + for (int i = 0; i < count; ++i) + { + BlastProjectileNode* projectileNode = projectiles[i]; + + QTreeWidgetItem* projectileTreeWidgetItem = new QTreeWidgetItem(ui.blastSceneTree); + projectileTreeWidgetItem->setText(0, projectileNode->name.c_str()); + projectileTreeWidgetItem->setIcon(0, QIcon(":/AppMainWindow/images/Projectile.png")); + VisualButton* btn = new VisualButton(this, projectileNode); + ui.blastSceneTree->setItemWidget(projectileTreeWidgetItem, 1, btn); + _treeItemDataMap.insert(projectileTreeWidgetItem, projectileNode); + _treeDataItemMap.insert(projectileNode, projectileTreeWidgetItem); + } + + std::vector<BlastGraphicsMeshNode*>& graphicsMeshes = BlastTreeData::ins().getGraphicsMeshNodes(); + count = graphicsMeshes.size(); + for (int i = 0; i < count; ++i) + { + BlastGraphicsMeshNode* graphicsMesheNode = graphicsMeshes[i]; + + QTreeWidgetItem* graphicsMesheTreeWidgetItem = new QTreeWidgetItem(ui.blastSceneTree); + graphicsMesheTreeWidgetItem->setText(0, graphicsMesheNode->name.c_str()); + VisualButton* btn = new VisualButton(this, graphicsMesheNode); + ui.blastSceneTree->setItemWidget(graphicsMesheTreeWidgetItem, 1, btn); + _treeItemDataMap.insert(graphicsMesheTreeWidgetItem, graphicsMesheNode); + _treeDataItemMap.insert(graphicsMesheNode, graphicsMesheTreeWidgetItem); + } + + //for (int j = 0; j < ui.blastSceneTree->topLevelItemCount(); ++j) + //{ + // QTreeWidgetItem* topLevelItem = ui.blastSceneTree->topLevelItem(j); + // ui.blastSceneTree->expandItem(topLevelItem); + //} + ui.blastSceneTree->expandAll(); +} + +void BlastSceneTree::_addChunkUI(const BlastNode* parentNode, QTreeWidgetItem* parentTreeItem) +{ + if (parentNode != nullptr && parentTreeItem != nullptr) + { + for (size_t i = 0; i < parentNode->children.size(); ++i) + { + BlastNode* node = parentNode->children[i]; + if (node == nullptr) + continue; + + QTreeWidgetItem* treeWidgetItem = nullptr; + + if (node->getType() == eChunk) + { + BlastChunkNode* chunk = static_cast<BlastChunkNode*>(node); + treeWidgetItem = new QTreeWidgetItem(parentTreeItem); + treeWidgetItem->setText(0, chunk->name.c_str()); + if (chunk->isSupport()) + { + treeWidgetItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Support_Unstatic.png")); + } + else + { + treeWidgetItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Unsupport_Unstatic.png")); + } + + _addChunkUI(chunk, treeWidgetItem); + } + else if (node->getType() == eBond) + { + BlastBondNode* bond = static_cast<BlastBondNode*>(node); + treeWidgetItem = new QTreeWidgetItem(parentTreeItem); + treeWidgetItem->setIcon(0, QIcon(":/AppMainWindow/images/Bond.png")); + treeWidgetItem->setText(0, bond->name.c_str()); + } + + if (treeWidgetItem == nullptr) + continue; + VisualButton* btn = new VisualButton(this, node); + ui.blastSceneTree->setItemWidget(treeWidgetItem, 1, btn); + _treeItemDataMap.insert(treeWidgetItem, node); + _treeDataItemMap.insert(node, treeWidgetItem); + } + } +} + +void BlastSceneTree::_updateChunkTreeItemAndMenu(BPPChunk* chunk, QTreeWidgetItem* chunkItem) +{ + assert(chunk != nullptr); + + _removeSupportAction->setEnabled(true); + _makeSupportAction->setEnabled(true); + _makeStaticSupportAction->setEnabled(true); + + if (!chunk->support && !chunk->staticFlag) + { + _removeSupportAction->setEnabled(false); + chunkItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Unsupport_Unstatic.png")); + } + else if (chunk->support && !chunk->staticFlag) + { + _makeSupportAction->setEnabled(false); + chunkItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Support_Unstatic.png")); + } + else if (chunk->support && chunk->staticFlag) + { + _makeStaticSupportAction->setEnabled(false); + chunkItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Support_Static.png")); + } +} + +void BlastSceneTree::_updateChunkTreeItems() +{ + for (QMap<BlastNode*, QTreeWidgetItem*>::iterator itr = _treeDataItemMap.begin(); itr != _treeDataItemMap.end(); ++itr) + { + BlastNode* node = itr.key(); + QTreeWidgetItem* treeItem = itr.value(); + if (eChunk == node->getType()) + { + BPPChunk* chunk = static_cast<BPPChunk*>(node->getData()); + if (!chunk->support && !chunk->staticFlag) + { + treeItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Unsupport_Unstatic.png")); + } + else if (chunk->support && !chunk->staticFlag) + { + treeItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Support_Unstatic.png")); + } + else if (chunk->support && chunk->staticFlag) + { + treeItem->setIcon(0, QIcon(":/AppMainWindow/images/Chunk_Support_Static.png")); + } + } + } +} + +void BlastSceneTree::_selectTreeItem(BlastNode* node) +{ + QMap<BlastNode*, QTreeWidgetItem*>::iterator itr = _treeDataItemMap.find(node); + if (itr != _treeDataItemMap.end()) + { + ui.blastSceneTree->setItemSelected(itr.value(), true); + } +} + +//void BlastSceneTree::_createTestData() +//{ +// BPPBlast& blast = BlastProject::ins().getParams().blast; +// +// // compoistie +// { +// BPPComposite& composite = blast.composite; +// composite.composite.buf = nullptr; +// composite.visible = true; +// +// copy(composite.composite, "BlastComposite"); +// +// // asset instance array +// { +// BPPAssetInstanceArray& instanceArray = composite.blastAssetInstances; +// instanceArray.buf = new BPPAssetInstance[4]; +// instanceArray.arraySizes[0] = 4; +// instanceArray.buf[0].name.buf = nullptr; +// instanceArray.buf[1].name.buf = nullptr; +// instanceArray.buf[2].name.buf = nullptr; +// instanceArray.buf[3].name.buf = nullptr; +// instanceArray.buf[0].source.buf = nullptr; +// instanceArray.buf[1].source.buf = nullptr; +// instanceArray.buf[2].source.buf = nullptr; +// instanceArray.buf[3].source.buf = nullptr; +// +// copy(instanceArray.buf[0].name, "BlastAsset_instance1"); +// instanceArray.buf[0].visible = true; +// +// copy(instanceArray.buf[1].name, "BlastAsset_instance2"); +// instanceArray.buf[1].visible = true; +// +// copy(instanceArray.buf[2].name, "BlastAsset1_instance1"); +// instanceArray.buf[2].visible = true; +// +// copy(instanceArray.buf[3].name, "BlastAsset1_instance2"); +// instanceArray.buf[3].visible = true; +// } +// +// // landmark array +// { +// BPPLandmarkArray& landmarkArray = composite.landmarks; +// landmarkArray.buf = new BPPLandmark[2]; +// landmarkArray.arraySizes[0] = 2; +// landmarkArray.buf[0].name.buf = nullptr; +// landmarkArray.buf[1].name.buf = nullptr; +// +// copy(landmarkArray.buf[0].name, "Landmark_1"); +// copy(landmarkArray.buf[1].name, "Landmark_2"); +// } +// } +// +// // asset array +// { +// BPPAssetArray& assetArray = blast.blastAssets; +// assetArray.buf = new BPPAsset[2]; +// assetArray.arraySizes[0] = 2; +// +// // asset 0 +// { +// BPPAsset& asset = assetArray.buf[0]; +// asset.path.buf = nullptr; +// asset.activePreset.buf = nullptr; +// asset.bonds.buf = nullptr; +// asset.chunks.buf = nullptr; +// +// copy(asset.path, "c:/temp/BlastAsset.asset"); +// +// // chunks +// { +// asset.chunks.buf = new BPPChunk[10]; +// asset.chunks.arraySizes[0] = 10; +// for (int i = 0; i < 10; ++i) +// { +// asset.chunks.buf[i].name.buf = nullptr; +// asset.chunks.buf[i].visible = true; +// asset.chunks.buf[i].staticFlag = false; +// } +// +// copy(asset.chunks.buf[0].name, "Chunk_L0_00"); +// asset.chunks.buf[0].ID = 0; +// asset.chunks.buf[0].parentID = -1; +// asset.chunks.buf[0].support = false; +// +// copy(asset.chunks.buf[1].name, "Chunk_L0_01"); +// asset.chunks.buf[1].ID = 1; +// asset.chunks.buf[1].parentID = -1; +// asset.chunks.buf[1].support = false; +// +// copy(asset.chunks.buf[2].name, "Chunk_L1_02"); +// asset.chunks.buf[2].ID = 2; +// asset.chunks.buf[2].parentID = 0; +// asset.chunks.buf[2].support = false; +// +// copy(asset.chunks.buf[3].name, "Chunk_L1_03"); +// asset.chunks.buf[3].ID = 3; +// asset.chunks.buf[3].parentID = 0; +// asset.chunks.buf[3].support = false; +// +// copy(asset.chunks.buf[4].name, "Chunk_L1_04"); +// asset.chunks.buf[4].ID = 4; +// asset.chunks.buf[4].parentID = 1; +// asset.chunks.buf[4].support = false; +// +// copy(asset.chunks.buf[5].name, "Chunk_L1_05"); +// asset.chunks.buf[5].ID = 5; +// asset.chunks.buf[5].parentID = 1; +// asset.chunks.buf[5].support = false; +// +// copy(asset.chunks.buf[6].name, "Chunk_L2_06"); +// asset.chunks.buf[6].ID = 6; +// asset.chunks.buf[6].parentID = 2; +// asset.chunks.buf[6].support = true; +// +// copy(asset.chunks.buf[7].name, "Chunk_L2_07"); +// asset.chunks.buf[7].ID = 7; +// asset.chunks.buf[7].parentID = 2; +// asset.chunks.buf[7].support = true; +// +// copy(asset.chunks.buf[8].name, "Chunk_L2_08"); +// asset.chunks.buf[8].ID = 8; +// asset.chunks.buf[8].parentID = 3; +// asset.chunks.buf[8].support = true; +// +// copy(asset.chunks.buf[9].name, "Chunk_L2_09"); +// asset.chunks.buf[9].ID = 9; +// asset.chunks.buf[9].parentID = 3; +// asset.chunks.buf[9].support = true; +// } +// +// // bonds +// { +// asset.bonds.buf = new BPPBond[4]; +// asset.bonds.arraySizes[0] = 4; +// for (int i = 0; i < 4; ++i) +// { +// asset.bonds.buf[i].name.buf = nullptr; +// asset.bonds.buf[i].visible = true; +// asset.bonds.buf[i].support.healthMask.buf = nullptr; +// } +// +// copy(asset.bonds.buf[0].name, "Chunk_L2_08"); +// asset.bonds.buf[0].fromChunk = 6; +// asset.bonds.buf[0].toChunk = 8; +// +// copy(asset.bonds.buf[1].name, "Chunk_L2_06"); +// asset.bonds.buf[1].fromChunk = 6; +// asset.bonds.buf[1].toChunk = 8; +// +// copy(asset.bonds.buf[2].name, "Chunk_L2_09"); +// asset.bonds.buf[2].fromChunk = 7; +// asset.bonds.buf[2].toChunk = 9; +// +// copy(asset.bonds.buf[3].name, "Chunk_L2_07"); +// asset.bonds.buf[3].fromChunk = 7; +// asset.bonds.buf[3].toChunk = 9; +// } +// } +// +// // asset 1 +// { +// BPPAsset& asset = assetArray.buf[1]; +// asset.path.buf = nullptr; +// asset.activePreset.buf = nullptr; +// asset.bonds.buf = nullptr; +// asset.chunks.buf = nullptr; +// +// copy(asset.path, "c:/temp/BlastAsset1.asset"); +// { +// asset.chunks.buf = new BPPChunk[10]; +// asset.chunks.arraySizes[0] = 10; +// for (int i = 0; i < 10; ++i) +// { +// asset.chunks.buf[i].name.buf = nullptr; +// asset.chunks.buf[i].visible = true; +// } +// +// copy(asset.chunks.buf[0].name, "Chunk_L0_00"); +// asset.chunks.buf[0].ID = 0; +// asset.chunks.buf[0].parentID = -1; +// asset.chunks.buf[0].support = false; +// +// copy(asset.chunks.buf[1].name, "Chunk_L0_01"); +// asset.chunks.buf[1].ID = 1; +// asset.chunks.buf[1].parentID = -1; +// asset.chunks.buf[1].support = false; +// +// copy(asset.chunks.buf[2].name, "Chunk_L1_02"); +// asset.chunks.buf[2].ID = 2; +// asset.chunks.buf[2].parentID = 0; +// asset.chunks.buf[2].support = false; +// +// copy(asset.chunks.buf[3].name, "Chunk_L1_03"); +// asset.chunks.buf[3].ID = 3; +// asset.chunks.buf[3].parentID = 0; +// asset.chunks.buf[3].support = false; +// +// copy(asset.chunks.buf[4].name, "Chunk_L1_04"); +// asset.chunks.buf[4].ID = 4; +// asset.chunks.buf[4].parentID = 1; +// asset.chunks.buf[4].support = false; +// +// copy(asset.chunks.buf[5].name, "Chunk_L1_05"); +// asset.chunks.buf[5].ID = 5; +// asset.chunks.buf[5].parentID = 1; +// asset.chunks.buf[5].support = false; +// +// copy(asset.chunks.buf[6].name, "Chunk_L2_06"); +// asset.chunks.buf[6].ID = 6; +// asset.chunks.buf[6].parentID = 2; +// asset.chunks.buf[6].support = true; +// +// copy(asset.chunks.buf[7].name, "Chunk_L2_07"); +// asset.chunks.buf[7].ID = 7; +// asset.chunks.buf[7].parentID = 2; +// asset.chunks.buf[7].support = true; +// +// copy(asset.chunks.buf[8].name, "Chunk_L2_08"); +// asset.chunks.buf[8].ID = 8; +// asset.chunks.buf[8].parentID = 3; +// asset.chunks.buf[8].support = true; +// +// copy(asset.chunks.buf[9].name, "Chunk_L2_09"); +// asset.chunks.buf[9].ID = 9; +// asset.chunks.buf[9].parentID = 3; +// asset.chunks.buf[9].support = true; +// } +// } +// } +// +// // projectile +// { +// BPPProjectileArray& projectileArray = blast.projectiles; +// projectileArray.buf = new BPPProjectile[1]; +// projectileArray.arraySizes[0] = 1; +// projectileArray.buf[0].name.buf = nullptr; +// copy(projectileArray.buf[0].name, "Projectile"); +// projectileArray.buf[0].visible = true; +// } +// +// // graphics meshes +// { +// BPPGraphicsMeshArray& graphicsMeshArray = blast.graphicsMeshes; +// graphicsMeshArray.buf = new BPPGraphicsMesh[3]; +// graphicsMeshArray.arraySizes[0] = 3; +// graphicsMeshArray.buf[0].name.buf = nullptr; +// copy(graphicsMeshArray.buf[0].name, "SurfaceMesh1"); +// graphicsMeshArray.buf[0].visible = true; +// +// graphicsMeshArray.buf[1].name.buf = nullptr; +// copy(graphicsMeshArray.buf[1].name, "SurfaceMesh2"); +// graphicsMeshArray.buf[1].visible = true; +// +// graphicsMeshArray.buf[2].name.buf = nullptr; +// copy(graphicsMeshArray.buf[2].name, "DisplayMesh1"); +// graphicsMeshArray.buf[2].visible = true; +// } +//} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastSceneTree.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastSceneTree.h new file mode 100644 index 0000000..540f420 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastSceneTree.h @@ -0,0 +1,284 @@ +#ifndef BLASTSCENETREE_H +#define BLASTSCENETREE_H + +#include <QtWidgets/QDockWidget> +#include "ui_BlastSceneTree.h" +#include "ProjectParams.h" +#include <vector> +#include <string> +#include <QtCore/QMap> + +class QTreeWidgetItem; +class BlastAsset; + +enum EBlastNodeType +{ + eBond, + eChunk, + eAsset, + eProjectile, + eGraphicsMesh, + eAssetInstance, + eLandmark, + eComposite, +}; + +class BlastNode +{ +public: + BlastNode(const std::string& inName, void* inData) + : name(inName) + , _data(inData) + { + } + + void* getData() { return _data; } + void setParent(BlastNode* parent) { _parent = parent; } + BlastNode* getParent() { return _parent; } + virtual EBlastNodeType getType() = 0; + virtual bool getVisible() = 0; + virtual void setVisible(bool val) = 0; + + std::string name; + std::vector<BlastNode*> children; + +protected: + void* _data; + BlastNode* _parent; +}; + +class BlastBondNode : public BlastNode +{ +public: + BlastBondNode(const std::string& inName, BPPBond& inData) + : BlastNode(inName, &inData) + { + } + virtual EBlastNodeType getType() { return eBond; } + virtual bool getVisible() { return ((BPPBond*)_data)->visible; } + virtual void setVisible(bool val) { ((BPPBond*)_data)->visible = val; } + +private: + std::vector<BlastNode*> children; +}; + +class BlastChunkNode : public BlastNode +{ +public: + BlastChunkNode(const std::string& inName, BPPChunk& inData, void* assetPtr) + : BlastNode(inName, &inData) + { + _assetPtr = assetPtr; + } + virtual EBlastNodeType getType() { return eChunk; } + virtual bool getVisible() { return ((BPPChunk*)_data)->visible; } + virtual void setVisible(bool val);// { ((BPPChunk*)_data)->visible = val; } + void setSelected(bool val); + bool isSupport() { return ((BPPChunk*)_data)->support; } + void* _assetPtr; +}; + +class BlastAssetNode : public BlastNode +{ +public: + BlastAssetNode(const std::string& inName, BPPAsset& inData) + : BlastNode(inName, &inData) + { + } + virtual EBlastNodeType getType() { return eAsset; } + virtual bool getVisible() { return ((BPPAsset*)_data)->visible; } + virtual void setVisible(bool val) { ((BPPAsset*)_data)->visible = val; } +}; + +class BlastProjectileNode : public BlastNode +{ +public: + BlastProjectileNode(const std::string& inName, BPPProjectile& inData) + : BlastNode(inName, &inData) + { + } + virtual EBlastNodeType getType() { return eProjectile; } + virtual bool getVisible() { return ((BPPProjectile*)_data)->visible; } + virtual void setVisible(bool val) { ((BPPProjectile*)_data)->visible = val; } +}; + +class BlastGraphicsMeshNode : public BlastNode +{ +public: + BlastGraphicsMeshNode(const std::string& inName, BPPGraphicsMesh& inData) + : BlastNode(inName, &inData) + { + } + virtual EBlastNodeType getType() { return eGraphicsMesh; } + virtual bool getVisible() { return ((BPPGraphicsMesh*)_data)->visible; } + virtual void setVisible(bool val) { ((BPPGraphicsMesh*)_data)->visible = val; } +}; + +class BlastAssetInstanceNode : public BlastNode +{ +public: + BlastAssetInstanceNode(const std::string& inName, BPPAssetInstance& inData) + : BlastNode(inName, &inData) + { + } + virtual EBlastNodeType getType() { return eAssetInstance; } + virtual bool getVisible() { return ((BPPAssetInstance*)_data)->visible; } + virtual void setVisible(bool val) { ((BPPAssetInstance*)_data)->visible = val; } + void setSelected(bool val); +}; + +class BlastLandmarkNode : public BlastNode +{ +public: + BlastLandmarkNode(const std::string& inName, BPPLandmark& inData) + : BlastNode(inName, &inData) + { + } + virtual EBlastNodeType getType() { return eLandmark; } + virtual bool getVisible() { return ((BPPLandmark*)_data)->visible; } + virtual void setVisible(bool val) { ((BPPLandmark*)_data)->visible = val; } +}; + +class BlastCompositeNode : public BlastNode +{ +public: + BlastCompositeNode(const std::string& inName, BPPComposite& inData) + : BlastNode(inName, &inData) + { + } + virtual EBlastNodeType getType() { return eComposite; } + virtual bool getVisible() { return ((BPPComposite*)_data)->visible; } + virtual void setVisible(bool val) { ((BPPComposite*)_data)->visible = val; } +}; + +class BlastTreeData +{ +public: + static BlastTreeData& ins(); + static bool isChild(BlastChunkNode* parent, BlastChunkNode* child); + static std::vector<BlastChunkNode*> getTopChunkNodes(std::vector<BlastChunkNode*>& nodes); + static bool isRoot(BlastChunkNode* node); + static bool isLeaf(BlastChunkNode* node); + static void makeSupport(BlastChunkNode* node); + static void makeStaticSupport(BlastChunkNode* node); + static void removeSupport(BlastChunkNode* node); + + BlastNode* getBlastNodeByProjectData(void* blastProjectData); + BlastCompositeNode* getCompsiteNode() { return _composite; } + std::vector<BlastAssetNode*>& getAssetNodes() { return _assets; } + std::vector<BlastProjectileNode*>& getProjectileNodes() { return _projectiles; } + std::vector<BlastGraphicsMeshNode*>& getGraphicsMeshNodes() { return _graphicsMeshes; } + std::vector<BlastChunkNode*> getChunkNodeByBlastChunk(const BlastAsset* asset, const std::vector<uint32_t>& chunkIndexes); + bool isCompleteSupportAsset(const BlastAsset* asset); + bool isCompleteSupportAsset(const BlastAssetNode* node); + bool isOverlapSupportAsset(const BlastAsset* asset); + bool isOverlapSupportAsset(const BlastAssetNode* node); + void update(); + + void updateVisible(uint32_t assetIndex, uint32_t chunkIndex, bool visible); + +private: + BlastTreeData(); + void _addChunkNode(const BPPChunk& parentData, BPPAsset& asset, BlastChunkNode* parentNode, void* assetPtr); + void _freeBlastNode(); + BlastAssetNode* _getAssetNode(const BlastAsset* asset); + +private: + BlastCompositeNode* _composite; + std::vector<BlastAssetNode*> _assets; + std::vector<BlastProjectileNode*> _projectiles; + std::vector<BlastGraphicsMeshNode*> _graphicsMeshes; + std::map<void*, BlastNode*> _blastProjectDataToNodeMap; +}; + +class ISceneObserver +{ +public: + virtual void dataSelected(std::vector<BlastNode*> selections) = 0; +}; + +class VisualButton : public QWidget +{ + Q_OBJECT +public: + VisualButton(QWidget* parent, BlastNode* blastItem); + +protected slots: + void on_visualbility_toggled(bool checked); +private: + void _updateBlast(bool visible); + +private: + QPushButton* _button; + BlastNode* _blastItem; +}; + +class BlastSceneTree : public QDockWidget, public ISceneObserver +{ + Q_OBJECT + +public: + static BlastSceneTree* ins(); + + BlastSceneTree(QWidget *parent = 0); + ~BlastSceneTree(); + + void updateValues(bool updataData = true); + + virtual void dataSelected(std::vector<BlastNode*> selections); + + void addObserver(ISceneObserver* observer); + void removeObserver(ISceneObserver* observer); + + void updateVisible(uint32_t assetIndex, uint32_t chunkIndex, bool visible); + void updateChunkItemSelection(); + + void makeSupport(); + void makeStaticSupport(); + void removeSupport(); + void bondChunks(); + void bondChunksWithJoints(); + void removeAllBonds(); + +protected slots: + void on_btnAsset_clicked(); + void on_assetComposite_clicked(); + void on_btnChunk_clicked(); + void on_btnBond_clicked(); + void on_btnProjectile_clicked(); + void on_blastSceneTree_customContextMenuRequested(const QPoint &pos); + void on_blastSceneTree_itemSelectionChanged(); + void onMakeSupportMenuItemClicked(); + void onMakeStaticSupportMenuItemClicked(); + void onRemoveSupportMenuItemClicked(); + void onBondChunksMenuItemClicked(); + void onBondChunksWithJointsMenuItemClicked(); + void onRemoveAllBondsMenuItemClicked(); + +private: + void _updateTreeUIs(); + void _addChunkUI(const BlastNode* parentNode, QTreeWidgetItem* parentTreeItem); + void _updateChunkTreeItemAndMenu(BPPChunk* chunk, QTreeWidgetItem* chunkItem); + void _updateChunkTreeItems(); + + void _selectTreeItem(BlastNode* node); + + //void _createTestData(); + +private: + Ui::BlastSceneTree ui; + QMap<QTreeWidgetItem*, BlastNode*> _treeItemDataMap; + QMap<BlastNode*, QTreeWidgetItem*> _treeDataItemMap; + QMenu* _treeChunkContextMenu; + QMenu* _treeBondContextMenu; + QAction* _makeSupportAction; + QAction* _makeStaticSupportAction; + QAction* _removeSupportAction; + QAction* _bondChunksAction; + QAction* _bondChunksWithJointsAction; + QAction* _removeAllBondsAction; + std::vector<ISceneObserver*> _observers; + bool _updateData; +}; + +#endif // BLASTSCENETREE_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastToolBar.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastToolBar.cpp new file mode 100644 index 0000000..98b5646 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastToolBar.cpp @@ -0,0 +1,523 @@ +#include "BlastToolbar.h" + +#include <QtWidgets/QFileDialog> +#include "AppMainWindow.h" +#include "PhysXController.h" +#include "QtUtil.h" + +BlastToolbar::BlastToolbar(QWidget* parent) + : QDockWidget(parent) +{ + // to hide the title bar completely must replace the default widget with a generic one + QWidget* titleWidget = new QWidget(this); + this->setTitleBarWidget(titleWidget); + this->setObjectName(QString::fromUtf8("AppMainToolbar")); + this->setMinimumSize(QSize(0, 50)); + this->setMaximumSize(QSize(16777215, 80)); + + if (this->objectName().isEmpty()) + this->setObjectName(QStringLiteral("AppMainToolbar")); + this->resize(1330, 54); + + QWidget* widget = new QWidget(); + hLayout = new QHBoxLayout(widget); + hLayout->setObjectName(QStringLiteral("hLayout")); + hLayout->setContentsMargins(-1, 3, -1, 3); + + QSizePolicy sizePolicy1(QSizePolicy::Fixed, QSizePolicy::Fixed); + sizePolicy1.setHorizontalStretch(0); + sizePolicy1.setVerticalStretch(0); + + btnOpenProject = new QPushButton(widget); + setStyledToolTip(btnOpenProject, "Open Blast Asset"); + const QFont& font = btnOpenProject->font(); + QFont fontCopy(font); + fontCopy.setPixelSize(9); + + btnOpenProject->setObjectName(QStringLiteral("btnOpenProject")); + sizePolicy1.setHeightForWidth(btnOpenProject->sizePolicy().hasHeightForWidth()); + btnOpenProject->setSizePolicy(sizePolicy1); + btnOpenProject->setMinimumSize(QSize(40, 40)); + btnOpenProject->setMaximumSize(QSize(40, 40)); + btnOpenProject->setText(QApplication::translate("AppMainToolbar", "Open", 0)); + hLayout->addWidget(btnOpenProject); + + btnSaveProject = new QPushButton(widget); + setStyledToolTip(btnSaveProject, "Not Implement"); + btnSaveProject->setObjectName(QStringLiteral("btnSaveProject")); + sizePolicy1.setHeightForWidth(btnOpenProject->sizePolicy().hasHeightForWidth()); + btnSaveProject->setSizePolicy(sizePolicy1); + btnSaveProject->setMinimumSize(QSize(40, 40)); + btnSaveProject->setMaximumSize(QSize(40, 40)); + btnSaveProject->setText(QApplication::translate("AppMainToolbar", "Save\nAll", 0)); + hLayout->addWidget(btnSaveProject); + + btnExportAssets = new QPushButton(widget); + setStyledToolTip(btnExportAssets, "Not Implement"); + btnExportAssets->setObjectName(QStringLiteral("btnExportAssets")); + sizePolicy1.setHeightForWidth(btnExportAssets->sizePolicy().hasHeightForWidth()); + btnExportAssets->setSizePolicy(sizePolicy1); + btnExportAssets->setMinimumSize(QSize(40, 40)); + btnExportAssets->setMaximumSize(QSize(40, 40)); + btnExportAssets->setText(QApplication::translate("AppMainToolbar", "Export", 0)); + hLayout->addWidget(btnExportAssets); + + vLayoutExport = new QVBoxLayout(); + vLayoutExport->setObjectName(QStringLiteral("vLayoutExport")); + + hLayoutExport = new QHBoxLayout(); + hLayoutExport->setObjectName(QStringLiteral("hLayoutExport")); + + lExportFilepath = new QLabel(widget); + lExportFilepath->setObjectName(QStringLiteral("lExportFilepath")); + lExportFilepath->setText(QApplication::translate("AppMainToolbar", "Export Path", 0)); + hLayoutExport->addWidget(lExportFilepath); + + btnExportFilepath = new QPushButton(widget); + btnExportFilepath->setObjectName(QStringLiteral("btnExportFilepath")); + sizePolicy1.setHeightForWidth(btnExportFilepath->sizePolicy().hasHeightForWidth()); + btnExportFilepath->setSizePolicy(sizePolicy1); + btnExportFilepath->setMinimumSize(QSize(14, 14)); + btnExportFilepath->setMaximumSize(QSize(14, 14)); + btnExportFilepath->setText(QApplication::translate("AppMainToolbar", "", 0)); + btnExportFilepath->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnExportFilepath.png")); + btnExportFilepath->setIconSize(QSize(14, 14)); + hLayoutExport->addWidget(btnExportFilepath); + + vLayoutExport->addLayout(hLayoutExport); + + leExportFilepath = new QLineEdit(widget); + leExportFilepath->setObjectName(QStringLiteral("leExportFilepath")); + sizePolicy1.setHeightForWidth(leExportFilepath->sizePolicy().hasHeightForWidth()); + leExportFilepath->setSizePolicy(sizePolicy1); + leExportFilepath->setMinimumSize(QSize(150, 20)); + leExportFilepath->setMaximumSize(QSize(150, 20)); + leExportFilepath->setText(QApplication::translate("AppMainToolbar", "", 0)); + vLayoutExport->addWidget(leExportFilepath); + + hLayout->addLayout(vLayoutExport); + + fSeparate = new QFrame(widget); + fSeparate->setObjectName(QStringLiteral("fSeparate")); + fSeparate->setFrameShape(QFrame::VLine); + fSeparate->setFrameShadow(QFrame::Sunken); + hLayout->addWidget(fSeparate); + + vLayoutDepthCoverage = new QVBoxLayout(); + vLayoutDepthCoverage->setObjectName(QStringLiteral("vLayoutDepthCoverage")); + + hlDepthPreview = new QHBoxLayout(); + hlDepthPreview->setObjectName(QStringLiteral("hlDepthPreview")); + + lbDepthPreview = new QLabel(widget); + lbDepthPreview->setObjectName(QStringLiteral("lbDepthPreview")); + lbDepthPreview->setText(QApplication::translate("AppMainToolbar", "Depth Preview", 0)); + hlDepthPreview->addWidget(lbDepthPreview); + + ssbiDepthPreview = new SlideSpinBoxInt(widget); + ssbiDepthPreview->setObjectName(QStringLiteral("ssbiDepthPreview")); + QSizePolicy sizePolicy2(QSizePolicy::Minimum, QSizePolicy::Fixed); + sizePolicy2.setHorizontalStretch(0); + sizePolicy2.setVerticalStretch(0); + sizePolicy2.setHeightForWidth(ssbiDepthPreview->sizePolicy().hasHeightForWidth()); + ssbiDepthPreview->setSizePolicy(sizePolicy2); + ssbiDepthPreview->setMinimumSize(QSize(40, 20)); + ssbiDepthPreview->setMaximumSize(QSize(100, 16777215)); + hlDepthPreview->addWidget(ssbiDepthPreview); + + vLayoutDepthCoverage->addLayout(hlDepthPreview); + + hlExactCoverage = new QHBoxLayout(); + hlExactCoverage->setObjectName(QStringLiteral("hlExactCoverage")); + + lbDepthPreview = new QLabel(widget); + lbDepthPreview->setObjectName(QStringLiteral("hlExactCoverage")); + lbDepthPreview->setText(QApplication::translate("AppMainToolbar", "Exact Coverage", 0)); + hlExactCoverage->addWidget(lbDepthPreview); + + cbExactCoverage = new QCheckBox(widget); + cbExactCoverage->setObjectName(QStringLiteral("cbExactCoverage")); + sizePolicy1.setHeightForWidth(cbExactCoverage->sizePolicy().hasHeightForWidth()); + cbExactCoverage->setSizePolicy(sizePolicy1); + cbExactCoverage->setLayoutDirection(Qt::RightToLeft); + hlExactCoverage->addWidget(cbExactCoverage); + + vLayoutDepthCoverage->addLayout(hlExactCoverage); + + hLayout->addLayout(vLayoutDepthCoverage); + + fSeparate = new QFrame(widget); + fSeparate->setObjectName(QStringLiteral("fSeparate")); + fSeparate->setFrameShape(QFrame::VLine); + fSeparate->setFrameShadow(QFrame::Sunken); + hLayout->addWidget(fSeparate); + + btnSelectTool = new QPushButton(widget); + setStyledToolTip(btnSelectTool, "Switch to Selection Mode"); + btnSelectTool->setObjectName(QStringLiteral("btnSelectTool")); + sizePolicy1.setHeightForWidth(btnSelectTool->sizePolicy().hasHeightForWidth()); + btnSelectTool->setSizePolicy(sizePolicy1); + btnSelectTool->setMinimumSize(QSize(40, 40)); + btnSelectTool->setMaximumSize(QSize(40, 40)); + btnSelectTool->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnSelectTool.png")); + btnSelectTool->setIconSize(QSize(40, 40)); + QAction* pointselect_action = new QAction(tr("point select"), this); + QAction* rectselect_action = new QAction(tr("rect select"), this); + QAction* drawselect_action = new QAction(tr("draw select"), this); + connect(pointselect_action, SIGNAL(triggered()), this, SLOT(on_pointselect_action())); + connect(rectselect_action, SIGNAL(triggered()), this, SLOT(on_rectselect_action())); + connect(drawselect_action, SIGNAL(triggered()), this, SLOT(on_drawselect_action())); + QMenu* menu = new QMenu(btnSelectTool); + menu->addAction(pointselect_action); + menu->addAction(rectselect_action); + menu->addAction(drawselect_action); + btnSelectTool->setMenu(menu); + hLayout->addWidget(btnSelectTool); + + btnPaintbrush = new QPushButton(widget); + setStyledToolTip(btnPaintbrush, "Not Implement"); + btnPaintbrush->setObjectName(QStringLiteral("btnPaintbrush")); + sizePolicy1.setHeightForWidth(btnPaintbrush->sizePolicy().hasHeightForWidth()); + btnPaintbrush->setSizePolicy(sizePolicy1); + btnPaintbrush->setMinimumSize(QSize(40, 40)); + btnPaintbrush->setMaximumSize(QSize(40, 40)); + btnPaintbrush->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnPaintbrush.png")); + btnPaintbrush->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnPaintbrush); + + btnFractureTool = new QPushButton(widget); + setStyledToolTip(btnFractureTool, "Not Implement"); + btnFractureTool->setObjectName(QStringLiteral("btnFractureTool")); + sizePolicy1.setHeightForWidth(btnFractureTool->sizePolicy().hasHeightForWidth()); + btnFractureTool->setSizePolicy(sizePolicy1); + btnFractureTool->setMinimumSize(QSize(40, 40)); + btnFractureTool->setMaximumSize(QSize(40, 40)); + btnFractureTool->setText(QApplication::translate("AppMainToolbar", "Fracture", 0)); + btnFractureTool->setFont(fontCopy); + hLayout->addWidget(btnFractureTool); + + btnExplodedViewTool = new QPushButton(widget); + setStyledToolTip(btnExplodedViewTool, "Not Implement"); + btnExplodedViewTool->setObjectName(QStringLiteral("btnExplodedViewTool")); + sizePolicy1.setHeightForWidth(btnExplodedViewTool->sizePolicy().hasHeightForWidth()); + btnExplodedViewTool->setSizePolicy(sizePolicy1); + btnExplodedViewTool->setMinimumSize(QSize(40, 40)); + btnExplodedViewTool->setMaximumSize(QSize(40, 40)); + btnExplodedViewTool->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnExplodedViewTool.png")); + btnExplodedViewTool->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnExplodedViewTool); + + btnJointsTool = new QPushButton(widget); + setStyledToolTip(btnJointsTool, "Not Implement"); + btnJointsTool->setObjectName(QStringLiteral("btnJointsTool")); + sizePolicy1.setHeightForWidth(btnJointsTool->sizePolicy().hasHeightForWidth()); + btnJointsTool->setSizePolicy(sizePolicy1); + btnJointsTool->setMinimumSize(QSize(40, 40)); + btnJointsTool->setMaximumSize(QSize(40, 40)); + btnJointsTool->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnJointsTool.png")); + btnJointsTool->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnJointsTool); + + btnFuseSelectedChunks = new QPushButton(widget); + setStyledToolTip(btnFuseSelectedChunks, "Not Implement"); + btnFuseSelectedChunks->setObjectName(QStringLiteral("btnFuseSelectedChunks")); + sizePolicy1.setHeightForWidth(btnFuseSelectedChunks->sizePolicy().hasHeightForWidth()); + btnFuseSelectedChunks->setSizePolicy(sizePolicy1); + btnFuseSelectedChunks->setMinimumSize(QSize(40, 40)); + btnFuseSelectedChunks->setMaximumSize(QSize(40, 40)); + btnFuseSelectedChunks->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnFuseSelectedChunks.png")); + btnFuseSelectedChunks->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnFuseSelectedChunks); + + fSeparate = new QFrame(widget); + fSeparate->setObjectName(QStringLiteral("fSeparate")); + fSeparate->setFrameShape(QFrame::VLine); + fSeparate->setFrameShadow(QFrame::Sunken); + hLayout->addWidget(fSeparate); + + btnReset = new QPushButton(widget); + setStyledToolTip(btnReset, "Reset Chunks and Switch to Edition Mode"); + btnReset->setObjectName(QStringLiteral("btnReset")); + sizePolicy1.setHeightForWidth(btnReset->sizePolicy().hasHeightForWidth()); + btnReset->setSizePolicy(sizePolicy1); + btnReset->setMinimumSize(QSize(40, 40)); + btnReset->setMaximumSize(QSize(40, 40)); + btnReset->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnReset.png")); + btnReset->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnReset); + + btnSimulatePlay = new QPushButton(widget); + setStyledToolTip(btnSimulatePlay, "Switch to Simulate Mode"); + btnSimulatePlay->setObjectName(QStringLiteral("btnSimulatePlay")); + sizePolicy1.setHeightForWidth(btnSimulatePlay->sizePolicy().hasHeightForWidth()); + btnSimulatePlay->setSizePolicy(sizePolicy1); + btnSimulatePlay->setMinimumSize(QSize(40, 40)); + btnSimulatePlay->setMaximumSize(QSize(40, 40)); + btnSimulatePlay->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnSimulatePlay.png")); + btnSimulatePlay->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnSimulatePlay); + + btnFrameStepForward = new QPushButton(widget); + setStyledToolTip(btnFrameStepForward, "Switch to StepForward Mode"); + btnFrameStepForward->setObjectName(QStringLiteral("btnFrameStepForward")); + sizePolicy1.setHeightForWidth(btnFrameStepForward->sizePolicy().hasHeightForWidth()); + btnFrameStepForward->setSizePolicy(sizePolicy1); + btnFrameStepForward->setMinimumSize(QSize(40, 40)); + btnFrameStepForward->setMaximumSize(QSize(40, 40)); + btnFrameStepForward->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnFrameStepForward.png")); + btnFrameStepForward->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnFrameStepForward); + + fSeparate = new QFrame(widget); + fSeparate->setObjectName(QStringLiteral("fSeparate")); + fSeparate->setFrameShape(QFrame::VLine); + fSeparate->setFrameShadow(QFrame::Sunken); + hLayout->addWidget(fSeparate); + + btnBomb = new QPushButton(widget); + setStyledToolTip(btnBomb, "Not Implement"); + btnBomb->setObjectName(QStringLiteral("btnBomb")); + sizePolicy1.setHeightForWidth(btnBomb->sizePolicy().hasHeightForWidth()); + btnBomb->setSizePolicy(sizePolicy1); + btnBomb->setMinimumSize(QSize(40, 40)); + btnBomb->setMaximumSize(QSize(40, 40)); + btnBomb->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnBomb.png")); + btnBomb->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnBomb); + + btnProjectile = new QPushButton(widget); + setStyledToolTip(btnProjectile, "Throw a Box to Chunks"); + btnProjectile->setObjectName(QStringLiteral("btnProjectile")); + sizePolicy1.setHeightForWidth(btnProjectile->sizePolicy().hasHeightForWidth()); + btnProjectile->setSizePolicy(sizePolicy1); + btnProjectile->setMinimumSize(QSize(40, 40)); + btnProjectile->setMaximumSize(QSize(40, 40)); + btnProjectile->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnProjectile.png")); + btnProjectile->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnProjectile); + + btnDropObject = new QPushButton(widget); + setStyledToolTip(btnDropObject, "Not Implement"); + btnDropObject->setObjectName(QStringLiteral("btnDropObject")); + sizePolicy1.setHeightForWidth(btnDropObject->sizePolicy().hasHeightForWidth()); + btnDropObject->setSizePolicy(sizePolicy1); + btnDropObject->setMinimumSize(QSize(40, 40)); + btnDropObject->setMaximumSize(QSize(40, 40)); + btnDropObject->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnDropObject.png")); + btnDropObject->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnDropObject); + + fSeparate = new QFrame(widget); + fSeparate->setObjectName(QStringLiteral("fSeparate")); + fSeparate->setFrameShape(QFrame::VLine); + fSeparate->setFrameShadow(QFrame::Sunken); + hLayout->addWidget(fSeparate); + + btnPreferences = new QPushButton(widget); + setStyledToolTip(btnPreferences, "Save Blast Asset"); + btnPreferences->setObjectName(QStringLiteral("btnPreferences")); + sizePolicy1.setHeightForWidth(btnPreferences->sizePolicy().hasHeightForWidth()); + btnPreferences->setSizePolicy(sizePolicy1); + btnPreferences->setMinimumSize(QSize(40, 40)); + btnPreferences->setMaximumSize(QSize(40, 40)); + btnPreferences->setIcon(QIcon(":/AppMainWindow/images/Blast_ToolBar_btnPreferences.png")); + btnPreferences->setIconSize(QSize(40, 40)); + hLayout->addWidget(btnPreferences); + + QSpacerItem *horizontalSpacer; + horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + hLayout->addItem(horizontalSpacer); + + this->setWidget(widget); + + connect(btnOpenProject, SIGNAL(clicked()), this, SLOT(on_btnOpenProject_clicked())); + connect(btnSaveProject, SIGNAL(clicked()), this, SLOT(on_btnSaveProject_clicked())); + connect(btnExportAssets, SIGNAL(clicked()), this, SLOT(on_btnExportAssets_clicked())); + connect(btnExportFilepath, SIGNAL(clicked()), this, SLOT(on_btnExportFilepath_clicked())); + connect(ssbiDepthPreview, SIGNAL(valueChanged(int)), this, SLOT(on_ssbiDepthPreview_valueChanged(int))); + connect(cbExactCoverage, SIGNAL(stateChanged(int)), this, SLOT(on_cbExactCoverage_stateChanged(int))); + connect(btnSelectTool, SIGNAL(clicked()), this, SLOT(on_btnSelectTool_clicked())); + connect(btnPaintbrush, SIGNAL(clicked()), this, SLOT(on_btnPaintbrush_clicked())); + connect(btnFractureTool, SIGNAL(clicked()), this, SLOT(on_btnFractureTool_clicked())); + connect(btnExplodedViewTool, SIGNAL(clicked()), this, SLOT(on_btnExplodedViewTool_clicked())); + connect(btnJointsTool, SIGNAL(clicked()), this, SLOT(on_btnJointsTool_clicked())); + connect(btnFuseSelectedChunks, SIGNAL(clicked()), this, SLOT(on_btnFuseSelectedChunks_clicked())); + connect(btnReset, SIGNAL(clicked()), this, SLOT(on_btnReset_clicked())); + connect(btnSimulatePlay, SIGNAL(clicked()), this, SLOT(on_btnSimulatePlay_clicked())); + connect(btnFrameStepForward, SIGNAL(clicked()), this, SLOT(on_btnFrameStepForward_clicked())); + connect(btnBomb, SIGNAL(clicked()), this, SLOT(on_btnBomb_clicked())); + connect(btnProjectile, SIGNAL(clicked()), this, SLOT(on_btnProjectile_clicked())); + connect(btnDropObject, SIGNAL(clicked()), this, SLOT(on_btnDropObject_clicked())); + connect(btnPreferences, SIGNAL(clicked()), this, SLOT(on_btnPreferences_clicked())); +} + +void BlastToolbar::updateValues() +{ +} + +#include <Sample.h> +#include <SimpleScene.h> +#include <SampleManager.h> +#include <SceneController.h> +#include <SourceAssetOpenDlg.h> + +void BlastToolbar::on_btnOpenProject_clicked() +{ + qDebug("%s", __FUNCTION__); + + SourceAssetOpenDlg dlg(true, &AppMainWindow::Inst()); + int res = dlg.exec(); + if (res != QDialog::Accepted || dlg.getFile().isEmpty()) + return; + + QFileInfo fileInfo(dlg.getFile()); + std::string dir = QDir::toNativeSeparators(fileInfo.absoluteDir().absolutePath()).toLocal8Bit(); + std::string file = fileInfo.baseName().toLocal8Bit(); + + physx::PxTransform t(physx::PxIdentity); + { + QVector3D Position = dlg.getPosition(); + t.p = physx::PxVec3(Position.x(), Position.y(), Position.z()); + + QVector3D RotationAxis = dlg.getRotationAxis(); + physx::PxVec3 Axis = physx::PxVec3(RotationAxis.x(), RotationAxis.y(), RotationAxis.z()); + Axis = Axis.getNormalized(); + float RotationDegree = dlg.getRotationDegree(); + float DEGREE_TO_RAD = acos(-1.0) / 180.0; + RotationDegree = RotationDegree * DEGREE_TO_RAD; + t.q = physx::PxQuat(RotationDegree, Axis); + } + + SimpleScene::Inst()->GetSampleManager().addModelAsset(file, dlg.getSkinned(), t, !dlg.isAppend()); +} + +void BlastToolbar::on_btnSaveProject_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnExportAssets_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnExportFilepath_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_ssbiDepthPreview_valueChanged(int v) +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_cbExactCoverage_stateChanged(int state) +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnSelectTool_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_pointselect_action() +{ + qDebug("%s", __FUNCTION__); + + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Select); +} + +void BlastToolbar::on_rectselect_action() +{ + qDebug("%s", __FUNCTION__); + + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + sampleManager.setBlastToolType(BTT_Select); +} + +void BlastToolbar::on_drawselect_action() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnPaintbrush_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnFractureTool_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnExplodedViewTool_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnJointsTool_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnFuseSelectedChunks_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnReset_clicked() +{ + qDebug("%s", __FUNCTION__); + + SampleManager* pSampleManager = SampleManager::ins(); + SceneController& sceneController = pSampleManager->getSceneController(); + sceneController.ResetScene(); + pSampleManager->setBlastToolType(BTT_Edit); +} + +void BlastToolbar::on_btnSimulatePlay_clicked() +{ + qDebug("%s", __FUNCTION__); + + SampleManager* pSampleManager = SampleManager::ins(); + pSampleManager->setBlastToolType(BTT_Damage); +} + +void BlastToolbar::on_btnFrameStepForward_clicked() +{ + qDebug("%s", __FUNCTION__); + + SampleManager* pSampleManager = SampleManager::ins(); + pSampleManager->setBlastToolType(BTT_Damage); + PhysXController& physXController = pSampleManager->getPhysXController(); + physXController.m_bForce = true; +} + +void BlastToolbar::on_btnBomb_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnProjectile_clicked() +{ + qDebug("%s", __FUNCTION__); + + SampleManager& sampleManager = SimpleScene::Inst()->GetSampleManager(); + SceneController& sceneController = sampleManager.getSceneController(); + sceneController.addProjectile(); +} + +void BlastToolbar::on_btnDropObject_clicked() +{ + qDebug("%s", __FUNCTION__); +} + +void BlastToolbar::on_btnPreferences_clicked() +{ + qDebug("%s", __FUNCTION__); + + SampleManager* pSampleManager = SampleManager::ins(); + pSampleManager->saveAsset(); +}
\ No newline at end of file diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastToolBar.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastToolBar.h new file mode 100644 index 0000000..f44dcfb --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/BlastToolBar.h @@ -0,0 +1,94 @@ +#ifndef BlastToolbar_h__ +#define BlastToolbar_h__ + +#include <QtWidgets/QApplication> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QDockWidget> +#include <QtWidgets/QHBoxLayout> +#include <QtWidgets/QLabel> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QMenu> +#include <QtWidgets/QVBoxLayout> +#include <QtWidgets/QLineEdit> + +#include "SlideSpinBox.h" + +class BlastToolbar : public QDockWidget +{ + Q_OBJECT + +public: + BlastToolbar(QWidget* parent); + + void updateValues(); + +public slots: + void on_btnOpenProject_clicked(); + void on_btnSaveProject_clicked(); + void on_btnExportAssets_clicked(); + + void on_btnExportFilepath_clicked(); + void on_ssbiDepthPreview_valueChanged(int v); + void on_cbExactCoverage_stateChanged(int state); + + void on_btnSelectTool_clicked(); + void on_pointselect_action(); + void on_rectselect_action(); + void on_drawselect_action(); + + void on_btnPaintbrush_clicked(); + void on_btnFractureTool_clicked(); + void on_btnExplodedViewTool_clicked(); + void on_btnJointsTool_clicked(); + void on_btnFuseSelectedChunks_clicked(); + + void on_btnReset_clicked(); + void on_btnSimulatePlay_clicked(); + void on_btnFrameStepForward_clicked(); + + void on_btnBomb_clicked(); + void on_btnProjectile_clicked(); + void on_btnDropObject_clicked(); + + void on_btnPreferences_clicked(); + +private: + QHBoxLayout *hLayout; + QFrame *fSeparate; + + QPushButton *btnOpenProject; + QPushButton *btnSaveProject; + QPushButton *btnExportAssets; + + QVBoxLayout *vLayoutExport; + QHBoxLayout *hLayoutExport; + QLabel *lExportFilepath; + QPushButton *btnExportFilepath; + QLineEdit* leExportFilepath; + + QVBoxLayout *vLayoutDepthCoverage; + QHBoxLayout *hlDepthPreview; + QLabel *lbDepthPreview; + SlideSpinBoxInt* ssbiDepthPreview; + QHBoxLayout *hlExactCoverage; + QLabel *lbExactCoverage; + QCheckBox* cbExactCoverage; + + QPushButton *btnSelectTool; + QPushButton *btnPaintbrush; + QPushButton *btnFractureTool; + QPushButton *btnExplodedViewTool; + QPushButton *btnJointsTool; + QPushButton *btnFuseSelectedChunks; + + QPushButton *btnReset; + QPushButton *btnSimulatePlay; + QPushButton *btnFrameStepForward; + + QPushButton *btnBomb; + QPushButton *btnProjectile; + QPushButton *btnDropObject; + + QPushButton *btnPreferences; +}; +#endif // BlastToolbar_h__ diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/CollisionToolsDlg.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/CollisionToolsDlg.cpp new file mode 100644 index 0000000..4aa2b79 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/CollisionToolsDlg.cpp @@ -0,0 +1,54 @@ +#include "CollisionToolsDlg.h" +#include "ui_CollisionToolsDlg.h" + +CollisionToolsDlg::CollisionToolsDlg(QWidget *parent) : + QDialog(parent), + ui(new Ui::CollisionToolsDlg) +{ + ui->setupUi(this); +} + +CollisionToolsDlg::~CollisionToolsDlg() +{ + delete ui; +} + +void CollisionToolsDlg::on_comboBoxApplyFilter_currentIndexChanged(int index) +{ + +} + +void CollisionToolsDlg::on_comboBoxCollisionShape_currentIndexChanged(int index) +{ + +} + +void CollisionToolsDlg::on_spinBoxQuality_valueChanged(int arg1) +{ + +} + +void CollisionToolsDlg::on_spinBoxMaxHulls_valueChanged(int arg1) +{ + +} + +void CollisionToolsDlg::on_spinBoxTrimHulls_valueChanged(int arg1) +{ + +} + +void CollisionToolsDlg::on_comboBoxTargetPlatform_currentIndexChanged(int index) +{ + +} + +void CollisionToolsDlg::on_btnReset_clicked() +{ + +} + +void CollisionToolsDlg::on_btnApply_clicked() +{ + +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/CollisionToolsDlg.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/CollisionToolsDlg.h new file mode 100644 index 0000000..d3c8c00 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/CollisionToolsDlg.h @@ -0,0 +1,39 @@ +#ifndef COLLISIONTOOLSDLG_H +#define COLLISIONTOOLSDLG_H + +#include <QtWidgets/QDialog> + +namespace Ui { +class CollisionToolsDlg; +} + +class CollisionToolsDlg : public QDialog +{ + Q_OBJECT + +public: + explicit CollisionToolsDlg(QWidget *parent = 0); + ~CollisionToolsDlg(); + +private slots: + void on_comboBoxApplyFilter_currentIndexChanged(int index); + + void on_comboBoxCollisionShape_currentIndexChanged(int index); + + void on_spinBoxQuality_valueChanged(int arg1); + + void on_spinBoxMaxHulls_valueChanged(int arg1); + + void on_spinBoxTrimHulls_valueChanged(int arg1); + + void on_comboBoxTargetPlatform_currentIndexChanged(int index); + + void on_btnReset_clicked(); + + void on_btnApply_clicked(); + +private: + Ui::CollisionToolsDlg *ui; +}; + +#endif // COLLISIONTOOLSDLG_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/DefaultDamagePanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/DefaultDamagePanel.cpp new file mode 100644 index 0000000..e52dfb2 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/DefaultDamagePanel.cpp @@ -0,0 +1,104 @@ +#include "DefaultDamagePanel.h" +#include "ui_DefaultDamagePanel.h" +#include "ProjectParams.h" +#include "BlastSceneTree.h" + +DefaultDamagePanel::DefaultDamagePanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::DefaultDamagePanel) +{ + ui->setupUi(this); +} + +DefaultDamagePanel::~DefaultDamagePanel() +{ + delete ui; +} + +void DefaultDamagePanel::updateValues() +{ + if (_selectedAssets.size() > 0) + { + BPPDefaultDamage& damage = _selectedAssets[0]->defaultDamage; + + ui->spinBoxMinRadius->setValue(damage.minRadius); + ui->spinBoxMaxRadius->setValue(damage.maxRadius); + ui->comboBoxFallOff->setCurrentIndex(damage.FallOff); + ui->spinBoxMaxChunkSpeed->setValue(damage.maxChunkSpeed); + } + else + { + ui->spinBoxMinRadius->setValue(0.0f); + ui->spinBoxMaxRadius->setValue(0.0f); + ui->checkBoxMaxRadius->setChecked(false); + ui->comboBoxFallOff->setCurrentIndex(-1); + ui->spinBoxMaxChunkSpeed->setValue(0.0f); + } +} + +void DefaultDamagePanel::dataSelected(std::vector<BlastNode*> selections) +{ + _selectedAssets.clear(); + + for (BlastNode* node: selections) + { + if (eAsset == node->getType()) + { + BPPAsset* asset = static_cast<BPPAsset*>(node->getData()); + _selectedAssets.push_back(asset); + } + } + + updateValues(); +} + +void DefaultDamagePanel::on_spinBoxMinRadius_valueChanged(double arg1) +{ + for (size_t i = 0; i < _selectedAssets.size(); ++i) + { + BPPDefaultDamage& damage = _selectedAssets[i]->defaultDamage; + damage.minRadius = arg1; + } +} + +void DefaultDamagePanel::on_spinBoxMaxRadius_valueChanged(double arg1) +{ + for (size_t i = 0; i < _selectedAssets.size(); ++i) + { + BPPDefaultDamage& damage = _selectedAssets[i]->defaultDamage; + + damage.maxRadius = arg1; + + if (arg1 < damage.minRadius) + { + damage.maxRadius = damage.minRadius; + } + } +} + +void DefaultDamagePanel::on_checkBoxMaxRadius_stateChanged(int arg1) +{ + for (size_t i = 0; i < _selectedAssets.size(); ++i) + { + BPPDefaultDamage& damage = _selectedAssets[i]->defaultDamage; + damage.maxRadiusEnable = (arg1 != 0 ? true: false); + } +} + +void DefaultDamagePanel::on_comboBoxFallOff_currentIndexChanged(int index) +{ + for (size_t i = 0; i < _selectedAssets.size(); ++i) + { + BPPDefaultDamage& damage = _selectedAssets[i]->defaultDamage; + damage.FallOff = index; + } +} + +void DefaultDamagePanel::on_spinBoxMaxChunkSpeed_valueChanged(double arg1) +{ + for (size_t i = 0; i < _selectedAssets.size(); ++i) + { + BPPDefaultDamage& damage = _selectedAssets[i]->defaultDamage; + damage.maxChunkSpeed = arg1; + } +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/DefaultDamagePanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/DefaultDamagePanel.h new file mode 100644 index 0000000..bbd4d3e --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/DefaultDamagePanel.h @@ -0,0 +1,38 @@ +#ifndef DEFAULTDAMAGEPANEL_H +#define DEFAULTDAMAGEPANEL_H + +#include <QtWidgets/QWidget> +#include "BlastSceneTree.h" + +namespace Ui { +class DefaultDamagePanel; +} + +class DefaultDamagePanel : public QWidget, public ISceneObserver +{ + Q_OBJECT + +public: + explicit DefaultDamagePanel(QWidget *parent = 0); + ~DefaultDamagePanel(); + void updateValues(); + + virtual void dataSelected(std::vector<BlastNode*> selections); + +private slots: + void on_spinBoxMinRadius_valueChanged(double arg1); + + void on_spinBoxMaxRadius_valueChanged(double arg1); + + void on_checkBoxMaxRadius_stateChanged(int arg1); + + void on_comboBoxFallOff_currentIndexChanged(int index); + + void on_spinBoxMaxChunkSpeed_valueChanged(double arg1); + +private: + Ui::DefaultDamagePanel *ui; + std::vector<BPPAsset*> _selectedAssets; +}; + +#endif // DEFAULTDAMAGEPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FileReferencesPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FileReferencesPanel.cpp new file mode 100644 index 0000000..62b294c --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FileReferencesPanel.cpp @@ -0,0 +1,148 @@ +#include "FileReferencesPanel.h" +#include "ui_FileReferencesPanel.h" +#include "AppMainWindow.h" +#include <QtWidgets/QFileDialog> +#include "ProjectParams.h" +#include <QtCore/QFile> +#include <QtCore/QDebug> +#include "GlobalSettings.h" + +FileReferencesPanel::FileReferencesPanel(QWidget *parent) + : QWidget(parent) + , ui(new Ui::FileReferencesPanel) + , _saveFBX(true) + , _saveBlast(true) + , _saveCollision(true) +{ + ui->setupUi(this); + ui->lineEditFBXSourceAsset->setReadOnly(true); + + ui->checkBoxFBX->setChecked(_saveFBX); + ui->checkBoxBlast->setChecked(_saveBlast); + ui->checkBoxCollision->setChecked(_saveCollision); + + updateValues(); +} + +FileReferencesPanel::~FileReferencesPanel() +{ + delete ui; +} + +void FileReferencesPanel::updateValues() +{ + AppMainWindow& window = AppMainWindow::Inst(); + BPParams& projectParams = BlastProject::ins().getParams(); + BPPFileReferences& fileReferences = projectParams.blast.fileReferences; + if (fileReferences.fbxSourceAsset.buf != nullptr) + ui->lineEditFBXSourceAsset->setText(fileReferences.fbxSourceAsset.buf); + else + ui->lineEditFBXSourceAsset->setText(""); + + GlobalSettings& globalSettings = GlobalSettings::Inst(); + QString projectFileName = globalSettings.m_projectFileName.c_str(); + + if (projectFileName.isEmpty()) + { + ui->lineEditFBX->setText("New.fbx"); + ui->lineEditBlast->setText("New.Blast"); + ui->lineEditCollision->setText("New.repx"); + } + else + { + QFileInfo fileInfo(projectFileName); + + if (fileReferences.fbx.buf != nullptr) + ui->lineEditFBX->setText(fileReferences.fbx.buf); + else + { + ui->lineEditFBX->setText(fileInfo.baseName() + " New.fbx"); + } + + if (fileReferences.blast.buf != nullptr) + ui->lineEditBlast->setText(fileReferences.blast.buf); + else + { + ui->lineEditBlast->setText(fileInfo.baseName() + " New.Blast"); + } + + if (fileReferences.collision.buf != nullptr) + ui->lineEditCollision->setText(fileReferences.collision.buf); + else + { + ui->lineEditCollision->setText(fileInfo.baseName() + " New.repX"); + } + } +} + +void FileReferencesPanel::on_btnOpenFile_clicked() +{ + AppMainWindow& window = AppMainWindow::Inst(); + GlobalSettings& globalSettings = GlobalSettings::Inst(); + + BPParams& projectParams = BlastProject::ins().getParams(); + BPPFileReferences& fileReferences = projectParams.blast.fileReferences; + const char* fbxSourceAsset = fileReferences.fbxSourceAsset.buf; + QString lastDir = (fbxSourceAsset != nullptr ? fbxSourceAsset : window._lastFilePath); + QString fileName = QFileDialog::getOpenFileName(&window, "Open FBX File", lastDir, "FBX File (*.FBX)"); + + ui->lineEditFBXSourceAsset->setText(fileName); +} + +void FileReferencesPanel::on_btnReload_clicked() +{ + +} + +void FileReferencesPanel::on_btnRemove_clicked() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPFileReferences& fileReferences = projectParams.blast.fileReferences; + if (fileReferences.fbxSourceAsset.buf != nullptr) + { + ui->lineEditFBXSourceAsset->setText(""); + freeString(fileReferences.fbxSourceAsset); + // to do: remove source fbx file + } +} + +void FileReferencesPanel::on_checkBoxFBX_stateChanged(int arg1) +{ + _saveFBX = (arg1 == 0 ? false : true); +} + +void FileReferencesPanel::on_checkBoxBlast_stateChanged(int arg1) +{ + _saveBlast = (arg1 == 0 ? false : true); +} + +void FileReferencesPanel::on_checkBoxCollision_stateChanged(int arg1) +{ + _saveCollision = (arg1 == 0 ? false : true); +} + +void FileReferencesPanel::on_btnSave_clicked() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPFileReferences& fileReferences = projectParams.blast.fileReferences; + + copy(fileReferences.fbxSourceAsset, ui->lineEditFBXSourceAsset->text().toUtf8().data()); + + if (_saveFBX) + { + copy(fileReferences.fbx, ui->lineEditFBX->text().toUtf8().data()); + // to do: save fbx file + } + + if (_saveBlast) + { + copy(fileReferences.blast, ui->lineEditBlast->text().toUtf8().data()); + // to do: save blast file + } + + if (_saveCollision) + { + copy(fileReferences.collision, ui->lineEditCollision->text().toUtf8().data()); + // to do: save collision file + } +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FileReferencesPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FileReferencesPanel.h new file mode 100644 index 0000000..e393f33 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FileReferencesPanel.h @@ -0,0 +1,41 @@ +#ifndef FILEREFERENCESPANEL_H +#define FILEREFERENCESPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class FileReferencesPanel; +} + +class FileReferencesPanel : public QWidget +{ + Q_OBJECT + +public: + explicit FileReferencesPanel(QWidget *parent = 0); + ~FileReferencesPanel(); + void updateValues(); + +private slots: + void on_btnOpenFile_clicked(); + + void on_btnReload_clicked(); + + void on_btnRemove_clicked(); + + void on_checkBoxFBX_stateChanged(int arg1); + + void on_checkBoxBlast_stateChanged(int arg1); + + void on_checkBoxCollision_stateChanged(int arg1); + + void on_btnSave_clicked(); + +private: + Ui::FileReferencesPanel *ui; + bool _saveFBX; + bool _saveBlast; + bool _saveCollision; +}; + +#endif // FILEREFERENCESPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FiltersDockWidget.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FiltersDockWidget.cpp new file mode 100644 index 0000000..a537140 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FiltersDockWidget.cpp @@ -0,0 +1,389 @@ +#include "FiltersDockWidget.h" +#include "ui_FiltersDockWidget.h" +#include "ProjectParams.h" +#include <QtWidgets/QInputDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QMessageBox> +#include "SampleManager.h" + +const QString LISTITEM_NORMAL_STYLESHEET = ":enabled { background: rgb(68,68,68); }"; + +const QString LISTITEM_SELECTED_STYLESHEET = ":enabled { background: rgba(118,185,0, 250); }"; + +const QString LISTITEM_BUTTON_STYLESHEET = ":enabled { border: 0px; }"; + +class FilterItemWidget; + +struct FilterItemInfo +{ +public: + FilterItemInfo(FilterItemWidget* inWidget, const QString& inText) + : itemWidget(inWidget) + , text(inText) + { + } + + FilterItemWidget* itemWidget; + QString text; +}; + +FilterItemWidget::FilterItemWidget(FiltersDockWidget* parent, QListWidgetItem* item, const QString& filterPreset, int depth) + : QWidget(parent) + , _relatedListWidgetItem(item) + , _filterPreset(filterPreset) + , _depth(depth) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + _label = new QLabel(this); + + _removeBtn = new QPushButton(this); + _removeBtn->setMaximumSize(20, 20); + _removeBtn->setText("X"); + _removeBtn->setStyleSheet(LISTITEM_BUTTON_STYLESHEET); + + layout->addWidget(_label); + layout->addWidget(_removeBtn); + + this->setLayout(layout); + + QObject::connect(_removeBtn, SIGNAL(clicked()), this, SLOT(onRemoveButtonClicked())); + QObject::connect(this, SIGNAL(RemoveItem(QListWidgetItem*)), parent, SLOT(onListWidgetRemoveBtnClicked(QListWidgetItem*))); + + deSelect(); +} + +void FilterItemWidget::setText(const QString& title) +{ + _label->setText(title); +} + +void FilterItemWidget::select() +{ + _label->setStyleSheet(LISTITEM_SELECTED_STYLESHEET); +} + +void FilterItemWidget::deSelect() +{ + _label->setStyleSheet(LISTITEM_NORMAL_STYLESHEET); +} + +void FilterItemWidget::onRemoveButtonClicked() +{ + emit RemoveItem(_relatedListWidgetItem); +} + +FiltersDockWidget::FiltersDockWidget(QWidget *parent) : + QDockWidget(parent), + ui(new Ui::FiltersDockWidget), + _filterUIItems(), + _filterItemWidgets(), + _lastSelectRow(-1) +{ + ui->setupUi(this); + + _depthButtons.push_back(ui->btnDepth0); + _depthButtons.push_back(ui->btnDepth1); + _depthButtons.push_back(ui->btnDepth2); + _depthButtons.push_back(ui->btnDepth3); + _depthButtons.push_back(ui->btnDepth4); + _depthButtons.push_back(ui->btnDepth5); + + _updateFilterItemList(); + _updateFilterDepthBtns(); +} + +FiltersDockWidget::~FiltersDockWidget() +{ + delete ui; +} + +void FiltersDockWidget::updateValues() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPFilterPresetArray& filterPresetArray = projectParams.filter.filters; + + ui->comboBoxFilterPreset->clear(); + QStringList filterNames; + int count = filterPresetArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + filterNames.append(filterPresetArray.buf[i].name.buf); + } + ui->comboBoxFilterPreset->addItems(filterNames); + + if (count > 0) + { + ui->btnModifyFilterPreset->setEnabled(true); + ui->btnRemoveFilterPreset->setEnabled(true); + } + else + { + ui->btnModifyFilterPreset->setEnabled(false); + ui->btnRemoveFilterPreset->setEnabled(false); + } +} + +void FiltersDockWidget::on_comboBoxFilterPreset_currentIndexChanged(int index) +{ + BPParams& projectParams = BlastProject::ins().getParams(); + projectParams.filter.activeFilter = index; + + _updateFilterItemList(); + _updateFilterDepthBtns(); +} + +void FiltersDockWidget::on_btnAddFilterPrest_clicked() +{ + bool ok = false; + QString name = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input name for new filter preset:"), + QLineEdit::Normal, + "", + &ok); + bool nameExist = BlastProject::ins().isFilterPresetNameExist(name.toUtf8().data()); + if (ok && !name.isEmpty() && !nameExist) + { + BlastProject::ins().addFilterPreset(name.toUtf8().data()); + updateValues(); + ui->comboBoxFilterPreset->setCurrentIndex(ui->comboBoxFilterPreset->count() - 1); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && name.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new filter preset!"); + } +} + +void FiltersDockWidget::on_btnModifyFilterPreset_clicked() +{ + QByteArray tmp = ui->comboBoxFilterPreset->currentText().toUtf8(); + const char* oldName = tmp.data(); + + bool ok = false; + QString newName = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input new name for the selected filter preset:"), + QLineEdit::Normal, + oldName, + &ok); + bool nameExist = BlastProject::ins().isFilterPresetNameExist(newName.toUtf8().data()); + if (ok && !newName.isEmpty() && !nameExist) + { + int index = ui->comboBoxFilterPreset->currentIndex(); + BlastProject::ins().renameFilterPreset(oldName, newName.toUtf8().data()); + updateValues(); + ui->comboBoxFilterPreset->setCurrentIndex(index); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && newName.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the selected filter preset!"); + } +} + +void FiltersDockWidget::on_btnRemoveFilterPreset_clicked() +{ + QByteArray tmp = ui->comboBoxFilterPreset->currentText().toUtf8(); + const char* name = tmp.data(); + BlastProject::ins().removeFilterPreset(name); + updateValues(); +} + +void FiltersDockWidget::on_btnDepth0_clicked(bool val) +{ + _addRemoveDepthFilter(0, val); +} + +void FiltersDockWidget::on_btnDepth1_clicked(bool val) +{ + _addRemoveDepthFilter(1, val); +} + +void FiltersDockWidget::on_btnDepth2_clicked(bool val) +{ + _addRemoveDepthFilter(2, val); +} + +void FiltersDockWidget::on_btnDepth3_clicked(bool val) +{ + _addRemoveDepthFilter(3, val); +} + +void FiltersDockWidget::on_btnDepth4_clicked(bool val) +{ + _addRemoveDepthFilter(4, val); +} + +void FiltersDockWidget::on_btnDepth5_clicked(bool val) +{ + _addRemoveDepthFilter(5, val); +} + +void FiltersDockWidget::on_btnAddDepthFilter_clicked() +{ + +} + +void FiltersDockWidget::on_btnAddFilter_clicked() +{ + +} + +void FiltersDockWidget::on_btnSelect_clicked() +{ + std::vector<uint32_t> depths; + int row = ui->listWidget->currentRow(); + if (-1 != row) + { + depths.push_back(_filterItemWidgets[row]->_depth); + } + SampleManager::ins()->setChunkSelected(depths, true); +} + +void FiltersDockWidget::on_btnVisible_clicked() +{ + std::vector<uint32_t> depths; + int row = ui->listWidget->currentRow(); + if (-1 != row) + { + depths.push_back(_filterItemWidgets[row]->_depth); + } + SampleManager::ins()->setChunkVisible(depths, true); +} + +void FiltersDockWidget::on_btnInVisible_clicked() +{ + std::vector<uint32_t> depths; + int row = ui->listWidget->currentRow(); + if (-1 != row) + { + depths.push_back(_filterItemWidgets[row]->_depth); + } + SampleManager::ins()->setChunkVisible(depths, false); +} + +void FiltersDockWidget::on_listWidget_currentRowChanged(int index) +{ + if (-1 != _lastSelectRow && _lastSelectRow < _filterItemWidgets.size()) + static_cast<FilterItemWidget*>(_filterItemWidgets[_lastSelectRow])->deSelect(); + + if (-1 != index && index < _filterItemWidgets.size()) + static_cast<FilterItemWidget*>(_filterItemWidgets[index])->select(); + + _lastSelectRow = index; +} + +void FiltersDockWidget::onListWidgetRemoveBtnClicked(QListWidgetItem* item) +{ + /// remove former ui info + map<QListWidgetItem*, FilterItemInfo*>::iterator toRemoveItem = _filterUIItems.find(item); + if (toRemoveItem != _filterUIItems.end()) + { + FilterItemWidget* itemWidget = toRemoveItem->second->itemWidget; + itemWidget->setParent(nullptr); + + _filterItemWidgets.erase(std::find(_filterItemWidgets.begin(), _filterItemWidgets.end(), toRemoveItem->second->itemWidget)); + + if (ui->comboBoxFilterPreset->currentIndex() != -1) + { + QByteArray filterPreset = itemWidget->_filterPreset.toUtf8(); + BlastProject::ins().removeFilterDepth(filterPreset.data(), itemWidget->_depth); + } + + ui->listWidget->takeItem(ui->listWidget->row(item)); + ui->listWidget->removeItemWidget(item); + delete item; + delete itemWidget; + _filterUIItems.erase(toRemoveItem); + + //_updateFilterItemList(); + _updateFilterDepthBtns(); + } +} + +void FiltersDockWidget::_updateFilterItemList() +{ + /// remove former ui info + map<QListWidgetItem*, FilterItemInfo*>::iterator theEnd = _filterUIItems.end(); + for (map<QListWidgetItem*, FilterItemInfo*>::iterator itr = _filterUIItems.begin(); itr != theEnd; ++itr) + { + itr->second->itemWidget->setParent(nullptr); + delete itr->first; + delete itr->second->itemWidget; + delete itr->second; + } + _filterUIItems.clear(); + ui->listWidget->clear(); + _filterItemWidgets.clear(); + + int filterPresetIndex = ui->comboBoxFilterPreset->currentIndex(); + if (filterPresetIndex < 0) + return; + + BPParams& projectParams = BlastProject::ins().getParams(); + BPPFilterPresetArray& filterPresetArray = projectParams.filter.filters; + BPPFilterPreset& filterPresset = filterPresetArray.buf[filterPresetIndex]; + + int filterCount = filterPresset.depthFilters.arraySizes[0]; + + for (int i = 0; i < filterCount; ++i) + { + QListWidgetItem* item = new QListWidgetItem(NULL); + int depth = filterPresset.depthFilters.buf[i]; + FilterItemWidget* itemWidget = new FilterItemWidget(this, item, filterPresset.name.buf, depth); + + QString depthFilterLabel = QString(QObject::tr("Depth-%1")).arg(depth); + _filterUIItems.insert(std::make_pair(item, new FilterItemInfo(itemWidget, depthFilterLabel))); + itemWidget->setText(depthFilterLabel); + _filterItemWidgets.push_back(itemWidget); + + ui->listWidget->addItem(item); + ui->listWidget->setItemWidget(item, itemWidget); + } +} + +void FiltersDockWidget::_updateFilterDepthBtns() +{ + for (int i = 0; i <= 5; ++i) + _depthButtons[i]->setChecked(false); + + int filterPresetIndex = ui->comboBoxFilterPreset->currentIndex(); + if (filterPresetIndex < 0) + return; + + BPParams& projectParams = BlastProject::ins().getParams(); + BPPFilterPresetArray& filterPresetArray = projectParams.filter.filters; + BPPFilterPreset& filterPresset = filterPresetArray.buf[filterPresetIndex]; + + int filterCount = filterPresset.depthFilters.arraySizes[0]; + + for (int i = 0; i < filterCount; ++i) + { + int depth = filterPresset.depthFilters.buf[i]; + + _depthButtons[depth]->setChecked(true); + } +} + +void FiltersDockWidget::_addRemoveDepthFilter(int depth, bool add) +{ + if (ui->comboBoxFilterPreset->currentIndex() != -1) + { + QByteArray filterPreset = ui->comboBoxFilterPreset->currentText().toUtf8(); + + if (add) + BlastProject::ins().addFilterDepth(filterPreset.data(), depth); + else + BlastProject::ins().removeFilterDepth(filterPreset.data(), depth); + + _updateFilterItemList(); + } +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FiltersDockWidget.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FiltersDockWidget.h new file mode 100644 index 0000000..cf25073 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FiltersDockWidget.h @@ -0,0 +1,104 @@ +#ifndef FILTERSDOCKWIDGET_H +#define FILTERSDOCKWIDGET_H + +#include <QtWidgets/QDockWidget> +#include <vector> +#include <map> +using namespace std; + +namespace Ui { +class FiltersDockWidget; +} + +class QLabel; +class QPushButton; +class QListWidgetItem; +struct FilterItemInfo; +class FilterItemWidget; +class FiltersDockWidget; + +class FilterItemWidget : public QWidget +{ + Q_OBJECT +public: + FilterItemWidget(FiltersDockWidget* parent, QListWidgetItem* item, const QString& filterPreset, int depth); + ~FilterItemWidget() + { + } + + void setText(const QString& title); + void select(); + void deSelect(); + +signals: + void RemoveItem(QListWidgetItem* item); + +private slots: + void onRemoveButtonClicked(); + +public: + QLabel* _label; + QPushButton* _removeBtn; + QListWidgetItem* _relatedListWidgetItem; + QString _filterPreset; + int _depth; +}; + +class FiltersDockWidget : public QDockWidget +{ + Q_OBJECT + +public: + explicit FiltersDockWidget(QWidget *parent = 0); + ~FiltersDockWidget(); + void updateValues(); + +private slots: + void on_comboBoxFilterPreset_currentIndexChanged(int index); + + void on_btnAddFilterPrest_clicked(); + + void on_btnModifyFilterPreset_clicked(); + + void on_btnRemoveFilterPreset_clicked(); + + void on_btnDepth0_clicked(bool val); + + void on_btnDepth1_clicked(bool val); + + void on_btnDepth2_clicked(bool val); + + void on_btnDepth3_clicked(bool val); + + void on_btnDepth4_clicked(bool val); + + void on_btnDepth5_clicked(bool val); + + void on_btnAddDepthFilter_clicked(); + + void on_btnAddFilter_clicked(); + + void on_btnSelect_clicked(); + + void on_btnVisible_clicked(); + + void on_btnInVisible_clicked(); + + void on_listWidget_currentRowChanged(int index); + + void onListWidgetRemoveBtnClicked(QListWidgetItem* item); + +private: + void _updateFilterItemList(); + void _updateFilterDepthBtns(); + void _addRemoveDepthFilter(int depth, bool add); + +private: + Ui::FiltersDockWidget *ui; + map<QListWidgetItem*, FilterItemInfo*> _filterUIItems; + vector<FilterItemWidget*> _filterItemWidgets; + int _lastSelectRow; + vector<QPushButton*> _depthButtons; +}; + +#endif // FILTERSDOCKWIDGET_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureCutoutSettingsPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureCutoutSettingsPanel.cpp new file mode 100644 index 0000000..ea24278 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureCutoutSettingsPanel.cpp @@ -0,0 +1,155 @@ +#include "FractureCutoutSettingsPanel.h" +#include "ui_FractureCutoutSettingsPanel.h" +#include "ProjectParams.h" +#include <QtWidgets/QInputDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QMessageBox> +#include <QtCore/QFileInfo> +#include "AppMainWindow.h" + +FractureCutoutSettingsPanel::FractureCutoutSettingsPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::FractureCutoutSettingsPanel) +{ + ui->setupUi(this); +} + +FractureCutoutSettingsPanel::~FractureCutoutSettingsPanel() +{ + delete ui; +} + +void FractureCutoutSettingsPanel::updateValues() +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + + _updateTextureListWidget(); + + ui->comboBoxCutoutType->setCurrentIndex(cutoutProjection.cutoutType); + ui->spinBoxPixelThreshold->setValue(cutoutProjection.pixelThreshold); + ui->checkBoxTiled->setChecked(cutoutProjection.tiled); + ui->checkBoxInvertU->setChecked(cutoutProjection.invertU); + ui->checkBoxInvertV->setChecked(cutoutProjection.invertV); +} + +void FractureCutoutSettingsPanel::on_btnAddTexture_clicked() +{ + QString texName = AppMainWindow::Inst().OpenTextureFile(); + + if (texName.isEmpty()) + return; + + QFileInfo fileInfo(texName); + QByteArray ba = fileInfo.absoluteFilePath().toLocal8Bit(); + const char* filePath = (const char*)(ba); + + if (!BlastProject::ins().isCutoutTextureNameExist(texName.toUtf8().data())) + { + BlastProject::ins().addCutoutTexture(filePath); + _updateTextureListWidget(); + ui->listWidget->setCurrentRow(ui->listWidget->count() - 1); + } + else + { + QMessageBox::warning(this, "Blast Tool", "The texture you selected is already exist!"); + } +} + +void FractureCutoutSettingsPanel::on_btnReloadTexture_clicked() +{ + +} + +void FractureCutoutSettingsPanel::on_btnRemoveTexture_clicked() +{ + if (ui->listWidget->currentRow() != -1) + { + QListWidgetItem *item = ui->listWidget->currentItem(); + QString texture = _getTexturePathByName(item->text()); + QByteArray ba = texture.toLocal8Bit(); + BlastProject::ins().removeCutoutTexture(ba.data()); + _updateTextureListWidget(); + } +} + +void FractureCutoutSettingsPanel::on_listWidget_currentRowChanged(int currentRow) +{ + +} + +void FractureCutoutSettingsPanel::on_btnTextureMap_clicked() +{ + +} + +void FractureCutoutSettingsPanel::on_comboBoxCutoutType_currentIndexChanged(int index) +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + cutoutProjection.cutoutType = index; +} + +void FractureCutoutSettingsPanel::on_spinBoxPixelThreshold_valueChanged(int arg1) +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + cutoutProjection.pixelThreshold = arg1; +} + +void FractureCutoutSettingsPanel::on_checkBoxTiled_stateChanged(int arg1) +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + cutoutProjection.tiled = (arg1 != 0 ? true : false); +} + +void FractureCutoutSettingsPanel::on_checkBoxInvertU_stateChanged(int arg1) +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + cutoutProjection.invertU = (arg1 != 0 ? true : false); +} + +void FractureCutoutSettingsPanel::on_checkBoxInvertV_stateChanged(int arg1) +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + cutoutProjection.invertV = (arg1 != 0 ? true : false); +} + +void FractureCutoutSettingsPanel::on_btnFitToObject_clicked() +{ + +} + +void FractureCutoutSettingsPanel::on_btnApplyFracture_clicked() +{ + +} + +QString FractureCutoutSettingsPanel::_getTexturePathByName(const QString& name) +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + BPPStringArray& textureArray = cutoutProjection.textures; + + int count = textureArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + QFileInfo fileInfo(textureArray.buf[i].buf); + if (fileInfo.baseName() == name) + return textureArray.buf[i].buf; + } + + return ""; +} + +void FractureCutoutSettingsPanel::_updateTextureListWidget() +{ + BPPCutoutProjection& cutoutProjection = BlastProject::ins().getParams().fracture.cutoutProjection; + + ui->listWidget->clear(); + QStringList items; + for (int i = 0; i < cutoutProjection.textures.arraySizes[0]; ++i) + { + QFileInfo fileInfo(cutoutProjection.textures.buf[i].buf); + QByteArray ba = fileInfo.baseName().toLocal8Bit(); + const char* texture = (const char*)(ba); + items.append(texture); + } + ui->listWidget->addItems(items); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureCutoutSettingsPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureCutoutSettingsPanel.h new file mode 100644 index 0000000..7faf2ae --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureCutoutSettingsPanel.h @@ -0,0 +1,52 @@ +#ifndef FRACTURECUTOUTSETTINGSPANEL_H +#define FRACTURECUTOUTSETTINGSPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class FractureCutoutSettingsPanel; +} + +class FractureCutoutSettingsPanel : public QWidget +{ + Q_OBJECT + +public: + explicit FractureCutoutSettingsPanel(QWidget *parent = 0); + ~FractureCutoutSettingsPanel(); + void updateValues(); + +private slots: + void on_btnAddTexture_clicked(); + + void on_btnReloadTexture_clicked(); + + void on_btnRemoveTexture_clicked(); + + void on_listWidget_currentRowChanged(int currentRow); + + void on_btnTextureMap_clicked(); + + void on_comboBoxCutoutType_currentIndexChanged(int index); + + void on_spinBoxPixelThreshold_valueChanged(int arg1); + + void on_checkBoxTiled_stateChanged(int arg1); + + void on_checkBoxInvertU_stateChanged(int arg1); + + void on_checkBoxInvertV_stateChanged(int arg1); + + void on_btnFitToObject_clicked(); + + void on_btnApplyFracture_clicked(); + +private: + QString _getTexturePathByName(const QString& name); + void _updateTextureListWidget(); + +private: + Ui::FractureCutoutSettingsPanel *ui; +}; + +#endif // FRACTURECUTOUTSETTINGSPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureGeneralPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureGeneralPanel.cpp new file mode 100644 index 0000000..1f7068d --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureGeneralPanel.cpp @@ -0,0 +1,63 @@ +#include "FractureGeneralPanel.h" +#include "ui_FractureGeneralPanel.h" +#include "ProjectParams.h" + +FractureGeneralPanel::FractureGeneralPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::FractureGeneralPanel) +{ + ui->setupUi(this); +} + +FractureGeneralPanel::~FractureGeneralPanel() +{ + delete ui; +} + +void FractureGeneralPanel::updateValues() +{ + BPPFractureGeneral& fractureGeneral = BlastProject::ins().getParams().fracture.general; + + ui->comboBoxFracturePreset->setCurrentIndex(fractureGeneral.fracturePreset); + ui->comboBoxFractureType->setCurrentIndex(fractureGeneral.fractureType); + ui->checkBoxAddDepth->setChecked(fractureGeneral.addDepth); + ui->checkBoxPerChunk->setChecked(fractureGeneral.perChunk); + ui->checkBoxNewMatID->setChecked(fractureGeneral.newMatID); + ui->comboBoxApplyMaterial->setCurrentIndex(fractureGeneral.applyMaterial); +} + +void FractureGeneralPanel::on_comboBoxFracturePreset_currentIndexChanged(int index) +{ + BPPFractureGeneral& fractureGeneral = BlastProject::ins().getParams().fracture.general; + fractureGeneral.fracturePreset = index; +} + +void FractureGeneralPanel::on_comboBoxFractureType_currentIndexChanged(int index) +{ + BPPFractureGeneral& fractureGeneral = BlastProject::ins().getParams().fracture.general; + fractureGeneral.fractureType = index; +} + +void FractureGeneralPanel::on_checkBoxAddDepth_stateChanged(int arg1) +{ + BPPFractureGeneral& fractureGeneral = BlastProject::ins().getParams().fracture.general; + fractureGeneral.addDepth = (arg1 != 0 ? true : false); +} + +void FractureGeneralPanel::on_checkBoxPerChunk_stateChanged(int arg1) +{ + BPPFractureGeneral& fractureGeneral = BlastProject::ins().getParams().fracture.general; + fractureGeneral.perChunk = (arg1 != 0 ? true : false); +} + +void FractureGeneralPanel::on_checkBoxNewMatID_stateChanged(int arg1) +{ + BPPFractureGeneral& fractureGeneral = BlastProject::ins().getParams().fracture.general; + fractureGeneral.newMatID = (arg1 != 0 ? true:false); +} + +void FractureGeneralPanel::on_comboBoxApplyMaterial_currentIndexChanged(int index) +{ + BPPFractureGeneral& fractureGeneral = BlastProject::ins().getParams().fracture.general; + fractureGeneral.applyMaterial = index; +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureGeneralPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureGeneralPanel.h new file mode 100644 index 0000000..4b51f5e --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureGeneralPanel.h @@ -0,0 +1,36 @@ +#ifndef FRACTUREGENERALPANEL_H +#define FRACTUREGENERALPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class FractureGeneralPanel; +} + +class FractureGeneralPanel : public QWidget +{ + Q_OBJECT + +public: + explicit FractureGeneralPanel(QWidget *parent = 0); + ~FractureGeneralPanel(); + void updateValues(); + +private slots: + void on_comboBoxFracturePreset_currentIndexChanged(int index); + + void on_comboBoxFractureType_currentIndexChanged(int index); + + void on_checkBoxAddDepth_stateChanged(int arg1); + + void on_checkBoxPerChunk_stateChanged(int arg1); + + void on_checkBoxNewMatID_stateChanged(int arg1); + + void on_comboBoxApplyMaterial_currentIndexChanged(int index); + +private: + Ui::FractureGeneralPanel *ui; +}; + +#endif // FRACTUREGENERALPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureShellCutSettingsPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureShellCutSettingsPanel.cpp new file mode 100644 index 0000000..c08e3ba --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureShellCutSettingsPanel.cpp @@ -0,0 +1,40 @@ +#include "FractureShellCutSettingsPanel.h" +#include "ui_FractureShellCutSettingsPanel.h" +#include "ProjectParams.h" + +FractureShellCutSettingsPanel::FractureShellCutSettingsPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::FractureShellCutSettingsPanel) +{ + ui->setupUi(this); +} + +FractureShellCutSettingsPanel::~FractureShellCutSettingsPanel() +{ + delete ui; +} + +void FractureShellCutSettingsPanel::updateValues() +{ + BPPShellCut& shellCut = BlastProject::ins().getParams().fracture.shellCut; + + ui->spinBoxThickness->setValue(shellCut.thickness); + ui->spinBoxThicknessVariation->setValue(shellCut.thicknessVariation); +} + +void FractureShellCutSettingsPanel::on_spinBoxThickness_valueChanged(double arg1) +{ + BPPShellCut& shellCut = BlastProject::ins().getParams().fracture.shellCut; + shellCut.thickness = arg1; +} + +void FractureShellCutSettingsPanel::on_spinBoxThicknessVariation_valueChanged(double arg1) +{ + BPPShellCut& shellCut = BlastProject::ins().getParams().fracture.shellCut; + shellCut.thicknessVariation = arg1; +} + +void FractureShellCutSettingsPanel::on_btnApplyFracture_clicked() +{ + +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureShellCutSettingsPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureShellCutSettingsPanel.h new file mode 100644 index 0000000..a664adb --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureShellCutSettingsPanel.h @@ -0,0 +1,30 @@ +#ifndef FRACTURESHELLCUTSETTINGSPANEL_H +#define FRACTURESHELLCUTSETTINGSPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class FractureShellCutSettingsPanel; +} + +class FractureShellCutSettingsPanel : public QWidget +{ + Q_OBJECT + +public: + explicit FractureShellCutSettingsPanel(QWidget *parent = 0); + ~FractureShellCutSettingsPanel(); + void updateValues(); + +private slots: +void on_spinBoxThickness_valueChanged(double arg1); + + void on_spinBoxThicknessVariation_valueChanged(double arg1); + + void on_btnApplyFracture_clicked(); + +private: + Ui::FractureShellCutSettingsPanel *ui; +}; + +#endif // FRACTURESHELLCUTSETTINGSPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureSliceSettingsPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureSliceSettingsPanel.cpp new file mode 100644 index 0000000..fa82ee2 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureSliceSettingsPanel.cpp @@ -0,0 +1,105 @@ +#include "FractureSliceSettingsPanel.h" +#include "ui_FractureSliceSettingsPanel.h" +#include "ProjectParams.h" +#include "SimpleScene.h" +#include "SampleManager.h" +#include <QtWidgets/QMessageBox> + +FractureSliceSettingsPanel::FractureSliceSettingsPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::FractureSliceSettingsPanel) +{ + ui->setupUi(this); +} + +FractureSliceSettingsPanel::~FractureSliceSettingsPanel() +{ + delete ui; +} + +void FractureSliceSettingsPanel::updateValues() +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + + ui->spinBoxNumSlices->setValue(slice.numSlices); + ui->spinBoxOffsetVariation->setValue(slice.offsetVariation); + ui->spinBoxRotationVariation->setValue(slice.rotationVariation); + ui->spinBoxNoiseAmplitude->setValue(slice.noiseAmplitude); + ui->spinBoxNoiseFrequency->setValue(slice.noiseFrequency); + ui->spinBoxNoiseSeed->setValue(slice.noiseSeed); +} + +void FractureSliceSettingsPanel::on_spinBoxNumSlices_valueChanged(int arg1) +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + slice.numSlices = arg1; +} + +void FractureSliceSettingsPanel::on_spinBoxOffsetVariation_valueChanged(double arg1) +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + slice.offsetVariation = arg1; +} + +void FractureSliceSettingsPanel::on_spinBoxRotationVariation_valueChanged(double arg1) +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + slice.rotationVariation = arg1; +} + +void FractureSliceSettingsPanel::on_spinBoxNoiseAmplitude_valueChanged(double arg1) +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + slice.noiseAmplitude = arg1; +} + +void FractureSliceSettingsPanel::on_spinBoxNoiseFrequency_valueChanged(double arg1) +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + slice.noiseFrequency = arg1; +} + +void FractureSliceSettingsPanel::on_spinBoxNoiseSeed_valueChanged(int arg1) +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + slice.noiseSeed = arg1; +} + +void FractureSliceSettingsPanel::on_btnApplyFracture_clicked() +{ + BPPSlice& slice = BlastProject::ins().getParams().fracture.slice; + SliceFractureExecutor executor; + executor.applyNoise(slice.noiseAmplitude, slice.noiseAmplitude, 0, 0, 0, slice.noiseSeed); + executor.applyConfig(slice.numSlices, slice.numSlices, slice.numSlices, slice.offsetVariation, slice.rotationVariation); + + bool multiplyChunksSelected = false; + std::map<BlastAsset*, std::vector<uint32_t>> selectedChunks = SampleManager::ins()->getSelectedChunks(); + std::map<BlastAsset*, std::vector<uint32_t>>::iterator itrAssetSelectedChunks = selectedChunks.begin(); + + if (selectedChunks.size() > 1) + { + multiplyChunksSelected = true; + } + else if (selectedChunks.size() == 1 && itrAssetSelectedChunks->second.size() > 1) + { + multiplyChunksSelected = true; + } + else if((selectedChunks.size() == 1 && itrAssetSelectedChunks->second.size() == 0) || (selectedChunks.size() == 0)) + { + return; + } + + if (multiplyChunksSelected) + { + QMessageBox::warning(NULL, "Blast Tool", "Now, this tool can only fracture one chunk!"); + return; + } + + executor.setSourceAsset(itrAssetSelectedChunks->first); + executor.setTargetChunk(itrAssetSelectedChunks->second.at(0)); + executor.execute(); + + //VoronoiFractureExecutor executor; + //executor.setTargetChunk(0); + //executor.execute(); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureSliceSettingsPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureSliceSettingsPanel.h new file mode 100644 index 0000000..b85b58f --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureSliceSettingsPanel.h @@ -0,0 +1,38 @@ +#ifndef FRACTURESLICESETTINGSPANEL_H +#define FRACTURESLICESETTINGSPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class FractureSliceSettingsPanel; +} + +class FractureSliceSettingsPanel : public QWidget +{ + Q_OBJECT + +public: + explicit FractureSliceSettingsPanel(QWidget *parent = 0); + ~FractureSliceSettingsPanel(); + void updateValues(); + +private slots: + void on_spinBoxNumSlices_valueChanged(int arg1); + + void on_spinBoxOffsetVariation_valueChanged(double arg1); + + void on_spinBoxRotationVariation_valueChanged(double arg1); + + void on_spinBoxNoiseAmplitude_valueChanged(double arg1); + + void on_spinBoxNoiseFrequency_valueChanged(double arg1); + + void on_spinBoxNoiseSeed_valueChanged(int arg1); + + void on_btnApplyFracture_clicked(); + +private: + Ui::FractureSliceSettingsPanel *ui; +}; + +#endif // FRACTURESLICESETTINGSPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVisualizersPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVisualizersPanel.cpp new file mode 100644 index 0000000..0f77e27 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVisualizersPanel.cpp @@ -0,0 +1,36 @@ +#include "FractureVisualizersPanel.h" +#include "ui_FractureVisualizersPanel.h" +#include "ProjectParams.h" + +FractureVisualizersPanel::FractureVisualizersPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::FractureVisualizersPanel) +{ + ui->setupUi(this); +} + +FractureVisualizersPanel::~FractureVisualizersPanel() +{ + delete ui; +} + +void FractureVisualizersPanel::updateValues() +{ + BPPFractureVisualization& fractureVisualization = BlastProject::ins().getParams().fracture.visualization; + + ui->checkBoxFracturePreview->setChecked(fractureVisualization.fracturePreview); + ui->checkBoxDisplayFractureWidget->setChecked(fractureVisualization.displayFractureWidget); +} + +void FractureVisualizersPanel::on_checkBoxFracturePreview_stateChanged(int arg1) +{ + BPPFractureVisualization& fractureVisualization = BlastProject::ins().getParams().fracture.visualization; + fractureVisualization.fracturePreview = (arg1 != 0 ? true : false); +} + +void FractureVisualizersPanel::on_checkBoxDisplayFractureWidget_stateChanged(int arg1) +{ + BPPFractureVisualization& fractureVisualization = BlastProject::ins().getParams().fracture.visualization; + fractureVisualization.displayFractureWidget = (arg1 != 0 ? true : false); +} + diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVisualizersPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVisualizersPanel.h new file mode 100644 index 0000000..d542d7f --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVisualizersPanel.h @@ -0,0 +1,28 @@ +#ifndef FRACTUREVISUALIZERSPANEL_H +#define FRACTUREVISUALIZERSPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class FractureVisualizersPanel; +} + +class FractureVisualizersPanel : public QWidget +{ + Q_OBJECT + +public: + explicit FractureVisualizersPanel(QWidget *parent = 0); + ~FractureVisualizersPanel(); + void updateValues(); + +private slots: + void on_checkBoxFracturePreview_stateChanged(int arg1); + + void on_checkBoxDisplayFractureWidget_stateChanged(int arg1); + +private: + Ui::FractureVisualizersPanel *ui; +}; + +#endif // FRACTUREVISUALIZERSPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVoronoiSettingsPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVoronoiSettingsPanel.cpp new file mode 100644 index 0000000..2142f80 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVoronoiSettingsPanel.cpp @@ -0,0 +1,354 @@ +#include "FractureVoronoiSettingsPanel.h" +#include "ui_FractureVoronoiSettingsPanel.h" +#include "ProjectParams.h" +#include <QtWidgets/QInputDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QMessageBox> +#include <QtCore/QFileInfo> +#include "AppMainWindow.h" +#include "ProjectParams.h" +#include "SimpleScene.h" +#include "SampleManager.h" + +FractureVoronoiSettingsPanel::FractureVoronoiSettingsPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::FractureVoronoiSettingsPanel), + _updateData(true) +{ + ui->setupUi(this); + + ui->groupBoxVisualizers->hide(); +} + +FractureVoronoiSettingsPanel::~FractureVoronoiSettingsPanel() +{ + delete ui; +} + +void FractureVoronoiSettingsPanel::updateValues() +{ + _updateData = false; + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + + ui->spinBoxNumberOfSites->setValue(voronoi.numSites); + ui->comboBoxSiteGeneration->setCurrentIndex(voronoi.siteGeneration); + ui->spinBoxGridSize->setValue(voronoi.gridSize); + ui->spinBoxGridScale->setValue(voronoi.gridScale); + ui->spinBoxAmplitude->setValue(voronoi.amplitude); + ui->spinBoxFrequency->setValue(voronoi.frequency); + + _updatePaintMaskComboBox(); + + _updateMeshCutterComboBox(); + ui->checkBoxFractureInsideCutter->setChecked(voronoi.fractureInsideCutter); + ui->checkBoxFractureOutsideCutter->setChecked(voronoi.fractureOutsideCutter); + + ui->spinBoxTextureSites->setValue(voronoi.numTextureSites); + + _updateTextureListWidget(); + _updateData = true; +} + +void FractureVoronoiSettingsPanel::on_checkBoxGridPreview_stateChanged(int arg1) +{ + +} + +void FractureVoronoiSettingsPanel::on_checkBoxFracturePreview_stateChanged(int arg1) +{ + +} + +void FractureVoronoiSettingsPanel::on_checkBoxCutterMesh_stateChanged(int arg1) +{ + +} + +void FractureVoronoiSettingsPanel::on_spinBoxNumberOfSites_valueChanged(int arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.numSites = arg1; +} + +void FractureVoronoiSettingsPanel::on_comboBoxSiteGeneration_currentIndexChanged(int index) +{ + if (!_updateData) + return; + + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.siteGeneration = index; +} + +void FractureVoronoiSettingsPanel::on_spinBoxGridSize_valueChanged(int arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.gridSize = arg1; +} + +void FractureVoronoiSettingsPanel::on_spinBoxGridScale_valueChanged(double arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.gridScale = arg1; +} + +void FractureVoronoiSettingsPanel::on_spinBoxAmplitude_valueChanged(double arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.amplitude = arg1; +} + +void FractureVoronoiSettingsPanel::on_spinBoxFrequency_valueChanged(int arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.frequency = arg1; +} + +void FractureVoronoiSettingsPanel::on_comboBoxPaintMasks_currentIndexChanged(int index) +{ + if (!_updateData) + return; + + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.activePaintMask = index; +} + +void FractureVoronoiSettingsPanel::on_btnAddPaintMasks_clicked() +{ + bool ok = false; + QString name = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input name for new paint mask:"), + QLineEdit::Normal, + "", + &ok); + bool nameExist = BlastProject::ins().isPaintMaskNameExist(name.toUtf8().data()); + if (ok && !name.isEmpty() && !nameExist) + { + BlastProject::ins().addPaintMasks(name.toUtf8().data()); + _updatePaintMaskComboBox(); + ui->comboBoxPaintMasks->setCurrentIndex(ui->comboBoxPaintMasks->count() - 1); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && name.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new paint mask!"); + } +} + +void FractureVoronoiSettingsPanel::on_btnRemovePaintMasks_clicked() +{ + if (ui->comboBoxPaintMasks->currentIndex() > -1) + { + BlastProject::ins().removePaintMasks(ui->comboBoxPaintMasks->currentText().toUtf8().data()); + _updatePaintMaskComboBox(); + } +} + +void FractureVoronoiSettingsPanel::on_comboBoxMeshCutter_currentIndexChanged(int index) +{ + if (!_updateData) + return; + + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.activeMeshCutter = index; +} + +void FractureVoronoiSettingsPanel::on_btnAddMeshCutter_clicked() +{ + bool ok = false; + QString name = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input name for new mesh cutter:"), + QLineEdit::Normal, + "", + &ok); + bool nameExist = BlastProject::ins().isMeshCutterNameExist(name.toUtf8().data()); + if (ok && !name.isEmpty() && !nameExist) + { + BlastProject::ins().addMeshCutter(name.toUtf8().data()); + _updateMeshCutterComboBox(); + ui->comboBoxMeshCutter->setCurrentIndex(ui->comboBoxMeshCutter->count() - 1); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && name.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new cutter mesh!"); + } +} + +void FractureVoronoiSettingsPanel::on_btnRemoveMeshCutter_clicked() +{ + if (ui->comboBoxMeshCutter->currentIndex() > -1) + { + BlastProject::ins().removeMeshCutter(ui->comboBoxMeshCutter->currentText().toUtf8().data()); + _updateMeshCutterComboBox(); + } +} + +void FractureVoronoiSettingsPanel::on_checkBoxFractureInsideCutter_stateChanged(int arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.fractureInsideCutter = (arg1 != 0 ? true : false); +} + +void FractureVoronoiSettingsPanel::on_checkBoxFractureOutsideCutter_stateChanged(int arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.fractureOutsideCutter = (arg1 != 0 ? true : false); +} + +void FractureVoronoiSettingsPanel::on_btnAddTexture_clicked() +{ + QString texName = AppMainWindow::Inst().OpenTextureFile(); + + if (texName.isEmpty()) + return; + + QFileInfo fileInfo(texName); + QByteArray ba = fileInfo.absoluteFilePath().toLocal8Bit(); + const char* filePath = (const char*)(ba); + + if (!BlastProject::ins().isVoronoiTextureNameExist(texName.toUtf8().data())) + { + BlastProject::ins().addVoronoiTexture(filePath); + _updateTextureListWidget(); + ui->listWidgetTexture->setCurrentRow(ui->listWidgetTexture->count() - 1); + } + else + { + QMessageBox::warning(this, "Blast Tool", "The texture you selected is already exist!"); + } +} + +void FractureVoronoiSettingsPanel::on_btnReloadTexture_clicked() +{ + +} + +void FractureVoronoiSettingsPanel::on_btnRemoveTexture_clicked() +{ + if (ui->listWidgetTexture->currentRow() != -1) + { + QListWidgetItem *item = ui->listWidgetTexture->currentItem(); + QString texture = _getTexturePathByName(item->text()); + QByteArray ba = texture.toLocal8Bit(); + BlastProject::ins().removeVoronoiTexture(ba.data()); + _updateTextureListWidget(); + } +} + +void FractureVoronoiSettingsPanel::on_spinBoxTextureSites_valueChanged(int arg1) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + voronoi.numTextureSites = arg1; +} + +void FractureVoronoiSettingsPanel::on_listWidgetTexture_itemSelectionChanged() +{ + +} + +void FractureVoronoiSettingsPanel::on_btnTextureMap_clicked() +{ + +} + +void FractureVoronoiSettingsPanel::on_btnApplyFracture_clicked() +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + VoronoiFractureExecutor executor; + executor.setCellsCount(voronoi.numSites); + + bool multiplyChunksSelected = false; + std::map<BlastAsset*, std::vector<uint32_t>> selectedChunks = SampleManager::ins()->getSelectedChunks(); + std::map<BlastAsset*, std::vector<uint32_t>>::iterator itrAssetSelectedChunks = selectedChunks.begin(); + + if (selectedChunks.size() > 1) + { + multiplyChunksSelected = true; + } + else if (selectedChunks.size() == 1 && itrAssetSelectedChunks->second.size() > 1) + { + multiplyChunksSelected = true; + } + else if ((selectedChunks.size() == 1 && itrAssetSelectedChunks->second.size() == 0) || (selectedChunks.size() == 0)) + { + return; + } + + if (multiplyChunksSelected) + { + QMessageBox::warning(NULL, "Blast Tool", "Now, this tool can only fracture one chunk!"); + return; + } + + executor.setSourceAsset(itrAssetSelectedChunks->first); + executor.setTargetChunk(itrAssetSelectedChunks->second.at(0)); + executor.execute(); +} + +QString FractureVoronoiSettingsPanel::_getTexturePathByName(const QString& name) +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + BPPStringArray& textureArray = voronoi.textureSites; + + int count = textureArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + QFileInfo fileInfo(textureArray.buf[i].buf); + if (fileInfo.baseName() == name) + return textureArray.buf[i].buf; + } + + return ""; +} + +void FractureVoronoiSettingsPanel::_updatePaintMaskComboBox() +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + + ui->comboBoxPaintMasks->clear(); + QStringList items; + for (int i = 0; i < voronoi.paintMasks.arraySizes[0]; ++i) + { + items.append(voronoi.paintMasks.buf[i].buf); + } + ui->comboBoxPaintMasks->addItems(items); + ui->comboBoxPaintMasks->setCurrentIndex(voronoi.activePaintMask); +} + +void FractureVoronoiSettingsPanel::_updateMeshCutterComboBox() +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + + ui->comboBoxMeshCutter->clear(); + QStringList items; + for (int i = 0; i < voronoi.meshCutters.arraySizes[0]; ++i) + { + items.append(voronoi.meshCutters.buf[i].buf); + } + ui->comboBoxMeshCutter->addItems(items); + ui->comboBoxMeshCutter->setCurrentIndex(voronoi.activeMeshCutter); +} + +void FractureVoronoiSettingsPanel::_updateTextureListWidget() +{ + BPPVoronoi& voronoi = BlastProject::ins().getParams().fracture.voronoi; + + ui->listWidgetTexture->clear(); + QStringList items; + for (int i = 0; i < voronoi.textureSites.arraySizes[0]; ++i) + { + QFileInfo fileInfo(voronoi.textureSites.buf[i].buf); + QByteArray ba = fileInfo.baseName().toLocal8Bit(); + const char* texture = (const char*)(ba); + items.append(texture); + } + ui->listWidgetTexture->addItems(items); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVoronoiSettingsPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVoronoiSettingsPanel.h new file mode 100644 index 0000000..6a0668d --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/FractureVoronoiSettingsPanel.h @@ -0,0 +1,79 @@ +#ifndef FRACTUREVORONOISETTINGSPANEL_H +#define FRACTUREVORONOISETTINGSPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class FractureVoronoiSettingsPanel; +} + +class FractureVoronoiSettingsPanel : public QWidget +{ + Q_OBJECT + +public: + explicit FractureVoronoiSettingsPanel(QWidget *parent = 0); + ~FractureVoronoiSettingsPanel(); + void updateValues(); + +private slots: + void on_checkBoxGridPreview_stateChanged(int arg1); + + void on_checkBoxFracturePreview_stateChanged(int arg1); + + void on_checkBoxCutterMesh_stateChanged(int arg1); + + void on_spinBoxNumberOfSites_valueChanged(int arg1); + + void on_comboBoxSiteGeneration_currentIndexChanged(int index); + + void on_spinBoxGridSize_valueChanged(int arg1); + + void on_spinBoxGridScale_valueChanged(double arg1); + + void on_spinBoxAmplitude_valueChanged(double arg1); + + void on_spinBoxFrequency_valueChanged(int arg1); + + void on_comboBoxPaintMasks_currentIndexChanged(int index); + + void on_btnAddPaintMasks_clicked(); + + void on_btnRemovePaintMasks_clicked(); + + void on_comboBoxMeshCutter_currentIndexChanged(int index); + + void on_btnAddMeshCutter_clicked(); + + void on_btnRemoveMeshCutter_clicked(); + + void on_checkBoxFractureInsideCutter_stateChanged(int arg1); + + void on_checkBoxFractureOutsideCutter_stateChanged(int arg1); + + void on_btnAddTexture_clicked(); + + void on_btnReloadTexture_clicked(); + + void on_btnRemoveTexture_clicked(); + + void on_spinBoxTextureSites_valueChanged(int arg1); + + void on_listWidgetTexture_itemSelectionChanged(); + + void on_btnTextureMap_clicked(); + + void on_btnApplyFracture_clicked(); + +private: + QString _getTexturePathByName(const QString& name); + void _updatePaintMaskComboBox(); + void _updateMeshCutterComboBox(); + void _updateTextureListWidget(); + +private: + Ui::FractureVoronoiSettingsPanel *ui; + bool _updateData; +}; + +#endif // FRACTUREVORONOISETTINGSPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/GeneralPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/GeneralPanel.cpp new file mode 100644 index 0000000..88915f1 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/GeneralPanel.cpp @@ -0,0 +1,281 @@ +#include "GeneralPanel.h" +#include "ui_GeneralPanel.h" +#include <QtWidgets/QInputDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QMessageBox> + +GeneralPanel::GeneralPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::GeneralPanel) +{ + ui->setupUi(this); +} + +GeneralPanel::~GeneralPanel() +{ + delete ui; +} + +void GeneralPanel::updateValues() +{ + std::vector<StressSolverUserPreset> presets = BlastProject::ins().getUserPresets(); + ui->comboBoxUserPreset->clear(); + int countUserPresets = (int)presets.size(); + if (countUserPresets > 0) + { + QStringList userPresets; + for (int i = 0; i < countUserPresets; ++i) + { + userPresets.append(presets[i].name.c_str()); + } + ui->comboBoxUserPreset->addItems(userPresets); + } + + std::vector<BPPAsset*> selectedAssets = BlastProject::ins().getSelectedBlastAssets(); + if (selectedAssets.size() > 0) + { + ui->comboBoxUserPreset->setCurrentText(selectedAssets[0]->activePreset.buf); + + _updateStressSolverUIs(); + } + else + { + ui->comboBoxUserPreset->setCurrentIndex(-1); + + } +} + +void GeneralPanel::on_comboBoxUserPreset_currentIndexChanged(int index) +{ + std::vector<BPPAsset*> assets = BlastProject::ins().getSelectedBlastAssets(); + for (size_t i = 0; i < assets.size(); ++i) + { + QByteArray tem = ui->comboBoxUserPreset->currentText().toUtf8(); + copy(assets[i]->activePreset, tem.data()); + + BPPStressSolver* preset = _getUserPreset(tem.data()); + if (preset) + { + copy(assets[i]->stressSolver, *preset); + } + } + _updateStressSolverUIs(); +} + +void GeneralPanel::on_btnAddUserPreset_clicked() +{ + bool ok = false; + QString name = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input name for new User preset:"), + QLineEdit::Normal, + "", + &ok); + bool nameExist = BlastProject::ins().isUserPresetNameExist(name.toUtf8().data()); + if (ok && !name.isEmpty() && !nameExist) + { + BlastProject::ins().addUserPreset(name.toUtf8().data()); + updateValues(); + ui->comboBoxUserPreset->setCurrentIndex(ui->comboBoxUserPreset->count() - 1); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && name.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new preset!"); + } +} + +void GeneralPanel::on_btnModifyUserPreset_clicked() +{ + if (ui->comboBoxUserPreset->currentIndex() == -1) + { + QMessageBox::warning(this, "Blast Tool", "You should select an user preset!"); + return; + } + + QByteArray tmp = ui->comboBoxUserPreset->currentText().toUtf8(); + const char* oldName = tmp.data(); + + bool ok = false; + QString newName = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input new name for the selected user preset:"), + QLineEdit::Normal, + oldName, + &ok); + bool nameExist = BlastProject::ins().isUserPresetNameExist(newName.toUtf8().data()); + if (ok && !newName.isEmpty() && !nameExist) + { + int curIndex = ui->comboBoxUserPreset->currentIndex(); + + std::vector<StressSolverUserPreset>& presets = BlastProject::ins().getUserPresets(); + presets[curIndex].name = newName.toUtf8().data(); + updateValues(); + ui->comboBoxUserPreset->setCurrentIndex(curIndex); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && newName.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the selected graphics material!"); + } +} + +void GeneralPanel::on_btnSaveUserPreset_clicked() +{ + int currentUserPreset = ui->comboBoxUserPreset->currentIndex(); + if (-1 != currentUserPreset) + { + std::vector<StressSolverUserPreset>& presets = BlastProject::ins().getUserPresets(); + BPPStressSolver& stressSolver = presets[currentUserPreset].stressSolver; + stressSolver.solverMode = ui->comboBoxSolverMode->currentIndex(); + stressSolver.linearFactor = ui->spinBoxLinearFactor->value(); + stressSolver.angularFactor = ui->spinBoxAngularFactor->value(); + stressSolver.meanError = ui->spinBoxMeanError->value(); + stressSolver.varianceError = ui->spinBoxVarianceError->value(); + stressSolver.bondsPerFrame = ui->spinBoxBondsPerFrame->value(); + stressSolver.bondsIterations = ui->spinBoxBondsIterations->value(); + } + + BlastProject::ins().saveUserPreset(); +} + +void GeneralPanel::on_comboBoxSolverMode_currentIndexChanged(int index) +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + + if (stressSolver) + { + stressSolver->solverMode = index; + } +} + +void GeneralPanel::on_spinBoxLinearFactor_valueChanged(double arg1) +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + + if (stressSolver) + { + stressSolver->linearFactor = arg1; + } + +} + +void GeneralPanel::on_spinBoxAngularFactor_valueChanged(double arg1) +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + + if (stressSolver) + { + stressSolver->angularFactor = arg1; + } +} + +void GeneralPanel::on_spinBoxMeanError_valueChanged(double arg1) +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + + if (stressSolver) + { + stressSolver->meanError = arg1; + } +} + +void GeneralPanel::on_spinBoxVarianceError_valueChanged(double arg1) +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + + if (stressSolver) + { + stressSolver->varianceError = arg1; + } +} + +void GeneralPanel::on_spinBoxBondsPerFrame_valueChanged(int arg1) +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + + if (stressSolver) + { + stressSolver->bondsPerFrame = arg1; + } +} + +void GeneralPanel::on_spinBoxBondsIterations_valueChanged(int arg1) +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + + if (stressSolver) + { + stressSolver->bondsIterations = arg1; + } +} + +BPPStressSolver* GeneralPanel::_getCurrentStressSolver() +{ + int currentUserPreset = ui->comboBoxUserPreset->currentIndex(); + + if (-1 != currentUserPreset) + { + std::vector<StressSolverUserPreset>& presets = BlastProject::ins().getUserPresets(); + return &(presets[currentUserPreset].stressSolver); + } + else + { + std::vector<BPPAsset*> assets = BlastProject::ins().getSelectedBlastAssets(); + + if (assets.size() > 0) + { + return &(assets[0]->stressSolver); + } + } + + return nullptr; +} + +BPPStressSolver* GeneralPanel::_getUserPreset(const char* name) +{ + std::vector<StressSolverUserPreset>& presets = BlastProject::ins().getUserPresets(); + + for (size_t i = 0; i < presets.size(); ++i) + { + if (presets[i].name == name) + return &(presets[i].stressSolver); + } + + return nullptr; +} + +void GeneralPanel::_updateStressSolverUIs() +{ + BPPStressSolver* stressSolver = _getCurrentStressSolver(); + if (stressSolver != nullptr) + { + ui->comboBoxSolverMode->setCurrentIndex(stressSolver->solverMode); + ui->spinBoxLinearFactor->setValue(stressSolver->linearFactor); + ui->spinBoxAngularFactor->setValue(stressSolver->angularFactor); + ui->spinBoxMeanError->setValue(stressSolver->meanError); + ui->spinBoxVarianceError->setValue(stressSolver->varianceError); + ui->spinBoxBondsPerFrame->setValue(stressSolver->bondsPerFrame); + ui->spinBoxBondsIterations->setValue(stressSolver->bondsIterations); + } + else + { + BPPStressSolver noStressSolver; + init(noStressSolver); + + ui->comboBoxSolverMode->setCurrentIndex(noStressSolver.solverMode); + ui->spinBoxLinearFactor->setValue(noStressSolver.linearFactor); + ui->spinBoxAngularFactor->setValue(noStressSolver.angularFactor); + ui->spinBoxMeanError->setValue(noStressSolver.meanError); + ui->spinBoxVarianceError->setValue(noStressSolver.varianceError); + ui->spinBoxBondsPerFrame->setValue(noStressSolver.bondsPerFrame); + ui->spinBoxBondsIterations->setValue(noStressSolver.bondsIterations); + } + +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/GeneralPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/GeneralPanel.h new file mode 100644 index 0000000..a7a52e3 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/GeneralPanel.h @@ -0,0 +1,52 @@ +#ifndef GENERALPANEL_H +#define GENERALPANEL_H + +#include <QtWidgets/QWidget> +#include "ProjectParams.h" + +namespace Ui { +class GeneralPanel; +} + +class GeneralPanel : public QWidget +{ + Q_OBJECT + +public: + explicit GeneralPanel(QWidget *parent = 0); + ~GeneralPanel(); + void updateValues(); + +private slots: + void on_comboBoxUserPreset_currentIndexChanged(int index); + + void on_btnAddUserPreset_clicked(); + + void on_btnModifyUserPreset_clicked(); + + void on_btnSaveUserPreset_clicked(); + + void on_comboBoxSolverMode_currentIndexChanged(int index); + + void on_spinBoxLinearFactor_valueChanged(double arg1); + + void on_spinBoxAngularFactor_valueChanged(double arg1); + + void on_spinBoxMeanError_valueChanged(double arg1); + + void on_spinBoxVarianceError_valueChanged(double arg1); + + void on_spinBoxBondsPerFrame_valueChanged(int arg1); + + void on_spinBoxBondsIterations_valueChanged(int arg1); + +private: + BPPStressSolver* _getCurrentStressSolver(); + BPPStressSolver* _getUserPreset(const char* name); + void _updateStressSolverUIs(); + +private: + Ui::GeneralPanel *ui; +}; + +#endif // GENERALPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialAssignmentsPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialAssignmentsPanel.cpp new file mode 100644 index 0000000..6095f67 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialAssignmentsPanel.cpp @@ -0,0 +1,265 @@ +#include "MaterialAssignmentsPanel.h" +#include "ui_MaterialAssignmentsPanel.h" +#include "ProjectParams.h" +#include "RenderMaterial.h" +#include "SampleManager.h" +#include "MaterialLibraryPanel.h" + +MaterialAssignmentsPanel* pMaterialAssignmentsPanel = nullptr; +MaterialAssignmentsPanel* MaterialAssignmentsPanel::ins() +{ + return pMaterialAssignmentsPanel; +} + +MaterialAssignmentsPanel::MaterialAssignmentsPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::MaterialAssignmentsPanel), + _selectedGraphicsMesh(-1) +{ + ui->setupUi(this); + pMaterialAssignmentsPanel = this; + m_bValid = true; +} + +void MaterialAssignmentsPanel::getMaterialNameAndPaths(std::vector<std::string>& materialNames, std::vector<std::string>& materialPaths) +{ + QString m1 = ui->comboBoxMaterialID1->currentText(); + QString m2 = ui->comboBoxMaterialID2->currentText(); + std::string name1 = m1.toUtf8().data(); + std::string name2 = m2.toUtf8().data(); + std::string path1 = ""; + std::string path2 = ""; + + BPParams& projectParams = BlastProject::ins().getParams(); + BPPGraphicsMaterialArray& theArray = projectParams.graphicsMaterials; + int count = theArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPGraphicsMaterial& item = theArray.buf[i]; + std::string name = item.name.buf; + std::string path = item.diffuseTextureFilePath.buf; + if (name1 == name) + { + path1 = path; + } + else if (name2 == name) + { + path2 = path; + } + else if (path1 != "" && path2 != "") + { + break; + } + } + + materialNames.push_back(name1); + materialNames.push_back(name2); + materialPaths.push_back(path1); + materialPaths.push_back(path2); +} + +MaterialAssignmentsPanel::~MaterialAssignmentsPanel() +{ + delete ui; +} + +void MaterialAssignmentsPanel::updateValues() +{ + m_bValid = false; + ui->comboBoxMaterialID1->clear(); + ui->comboBoxMaterialID2->clear(); + m_bValid = true; + + QStringList materialNames; + materialNames.append("None"); + BPParams& projectParams = BlastProject::ins().getParams(); + BPPGraphicsMaterialArray& theArray = projectParams.graphicsMaterials; + int count = theArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + BPPGraphicsMaterial& item = theArray.buf[i]; + materialNames.append(item.name.buf); + } + + m_bValid = false; + ui->comboBoxMaterialID1->insertItems(0, materialNames); + ui->comboBoxMaterialID2->insertItems(0, materialNames); + m_bValid = true; + + SampleManager* pSampleManager = SampleManager::ins(); + if (pSampleManager == nullptr) + { + return; + } + + BlastAsset* pBlastAsset = nullptr; + int index = -1; + pSampleManager->getCurrentSelectedInstance(&pBlastAsset, index); + if (pBlastAsset == nullptr || index == -1) + { + return; + } + + RenderMaterial* pRenderMaterial[] = { nullptr, nullptr }; + std::string strMaterialNames[] = { "None", "None" }; + bool ex[] = { true, false }; + for (int i = 0; i < 2; i++) + { + pSampleManager->getMaterialForCurrentFamily(&pRenderMaterial[i], ex[i]); + if (pRenderMaterial[i] != nullptr) + { + std::string m = pRenderMaterial[i]->getMaterialName(); + if (m != "") + { + strMaterialNames[i] = m; + } + } + } + + m_bValid = false; + ui->comboBoxMaterialID1->setCurrentText(strMaterialNames[0].c_str()); + ui->comboBoxMaterialID2->setCurrentText(strMaterialNames[1].c_str()); + m_bValid = true; + + return; + + if (_selectedGraphicsMesh > -1) + { + BPParams& projectParams = BlastProject::ins().getParams(); + BPPBlast& blast = projectParams.blast; + BPPGraphicsMaterialArray& graphicsMaterialsArray = projectParams.graphicsMaterials; + + BPPMaterialAssignments& assignment = blast.graphicsMeshes.buf[_selectedGraphicsMesh].materialAssignments; + + ui->comboBoxMaterialID1->clear(); + ui->comboBoxMaterialID2->clear(); + ui->comboBoxMaterialID3->clear(); + ui->comboBoxMaterialID4->clear(); + + QStringList materialNames; + materialNames.append("None"); + int count = graphicsMaterialsArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + materialNames.append(graphicsMaterialsArray.buf[i].name.buf); + } + + ui->comboBoxMaterialID1->insertItems(0, materialNames); + ui->comboBoxMaterialID2->insertItems(0, materialNames); + ui->comboBoxMaterialID3->insertItems(0, materialNames); + ui->comboBoxMaterialID4->insertItems(0, materialNames); + + ui->comboBoxMaterialID1->setCurrentIndex(assignment.materialIndexes[0] + 1); + ui->comboBoxMaterialID2->setCurrentIndex(assignment.materialIndexes[1] + 1); + ui->comboBoxMaterialID3->setCurrentIndex(assignment.materialIndexes[2] + 1); + ui->comboBoxMaterialID4->setCurrentIndex(assignment.materialIndexes[3] + 1); + } + + +} + +void MaterialAssignmentsPanel::on_comboBoxMaterialID1_currentIndexChanged(int index) +{ + if (index < 0 || !m_bValid) + return; + + RenderMaterial* pRenderMaterial = nullptr; + + QString currentText = ui->comboBoxMaterialID1->currentText(); + std::string name = currentText.toUtf8().data(); + + SampleManager* pSampleManager = SampleManager::ins(); + if (pSampleManager == nullptr) + { + return; + } + std::map<std::string, RenderMaterial*>& renderMaterials = pSampleManager->getRenderMaterials(); + std::map<std::string, RenderMaterial*>::iterator it = renderMaterials.find(name); + if (it != renderMaterials.end()) + { + pRenderMaterial = it->second; + } + else + { + MaterialLibraryPanel* pMaterialLibraryPanel = MaterialLibraryPanel::ins(); + std::map<std::string, RenderMaterial*>& renderMaterials2 = pMaterialLibraryPanel->getRenderMaterials(); + it = renderMaterials2.find(name); + if (it != renderMaterials2.end()) + { + pRenderMaterial = it->second; + } + } + + pSampleManager->setMaterialForCurrentFamily(pRenderMaterial, true); + + return; + assignMaterialToMaterialID(0, index - 1); +} + +void MaterialAssignmentsPanel::on_comboBoxMaterialID2_currentIndexChanged(int index) +{ + if (index < 0 || !m_bValid) + return; + + RenderMaterial* pRenderMaterial = nullptr; + + QString currentText = ui->comboBoxMaterialID2->currentText(); + std::string name = currentText.toUtf8().data(); + + SampleManager* pSampleManager = SampleManager::ins(); + if (pSampleManager == nullptr) + { + return; + } + std::map<std::string, RenderMaterial*>& renderMaterials = pSampleManager->getRenderMaterials(); + std::map<std::string, RenderMaterial*>::iterator it = renderMaterials.find(name); + if (it != renderMaterials.end()) + { + pRenderMaterial = it->second; + } + else + { + MaterialLibraryPanel* pMaterialLibraryPanel = MaterialLibraryPanel::ins(); + std::map<std::string, RenderMaterial*>& renderMaterials2 = pMaterialLibraryPanel->getRenderMaterials(); + it = renderMaterials2.find(name); + if (it != renderMaterials2.end()) + { + pRenderMaterial = it->second; + } + } + + pSampleManager->setMaterialForCurrentFamily(pRenderMaterial, false); + + return; + assignMaterialToMaterialID(1, index - 1); +} + +void MaterialAssignmentsPanel::on_comboBoxMaterialID3_currentIndexChanged(int index) +{ + assignMaterialToMaterialID(2, index - 1); +} + +void MaterialAssignmentsPanel::on_comboBoxMaterialID4_currentIndexChanged(int index) +{ + assignMaterialToMaterialID(3, index - 1); +} + +void MaterialAssignmentsPanel::assignMaterialToMaterialID(int materialID, int materialIndex) +{ + if (materialID < 0 || materialID > 3 || materialIndex < 0) + return; + + BPParams& projectParams = BlastProject::ins().getParams(); + BPPGraphicsMaterialArray& graphicsMaterialArray = projectParams.graphicsMaterials; + BPPBlast& blast = projectParams.blast; + + if (materialIndex >= graphicsMaterialArray.arraySizes[0]) + return; + + BPPGraphicsMeshArray& graphicsMeshArray = blast.graphicsMeshes; + + if (_selectedGraphicsMesh > -1 && _selectedGraphicsMesh < graphicsMeshArray.arraySizes[0]) + { + graphicsMeshArray.buf[_selectedGraphicsMesh].materialAssignments.materialIndexes[materialID] = materialIndex; + } +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialAssignmentsPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialAssignmentsPanel.h new file mode 100644 index 0000000..782baa8 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialAssignmentsPanel.h @@ -0,0 +1,40 @@ +#ifndef MATERIALASSIGNMENTSPANEL_H +#define MATERIALASSIGNMENTSPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class MaterialAssignmentsPanel; +} + +class MaterialAssignmentsPanel : public QWidget +{ + Q_OBJECT + +public: + explicit MaterialAssignmentsPanel(QWidget *parent = 0); + ~MaterialAssignmentsPanel(); + void updateValues(); + + static MaterialAssignmentsPanel* ins(); + void getMaterialNameAndPaths(std::vector<std::string>& materialNames, std::vector<std::string>& materialPaths); + +private slots: + void on_comboBoxMaterialID1_currentIndexChanged(int index); + + void on_comboBoxMaterialID2_currentIndexChanged(int index); + + void on_comboBoxMaterialID3_currentIndexChanged(int index); + + void on_comboBoxMaterialID4_currentIndexChanged(int index); + +private: + void assignMaterialToMaterialID(int materialID, int materialIndex); + +private: + Ui::MaterialAssignmentsPanel *ui; + int _selectedGraphicsMesh; + bool m_bValid; +}; + +#endif // MATERIALASSIGNMENTSPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialLibraryPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialLibraryPanel.cpp new file mode 100644 index 0000000..963326c --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialLibraryPanel.cpp @@ -0,0 +1,473 @@ +#include "MaterialLibraryPanel.h" +#include "ui_MaterialLibraryPanel.h" +#include <QtCore/QFileInfo> +#include <QtWidgets/QInputDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QMessageBox> +#include "QtUtil.h" +#include "AppMainWindow.h" +#include "SimpleScene.h" +#include "RenderMaterial.h" +#include "ResourceManager.h" +#include "SampleManager.h" +#include "MaterialAssignmentsPanel.h" +#include "Renderable.h" +enum ETextureType +{ + eDiffuseTexture, + eSpecularTexture, + eNormalTexture +}; + +void OnTextureButtonClicked(BPPGraphicsMaterial& material, ETextureType t, QPushButton* pButton) +{ + QString texName = AppMainWindow::Inst().OpenTextureFile(); + + QFileInfo fileInfo(texName); + QByteArray ba = fileInfo.absoluteFilePath().toLocal8Bit(); + const char* filePath = (const char*)(ba); + + switch (t) + { + case eDiffuseTexture: + copy(material.diffuseTextureFilePath, filePath); + break; + case eSpecularTexture: + copy(material.specularTextureFilePath, filePath); + break; + case eNormalTexture: + copy(material.normalTextureFilePath, filePath); + break; + } + + if (texName.isEmpty()) + pButton->setIcon(QIcon(":/AppMainWindow/images/TextureEnabled_icon.png")); + else + pButton->setIcon(QIcon(":/AppMainWindow/images/TextureIsUsed_icon.png")); + + SimpleScene::Inst()->SetFurModified(true); +} + +void OnTextureReload(BPPGraphicsMaterial& material, ETextureType t, QPushButton* pButton) +{ + QString texName; + switch (t) + { + case eDiffuseTexture: + texName = material.diffuseTextureFilePath.buf; + // to do: reload texture + break; + case eSpecularTexture: + texName = material.specularTextureFilePath.buf; + // to do: reload texture + break; + case eNormalTexture: + texName = material.normalTextureFilePath.buf; + // to do: reload texture + break; + } + + if (texName.isEmpty()) + pButton->setIcon(QIcon(":/AppMainWindow/images/TextureEnabled_icon.png")); + else + pButton->setIcon(QIcon(":/AppMainWindow/images/TextureIsUsed_icon.png")); + + SimpleScene::Inst()->SetFurModified(true); +} + +void OnTextureClear(BPPGraphicsMaterial& material, ETextureType t, QPushButton* pButton) +{ + switch (t) + { + case eDiffuseTexture: + freeString(material.diffuseTextureFilePath); + // to do: clear texture + break; + case eSpecularTexture: + freeString(material.specularTextureFilePath); + // to do: clear texture + break; + case eNormalTexture: + freeString(material.normalTextureFilePath); + // to do: clear texture + break; + } + + pButton->setIcon(QIcon(":/AppMainWindow/images/TextureEnabled_icon.png")); + + SimpleScene::Inst()->SetFurModified(true); +} + +MaterialLibraryPanel* pMaterialLibraryPanel = nullptr; +MaterialLibraryPanel* MaterialLibraryPanel::ins() +{ + return pMaterialLibraryPanel; +} + +void MaterialLibraryPanel::addMaterial(std::string materialName, std::string diffuseTexture) +{ + if (!BlastProject::ins().isGraphicsMaterialNameExist(materialName.c_str())) + { + BlastProject::ins().addGraphicsMaterial(materialName.c_str(), diffuseTexture.c_str()); + updateValues(); + ui->listWidget->setCurrentRow(ui->listWidget->count() - 1); + } +} + +void MaterialLibraryPanel::removeMaterial(std::string name) +{ + BlastProject::ins().removeGraphicsMaterial(name.c_str()); + updateValues(); + ui->listWidget->setCurrentRow(ui->listWidget->count() - 1); +} + +void MaterialLibraryPanel::deleteMaterials() +{ + std::vector<std::string>::iterator itStr; + std::vector<Renderable*>::iterator itRenderable; + + for (itStr = m_NeedDeleteRenderMaterials.begin(); itStr != m_NeedDeleteRenderMaterials.end(); itStr++) + { + std::string materialName = *itStr; + RenderMaterial* pRenderMaterial = m_RenderMaterialMap[materialName]; + std::vector<Renderable*>& renderables = pRenderMaterial->getRelatedRenderables(); + for (itRenderable = renderables.begin(); itRenderable != renderables.end(); itRenderable++) + { + Renderable* pRenderable = *itRenderable; + pRenderable->setMaterial(*RenderMaterial::getDefaultRenderMaterial()); + } + + std::map<std::string, RenderMaterial*>::iterator it = m_RenderMaterialMap.find(materialName); + if (it != m_RenderMaterialMap.end()) + { + m_RenderMaterialMap.erase(it); + MaterialLibraryPanel::ins()->removeMaterial(materialName); + } + } + + m_NeedDeleteRenderMaterials.clear(); +} + +MaterialLibraryPanel::MaterialLibraryPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::MaterialLibraryPanel) +{ + ui->setupUi(this); + + pMaterialLibraryPanel = this; +} + +MaterialLibraryPanel::~MaterialLibraryPanel() +{ + delete ui; +} + +void MaterialLibraryPanel::updateValues() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPGraphicsMaterialArray& graphicsMaterialArray = projectParams.graphicsMaterials; + + ui->listWidget->clear(); + QStringList materialNames; + int count = graphicsMaterialArray.arraySizes[0]; + for (int i = 0; i < count; ++i) + { + materialNames.append(graphicsMaterialArray.buf[i].name.buf); + } + ui->listWidget->addItems(materialNames); + + if (count > 0) + { + ui->btnModifyMat->setEnabled(true); + ui->btnRemoveMat->setEnabled(true); + } + else + { + ui->btnModifyMat->setEnabled(false); + ui->btnRemoveMat->setEnabled(false); + } + + MaterialAssignmentsPanel::ins()->updateValues(); +} + +void MaterialLibraryPanel::on_btnAddMat_clicked() +{ + bool ok = false; + QString name = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input name for new graphics material:"), + QLineEdit::Normal, + "", + &ok); + bool nameExist = BlastProject::ins().isGraphicsMaterialNameExist(name.toUtf8().data()); + if (ok && !name.isEmpty() && !nameExist) + { + ResourceManager* pResourceManager = ResourceManager::ins(); + std::string strName = name.toUtf8().data(); + RenderMaterial* pRenderMaterial = new RenderMaterial(strName.c_str(), *pResourceManager, "model_simple_textured_ex"); + m_RenderMaterialMap[strName] = pRenderMaterial; + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && name.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the new graphics material!"); + } +} + +void MaterialLibraryPanel::on_btnModifyMat_clicked() +{ + QList<QListWidgetItem*> items = ui->listWidget->selectedItems(); + if (items.size() == 0) + { + SampleManager::ins()->output("please select a material first !"); + return; + } + QByteArray tmp = items.at(0)->text().toUtf8(); + const char* oldName = tmp.data(); + + bool ok = false; + QString newName = QInputDialog::getText(this, + tr("Blast Tool"), + tr("Please input new name for the selected graphics material:"), + QLineEdit::Normal, + oldName, + &ok); + bool nameExist = BlastProject::ins().isGraphicsMaterialNameExist(newName.toUtf8().data()); + if (ok && !newName.isEmpty() && !nameExist) + { + std::string strOldName = oldName; + std::string strNewName = newName.toUtf8().data(); + + std::map<std::string, RenderMaterial*>::iterator it = m_RenderMaterialMap.find(strOldName); + if (it != m_RenderMaterialMap.end()) + { + RenderMaterial* pRenderMaterial = it->second; + m_RenderMaterialMap.erase(it); + m_RenderMaterialMap[strNewName] = pRenderMaterial; + } + + SampleManager::ins()->renameRenderMaterial(strOldName, strNewName); + + BlastProject::ins().renameGraphicsMaterial(oldName, newName.toUtf8().data()); + updateValues(); + } + else if (ok && nameExist) + { + QMessageBox::warning(this, "Blast Tool", "The name you input is already exist!"); + } + else if (ok && newName.isEmpty()) + { + QMessageBox::warning(this, "Blast Tool", "You need input a name for the selected graphics material!"); + } +} + +void MaterialLibraryPanel::on_btnRemoveMat_clicked() +{ + QList<QListWidgetItem*> items = ui->listWidget->selectedItems(); + if (items.size() == 0) + { + SampleManager::ins()->output("please select a material first !"); + return; + } + QByteArray tem = items.at(0)->text().toUtf8(); + + std::string strName = tem.data(); + std::map<std::string, RenderMaterial*>::iterator it = m_RenderMaterialMap.find(strName); + if (it != m_RenderMaterialMap.end()) + { + m_NeedDeleteRenderMaterials.push_back(it->second->getMaterialName()); + } + else + { + SampleManager::ins()->deleteRenderMaterial(strName); + } +} + +void MaterialLibraryPanel::on_listWidget_currentRowChanged(int currentRow) +{ + _refreshMaterialValues(currentRow); +} + +void MaterialLibraryPanel::on_btnDiffuseColor_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + atcore_float4* color = (atcore_float4*)&(material->diffuseColor); + pickColor(*color); + setButtonColor(ui->btnDiffuseColor, color->x, color->y, color->z); + } +} + +void MaterialLibraryPanel::on_btnDiffuseColorTex_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureButtonClicked(*material, eDiffuseTexture, ui->btnDiffuseColorTex); + } +} + +void MaterialLibraryPanel::on_btnDiffuseColorTexReload_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureReload(*material, eDiffuseTexture, ui->btnDiffuseColorTex); + + QString qName = material->name.buf; + std::string strName = qName.toUtf8().data(); + QString qTexture = material->diffuseTextureFilePath.buf; + std::string strTexture = qTexture.toUtf8().data(); + + std::map<std::string, RenderMaterial*>& renderMaterials = SampleManager::ins()->getRenderMaterials(); + std::map<std::string, RenderMaterial*>::iterator it = renderMaterials.find(strName); + if (it != renderMaterials.end()) + { + it->second->setTextureFileName(strTexture); + } + } +} + +void MaterialLibraryPanel::on_btnDiffuseColorTexClear_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureClear(*material, eDiffuseTexture, ui->btnDiffuseColorTex); + + QString qName = material->name.buf; + std::string strName = qName.toUtf8().data(); + QString qTexture = material->diffuseTextureFilePath.buf; + std::string strTexture = qTexture.toUtf8().data(); + + std::map<std::string, RenderMaterial*>& renderMaterials = SampleManager::ins()->getRenderMaterials(); + std::map<std::string, RenderMaterial*>::iterator it = renderMaterials.find(strName); + if (it != renderMaterials.end()) + { + it->second->setTextureFileName(strTexture); + } + } +} + +void MaterialLibraryPanel::on_btnSpecularColor_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + atcore_float4* color = (atcore_float4*)&(material->specularColor); + pickColor(*color); + setButtonColor(ui->btnSpecularColor, color->x, color->y, color->z); + } +} + +void MaterialLibraryPanel::on_btnSpecularColorTex_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureButtonClicked(*material, eSpecularTexture, ui->btnSpecularColorTex); + } +} + +void MaterialLibraryPanel::on_btnSpecularColorTexReload_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureReload(*material, eSpecularTexture, ui->btnSpecularColorTex); + } +} + +void MaterialLibraryPanel::on_btnSpecularColorTexClear_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureClear(*material, eSpecularTexture, ui->btnSpecularColorTex); + } +} + +void MaterialLibraryPanel::on_spinSpecularShin_valueChanged(double arg1) +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + material->specularShininess = (float)arg1; + } +} + +void MaterialLibraryPanel::on_btnNormalColorTex_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureButtonClicked(*material, eNormalTexture, ui->btnNormalColorTex); + } +} + +void MaterialLibraryPanel::on_btnNormalColorTexReload_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureReload(*material, eNormalTexture, ui->btnNormalColorTex); + } +} + +void MaterialLibraryPanel::on_btnNormalColorTexClear_clicked() +{ + BPPGraphicsMaterial* material = _getSelectedMaterial(); + if (material) + { + OnTextureClear(*material, eNormalTexture, ui->btnNormalColorTex); + } +} + +void MaterialLibraryPanel::_refreshMaterialValues(int idx) +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPGraphicsMaterialArray& graphicsMaterialArray = projectParams.graphicsMaterials; + int count = graphicsMaterialArray.arraySizes[0]; + if (idx >= 0 && idx < count) + { + const BPPGraphicsMaterial& material = graphicsMaterialArray.buf[idx]; + + ui->spinSpecularShin->setValue(material.specularShininess); + + const nvidia::NvVec4& diffuseColor = material.diffuseColor; + const nvidia::NvVec4& specularColor = material.specularColor; + setButtonColor(ui->btnDiffuseColor, diffuseColor.x, diffuseColor.y, diffuseColor.z); + setButtonColor(ui->btnSpecularColor, specularColor.x, specularColor.y, specularColor.z); + + updateTextureButton(ui->btnDiffuseColorTex, material.diffuseTextureFilePath.buf); + updateTextureButton(ui->btnSpecularColorTex, material.specularTextureFilePath.buf); + updateTextureButton(ui->btnNormalColorTex, material.normalTextureFilePath.buf); + } + else + { + ui->spinSpecularShin->setValue(0.0f); + + setButtonColor(ui->btnDiffuseColor, 0, 0, 0); + setButtonColor(ui->btnSpecularColor, 0, 0, 0); + updateTextureButton(ui->btnDiffuseColorTex, ""); + updateTextureButton(ui->btnSpecularColorTex, ""); + updateTextureButton(ui->btnNormalColorTex, ""); + } +} + +BPPGraphicsMaterial* MaterialLibraryPanel::_getSelectedMaterial() +{ + BPParams& projectParams = BlastProject::ins().getParams(); + BPPGraphicsMaterialArray& graphicsMaterialArray = projectParams.graphicsMaterials; + + int idx = ui->listWidget->currentRow(); + int count = graphicsMaterialArray.arraySizes[0]; + if (idx < 0 || idx > count) + return nullptr; + + return &(graphicsMaterialArray.buf[idx]); +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialLibraryPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialLibraryPanel.h new file mode 100644 index 0000000..5c2c970 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/MaterialLibraryPanel.h @@ -0,0 +1,72 @@ +#ifndef MATERIALLIBRARYPANEL_H +#define MATERIALLIBRARYPANEL_H + +#include <QtWidgets/QWidget> +#include "ProjectParams.h" + +class RenderMaterial; + +namespace Ui { +class MaterialLibraryPanel; +} + +class MaterialLibraryPanel : public QWidget +{ + Q_OBJECT + +public: + explicit MaterialLibraryPanel(QWidget *parent = 0); + ~MaterialLibraryPanel(); + void updateValues(); + + static MaterialLibraryPanel* ins(); + void addMaterial(std::string materialName, std::string diffuseTexture); + void removeMaterial(std::string name); + std::map<std::string, RenderMaterial*>& getRenderMaterials(){ return m_RenderMaterialMap; } + void deleteMaterials(); + +private slots: + void on_btnAddMat_clicked(); + + void on_btnModifyMat_clicked(); + + void on_btnRemoveMat_clicked(); + + void on_listWidget_currentRowChanged(int currentRow); + + void on_btnDiffuseColor_clicked(); + + void on_btnDiffuseColorTex_clicked(); + + void on_btnDiffuseColorTexReload_clicked(); + + void on_btnDiffuseColorTexClear_clicked(); + + void on_btnSpecularColor_clicked(); + + void on_btnSpecularColorTex_clicked(); + + void on_btnSpecularColorTexReload_clicked(); + + void on_btnSpecularColorTexClear_clicked(); + + void on_spinSpecularShin_valueChanged(double arg1); + + void on_btnNormalColorTex_clicked(); + + void on_btnNormalColorTexReload_clicked(); + + void on_btnNormalColorTexClear_clicked(); + +private: + void _refreshMaterialValues(int idx); + BPPGraphicsMaterial* _getSelectedMaterial(); + + std::map<std::string, RenderMaterial*> m_RenderMaterialMap; + std::vector<std::string> m_NeedDeleteRenderMaterials; + +private: + Ui::MaterialLibraryPanel *ui; +}; + +#endif // MATERIALLIBRARYPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/NoiseToolsDlg.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/NoiseToolsDlg.cpp new file mode 100644 index 0000000..748002c --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/NoiseToolsDlg.cpp @@ -0,0 +1,39 @@ +#include "NoiseToolsDlg.h" +#include "ui_NoiseToolsDlg.h" + +NoiseToolsDlg::NoiseToolsDlg(QWidget *parent) : + QDialog(parent), + ui(new Ui::NoiseToolsDlg) +{ + ui->setupUi(this); +} + +NoiseToolsDlg::~NoiseToolsDlg() +{ + delete ui; +} + +void NoiseToolsDlg::on_comboBoxApplyByMaterial_currentIndexChanged(int index) +{ + +} + +void NoiseToolsDlg::on_spinBoxAmplitude_valueChanged(double arg1) +{ + +} + +void NoiseToolsDlg::on_spinBoxFrequency_valueChanged(double arg1) +{ + +} + +void NoiseToolsDlg::on_spinBoxAmplitude_3_valueChanged(double arg1) +{ + +} + +void NoiseToolsDlg::on_btnApply_clicked() +{ + +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/NoiseToolsDlg.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/NoiseToolsDlg.h new file mode 100644 index 0000000..057dd42 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/NoiseToolsDlg.h @@ -0,0 +1,33 @@ +#ifndef NOISETOOLSDLG_H +#define NOISETOOLSDLG_H + +#include <QtWidgets/QDialog> + +namespace Ui { +class NoiseToolsDlg; +} + +class NoiseToolsDlg : public QDialog +{ + Q_OBJECT + +public: + explicit NoiseToolsDlg(QWidget *parent = 0); + ~NoiseToolsDlg(); + +private slots: + void on_comboBoxApplyByMaterial_currentIndexChanged(int index); + + void on_spinBoxAmplitude_valueChanged(double arg1); + + void on_spinBoxFrequency_valueChanged(double arg1); + + void on_spinBoxAmplitude_3_valueChanged(double arg1); + + void on_btnApply_clicked(); + +private: + Ui::NoiseToolsDlg *ui; +}; + +#endif // NOISETOOLSDLG_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/QtUtil.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/QtUtil.cpp new file mode 100644 index 0000000..b2fdd75 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/QtUtil.cpp @@ -0,0 +1,155 @@ +#include "QtUtil.h" + +#include <QtWidgets/QLabel> +#include "AppMainWindow.h" + +#include "SimpleScene.h" + +////////////////////////////////////////////////////////// +void setStyledToolTip(QPushButton *pButton, const char *tooltip) +{ + char styledString[1024]; + sprintf(styledString, "<span style=\"color:black;\">%s</span>", tooltip); + pButton->setToolTip(styledString); +} + +////////////////////////////////////////////////////////// +QString addStar(QString text, bool add) +{ + QByteArray ba = text.toUtf8(); + + const char* in = ba.data(); + char out[1024]; + + int i = 0; + for (i = 0; i < strlen(in); i++) + { + if (in[i] == '*') + break; + out[i] = in[i]; + } + out[i] = 0; + + QString newtext; + if (add) + newtext = QString((const char*)out) + QString("*"); + else + newtext = QString((const char*)out) ; + return newtext; +} + +////////////////////////////////////////////////////////// +void setFocusColor(QWidget* qWidget, bool sameAsDefault, bool sameForAllAssets) +{ + if (!qWidget) + return; + + QString sameStyle = QString("font: ; color: rgb(150,150,150);") ; + QString differentStyle = QString("font: bold; color: rgb(255,55,55);"); + QString style = (sameForAllAssets) ? sameStyle : differentStyle; + + qWidget->setStyleSheet(style); + + QLabel* label = dynamic_cast<QLabel*>(qWidget); + if (label) + { + QString newtext = addStar(label->text(), !sameAsDefault); + + label->setFrameStyle(0); + label->setText(newtext); + } +} + +////////////////////////////////////////////////////////// +void pickColor(atcore_float4& color) +{ + QColor currentColor; + currentColor.setRgbF(color.x, color.y, color.z); + + QColor newColor = QColorDialog::getColor(currentColor, NV_NULL); + if(newColor.isValid()) + { + qreal r,g,b; + newColor.getRgbF(&r, &g, &b); + + color.x = r; + color.y = g; + color.z = b; + } +} + +////////////////////////////////////////////////////////// +void setButtonColor(QPushButton *button, float r, float g, float b) +{ + QColor specColor; + specColor.setRgbF(r,g,b); + QString specBtnStyle = QString("background-color: rgb(%1,%2,%3);") + .arg(specColor.red()) + .arg(specColor.green()) + .arg(specColor.blue()); + + button->setStyleSheet(specBtnStyle); +} + + +///////////////////////////////////////////////////////////////////////////////////// +void updateColorButton(QPushButton* button, int paramID, QLabel* label) +{ + //atcore_float4 v; + //SimpleScene::Inst()->GetFurCharacter().GetHairParam(paramID, &v); + + //setButtonColor(button, v.x, v.y, v.z); + + //if (label) + // setFocusColor(label, paramID); +} + +///////////////////////////////////////////////////////////////////////////////////// +void setClearButtonIcon(QPushButton *pButton) +{ + pButton->setIcon(QIcon(":/AppMainWindow/images/Remove_icon.png")); +} + +///////////////////////////////////////////////////////////////////////////////////// +void setTextureButtons(QPushButton *pTex, QPushButton *pReload, QPushButton *pClear) +{ + pTex->setIcon(QIcon(":/AppMainWindow/images/TextureEnabled_icon.png")); + pReload->setIcon(QIcon(":/AppMainWindow/images/Refresh_icon.png")); + pClear->setIcon(QIcon(":/AppMainWindow/images/Remove_icon.png")); + + pTex->setIconSize(QSize(12,12)); + pReload->setIconSize(QSize(12,12)); + pClear->setIconSize(QSize(12,12)); +} + +///////////////////////////////////////////////////////////////////////////////////// +void updateTextureButton(QPushButton* pButton, const QString& texturePath) +{ + if (!texturePath.isEmpty()) setStyledToolTip(pButton, texturePath.toUtf8().data()); + + bool isTextureUsed = true; + QIcon notUsedIcon = QIcon(":/AppMainWindow/images/TextureEnabled_icon.png"); + QIcon isUsedIcon = QIcon(":/AppMainWindow/images/TextureIsUsed_icon.png"); + QIcon disabledIcon = QIcon(":/AppMainWindow/images/TextureDisabled_icon.png"); + + pButton->setIcon(!texturePath.isEmpty() ? isUsedIcon : notUsedIcon); +} + +/////////////////////////////////////////////////////////////////////////////////////// +//bool LoadHairTexture(NvHair::TextureType::Enum textureType) +//{ +// QString texName = AppMainWindow::Inst().OpenTextureFile(); +// return SimpleScene::Inst()->GetFurCharacter().LoadHairTexture(textureType, texName.toLocal8Bit()); +//} +// +/////////////////////////////////////////////////////////////////////////////////////// +//bool ReloadHairTexture(NvHair::TextureType::Enum textureType) +//{ +// return SimpleScene::Inst()->GetFurCharacter().ReloadHairTexture(textureType); +//} +// +/////////////////////////////////////////////////////////////////////////////////////// +//bool ClearHairTexture(NvHair::TextureType::Enum textureType) +//{ +// return SimpleScene::Inst()->GetFurCharacter().ClearHairTexture(textureType); +//} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/QtUtil.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/QtUtil.h new file mode 100644 index 0000000..2372b06 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/QtUtil.h @@ -0,0 +1,37 @@ +#ifndef QtUtil_h__ +#define QtUtil_h__ + +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtWidgets/QColorDialog> +#include <QtGui/QPalette> +#include <QtWidgets/QWidget> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QSpinBox> +#include <QtWidgets/QDoubleSpinBox> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QComboBox> +#include <QtWidgets/QLabel> +#include <QtWidgets/QSlider> +#include "corelib_global.h" + +// utility functions to quickly set and update UI + +void setStyledToolTip(QPushButton *pButton, const char *tooltip); +void pickColor(atcore_float4& color); +void setButtonColor(QPushButton *button, float r, float g, float b); + +void setFocusColor(QWidget* qWidget, bool sameAsDefault, bool sameForAllAssets); + +void updateColorButton(QPushButton* pButton, int paramID, QLabel* label = 0); + +void setTextureButtons(QPushButton *pButton, QPushButton *pReload, QPushButton *pClear); +void updateTextureButton(QPushButton* pButton, const QString& texturePath); + +void setClearButtonIcon(QPushButton *pButton); + +//bool LoadHairTexture(NvHair::TextureType::Enum textureType); +//bool ReloadHairTexture(NvHair::TextureType::Enum textureType); +//bool ClearHairTexture(NvHair::TextureType::Enum textureType); + +#endif diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SourceAssetOpenDlg.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SourceAssetOpenDlg.cpp new file mode 100644 index 0000000..db40407 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SourceAssetOpenDlg.cpp @@ -0,0 +1,82 @@ +#include "SourceAssetOpenDlg.h" +#include "ui_SourceAssetOpenDlg.h" +#include <QtWidgets/QFileDialog> +#include "AppMainWindow.h" + +SourceAssetOpenDlg::SourceAssetOpenDlg(bool bOpenBlastFile, QWidget *parent) : + QDialog(parent), + ui(new Ui::SourceAssetOpenDlg) +{ + ui->setupUi(this); + + m_bOpenBlastFile = bOpenBlastFile; + ui->buttonBox->button(QDialogButtonBox::Ok)->setFixedWidth(100); + ui->buttonBox->button(QDialogButtonBox::Cancel)->setFixedWidth(100); + ui->spinBoxDegree->setMaximum(180); + ui->spinBoxDegree->setMinimum(-180); +} + +SourceAssetOpenDlg::~SourceAssetOpenDlg() +{ + delete ui; +} + +QString SourceAssetOpenDlg::getFile() +{ + return ui->lineEditFile->text(); +} + +bool SourceAssetOpenDlg::getSkinned() +{ + return ui->checkBoxSkinned->isChecked(); +} + +QVector3D SourceAssetOpenDlg::getPosition() +{ + return QVector3D(ui->spinBoxXPosition->value(), ui->spinBoxYPosition->value(), ui->spinBoxZPosition->value()); +} + +QVector3D SourceAssetOpenDlg::getRotationAxis() +{ + return QVector3D(ui->spinBoxXAxis->value(), ui->spinBoxYAxis->value(), ui->spinBoxZAxis->value()); +} + +double SourceAssetOpenDlg::getRotationDegree() +{ + return ui->spinBoxDegree->value(); +} + +bool SourceAssetOpenDlg::isAppend() +{ + return ui->checkBoxAppend->isChecked(); +} + +void SourceAssetOpenDlg::on_btnOpenFile_clicked() +{ + QString lastDir = AppMainWindow::Inst()._lastFilePath; + QString titleStr = "Open Source Asset File"; + + QString filetype = "Source Asset (*.fbx)"; + if (m_bOpenBlastFile) + { + filetype = "Source Asset (*.bpxa)"; + } + QString fileName = QFileDialog::getOpenFileName(this, titleStr, lastDir, filetype); + if (!fileName.isEmpty()) + { + QFileInfo fileInfo(fileName); + AppMainWindow::Inst()._lastFilePath = fileInfo.absoluteDir().absolutePath(); + } + + ui->lineEditFile->setText(fileName); +} + +void SourceAssetOpenDlg::on_buttonBox_accepted() +{ + +} + +void SourceAssetOpenDlg::on_buttonBox_rejected() +{ + +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SourceAssetOpenDlg.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SourceAssetOpenDlg.h new file mode 100644 index 0000000..ec03ee9 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SourceAssetOpenDlg.h @@ -0,0 +1,38 @@ +#ifndef SOURCEASSETOPENDLG_H +#define SOURCEASSETOPENDLG_H + +#include <QtWidgets/QDialog> +#include <QtGui/QVector3D> + +namespace Ui { +class SourceAssetOpenDlg; +} + +class SourceAssetOpenDlg : public QDialog +{ + Q_OBJECT + +public: + explicit SourceAssetOpenDlg(bool bOpenBlastFile = true, QWidget *parent = 0); + ~SourceAssetOpenDlg(); + + QString getFile(); + bool getSkinned(); + QVector3D getPosition(); + QVector3D getRotationAxis(); + double getRotationDegree(); + bool isAppend(); + +private slots: + void on_btnOpenFile_clicked(); + + void on_buttonBox_accepted(); + + void on_buttonBox_rejected(); + +private: + Ui::SourceAssetOpenDlg *ui; + bool m_bOpenBlastFile; +}; + +#endif // SOURCEASSETOPENDLG_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SupportPanel.cpp b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SupportPanel.cpp new file mode 100644 index 0000000..1057402 --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SupportPanel.cpp @@ -0,0 +1,49 @@ +#include "SupportPanel.h" +#include "ui_SupportPanel.h" + +SupportPanel::SupportPanel(QWidget *parent) : + QWidget(parent), + ui(new Ui::SupportPanel) +{ + ui->setupUi(this); +} + +SupportPanel::~SupportPanel() +{ + delete ui; +} + +void SupportPanel::updateValues() +{ + +} + +void SupportPanel::on_comboBoxHealthMask_currentIndexChanged(int index) +{ + +} + +void SupportPanel::on_btnAddHealthMask_clicked() +{ + +} + +void SupportPanel::on_btnPen_clicked() +{ + +} + +void SupportPanel::on_btnRemove_clicked() +{ + +} + +void SupportPanel::on_spinBoxBondStrength_valueChanged(double arg1) +{ + +} + +void SupportPanel::on_checkBoxEnableJoint_stateChanged(int arg1) +{ + +} diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SupportPanel.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SupportPanel.h new file mode 100644 index 0000000..518d2cd --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/Window/SupportPanel.h @@ -0,0 +1,36 @@ +#ifndef SUPPORTPANEL_H +#define SUPPORTPANEL_H + +#include <QtWidgets/QWidget> + +namespace Ui { +class SupportPanel; +} + +class SupportPanel : public QWidget +{ + Q_OBJECT + +public: + explicit SupportPanel(QWidget *parent = 0); + ~SupportPanel(); + void updateValues(); + +private slots: + void on_comboBoxHealthMask_currentIndexChanged(int index); + + void on_btnAddHealthMask_clicked(); + + void on_btnPen_clicked(); + + void on_btnRemove_clicked(); + + void on_spinBoxBondStrength_valueChanged(double arg1); + + void on_checkBoxEnableJoint_stateChanged(int arg1); + +private: + Ui::SupportPanel *ui; +}; + +#endif // SUPPORTPANEL_H diff --git a/NvBlast/tools/ArtistTools/source/BlastPlugin/blastplugin_global.h b/NvBlast/tools/ArtistTools/source/BlastPlugin/blastplugin_global.h new file mode 100644 index 0000000..082519a --- /dev/null +++ b/NvBlast/tools/ArtistTools/source/BlastPlugin/blastplugin_global.h @@ -0,0 +1,11 @@ +#ifdef PLUGINBT_LIB +# define PLUGINBT_EXPORT Q_DECL_EXPORT +#else +# define PLUGINBT_EXPORT Q_DECL_IMPORT +#endif + +#ifdef PLUGINBTRENDER_LIB +# define PLUGINBTRENDER_EXPORT Q_DECL_EXPORT +#else +# define PLUGINBTRENDER_EXPORT Q_DECL_IMPORT +#endif
\ No newline at end of file |