diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleLargeWorld | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Samples/SampleLargeWorld')
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.cpp | 1232 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/ChunkLoader.h | 242 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.cpp | 181 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/MeshBuilder.h | 75 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.cpp | 1039 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorld.h | 203 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldCCT.cpp | 70 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleLargeWorld/SampleLargeWorldInputEventIds.h | 45 |
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 |