/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of HPL1 Engine. */ // NEW #include "hpl1/engine/graphics/Graphics.h" // --- #include "hpl1/engine/graphics/ParticleEmitter3D_UserData.h" //#include "hpl1/engine/graphics/Mesh.h" //#include "hpl1/engine/graphics/SubMesh.h" #include "hpl1/engine/graphics/ParticleSystem3D.h" #include "hpl1/engine/graphics/RenderList.h" #include "hpl1/engine/impl/tinyXML/tinyxml.h" #include "hpl1/engine/resources/MaterialManager.h" #include "hpl1/engine/resources/Resources.h" //#include "hpl1/engine/resources/MeshManager.h" #include "hpl1/engine/physics/PhysicsBody.h" #include "hpl1/engine/physics/PhysicsWorld.h" #include "hpl1/engine/scene/World3D.h" #include "hpl1/engine/math/Math.h" namespace hpl { ////////////////////////////////////////////////////////////////////////// // LOADER ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cParticleEmitterData3D_UserData::cParticleEmitterData3D_UserData( const tString &asName, cResources *apResources, cGraphics *apGraphics) : iParticleEmitterData(asName, apResources, apGraphics) { } //----------------------------------------------------------------------- iParticleEmitter *cParticleEmitterData3D_UserData::Create(tString asName, cVector3f avSize) { iParticleEmitter3D *pPE = hplNew(cParticleEmitter3D_UserData, (asName, &mvMaterials, avSize, mpGraphics, mpResources, this)); cMatrixf mtxOffset = cMath::MatrixRotate(mvAngleOffset, eEulerRotationOrder_XYZ); mtxOffset.SetTranslation(mvPosOffset); pPE->SetMatrix(mtxOffset); return pPE; } ////////////////////////// // NEW static ePEType GetPEType(const char *apString) { if (apString == NULL) return ePEType_Normal; tString sType = cString::ToLowerCase(apString); if (sType == "beam") return ePEType_Beam; else if (sType == "normal") return ePEType_Normal; return ePEType_Normal; } // --- ///////////////////////// static ePEStartPosType GetStartPosType(const char *apString) { if (apString == NULL) return ePEStartPosType_Box; tString sType = cString::ToLowerCase(apString); if (sType == "box") return ePEStartPosType_Box; else if (sType == "sphere") return ePEStartPosType_Sphere; return ePEStartPosType_Box; } ///////////////////////// static eParticleEmitter3DCoordSystem GetCoordSystem(const char *apString) { if (apString == NULL) return eParticleEmitter3DCoordSystem_World; tString sType = cString::ToLowerCase(apString); if (sType == "world") return eParticleEmitter3DCoordSystem_World; else if (sType == "local") return eParticleEmitter3DCoordSystem_Local; return eParticleEmitter3DCoordSystem_World; } ///////////////////////// static ePEDeathType GetDeathType(const char *apString) { if (apString == NULL) return ePEDeathType_Age; tString sType = cString::ToLowerCase(apString); if (sType == "age") return ePEDeathType_Age; return ePEDeathType_Age; } ///////////////////////// static eParticleEmitter3DType GetDrawType(const char *apString) { if (apString == NULL) return eParticleEmitter3DType_DynamicPoint; tString sType = cString::ToLowerCase(apString); if (sType == "point") return eParticleEmitter3DType_DynamicPoint; else if (sType == "line") return eParticleEmitter3DType_Line; else if (sType == "axis") return eParticleEmitter3DType_Axis; return eParticleEmitter3DType_DynamicPoint; } ///////////////////////// static ePEGravityType GetGravityType(const char *apString) { if (apString == NULL) return ePEGravityType_None; tString sType = cString::ToLowerCase(apString); if (sType == "none") return ePEGravityType_None; else if (sType == "vector") return ePEGravityType_Vector; else if (sType == "center") return ePEGravityType_Center; return ePEGravityType_None; } ///////////////////////// static ePESubDivType GetSubDivType(const char *apString) { if (apString == NULL) return ePESubDivType_Random; tString sType = cString::ToLowerCase(apString); if (sType == "random") return ePESubDivType_Random; else if (sType == "animation") return ePESubDivType_Animation; return ePESubDivType_Random; } //////////////////////// /// NEW static ePEPartSpinType GetPartSpinType(const char *apString) { if (apString == NULL) return ePEPartSpinType_Constant; tString sType = cString::ToLowerCase(apString); if (sType == "constant") return ePEPartSpinType_Constant; else if (sType == "movement") return ePEPartSpinType_Movement; return ePEPartSpinType_Constant; } /// --- ///////////////////////// void cParticleEmitterData3D_UserData::LoadFromElement(TiXmlElement *apElement) { ///////// GENERAL ///////////// msName = cString::ToString(apElement->Attribute("Name"), ""); // NEW mPEType = GetPEType(apElement->Attribute("PEType")); // --- mlMaxParticleNum = cString::ToInt(apElement->Attribute("MaxParticleNum"), 1); mbRespawn = cString::ToBool(apElement->Attribute("Respawn"), false); mfParticlesPerSecond = cString::ToFloat(apElement->Attribute("ParticlesPerSecond"), 1); mfStartTimeOffset = cString::ToFloat(apElement->Attribute("StartTimeOffset"), 0); mfWarmUpTime = cString::ToFloat(apElement->Attribute("WarmUpTime"), 0); mfWarmUpStepsPerSec = cString::ToFloat(apElement->Attribute("WarmUpStepsPerSec"), 60); mfMinPauseLength = cString::ToFloat(apElement->Attribute("MinPauseLength"), 0); mfMaxPauseLength = cString::ToFloat(apElement->Attribute("MaxPauseLength"), 0); mfMinPauseInterval = cString::ToFloat(apElement->Attribute("MinPauseInterval"), 0); mfMaxPauseInterval = cString::ToFloat(apElement->Attribute("MaxPauseInterval"), 0); mvPosOffset = cString::ToVector3f(apElement->Attribute("PosOffset"), 0); mvAngleOffset = cString::ToVector3f(apElement->Attribute("AngleOffset"), 0); mvAngleOffset.x = cMath::ToRad(mvAngleOffset.x); mvAngleOffset.y = cMath::ToRad(mvAngleOffset.y); mvAngleOffset.z = cMath::ToRad(mvAngleOffset.z); /////////// MATERIAL //////// int lMaterialNum = cString::ToInt(apElement->Attribute("MaterialNum"), 1); float fAnimationLength = cString::ToFloat(apElement->Attribute("AnimationLength"), 1); tString sMaterial = cString::ToString(apElement->Attribute("Material"), ""); mvSubDiv = cString::ToVector2l(apElement->Attribute("SubDiv"), 1); mSubDivType = GetSubDivType(apElement->Attribute("SubDivType")); if (lMaterialNum <= 1) { sMaterial = cString::SetFileExt(sMaterial, "mat"); iMaterial *pMaterial = mpResources->GetMaterialManager()->CreateMaterial(sMaterial); if (pMaterial) mvMaterials.push_back(pMaterial); } else { for (int i = 1; i < lMaterialNum + 1; ++i) { tString sFileName; if (i > 9) sFileName = sMaterial + cString::ToString(i); else sFileName = sMaterial + "0" + cString::ToString(i); sFileName = cString::SetFileExt(sFileName, "mat"); iMaterial *pMaterial = mpResources->GetMaterialManager()->CreateMaterial(sFileName); if (pMaterial) mvMaterials.push_back(pMaterial); } } mfFrameStep = 1 / (fAnimationLength / (float)mvMaterials.size()); mfMaxFrameTime = ((float)mvMaterials.size()) - 0.0001f; ///////// START POS ////////// mStartPosType = GetStartPosType(apElement->Attribute("StartPosType")); mvMinStartPos = cString::ToVector3f(apElement->Attribute("MinStartPos"), 0); mvMaxStartPos = cString::ToVector3f(apElement->Attribute("MaxStartPos"), 0); mvMinStartAngles = cString::ToVector2f(apElement->Attribute("MinStartAngles"), 0); mvMaxStartAngles = cString::ToVector2f(apElement->Attribute("MaxStartAngles"), 0); mvMinStartAngles.x = cMath::ToRad(mvMinStartAngles.x); mvMinStartAngles.y = cMath::ToRad(mvMinStartAngles.y); mvMaxStartAngles.x = cMath::ToRad(mvMaxStartAngles.x); mvMaxStartAngles.y = cMath::ToRad(mvMaxStartAngles.y); mfMinStartRadius = cString::ToFloat(apElement->Attribute("MinStartRadius"), 0); mfMaxStartRadius = cString::ToFloat(apElement->Attribute("MaxStartRadius"), 0); // NEW // cMesh *mshTempMesh = mpResources->GetMeshManager()->CreateMesh("character_roach.dae"); // mVBMeshData = mshTempMesh->GetSubMeshName("polySurfaceShape38")->GetVertexBuffer(); // mpfMeshVtxData = mVBMeshData->GetArray(eVertexFlag_Position); // --- /////////// MOVEMENT //////// mStartVelType = GetStartPosType(apElement->Attribute("StartVelType")); mvMinStartVel = cString::ToVector3f(apElement->Attribute("MinStartVel"), 0); mvMaxStartVel = cString::ToVector3f(apElement->Attribute("MaxStartVel"), 0); mvMinStartVelAngles = cString::ToVector2f(apElement->Attribute("MinStartVelAngles"), 0); mvMaxStartVelAngles = cString::ToVector2f(apElement->Attribute("MaxStartVelAngles"), 0); mvMinStartVelAngles.x = cMath::ToRad(mvMinStartVelAngles.x); mvMinStartVelAngles.y = cMath::ToRad(mvMinStartVelAngles.y); mvMaxStartVelAngles.x = cMath::ToRad(mvMaxStartVelAngles.x); mvMaxStartVelAngles.y = cMath::ToRad(mvMaxStartVelAngles.y); mfMinStartVelSpeed = cString::ToFloat(apElement->Attribute("MinStartVelSpeed"), 0); mfMaxStartVelSpeed = cString::ToFloat(apElement->Attribute("MaxStartVelSpeed"), 0); mfMinSpeedMultiply = cString::ToFloat(apElement->Attribute("MinSpeedMultiply"), 0); mfMaxSpeedMultiply = cString::ToFloat(apElement->Attribute("MaxSpeedMultiply"), 0); mvMinStartAcc = cString::ToVector3f(apElement->Attribute("MinStartAcc"), 0); mvMaxStartAcc = cString::ToVector3f(apElement->Attribute("MaxStartAcc"), 0); mfMinVelMaximum = cString::ToFloat(apElement->Attribute("MinVelMaximum"), 0); mfMaxVelMaximum = cString::ToFloat(apElement->Attribute("MaxVelMaximum"), 0); mbUsesDirection = cString::ToBool(apElement->Attribute("UsesDirection"), false); mGravityType = GetGravityType(apElement->Attribute("GravityType")); mvGravityAcc = cString::ToVector3f(apElement->Attribute("GravityAcc"), 0); mCoordSystem = GetCoordSystem(apElement->Attribute("CoordSystem")); // NEW mbUsePartSpin = cString::ToBool(apElement->Attribute("UsePartSpin"), false); mPartSpinType = GetPartSpinType(apElement->Attribute("PartSpinType")); mfMinSpinRange = cString::ToFloat(apElement->Attribute("MinSpinRange"), 0); mfMaxSpinRange = cString::ToFloat(apElement->Attribute("MaxSpinRange"), 0); mbUseRevolution = cString::ToBool(apElement->Attribute("UseRevolution"), false); mvMinRevVel = cString::ToVector3f(apElement->Attribute("MinRevVel"), 0); mvMaxRevVel = cString::ToVector3f(apElement->Attribute("MaxRevVel"), 0); // --- /////////// LIFESPAN //////// mfMinLifeSpan = cString::ToFloat(apElement->Attribute("MinLifeSpan"), 0); mfMaxLifeSpan = cString::ToFloat(apElement->Attribute("MaxLifeSpan"), 0); mDeathType = GetDeathType(apElement->Attribute("DeathType")); msDeathPS = cString::ToString(apElement->Attribute("DeathPS"), ""); /////////// RENDERING //////// mDrawType = GetDrawType(apElement->Attribute("DrawType")); // eParticleEmitter3DType Heading // cVector2l subdivisions. mvMinStartSize = cString::ToVector2f(apElement->Attribute("MinStartSize"), 1); mvMaxStartSize = cString::ToVector2f(apElement->Attribute("MaxStartSize"), 1); mfStartRelSize = cString::ToFloat(apElement->Attribute("StartRelSize"), 0); mfMiddleRelSize = cString::ToFloat(apElement->Attribute("MiddleRelSize"), 0); mfMiddleRelSizeTime = cString::ToFloat(apElement->Attribute("MiddleRelSizeTime"), 0); mfMiddleRelSizeLength = cString::ToFloat(apElement->Attribute("MiddleRelSizeLength"), 0); mfEndRelSize = cString::ToFloat(apElement->Attribute("EndRelSize"), 0); mbMultiplyRGBWithAlpha = cString::ToBool(apElement->Attribute("MultiplyRGBWithAlpha"), false); /////////// COLOR //////// mMinStartColor = cString::ToColor(apElement->Attribute("MinStartColor"), cColor(1, 1)); mMaxStartColor = cString::ToColor(apElement->Attribute("MaxStartColor"), cColor(1, 1)); mStartRelColor = cString::ToColor(apElement->Attribute("StartRelColor"), cColor(1, 1)); mMiddleRelColor = cString::ToColor(apElement->Attribute("MiddleRelColor"), cColor(1, 1)); mfMiddleRelColorTime = cString::ToFloat(apElement->Attribute("MiddleRelColorTime"), 0); mfMiddleRelColorLength = cString::ToFloat(apElement->Attribute("MiddleRelColorLength"), 0); mEndRelColor = cString::ToColor(apElement->Attribute("EndRelColor"), cColor(1, 1)); /////////// COLLISION //////// mbCollides = cString::ToBool(apElement->Attribute("Collides"), false); mfMinBounceAmount = cString::ToFloat(apElement->Attribute("MinBounceAmount"), 0); mfMaxBounceAmount = cString::ToFloat(apElement->Attribute("MaxBounceAmount"), 0); mlMinCollisionMax = cString::ToInt(apElement->Attribute("MinCollisionMax"), 0); mlMaxCollisionMax = cString::ToInt(apElement->Attribute("MaxCollisionMax"), 0); mlCollisionUpdateRate = cString::ToInt(apElement->Attribute("CollisionUpdateRate"), 0); // NEW ////////// BEAM SPECIFIC ////////// mbUseBeamNoise = cString::ToBool(apElement->Attribute("UseBeamNoise"), false); mlLowFreqPoints = cString::ToInt(apElement->Attribute("LowFreqPoints"), 4); mlHighFreqPoints = cString::ToInt(apElement->Attribute("HighFreqPoints"), 5); mvMinLowFreqNoise = cString::ToVector3f(apElement->Attribute("MinLowFreqNoise"), 0); mvMaxLowFreqNoise = cString::ToVector3f(apElement->Attribute("MaxLowFreqNoise"), 0); mvMinHighFreqNoise = cString::ToVector3f(apElement->Attribute("MinHighFreqNoise"), 0); mvMaxHighFreqNoise = cString::ToVector3f(apElement->Attribute("MaxHighFreqNoise"), 0); // --- } //----------------------------------------------------------------------- bool cParticleEmitterData3D_UserData::OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams) { if (pBody->IsActive() == false || pBody->GetCollide() == false || pBody->IsCharacter()) { return true; } if (mfShortestDist > apParams->mfDist) { mbIntersected = true; mfShortestDist = apParams->mfDist; *mpIntersectPos = apParams->mvPoint; *mpIntersectNormal = apParams->mvNormal; } return true; } bool cParticleEmitterData3D_UserData::CheckCollision(const cVector3f &avStart, const cVector3f &avEnd, iPhysicsWorld *apPhysicsWorld, cVector3f *apNormalVec, cVector3f *apPosVec) { mfShortestDist = 99999.0f; mbIntersected = false; mpIntersectPos = apPosVec; mpIntersectNormal = apNormalVec; apPhysicsWorld->CastRay(this, avStart, avEnd, true, true, true); return mbIntersected; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cParticleEmitter3D_UserData::cParticleEmitter3D_UserData( tString asName, tMaterialVec *apMaterials, cVector3f avSize, cGraphics *apGraphics, cResources *apResources, cParticleEmitterData3D_UserData *apData) : iParticleEmitter3D(asName, apMaterials, apData->mlMaxParticleNum, avSize, apGraphics, apResources) { mpData = apData; mvDrawSize = 1; mfTime = 0; mfCreateCount = 0; mfPauseCount = 0; mfPauseWaitCount = 0; mbPaused = false; mfCollideCount = 1.0f / (float)mpData->mlCollisionUpdateRate; mCoordSystem = apData->mCoordSystem; mDrawType = apData->mDrawType; mbUsesDirection = apData->mbUsesDirection; // mbDying = !apData->mbRespawn; mbRespawn = apData->mbRespawn; SetSubDivUV(mpData->mvSubDiv); // NEW mbUsePartSpin = apData->mbUsePartSpin; mbUseRevolution = apData->mbUseRevolution; mPEType = apData->mPEType; // Calculate max size of particles. float fSizeMul = apData->mfStartRelSize; if (fSizeMul < apData->mfMiddleRelSize) fSizeMul = apData->mfMiddleRelSize; if (fSizeMul < apData->mfEndRelSize) fSizeMul = apData->mfEndRelSize; mvMaxDrawSize = apData->mvMaxStartSize * fSizeMul; /* int i = 0; int j = 0; int k = 0; switch ( mPEType ) { case ePEType_Beam: hplDelete(mpVtxBuffer); // Destroy the current Vertex Buffer, as it's filled with quads we don't need now :) if ( apData->mbUseBeamNoise ) { // Calculate the Frequency Points Lookup Table, this is needed to create the Vertex Buffer.It is also needed by every beam particle created, // as it needs to know the type and index of each when updating. while ( (i < apData->mlLowFreqPoints) && (j < apData->mlHighFreqPoints) ) { float fLowRelPos = (float) i / (apData->mlLowFreqPoints -1 ); float fHighRelPos = (float) j / (apData->mlHighFreqPoints -1 ); float fLastLowRelPos = 0.0f; tBeamNoisePoint tempBNP; // tempBNP.lLowFreqNoiseIdx = i; // tempBNP.lHighFreqNoiseIdx = j; tempBNP.fRelToBendPos = (fHighRelPos-fLastLowRelPos)/(fLowRelPos-fLastLowRelPos); if ( fLowRelPos <= fHighRelPos ) { if ( fLowRelPos == fHighRelPos ) { tempBNP.noiseType = ePENoiseType_Both; ++i; ++j; } else { tempBNP.noiseType = ePENoiseType_LowFreq; ++i; } tempBNP.fRelToBeamPos = fLowRelPos; apData->mvLFIndices.push_back (k); } else { tempBNP.fRelToBeamPos = fHighRelPos; tempBNP.noiseType = ePENoiseType_HighFreq; ++j; } fLastLowRelPos = fLowRelPos; mpData->mvBeamNoisePoints.push_back(tempBNP); ++k; } } else { tBeamNoisePoint tempBNP; tempBNP.fRelToBeamPos = 0.0f; tempBNP.fRelToBendPos = 0.0f; tempBNP.noiseType = ePENoiseType_None; mpData->mvBeamNoisePoints.push_back(tempBNP); tempBNP.fRelToBeamPos = 1.0f; tempBNP.fRelToBendPos = 1.0f; tempBNP.noiseType = ePENoiseType_None; mpData->mvBeamNoisePoints.push_back(tempBNP); } mpVtxBuffer = apGraphics->GetLowLevel()->CreateVertexBuffer ( eVertexFlag_Position, // Now that we know how many points we have, we create the Vertex Buffer eVertexBufferDrawType_Tri, eVertexBufferUsageType_Stream, mlMaxParticles*mpData->mvBeamNoisePoints.size()*2, mlMaxParticles*(mpData->mvBeamNoisePoints.size()-1)*6); for ( int i = 0; i < (int) mlMaxParticles; ++i ) { for ( int j = 0; j < (int) mpData->mvBeamNoisePoints.size()-1; ++j ) { int lStart = j*2; mpVtxBuffer->AddIndex(lStart); // Half quad ( tri ) mpVtxBuffer->AddIndex(lStart+1); mpVtxBuffer->AddIndex(lStart+3); mpVtxBuffer->AddIndex(lStart+3); // The other half mpVtxBuffer->AddIndex(lStart+2); mpVtxBuffer->AddIndex(lStart); } } for ( int i = 0; i < (int) mlMaxParticles; ++i ) { for (int j = 0; j < (int) mpData->mvBeamNoisePoints.size(); ++j ) { mpVtxBuffer->AddVertex(eVertexFlag_Texture0, cVector2f(mpData->mvBeamNoisePoints[j].fRelToBeamPos,1)); mpVtxBuffer->AddVertex(eVertexFlag_Texture0, cVector2f(mpData->mvBeamNoisePoints[j].fRelToBeamPos,0)); } } for ( int i = 0; i < (int) mlMaxParticles; ++i ) { for (int j = 0; j < (int) mpData->mvBeamNoisePoints.size()*2; ++j ) { mpVtxBuffer->AddVertex(eVertexFlag_Position, 0); mpVtxBuffer->AddColor(eVertexFlag_Color0, cColor(1,1)); } } mpVtxBuffer->Compile(0); break; case ePEType_Normal: break; default: break; } */ // --- } //----------------------------------------------------------------------- cParticleEmitter3D_UserData::~cParticleEmitter3D_UserData() { } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- bool cParticleEmitter3D_UserData::IsDying() { if (mbRespawn == false || mbDying) return true; return false; } //----------------------------------------------------------------------- void cParticleEmitter3D_UserData::Kill() { mbRespawn = false; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cParticleEmitter3D_UserData::SetParticleDefaults(cParticle *apParticle) { /////////////////////////////////// // Start Color apParticle->mStartColor = cMath::RandRectColor(mpData->mMinStartColor, mpData->mMaxStartColor); apParticle->mColor = apParticle->mStartColor * mpData->mStartRelColor; /////////////////////////////////// // Start Size if (mpData->mvMinStartSize.y == 0 && mpData->mvMaxStartSize.y == 0) apParticle->mvStartSize = cMath::RandRectf(mpData->mvMinStartSize.x, mpData->mvMaxStartSize.x); else apParticle->mvStartSize = cMath::RandRectVector2f(mpData->mvMinStartSize, mpData->mvMaxStartSize); apParticle->mvSize = apParticle->mvStartSize * mpData->mfStartRelSize; //////////////////////////////////// // Start sub division if (mvSubDivUV.size() > 1) { if (mpData->mSubDivType == ePESubDivType_Animation) { apParticle->mlSubDivNum = 0; } else { apParticle->mlSubDivNum = cMath::RandRectl(0, (int)mvSubDivUV.size() - 1); } } //////////////////////////////////// // Start collision apParticle->mfBounceAmount = cMath::RandRectf(mpData->mfMinBounceAmount, mpData->mfMaxBounceAmount); apParticle->mlBounceCount = cMath::RandRectl(mpData->mlMinCollisionMax, mpData->mlMaxCollisionMax); //////////////////////////////////// // Start Position // Matrix to start from cMatrixf mtxStart; if (mpData->mCoordSystem == eParticleEmitter3DCoordSystem_World) { mtxStart = GetWorldMatrix(); } else { // Not what should be here, perhaps only identity. mtxStart = GetLocalMatrix(); } // Sphere or box start if (mpData->mStartPosType == ePEStartPosType_Box) { apParticle->mvPos = mtxStart.GetTranslation() + cMath::RandRectVector3f(mpData->mvMinStartPos, mpData->mvMaxStartPos); } else if (mpData->mStartPosType == ePEStartPosType_Sphere) { cVector2f vRot = cMath::RandRectVector2f(mpData->mvMinStartAngles, mpData->mvMaxStartAngles); cMatrixf mtxRot = cMath::MatrixRotate(vRot, eEulerRotationOrder_XYZ); cVector3f vPos = cVector3f(0, cMath::RandRectf(mpData->mfMinStartRadius, mpData->mfMaxStartRadius), 0); apParticle->mvPos = mtxStart.GetTranslation() + cMath::MatrixMul(mtxRot, vPos); } // NEW // if (mpData->mVBMeshData) // { /* cVector3f vTrans = mtxStart.GetTranslation(); posI = cMath::RandRectl(0,mpData->mVBMeshData->GetVertexNum()-1); vTrans.x += mpData->mpfMeshVtxData[posI*4]; vTrans.y += mpData->mpfMeshVtxData[posI*4 + 1]; vTrans.z += mpData->mpfMeshVtxData[posI*4 + 2]; apParticle->mvPos = vTrans; */ // apParticle->mvPos = mtxStart.GetTranslation() + mpData->mVBMeshData->GetVector3( eVertexFlag_Position, cMath::RandRectl(0,mpData->mVBMeshData->GetVertexNum()-1) ); // ++posI; // if ( posI == mpData->mVBMeshData->GetVertexNum() ) // posI = 0; // } // --- apParticle->mvLastPos = apParticle->mvPos; apParticle->mvLastCollidePos = apParticle->mvPos; //////////////////////////////////// // Start Velocity // Sphere or box start if (mpData->mStartVelType == ePEStartPosType_Box) { apParticle->mvVel = cMath::RandRectVector3f(mpData->mvMinStartVel, mpData->mvMaxStartVel); } else if (mpData->mStartVelType == ePEStartPosType_Sphere) { cVector2f vRot = cMath::RandRectVector2f(mpData->mvMinStartVelAngles, mpData->mvMaxStartVelAngles); cMatrixf mtxRot = cMath::MatrixRotate(vRot, eEulerRotationOrder_XYZ); cVector3f vPos = cVector3f(0, cMath::RandRectf(mpData->mfMinStartVelSpeed, mpData->mfMaxStartVelSpeed), 0); apParticle->mvVel = cMath::MatrixMul(mtxRot, vPos); } // If it uses the direction, if (mpData->mbUsesDirection && mpData->mCoordSystem == eParticleEmitter3DCoordSystem_World) { apParticle->mvVel = cMath::MatrixMul(mtxStart.GetRotation(), apParticle->mvVel); } apParticle->mfMaxSpeed = cMath::RandRectf(mpData->mfMinVelMaximum, mpData->mfMaxVelMaximum); apParticle->mfSpeedMul = cMath::RandRectf(mpData->mfMinSpeedMultiply, mpData->mfMaxSpeedMultiply); //////////////////////////////////// // Start Acceleration apParticle->mvAcc = cMath::RandRectVector3f(mpData->mvMinStartAcc, mpData->mvMaxStartAcc); // NEW //////////////////////////////////// // Start Spin Velocity if (mpData->mPartSpinType == ePEPartSpinType_Constant) { apParticle->mfSpinVel = cMath::RandRectf(mpData->mfMinSpinRange, mpData->mfMaxSpinRange); } else if (mpData->mPartSpinType == ePEPartSpinType_Movement) { apParticle->mfSpinFactor = cMath::RandRectf(mpData->mfMinSpinRange, mpData->mfMaxSpinRange); apParticle->mfSpinVel = 0.0f; } apParticle->mfSpin = cMath::RandRectf(0.0f, k2Pif); //////////////////////////////////// // Start Revolution Velocity apParticle->mvRevolutionVel = cMath::RandRectVector3f(mpData->mvMinRevVel, mpData->mvMaxRevVel); // --- /////////////////////////////////// // Life Span apParticle->mfStartLife = cMath::RandRectf(mpData->mfMinLifeSpan, mpData->mfMaxLifeSpan); apParticle->mfLife = apParticle->mfStartLife; apParticle->mfLifeSize_MiddleStart = apParticle->mfLife * (1 - mpData->mfMiddleRelSizeTime); apParticle->mfLifeSize_MiddleEnd = apParticle->mfLife * (1 - (mpData->mfMiddleRelSizeTime + mpData->mfMiddleRelSizeLength)); apParticle->mfLifeColor_MiddleStart = apParticle->mfLife * (1 - mpData->mfMiddleRelColorTime); apParticle->mfLifeColor_MiddleEnd = apParticle->mfLife * (1 - (mpData->mfMiddleRelColorTime + mpData->mfMiddleRelColorLength)); /*Log("Created particle with Pos: (%s) Color: (%s) Size (%s) Vel: (%s) Acc: (%s) Life: %f SizeMiddleStart: %f SizeMiddleEnd: %f\n", apParticle->mvPos.ToString().c_str(), apParticle->mColor.ToString().c_str(), apParticle->mvSize.ToString().c_str(), apParticle->mvVel.ToString().c_str(), apParticle->mvAcc.ToString().c_str(), apParticle->mfLife, apParticle->mfLifeSize_MiddleStart, apParticle->mfLifeSize_MiddleEnd);*/ // NEW ///////////////////////////////////// // Beam Specific if (mPEType == ePEType_Beam) { /* if (apParticle->mvBeamPoints.size() == 0 ) { for (int i = 0; i < (int) mpData->mvBeamNoisePoints.size(); ++i) apParticle->mvBeamPoints.push_back(cVector(0.0f)); } int j = 1; cVector3f vLFPointPos = apParticle->mvPos + apParticle->mvVel * mpData->mvBeamNoisePoints.at(mpData->mvLFIndices[j]).fRelToBeamPos; cVector3f vLastLFPointPos = apParticle->mvPos; cVector3f vDir; for ( int i = 1; i < (int) mpData->mvBeamNoisePoints.size(); ++i ) { apParticle->mvBeamPoints[i] = vLastLFPointPos + vDir * mpData->mvBeamNoisePoints[i].fRelToBendPos; switch (mpData->mvBeamNoisePoints[i].noiseType) { case ePENoiseType_HighFreq: apParticle->mvBeamPoints[i] += cMath::RandRectVector3f(mpData->mvMinHighFreqNoise, mpData->mvMaxHighFreqNoise); break; case ePENoiseType_LowFreq: ++j; vLastLFPointPos = vLFPointPos; vLFPointPos = apParticle->mvPos + apParticle->mvVel * mpData->mvBeamNoisePoints.at(mpData->mvLFIndices[j]).fRelToBeamPos + cMath::RandRectVector3f(mpData->mvMinLowFreqNoise, mpData->mvMaxLowFreqNoise); vDir = vLFPointPos - vLastLFPointPos; break; case ePENoiseType_Both: apParticle->mvBeamPoints[i] += cMath::RandRectVector3f(mpData->mvMinHighFreqNoise, mpData->mvMaxHighFreqNoise); ++j; vLastLFPointPos = vLFPointPos; vLFPointPos = apParticle->mvPos + apParticle->mvVel * mpData->mvBeamNoisePoints.at(mpData->mvLFIndices[j]).fRelToBeamPos + cMath::RandRectVector3f(mpData->mvMinLowFreqNoise, mpData->mvMaxLowFreqNoise); vDir = vLFPointPos - vLastLFPointPos; break; default: break; } } */ } // --- } //----------------------------------------------------------------------- void cParticleEmitter3D_UserData::UpdateMotion(float afTimeStep) { /////////////////////////////////////////////// // If not rendered this previous frame check if it should be paused. // To be safe skip systems that has a parent... if (mbDying == false && mbRespawn && mpParentSystem->GetParent() == NULL) { if (GetGlobalRenderCount() != cRenderList::GetGlobalRenderCount()) { if (mlUpdateCount > 120) { return; } mlUpdateCount++; } else { mlUpdateCount = 0; } } /////////////////////////////////////////// // Check if the emitter is ready to start. if (mfTime < mpData->mfStartTimeOffset) { mfTime += afTimeStep; return; } /////////////////////////////////////////// // Delay check if (mbPaused) { mfPauseCount -= afTimeStep; if (mfPauseCount <= 0) { mbPaused = false; mfPauseWaitCount = cMath::RandRectf(mpData->mfMinPauseInterval, mpData->mfMaxPauseInterval); } } else if (mpData->mfMinPauseLength > 0 && mpData->mfMinPauseInterval > 0) { mfPauseWaitCount -= afTimeStep; if (mfPauseWaitCount <= 0) { mfPauseCount = cMath::RandRectf(mpData->mfMinPauseLength, mpData->mfMaxPauseLength); mbPaused = true; } } /////////////////////////////////////////// // Particle creation if (mbPaused == false && mlNumOfParticles < mlMaxParticles) { mfCreateCount += mpData->mfParticlesPerSecond * afTimeStep; while (mfCreateCount >= 0.99999f && (mlNumOfParticles < mlMaxParticles)) { SetParticleDefaults(CreateParticle()); mfCreateCount -= 1.0f; } } /////////////////////////////////////////// // Collision Update bool bColliding = false; if (mpData->mbCollides) { mfCollideCount -= afTimeStep; if (mfCollideCount <= 0) { mfCollideCount = 1.0f / (float)mpData->mlCollisionUpdateRate; bColliding = true; } } /////////////////////////////////////////// // Particle update for (unsigned int i = 0; i < mlNumOfParticles; ++i) { cParticle *pParticle = mvParticles[i]; //////////// // Position Update pParticle->mvLastPos = pParticle->mvPos; pParticle->mvPos += pParticle->mvVel * afTimeStep; //////////// // Speed Update pParticle->mvVel += pParticle->mvAcc * afTimeStep; // gravity switch (mpData->mGravityType) { case ePEGravityType_None: { break; } case ePEGravityType_Vector: { pParticle->mvVel += mpData->mvGravityAcc * afTimeStep; break; } case ePEGravityType_Center: { cVector3f vDir; cMatrixf mtxStart; if (mpData->mCoordSystem == eParticleEmitter3DCoordSystem_World) { vDir = pParticle->mvPos - GetWorldMatrix().GetTranslation(); } else { // Perhaps on mvPos is needed.. and no subtraction. vDir = pParticle->mvPos - GetLocalMatrix().GetTranslation(); } vDir.Normalise(); pParticle->mvVel += vDir * mpData->mvGravityAcc.y * afTimeStep; break; } case ePEGravityType_LastEnum: break; } if (pParticle->mfMaxSpeed > 0) { float fSpeed = pParticle->mvVel.Length(); if (fSpeed > pParticle->mfMaxSpeed) { pParticle->mvVel = (pParticle->mvVel / fSpeed) * pParticle->mfMaxSpeed; } } if (pParticle->mfSpeedMul != 0 && pParticle->mfSpeedMul != 1) { pParticle->mvVel = pParticle->mvVel * pow(pParticle->mfSpeedMul, afTimeStep); } // NEW /////////// // Spin Update if (mpData->mbUsePartSpin) { pParticle->mfSpin += pParticle->mfSpinVel * afTimeStep; if (mpData->mPartSpinType == ePEPartSpinType_Movement) pParticle->mfSpinVel = pParticle->mvVel.Length() * pParticle->mfSpinFactor; if (pParticle->mfSpin >= k2Pif) pParticle->mfSpin -= k2Pif; else if (pParticle->mfSpin <= -k2Pif) pParticle->mfSpin += k2Pif; } // --- // NEW // Revolution if (mbUseRevolution) { // pParticle->mvRevolution += pParticle->mvRevolutionVel * afTimeStep; cMatrixf mtxRotationMatrix = cMath::MatrixRotate(pParticle->mvRevolutionVel * afTimeStep, eEulerRotationOrder_XYZ); pParticle->mvPos = cMath::MatrixMul(mtxRotationMatrix, pParticle->mvPos); pParticle->mvVel = cMath::MatrixMul(mtxRotationMatrix, pParticle->mvVel); } // --- //////////// // Collison update if (bColliding) { cVector3f vPos, vNormal; if (mpData->CheckCollision(pParticle->mvLastCollidePos, pParticle->mvPos, mpWorld->GetPhysicsWorld(), &vNormal, &vPos)) { // Log("Coll pos: %s\n",vPos.ToString().c_str()); // Log("Coll normal: %s\n",vNormal.ToString().c_str()); pParticle->mvPos = vPos; float fSpeed = pParticle->mvVel.Length(); cVector3f vReflection = pParticle->mvVel - (vNormal * 2 * cMath::Vector3Dot(pParticle->mvVel, vNormal)); vReflection.Normalise(); pParticle->mvVel = vReflection * (fSpeed * pParticle->mfBounceAmount); pParticle->mlBounceCount--; if (pParticle->mlBounceCount <= 0) { pParticle->mfLife = 0; } } pParticle->mvLastCollidePos = pParticle->mvPos; } //////////// // Life Update pParticle->mfLife -= afTimeStep; if (pParticle->mfLife <= 0) { if (mbRespawn) { if (mbPaused) SwapRemove(i); else SetParticleDefaults(pParticle); } else { SwapRemove(i); mlMaxParticles--; if (mlMaxParticles <= 0) { mbDying = true; } } } //////////// // Subdiv Update if (mpData->mSubDivType == ePESubDivType_Animation) { float fLifePercent = (1.0f - (pParticle->mfLife / pParticle->mfStartLife)); pParticle->mlSubDivNum = (int)(fLifePercent * (float)mvSubDivUV.size() - 0.0001f); } //////////// // Color Update // Start if (pParticle->mfLife > pParticle->mfLifeColor_MiddleStart) { float fT = (pParticle->mfLife - pParticle->mfLifeColor_MiddleStart) / (pParticle->mfStartLife - pParticle->mfLifeColor_MiddleStart); pParticle->mColor = (pParticle->mStartColor * mpData->mStartRelColor * fT) + (pParticle->mStartColor * mpData->mMiddleRelColor * (1 - fT)); } // Middle else if (pParticle->mfLife > pParticle->mfLifeColor_MiddleEnd) { pParticle->mColor = pParticle->mStartColor * mpData->mMiddleRelColor; } // End else { float fT = pParticle->mfLife / pParticle->mfLifeColor_MiddleEnd; pParticle->mColor = (pParticle->mStartColor * mpData->mMiddleRelColor * fT) + (pParticle->mStartColor * mpData->mEndRelColor * (1 - fT)); } if (mpData->mbMultiplyRGBWithAlpha) { pParticle->mColor.r *= pParticle->mColor.a; pParticle->mColor.g *= pParticle->mColor.a; pParticle->mColor.b *= pParticle->mColor.a; } //////////// // Size Update // Start if (pParticle->mfLife > pParticle->mfLifeSize_MiddleStart) { float fT = (pParticle->mfLife - pParticle->mfLifeSize_MiddleStart) / (pParticle->mfStartLife - pParticle->mfLifeSize_MiddleStart); pParticle->mvSize = (pParticle->mvStartSize * mpData->mfStartRelSize * fT) + (pParticle->mvStartSize * mpData->mfMiddleRelSize * (1 - fT)); } // Middle else if (pParticle->mfLife > pParticle->mfLifeSize_MiddleEnd) { pParticle->mvSize = pParticle->mvStartSize * mpData->mfMiddleRelSize; } // End else { float fT = pParticle->mfLife / pParticle->mfLifeSize_MiddleEnd; pParticle->mvSize = (pParticle->mvStartSize * mpData->mfMiddleRelSize * fT) + (pParticle->mvStartSize * mpData->mfEndRelSize * (1 - fT)); } } /////////////////////////////////////////// // Frame Update if (mvMaterials->size() > 1) { mfFrame += mpData->mfFrameStep * afTimeStep; if (mfFrame >= mpData->mfMaxFrameTime) { mfFrame = 0; } } } //----------------------------------------------------------------------- } // namespace hpl