//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2002. // ------------------------------------------------------------------------- // File name: spritemanager.cpp // Version: v1.00 // Created: 18/7/2003 by Timur. // Compilers: Visual Studio.NET // Description: // ------------------------------------------------------------------------- // History: Created by Vladimir // //////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "partman.h" #include "objman.h" #include "visareas.h" //#include "ParticleEffect.h" #include "3dEngine.h" CSpriteManager::CSpriteManager( CPartManager *pPartManager ) { m_nMaxSpritesCount = min(16384, max(16,GetCVars()->e_particles_max_count)); m_arrSprites = new CSprite[m_nMaxSpritesCount]; m_nCurSpritesCount=0; memset(m_arrSprites,0,sizeof(CSprite)*m_nMaxSpritesCount); m_pSystem = GetSystem(); m_p3DEngine = Get3DEngine(); m_pVisAreaManager = GetVisAreaManager(); m_pObjManager = ((C3DEngine*)m_p3DEngine)->GetObjManager(); m_pPartManager = pPartManager; } CSpriteManager::~CSpriteManager() { delete [] m_arrSprites; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// void CSpriteManager::Spawn( CParticleEmitter &emitter,bool bChildProcess ) { FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled ); // make sprites ParticleParams &Params = (!bChildProcess) ? *emitter.m_pParams : *emitter.m_pParams->pChild; if(!_finite(Params.vPosition.x) || !_finite(Params.vPosition.y) || !_finite(Params.vPosition.z)) { // GetLog()->Log("Warning: CSpriteManager::Spawn: Particle emitter position is undefined"); return; } ////////////////////////////////////////////////////////////////////////// /* if(GetCVars()->e_particles_debug==1) { Params.fSpeed = Params.fSpeed / 10; Params.fLifeTime = Params.fLifeTime*10; Params.vGravity/=10; }*/ /* if (Params.fScale != 1.0f && Params.fScale > 0) { float fScale = Params.fScale; // Adjust particle parameters by scale. Params.fSize = Params.fSize*fScale; Params.fPosRandomOffset *= fScale; Params.vGravity *= fScale; Params.vPositionOffset *= fScale; Params.vRandomPositionOffset *= fScale; Params.fSizeSpeed *= fScale; Params.fSpeed = Params.fSpeed*fScale; Params.fTailLenght *= fScale; Params.fTurbulenceSize *= fScale; //Params.fTurbulenceSpeed *= fScale; if (Params.pChild) { Params.pChild->fSize = Params.pChild->fSize*fScale; Params.pChild->fPosRandomOffset *= fScale; Params.pChild->vGravity *= fScale; Params.pChild->vPositionOffset *= fScale; Params.pChild->vRandomPositionOffset *= fScale; Params.pChild->fSizeSpeed *= fScale; Params.pChild->fSpeed = Params.pChild->fSpeed*fScale; Params.pChild->fTailLenght *= fScale; Params.pChild->fTurbulenceSize *= fScale; } } */ float fCurrTime = m_pPartManager->GetParticlesTime(); int nCount = max(1,int(Params.nCount*GetCVars()->e_particles_lod)); // pass Params structure to CPartSpray::Spawn() nCount times for(int i=0; i < nCount; i++) { if(m_nCurSpritesCount>=m_nMaxSpritesCount) break; CSprite * pSprite = &m_arrSprites[m_nCurSpritesCount]; // spawn one sprite SpawnParticle( emitter,bChildProcess,fCurrTime,pSprite ); m_nCurSpritesCount++; } } ////////////////////////////////////////////////////////////////////////// void CSpriteManager::SpawnParticle( CParticleEmitter &emitter,bool bChildProcess,float fCurrTime,CParticle *pPart ) { if (!bChildProcess) pPart->m_pParams = emitter.m_pParams; else pPart->m_pParams = emitter.m_pParams->pChild; ParticleParams &Params = *pPart->m_pParams; // Params.nParticleFlags |= PART_FLAG_LINEPARTICLE; //Params.vDirection = Vec3d(0,100,0); //pPart->m_pVisArea = m_pVisAreaManager->GetVisAreaFromPos(Params.vPosition); pPart->m_pEmitter = &emitter; pPart->m_pEmitter->AddRef(); // Get scale for this particle. float fScale = emitter.m_fScale; pPart->m_fScale = fScale; pPart->m_nParticleFlags = Params.nParticleFlags; if (Params.eBlendType == ParticleBlendType_Additive) { pPart->m_nParticleFlags |= CParticle::PARTICLE_COLOR_BASED | CParticle::PARTICLE_ADDITIVE; } else if (Params.eBlendType == ParticleBlendType_ColorBased) { pPart->m_nParticleFlags |= CParticle::PARTICLE_COLOR_BASED; } if (Params.nParticleFlags & PART_FLAG_RIGIDBODY) { // Also set no offset flag. Params.nParticleFlags |= PART_FLAG_NO_OFFSET; } if (Params.nTexAnimFramesCount > 1) pPart->m_nParticleFlags |= CParticle::PARTICLE_ANIMATED_TEXTURE; // calculate focus and dir if(Params.nParticleFlags & PART_FLAG_LINEPARTICLE) pPart->m_vDelta = Params.vDirection; else if(Params.nParticleFlags & PART_FLAG_FOCUS_PLANE) { // Distribute particles on plane. Vec3 dir = Params.vDirection; if(Params.nParticleFlags & PART_FLAG_SPEED_IN_GRAVITY_DIRECTION) { dir = -Params.vGravity; if (dir.IsZero()) dir = Vec3(0,0,1); dir.Normalize(); } Vec3 n1 = Vec3(0,1,0); if (n1 == dir) n1 = Vec3(1,0,0); n1 = dir.Cross(n1); Vec3 n2 = dir.Cross(n1); Matrix33 tm; tm.SetMatFromVectors( dir,n1,n2 ); Vec3d vPartDir(2.0f*rnd()-1.0f,2.0f*rnd()-1.0f,2.0f*rnd()-1.0f); float focus = max(0,min(1,Params.fFocus)); vPartDir.x *= focus; vPartDir.Normalize(); vPartDir = tm * vPartDir; vPartDir *= Params.fSpeed.GetVariantValue(); pPart->m_vDelta = vPartDir*fScale; } else if(Params.nParticleFlags & PART_FLAG_SPEED_IN_GRAVITY_DIRECTION) { Vec3d vGravityDir = -Params.vGravity; Vec3d vPartDir(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f); if (vPartDir.IsZero()) vPartDir = Vec3(0,0,1); if (vGravityDir.IsZero()) vGravityDir = Vec3(0,0,-1); else vGravityDir.Normalize(); vPartDir.Normalize(); vPartDir += vGravityDir*Params.fFocus; vPartDir.Normalize(); vPartDir *= Params.fSpeed.GetVariantValue();/* * (0.75f+0.5f*rnd());*/ pPart->m_vDelta = vPartDir*fScale; } else { Vec3d vPartDir(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f); vPartDir.Normalize(); vPartDir += Params.vDirection*Params.fFocus; vPartDir.Normalize(); vPartDir *= Params.fSpeed.GetVariantValue();/* * (0.75f+0.5f*rnd());*/ pPart->m_vDelta = vPartDir*fScale; } // do not move water waves in vertical direction if(Params.nParticleFlags & PART_FLAG_HORIZONTAL) pPart->m_vDelta.z = 0; // set params if(Params.nParticleFlags & PART_FLAG_SPACELOOP) { pPart->m_vPos = Params.vPosition + Vec3d(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f)*32; /* float fModX = fabs(Params.vDirection.x); float fModY = fabs(Params.vDirection.y); float fModZ = fabs(Params.vDirection.z); if(fModX>fModY && fModX>fModZ) pPart->m_vPos.x = Params.vPosition.x + (Params.vDirection.x>0 ? -Params.vSpaceLoopBoxSize.x : Params.vSpaceLoopBoxSize.x); else if(fModY>fModX && fModY>fModZ) pPart->m_vPos.y = Params.vPosition.y + (Params.vDirection.y>0 ? -Params.vSpaceLoopBoxSize.y : Params.vSpaceLoopBoxSize.y); else pPart->m_vPos.z = Params.vPosition.z + (Params.vDirection.z>0 ? -Params.vSpaceLoopBoxSize.z : Params.vSpaceLoopBoxSize.z);*/ } else if(Params.fPosRandomOffset) { // random offset Vec3d vOffset(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f); vOffset *= (Params.fPosRandomOffset*2)*fScale; pPart->m_vPos = Params.vPosition + vOffset; } else { pPart->m_vPos = Params.vPosition; } if (!Params.vRandomPositionOffset.IsZero()) { Vec3 vrnd; vrnd.x = (2.0f*rnd()-1.0f) * Params.vRandomPositionOffset.x; vrnd.y = (2.0f*rnd()-1.0f) * Params.vRandomPositionOffset.y; vrnd.z = (2.0f*rnd()-1.0f) * Params.vRandomPositionOffset.z; pPart->m_vPos += vrnd*fScale; } pPart->m_vPos += Params.vPositionOffset*fScale; pPart->m_fSizeOriginal = Params.fSize.GetVariantValue()*fScale; pPart->m_fSize = pPart->m_fSizeOriginal; pPart->m_vAngles = Params.vInitAngles.GetVariantValue(); pPart->m_vRotation = Params.vRotation.GetVariantValue(); pPart->m_fLifeTime = Params.fLifeTime.GetVariantValue(); pPart->m_fSpawnTime = fCurrTime; if (Params.fTailLenght) { pPart->m_nTailSteps = Params.nTailSteps; if (pPart->m_nTailSteps <= 0) pPart->m_nTailSteps = 8; // Default steps. if (pPart->m_nTailSteps > 16) pPart->m_nTailSteps = 16; // Max steps (Renderer cant do more). // init history stack pPart->m_fTrailCurPos = 1.0f; pPart->m_pArrvPosHistory = new Vec3[pPart->m_nTailSteps]; for(int t=0; t < pPart->m_nTailSteps; t++) pPart->m_pArrvPosHistory[t] = Params.vPosition; } // init physical particle if requested if(Params.bRealPhysics /* && GetCVars()->e_particles_allow_physics */) pPart->Physicalize( Params,m_pSystem->GetIPhysicalWorld() ); pPart->m_fChildSpawnLastTime = fCurrTime; // set statobj // if(Params.pStatObj) // Params.pStatObj->RegisterUser(); // prevent object deleting // get ambient color Vec3d vAmbientColor = m_p3DEngine->GetAmbientColorFromPosition(Params.vPosition); Vec3d vWorldColor = Get3DEngine()->GetWorldColor(); vAmbientColor.x *= vWorldColor.x; vAmbientColor.y *= vWorldColor.y; vAmbientColor.z *= vWorldColor.z; vAmbientColor.CheckMin(Vec3d(1,1,1)); pPart->m_cAmbientColor = pPart->Vec2Color(vAmbientColor); //pPart->m_nDynLightMask = 0;//pSystem->GetI3DEngine()->GetLightMaskFromPosition(Params.vPosition); //float fSize = pPart->m_fSize; //pPart->m_nFogVolumeId = m_p3DEngine->GetFogVolumeIdFromBBox( //Params.vPosition-Vec3d(fSize,fSize,fSize), //Params.vPosition+Vec3d(fSize,fSize,fSize)); if (Params.pMaterial) { pPart->m_pMaterial = Params.pMaterial; } else pPart->m_pMaterial = emitter.m_pMaterial; pPart->m_pSpawnerEntity = emitter.m_pSpawnerEntity; } ////////////////////////////////////////////////////////////////////////// void CSpriteManager::Render(CObjManager * pObjManager, CTerrain * pTerrain, int nRecursionLevel, CPartManager * pPartManager, IShader * pPartLightShader) { // update max sprites count if console variable changed if(m_nMaxSpritesCount != min(16384, max(16,GetCVars()->e_particles_max_count))) { m_nMaxSpritesCount = min(16384, max(16,GetCVars()->e_particles_max_count)); delete [] m_arrSprites; m_arrSprites = new CSprite[m_nMaxSpritesCount]; memset(m_arrSprites,0,sizeof(CSprite)*m_nMaxSpritesCount); m_nCurSpritesCount=0; } // get orientation for billboard particles Matrix44 mat; mat.SetIdentity(); GetRenderer()->GetModelViewMatrix(mat.GetData()); Vec3d vRight,vUp,vFront; //CELL_CHANGED_BY_IVO //vRight(mat.cell(0), mat.cell(4), mat.cell(8)); //vUp (mat.cell(1), mat.cell(5), mat.cell(9)); //vFront(mat.cell(2), mat.cell(6), mat.cell(10)); vRight = GetNormalized(mat.GetColumn(0)); vUp = GetNormalized(mat.GetColumn(1)); vFront = GetNormalized(mat.GetColumn(2)); Vec3d vCamPos = GetViewCamera().GetPos(); CCamera * pCamera = &GetViewCamera(); CVars * pCVars = GetCVars(); PartProcessParams ProcParams; ProcParams.fCurTime = pPartManager->GetParticlesTime();; ProcParams.fFrameTime = pPartManager->GetParticlesFrameTime(); ProcParams.vRight=vRight; ProcParams.vUp=vUp; ProcParams.vFront=vFront; ProcParams.pIRenderer=GetRenderer(); ProcParams.pObjManager=pObjManager; ProcParams.pTerrain=pTerrain; ProcParams.pPhysicalWorld=GetPhysicalWorld(); ProcParams.pCamera=pCamera; ProcParams.pVertBufChunk=0; ProcParams.pSystem = GetSystem(); ProcParams.p3DEngine = (C3DEngine*)m_p3DEngine; ProcParams.pPartManager = pPartManager; ProcParams.vCamPos = pCamera->GetPos(); for( int i=0; iUpdate(ProcParams); //Vec3 vsz = Vec3(pSprite->m_fSize,pSprite->m_fSize,pSprite->m_fSize); //pSprite->m_pEmitter->m_bbox.Add( pSprite->m_vPos - vsz ); //pSprite->m_pEmitter->m_bbox.Add( pSprite->m_vPos + vsz ); } if (!nRecursionLevel || (!(pSprite->m_nParticleFlags & PART_FLAG_HORIZONTAL)) ) { bool bVisible = false; if(pSprite->m_nParticleFlags & PART_FLAG_LINEPARTICLE) { // find bbox Vec3d vBoxMin = pSprite->m_vPos; Vec3d vBoxMax = pSprite->m_vPos; vBoxMin.CheckMin(pSprite->m_vPos + pSprite->m_vDelta); vBoxMax.CheckMax(pSprite->m_vPos + pSprite->m_vDelta); vBoxMin -= Vec3d(pSprite->m_fSize,pSprite->m_fSize,pSprite->m_fSize); vBoxMax += Vec3d(pSprite->m_fSize,pSprite->m_fSize,pSprite->m_fSize); bVisible = pCamera->IsAABBVisibleFast( AABB(vBoxMin,vBoxMax) ); } else bVisible = pCamera->IsSphereVisibleFast( Sphere(pSprite->m_vPos,pSprite->m_fSize) ); if ( bVisible && (!(pSprite->m_nParticleFlags & PART_FLAG_SPACELIMIT) || bActive)) pSprite->Render( ProcParams,pPartLightShader ); } if (!bActive) { // remove pSprite->DeActivateParticle(GetPhysicalWorld()); if(i < m_nCurSpritesCount-1) { m_arrSprites[i] = m_arrSprites[m_nCurSpritesCount-1]; memset(&m_arrSprites[m_nCurSpritesCount-1],0,sizeof(m_arrSprites[m_nCurSpritesCount-1])); } m_nCurSpritesCount--; i--; } } }