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/samples | |
| download | blast-1.0.0-beta.tar.xz blast-1.0.0-beta.zip | |
first commitv1.0.0-beta
Diffstat (limited to 'NvBlast/samples')
100 files changed, 14634 insertions, 0 deletions
diff --git a/NvBlast/samples/CMakeLists.txt b/NvBlast/samples/CMakeLists.txt new file mode 100644 index 0000000..28c14a2 --- /dev/null +++ b/NvBlast/samples/CMakeLists.txt @@ -0,0 +1,98 @@ +cmake_minimum_required(VERSION 3.3) + +project(BlastSamples CXX) + +CMAKE_POLICY(SET CMP0057 NEW) # Enable IN_LIST + +IF(NOT DEFINED BLAST_ROOT_DIR) + + STRING(REPLACE "\\" "/" BRD_TEMP $ENV{BLAST_ROOT_DIR}) + + # This env variable is set by GenerateProjects.bat, and is no longer available when CMake rebuilds, so this stores it in the cache + SET(BLAST_ROOT_DIR ${BRD_TEMP} CACHE INTERNAL "Root of the Blast source tree") + +ENDIF() + +IF(NOT EXISTS ${BLAST_ROOT_DIR}) + MESSAGE(FATAL_ERROR "BLAST_ROOT_DIR environment variable wasn't set or was invalid.") +ENDIF() + +SET(GW_DEPS_ROOT $ENV{PM_PACKAGES_ROOT}) + +# Add the project specific CMake modules to the module path +LIST(APPEND CMAKE_MODULE_PATH ${BLAST_ROOT_DIR}/sdk/compiler/cmake/modules/) + +IF(NOT DEFINED CMAKEMODULES_VERSION) + SET(CMAKEMODULES_VERSION $ENV{PM_CMakeModules_VERSION} CACHE INTERNAL "CMakeModules version from generation batch") +ENDIF() + +#TODO: More elegance +IF(NOT EXISTS ${GW_DEPS_ROOT}/CMakeModules/${CMAKEMODULES_VERSION}) + MESSAGE(FATAL_ERROR "Could not find CMakeModules at ${GW_DEPS_ROOT}") +ENDIF() + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${GW_DEPS_ROOT}/CMakeModules/${CMAKEMODULES_VERSION}") + +MESSAGE("Module path:" ${CMAKE_MODULE_PATH}) + + +IF(CMAKE_CONFIGURATION_TYPES) + SET(CMAKE_CONFIGURATION_TYPES debug profile checked release) + SET(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING + "Reset config to what we need" + FORCE) + + SET(CMAKE_SHARED_LINKER_FLAGS_CHECKED "") + SET(CMAKE_SHARED_LINKER_FLAGS_PROFILE "") + + SET(CMAKE_EXE_LINKER_FLAGS_CHECKED "") + SET(CMAKE_EXE_LINKER_FLAGS_PROFILE "") + +ENDIF() + +# Default to appending "DEBUG", "PROFILE", etc to produced artifacts +IF(NOT DEFINED APPEND_CONFIG_NAME) + SET(APPEND_CONFIG_NAME ON) +ENDIF() + +IF (APPEND_CONFIG_NAME) + MESSAGE("Appending config to output names") + + SET(CMAKE_DEBUG_POSTFIX "DEBUG") + SET(CMAKE_PROFILE_POSTFIX "PROFILE") + SET(CMAKE_CHECKED_POSTFIX "CHECKED") + SET(CMAKE_RELEASE_POSTFIX "") +ENDIF() + +INCLUDE(SetOutputPaths) + +# Either have to define a single output path, or each one. + +IF(NOT DEFINED BL_OUTPUT_DIR) + IF (NOT DEFINED BL_LIB_OUTPUT_DIR) + MESSAGE(FATAL_ERROR "BL_LIB_OUTPUT_DIR not defined - Define either BL_OUTPUT_DIR or BL_LIB_OUTPUT_DIR and BL_DLL_OUTPUT_DIR and BL_EXE_OUTPUT_DIR") + ENDIF() + + IF (NOT DEFINED BL_DLL_OUTPUT_DIR) + MESSAGE(FATAL_ERROR "BL_DLL_OUTPUT_DIR not defined - Define either BL_OUTPUT_DIR or BL_LIB_OUTPUT_DIR and BL_DLL_OUTPUT_DIR and BL_EXE_OUTPUT_DIR") + ENDIF() + + IF (NOT DEFINED BL_EXE_OUTPUT_DIR) + MESSAGE(FATAL_ERROR "BL_EXE_OUTPUT_DIR not defined - Define either BL_OUTPUT_DIR or BL_LIB_OUTPUT_DIR and BL_DLL_OUTPUT_DIR and BL_EXE_OUTPUT_DIR") + ENDIF() + + SetLibOutputPath(${BL_LIB_OUTPUT_DIR}) + SetDllOutputPath(${BL_DLL_OUTPUT_DIR}) + SetExeOutputPath(${BL_EXE_OUTPUT_DIR}) +ELSE() + SetSingleOutputPath(${BL_OUTPUT_DIR}) +ENDIF() + +SET(PROJECT_CMAKE_FILES_DIR compiler/cmake/) + +# Should this be here or in the common part? +#ADD_SUBDIRECTORY(${BLAST_ROOT_DIR}/sdk "${CMAKE_CURRENT_BINARY_DIR}/blast_bin") + + +# Include the platform specific configuration +INCLUDE(${PROJECT_CMAKE_FILES_DIR}${TARGET_BUILD_PLATFORM}/CMakeLists.txt OPTIONAL) diff --git a/NvBlast/samples/SampleAssetViewer/Main.cpp b/NvBlast/samples/SampleAssetViewer/Main.cpp new file mode 100644 index 0000000..fca0339 --- /dev/null +++ b/NvBlast/samples/SampleAssetViewer/Main.cpp @@ -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. +*/ + +#include "Sample.h" +#include "tclap/CmdLine.h" +#include <sstream> + +#include <Windows.h> + + +#define DEFAULT_ASSET_LIST "assets.xml" + +struct TCLAPvec3 +{ + float x, y, z; + TCLAPvec3() :x(0), y(0), z(0){}; + TCLAPvec3& operator=(const std::string &inp) + { + std::istringstream stream(inp); + if (!(stream >> x >> y >> z)) + throw TCLAP::ArgParseException(inp + " is not vec3"); + return *this; + } +}; + +struct TCLAPvec4 +{ + float x, y, z, w; + TCLAPvec4() :x(0), y(0), z(0), w(0){}; + TCLAPvec4& operator=(const std::string &inp) + { + std::istringstream stream(inp); + if (!(stream >> x >> y >> z >> w)) + throw TCLAP::ArgParseException(inp + " is not vec4"); + return *this; + } +}; + +namespace TCLAP { + template<> + struct ArgTraits<TCLAPvec3> { + typedef StringLike ValueCategory; + }; + template<> + struct ArgTraits<TCLAPvec4> { + typedef StringLike ValueCategory; + }; +} + +using namespace std; +using namespace physx; + +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) +{ + PX_UNUSED(hInstance); + PX_UNUSED(hPrevInstance); + PX_UNUSED(lpCmdLine); + PX_UNUSED(nCmdShow); + + // Enable run-time memory check for debug builds. +#if defined(DEBUG) | defined(_DEBUG) + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + AllocConsole(); +#endif + + + LPWSTR* argv; + int argc; + argv = CommandLineToArgvW(GetCommandLineW(), &argc); + TCLAP::CmdLine cmd("Blast Sample: Asset Viewer", ' ', "0.1"); + TCLAP::ValueArg<std::string> inpXmlArg("x", "xml", "Asset list to load", false, DEFAULT_ASSET_LIST, "inassetlist"); + cmd.add(inpXmlArg); + TCLAP::ValueArg<std::string> alternatePathArg("t", "path", "Alternate path", false, "", "altPath"); + cmd.add(alternatePathArg); + + TCLAP::ValueArg<std::string> addAssetArg("n", "nAsset", "Additional asset to load", false, "", "additionalAsset"); + cmd.add(addAssetArg); + + TCLAP::ValueArg<TCLAPvec4> rotationArg("r", "rot", "Additional asset rotation", false, TCLAPvec4(), "rotation"); + cmd.add(rotationArg); + TCLAP::ValueArg<TCLAPvec3> positionArg("p", "pos", "Additional asset position", false, TCLAPvec3(), "position"); + cmd.add(positionArg); + + + PxVec3 transform; + bool addedExternalAsset = false; + + std::vector<string> argsVect; + if (argc > 1) + { + for (size_t i = 0; i < (size_t)argc; ++i) + { + argsVect.push_back(string()); + argsVect.back().resize(wcslen(argv[i]), 0); + wcstombs(&argsVect.back()[0], argv[i], 255); + } + cmd.parse(argsVect); + } + LocalFree(argv); + + SampleConfig config; + config.assetsFile = inpXmlArg.getValue(); + config.sampleName = L"Blast Sample: Asset Viewer"; + + config.assetsFile = inpXmlArg.getValue(); + if (alternatePathArg.isSet()) + { + config.additionalResourcesDir.push_back(alternatePathArg.getValue().c_str()); + } + if (addAssetArg.isSet()) + { + AssetList::ModelAsset asset; + TCLAPvec3 p = positionArg.getValue(); + TCLAPvec4 r = rotationArg.getValue(); + asset.transform.p = PxVec3(p.x, p.y, p.z); + asset.transform.q = PxQuat(r.w, PxVec3(r.x, r.y, r.z).getNormalized()); + asset.name = addAssetArg.getValue(); + asset.id = asset.name; + config.additionalAssetList.models.push_back(asset); + } + + int result = runSample(config); + + return result; +} diff --git a/NvBlast/samples/SampleBase/Sample.h b/NvBlast/samples/SampleBase/Sample.h new file mode 100644 index 0000000..c9fa503 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastAsset.cpp b/NvBlast/samples/SampleBase/blast/BlastAsset.cpp new file mode 100644 index 0000000..b3b5d84 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastAsset.cpp @@ -0,0 +1,28 @@ +/* +* 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" + + +BlastAsset::BlastAsset(Renderer& renderer) + : m_renderer(renderer) +{ +} + +void BlastAsset::validate() +{ +} + +size_t BlastAsset::getBlastAssetSize() const +{ + return m_pxAsset->getTkAsset().getDataSize(); +} diff --git a/NvBlast/samples/SampleBase/blast/BlastAsset.h b/NvBlast/samples/SampleBase/blast/BlastAsset.h new file mode 100644 index 0000000..4740791 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastAsset.h @@ -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. +*/ + +#ifndef BLAST_ASSET_H +#define BLAST_ASSET_H + +#include <memory> +#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; + +typedef std::shared_ptr<BlastFamily> BlastFamilyPtr; + + +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; + + +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/samples/SampleBase/blast/BlastAssetBoxes.cpp b/NvBlast/samples/SampleBase/blast/BlastAssetBoxes.cpp new file mode 100644 index 0000000..dfa0138 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastAssetBoxes.h b/NvBlast/samples/SampleBase/blast/BlastAssetBoxes.h new file mode 100644 index 0000000..518e93d --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastAssetModel.cpp b/NvBlast/samples/SampleBase/blast/BlastAssetModel.cpp new file mode 100644 index 0000000..c42215e --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastAssetModel.h b/NvBlast/samples/SampleBase/blast/BlastAssetModel.h new file mode 100644 index 0000000..03045d4 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastAssetModel.h @@ -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. +*/ + +#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 + { + return *m_model.get(); + } + +private: + //////// private internal data //////// + + BlastModelPtr m_model; +}; + +#endif //BLAST_ASSET_MODEL_H
\ No newline at end of file diff --git a/NvBlast/samples/SampleBase/blast/BlastAssetModelSimple.cpp b/NvBlast/samples/SampleBase/blast/BlastAssetModelSimple.cpp new file mode 100644 index 0000000..fa423e2 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastAssetModelSimple.cpp @@ -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. +*/ + + +#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 + for (const BlastModel::Material& material : getModel().materials) + { + if (material.diffuseTexture.empty()) + m_renderMaterials.push_back(new RenderMaterial(renderer.getResourceManager(), "model_simple")); + else + m_renderMaterials.push_back(new RenderMaterial(renderer.getResourceManager(), "model_simple_textured", material.diffuseTexture.c_str())); + } + + validate(); +} + + +BlastAssetModelSimple::~BlastAssetModelSimple() +{ + // release materials + for (RenderMaterial* r : m_renderMaterials) + { + 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/samples/SampleBase/blast/BlastAssetModelSimple.h b/NvBlast/samples/SampleBase/blast/BlastAssetModelSimple.h new file mode 100644 index 0000000..7e61616 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastAssetModelSkinned.cpp b/NvBlast/samples/SampleBase/blast/BlastAssetModelSkinned.cpp new file mode 100644 index 0000000..6b96580 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastAssetModelSkinned.cpp @@ -0,0 +1,42 @@ +/* +* 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) +{ + for (const BlastModel::Material& material : getModel().materials) + { + if (material.diffuseTexture.empty()) + m_renderMaterials.push_back(new RenderMaterial(renderer.getResourceManager(), "model_skinned")); + else + m_renderMaterials.push_back(new RenderMaterial(renderer.getResourceManager(), "model_skinned_textured", material.diffuseTexture.c_str())); + } + + 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/samples/SampleBase/blast/BlastAssetModelSkinned.h b/NvBlast/samples/SampleBase/blast/BlastAssetModelSkinned.h new file mode 100644 index 0000000..149c8e8 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastController.cpp b/NvBlast/samples/SampleBase/blast/BlastController.cpp new file mode 100644 index 0000000..77e2047 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastController.cpp @@ -0,0 +1,477 @@ +/* +* 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" + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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); + } + } +} + + +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(); +} + +void BlastController::removeAllFamilies() +{ + while (!m_families.empty()) + { + removeFamily(m_families.back()); + } + m_replay->reset(); +} + +void BlastController::recalculateAssetsSize() +{ + 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/samples/SampleBase/blast/BlastController.h b/NvBlast/samples/SampleBase/blast/BlastController.h new file mode 100644 index 0000000..f7f362f --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastController.h @@ -0,0 +1,239 @@ +/* +* 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; + } + + 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/samples/SampleBase/blast/BlastFamily.cpp b/NvBlast/samples/SampleBase/blast/BlastFamily.cpp new file mode 100644 index 0000000..95444b3 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastFamily.cpp @@ -0,0 +1,570 @@ +/* +* 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) +{ + 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); + +} diff --git a/NvBlast/samples/SampleBase/blast/BlastFamily.h b/NvBlast/samples/SampleBase/blast/BlastFamily.h new file mode 100644 index 0000000..0cb9bb3 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastFamily.h @@ -0,0 +1,201 @@ +/* +* 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> + + +class DebugRenderBuffer; + +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(); + + + 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; + +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/samples/SampleBase/blast/BlastFamilyBoxes.cpp b/NvBlast/samples/SampleBase/blast/BlastFamilyBoxes.cpp new file mode 100644 index 0000000..e8b7b27 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastFamilyBoxes.h b/NvBlast/samples/SampleBase/blast/BlastFamilyBoxes.h new file mode 100644 index 0000000..1f70451 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastFamilyModelSimple.cpp b/NvBlast/samples/SampleBase/blast/BlastFamilyModelSimple.cpp new file mode 100644 index 0000000..858758f --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastFamilyModelSimple.cpp @@ -0,0 +1,335 @@ +/* +* 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); + } + + } + + +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; + 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; + + } + } + + // 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]); + } + } +} + +void BlastFamilyModelSimple::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++) + { + uint32_t chunkIndex = chunkIndices[i]; + std::vector<Renderable*>& renderables = m_chunks[chunkIndex].renderables; + for (Renderable* r : renderables) + { + r->setTransform(actor.getPhysXActor().getGlobalPose() * subChunks[chunks[chunkIndex].firstSubchunkIndex].transform); + } + } +} + +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); + } + } +} + +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); + } + } +} diff --git a/NvBlast/samples/SampleBase/blast/BlastFamilyModelSimple.h b/NvBlast/samples/SampleBase/blast/BlastFamilyModelSimple.h new file mode 100644 index 0000000..7816690 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastFamilyModelSimple.h @@ -0,0 +1,52 @@ +/* +* 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(); + +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; + }; + + std::vector<Chunk> m_chunks; +}; + + +#endif //BLAST_FAMILY_MODEL_SIMPLE_H
\ No newline at end of file diff --git a/NvBlast/samples/SampleBase/blast/BlastFamilyModelSkinned.cpp b/NvBlast/samples/SampleBase/blast/BlastFamilyModelSkinned.cpp new file mode 100644 index 0000000..c0731d5 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastFamilyModelSkinned.h b/NvBlast/samples/SampleBase/blast/BlastFamilyModelSkinned.h new file mode 100644 index 0000000..aeb9353 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastModel.cpp b/NvBlast/samples/SampleBase/blast/BlastModel.cpp new file mode 100644 index 0000000..88ddf3c --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastModel.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 "BlastModel.h" + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + + +using namespace physx; + +BlastModelPtr BlastModel::loadFromFileTinyLoader(const char* path) +{ + std::shared_ptr<BlastModel> model = std::shared_ptr<BlastModel>(new BlastModel()); + + 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()) + { + 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/samples/SampleBase/blast/BlastModel.h b/NvBlast/samples/SampleBase/blast/BlastModel.h new file mode 100644 index 0000000..2ef39f6 --- /dev/null +++ b/NvBlast/samples/SampleBase/blast/BlastModel.h @@ -0,0 +1,55 @@ +/* +* 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; +typedef std::shared_ptr<const BlastModel> BlastModelPtr; + +/** +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 + { + 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/samples/SampleBase/blast/BlastReplay.cpp b/NvBlast/samples/SampleBase/blast/BlastReplay.cpp new file mode 100644 index 0000000..13d2b33 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/blast/BlastReplay.h b/NvBlast/samples/SampleBase/blast/BlastReplay.h new file mode 100644 index 0000000..a85c996 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/core/Application.cpp b/NvBlast/samples/SampleBase/core/Application.cpp new file mode 100644 index 0000000..40d975b --- /dev/null +++ b/NvBlast/samples/SampleBase/core/Application.cpp @@ -0,0 +1,73 @@ +/* +* 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(std::wstring sampleName) +: m_sampleName(sampleName) +{ + m_deviceManager = new DeviceManager(); +} + +void Application::addControllerToFront(IApplicationController* controller) +{ + m_controllers.push_back(controller); +} + +int Application::run() +{ + // FirstPersonCamera uses this timer, without it it will be FPS-dependent + DXUTGetGlobalTimer()->Start(); + + for (auto it = m_controllers.begin(); it != m_controllers.end(); it++) + m_deviceManager->AddControllerToFront(*it); + + DeviceCreationParameters deviceParams; + deviceParams.swapChainFormat = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + deviceParams.swapChainSampleCount = 4; + deviceParams.startFullscreen = false; + deviceParams.backBufferWidth = 1600; + deviceParams.backBufferHeight = 900; +#if defined(DEBUG) | defined(_DEBUG) + deviceParams.createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG; +#endif + deviceParams.featureLevel = D3D_FEATURE_LEVEL_11_0; + + if (FAILED(m_deviceManager->CreateWindowDeviceAndSwapChain(deviceParams, m_sampleName.c_str()))) + { + MessageBoxA(nullptr, "Cannot initialize the D3D11 device with the requested parameters", "Error", + MB_OK | MB_ICONERROR); + return 1; + } + + 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); + m_deviceManager->MessageLoop(); + + 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(); + delete m_deviceManager; + + return 0; +} diff --git a/NvBlast/samples/SampleBase/core/Application.h b/NvBlast/samples/SampleBase/core/Application.h new file mode 100644 index 0000000..b4bd75b --- /dev/null +++ b/NvBlast/samples/SampleBase/core/Application.h @@ -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. +*/ + +#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(std::wstring sampleName); + void addControllerToFront(IApplicationController* controller); + + const std::vector<IApplicationController*>& getControllers() const + { + return m_controllers; + } + + int run(); + +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/samples/SampleBase/core/DeviceManager.cpp b/NvBlast/samples/SampleBase/core/DeviceManager.cpp new file mode 100644 index 0000000..26f9fbb --- /dev/null +++ b/NvBlast/samples/SampleBase/core/DeviceManager.cpp @@ -0,0 +1,795 @@ +// TAGRELEASE: PUBLIC + +#include "DeviceManager.h" +#include <WinUser.h> +#include <Windows.h> +#include <assert.h> +#include <sstream> +#include <algorithm> +#include "SampleProfiler.h" + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } +#endif + +#define WINDOW_CLASS_NAME L"NvDX11" + +#define WINDOW_STYLE_NORMAL (WS_OVERLAPPEDWINDOW | WS_VISIBLE) +#define WINDOW_STYLE_FULLSCREEN (WS_POPUP | WS_SYSMENU | WS_VISIBLE) + +// A singleton, sort of... To pass the events from WindowProc to the object. +DeviceManager* g_DeviceManagerInstance = NULL; + +#undef min +#undef max + +LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if(g_DeviceManagerInstance) + return g_DeviceManagerInstance->MsgProc(hWnd, uMsg, wParam, lParam); + else + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +DeviceManager* GetDeviceManager() +{ + return g_DeviceManagerInstance; +} + +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; + } + + unsigned int adapterNo = 0; + while (SUCCEEDED(hres)) + { + IDXGIAdapter* pAdapter = NULL; + hres = IDXGIFactory_0001->EnumAdapters(adapterNo, (IDXGIAdapter**)&pAdapter); + + if (SUCCEEDED(hres)) + { + DXGI_ADAPTER_DESC aDesc; + pAdapter->GetDesc(&aDesc); + + // If no name is specified, return the first adapater. This is the same behaviour as the + // default specified for D3D11CreateDevice when no adapter is specified. + if (wcslen(targetName) == 0) + { + targetAdapter = pAdapter; + isNv = IsNvDeviceID(aDesc.VendorId); + break; + } + + std::wstring aName = aDesc.Description; + if (aName.find(targetName) != std::string::npos) + { + targetAdapter = pAdapter; + isNv = IsNvDeviceID(aDesc.VendorId); + } + else + { + pAdapter->Release(); + } + } + + adapterNo++; + } + + 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, std::wstring title) +{ + g_DeviceManagerInstance = this; + m_WindowTitle = title; + + HINSTANCE hInstance = GetModuleHandle(NULL); + WNDCLASSEX windowClass = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WindowProc, + 0L, 0L, hInstance, NULL, NULL, NULL, NULL, WINDOW_CLASS_NAME, NULL }; + + windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); + + RegisterClassEx(&windowClass); + + UINT windowStyle = params.startFullscreen + ? WINDOW_STYLE_FULLSCREEN + : params.startMaximized + ? (WINDOW_STYLE_NORMAL | WS_MAXIMIZE) + : WINDOW_STYLE_NORMAL; + + RECT rect = { 0, 0, params.backBufferWidth, params.backBufferHeight }; + AdjustWindowRect(&rect, windowStyle, FALSE); + + IDXGIAdapter* targetAdapter = FindAdapter(params.adapterNameSubstring, m_IsNvidia); + if (targetAdapter) + { + rect = MoveWindowOntoAdapter(targetAdapter, rect); + } + else + { + // We could silently use a default adapter in this case. I think it's better to choke. + std::wostringstream ostr; + ostr << L"Could not find an adapter matching \"" << params.adapterNameSubstring << "\"" << std::ends; + MessageBox(NULL, ostr.str().c_str(), m_WindowTitle.c_str(), MB_OK | MB_ICONERROR); + return E_FAIL; + } + + m_hWnd = CreateWindowEx( + 0, + WINDOW_CLASS_NAME, + title.c_str(), + windowStyle, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + GetDesktopWindow(), + NULL, + hInstance, + NULL + ); + + if(!m_hWnd) + { +#ifdef DEBUG + DWORD errorCode = GetLastError(); + printf("CreateWindowEx error code = 0x%x\n", errorCode); +#endif + + MessageBox(NULL, L"Cannot create window", m_WindowTitle.c_str(), MB_OK | MB_ICONERROR); + return E_FAIL; + } + + UpdateWindow(m_hWnd); + + HRESULT hr = E_FAIL; + + 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(); + + if(FAILED(hr)) + return hr; + + DeviceCreated(); + BackBufferResized(); + + return S_OK; +} + +void +DeviceManager::Shutdown() +{ + if(m_SwapChain && GetWindowState() == kWindowFullscreen) + m_SwapChain->SetFullscreenState(false, NULL); + + DeviceDestroyed(); + + SAFE_RELEASE(m_BackBufferRTV); + SAFE_RELEASE(m_DepthStencilDSV); + SAFE_RELEASE(m_DepthStencilBuffer); + + g_DeviceManagerInstance = NULL; + SAFE_RELEASE(m_ImmediateContext); + SAFE_RELEASE(m_SwapChain); + + 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(); + } + } + 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; +} + +void +DeviceManager::MessageLoop() +{ + MSG msg = {0}; + + LARGE_INTEGER perfFreq, previousTime; + QueryPerformanceFrequency(&perfFreq); + QueryPerformanceCounter(&previousTime); + + while (WM_QUIT != msg.message) + { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + PROFILER_BEGIN("Main Loop"); + + 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); + Render(); + 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; + + PROFILER_END(); + PROFILER_RESET(); + } + + } +} + +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 || + uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST ) + { + // 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; + } + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +void +DeviceManager::ResizeSwapChain() +{ + 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() +{ + PROFILER_SCOPED_FUNCTION(); + + 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) +{ + PROFILER_SCOPED_FUNCTION(); + + // 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; +} + +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; +} diff --git a/NvBlast/samples/SampleBase/core/DeviceManager.h b/NvBlast/samples/SampleBase/core/DeviceManager.h new file mode 100644 index 0000000..98b8eee --- /dev/null +++ b/NvBlast/samples/SampleBase/core/DeviceManager.h @@ -0,0 +1,166 @@ +// TAGRELEASE: PUBLIC + +#pragma once +#include <Windows.h> +#include <DXGI.h> +#include <D3D11.h> +#include <list> + + +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; + + // 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"") + { } +}; + +#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) + +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; +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) + { } + + virtual ~DeviceManager() + { Shutdown(); } + + virtual HRESULT CreateWindowDeviceAndSwapChain(const DeviceCreationParameters& params, std::wstring windowTitle); + 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; } +}; + + +DeviceManager* GetDeviceManager(); diff --git a/NvBlast/samples/SampleBase/core/SampleController.cpp b/NvBlast/samples/SampleBase/core/SampleController.cpp new file mode 100644 index 0000000..163b3b4 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/core/SampleController.h b/NvBlast/samples/SampleBase/core/SampleController.h new file mode 100644 index 0000000..a52c2fe --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/core/SampleManager.cpp b/NvBlast/samples/SampleBase/core/SampleManager.cpp new file mode 100644 index 0000000..da5cb22 --- /dev/null +++ b/NvBlast/samples/SampleBase/core/SampleManager.cpp @@ -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. +*/ + +#include "SampleManager.h" + +#include "Utils.h" + +#include "Renderer.h" +#include "PhysXController.h" +#include "BlastController.h" +#include "CommonUIController.h" +#include "DamageToolController.h" +#include "SceneController.h" +#include "SampleController.h" + + +SampleManager::SampleManager(const SampleConfig& config) +: m_config(config) +{ +} + +int SampleManager::run() +{ + Application app(getConfig().sampleName); + + m_renderer = new Renderer(); + m_physXController = new PhysXController(ExtImpactDamageManager::FilterShader); + m_blastController = new BlastController(); + m_sceneController = new SceneController(); + m_damageToolController = new DamageToolController(); + m_sampleController = new SampleController(); + m_commonUIController = new CommonUIController(); + + app.addControllerToFront(m_renderer); + app.addControllerToFront(m_physXController); + app.addControllerToFront(m_blastController); + app.addControllerToFront(m_sceneController); + app.addControllerToFront(m_damageToolController); + app.addControllerToFront(m_sampleController); + app.addControllerToFront(m_commonUIController); + + for (IApplicationController* c : app.getControllers()) + { + (static_cast<ISampleController*>(c))->setManager(this); + } + + int result = app.run(); + + delete m_renderer; + delete m_physXController; + delete m_blastController; + delete m_sceneController; + delete m_damageToolController; + delete m_sampleController; + delete m_commonUIController; + + return result; +} + + +int runSample(const SampleConfig& config) +{ + SampleManager sampleManager(config); + return sampleManager.run(); +}
\ No newline at end of file diff --git a/NvBlast/samples/SampleBase/core/SampleManager.h b/NvBlast/samples/SampleBase/core/SampleManager.h new file mode 100644 index 0000000..59ecc8c --- /dev/null +++ b/NvBlast/samples/SampleBase/core/SampleManager.h @@ -0,0 +1,111 @@ +/* +* 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" + + +class SampleManager; + +class ISampleController : public IApplicationController +{ +public: + + void setManager(SampleManager* manager) + { + m_manager = manager; + } +protected: + + SampleManager* getManager() const + { + return m_manager; + } + +private: + SampleManager* m_manager; +}; + + +class Renderer; +class PhysXController; +class BlastController; +class SceneController; +class DamageToolController; +class SampleController; +class CommonUIController; + + +/** +*/ +class SampleManager +{ + public: + SampleManager(const SampleConfig& config); + int run(); + + 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; + } + + SampleController& getSampleController() const + { + return *m_sampleController; + } + + CommonUIController& getCommonUIController() const + { + return *m_commonUIController; + } + + const SampleConfig& getConfig() const + { + return m_config; + } + + + private: + Renderer* m_renderer; + PhysXController* m_physXController; + BlastController* m_blastController; + SceneController* m_sceneController; + DamageToolController* m_damageToolController; + SampleController* m_sampleController; + CommonUIController* m_commonUIController; + + const SampleConfig& m_config; +}; + + +#endif
\ No newline at end of file diff --git a/NvBlast/samples/SampleBase/physx/PhysXController.cpp b/NvBlast/samples/SampleBase/physx/PhysXController.cpp new file mode 100644 index 0000000..1df06be --- /dev/null +++ b/NvBlast/samples/SampleBase/physx/PhysXController.cpp @@ -0,0 +1,726 @@ +/* + * 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); +} + +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(); + + if (m_paused) + return; + + // 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 + { + 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); + } + + // 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; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/NvBlast/samples/SampleBase/physx/PhysXController.h b/NvBlast/samples/SampleBase/physx/PhysXController.h new file mode 100644 index 0000000..625de0c --- /dev/null +++ b/NvBlast/samples/SampleBase/physx/PhysXController.h @@ -0,0 +1,286 @@ +/* +* 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; + } + + 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/samples/SampleBase/renderer/ConvexRenderMesh.cpp b/NvBlast/samples/SampleBase/renderer/ConvexRenderMesh.cpp new file mode 100644 index 0000000..074cc2d --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/ConvexRenderMesh.h b/NvBlast/samples/SampleBase/renderer/ConvexRenderMesh.h new file mode 100644 index 0000000..dfe8d8f --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/CustomRenderMesh.cpp b/NvBlast/samples/SampleBase/renderer/CustomRenderMesh.cpp new file mode 100644 index 0000000..61ae9e0 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/CustomRenderMesh.h b/NvBlast/samples/SampleBase/renderer/CustomRenderMesh.h new file mode 100644 index 0000000..b0ddea1 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/DebugRenderBuffer.h b/NvBlast/samples/SampleBase/renderer/DebugRenderBuffer.h new file mode 100644 index 0000000..7810733 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/Mesh.cpp b/NvBlast/samples/SampleBase/renderer/Mesh.cpp new file mode 100644 index 0000000..cdf63f2 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/Mesh.h b/NvBlast/samples/SampleBase/renderer/Mesh.h new file mode 100644 index 0000000..6951198 --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/Mesh.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 MESH_H +#define MESH_H + +#include <vector> +#include "PxVec2.h" +#include "PxVec3.h" + + +class Mesh +{ + 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. +*/ +class SimpleMesh : public Mesh +{ +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/samples/SampleBase/renderer/PrimitiveRenderMesh.cpp b/NvBlast/samples/SampleBase/renderer/PrimitiveRenderMesh.cpp new file mode 100644 index 0000000..329f47b --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/PrimitiveRenderMesh.cpp @@ -0,0 +1,205 @@ +/* +* 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() +{ +} diff --git a/NvBlast/samples/SampleBase/renderer/PrimitiveRenderMesh.h b/NvBlast/samples/SampleBase/renderer/PrimitiveRenderMesh.h new file mode 100644 index 0000000..f72c191 --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/PrimitiveRenderMesh.h @@ -0,0 +1,61 @@ +/* +* 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(); +}; + + +struct PrimitiveRenderMeshType +{ + enum Enum + { + Box, + Plane, + Sphere, + Count + }; +}; + +#endif //PRIMITIVE_RENDER_MESH_H
\ No newline at end of file diff --git a/NvBlast/samples/SampleBase/renderer/RenderMaterial.cpp b/NvBlast/samples/SampleBase/renderer/RenderMaterial.cpp new file mode 100644 index 0000000..cb40ec7 --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/RenderMaterial.cpp @@ -0,0 +1,206 @@ +/* +* 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" + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// RenderMaterial +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +RenderMaterial::RenderMaterial(ResourceManager& resourceCallback, const char* shaderFileName, + const char* textureFileName, BlendMode blendMode) +{ + 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; + mTextureFileName = textureFileName; + + 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(); + + SAFE_RELEASE(mTextureSRV); +} + +RenderMaterial::~RenderMaterial() +{ + 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()) + { + if (!(*it).second.expired()) + { + return (*it).second.lock(); + } + } + + // 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(); +} diff --git a/NvBlast/samples/SampleBase/renderer/RenderMaterial.h b/NvBlast/samples/SampleBase/renderer/RenderMaterial.h new file mode 100644 index 0000000..a342459 --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/RenderMaterial.h @@ -0,0 +1,118 @@ +/* +* 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 RenderMaterial +{ + public: + + enum BlendMode + { + BLEND_NONE, + BLEND_ALPHA_BLENDING, + BLEND_ADDITIVE + }; + + RenderMaterial(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; + }; + + typedef std::shared_ptr<Instance> InstancePtr; + + 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 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; + }; + + std::map<const IRenderMesh*, std::weak_ptr<Instance>> mRenderMeshToInstanceMap; + 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/samples/SampleBase/renderer/RenderUtils.h b/NvBlast/samples/SampleBase/renderer/RenderUtils.h new file mode 100644 index 0000000..12df9f2 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/Renderable.cpp b/NvBlast/samples/SampleBase/renderer/Renderable.cpp new file mode 100644 index 0000000..340874b --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/Renderable.cpp @@ -0,0 +1,48 @@ +/* +* 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) +{ + setMaterial(material); +} + +void Renderable::setMaterial(RenderMaterial& material) +{ + 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(); + renderer.m_context->Unmap(renderer.m_objectCB, 0); + } + + m_mesh.render(*renderer.m_context); +} diff --git a/NvBlast/samples/SampleBase/renderer/Renderable.h b/NvBlast/samples/SampleBase/renderer/Renderable.h new file mode 100644 index 0000000..f1faa52 --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/Renderable.h @@ -0,0 +1,128 @@ +/* +* 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; +}; + +/** +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; + } + + 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; +}; + +#endif //RENDERABLE_H
\ No newline at end of file diff --git a/NvBlast/samples/SampleBase/renderer/Renderer.cpp b/NvBlast/samples/SampleBase/renderer/Renderer.cpp new file mode 100644 index 0000000..94ea3c3 --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/Renderer.cpp @@ -0,0 +1,729 @@ +/* +* 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)); + desc.CullMode = D3D11_CULL_FRONT; + 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; + 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/samples/SampleBase/renderer/Renderer.h b/NvBlast/samples/SampleBase/renderer/Renderer.h new file mode 100644 index 0000000..56e6e4a --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/Renderer.h @@ -0,0 +1,248 @@ +/* +* 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; + }; + + + //////// 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/samples/SampleBase/renderer/RendererHBAO.cpp b/NvBlast/samples/SampleBase/renderer/RendererHBAO.cpp new file mode 100644 index 0000000..5e20a49 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/RendererHBAO.h b/NvBlast/samples/SampleBase/renderer/RendererHBAO.h new file mode 100644 index 0000000..2478628 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/RendererShadow.cpp b/NvBlast/samples/SampleBase/renderer/RendererShadow.cpp new file mode 100644 index 0000000..28a79e5 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/RendererShadow.h b/NvBlast/samples/SampleBase/renderer/RendererShadow.h new file mode 100644 index 0000000..cc81c67 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/ResourceManager.cpp b/NvBlast/samples/SampleBase/renderer/ResourceManager.cpp new file mode 100644 index 0000000..f8a4b7b --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/ResourceManager.cpp @@ -0,0 +1,212 @@ +/* +* 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 + + +ResourceManager::ResourceManager() +{ + // search for root folder by default + addSearchDir("."); +} + +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]; + const char* exts[] = { "dds", "tga" }; + 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)); + } + 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); + + 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/samples/SampleBase/renderer/ResourceManager.h b/NvBlast/samples/SampleBase/renderer/ResourceManager.h new file mode 100644 index 0000000..6a9b8cd --- /dev/null +++ b/NvBlast/samples/SampleBase/renderer/ResourceManager.h @@ -0,0 +1,93 @@ +/* +* 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(); + + //////// 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/samples/SampleBase/renderer/ShaderUtils.h b/NvBlast/samples/SampleBase/renderer/ShaderUtils.h new file mode 100644 index 0000000..778c811 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/SkinnedRenderMesh.cpp b/NvBlast/samples/SampleBase/renderer/SkinnedRenderMesh.cpp new file mode 100644 index 0000000..c575d6c --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/renderer/SkinnedRenderMesh.h b/NvBlast/samples/SampleBase/renderer/SkinnedRenderMesh.h new file mode 100644 index 0000000..2f690d8 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/scene/SampleAssetListParser.cpp b/NvBlast/samples/SampleBase/scene/SampleAssetListParser.cpp new file mode 100644 index 0000000..00cf4df --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/scene/SampleAssetListParser.h b/NvBlast/samples/SampleBase/scene/SampleAssetListParser.h new file mode 100644 index 0000000..b6303ec --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/scene/SceneController.cpp b/NvBlast/samples/SampleBase/scene/SceneController.cpp new file mode 100644 index 0000000..eeaca25 --- /dev/null +++ b/NvBlast/samples/SampleBase/scene/SceneController.cpp @@ -0,0 +1,1363 @@ +/* +* 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; + } + + 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); + for (SceneActor* a : m_sceneActors) + { + shift += a->getSpawnShift(); + } + + 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); + + // prepare scene + spawnAsset(0); +} + +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); + + m_scene->addSceneActor(new PhysXSceneActor(getPhysXController(), cube, "Cube")); +} + +void SceneController::spawnAsset(int32_t num) +{ + m_scene->spawnAsset(num); +} + +int SceneController::releaseAll() +{ + return m_scene->releaseAll(); +} diff --git a/NvBlast/samples/SampleBase/scene/SceneController.h b/NvBlast/samples/SampleBase/scene/SceneController.h new file mode 100644 index 0000000..0b13878 --- /dev/null +++ b/NvBlast/samples/SampleBase/scene/SceneController.h @@ -0,0 +1,83 @@ +/* +* 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; + +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); + + +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; +}; + +#endif
\ No newline at end of file diff --git a/NvBlast/samples/SampleBase/ui/CommonUIController.cpp b/NvBlast/samples/SampleBase/ui/CommonUIController.cpp new file mode 100644 index 0000000..e56a124 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/ui/CommonUIController.h b/NvBlast/samples/SampleBase/ui/CommonUIController.h new file mode 100644 index 0000000..da62674 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/ui/DamageToolController.cpp b/NvBlast/samples/SampleBase/ui/DamageToolController.cpp new file mode 100644 index 0000000..1850b26 --- /dev/null +++ b/NvBlast/samples/SampleBase/ui/DamageToolController.cpp @@ -0,0 +1,292 @@ +/* +* 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 + m_pickPointerRenderMaterial = new RenderMaterial(getRenderer().getResourceManager(), "physx_primitive_transparent", "", RenderMaterial::BLEND_ALPHA_BLENDING); + 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/samples/SampleBase/ui/DamageToolController.h b/NvBlast/samples/SampleBase/ui/DamageToolController.h new file mode 100644 index 0000000..9dcea39 --- /dev/null +++ b/NvBlast/samples/SampleBase/ui/DamageToolController.h @@ -0,0 +1,122 @@ +/* +* 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; + } + +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/samples/SampleBase/ui/imgui_impl_dx11.cpp b/NvBlast/samples/SampleBase/ui/imgui_impl_dx11.cpp new file mode 100644 index 0000000..11f66f0 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/ui/imgui_impl_dx11.h b/NvBlast/samples/SampleBase/ui/imgui_impl_dx11.h new file mode 100644 index 0000000..7d6f710 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/utils/PxInputDataFromPxFileBuf.h b/NvBlast/samples/SampleBase/utils/PxInputDataFromPxFileBuf.h new file mode 100644 index 0000000..dfa8260 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/utils/SampleProfiler.cpp b/NvBlast/samples/SampleBase/utils/SampleProfiler.cpp new file mode 100644 index 0000000..4df23fd --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/utils/SampleProfiler.h b/NvBlast/samples/SampleBase/utils/SampleProfiler.h new file mode 100644 index 0000000..1ea3663 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/utils/SampleTime.h b/NvBlast/samples/SampleBase/utils/SampleTime.h new file mode 100644 index 0000000..c62ced2 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/utils/UIHelpers.h b/NvBlast/samples/SampleBase/utils/UIHelpers.h new file mode 100644 index 0000000..b23eb84 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/utils/Utils.cpp b/NvBlast/samples/SampleBase/utils/Utils.cpp new file mode 100644 index 0000000..a271137 --- /dev/null +++ b/NvBlast/samples/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/samples/SampleBase/utils/Utils.h b/NvBlast/samples/SampleBase/utils/Utils.h new file mode 100644 index 0000000..5d4addc --- /dev/null +++ b/NvBlast/samples/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/samples/compiler/cmake/SampleAssetViewer.cmake b/NvBlast/samples/compiler/cmake/SampleAssetViewer.cmake new file mode 100644 index 0000000..cbd666f --- /dev/null +++ b/NvBlast/samples/compiler/cmake/SampleAssetViewer.cmake @@ -0,0 +1,57 @@ +# +# Build SampleAssetViewer Common +# + + +SET(SAV_SOURCE_DIR ${PROJECT_SOURCE_DIR}/SampleAssetViewer) +SET(SAMPLEBASE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/SampleBase) + + +# Include here after the directories are defined so that the platform specific file can use the variables. +include(${PROJECT_CMAKE_FILES_DIR}/${TARGET_BUILD_PLATFORM}/SampleAssetViewer.cmake) + +SET(ROOT_FILES + ${SAV_SOURCE_DIR}/Main.cpp +) + +ADD_EXECUTABLE(SampleAssetViewer + ${ROOT_FILES} +) + +set_target_properties(SampleAssetViewer + PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX} + CHECKED_POSTFIX ${CMAKE_CHECKED_POSTFIX} + RELEASE_POSTFIX ${CMAKE_RELEASE_POSTFIX} + PROFILE_POSTFIX ${CMAKE_PROFILE_POSTFIX} +) + +SOURCE_GROUP("Source" FILES ${ROOT_FILES}) + +# Target specific compile options +TARGET_INCLUDE_DIRECTORIES(SampleAssetViewer + PRIVATE ${SAMPLEASSETVIEWER_PLATFORM_INCLUDES} + + PRIVATE ${TCLAP_INCLUDE_DIRS} + PRIVATE ${PXSHAREDSDK_INCLUDE_DIRS} + + PRIVATE ${SAMPLEBASE_SOURCE_DIR} + +) + +TARGET_COMPILE_DEFINITIONS(SampleAssetViewer + PRIVATE ${SAMPLEASSETVIEWER_COMPILE_DEFS} +) + +SET_TARGET_PROPERTIES(SampleAssetViewer PROPERTIES + COMPILE_PDB_NAME_DEBUG "SampleAssetViewer${CMAKE_DEBUG_POSTFIX}" + COMPILE_PDB_NAME_CHECKED "SampleAssetViewer${CMAKE_CHECKED_POSTFIX}" + COMPILE_PDB_NAME_PROFILE "SampleAssetViewer${CMAKE_PROFILE_POSTFIX}" + COMPILE_PDB_NAME_RELEASE "SampleAssetViewer${CMAKE_RELEASE_POSTFIX}" +) + +TARGET_COMPILE_OPTIONS(SampleAssetViewer PRIVATE /wd4005 /wd4244 ${SAMPLEASSETVIEWER_COMPILE_OPTIONS}) + +# Do final direct sets after the target has been defined +TARGET_LINK_LIBRARIES(SampleAssetViewer PUBLIC SampleBase) + +SET_TARGET_PROPERTIES(SampleAssetViewer PROPERTIES LINK_FLAGS ${SAMPLEASSETVIEWER_LINK_FLAGS}) diff --git a/NvBlast/samples/compiler/cmake/SampleBase.cmake b/NvBlast/samples/compiler/cmake/SampleBase.cmake new file mode 100644 index 0000000..a71f67d --- /dev/null +++ b/NvBlast/samples/compiler/cmake/SampleBase.cmake @@ -0,0 +1,212 @@ +# +# Build SampleBase Common +# + + +SET(SB_SOURCE_DIR ${PROJECT_SOURCE_DIR}/SampleBase) +SET(SB_BLAST_SOURCE_DIR ${SB_SOURCE_DIR}/blast) +SET(SB_CORE_SOURCE_DIR ${SB_SOURCE_DIR}/core) +SET(SB_PHYSX_SOURCE_DIR ${SB_SOURCE_DIR}/physx) +SET(SB_RENDERER_SOURCE_DIR ${SB_SOURCE_DIR}/renderer) +SET(SB_SCENE_SOURCE_DIR ${SB_SOURCE_DIR}/scene) +SET(SB_UI_SOURCE_DIR ${SB_SOURCE_DIR}/ui) +SET(SB_UTILS_SOURCE_DIR ${SB_SOURCE_DIR}/utils) +SET(SHARED_UTILS_SOURCE_DIR ${BLAST_ROOT_DIR}shared/utils) + + +FIND_PACKAGE(PhysXSDK $ENV{PM_PhysX_VERSION} REQUIRED) +FIND_PACKAGE(PxSharedSDK $ENV{PM_PxShared_VERSION} REQUIRED) +FIND_PACKAGE(DXUT $ENV{PM_DXUT_VERSION} REQUIRED) +FIND_PACKAGE(DirectXTex $ENV{PM_DirectXTex_VERSION} REQUIRED) +FIND_PACKAGE(imgui $ENV{PM_imgui_VERSION} REQUIRED) +FIND_PACKAGE(tinyObjLoader $ENV{PM_tinyObjLoader_VERSION} REQUIRED) +FIND_PACKAGE(tclap $ENV{PM_tclap_VERSION} REQUIRED) +FIND_PACKAGE(hbao_plus $ENV{PM_hbao_plus_VERSION} REQUIRED) +FIND_PACKAGE(shadow_lib $ENV{PM_shadow_lib_VERSION} REQUIRED) +FIND_PACKAGE(d3dcompiler $ENV{PM_d3dcompiler_VERSION} REQUIRED) + +# Include here after the directories are defined so that the platform specific file can use the variables. +include(${PROJECT_CMAKE_FILES_DIR}/${TARGET_BUILD_PLATFORM}/SampleBase.cmake) + +SET(BLAST_FILES + ${SB_BLAST_SOURCE_DIR}/BlastFamily.cpp + ${SB_BLAST_SOURCE_DIR}/BlastFamily.h + ${SB_BLAST_SOURCE_DIR}/BlastFamilyBoxes.cpp + ${SB_BLAST_SOURCE_DIR}/BlastFamilyBoxes.h + ${SB_BLAST_SOURCE_DIR}/BlastFamilyModelSimple.cpp + ${SB_BLAST_SOURCE_DIR}/BlastFamilyModelSimple.h + ${SB_BLAST_SOURCE_DIR}/BlastFamilyModelSkinned.cpp + ${SB_BLAST_SOURCE_DIR}/BlastFamilyModelSkinned.h + ${SB_BLAST_SOURCE_DIR}/BlastAsset.cpp + ${SB_BLAST_SOURCE_DIR}/BlastAsset.h + ${SB_BLAST_SOURCE_DIR}/BlastAssetBoxes.cpp + ${SB_BLAST_SOURCE_DIR}/BlastAssetBoxes.h + ${SB_BLAST_SOURCE_DIR}/BlastAssetModel.cpp + ${SB_BLAST_SOURCE_DIR}/BlastAssetModel.h + ${SB_BLAST_SOURCE_DIR}/BlastAssetModelSimple.cpp + ${SB_BLAST_SOURCE_DIR}/BlastAssetModelSimple.h + ${SB_BLAST_SOURCE_DIR}/BlastAssetModelSkinned.cpp + ${SB_BLAST_SOURCE_DIR}/BlastAssetModelSkinned.h + ${SB_BLAST_SOURCE_DIR}/BlastController.cpp + ${SB_BLAST_SOURCE_DIR}/BlastController.h + ${SB_BLAST_SOURCE_DIR}/BlastModel.cpp + ${SB_BLAST_SOURCE_DIR}/BlastModel.h + ${SB_BLAST_SOURCE_DIR}/BlastReplay.cpp + ${SB_BLAST_SOURCE_DIR}/BlastReplay.h +) + +SET(CORE_FILES + ${SB_CORE_SOURCE_DIR}/Application.cpp + ${SB_CORE_SOURCE_DIR}/Application.h + ${SB_CORE_SOURCE_DIR}/DeviceManager.cpp + ${SB_CORE_SOURCE_DIR}/DeviceManager.h + ${SB_CORE_SOURCE_DIR}/SampleController.cpp + ${SB_CORE_SOURCE_DIR}/SampleController.h + ${SB_CORE_SOURCE_DIR}/SampleManager.cpp + ${SB_CORE_SOURCE_DIR}/SampleManager.h +) + +SET(PHYSX_FILES + ${SB_PHYSX_SOURCE_DIR}/PhysXController.cpp + ${SB_PHYSX_SOURCE_DIR}/PhysXController.h +) + +SET(RENDERER_FILES + ${SB_RENDERER_SOURCE_DIR}/ConvexRenderMesh.cpp + ${SB_RENDERER_SOURCE_DIR}/ConvexRenderMesh.h + ${SB_RENDERER_SOURCE_DIR}/CustomRenderMesh.cpp + ${SB_RENDERER_SOURCE_DIR}/CustomRenderMesh.h + ${SB_RENDERER_SOURCE_DIR}/DebugRenderBuffer.h + ${SB_RENDERER_SOURCE_DIR}/Mesh.cpp + ${SB_RENDERER_SOURCE_DIR}/Mesh.h + ${SB_RENDERER_SOURCE_DIR}/PrimitiveRenderMesh.cpp + ${SB_RENDERER_SOURCE_DIR}/PrimitiveRenderMesh.h + ${SB_RENDERER_SOURCE_DIR}/Renderable.cpp + ${SB_RENDERER_SOURCE_DIR}/Renderable.h + ${SB_RENDERER_SOURCE_DIR}/Renderer.cpp + ${SB_RENDERER_SOURCE_DIR}/Renderer.h + ${SB_RENDERER_SOURCE_DIR}/RendererHBAO.cpp + ${SB_RENDERER_SOURCE_DIR}/RendererHBAO.h + ${SB_RENDERER_SOURCE_DIR}/RendererShadow.cpp + ${SB_RENDERER_SOURCE_DIR}/RendererShadow.h + ${SB_RENDERER_SOURCE_DIR}/RenderMaterial.cpp + ${SB_RENDERER_SOURCE_DIR}/RenderMaterial.h + ${SB_RENDERER_SOURCE_DIR}/RenderUtils.h + ${SB_RENDERER_SOURCE_DIR}/ResourceManager.cpp + ${SB_RENDERER_SOURCE_DIR}/ResourceManager.h + ${SB_RENDERER_SOURCE_DIR}/ShaderUtils.h + ${SB_RENDERER_SOURCE_DIR}/SkinnedRenderMesh.cpp + ${SB_RENDERER_SOURCE_DIR}/SkinnedRenderMesh.h +) + +SET(SCENE_FILES + ${SB_SCENE_SOURCE_DIR}/SampleAssetListParser.cpp + ${SB_SCENE_SOURCE_DIR}/SampleAssetListParser.h + ${SB_SCENE_SOURCE_DIR}/SceneController.cpp + ${SB_SCENE_SOURCE_DIR}/SceneController.h +) + +SET(UI_FILES + ${SB_UI_SOURCE_DIR}/CommonUIController.cpp + ${SB_UI_SOURCE_DIR}/CommonUIController.h + ${SB_UI_SOURCE_DIR}/DamageToolController.cpp + ${SB_UI_SOURCE_DIR}/DamageToolController.h + ${SB_UI_SOURCE_DIR}/imgui_impl_dx11.cpp + ${SB_UI_SOURCE_DIR}/imgui_impl_dx11.h +) + +SET(UTIL_FILES + ${SHARED_UTILS_SOURCE_DIR}/AssetGenerator.cpp + ${SHARED_UTILS_SOURCE_DIR}/AssetGenerator.h + ${SB_UTILS_SOURCE_DIR}/SampleProfiler.cpp + ${SB_UTILS_SOURCE_DIR}/SampleProfiler.h + ${SB_UTILS_SOURCE_DIR}/SampleTime.h + ${SB_UTILS_SOURCE_DIR}/UIHelpers.h + ${SB_UTILS_SOURCE_DIR}/Utils.cpp + ${SB_UTILS_SOURCE_DIR}/Utils.h + ${SB_UTILS_SOURCE_DIR}/PxInputDataFromPxFileBuf.h +) + +SET(ROOT_FILES + ${SB_SOURCE_DIR}/Sample.h +) + +ADD_LIBRARY(SampleBase STATIC + ${BLAST_FILES} + ${CORE_FILES} + ${PHYSX_FILES} + ${RENDERER_FILES} + ${SCENE_FILES} + ${UI_FILES} + ${UTIL_FILES} + ${ROOT_FILES} + + + ${IMGUI_SOURCE_FILES} +) + +SOURCE_GROUP("Source" FILES ${ROOT_FILES}) + +SOURCE_GROUP("Source\\blast" FILES ${BLAST_FILES}) +SOURCE_GROUP("Source\\core" FILES ${CORE_FILES}) +SOURCE_GROUP("Source\\imgui" FILES ${IMGUI_SOURCE_FILES}) +SOURCE_GROUP("Source\\physx" FILES ${PHYSX_FILES}) +SOURCE_GROUP("Source\\renderer" FILES ${RENDERER_FILES}) +SOURCE_GROUP("Source\\scene" FILES ${SCENE_FILES}) +SOURCE_GROUP("Source\\ui" FILES ${UI_FILES}) +SOURCE_GROUP("Source\\utils" FILES ${UTIL_FILES}) + +# Target specific compile options + +TARGET_INCLUDE_DIRECTORIES(SampleBase + PRIVATE ${SAMPLEBASE_PLATFORM_INCLUDES} + + PRIVATE ${DIRECTXTEX_INCLUDE_DIRS} + PRIVATE ${DXUT_INCLUDE_DIRS} + + PRIVATE ${IMGUI_INCLUDE_DIRS} + + PRIVATE ${TINYOBJLOADER_INCLUDE_DIRS} + PRIVATE ${TCLAP_INCLUDE_DIRS} + PRIVATE ${HBAO_PLUS_INCLUDE_DIRS} + PRIVATE ${SHADOW_LIB_INCLUDE_DIRS} + + PRIVATE ${SB_SOURCE_DIR} + PRIVATE ${SB_SOURCE_DIR}/blast + PRIVATE ${SB_SOURCE_DIR}/core + PRIVATE ${SB_SOURCE_DIR}/physx + PRIVATE ${SB_SOURCE_DIR}/renderer + PRIVATE ${SB_SOURCE_DIR}/scene + PRIVATE ${SB_SOURCE_DIR}/ui + PRIVATE ${SB_SOURCE_DIR}/utils + + PRIVATE ${SHARED_UTILS_SOURCE_DIR} + + PRIVATE ${PHYSXSDK_INCLUDE_DIRS} + PRIVATE ${PXSHAREDSDK_INCLUDE_DIRS} + +) + +TARGET_COMPILE_DEFINITIONS(SampleBase + PRIVATE ${SAMPLEBASE_COMPILE_DEFS} +) + +SET_TARGET_PROPERTIES(SampleBase PROPERTIES + COMPILE_PDB_NAME_DEBUG "SampleBase${CMAKE_DEBUG_POSTFIX}" + COMPILE_PDB_NAME_CHECKED "SampleBase${CMAKE_CHECKED_POSTFIX}" + COMPILE_PDB_NAME_PROFILE "SampleBase${CMAKE_PROFILE_POSTFIX}" + COMPILE_PDB_NAME_RELEASE "SampleBase${CMAKE_RELEASE_POSTFIX}" +) + +TARGET_COMPILE_OPTIONS(SampleBase PRIVATE /wd4005 /wd4244) + +# Do final direct sets after the target has been defined +TARGET_LINK_LIBRARIES(SampleBase + PUBLIC NvBlast NvBlastExtShaders NvBlastExtPhysX NvBlastTk d3dcompiler.lib d3d11.lib dxgi.lib comctl32.lib + PUBLIC $<$<CONFIG:debug>:${PXPVDSDK_LIB_DEBUG}> $<$<CONFIG:debug>:${PXFOUNDATION_LIB_DEBUG}> $<$<CONFIG:debug>:${PXTASK_LIB_DEBUG}> $<$<CONFIG:debug>:${PSFASTXML_LIB_DEBUG}> $<$<CONFIG:debug>:${PHYSX3COMMON_LIB_DEBUG}> + PUBLIC $<$<CONFIG:checked>:${PXPVDSDK_LIB_CHECKED}> $<$<CONFIG:checked>:${PXFOUNDATION_LIB_CHECKED}> $<$<CONFIG:checked>:${PXTASK_LIB_CHECKED}> $<$<CONFIG:checked>:${PSFASTXML_LIB_CHECKED}> $<$<CONFIG:checked>:${PHYSX3COMMON_LIB_CHECKED}> + PUBLIC $<$<CONFIG:profile>:${PXPVDSDK_LIB_PROFILE}> $<$<CONFIG:profile>:${PXFOUNDATION_LIB_PROFILE}> $<$<CONFIG:profile>:${PXTASK_LIB_PROFILE}> $<$<CONFIG:profile>:${PSFASTXML_LIB_PROFILE}> $<$<CONFIG:profile>:${PHYSX3COMMON_LIB_PROFILE}> + PUBLIC $<$<CONFIG:release>:${PXPVDSDK_LIB}> $<$<CONFIG:release>:${PXFOUNDATION_LIB}> $<$<CONFIG:release>:${PXTASK_LIB}> $<$<CONFIG:release>:${PSFASTXML_LIB}> $<$<CONFIG:release>:${PHYSX3COMMON_LIB}> + PUBLIC ${HBAO_PLUS_LIB} ${SHADOW_LIB_LIB} ${DXUT_LIBRARIES} ${DIRECTXTEX_LIBRARIES} ) + +include(${PROJECT_CMAKE_FILES_DIR}/${TARGET_BUILD_PLATFORM}/SampleBase-AT.cmake OPTIONAL) diff --git a/NvBlast/samples/compiler/cmake/windows/CMakeLists.txt b/NvBlast/samples/compiler/cmake/windows/CMakeLists.txt new file mode 100644 index 0000000..6820dde --- /dev/null +++ b/NvBlast/samples/compiler/cmake/windows/CMakeLists.txt @@ -0,0 +1,52 @@ +#Platform specific compile flags and project includes + +#NOTE: Warnings lowered on the sample projects as it's got a lot of warnings. Defines below hide more. +SET(CMAKE_CXX_FLAGS "/GR- /GF /MP /Gy /EHsc /d2Zi+ /errorReport:prompt /fp:fast /Gd /Gm- /GS- /nologo /W3 /WX /Zc:forScope /Zc:inline /Zc:wchar_t /Zi") + +# Are we using the static or dynamic RT library? Whatever we use, it needs to be the same in any dependencies +# we pull in or we're potentially having mismatch issues. +IF(STATIC_WINCRT) + SET(WINCRT_NDEBUG "/MT") + SET(WINCRT_DEBUG "/MTd") +ELSE() + SET(WINCRT_NDEBUG "/MD") + SET(WINCRT_DEBUG "/MDd") +ENDIF() + +SET(CMAKE_CXX_FLAGS_DEBUG "/Od /RTCsu ${WINCRT_DEBUG}") +SET(CMAKE_CXX_FLAGS_CHECKED "/Ox ${WINCRT_NDEBUG}") +SET(CMAKE_CXX_FLAGS_PROFILE "/Ox ${WINCRT_NDEBUG}") +SET(CMAKE_CXX_FLAGS_RELEASE "/Ox ${WINCRT_NDEBUG}") + +# Build PDBs for all configurations +SET(CMAKE_SHARED_LINKER_FLAGS "/DEBUG") + +IF(CMAKE_CL_64) + ADD_DEFINITIONS(-DWIN64) +ENDIF(CMAKE_CL_64) + +SET(SAMPLES_SLN_COMPILE_DEFS _UNICODE;UNICODE;WIN32;WIN64;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;__GFSDK_DX11__;) +#NvBlastExt doesn't have the _CONSOLE flag + +SET(SAMPLES_SLN_DEBUG_COMPILE_DEFS _DEBUG;NV_DEBUG=1;) +SET(SAMPLES_SLN_CHECKED_COMPILE_DEFS NDEBUG;NV_CHECKED=1;) +SET(SAMPLES_SLN_PROFILE_COMPILE_DEFS NDEBUG;NV_PROFILE=1;) +SET(SAMPLES_SLN_RELEASE_COMPILE_DEFS NDEBUG;) + +IF(CMAKE_CL_64) + SET(LIBPATH_SUFFIX "x64") +ELSE(CMAKE_CL_64) + SET(LIBPATH_SUFFIX "x86") +ENDIF(CMAKE_CL_64) + +SET(CMAKE_DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}_${LIBPATH_SUFFIX}") +SET(CMAKE_PROFILE_POSTFIX "${CMAKE_PROFILE_POSTFIX}_${LIBPATH_SUFFIX}") +SET(CMAKE_CHECKED_POSTFIX "${CMAKE_CHECKED_POSTFIX}_${LIBPATH_SUFFIX}") +SET(CMAKE_RELEASE_POSTFIX "${CMAKE_RELEASE_POSTFIX}_${LIBPATH_SUFFIX}") + + +# Include all of the projects +INCLUDE(${PROJECT_CMAKE_FILES_DIR}/SampleBase.cmake) +INCLUDE(${PROJECT_CMAKE_FILES_DIR}/SampleAssetViewer.cmake) + + diff --git a/NvBlast/samples/compiler/cmake/windows/SampleAssetViewer-AT.cmake b/NvBlast/samples/compiler/cmake/windows/SampleAssetViewer-AT.cmake new file mode 100644 index 0000000..d0defc9 --- /dev/null +++ b/NvBlast/samples/compiler/cmake/windows/SampleAssetViewer-AT.cmake @@ -0,0 +1,7 @@ +# Copy the dlls from the deps + +ADD_CUSTOM_COMMAND(TARGET SampleAssetViewer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PXSHAREDSDK_DLLS} ${PHYSXSDK_DLLS} + ${BL_EXE_OUTPUT_DIR} +) diff --git a/NvBlast/samples/compiler/cmake/windows/SampleAssetViewer.cmake b/NvBlast/samples/compiler/cmake/windows/SampleAssetViewer.cmake new file mode 100644 index 0000000..172b2ea --- /dev/null +++ b/NvBlast/samples/compiler/cmake/windows/SampleAssetViewer.cmake @@ -0,0 +1,25 @@ +# +# Build SampleAssetViewer Windows +# + +SET(SAMPLEASSETVIEWER_PLATFORM_COMMON_FILES +) + +SET(SAMPLEASSETVIEWER_PLATFORM_INCLUDES +) + +SET(SAMPLEASSETVIEWER_COMPILE_DEFS + # Common to all configurations + ${SAMPLES_SLN_COMPILE_DEFS} + + $<$<CONFIG:debug>:${SAMPLES_SLN_DEBUG_COMPILE_DEFS}> + $<$<CONFIG:checked>:${SAMPLES_SLN_CHECKED_COMPILE_DEFS}> + $<$<CONFIG:profile>:${SAMPLES_SLN_PROFILE_COMPILE_DEFS}> + $<$<CONFIG:release>:${SAMPLES_SLN_RELEASE_COMPILE_DEFS}> +) + +SET(SAMPLEASSETVIEWER_LINK_FLAGS "/SUBSYSTEM:WINDOWS") + + +#TARGET_LINK_LIBRARIES(NvBlast PUBLIC ${NVTOOLSEXT_LIBRARIES}) +#SET_TARGET_PROPERTIES(NvBlast PROPERTIES LINK_FLAGS "/MAP" ) diff --git a/NvBlast/samples/compiler/cmake/windows/SampleBase-AT.cmake b/NvBlast/samples/compiler/cmake/windows/SampleBase-AT.cmake new file mode 100644 index 0000000..98d980b --- /dev/null +++ b/NvBlast/samples/compiler/cmake/windows/SampleBase-AT.cmake @@ -0,0 +1,7 @@ +# Copy the dlls from the deps + +ADD_CUSTOM_COMMAND(TARGET SampleBase POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PXSHAREDSDK_DLLS} ${PHYSXSDK_DLLS} ${SHADOW_LIB_DLL} ${HBAO_PLUS_DLL} ${D3DCOMPILER_DLL} + ${BL_EXE_OUTPUT_DIR} +) diff --git a/NvBlast/samples/compiler/cmake/windows/SampleBase.cmake b/NvBlast/samples/compiler/cmake/windows/SampleBase.cmake new file mode 100644 index 0000000..19133c4 --- /dev/null +++ b/NvBlast/samples/compiler/cmake/windows/SampleBase.cmake @@ -0,0 +1,21 @@ +# +# Build SampleBase Windows +# + +SET(SAMPLEBASE_PLATFORM_COMMON_FILES +) + +SET(SAMPLEBASE_PLATFORM_INCLUDES +) + +SET(SAMPLEBASE_COMPILE_DEFS + # Common to all configurations + ${SAMPLES_SLN_COMPILE_DEFS} + + $<$<CONFIG:debug>:${SAMPLES_SLN_DEBUG_COMPILE_DEFS}> + $<$<CONFIG:checked>:${SAMPLES_SLN_CHECKED_COMPILE_DEFS}> + $<$<CONFIG:profile>:${SAMPLES_SLN_PROFILE_COMPILE_DEFS}> + $<$<CONFIG:release>:${SAMPLES_SLN_RELEASE_COMPILE_DEFS}> +) + +SET(SAMPLEBASE_ADDITIONAL_DLLS "") diff --git a/NvBlast/samples/resources/configs/assets.xml b/NvBlast/samples/resources/configs/assets.xml new file mode 100644 index 0000000..6482345 --- /dev/null +++ b/NvBlast/samples/resources/configs/assets.xml @@ -0,0 +1,88 @@ +<Model file="wall" name="Model Wall (Simple)" position="0 11.5 0" rotation="1 0 0 -90"/> +<Model file="wall" name="Model Wall (Skinned)" position="0 11.5 0" rotation="1 0 0 -90" isSkinned = "true"/> +<Model file="hugeAsset" name="Tower - 38k chunks (Skinned)" position="0 0 0" rotation="1 0 0 0" isSkinned = "true"/> +<Model file="towerSubsupport1" name="Tower subsupport-1 level (Simple)" position="0 0 0" rotation="1 0 0 0" isSkinned = "false"/> +<Model file="towerSubsupport1" name="Tower subsupport-1 level (Skinned)" position="0 0 0" rotation="1 0 0 0" isSkinned = "true"/> +<Model file="towerSubsupport2" name="Tower subsupport-2 level (Skinned)" position="0 0 0" rotation="1 0 0 0" isSkinned = "true"/> +<Model file="towerSupport" name="Tower - only support (Skinned)" position="0 0 0" rotation="1 0 0 0" isSkinned = "true"/> +<Model file="vase" name="Vase (Skinned)" position="0 1 0" rotation="1 0 0 0" isSkinned = "true"/> +<Model file="table" name="Table" position="0 0.38 0" rotation="1 0 0 0"/> +<Model file="bunny" name="Bunny (Simple)"/> +<Model file="bunny" name="Bunny (Skinned)" isSkinned = "true"/> +<Model file="bunnySubsupport" name="Bunny Subsupport (Simple)"/> +<Model file="bunnySubsupport" name="Bunny Subsupport (Skinned)" isSkinned = "true"/> +<Model file="bunnySupportOn2Level" name="Bunny Support on 2nd depth (Simple)"/> +<Model file="bunnySupportOn2Level" name="Bunny Support on 2nd depth (Skinned)" isSkinned = "true"/> +<Model id="blockwall" file="blockwall" name="Block Wall" position="0 7 0" isSkinned = "false"/> + +<Composite name="Block Walls (composite)" position="0 0 0"> + <AssetRef id="blockwall" position="0 7 0" rotation="1 0 0 0" /> + <AssetRef id="blockwall" position="0 21 0" rotation="1 0 0 0" /> + <Joint asset0="0" asset1="1" chunk0="81" chunk1="70" position0="-11 7 0" position1="-11 -7 0" /> + <Joint asset0="0" asset1="1" chunk0="46" chunk1="13" position0="0 7 0" position1="0 -7 0" /> + <Joint asset0="0" asset1="1" chunk0="39" chunk1="4" position0="11 7 0" position1="11 -7 0" /> +</Composite> + +<Composite name="Lego (composite)" position="0 0 0"> + <AssetRef id="blockwall" position="-5 7 -5" /> + <AssetRef id="blockwall" position="5 7 5" /> + <AssetRef id="column" position="0 15 0" rotation="1 0 0 -90" /> + <AssetRef id="column" position="0 27 0" /> +</Composite> + +<Composite name="NRF Joints (composite)" position="0 0 0"> + <AssetRef id="column support 1" position="15 10 0" /> + <AssetRef id="column support 1" position="-15 10 0" /> + <Joint asset0="0" asset1="-1" chunk0="3" chunk1="0" position0="0 0 0" position1="15 30 0" /> + <Joint asset0="1" asset1="-1" chunk0="5" chunk1="0" position0="0 8 0" position1="-15 38 0" /> +</Composite> + +<Box name="Wall (3 depth, 625 nodes)" extents="20 20 2" staticHeight="0.5"> + <Level slices="1 1 1" /> + <Level slices="5 5 1" /> + <Level slices="5 5 1" isSupport="true" /> +</Box> + +<Box name="Wall (2 depth, 625 nodes, no root chunk)" extents="20 20 2" staticHeight="0.5"> + <Level slices="5 5 1" /> + <Level slices="5 5 1" isSupport="true" /> +</Box> + +<Box name="Poor Man's Cloth" extents="20 20 0.2" jointAllBonds = "true" > + <Level slices="1 1 1" /> + <Level slices="20 20 1" isSupport="true" /> + <Level slices="2 2 1" /> +</Box> + +<Box name="Cube (4 depth, 1728 nodes)" extents="20 20 20"> + <Level slices="1 1 1" /> + <Level slices="2 2 2" /> + <Level slices="2 2 2" /> + <Level slices="3 3 3" isSupport="true" /> +</Box> + +<Box id="column" name="Column (3 depth, 50 nodes)" extents="2 20 2"> + <Level slices="1 1 1" /> + <Level slices="1 5 1" /> + <Level slices="1 10 1" isSupport="true"/> +</Box> + +<Box id="column support 1" name="Column (3 depth, 50 nodes)" extents="2 20 2"> + <Level slices="1 1 1" /> + <Level slices="1 5 1" isSupport="true" /> + <Level slices="1 10 1" /> +</Box> + +<Box name="Cube of Layers (3 depth, 1250 nodes)" extents="20 20 20"> + <Level slices="1 1 1" /> + <Level slices="1 1 10" /> + <Level slices="5 5 5" isSupport="true"/> +</Box> + +<Box name="Brittle Wall" extents="40 20 1" staticHeight="0.5"> + <Level slices="1 1 1" /> + <Level slices="2 2 1" /> + <Level slices="2 2 1" isSupport="true"/> + <Level slices="2 2 2" /> + <Level slices="2 2 2" /> +</Box>
\ No newline at end of file diff --git a/NvBlast/samples/resources/configs/resources.xml b/NvBlast/samples/resources/configs/resources.xml new file mode 100644 index 0000000..57b709c --- /dev/null +++ b/NvBlast/samples/resources/configs/resources.xml @@ -0,0 +1,5 @@ +<project toolsVersion="3.5"> + <platform name="win"> + <dependency name="BlastSampleResources" version="21645816"/> + </platform> +</project> diff --git a/NvBlast/samples/resources/shaders/common_buffers.hlsl b/NvBlast/samples/resources/shaders/common_buffers.hlsl new file mode 100644 index 0000000..1aa3386 --- /dev/null +++ b/NvBlast/samples/resources/shaders/common_buffers.hlsl @@ -0,0 +1,28 @@ +#ifndef COMMON_BUFFERS_HLSL +#define COMMON_BUFFERS_HLSL + +cbuffer Camera : register(b0) +{ + row_major matrix viewProjection; + row_major matrix projectionInv; + float3 viewPos; +}; + +cbuffer World : register(b1) +{ + float3 ambientColor; + float3 pointLightPos; + float3 pointLightColor; + float3 dirLightDir; + float specularPower; + float3 dirLightColor; + float specularIntensity; +}; + +cbuffer Object : register(b2) +{ + row_major matrix model; + float4 defaultColor; +}; + +#endif
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/debug_primitive.hlsl b/NvBlast/samples/resources/shaders/debug_primitive.hlsl new file mode 100644 index 0000000..a24ebfb --- /dev/null +++ b/NvBlast/samples/resources/shaders/debug_primitive.hlsl @@ -0,0 +1,31 @@ +#include "common_buffers.hlsl" + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 color : COLOR0; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float3 color : COLOR0; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + float4 eyeSpacePos = mul(worldSpacePos, viewProjection); + oV.position = mul(worldSpacePos, viewProjection); + + oV.color = iV.color; + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + return float4(iV.color, 1); +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/lighting.hlsl b/NvBlast/samples/resources/shaders/lighting.hlsl new file mode 100644 index 0000000..2dacc14 --- /dev/null +++ b/NvBlast/samples/resources/shaders/lighting.hlsl @@ -0,0 +1,51 @@ +#include "common_buffers.hlsl" + +static const float att_c = 1.0f; +static const float att_l = 0.014f; +static const float att_q = 0.0007f; + + +float CalcAttenuation(float distance) +{ + return 1 / (att_c + att_l * distance + att_q * distance * distance); +}; + + +float3 CalcLight(float3 textureColor, float3 lightDir, float3 viewDir, float3 normal, float3 lightColor, float specPower, float specIntensity, float attenuation) +{ + normal = normalize(normal); + + // diffuse + float3 dirToLight = normalize(-lightDir); + float diffuseFactor = max(dot(normal, dirToLight), 0.0); + float3 diffuse = lightColor * textureColor * diffuseFactor * attenuation; + + // specular (Blinn-Phong) + float3 halfwayDir = normalize(dirToLight + viewDir); + float specFactor = pow(max(dot(viewDir, halfwayDir), 0.0), specPower); + float3 spec = lightColor * specFactor * attenuation * specIntensity; + + return diffuse + spec; +}; + +float3 CalcPixelLight(float3 diffuseColor, float3 worldPos, float3 normal) +{ + float3 viewDir = normalize(viewPos - worldPos); + + // ambient + float3 ambient = ambientColor * diffuseColor; + + // dir light + float3 dirLight = CalcLight(diffuseColor, dirLightDir, viewDir, normal, dirLightColor, specularPower, specularIntensity, 1); + + // point light + float3 pointLightDir = worldPos - pointLightPos; + float distance = length(pointLightDir); + float attenuation = CalcAttenuation(distance); + float3 pointLight = CalcLight(diffuseColor, pointLightDir, viewDir, normal, pointLightColor, specularPower, specularIntensity, attenuation); + + // hacky hack: ambient attenuates within point light distance + ambient *= attenuation; + + return ambient + dirLight + pointLight; +};
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/model_simple.hlsl b/NvBlast/samples/resources/shaders/model_simple.hlsl new file mode 100644 index 0000000..7d55a72 --- /dev/null +++ b/NvBlast/samples/resources/shaders/model_simple.hlsl @@ -0,0 +1,42 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; + float health : TEXCOORD1; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 worldPos : POSITION0; + float3 normal : NORMAL0; + float health : TEXCOORD1; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.worldPos = worldSpacePos; + + // normals + float3 worldNormal = mul(iV.normal, (float3x3)model); + oV.normal = worldNormal; + + oV.health = iV.health; + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + float3 lightColor = CalcPixelLight(defaultColor.xyz, iV.worldPos.xyz, iV.normal); + lightColor.r = 1.0f - iV.health; // hack for health + return float4(lightColor, 1); +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/model_simple_textured.hlsl b/NvBlast/samples/resources/shaders/model_simple_textured.hlsl new file mode 100644 index 0000000..5167837 --- /dev/null +++ b/NvBlast/samples/resources/shaders/model_simple_textured.hlsl @@ -0,0 +1,76 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +SamplerState defaultSampler : register(s0); +Texture2D diffuseTexture : register(t0); + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; + float2 uv : TEXCOORD0; + float health : TEXCOORD1; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 worldPos : POSITION0; + float2 uv : TEXCOORD0; + float3 normal : NORMAL0; + float health : TEXCOORD1; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.worldPos = worldSpacePos; + + // normals + float3 worldNormal = mul(float4(iV.normal, 0.0f), model); + oV.normal = worldNormal; + + oV.uv = iV.uv; + oV.health = iV.health; + + return oV; +} + +float noise2(float2 co) +{ + return frac(sin(dot(co.xy, float2(12.9898,78.233))) * 43758.5453); +} + +float voronoi( float2 x ) +{ + int2 p = floor( x ); + float2 f = frac( x ); + + float res = 8.0; + for( int j=-1; j<=1; j++ ) + for( int i=-1; i<=1; i++ ) + { + int2 b = int2( i, j ); + float2 r = float2( b ) - f + noise2( p + b ); + float d = dot( r, r ); + + res = min( res, d ); + } + return sqrt( res ); +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + float4 textureColor = diffuseTexture.Sample(defaultSampler, iV.uv); + + // health cracks hack + float crack = 1.0f - voronoi(iV.uv * 50.0f); + crack = smoothstep(0.0f, 0.5f, crack); + textureColor = textureColor * lerp(1.0f, crack, (1.0f - iV.health) * 0.7f); + + return float4(CalcPixelLight(textureColor, iV.worldPos, iV.normal), 1); +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/model_skinned.hlsl b/NvBlast/samples/resources/shaders/model_skinned.hlsl new file mode 100644 index 0000000..1e26c95 --- /dev/null +++ b/NvBlast/samples/resources/shaders/model_skinned.hlsl @@ -0,0 +1,54 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +SamplerState defaultSampler : register(s0); +Texture2D diffuseTexture : register(t0); +Texture2D bonesTexture : register(t1); + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; + float2 uv : TEXCOORD0; + uint boneIndex : TEXCOORD1; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 worldPos : POSITION0; + float2 uv : TEXCOORD0; + float3 normal : NORMAL0; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4x4 boneMatrix; + boneMatrix[0] = bonesTexture.Load(int3(0, iV.boneIndex, 0)); + boneMatrix[1] = bonesTexture.Load(int3(1, iV.boneIndex, 0)); + boneMatrix[2] = bonesTexture.Load(int3(2, iV.boneIndex, 0)); + boneMatrix[3] = bonesTexture.Load(int3(3, iV.boneIndex, 0)); + + float3 skinnedPos = mul(float4(iV.position, 1.0f), boneMatrix); + float4 worldSpacePos = mul(float4(skinnedPos, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.worldPos = worldSpacePos; + + // normals + float3 localNormal = mul(float4(iV.normal, 0.0f), boneMatrix); + float3 worldNormal = mul(float4(localNormal, 0.0f), model); + oV.normal = worldNormal; + + oV.uv = iV.uv; + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + float3 lightColor = CalcPixelLight(defaultColor.xyz, iV.worldPos.xyz, iV.normal); + return float4(lightColor, 1); +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/model_skinned_textured.hlsl b/NvBlast/samples/resources/shaders/model_skinned_textured.hlsl new file mode 100644 index 0000000..2b2bb0e --- /dev/null +++ b/NvBlast/samples/resources/shaders/model_skinned_textured.hlsl @@ -0,0 +1,54 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +SamplerState defaultSampler : register(s0); +Texture2D diffuseTexture : register(t0); +Texture2D bonesTexture : register(t1); + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; + float2 uv : TEXCOORD0; + uint boneIndex : TEXCOORD1; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 worldPos : POSITION0; + float2 uv : TEXCOORD0; + float3 normal : NORMAL0; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4x4 boneMatrix; + boneMatrix[0] = bonesTexture.Load(int3(0, iV.boneIndex, 0)); + boneMatrix[1] = bonesTexture.Load(int3(1, iV.boneIndex, 0)); + boneMatrix[2] = bonesTexture.Load(int3(2, iV.boneIndex, 0)); + boneMatrix[3] = bonesTexture.Load(int3(3, iV.boneIndex, 0)); + + float3 skinnedPos = mul(float4(iV.position, 1.0f), boneMatrix); + float4 worldSpacePos = mul(float4(skinnedPos, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.worldPos = worldSpacePos; + + // normals + float3 localNormal = mul(float4(iV.normal, 0.0f), boneMatrix); + float3 worldNormal = mul(float4(localNormal, 0.0f), model); + oV.normal = worldNormal; + + oV.uv = iV.uv; + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + float4 textureColor = diffuseTexture.Sample(defaultSampler, iV.uv); + return float4(CalcPixelLight(textureColor, iV.worldPos, iV.normal), 1); +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/physx_primitive.hlsl b/NvBlast/samples/resources/shaders/physx_primitive.hlsl new file mode 100644 index 0000000..03fd137 --- /dev/null +++ b/NvBlast/samples/resources/shaders/physx_primitive.hlsl @@ -0,0 +1,37 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 worldPos : POSITION0; + float3 normal : NORMAL0; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.worldPos = worldSpacePos; + + // normals + float3 worldNormal = mul(iV.normal, (float3x3)model); + oV.normal = worldNormal; + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + float3 lightColor = CalcPixelLight(defaultColor.xyz, iV.worldPos.xyz, iV.normal); + return float4(lightColor, 1); +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/physx_primitive_plane.hlsl b/NvBlast/samples/resources/shaders/physx_primitive_plane.hlsl new file mode 100644 index 0000000..3b2ec5d --- /dev/null +++ b/NvBlast/samples/resources/shaders/physx_primitive_plane.hlsl @@ -0,0 +1,64 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; + float2 uv : TEXCOORD0; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 worldPos : POSITION0; + float2 uv : TEXCOORD0; + float3 normal : NORMAL0; +}; + +float filterwidth(float2 v) +{ + float2 fw = max(abs(ddx(v)), abs(ddy(v))); + return max(fw.x, fw.y); +} + +float2 bump(float2 x) +{ + return (floor(x/2) + 2.f * max((x/2) - floor(x/2) - .5f, 0.f)); +} + +float checker(float2 uv) +{ + float width = filterwidth(uv); + float2 p0 = uv - 0.5 * width; + float2 p1 = uv + 0.5 * width; + + float2 i = (bump(p1) - bump(p0)) / width; + return i.x * i.y + (1 - i.x) * (1 - i.y); +} + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.uv = iV.uv; + + oV.worldPos = worldSpacePos; + + // normals + float3 worldNormal = mul(iV.normal, (float3x3)model); + oV.normal = worldNormal; + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + float4 color = defaultColor; + color *= 1.0 - 0.25 * checker(iV.uv); + float3 lightColor = CalcPixelLight(color.xyz, iV.worldPos.xyz, iV.normal); + return float4(lightColor, 1); +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/physx_primitive_transparent.hlsl b/NvBlast/samples/resources/shaders/physx_primitive_transparent.hlsl new file mode 100644 index 0000000..d52392e --- /dev/null +++ b/NvBlast/samples/resources/shaders/physx_primitive_transparent.hlsl @@ -0,0 +1,40 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 worldPos : POSITION0; + float3 normal : NORMAL0; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.worldPos = worldSpacePos; + + // normals + float3 worldNormal = mul(iV.normal, (float3x3)model); + oV.normal = worldNormal; + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + float4 color = defaultColor; + float3 viewDir = normalize(viewPos - iV.worldPos.xyz); + float factor = max(0.0f, dot(normalize(iV.normal), viewDir)); + color.a *= factor; + return color; +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/pointsprite.hlsl b/NvBlast/samples/resources/shaders/pointsprite.hlsl new file mode 100644 index 0000000..2bff194 --- /dev/null +++ b/NvBlast/samples/resources/shaders/pointsprite.hlsl @@ -0,0 +1,106 @@ +#include "common_buffers.hlsl" +#include "lighting.hlsl" + +SamplerState linearSampler : register(s0); +SamplerState pointSampler : register(s1); +Texture2D diffuseTexture : register(t0); +Texture2D<float> depthTexture : register(t1); + +static const float POINT_SIZE = 1.00f; +static const float FADE_DISTANCE = 1.0f; + +struct VS_INPUT +{ + float3 position : POSITION0; + float4 color : COLOR0; + float2 scale : TANGENT; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; + float4 color : COLOR0; + float2 uv : TEXCOORD0; + float2 screenPos : TEXCOORD1; + float2 depth : TEXCOORD2; + float2 pointSize : PSIZE; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + oV.color = iV.color; + oV.uv = float2(0, 0); + + // uncomment to use scale + //oV.pointSize = iV.scale * POINT_SIZE; + oV.pointSize = float2(1, 1) * POINT_SIZE; + + return oV; +} + +static const float4 SPRITE_VERTEX_POSITIONS[4] = +{ + float4( 0.5, -0.5, 0, 0), + float4( 0.5, 0.5, 0, 0), + float4( -0.5, -0.5, 0, 0), + float4( -0.5, 0.5, 0, 0), +}; + +static const float2 SPRITE_VERTEX_TEXCOORDS[4] = +{ + float2(1, 0), + float2(1, 1), + float2(0, 0), + float2(0, 1), +}; + +[maxvertexcount(4)] +void GS( point VS_OUTPUT sprite[1], inout TriangleStream<VS_OUTPUT> triStream ) +{ + VS_OUTPUT v; + + v.color = sprite[0].color; + v.pointSize = sprite[0].pointSize; + + float4 aspectFactor = float4((projection[0][0] / projection[1][1]) * v.pointSize.x, 1.0 * v.pointSize.y, 0, 0); + + [unroll] for(int i = 0; i < 4; ++i) + { + v.position = sprite[0].position + SPRITE_VERTEX_POSITIONS[i] * aspectFactor; + v.screenPos = v.position.xy / v.position.w; + v.depth = v.position.zw; + v.uv = SPRITE_VERTEX_TEXCOORDS[i]; + triStream.Append(v); + } + + triStream.RestartStrip(); +} + +float4 PS(VS_OUTPUT input) : SV_Target0 +{ + // soft particles fade: + float2 screenPos = 0.5*( (input.screenPos) + float2(1,1)); + screenPos.y = 1 - screenPos.y; + + float particleDepth = input.depth.x / input.depth.y; + + float depthSample = depthTexture.Sample(pointSampler, screenPos); + + float4 depthViewSample = mul(float4(input.screenPos, depthSample, 1), projectionInv ); + float4 depthViewParticle = mul(float4(input.screenPos, particleDepth, 1), projectionInv); + + float depthDiff = depthViewSample.z / depthViewSample.w - depthViewParticle.z / depthViewParticle.w; + if( depthDiff < 0 ) + discard; + + float depthFade = saturate( depthDiff / FADE_DISTANCE ); + + float4 textureColor = diffuseTexture.Sample(linearSampler, input.uv) * input.color; + textureColor.a *= depthFade; + return textureColor; +}
\ No newline at end of file diff --git a/NvBlast/samples/resources/shaders/unlit_transparent.hlsl b/NvBlast/samples/resources/shaders/unlit_transparent.hlsl new file mode 100644 index 0000000..0c2158a --- /dev/null +++ b/NvBlast/samples/resources/shaders/unlit_transparent.hlsl @@ -0,0 +1,27 @@ +#include "common_buffers.hlsl" + +struct VS_INPUT +{ + float3 position : POSITION0; + float3 normal : NORMAL0; +}; + +struct VS_OUTPUT +{ + float4 position : SV_POSITION; +}; + +VS_OUTPUT VS(VS_INPUT iV) +{ + VS_OUTPUT oV; + + float4 worldSpacePos = mul(float4(iV.position, 1.0f), model); + oV.position = mul(worldSpacePos, viewProjection); + + return oV; +} + +float4 PS(VS_OUTPUT iV) : SV_Target0 +{ + return defaultColor; +}
\ No newline at end of file |