/**************************************************************************** Copyright (c) 2011-2013,WebJet Business Division,CYOU http://www.genesis-3d.com.cn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "stdneb.h" #include "appframework/actor.h" #include "particlefeature/components/particlerenderobject.h" #include "particlefeature/components/particlerendercomponent.h" #include "particlefeature/particlefeatureprotocol.h" #include "graphicfeature/graphicsfeatureprotocol.h" #include "particles/particletarget.h" #include "particles/targets/particleEntityTarget.h" #include "particles/particleserver.h" #include "serialization/serializeserver.h" #include "graphicfeature/graphicsfeature.h" #include "basegamefeature/managers/timemanager.h" #include "basegamefeature/managers/timesource.h" #include "graphicfeature/components/skinnedmeshrendercomponent.h" #include "particles/affectors/particleLinearForceAffector.h" #include "particles/affectors/particleTextureRotatorAffector.h" #include "particles/affectors/particleGravityAffector.h" #include "particles/affectors/particleVortexAffector.h" #include "particles/affectors/particleLimitAffector.h" #include "particles/affectors/particleColorAffector.h" #include "particles/affectors/particleMovementAffector.h" #include "particles/affectors/particleScaleAffector.h" #include "particles/affectors/particleTextureAnimatorAffector.h" #include "particles/emitters/particleSphereSurfaceEmitter.h" #include "particles/emitters/particleModelEmitter.h" #include "particles/emitters/particleBoxEmitter.h" #include "particles/emitters/particleConeEmitter.h" #include "particles/targets/particlebillboardtarget.h" #include "particles/targets/particleDecalTarget.h" #include "particles/targets/particleGPUTarget.h" #include "particles/targets/particleEntityTarget.h" #include "graphicfeature/components/skinnedmeshrendercomponent.h" namespace App { using namespace Resources; using namespace Particles; using namespace RenderBase; using namespace Graphic; __ImplementClass(App::ParticleRenderComponent, 'APRC', App::RenderComponent); //------------------------------------------------------------------------ ParticleRenderComponent::ParticleRenderComponent() : mIsBuild(false) , mIsAttached(false) , mIsTrans(false) , mPrimitiveResInfo(NULL) , mEmitMeshRes(NULL) , mShowSimpleShape(false) , mSelectTech(0) , mTemplateName("sys:Mesh.template") { mMeshInfo.dirty = false; mMeshInfo.meshID = "sys:box.mesh"; mMeshInfo.priority = Resources::ResourcePriority::Synchronization; } //------------------------------------------------------------------------ void ParticleRenderComponent::InitParticleSystem() { GPtr ParSystem = ParticleSystem::Create(); { GPtr emitter = SphereSurfaceEmitter::Create(); emitter->getMinMaxCurve(Emitter_SphereRadius)->SetScalar(0.1f); ParSystem->SetEmitter( emitter.get() ); GPtr pAffector = ParticleAffector::Create(); ParSystem->AddAffector( pAffector.get() ); GPtr target = ParticleBillBoardTarget::Create(); ParSystem->SetTarget( target.get() ); } ParSystem->SetName(Util::String("system_14")); this->SetParticleSystem(ParSystem); //create Matrails this->SetMaterialID(0, "sys:Default_Particle.material"); } //------------------------------------------------------------------------ void ParticleRenderComponent::InitMobielParticle() { GPtr ParSystem = ParticleSystem::Create(); { GPtr emitter = SphereSurfaceEmitter::Create(); emitter->getMinMaxCurve(Emitter_SphereRadius)->SetScalar(0.1f); ParSystem->SetEmitter( emitter.get() ); GPtr target = ParticleGPUTarget::Create(); ParSystem->SetTarget( target.get() ); } ParSystem->SetName(Util::String("system_14")); this->SetParticleSystem(ParSystem); //create Matrails this->SetMaterialID(0, "sys:Default_MobielParticle.material"); } //------------------------------------------------------------------------ ParticleRenderComponent::~ParticleRenderComponent() { mPrimitiveResInfo = NULL; } //------------------------------------------------------------------------ void ParticleRenderComponent::SetupCallbacks(void) { mActor->RegisterComponentCallback(this, BeginFrame ); mActor->RegisterComponentCallback(this, OnFrame ); mActor->RegisterComponentCallback(this, MoveAfter); Super::SetupCallbacks(); } //------------------------------------------------------------------------ void ParticleRenderComponent::SetupAcceptedMessages() { Super::SetupAcceptedMessages(); } //------------------------------------------------------------------------ void ParticleRenderComponent::HandleMessage(const GPtr& msg) { } //------------------------------------------------------------------------ void ParticleRenderComponent::SetRenderShapeEnable(bool enable) { //[zhongdaohuan][render_obj } //------------------------------------------------------------------------ void ParticleRenderComponent::OnActivate() { if ( mParticleSystem.isvalid() ) { mParticleSystem->Active(); if ( NULL!=mActor ) { mParticleSystem->SetWorldMatrix( mActor->GetWorldTransform() ); } } n_assert( mRenderDates.Size() == 0 ); LoadEmitterMesh(); BuildRenderData(); Graphic::GraphicSystem::Instance()->m_BeforeDrawEvent += Delegates::newDelegate(this, &ParticleRenderComponent::_updateTarget); Super::OnActivate(); } //------------------------------------------------------------------------ void ParticleRenderComponent::OnDeactivate() { if ( mParticleSystem.isvalid() ) { mParticleSystem->DeActive(); } _DeattachRenderObject(); DiscardRenderData(); Graphic::GraphicSystem::Instance()->m_BeforeDrawEvent -= Delegates::newDelegate(this, &ParticleRenderComponent::_updateTarget); Super::OnDeactivate(); } //------------------------------------------------------------------------ void ParticleRenderComponent::OnDestroy() { if ( mParticleSystem.isvalid() && mParticleSystem->IsActive() ) { mParticleSystem->DeActive(); } mParticleSystem = NULL; _DeattachRenderObject(); DiscardRenderData(); } //------------------------------------------------------------------------ void ParticleRenderComponent::_OnMoveAfter() { if ( !mActor || !mParticleSystem.isvalid() ) return; if ( !mActor || !mParticleSystem.isvalid() ) return; //const Math::vector& wolrdPos = mActor->GetWorldPosition(); const Math::matrix44& worldMat = mActor->GetWorldTransform(); mParticleSystem->SetWorldMatrix(worldMat); if (mRenderObject.isvalid()) { mRenderObject->SetTransform(worldMat); } //if (mSimpleShape.isvalid()) //{ // mSimpleShape->SetTransform(worldMat); //} } //------------------------------------------------------------------------ void ParticleRenderComponent::_OnBeginFrame() { if ( !mParticleSystem.isvalid() ) return; if ( mMeshInfo.dirty) { if (CheckMeshChanged() ) { mIsBuild = false; mIsAttached = false; mMeshInfo.dirty = false; _DeattachRenderObject(); } } //const GPtr& pCamera = GraphicsFeature::Instance()->GetDefaultCameraActor(); // if ( pCamera.isvalid() ) // mParticleSystem->SetCameraMatrix( pCamera->GetWorldTransform() ); LoadEmitterMesh(); BuildRenderData(); Super::_OnBeginFrame(); } //------------------------------------------------------------------------ void ParticleRenderComponent::OnParticleDataChange() { _DeattachRenderObject(); DiscardRenderData(); BuildRenderData(); } //------------------------------------------------------------------------ bool ParticleRenderComponent::CheckMeshChanged(void) { if(mPrimitiveResInfo&& mPrimitiveResInfo->GetHandle().IsValid()) return true; return false; } //-------------------------------------------------------------------------------- const GPtr ParticleRenderComponent::GetMesh() const { if (!mPrimitiveResInfo || !mPrimitiveResInfo->GetRes().isvalid()) { return NULL; } else { return mPrimitiveResInfo->GetRes().downcast(); } } //-------------------------------------------------------------------------------- void ParticleRenderComponent::LoadEmitterMesh(void) { const GPtr& parSystem = GetParticleSystem(); if ( !parSystem.isvalid() ) return; // load modelEmitter 's meshres if ( !parSystem->IsLoadEmitterMesh()) { const GPtr& pEmit = parSystem->GetEmitter(); if( pEmit.isvalid() && pEmit->IsA( Particles::ModelEmitter::RTTI ) ) { const GPtr& pModelEmit = pEmit.downcast(); const Resources::ResourceId& meshId= pModelEmit->GetMeshName(); if("" == meshId.AsString()) return; if ( !mEmitMeshRes || mEmitMeshRes->GetResID() != meshId) { mEmitMeshRes = Resources::ResourceManager::Instance()->CreatePrimitiveInfo(meshId, Resources::ResourcePriority::MeshDefault); } if ( mEmitMeshRes->GetHandle().IsValid() ) { pModelEmit->SetMeshRes(mEmitMeshRes->GetRes()); } } parSystem->SetLoadEmitterMesh(true); } } //------------------------------------------------------------------------ void ParticleRenderComponent::BuildRenderData(void) { if ( mIsBuild ) return; mRenderDates.Clear(); n_assert( mRenderDates.Size() == 0 ); const GPtr& parSystem = GetParticleSystem(); if ( !parSystem.isvalid() ) return; const GPtr& pTarget = parSystem->GetTarget(); if( !pTarget.isvalid() ) return; if ( pTarget->GetTargetType() == ParticleTarget::Mesh ) { ResourceId& resId = mMeshInfo.meshID; Resources::Priority priority = mMeshInfo.priority; if ( !mPrimitiveResInfo.isvalid() || mPrimitiveResInfo->GetResID() != resId ) { mPrimitiveResInfo = Resources::ResourceManager::Instance()->CreatePrimitiveInfo( resId, priority); return; } if ( !mPrimitiveResInfo->GetHandle().IsValid() ) return; const GPtr& resource = mPrimitiveResInfo->GetRes(); if ( resource.isvalid() && resource->GetState() == Resource::Loaded ) { const GPtr& meshResource = resource.downcast(); n_assert( meshResource.isvalid() ); SizeT subMeshCount = meshResource->GetSubMeshCount(); while ( mRenderableResUnitList.Size() < subMeshCount ) { mRenderableResUnitList.Append(RenderbleResUnit()); mRenderableResUnitList.Back().CopyFrom( mRenderableResUnitList[0]); } Math::bbox box; box.begin_extend(); SizeT curMat = 0; for ( IndexT subIndex = 0 ; subIndex < subMeshCount; ++subIndex) { mRenderDates.Append( RenderData()); RenderData& renderData = mRenderDates.Back(); renderData.mPartType = (ushort)ParticleTarget::Mesh; renderData.mPrimitiveHandle = mPrimitiveResInfo->GetHandle(); renderData.mSubmeshIndex = subIndex; renderData.mTargetIndex = 0; const SubMesh* subMesh = meshResource->GetSubMesh(subIndex); RenderObjectType::RenderableType* renderable = mRenderableResUnitList[curMat].ResetRenderable(); _SetRenderable( meshResource, curMat, renderable); box.extend( subMesh->box ); ++curMat; } box.end_extend(); const ParticleTargetPtr& target = mParticleSystem->GetTarget(); target.downcast()->_setMeshBox(box); } else { _DeattachRenderObject(); return; } } else { // just rebuild pool int quota = parSystem->GetParticleQuota(); parSystem->_resetPool( quota ); mRenderDates.Append( RenderData() ); RenderData& renderData = mRenderDates[0]; //renderData.mPrimitiveGroup = PrimitiveGroup::Create(); renderData.mTargetIndex = 0; renderData.mPartType = pTarget->GetTargetType(); //pTarget->SetPrimitiveGroup( renderData.mPrimitiveGroup ); pTarget->SetNeedPrimitive(true); RenderObjectType::RenderableType* renderable = mRenderableResUnitList[0].ResetRenderable(); _SetRenderable(NULL, 0, renderable); } //New RenderObject if( !mRenderObject.isvalid() ) { mRenderObject = RenderObjectType::Create(); } mRenderObject->SetOwner(this); mRenderObject->SetTransform(mActor->GetWorldTransform()); _AttachRenderObject(); mIsBuild = true; } //------------------------------------------------------------------------ void ParticleRenderComponent::DiscardRenderData(void) { //if ( !mIsBuild ) //{ // n_assert( mRenderDates.IsEmpty() ); // return; //} mIsBuild = false; SizeT count = mRenderDates.Size(); for ( IndexT index = 0; index < mRenderDates.Size(); ++index ) { RenderData& renderData = mRenderDates[index]; if ( renderData.mPrimitiveHandle.IsValid() ) { //GraphicSystem::Instance()->RemovePrimitive( renderData.mPrimitiveHandle ); //GraphicObjectManager::Instance()->DiscardPrimitiveHandle( renderData.mPrimitiveHandle ); const ParticleTargetPtr& target = mParticleSystem->GetTarget(); if(target.isvalid()) target->SetDirtyPrim(true); renderData.mPrimitiveHandle = RenderBase::PrimitiveHandle(); } } mRenderDates.Clear(); } void ParticleRenderComponent::UpdateRenderLayer() { if (mRenderObject.isvalid()) { mRenderObject->SetLayerID(mActor->GetLayerID()); } } void ParticleRenderComponent::SetVisible(bool bVis) { mVisible = bVis; if (IsActive()) { if (mVisible) { _AttachRenderObject(); } else { _DeattachRenderObject(); } } } void ParticleRenderComponent::OnRenderSceneChanged() { if (mRenderObject.isvalid() && mRenderObject->Attached()) { mRenderObject->Attach(mActor->GetRenderScene()); } } void ParticleRenderComponent::_AttachRenderObject() { if(!mVisible) return; if (mRenderObject.isvalid()) { n_assert(mActor); mRenderObject->Attach(mActor->GetRenderScene()); } } void ParticleRenderComponent::_DeattachRenderObject() { if (mRenderObject.isvalid()) { n_assert(mActor); mRenderObject->Detach(); } } void ParticleRenderComponent::_updateTarget( Graphic::Camera* camera ) { if(mIsBuild) { mParticleSystem->SetCameraMatrix( camera->GetTransform()); mParticleSystem->_postProcessParticles(); UpdateRenderData(); } mCurCamera = camera; } void ParticleRenderComponent::_SetRenderable(const GPtr& meshRes, IndexT index, RenderObjectType::RenderableType* renderable) { if (meshRes.isvalid()) { SubMesh* subMesh = meshRes->GetSubMesh(index); n_assert(subMesh); renderable->SetParticleRenderInfo(index, subMesh->firstVertex, subMesh->numVertex, subMesh->FirstIndex, subMesh->numIndex); } else { RenderData& renderdata = mRenderDates[index]; if ( renderdata.mPrimitiveHandle.IsValid()) { const ParticleTargetPtr& target = mParticleSystem->GetTarget(); renderable->SetParticleRenderInfo(index, 0, target->GetActiveVertexCount(), 0, target->GetActiveIndexCount()); } else { renderable->SetParticleRenderInfo(index, 0, 0, 0, 0); } } } void ParticleRenderComponent::_UpdateRenderable(IndexT index, SizeT activeVertexCount, SizeT activeIndexCount, signed char sort, RenderObjectType::RenderableType* renderable) { renderable->SetParticleRenderInfo(index, 0, activeVertexCount, 0, activeIndexCount); renderable->SetSort(sort); } //------------------------------------------------------------------------ void ParticleRenderComponent::UpdateRenderData(void) { for ( IndexT index = 0; index < mRenderDates.Size(); ++index ) { RenderData& renderData = mRenderDates[index]; RenderObjectType::RenderableType* renderable = mRenderableResUnitList[index].GetRenderableFast(); if ( renderData.mPartType == ParticleTarget::Mesh ) { const GPtr& parSystem = GetParticleSystem(); if ( !parSystem.isvalid() ) return; const ParticleTargetPtr& target = parSystem->GetTarget(); const GPtr& entityTarget = target.downcast(); if ( !entityTarget->IsNeedToRender() ) return; GPtr meshres = mPrimitiveResInfo->GetRes().downcast(); if ( meshres.isvalid() && meshres->GetState() == Resource::Loaded ) { SizeT vertexCount = meshres->GetVertexCount(); ColorData colorData; Math::Color32 color(255,255,255,255); ColorData::Elem* elem = meshres->GetVertexData(); if ( elem == NULL ) { colorData.Fill(0, vertexCount, color ); if( !meshres->SetVertexData(&colorData[0], vertexCount ) ) return; } if ( !renderData.mPrimitiveHandle.IsValid() ) renderData.mPrimitiveHandle = mPrimitiveResInfo->GetHandle(); else GraphicObjectManager::Instance()->UpdataPrimitiveHandle(meshres); if( renderData.mSubmeshIndex >= meshres->GetSubMeshCount()) continue; _SetRenderable(meshres, index, renderable); } }// end: if ( renderData.mPartType == ParticleTarget::Mesh ) else { const ParticleTargetPtr& target = mParticleSystem->GetTarget(); signed char sort = mParticleSystem->GetSort(); if (target.isvalid()) { if (target->IsDirtyPrim()) { renderData.mPrimitiveHandle = mParticleSystem->GetTarget()->GetPrimitiveHandle(); target->SetDirtyPrim(false); } _UpdateRenderable(index, target->GetActiveVertexCount(), target->GetActiveIndexCount(), sort, renderable); } else { _UpdateRenderable(index, 0, 0, sort, renderable); } }//end: if ( renderData.mPartType != ParticleTarget::Mesh ) }//end: for ( IndexT index = 0; index < mRenderDates.Size(); ++index ) if(mParticleSystem->_NeedUpdateBox()) { Math::bbox box; box.begin_extend(); Math::bbox particleBox = mParticleSystem->GetBoundingBox(); box.extend(particleBox); box.end_extend(); mRenderObject->SetBoundingBox(box); } } //------------------------------------------------------------------------ void ParticleRenderComponent::_OnFrame() { } //------------------------------------------------------------------------ void ParticleRenderComponent::SetShaderMask() { SizeT sub_count = mRenderableResUnitList.Size(); for ( IndexT index = 0; index < sub_count; ++index ) { Renderable* renderable = mRenderableResUnitList[index].GetRenderable(); if (renderable == NULL) { return; } const MaterialInstance* material_instance = renderable->GetMaterial(); { const Util::Array< GPtr >& passList = material_instance->GetTech()->GetPassList(); //打开forward pass 里用到的 宏 const GPtr& pass = passList[eForward - 1]; const GPtr& pMarcro = pass->GetShaderMarcro(); pMarcro->Reset(); mParticleSystem->SetShaderMask(pMarcro); renderable->SetShaderMask(eForward,pMarcro->GetShaderMask()); } } } //------------------------------------------------------------------------ void ParticleRenderComponent::GetTargetInfo(ushort& partType,Util::Array& mMats, Util::Array& mColors) { const GPtr& parSystem = GetParticleSystem(); if ( !parSystem.isvalid() ) return ; const GPtr& pTarget = parSystem->GetTarget(); if( !pTarget.isvalid() ) return ; partType = pTarget->GetTargetType(); if ( partType == ParticleTarget::Mesh ) { GPtr entityTar = pTarget.downcast(); mMats.AppendArray( entityTar->GetMatrixList()); mColors.AppendArray( entityTar->GetColorList()); } else if ( partType == ParticleTarget::Decal ) { GPtr decalTar = pTarget.downcast(); mMats.Append( decalTar->GetDecalRotation()); mColors.Append( Math::float4(1.0f,1.0f,1.0f,1.0f)); } else { mMats.Append( Math::matrix44::identity()); mColors.Append( Math::float4(1.0f,1.0f,1.0f,1.0f)); } } //------------------------------------------------------------------------ void ParticleRenderComponent::CalculateBBox(Math::bbox& box,const Util::Array& matlist) { SizeT PosIndex = 0; while (PosIndex < matlist.Size()) { Math::float4 curPos = matlist[PosIndex].get_position(); box.extend(curPos); PosIndex++; } } //-------------------------------------------------------------------------------- void ParticleRenderComponent::RemoveShader( IndexT iSubMesh ) { if ( iSubMesh < 0 ) { return; } //whether need to determine the render type is entity target if ( iSubMesh >= mRenderableResUnitList.Size() ) { // delete the renderable from graphic system mRenderableResUnitList.EraseIndex(iSubMesh); } } //------------------------------------------------------------------------ void ParticleRenderComponent::SetParticleSystem( const GPtr& parSystem ) { if ( mParticleSystem == parSystem ) { return; } if ( mParticleSystem.isvalid() ) { if ( mParticleSystem->IsActive() ) { mParticleSystem->DeActive(); } } mParticleSystem = parSystem; if ( mParticleSystem.isvalid() ) { if ( IsActive() ) { mParticleSystem->Active(); } } OnParticleSystemChange(); } //-------------------------------------------------------------------------------- void ParticleRenderComponent::SetEmitMeshRes(const Resources::ResourceId& meshID, int techIdx , int emitIdx ) { const GPtr& parSystem = GetParticleSystem(); if ( !parSystem.isvalid() ) return; const GPtr& pEmit = parSystem->GetEmitter(); if( pEmit.isvalid() && pEmit->IsA( Particles::ModelEmitter::RTTI ) ) { const GPtr& pModelEmit = pEmit.downcast(); pModelEmit->SetMeshName(meshID.AsString()); } } //------------------------------------------------------------------------ void ParticleRenderComponent::OnParticleSystemChange() { if ( mActor ) { GPtr msg = ParticleComponentChangeMsg::Create(); mActor->SendSync( msg.upcast() ); } } //------------------------------------------------------------------------ void ParticleRenderComponent::CopyFrom( const GPtr& pComponent ) { if( !pComponent.isvalid() ) return; if( !pComponent->GetRtti()->IsDerivedFrom( *(this->GetRtti()) ) ) return; GPtr pSource = pComponent.downcast(); SetMeshID(pSource->GetMeshID(), pSource->GetMeshLoadPriority()); mTemplateName = pSource->GetTemplateID(); ParticleSystemPtr newPartSystem = ParticleSystem::Create(); newPartSystem->CopyFrom(pSource->GetParticleSystem()); SetParticleSystem(newPartSystem); Super::CopyFrom( pComponent ); } //------------------------------------------------------------------------------ void ParticleRenderComponent::GetReferenceResourceId(Util::Array& list) const { if (mEmitMeshRes.isvalid()) { list.Append(ReferenceResource(mEmitMeshRes->GetResID(), Resources::RR_Unknown)); } list.Append(ReferenceResource(mTemplateName, Resources::RR_Unknown)); Super::GetReferenceResourceId(list); } //------------------------------------------------------------------------ void ParticleRenderComponent::SetMeshID(const Resources::ResourceId& meshID, Resources::Priority priority ) { if( mMeshInfo.meshID != meshID ) { if (mActor && mActor->PriorityDefinition()) { priority = mActor->GetPriority(); } mMeshInfo.meshID = meshID; mMeshInfo.priority = priority; mMeshInfo.dirty = true; } } //------------------------------------------------------------------------ void ParticleRenderComponent::SetTemplateID( const Resources::ResourceId& templateID ) { mTemplateName = templateID; } //------------------------------------------------------------------------ const Resources::ResourceId& ParticleRenderComponent::GetTemplateID( void ) const { return mTemplateName; } }