diff options
Diffstat (limited to 'APEX_1.4/module/pxparticleios/src/ParticleIosActorImpl.cpp')
| -rw-r--r-- | APEX_1.4/module/pxparticleios/src/ParticleIosActorImpl.cpp | 818 |
1 files changed, 818 insertions, 0 deletions
diff --git a/APEX_1.4/module/pxparticleios/src/ParticleIosActorImpl.cpp b/APEX_1.4/module/pxparticleios/src/ParticleIosActorImpl.cpp new file mode 100644 index 00000000..0274520a --- /dev/null +++ b/APEX_1.4/module/pxparticleios/src/ParticleIosActorImpl.cpp @@ -0,0 +1,818 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "ApexDefs.h" +#include "Apex.h" +#include "SceneIntl.h" +#include "ApexSDKIntl.h" +#include "ParticleIosActor.h" +#include "ParticleIosActorImpl.h" +#include "ParticleIosAssetImpl.h" + +#include "iofx/IofxAsset.h" +#include "iofx/IofxActor.h" + +#include "ModuleParticleIosImpl.h" +#include "ParticleIosScene.h" +#include "RenderDebugInterface.h" +#include "AuthorableObjectIntl.h" +#include "ModuleIofxIntl.h" +#include "FieldSamplerManagerIntl.h" +#include "FieldSamplerQueryIntl.h" +#include "FieldSamplerSceneIntl.h" +#include "ApexResourceHelper.h" +#include "ApexMirroredArray.h" + +#include <PxPhysics.h> +#include <PsAsciiConversion.h> +#include "ReadCheck.h" +#include "WriteCheck.h" + +#include "PsMathUtils.h" + +namespace nvidia +{ +namespace pxparticleios +{ + +using namespace physx; + +void ParticleIosActorImpl::initStorageGroups(InplaceStorage& storage) +{ + mSimulationStorageGroup.init(storage); +} + +#pragma warning(disable: 4355) // 'this' : used in base member initializer list + +ParticleIosActorImpl::ParticleIosActorImpl( + ResourceList& list, + ParticleIosAssetImpl& asset, + ParticleIosScene& scene, + IofxAsset& iofxAsset, + bool isDataOnDevice) + : mAsset(&asset) + , mParticleIosScene(&scene) + , mIsParticleSystem(false) + , mParticleActor(NULL) + , mIofxMgr(NULL) + , mTotalElapsedTime(0.0f) + , mParticleCount(0) + , mParticleBudget(0) + , mInjectedCount(0) + , mLastActiveCount(0) + , mLastBenefitSum(0) + , mLastBenefitMin(+FLT_MAX) + , mLastBenefitMax(-FLT_MAX) + , mLifeSpan(scene.getApexScene(), PX_ALLOC_INFO("mLifeSpan", PARTICLES)) + , mLifeTime(scene.getApexScene(), PX_ALLOC_INFO("mLifeTime", PARTICLES)) + , mInjector(scene.getApexScene(), PX_ALLOC_INFO("mInjector", PARTICLES)) + , mBenefit(scene.getApexScene(), PX_ALLOC_INFO("mBenefit", PARTICLES)) + , mInjectorsCounters(scene.getApexScene(), PX_ALLOC_INFO("mInjectorsCounters", PARTICLES)) + , mInputIdToParticleIndex(scene.getApexScene(), PX_ALLOC_INFO("mInputIdToParticleIndex", PARTICLES)) + , mGridDensityGrid(scene.getApexScene(), PX_ALLOC_INFO("mGridDensityGrid", PARTICLES)) + , mGridDensityGridLowPass(scene.getApexScene(), PX_ALLOC_INFO("mGridDensityGridLowPass", PARTICLES)) + , mFieldSamplerQuery(NULL) + , mField(scene.getApexScene(), PX_ALLOC_INFO("mField", PARTICLES)) + , mInjectTask(*this) + , mDensityOrigin(0.f,0.f,0.f) + , mOnStartCallback(NULL) + , mOnFinishCallback(NULL) +{ + list.add(*this); + + if (mAsset->getParticleDesc()->Enable == false) + { + APEX_DEBUG_WARNING("ParticleIos Asset '%s' has Enable=false, particle simulation is disabled.", mAsset->getName()); + } + + mMaxParticleCount = mAsset->mParams->maxParticleCount; + float maxInjectCount = mAsset->mParams->maxInjectedParticleCount; + mMaxTotalParticleCount = mMaxParticleCount + uint32_t(maxInjectCount <= 1.0f ? mMaxParticleCount * maxInjectCount : maxInjectCount); + + IofxManagerDescIntl desc; + desc.iosAssetName = mAsset->getName(); + desc.iosSupportsDensity = mAsset->getSupportsDensity(); + desc.iosSupportsCollision = true; + desc.iosSupportsUserData = true; + desc.iosOutputsOnDevice = isDataOnDevice; + desc.maxObjectCount = mMaxParticleCount; + desc.maxInputCount = mMaxTotalParticleCount; + desc.maxInStateCount = mMaxTotalParticleCount; + + ModuleIofxIntl* moduleIofx = mAsset->mModule->getInternalModuleIofx(); + if (moduleIofx) + { + mIofxMgr = moduleIofx->createActorManager(*mParticleIosScene->mApexScene, iofxAsset, desc); + mIofxMgr->createSimulationBuffers(mBufDesc); + + for (uint32_t i = 0 ; i < mMaxParticleCount ; i++) + { + mBufDesc.pmaInStateToInput->get(i) = IosBufferDescIntl::NOT_A_PARTICLE; + } + } + + FieldSamplerManagerIntl* fieldSamplerManager = mParticleIosScene->getInternalFieldSamplerManager(); + if (fieldSamplerManager) + { + FieldSamplerQueryDescIntl queryDesc; + queryDesc.maxCount = mMaxParticleCount; + queryDesc.samplerFilterData = ApexResourceHelper::resolveCollisionGroup128(mAsset->mParams->fieldSamplerFilterData); + + mFieldSamplerQuery = fieldSamplerManager->createFieldSamplerQuery(queryDesc); + } + + addSelfToContext(*scene.mApexScene->getApexContext()); // add self to Scene + addSelfToContext(*DYNAMIC_CAST(ApexContext*)(&scene)); // add self to ParticleIosScene + + // Pull Grid Density Parameters + { + if(mIsParticleSystem && mBufDesc.pmaDensity) + { + ParticleIosAssetParam* params = (ParticleIosAssetParam*)(mAsset->getAssetNvParameterized()); + const SimpleParticleSystemParams* gridParams = static_cast<SimpleParticleSystemParams*>(params->particleType); + mGridDensityParams.Enabled = gridParams->GridDensity.Enabled; + mGridDensityParams.GridSize = gridParams->GridDensity.GridSize; + mGridDensityParams.GridMaxCellCount = gridParams->GridDensity.MaxCellCount; + mGridDensityParams.GridResolution = general_string_parsing2::PxAsc::strToU32(&gridParams->GridDensity.Resolution[4],NULL); + mGridDensityParams.DensityOrigin = mDensityOrigin; + } + else + { + mGridDensityParams.Enabled = false; + mGridDensityParams.GridSize = 1.f; + mGridDensityParams.GridMaxCellCount = 1u; + mGridDensityParams.GridResolution = 8; + mGridDensityParams.DensityOrigin = mDensityOrigin; + } + } +} + +ParticleIosActorImpl::~ParticleIosActorImpl() +{ +} + +void ParticleIosActorImpl::release() +{ + if (mInRelease) + { + return; + } + mInRelease = true; + mAsset->releaseIosActor(*this); +} + +void ParticleIosActorImpl::destroy() +{ + ApexActor::destroy(); + + setPhysXScene(NULL); + + // remove ourself from our asset's resource list, in case releasing our emitters + // causes our asset's resource count to reach zero and for it to be released. + ApexResource::removeSelf(); + + // Release all injectors, releasing all emitters and their IOFX asset references + while (mInjectorList.getSize()) + { + ParticleParticleInjector* inj = DYNAMIC_CAST(ParticleParticleInjector*)(mInjectorList.getResource(mInjectorList.getSize() - 1)); + inj->release(); + } + + if (mIofxMgr) + { + mIofxMgr->release(); + } + if (mFieldSamplerQuery) + { + mFieldSamplerQuery->release(); + } + + delete this; +} + +void ParticleIosActorImpl::setPhysXScene(PxScene* scene) +{ + if (scene) + { + putInScene(scene); + } + else + { + removeFromScene(); + } +} + +PxScene* ParticleIosActorImpl::getPhysXScene() const +{ + if (mParticleActor) + { + return mParticleActor->getScene(); + } + else + { + return NULL; + } +} + +void ParticleIosActorImpl::putInScene(PxScene* scene) +{ + SCOPED_PHYSX_LOCK_WRITE(scene); + mUp = scene->getGravity(); + + // apply asset's scene gravity scale and external acceleration + // mUp *= mAsset->getSceneGravityScale(); + // mUp += mAsset->getExternalAcceleration(); + + mGravity = mUp.magnitude(); + if (!PxIsFinite(mGravity)) + { + // and they could set both to 0,0,0 + mUp = PxVec3(0.0f, -1.0f, 0.0f); + mGravity = 1.0f; + } + mUp *= -1.0f; + + const ParticleIosAssetParam* desc = mAsset->getParticleDesc(); + + if (!isParticleDescValid(desc)) + { + PX_ASSERT(0); + return; + } + + uint32_t maxParticles = mMaxParticleCount; + PxParticleBase* particle = NULL; + PxParticleFluid* fluid = NULL; + + ApexSimpleString className(mAsset->getParticleTypeClassName()); + if (className == SimpleParticleSystemParams::staticClassName()) + { + mIsParticleSystem = true; + particle = scene->getPhysics().createParticleSystem(maxParticles, desc->PerParticleRestOffset); + } + else + { + mIsParticleSystem = false; + fluid = scene->getPhysics().createParticleFluid(maxParticles, desc->PerParticleRestOffset); + particle = fluid; + } + + if (particle) + { + particle->setMaxMotionDistance(desc->maxMotionDistance); + particle->setContactOffset(desc->contactOffset); + particle->setRestOffset(desc->restOffset); + particle->setGridSize(desc->gridSize); + particle->setDamping(desc->damping); + particle->setExternalAcceleration(desc->externalAcceleration); + particle->setProjectionPlane(desc->projectionPlaneNormal, desc->projectionPlaneDistance); + particle->setParticleMass(desc->particleMass); + particle->setRestitution(desc->restitution); + particle->setDynamicFriction(desc->dynamicFriction); + particle->setStaticFriction(desc->staticFriction); + if (desc->fieldSamplerFilterData && desc->fieldSamplerFilterData[0]) + { + ResourceProviderIntl* nrp = mAsset->mModule->mSdk->getInternalResourceProvider(); + + ResID cgmns = mAsset->mModule->mSdk->getCollisionGroup128NameSpace(); + ResID cgmresid = nrp->createResource(cgmns, desc->fieldSamplerFilterData); + void* tmpCGM = nrp->getResource(cgmresid); + if (tmpCGM) + { + particle->setSimulationFilterData(*(static_cast<PxFilterData*>(tmpCGM))); + } + //nrp->releaseResource( cgresid ); + } + particle->setParticleBaseFlag(PxParticleBaseFlag::eCOLLISION_TWOWAY, desc->CollisionTwoway); + particle->setParticleBaseFlag(PxParticleBaseFlag::eCOLLISION_WITH_DYNAMIC_ACTORS, desc->CollisionWithDynamicActors); + particle->setParticleBaseFlag(PxParticleBaseFlag::eENABLED, desc->Enable); + particle->setParticleBaseFlag(PxParticleBaseFlag::ePROJECT_TO_PLANE, desc->ProjectToPlane); + // PxParticleBaseFlag::ePER_PARTICLE_REST_OFFSET is set in create() function + particle->setParticleBaseFlag(PxParticleBaseFlag::ePER_PARTICLE_COLLISION_CACHE_HINT, desc->PerParticleCollisionCacheHint); + // set hardware flag only if hardware is available + particle->setParticleBaseFlag(PxParticleBaseFlag::eGPU, NULL != scene->getTaskManager()->getGpuDispatcher()); + + particle->setParticleReadDataFlag(PxParticleReadDataFlag::ePOSITION_BUFFER, true); + particle->setParticleReadDataFlag(PxParticleReadDataFlag::eVELOCITY_BUFFER, true); + particle->setParticleReadDataFlag(PxParticleReadDataFlag::eREST_OFFSET_BUFFER, desc->PerParticleRestOffset); + particle->setParticleReadDataFlag(PxParticleReadDataFlag::eFLAGS_BUFFER, true); + particle->setParticleReadDataFlag(PxParticleReadDataFlag::eCOLLISION_NORMAL_BUFFER, true); + if (fluid) + { + particle->setParticleReadDataFlag(PxParticleReadDataFlag::eDENSITY_BUFFER, desc->DensityBuffer); + + const FluidParticleSystemParams* fluidDesc = (FluidParticleSystemParams*)desc->particleType; + fluid->setRestParticleDistance(fluidDesc->restParticleDistance); + fluid->setStiffness(fluidDesc->stiffness); + fluid->setViscosity(fluidDesc->viscosity); + } + } + mParticleActor = particle; + + PX_ASSERT(mParticleActor); + + scene->addActor(*mParticleActor); + if (mParticleIosScene->getInternalFieldSamplerManager()) + { + mParticleIosScene->getInternalFieldSamplerManager()->registerUnhandledParticleSystem(mParticleActor); + } + PX_ASSERT(mParticleActor->getScene()); + + mIofxMgr->setSimulationParameters(desc->restOffset, mUp, mGravity, 1 / desc->restOffset); +} + +void ParticleIosActorImpl::removeFromScene() +{ + if (mParticleActor) + { + if (mParticleIosScene->getInternalFieldSamplerManager()) + { + mParticleIosScene->getInternalFieldSamplerManager()->unregisterUnhandledParticleSystem(mParticleActor); + } + SCOPED_PHYSX_LOCK_WRITE(mParticleActor->getScene()); + mParticleActor->getScene()->removeActor(*mParticleActor); + mParticleActor->release(); + } + mParticleActor = NULL; + mParticleCount = 0; +} + + + +void ParticleIosActorImpl::getLodRange(float& min, float& max, bool& intOnly) const +{ + READ_ZONE(); + PX_UNUSED(min); + PX_UNUSED(max); + PX_UNUSED(intOnly); + APEX_INVALID_OPERATION("not implemented"); +} + + +float ParticleIosActorImpl::getActiveLod() const +{ + READ_ZONE(); + APEX_INVALID_OPERATION("ParticleIosActor does not support this operation"); + return -1.0f; +} + + +void ParticleIosActorImpl::forceLod(float lod) +{ + WRITE_ZONE(); + PX_UNUSED(lod); + APEX_INVALID_OPERATION("not implemented"); +} + + + +const PxVec3* ParticleIosActorImpl::getRecentPositions(uint32_t& count, uint32_t& stride) const +{ + count = mParticleCount; + stride = sizeof(PxVec4); + return (const PxVec3*) mBufDesc.pmaPositionMass->getPtr(); +} + +IosInjectorIntl* ParticleIosActorImpl::allocateInjector(IofxAsset* iofxAsset) +{ + ParticleParticleInjector* inj = 0; + //createInjector + { + uint32_t injectorID = mParticleIosScene->getInjectorAllocator().allocateInjectorID(); + if (injectorID != ParticleIosInjectorAllocator::NULL_INJECTOR_INDEX) + { + inj = PX_NEW(ParticleParticleInjector)(mInjectorList, *this, injectorID); + } + } + if (inj == 0) + { + APEX_INTERNAL_ERROR("Failed to create new ParticleIos injector."); + return NULL; + } + + inj->init(iofxAsset); + return inj; +} + +void ParticleIosActorImpl::releaseInjector(IosInjectorIntl& injector) +{ + ParticleParticleInjector* inj = DYNAMIC_CAST(ParticleParticleInjector*)(&injector); + //destroyInjector + { + //set mLODBias to FLT_MAX to mark released injector + //all particles from released injectors will be removed in simulation + Px3InjectorParams injParams; + mParticleIosScene->fetchInjectorParams(inj->mInjectorID, injParams); + injParams.mLODBias = FLT_MAX; + mParticleIosScene->updateInjectorParams(inj->mInjectorID, injParams); + + mParticleIosScene->getInjectorAllocator().releaseInjectorID(inj->mInjectorID); + inj->destroy(); + } + + if(mInjectorList.getSize() == 0) + { + //if we have no injectors - release self + release(); + } +} + +void ParticleIosActorImpl::visualize() +{ +#ifndef WITHOUT_DEBUG_VISUALIZE + if ( !mEnableDebugVisualization ) return; + RenderDebugInterface* renderer = mParticleIosScene->mRenderDebug; + const physx::PxMat44& savedPose = *RENDER_DEBUG_IFACE(renderer)->getPoseTyped(); + RENDER_DEBUG_IFACE(renderer)->setIdentityPose(); + if(mParticleIosScene->mParticleIosDebugRenderParams->VISUALIZE_PARTICLE_IOS_GRID_DENSITY) + { + if(mGridDensityParams.Enabled) + { + RENDER_DEBUG_IFACE(renderer)->setCurrentColor(0x0000ff); + uint32_t onScreenRes = mGridDensityParams.GridResolution - 4; + for (uint32_t i = 0 ; i <= onScreenRes; i++) + { + float u = 2.f*((float)i/(onScreenRes))-1.f; + PxVec4 a = mDensityDebugMatInv.transform(PxVec4(u,-1.f,0.1f,1.f)); + PxVec4 b = mDensityDebugMatInv.transform(PxVec4(u, 1.f,0.1f,1.f)); + PxVec4 c = mDensityDebugMatInv.transform(PxVec4(-1.f,u,0.1f,1.f)); + PxVec4 d = mDensityDebugMatInv.transform(PxVec4( 1.f,u,0.1f,1.f)); + RENDER_DEBUG_IFACE(renderer)->debugLine(PxVec3(a.getXYZ()/a.w),PxVec3(b.getXYZ()/b.w)); + RENDER_DEBUG_IFACE(renderer)->debugLine(PxVec3(c.getXYZ()/c.w),PxVec3(d.getXYZ()/d.w)); + } + } + } + RENDER_DEBUG_IFACE(renderer)->setPose(savedPose); +#endif +} + + +PxTaskID ParticleIosActorImpl::submitTasks(PxTaskManager* tm) +{ + return tm->submitUnnamedTask(mInjectTask); +} + +void ParticleIosActorImpl::setTaskDependencies(PxTaskID taskStartAfterID, PxTaskID taskFinishBeforeID, PxTask* iosTask, bool isDataOnDevice) +{ + PxTaskManager* tm = mParticleIosScene->getApexScene().getTaskManager(); + + PxTaskID simTaskID = tm->getNamedTask(AST_PHYSX_SIMULATE); + mInjectTask.finishBefore(simTaskID); + if (iosTask == 0) + { + return; + } + iosTask->startAfter(mInjectTask.getTaskID()); + + if (taskStartAfterID != (PxTaskID)0xFFFFFFFF) + { + iosTask->startAfter(taskStartAfterID); + } + if (taskFinishBeforeID != (PxTaskID)0xFFFFFFFF) + { + iosTask->finishBefore(taskFinishBeforeID); + } + + if (mFieldSamplerQuery != NULL) + { + float deltaTime = mParticleIosScene->getApexScene().getPhysXSimulateTime(); + + FieldSamplerQueryDataIntl queryData; + queryData.timeStep = deltaTime; + queryData.count = mParticleCount; + queryData.isDataOnDevice = isDataOnDevice; + queryData.positionStrideBytes = sizeof(PxVec4); + queryData.velocityStrideBytes = sizeof(PxVec4); + queryData.massStrideBytes = sizeof(PxVec4); + queryData.pmaInIndices = 0; + if (isDataOnDevice) + { +#if APEX_CUDA_SUPPORT + queryData.pmaInPosition = (float*)mBufDesc.pmaPositionMass->getGpuPtr(); + queryData.pmaInVelocity = (float*)mBufDesc.pmaVelocityLife->getGpuPtr(); + queryData.pmaInMass = &mBufDesc.pmaPositionMass->getGpuPtr()->w; + queryData.pmaOutField = mField.getGpuPtr(); +#endif + } + else + { + queryData.pmaInPosition = (float*)mBufDesc.pmaPositionMass->getPtr(); + queryData.pmaInVelocity = (float*)mBufDesc.pmaVelocityLife->getPtr(); + queryData.pmaInMass = &mBufDesc.pmaPositionMass->getPtr()->w; + queryData.pmaOutField = mField.getPtr(); + } + + mFieldSamplerQuery->submitFieldSamplerQuery(queryData, iosTask->getTaskID()); + } + + const PxTaskID postIofxTaskID = tm->getNamedTask(AST_PHYSX_FETCH_RESULTS); + PxTaskID iofxTaskID = mIofxMgr->getUpdateEffectsTaskID(postIofxTaskID); + if (iofxTaskID == (PxTaskID)0xFFFFFFFF) + { + iofxTaskID = postIofxTaskID; + } + iosTask->finishBefore(iofxTaskID); +} + +void ParticleIosActorImpl::fetchResults() +{ + for(uint32_t i = 0; i < mInjectorList.getSize(); ++i) + { + ParticleParticleInjector* inj = DYNAMIC_CAST(ParticleParticleInjector*)(mInjectorList.getResource(i)); + inj->assignSimParticlesCount(mInjectorsCounters.get(i)); + } +} + +void ParticleIosActorImpl::injectNewParticles() +{ + mInjectedBenefitSum = 0; + mInjectedBenefitMin = +FLT_MAX; + mInjectedBenefitMax = -FLT_MAX; + + uint32_t maxInjectCount = (mMaxTotalParticleCount - mParticleCount); + + uint32_t injectCount = 0; + uint32_t lastInjectCount = 0; + do + { + lastInjectCount = injectCount; + for (uint32_t i = 0; i < mInjectorList.getSize(); i++) + { + ParticleParticleInjector* inj = DYNAMIC_CAST(ParticleParticleInjector*)(mInjectorList.getResource(i)); + if (inj->mInjectedParticles.size() == 0) + { + continue; + } + + if (injectCount < maxInjectCount) + { + IosNewObject obj; + if (inj->mInjectedParticles.popFront(obj)) + { + PX_ASSERT(obj.lifetime > 0.0f); + PX_ASSERT(PxIsFinite(obj.lodBenefit)); + + uint32_t injectIndex = mParticleCount + injectCount; + + float particleMass = mAsset->getParticleMass(); + mBufDesc.pmaPositionMass->get(injectIndex) = PxVec4(obj.initialPosition.x, obj.initialPosition.y, obj.initialPosition.z, particleMass); + mBufDesc.pmaVelocityLife->get(injectIndex) = PxVec4(obj.initialVelocity.x, obj.initialVelocity.y, obj.initialVelocity.z, 1.0f); + mBufDesc.pmaCollisionNormalFlags->get(injectIndex).setZero(); + mBufDesc.pmaActorIdentifiers->get(injectIndex) = obj.iofxActorID; + + mBufDesc.pmaUserData->get(injectIndex) = obj.userData; + + mLifeSpan[injectIndex] = obj.lifetime; + mInjector[injectIndex] = inj->mInjectorID; + mBenefit[injectIndex] = obj.lodBenefit; + + mInjectedBenefitSum += obj.lodBenefit; + mInjectedBenefitMin = PxMin(mInjectedBenefitMin, obj.lodBenefit); + mInjectedBenefitMax = PxMax(mInjectedBenefitMax, obj.lodBenefit); + + ++injectCount; + } + } + } + } + while (injectCount > lastInjectCount); + + mInjectedCount = injectCount; + + //clear injectors FIFO + for (uint32_t i = 0; i < mInjectorList.getSize(); i++) + { + ParticleParticleInjector* inj = DYNAMIC_CAST(ParticleParticleInjector*)(mInjectorList.getResource(i)); + + IosNewObject obj; + while (inj->mInjectedParticles.popFront(obj)) + { + ; + } + } +} + +bool ParticleIosActorImpl::isParticleDescValid( const ParticleIosAssetParam* desc) const +{ + if (desc->gridSize <= 0.0f) return false; + if (desc->maxMotionDistance <= 0.0f) return false; + if (desc->maxMotionDistance + desc->contactOffset > desc->gridSize) return false; + if (desc->contactOffset < 0.0f) return false; + if (desc->contactOffset < desc->restOffset) return false; + if (desc->particleMass < 0.0f) return false; + if (desc->damping < 0.0f) return false; + if (desc->projectionPlaneNormal.isZero()) return false; + if (desc->restitution < 0.0f || desc->restitution > 1.0f) return false; + if (desc->dynamicFriction < 0.0f || desc->dynamicFriction > 1.0f) return false; + if (desc->staticFriction < 0.0f) return false; + if (desc->maxParticleCount < 1) return false; + + ApexSimpleString className(mAsset->getParticleTypeClassName()); + if (className == SimpleParticleSystemParams::staticClassName()) + { + return true; + } + else + if (className == FluidParticleSystemParams::staticClassName()) + { + const FluidParticleSystemParams* fluidDesc = (FluidParticleSystemParams*)desc->particleType; + if (fluidDesc->restParticleDistance <= 0.0f) return false; + + if (fluidDesc->stiffness <= 0.0f) return false; + if (fluidDesc->viscosity <= 0.0f) return false; + + return true; + } + else + { + return false; + } +} +//////////////////////////////////////////////////////////////////////////////// + +ParticleParticleInjector::ParticleParticleInjector(ResourceList& list, ParticleIosActorImpl& actor, uint32_t injectorID) + : mIosActor(&actor) + , mIofxClient(NULL) + , mVolume(NULL) + , mLastRandomID(0) + , mVolumeID(IofxActorIDIntl::NO_VOLUME) + , mInjectorID(injectorID) + , mSimulatedParticlesCount(0) +{ + list.add(*this); + + setLODWeights(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); + + mInjectedParticles.reserve(actor.mMaxTotalParticleCount); +} + +void ParticleParticleInjector::setListIndex(ResourceList& list, uint32_t index) +{ + m_listIndex = index; + m_list = &list; + + Px3InjectorParams injParams; + mIosActor->mParticleIosScene->fetchInjectorParams(mInjectorID, injParams); + injParams.mLocalIndex = index; + mIosActor->mParticleIosScene->updateInjectorParams(mInjectorID, injParams); +} + +/* Emitter calls this function to adjust their particle weights with respect to other emitters */ +void ParticleParticleInjector::setLODWeights(float maxDistance, float distanceWeight, float speedWeight, float lifeWeight, float separationWeight, float bias) +{ + PX_UNUSED(separationWeight); + + Px3InjectorParams injParams; + mIosActor->mParticleIosScene->fetchInjectorParams(mInjectorID, injParams); + + injParams.mLODMaxDistance = maxDistance; + injParams.mLODDistanceWeight = distanceWeight; + injParams.mLODSpeedWeight = speedWeight; + injParams.mLODLifeWeight = lifeWeight; + injParams.mLODBias = bias; + + mIosActor->mParticleIosScene->updateInjectorParams(mInjectorID, injParams); +} + +PxTaskID ParticleParticleInjector::getCompletionTaskID() const +{ + return mIosActor->mInjectTask.getTaskID(); +} + +void ParticleParticleInjector::setObjectScale(float objectScale) +{ + PX_ASSERT(mIofxClient); + IofxManagerClientIntl::Params params; + mIofxClient->getParams(params); + params.objectScale = objectScale; + mIofxClient->setParams(params); +} + +void ParticleParticleInjector::init(IofxAsset* iofxAsset) +{ + mIofxClient = mIosActor->mIofxMgr->createClient(iofxAsset, IofxManagerClientIntl::Params()); + + /* add this injector to the IOFX asset's context (so when the IOFX goes away our ::release() is called) */ + iofxAsset->addDependentActor(this); + + mRandomActorClassIDs.clear(); + if (iofxAsset->getMeshAssetCount() < 2) + { + mRandomActorClassIDs.pushBack(mIosActor->mIofxMgr->getActorClassID(mIofxClient, 0)); + return; + } + + /* Cache actorClassIDs for this asset */ + physx::Array<uint16_t> temp; + for (uint32_t i = 0 ; i < iofxAsset->getMeshAssetCount() ; i++) + { + uint32_t w = iofxAsset->getMeshAssetWeight(i); + uint16_t acid = mIosActor->mIofxMgr->getActorClassID(mIofxClient, (uint16_t) i); + for (uint32_t j = 0 ; j < w ; j++) + { + temp.pushBack(acid); + } + } + + mRandomActorClassIDs.reserve(temp.size()); + while (temp.size()) + { + uint32_t index = (uint32_t)physx::shdfnd::rand(0, (int32_t)temp.size() - 1); + mRandomActorClassIDs.pushBack(temp[ index ]); + temp.replaceWithLast(index); + } +} + + +void ParticleParticleInjector::release() +{ + if (mInRelease) + { + return; + } + mInRelease = true; + mIosActor->releaseInjector(*this); +} + +void ParticleParticleInjector::destroy() +{ + ApexActor::destroy(); + + mIosActor->mIofxMgr->releaseClient(mIofxClient); + + delete this; +} + +void ParticleParticleInjector::setPreferredRenderVolume(RenderVolume* volume) +{ + mVolume = volume; + mVolumeID = mVolume ? mIosActor->mIofxMgr->getVolumeID(mVolume) : IofxActorIDIntl::NO_VOLUME; +} + +/* Emitter calls this virtual injector API to insert new particles. It is safe for an emitter to + * call this function at any time except for during the IOS::fetchResults(). Since + * ParticleScene::fetchResults() is single threaded, it should be safe to call from + * emitter::fetchResults() (destruction may want to do this because of contact reporting) + */ +void ParticleParticleInjector::createObjects(uint32_t count, const IosNewObject* createList) +{ + PX_PROFILE_ZONE("ParticleIosCreateObjects", GetInternalApexSDK()->getContextId()); + + if (mRandomActorClassIDs.size() == 0) + { + return; + } + + const PxVec3& eyePos = mIosActor->mParticleIosScene->getApexScene().getEyePosition(); + Px3InjectorParams injParams; + mIosActor->mParticleIosScene->fetchInjectorParams(mInjectorID, injParams); + + // Append new objects to our FIFO. We do copies because we must perform buffering for the + // emitters. We have to hold these new objects until there is room in the TurbulenceFS and the + // injector's virtID range to emit them. + for (uint32_t i = 0 ; i < count ; i++) + { + if (mInjectedParticles.size() == mInjectedParticles.capacity()) + { + break; + } + + IosNewObject obj = *createList++; + + obj.lodBenefit = calcParticleBenefit(injParams, eyePos, obj.initialPosition, obj.initialVelocity, 1.0f); + obj.iofxActorID.set(mVolumeID, mRandomActorClassIDs[ mLastRandomID++ ]); + mLastRandomID = mLastRandomID == mRandomActorClassIDs.size() ? 0 : mLastRandomID; + //mInjectedParticleBenefit += obj.lodBenefit; + mInjectedParticles.pushBack(obj); + } +} + +#if APEX_CUDA_SUPPORT +void ParticleParticleInjector::createObjects(ApexMirroredArray<const IosNewObject>& createArray) +{ + PX_UNUSED(createArray); + + // An emitter will call this API when it has filled a host or device buffer. The injector + // should trigger a copy to the location it would like to see the resulting data when the + // IOS is finally ticked. + + PX_ALWAYS_ASSERT(); /* Not yet supported */ +} +#endif + +uint32_t ParticleParticleInjector::getActivePaticleCount() const +{ + return mSimulatedParticlesCount; +} + +} +} // end namespace nvidia + |