diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/internal/include | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'APEX_1.4/shared/internal/include')
16 files changed, 6957 insertions, 0 deletions
diff --git a/APEX_1.4/shared/internal/include/ApexSharedSerialization.h b/APEX_1.4/shared/internal/include/ApexSharedSerialization.h new file mode 100644 index 00000000..20e8c1d4 --- /dev/null +++ b/APEX_1.4/shared/internal/include/ApexSharedSerialization.h @@ -0,0 +1,809 @@ +/* + * 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 __APEXSHAREDSERIALIZATION_H__ +#define __APEXSHAREDSERIALIZATION_H__ + +#include "Apex.h" +#include "ApexStream.h" +#include "ApexString.h" +#include "ApexSharedUtils.h" +#include "ApexSDKIntl.h" +#include "nvparameterized/NvParameterized.h" + +namespace nvidia +{ +namespace apex +{ + +struct ApexStreamVersion +{ + enum Enum + { + First = 0, + ConsolidatedSubmeshes = 1, + TriangleFlags = 2, + ConvexHull_VolumeStreamed = 3, + AddedDestrucibleDeformation = 4, + RemovedParticleSizeFromDestructibleParameters = 5, + TriangleFlagsChangedToExtraDataIndex = 6, + ConvexHull_EdgesStreamed = 7, + AddedDestrucibleDebrisParamaters = 8, + DestrucibleDebrisParamatersHaveLODRange = 9, + UniversalNamedAssetHeader = 10, + ClothMeshBindPoses = 10, // PH: This is not a mistake, this enum was added in another branch while other enums were added in //trunk + VariableVertexData = 11, + SoftBodyNormalsStreamed = 11, // PH: This is not a mistake, this enum was added in another branch while other enums were added in //trunk + UsingApexMaterialLibrary_and_NoFlagsInRenderTriangle = 12, + AddingTextureTypeInformationToVertexFormat = 13, + SoftBodyNormalsInTetraLink = 14, + ClothingVertexFlagsStreamed = 15, + ConvexHullModifiedForEfficientCollisionTests = 16, + RenderMeshAssetRedesign = 17, + FixedSerializationAfterRenderMeshAssetRedesign = 18, + AddedRenderCullModeToRenderMeshAsset = 19, + AddedTextureUVOriginField = 19, // BRG: merge conflict + AddedDynamicVertexBufferField = 20, + RenderMeshAssetBufferOverrunFix = 21, + CleanupOfApexRenderMesh = 22, + RemovedTextureTypeInformationFromVertexFormat = 23, + AddedDestructibleFlag_FormExtendedStructures = 24, + MarkingDestructibleChunksWithFlagToDenoteUnfracturableDescendant = 25, + AddedValidBoundsToDestructibleParameters = 26, + ReducingAssetUponDeserializationForReducedLOD = 27, + AddedDustMeshParticleFactoryNameToDestructibleAsset = 28, + AddedChunkSurfaceTracesToDestructibleAsset = 29, + AddedInteriorSubmeshIndexToDestructibleAsset = 30, + AddedMaxChunkSpeedAndMassScaleExponentToDestructibleAsset = 31, + AddedGrbVolumeLimit = 32, + Removing_rollSign_and_rollAxis_fromAPI = 33, + AddedFractureImpulseScale = 34, + AddedMissingRuntimeFlagsAndAlsoTraceSetAverageNormalToDestructibleAssetStream = 35, + CachingChunkOverlapDataInDestructibleAsset = 36, + AddedRotationCaps = 37, + AddedImpactVelocityThreshold = 37, // SJB: Trust me, this should be 37 + ChangedVertexColorFormatToReal = 38, + AddedEssentialDepthParameter = 39, + AddedSeparateBoneBufferFlagToRenderMeshAsset = 40, + DoNotNormalizeBoneWeightsOnLoad = 41, // PH: This is a change for deserialization only, we don't need to do additional processing when newer than this + MovedChunkSurfaceNormalFromTraceSetToChunk = 41, + FlattenedVertexBuffer = 42, + RemovedSubmeshTriangleStruct = 43, + DestructibleAssetRearrangementForParameterization = 44, + AddedDestructibleMaterialStrength = 45, + ExposedChunkNeighborPadding = 46, + ChangedVertexFormat = 47, + UnifiedCustomAndStandardSemantics = 48, + AddedAdjacentPlanesToConvexHullStream = 49, + // Always add a new version just before this line + + Count, + Current = Count - 1 + }; +}; + +/*****************************************************************************/ +// Non-versioned data (e.g. basic types) may use the << and >> operators +// defined in ApexStream.h. This file contains (de)serialization for +// versioned data. +// +// Serialization version is written "upstream" by a versioned parent object. +// To add the version number to the streamed data for an object, record this +// change in the ApexStreamVersion enum, and add the line: +// stream << (uint32_t)ApexStreamVersion_Current; +// to the serialize function. +// +// Serialization signature: +// void serialize( physx::PxFileBuf& stream, const typename& object ) +// +// Deserialization signature: +// void deserialize( physx::PxFileBuf& stream, uint32_t version, typename& object ) +/*****************************************************************************/ + + +// Template foo +PX_INLINE void serialize(physx::PxFileBuf& stream, const ExplicitRenderTriangle& t); +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, ExplicitRenderTriangle& t); +PX_INLINE void serialize(physx::PxFileBuf& stream, const VertexUV& uv); +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, VertexUV& uv); +PX_INLINE void serialize(physx::PxFileBuf& stream, const Vertex& v); +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, Vertex& v); +PX_INLINE void serialize(physx::PxFileBuf& stream, const ApexSimpleString& s); +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, ApexSimpleString& s); +PX_INLINE void serialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + const NvParameterized::Interface* param, + NvParameterized::Handle& childHandle); +PX_INLINE void serialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + const NvParameterized::Interface* param, + const char* memberName, + NvParameterized::Handle* structHandle = NULL); +PX_INLINE void deserialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + NvParameterized::Interface* param, + NvParameterized::Handle& childHandle); +PX_INLINE void deserialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + NvParameterized::Interface* param, + const char* memberName, + NvParameterized::Handle* structHandle = NULL); + +// Utility to write an APEX asset stream header +PX_INLINE void serializeCurrentApexStreamVersion(physx::PxFileBuf& stream, const ApexSimpleString& assetTypeName, uint32_t assetVersion) +{ + stream << (uint32_t)ApexStreamVersion::Current; + serialize(stream, assetTypeName); + stream << assetVersion; +} + +// Utility to read version header from the start of an APEX asset stream +PX_INLINE ApexStreamVersion::Enum deserializeApexStreamVersion(physx::PxFileBuf& stream, const ApexSimpleString& assetTypeName, uint32_t& assetVersion) +{ + uint32_t headerVersion; + stream >> headerVersion; + if (headerVersion > ApexStreamVersion::Current) + { + APEX_INTERNAL_ERROR("Stream version (%d) is newer than this library (%d)", headerVersion, ApexStreamVersion::Current); + PX_ALWAYS_ASSERT(); + } + else if (headerVersion >= ApexStreamVersion::UniversalNamedAssetHeader) + { + ApexSimpleString streamedName; + deserialize(stream, headerVersion, streamedName); + if (streamedName == assetTypeName) + { + stream >> assetVersion; + } + else + { + APEX_INTERNAL_ERROR("Asset type name mismatch. File <%s> != asset name <%s>", + assetTypeName.c_str(), streamedName.c_str()); + PX_ALWAYS_ASSERT(); + } + } + return (ApexStreamVersion::Enum)headerVersion; +} + +// Utility to read version header from the start of an APEX asset stream, when the type is unknown +PX_INLINE ApexStreamVersion::Enum deserializeGenericApexStreamVersion(physx::PxFileBuf& stream, ApexSimpleString& outAssetTypeName, uint32_t& outAssetVersion) +{ + uint32_t headerVersion; + stream >> headerVersion; + + if (headerVersion > ApexStreamVersion::Current) + { + APEX_INTERNAL_ERROR("Stream version (%d) is newer than this library (%d)", headerVersion, ApexStreamVersion::Current); + PX_ALWAYS_ASSERT(); + } + else if (headerVersion >= ApexStreamVersion::UniversalNamedAssetHeader) + { + ApexSimpleString streamedName; + deserialize(stream, headerVersion, outAssetTypeName); + stream >> outAssetVersion; + } + else + { + APEX_INTERNAL_ERROR("Stream version (%d) does not contain a universal named asset header, " \ + "use a specific asset creation method to load this asset", headerVersion); + PX_ALWAYS_ASSERT(); + } + return (ApexStreamVersion::Enum)headerVersion; +} + +// Versioned wrappers for non-versioned data +template <class T> PX_INLINE void serialize(physx::PxFileBuf& stream, const T& t) +{ + stream << t; +} + +template <class T> PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, T& t) +{ + PX_UNUSED(version); + stream >> t; +} + + +// physx::Array<T> +template <class T> PX_INLINE void serialize(physx::PxFileBuf& stream, const physx::Array<T>& array) +{ + const uint32_t size = array.size(); + stream << size; + for (uint32_t i = 0; i < size; ++i) + { + serialize(stream, array[i]); + } +} + +template <class T> PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, physx::Array<T>& array) +{ + uint32_t size; + stream >> size; + array.resize(size); + for (uint32_t i = 0; i < size; ++i) + { + deserialize(stream, version, array[i]); + } +} + +// Several serialized objects have multiple associated versions +template <class T> PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version0, uint32_t version1, physx::Array<T>& array) +{ + uint32_t size; + stream >> size; + array.resize(size); + for (uint32_t i = 0; i < size; ++i) + { + deserialize(stream, version0, version1, array[i]); + } +} + +// VertexUV +PX_INLINE void serialize(physx::PxFileBuf& stream, const VertexUV& uv) +{ + stream << uv.u << uv.v; +} + +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, VertexUV& uv) +{ + // original version + PX_UNUSED(version); + stream >> uv.u >> uv.v; +} + + +// VertexColor +PX_INLINE void serialize(physx::PxFileBuf& stream, const VertexColor& c) +{ + stream << c.r << c.g << c.b << c.a; +} + +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, VertexColor& c) +{ + // original version + PX_UNUSED(version); + stream >> c.r >> c.g >> c.b >> c.a; +} + + +// Vertex +PX_INLINE void serialize(physx::PxFileBuf& stream, const Vertex& v) +{ + // + stream << v.position << v.normal << v.tangent << v.binormal; + serialize(stream, v.uv[0]); + serialize(stream, v.uv[1]); + serialize(stream, v.uv[2]); + serialize(stream, v.uv[3]); + serialize(stream, v.color); + for (uint32_t i = 0; i < 4; i++) + { + stream << v.boneIndices[i]; + stream << v.boneWeights[i]; + } +} + +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, Vertex& v) +{ + if (version < ApexStreamVersion::RenderMeshAssetRedesign) + { + // set all other indices and weights to 0 + v.boneWeights[0] = 1.0f; + for (uint32_t i = 1; i < 4; i++) + { + v.boneIndices[i] = 0; + v.boneWeights[i] = 0.0f; + } + } + + if (version >= ApexStreamVersion::VariableVertexData) + { + stream >> v.position >> v.normal >> v.tangent >> v.binormal; + deserialize(stream, version, v.uv[0]); + deserialize(stream, version, v.uv[1]); + deserialize(stream, version, v.uv[2]); + deserialize(stream, version, v.uv[3]); + if (version >= ApexStreamVersion::ChangedVertexColorFormatToReal) + { + deserialize(stream, version, v.color); + } + else + { + uint32_t intColor; + stream >> intColor; + v.color = VertexColor(ColorRGBA((uint8_t)(intColor & 255), (uint8_t)((intColor >> 8) & 255), (uint8_t)((intColor >> 16) & 255), (uint8_t)(intColor >> 24))); + } + if (version >= ApexStreamVersion::RenderMeshAssetRedesign) + { + for (uint32_t i = 0; i < 4; i++) + { + stream >> v.boneIndices[i]; + stream >> v.boneWeights[i]; + } + if (version < ApexStreamVersion::RenderMeshAssetBufferOverrunFix) + { + uint16_t dummyU16; + float dummyF32; + for (uint32_t i = 0; i < 4; i++) + { + stream >> dummyU16; + stream >> dummyF32; + } + } + } + else + { + uint32_t boneIndex; + stream >> boneIndex; + v.boneIndices[0] = (uint16_t)boneIndex; + } + } + else + { + stream >> v.position >> v.normal >> v.tangent >> v.binormal >> v.uv[0][0] >> v.uv[0][1]; + uint32_t intColor; + stream >> intColor; + v.color = VertexColor(ColorRGBA((uint8_t)(intColor & 255), (uint8_t)((intColor >> 8) & 255), (uint8_t)((intColor >> 16) & 255), (uint8_t)(intColor >> 24))); + stream >> v.boneIndices[0]; + } +} + + +// ExplicitRenderTriangle +PX_INLINE void serialize(physx::PxFileBuf& stream, const ExplicitRenderTriangle& t) +{ + serialize(stream, t.vertices[0]); + serialize(stream, t.vertices[1]); + serialize(stream, t.vertices[2]); + stream << t.submeshIndex << t.smoothingMask << t.extraDataIndex; +} + +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, ExplicitRenderTriangle& t) +{ + deserialize(stream, version, t.vertices[0]); + deserialize(stream, version, t.vertices[1]); + deserialize(stream, version, t.vertices[2]); + stream >> t.submeshIndex >> t.smoothingMask; + if (version >= ApexStreamVersion::TriangleFlagsChangedToExtraDataIndex) + { + stream >> t.extraDataIndex; + } + else + { + if (version >= ApexStreamVersion::TriangleFlags) + { + uint32_t deadData; + stream >> deadData; + } + t.extraDataIndex = 0xFFFFFFFF; + } +} + +// ApexSimpleString +PX_INLINE void serialize(physx::PxFileBuf& stream, const ApexSimpleString& s) +{ + s.serialize(stream); + //stream << s.len(); + //stream.storeBuffer( s.c_str(), s.len() ); +} + +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, ApexSimpleString& s) +{ + PX_UNUSED(version); + s.deserialize(stream); +} + + +// ConvexHullImpl +PX_INLINE void serialize(physx::PxFileBuf& stream, const ConvexHullImpl& h) +{ + if (h.mParams == NULL) + { + PX_ASSERT(!"Attempting to serialize a ConvexHullImpl with NULL NvParameters."); + return; + } + + Array<physx::PxVec3> vertices; + Array<physx::PxPlane> uniquePlanes; + Array<uint32_t> edges; + Array<uint32_t> adjacentFaces; + Array<float> widths; + + NvParameterized::Handle handle(*h.mParams); + + // vertices + vertices.resize((uint32_t)h.mParams->vertices.arraySizes[0]); + h.mParams->getParameterHandle("vertices", handle); + h.mParams->getParamVec3Array(handle, vertices.begin(), (int32_t)vertices.size()); + serialize(stream, vertices); + + // uniquePlanes + uniquePlanes.resize((uint32_t)h.mParams->uniquePlanes.arraySizes[0]); + for (uint32_t i = 0; i < (uint32_t)h.mParams->uniquePlanes.arraySizes[0]; ++i) + { + ConvexHullParametersNS::Plane_Type& plane = h.mParams->uniquePlanes.buf[i]; + uniquePlanes[i] = physx::PxPlane(plane.normal, plane.d); + } + serialize(stream, uniquePlanes); + + // bounds + stream << h.mParams->bounds; + + // volume + stream << h.mParams->volume; + + // edges + edges.resize((uint32_t)h.mParams->edges.arraySizes[0]); + h.mParams->getParameterHandle("edges", handle); + h.mParams->getParamU32Array(handle, edges.begin(), (int32_t)edges.size()); + serialize(stream, edges); + + // adjacentFaces + adjacentFaces.resize((uint32_t)h.mParams->adjacentFaces.arraySizes[0]); + h.mParams->getParameterHandle("adjacentFaces", handle); + h.mParams->getParamU32Array(handle, adjacentFaces.begin(), (int32_t)adjacentFaces.size()); + serialize(stream, adjacentFaces); + + // widths + widths.resize((uint32_t)h.mParams->widths.arraySizes[0]); + h.mParams->getParameterHandle("widths", handle); + h.mParams->getParamF32Array(handle, widths.begin(), (int32_t)widths.size()); + serialize(stream, widths); + + // unique direction count + stream << h.mParams->uniqueEdgeDirectionCount; + + // plane count + stream << h.mParams->planeCount; +} + +PX_INLINE void deserialize(physx::PxFileBuf& stream, uint32_t version, ConvexHullImpl& h) +{ + if (h.mParams == NULL) + { + h.init(); + } + + Array<physx::PxVec3> vertices; + Array<physx::PxPlane> uniquePlanes; + Array<uint32_t> edges; + Array<uint32_t> adjacentFaces; + Array<float> widths; + + NvParameterized::Handle handle(*h.mParams); + + // vertices + deserialize(stream, version, vertices); + h.mParams->getParameterHandle("vertices", handle); + h.mParams->resizeArray(handle, (int32_t)vertices.size()); + h.mParams->setParamVec3Array(handle, vertices.begin(), (int32_t)vertices.size()); + + // uniquePlanes + deserialize(stream, version, uniquePlanes); + h.mParams->getParameterHandle("uniquePlanes", handle); + h.mParams->resizeArray(handle, (int32_t)uniquePlanes.size()); + for (uint32_t i = 0; i < uniquePlanes.size(); ++i) + { + physx::PxPlane& plane = uniquePlanes[i]; + ConvexHullParametersNS::Plane_Type& paramPlane = h.mParams->uniquePlanes.buf[i]; + paramPlane.normal = plane.n; + paramPlane.d = plane.d; + } + + // bounds + stream >> h.mParams->bounds; + + // volume + if (version >= ApexStreamVersion::ConvexHull_VolumeStreamed) + { + stream >> h.mParams->volume; + } + + bool needsRebuild = false; + + if (version >= ApexStreamVersion::ConvexHull_EdgesStreamed) + { + // edges + deserialize(stream, version, edges); + h.mParams->getParameterHandle("edges", handle); + h.mParams->resizeArray(handle, (int32_t)edges.size()); + h.mParams->setParamU32Array(handle, edges.begin(), (int32_t)edges.size()); + + if (version >= ApexStreamVersion::AddedAdjacentPlanesToConvexHullStream) + { + // adjacentFaces + deserialize(stream, version, adjacentFaces); + h.mParams->getParameterHandle("adjacentFaces", handle); + h.mParams->resizeArray(handle, (int32_t)adjacentFaces.size()); + h.mParams->setParamU32Array(handle, adjacentFaces.begin(), (int32_t)adjacentFaces.size()); + } + else + { + needsRebuild = true; + } + + if (version >= ApexStreamVersion::ConvexHullModifiedForEfficientCollisionTests) + { + // widths + deserialize(stream, version, widths); + h.mParams->getParameterHandle("widths", handle); + h.mParams->resizeArray(handle, (int32_t)widths.size()); + h.mParams->setParamF32Array(handle, widths.begin(), (int32_t)widths.size()); + + // unique direction count + stream >> h.mParams->uniqueEdgeDirectionCount; + + // plane count + stream >> h.mParams->planeCount; + } + else + { + // Fix up + // Ouch - rebuilding! + // \todo - issue load performance warning + h.buildFromPoints(vertices.begin(), vertices.size(), sizeof(physx::PxVec3)); + } + } + else + { + needsRebuild = true; + } + + if (needsRebuild) + { + // Ouch - rebuilding! + // \todo - issue load performance warning + h.buildFromPoints(vertices.begin(), vertices.size(), sizeof(physx::PxVec3)); + } +} + +// PxParamerized F32, U32, string, enum, and named ref +PX_INLINE void serialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + const NvParameterized::Interface* param, + NvParameterized::Handle& childHandle) +{ + PX_UNUSED(headerVersion); + PX_UNUSED(param); + PX_ASSERT(childHandle.getConstInterface() == param); + + ApexSimpleString tmpString; + + if (childHandle.parameterDefinition()->type() == NvParameterized::TYPE_REF) + { + // named reference (we should check that it is not INCLUDED) + + NvParameterized::Interface* childParamPtr = 0; + + // just in case it wasn't initialized + //if( param->initParamRef(childHandle, NULL, true) != NvParameterized::ERROR_NONE ) + //{ + // return; + //} + + childHandle.getParamRef(childParamPtr); + + if (!childParamPtr) //Special case hack... + { + childHandle.initParamRef(NULL, true); + childHandle.getParamRef(childParamPtr); + } + + if (childParamPtr) + { + tmpString = childParamPtr->className(); + tmpString.serialize(stream); + + tmpString = childParamPtr->name(); + tmpString.serialize(stream); + } + } + else if (childHandle.parameterDefinition()->type() == NvParameterized::TYPE_STRING) + { + const char* str; + childHandle.getParamString(str); + tmpString = str; + tmpString.serialize(stream); + } + else if (childHandle.parameterDefinition()->type() == NvParameterized::TYPE_ENUM) + { + const char* str; + childHandle.getParamEnum(str); + tmpString = str; + tmpString.serialize(stream); + } + else + { + switch (childHandle.parameterDefinition()->type()) + { + case NvParameterized::TYPE_VEC3: + { + physx::PxVec3 d; + childHandle.getParamVec3(d); + stream << d; + break; + } + case NvParameterized::TYPE_F32: + { + float d; + childHandle.getParamF32(d); + stream << d; + break; + } + case NvParameterized::TYPE_U32: + { + uint32_t d; + childHandle.getParamU32(d); + stream << d; + break; + } + case NvParameterized::TYPE_BOOL: + { + bool d; + childHandle.getParamBool(d); + if (d) + { + stream.storeByte((uint8_t)1); + } + else + { + stream.storeByte((uint8_t)0); + } + break; + } + default: + PX_ALWAYS_ASSERT(); + } + } +} + +PX_INLINE void serialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + const NvParameterized::Interface* param, + const char* memberName, + NvParameterized::Handle* structHandle) +{ + PX_UNUSED(headerVersion); + + NvParameterized::Handle childHandle(*param); + if (structHandle) + { + structHandle->getChildHandle(param, memberName, childHandle); + } + else + { + param->getParameterHandle(memberName, childHandle); + } + + serialize(stream, headerVersion, param, childHandle); +} + + +// PxParamerized F32, U32, string, enum, and named ref +// PxParamerized F32, U32, string, enum, and named ref +PX_INLINE void deserialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + NvParameterized::Interface* param, + NvParameterized::Handle& childHandle) +{ + PX_UNUSED(param); + PX_ASSERT(childHandle.getConstInterface() == param); + ApexSimpleString tmpString; + + if (childHandle.parameterDefinition()->type() == NvParameterized::TYPE_REF) + { + deserialize(stream, headerVersion, tmpString); + + // named reference (we should check that it is not INCLUDED + NvParameterized::Interface* childParamPtr = 0; + + // tmpString is the className (asset authorable name) + childHandle.initParamRef(tmpString.c_str(), true); + childHandle.getParamRef(childParamPtr); + + PX_ASSERT(childParamPtr); + if (childParamPtr) + { + deserialize(stream, headerVersion, tmpString); + childParamPtr->setName(tmpString.c_str()); + } + + } + else if (childHandle.parameterDefinition()->type() == NvParameterized::TYPE_STRING) + { + deserialize(stream, headerVersion, tmpString); + childHandle.setParamString(tmpString.c_str()); + } + else if (childHandle.parameterDefinition()->type() == NvParameterized::TYPE_ENUM) + { + deserialize(stream, headerVersion, tmpString); + if (childHandle.setParamEnum(tmpString.c_str()) != NvParameterized::ERROR_NONE) + { + APEX_DEBUG_WARNING("NvParameterized ENUM value not correct: %s, substituting: %s", \ + tmpString.c_str(), childHandle.parameterDefinition()->enumVal(0)); + + childHandle.setParamEnum(childHandle.parameterDefinition()->enumVal(0)); + } + + } + else + { + switch (childHandle.parameterDefinition()->type()) + { + case NvParameterized::TYPE_VEC3: + { + physx::PxVec3 d; + stream >> d; + childHandle.setParamVec3(d); + break; + } + case NvParameterized::TYPE_F32: + { + float d; + stream >> d; + childHandle.setParamF32(d); + break; + } + case NvParameterized::TYPE_U32: + { + uint32_t d; + stream >> d; + childHandle.setParamU32(d); + break; + } + case NvParameterized::TYPE_BOOL: + { + bool d; + uint8_t value = stream.readByte(); + if (value) + { + d = true; + } + else + { + d = false; + } + + childHandle.setParamBool(d); + break; + } + default: + PX_ALWAYS_ASSERT(); + } + } + +} + +PX_INLINE void deserialize(physx::PxFileBuf& stream, + uint32_t headerVersion, + NvParameterized::Interface* param, + const char* memberName, + NvParameterized::Handle* structHandle) +{ + NvParameterized::Handle childHandle(*param); + if (structHandle) + { + structHandle->getChildHandle(param, memberName, childHandle); + } + else + { + param->getParameterHandle(memberName, childHandle); + } + + deserialize(stream, headerVersion, param, childHandle); +} + + +} +} // end namespace nvidia::apex + + +#endif // __APEXSHAREDSERIALIZATIONHELPERS_H__ diff --git a/APEX_1.4/shared/internal/include/ApexStream.h b/APEX_1.4/shared/internal/include/ApexStream.h new file mode 100644 index 00000000..b5ec3b91 --- /dev/null +++ b/APEX_1.4/shared/internal/include/ApexStream.h @@ -0,0 +1,191 @@ +/* + * 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 __APEX_STREAM_H__ +#define __APEX_STREAM_H__ + +#include "ApexDefs.h" +#include "PxPlane.h" + + +namespace nvidia +{ +namespace apex +{ + +// Public, useful operators for serializing nonversioned data follow. +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, bool& b) +{ + b = (0 != stream.readByte()); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, int8_t& b) +{ + b = (int8_t)stream.readByte(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, int16_t& w) +{ + w = (int16_t)stream.readWord(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, int32_t& d) +{ + d = (int32_t)stream.readDword(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, uint8_t& b) +{ + b = stream.readByte(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, uint16_t& w) +{ + w = stream.readWord(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, uint32_t& d) +{ + d = stream.readDword(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, float& f) +{ + f = stream.readFloat(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, double& f) +{ + f = stream.readDouble(); + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, physx::PxVec2& v) +{ + stream >> v.x >> v.y; + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, physx::PxVec3& v) +{ + stream >> v.x >> v.y >> v.z; + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, physx::PxVec4& v) +{ + stream >> v.x >> v.y >> v.z >> v.w; + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, physx::PxBounds3& b) +{ + stream >> b.minimum >> b.maximum; + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, physx::PxQuat& q) +{ + stream >> q.x >> q.y >> q.z >> q.w; + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, physx::PxPlane& p) +{ + stream >> p.n.x >> p.n.y >> p.n.z >> p.d; + return stream; +} +PX_INLINE physx::PxFileBuf& operator >> (physx::PxFileBuf& stream, physx::PxMat44& m) +{ + stream >> m.column0 >> m.column1 >> m.column2 >> m.column3; + return stream; +} + +// The opposite of the above operators--takes data and writes it to a stream. +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const bool b) +{ + stream.storeByte(b ? (uint8_t)1 : (uint8_t)0); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const int8_t b) +{ + stream.storeByte((uint8_t)b); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const int16_t w) +{ + stream.storeWord((uint16_t)w); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const int32_t d) +{ + stream.storeDword((uint32_t)d); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const uint8_t b) +{ + stream.storeByte(b); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const uint16_t w) +{ + stream.storeWord(w); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const uint32_t d) +{ + stream.storeDword(d); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const float f) +{ + stream.storeFloat(f); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const double f) +{ + stream.storeDouble(f); + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const physx::PxVec2& v) +{ + stream << v.x << v.y; + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const physx::PxVec3& v) +{ + stream << v.x << v.y << v.z; + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const physx::PxVec4& v) +{ + stream << v.x << v.y << v.z << v.w; + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const physx::PxBounds3& b) +{ + stream << b.minimum << b.maximum; + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const physx::PxQuat& q) +{ + stream << q.x << q.y << q.z << q.w; + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const physx::PxPlane& p) +{ + stream << p.n.x << p.n.y << p.n.z << p.d; + return stream; +} +PX_INLINE physx::PxFileBuf& operator << (physx::PxFileBuf& stream, const physx::PxMat44& m) +{ + stream << m.column0 << m.column1 << m.column2 << m.column3; + return stream; +} + + +} +} // end namespace apex + +#endif // __APEX_STREAM_H__
\ No newline at end of file diff --git a/APEX_1.4/shared/internal/include/ApexString.h b/APEX_1.4/shared/internal/include/ApexString.h new file mode 100644 index 00000000..20d4f8c7 --- /dev/null +++ b/APEX_1.4/shared/internal/include/ApexString.h @@ -0,0 +1,276 @@ +/* + * 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 APEX_STRING_H +#define APEX_STRING_H + +#include "ApexUsingNamespace.h" +#include "PsArray.h" +#include "PsString.h" +#include "PsArray.h" +#include "PsUserAllocated.h" +#include <PxFileBuf.h> + +namespace nvidia +{ +namespace apex +{ + +/** + * ApexSimpleString - a simple string class + */ +class ApexSimpleString : public physx::Array<char>, public UserAllocated +{ +public: + ApexSimpleString() : physx::Array<char>(), length(0) + { + } + + explicit ApexSimpleString(const char* cStr) : physx::Array<char>(), length(0) + { + if (cStr) + { + length = (uint32_t)strlen(cStr); + if (length > 0) + { + resize(length + 1); + nvidia::strlcpy(begin(), size(), cStr); + } + } + } + + ApexSimpleString(const ApexSimpleString& other) : physx::Array<char>() + { + length = other.length; + if (length > 0) + { + resize(length + 1); + nvidia::strlcpy(begin(), capacity(), other.c_str()); + } + else + { + resize(0); + } + } + + ApexSimpleString(uint32_t number, uint32_t fixedLength = 0) : length(fixedLength) + { + if (fixedLength) + { + char format[5]; format[0] = '%'; format[1] = '0'; + char buffer[10]; + if (fixedLength > 9) + { + PX_ASSERT(fixedLength); + fixedLength = 9; + } + physx::shdfnd::snprintf(format + 2, 2, "%d", fixedLength); + format[3] = 'd'; format[4] = '\0'; + physx::shdfnd::snprintf(buffer, 10, format, number); + resize(length + 1); + nvidia::strlcpy(begin(), size(), buffer); + } + else + { + char buffer[10]; + physx::shdfnd::snprintf(buffer, 10, "%d", number); + length = 1; + while (number >= 10) + { + number /= 10; + length++; + } + resize(length + 1); + nvidia::strlcpy(begin(), size(), buffer); + } + } + + ApexSimpleString& operator = (const ApexSimpleString& other) + { + length = other.length; + if (length > 0) + { + resize(length + 1); + nvidia::strlcpy(begin(), capacity(), other.c_str()); + } + else + { + resize(0); + } + return *this; + } + + ApexSimpleString& operator = (const char* cStr) + { + if (!cStr) + { + erase(); + } + else + { + length = (uint32_t)strlen(cStr); + if (length > 0) + { + resize(length + 1); + nvidia::strlcpy(begin(), capacity(), cStr); + } + else + { + resize(0); + } + } + return *this; + } + + void truncate(uint32_t newLength) + { + if (newLength < length) + { + length = newLength; + begin()[length] = '\0'; + } + } + + void serialize(physx::PxFileBuf& stream) const + { + stream.storeDword(length); + stream.write(begin(), length); + } + + void deserialize(physx::PxFileBuf& stream) + { + uint32_t len = stream.readDword(); + if (len > 0) + { + resize(len + 1); + stream.read(begin(), len); + begin()[len] = '\0'; + length = len; + } + else + { + erase(); + } + } + + uint32_t len() const + { + return length; + } + + /* PH: Cast operator not allowed by coding guidelines, and evil in general anyways + operator const char* () const + { + return capacity() ? begin() : ""; + } + */ + const char* c_str() const + { + return capacity() > 0 ? begin() : ""; + } + + bool operator==(const ApexSimpleString& s) const + { + return nvidia::strcmp(c_str(), s.c_str()) == 0; + } + bool operator!=(const ApexSimpleString& s) const + { + return ! this->operator==(s); + } + bool operator==(const char* s) const + { + return nvidia::strcmp(c_str(), s) == 0; + } + bool operator!=(const char* s) const + { + return ! this->operator==(s); + } + bool operator < (const ApexSimpleString& s) const + { + return nvidia::strcmp(c_str(), s.c_str()) < 0; + } + + ApexSimpleString& operator += (const ApexSimpleString& s) + { + expandTo(length + s.length); + nvidia::strlcpy(begin() + length, capacity() - length, s.c_str()); + length += s.length; + return *this; + } + + ApexSimpleString& operator += (char c) + { + expandTo(length + 1); + begin()[length++] = c; + begin()[length] = '\0'; + return *this; + } + + ApexSimpleString operator + (const ApexSimpleString& s) + { + ApexSimpleString sum = *this; + sum += s; + return sum; + } + + ApexSimpleString& clear() + { + if (capacity()) + { + begin()[0] = '\0'; + } + length = 0; + return *this; + } + + ApexSimpleString& erase() + { + resize(0); + return clear(); + } + + static PX_INLINE void ftoa(float f, ApexSimpleString& s) + { + char buf[20]; + physx::shdfnd::snprintf(buf, sizeof(buf), "%g", f); + s = buf; + } + + static PX_INLINE void itoa(uint32_t i, ApexSimpleString& s) + { + char buf[20]; + physx::shdfnd::snprintf(buf, sizeof(buf), "%i", i); + s = buf; + } + +private: + + void expandTo(uint32_t stringCapacity) + { + if (stringCapacity + 1 > capacity()) + { + resize(2 * stringCapacity + 1); + } + } + + uint32_t length; +}; + +PX_INLINE ApexSimpleString operator + (const ApexSimpleString& s1, const ApexSimpleString& s2) +{ + ApexSimpleString result = s1; + result += s2; + return result; +} + +} // namespace apex +} // namespace nvidia + +#endif // APEX_STRING_H diff --git a/APEX_1.4/shared/internal/include/FractureTools.h b/APEX_1.4/shared/internal/include/FractureTools.h new file mode 100644 index 00000000..ec9ea1c6 --- /dev/null +++ b/APEX_1.4/shared/internal/include/FractureTools.h @@ -0,0 +1,466 @@ +/* + * 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 FRACTURE_TOOLS_H +#define FRACTURE_TOOLS_H + +#include "Px.h" +#include "ExplicitHierarchicalMesh.h" +#include "FractureToolsStructs.h" + +PX_PUSH_PACK_DEFAULT + +namespace nvidia +{ + namespace apex + { + struct IntersectMesh; + class DestructibleAsset; + } +} + +namespace FractureTools +{ + +/** + Tools for fracturing meshes. +*/ + + +/** Instantiates a blank CutoutSet */ +CutoutSet* createCutoutSet(); + +/** + Builds a cutout set (which must have been initially created by createCutoutSet()). + Uses a bitmap described by pixelBuffer, bufferWidth, and bufferHeight. Each pixel is represented + by one byte in the buffer. + + cutoutSet: the CutoutSet to build + pixelBuffer: pointer to be beginning of the pixel buffer + bufferWidth: the width of the buffer in pixels + bufferHeight: the height of the buffer in pixels + snapThreshold: the pixel distance at which neighboring cutout vertices and segments may be fudged into alignment. + periodic: whether or not to use periodic boundary conditions when creating cutouts from the map +*/ +void buildCutoutSet(CutoutSet& cutoutSet, const uint8_t* pixelBuffer, uint32_t bufferWidth, uint32_t bufferHeight, float snapThreshold, bool periodic); + +/** + Calculate the mapping between a cutout fracture map and a given triangle. + The result is a 3 by 3 matrix M composed by an affine transformation and a rotation, we can get the 3-D projection for a texture coordinate pair (u,v) with such a formula: + (x,y,z) = M*PxVec3(u,v,1) + + triangle: the target face's normal + theMapping: resulted mapping, composed by an affine transformation and a rotation +*/ +bool calculateCutoutUVMapping(const nvidia::ExplicitRenderTriangle& triangle, physx::PxMat33& theMapping); + +/** + Uses the passed-in target direction to find the best triangle in the root mesh with normal near the given targetDirection. If triangles exist + with normals within one degree of the given target direction, then one with the greatest area of such triangles is used. Otherwise, the triangle + with normal closest to the given target direction is used. The resulting triangle is used to calculate a UV mapping as in the function + calculateCutoutUVMapping (above). + + The assumption is that there exists a single mapping for all triangles on a specified face, for this feature to be useful. + + hMesh: the explicit mesh with well rectangle-shaped faces + targetDirection: the target face's normal + theMapping: resulted mapping, composed by an affine transformation and a rotation +*/ +bool calculateCutoutUVMapping(nvidia::ExplicitHierarchicalMesh& hMesh, const physx::PxVec3& targetDirection, physx::PxMat33& theMapping); + +/** + Splits the mesh in chunk[0], forming fractured pieces chunks[1...] using + Voronoi decomposition fracturing. + + hMesh: the mesh to split + iHMeshCore: if this mesh is not empty, chunk 0 will be used as an indestructible "core" of the fractured + mesh. That is, it will be subtracted from hMesh, and placed at level 1 of the hierarchy. The remainder + of hMesh will be split as usual, creating chunks at level 1 (and possibly deeper). + exportCoreMesh: if true, a core mesh chunk will be created from iHMeshCore + coreMeshImprintSubmeshIndex: if this is < 0, use the core mesh materials (was applyCoreMeshMaterialToNeighborChunks). Otherwise, use the given submesh + meshProcessingParams: describes generic mesh processing directives + desc: describes the voronoi splitting parameters surfaces (see FractureVoronoiDesc) + collisionDesc: convex hulls will be generated for each chunk using the method. See CollisionDesc. + randomSeed: seed for the random number generator, to ensure reproducibility. + progressListener: The user must instantiate an IProgressListener, so that this function may report progress of this operation + cancel: if not NULL and *cancel is set to true, the root mesh will be restored to its original state, and the function will return at its earliest opportunity. Meant to be set from another thread. + + returns true if successful. +*/ +bool createVoronoiSplitMesh +( + nvidia::ExplicitHierarchicalMesh& hMesh, + nvidia::ExplicitHierarchicalMesh& iHMeshCore, + bool exportCoreMesh, + int32_t coreMeshImprintSubmeshIndex, + const MeshProcessingParameters& meshProcessingParams, + const FractureVoronoiDesc& desc, + const nvidia::CollisionDesc& collisionDesc, + uint32_t randomSeed, + nvidia::IProgressListener& progressListener, + volatile bool* cancel = NULL +); + +/** + Generates a set of uniformly distributed points in the interior of the root mesh. + + hMesh: the mesh in which to distribute sites + siteBuffer: an array of physx::PxVec3, at least the size of siteCount + siteChunkIndices: if not NULL, then must be at least the size of siteCount. siteCount indices will be written to this buffer, associating each site with a chunk that contains it. + siteCount: the number of points to write into siteBuffer + randomSeed: pointer to a seed for the random number generator, to ensure reproducibility. If NULL, the random number generator will not be re-seeded. + microgridSize: pointer to a grid size used for BSP creation. If NULL, the default settings will be used. + progressListener: The user must instantiate an IProgressListener, so that this function may report progress of this operation + meshMode: Open mesh handling. Modes: Automatic, Closed, Open (see BSPOpenMode) + chunkIndex: If this is a valid index, the voronoi sites will only be created within the volume of the indexed chunk. Otherwise, + the sites will be created within each of the root-level chunks. Default value is an invalid index. + + returns the number of sites actually created (written to siteBuffer and siteChunkIndices). This may be less than the number of sites requested if site placement fails. +*/ +uint32_t createVoronoiSitesInsideMesh +( + nvidia::ExplicitHierarchicalMesh& hMesh, + physx::PxVec3* siteBuffer, + uint32_t* siteChunkIndices, + uint32_t siteCount, + uint32_t* randomSeed, + uint32_t* microgridSize, + nvidia::BSPOpenMode::Enum meshMode, + nvidia::IProgressListener& progressListener, + uint32_t chunkIndex = 0xFFFFFFFF +); + +/** + Creates scatter mesh sites randomly distributed on the mesh. + + meshIndices: user-allocated array of size scatterMeshInstancesBufferSize which will be filled in by this function, giving the scatter mesh index used + relativeTransforms: user-allocated array of size scatterMeshInstancesBufferSize which will be filled in by this function, giving the chunk-relative transform for each chunk instance + chunkMeshStarts: user-allocated array which will be filled in with offsets into the meshIndices and relativeTransforms array. + For a chunk indexed by i, the corresponding range [chunkMeshStart[i], chunkMeshStart[i+1]-1] in meshIndices and relativeTransforms is used. + *NOTE*: chunkMeshStart array must be of at least size N+1, where N is the number of chunks in the base explicit hierarchical mesh. + scatterMeshInstancesBufferSize: the size of meshIndices and relativeTransforms array. + scatterMeshInstancesBufferSize: the size of meshIndices and relativeTransforms array. + hMesh: the mesh in which to distribute sites + targetChunkCount: how many chunks are in the array targetChunkIndices + targetChunkIndices: an array of chunk indices which are candidates for scatter meshes. The elements in the array chunkIndices will come from this array + randomSeed: pointer to a seed for the random number generator, to ensure reproducibility. If NULL, the random number generator will not be re-seeded. + scatterMeshAssetCount: the number of different scatter meshes (not instances). Should not exceed 255. If scatterMeshAssetCount > 255, only the first 255 will be used. + scatterMeshAssets: an array of size scatterMeshAssetCount, of the render mesh assets which will be used for the scatter meshes + minCount: an array of size scatterMeshAssetCount, giving the minimum number of instances to place for each mesh + maxCount: an array of size scatterMeshAssetCount, giving the maximum number of instances to place for each mesh + minScales: an array of size scatterMeshAssetCount, giving the minimum scale to apply to each scatter mesh + maxScales: an array of size scatterMeshAssetCount, giving the maximum scale to apply to each scatter mesh + maxAngles: an array of size scatterMeshAssetCount, giving a maximum deviation angle (in degrees) from the surface normal to apply to each scatter mesh + + return value: the number of instances placed in indices and relativeTransforms (will not exceed scatterMeshInstancesBufferSize) +*/ +uint32_t createScatterMeshSites +( + uint8_t* meshIndices, + physx::PxMat44* relativeTransforms, + uint32_t* chunkMeshStarts, + uint32_t scatterMeshInstancesBufferSize, + nvidia::ExplicitHierarchicalMesh& hMesh, + uint32_t targetChunkCount, + const uint16_t* targetChunkIndices, + uint32_t* randomSeed, + uint32_t scatterMeshAssetCount, + nvidia::RenderMeshAsset** scatterMeshAssets, + const uint32_t* minCount, + const uint32_t* maxCount, + const float* minScales, + const float* maxScales, + const float* maxAngles +); + +/** + Utility to visualize Voronoi cells for a given set of sites. + + debugRender: rendering object which will receive the drawing primitives associated with this cell visualization + sites: an array of Voronoi cell sites, of length siteCount + siteCount: the number of Voronoi cell sites (length of sites array) + cellColors: an optional array of colors (see ApexRenderDebug for format) for the cells. If NULL, the white (0xFFFFFFFF) color will be used. + If not NULL, this (of length cellColorCount) is used to color the cell graphics. The number cellColorCount need not match siteCount. If + cellColorCount is less than siteCount, the cell colors will cycle. That is, site N gets cellColor[N%cellColorCount]. + cellColorCount: the number of cell colors (the length of cellColors array) + bounds: defines an axis-aligned bounding box which clips the visualization, since some cells extend to infinity + cellIndex: if this is a valid index (cellIndex < siteCount), then only the cell corresponding to sites[cellIndex] will be drawn. Otherwise, all cells will be drawn. +*/ +void visualizeVoronoiCells +( + nvidia::RenderDebugInterface& debugRender, + const physx::PxVec3* sites, + uint32_t siteCount, + const uint32_t* cellColors, + uint32_t cellColorCount, + const physx::PxBounds3& bounds, + uint32_t cellIndex = 0xFFFFFFFF +); + +/** + Builds a new ExplicitHierarchicalMesh from an array of triangles. + + iHMesh: the ExplicitHierarchicalMesh to build + meshTriangles: pointer to array of ExplicitRenderTriangles which make up the mesh + meshTriangleCount the size of the meshTriangles array + submeshData: pointer to array of ExplicitSubmeshData, describing the submeshes + submeshCount: the size of the submeshData array + meshPartition: if not NULL, an array of size meshPartitionCount, giving the end elements of contiguous subsets of meshTriangles. + If meshPartition is NULL, one partition is assumed. + When there is one partition, these triangles become the level 0 part. + When there is more than one partition, these triangles become level 1 parts, the behavior is determined by firstPartitionIsDepthZero (see below). + meshPartitionCount: if meshPartition is not NULL, this is the size of the meshPartition array. + parentIndices: if not NULL, the parent indices for each chunk (corresponding to a partition in the mesh partition). + parentIndexCount: the size of the parentIndices array. This does not need to match meshPartitionCount. If a mesh partition has an index beyond the end of parentIndices, + then the parentIndex is considered to be 0. Therefore, if parentIndexCount = 0, all parents are 0 and so all chunks created will be depth 1. This will cause a + depth 0 chunk to be created that is the aggregate of the depth 1 chunks. If parentIndexCount > 0, then the depth-0 chunk must have a parentIndex of -1. + To reproduce the effect of the old parameter 'firstPartitionIsDepthZero' = true, set parentIndices to the address of a int32_t containing the value -1, and set parentIndexCount = 1. + To reproduce the effect of the old parameter 'firstPartitionIsDepthZero' = false, set parentIndexCount = 0. + Note: if parent indices are given, the first one must be -1, and *only* that index may be negative. That is, there may be only one depth-0 mesh and it must be the first mesh. +*/ +bool buildExplicitHierarchicalMesh +( + nvidia::ExplicitHierarchicalMesh& iHMesh, + const nvidia::ExplicitRenderTriangle* meshTriangles, + uint32_t meshTriangleCount, + const nvidia::ExplicitSubmeshData* submeshData, + uint32_t submeshCount, + uint32_t* meshPartition = NULL, + uint32_t meshPartitionCount = 0, + int32_t* parentIndices = NULL, + uint32_t parentIndexCount = 0 +); + +/** + Set the tolerances used in CSG calculations with BSPs. + + linearTolerance: relative (to mesh size) tolerance used with angularTolerance to determine coplanarity. Default = 1.0e-4. + angularTolerance: used with linearTolerance to determine coplanarity. Default = 1.0e-3 + baseTolerance: relative (to mesh size) tolerance used for spatial partitioning + clipTolerance: relative (to mesh size) tolerance used when clipping triangles for CSG mesh building operations. Default = 1.0e-4. + cleaningTolerance: relative (to mesh size) tolerance used when cleaning the out put mesh generated from the toMesh() function. Default = 1.0e-7. +*/ +void setBSPTolerances +( + float linearTolerance, + float angularTolerance, + float baseTolerance, + float clipTolerance, + float cleaningTolerance +); + +/** + Set the parameters used in BSP building operations. + + logAreaSigmaThreshold: At each step in the tree building process, the surface with maximum triangle area is compared + to the other surface triangle areas. If the maximum area surface is far from the "typical" set of + surface areas, then that surface is chosen as the next splitting plane. Otherwise, a random + test set is chosen and a winner determined based upon the weightings below. + The value logAreaSigmaThreshold determines how "atypical" the maximum area surface must be to + be chosen in this manner. + Default value = 2.0. + testSetSize: Larger values of testSetSize may find better BSP trees, but will take more time to create. + testSetSize = 0 is treated as infinity (all surfaces will be tested for each branch). + Default value = 10. + splitWeight: How much to weigh the relative number of triangle splits when searching for a BSP surface. + Default value = 0.5. + imbalanceWeight: How much to weigh the relative triangle imbalance when searching for a BSP surface. + Default value = 0.0. +*/ +void setBSPBuildParameters +( + float logAreaSigmaThreshold, + uint32_t testSetSize, + float splitWeight, + float imbalanceWeight +); + + +/** + Builds the root ExplicitHierarchicalMesh from an RenderMeshAsset. + Since an DestructibleAsset contains no hierarchy information, the input mesh must have only one part. + + iHMesh: the ExplicitHierarchicalMesh to build + renderMeshAsset: Input RenderMesh asset + maxRootDepth: cap the root depth at this value. Re-fracturing of the mesh will occur at this depth. Default = UINT32_MAX +*/ +bool buildExplicitHierarchicalMeshFromRenderMeshAsset(nvidia::ExplicitHierarchicalMesh& iHMesh, const nvidia::RenderMeshAsset& renderMeshAsset, uint32_t maxRootDepth = UINT32_MAX); + +/** + Builds the root ExplicitHierarchicalMesh from an DestructibleAsset. + Since an DestructibleAsset contains hierarchy information, the explicit mesh formed + will have this hierarchy structure. + + iHMesh: the ExplicitHierarchicalMesh to build + destructibleAsset: Input Destructible asset + maxRootDepth: cap the root depth at this value. Re-fracturing of the mesh will occur at this depth. Default = UINT32_MAX +*/ +bool buildExplicitHierarchicalMeshFromDestructibleAsset(nvidia::ExplicitHierarchicalMesh& iHMesh, const nvidia::DestructibleAsset& destructibleAsset, uint32_t maxRootDepth = UINT32_MAX); + +/** + Partitions (and possibly re-orders) the mesh array if the triangles form disjoint islands. + mesh: pointer to array of ExplicitRenderTriangles which make up the mesh + meshTriangleCount: the size of the meshTriangles array + meshPartition: user-allocated array for mesh partition, will be filled with the end elements of contiguous subsets of meshTriangles. + meshPartitionMaxCount: size of user-allocated meshPartitionArray + padding: distance (as a fraction of the mesh size) to consider vertices touching + + Returns the number of partitions. The value may be larger than meshPartitionMaxCount. In that case, the partitions beyond meshPartitionMaxCount are not recorded. +*/ +uint32_t partitionMeshByIslands +( + nvidia::ExplicitRenderTriangle* mesh, + uint32_t meshTriangleCount, + uint32_t* meshPartition, + uint32_t meshPartitionMaxCount, + float padding = 0.0001f +); + +/** + Splits the mesh in chunk[0], forming a hierarchy of fractured meshes in chunks[1...] + + hMesh: the mesh to split + iHMeshCore: if this mesh is not empty, chunk 0 will be used as an indestructible "core" of the fractured + mesh. That is, it will be subtracted from hMesh, and placed at level 1 of the hierarchy. The remainder + of hMesh will be split as usual, creating chunks at level 1 (and possibly deeper). + exportCoreMesh: if true, a core mesh chunk will be created from iHMeshCore + coreMeshImprintSubmeshIndex: if this is < 0, use the core mesh materials (was applyCoreMeshMaterialToNeighborChunks). Otherwise, use the given submesh + meshProcessingParams: describes generic mesh processing directives + desc: describes the slicing surfaces (see FractureSliceDesc) + collisionDesc: convex hulls will be generated for each chunk using the method. See CollisionDesc. + randomSeed: seed for the random number generator, to ensure reproducibility. + progressListener: The user must instantiate an IProgressListener, so that this function may report progress of this operation + cancel: if not NULL and *cancel is set to true, the root mesh will be restored to its original state, and the function will return at its earliest opportunity. Meant to be set from another thread. + + returns true if successful. +*/ +bool createHierarchicallySplitMesh +( + nvidia::ExplicitHierarchicalMesh& hMesh, + nvidia::ExplicitHierarchicalMesh& iHMeshCore, + bool exportCoreMesh, + int32_t coreMeshImprintSubmeshIndex, + const MeshProcessingParameters& meshProcessingParams, + const FractureSliceDesc& desc, + const nvidia::CollisionDesc& collisionDesc, + uint32_t randomSeed, + nvidia::IProgressListener& progressListener, + volatile bool* cancel = NULL +); + +/** + Chips the mesh in chunk[0], forming a hierarchy of fractured meshes in chunks[1...] + + hMesh: the mesh to split + meshProcessingParams: describes generic mesh processing directives + desc: describes the slicing surfaces (see FractureCutoutDesc) + iCutoutSet: the cutout set to use for fracturing (see CutoutSet) + sliceDesc: used if desc.chunkFracturingMethod = SliceFractureCutoutChunks + voronoiDesc: used if desc.chunkFracturingMethod = VoronoiFractureCutoutChunks + collisionDesc: convex hulls will be generated for each chunk using the method. See CollisionDesc. + randomSeed: seed for the random number generator, to ensure reproducibility. + progressListener: The user must instantiate an IProgressListener, so that this function may report progress of this operation + cancel: if not NULL and *cancel is set to true, the root mesh will be restored to its original state, and the function will return at its earliest opportunity. Meant to be set from another thread. + + returns true if successful. +*/ +bool createChippedMesh +( + nvidia::ExplicitHierarchicalMesh& hMesh, + const MeshProcessingParameters& meshProcessingParams, + const FractureCutoutDesc& desc, + const CutoutSet& iCutoutSet, + const FractureSliceDesc& sliceDesc, + const FractureVoronoiDesc& voronoiDesc, + const nvidia::CollisionDesc& collisionDesc, + uint32_t randomSeed, + nvidia::IProgressListener& progressListener, + volatile bool* cancel = NULL +); + +/** + Splits the chunk in chunk[chunkIndex], forming a hierarchy of fractured chunks using + slice-mode fracturing. The chunks will be rearranged so that they are in breadth-first order. + + hMesh: the ExplicitHierarchicalMesh to act upon + chunkIndex: index of chunk to be split + meshProcessingParams: used to create a BSP for this chunk + desc: describes the slicing surfaces (see FractureSliceDesc) + collisionDesc: convex hulls will be generated for each chunk using the method. See CollisionDesc. + randomSeed: pointer to a seed for the random number generator, to ensure reproducibility. If NULL, the random number generator will not be re-seeded. + progressListener: The user must instantiate an IProgressListener, so that this function may report progress of this operation + cancel: if not NULL and *cancel is set to true, the root mesh will be restored to its original state, and the function will return at its earliest opportunity. Meant to be set from another thread. + + returns true if successful. +*/ +bool hierarchicallySplitChunk +( + nvidia::ExplicitHierarchicalMesh& hMesh, + uint32_t chunkIndex, + const MeshProcessingParameters& meshProcessingParams, + const FractureSliceDesc& desc, + const nvidia::CollisionDesc& collisionDesc, + uint32_t* randomSeed, + nvidia::IProgressListener& progressListener, + volatile bool* cancel = NULL +); + +/** + Splits the chunk in chunk[chunkIndex], forming fractured chunks using + Voronoi decomposition fracturing. The chunks will be rearranged so that they are in breadth-first order. + + hMesh: the ExplicitHierarchicalMesh to act upon + chunkIndex: index of chunk to be split + meshProcessingParams: describes generic mesh processing directives + desc: describes the voronoi splitting parameters surfaces (see FractureVoronoiDesc) + collisionDesc: convex hulls will be generated for each chunk using the method. See CollisionDesc. + randomSeed: pointer to a seed for the random number generator, to ensure reproducibility. If NULL, the random number generator will not be re-seeded. + progressListener: The user must instantiate an IProgressListener, so that this function may report progress of this operation + cancel: if not NULL and *cancel is set to true, the root mesh will be restored to its original state, and the function will return at its earliest opportunity. Meant to be set from another thread. + + returns true if successful. +*/ +bool voronoiSplitChunk +( + nvidia::ExplicitHierarchicalMesh& hMesh, + uint32_t chunkIndex, + const MeshProcessingParameters& meshProcessingParams, + const FractureVoronoiDesc& desc, + const nvidia::CollisionDesc& collisionDesc, + uint32_t* randomSeed, + nvidia::IProgressListener& progressListener, + volatile bool* cancel = NULL +); + +/** + Builds a mesh used for slice fracturing, given the noise parameters and random seed. This function is mostly intended + for visualization - to give the user a "typical" slice surface used for fracturing. +*/ +bool buildSliceMesh +( + nvidia::IntersectMesh& intersectMesh, + nvidia::ExplicitHierarchicalMesh& referenceMesh, + const physx::PxPlane& slicePlane, + const FractureTools::NoiseParameters& noiseParameters, + uint32_t randomSeed +); + +/** Instantiates an ExplicitHierarchicalMesh */ +nvidia::ExplicitHierarchicalMesh* createExplicitHierarchicalMesh(); + +/** Instantiates an ExplicitHierarchicalMesh::ConvexHull */ +nvidia::ExplicitHierarchicalMesh::ConvexHull* createExplicitHierarchicalMeshConvexHull(); + +PX_POP_PACK + +} // namespace FractureTools + +#endif // FRACTURE_TOOLS_H diff --git a/APEX_1.4/shared/internal/include/Link.h b/APEX_1.4/shared/internal/include/Link.h new file mode 100644 index 00000000..d006d5b1 --- /dev/null +++ b/APEX_1.4/shared/internal/include/Link.h @@ -0,0 +1,75 @@ +/* + * 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 LINK_H +#define LINK_H + +#include "PxSimpleTypes.h" +#include "PxAssert.h" + +namespace nvidia +{ +namespace apex +{ + +class Link +{ +public: + Link() + { + adj[1] = adj[0] = this; + } + + virtual ~Link() + { + remove(); + } + + /* + which = 0: (-A-...-B-link-) + (-this-X-...-Y-) = (-A-...-B-link-this-X-...-Y-) + which = 1: (-X-...-Y-this-) + (-link-A-...-B-) = (-X-...-Y-this-link-A-...-B-) + */ + void setAdj(uint32_t which, Link* link) + { + uint32_t other = (which &= 1) ^ 1; + Link* linkAdjOther = link->adj[other]; + adj[which]->adj[other] = linkAdjOther; + linkAdjOther->adj[which] = adj[which]; + adj[which] = link; + link->adj[other] = this; + } + + Link* getAdj(uint32_t which) const + { + return adj[which & 1]; + } + + void remove() + { + adj[1]->adj[0] = adj[0]; + adj[0]->adj[1] = adj[1]; + adj[1] = adj[0] = this; + } + + bool isSolitary() const + { + PX_ASSERT((adj[0] == this) == (adj[1] == this)); + return adj[0] == this; + } + +protected: + Link* adj[2]; +}; + +} +} // end namespace nvidia::apex + + +#endif // #ifndef LINK_H diff --git a/APEX_1.4/shared/internal/include/ParamArray.h b/APEX_1.4/shared/internal/include/ParamArray.h new file mode 100644 index 00000000..9f2788e2 --- /dev/null +++ b/APEX_1.4/shared/internal/include/ParamArray.h @@ -0,0 +1,225 @@ +/* + * 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 PARAM_ARRAY_H +#define PARAM_ARRAY_H + +#include "nvparameterized/NvParameterized.h" +#include "PsUserAllocated.h" +#include "PxAssert.h" + +namespace nvidia +{ +namespace apex +{ + +struct ParamDynamicArrayStruct +{ + void* buf; + bool isAllocated; + int elementSize; + int arraySizes[1]; +}; + + +template <class ElemType> +class ParamArray : public physx::UserAllocated +{ +public: + + ParamArray() : mParams(NULL), mArrayHandle(0), mArrayStruct(NULL) {} + + ParamArray(NvParameterized::Interface* params, const char* arrayName, ParamDynamicArrayStruct* arrayStruct) : + mParams(params), + mArrayHandle(*params), + mArrayStruct(arrayStruct) + { + PX_ASSERT(mParams); + + mParams->getParameterHandle(arrayName, mArrayHandle); + + PX_ASSERT(mArrayStruct->elementSize == sizeof(ElemType)); + } + + ParamArray(NvParameterized::Interface* params, const NvParameterized::Handle& handle, ParamDynamicArrayStruct* arrayStruct) : + mParams(params), + mArrayHandle(handle), + mArrayStruct(arrayStruct) + { + PX_ASSERT(mArrayStruct->elementSize == sizeof(ElemType)); + } + + PX_INLINE bool init(NvParameterized::Interface* params, const char* arrayName, ParamDynamicArrayStruct* arrayStruct) + { + if (mParams == NULL && mArrayStruct == NULL) + { + mParams = params; + mArrayStruct = arrayStruct; + mArrayHandle.setInterface(mParams); + mParams->getParameterHandle(arrayName, mArrayHandle); + + PX_ASSERT(mArrayStruct->elementSize == sizeof(ElemType)); + + return true; + } + return false; + } + + PX_INLINE uint32_t size() const + { + // this only works for fixed structs + //return (uint32_t)mArrayHandle.parameterDefinition()->arraySize(0); + int outSize = 0; + if (mParams != NULL) + { + PX_ASSERT(mArrayHandle.getConstInterface() == mParams); + mArrayHandle.getArraySize(outSize); + } + return (uint32_t)outSize; + } + + /** + Returns a constant reference to an element in the sequence. + */ + PX_INLINE const ElemType& operator[](unsigned int n) const + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); +#if _DEBUG + uint32_t NxParamArraySize = 0; + mArrayHandle.getArraySize((int&)NxParamArraySize); + PX_ASSERT(NxParamArraySize > n); +#endif + return ((ElemType*)mArrayStruct->buf)[n]; + } + + /** + Returns a reference to an element in the sequence. + */ + PX_INLINE ElemType& operator[](unsigned int n) + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + //NvParameterized::Handle indexHandle; + //arrayHandle.getChildHandle( n, indexHandle ); +#if _DEBUG + uint32_t NxParamArraySize = 0; + mArrayHandle.getArraySize((int&)NxParamArraySize); + PX_ASSERT(NxParamArraySize > n); +#endif + return ((ElemType*)mArrayStruct->buf)[n]; + } + + // resize is marginally useful because the ElemType doesn't have proper + // copy constructors, and if strings are withing ElemType that doesn't work well + PX_INLINE void resize(unsigned int n) + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + PX_ASSERT(mParams == mArrayHandle.getConstInterface()); + mArrayHandle.resizeArray((int32_t)n); + } + + // pushBack is marginally useful because the ElemType doesn't have proper + // copy constructors, and if strings are withing ElemType that doesn't work well + PX_INLINE void pushBack(const ElemType& x) + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + + int32_t paramArraySize = 0; + + mArrayHandle.getArraySize(paramArraySize); + mArrayHandle.resizeArray(paramArraySize + 1); + + ((ElemType*)mArrayStruct->buf)[(uint32_t)paramArraySize] = x; + } + + PX_INLINE ElemType& pushBack() + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + + int32_t paramArraySize = 0; + + mArrayHandle.getArraySize(paramArraySize); + mArrayHandle.resizeArray(paramArraySize + 1); + + return ((ElemType*)mArrayStruct->buf)[(uint32_t)paramArraySize]; + } + + PX_INLINE void replaceWithLast(unsigned position) + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + + uint32_t arraySize = size(); + PX_ASSERT(position < arraySize); + if (position != arraySize - 1) + { + // TODO should we call the destructor here or not? + //(*this)[position].~ElemType(); + + ElemType elem = back(); + + // put the replaced one in the back (possibly to be deleted) + (*this)[arraySize - 1] = (*this)[position]; + + (*this)[position] = elem; + } + popBack(); + } + + PX_INLINE bool isEmpty() const + { + return size() == 0; + } + + PX_INLINE ElemType* begin() + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + return &((ElemType*)mArrayStruct->buf)[0]; + } + + PX_INLINE ElemType* end() + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + return &((ElemType*)mArrayStruct->buf)[size()]; + } + + PX_INLINE ElemType& front() + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + return ((ElemType*)mArrayStruct->buf)[0]; + } + + PX_INLINE ElemType& back() + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + return ((ElemType*)mArrayStruct->buf)[size() - 1]; + } + + PX_INLINE void clear() + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + resize(0); + } + + PX_INLINE void popBack() + { + PX_ASSERT(mParams != NULL && mArrayStruct != NULL); + resize(size() - 1); + } + +private: + NvParameterized::Interface* mParams; + NvParameterized::Handle mArrayHandle; + ParamDynamicArrayStruct* mArrayStruct; +}; + +} +} // end namespace nvidia::apex + +#endif + diff --git a/APEX_1.4/shared/internal/include/PvdNxParamSerializer.h b/APEX_1.4/shared/internal/include/PvdNxParamSerializer.h new file mode 100644 index 00000000..645dd5f0 --- /dev/null +++ b/APEX_1.4/shared/internal/include/PvdNxParamSerializer.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. + */ + +#if TODO_PVD_NXPARAM_SERIALIZER + +#ifndef PVD_NXPARAM_SERIALIZER +#define PVD_NXPARAM_SERIALIZER +#include "PxSimpleTypes.h" +#include "nvparameterized/NvParameterized.h" + +namespace PVD +{ +class PvdDataStream; +} + +namespace NvParameterized +{ +class Interface; +} + +namespace PvdNxParamSerializer +{ + +NvParameterized::ErrorType +traverseParamDefTree(NvParameterized::Interface& obj, + PVD::PvdDataStream* remoteDebugger, + void* curPvdObj, + NvParameterized::Handle& handle); + +}; // namespacePvdNxParamSerializer + +#endif // #ifndef PVD_NXPARAM_SERIALIZER + +#endif
\ No newline at end of file diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSG.h b/APEX_1.4/shared/internal/include/authoring/ApexCSG.h new file mode 100644 index 00000000..711d90de --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexCSG.h @@ -0,0 +1,404 @@ +/* + * 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 APEX_CSG_H +#define APEX_CSG_H + + +#include "ApexUsingNamespace.h" +#include "RenderMeshAsset.h" + +#ifndef WITHOUT_APEX_AUTHORING + +namespace ApexCSG +{ + +class UserRandom +{ +public: + virtual uint32_t getInt() = 0; + virtual float getReal(float min, float max) = 0; +}; + + +struct BSPBuildParameters +{ + /* + Used for searching splitting planes. + If NULL, a default random # generator will be used. + */ + UserRandom* rnd; + + /* + Mesh pre-processing. The mesh is initially scaled to fit in a unit cube, then (if gridSize is not + zero), the vertices of the scaled mesh are snapped to a grid of size 1/gridSize. + A power of two is recommended. + Default value = 65536. + */ + uint32_t snapGridSize; + + /* + At each step in the tree building process, the surface with maximum triangle area is compared + to the other surface triangle areas. If the maximum area surface is far from the "typical" set of + surface areas, then that surface is chosen as the next splitting plane. Otherwise, a random + test set is chosen and a winner determined based upon the weightings below. + The value logAreaSigmaThreshold determines how "atypical" the maximum area surface must be to + be chosen in this manner. + Default value = 2.0. + */ + float logAreaSigmaThreshold; + + /* + Larger values of testSetSize may find better BSP trees, but will take more time to create. + testSetSize = 0 is treated as infinity (all surfaces will be tested for each branch). + */ + uint32_t testSetSize; + + /* + How much to weigh the relative number of triangle splits when searching for a BSP surface. + */ + float splitWeight; + + /* + How much to weigh the relative triangle imbalance when searching for a BSP surface. + */ + float imbalanceWeight; + + /* + The BSP representation of the mesh will be transformed from the space of the mesh input into IApexBSP::fromMesh + using this transform. By default, this is the identity transformation. If the user wishes to use a + different transformation, it may be set using internalTransform. However, note that when combining + BSPs using the IApexBSP::combine function, the two BSPs should use the same internal transform. If they don't, + the resulting behavior is not specified. When a mesh is created using IApexBSP::toMesh, the inverse + of the internal transform is applied to put the mesh back into the original space. + + A special value for internalTransform is the zero 4x4 matrix. If this is used, an internal transform + will be calculated in the IApexBSP::fromMesh function. This may be read using IApexBSP::getInternalTransform(), + and applied when creating other BSPs which are to be used in combine operations. + */ + physx::PxMat44 internalTransform; + + /* + If false, the triangles associated with this BSP will not be kept. The BSP may be used for CSG, but will + not provide any mesh data. + + Default = true + */ + bool keepTriangles; + + BSPBuildParameters() + { + setToDefault(); + } + + void setToDefault() + { + rnd = NULL; + snapGridSize = 65536; + logAreaSigmaThreshold = (float)2.0; + testSetSize = 10; + splitWeight = (float)0.5; + imbalanceWeight = 0; + internalTransform = physx::PxMat44(physx::PxIdentity); + keepTriangles = true; + } +}; + +struct BSPTolerances +{ + /* + A unitless value (relative to mesh size) used to determine mesh triangle coplanarity during BSP building. + Default value = 1.0e-6. + */ + float linear; + + /* + A threshold angle (in radians) used to determine mesh triangle coplanarity during BSP building. + Default value = 1.0e-5. + */ + float angular; + + /* + A unitless value (relative to mesh size) used to determine triangle splitting during BSP building. + Default value = 1.0e-9. + */ + float base; + + /* + A unitless value (relative to mesh size) used to determine a skin width for mesh clipping against BSP + nodes during mesh creation from the BSP. + Default value = 1.0e-13. + */ + float clip; + + /* + Mesh postprocessing. A unitless value (relative to mesh size) used to determine merge tolerances for + mesh clean-up after triangles have been clipped to BSP leaves. A value of 0.0 disables this feature. + Default value = 1.0e-6. + */ + float cleaning; + + BSPTolerances() + { + setToDefault(); + } + + void setToDefault() + { + linear = (float)1.0e-6; + angular = (float)1.0e-5; + base = (float)1.0e-9; + clip = (float)1.0e-13; + cleaning = (float)1.0e-6; + } +}; + +extern BSPTolerances gDefaultTolerances; + +struct Operation +{ + enum Enum + { + Empty_Set = 0x0, // constant + All_Space = 0x1, // constant + Set_A = 0x2, // unary + Set_A_Complement = 0x3, // unary + Set_B = 0x4, // unary + Set_B_Complement = 0x5, // unary + Exclusive_Or = 0x6, + Equivalent = 0x7, + Intersection = 0x8, + Intersection_Complement = 0x9, + A_Minus_B = 0xA, + A_Implies_B = 0xB, + B_Minus_A = 0xC, + B_Implies_A = 0xD, + Union = 0xE, + Union_Complement = 0xF, + + NOP = 0x80000000 // no op + }; +}; + + +struct BSPVisualizationFlags +{ + enum Enum + { + OutsideRegions = (1 << 0), + InsideRegions = (1 << 1), + + SingleRegion = (1 << 16) + }; +}; + + +struct BSPType +{ + enum Enum + { + Empty_Set, // BSP has a single node, which is an outside leaf. Therefore the inside region is the empty set. + All_Space, // BSP has a single node, which is an inside leaf. Therefore the inside region is all of space. + Nontrivial, // BSP has more than a single node. + Combined, // BSP is the combination of two BSPs, ready for a CSG operation to define a single BSP. + + BSPTypeCount + }; +}; + + +/* + Memory cache for BSP construction. Not global, so that concurrent calculations can use different pools. + */ +class IApexBSPMemCache +{ +public: + + /* + Deallocate all memory buffers. + */ + virtual void clearAll() = 0; + + /* + Deallocate only temporary data buffers. + */ + virtual void clearTemp() = 0; + + /* + Clean up. + */ + virtual void release() = 0; + +protected: + + IApexBSPMemCache() {} + virtual ~IApexBSPMemCache() {} +}; + + +/* + BSP interface. + + Convert a mesh into a BSP, perform boolean operations between BSPs, and extract the resulting mesh. + */ + +class IApexBSP +{ +public: + /* + Set the tolerances used for various aspects of BSP creation, merging, mesh creation, etc. + Default values are those in BSPTolerances. + */ + virtual void setTolerances(const BSPTolerances& tolerances) = 0; + + /* + Construct a BSP from the given mesh, using the given parameters. + */ + virtual bool fromMesh(const nvidia::ExplicitRenderTriangle* mesh, uint32_t meshSize, const BSPBuildParameters& params, nvidia::IProgressListener* progressListener = NULL, volatile bool* cancel = NULL) = 0; + + /* + Construct a BSP from a convex polyhedron defined by a list of planes. + See the definition of internalTransform in BSPBuildParameters. The same meaning applies here. + The mesh array is optional. If included, the single internal leaf created will be associated with these triangles. + */ + virtual bool fromConvexPolyhedron(const physx::PxPlane* poly, uint32_t polySize, const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxIdentity), const nvidia::ExplicitRenderTriangle* mesh = NULL, uint32_t meshSize = 0) = 0; + + /* + Build a combination of two BSPs (this and the passed-in bsp), upon which boolean operations of the two can be performed. + */ + virtual bool combine(const IApexBSP& bsp) = 0; + + /* + Build a BSP resulting from a boolean operation upon a combination. + Note: you may do this "in place," i.e. + bsp.op( bsp, operation ); + ... in this case, bsp will no longer be a combined BSP. + */ + virtual bool op(const IApexBSP& combinedBSP, Operation::Enum operation) = 0; + + /* + This BSP is changed to its complement (inside <-> outside) + */ + virtual bool complement() = 0; + + /* + The transform from mesh space to BSP space. This may be used in the BSPBuildParameters passed into fromMesh, + in order to match the transform used for a combining mesh. + */ + virtual physx::PxMat44 getInternalTransform() const = 0; + + /* + Returns an enum characterizing the BSP. See BSPType. + */ + virtual BSPType::Enum getType() const = 0; + + /* + Returns the total surface area and volume of the regions designated to be on the given side. + If this is a combined BSP, then you must provide a merge operation. In this case, + the BSP will not actually be merged, but the resulting area will be that of the + merged BSP you would get if you did perform the merge with the op() function. + If this is not a combined BSP and you provide a merge operation, it will be ignored. + + If there the volume or area of one of the leaves in consideration is infinite, then this function returns false. Otherwise it returns true. + */ + virtual bool getSurfaceAreaAndVolume(float& area, float& volume, bool inside, Operation::Enum operation = Operation::NOP) const = 0; + + /* + Determines if given point is in an outside or inside leaf. + If this is a combined BSP, then you must provide a merge operation. In this case, + the BSP will not actually be merged, but the resulting area will be that of the + merged BSP you would get if you did perform the merge with the op() function. + If this is not a combined BSP and you provide a merge operation, it will be ignored. + */ + virtual bool pointInside(const physx::PxVec3& point, Operation::Enum operation = Operation::NOP) const = 0; + + /* + Construct a mesh from the current BSP. + */ + virtual bool toMesh(physx::Array<nvidia::ExplicitRenderTriangle>& mesh) const = 0; + + /* + Deep copy of given bsp. + Input bsp may be the same as *this. + The transform tm will be applied. + If the internalTransform given is not zero, it will become the new internal transform. The mesh will be scaled internally appropriately with the given tm. + A combined BSP may be copied. + */ + virtual void copy(const IApexBSP& bsp, const physx::PxMat44& tm = physx::PxMat44(physx::PxIdentity), const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxZero)) = 0; + + /* + Decompose into disjoint islands. + This BSP is not affected. + The BSP is split into a set of BSPs, each representing one connected island. + The set of BSPs is returned as the first BSP in the list, with access + to the remainder of the list through the getNext() and getPrev() functions. + The BSP must be not be a combined BSP (getType() != BSPType::Combined). + Returns this if the BSP is already an island. + Returns NULL if the operation fails (e.g. this is a combined BSP). + */ + virtual IApexBSP* decomposeIntoIslands() const = 0; + + /** + Utility to replace the submesh on a set of interior triangles. + */ + virtual void replaceInteriorSubmeshes(uint32_t frameCount, uint32_t* frameIndices, uint32_t submeshIndex) = 0; + + /* + Deletes the triangles associated with this BSP. The BSP may be used for CSG, but will not provide any mesh data. + */ + virtual void deleteTriangles() = 0; + + /* + If a BSP has been decomposed into islands, getNext() and getPrev() will iterate through the + BSPs in the decomposition. NULL is returned if an attempt is made to iterate past + the beginning or end of the list. + */ + virtual IApexBSP* getNext() const = 0; + virtual IApexBSP* getPrev() const = 0; + + /* + Serialization. + */ + virtual void serialize(physx::PxFileBuf& stream) const = 0; + virtual void deserialize(physx::PxFileBuf& stream) = 0; + + /* + Visualization. + Set flags to bits from BSPVisualizationFlags::Enum. + */ + virtual void visualize(nvidia::RenderDebugInterface& debugRender, uint32_t flags, uint32_t index = 0) const = 0; + + /* + Clean up. + */ + virtual void release() = 0; + +protected: + + IApexBSP() {} + virtual ~IApexBSP() {} +}; + + +// CSG Tools API + +// Create a BSP memory cache to share among several BSPs +IApexBSPMemCache* +createBSPMemCache(); + +// Instantiate a BSP. If cache = NULL, the BSP will create and own its own cache. +IApexBSP* +createBSP(IApexBSPMemCache* memCache = NULL, const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxIdentity)); + +}; // namespace ApexCSG + +#endif + +#endif // #ifndef APEX_CSG_H diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h b/APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h new file mode 100644 index 00000000..ebfb105a --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h @@ -0,0 +1,1064 @@ +/* + * 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 APEX_CSG_DEFS_H +#define APEX_CSG_DEFS_H + +#include "ApexUsingNamespace.h" +#include "ApexSharedUtils.h" +#include "ApexRand.h" +#include "Link.h" +#include "authoring/ApexCSG.h" +#include "authoring/ApexCSGMath.h" +#include "authoring/ApexGSA.h" +#include "PsUserAllocated.h" +#include "ApexGSA.h" + +#ifndef WITHOUT_APEX_AUTHORING + +namespace ApexCSG +{ + +// Binary tree node +class BinaryNode +{ +public: + PX_INLINE BinaryNode(); + + PX_INLINE void setChild(uint32_t index, BinaryNode* child); + + PX_INLINE void detach(); + + PX_INLINE BinaryNode* getParent() const + { + return m_parent; + } + + PX_INLINE BinaryNode* getChild(uint32_t index) const + { + PX_ASSERT((index & 1) == index); + return m_children[index & 1]; + } + + PX_INLINE uint32_t getIndex() const + { + return m_index; + } + +protected: + BinaryNode* m_parent; + BinaryNode* m_children[2]; + uint32_t m_index; // index of this node in parent (0xFFFFFFFF => not attached) +}; + +PX_INLINE +BinaryNode::BinaryNode() +{ + m_index = 0xFFFFFFFF; + m_children[1] = m_children[0] = m_parent = NULL; +} + +PX_INLINE void +BinaryNode::setChild(uint32_t index, BinaryNode* child) +{ + index &= 1; + BinaryNode*& oldChild = m_children[index]; + + if (oldChild != NULL) + { + oldChild->detach(); + } + + oldChild = child; + + if (child != NULL) + { + child->detach(); + child->m_parent = this; + child->m_index = index; + } +} + +PX_INLINE void +BinaryNode::detach() +{ + if (m_parent != NULL) + { + PX_ASSERT(m_parent->getChild(m_index) == this); + m_parent->m_children[m_index & 1] = NULL; + m_parent = NULL; + m_index = 0xFFFFFFFF; + } +} + + +// CSG mesh representation + +class UV : public Vec<Real, 2> +{ +public: + + PX_INLINE UV() {} + PX_INLINE UV(const float* uv) + { + set((Real)uv[0], (Real)uv[1]); + } + PX_INLINE UV(const double* uv) + { + set((Real)uv[0], (Real)uv[1]); + } + PX_INLINE UV& operator = (const UV& uv) + { + el[0] = uv.el[0]; + el[1] = uv.el[1]; + return *this; + } + + PX_INLINE void set(Real u, Real v) + { + el[0] = u; + el[1] = v; + } + + PX_INLINE const Real& u() const + { + return el[0]; + } + PX_INLINE const Real& v() const + { + return el[1]; + } +}; + +class Color : public Vec<Real, 4> +{ +public: + + PX_INLINE Color() {} + PX_INLINE Color(const uint32_t c); + PX_INLINE Color& operator = (const Color& c) + { + el[0] = c.el[0]; + el[1] = c.el[1]; + el[2] = c.el[2]; + el[3] = c.el[3]; + return *this; + } + + PX_INLINE void set(Real r, Real g, Real b, Real a) + { + el[0] = r; + el[1] = g; + el[2] = b; + el[3] = a; + } + + PX_INLINE uint32_t toInt() const; + + PX_INLINE const Real& r() const + { + return el[0]; + } + PX_INLINE const Real& g() const + { + return el[1]; + } + PX_INLINE const Real& b() const + { + return el[2]; + } + PX_INLINE const Real& a() const + { + return el[3]; + } +}; + +PX_INLINE +Color::Color(const uint32_t c) +{ + const Real recip255 = 1 / (Real)255; + set((Real)(c & 0xFF)*recip255, (Real)((c >> 8) & 0xFF)*recip255, (Real)((c >> 16) & 0xFF)*recip255, (Real)(c >> 24)*recip255); +} + +PX_INLINE uint32_t +Color::toInt() const +{ + return (uint32_t)((int)(255 * el[3] + (Real)0.5)) << 24 | (uint32_t)((int)(255 * el[2] + (Real)0.5)) << 16 | (uint32_t)((int)(255 * el[1] + (Real)0.5)) << 8 | (uint32_t)((int)(255 * el[0] + (Real)0.5)); +} + +struct VertexData +{ + Dir normal; + Dir tangent; + Dir binormal; + UV uv[nvidia::VertexFormat::MAX_UV_COUNT]; + Color color; +}; + +struct Triangle +{ + Pos vertices[3]; + Dir normal; + Real area; + int32_t submeshIndex; + uint32_t smoothingMask; + uint32_t extraDataIndex; + + void fromExplicitRenderTriangle(VertexData vertexData[3], const nvidia::ExplicitRenderTriangle& tri) + { + for (unsigned i = 0; i < 3; ++i) + { + vertices[i] = Pos(tri.vertices[i].position); + vertexData[i].normal = Dir(tri.vertices[i].normal); + vertexData[i].tangent = Dir(tri.vertices[i].tangent); + vertexData[i].binormal = Dir(tri.vertices[i].binormal); + for (unsigned j = 0; j < nvidia::VertexFormat::MAX_UV_COUNT; ++j) + { + vertexData[i].uv[j] = UV(&tri.vertices[i].uv[j][0]); + } + vertexData[i].color.set((Real)tri.vertices[i].color.r, (Real)tri.vertices[i].color.g, (Real)tri.vertices[i].color.b, (Real)tri.vertices[i].color.a); + } + submeshIndex = tri.submeshIndex; + smoothingMask = tri.smoothingMask; + extraDataIndex = tri.extraDataIndex; + calculateQuantities(); + } + + void toExplicitRenderTriangle(nvidia::ExplicitRenderTriangle& tri, const VertexData vertexData[3]) const + { + for (unsigned i = 0; i < 3; ++i) + { + tri.vertices[i].position = ApexCSG::GSA::toPxVec3(vertices[i]); + tri.vertices[i].normal = ApexCSG::GSA::toPxVec3(vertexData[i].normal); + tri.vertices[i].tangent = ApexCSG::GSA::toPxVec3(vertexData[i].tangent); + tri.vertices[i].binormal = ApexCSG::GSA::toPxVec3(vertexData[i].binormal); + for (unsigned j = 0; j < nvidia::VertexFormat::MAX_UV_COUNT; ++j) + { + tri.vertices[i].uv[j].set((float)vertexData[i].uv[j][0], (float)vertexData[i].uv[j][1]); + } + tri.vertices[i].color.set((float)vertexData[i].color.r(), (float)vertexData[i].color.g(), (float)vertexData[i].color.b(), (float)vertexData[i].color.a()); + } + tri.submeshIndex = submeshIndex; + tri.smoothingMask = smoothingMask; + tri.extraDataIndex = extraDataIndex; + } + + void calculateQuantities() + { + const Dir e0 = Dir(vertices[1] - vertices[0]); + const Dir e1 = Dir(vertices[2] - vertices[1]); + const Dir e2 = Dir(vertices[0] - vertices[2]); + normal = (e0^e1) + (e1^e2) + (e2^e0); + area = (Real)0.5 * normal.normalize(); + } + + void transform(const Mat4Real& tm) + { + for (int i = 0; i < 3; ++i) + { + vertices[i] = tm*vertices[i]; + } + calculateQuantities(); + } +}; + +struct LinkedVertex : public nvidia::Link +{ + LinkedVertex* getAdj(uint32_t which) const + { + return (LinkedVertex*)nvidia::Link::getAdj(which); + } + + Pos vertex; +}; + +struct LinkedEdge2D : public nvidia::Link +{ + LinkedEdge2D() : loopID(-1) {} + ~LinkedEdge2D() + { + remove(); + } + + void setAdj(uint32_t which, LinkedEdge2D* link) + { + // Ensure neighboring links' adjoining vertices are equal + which &= 1; + const uint32_t other = which ^ 1; + v[which] = link->v[other]; + ((LinkedEdge2D*)link->adj[other])->v[which] = ((LinkedEdge2D*)adj[which])->v[other]; + nvidia::Link::setAdj(which, link); + } + + LinkedEdge2D* getAdj(uint32_t which) const + { + return (LinkedEdge2D*)nvidia::Link::getAdj(which); + } + + void remove() + { + // Ensure neighboring links' adjoining vertices are equal + ((LinkedEdge2D*)adj[0])->v[1] = ((LinkedEdge2D*)adj[1])->v[0] = (Real)0.5 * (v[0] + v[1]); + nvidia::Link::remove(); + } + + Vec2Real v[2]; + int32_t loopID; +}; + +struct Surface +{ + uint32_t planeIndex; + uint32_t triangleIndexStart; + uint32_t triangleIndexStop; + float totalTriangleArea; // Keeping it 32-bit real, since we don't need precision here +}; + +struct Region +{ + uint32_t side; + + // Not to be serialized, but we have this extra space since Region is used in a union with Surface + uint32_t tempIndex1; + uint32_t tempIndex2; + uint32_t tempIndex3; +}; + + +// Interpolator - calculates interpolation data for triangle quantities +class Interpolator +{ +public: + + enum VertexField + { + Normal_x, Normal_y, Normal_z, + Tangent_x, Tangent_y, Tangent_z, + Binormal_x, Binormal_y, Binormal_z, + UV0_u, UV0_v, UV1_u, UV1_v, UV2_u, UV2_v, UV3_u, UV3_v, + Color_r, Color_g, Color_b, Color_a, + + VertexFieldCount + }; + + Interpolator() {} + Interpolator(const Triangle& tri, const VertexData vertexData[3]) + { + setFromTriangle(tri, vertexData); + } + Interpolator(const Dir tangents[3], const Vec<Real, 2>& uvScale) + { + setFlat(tangents, uvScale); + } + + PX_INLINE void setFromTriangle(const Triangle& tri, const VertexData vertexData[3]); + PX_INLINE void setFlat(const Dir tangents[3], const Vec<Real, 2>& uvScale); + + PX_INLINE void interpolateVertexData(VertexData& vertexData, const Pos& point) const; + + PX_INLINE bool equals(const Interpolator& interpolator, Real frameDirTol, Real frameScaleTol, Real dirTol, Real uvTol, Real colorTol) const; + + PX_INLINE void transform(Interpolator& transformedInterpolator, const Mat4Real& tm, const Mat4Real& cofTM) const; + + void serialize(physx::PxFileBuf& stream) const; + void deserialize(physx::PxFileBuf& stream, uint32_t version); + +private: + ApexCSG::Plane m_frames[VertexFieldCount]; + static size_t s_offsets[VertexFieldCount]; + + friend class InterpolatorBuilder; +}; + +PX_INLINE void +Interpolator::setFromTriangle(const Triangle& tri, const VertexData vertexData[3]) +{ + const Pos& p0 = tri.vertices[0]; + const Pos& p1 = tri.vertices[1]; + const Pos& p2 = tri.vertices[2]; + const Dir p1xp2 = Dir(p1) ^ Dir(p2); + const Dir p2xp0 = Dir(p2) ^ Dir(p0); + const Dir p0xp1 = Dir(p0) ^ Dir(p1); + const Dir n = p1xp2 + p2xp0 + p0xp1; + const Real n2 = n | n; + if (n2 < EPS_REAL * EPS_REAL) + { + for (uint32_t i = 0; i < VertexFieldCount; ++i) + { + m_frames[i].set(Dir((Real)0), 0); + } + return; + } + + // Calculate inverse 4x4 matrix (only need first three columns): + const Dir nP = n / n2; // determinant is -n2 + const Dir Q0(nP[2] * (p1[1] - p2[1]) - nP[1] * (p1[2] - p2[2]), nP[2] * (p2[1] - p0[1]) - nP[1] * (p2[2] - p0[2]), nP[2] * (p0[1] - p1[1]) - nP[1] * (p0[2] - p1[2])); + const Dir Q1(nP[0] * (p1[2] - p2[2]) - nP[2] * (p1[0] - p2[0]), nP[0] * (p2[2] - p0[2]) - nP[2] * (p2[0] - p0[0]), nP[0] * (p0[2] - p1[2]) - nP[2] * (p0[0] - p1[0])); + const Dir Q2(nP[1] * (p1[0] - p2[0]) - nP[0] * (p1[1] - p2[1]), nP[1] * (p2[0] - p0[0]) - nP[0] * (p2[1] - p0[1]), nP[1] * (p0[0] - p1[0]) - nP[0] * (p0[1] - p1[1])); + const Dir r(nP | p1xp2, nP | p2xp0, nP | p0xp1); + + for (uint32_t i = 0; i < VertexFieldCount; ++i) + { + const size_t offset = s_offsets[i]; + const Dir vi(*(Real*)(((uint8_t*)&vertexData[0]) + offset), *(Real*)(((uint8_t*)&vertexData[1]) + offset), *(Real*)(((uint8_t*)&vertexData[2]) + offset)); + Dir n(Q0 | vi, Q1 | vi, Q2 | vi); + if ((n | n) < 100 * EPS_REAL * EPS_REAL) + { + n.set((Real)0, (Real)0, (Real)0); + } + Real o = r | vi; + if (physx::PxAbs(o) < 100 * EPS_REAL) + { + o = (Real)0; + } + m_frames[i].set(n, o); + } +} + +PX_INLINE void +Interpolator::setFlat(const Dir tangents[3], const Vec<Real, 2>& uvScale) +{ + // Local z ~ normal = tangents[2], x ~ u and tangent = tangents[0], y ~ v and binormal = tangents[1] + m_frames[Normal_x].set(Dir((Real)0), tangents[2][0]); + m_frames[Normal_y].set(Dir((Real)0), tangents[2][1]); + m_frames[Normal_z].set(Dir((Real)0), tangents[2][2]); + m_frames[Tangent_x].set(Dir((Real)0), tangents[0][0]); + m_frames[Tangent_y].set(Dir((Real)0), tangents[0][1]); + m_frames[Tangent_z].set(Dir((Real)0), tangents[0][2]); + m_frames[Binormal_x].set(Dir((Real)0), tangents[1][0]); + m_frames[Binormal_y].set(Dir((Real)0), tangents[1][1]); + m_frames[Binormal_z].set(Dir((Real)0), tangents[1][2]); + const Dir su = (uvScale[0] ? 1 / uvScale[0] : (Real)0) * tangents[0]; + const Dir sv = (uvScale[1] ? 1 / uvScale[1] : (Real)0) * tangents[1]; + m_frames[UV0_u].set(su, 0); + m_frames[UV0_v].set(sv, 0); + m_frames[UV1_u].set(su, 0); + m_frames[UV1_v].set(sv, 0); + m_frames[UV2_u].set(su, 0); + m_frames[UV2_v].set(sv, 0); + m_frames[UV3_u].set(su, 0); + m_frames[UV3_v].set(sv, 0); + m_frames[Color_r].set(Dir((Real)0), (Real)1); + m_frames[Color_g].set(Dir((Real)0), (Real)1); + m_frames[Color_b].set(Dir((Real)0), (Real)1); + m_frames[Color_a].set(Dir((Real)0), (Real)1); +} + +PX_INLINE void +Interpolator::interpolateVertexData(VertexData& vertexData, const Pos& point) const +{ + for (uint32_t i = 0; i < VertexFieldCount; ++i) + { + Real& value = *(Real*)(((uint8_t*)&vertexData) + s_offsets[i]); + value = m_frames[i].distance(point); + } +} + +PX_INLINE bool +framesEqual(const Plane& f0, const Plane& f1, Real twoFrameScaleTol2, Real sinFrameTol2, Real tol2) +{ + const Dir n0 = f0.normal(); + const Dir n1 = f1.normal(); + const Real n02 = n0 | n0; + const Real n12 = n1 | n1; + const Real n2Diff = n02 - n12; + + if (n2Diff * n2Diff > twoFrameScaleTol2 * (n02 + n12)) + { + return false; // Scales differ by more than frame scale tolerance + } + + const Real n2Prod = n02 * n12; + const Real unnormalizedSinFrameTheta2 = (n0 ^ n1).lengthSquared(); + if (unnormalizedSinFrameTheta2 > n2Prod * sinFrameTol2) + { + return false; // Directions differ by more than frame angle tolerance + } + + const Real unnormalizedOriginDiff = f0.d() - f1.d(); + const Real originScale = 0.5f * (physx::PxAbs(f0.d()) + physx::PxAbs(f1.d())); + if (unnormalizedOriginDiff * unnormalizedOriginDiff > tol2 * originScale * originScale) + { + return false; // Origins differ by more than tolerance + } + + return true; +} + +PX_INLINE bool +Interpolator::equals(const Interpolator& interpolator, Real frameDirTol, Real frameScaleTol, Real dirTol, Real uvTol, Real colorTol) const +{ + const Real twoFrameScaleTol2 = (Real)2 * frameScaleTol * frameScaleTol; + const Real sinFrameTol2 = frameDirTol * frameDirTol; + const Real dirTol2 = dirTol * dirTol; + const Real uvTol2 = uvTol * uvTol; + const Real colorTol2 = colorTol * colorTol; + + // Directions + for (uint32_t i = Normal_x; i <= Binormal_z; ++i) + { + if (!framesEqual(m_frames[i], interpolator.m_frames[i], twoFrameScaleTol2, sinFrameTol2, dirTol2)) + { + return false; + } + } + + // UVs + for (uint32_t i = UV0_u; i <= UV3_v; ++i) + { + if (!framesEqual(m_frames[i], interpolator.m_frames[i], twoFrameScaleTol2, sinFrameTol2, uvTol2)) + { + return false; + } + } + + // Color + for (uint32_t i = Color_r; i <= Color_a; ++i) + { + if (!framesEqual(m_frames[i], interpolator.m_frames[i], twoFrameScaleTol2, sinFrameTol2, colorTol2)) + { + return false; + } + } + + return true; +} + +PX_INLINE void +Interpolator::transform(Interpolator& transformedInterpolator, const Mat4Real& tm, const Mat4Real& invTransposeTM) const +{ + // Apply left-hand transform. + for (uint32_t i = 0; i < VertexFieldCount; ++i) + { + transformedInterpolator.m_frames[i] = invTransposeTM * m_frames[i]; + } + // Apply right-hand transform. This is specific to the quantities being transformed. + for (int i = 0; i < 4; ++i) + { + // Normal, transform by invTransposeTM: + Dir normal_frame_i(transformedInterpolator.m_frames[Interpolator::Normal_x][i], transformedInterpolator.m_frames[Interpolator::Normal_y][i], transformedInterpolator.m_frames[Interpolator::Normal_z][i]); + normal_frame_i = invTransposeTM * normal_frame_i; + transformedInterpolator.m_frames[Interpolator::Normal_x][i] = normal_frame_i[0]; + transformedInterpolator.m_frames[Interpolator::Normal_y][i] = normal_frame_i[1]; + transformedInterpolator.m_frames[Interpolator::Normal_z][i] = normal_frame_i[2]; + // Tangent, transform by tm: + Dir tangent_frame_i(transformedInterpolator.m_frames[Interpolator::Tangent_x][i], transformedInterpolator.m_frames[Interpolator::Tangent_y][i], transformedInterpolator.m_frames[Interpolator::Tangent_z][i]); + tangent_frame_i = tm * tangent_frame_i; + transformedInterpolator.m_frames[Interpolator::Tangent_x][i] = tangent_frame_i[0]; + transformedInterpolator.m_frames[Interpolator::Tangent_y][i] = tangent_frame_i[1]; + transformedInterpolator.m_frames[Interpolator::Tangent_z][i] = tangent_frame_i[2]; + // Binormal, transform by tm: + Dir binormal_frame_i(transformedInterpolator.m_frames[Interpolator::Binormal_x][i], transformedInterpolator.m_frames[Interpolator::Binormal_y][i], transformedInterpolator.m_frames[Interpolator::Binormal_z][i]); + binormal_frame_i = tm * binormal_frame_i; + transformedInterpolator.m_frames[Interpolator::Binormal_x][i] = binormal_frame_i[0]; + transformedInterpolator.m_frames[Interpolator::Binormal_y][i] = binormal_frame_i[1]; + transformedInterpolator.m_frames[Interpolator::Binormal_z][i] = binormal_frame_i[2]; + // Other quantities are scalars + } +} + + +class InterpolatorBuilder +{ +public: + InterpolatorBuilder() + { +#define CREATE_OFFSET( field ) (size_t)((uintptr_t)&vertexData.field-(uintptr_t)&vertexData) + + VertexData vertexData; + Interpolator::s_offsets[Interpolator::Normal_x] = CREATE_OFFSET(normal[0]); + Interpolator::s_offsets[Interpolator::Normal_y] = CREATE_OFFSET(normal[1]); + Interpolator::s_offsets[Interpolator::Normal_z] = CREATE_OFFSET(normal[2]); + Interpolator::s_offsets[Interpolator::Tangent_x] = CREATE_OFFSET(tangent[0]); + Interpolator::s_offsets[Interpolator::Tangent_y] = CREATE_OFFSET(tangent[1]); + Interpolator::s_offsets[Interpolator::Tangent_z] = CREATE_OFFSET(tangent[2]); + Interpolator::s_offsets[Interpolator::Binormal_x] = CREATE_OFFSET(binormal[0]); + Interpolator::s_offsets[Interpolator::Binormal_y] = CREATE_OFFSET(binormal[1]); + Interpolator::s_offsets[Interpolator::Binormal_z] = CREATE_OFFSET(binormal[2]); + Interpolator::s_offsets[Interpolator::UV0_u] = CREATE_OFFSET(uv[0].u()); + Interpolator::s_offsets[Interpolator::UV0_v] = CREATE_OFFSET(uv[0].v()); + Interpolator::s_offsets[Interpolator::UV1_u] = CREATE_OFFSET(uv[1].u()); + Interpolator::s_offsets[Interpolator::UV1_v] = CREATE_OFFSET(uv[1].v()); + Interpolator::s_offsets[Interpolator::UV2_u] = CREATE_OFFSET(uv[2].u()); + Interpolator::s_offsets[Interpolator::UV2_v] = CREATE_OFFSET(uv[2].v()); + Interpolator::s_offsets[Interpolator::UV3_u] = CREATE_OFFSET(uv[3].u()); + Interpolator::s_offsets[Interpolator::UV3_v] = CREATE_OFFSET(uv[3].v()); + Interpolator::s_offsets[Interpolator::Color_r] = CREATE_OFFSET(color.r()); + Interpolator::s_offsets[Interpolator::Color_g] = CREATE_OFFSET(color.g()); + Interpolator::s_offsets[Interpolator::Color_b] = CREATE_OFFSET(color.b()); + Interpolator::s_offsets[Interpolator::Color_a] = CREATE_OFFSET(color.a()); + } +}; + + +// ClippedTriangleInfo - used to map bsp output back to the original mesh +struct ClippedTriangleInfo +{ + uint32_t planeIndex; + uint32_t originalTriangleIndex; + uint32_t clippedTriangleIndex; + uint32_t ccw; + + static int cmp(const void* a, const void* b) + { + const int planeIndexDiff = (int)((ClippedTriangleInfo*)a)->planeIndex - (int)((ClippedTriangleInfo*)b)->planeIndex; + if (planeIndexDiff != 0) + { + return planeIndexDiff; + } + const int originalTriangleDiff = (int)((ClippedTriangleInfo*)a)->originalTriangleIndex - (int)((ClippedTriangleInfo*)b)->originalTriangleIndex; + if (originalTriangleDiff != 0) + { + return originalTriangleDiff; + } + return (int)((ClippedTriangleInfo*)a)->clippedTriangleIndex - (int)((ClippedTriangleInfo*)b)->clippedTriangleIndex; + } +}; + +// BSPLink - a link with an "isBSP" method to act as a stop +class BSPLink : public nvidia::Link, public nvidia::UserAllocated +{ +public: + virtual bool isBSP() + { + return false; + } + + BSPLink* getAdjBSP(uint32_t which) const + { + if (isSolitary()) + { + return NULL; + } + BSPLink* adjLink = static_cast<BSPLink*>(getAdj(which)); + return adjLink->isBSP() ? adjLink : NULL; + } + + void removeBSPLink() + { + BSPLink* adjLink = static_cast<BSPLink*>(getAdj(1)); + remove(); + if (!adjLink->isBSP() && adjLink->isSolitary()) + { + delete adjLink; + } + } +}; + +// Specialized progress listener implementation +class QuantityProgressListener : public nvidia::IProgressListener +{ +public: + QuantityProgressListener(Real totalAmount, IProgressListener* parent) : + m_total((Real)0) + , m_parent(parent) + { + m_scale = totalAmount > (Real)0 ? (Real)100/(Real)totalAmount : (Real)0; + } + + // IProgressListener interface + virtual void setProgress(int progress, const char* taskName = NULL) + { + if (m_parent != NULL) + { + m_parent->setProgress(progress, taskName); + } + } + + virtual void add(Real amount) + { + m_total += amount; + if (m_parent != NULL) + { + m_parent->setProgress((int)(m_total*m_scale + (Real)0.5)); + } + } + +private: + Real m_total; + Real m_scale; + IProgressListener* m_parent; +}; + + +// IApexBSP implementation +class BSP : public IApexBSP, public BSPLink +{ +public: + BSP(IApexBSPMemCache* memCache = NULL, const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxIdentity)); + ~BSP(); + + // IApexBSP implementation + void setTolerances(const BSPTolerances& tolerances); + bool fromMesh(const nvidia::ExplicitRenderTriangle* mesh, uint32_t meshSize, const BSPBuildParameters& params, nvidia::IProgressListener* progressListener = NULL, volatile bool* cancel = NULL); + bool fromConvexPolyhedron(const physx::PxPlane* poly, uint32_t polySize, const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxIdentity), const nvidia::ExplicitRenderTriangle* mesh = NULL, uint32_t meshSize = 0); + bool combine(const IApexBSP& bsp); + bool op(const IApexBSP& combinedBSP, Operation::Enum operation); + bool complement(); + BSPType::Enum getType() const; + bool getSurfaceAreaAndVolume(float& area, float& volume, bool inside, Operation::Enum operation = Operation::NOP) const; + bool pointInside(const physx::PxVec3& point, Operation::Enum operation = Operation::NOP) const; + bool toMesh(physx::Array<nvidia::ExplicitRenderTriangle>& mesh) const; + void copy(const IApexBSP& bsp, const physx::PxMat44& tm = physx::PxMat44(physx::PxIdentity), const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxZero)); + physx::PxMat44 getInternalTransform() const + { + return m_internalTransform; + } + + void replaceInteriorSubmeshes(uint32_t frameCount, uint32_t* frameIndices, uint32_t submeshIndex); + + IApexBSP* decomposeIntoIslands() const; + IApexBSP* getNext() const + { + return static_cast<BSP*>(getAdjBSP(1)); + } + IApexBSP* getPrev() const + { + return static_cast<BSP*>(getAdjBSP(0)); + } + + void deleteTriangles(); + + void serialize(physx::PxFileBuf& stream) const; + void deserialize(physx::PxFileBuf& stream); + void visualize(nvidia::RenderDebugInterface& debugRender, uint32_t flags, uint32_t index = 0) const; + void release(); + + // Debug + void performDiagnostics() const; + + // BSPLink + bool isBSP() + { + return true; + } + + // Node, a binary node with geometric data + class Node : public BinaryNode + { + Node& operator = (const Node&); // No assignment + + public: + enum Type { Leaf, Branch }; + + Node() : m_type(Leaf) + { + m_leafData.side = 1; + } + + PX_INLINE void setLeafData(const Region& leafData) + { + m_type = Leaf; + m_leafData = leafData; + } + PX_INLINE void setBranchData(const Surface& branchData) + { + m_type = Branch; + m_branchData = branchData; + } + + PX_INLINE Type getType() const + { + return (Type)m_type; + } + + PX_INLINE Region* getLeafData() + { + PX_ASSERT(getType() == Leaf); + return &m_leafData; + } + PX_INLINE Surface* getBranchData() + { + PX_ASSERT(getType() == Branch); + return &m_branchData; + } + PX_INLINE const Region* getLeafData() const + { + PX_ASSERT(getType() == Leaf); + return &m_leafData; + } + PX_INLINE const Surface* getBranchData() const + { + PX_ASSERT(getType() == Branch); + return &m_branchData; + } + + PX_INLINE Node* getParent() const + { + return (Node*)BinaryNode::getParent(); + } + PX_INLINE Node* getChild(uint32_t index) const + { + return (Node*)BinaryNode::getChild(index); + } + + // Iterator (uses a stack, but no recursion) + // Can handle branches with NULL children + class It + { + public: + PX_INLINE It(const Node* root) : m_current(const_cast<Node*>(root)), m_valid(true) {} + PX_INLINE It(Node* root) : m_current(root), m_valid(true) {} + + PX_INLINE bool valid() const + { + return m_valid; + } + + PX_INLINE Node* node() const + { + return m_current; + } + + PX_INLINE void inc() + { + if (m_current != NULL && m_current->getType() == Branch) + { + m_stack.pushBack(m_current->getChild(1)); + m_current = m_current->getChild(0); + } + else + if (!m_stack.empty()) + { + m_current = m_stack.popBack(); + } + else + { + m_current = NULL; + m_valid = false; + } + } + + private: + Node* m_current; + physx::Array<Node*> m_stack; + bool m_valid; + }; + + protected: + uint32_t m_type; + + union + { + Region m_leafData; + Surface m_branchData; + }; + }; + + class Halfspace : public GSA::VS3D_Halfspace_Set + { + public: + Halfspace(const Plane plane) : m_plane(plane) {} + + virtual GSA::real farthest_halfspace(GSA::real plane[4], const GSA::real point[4]) + { + for (int i = 0; i < 4; ++i) plane[i] = (GSA::real)m_plane[i]; + return plane[0]*point[0] + plane[1]*point[1] + plane[2]*point[2] + plane[3]*point[3]; + } + + Halfspace& operator = (const Halfspace& halfspace) { m_plane = halfspace.m_plane; return *this; } + + private: + Plane m_plane; + }; + + class RegionShape : public GSA::VS3D_Halfspace_Set + { + public: + RegionShape(const Plane* planes, Real skinWidth = (Real)0) : m_planes(planes), m_leaf(NULL), m_nonempty(true), m_skinWidth(skinWidth) {} + + virtual GSA::real farthest_halfspace(GSA::real plane[4], const GSA::real point[4]); + + void set_leaf(const BSP::Node* leaf) + { + m_leaf = leaf; + } + + void calculate() + { + m_nonempty = (1 == GSA::vs3d_test(*this)); + } + + bool is_nonempty() const + { + return m_nonempty; + } + +#if 0 + bool intersects_halfspace(const Plane* plane) + { + Halfspace halfspace(plane); + set_shapes(this, &halfspace); + return intersect(); + } +#endif + + private: + const Plane* m_planes; + const BSP::Node* m_leaf; + bool m_nonempty; + Real m_skinWidth; + }; + +private: + class BoolOp + { + public: + BoolOp(Operation::Enum op) : c_ba(((uint32_t)op >> 3) & 1), c_b(((uint32_t)op >> 2) & 1), c_a(((uint32_t)op >> 1) & 1), c_k((uint32_t)op & 1) {} + + uint32_t operator()(uint32_t a, uint32_t b) const + { + return (c_ba & a & b) ^(c_b & b) ^(c_a & a) ^ c_k; + } + + private: + uint32_t c_ba, c_b, c_a, c_k; + }; + + struct BuildConstants + { + BSPBuildParameters m_params; + float m_recipMaxArea; + }; + + void clear(); + + void transform(const Mat4Real& tm, bool transformFrames = true); + + // Returns the area and volume of the clipped mesh. clippedMesh and triangleInfo may be NULL, in which case nothing is done but + // the area and volume calculation. + void clipMeshToLeaf(Real& area, Real& volume, physx::Array<Triangle>* clippedMesh, physx::Array<ClippedTriangleInfo>* triangleInfo, const Node* leaf, float clipTolerance) const; + + // Called by buildTree - forcing no inline to ensure a small stack frame + + // Returns a new stackReadStop + PX_INLINE uint32_t removeRedundantSurfacesFromStack(physx::Array<Surface>& surfaceStack, uint32_t stackReadStart, uint32_t stackReadStop, Node* leaf); + PX_INLINE void assignLeafSide(Node* leaf, QuantityProgressListener* quantityListener); + PX_INLINE void createBranchSurfaceAndSplitStack(uint32_t childReadStart[2], uint32_t childReadStop[2], Node* node, physx::Array<Surface>& surfaceStack, + uint32_t stackReadStart, uint32_t stackReadStop, const BuildConstants& buildConstants); + + // Recursive functions + void complementLeaves(Node* root) const; + void mergeLeaves(const BoolOp& op, Node* root); + void clipMeshToLeaves(physx::Array<Triangle>& clippedMesh, physx::Array<ClippedTriangleInfo>& triangleInfo, Node* root, float clipTolerance) const; + void clone(Node* root, const Node* originalRoot); + void combineTrees(Node* root, const Node* combineRoot, uint32_t triangleIndexOffset, uint32_t planeIndexOffset); + bool buildTree(Node* root, physx::Array<Surface>& surfaceStack, uint32_t stackReadStart, uint32_t stackReadStop, + const BuildConstants& buildConstants, QuantityProgressListener* quantityListener, volatile bool* cancel = NULL); + void visualizeNode(nvidia::RenderDebugInterface& debugRender, uint32_t flags, const Node* root) const; + bool addLeafAreasAndVolumes(Real& totalArea, Real& totalVolume, const Node* root, bool inside, const BoolOp& op) const; + void serializeNode(const Node* root, physx::PxFileBuf& stream) const; + Node* deserializeNode(uint32_t version, physx::PxFileBuf& stream); + void releaseNode(Node* node); + void indexInsideLeaves(uint32_t& index, Node* root) const; + void listInsideLeaves(physx::Array<Node*>& insideLeaves, Node* root) const; + void findInsideLeafNeighbors(physx::Array<nvidia::IntPair>& neighbors, Node* root) const; + + void clean(); + + // Parameters + BSPTolerances m_tolerarnces; + + // Tree + Node* m_root; + + // Internal mesh representation + physx::Array<Triangle> m_mesh; + physx::Array<Interpolator> m_frames; + Real m_meshSize; + physx::PxBounds3 m_meshBounds; + physx::PxMat44 m_internalTransform; + Mat4Real m_internalTransformInverse; + bool m_incidentalMesh; + + + // Unique splitting planes + physx::Array<Plane> m_planes; + + // Combination data + bool m_combined; + Real m_combiningMeshSize; + bool m_combiningIncidentalMesh; + + // Memory cache + class BSPMemCache* m_memCache; + bool m_ownsMemCache; +}; + + +// Surface iterator; walks from a leaf's parent to the root of a tree, allowing inspection of surfaces along the way +class SurfaceIt +{ +public: + PX_INLINE SurfaceIt() : m_current(NULL), m_side(0xFFFFFFFF) {} + PX_INLINE SurfaceIt(const BSP::Node* leaf) : m_current((BSP::Node*)leaf) + { + PX_ASSERT(leaf != NULL && leaf->getType() == BSP::Node::Leaf); + inc(); + } + + PX_INLINE bool valid() const + { + return m_current != NULL; + } + + PX_INLINE void inc() + { + m_side = m_current->getIndex(); + m_current = m_current->getParent(); + } + + PX_INLINE const Surface* surface() const + { + return m_current->getBranchData(); + } + + PX_INLINE uint32_t side() const + { + return m_side; + } + +private: + BSP::Node* m_current; + uint32_t m_side; +}; + + +// IBSPMemCache implementation, several pools and growable arrays. Not global, so that concurrent calculations can use different pools +class BSPMemCache : public IApexBSPMemCache, public nvidia::UserAllocated +{ +public: + + BSPMemCache(); + + void clearAll(); + void clearTemp(); + + void release(); + + // Persistent data + nvidia::Pool<BSP::Node> m_nodePool; + + // Temporary data + nvidia::Pool<LinkedVertex> m_linkedVertexPool; + physx::Array<uint8_t> m_surfaceFlags; + physx::Array<uint8_t> m_surfaceTestFlags; +}; + + +// Mesh cleaning interface +void +cleanMesh(physx::Array<nvidia::ExplicitRenderTriangle>& cleanedMesh, const physx::Array<Triangle>& mesh, physx::Array<ClippedTriangleInfo>& triangleInfo, const physx::Array<Plane>& planes, const physx::Array<Triangle>& originalTriangles, const physx::Array<Interpolator>& frames, Real distanceTol, const Mat4Real& BSPToMeshTM); + +}; // namespace ApexCSG + +#endif + +#endif // #define APEX_CSG_DEFS_H diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSGFastMath.h b/APEX_1.4/shared/internal/include/authoring/ApexCSGFastMath.h new file mode 100644 index 00000000..22884507 --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexCSGFastMath.h @@ -0,0 +1,794 @@ +/* + * 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 APEX_CSG_FAST_MATH_H +#define APEX_CSG_FAST_MATH_H + +#include "ApexUsingNamespace.h" +#include "PxMath.h" +#include "PxVec3.h" + +#include "PsUtilities.h" + +#include "PxIntrinsics.h" +#include <emmintrin.h> +#include <fvec.h> + +#include <math.h> +#include <float.h> + +#ifdef __SSE2__ +#define APEX_CSG_SSE +#include <mmintrin.h> +#include <emmintrin.h> +#endif +#ifdef __SSE3__ +#include <pmmintrin.h> +#endif +#ifdef __SSE4_1__ +#include <smmintrin.h> +#endif + +namespace ApexCSG +{ + +/* Utilities */ + +template<typename T> +T square(T t) +{ + return t * t; +} + + +/* Linear algebra */ + +#define ALL_i( _D, _exp ) for( int i = 0; i < _D; ++i ) { _exp; } + +#ifndef APEX_CSG_LOOP_UNROLL +#define APEX_CSG_LOOP_UNROLL 1 +#endif + +#ifndef APEX_CSG_SSE +#define APEX_CSG_SSE 1 +#endif + +#ifndef APEX_CSG_INLINE +#define APEX_CSG_INLINE 1 +#endif + +#ifndef APEX_CSG_ALIGN +#define APEX_CSG_ALIGN 16 +#endif + +#if APEX_CSG_LOOP_UNROLL + +#define VEC_SIZE() sizeof(*this)/sizeof(Real) + +#define OP_VV(a,op,b,i) a[i] op b[i] +#define OP_SV(a,op,b,i) a op b[i] +#define OP_VS(a,op,b,i) a[i] op b +#define OP_VVV(a,op1,b,op2,c,i) a[i] op1 b[i] op2 c[i] +#define OP_SVV(a,op1,b,op2,c,i) a op1 b[i] op2 c[i] +#define OP_VVS(a,op1,b,op2,c,i) a[i] op1 b[i] op2 c +#define OP_D(_D) (_D == 0 ? 0 : (_D == 1 ? 1 : (_D == 2 ? 2 : (_D == 3 ? 3 : 3)))) +#define OP_NAME(_T) PX_CONCAT(OP_,_T) +#define OP_2_NAME(_D) ALL_2_##_D /*PX_CONCAT(ALL_2_,OP_D(_D))*/ +#define OP_3_NAME(_D) ALL_3_##_D /*PX_CONCAT(ALL_3_,OP_D(_D))*/ + +#define ALL_2_1( _T, a,op,b) OP_##_T (a,op,b,0) +#define ALL_2_2( _T, a,op,b) ALL_2_1(_T,a,op,b); OP_##_T (a,op,b,1) +#define ALL_2_3( _T, a,op,b) ALL_2_2(_T,a,op,b); OP_##_T (a,op,b,2) +#define ALL_2_4( _T, a,op,b) ALL_2_3(_T,a,op,b); OP_##_T (a,op,b,3) +#define ALL_VV_i( _D, a,op,b) OP_2_NAME(_D)(VV,a,op,b) +#define ALL_SV_i( _D, a,op,b) OP_2_NAME(_D)(SV,a,op,b) +#define ALL_VS_i( _D, a,op,b) OP_2_NAME(_D)(VS,a,op,b) + +#define ALL_3_1( _T, a,op1,b,op2,c) OP_NAME(_T) (a,op1,b,op2,c,0) +#define ALL_3_2( _T, a,op1,b,op2,c) ALL_3_1(_T,a,op1,b,op2,c); OP_NAME(_T) (a,op1,b,op2,c,1) +#define ALL_3_3( _T, a,op1,b,op2,c) ALL_3_2(_T,a,op1,b,op2,c); OP_NAME(_T) (a,op1,b,op2,c,2) +#define ALL_3_4( _T, a,op1,b,op2,c) ALL_3_3(_T,a,op1,b,op2,c); OP_NAME(_T) (a,op1,b,op2,c,3) +#define ALL_VVV_i( _D, a,op1,b,op2,c) OP_3_NAME(_D)(VVV,a,op1,b,op2,c) +#define ALL_SVV_i( _D, a,op1,b,op2,c) OP_3_NAME(_D)(SVV,a,op1,b,op2,c) +#define ALL_VVS_i( _D, a,op1,b,op2,c) OP_3_NAME(_D)(VVS,a,op1,b,op2,c) +#define ALL_VVV( a,op1,b,op2,c) OP_3_NAME(VEC_SIZE())(VVV,a,op1,b,op2,c) +#define ALL_SVV( a,op1,b,op2,c) OP_3_NAME(VEC_SIZE())(SVV,a,op1,b,op2,c) +#define ALL_VVS( a,op1,b,op2,c) OP_3_NAME(VEC_SIZE())(VVS,a,op1,b,op2,c) + +#else + +#define ALL_VV_i( _D, a,op,b) ALL_i( _D, a[i] op b[i] ) +#define ALL_SV_i( _D, a,op,b) ALL_i( _D, a op b[i] ) +#define ALL_VS_i( _D, a,op,b) ALL_i( _D, a[i] op b ) +#define ALL_VVV_i( _D, a,op1,b,op2,c) ALL_i( _D, a[i] op1 b[i] op2 c[i] ) +#define ALL_SVV_i( _D, a,op1,b,op2,c) ALL_i( _D, a op1 b[i] op2 c[i] ) +#define ALL_VVS_i( _D, a,op1,b,op2,c) ALL_i( _D, a[i] op1 b[i] op2 c ) + +#endif + +/* General vector */ + +__declspec(align(APEX_CSG_ALIGN)) class aligned { }; + +template<typename T, int D> +class Vec : public aligned +{ +public: + + PX_INLINE Vec() {} + PX_INLINE Vec(const T& v) + { + set(v); + } + PX_INLINE Vec(const T* v) + { + set(v); + } + + PX_INLINE void set(const T& v) + { + ALL_i(D, el[i] = v); + } + PX_INLINE void set(const T* v) + { + ALL_i(D, el[i] = v[i]); + } + + PX_INLINE T& operator [](int i) + { + return el[i]; + } + PX_INLINE const T& operator [](int i) const + { + return el[i]; + } + + PX_INLINE Vec operator - () const + { + Vec r; + ALL_i(D, r[i] = -el[i]); + return r; + } + + PX_INLINE Vec operator + (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] + v[i]); + return r; + } + PX_INLINE Vec operator - (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] - v[i]); + return r; + } + PX_INLINE Vec operator * (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] * v[i]); + return r; + } + PX_INLINE Vec operator / (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] / v[i]); + return r; + } + + PX_INLINE Vec operator * (T v) const + { + Vec r; + ALL_i(D, r[i] = el[i] * v); + return r; + } + PX_INLINE Vec operator / (T v) const + { + return *this * ((T)1 / v); + } + + PX_INLINE Vec& operator += (const Vec& v) + { + ALL_i(D, el[i] += v[i]); + return *this; + } + PX_INLINE Vec& operator -= (const Vec& v) + { + ALL_i(D, el[i] -= v[i]); + return *this; + } + PX_INLINE Vec& operator *= (const Vec& v) + { + ALL_i(D, el[i] *= v[i]); + return *this; + } + PX_INLINE Vec& operator /= (const Vec& v) + { + ALL_i(D, el[i] /= v[i]); + return *this; + } + + PX_FORCE_INLINE T operator | (const Vec& v) const + { + T r = (T)0; + ALL_i(D, r += el[i] * v[i]); + return r; + } + + PX_INLINE T normalize(); + + PX_INLINE T lengthSquared() const + { + return *this | *this; + } + +protected: + T el[D]; +}; + +template<typename T, int D> +PX_INLINE T +Vec<T, D>::normalize() +{ + const T l2 = *this | *this; + if (l2 == (T)0) + { + return (T)0; + } + const T recipL = (T)1 / physx::PxSqrt(l2); + *this *= recipL; + return recipL * l2; +} + +template<typename T, int D> +PX_INLINE Vec<T, D> +operator * (T s, const Vec<T, D>& v) +{ + Vec<T, D> r; + ALL_i(D, r[i] = s * v[i]); + //ALL_VVS_i(D, r, =, v, *, s); + return r; +} + + +/* Popular real vectors */ +template<typename T> +class Vec2 : public Vec<T, 2> +{ +public: + PX_INLINE Vec2() {} + PX_INLINE Vec2(const Vec2& v) + { + ALL_VV_i(2, el, =, v); + } + PX_INLINE Vec2(const Vec<T, 2>& v) + { + ALL_VV_i(2, el, =, v); + } + PX_INLINE Vec2(T x, T y) + { + set(x, y); + } + PX_INLINE Vec2& operator = (const Vec2& v) + { + ALL_VV_i(2, el, =, v); + return *this; + } + + PX_INLINE void set(const T* v) + { + ALL_VV_i(2, el, =, v); + } + PX_INLINE void set(T x, T y) + { + el[0] = x; + el[1] = y; + } + + PX_INLINE T operator ^(const Vec2& v) const + { + return el[0] * v.el[1] - el[1] * v.el[0]; + } +}; +typedef Vec2<Real> Vec2Real; + +template<typename T> +class Vec3 : public Vec<T, 3> +{ +public: + PX_INLINE Vec3() {} + PX_INLINE Vec3(const Vec3& v) + { + ALL_VV_i(3, el, =, v); + } + PX_INLINE Vec3(const Vec<T, 3>& v) + { + ALL_VV_i(3, el, =, v); + } + PX_INLINE Vec3(T x, T y, T z) + { + set(x, y, z); + } + PX_INLINE Vec3& operator = (const Vec3& v) + { + ALL_VV_i(3, el, =, v); + return *this; + } + + PX_INLINE void set(const T* v) + { + ALL_VV_i(3, el, =, v); + } + PX_INLINE void set(T x, T y, T z) + { + el[0] = x; + el[1] = y; + el[2] = z; + } +}; +typedef Vec3<Real> Vec3Real; + +template<typename T> +class Vec4 : public Vec<Real, 4> +{ +public: + PX_INLINE Vec4() {} + PX_INLINE Vec4(const Vec4& v) + { + ALL_VV_i(4, el, =, v); + } + PX_INLINE Vec4(const Vec<T, 4>& v) + { + ALL_VV_i(4, el, =, v); + } + PX_INLINE Vec4(T x, T y, T z, T w) + { + set(x, y, z, w); + } + PX_INLINE Vec4& operator = (const Vec4& v) + { + ALL_VV_i(4, el, =, v); + return *this; + } + + PX_INLINE void set(const T* v) + { + ALL_VV_i(4, el, =, v); + } + PX_INLINE void set(T x, T y, T z, T w) + { + el[0] = x; + el[1] = y; + el[2] = z; + el[3] = w; + } + +#if APEX_CSG_INLINE + PX_INLINE Vec operator - () const + { + Vec4Real r; + ALL_VV_i(4, r, =, -el); + return r; + } + + PX_INLINE Vec4 operator + (const Vec4& v) const + { + Vec r; + ALL_VVV_i(4, r, =, el, +, v); + return r; + } + PX_INLINE Vec4 operator - (const Vec4& v) const + { + Vec r; + ALL_VVV_i(4, r, =, el, -, v); + return r; + } + PX_INLINE Vec4 operator * (const Vec4& v) const + { + Vec r; + ALL_VVV_i(4, r, =, el, *, v); + return r; + } + PX_INLINE Vec4 operator / (const Vec4& v) const + { + Vec4 r; + ALL_VVV_i(4, r, =, el, /, v); + return r; + } + + PX_INLINE Vec4 operator * (Real v) const + { + Vec4 r; + ALL_VVS_i(4, r, = , el, *, v); + return r; + } + PX_INLINE Vec4 operator / (Real v) const + { + return *this * (1. / v); + } + + PX_INLINE Vec4& operator += (const Vec4& v) + { + ALL_VV_i(4, el, +=, v); + return *this; + } + PX_INLINE Vec4& operator -= (const Vec4& v) + { + ALL_VV_i(4, el, -=, v); + return *this; + } + PX_INLINE Vec4& operator *= (const Vec4& v) + { + ALL_VV_i(4, el, *=, v); + return *this; + } + PX_INLINE Vec4& operator *= (Real v) + { + ALL_VS_i(4, el, *=, v); + return *this; + } + PX_INLINE Vec4& operator /= (Real v) + { + Real vInv = 1. / v; + return operator*=(vInv); + } + PX_INLINE Vec4& operator /= (const Vec4& v) + { + ALL_VV_i(4, el, /=, v); + return *this; + } +#endif /* #if APEX_CGS_INLINE */ + + template<typename U> friend U dot(const Vec4<U>&, const Vec4<U>&); + PX_FORCE_INLINE Real operator | (const Vec4& v) const + { + return dot(*this, v); + } +}; +typedef Vec4<Real> Vec4Real; + +template<typename T> +PX_FORCE_INLINE T dot(const Vec4<T>& a, const Vec4<T>& b) +{ + Real r = 0; + ALL_SVV_i(sizeof(a)/sizeof(T), r, +=, a, *, b); + return r; +} + +#if APEX_CSG_SSE + +template<typename T> PX_INLINE __m128d& xy(Vec4<T>& v) { return *reinterpret_cast< __m128d*>(&v[0]); } +template<typename T> PX_INLINE const __m128d& xy(const Vec4<T>& v) { return *reinterpret_cast<const __m128d*>(&v[0]); } +template<typename T> PX_INLINE __m128d& zw(Vec4<T>& v) { return *reinterpret_cast< __m128d*>(&v[2]); } +template<typename T> PX_INLINE const __m128d& zw(const Vec4<T>& v) { return *reinterpret_cast<const __m128d*>(&v[2]); } +template<typename T> PX_INLINE __m128& xyzw(Vec4<T>& v) { return *reinterpret_cast< __m128*>(&v[0]); } +template<typename T> PX_INLINE const __m128& xyzw(const Vec4<T>& v) { return *reinterpret_cast<const __m128*>(&v[0]); } + +template<> +PX_FORCE_INLINE double dot<double>(const Vec4<double>& a, const Vec4<double>& b) +{ + __declspec(align(16)) double r[2] = { 0., 0. }; + __m128d mresult; + mresult = _mm_add_pd(_mm_mul_pd( xy(a), xy(b) ), + _mm_mul_pd( zw(a), zw(b) ) ); + _mm_store_pd(r, mresult); + return r[0] + r[1]; +} + +#endif /* #if APEX_CSG_SSE */ + +/* Position */ + +class Pos : public Vec4Real +{ +public: + + PX_INLINE Pos() + { + el[3] = 1; + } + PX_INLINE Pos(Real x, Real y, Real z) + { + set(x, y, z); + } + PX_INLINE Pos(Real c) + { + set(c, c, c); + } + PX_INLINE Pos(physx::PxVec3 p) + { + set(p.x, p.y, p.z); + } + PX_INLINE Pos(const Vec<Real, 4>& v) + { + set(v[0], v[1], v[2]); + } + PX_INLINE Pos(const float* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Pos(const double* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Pos(const Pos& p) + { + set(p[0], p[1], p[2]); + } + PX_INLINE Pos& operator = (const Pos& p) + { + set(p[0], p[1], p[2]); + return *this; + } + + PX_INLINE void set(Real x, Real y, Real z) + { + Vec4Real::set(x, y, z, (Real)1); + } + +}; + + +/* Direction */ + +class Dir : public Vec4Real +{ +public: + + PX_INLINE Dir() + { + el[3] = 0; + } + PX_INLINE Dir(Real x, Real y, Real z) + { + set(x, y, z); + } + PX_INLINE Dir(Real c) + { + set(c, c, c); + } + PX_INLINE Dir(physx::PxVec3 p) + { + set(p.x, p.y, p.z); + } + PX_INLINE Dir(const Vec<Real, 4>& v) + { + set(v[0], v[1], v[2]); + } + PX_INLINE Dir(const float* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Dir(const double* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Dir(const Dir& d) + { + set(d[0], d[1], d[2]); + } + PX_INLINE Dir& operator = (const Dir& d) + { + set(d[0], d[1], d[2]); + return *this; + } + + PX_INLINE void set(Real x, Real y, Real z) + { + Vec4Real::set(x, y, z, (Real)0); + } + + PX_INLINE Dir operator ^(const Dir& d) const + { + return Dir(el[1] * d[2] - el[2] * d[1], el[2] * d[0] - el[0] * d[2], el[0] * d[1] - el[1] * d[0]); + } + +}; + + +/* Plane */ + +class Plane : public Vec4Real +{ +public: + + PX_INLINE Plane() {} + PX_INLINE Plane(const Dir& n, Real d) + { + set(n, d); + } + PX_INLINE Plane(const Dir& n, const Pos& p) + { + set(n, p); + } + PX_INLINE Plane(const Vec<Real, 4>& v) + { + Vec4Real::set(v[0], v[1], v[2], v[3]); + } + PX_INLINE Plane(const Plane& p) + { + ALL_VV_i(4, el, =, p); + } + PX_INLINE Plane& operator = (const Plane& p) + { + ALL_VV_i(4, el, =, p); + return *this; + } + + PX_INLINE void set(const Dir& n, Real d) + { + ALL_VV_i(3, el, =, n); + el[3] = d; + } + PX_INLINE void set(const Dir& n, const Pos& p) + { + ALL_VV_i(3, el, =, n); + el[3] = -(n | p); + } + + PX_INLINE Dir normal() const + { + return Dir(el[0], el[1], el[2]); + } + PX_INLINE Real d() const + { + return el[3]; + } + PX_INLINE Real distance(const Pos& p) const + { + return p | *this; + } + PX_INLINE Pos project(const Pos& p) const + { + return p - normal() * distance(p); + } + + PX_INLINE Real normalize(); +}; + +PX_INLINE Real +Plane::normalize() +{ + const Real oldD = el[3]; + el[3] = 0; + const Real l2 = *this | *this; + if (l2 == 0) + { + return 0; + } + const Real recipL = 1. / physx::PxSqrt(l2); + el[3] = oldD; + *this *= recipL; + return recipL * l2; +} + + +/* Matrix */ + +__declspec(align(16)) class Mat4Real : public Vec<Vec4Real, 4> +{ +public: + + PX_INLINE Mat4Real() {} + PX_INLINE Mat4Real(const Real v) + { + set(v); + } + PX_INLINE Mat4Real(const Real* v) + { + set(v); + } + + PX_INLINE void set(const Real v) + { + el[0].set(v, 0, 0, 0); + el[1].set(0, v, 0, 0); + el[2].set(0, 0, v, 0); + el[3].set(0, 0, 0, v); + } + PX_INLINE void set(const Real* v) + { + ALL_i(4, el[i].set(v + 4 * i)); + } + PX_INLINE void setCol(int colN, const Vec4Real& col) + { + ALL_i(4, el[i][colN] = col[i]); + } + + PX_INLINE Vec4Real operator * (const Vec4Real& v) const + { + Vec4Real r; + ALL_VVS_i(4, r, =, el, |, v); + return r; + } + PX_INLINE Mat4Real operator * (const Mat4Real& m) const + { + Mat4Real r((Real)0); + for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) for (int k = 0; k < 4; ++k) + { + r[i][j] += el[i][k] * m[k][j]; + } + return r; + } + PX_INLINE Mat4Real operator * (Real s) const + { + Mat4Real r; + ALL_VVS_i(4, r, =, el, *, s); + return r; + } + PX_INLINE Mat4Real operator / (Real s) const + { + return *this * ((Real)1 / s); + } + + PX_INLINE Mat4Real& operator *= (Real s) + { + ALL_VS_i(4, el, *=, s); + return *this; + } + PX_INLINE Mat4Real& operator /= (Real s) + { + *this *= ((Real)1 / s); + return *this; + } + + PX_INLINE Vec4Real getCol(int colN) const + { + Vec4Real col; + ALL_i(4, col[i] = el[i][colN]); + return col; + } + PX_INLINE Real det3() const + { + return el[0] | (Dir(el[1]) ^ Dir(el[2])); // Determinant of upper-left 3x3 block (same as full determinant if last row = (0,0,0,1)) + } + PX_INLINE Mat4Real cof34() const; // Assumes last row = (0,0,0,1) + PX_INLINE Mat4Real inverse34() const; // Assumes last row = (0,0,0,1) +}; + +PX_INLINE Mat4Real +Mat4Real::cof34() const +{ + Mat4Real r; + r[0].set(el[1][1]*el[2][2] - el[1][2]*el[2][1], el[1][2]*el[2][0] - el[1][0]*el[2][2], el[1][0]*el[2][1] - el[1][1]*el[2][0], 0); + r[1].set(el[2][1]*el[0][2] - el[2][2]*el[0][1], el[2][2]*el[0][0] - el[2][0]*el[0][2], el[2][0]*el[0][1] - el[2][1]*el[0][0], 0); + r[2].set(el[0][1]*el[1][2] - el[0][2]*el[1][1], el[0][2]*el[1][0] - el[0][0]*el[1][2], el[0][0]*el[1][1] - el[0][1]*el[1][0], 0); + r[3] = -el[0][3] * r[0] - el[1][3] * r[1] - el[2][3] * r[2]; + r[3][3] = r[0][0] * el[0][0] + r[0][1] * el[0][1] + r[0][2] * el[0][2]; + return r; +} + +PX_INLINE Mat4Real +Mat4Real::inverse34() const +{ + const Mat4Real cof = cof34(); + Mat4Real inv; + const Real recipDet = physx::PxAbs(cof[3][3]) > EPS_REAL * EPS_REAL * EPS_REAL ? 1 / cof[3][3] : (Real)0; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 4; ++j) + { + inv[i][j] = cof[j][i] * recipDet; + } + } + inv[3].set(0, 0, 0, 1); + return inv; +} + +PX_INLINE Mat4Real +operator * (Real s, const Mat4Real& m) +{ + Mat4Real r; + ALL_VVS_i(4, r, =, m, *, s); + return r; +} + +} // namespace ApexCSG + +#endif // #define APEX_CSG_FAST_MATH_H diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSGFastMath2.h b/APEX_1.4/shared/internal/include/authoring/ApexCSGFastMath2.h new file mode 100644 index 00000000..6f0f9ccf --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexCSGFastMath2.h @@ -0,0 +1,630 @@ +/* + * 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 APEX_CSG_FAST_MATH_2_H +#define APEX_CSG_FAST_MATH_2_H + +#include "ApexUsingNamespace.h" +#include "PxMath.h" +#include "PxVec3.h" + +#include "PsUtilities.h" + +#include "PxIntrinsics.h" +#include <emmintrin.h> +#include <fvec.h> + +#include <math.h> +#include <float.h> + +#ifdef __SSE2__ +#define APEX_CSG_SSE +#include <mmintrin.h> +#include <emmintrin.h> +#endif +#ifdef __SSE3__ +#include <pmmintrin.h> +#endif +#ifdef __SSE4_1__ +#include <smmintrin.h> +#endif + +namespace ApexCSG +{ + +/* Utilities */ + +template<typename T> +T square(T t) +{ + return t * t; +} + + +/* Linear algebra */ + +#define ALL_i( _D, _exp ) for( int i = 0; i < _D; ++i ) { _exp; } + +#ifndef APEX_CSG_LOOP_UNROLL +#define APEX_CSG_LOOP_UNROLL 1 +#endif + +#ifndef APEX_CSG_SSE +#define APEX_CSG_SSE 1 +#endif + +#ifndef APEX_CSG_INLINE +#define APEX_CSG_INLINE 1 +#endif + +#ifndef APEX_CSG_ALIGN +#define APEX_CSG_ALIGN 16 +#endif + +#if APEX_CSG_LOOP_UNROLL + +#define VEC_SIZE() sizeof(*this)/sizeof(Real) + +#define OP_VV(a,op,b,i) a[i] op b[i] +#define OP_SV(a,op,b,i) a op b[i] +#define OP_VS(a,op,b,i) a[i] op b +#define OP_VVV(a,op1,b,op2,c,i) a[i] op1 b[i] op2 c[i] +#define OP_SVV(a,op1,b,op2,c,i) a op1 b[i] op2 c[i] +#define OP_VVS(a,op1,b,op2,c,i) a[i] op1 b[i] op2 c +#define OP_D(_D) (_D == 0 ? 0 : (_D == 1 ? 1 : (_D == 2 ? 2 : (_D == 3 ? 3 : 3)))) +#define OP_NAME(_T) PX_CONCAT(OP_,_T) +#define OP_2_NAME(_D) ALL_2_##_D /*PX_CONCAT(ALL_2_,OP_D(_D))*/ +#define OP_3_NAME(_D) ALL_3_##_D /*PX_CONCAT(ALL_3_,OP_D(_D))*/ + +#define ALL_2_1( _T, a,op,b) OP_##_T (a,op,b,0) +#define ALL_2_2( _T, a,op,b) ALL_2_1(_T,a,op,b); OP_##_T (a,op,b,1) +#define ALL_2_3( _T, a,op,b) ALL_2_2(_T,a,op,b); OP_##_T (a,op,b,2) +#define ALL_2_4( _T, a,op,b) ALL_2_3(_T,a,op,b); OP_##_T (a,op,b,3) +#define ALL_VV_i( _D, a,op,b) OP_2_NAME(_D)(VV,a,op,b) +#define ALL_SV_i( _D, a,op,b) OP_2_NAME(_D)(SV,a,op,b) +#define ALL_VS_i( _D, a,op,b) OP_2_NAME(_D)(VS,a,op,b) + +#define ALL_3_1( _T, a,op1,b,op2,c) OP_NAME(_T) (a,op1,b,op2,c,0) +#define ALL_3_2( _T, a,op1,b,op2,c) ALL_3_1(_T,a,op1,b,op2,c); OP_NAME(_T) (a,op1,b,op2,c,1) +#define ALL_3_3( _T, a,op1,b,op2,c) ALL_3_2(_T,a,op1,b,op2,c); OP_NAME(_T) (a,op1,b,op2,c,2) +#define ALL_3_4( _T, a,op1,b,op2,c) ALL_3_3(_T,a,op1,b,op2,c); OP_NAME(_T) (a,op1,b,op2,c,3) +#define ALL_VVV_i( _D, a,op1,b,op2,c) OP_3_NAME(_D)(VVV,a,op1,b,op2,c) +#define ALL_SVV_i( _D, a,op1,b,op2,c) OP_3_NAME(_D)(SVV,a,op1,b,op2,c) +#define ALL_VVS_i( _D, a,op1,b,op2,c) OP_3_NAME(_D)(VVS,a,op1,b,op2,c) +#define ALL_VVV( a,op1,b,op2,c) OP_3_NAME(VEC_SIZE())(VVV,a,op1,b,op2,c) +#define ALL_SVV( a,op1,b,op2,c) OP_3_NAME(VEC_SIZE())(SVV,a,op1,b,op2,c) +#define ALL_VVS( a,op1,b,op2,c) OP_3_NAME(VEC_SIZE())(VVS,a,op1,b,op2,c) + +#else + +#define ALL_VV_i( _D, a,op,b) ALL_i( _D, a[i] op b[i] ) +#define ALL_SV_i( _D, a,op,b) ALL_i( _D, a op b[i] ) +#define ALL_VS_i( _D, a,op,b) ALL_i( _D, a[i] op b ) +#define ALL_VVV_i( _D, a,op1,b,op2,c) ALL_i( _D, a[i] op1 b[i] op2 c[i] ) +#define ALL_SVV_i( _D, a,op1,b,op2,c) ALL_i( _D, a op1 b[i] op2 c[i] ) +#define ALL_VVS_i( _D, a,op1,b,op2,c) ALL_i( _D, a[i] op1 b[i] op2 c ) + +#endif + +#if 1 + +#define DEFINE_VEC(_D) \ + public: \ + typedef Vec<T,_D> VecD; \ + PX_INLINE VecD() {} \ + PX_INLINE T& operator [](int i) { return el[i]; } \ + PX_INLINE const T& operator [](int i) const { return el[i]; } \ + PX_INLINE VecD(const VecD& v) { set(v); } \ + PX_INLINE VecD(const T& v) { set(v); } \ + PX_INLINE VecD(const T* v) { set(v); } \ + PX_INLINE VecD& operator=(const VecD& v) { ALL_VV_i(_D, el, =, v); return *this; } \ + PX_INLINE VecD operator/(T v) const { return *this * ((T)1 / v); } \ + PX_INLINE VecD operator+(const VecD& v) const { VecD r; ALL_VVV_i(_D, r, =, el, +, v); return r; } \ + PX_INLINE VecD operator-(const VecD& v) const { VecD r; ALL_VVV_i(_D, r, =, el, -, v); return r; } \ + PX_INLINE VecD operator*(const VecD& v) const { VecD r; ALL_VVV_i(_D, r, =, el, *, v); return r; } \ + PX_INLINE VecD operator-( ) const { VecD r; ALL_VV_i( _D, r, =, -el); return r;} \ + PX_INLINE VecD& operator+=(const VecD& v) {ALL_VV_i(_D, el, +=, v); return *this; } \ + PX_INLINE VecD& operator-=(const VecD& v) {ALL_VV_i(_D, el, -=, v); return *this; } \ + PX_INLINE VecD& operator*=(const VecD& v) {ALL_VV_i(_D, el, *=, v); return *this; } \ + PX_INLINE VecD& operator/=(const VecD& v) {ALL_VV_i(_D, el, /=, v); return *this; } \ + PX_INLINE void set(const VecD& v) { ALL_VV_i(_D, el, =, v); } \ + PX_INLINE void set(const T* v) { ALL_VV_i(_D, el, =, v); } \ + PX_INLINE void set(const T& v) { ALL_VS_i(_D, el, =, v); } \ + PX_INLINE T lengthSquared() const { return *this | *this; } \ + PX_INLINE T normalize() { const T l2 = *this | *this; if (l2 == (T)0) { return (T)0; } const T recipL = (T)1 / physx::PxSqrt(l2); *this *= recipL; return recipL * l2; } \ + protected:T el[_D]; \ + + //PX_FORCE_INLINE T operator|(const VecD& v) const { T r = (T)0; ALL_SVV_i(_D, r, +=, el, *, v); return r; } +#endif + +/* General vector */ + +__declspec(align(APEX_CSG_ALIGN)) class aligned { }; + +template<typename T, int D> +class Vec : public aligned +{ + +}; + + +template<typename T, int D> +PX_INLINE Vec<T, D> +operator * (T s, const Vec<T, D>& v) +{ + Vec<T, D> r; + ALL_i(D, r[i] = s * v[i]); + //ALL_VVS_i(D, r, =, v, *, s); + return r; +} + +template<typename T> +class Vec<T, 2> : public aligned { + DEFINE_VEC(2); +public: + typedef Vec<T,2> Vec2; + + PX_INLINE Vec2(T x, T y) + { + set(x, y); + } + + PX_INLINE void set(T x, T y) + { + el[0] = x; + el[1] = y; + } + + PX_INLINE Real operator ^ (const Vec2& v) const + { + return el[0] * v.el[1] - el[1] * v.el[0]; + } + + PX_FORCE_INLINE T operator | (const Vec2& v) const + { + T r = (T)0; + ALL_SVV_i(2, r, +=, el, *, v); + return r; + } + +}; + +template<typename T> +class Vec<T, 3> : public aligned { + DEFINE_VEC(3); +public: + typedef Vec<T,3> Vec3; + + PX_INLINE Vec3(T x, T y, T z) + { + set(x, y, z); + } + + PX_INLINE void set(T x, T y, T z) + { + el[0] = x; + el[1] = y; + el[2] = z; + } + + PX_FORCE_INLINE T operator | (const Vec3& v) const + { + T r = (T)0; + ALL_SVV_i(3, r, +=, el, *, v); + return r; + } +}; + +template<typename T> +class Vec<T, 4> : public aligned { + DEFINE_VEC(4); +public: + typedef Vec<T,4> Vec4; + + PX_INLINE Vec4(T x, T y, T z, T w) + { + set(x, y, z, w); + } + + PX_INLINE void set(T x, T y, T z, T w) + { + el[0] = x; + el[1] = y; + el[2] = z; + el[3] = w; + } + +#if APEX_CSG_SSE + +#if APEX_CSG_DBL + PX_INLINE __m128d& xy() { return *reinterpret_cast< __m128d*>(&el[0]); } + PX_INLINE const __m128d& xy() const { return *reinterpret_cast<const __m128d*>(&el[0]); } + PX_INLINE __m128d& zw() { return *reinterpret_cast< __m128d*>(&el[2]); } + PX_INLINE const __m128d& zw() const { return *reinterpret_cast<const __m128d*>(&el[2]); } +#else + PX_INLINE __m128& xyzw() { return *reinterpret_cast< __m128*>(&el[0]); } + PX_INLINE const __m128& xyzw() const { return *reinterpret_cast<const __m128*>(&el[0]); } +#endif /* #if APEX_CSG_DBL */ + + friend Real dot(const Vec4&, const Vec4&); + PX_FORCE_INLINE Real operator | (const Vec4& v) const + { + return dot(*this, v); + } + +#endif /* #if APEX_CSG_SSE */ +}; + +/* Popular real vectors */ + +typedef Vec<Real, 2> Vec2Real; +typedef Vec<Real, 3> Vec3Real; +typedef Vec<Real, 4> Vec4Real; + +#if APEX_CSG_SSE + +#if APEX_CSG_DBL + +PX_FORCE_INLINE Real dot(const Vec4Real& a, const Vec4Real& b) +{ + /* + __m128d mr = _mm_add_sd ( _mm_mul_pd ( a.xy(), b.xy()), + _mm_mul_sd ( a.zw(), b.zw()) ) ; + mr = _mm_add_sd ( _mm_unpackhi_pd ( mr , mr ), mr ); + double r; + _mm_store_sd(&r, mr); + return r;*/ + __declspec(align(16)) double r[2] = { 0., 0. }; + __m128d mresult; + mresult = _mm_add_pd(_mm_mul_pd( a.xy(), b.xy() ), + _mm_mul_pd( a.zw(), b.zw() ) ); + _mm_store_pd(r, mresult); + return r[0] + r[1]; +} + +#else + +PX_FORCE_INLINE Real dot(const Vec4Real& a, const Vec4Real& b) +{ + float r; + _mm_store_ps(&s, _mm_dot_pos(a.xyzw(), b.xyzw())); + return r; +} + +#endif /* #if APEX_CSG_DBL */ + +#else + +PX_FORCE_INLINE Real dot(const Vec4Real& a, const Vec4Real& b) +{ + Real r = 0; + ALL_SVV_i(sizeof(a)/sizeof(Real), r, +=, a, *, b); + return r; +} + +#endif /* #if APEX_CSG_SSE */ + +/* Position */ + +class Pos : public Vec4Real +{ +public: + + PX_INLINE Pos() + { + el[3] = 1; + } + PX_INLINE Pos(Real x, Real y, Real z) + { + set(x, y, z); + } + PX_INLINE Pos(Real c) + { + set(c, c, c); + } + PX_INLINE Pos(physx::PxVec3 p) + { + set(p.x, p.y, p.z); + } + PX_INLINE Pos(const Vec<Real, 4>& v) + { + set(v[0], v[1], v[2]); + } + PX_INLINE Pos(const float* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Pos(const double* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Pos(const Pos& p) + { + set(p[0], p[1], p[2]); + } + PX_INLINE Pos& operator = (const Pos& p) + { + set(p[0], p[1], p[2]); + return *this; + } + + PX_INLINE void set(Real x, Real y, Real z) + { + Vec4Real::set(x, y, z, (Real)1); + } + +}; + + +/* Direction */ + +class Dir : public Vec4Real +{ +public: + + PX_INLINE Dir() + { + el[3] = 0; + } + PX_INLINE Dir(Real x, Real y, Real z) + { + set(x, y, z); + } + PX_INLINE Dir(Real c) + { + set(c, c, c); + } + PX_INLINE Dir(physx::PxVec3 p) + { + set(p.x, p.y, p.z); + } + PX_INLINE Dir(const Vec<Real, 4>& v) + { + set(v[0], v[1], v[2]); + } + PX_INLINE Dir(const float* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Dir(const double* v) + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Dir(const Dir& d) + { + set(d[0], d[1], d[2]); + } + PX_INLINE Dir& operator = (const Dir& d) + { + set(d[0], d[1], d[2]); + return *this; + } + + PX_INLINE void set(Real x, Real y, Real z) + { + Vec4Real::set(x, y, z, (Real)0); + } + + PX_INLINE Dir operator ^(const Dir& d) const + { + return Dir(el[1] * d[2] - el[2] * d[1], el[2] * d[0] - el[0] * d[2], el[0] * d[1] - el[1] * d[0]); + } + +}; + + +/* Plane */ + +class Plane : public Vec4Real +{ +public: + + PX_INLINE Plane() {} + PX_INLINE Plane(const Dir& n, Real d) + { + set(n, d); + } + PX_INLINE Plane(const Dir& n, const Pos& p) + { + set(n, p); + } + PX_INLINE Plane(const Vec<Real, 4>& v) + { + Vec4Real::set(v[0], v[1], v[2], v[3]); + } + PX_INLINE Plane(const Plane& p) + { + //ALL_i(4, el[i] = p[i]); + ALL_VV_i(4, el, =, p); + } + PX_INLINE Plane& operator = (const Plane& p) + { + ALL_VV_i(4, el, =, p); + //ALL_i(4, el[i] = p[i]); + return *this; + } + + PX_INLINE void set(const Dir& n, Real d) + { + //ALL_i(3, el[i] = n[i]); + ALL_VV_i(3, el, =, n); + el[3] = d; + } + PX_INLINE void set(const Dir& n, const Pos& p) + { + //ALL_i(3, el[i] = n[i]); + ALL_VV_i(3, el, =, n); + el[3] = -(n | p); + } + + PX_INLINE Dir normal() const + { + return Dir(el[0], el[1], el[2]); + } + PX_INLINE Real d() const + { + return el[3]; + } + PX_INLINE Real distance(const Pos& p) const + { + return p | *this; + } + PX_INLINE Pos project(const Pos& p) const + { + return p - normal() * distance(p); + } + + PX_INLINE Real normalize(); +}; + +PX_INLINE Real +Plane::normalize() +{ + const Real oldD = el[3]; + el[3] = 0; + const Real l2 = *this | *this; + if (l2 == 0) + { + return 0; + } + const Real recipL = 1. / physx::PxSqrt(l2); + el[3] = oldD; + *this *= recipL; + return recipL * l2; +} + + +/* Matrix */ + +__declspec(align(16)) class Mat4Real : public Vec<Vec4Real, 4> +{ +public: + + PX_INLINE Mat4Real() {} + PX_INLINE Mat4Real(const Real v) + { + set(v); + } + PX_INLINE Mat4Real(const Real* v) + { + set(v); + } + + PX_INLINE void set(const Real v) + { + el[0].set(v, 0, 0, 0); + el[1].set(0, v, 0, 0); + el[2].set(0, 0, v, 0); + el[3].set(0, 0, 0, v); + } + PX_INLINE void set(const Real* v) + { + ALL_i(4, el[i].set(v + 4 * i)); + } + PX_INLINE void setCol(int colN, const Vec4Real& col) + { + ALL_i(4, el[i][colN] = col[i]); + } + + PX_INLINE Vec4Real operator * (const Vec4Real& v) const + { + Vec4Real r; + //ALL_i(4, r[i] = el[i] | v); + ALL_VVS_i(4, r, =, el, |, v); + return r; + } + PX_INLINE Mat4Real operator * (const Mat4Real& m) const + { + Mat4Real r((Real)0); + for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) for (int k = 0; k < 4; ++k) + { + r[i][j] += el[i][k] * m[k][j]; + } + return r; + } + PX_INLINE Mat4Real operator * (Real s) const + { + Mat4Real r; + //ALL_i(4, r[i] = el[i] * s); + ALL_VVS_i(4, r, =, el, *, s); + return r; + } + PX_INLINE Mat4Real operator / (Real s) const + { + return *this * ((Real)1 / s); + } + + PX_INLINE Mat4Real& operator *= (Real s) + { + //ALL_i(4, el[i] *= s); + ALL_VS_i(4, el, *=, s); + return *this; + } + PX_INLINE Mat4Real& operator /= (Real s) + { + *this *= ((Real)1 / s); + return *this; + } + + PX_INLINE Vec4Real getCol(int colN) const + { + Vec4Real col; + ALL_i(4, col[i] = el[i][colN]); + return col; + } + PX_INLINE Real det3() const + { + return el[0] | (Dir(el[1]) ^ Dir(el[2])); // Determinant of upper-left 3x3 block (same as full determinant if last row = (0,0,0,1)) + } + PX_INLINE Mat4Real cof34() const; // Assumes last row = (0,0,0,1) + PX_INLINE Mat4Real inverse34() const; // Assumes last row = (0,0,0,1) +}; + +PX_INLINE Mat4Real +Mat4Real::cof34() const +{ + Mat4Real r; + r[0].set(el[1][1]*el[2][2] - el[1][2]*el[2][1], el[1][2]*el[2][0] - el[1][0]*el[2][2], el[1][0]*el[2][1] - el[1][1]*el[2][0], 0); + r[1].set(el[2][1]*el[0][2] - el[2][2]*el[0][1], el[2][2]*el[0][0] - el[2][0]*el[0][2], el[2][0]*el[0][1] - el[2][1]*el[0][0], 0); + r[2].set(el[0][1]*el[1][2] - el[0][2]*el[1][1], el[0][2]*el[1][0] - el[0][0]*el[1][2], el[0][0]*el[1][1] - el[0][1]*el[1][0], 0); + r[3] = -el[0][3] * r[0] - el[1][3] * r[1] - el[2][3] * r[2]; + r[3][3] = r[0][0] * el[0][0] + r[0][1] * el[0][1] + r[0][2] * el[0][2]; + return r; +} + +PX_INLINE Mat4Real +Mat4Real::inverse34() const +{ + const Mat4Real cof = cof34(); + Mat4Real inv; + const Real recipDet = physx::PxAbs(cof[3][3]) > EPS_REAL * EPS_REAL * EPS_REAL ? 1 / cof[3][3] : (Real)0; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 4; ++j) + { + inv[i][j] = cof[j][i] * recipDet; + } + } + inv[3].set(0, 0, 0, 1); + return inv; +} + +PX_INLINE Mat4Real +operator * (Real s, const Mat4Real& m) +{ + Mat4Real r; + //ALL_i(4, r[i] = s * m[i]); + ALL_VVS_i(4, r, =, m, *, s); + return r; +} + +} // namespace ApexCSG + +#endif // #define APEX_CSG_FAST_MATH_2_H diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSGHull.h b/APEX_1.4/shared/internal/include/authoring/ApexCSGHull.h new file mode 100644 index 00000000..f8b25457 --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexCSGHull.h @@ -0,0 +1,187 @@ +/* + * 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 APEX_CSG_HULL_H +#define APEX_CSG_HULL_H + +#include "ApexUsingNamespace.h" +#include "authoring/ApexCSGMath.h" +#include "PsArray.h" +#include "PxFileBuf.h" + +#ifndef WITHOUT_APEX_AUTHORING + +namespace ApexCSG +{ + +/* Convex hull that handles unbounded sets. */ + +class Hull +{ +public: + struct Edge + { + uint32_t m_indexV0; + uint32_t m_indexV1; + uint32_t m_indexF1; + uint32_t m_indexF2; + }; + + struct EdgeType + { + enum Enum + { + LineSegment, + Ray, + Line + }; + }; + + PX_INLINE Hull() + { + setToAllSpace(); + } + PX_INLINE Hull(const Hull& geom) + { + *this = geom; + } + + PX_INLINE void setToAllSpace() + { + clear(); + allSpace = true; + } + PX_INLINE void setToEmptySet() + { + clear(); + emptySet = true; + } + + void intersect(const Plane& plane, Real distanceTol); + + PX_INLINE void transform(const Mat4Real& tm, const Mat4Real& cofTM); + + PX_INLINE uint32_t getFaceCount() const + { + return faces.size(); + } + PX_INLINE const Plane& getFace(uint32_t faceIndex) const + { + return faces[faceIndex]; + } + + PX_INLINE uint32_t getEdgeCount() const + { + return edges.size(); + } + PX_INLINE const Edge& getEdge(uint32_t edgeIndex) const + { + return edges[edgeIndex]; + } + + PX_INLINE uint32_t getVertexCount() const + { + return vertexCount; + } + PX_INLINE const Pos& getVertex(uint32_t vertexIndex) const + { + return *(const Pos*)(vectors.begin() + vertexIndex); + } + + PX_INLINE bool isEmptySet() const + { + return emptySet; + } + PX_INLINE bool isAllSpace() const + { + return allSpace; + } + + Real calculateVolume() const; + + // Edge accessors + PX_INLINE EdgeType::Enum getType(const Edge& edge) const + { + return (EdgeType::Enum)((uint32_t)(edge.m_indexV0 >= vertexCount) + (uint32_t)(edge.m_indexV1 >= vertexCount)); + } + PX_INLINE const Pos& getV0(const Edge& edge) const + { + return *(Pos*)(vectors.begin() + edge.m_indexV0); + } + PX_INLINE const Pos& getV1(const Edge& edge) const + { + return *(Pos*)(vectors.begin() + edge.m_indexV1); + } + PX_INLINE const Dir& getDir(const Edge& edge) const + { + PX_ASSERT(edge.m_indexV1 >= vertexCount); + return *(Dir*)(vectors.begin() + edge.m_indexV1); + } + PX_INLINE uint32_t getF1(const Edge& edge) const + { + return edge.m_indexF1; + } + PX_INLINE uint32_t getF2(const Edge& edge) const + { + return edge.m_indexF2; + } + + // Serialization + void serialize(physx::PxFileBuf& stream) const; + void deserialize(physx::PxFileBuf& stream, uint32_t version); + +protected: + PX_INLINE void clear(); + + bool testConsistency(Real distanceTol, Real angleTol) const; + + // Faces + physx::Array<Plane> faces; + physx::Array<Edge> edges; + physx::Array<Vec4Real> vectors; + uint32_t vertexCount; // vectors[i], i >= vertexCount, are used to store vectors for ray and line edges + bool allSpace; + bool emptySet; +}; + +PX_INLINE void +Hull::transform(const Mat4Real& tm, const Mat4Real& cofTM) +{ + for (uint32_t i = 0; i < faces.size(); ++i) + { + Plane& face = faces[i]; + face = cofTM * face; + face.normalize(); + } + + for (uint32_t i = 0; i < vectors.size(); ++i) + { + Vec4Real& vector = vectors[i]; + vector = tm * vector; + } +} + +PX_INLINE void +Hull::clear() +{ + vectors.reset(); + edges.reset(); + faces.reset(); + vertexCount = 0; + allSpace = false; + emptySet = false; +} + + +}; // namespace ApexCSG + +#endif + +#endif // #define APEX_CSG_HULL_H diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSGMath.h b/APEX_1.4/shared/internal/include/authoring/ApexCSGMath.h new file mode 100644 index 00000000..bdc605ea --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexCSGMath.h @@ -0,0 +1,648 @@ +/* + * 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 APEX_CSG_MATH_H +#define APEX_CSG_MATH_H + +#include "ApexUsingNamespace.h" +#include "PxMath.h" +#include "PxVec3.h" + +#include <math.h> +#include <float.h> + +#ifndef WITHOUT_APEX_AUTHORING + + +// APEX_CSG_DBL may be defined externally +#ifndef APEX_CSG_DBL +#define APEX_CSG_DBL 1 +#endif + + +namespace ApexCSG +{ +#if !(APEX_CSG_DBL) +typedef float Real; +#define MAX_REAL FLT_MAX +#define EPS_REAL FLT_EPSILON +#else +typedef double Real; +#define MAX_REAL DBL_MAX +#define EPS_REAL DBL_EPSILON +#endif + + +/* Utilities */ + +template<typename T> +T square(T t) +{ + return t * t; +} + + +/* Linear algebra */ + +#define ALL_i( _D, _exp ) for( int i = 0; i < _D; ++i ) { _exp; } + + +/* General vector */ + +template<typename T, int D> +class Vec +{ +public: + + PX_INLINE Vec() {} + PX_INLINE Vec(const T& v) + { + set(v); + } + PX_INLINE Vec(const T* v) + { + set(v); + } + + PX_INLINE void set(const T& v) + { + ALL_i(D, el[i] = v); + } + PX_INLINE void set(const T* v) + { + ALL_i(D, el[i] = v[i]); + } + + PX_INLINE T& operator [](int i) + { + return el[i]; + } + PX_INLINE const T& operator [](int i) const + { + return el[i]; + } + + PX_INLINE T& operator [](unsigned i) + { + return el[i]; + } + PX_INLINE const T& operator [](unsigned i) const + { + return el[i]; + } + + PX_INLINE Vec operator - () const + { + Vec r; + ALL_i(D, r[i] = -el[i]); + return r; + } + + PX_INLINE Vec operator + (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] + v[i]); + return r; + } + PX_INLINE Vec operator - (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] - v[i]); + return r; + } + PX_INLINE Vec operator * (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] * v[i]); + return r; + } + PX_INLINE Vec operator / (const Vec& v) const + { + Vec r; + ALL_i(D, r[i] = el[i] / v[i]); + return r; + } + + PX_INLINE Vec operator * (T v) const + { + Vec r; + ALL_i(D, r[i] = el[i] * v); + return r; + } + PX_INLINE Vec operator / (T v) const + { + return *this * ((T)1 / v); + } + + PX_INLINE Vec& operator += (const Vec& v) + { + ALL_i(D, el[i] += v[i]); + return *this; + } + PX_INLINE Vec& operator -= (const Vec& v) + { + ALL_i(D, el[i] -= v[i]); + return *this; + } + PX_INLINE Vec& operator *= (const Vec& v) + { + ALL_i(D, el[i] *= v[i]); + return *this; + } + PX_INLINE Vec& operator /= (const Vec& v) + { + ALL_i(D, el[i] /= v[i]); + return *this; + } + + PX_INLINE T operator | (const Vec& v) const + { + T r = (T)0; + ALL_i(D, r += el[i] * v[i]); + return r; + } + + PX_INLINE T normalize(); + + PX_INLINE T lengthSquared() const + { + return *this | *this; + } + +protected: + T el[D]; +}; + +template<typename T, int D> +PX_INLINE T +Vec<T, D>::normalize() +{ + const T l2 = *this | *this; + if (l2 == (T)0) + { + return (T)0; + } + const T recipL = (T)1 / physx::PxSqrt(l2); + *this *= recipL; + return recipL * l2; +} + +template<typename T, int D> +PX_INLINE Vec<T, D> +operator * (T s, const Vec<T, D>& v) +{ + Vec<T, D> r; + ALL_i(D, r[i] = s * v[i]); + return r; +} + + +/* Popular real vectors */ + +class Vec2Real : public Vec<Real, 2> +{ +public: + PX_INLINE Vec2Real() : Vec<Real, 2>() + { + } + PX_INLINE Vec2Real(const Vec2Real& v) : Vec<Real, 2>() + { + ALL_i(2, el[i] = v[i]); + } + PX_INLINE Vec2Real(const Vec<Real, 2>& v) : Vec<Real, 2>() + { + ALL_i(2, el[i] = v[i]); + } + PX_INLINE Vec2Real(Real x, Real y) : Vec<Real, 2>() + { + set(x, y); + } + PX_INLINE Vec2Real& operator = (const Vec2Real& v) + { + ALL_i(2, el[i] = v[i]); + return *this; + } + + PX_INLINE void set(const Real* v) + { + ALL_i(2, el[i] = v[i]); + } + PX_INLINE void set(Real x, Real y) + { + el[0] = x; + el[1] = y; + } + + PX_INLINE Real operator ^(const Vec2Real& v) const + { + return el[0] * v.el[1] - el[1] * v.el[0]; + } + + PX_INLINE Vec2Real perp() const + { + Vec2Real result; + result.el[0] = el[1]; + result.el[1] = -el[0]; + return result; + } +}; + +class Vec4Real : public Vec<Real, 4> +{ +public: + PX_INLINE Vec4Real() : Vec<Real, 4>() + { + } + PX_INLINE Vec4Real(const Vec4Real& v) : Vec<Real, 4>() + { + ALL_i(4, el[i] = v[i]); + } + PX_INLINE Vec4Real(const Vec<Real, 4>& v) : Vec<Real, 4>() + { + ALL_i(4, el[i] = v[i]); + } + PX_INLINE Vec4Real(Real x, Real y, Real z, Real w) : Vec<Real, 4>() + { + set(x, y, z, w); + } + PX_INLINE Vec4Real& operator = (const Vec4Real& v) + { + ALL_i(4, el[i] = v[i]); + return *this; + } + + PX_INLINE void set(const Real* v) + { + ALL_i(4, el[i] = v[i]); + } + PX_INLINE void set(Real x, Real y, Real z, Real w) + { + el[0] = x; + el[1] = y; + el[2] = z; + el[3] = w; + } +}; + + +/* Position */ + +class Pos : public Vec4Real +{ +public: + + PX_INLINE Pos() : Vec4Real() + { + el[3] = 1; + } + PX_INLINE Pos(Real x, Real y, Real z) : Vec4Real() + { + set(x, y, z); + } + PX_INLINE Pos(Real c) : Vec4Real() + { + set(c, c, c); + } + PX_INLINE Pos(physx::PxVec3 p) : Vec4Real() + { + set(p.x, p.y, p.z); + } + PX_INLINE Pos(const Vec<Real, 4>& v) : Vec4Real() + { + set(v[0], v[1], v[2]); + } + PX_INLINE Pos(const float* v) : Vec4Real() + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Pos(const double* v) : Vec4Real() + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Pos(const Pos& p) : Vec4Real() + { + set(p[0], p[1], p[2]); + } + PX_INLINE Pos& operator = (const Pos& p) + { + set(p[0], p[1], p[2]); + return *this; + } + + PX_INLINE void set(Real x, Real y, Real z) + { + Vec4Real::set(x, y, z, (Real)1); + } +}; + + +/* Direction */ + +class Dir : public Vec4Real +{ +public: + + PX_INLINE Dir() : Vec4Real() + { + el[3] = 0; + } + PX_INLINE Dir(Real x, Real y, Real z) : Vec4Real() + { + set(x, y, z); + } + PX_INLINE Dir(Real c) : Vec4Real() + { + set(c, c, c); + } + PX_INLINE Dir(physx::PxVec3 p) : Vec4Real() + { + set(p.x, p.y, p.z); + } + PX_INLINE Dir(const Vec<Real, 4>& v) : Vec4Real() + { + set(v[0], v[1], v[2]); + } + PX_INLINE Dir(const float* v) : Vec4Real() + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Dir(const double* v) : Vec4Real() + { + set((Real)v[0], (Real)v[1], (Real)v[2]); + } + PX_INLINE Dir(const Dir& d) : Vec4Real() + { + set(d[0], d[1], d[2]); + } + PX_INLINE Dir& operator = (const Dir& d) + { + set(d[0], d[1], d[2]); + return *this; + } + + PX_INLINE void set(Real x, Real y, Real z) + { + Vec4Real::set(x, y, z, (Real)0); + } + + PX_INLINE Dir cross(const Dir& d) const // Simple cross-product + { + return Dir(el[1] * d[2] - el[2] * d[1], el[2] * d[0] - el[0] * d[2], el[0] * d[1] - el[1] * d[0]); + } + + PX_INLINE Real dot(const Dir& d) const // Simple dot-product + { + return el[0]*d[0] + el[1]*d[1] + el[2]*d[2]; + } + + PX_INLINE Dir operator ^(const Dir& d) const // Uses an improvement step for more accuracy + { + const Dir c = cross(d); // Cross-product gives perpendicular + const Real c2 = c|c; + if (c2 != 0.0f) + { + return c + ((dot(c))*(c.cross(d)) + (d|c)*(cross(c)))/c2; + } + return c; // Improvement to (*this d)^T(c) = (0) + } +}; + + +/* Plane */ + +class Plane : public Vec4Real +{ +public: + + PX_INLINE Plane() : Vec4Real() {} + PX_INLINE Plane(const Dir& n, Real d) : Vec4Real() + { + set(n, d); + } + PX_INLINE Plane(const Dir& n, const Pos& p) : Vec4Real() + { + set(n, p); + } + PX_INLINE Plane(const Vec<Real, 4>& v) : Vec4Real() + { + Vec4Real::set(v[0], v[1], v[2], v[3]); + } + PX_INLINE Plane(const Plane& p) : Vec4Real() + { + ALL_i(4, el[i] = p[i]); + } + PX_INLINE Plane& operator = (const Plane& p) + { + ALL_i(4, el[i] = p[i]); + return *this; + } + + PX_INLINE void set(const Dir& n, Real d) + { + ALL_i(3, el[i] = n[i]); + el[3] = d; + } + PX_INLINE void set(const Dir& n, const Pos& p) + { + ALL_i(3, el[i] = n[i]); + el[3] = -(n | p); + } + + PX_INLINE Dir normal() const + { + return Dir(el[0], el[1], el[2]); + } + PX_INLINE Real d() const + { + return el[3]; + } + PX_INLINE Real distance(const Pos& p) const + { + return p | *this; + } + PX_INLINE Pos project(const Pos& p) const + { + return p - normal() * distance(p); + } + + PX_INLINE Real normalize(); +}; + +PX_INLINE Real +Plane::normalize() +{ + const Real oldD = el[3]; + el[3] = 0; + const Real l2 = *this | *this; + if (l2 == 0) + { + return 0; + } + Real recipL = 1 / physx::PxSqrt(l2); + recipL *= (Real)1.5 - (Real)0.5*l2*recipL*recipL; + recipL *= (Real)1.5 - (Real)0.5*l2*recipL*recipL; + el[3] = oldD; + *this *= recipL; + return recipL * l2; +} + + +/* Matrix */ + +class Mat4Real : public Vec<Vec4Real, 4> +{ +public: + + PX_INLINE Mat4Real() {} + PX_INLINE Mat4Real(const Real v) + { + set(v); + } + PX_INLINE Mat4Real(const Real* v) + { + set(v); + } + + PX_INLINE void set(const Real v) + { + el[0].set(v, 0, 0, 0); + el[1].set(0, v, 0, 0); + el[2].set(0, 0, v, 0); + el[3].set(0, 0, 0, v); + } + PX_INLINE void set(const Real* v) + { + ALL_i(4, el[i].set(v + 4 * i)); + } + PX_INLINE void setCol(int colN, const Vec4Real& col) + { + ALL_i(4, el[i][colN] = col[i]); + } + + PX_INLINE Vec4Real operator * (const Vec4Real& v) const + { + Vec4Real r; + ALL_i(4, r[i] = el[i] | v); + return r; + } + PX_INLINE Mat4Real operator + (const Mat4Real& m) const + { + Mat4Real r; + for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) + { + r[i][j] = el[i][j] + m[i][j]; + } + return r; + } + PX_INLINE Mat4Real operator - (const Mat4Real& m) const + { + Mat4Real r; + for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) + { + r[i][j] = el[i][j] - m[i][j]; + } + return r; + } + PX_INLINE Mat4Real operator * (const Mat4Real& m) const + { + Mat4Real r((Real)0); + for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) for (int k = 0; k < 4; ++k) + { + r[i][j] += el[i][k] * m[k][j]; + } + return r; + } + PX_INLINE Mat4Real operator * (Real s) const + { + Mat4Real r; + ALL_i(4, r[i] = el[i] * s); + return r; + } + PX_INLINE Mat4Real operator / (Real s) const + { + return *this * ((Real)1 / s); + } + + PX_INLINE Mat4Real& operator *= (Real s) + { + ALL_i(4, el[i] *= s); + return *this; + } + PX_INLINE Mat4Real& operator /= (Real s) + { + *this *= ((Real)1 / s); + return *this; + } + + PX_INLINE Vec4Real getCol(int colN) const + { + Vec4Real col; + ALL_i(4, col[i] = el[i][colN]); + return col; + } + PX_INLINE Real det3() const + { + return el[0] | (Dir(el[1]) ^ Dir(el[2])); // Determinant of upper-left 3x3 block (same as full determinant if last row = (0,0,0,1)) + } + PX_INLINE Mat4Real cof34() const; // Assumes last row = (0,0,0,1) + PX_INLINE Mat4Real inverse34() const; // Assumes last row = (0,0,0,1) + PX_INLINE Mat4Real transpose() const + { + Mat4Real r; + for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) + { + r[i][j] = el[j][i]; + } + return r; + } +}; + +PX_INLINE Mat4Real +Mat4Real::cof34() const +{ + Mat4Real r; + r[0].set(el[1][1]*el[2][2] - el[1][2]*el[2][1], el[1][2]*el[2][0] - el[1][0]*el[2][2], el[1][0]*el[2][1] - el[1][1]*el[2][0], 0); + r[1].set(el[2][1]*el[0][2] - el[2][2]*el[0][1], el[2][2]*el[0][0] - el[2][0]*el[0][2], el[2][0]*el[0][1] - el[2][1]*el[0][0], 0); + r[2].set(el[0][1]*el[1][2] - el[0][2]*el[1][1], el[0][2]*el[1][0] - el[0][0]*el[1][2], el[0][0]*el[1][1] - el[0][1]*el[1][0], 0); + r[3] = -el[0][3] * r[0] - el[1][3] * r[1] - el[2][3] * r[2]; + r[3][3] = r[0][0] * el[0][0] + r[0][1] * el[0][1] + r[0][2] * el[0][2]; + return r; +} + +PX_INLINE Mat4Real +Mat4Real::inverse34() const +{ + const Mat4Real cof = cof34(); + Mat4Real inv; + const Real recipDet = physx::PxAbs(cof[3][3]) > EPS_REAL * EPS_REAL * EPS_REAL ? 1 / cof[3][3] : (Real)0; + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 4; ++j) + { + inv[i][j] = cof[j][i] * recipDet; + } + } + inv[3].set(0, 0, 0, 1); + return inv; +} + +PX_INLINE Mat4Real +operator * (Real s, const Mat4Real& m) +{ + Mat4Real r; + ALL_i(4, r[i] = s * m[i]); + return r; +} + +} // namespace ApexCSG + +#endif // #define !WITHOUT_APEX_AUTHORING + +#endif // #define APEX_CSG_MATH_H diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSGSerialization.h b/APEX_1.4/shared/internal/include/authoring/ApexCSGSerialization.h new file mode 100644 index 00000000..ff77d2dc --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexCSGSerialization.h @@ -0,0 +1,191 @@ +/* + * 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 APEX_CSG_SERIALIZATION_H +#define APEX_CSG_SERIALIZATION_H + +#include "ApexUsingNamespace.h" +#include "ApexSharedUtils.h" +#include "ApexStream.h" +#include "authoring/ApexCSGDefs.h" +#include "authoring/ApexCSGHull.h" + +#ifndef WITHOUT_APEX_AUTHORING + +namespace nvidia +{ +namespace apex +{ + +/* Version for serialization */ +struct Version +{ + enum Enum + { + Initial = 0, + RevisedMeshTolerances, + UsingOnlyPositionDataInVertex, + SerializingTriangleFrames, + UsingGSA, + SerializingMeshBounds, + AddedInternalTransform, + IncidentalMeshDistinction, + + Count, + Current = Count - 1 + }; +}; + + +// Vec<T,D> +template<typename T, int D> +PX_INLINE physx::PxFileBuf& +operator << (physx::PxFileBuf& stream, const ApexCSG::Vec<T, D>& v) +{ + for (uint32_t i = 0; i < D; ++i) + { + stream << v[(int32_t)i]; + } + return stream; +} + +template<typename T, int D> +PX_INLINE physx::PxFileBuf& +operator >> (physx::PxFileBuf& stream, ApexCSG::Vec<T, D>& v) +{ + for (uint32_t i = 0; i < D; ++i) + { + stream >> v[(int32_t)i]; + } + + return stream; +} + + +// Edge +PX_INLINE void +serialize(physx::PxFileBuf& stream, const ApexCSG::Hull::Edge& e) +{ + stream << e.m_indexV0 << e.m_indexV1 << e.m_indexF1 << e.m_indexF2; +} + +PX_INLINE void +deserialize(physx::PxFileBuf& stream, uint32_t version, ApexCSG::Hull::Edge& e) +{ + PX_UNUSED(version); // Initial + + stream >> e.m_indexV0 >> e.m_indexV1 >> e.m_indexF1 >> e.m_indexF2; +} + + +// Region +PX_INLINE void +serialize(physx::PxFileBuf& stream, const ApexCSG::Region& r) +{ + stream << r.side; +} + +PX_INLINE void +deserialize(physx::PxFileBuf& stream, uint32_t version, ApexCSG::Region& r) +{ + if (version < Version::UsingGSA) + { + ApexCSG::Hull hull; + hull.deserialize(stream, version); + } + + stream >> r.side; +} + + +// Surface +PX_INLINE void +serialize(physx::PxFileBuf& stream, const ApexCSG::Surface& s) +{ + stream << s.planeIndex; + stream << s.triangleIndexStart; + stream << s.triangleIndexStop; + stream << s.totalTriangleArea; +} + +PX_INLINE void +deserialize(physx::PxFileBuf& stream, uint32_t version, ApexCSG::Surface& s) +{ + PX_UNUSED(version); // Initial + + stream >> s.planeIndex; + stream >> s.triangleIndexStart; + stream >> s.triangleIndexStop; + stream >> s.totalTriangleArea; +} + + +// Triangle +PX_INLINE void +serialize(physx::PxFileBuf& stream, const ApexCSG::Triangle& t) +{ + for (uint32_t i = 0; i < 3; ++i) + { + stream << t.vertices[i]; + } + stream << t.submeshIndex; + stream << t.smoothingMask; + stream << t.extraDataIndex; + stream << t.normal; + stream << t.area; +} + +PX_INLINE void +deserialize(physx::PxFileBuf& stream, uint32_t version, ApexCSG::Triangle& t) +{ + for (uint32_t i = 0; i < 3; ++i) + { + stream >> t.vertices[i]; + if (version < Version::UsingOnlyPositionDataInVertex) + { + ApexCSG::Dir v; + stream >> v; // normal + stream >> v; // tangent + stream >> v; // binormal + ApexCSG::UV uv; + for (uint32_t uvN = 0; uvN < VertexFormat::MAX_UV_COUNT; ++uvN) + { + stream >> uv; // UVs + } + ApexCSG::Color c; + stream >> c; // color + } + } + stream >> t.submeshIndex; + stream >> t.smoothingMask; + stream >> t.extraDataIndex; + stream >> t.normal; + stream >> t.area; +} + +// Interpolator +PX_INLINE void +serialize(physx::PxFileBuf& stream, const ApexCSG::Interpolator& t) +{ + t.serialize(stream); +} + +PX_INLINE void +deserialize(physx::PxFileBuf& stream, uint32_t version, ApexCSG::Interpolator& t) +{ + t.deserialize(stream, version); +} + +} +}; // namespace nvidia::apex + +#endif + +#endif // #define APEX_CSG_SERIALIZATION_H diff --git a/APEX_1.4/shared/internal/include/authoring/ApexGSA.h b/APEX_1.4/shared/internal/include/authoring/ApexGSA.h new file mode 100644 index 00000000..1e66b7b4 --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/ApexGSA.h @@ -0,0 +1,412 @@ +/* + * 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. + */ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef APEX_GSA_H +#define APEX_GSA_H + + +#include "ApexCSGMath.h" + +#ifndef WITHOUT_APEX_AUTHORING + +namespace ApexCSG +{ +namespace GSA +{ + +// Utility vector format translation +inline physx::PxVec3 toPxVec3(const Vec4Real& p) +{ + return physx::PxVec3(static_cast<float>(p[0]), static_cast<float>(p[1]), static_cast<float>(p[2])); +} + + +/*** Compact implementation of the void simplex algorithm for D = 3 ***/ + +typedef physx::PxF32 real; + +/* + The implementation of farthest_halfspace should return the half-space "most below" the given point. The point + is represented by a vector in projective coordinates, and its last element (point[3]) will not necessarily equal 1. + However, point[3] will be non-negative. The plane returned is the boundary of the half-space found, and is also + represented as a vector in projective coordinates (the coefficients of the plane equation). The plane vector + returned should have the greatest dot product with the input point. + + plane = the returned half-space boundary + point = the input point + returns the dot product of point and plane +*/ +struct VS3D_Halfspace_Set +{ + virtual real farthest_halfspace(real plane[4], const real point[4]) = 0; +}; + + +#define VS3D_HIGH_ACCURACY 1 +#define VS3D_UNNORMALIZED_PLANE_HANDLING 0 // 0 = planes must be normalized, 1 = planes must be near-normalized, 2 = planes may be arbitrary +#define REAL_DOUBLE 0 + + +#if VS3D_UNNORMALIZED_PLANE_HANDLING == 1 +// Returns approximation to 1/sqrt(x) +inline real vs3d_recip_sqrt(real x) +{ + real y = (real)1.5 - (real)0.5*x; +#if REAL_DOUBLE + y *= (real)1.5 - (real)0.5*x*y*y; // Perform another iteration for doubles, to handle the case where float-normalized normals are converted to double-precision +#endif + return y; +} +#elif VS3D_UNNORMALIZED_PLANE_HANDLING == 2 +#include <cmath> +inline real vs3d_recip_sqrt(real x) { return 1/sqrt(x); } +#elif VS3D_UNNORMALIZED_PLANE_HANDLING != 0 +#error Unrecognized value given for VS3D_UNNORMALIZED_PLANE_HANDLING. Please set to 0, 1, or 2. +#endif + + +// Simple types and operations for internal calculations +struct Vec3 { real x, y, z; }; // 3-vector +inline Vec3 vec3(real x, real y, real z) { Vec3 r; r.x = x; r.y = y; r.z = z; return r; } // vector builder +inline Vec3 operator + (const Vec3& a, const Vec3& b) { return vec3(a.x+b.x, a.y+b.y, a.z+b.z); } // vector addition +inline Vec3 operator * (real s, const Vec3& v) { return vec3(s*v.x, s*v.y, s*v.z); } // scalar multiplication +inline real operator | (const Vec3& a, const Vec3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; } // dot product +inline Vec3 operator ^ (const Vec3& a, const Vec3& b) { return vec3(a.y*b.z - b.y*a.z, a.z*b.x - b.z*a.x, a.x*b.y - b.x*a.y); } // cross product + +struct Vec4 { Vec3 v; real w; }; // 4-vector split into 3-vector and scalar parts +inline Vec4 vec4(const Vec3& v, real w) { Vec4 r; r.v = v; r.w = w; return r; } // vector builder +inline real operator | (const Vec4& a, const Vec4& b) { return (a.v|b.v) + a.w*b.w; } // dot product + +// More accurate perpendicular +inline Vec3 perp(const Vec3& a, const Vec3& b) +{ + Vec3 c = a^b; // Cross-product gives perpendicular +#if VS3D_HIGH_ACCURACY || REAL_DOUBLE + const real c2 = c|c; + if (c2 != 0) c = c + (1/c2)*((a|c)*(c^b) + (b|c)*(a^c)); // Improvement to (a b)^T(c) = (0) +#endif + return c; +} + +// Square +inline real sq(real x) { return x*x; } + +// Returns index of the extremal element in a three-element set {e0, e1, e2} based upon comparisons c_ij. The extremal index m is such that c_mn is true, or e_m == e_n, for all n. +inline int ext_index(int c_10, int c_21, int c_20) { return c_10<<c_21|(c_21&c_20)<<1; } + +// Returns index (0, 1, or 2) of minimum argument +inline int index_of_min(real x0, real x1, real x2) { return ext_index((int)(x1 < x0), (int)(x2 < x1), (int)(x2 < x0)); } + +// Compare fractions with positive deominators. Returns a_num*sqrt(a_rden2) > b_num*sqrt(b_rden2) +inline bool frac_gt(real a_num, real a_rden2, real b_num, real b_rden2) +{ + const bool a_num_neg = a_num < 0; + const bool b_num_neg = b_num < 0; + return a_num_neg != b_num_neg ? b_num_neg : ((a_num*a_num*a_rden2 > b_num*b_num*b_rden2) != a_num_neg); +} + +// Returns index (0, 1, or 2) of maximum fraction with positive deominators +inline int index_of_max_frac(real x0_num, real x0_rden2, real x1_num, real x1_rden2, real x2_num, real x2_rden2) +{ + return ext_index((int)frac_gt(x1_num, x1_rden2, x0_num, x0_rden2), (int)frac_gt(x2_num, x2_rden2, x1_num, x1_rden2), (int)frac_gt(x2_num, x2_rden2, x0_num, x0_rden2)); +} + +// Compare values given their signs and squares. Returns a > b. a2 and b2 may have any constant offset applied to them. +inline bool sgn_sq_gt(real sgn_a, real a2, real sgn_b, real b2) { return sgn_a*sgn_b < 0 ? (sgn_b < 0) : ((a2 > b2) != (sgn_a < 0)); } + +// Returns index (0, 1, or 2) of maximum value given their signs and squares. sq_x0, sq_x1, and sq_x2 may have any constant offset applied to them. +inline int index_of_max_sgn_sq(real sgn_x0, real sq_x0, real sgn_x1, real sq_x1, real sgn_x2, real sq_x2) +{ + return ext_index((int)sgn_sq_gt(sgn_x1, sq_x1, sgn_x0, sq_x0), (int)sgn_sq_gt(sgn_x2, sq_x2, sgn_x1, sq_x1), (int)sgn_sq_gt(sgn_x2, sq_x2, sgn_x0, sq_x0)); +} + +// Project 2D (homogeneous) vector onto 2D half-space boundary +inline void project2D(Vec3& r, const Vec3& plane, real delta, real recip_n2, real eps2) +{ + r = r + (-delta*recip_n2)*vec3(plane.x, plane.y, 0); + r = r + (-(r|plane)*recip_n2)*vec3(plane.x, plane.y, 0); // Second projection for increased accuracy + if ((r|r) > eps2) return; + r = (-plane.z*recip_n2)*vec3(plane.x, plane.y, 0); + r.z = 1; +} + + +// Update function for vs3d_test +static bool vs3d_update(Vec4& p, Vec4 S[4], int& plane_count, const Vec4& q, real eps2) +{ + // h plane is the last plane + const Vec4& h = S[plane_count-1]; + + // Handle plane_count == 1 specially (optimization; this could be commented out) + if (plane_count == 1) + { + // Solution is objective projected onto h plane + p = q; + p.v = p.v + -(p|h)*h.v; + if ((p|p) <= eps2) p = vec4(-h.w*h.v, 1); // If p == 0 then q is a direction vector, any point in h is a support point + return true; + } + + // Create basis in the h plane + const int min_i = index_of_min(h.v.x*h.v.x, h.v.y*h.v.y, h.v.z*h.v.z); + const Vec3 y = h.v^vec3((real)(min_i == 0), (real)(min_i == 1), (real)(min_i == 2)); + const Vec3 x = y^h.v; + + // Use reduced vector r instead of p + Vec3 r = {x|q.v, y|q.v, q.w*(y|y)}; // (x|x) = (y|y) = square of plane basis scale + + // If r == 0 (within epsilon), then it is a direction vector, and we have a bounded solution + if ((r|r) <= eps2) r.z = 1; + + // Create plane equations in the h plane. These will not be normalized in general. + int N = 0; // Plane count in h subspace + Vec3 R[3]; // Planes in h subspace + real recip_n2[3]; // Plane normal vector reciprocal lengths squared + real delta[3]; // Signed distance of objective to the planes + int index[3]; // Keep track of original plane indices + for (int i = 0; i < plane_count-1; ++i) + { + const Vec3& vi = S[i].v; + const real cos_theta = h.v|vi; + R[N] = vec3(x|vi, y|vi, S[i].w - h.w*cos_theta); + index[N] = i; + const real n2 = R[N].x*R[N].x + R[N].y*R[N].y; + if (n2 >= eps2) + { + const real lin_norm = (real)1.5-(real)0.5*n2; // 1st-order approximation to 1/sqrt(n2) expanded about n2 = 1 + R[N] = lin_norm*R[N]; // We don't need normalized plane equations, but rescaling (even with an approximate normalization) gives better numerical behavior + recip_n2[N] = 1/(R[N].x*R[N].x + R[N].y*R[N].y); + delta[N] = r|R[N]; + ++N; // Keep this plane + } + else if (cos_theta < 0) return false; // Parallel cases are redundant and rejected, anti-parallel cases are 1D voids + } + + // Now work with the N-sized R array of half-spaces in the h plane + switch (N) + { + case 1: one_plane: + if (delta[0] < 0) N = 0; // S[0] is redundant, eliminate it + else project2D(r, R[0], delta[0], recip_n2[0], eps2); + break; + case 2: two_planes: + if (delta[0] < 0 && delta[1] < 0) N = 0; // S[0] and S[1] are redundant, eliminate them + else + { + const int max_d_index = (int)frac_gt(delta[1], recip_n2[1], delta[0], recip_n2[0]); + project2D(r, R[max_d_index], delta[max_d_index], recip_n2[max_d_index], eps2); + const int min_d_index = max_d_index^1; + const real new_delta_min = r|R[min_d_index]; + if (new_delta_min < 0) + { + index[0] = index[max_d_index]; + N = 1; // S[min_d_index] is redundant, eliminate it + } + else + { + // Set r to the intersection of R[0] and R[1] and keep both + r = perp(R[0], R[1]); + if (r.z*r.z*recip_n2[0]*recip_n2[1] < eps2) + { + if (R[0].x*R[1].x + R[0].y*R[1].y < 0) return false; // 2D void found + goto one_plane; + } + r = (1/r.z)*r; // We could just as well multiply r by sgn(r.z); we just need to ensure r.z > 0 + } + } + break; + case 3: + if (delta[0] < 0 && delta[1] < 0 && delta[2] < 0) N = 0; // S[0], S[1], and S[2] are redundant, eliminate them + else + { + const Vec3 row_x = {R[0].x, R[1].x, R[2].x}; + const Vec3 row_y = {R[0].y, R[1].y, R[2].y}; + const Vec3 row_w = {R[0].z, R[1].z, R[2].z}; + const Vec3 cof_w = perp(row_x, row_y); + const bool detR_pos = (row_w|cof_w) > 0; + const int nrw_sgn0 = cof_w.x*cof_w.x*recip_n2[1]*recip_n2[2] < eps2 ? 0 : (((int)((cof_w.x > 0) == detR_pos)<<1)-1); + const int nrw_sgn1 = cof_w.y*cof_w.y*recip_n2[2]*recip_n2[0] < eps2 ? 0 : (((int)((cof_w.y > 0) == detR_pos)<<1)-1); + const int nrw_sgn2 = cof_w.z*cof_w.z*recip_n2[0]*recip_n2[1] < eps2 ? 0 : (((int)((cof_w.z > 0) == detR_pos)<<1)-1); + + if ((nrw_sgn0|nrw_sgn1|nrw_sgn2) >= 0) return false; // 3D void found + + const int positive_width_count = ((nrw_sgn0>>1)&1) + ((nrw_sgn1>>1)&1) + ((nrw_sgn2>>1)&1); + if (positive_width_count == 1) + { + // A single positive width results from a redundant plane. Eliminate it and peform N = 2 calculation. + const int pos_width_index = ((nrw_sgn1>>1)&1)|(nrw_sgn2&2); // Calculates which index corresponds to the positive-width side + R[pos_width_index] = R[2]; + recip_n2[pos_width_index] = recip_n2[2]; + delta[pos_width_index] = delta[2]; + index[pos_width_index] = index[2]; + N = 2; + goto two_planes; + } + + // Find the max dot product of r and R[i]/|R_normal[i]|. For numerical accuracy when the angle between r and the i^{th} plane normal is small, we take some care below: + const int max_d_index = r.z != 0 + ? index_of_max_frac(delta[0], recip_n2[0], delta[1], recip_n2[1], delta[2], recip_n2[2]) // displacement term resolves small-angle ambiguity, just use dot product + : index_of_max_sgn_sq(delta[0], -sq(r.x*R[0].y - r.y*R[0].x)*recip_n2[0], delta[1], -sq(r.x*R[1].y - r.y*R[1].x)*recip_n2[1], delta[2], -sq(r.x*R[2].y - r.y*R[2].x)*recip_n2[2]); // No displacement term. Use wedge product to find the sine of the angle. + + // Project r onto max-d plane + project2D(r, R[max_d_index], delta[max_d_index], recip_n2[max_d_index], eps2); + N = 1; // Unless we use a vertex in the loop below + const int index_max = index[max_d_index]; + + // The number of finite widths should be >= 2. If not, it should be 0, but in any case it implies three parallel lines in the plane, which we should not have here. + // If we do have three parallel lines (# of finite widths < 2), we've picked the line corresponding to the half-plane farthest from r, which is correct. + const int finite_width_count = (nrw_sgn0&1) + (nrw_sgn1&1) + (nrw_sgn2&1); + if (finite_width_count >= 2) + { + const int i_remaining[2] = {(1<<max_d_index)&3, (3>>max_d_index)^1}; // = {(max_d_index+1)%3, (max_d_index+2)%3} + const int i_select = (int)frac_gt(delta[i_remaining[1]], recip_n2[i_remaining[1]], delta[i_remaining[0]], recip_n2[i_remaining[0]]); // Select the greater of the remaining dot products + for (int i = 0; i < 2; ++i) + { + const int j = i_remaining[i_select^i]; // i = 0 => the next-greatest, i = 1 => the least + if ((r|R[j]) >= 0) + { + r = perp(R[max_d_index], R[j]); + r = (1/r.z)*r; // We could just as well multiply r by sgn(r.z); we just need to ensure r.z > 0 + index[1] = index[j]; + N = 2; + break; + } + } + } + + index[0] = index_max; + } + break; + } + + // Transform r back to 3D space + p = vec4(r.x*x + r.y*y + (-r.z*h.w)*h.v, r.z); + + // Pack S array with kept planes + if (N < 2 || index[1] != 0) { for (int i = 0; i < N; ++i) S[i] = S[index[i]]; } // Safe to copy columns in order + else { const Vec4 temp = S[0]; S[0] = S[index[0]]; S[1] = temp; } // Otherwise use temp storage to avoid overwrite + S[N] = h; + plane_count = N+1; + + return true; +} + + +// Performs the VS algorithm for D = 3 +inline int vs3d_test(VS3D_Halfspace_Set& halfspace_set, real* q = NULL) +{ + // Objective = q if it is not NULL, otherwise it is the origin represented in homogeneous coordinates + const Vec4 objective = q ? (q[3] != 0 ? vec4((1/q[3])*vec3(q[0], q[1], q[2]), 1) : *(Vec4*)q) : vec4(vec3(0, 0, 0), 1); + + // Tolerance for 3D void simplex algorithm + const real eps_f = (real)1/(sizeof(real) == 4 ? (1L<<23) : (1LL<<52)); // Floating-point epsilon +#if VS3D_HIGH_ACCURACY || REAL_DOUBLE + const real eps = 8*eps_f; +#else + const real eps = 80*eps_f; +#endif + const real eps2 = eps*eps; // Using epsilon squared + + // Maximum allowed iterations of main loop. If exceeded, error code is returned + const int max_iteration_count = 50; + + // State + Vec4 S[4]; // Up to 4 planes + int plane_count = 0; // Number of valid planes + Vec4 p = objective; // Test point, initialized to objective + + // Default result, changed to valid result if found in loop below + int result = -1; + + // Iterate until a stopping condition is met or the maximum number of iterations is reached + for (int i = 0; result < 0 && i < max_iteration_count; ++i) + { + Vec4& plane = S[plane_count++]; + real delta = halfspace_set.farthest_halfspace(&plane.v.x, &p.v.x); +#if VS3D_UNNORMALIZED_PLANE_HANDLING != 0 + const real recip_norm = vs3d_recip_sqrt(plane.v|plane.v); + plane = vec4(recip_norm*plane.v, recip_norm*plane.w); + delta *= recip_norm; +#endif + if (delta <= 0 || delta*delta <= eps2*(p|p)) result = 1; // Intersection found + else if (!vs3d_update(p, S, plane_count, objective, eps2)) result = 0; // Void simplex found + } + + // If q is given, fill it with the solution (normalize p.w if it is not zero) + if (q) *(Vec4*)q = (p.w != 0) ? vec4((1/p.w)*p.v, 1) : p; + + PX_ASSERT(result >= 0); + + return result; +} + + +/* + Utility class derived from GSA::ConvexShape, to handle common implementations + + PlaneIterator must have: + 1) a constructor which takes an object of type IteratorInitValues (either by value or refrence) in its constructor, + 2) a valid() method which returns a bool (true iff the plane() function can return a valid plane, see below), + 3) an inc() method to advance to the next plane, and + 4) a plane() method which returns a plane of type ApexCSG::Plane, either by value or reference (the plane will be copied). +*/ +template<class PlaneIterator, class IteratorInitValues> +class StaticConvexPolyhedron : public VS3D_Halfspace_Set +{ +public: + virtual GSA::real farthest_halfspace(GSA::real plane[4], const GSA::real point[4]) + { + plane[0] = plane[1] = plane[2] = 0.0f; + plane[3] = 1.0f; + Real greatest_s = -MAX_REAL; + + for (PlaneIterator it(m_initValues); it.valid(); it.inc()) + { + const Plane test = it.plane(); + const Real s = point[0]*test[0] + point[1]*test[1] + point[2]*test[2] + point[3]*test[3]; + if (s > greatest_s) + { + greatest_s = s; + for (int i = 0; i < 4; ++i) + { + plane[i] = (GSA::real)test[i]; + } + } + } + + // Return results + return (GSA::real)greatest_s; + } + +protected: + IteratorInitValues m_initValues; +}; + +}; // namespace GSA +}; // namespace ApexCSG + +#endif // #ifndef WITHOUT_APEX_AUTHORING + +#endif // #ifndef APEX_GSA_H diff --git a/APEX_1.4/shared/internal/include/authoring/Fracturing.h b/APEX_1.4/shared/internal/include/authoring/Fracturing.h new file mode 100644 index 00000000..751d1ae9 --- /dev/null +++ b/APEX_1.4/shared/internal/include/authoring/Fracturing.h @@ -0,0 +1,544 @@ +/* + * 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 FRACTURING_H + +#define FRACTURING_H + +#include "Apex.h" +#include "ApexUsingNamespace.h" +#include "PxPlane.h" +//#include "ApexSharedSerialization.h" +#include "FractureTools.h" +#include "ApexString.h" +#include "ExplicitHierarchicalMesh.h" +#include "authoring/ApexCSG.h" + +#ifndef WITHOUT_APEX_AUTHORING + +namespace nvidia +{ +namespace apex +{ + +using namespace FractureTools; + + +struct IntersectMesh +{ + enum GridPattern + { + None, // An infinite plane + Equilateral, + Right + }; + + float getSide(const physx::PxVec3& v) + { + if (m_pattern == None) + { + return m_plane.distance(v); + } + physx::PxVec3 vLocal = m_tm.inverseRT().transform(v); + float x = vLocal.x - m_cornerX; + float y = vLocal.y - m_cornerY; + if (y < 0) + { + return 0; + } + float scaledY = y / m_ySpacing; + uint32_t gridY = (uint32_t)scaledY; + if (gridY >= m_numY) + { + return 0; + } + scaledY -= (float)gridY; + uint32_t yParity = gridY & 1; + if (yParity != 0) + { + scaledY = 1.0f - scaledY; + } + if (m_pattern == Equilateral) + { + x += 0.5f * m_xSpacing * scaledY; + } + if (x < 0) + { + return 0; + } + float scaledX = x / m_xSpacing; + uint32_t gridX = (uint32_t)scaledX; + if (gridX >= m_numX) + { + return 0; + } + scaledX -= (float)gridX; + uint32_t xParity = (uint32_t)(scaledX >= scaledY); + uint32_t triangleNum = 2 * (gridY * m_numX + gridX) + xParity; + PX_ASSERT(triangleNum < m_triangles.size()); + nvidia::ExplicitRenderTriangle& triangle = m_triangles[triangleNum]; + physx::PxVec3& v0 = triangle.vertices[0].position; + physx::PxVec3& v1 = triangle.vertices[1].position; + physx::PxVec3& v2 = triangle.vertices[2].position; + return ((v1 - v0).cross(v2 - v0)).dot(v - v0); + } + + void clear() + { + m_pattern = None; + m_plane = physx::PxPlane(0, 0, 1, 0); + m_vertices.reset(); + m_triangles.reset(); + } + + void build(const physx::PxPlane& plane) + { + clear(); + m_plane = plane; + } + + void build(GridPattern pattern, const physx::PxPlane& plane, + float cornerX, float cornerY, float xSpacing, float ySpacing, uint32_t numX, uint32_t numY, + const PxMat44& tm, float noiseAmplitude, float relativeFrequency, float xPeriod, float yPeriod, + int noiseType, int noiseDir, uint32_t submeshIndex, uint32_t frameIndex, const TriangleFrame& triangleFrame, bool forceGrid); + + GridPattern m_pattern; + + PxMat44 m_tm; + physx::PxPlane m_plane; + physx::Array<nvidia::Vertex> m_vertices; + physx::Array<nvidia::ExplicitRenderTriangle> m_triangles; + + uint32_t m_numX; + float m_cornerX; + float m_xSpacing; + uint32_t m_numY; + float m_cornerY; + float m_ySpacing; +}; + +struct DisplacementMapVolumeImpl : public DisplacementMapVolume +{ + DisplacementMapVolumeImpl(); + + void init(const FractureSliceDesc& desc); + + void getData(uint32_t& width, uint32_t& height, uint32_t& depth, uint32_t& size, unsigned char const** ppData) const; + +private: + + void buildData(const physx::PxVec3 scale = physx::PxVec3(1)) const; + + // Data creation is lazy, and does not effect externally visible state + // Note: At some point, we will want to switch to floating point displacements + mutable physx::Array<unsigned char> data; + + uint32_t width; + uint32_t height; + uint32_t depth; + +}; + +// CutoutSetImpl + +struct PolyVert +{ + uint16_t index; + uint16_t flags; +}; + +struct ConvexLoop +{ + physx::Array<PolyVert> polyVerts; +}; + +struct Cutout +{ + physx::Array<physx::PxVec3> vertices; + physx::Array<ConvexLoop> convexLoops; +}; + +struct CutoutSetImpl : public CutoutSet +{ + CutoutSetImpl() : periodic(false), dimensions(0.0f) + { + } + + enum Version + { + First = 0, + // New versions must be put here. There is no need to explicitly number them. The + // numbers above were put there to conform to the old DestructionToolStreamVersion enum. + + Count, + Current = Count - 1 + }; + + uint32_t getCutoutCount() const + { + return cutouts.size(); + } + + uint32_t getCutoutVertexCount(uint32_t cutoutIndex) const + { + return cutouts[cutoutIndex].vertices.size(); + } + uint32_t getCutoutLoopCount(uint32_t cutoutIndex) const + { + return cutouts[cutoutIndex].convexLoops.size(); + } + + const physx::PxVec3& getCutoutVertex(uint32_t cutoutIndex, uint32_t vertexIndex) const + { + return cutouts[cutoutIndex].vertices[vertexIndex]; + } + + uint32_t getCutoutLoopSize(uint32_t cutoutIndex, uint32_t loopIndex) const + { + return cutouts[cutoutIndex].convexLoops[loopIndex].polyVerts.size(); + } + + uint32_t getCutoutLoopVertexIndex(uint32_t cutoutIndex, uint32_t loopIndex, uint32_t vertexNum) const + { + return cutouts[cutoutIndex].convexLoops[loopIndex].polyVerts[vertexNum].index; + } + uint32_t getCutoutLoopVertexFlags(uint32_t cutoutIndex, uint32_t loopIndex, uint32_t vertexNum) const + { + return cutouts[cutoutIndex].convexLoops[loopIndex].polyVerts[vertexNum].flags; + } + bool isPeriodic() const + { + return periodic; + } + const physx::PxVec2& getDimensions() const + { + return dimensions; + } + + void serialize(physx::PxFileBuf& stream) const; + void deserialize(physx::PxFileBuf& stream); + + void release() + { + delete this; + } + + physx::Array<Cutout> cutouts; + bool periodic; + physx::PxVec2 dimensions; +}; + +class PartConvexHullProxy : public ExplicitHierarchicalMesh::ConvexHull, public UserAllocated +{ +public: + ConvexHullImpl impl; + + PartConvexHullProxy() + { + impl.init(); + } + + PartConvexHullProxy(const PartConvexHullProxy& hull) + { + *this = hull; + } + + PartConvexHullProxy& operator = (const PartConvexHullProxy& hull) + { + impl.init(); + if (hull.impl.mParams) + { + impl.mParams->copy(*hull.impl.mParams); + } + return *this; + } + + virtual void buildFromPoints(const void* points, uint32_t numPoints, uint32_t pointStrideBytes) + { + impl.buildFromPoints(points, numPoints, pointStrideBytes); + } + + virtual const physx::PxBounds3& getBounds() const + { + return impl.getBounds(); + } + + virtual float getVolume() const + { + return impl.getVolume(); + } + + virtual uint32_t getVertexCount() const + { + return impl.getVertexCount(); + } + + virtual physx::PxVec3 getVertex(uint32_t vertexIndex) const + { + if (vertexIndex < impl.getVertexCount()) + { + return impl.getVertex(vertexIndex); + } + return physx::PxVec3(0.0f); + } + + virtual uint32_t getEdgeCount() const + { + return impl.getEdgeCount(); + } + + virtual physx::PxVec3 getEdgeEndpoint(uint32_t edgeIndex, uint32_t whichEndpoint) const + { + if (edgeIndex < impl.getEdgeCount()) + { + return impl.getVertex(impl.getEdgeEndpointIndex(edgeIndex, whichEndpoint)); + } + return physx::PxVec3(0.0f); + } + + /** + This is the number of planes which bound the convex hull. + */ + virtual uint32_t getPlaneCount() const + { + return impl.getPlaneCount(); + } + + /** + This is the plane indexed by planeIndex, which must in + the range [0, getPlaneCount()-1]. + */ + virtual physx::PxPlane getPlane(uint32_t planeIndex) const + { + if (planeIndex < impl.getPlaneCount()) + { + return impl.getPlane(planeIndex); + } + return physx::PxPlane(physx::PxVec3(0.0f), 0.0f); + } + + virtual bool rayCast(float& in, float& out, const physx::PxVec3& orig, const physx::PxVec3& dir, + const physx::PxTransform& localToWorldRT, const physx::PxVec3& scale, physx::PxVec3* normal = NULL) const + { + return impl.rayCast(in, out, orig, dir, localToWorldRT, scale, normal); + } + + virtual bool reduceHull(uint32_t maxVertexCount, uint32_t maxEdgeCount, uint32_t maxFaceCount, bool inflated) + { + return impl.reduceHull(maxVertexCount, maxEdgeCount, maxFaceCount, inflated); + } + + virtual void release() + { + delete this; + } +}; + +PX_INLINE void resizeCollision(physx::Array<PartConvexHullProxy*>& collision, uint32_t hullCount) +{ + const uint32_t oldHullCount = collision.size(); + for (uint32_t i = hullCount; i < oldHullCount; ++i) + { + collision[i]->release(); + } + collision.resize(hullCount); + for (uint32_t i = oldHullCount; i < hullCount; ++i) + { + collision[i] = PX_NEW(PartConvexHullProxy)(); + } +} + +void buildCollisionGeometry(physx::Array<PartConvexHullProxy*>& volumes, const CollisionVolumeDesc& desc, + const physx::PxVec3* vertices, uint32_t vertexCount, uint32_t vertexByteStride, + const uint32_t* indices, uint32_t indexCount); + + +// ExplicitHierarchicalMeshImpl + +static uint64_t sNextChunkEUID = 0; // Execution-unique identifier for chunks + +class ExplicitHierarchicalMeshImpl : public ExplicitHierarchicalMesh, public UserAllocated +{ +public: + + // This has been copied from DestructionToolStreamVersion, at ToolStreamVersion_RemovedExplicitHMesh_mMaxDepth. + enum Version + { + First = 0, + AddedMaterialFramesToHMesh_and_NoiseType_and_GridSize_to_Cleavage = 7, + IncludingVertexFormatInSubmeshData = 12, + AddedMaterialLibraryToMesh = 14, + AddedCacheChunkSurfaceTracesAndInteriorSubmeshIndex = 32, + RemovedExplicitHMesh_mMaxDepth = 38, + UsingExplicitPartContainers, + SerializingMeshBSP, + SerializingMeshBounds, + AddedFlagsFieldToPart, + PerPartMeshBSPs, + StoringRootSubmeshCount, + MultipleConvexHullsPerChunk, + InstancingData, + UVInstancingData, + DisplacementData, + ChangedMaterialFrameToIncludeFracturingMethodContext, + RemovedInteriorSubmeshIndex, + AddedSliceDepthToMaterialFrame, + RemovedNxChunkAuthoringFlag, + ReaddedFlagsToPart, + IntroducingChunkPrivateFlags, + // New versions must be put here. There is no need to explicitly number them. The + // numbers above were put there to conform to the old DestructionToolStreamVersion enum. + + Count, + Current = Count - 1 + }; + + struct Part : public UserAllocated + { + Part() : mMeshBSP(NULL), mSurfaceNormal(0.0f), mFlags(0) + { + mBounds.setEmpty(); + } + + ~Part() + { + if (mMeshBSP != NULL) + { + mMeshBSP->release(); + mMeshBSP = NULL; + } + resizeCollision(mCollision, 0); + } + + enum Flags + { + MeshOpen = (1<<0), + }; + + physx::PxBounds3 mBounds; + physx::Array<nvidia::ExplicitRenderTriangle> mMesh; + ApexCSG::IApexBSP* mMeshBSP; + physx::Array<PartConvexHullProxy*> mCollision; + physx::PxVec3 mSurfaceNormal; // used to kick chunk out if desired + uint32_t mFlags; // See Flags + }; + + struct Chunk : public UserAllocated + { + Chunk() : mParentIndex(-1), mFlags(0), mPartIndex(-1), mInstancedPositionOffset(physx::PxVec3(0.0f)), mInstancedUVOffset(physx::PxVec2(0.0f)), mPrivateFlags(0) + { + mEUID = sNextChunkEUID++; + } + + enum Flags + { + Root = (1<<0), + RootLeaf = (1<<1), + }; + + bool isRootChunk() const + { + return (mPrivateFlags & Root) != 0; + } + + bool isRootLeafChunk() const // This means that the chunk is a root chunk and has no children that are root chunks + { + return (mPrivateFlags & RootLeaf) != 0; + } + + PX_INLINE uint64_t getEUID() const + { + return mEUID; + } + + int32_t mParentIndex; + uint32_t mFlags; // See DestructibleAsset::ChunkFlags + int32_t mPartIndex; + physx::PxVec3 mInstancedPositionOffset; // if instanced, the offsetPosition + physx::PxVec2 mInstancedUVOffset; // if instanced, the offset UV + uint32_t mPrivateFlags; // Things that don't make it to the DestructibleAsset; authoring only. See ExplicitHierarchicalMeshImpl::Chunk::Flags + + private: + uint64_t mEUID; // A unique identifier during the application execution. Not to be serialized. + }; + + physx::Array<Part*> mParts; + physx::Array<Chunk*> mChunks; + physx::Array<ExplicitSubmeshData> mSubmeshData; + physx::Array<nvidia::MaterialFrame> mMaterialFrames; + uint32_t mRootSubmeshCount; // How many submeshes came with the root mesh + + ApexCSG::IApexBSPMemCache* mBSPMemCache; + + DisplacementMapVolumeImpl mDisplacementMapVolume; + + ExplicitHierarchicalMeshImpl(); + ~ExplicitHierarchicalMeshImpl(); + + // Sorts chunks in parent-sorted order (stable) + void sortChunks(physx::Array<uint32_t>* indexRemap = NULL); + + // Generate part surface normals, if possible + void createPartSurfaceNormals(); + + // ExplicitHierarchicalMesh implementation: + + uint32_t addPart(); + bool removePart(uint32_t index); + uint32_t addChunk(); + bool removeChunk(uint32_t index); + void serialize(physx::PxFileBuf& stream, Embedding& embedding) const; + void deserialize(physx::PxFileBuf& stream, Embedding& embedding); + int32_t maxDepth() const; + uint32_t partCount() const; + uint32_t chunkCount() const; + uint32_t depth(uint32_t chunkIndex) const; + int32_t* parentIndex(uint32_t chunkIndex); + uint64_t chunkUniqueID(uint32_t chunkIndex); + int32_t* partIndex(uint32_t chunkIndex); + physx::PxVec3* instancedPositionOffset(uint32_t chunkIndex); + physx::PxVec2* instancedUVOffset(uint32_t chunkIndex); + uint32_t meshTriangleCount(uint32_t partIndex) const; + nvidia::ExplicitRenderTriangle* meshTriangles(uint32_t partIndex); + physx::PxBounds3 meshBounds(uint32_t partIndex) const; + physx::PxBounds3 chunkBounds(uint32_t chunkIndex) const; + uint32_t* chunkFlags(uint32_t chunkIndex) const; + uint32_t convexHullCount(uint32_t partIndex) const; + const ExplicitHierarchicalMesh::ConvexHull** convexHulls(uint32_t partIndex) const; + physx::PxVec3* surfaceNormal(uint32_t partIndex); + const DisplacementMapVolume& displacementMapVolume() const; + uint32_t submeshCount() const; + ExplicitSubmeshData* submeshData(uint32_t submeshIndex); + uint32_t addSubmesh(const ExplicitSubmeshData& submeshData); + uint32_t getMaterialFrameCount() const; + nvidia::MaterialFrame getMaterialFrame(uint32_t index) const; + void setMaterialFrame(uint32_t index, const nvidia::MaterialFrame& materialFrame); + uint32_t addMaterialFrame(); + void clear(bool keepRoot = false); + void set(const ExplicitHierarchicalMesh& mesh); + bool calculatePartBSP(uint32_t partIndex, uint32_t randomSeed, uint32_t microgridSize, BSPOpenMode::Enum meshMode, IProgressListener* progressListener = NULL, volatile bool* cancel = NULL); + void calculateMeshBSP(uint32_t randomSeed, IProgressListener* progressListener = NULL, const uint32_t* microgridSize = NULL, BSPOpenMode::Enum meshMode = BSPOpenMode::Automatic); + void replaceInteriorSubmeshes(uint32_t partIndex, uint32_t frameCount, uint32_t* frameIndices, uint32_t submeshIndex); + void visualize(RenderDebugInterface& debugRender, uint32_t flags, uint32_t index = 0) const; + void release(); + void buildMeshBounds(uint32_t partIndex); + void buildCollisionGeometryForPart(uint32_t partIndex, const CollisionVolumeDesc& desc); + void buildCollisionGeometryForRootChunkParts(const CollisionDesc& desc, bool aggregateRootChunkParentCollision = true); + void initializeDisplacementMapVolume(const nvidia::FractureSliceDesc& desc); + void reduceHulls(const CollisionDesc& desc, bool inflated); + void aggregateCollisionHullsFromRootChildren(uint32_t chunkIndex); +}; + +} +} // end namespace nvidia::apex + +#endif + +#endif |