aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Samples/SampleLargeWorld
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleLargeWorld
downloadphysx-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 'PhysX_3.4/Samples/SampleLargeWorld')
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.cpp1232
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.h242
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.cpp181
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.h75
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.cpp1039
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.h203
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldCCT.cpp70
-rw-r--r--PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldInputEventIds.h45
8 files changed, 3087 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.cpp b/PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.cpp
new file mode 100644
index 00000000..4dcaa544
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.cpp
@@ -0,0 +1,1232 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxTkRandom.h"
+#include "RenderMeshActor.h"
+#include "SampleDirManager.h"
+#include "ChunkLoader.h"
+#include "SampleLargeWorld.h"
+#include <algorithm>
+#include "MeshBuilder.h"
+#include "PsMathUtils.h"
+#include "PxTkFile.h"
+#include "wavefront.h"
+#include "PsString.h"
+#include "PxScene.h"
+#include "geometry/PxGeometryQuery.h"
+#include "extensions/PxCollectionExt.h"
+
+using namespace PxToolkit;
+using namespace physx;
+using namespace shdfnd;
+
+#define MATERIAL_ID 0x01
+
+#define CHUNK_DEBRIS_NUM 1
+#define ADD_TREES 1
+#define ADD_WIND_MILL 1
+
+static const ChunkID FARM_CHUNKID = {{4, 3}};
+static const ChunkID CITY_CHUNKID = {{4, 2}};
+static const ChunkID FORTRESS_CHUNKID = {{1, 2}};
+static const ChunkID FOREST_CHUNKID = {{5, 3}};
+
+static const char* gFarmName = "Farm";
+static const char* gCityName = "City";
+static const char* gTreeName = "Tree";
+
+static const float gFortrestScale = 0.05f;
+
+static const PxBounds3 gCityBounds( PxVec3(927.65833,17.403145,452.00970), PxVec3(1119.6967,256.83026,576.55121));
+static const PxBounds3 gFarmBounds( PxVec3(1001.8151,9.4852743,732.46741), PxVec3(1036.2266,16.729010,787.07898));
+static const PxBounds3 gFortressBounds( PxVec3(-584.924011,0.000122,-586.000305), PxVec3(584.924011,1875.750488,585.999939));
+
+static const PxVec3 gCityPos(1024.0000,17.414299,512.00000);
+static const PxVec3 gFarmPos(1024.0000, 9.4852762, 768.0f);
+static const PxVec3 gFortressPos(256.00000,81.219383,512.000000);
+
+static PX_INLINE ChunkID getChunkIdFromPosition(const PxVec3& position, CoordType terrainDim, PxF32 terrainSize)
+{
+ CoordType xCoor = (CoordType)((position.x + terrainSize*0.5f) / terrainSize);
+ xCoor = PxClamp((CoordType)xCoor, (CoordType)0, (CoordType)(terrainDim -1));
+
+ CoordType yCoor = (CoordType)((position.z + terrainSize*0.5f) / terrainSize);
+ yCoor = PxClamp((CoordType)yCoor, (CoordType)0, (CoordType)(terrainDim -1));
+
+ ChunkID res;
+ res.coord.x = xCoor;
+ res.coord.y = yCoor;
+
+ return res;
+}
+
+static PxI32 getFileSize(const char* name)
+{
+ if(!name)
+ return 0;
+
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, name, "rb");
+ if( !fp )
+ return 0;
+
+ fseek(fp, 0, SEEK_END);
+ PxI32 filesize = (PxI32)ftell(fp);
+ fclose(fp);
+ return filesize;
+}
+
+void SampleLargeWorld::addWindMills(const PxTriangleMeshGeometry& meshGeom, BasicRandom& random, const PxBounds3& bound, PxCollection& outCollection)
+{
+ PxPhysics& physics = getPhysics();
+ PxMaterial& material = getDefaultMaterial();
+
+ const PxReal millHalfHeight = 20.0f;
+ const PxReal millRadius =9.0f;
+ const PxReal fanRadius = 22.0f;
+ const PxReal fanWidth = 3.0f;
+ const PxReal fanThin = 0.5f;
+ const PxReal axisHalfHeight = 5.0f;
+ const PxReal axisRadius = 1.0f;
+ const PxVec3 millExtent(
+ millRadius*0.5f + axisHalfHeight + axisRadius + fanThin,
+ fanRadius*0.5f + millRadius + millHalfHeight,
+ millRadius*0.5f + axisHalfHeight + axisRadius + fanThin
+ ) ;
+
+ PxBounds3 millBornBound = bound;
+ millBornBound.fattenFast(-millRadius*2.0f);
+
+ //Store mill position to check if new mill is overlaped with old mills
+ PxVec3 millPts[5];
+
+ PxU32 mills = 0, retryNum = 1;
+ do
+ {
+ //Raycast against terrain from random pos to get mill foot point
+ PxVec3 rayStart(
+ random.rand( millBornBound.minimum.x, millBornBound.maximum.x),
+ bound.maximum.y,
+ random.rand( millBornBound.minimum.z, millBornBound.maximum.z));
+
+ PxReal maxDist = 2*(bound.maximum.y - bound.minimum.y);
+
+ PxRaycastHit hit;
+
+ PxU32 hitsNum = PxGeometryQuery::raycast(
+ rayStart, PxVec3(0.0f,-1.0f,0.0f),
+ meshGeom, PxTransform(PxIdentity), maxDist,
+ PxHitFlag::ePOSITION, 1, &hit);
+
+ if( hitsNum )
+ {
+ PxVec3 millPt = hit.position;
+ millPt.y += millHalfHeight - millRadius;
+
+ PxVec3 axisPt = millPt;
+ axisPt.y += millHalfHeight + millRadius;
+ axisPt.x += millRadius;
+
+ PxVec3 fanPt = axisPt;
+ fanPt.x += axisHalfHeight;
+
+ //Roughly check if fans of mill collided with terrain
+ PxQueryFilterData filter( PxQueryFlag::eANY_HIT);
+ PxOverlapBuffer buf;
+ PxBoxGeometry fanBox(fanThin, fanRadius, fanRadius);
+ if(PxGeometryQuery::overlap(fanBox, PxTransform(fanPt), meshGeom, PxTransform(PxIdentity)))
+ {
+ continue;
+ }
+
+
+ PxBounds3 curBounds = PxBounds3::centerExtents( millPt, millExtent);
+
+ bool needRegenerate = false;
+
+ for(PxU32 t = 0; t < mills; t++)
+ {
+ PxBounds3 otherBounds = PxBounds3::centerExtents( millPts[t], millExtent);
+ if( otherBounds.intersects(curBounds) )
+ needRegenerate = true;
+ }
+
+ if(needRegenerate)
+ {
+ continue;
+ }
+
+ millPts[mills] = millPt;
+ millPts[mills].x = millPts[mills].x + millRadius - millExtent.x;
+ ++mills;
+
+ PxCapsuleGeometry millGeom(millRadius, millHalfHeight);
+ PxCapsuleGeometry axisGeom(axisRadius, axisHalfHeight);
+ PxBoxGeometry fanGeom(fanRadius, fanWidth, fanThin);
+
+ PxQuat verticleRote( PxHalfPi, PxVec3(0.0f,0.0f,1.0f));
+ PxQuat y90Rote( PxHalfPi, PxVec3(0.0f,1.0f,0.0f));
+
+ PxRigidStatic* millBody = physics.createRigidStatic(PxTransform(millPt));
+ PxShape* millShape0 = PxRigidActorExt::createExclusiveShape(*millBody, millGeom, material);
+ millShape0->setLocalPose(PxTransform(verticleRote));
+ PxShape* millShape1 = PxRigidActorExt::createExclusiveShape(*millBody, axisGeom, material);
+ millShape1->setLocalPose(PxTransform(axisPt - millPt));
+
+ PxRigidDynamic* fan = physics.createRigidDynamic(PxTransform(fanPt));
+ PxShape* fanShape0 = PxRigidActorExt::createExclusiveShape(*fan, fanGeom, material);
+ fanShape0->setLocalPose(PxTransform(PxIdentity));
+ PxShape* fanShape1 = PxRigidActorExt::createExclusiveShape(*fan, fanGeom, material);
+ fanShape1->setLocalPose(PxTransform(verticleRote));
+
+ //Disable the collision between fans and other objects in scene
+ setCollisionGroup(fan, FAN_COLLISION_GROUP);
+
+ PxRevoluteJoint* joint = PxRevoluteJointCreate(physics,
+ millBody, PxTransform(fanPt - millPt),
+ fan, PxTransform(PxVec3(0), y90Rote));
+
+ joint->setDriveVelocity(10.0f);
+ joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, true);
+
+ outCollection.add(*millBody);
+ outCollection.add(*fan);
+ outCollection.add(*joint);
+ }
+
+ }while( mills < retryNum);
+}
+
+void SampleLargeWorld::addTrees(const PxTriangleMeshGeometry& meshGeom, const PxBounds3& bound, PxCollection& outCollection)
+{
+ const char* filename = getSampleMediaFilename("tree.obj");
+ const char* filenameCooked = getSampleOutputFilePath("tree.obj", "");
+
+ PxReal maxDist = 2*(bound.maximum.y - bound.minimum.y);
+ for(PxU32 i = (PxU32)bound.minimum.z; i < (PxU32)bound.maximum.z; i += 80)
+ {
+ PxVec3 rayStart(bound.minimum.x, bound.maximum.y, (PxReal)i);
+
+ PxRaycastBuffer hit;
+ PxQueryFilterData filter(PxQueryFlag::eSTATIC);
+ PxScene& scene = getActiveScene();
+ bool ret = false;
+ {
+ PxSceneReadLock scopedLock(scene);
+ ret = scene.raycast(rayStart, PxVec3(0.0f,-1.0f,0.0f), maxDist, hit, PxHitFlag::ePOSITION, filter);
+ }
+ if( ret )
+ {
+ MeshBuilder::addObjMeshToPxCollection(
+ getPhysics(), getCooking(), getDefaultMaterial(),
+ filename, filenameCooked,
+ PxTransform(hit.block.position, PxQuat(-PxHalfPi, PxVec3(1,0,0))), PxVec3(200, 200, 200),
+ outCollection, gTreeName);
+
+ }
+ }
+
+}
+
+static void flattenChunk(SampleArray<PxVec3>& terrainVertices, const PxBounds3& bound, PxReal dataY)
+{
+ PxBounds3 bound1 = bound;
+ PxReal deltaX = bound1.maximum.x - bound1.minimum.x;
+ PxReal deltaZ = bound1.maximum.z- bound1.minimum.z;
+ PxReal delta = deltaX < deltaZ ? deltaX : deltaZ;
+ bound1.fattenFast(delta/32);
+
+ const PxU32 size = terrainVertices.size();
+
+ for(PxU32 i = 0; i < size; ++i)
+ {
+ if((terrainVertices[i].x <= bound1.maximum.x && terrainVertices[i].x >= bound1.minimum.x)
+ && (terrainVertices[i].z <= bound1.maximum.z && terrainVertices[i].z >= bound1.minimum.z))
+ {
+ terrainVertices[i].y = dataY;
+ }
+ }
+}
+
+void SampleLargeWorld::addCity(SampleArray<PxVec3>& terrainVertices, const PxBounds3& bound, PxCollection& outCollection)
+{
+ const char* filename = getSampleMediaFilename("city.obj");
+ const char* filenameCooked = getSampleOutputFilePath("city.obj", "");
+
+ MeshBuilder::addObjMeshToPxCollection(
+ getPhysics(), getCooking(), getDefaultMaterial(),
+ filename, filenameCooked,
+ PxTransform(gCityPos, PxQuat(-PxHalfPi, PxVec3(1,0,0))), PxVec3(100, 100, 120),
+ outCollection, gCityName);
+}
+
+void SampleLargeWorld::addFarm(SampleArray<PxVec3>& terrainVertices, const PxBounds3& bound, PxCollection& outCollection)
+{
+ const char* filename = getSampleMediaFilename("barn.obj");
+ const char* filenameCooked = getSampleOutputFilePath("barn.obj", "");
+
+ MeshBuilder::addObjMeshToPxCollection(
+ getPhysics(), getCooking(), getDefaultMaterial(),
+ filename, filenameCooked,
+ PxTransform(gFarmPos, PxQuat(PxPi, PxVec3(1,0,0))), PxVec3(100, 100, 100),
+ outCollection, gFarmName);
+
+}
+
+
+void SampleLargeWorld::addFortress(SampleArray<PxVec3>& terrainVertices, const PxBounds3& bound, PxCollection& outCollection)
+{
+ const char* pathname = getSampleMediaFilename("WallTower.repx");
+
+ MeshBuilder* mb = SAMPLE_NEW(MeshBuilder)(*this, pathname );
+ const PxQuat q = PxShortestRotation(PxVec3(0.0f, 0.0f, 1.0f), PxVec3(0.0f, 1.0f, 0.0f));
+
+ mb->addRepXToPxCollection( PxTransform(gFortressPos, q), PxVec3(0.05f, 0.05f, 0.05f), outCollection);
+
+ DELETESINGLE( mb );
+}
+
+PxTriangleMesh* SampleLargeWorld::generateTriMesh(const SampleArray<PxVec3>* vertices, const SampleArray<PxU32>* indices)
+{
+ //Cooking mesh
+ PxTriangleMeshDesc meshDesc;
+ meshDesc.points.count = vertices->size();
+ meshDesc.triangles.count = indices->size()/3;
+ meshDesc.points.stride = sizeof(PxVec3);
+ meshDesc.triangles.stride = sizeof(PxU32)*3;
+ meshDesc.points.data = &(*vertices)[0];
+ meshDesc.triangles.data = &(*indices)[0];
+ meshDesc.flags = PxMeshFlags(0);
+
+ PxDefaultMemoryOutputStream stream;
+ bool ok = getCooking().cookTriangleMesh(meshDesc, stream);
+ if( !ok )
+ return NULL;
+
+ PxDefaultMemoryInputData rb(stream.getData(), stream.getSize());
+
+ return getPhysics().createTriangleMesh(rb);
+}
+
+void SampleLargeWorld::createChunk(CoordType coordX, CoordType coordY, PxCollection& outCollection)
+{
+ CoordType dim = binData.mDim;
+
+ SampleArray<SampleArray<PxVec3> >& terrainVertices = binData.mTerrainVertices;
+
+ SampleArray<SampleArray<PxU32> >& terrainIndices = binData.mTerrainIndices;
+
+ SampleArray<PxVec3> tmpV;
+ SampleArray<PxU32> tmpI;
+
+ SampleArray<PxVec3>* vertices;
+ SampleArray<PxU32>* indices;
+ PxVec3 xAxis( (coordX / dim ) * CHUNK_WIDTH * dim - 0.5f * CHUNK_WIDTH, 0.0f, 0.0f );
+ PxVec3 zAxis( 0.0f, 0.0f, ( coordY / dim ) * CHUNK_WIDTH * dim - 0.5f * CHUNK_WIDTH );
+ CoordType x = coordX %( dim << 1 ), z = coordY % ( dim <<1 );
+ PxVec3 xRevert(1.0f), zRevert(1.0f);
+
+ bool needRevertMesh = false;
+ bool useRawDirectly = true;
+
+ //The terrain template is 16*16, if chunk is out of the range, use mirror to create new one
+ if(coordX >= dim || coordY >= dim)
+ useRawDirectly = false;
+
+ if( useRawDirectly )
+ {
+ vertices = &terrainVertices[coordY * dim + coordX];
+ indices = &terrainIndices[coordY * dim + coordX];
+ }
+ else //Just use mirror to create new terrain, so terrain can be expand to infinite size
+ {
+ if( x >= dim )
+ {
+ x = x % dim;
+ xRevert.x = -1.0f;
+ needRevertMesh = !needRevertMesh;
+ x = dim - x - 1;
+ }
+
+ if( z >= dim )
+ {
+ z = z % dim;
+ zRevert.z = -1.0f;
+ needRevertMesh = !needRevertMesh;
+ z = dim - z - 1;
+ }
+
+ SampleArray<PxVec3>& templateV = terrainVertices[z*dim + x];
+
+ for( PxU32 v = 0; v < templateV.size(); v++)
+ {
+ PxVec3 vert = templateV[v];
+ if(xRevert.x < 0.0f)
+ {
+ vert.x = CHUNK_WIDTH * dim - 0.5f * CHUNK_WIDTH - templateV[v].x + xAxis.x;
+ }
+ else
+ {
+ vert.x = templateV[v].x - -0.5f * CHUNK_WIDTH + xAxis.x;
+ }
+
+ if(zRevert.z < 0.0f)
+ {
+ vert.z = CHUNK_WIDTH * dim - 0.5f * CHUNK_WIDTH - templateV[v].z + zAxis.z;
+ }
+ else
+ {
+ vert.z = templateV[v].z - -0.5f * CHUNK_WIDTH + zAxis.z;
+ }
+
+ tmpV.pushBack(vert);
+ }
+
+ vertices = &tmpV;
+
+ if(needRevertMesh)
+ {
+ SampleArray<PxU32>& templateI = terrainIndices[z*dim + x];
+
+ for(PxU32 d = 0; d < templateI.size(); d += 3)
+ {
+ tmpI.pushBack(templateI[d]);
+ tmpI.pushBack(templateI[d+2]);
+ tmpI.pushBack(templateI[d+1]);
+
+ }
+
+ indices = &tmpI;
+ }
+ else
+ indices = &terrainIndices[z*dim + x];
+
+ }
+
+ //Both pose and scale are identity, so local bounds == global bounds
+ PxBounds3 bound = PxBounds3::empty();
+
+ for( SampleArray<PxVec3>::Iterator iter = vertices->begin();
+ iter != vertices->end(); iter++ )
+ {
+ bound.include( *iter );
+ }
+
+ ChunkID id;
+ id.coord.x = coordX;
+ id.coord.y = coordY;
+ BasicRandom random(id.id);
+
+ PxBounds3 objBounds[3];
+ PxF32 flatHeight[3];
+ const float flattenScale = 1.1f;
+
+ objBounds[0] = gCityBounds;
+ objBounds[1] = gFarmBounds;
+ objBounds[1].fattenFast(1.5f);
+
+ PxBounds3 fortressScaledBound( gFortressBounds.minimum * gFortrestScale, gFortressBounds.maximum * gFortrestScale );
+ objBounds[2] = PxBounds3::centerExtents( gFortressPos + fortressScaledBound.getCenter(), fortressScaledBound.getExtents() * flattenScale);
+
+ flatHeight[0] = gCityPos.y;
+ flatHeight[1] = gFarmPos.y;
+ flatHeight[2] = gFortressPos.y;
+
+ for(PxU32 i = 0; i < 3; i++)
+ {
+ if(bound.intersects(objBounds[i]))
+ {
+ flattenChunk(*vertices, objBounds[i], flatHeight[i]);
+ }
+ }
+
+ bool isEmpty = false;
+ if(id.id == FARM_CHUNKID.id)
+ {
+ addFarm(*vertices, bound, outCollection);
+ }
+ else if(id.id == CITY_CHUNKID.id)
+ {
+ addCity(*vertices, bound, outCollection);
+ }
+ else if(id.id == FORTRESS_CHUNKID.id)
+ {
+ addFortress(*vertices, bound, outCollection);
+ }
+ else
+ {
+ isEmpty = true;
+ }
+
+ PxTriangleMesh* triangleMesh = generateTriMesh(vertices, indices);
+ if( !triangleMesh )
+ return;
+
+ PxTriangleMeshGeometry meshGeom(triangleMesh);
+ PxMaterial& material = getDefaultMaterial();
+ //Create terrain actor
+ PxRigidStatic* actor = PxCreateStatic(getPhysics(), PxTransform(PxIdentity), meshGeom, material);
+
+ //Enable ccd for terrain
+ PxShape* meshShape = getShape(*actor);
+ SampleLargeWorld::setCCDActive(*meshShape);
+ meshShape->setFlag(PxShapeFlag::eVISUALIZATION, false);
+
+ if(id.id == FOREST_CHUNKID.id)
+ {
+ addTrees(meshGeom, bound, outCollection);
+ isEmpty = false;
+ }
+
+ if(isEmpty)
+ {
+#if ADD_WIND_MILL
+ addWindMills(meshGeom, random, bound, outCollection);
+#endif
+ }
+
+ outCollection.add(*actor);
+ return;
+}
+
+BackgroundLoader::BackgroundLoader(SampleLargeWorld& sample, CoordType halfRange, CoordType terrainRange, PxF32 chunkWidth)
+ : mSampleLargeWorld(&sample)
+ , mPhysics(sample.getPhysics())
+ , mScene(sample.getActiveScene())
+ , mMaterial(sample.getDefaultMaterial())
+ , mHalfRange(halfRange)
+ , mTerrainRange(terrainRange)
+ , mChunkWidth(chunkWidth)
+{
+ mCurChunkId.id = 0;
+ mDiskIOTime = 0;
+ mPhyXStreamTime = 0;
+ mGraphicStreamTime = 0;
+
+ mLoaderThread = PX_NEW(Thread)(loaderThread, this);
+ mLoaderThread->start(0);
+ mSr = PxSerialization::createSerializationRegistry(mPhysics);
+}
+
+BackgroundLoader::~BackgroundLoader()
+{
+ mLoaderThread->signalQuit();
+ mRequestReady.set();
+ mLoaderThread->waitForQuit();
+ delete mLoaderThread;
+
+ deleteLoadedRenderQueue();
+
+ deleteCollections();
+ mSr->release();
+}
+
+void BackgroundLoader::onTick()
+{
+ //Use local queue here to minimize the lock time, prevent blocking loader thread.
+ std::vector<ChunkCommand> theCmdQueue;
+ std::vector<DeferredLoadedRenderData> theLoadedRenderDataQueue;
+
+ mQueueLock.lock();
+ theCmdQueue = mChunkCmds;
+ theLoadedRenderDataQueue = mLoadedRenderDataQueue;
+ mLoadedRenderDataQueue.clear();
+ mChunkCmds.clear();
+ mQueueLock.unlock();
+
+ size_t cmdQueueSize = theCmdQueue.size();
+ if(cmdQueueSize == 0)
+ return;
+
+ //filter the same chunk with different commands
+ for(PxU32 i = 0; i < cmdQueueSize; ++i)
+ {
+ ChunkCommand cmdQueue = theCmdQueue[i];
+
+ bool isOutdatedCommand = false;
+ for(PxU32 j = i + 1; j < cmdQueueSize && !isOutdatedCommand; ++j)
+ {
+ isOutdatedCommand = (cmdQueue.id == theCmdQueue[j].id);
+ }
+
+ if(isOutdatedCommand)
+ continue;
+
+ ChunkCommandType::Enum type = cmdQueue.type;
+ if(type == ChunkCommandType::eAdd)
+ {
+ addReadyChunkToScene(cmdQueue.id);
+ }
+ else if(type == ChunkCommandType::eRemove)
+ {
+ destroyChunk(cmdQueue.id);
+ }
+ }
+
+ Ps::Time localTimer;
+ for(PxU32 i = 0; i < theLoadedRenderDataQueue.size(); i++)
+ {
+ DeferredLoadedRenderData& cq = theLoadedRenderDataQueue[i];
+ RenderBaseActor* renderMesh = mSampleLargeWorld->createRenderMeshFromRawMesh( cq);
+
+ //Link physic actor to render actor
+ cq.shape->userData = renderMesh;
+
+ {
+ PxSceneReadLock scopedLock(mSampleLargeWorld->getActiveScene());
+ renderMesh->setPhysicsShape(cq.shape, cq.shape->getActor());
+ renderMesh->setEnableCameraCull(true);
+
+ PxTriangleMeshGeometry geometry;
+ cq.shape->getTriangleMeshGeometry(geometry);
+ renderMesh->setMeshScale(geometry.scale);
+ }
+ PxVec3 *verts = const_cast<PxVec3*>(cq.mVerts);
+ SAMPLE_FREE(verts);
+
+ PxU32 *indices = const_cast<PxU32*>(cq.mIndices);
+ SAMPLE_FREE(indices);
+
+ PxReal *normals = (PxReal*)const_cast<PxVec3*>(cq.mVertexNormals);
+ SAMPLE_FREE(normals);
+
+ PxReal* uvs = const_cast<PxReal*>(cq.mUVs);
+ SAMPLE_FREE(uvs);
+ }
+
+ Ps::Time::Second timeCost = localTimer.getElapsedSeconds();
+
+ mLoaderStatusLock.lockWriter();
+ mGraphicStreamTime += timeCost;
+ mLoaderStatusLock.unlockWriter();
+
+ {
+ PxSceneWriteLock scopedLock(mSampleLargeWorld->getActiveScene());
+ for(PxU32 i = 0; i < mRemovingActors.size(); i++)
+ {
+ mRemovingActors[i]->release();
+ }
+ }
+
+ mRemovingActors.clear();
+}
+
+void BackgroundLoader::updateChunk(const PxVec3& cameraPos)
+{
+ ChunkID id = getChunkIdFromPosition(cameraPos, mTerrainRange, mChunkWidth);
+ if( id.id == mCurChunkId.id)
+ return;
+
+ mLocalBounds = PxBounds3::centerExtents( PxVec3(id.coord.x*mChunkWidth, 0.0f, id.coord.y*mChunkWidth), PxVec3(mChunkWidth));
+ updateDynamicChunkId();
+
+ mCurChunkId = id;
+ CoordType x = PxClamp(id.coord.x, (CoordType)mHalfRange, (CoordType)(mTerrainRange - mHalfRange));
+ CoordType y = PxClamp(id.coord.y, (CoordType)mHalfRange, (CoordType)(mTerrainRange - mHalfRange));
+
+ std::vector<ChunkID> requestQueue;
+ for( CoordType i = PxMax( (CoordType)0, (CoordType)(x - mHalfRange) ); i <= PxMin( (CoordType)N2, (CoordType)(x + mHalfRange)); i++ )
+ {
+ for( CoordType j = PxMax( (CoordType)0, (CoordType)(y - mHalfRange)); j <= PxMin( (CoordType)N2, (CoordType)(y + mHalfRange)); j++ )
+ {
+ ChunkID id;
+ id.coord.x = i;
+ id.coord.y = j;
+ requestQueue.push_back(id);
+ }
+ }
+
+ mQueueLock.lock();
+ mRequestQueue = requestQueue;
+ mQueueLock.unlock();
+ mRequestReady.set();
+}
+
+static const char* getPlatformName()
+{
+#if PX_X86
+ return "PC32";
+#elif PX_X64
+ return "PC64";
+#elif PX_ARM_FAMILY
+ return "ARM";
+#else
+ return "";
+#endif
+}
+
+const char* BackgroundLoader::getPathname(ChunkID id)
+{
+ char tmpFilename[256];
+ sprintf(tmpFilename, "chunk_%d_%d_%s.bin", id.coord.x, id.coord.y, getPlatformName());
+
+ return mSampleLargeWorld->getSampleOutputFilePath(tmpFilename,"");
+}
+
+void BackgroundLoader::serialize(PxCollection* collection, ChunkID id)
+{
+ const char* theBinPath = getPathname( id );
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, theBinPath, "rb");
+ if( fp )
+ {
+ fclose(fp);
+ return;
+ }
+
+ PxCollection* theExtRef = PxCreateCollection();
+ theExtRef->add(mMaterial, MATERIAL_ID);
+ PxDefaultMemoryOutputStream memBuf;
+
+ PxSerialization::complete(*collection, *mSr, theExtRef);
+ bool bRet = PxSerialization::serializeCollectionToBinary(memBuf, *collection, *mSr, theExtRef, true );
+ PX_ASSERT(bRet);
+ PX_UNUSED(bRet);
+
+ PxDefaultFileOutputStream s( getPathname( id ) );
+
+ Ps::Time localTimer;
+ localTimer.getElapsedSeconds();
+ s.write( memBuf.getData(), memBuf.getSize());
+ mDiskIOTimeCounter += localTimer.getElapsedSeconds();
+
+ theExtRef->release();
+}
+
+//PhysX support buffer inserting actor, so no care about whether physic is simulating here
+void BackgroundLoader::addReadyChunkToScene(ChunkID id)
+{
+ PxCollection *theCollection = NULL;
+ {
+ shdfnd::Mutex::ScopedLock al( mCollectionLock );
+ CollectionIdMap::iterator it = mCollectionIdMap.find(id);
+ if(it == mCollectionIdMap.end() || it->second.addToScene )
+ {
+ return;
+ }
+
+ theCollection = it->second.collection;
+ if( !theCollection )
+ return;
+
+ it->second.addToScene = true;
+ }
+
+ PxU32 count = theCollection->getNbObjects();
+ for(PxU32 i = 0; i < count; i++)
+ {
+ PxBase *object = &theCollection->getObject(i);
+ PX_ASSERT(object);
+ PxType theType = object->getConcreteType();
+ if( theType == PxConcreteType::eRIGID_DYNAMIC )
+ {
+ PxRigidActor *actor = static_cast<PxRigidActor*>(object);
+ mSampleLargeWorld->createRenderObjectsFromActor(actor);
+ }
+ else if(theType == PxConcreteType::eRIGID_STATIC)
+ {
+ PxRigidStatic* actor = static_cast<PxRigidStatic*>(object);
+ PxShape* shape = getShape( *actor );
+ PxTriangleMeshGeometry geometry;
+ shape->getTriangleMeshGeometry(geometry);
+ //We create static render mesh in another loop
+ if(shape->getGeometryType() != PxGeometryType::eTRIANGLEMESH)
+ {
+ mSampleLargeWorld->createRenderObjectsFromActor(actor, NULL);
+ }
+ }
+ }
+
+ {
+ PxSceneWriteLock scopedLock(mSampleLargeWorld->getActiveScene());
+ mScene.addCollection(*theCollection);
+ }
+
+ //Melt the freezon important actors on this chunk
+ for(unsigned i = 0; i < mDyncActors.size(); ++i)
+ {
+ DynamicObjects* obj = mDyncActors[i];
+ if( obj->id.id == id.id && obj->isImportant )
+ {
+ PxSceneWriteLock scopedLock(mSampleLargeWorld->getActiveScene());
+ obj->actor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, false);
+ }
+ }
+}
+
+//just removed the actors from scene, do not release them
+void BackgroundLoader::destroyChunk(ChunkID id)
+{
+ PxCollection *theCollection = NULL;
+ bool inScene = false;
+ void* memory = NULL;
+ {
+ shdfnd::Mutex::ScopedLock al(mCollectionLock);
+
+ CollectionIdMap::iterator it = mCollectionIdMap.find(id);
+ if( it == mCollectionIdMap.end() )
+ return;
+
+ inScene = it->second.addToScene;
+ theCollection = it->second.collection;
+ memory = it->second.memory;
+ mCollectionIdMap.erase(it);
+ }
+
+
+ if(inScene)
+ {
+ //remove objects from scene first
+ PxU32 count = theCollection->getNbObjects();
+ {
+ PxSceneWriteLock scopedLock(mSampleLargeWorld->getActiveScene());
+ for(PxU32 i = 0; i < count; i++)
+ {
+ PxBase *object = &theCollection->getObject(i);
+ PX_ASSERT(object);
+ PxType type = object->getConcreteType();
+ if( type == PxConcreteType::eRIGID_STATIC || type == PxConcreteType::eRIGID_DYNAMIC )
+ {
+ mScene.removeActor( *static_cast<PxActor*>(object) );
+ }
+ }
+ }
+ }
+
+ //serialize the objects when they are not used
+ serialize(theCollection, id);
+ PxCollectionExt::releaseObjects(*theCollection);
+ theCollection->release();
+
+ if(memory)
+ {
+ free(memory);
+ memory = NULL;
+ }
+
+ //Remove the un-important actors on this chunk, freeze the important actors
+ std::vector<DynamicObjects*>::iterator it = mDyncActors.begin();
+ while(it != mDyncActors.end())
+ {
+ PxRigidDynamic* actor = (*it)->actor;
+ PxVec3 actorPos;
+ {
+ PxSceneReadLock scopedLock(mSampleLargeWorld->getActiveScene());
+ actorPos = actor->getGlobalPose().p;
+ }
+
+ ChunkID theId = getChunkIdFromPosition(actorPos, mTerrainRange, mChunkWidth);
+ if( theId.id == id.id )
+ {
+ PxSceneWriteLock scopedLock(mSampleLargeWorld->getActiveScene());
+ if( !(*it)->isImportant )
+ {
+ mSampleLargeWorld->removeActor(actor);
+ mDyncActors.erase(it);
+ it = mDyncActors.begin();
+ continue;
+ }
+ else
+ {
+ actor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+ }
+ }
+ ++it;
+ }
+}
+
+static bool isActorNULL(DynamicObjects* o)
+{
+ return o->actor == NULL;
+}
+
+void BackgroundLoader::updateDynamicChunkId()
+{
+ for(unsigned i = 0; i < mDyncActors.size(); ++i)
+ {
+ DynamicObjects* obj = mDyncActors[i];
+ PxRigidDynamic* actor = mDyncActors[i] ->actor;
+ PxVec3 pos;
+ {
+ PxSceneReadLock scopedLock(mSampleLargeWorld->getActiveScene());
+ pos = actor->getGlobalPose().p;
+ }
+
+ //Remove the un-important which go out of current grid.
+ if(obj->isImportant == false && !mLocalBounds.contains(pos))
+ {
+ mRemovingActors.push_back(actor);
+ obj->actor = NULL;
+ }
+ else
+ {
+ ChunkID theId = getChunkIdFromPosition(pos, mTerrainRange, mChunkWidth);
+ obj->id.id = theId.id;
+ }
+ }
+
+ std::vector<DynamicObjects*>::iterator new_end = std::remove_if( mDyncActors.begin(), mDyncActors.end(), isActorNULL);
+ mDyncActors.erase( new_end, mDyncActors.end());
+}
+
+PxCollection* BackgroundLoader::loadChunk(ChunkID id)
+{
+ {
+ shdfnd::Mutex::ScopedLock al(mCollectionLock);
+ if( mCollectionIdMap.find(id) != mCollectionIdMap.end() )
+ return NULL;
+ }
+
+ const char* theBinPath = getPathname( id );
+
+ PxCollection* theCollection = NULL;
+ void *theMemory = NULL;
+
+ Ps::Time localTimer;
+
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, theBinPath, "rb");
+ //If cannot find/deserilize the chunk file, create one collection
+ if( !fp )
+ {
+ theCollection = PxCreateCollection();
+ mSampleLargeWorld->createChunk( id.coord.x, id.coord.y, *theCollection );
+ }
+ else
+ {
+ localTimer.getElapsedSeconds();
+ PxU32 fileSize = getFileSize(theBinPath);
+ theMemory = malloc(fileSize + PX_SERIAL_FILE_ALIGN);
+
+ void* theMemoryA = (void*)((size_t(theMemory) + PX_SERIAL_FILE_ALIGN)&~(PX_SERIAL_FILE_ALIGN-1));
+ size_t numRead = fread(theMemoryA, 1, fileSize, fp);
+ fclose(fp);
+
+ mDiskIOTimeCounter += localTimer.getElapsedSeconds();
+ if(numRead != fileSize)
+ {
+ free(theMemory);
+ theMemory = NULL;
+ return NULL;
+ }
+
+ PxCollection* theExtRef = PxCreateCollection();
+ theExtRef->add(mMaterial, MATERIAL_ID);
+
+ theCollection = PxSerialization::createCollectionFromBinary(theMemoryA, *mSr, theExtRef);
+
+ theExtRef->release();
+
+ mPhyXStreamTimeCounter += localTimer.getElapsedSeconds();
+
+ }
+
+ CollectionMemory temp;
+ temp.collection = theCollection;
+ temp.memory = theMemory;
+ temp.addToScene = false;
+
+ {
+ shdfnd::Mutex::ScopedLock al(mCollectionLock);
+ mCollectionIdMap[id] = temp;
+ }
+
+ return theCollection;
+}
+
+
+void BackgroundLoader::deleteLoadedRenderQueue()
+{
+ std::vector<DeferredLoadedRenderData> theLoadedRenderDataQueue;
+
+ mQueueLock.lock();
+ theLoadedRenderDataQueue = mLoadedRenderDataQueue;
+ mQueueLock.unlock();
+
+ for(PxU32 i = 0; i < theLoadedRenderDataQueue.size(); i++)
+ {
+ DeferredLoadedRenderData& cq = theLoadedRenderDataQueue[i];
+
+ PxVec3 *verts = const_cast<PxVec3*>(cq.mVerts);
+ SAMPLE_FREE(verts);
+
+ PxU32 *indices = const_cast<PxU32*>(cq.mIndices);
+ SAMPLE_FREE(indices);
+
+ PxReal *normals = (PxReal*)const_cast<PxVec3*>(cq.mVertexNormals);
+ SAMPLE_FREE(normals);
+
+ PxReal* uvs = const_cast<PxReal*>(cq.mUVs);
+ SAMPLE_FREE(uvs);
+ }
+}
+
+void BackgroundLoader::deleteCollections()
+{
+ CollectionIdMap::iterator it = mCollectionIdMap.begin();
+ while(it!= mCollectionIdMap.end())
+ {
+ destroyChunk(it->first);
+ it = mCollectionIdMap.begin();
+ }
+}
+
+BackgroundLoader::DeferredLoadedRenderData* BackgroundLoader::createRawMeshFromObjMesh(const char* name, const PxTransform& pos, DeferredLoadedRenderData& rawMesh)
+{
+ PxU32 materialID = 0;
+ const char* filename = NULL;
+ if(Ps::stricmp(name, gCityName) == 0)
+ {
+ filename = "city.obj";
+ materialID = MATERIAL_BUILDING;
+ }
+ else if(Ps::stricmp(name, gFarmName) == 0)
+ {
+ filename = "barn.obj";
+ materialID = MATERIAL_FARM;
+ }
+ else if(Ps::stricmp(name, gTreeName) == 0)
+ {
+ filename = "tree.obj";
+ materialID = MATERIAL_TREE;
+ }
+
+ if( mSampleLargeWorld->createRAWMeshFromObjMesh( filename, pos, materialID, rawMesh ) != NULL )
+ return &rawMesh;
+ else
+ return NULL;
+}
+
+void* BackgroundLoader::loaderThread()
+{
+ std::vector<ChunkID> lastUpdateQueue;
+
+#if ENABLE_PROGRESS_BAR
+ mLoaderStatusLock.lockWriter();
+ mPhyXStreamTime = 0.0f;
+ mGraphicStreamTime = 0.0f;
+ mLoaderStatusLock.unlockWriter();
+#endif
+ while(mRequestReady.wait())
+ {
+ physx::shdfnd::Thread::yield();
+
+ mRequestReady.reset();
+
+ if (mLoaderThread->quitIsSignalled())
+ {
+ mLoaderThread->quit();
+ break;
+ }
+
+#if ENABLE_PROGRESS_BAR
+ mLoaderStatusLock.lockWriter();
+ mQueryLength = 0;
+ mQueryProgress = 0.0f;
+ mLoaderStatusLock.unlockWriter();
+#endif
+
+ bool bDirty = false;
+
+ std::vector<ChunkID> requestedQueue;
+ std::vector<DeferredLoadedRenderData> loadedRenderDataQueue;
+ std::vector<ChunkCommand> theChunkCmds;
+
+ mQueueLock.lock();
+ requestedQueue = mRequestQueue;
+ mQueueLock.unlock();
+
+ for(unsigned iLast = 0; iLast < lastUpdateQueue.size(); iLast++)
+ {
+ bool bFound = false;
+ for(unsigned iRequest = 0; iRequest < requestedQueue.size(); iRequest++)
+ {
+ bFound = lastUpdateQueue[iLast].id == requestedQueue[iRequest].id;
+ if(bFound)
+ break;
+ }
+ if(!bFound)
+ {
+ bDirty = true;
+ theChunkCmds.push_back(ChunkCommand(ChunkCommandType::eRemove,lastUpdateQueue[iLast]));
+ }
+ }
+
+ for(unsigned iRequest = 0; iRequest < requestedQueue.size(); iRequest++)
+ {
+ bool bFound = false;
+ for(unsigned iLast = 0; iLast < lastUpdateQueue.size(); iLast++)
+ {
+ bFound = requestedQueue[iRequest].id == lastUpdateQueue[iLast].id;
+ if(bFound)
+ break;
+ }
+ if(!bFound)
+ {
+ bDirty = true;
+ theChunkCmds.push_back(ChunkCommand(ChunkCommandType::eAdd,requestedQueue[iRequest]));
+ }
+ }
+
+ if(bDirty)
+ {
+ lastUpdateQueue = requestedQueue;
+ }
+ else
+ continue;
+
+ Ps::Time time;
+ Ps::Time::Second normalTime = 0.0f;
+ mDiskIOTimeCounter = 0.0f;
+ mPhyXStreamTimeCounter = 0.0f;
+ mGraphicStreamTimeCounter = 0.0f;
+
+ PxU32 loadedQueueSize = 0;
+ PxU32 cmdQueueSize = static_cast<PxU32>(theChunkCmds.size());
+ for(unsigned i = 0; i < cmdQueueSize; i++)
+ {
+ if(theChunkCmds[i].type == ChunkCommandType::eRemove )
+ {
+ continue;
+ }
+
+ ++loadedQueueSize;
+
+ PxCollection* theCollection = loadChunk(theChunkCmds[i].id);
+
+ time.getElapsedSeconds();
+
+ if(theCollection != NULL )
+ {
+ PxU32 nb = theCollection->getNbObjects();
+ for(PxU32 o = 0; o < nb; o++)
+ {
+ PxBase* s = &theCollection->getObject( o );
+ const PxType serialType = s->getConcreteType();
+
+ if( serialType==PxConcreteType::eRIGID_STATIC )
+ {
+ PxRigidStatic* actor = static_cast<PxRigidStatic*>(s);
+ const char* name = actor->getName();
+ //If actor has name, it should have only one shape
+ if(name)
+ {
+ PxShape* meshShape = NULL;
+ PxTriangleMeshGeometry geometry;
+ PxTransform actorPos;
+ {
+ meshShape = getShape(*actor);
+ meshShape->getTriangleMeshGeometry(geometry);
+ actorPos = actor->getGlobalPose();
+ }
+
+ DeferredLoadedRenderData rawMesh;
+ if( createRawMeshFromObjMesh(name, actorPos, rawMesh) != NULL )
+ {
+ rawMesh.shape = meshShape;
+ loadedRenderDataQueue.push_back(rawMesh);
+ }
+ }
+ else
+ {
+ const PxU32 numShapes = actor->getNbShapes();
+ PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes);
+ actor->getShapes(shapes, numShapes);
+ for(PxU32 i = 0; i < numShapes; i++)
+ {
+ PxShape* shape = shapes[i];
+ if(shape->getGeometryType() == PxGeometryType::eTRIANGLEMESH)
+ {
+ PxTriangleMeshGeometry mesh;
+ shape->getTriangleMeshGeometry(mesh);
+ DeferredLoadedRenderData rawMesh;
+ if( mSampleLargeWorld->createRawMeshFromMeshGeom(mesh, rawMesh) != NULL )
+ {
+ rawMesh.mTransform = actor->getGlobalPose();
+ rawMesh.shape = shape;
+ loadedRenderDataQueue.push_back(rawMesh);
+ }
+ }
+ }
+ SAMPLE_FREE(shapes);
+ }
+ }
+ }
+ physx::shdfnd::Thread::yield();
+ }
+
+ normalTime += time.getElapsedSeconds();
+
+#if ENABLE_PROGRESS_BAR
+ mLoaderStatusLock.lockWriter();
+ mQueryLength++;
+ PX_ASSERT(cmdQueueSize != 0);
+ mQueryProgress = (PxF32)i/(PxF32)cmdQueueSize;
+ mLoaderStatusLock.unlockWriter();
+#endif
+ if (mLoaderThread->quitIsSignalled())
+ {
+ break;
+ }
+
+ physx::shdfnd::Thread::yield();
+ }
+
+ mGraphicStreamTimeCounter += normalTime;
+ mQueueLock.lock();
+ mChunkCmds = theChunkCmds;
+ mLoadedRenderDataQueue = loadedRenderDataQueue;
+ mQueueLock.unlock();
+
+ if (mLoaderThread->quitIsSignalled())
+ {
+ mLoaderThread->quit();
+ break;
+ }
+#if ENABLE_PROGRESS_BAR
+ mLoaderStatusLock.lockWriter();
+ mQueryLength=0;
+ mQueryProgress = 0.0f;
+ mLoaderStatusLock.unlockWriter();
+#endif
+
+ mLoaderStatusLock.lockWriter();
+ mDiskIOTime = mDiskIOTimeCounter;;
+ mPhyXStreamTime = mPhyXStreamTimeCounter;
+ mGraphicStreamTime = mGraphicStreamTimeCounter;
+ mLoaderStatusLock.unlockWriter();
+ }
+
+ return NULL;
+}
+
+void* BackgroundLoader::loaderThread(void* loader)
+{
+ return ((BackgroundLoader*) loader)->loaderThread();
+}
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.h b/PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.h
new file mode 100644
index 00000000..b6edbe3f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.h
@@ -0,0 +1,242 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef CHUNKLOADER_H
+#define CHUNKLOADER_H
+
+#include "PsMutex.h"
+#include "PsThread.h"
+#include "PhysXSample.h"
+
+#include "PsTime.h"
+
+#define ENABLE_PROGRESS_BAR 1
+
+typedef PxU16 CoordType;
+typedef PxU32 IDType;
+
+#define N1 7
+//The terrain has 16*16 grids
+#define N2 256
+
+//The width of each terrain chunk, this is the hardcoded number accroding to Terrain.bin
+#define CHUNK_WIDTH 256.0f
+
+#define MATERIAL_ROAD_GRASS 1003
+#define MATERIAL_BRICKS 1004
+#define MATERIAL_BUILDING 1005
+#define MATERIAL_FARM 1006
+#define MATERIAL_TREE 1007
+
+PX_FORCE_INLINE PxShape* getShape(const PxRigidActor& actor)
+{
+ PX_ASSERT(actor.getNbShapes() >= 1);
+ PxShape* shape = NULL;
+ actor.getShapes(&shape, 1);
+ return shape;
+}
+
+typedef union
+{
+ struct{
+ CoordType x, y;
+ } coord;
+ IDType id;
+
+}ChunkID;
+
+static PX_INLINE bool operator < (const ChunkID& _Left, const ChunkID& _Right)
+{
+ return _Left.id < _Right.id;
+}
+static PX_INLINE bool operator == (const ChunkID& _Left, PxU32 _Right)
+{
+ return _Left.id == _Right;
+}
+
+static PX_INLINE bool operator == (const ChunkID& _Left, ChunkID _Right)
+{
+ return _Left.id == _Right.id;
+}
+
+struct ChunkCommandType
+{
+ enum Enum
+ {
+ eAdd,
+ eRemove
+ };
+};
+
+struct ChunkCommand
+{
+ ChunkCommand(ChunkCommandType::Enum _type, const ChunkID& _id)
+ {
+ type = _type;
+ id = _id;
+ }
+
+ ChunkCommandType::Enum type;
+ ChunkID id;
+};
+
+struct DynamicObjects
+{
+ DynamicObjects(PxRigidDynamic* _actor, bool _isImportant)
+ {
+ actor = _actor;
+ isImportant = _isImportant;
+ id.id = 0;
+ }
+
+ PxRigidDynamic* actor;
+ bool isImportant;
+ ChunkID id;
+};
+
+class SampleLargeWorld;
+class BackgroundLoader : public SampleAllocateable
+{
+public:
+ struct DeferredLoadedRenderData : public RAWMesh
+ {
+ DeferredLoadedRenderData():shape(NULL){}
+ //the shape to link with
+ PxShape* shape;
+ };
+public:
+
+ BackgroundLoader(SampleLargeWorld& sample, CoordType halfRange, CoordType terrainRange, PxF32 chunkWidth);
+ ~BackgroundLoader();
+
+ void addDynamicObject(PxRigidDynamic* inActor, bool inIsImportant)
+ {
+ mDyncActors.push_back(new DynamicObjects(inActor, inIsImportant));
+ updateDynamicChunkId();
+ }
+
+ void onTick();
+ void updateChunk(const PxVec3& cameraPos);
+
+ //The lock for accessing streaming progress and timing status
+ Ps::ReadWriteLock mLoaderStatusLock;
+
+
+#ifdef ENABLE_PROGRESS_BAR
+ volatile PxU32 mQueryLength;
+ volatile PxF32 mQueryProgress;
+#endif
+
+ volatile Ps::Time::Second mDiskIOTime;
+ volatile Ps::Time::Second mPhyXStreamTime;
+ volatile Ps::Time::Second mGraphicStreamTime;
+
+private:
+ const char* getPathname( ChunkID id );
+
+ void serialize(PxCollection* collection, ChunkID id);
+
+ void addReadyChunkToScene(ChunkID id);
+ void destroyChunk(ChunkID id);
+
+ void updateDynamicChunkId();
+
+ //Return NULL means already loaded or cannot load
+ PxCollection* loadChunk(ChunkID id);
+
+ void createRenderObjectsFromCollection(PxCollection* collection);
+ void deleteLoadedRenderQueue();
+ void deleteCollections();
+
+ void* loaderThread();
+ static void* loaderThread(void* loader);
+
+ DeferredLoadedRenderData* createRawMeshFromObjMesh(const char* name, const PxTransform& pos, DeferredLoadedRenderData& rawMesh);
+
+private:
+
+ struct CollectionMemory
+ {
+ CollectionMemory()
+ : collection(NULL)
+ , memory(NULL)
+ , addToScene(false)
+ {
+
+ }
+
+ PxCollection* collection;
+ void* memory;
+ bool addToScene;
+ };
+
+ typedef std::map<ChunkID, CollectionMemory> CollectionIdMap;
+ CollectionIdMap mCollectionIdMap;
+
+ std::vector<ChunkID> mRequestQueue;
+ std::vector<DynamicObjects*> mDyncActors;
+ std::vector<PxActor*> mRemovingActors;
+
+ //We calculate terrain's normals and store here
+ std::vector<DeferredLoadedRenderData> mLoadedRenderDataQueue;
+
+ physx::shdfnd::Thread* mLoaderThread;
+
+ //The lock to access ChunkQueue arrays
+ physx::shdfnd::Mutex mQueueLock;
+
+ //The lock to access mCollectionIdMap
+ physx::shdfnd::Mutex mCollectionLock;
+
+ //A signal to inform background thread new jobs
+ shdfnd::Sync mRequestReady;
+
+ SampleLargeWorld* mSampleLargeWorld;
+ PxPhysics& mPhysics;
+ PxScene& mScene;
+ PxMaterial& mMaterial;
+
+ ChunkID mCurChunkId;
+ CoordType mHalfRange;
+ CoordType mTerrainRange;
+ PxF32 mChunkWidth;
+
+ //Internal Timing varialbe
+ Ps::Time::Second mDiskIOTimeCounter;
+ Ps::Time::Second mPhyXStreamTimeCounter;
+ Ps::Time::Second mGraphicStreamTimeCounter;
+ PxBounds3 mLocalBounds;
+
+ PxSerializationRegistry* mSr;
+ std::vector<ChunkCommand> mChunkCmds;
+};
+
+#endif
+
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.cpp b/PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.cpp
new file mode 100644
index 00000000..972fb4f9
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.cpp
@@ -0,0 +1,181 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleDirManager.h"
+#include "SampleLargeWorld.h"
+#include "MeshBuilder.h"
+#include "wavefront.h"
+
+using namespace PxToolkit;
+using namespace physx;
+using namespace shdfnd;
+
+#define MATERIAL_ID 1
+
+
+MeshBuilder::MeshBuilder(SampleLargeWorld& sample, const char* filename)
+ : mSampleLargeWorld(&sample)
+ , mPhysics(sample.getPhysics())
+ , mScene(sample.getActiveScene())
+ , mCooking(sample.getCooking())
+ , mMaterial(sample.getDefaultMaterial())
+ , mStringTable(sample.mStringTable)
+{
+ PxDefaultFileInputData inputStream(filename);
+ PxSerializationRegistry* sr = PxSerialization::createSerializationRegistry(mPhysics);
+
+ PxCollection* c = PxSerialization::createCollectionFromXml(inputStream, mCooking, *sr, NULL, mStringTable);
+ PX_ASSERT( c );
+
+ c->add( mMaterial, MATERIAL_ID );
+ PxSerialization::complete(*c, *sr);
+
+ PxU32 count = c->getNbObjects();
+ for(PxU32 i = 0; i < count; i++)
+ {
+ PxBase* object = &c->getObject(i);
+ switch ( object->getConcreteType() )
+ {
+ case PxConcreteType::eCONVEX_MESH:
+ {
+ PxConvexMesh* j = static_cast<PxConvexMesh*>(object);
+ mConvexMeshes.push_back( j );
+ break;
+ }
+ case PxConcreteType::eTRIANGLE_MESH_BVH33:
+ case PxConcreteType::eTRIANGLE_MESH_BVH34:
+ {
+ PxTriangleMesh* j = static_cast<PxTriangleMesh*>(object);
+ mTriMeshes.push_back(j);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ c->release();
+ sr->release();
+}
+
+void MeshBuilder::addObjMeshToPxCollection(
+ PxPhysics& physics,
+ PxCooking& cooking,
+ PxMaterial& material,
+ const char* filename,
+ const char* filenameCooked,
+ const PxTransform& pose,
+ const PxVec3& scale,
+ PxCollection& collection,
+ const char* name)
+{
+ PxTriangleMesh* mesh = NULL;
+
+ PxDefaultFileInputData cooked(filenameCooked);
+ if (cooked.isValid())
+ {
+ //load from disc
+ mesh = physics.createTriangleMesh(cooked); //if this load fails, maybe old format. try to recook below.
+ }
+ if(!mesh)
+ {
+ WavefrontObj wfo;
+ if (!wfo.loadObj(filename, false))
+ {
+ shdfnd::printFormatted("Error loading file: %s\n", filename);
+ }
+
+ PxTriangleMeshDesc meshDesc;
+ meshDesc.points.count = wfo.mVertexCount;
+ meshDesc.triangles.count = wfo.mTriCount;
+ meshDesc.points.stride = sizeof(float) * 3;
+ meshDesc.triangles.stride = sizeof(int) * 3;
+ meshDesc.points.data = wfo.mVertices;
+ meshDesc.triangles.data = wfo.mIndices;
+
+ bool ok;
+ {
+ PxDefaultFileOutputStream stream(filenameCooked);
+ ok = cooking.cookTriangleMesh(meshDesc, stream);
+ }
+ if ( ok )
+ {
+ PxDefaultFileInputData stream(filenameCooked);
+ mesh = physics.createTriangleMesh(stream);
+ }
+ }
+ PX_ASSERT( mesh );
+
+ PxRigidStatic* actor = physics.createRigidStatic(pose);
+ PX_ASSERT( actor );
+ PxMeshScale meshScale = PxMeshScale(scale, PxQuat(PxIdentity));
+ PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(mesh, meshScale), material);
+ PX_ASSERT( shape );
+ shape->setFlag(PxShapeFlag::eVISUALIZATION, false);
+ if( name )
+ {
+ actor->setName(name);
+ }
+
+ collection.add(*actor);
+}
+
+void MeshBuilder::addRepXToPxCollection(
+ const PxTransform& pose,
+ const PxVec3& scale,
+ PxCollection& collection,
+ const char* name)
+{
+
+ PxRigidStatic* actor = mPhysics.createRigidStatic(pose);
+ PX_ASSERT( actor );
+
+ size_t size = mConvexMeshes.size();
+ PxMeshScale meshScale = PxMeshScale(scale, PxQuat(PxIdentity));
+ for(PxU32 i = 0; i < size; ++i)
+ {
+ PxConvexMesh* mesh = mConvexMeshes[i];
+ PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, PxConvexMeshGeometry(mesh, meshScale), mMaterial);
+ PX_ASSERT( shape );
+ shape->setFlag(PxShapeFlag::eVISUALIZATION, false);
+ }
+
+ size = mTriMeshes.size();
+ for(PxU32 i = 0; i < size; ++i)
+ {
+ PxTriangleMesh* mesh = mTriMeshes[i];
+ PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(mesh, meshScale), mMaterial);
+ PX_ASSERT( shape );
+ shape->setFlag(PxShapeFlag::eVISUALIZATION, false);
+ }
+
+ if( name )
+ actor->setName(name);
+
+ collection.add(*actor);
+}
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.h b/PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.h
new file mode 100644
index 00000000..c65864f7
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.h
@@ -0,0 +1,75 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef MESHBUILDER_H
+#define MESHBUILDER_H
+
+#include "PhysXSample.h"
+
+class SampleLargeWorld;
+class MeshBuilder : public SampleAllocateable
+{
+public:
+ MeshBuilder(SampleLargeWorld& sample, const char* filename);
+ ~MeshBuilder() {}
+
+ void addRepXToPxCollection(
+ const PxTransform& pose,
+ const PxVec3& scale,
+ PxCollection& collection,
+ const char* name = NULL);
+
+ static void addObjMeshToPxCollection(
+ PxPhysics& physics,
+ PxCooking& cooking,
+ PxMaterial& material,
+ const char* filename,
+ const char* filenameCooked,
+ const PxTransform& pose,
+ const PxVec3& scale,
+ PxCollection& collection,
+ const char* name = NULL);
+
+private:
+ MeshBuilder& operator=(const MeshBuilder&);
+ SampleLargeWorld* mSampleLargeWorld;
+
+ PxPhysics& mPhysics;
+ PxScene& mScene;
+ PxCooking& mCooking;
+ PxMaterial& mMaterial;
+ PxRigidStatic* mStaticActor;
+ PxStringTable* mStringTable;
+
+ std::vector<PxConvexMesh*> mConvexMeshes;
+ std::vector<PxTriangleMesh*> mTriMeshes;
+};
+
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.cpp b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.cpp
new file mode 100644
index 00000000..22db15c9
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.cpp
@@ -0,0 +1,1039 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "foundation/PxMemory.h"
+#include <PsString.h>
+#include "SampleLargeWorld.h"
+#include "RenderMeshActor.h"
+#include "RenderMaterial.h"
+
+#include <SampleBaseInputEventIds.h>
+#include <SamplePlatform.h>
+#include <SampleUserInput.h>
+#include <SampleUserInputIds.h>
+#include <SampleUserInputDefines.h>
+#include "SampleLargeWorldInputEventIds.h"
+
+using namespace SampleRenderer;
+using namespace SampleFramework;
+
+#include "ChunkLoader.h"
+#include "wavefront.h"
+#include "characterkinematic/PxControllerManager.h"
+#include "SampleCCTActor.h"
+#include "SampleCCTCameraController.h"
+
+#include "extensions/PxDefaultSimulationFilterShader.h"
+
+static const PxF32 gContactOffset = 0.01f;
+static const PxF32 gStepOffset = 0.05f;
+static const PxF32 gSlopeLimit = 0.0f;
+static const PxF32 gInvisibleWallsHeight = 0.0f;
+static const PxF32 gMaxJumpHeight = 0.0f;
+
+static const PxF32 gScaleFactor = 1.5f;
+static const PxF32 gStandingSize = 1.0f * gScaleFactor;
+static const PxF32 gCrouchingSize = 0.25f * gScaleFactor;
+static const PxF32 gControllerRadius = 0.3f * gScaleFactor;
+
+static const PxF32 CAMERA_MAX_SPEED = 120.0f;
+
+const char* gDynamic = "Dynamic";
+
+REGISTER_SAMPLE(SampleLargeWorld, "SampleLargeWorld")
+
+///////////////////////////////////////////////////////////////////////////////
+SampleLargeWorld::SampleLargeWorld(PhysXSampleApplication& app)
+ : PhysXSample(app)
+ , mCCTCamera(NULL)
+ , mActor(NULL)
+ , mControllerManager(NULL)
+ , mDiskIOTime(0)
+ , mPhysxStreaming(0)
+ , mGraphicStreaming(0)
+ , mReadyToSyncCCT(false)
+ , mAddRenderActor(false)
+ , mPick(false)
+ , mKeyShiftDown(false)
+ , mStringTable(NULL)
+{
+ mCreateGroundPlane = false;
+ mControllerInitialPosition = PxExtendedVec3(1035.0f, 49.0f, 989.0f);
+ mLastCCTPosition = mControllerInitialPosition;
+ mDefaultCameraSpeed = mCameraController.getCameraSpeed();
+
+ PxMemZero(mSkybox, sizeof(mSkybox));
+}
+
+SampleLargeWorld::~SampleLargeWorld()
+{
+ DELETESINGLE(mActor);
+ for(ObjMeshMap::Iterator iter = mRenderMeshCache.getIterator(); !iter.done(); ++iter)
+ {
+ RAWMesh& mesh = iter->second;
+
+ PxVec3 *verts = const_cast<PxVec3*>(mesh.mVerts);
+ SAMPLE_FREE(verts);
+ mesh.mVerts = NULL;
+
+ PxVec3 *normals = const_cast<PxVec3*>(mesh.mVertexNormals);
+ SAMPLE_FREE(normals);
+ mesh.mVertexNormals = NULL;
+
+ PxVec3 *colors = const_cast<PxVec3*>(mesh.mVertexColors);
+ SAMPLE_FREE(colors);
+ mesh.mVertexColors = NULL;
+
+ PxReal *uvs = const_cast<PxReal*>(mesh.mUVs);
+ SAMPLE_FREE(uvs);
+ mesh.mUVs = NULL;
+
+ PxU32 *indices = const_cast<PxU32*>(mesh.mIndices);
+ SAMPLE_FREE(indices);
+ mesh.mIndices = NULL;
+ }
+}
+
+void SampleLargeWorld::setCCDActive(PxShape& shape)
+{
+ PxFilterData fd = shape.getSimulationFilterData();
+ fd.word3 |= CCD_FLAG;
+ shape.setSimulationFilterData(fd);
+}
+
+bool SampleLargeWorld::isCCDActive(PxFilterData& filterData)
+{
+ return filterData.word3 & CCD_FLAG ? true : false;
+}
+
+PxFilterFlags SampleLargeWorld::filter( PxFilterObjectAttributes attributes0,
+ PxFilterData filterData0,
+ PxFilterObjectAttributes attributes1,
+ PxFilterData filterData1,
+ PxPairFlags& pairFlags,
+ const void* constantBlock,
+ PxU32 constantBlockSize)
+{
+ PxFilterFlags filterFlags = PxDefaultSimulationFilterShader(attributes0,
+ filterData0, attributes1, filterData1, pairFlags, constantBlock, constantBlockSize);
+
+ if (isCCDActive(filterData0) && isCCDActive(filterData1))
+ {
+ pairFlags |= PxPairFlag::eSOLVE_CONTACT;
+ pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT;
+ }
+
+ return filterFlags;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if PX_INTEL_FAMILY
+static const bool gFlip = false;
+#elif PX_PPC
+static const bool gFlip = true;
+#elif PX_ARM_FAMILY
+static const bool gFlip = false;
+#else
+#error Unknown platform!
+#endif
+
+static PX_INLINE void Flip(PxU32& v)
+{
+ PxU8* b = (PxU8*)&v;
+
+ PxU8 temp = b[0];
+ b[0] = b[3];
+ b[3] = temp;
+ temp = b[1];
+ b[1] = b[2];
+ b[2] = temp;
+}
+
+static PX_INLINE void Flip(PxF32& v)
+{
+ Flip((PxU32&)v);
+}
+
+class PxBinFile: public PxDefaultFileInputData
+{
+public:
+ PxBinFile(const char* name):PxDefaultFileInputData(name){}
+ ~PxBinFile(){}
+
+ PX_FORCE_INLINE PxU32 LoadDword(){ PxU32 t; read(&t, sizeof(PxU32)); if(gFlip) Flip(t); return t;}
+ PX_FORCE_INLINE PxF32 LoadFloat(){ PxF32 t; read(&t, sizeof(PxF32)); if(gFlip) Flip(t); return t;}
+};
+
+void SampleLargeWorld::BinData::serialize( SampleLargeWorld* parent, const char* terrainFile)
+{
+ PxBinFile binFile(terrainFile);
+
+ if( !binFile.isValid())
+ {
+ char errMsg[256];
+ Ps::snprintf(errMsg, 256, "Couldn't load %s\n", terrainFile);
+ parent->fatalError(errMsg);
+
+ return;
+ }
+
+ PxU32 nbMeshes = binFile.LoadDword();
+
+ //Suppose the terrain is N*N
+ mDim = (CoordType)PxSqrt((PxF32)nbMeshes);
+
+ PxU32 totalNbTris = 0;
+ PxU32 totalNbVerts = 0;
+
+ mTerrainVertices.resize( nbMeshes );
+ mTerrainIndices.resize( nbMeshes );
+
+ for(PxU32 i = 0; i < nbMeshes; ++i)
+ {
+ binFile.LoadDword();
+ binFile.LoadDword();
+
+ const PxU32 nbVerts = binFile.LoadDword();
+ const PxU32 nbFaces = binFile.LoadDword();
+
+ totalNbTris += nbFaces;
+ totalNbVerts += nbVerts;
+
+ SampleArray<PxVec3>& vertices = mTerrainVertices[i];
+ vertices.resize(nbVerts);
+
+ for(PxU32 j = 0; j < nbVerts; ++j)
+ {
+ vertices[j].x = binFile.LoadFloat();
+ vertices[j].y = binFile.LoadFloat();
+ vertices[j].z = binFile.LoadFloat();
+ }
+
+ SampleArray<PxU32>& indices = mTerrainIndices[i];
+ indices.resize(nbFaces * 3);
+
+ for(PxU32 j = 0; j < nbFaces * 3; ++j)
+ {
+ indices[j] = binFile.LoadDword();
+ }
+ }
+}
+
+//Hardcoded terrain.bin terrain.
+void SampleLargeWorld::onInit()
+{
+ PhysXSample::onInit();
+ mCameraController.setCameraSpeed( 2.0f );
+
+ mStringTable = &PxStringTableExt::createStringTable( Ps::getAllocator() );
+
+ mApplication.setMouseCursorHiding(true);
+ mApplication.setMouseCursorRecentering(true);
+
+ //Disable collision between differnt groups
+ PxSetGroupCollisionFlag(DEFAULT_COLLISION_GROUP,FAN_COLLISION_GROUP,false);
+ PxSetGroupCollisionFlag(DEFAULT_COLLISION_GROUP,PICKING_COLLISION_GROUP,false);
+ PxSetGroupCollisionFlag(FAN_COLLISION_GROUP,PICKING_COLLISION_GROUP,false);
+
+ mBGLoader = SAMPLE_NEW(BackgroundLoader)(*this, N1, N2-1, CHUNK_WIDTH);
+
+ const char* terrainFile = getSampleMediaFilename("Terrain.bin");
+ binData.serialize(this, terrainFile);
+
+ //Load the skydome.
+ importRAWFile("sky_mission_race1.raw", 2.0f);
+
+ //Load the terrain material
+ {
+ RAWTexture data;
+ data.mName = "grass_diffuse.dds";
+ RenderTexture* grassTexture = createRenderTextureFromRawTexture(data);
+ RenderMaterial* roadGravelMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(),
+ PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_ROAD_GRASS, grassTexture);
+ mRenderMaterials.push_back(roadGravelMaterial);
+ }
+
+ {
+ RAWTexture data;
+ data.mName = "DiffuseMap.bmp";
+ RenderTexture* bricksTexture = createRenderTextureFromRawTexture(data);
+ RenderMaterial* bricksMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(),
+ PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_BUILDING, bricksTexture);
+ mRenderMaterials.push_back(bricksMaterial);
+ }
+ {
+ RAWTexture data;
+ data.mName = "Fencing.tga";
+ RenderTexture* fencingTexture = createRenderTextureFromRawTexture(data);
+ RenderMaterial* fencingMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(),
+ PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_FARM, fencingTexture);
+ mRenderMaterials.push_back(fencingMaterial);
+ }
+ {
+ RAWTexture data;
+ data.mName = "Yellow_0.bmp";
+ RenderTexture* treeTexture = createRenderTextureFromRawTexture(data);
+ RenderMaterial* treeMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(),
+ PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_TREE, treeTexture);
+ mRenderMaterials.push_back(treeMaterial);
+ }
+ //Set up the fog.
+ getRenderer()->setFog(SampleRenderer::RendererColor(40,40,40), 225.0f);
+
+ mControllerManager = PxCreateControllerManager(getActiveScene());
+ mControllerManager->setOverlapRecoveryModule(false);
+
+ ControlledActorDesc desc;
+ desc.mType = PxControllerShapeType::eCAPSULE;
+ desc.mPosition = mControllerInitialPosition;
+ desc.mSlopeLimit = gSlopeLimit;
+ desc.mContactOffset = gContactOffset;
+ desc.mStepOffset = gStepOffset;
+ desc.mInvisibleWallHeight = gInvisibleWallsHeight;
+ desc.mMaxJumpHeight = gMaxJumpHeight;
+ desc.mRadius = gControllerRadius;
+ desc.mHeight = gStandingSize;
+ desc.mCrouchHeight = gCrouchingSize;
+ desc.mReportCallback = this;
+ desc.mBehaviorCallback = this;
+ {
+ mActor = SAMPLE_NEW(ControlledActor)(*this);
+
+ {
+ PxSceneWriteLock scopedLock(*mScene);
+ mActor->init(desc, mControllerManager);
+ }
+
+ mCCTCamera = SAMPLE_NEW(SampleCCTCameraController)(*this);
+ mCCTCamera->setControlled(&mActor, 0, 1);
+ mCCTCamera->setFilterCallback(this);
+ mCCTCamera->setGravity(-20.0f);
+
+ setCameraController(mCCTCamera);
+
+ mCCTCamera->setView(0,0);
+ mCCTCamera->setCameraMaxSpeed( CAMERA_MAX_SPEED );
+ mCCTCamera->enableCCT(false);
+ }
+
+ mWorldBound.minimum = PxVec3(-128.0f,-256.0f, -128.0f);
+ mWorldBound.maximum = PxVec3(-128.0f + 256.0f*N2,256.0f, -128.0f + 256.0f*N2);
+}
+
+void SampleLargeWorld::onShutdown()
+{
+ mCameraController.setCameraSpeed(mDefaultCameraSpeed);
+
+ if(isPaused())
+ {
+ togglePause();
+ }
+
+ mScene->fetchResults(true);
+ DELETESINGLE(mBGLoader);
+
+ {
+ PxSceneWriteLock scopedLock(*mScene);
+
+ if( !mAddRenderActor )
+ {
+ RenderBaseActor* actor = mActor->getRenderActorStanding();
+ DELETESINGLE( actor );
+
+ actor = mActor->getRenderActorCrouching();
+ DELETESINGLE( actor );
+ }
+
+ DELETESINGLE(mCCTCamera);
+ mControllerManager->release();
+
+ releaseJoints();
+ }
+
+ if(mStringTable)
+ {
+ mStringTable->release();
+ mStringTable = NULL;
+ }
+
+ PhysXSample::onShutdown();
+}
+
+void SampleLargeWorld::onTickPreRender(PxF32 dtime)
+{
+ if(!mPause)
+ {
+ mBGLoader->onTick();
+
+ //add render actor here, otherwise it has issues on render
+ if(!mReadyToSyncCCT)
+ {
+ mReadyToSyncCCT = readyToSyncCCT();
+ }
+
+ if( !mAddRenderActor && mReadyToSyncCCT )
+ {
+ RenderBaseActor* actor0 = mActor->getRenderActorStanding();
+ RenderBaseActor* actor1 = mActor->getRenderActorCrouching();
+
+ if(actor0)
+ {
+ mRenderActors.push_back(actor0);
+ }
+
+ if(actor1)
+ {
+ mRenderActors.push_back(actor1);
+ }
+
+ mAddRenderActor = true;
+ }
+
+ if( mReadyToSyncCCT && !mCCTCamera->getCCTState() )
+ {
+ mCCTCamera->enableCCT(true);
+ }
+ }
+
+ for( PxU32 i = 0; i < 2; i++)
+ {
+ if(mSkybox[i])
+ mSkybox[i]->setTransform(PxTransform(getCamera().getPos()));
+ }
+
+ PhysXSample::onTickPreRender(dtime);
+
+ if(mIsFlyCamera)
+ {
+ getDebugRenderer()->addAABB(mWorldBound, RendererColor(0,255,0), RENDER_DEBUG_WIREFRAME);
+ }
+
+#if ENABLE_PROGRESS_BAR
+ mBGLoader->mLoaderStatusLock.lockReader();
+ mProgressBarRatio = mBGLoader->mQueryProgress;
+ mDiskIOTime = mBGLoader->mDiskIOTime;
+ mPhysxStreaming = mBGLoader->mPhyXStreamTime;
+ mGraphicStreaming = mBGLoader->mGraphicStreamTime;
+ mBGLoader->mLoaderStatusLock.unlockReader();
+#endif
+
+ mProgressBarRatio = PxClamp( mProgressBarRatio, 0.0f, 1.0f);
+
+ if(!mPause && mReadyToSyncCCT)
+ {
+ mActor->sync();
+ }
+}
+
+void SampleLargeWorld::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val)
+{
+ if(val)
+ {
+ switch(ie.m_Id)
+ {
+ case RETRY:
+ {
+ PxSceneWriteLock scopedLock(*mScene);
+ mActor->reset();
+ mCCTCamera->setView(0,0);
+ }
+ break;
+
+ case FLY_CAMERA:
+ {
+ toggleFlyCamera();
+ mReadyToSyncCCT = false;
+ mPause = !mPause;
+ if( mPause )
+ {
+ mCCTCamera->enableCCT(false);
+ }
+
+ }
+ break;
+ case THROW_IMPORTANTOBJECT:
+ case THROW_UNIMPORTANCTOBJECT:
+ {
+ const PxVec3 pos = getCamera().getPos();
+ const PxVec3 vel = getCamera().getViewDir() * getDebugObjectsVelocity();
+
+ bool isImportant = ie.m_Id == THROW_IMPORTANTOBJECT;
+
+ PxSceneWriteLock scopedLock(*mScene);
+
+ PxRigidDynamic* actor = createBox(pos, getDebugBoxObjectExtents(), &vel,
+ isImportant ? mManagedMaterials[MATERIAL_RED] : mManagedMaterials[MATERIAL_GREEN], mDefaultDensity);
+
+ actor->setName(gDynamic);
+
+ mBGLoader->addDynamicObject(actor, isImportant);
+ }
+ break;
+
+ case PICK_NEARSETOBJECT:
+ {
+ mPick = !mPick;
+ if(mPick)
+ {
+ attachNearestObjectsToCCT();
+ }
+ else
+ {
+ releaseJoints();
+ }
+ }
+ break;
+ case CAMERA_SHIFT_SPEED:
+ {
+ mKeyShiftDown = true;
+ break;
+ }
+ case CAMERA_SPEED_INCREASE:
+ {
+ PxReal speed = getCurrentCameraController()->getCameraSpeed();
+ if(speed * 2 >= CAMERA_MAX_SPEED)
+ {
+ if(mKeyShiftDown)
+ shdfnd::printFormatted("running speed exceeds the maximum speed\n");
+ else
+ shdfnd::printFormatted("walking speed exceeds the maximum speed\n");
+ return;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if(ie.m_Id == CAMERA_SHIFT_SPEED) mKeyShiftDown = false;
+ }
+
+ PhysXSample::onDigitalInputEvent(ie,val);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+void SampleLargeWorld::customizeSceneDesc(PxSceneDesc& desc)
+{
+ desc.flags |= PxSceneFlag::eENABLE_CCD;
+ desc.flags |= PxSceneFlag::eREQUIRE_RW_LOCK;
+ desc.filterShader = filter;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SampleLargeWorld::customizeSample(SampleSetup& setup)
+{
+ setup.mName = "SampleLargeWorld";
+}
+
+void SampleLargeWorld::onSubstep(PxF32 dtime)
+{
+ PhysXSample::onSubstep(dtime);
+
+ mBGLoader->updateChunk(getCamera().getPos());
+
+ PxExtendedVec3 curCCTPosition = mActor->getController()->getPosition();
+ if(mWorldBound.contains(toVec3(curCCTPosition)))
+ {
+ mLastCCTPosition = curCCTPosition;
+ }
+ else
+ {
+ PxSceneWriteLock scopedLock(*mScene);
+ mActor->getController()->setPosition(mLastCCTPosition);
+ }
+}
+
+void SampleLargeWorld::collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents)
+{
+ PhysXSample::collectInputEvents(inputEvents);
+
+ getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(STEP_ONE_FRAME);
+ getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(PAUSE_SAMPLE);
+ getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(SPAWN_DEBUG_OBJECT);
+ getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_JUMP);
+ getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_CONTROLLER_INCREASE);
+
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_INCREASE, WKEY_ADD, XKEY_ADD, X1KEY_ADD, PS3KEY_ADD, PS4KEY_ADD, AKEY_UNKNOWN, OSXKEY_ADD, IKEY_UNKNOWN, LINUXKEY_ADD, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_DECREASE, WKEY_SUBTRACT, XKEY_SUBTRACT, X1KEY_SUBTRACT, PS3KEY_SUBTRACT, PS4KEY_SUBTRACT, AKEY_UNKNOWN, OSXKEY_SUBTRACT, IKEY_UNKNOWN, LINUXKEY_SUBTRACT, WIIUKEY_UNKNOWN);
+
+ DIGITAL_INPUT_EVENT_DEF(THROW_IMPORTANTOBJECT, WKEY_I, XKEY_I, X1KEY_I, PS3KEY_I, PS4KEY_I, AKEY_UNKNOWN, OSXKEY_I, IKEY_UNKNOWN, LINUXKEY_I, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(THROW_UNIMPORTANCTOBJECT, WKEY_U, XKEY_U, X1KEY_U, PS3KEY_U, PS4KEY_U, AKEY_UNKNOWN, OSXKEY_U, IKEY_UNKNOWN, LINUXKEY_U, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(PICK_NEARSETOBJECT, WKEY_E, XKEY_E, X1KEY_E, PS3KEY_E, PS4KEY_E, AKEY_UNKNOWN, OSXKEY_E, IKEY_UNKNOWN, LINUXKEY_E, WIIUKEY_UNKNOWN);
+
+ DIGITAL_INPUT_EVENT_DEF(FLY_CAMERA, WKEY_M, XKEY_M, X1KEY_M, PS3KEY_M, PS4KEY_M, AKEY_UNKNOWN, OSXKEY_M, IKEY_UNKNOWN, LINUXKEY_M, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(FLY_CAMERA, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_WEST);
+
+ DIGITAL_INPUT_EVENT_DEF(RETRY, WKEY_R, XKEY_R, X1KEY_R, PS3KEY_R, PS4KEY_R, AKEY_UNKNOWN, OSXKEY_R, IKEY_UNKNOWN, LINUXKEY_R, WIIUKEY_UNKNOWN);
+ TOUCH_INPUT_EVENT_DEF(RETRY, "Retry", ABUTTON_1, IBUTTON_1);
+ TOUCH_INPUT_EVENT_DEF(FLY_CAMERA, "Fly Mode", ABUTTON_3, IBUTTON_3);
+
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_INCREASE, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, AKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_TOP, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_TOP);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_SPEED_DECREASE, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, AKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_TOP, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_TOP);
+}
+
+void SampleLargeWorld::helpRender(PxU32 x, PxU32 y, PxU8 textAlpha)
+{
+ Renderer* renderer = getRenderer();
+ const PxU32 yInc = 18;
+ const PxReal scale = 0.5f;
+ const PxReal shadowOffset = 6.0f;
+ const RendererColor textColor(255, 255, 255, textAlpha);
+ const bool isMouseSupported = getApplication().getPlatform()->getSampleUserInput()->mouseSupported();
+ const bool isPadSupported = getApplication().getPlatform()->getSampleUserInput()->gamepadSupported();
+ const char* msg;
+
+ if (isMouseSupported && isPadSupported)
+ renderer->print(x, y += yInc, "Use mouse or right stick to rotate", scale, shadowOffset, textColor);
+ else if (isMouseSupported)
+ renderer->print(x, y += yInc, "Use mouse to rotate", scale, shadowOffset, textColor);
+ else if (isPadSupported)
+ renderer->print(x, y += yInc, "Use right stick to rotate", scale, shadowOffset, textColor);
+ if (isPadSupported)
+ renderer->print(x, y += yInc, "Use left stick to move",scale, shadowOffset, textColor);
+ msg = mApplication.inputMoveInfoMsg("Press "," to move", CAMERA_MOVE_FORWARD,CAMERA_MOVE_BACKWARD, CAMERA_MOVE_LEFT, CAMERA_MOVE_RIGHT);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+ msg = mApplication.inputInfoMsg("Press "," to move fast", CAMERA_SHIFT_SPEED, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
+ msg = mApplication.inputInfoMsg("Press "," to throw an object", SPAWN_DEBUG_OBJECT, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+
+ msg = mApplication.inputInfoMsg("Press "," to toggle fly camera", FLY_CAMERA, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+
+ msg = mApplication.inputInfoMsg("Press "," to increase fly camera speed", CAMERA_SPEED_INCREASE, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+
+ msg = mApplication.inputInfoMsg("Press "," to decrease fly camera speed", CAMERA_SPEED_DECREASE, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+
+ msg = mApplication.inputInfoMsg("Press "," to reset CCT position", RETRY, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+
+ msg = mApplication.inputInfoMsg("Press "," to throw an important object", THROW_IMPORTANTOBJECT, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+
+ msg = mApplication.inputInfoMsg("Press "," to throw an unimportant object", THROW_UNIMPORTANCTOBJECT, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+
+ msg = mApplication.inputInfoMsg("Press "," to pick up the nearest objects maximum=5, or release objects", PICK_NEARSETOBJECT, -1);
+ if(msg)
+ renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor);
+}
+
+void SampleLargeWorld::descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha)
+{
+ bool print=(textAlpha!=0.0f);
+
+ if(print)
+ {
+ Renderer* renderer = getRenderer();
+ const PxU32 yInc = 24;
+ const PxReal scale = 0.5f;
+ const PxReal shadowOffset = 6.0f;
+ const RendererColor textColor(255, 255, 255, textAlpha);
+
+ char line0[256]="This sample demonstrates the PhysX streaming feature. It can load";
+ char line1[256]="and unload parts of map procedurally, treats it as an infinite map.";
+ char line2[256]="We serialize/deserialize files in the background thread, to avoid";
+ char line3[256]="spikes in the framerate when your HD is lagging or something. We add";
+ char line4[256]="one farm, one city, some trees and one fortress for gameplay activity.";
+
+ renderer->print(x, y+=yInc, line0, scale, shadowOffset, textColor);
+ renderer->print(x, y+=yInc, line1, scale, shadowOffset, textColor);
+ renderer->print(x, y+=yInc, line2, scale, shadowOffset, textColor);
+ renderer->print(x, y+=yInc, line3, scale, shadowOffset, textColor);
+ renderer->print(x, y+=yInc, line4, scale, shadowOffset, textColor);
+ }
+}
+
+void SampleLargeWorld::customizeRender()
+{
+ PhysXSample::customizeRender();
+
+ renderProgressBar( mProgressBarRatio, false );
+ Renderer* renderer = getRenderer();
+ if(!renderer) return;
+
+ //ScopedRender renderSection(*renderer);
+ //if(renderSection)
+ {
+ const PxU32 yInc = 18;
+ char textBuf[256];
+
+ Camera& camera = getCamera();
+
+ Ps::snprintf(textBuf, 256, "Disk IO\t\t\t%0.1f ms", mDiskIOTime*1000.0f);
+ renderer->print(10, camera.getScreenHeight() - yInc*6, textBuf);
+
+ Ps::snprintf(textBuf, 256, "PhysX Streaming %0.1f ms", mPhysxStreaming*1000.0f);
+ renderer->print(10, camera.getScreenHeight() - yInc*5, textBuf);
+
+ Ps::snprintf(textBuf, 256, "Graphic Streaming %0.1f ms", mGraphicStreaming*1000.0f);
+ renderer->print(10, camera.getScreenHeight() - yInc*4, textBuf);
+
+ PxVec3 cameraPos = camera.getPos();
+ Ps::snprintf(textBuf, 256, "Position x=%0.1f,z=%0.1f", cameraPos.x, cameraPos.z);
+ renderer->print(camera.getScreenWidth() - 300, 10, textBuf);
+ }
+}
+
+//Sky box should not be culled
+void SampleLargeWorld::newMesh(const RAWMesh& data)
+{
+ static PxU32 submeshCount = 0;
+ if(submeshCount + 1<= (sizeof(mSkybox)/sizeof(mSkybox[0])))
+ {
+ mSkybox[submeshCount] = createRenderMeshFromRawMesh(data);
+ submeshCount++;
+ }
+}
+
+RAWMesh* SampleLargeWorld::createRawMeshFromMeshGeom(const PxTriangleMeshGeometry& mesh, RAWMesh &rawMesh)
+{
+ // Get physics geometry
+ PxTriangleMesh* tm = mesh.triangleMesh;
+
+ const PxU32 nbVerts = tm->getNbVertices();
+ const PxU32 nbTris = tm->getNbTriangles();
+ const void* tris = tm->getTriangles();
+ const bool has16BitTriangleIndices = tm->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES ? true : false;
+ PX_ASSERT(has16BitTriangleIndices);
+
+ PxVec3* verts = (PxVec3*)SAMPLE_ALLOC(sizeof(PxVec3)*nbVerts);
+ PxMemCopy( verts, tm->getVertices(), sizeof(PxVec3)*nbVerts);
+
+ PxReal* normals = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*nbVerts*3);
+ PxU32* indices32 = NULL;
+
+ if(has16BitTriangleIndices)
+ {
+ PxU16* indices16 = (PxU16*)tris;
+ indices32 = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*nbTris*3);
+ for( PxU32 i = 0; i < nbTris; i++)
+ {
+ indices32[i*3+0] = indices16[i*3+0];
+ indices32[i*3+1] = indices16[i*3+1];
+ indices32[i*3+2] = indices16[i*3+2];
+ }
+
+ PxBuildSmoothNormals(nbTris, nbVerts, verts, NULL, indices16, (PxVec3*)normals, true);
+ }
+ else
+ {
+ indices32 = (PxU32*)tris;
+ PxBuildSmoothNormals(nbTris, nbVerts, verts, indices32, NULL, (PxVec3*)normals, true);
+ }
+
+ PxBounds3 bound = mesh.triangleMesh->getLocalBounds();
+
+ PxF32* uv =(PxF32*)SAMPLE_ALLOC(sizeof(PxF32)*nbVerts*2);
+ for(PxU32 i = 0; i < nbVerts; i++)
+ {
+ uv[i*2+0] = (verts[i].x - bound.minimum.x)/(bound.maximum.x - bound.minimum.x);
+ uv[i*2+1] = (verts[i].z - bound.minimum.z)/(bound.maximum.z - bound.minimum.z);
+ }
+
+ rawMesh.mNbVerts = nbVerts;
+ rawMesh.mVerts = verts;
+ rawMesh.mNbFaces = nbTris;
+ rawMesh.mIndices = indices32;
+ rawMesh.mVertexNormals = (PxVec3*)normals;
+ rawMesh.mUVs = uv;
+ rawMesh.mMaterialID = MATERIAL_ROAD_GRASS;
+
+ return &rawMesh;
+}
+
+RAWMesh* SampleLargeWorld::createRAWMeshFromObjMesh( const char* inObjFileName, const PxTransform& inPos, PxU32 inMaterialID, RAWMesh &outRawMesh )
+{
+ const ObjMeshMap::Entry* entry = mRenderMeshCache.find(inObjFileName);
+ if( entry != NULL )
+ {
+ cloneMesh( entry->second, outRawMesh );
+ }
+ else
+ {
+ WavefrontObj wfo;
+ if (!wfo.loadObj(getSampleMediaFilename(inObjFileName), true))
+ return NULL;
+
+ PxU32 nbTris = wfo.mTriCount;
+ PxU32 nbVerts = wfo.mVertexCount;
+
+ PxVec3* verts = (PxVec3*)SAMPLE_ALLOC(sizeof(PxVec3)*nbVerts);
+ PxMemCopy( verts, wfo.mVertices, sizeof(PxVec3)*nbVerts );
+
+ PxU32* indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*nbTris*3);
+ PxMemCopy( indices, wfo.mIndices, sizeof(PxU32)*nbTris*3 );
+
+ PxReal* uvs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*nbVerts*2);
+ PxMemCopy( uvs, wfo.mTexCoords, sizeof(PxReal)*nbVerts*2 );
+
+ PxVec3* normals = (PxVec3*)SAMPLE_ALLOC(sizeof(PxVec3)*nbVerts);
+ PxBuildSmoothNormals(
+ nbTris,
+ nbVerts,
+ verts,
+ indices,
+ NULL,
+ normals,
+ true
+ );
+
+ outRawMesh.mNbVerts = nbVerts;
+ outRawMesh.mVerts = verts;
+ outRawMesh.mNbFaces = nbTris;
+ outRawMesh.mIndices = indices;
+ outRawMesh.mUVs = uvs;
+ outRawMesh.mVertexNormals = normals;
+ outRawMesh.mMaterialID = inMaterialID;
+ outRawMesh.mTransform = inPos;
+
+ RAWMesh cacheMesh;
+ cloneMesh( outRawMesh, cacheMesh );
+ mRenderMeshCache.insert( inObjFileName, cacheMesh );
+ }
+
+ return &outRawMesh;
+}
+
+void SampleLargeWorld::cloneMesh(const RAWMesh& inSrc, RAWMesh& outDst)
+{
+ PxVec3* verts = NULL;
+ PxU32* indices = NULL;
+ PxReal* uvs = NULL;
+ PxVec3* normals = NULL;
+ PxVec3* colors = NULL;
+
+ if( inSrc.mVerts )
+ {
+ verts = (PxVec3*)SAMPLE_ALLOC(sizeof(PxVec3)*inSrc.mNbVerts);
+ PxMemCopy( verts, inSrc.mVerts, sizeof(PxVec3)*inSrc.mNbVerts );
+ }
+
+ if( inSrc.mVertexNormals )
+ {
+ normals = (PxVec3*)SAMPLE_ALLOC(sizeof(PxVec3)*inSrc.mNbVerts);
+ PxMemCopy( normals, inSrc.mVertexNormals, sizeof(PxVec3)*inSrc.mNbVerts );
+ }
+
+ if( inSrc.mVertexColors )
+ {
+ colors = (PxVec3*)SAMPLE_ALLOC(sizeof(PxVec3)*inSrc.mNbVerts);
+ PxMemCopy( colors, inSrc.mVertexColors, sizeof(PxVec3)*inSrc.mNbVerts );
+ }
+
+ if( inSrc.mUVs )
+ {
+ uvs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*inSrc.mNbVerts*2);
+ PxMemCopy( uvs, inSrc.mUVs, sizeof(PxReal)*inSrc.mNbVerts*2 );
+ }
+
+ if( inSrc.mIndices )
+ {
+ indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*inSrc.mNbFaces*3);
+ PxMemCopy( indices, inSrc.mIndices, sizeof(PxU32)*inSrc.mNbFaces*3 );
+ }
+
+ outDst.mName = inSrc.mName;
+ outDst.mTransform = inSrc.mTransform;
+ outDst.mNbVerts = inSrc.mNbVerts;
+ outDst.mNbFaces = inSrc.mNbFaces;
+ outDst.mMaterialID = inSrc.mMaterialID;
+ outDst.mVerts = verts;
+ outDst.mVertexNormals = normals;
+ outDst.mVertexColors = colors;
+ outDst.mUVs = uvs;
+ outDst.mIndices = indices;
+}
+
+void SampleLargeWorld::renderProgressBar( PxF32 ratio, bool needFlush )
+{
+ const RendererColor backColor(0, 255, 39);
+
+ ScreenQuad sq;
+ sq.mX0 = 0.0f;
+ sq.mY0 = 0.8f;
+ sq.mX1 = ratio;
+ sq.mY1 = 0.85f;
+ sq.mLeftUpColor = backColor;
+ sq.mRightUpColor = backColor;
+ sq.mLeftDownColor = backColor;
+ sq.mRightDownColor = backColor;
+ sq.mAlpha = 1.0f;
+
+ if(needFlush)
+ getRenderer()->clearBuffers();
+
+ getRenderer()->drawScreenQuad(sq);
+
+ if(needFlush)
+ getRenderer()->swapBuffers();
+}
+
+void SampleLargeWorld::releaseJoints()
+{
+ PxSceneWriteLock scopedLock(*mScene);
+
+ const size_t nbJoints = mFixedJoints.size();
+
+ PxRigidActor* actor0 = NULL;
+ PxRigidActor* actor1 = NULL;
+
+ for(PxU32 i=0;i<nbJoints;i++)
+ {
+ mFixedJoints[i]->getActors(actor0, actor1);
+ setCollisionGroup( actor1, DEFAULT_COLLISION_GROUP );
+
+ mFixedJoints[i]->release();
+ }
+ mFixedJoints.clear();
+}
+
+bool SampleLargeWorld::readyToSyncCCT()
+{
+ PxSceneReadLock scopedLock(*mScene);
+ PxVec3 pos = toVec3(mActor->getController()->getPosition());
+
+ PxRigidDynamic* actor = mActor->getController()->getActor();
+ PxShape* capsuleShape = getShape( *actor );
+
+ PxCapsuleGeometry capGeom(capsuleShape->getGeometry().capsule());
+
+ PxQueryFilterData objType = PxQueryFilterData(PxQueryFlag::eSTATIC);
+ PxHitFlags hitFlag = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL;
+ PxSweepBuffer hit;
+ return getActiveScene().sweep(capGeom, PxTransform(pos), PxVec3(0.0f, -1.0f,0.0f), 1000.f, hit, hitFlag, objType);
+}
+
+void SampleLargeWorld::attachNearestObjectsToCCT()
+{
+ PxSceneWriteLock scopedLock(*mScene);
+
+ PxRigidDynamic* actor = mActor->getController()->getActor();
+ PxSphereGeometry sg(3.f);
+
+ PxI32 attachNum = 5;
+ PxVec3 footPos = toVec3(mActor->getController()->getFootPosition());
+
+ PxShape* capsuleShape = getShape( *actor );
+
+ const PxCapsuleGeometry& capGeom = capsuleShape->getGeometry().capsule();
+
+ PxF32 boxExtent = getDebugBoxObjectExtents().y + 0.1f;
+
+ PxOverlapHit hitBuffer[5];
+ PxMemZero(&hitBuffer, sizeof(hitBuffer));
+ PxFilterData fd(PICKING_COLLISION_GROUP,0,0,0);
+ PxOverlapBuffer buf(hitBuffer, 5);
+
+ getActiveScene().overlap(sg, PxTransform(footPos), buf, PxQueryFilterData(fd, PxQueryFlag::eDYNAMIC));
+ PxU32 hitNum = buf.getNbAnyHits();
+ if( hitNum == 0 )
+ return;
+
+ attachNum = hitNum == (PxU32)-1 ? attachNum : hitNum;
+
+ PxTransform lastTransform = PxTransform(actor->getGlobalPose().q);
+ PxVec3 hookPos = PxVec3( 0.0f, capGeom.halfHeight + capGeom.radius +boxExtent*2, capGeom.radius*2.0f);
+
+ for( PxI32 i = 0; i < attachNum; ++i)
+ {
+ PxRigidDynamic* attachedActor = hitBuffer[i].actor->is<PxRigidDynamic>();
+ setCollisionGroup( attachedActor, PICKING_COLLISION_GROUP );
+
+ PxFixedJoint *joint = PxFixedJointCreate(getPhysics(), actor,lastTransform, attachedActor, PxTransform(hookPos));
+ joint->setConstraintFlag( PxConstraintFlag::eCOLLISION_ENABLED, false );
+ mFixedJoints.push_back( joint );
+
+ hookPos.y += (boxExtent*1.5f);
+ }
+}
+
+PxRigidDynamic* SampleLargeWorld::createBox(const PxVec3& pos, const PxVec3& dims, const PxVec3* linVel, RenderMaterial* material, PxReal density)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+
+ PxRigidDynamic* box = PxCreateDynamic(*mPhysics, PxTransform(pos), PxBoxGeometry(dims), *mMaterial, density);
+ PX_ASSERT(box);
+
+ box->setActorFlag(PxActorFlag::eVISUALIZATION, true);
+ box->setAngularDamping(0.5f);
+
+ //Enable ccd of dynamic generated box
+ PxShape* boxShape = getShape(*box);
+ setCCDActive(*boxShape);
+
+ boxShape->setQueryFilterData(PxFilterData(PICKING_COLLISION_GROUP,0,0,0));
+
+ getActiveScene().addActor(*box);
+
+ if(linVel)
+ box->setLinearVelocity(*linVel);
+
+ createRenderObjectsFromActor(box, material);
+
+ return box;
+}
+
+void SampleLargeWorld::setCollisionGroup(PxRigidActor* actor, PxU32 group)
+{
+ PxSceneWriteLock scopedLock(*mScene);
+
+ PxU32 nbShapes = actor->getNbShapes();
+ if( nbShapes )
+ {
+ SampleArray<PxShape*> shapes(nbShapes);
+ actor->getShapes( &shapes[0], nbShapes);
+ for( PxU32 j = 0; j < nbShapes; j++)
+ {
+ PxFilterData fd = shapes[j]->getSimulationFilterData();
+ fd.word0 = group;
+ shapes[j]->setSimulationFilterData(fd);
+ }
+ }
+}
+///////////////////////////////////////////////////////////////////////////////
+
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.h b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.h
new file mode 100644
index 00000000..e7ab1a97
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.h
@@ -0,0 +1,203 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef SAMPLE_LARGE_WORLD_H
+#define SAMPLE_LARGE_WORLD_H
+
+#include "PhysXSample.h"
+#include "ChunkLoader.h"
+#include "characterkinematic/PxController.h"
+#include "characterkinematic/PxControllerBehavior.h"
+#include "PxTkRandom.h"
+
+
+namespace physx
+{
+ class PxControllerManager;
+}
+
+class SampleCCTCameraController;
+class ControlledActor;
+class RenderBaseActor;
+class BackgroundLoader;
+
+typedef Ps::HashMap<const char*, RAWMesh, Ps::Hash<const char*>, Ps::RawAllocator> ObjMeshMap;
+
+class SampleLargeWorld : public PhysXSample
+ , public PxUserControllerHitReport, public PxControllerBehaviorCallback, public PxQueryFilterCallback
+{
+ friend class BackgroundLoader;
+public:
+ SampleLargeWorld(PhysXSampleApplication& app);
+ virtual ~SampleLargeWorld();
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements SampleApplication
+ virtual void onInit();
+ virtual void onInit(bool restart) { onInit(); }
+ virtual void onShutdown();
+ virtual void onTickPreRender(PxF32 dtime);
+ virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val);
+
+ //virtual void onRelease(const PxBase* , void* , PxDeletionEventFlag::Enum ) {}
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements PhysXSampleApplication
+ virtual void customizeSceneDesc(PxSceneDesc&);
+ virtual void customizeSample(SampleSetup&);
+ virtual void onSubstep(PxF32 dtime);
+ virtual void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents);
+ virtual void helpRender(PxU32 x, PxU32 y, PxU8 textAlpha);
+ virtual void descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha);
+ virtual void customizeRender();
+ virtual void newMesh(const RAWMesh&);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements PxUserControllerHitReport
+ virtual void onShapeHit(const PxControllerShapeHit& hit);
+ virtual void onControllerHit(const PxControllersHit& hit) {}
+ virtual void onObstacleHit(const PxControllerObstacleHit& hit) {}
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements PxControllerBehaviorCallback
+ virtual PxControllerBehaviorFlags getBehaviorFlags(const PxShape& shape, const PxActor& actor);
+ virtual PxControllerBehaviorFlags getBehaviorFlags(const PxController& controller);
+ virtual PxControllerBehaviorFlags getBehaviorFlags(const PxObstacle& obstacle);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements PxQueryFilterCallback
+ virtual PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags);
+ virtual PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements PxSimulationFilterShader
+ enum
+ {
+ CCD_FLAG = 1<<29,
+ };
+
+ static PxFilterFlags filter(PxFilterObjectAttributes attributes0,
+ PxFilterData filterData0,
+ PxFilterObjectAttributes attributes1,
+ PxFilterData filterData1,
+ PxPairFlags& pairFlags,
+ const void* constantBlock,
+ PxU32 constantBlockSize);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ //Create chunk_i_j file
+ void createChunk(CoordType coordX, CoordType coordY, PxCollection& outCollection);
+
+
+private:
+ RAWMesh* createRawMeshFromMeshGeom(const PxTriangleMeshGeometry& mesh, RAWMesh &rawMesh);
+ RAWMesh* createRAWMeshFromObjMesh(const char* inObjFileName, const PxTransform& inPos, PxU32 inMaterialID, RAWMesh &outRawMesh);
+
+ //Deep cope
+ void cloneMesh(const RAWMesh& inSrc, RAWMesh& outDst);
+
+ void renderProgressBar(PxF32 ratio, bool needFlush = false);
+ void releaseJoints();
+ bool readyToSyncCCT();
+ void attachNearestObjectsToCCT();
+
+ PxRigidDynamic* createBox(const PxVec3& pos, const PxVec3& dims, const PxVec3* linVel,
+ RenderMaterial* material, PxReal density);
+ void addWindMills(const PxTriangleMeshGeometry& meshGeom, PxToolkit::BasicRandom& random,
+ const PxBounds3& bound, PxCollection& outCollection);
+ void addTrees(const PxTriangleMeshGeometry& meshGeom, const PxBounds3& bound, PxCollection& outCollection);
+ void addCity(SampleArray<PxVec3>& terrainVertices, const PxBounds3& bound, PxCollection& outCollection);
+ void addFarm(SampleArray<PxVec3>& terrainVertices, const PxBounds3& bound, PxCollection& outCollection);
+ void addFortress(SampleArray<PxVec3>& terrainVertices, const PxBounds3& bound, PxCollection& outCollection);
+
+ static void setCCDActive(PxShape& shape);
+ static bool isCCDActive(PxFilterData& filterData);
+
+ PxTriangleMesh* generateTriMesh(const SampleArray<PxVec3>* vertices, const SampleArray<PxU32>* indices);
+
+ void setCollisionGroup(PxRigidActor* actor, PxU32 group);
+
+ //Terrain template data from Terrain.bin
+ struct BinData
+ {
+ SampleArray<SampleArray<PxVec3> > mTerrainVertices;
+ SampleArray<SampleArray<PxU32> > mTerrainIndices;
+
+ CoordType mDim;
+
+ //Need parent to render progress bar
+ void serialize(SampleLargeWorld* parent, const char* terrainFile);
+
+ }binData;
+
+ ObjMeshMap mRenderMeshCache;
+
+ BackgroundLoader* mBGLoader;
+ SampleCCTCameraController* mCCTCamera;
+ ControlledActor* mActor;
+ PxControllerManager* mControllerManager;
+ PxExtendedVec3 mControllerInitialPosition;
+ PxExtendedVec3 mLastCCTPosition;
+ std::vector<PxFixedJoint*> mFixedJoints;
+
+ //Sky box
+ RenderBaseActor* mSkybox[5];
+
+ //For progress bar renderering
+ PxReal mProgressBarRatio;
+ Ps::Time::Second mDiskIOTime;
+ Ps::Time::Second mPhysxStreaming;
+ Ps::Time::Second mGraphicStreaming;
+
+ //Bound of the whole world
+ PxBounds3 mWorldBound;
+
+ bool mReadyToSyncCCT;
+ bool mAddRenderActor;
+ bool mPick;
+ bool mKeyShiftDown;
+
+ PxReal mDefaultCameraSpeed;
+
+public:
+ static const PxU32 DEFAULT_COLLISION_GROUP = 0;
+ static const PxU32 FAN_COLLISION_GROUP = 1;
+ static const PxU32 PICKING_COLLISION_GROUP = 2;
+
+ PxStringTable* mStringTable;
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldCCT.cpp b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldCCT.cpp
new file mode 100644
index 00000000..4ab2a22e
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldCCT.cpp
@@ -0,0 +1,70 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleLargeWorld.h"
+
+#include "KinematicPlatform.h"
+#include "SampleCCTActor.h"
+#include "SampleCCTCameraController.h"
+extern const char* gDynamic;
+
+void SampleLargeWorld::onShapeHit(const PxControllerShapeHit& hit)
+{
+ defaultCCTInteraction(hit);
+}
+
+PxControllerBehaviorFlags SampleLargeWorld::getBehaviorFlags(const PxShape& shape, const PxActor& actor)
+{
+ return PxControllerBehaviorFlags(0);
+}
+
+PxControllerBehaviorFlags SampleLargeWorld::getBehaviorFlags(const PxController&)
+{
+ return PxControllerBehaviorFlags(0);
+}
+
+PxControllerBehaviorFlags SampleLargeWorld::getBehaviorFlags(const PxObstacle&)
+{
+ return PxControllerBehaviorFlag::eCCT_CAN_RIDE_ON_OBJECT|PxControllerBehaviorFlag::eCCT_SLIDE;
+}
+
+PxQueryHitType::Enum SampleLargeWorld::preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags)
+{
+ PX_UNUSED(actor);
+ const char* actorName = shape->getActor()->getName();
+ if(actorName==gDynamic)
+ return PxQueryHitType::eNONE;
+
+ return PxQueryHitType::eBLOCK;
+}
+
+PxQueryHitType::Enum SampleLargeWorld::postFilter(const PxFilterData& filterData, const PxQueryHit& hit)
+{
+ return PxQueryHitType::eBLOCK;
+} \ No newline at end of file
diff --git a/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldInputEventIds.h b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldInputEventIds.h
new file mode 100644
index 00000000..bac0a952
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldInputEventIds.h
@@ -0,0 +1,45 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+#ifndef _SAMPLE_LARGE_WORLD_INPUT_EVENT_IDS_H
+#define _SAMPLE_LARGE_WORLD_INPUT_EVENT_IDS_H
+
+#include <SampleBaseInputEventIds.h>
+
+// InputEvents used by SampleCharacterController
+enum SampleLargeWorldInputEventIds
+{
+ SAMPLE_LARGE_WORLD_FIRST = NUM_SAMPLE_BASE_INPUT_EVENT_IDS,
+
+ RETRY,
+ THROW_IMPORTANTOBJECT,
+ THROW_UNIMPORTANCTOBJECT,
+ PICK_NEARSETOBJECT,
+ FLY_CAMERA,
+ NUM_SAMPLE_LARGE_WORLD_INPUT_EVENT_IDS,
+};
+
+#endif