LTBOOL ScaleSprite::Update() { if (m_bStartOn) { g_pCommonLT->SetObjectFlags(m_hObject, OFT_User, USRFLG_VISIBLE, USRFLG_VISIBLE); g_pCommonLT->SetObjectFlags(m_hObject, OFT_Flags, FLAG_VISIBLE, FLAG_VISIBLE); } SetNextUpdate(UPDATE_NEVER); // BUG - This isn't quite right. Sometimes this works (flipping the sprite) // other times the sprite shouldn't be flipped...Not sure what the bug is. // For some reason the sprites are sometimes backwards...Get the rotation // so we can flip it... LTRotation rRot; LTVector vPos, vDir, vU, vR, vF; g_pLTServer->GetObjectPos(m_hObject, &vPos); g_pLTServer->GetObjectRotation(m_hObject, &rRot); vU = rRot.Up(); vR = rRot.Right(); vF = rRot.Forward(); if (m_bFlushWithWorld) { // Align the sprite to the surface directly behind the sprite // (i.e., opposite the forward vector)... VEC_NORM(vF); VEC_MULSCALAR(vDir, vF, -1.0f); // Determine where on the surface to place the sprite... IntersectInfo iInfo; IntersectQuery qInfo; VEC_COPY(qInfo.m_From, vPos); VEC_COPY(qInfo.m_Direction, vDir); qInfo.m_Flags = IGNORE_NONSOLID | INTERSECT_OBJECTS | INTERSECT_HPOLY; qInfo.m_FilterFn = LTNULL; if (g_pLTServer->CastRay(&qInfo, &iInfo)) { LTVector vTemp; VEC_COPY(vPos, iInfo.m_Point); VEC_COPY(vDir, iInfo.m_Plane.m_Normal); // Place the sprite just above the surface... VEC_MULSCALAR(vTemp, vDir, 1.0f); VEC_ADD(vPos, vPos, vTemp); g_pLTServer->SetObjectPos(m_hObject, &vPos); } } return LTTRUE; }
bool CFallingStuffFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { // Perform base class initialisation if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) return false; // Store the first position as the last position m_vLastPos = pBaseData->m_vPos; // If we have a parent object, get it and apply it's rotation // to the plane direction m_vPlaneDir = GetProps()->m_vPlaneDir; if (m_hParent) { LTRotation orient; m_pLTClient->GetObjectRotation(m_hParent, &orient); LTMatrix mRot; Mat_SetBasisVectors(&mRot, &orient.Right(), &orient.Up(), &orient.Forward()); LTVector vTmp = m_vPlaneDir; MatVMul(&m_vPlaneDir, &mRot, &vTmp); } LTVector vUp; vUp.x = 0.0f; vUp.y = 1.0f; vUp.z = 0.0f; LTVector vTest = m_vPlaneDir; vTest.x = (float)fabs(vTest.x); vTest.y = (float)fabs(vTest.y); vTest.z = (float)fabs(vTest.z); if (vTest == vUp) { // Gotsta use another axis vUp.x = -1.0f; vUp.y = 0.0f; vUp.z = 0.0f; } m_vRight = m_vPlaneDir.Cross(vUp); m_vUp = m_vPlaneDir.Cross(m_vRight); // Create the base object CreateDummyObject(); // Success !! return true; }
LTBOOL CLaserTriggerFX::CalcBeamCoords() { if (!m_hServerObject) return LTFALSE; // The beam is relative to the server object's dims... LTVector vPos; g_pLTClient->GetObjectPos(m_hServerObject, &vPos); LTRotation rRot; g_pLTClient->GetObjectRotation(m_hServerObject, &rRot); LTVector vU, vR, vF; vU = rRot.Up(); vR = rRot.Right(); vF = rRot.Forward(); // Okay, the beam is always along the object's longest dim... LTVector vDir = vF; LTFLOAT fLongestDim = m_cs.vDims.z; // Assume forward first... m_pls.fMaxWidth = (m_cs.vDims.x + m_cs.vDims.y); // Assume x/y are same... if (m_cs.vDims.y > fLongestDim) { vDir = vU; fLongestDim = m_cs.vDims.y; m_pls.fMaxWidth = (m_cs.vDims.x + m_cs.vDims.z); } if (m_cs.vDims.x > fLongestDim) { vDir = vR; fLongestDim = m_cs.vDims.x; m_pls.fMaxWidth = (m_cs.vDims.y + m_cs.vDims.z); } m_pls.vStartPos = vPos + (vDir * fLongestDim); m_pls.vEndPos = vPos - (vDir * fLongestDim); return LTTRUE; }
void CFlashLight3rdPerson::GetLightPositions(LTVector& vStartPos, LTVector& vEndPos, LTVector& vUOffset, LTVector& vROffset) { if ( !m_hObj ) return; HMODELSOCKET hSocket; if ( LT_OK == g_pModelLT->GetSocket(m_hObj, "LeftHand", hSocket) ) { LTransform tf; if ( LT_OK == g_pModelLT->GetSocketTransform(m_hObj, hSocket, tf, LTTRUE) ) { LTVector vPos = tf.m_Pos; LTRotation rRot = tf.m_Rot; LTVector vRight, vUp, vForward; vRight = rRot.Right(); vUp = rRot.Up(); vForward = rRot.Forward(); //vStartPos = vPos - vUp*4.0f + vForward*8.0f; //vEndPos = vPos + vForward*200.0f; //vUOffset = vUp; //vROffset = vRight; vStartPos = vPos; vEndPos = vPos + (vForward * g_cvarFLLightOffsetForward.GetFloat()); vROffset = (vRight * g_cvarFLLightOffsetRight.GetFloat()); vUOffset = (vUp * g_cvarFLLightOffsetUp.GetFloat()); // Update the Start/End position to addjust for any offset... vEndPos += vROffset; vEndPos += vUOffset; vStartPos += vROffset; vStartPos += vUOffset; } } }
void CLaserBeam::Update(LTVector &vBeamStartPos, const LTRotation* pRDirRot, LTBOOL b3rdPerson, LTBOOL bDetect) { if (!m_bOn) return; // Calculate beam position... HOBJECT hCamera = g_pPlayerMgr->GetCamera(); if (!hCamera) return; HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (!hPlayerObj) return; HOBJECT hFilterList[] = {hPlayerObj, g_pPlayerMgr->GetMoveMgr()->GetObject(), LTNULL}; IntersectQuery qInfo; IntersectInfo iInfo; LTVector vPos(0, 0, 0); LTRotation rRot; LTVector vU, vR, vF; if (pRDirRot && b3rdPerson) { vPos = vBeamStartPos; vU = pRDirRot->Up(); vR = pRDirRot->Right(); vF = pRDirRot->Forward(); } else { g_pLTClient->GetObjectRotation(hCamera, &rRot); g_pLTClient->GetObjectPos(hCamera, &vPos); vU = rRot.Up(); vR = rRot.Right(); vF = rRot.Forward(); if (g_cvarLaserBeamDebug.GetFloat() == 0.0f) { vBeamStartPos += vPos; } else if (g_cvarLaserBeamDebug.GetFloat() == 1.0f) { vBeamStartPos = vPos; } else if (pRDirRot) { vU = pRDirRot->Up(); vR = pRDirRot->Right(); vF = pRDirRot->Forward(); vBeamStartPos = vBeamStartPos; } } LTVector vEndPos = vPos + (vF * 10000.0f); qInfo.m_From = vPos; qInfo.m_To = vEndPos; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; qInfo.m_FilterFn = ObjListFilterFn; qInfo.m_pUserData = hFilterList; if (g_pLTClient->IntersectSegment(&qInfo, &iInfo)) { vEndPos = iInfo.m_Point; } // Show the light beam... LTVector vColor = LTVector(GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f), GetRandom(35.0f, 55.0f));; LTFLOAT fAlpha = g_cvarLaserBeamAlpha.GetFloat(); if (iInfo.m_hObject && bDetect) { uint32 dwUsrFlgs = 0; g_pCommonLT->GetObjectFlags(iInfo.m_hObject, OFT_User, dwUsrFlgs); if (dwUsrFlgs & USRFLG_CHARACTER) { fAlpha = 0.95f; vColor.Init(GetRandom(35.0f, 55.0f), GetRandom(235.0f, 255.0f), GetRandom(35.0f, 55.0f));; } } LTFLOAT fWidth = g_cvarLaserBeamThickness.GetFloat(); fWidth = b3rdPerson ? fWidth*2.0f : fWidth; vBeamStartPos += (vF * g_cvarLaserBeamFOffset.GetFloat()); vBeamStartPos += (vR * g_cvarLaserBeamROffset.GetFloat()); vBeamStartPos += (vU * g_cvarLaserBeamUOffset.GetFloat()); PLFXCREATESTRUCT pls; if (g_cvarLaserBeamDebug.GetFloat() >= 0.0f) { // g_pLTClient->CPrint("StartPos = %.2f, %.2f, %.2f", VEC_EXPAND(vBeamStartPos)); // g_pLTClient->CPrint("EndPos = %.2f, %.2f, %.2f", VEC_EXPAND(vEndPos)); } pls.vStartPos = vBeamStartPos; pls.vEndPos = vEndPos; pls.vInnerColorStart = vColor; pls.vInnerColorEnd = pls.vInnerColorStart; pls.vOuterColorStart = LTVector(0, 0, 0); pls.vOuterColorEnd = LTVector(0, 0, 0); pls.fAlphaStart = fAlpha; pls.fAlphaEnd = fAlpha; pls.fMinWidth = 0; pls.fMaxWidth = fWidth; pls.fMinDistMult = 1.0f; pls.fMaxDistMult = 1.0f; pls.fLifeTime = 1.0f; pls.fAlphaLifeTime = 1.0f; pls.fPerturb = 0.0f; pls.bAdditive = LTTRUE; pls.bAlignFlat = b3rdPerson ? LTFALSE : LTTRUE; pls.nWidthStyle = PLWS_CONSTANT; pls.nNumSegments = (int)g_cvarLaserBeamNumSegments.GetFloat(); if (m_LightBeam.HasBeenDrawn()) { // Keep the light beam in the vis list... m_LightBeam.SetPos(vBeamStartPos); // Hide the beam in portals if 1st person...Also set flag really // close to true... uint32 dwFlags2, dwFlags; dwFlags = m_LightBeam.GetFlags(); dwFlags2 = m_LightBeam.GetFlags2(); if (b3rdPerson) { dwFlags &= ~FLAG_REALLYCLOSE; } else { if (g_cvarLaserBeamDebug.GetFloat() > 1.0f) { dwFlags |= FLAG_REALLYCLOSE; pls.bUseObjectRotation = LTTRUE; } } m_LightBeam.SetFlags(dwFlags); m_LightBeam.SetFlags2(dwFlags2); m_LightBeam.ReInit(&pls); } else { m_LightBeam.Init(&pls); m_LightBeam.CreateObject(g_pLTClient); } m_LightBeam.Update(); }
void CLightningFX::EmitBolts( float tmFrameTime ) { // Make sure enough time between emissions has passed... m_tmElapsedEmission += tmFrameTime; if( m_fDelay < m_tmElapsedEmission ) { LTransform lTrans; LTVector vAttractorPos; ILTModel *pModelLT = m_pLTClient->GetModelLT(); uint32 nActiveBolts = GetRandom( (int)GetProps()->m_nMinNumBolts, (int)GetProps()->m_nMaxNumBolts ); uint32 nBolt; bool bCanUseAttractors = (m_lstAttractors.size() > 0); bool bCanUseRadius = (GetProps()->m_fOmniDirectionalRadius >= 1.0f); CLightningBolt *pBolt = LTNULL; LightningBolts::iterator iter; for( nBolt = 0, iter = m_lstBolts.begin(); iter != m_lstBolts.end(), nBolt < nActiveBolts; ++iter, ++nBolt ) { pBolt = *iter; pBolt->m_fWidth = GetRandom( GetProps()->m_fMinBoltWidth, GetProps()->m_fMaxBoltWidth ); pBolt->m_fLifetime = GetRandom( GetProps()->m_fMinLifetime, GetProps()->m_fMaxLifetime ); pBolt->m_tmElapsed = 0.0f; pBolt->m_bActive = true; // Grab the position of the object to compensate for offset if( m_hTarget ) { m_pLTClient->GetObjectPos( m_hTarget, &vAttractorPos ); } else { vAttractorPos = m_vTargetPos; } // Decide if we should use an attractor or radius for the end pos... if( bCanUseAttractors && (!bCanUseRadius || GetRandom(0,1)) ) { uint8 nIndex = GetRandom( 0, (int)(m_lstAttractors.size()) - 1 ); CAttractor cAttractor = m_lstAttractors[nIndex]; if( cAttractor.GetTransform( lTrans, true ) == LT_OK ) { vAttractorPos = lTrans.m_Pos; } } else if( bCanUseRadius ) { LTVector vRandomPos; vRandomPos.x = GetRandom( -1.0f, 1.0f ); vRandomPos.y = GetRandom( -1.0f, 1.0f ); vRandomPos.z = GetRandom( -1.0f, 1.0f ); vRandomPos.Normalize(); vRandomPos *= GetRandom( -GetProps()->m_fOmniDirectionalRadius, GetProps()->m_fOmniDirectionalRadius ); vAttractorPos = m_vPos + vRandomPos; IntersectQuery iQuery; IntersectInfo iInfo; iQuery.m_From = m_vPos; iQuery.m_To = vAttractorPos; if( m_pLTClient->IntersectSegment( &iQuery, &iInfo )) { vAttractorPos = iInfo.m_Point; } } LTVector vNew = m_vPos; LTVector vDir = vAttractorPos - vNew; float fStep = vDir.Length() / (float)pBolt->m_nNumSegments; float fPerturb = GetRandom( GetProps()->m_fMinPerturb, GetProps()->m_fMaxPerturb ); vDir.Normalize(); LTRotation rRot = LTRotation( vDir, LTVector( 0.0f, 1.0f, 0.0f )); CLinkListNode<PT_TRAIL_SECTION> *pNode = pBolt->m_collPathPts.GetHead(); while( pNode ) { pNode->m_Data.m_vPos = vNew; pNode->m_Data.m_tmElapsed = 0.0f; pNode->m_Data.m_vBisector.Init(); // Add in some perturb going in the direction of the attractor pos for the next section... vNew += (rRot.Forward() * fStep ); vNew += (rRot.Up() * GetRandom( -fPerturb, fPerturb )); vNew += (rRot.Right() * GetRandom( -fPerturb, fPerturb )); // Make sure the last section goes to the end pos... if( !pNode->m_pNext ) pNode->m_Data.m_vPos = vAttractorPos; pNode = pNode->m_pNext; } } // Decide when the next emission will be... m_tmElapsedEmission = 0.0f; m_fDelay = GetRandom( GetProps()->m_fMinDelay, GetProps()->m_fMaxDelay ); } }
void CFlashLightPlayer::GetLightPositions(LTVector& vStartPos, LTVector& vEndPos, LTVector& vUOffset, LTVector& vROffset) { vStartPos.Init(); vEndPos.Init(); vUOffset.Init(); vROffset.Init(); CMoveMgr* pMoveMgr = g_pPlayerMgr->GetMoveMgr(); if (!pMoveMgr) return; LTRotation rRot; if (pMoveMgr->GetVehicleMgr()->IsVehiclePhysics()) { if (g_pPlayerMgr->IsFirstPerson()) { pMoveMgr->GetVehicleMgr()->GetVehicleLightPosRot(vStartPos, rRot); } else // 3rd person vehicle { // Get light pos on 3rd-person vehicle... HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (hPlayerObj) { g_pLTClient->GetObjectRotation(hPlayerObj, &rRot); g_pLTClient->GetObjectPos(hPlayerObj, &vStartPos); } } } else if (g_pPlayerMgr->IsFirstPerson()) { HOBJECT hCamera = g_pPlayerMgr->GetCamera(); if (!hCamera) return; g_pLTClient->GetObjectRotation(hCamera, &rRot); g_pLTClient->GetObjectPos(hCamera, &vStartPos); } else // 3rd person { // Get light pos from 3rd-person model... HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (hPlayerObj) { // g_pLTClient->GetObjectRotation(hPlayerObj, &rRot); // g_pLTClient->GetObjectPos(hPlayerObj, &vStartPos); HMODELSOCKET hSocket; if ( LT_OK == g_pModelLT->GetSocket(hPlayerObj, "LeftHand", hSocket) ) { LTransform tf; if ( LT_OK == g_pModelLT->GetSocketTransform(hPlayerObj, hSocket, tf, LTTRUE) ) { vStartPos = tf.m_Pos; rRot = tf.m_Rot; } } } } vEndPos = vStartPos + (rRot.Forward() * g_cvarFLLightOffsetForward.GetFloat()); if (g_pPlayerMgr->IsFirstPerson()) { vROffset = (rRot.Right() * g_cvarFLLightOffsetRight.GetFloat()); vUOffset = (rRot.Up() * g_cvarFLLightOffsetUp.GetFloat()); // Update the Start/End position to addjust for any offset... vEndPos += vROffset; vEndPos += vUOffset; vStartPos += vROffset; vStartPos += vUOffset; } }
void DebugLineSystem::AddOrientation( const LTVector& vCenter, const LTRotation& rRot, float fLength, uint8 nAlpha) { AddArrow(vCenter, vCenter + rRot.Right() * fLength, Color::Red, nAlpha); AddArrow(vCenter, vCenter + rRot.Up() * fLength, Color::Green, nAlpha); AddArrow(vCenter, vCenter + rRot.Forward() * fLength, Color::Blue, nAlpha); }
//function that handles the custom rendering void CParticleSystemGroup::RenderParticleSystem(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera) { //track our performance CTimedSystemBlock TimingBlock(g_tsClientFXParticles); //setup our vertex declaration if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK) return; //bind a quad index stream if(pInterface->BindQuadIndexStream() != LT_OK) return; //set the fact that we were visible *m_pVisibleFlag = true; //now determine the largest number of particles that we can render at any time uint32 nMaxParticlesPerBatch = QUAD_RENDER_INDEX_STREAM_SIZE / 6; nMaxParticlesPerBatch = LTMIN(nMaxParticlesPerBatch, DYNAMIC_RENDER_VERTEX_STREAM_SIZE / (sizeof(STexTangentSpaceVert) * 4)); //determine the screen orientation LTRotation rCamera = tCamera.m_rRot; if (m_pProps->m_bObjectSpace) { LTRotation rObjectRotation; g_pLTClient->GetObjectRotation(m_hCustomRender, &rObjectRotation); rCamera = rObjectRotation.Conjugate() * rCamera; } LTVector vUp = rCamera.Up(); LTVector vRight = rCamera.Right(); //create some vectors to offset to each corner (avoids adding for displacement in the inner loop) //Each one can just be scaled by the size of the particle to get the final offset static const float kfHalfRoot2 = 0.5f * MATH_SQRT2; //premultiplied versions of up and right scaled by half the square root of two LTVector vUpHalfRoot2 = vUp * kfHalfRoot2; LTVector vRightHalfRoot2 = vRight * kfHalfRoot2; //precalculate the diagonals for non-rotating particles since these are constant LTVector vDiagonals[4]; vDiagonals[0] = vUpHalfRoot2 - vRightHalfRoot2; vDiagonals[1] = vUpHalfRoot2 + vRightHalfRoot2; vDiagonals[2] = -vUpHalfRoot2 + vRightHalfRoot2; vDiagonals[3] = -vUpHalfRoot2 - vRightHalfRoot2; uint32 nNumParticlesLeft = m_Particles.GetNumParticles(); //precalculate some data for the basis space of the particles LTVector vNormal = -rCamera.Forward(); LTVector vTangent = vRight; LTVector vBinormal = -vUp; //the U scale for particle images float fUImageWidth = 1.0f / (float)m_pProps->m_nNumImages; //variables used within the inner loop float fSize; uint32 nColor; //now run through all the particles and render CParticleIterator itParticles = m_Particles.GetIterator(); while(nNumParticlesLeft > 0) { //determine our batch size uint32 nBatchSize = LTMIN(nNumParticlesLeft, nMaxParticlesPerBatch); //lock down our buffer for rendering SDynamicVertexBufferLockRequest LockRequest; if(pInterface->LockDynamicVertexBuffer(nBatchSize * 4, LockRequest) != LT_OK) return; //fill in a batch of particles STexTangentSpaceVert* pCurrOut = (STexTangentSpaceVert*)LockRequest.m_pData; if(m_pProps->m_bRotate) { //we need to render the particles rotated for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++) { //sanity check LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch"); //get the particle from the iterator SParticle* pParticle = (SParticle*)itParticles.GetParticle(); GetParticleSizeAndColor(pParticle, nColor, fSize); //determine the sin and cosine of this particle angle float fAngle = pParticle->m_fAngle; float fSinAngle = LTSin(fAngle); float fCosAngle = LTCos(fAngle); LTVector vRotRight = (vRightHalfRoot2 * fCosAngle + vUpHalfRoot2 * fSinAngle) * fSize; LTVector vRotUp = vNormal.Cross(vRotRight); LTVector vRotTangent = vTangent * fCosAngle + vBinormal * fSinAngle; LTVector vRotBinormal = vTangent * fSinAngle + vBinormal * fCosAngle; SetupParticle( pCurrOut, pParticle->m_Pos + vRotUp - vRotRight, pParticle->m_Pos + vRotUp + vRotRight, pParticle->m_Pos - vRotUp + vRotRight, pParticle->m_Pos - vRotUp - vRotRight, nColor, vNormal, vRotTangent, vRotBinormal, pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth); //move onto the next set of particles pCurrOut += 4; //move onto the next particle for processing itParticles.Next(); } } else if (m_pProps->m_bStreak) { //the particles are non-rotated but streaked along their velocity for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++) { //sanity check LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch"); //get the particle from the iterator SParticle* pParticle = (SParticle*)itParticles.GetParticle(); GetParticleSizeAndColor(pParticle, nColor, fSize); //in order to render the streak, we determine a line that passes through //the particle and runs in the direction of the velocity of the particle //we need to project the velocity onto the screen LTVector2 vScreen; vScreen.x = -(pParticle->m_Velocity.Dot(vRight)); vScreen.y = -(pParticle->m_Velocity.Dot(vUp)); //we know that the up and right vectors are normalized, so we can save some work by //just doing a 2d normalization float fMag = vScreen.Mag(); if(fMag == 0.0f) vScreen.Init(fSize, 0.0f); else vScreen *= fSize / fMag; //determine our actual screen space velocity LTVector vScreenRight = vUp * vScreen.y + vRight * vScreen.x; LTVector vScreenUp = vUp * -vScreen.x + vRight * vScreen.y; //and now compute the endpoint of the streak LTVector vEndPos = pParticle->m_Pos - pParticle->m_Velocity * m_pProps->m_fStreakScale; SetupParticle( pCurrOut, pParticle->m_Pos - vScreenRight - vScreenUp, vEndPos + vScreenRight - vScreenUp, vEndPos + vScreenRight + vScreenUp, pParticle->m_Pos - vScreenRight + vScreenUp, nColor, vNormal, vScreenRight, vScreenUp, pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth); //move onto the next set of particles pCurrOut += 4; //move onto the next particle for processing itParticles.Next(); } } else { //the particles are non-rotated for(uint32 nBatchParticle = 0; nBatchParticle < nBatchSize; nBatchParticle++) { //sanity check LTASSERT(!itParticles.IsDone(), "Error: Particle count and iterator mismatch"); //get the particle from the iterator SParticle* pParticle = (SParticle*)itParticles.GetParticle(); GetParticleSizeAndColor(pParticle, nColor, fSize); SetupParticle( pCurrOut, pParticle->m_Pos + vDiagonals[0] * fSize, pParticle->m_Pos + vDiagonals[1] * fSize, pParticle->m_Pos + vDiagonals[2] * fSize, pParticle->m_Pos + vDiagonals[3] * fSize, nColor, vNormal, vTangent, vBinormal, pParticle->m_nUserData & PARTICLE_IMAGE_MASK, fUImageWidth); //move onto the next set of particles pCurrOut += 4; //move onto the next particle for processing itParticles.Next(); } } //unlock and render the batch pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest); pInterface->RenderIndexed( eCustomRenderPrimType_TriangleList, 0, nBatchSize * 6, LockRequest.m_nStartIndex, 0, nBatchSize * 4); nNumParticlesLeft -= nBatchSize; } }
LTBOOL CShellCasingFX::Update() { if (!m_hObject || !m_pClientDE) return LTFALSE; if (g_pGameClientShell->IsServerPaused()) { return LTTRUE; } m_fElapsedTime += g_pGameClientShell->GetFrameTime(); m_fDieTime -= g_pGameClientShell->GetFrameTime(); if (m_fDieTime <= 0.0f) return LTFALSE; // Update object scale if necessary... LTVector vScale; m_pClientDE->GetObjectScale(m_hObject, &vScale); if (vScale != m_vFinalScale) { if (m_fElapsedTime <= g_vtShellScaleTime.GetFloat()) { LTVector vScaleRange = (m_vFinalScale - m_vInitialScale); vScale = m_vInitialScale + (vScaleRange * (m_fElapsedTime/g_vtShellScaleTime.GetFloat())); if (vScale > m_vFinalScale) { vScale = m_vFinalScale; } m_pClientDE->SetObjectScale(m_hObject, &vScale); } else { m_pClientDE->SetObjectScale(m_hObject, &m_vFinalScale); } } if (m_bResting) return LTTRUE; LTRotation rRot; g_pLTClient->GetObjectRotation(m_hObject, &rRot); // If velocity slows enough, and we're on the ground, just stop bouncing and just wait to expire. if (m_movingObj.m_dwPhysicsFlags & MO_RESTING) { m_bResting = LTTRUE; // Stop the spinning... rRot.Rotate(rRot.Up(), m_fYaw); g_pLTClient->SetObjectRotation(m_hObject, &rRot); // Shell is at rest, we can add a check here to see if we really want // to keep it around depending on detail settings... //HLOCALOBJ hObjs[1]; //uint32 nNumFound, nBogus; //m_pClientDE->FindObjectsInSphere(&m_movingObj.m_vPos, 64.0f, hObjs, 1, &nBogus, &nNumFound); // Remove thyself... //if (nNumFound > 15) return LTFALSE; } else { if (m_fPitchVel != 0 || m_fYawVel != 0) { LTFLOAT fDeltaTime = g_pGameClientShell->GetFrameTime(); m_fPitch += m_fPitchVel * fDeltaTime; m_fYaw += m_fYawVel * fDeltaTime; rRot.Rotate(rRot.Up(), m_fYaw); rRot.Rotate(rRot.Right(), m_fPitch); g_pLTClient->SetObjectRotation(m_hObject, &rRot); } } LTVector vNewPos; if (UpdateMovingObject(LTNULL, &m_movingObj, vNewPos)) { ClientIntersectInfo info; LTBOOL bBouncedOnGround = LTFALSE; if (BounceMovingObject(LTNULL, &m_movingObj, vNewPos, &info, INTERSECT_HPOLY, true, bBouncedOnGround)) { // If we hit the sky/invisible surface we're done... SurfaceType eType = GetSurfaceType(info); if (eType == ST_SKY || eType == ST_INVISIBLE) { return LTFALSE; } if (m_nBounceCount >= MAX_BOUNCE_COUNT) { if (!(m_movingObj.m_dwPhysicsFlags & MO_LIQUID)) { SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eType); if (pSurf) { // Play appropriate sound... if (pSurf->szShellImpactSnds[0]) { g_pClientSoundMgr->PlaySoundFromPos(vNewPos, pSurf->szShellImpactSnds[0], pSurf->fShellSndRadius, SOUNDPRIORITY_MISC_LOW); } } } } // Adjust the bouncing.. m_fPitchVel *= 0.75f; m_fYawVel *= -0.75f; m_nBounceCount--; if (m_nBounceCount <= 0) { m_movingObj.m_dwPhysicsFlags |= MO_RESTING; } } m_movingObj.m_vPos = vNewPos; if (g_pCommonLT->GetPointStatus(&vNewPos) == LT_OUTSIDE) { return LTFALSE; } g_pLTClient->SetObjectPos(m_hObject, &vNewPos); } return LTTRUE; }
void CPolyGridFX::CreateModelWaves(uint32 nKernalSize, uint32 nBuffer, float fFrameTime) { //maximum number of objects to find intersecting the grid static const uint32 knMaxObjToFind = 32; //find the radius of our polygrid float fPolyRad = m_vDims.Mag(); //amount to displace for a model float fDisplaceAmount = m_fModelDisplace * fFrameTime; //just bail if the models aren't going to displace at all if(fDisplaceAmount < 0.01f) return; HLOCALOBJ hFound[knMaxObjToFind]; uint32 nFound = 0; LTVector vPGPos; m_pClientDE->GetObjectPos(m_hObject, &vPGPos); LTVector vPGDims; m_pClientDE->Physics()->GetObjectDims(m_hObject, &vPGDims); //now run through all the characters and see which ones intersect CSpecialFXList* pCharacterList = g_pGameClientShell->GetSFXMgr()->GetFXList(SFX_CHARACTER_ID); LTVector vPGMin = vPGPos - vPGDims; LTVector vPGMax = vPGPos + vPGDims; for(uint32 nCurrChar = 0; nCurrChar < (uint32)pCharacterList->GetNumItems(); nCurrChar++) { if(!(*pCharacterList)[nCurrChar]) continue; //determine the HOBJECT of this character HOBJECT hChar = (*pCharacterList)[nCurrChar]->GetServerObj(); if(!hChar) continue; //get the object position and dimensions LTVector vCharPos, vCharDims; m_pClientDE->GetObjectPos(hChar, &vCharPos); m_pClientDE->Physics()->GetObjectDims(hChar, &vCharDims); LTVector vCharMin = vCharPos - vCharDims; LTVector vCharMax = vCharPos + vCharDims; //if it overlaps, add it to our list if( (vPGMin.x < vCharMax.x) && (vPGMax.x > vCharMin.x) && (vPGMin.y < vCharMax.y) && (vPGMax.y > vCharMin.y) && (vPGMin.z < vCharMax.z) && (vPGMax.z > vCharMin.z)) { //they intersect, add it to the list hFound[nFound] = hChar; nFound++; //see if we need to stop looking for objects if(nFound >= knMaxObjToFind) break; } } //bail if none if(nFound == 0) { //make sure all objects are cleared from the list for(uint32 nCurrRemove = 0; nCurrRemove < MAX_MODELS_TO_TRACK; nCurrRemove++) { m_hTrackedModels[nCurrRemove] = NULL; } return; } //precalc info //find the orienation of the polygrid LTRotation rRot; m_pClientDE->GetObjectRotation(m_hObject, &rRot); //now get the basis vectors of the object space LTVector vRight = rRot.Right(); LTVector vForward = rRot.Forward(); //make sure the polygrid is valid if((m_dwNumPoliesX == 0) || (m_dwNumPoliesY == 0)) return; //find the dimensions of the polygons of the polygrid float fXPolySize = (m_vDims.x * 2.0f) / (float)m_dwNumPoliesX; float fYPolySize = (m_vDims.z * 2.0f) / (float)m_dwNumPoliesY; //bail if not a valid size if((fXPolySize < 0.01f) || (fYPolySize < 0.01f)) return; //flag indicating which tracked models should be kept around bool bTouchedTrackedModels[MAX_MODELS_TO_TRACK]; for(uint32 nCurrTrack = 0; nCurrTrack < MAX_MODELS_TO_TRACK; nCurrTrack++) { bTouchedTrackedModels[nCurrTrack] = false; } //ok, now we run through all the objects we found and update our grid accordingly for(uint32 nCurrObj = 0; nCurrObj < nFound; nCurrObj++) { //the object we are checking HLOCALOBJ hObj = hFound[nCurrObj]; //now lets see if this is a tracked model, if it is, we know where it was last //update and we can create a wave line, otherwise we have no clue, and should //track it for the next update bool bTracked = false; LTVector vPrevPos; LTVector vPos; m_pClientDE->GetObjectPos(hObj, &vPos); //if we aren't currently tracking it, this is where to put it uint32 nInsertPos = MAX_MODELS_TO_TRACK - 1; for(uint32 nCurrModel = 0; nCurrModel < MAX_MODELS_TO_TRACK; nCurrModel++) { if(m_hTrackedModels[nCurrModel] == hObj) { //we found a match, we need to save this value, move //it to the front of the list, and update it vPrevPos = m_vTrackedModelsPos[nCurrModel]; //move all the items back so that this will be in the first slot for(uint32 nCurrMove = nCurrModel; nCurrMove > 0; nCurrMove--) { m_hTrackedModels[nCurrMove] = m_hTrackedModels[nCurrMove - 1]; m_vTrackedModelsPos[nCurrMove] = m_vTrackedModelsPos[nCurrMove - 1]; bTouchedTrackedModels[nCurrMove] = bTouchedTrackedModels[nCurrMove - 1]; } //update the first element m_hTrackedModels[0] = hObj; m_vTrackedModelsPos[0] = vPos; bTouchedTrackedModels[0] = true; //all done bTracked = true; break; } //also bail if one of the slots is NULL if(m_hTrackedModels[nCurrModel] == NULL) { nInsertPos = nCurrModel; } } //see if this was tracked or not if(!bTracked) { //was not! We need to add it to the list m_hTrackedModels[nInsertPos] = hObj; m_vTrackedModelsPos[nInsertPos] = vPos; bTouchedTrackedModels[nInsertPos] = true; continue; } //make sure that the model is actually moving if((vPrevPos - vPos).MagSqr() < 0.5f) continue; //ok, we have a model that intersects our polygrid, let us create some waves //find out the endpoints of the line that will displace float fX1 = vRight.Dot(vPrevPos - vPGPos) + m_vDims.x; float fY1 = vForward.Dot(vPrevPos - vPGPos) + m_vDims.z; float fX2 = vRight.Dot(vPos - vPGPos) + m_vDims.x; float fY2 = vForward.Dot(vPos - vPGPos) + m_vDims.z; //now find the greater delta in polygon units float fXDelta = (float)fabs(fX1 - fX2) / fXPolySize; float fYDelta = (float)fabs(fY1 - fY2) / fYPolySize; //increments for the X and Y directions float fXInc, fYInc; float fCurrX, fCurrY; //the variable to use for threshold comparisons float *pfCompare; //the threshold float fThreshold; //now scan convert accordingly if(fYDelta > fXDelta) { //make sure Y1 is smaller if(fY2 < fY1) { Swap(fY1, fY2); Swap(fX1, fX2); } fYInc = fYPolySize; fXInc = (fX2 - fX1) / (fY2 - fY1) * fYInc; fThreshold = fY2 / fYPolySize; pfCompare = &fCurrY; } else { //make sure Y1 is smaller if(fX2 < fX1) { Swap(fY1, fY2); Swap(fX1, fX2); } fXInc = fXPolySize; fYInc = (fY2 - fY1) / (fX2 - fX1) * fXInc; fThreshold = fX2 / fXPolySize; pfCompare = &fCurrX; } //start out at the first point fCurrY = fY1 / fYPolySize; fCurrX = fX1 / fXPolySize; fXInc /= fXPolySize; fYInc /= fXPolySize; float fXFrac; float fYFrac; uint32 nPrevBuffer = (nBuffer + 1) % 2; //we need to scale the displacement amount by the speed at which we are moving fDisplaceAmount *= (vPrevPos - vPos).Mag() / (fFrameTime * g_cvarPGDisplaceMoveScale.GetFloat()); //now scan convert! while(*pfCompare < fThreshold) { //convert this to an integer position int32 nXPos = (int32)(fCurrX); int32 nYPos = (int32)(fCurrY); //handle clipping if((nXPos >= (int32)nKernalSize) && (nYPos >= (int32)nKernalSize) && (nXPos < (int32)m_dwNumPoliesX - (int32)nKernalSize - 1) && (nYPos < (int32)m_dwNumPoliesY - (int32)nKernalSize - 1)) { fXFrac = fCurrX - nXPos; fYFrac = fCurrY - nYPos; m_WaveBuffer[nBuffer].Get(nXPos, nYPos) += fDisplaceAmount * (1.0f - fXFrac) * (1.0f - fYFrac); m_WaveBuffer[nBuffer].Get(nXPos + 1, nYPos) += fDisplaceAmount * fXFrac * (1.0f - fYFrac); m_WaveBuffer[nBuffer].Get(nXPos, nYPos + 1) += fDisplaceAmount * (1.0f - fXFrac) * fYFrac; m_WaveBuffer[nBuffer].Get(nXPos + 1, nYPos + 1) += fDisplaceAmount * fXFrac * fYFrac; m_WaveBuffer[nPrevBuffer].Get(nXPos, nYPos) += fDisplaceAmount * (1.0f - fXFrac) * (1.0f - fYFrac); m_WaveBuffer[nPrevBuffer].Get(nXPos + 1, nYPos) += fDisplaceAmount * fXFrac * (1.0f - fYFrac); m_WaveBuffer[nPrevBuffer].Get(nXPos, nYPos + 1) += fDisplaceAmount * (1.0f - fXFrac) * fYFrac; m_WaveBuffer[nPrevBuffer].Get(nXPos + 1, nYPos + 1) += fDisplaceAmount * fXFrac * fYFrac; } //move along fCurrX += fXInc; fCurrY += fYInc; } } //now that we are done, clear out any models that were not touched for(uint32 nCurrRemove = 0; nCurrRemove < MAX_MODELS_TO_TRACK; nCurrRemove++) { if(!bTouchedTrackedModels[nCurrRemove]) m_hTrackedModels[nCurrRemove] = NULL; } }
bool CPolyTubeFX::Update(float tmFrameTime) { // Base class update first if (!CBaseFX::Update(tmFrameTime)) return false; if ((!m_hTexture) && (!m_bLoadFailed)) { m_pLTClient->GetTexInterface()->CreateTextureFromName(m_hTexture, GetProps()->m_sPath); if (m_hTexture) { // Retrieve texture dims uint32 nHeight; m_pLTClient->GetTexInterface()->GetTextureDims(m_hTexture, m_dwWidth, nHeight); } else { m_bLoadFailed = true; } } if ((m_collPathPts.GetSize() < 2) && IsShuttingDown()) { m_collPathPts.RemoveAll(); return true; } float tmAddPtInterval = GetProps()->m_tmAddPtInterval * 2.0f; LTRotation rRot; m_pLTClient->GetObjectRotation( m_hObject, &rRot ); //increase the emission time elapse m_tmElapsedEmission += tmFrameTime; if (!IsShuttingDown() && (m_collPathPts.GetSize() < GetProps()->m_nMaxTrailLength) && ((m_tmElapsedEmission > GetProps()->m_tmAddPtInterval) || (m_collPathPts.GetSize() == 1))) { LTVector vNew = m_vPos; // Only add the new point if it's not the same as the last one.... // Add a new trail section PT_TRAIL_SECTION ts; ts.m_vPos = vNew; ts.m_tmElapsed = 0.0f; switch( GetProps()->m_eAllignment ) { case ePTA_Up: ts.m_vBisector = rRot.Up(); break; case ePTA_Right: ts.m_vBisector = rRot.Right(); break; case ePTA_Forward: ts.m_vBisector = rRot.Forward(); break; case ePTA_Camera: default: ts.m_vBisector.Init(); break; } // Compute u coordinate if (m_collPathPts.GetSize()) { LTVector vPrev = m_collPathPts.GetTail()->m_Data.m_vPos; float fUPrev = m_collPathPts.GetTail()->m_Data.m_uVal; float fWidth = (float)m_dwWidth; float fScalar = fWidth / GetProps()->m_fTrailWidth; ts.m_uVal = fUPrev + ((((vNew - vPrev).Mag()) / fWidth) * fScalar); } else { ts.m_uVal = 0.0f; } m_collPathPts.AddTail(ts); m_tmElapsedEmission = 0.0f; } // Render the tube.... if (m_collPathPts.GetSize() < 2) return true; CLinkListNode<PT_TRAIL_SECTION> *pNode = m_collPathPts.GetHead(); // Fudge the last point to be the current one... if( !IsShuttingDown() ) m_collPathPts.GetTail()->m_Data.m_vPos = m_vPos; // Transform the path LTMatrix mCam; if( m_bReallyClose || (GetProps()->m_eAllignment != ePTA_Camera)) { mCam.Identity(); } else { mCam = GetCamTransform(m_pLTClient, m_hCamera); } while (pNode) { MatVMul(&pNode->m_Data.m_vTran, &mCam, &pNode->m_Data.m_vPos); pNode = pNode->m_pNext; } // Do some precalculations pNode = m_collPathPts.GetHead(); float fCurU = 0.0f; while (pNode) { pNode->m_Data.m_tmElapsed += tmFrameTime; if( GetProps()->m_eAllignment == ePTA_Camera ) { LTVector vBisector; vBisector.z = 0.0f; // Compute the midpoint vectors if (pNode == m_collPathPts.GetHead()) { LTVector vStart = pNode->m_Data.m_vTran; LTVector vEnd = pNode->m_pNext->m_Data.m_vTran; vBisector.x = vEnd.y - vStart.y; vBisector.y = -(vEnd.x - vStart.x); } else if (pNode == m_collPathPts.GetTail()) { LTVector vEnd = pNode->m_Data.m_vTran; LTVector vStart = pNode->m_pPrev->m_Data.m_vTran; vBisector.x = vEnd.y - vStart.y; vBisector.y = -(vEnd.x - vStart.x); } else { LTVector vPrev = pNode->m_pPrev->m_Data.m_vTran; LTVector vStart = pNode->m_Data.m_vTran; LTVector vEnd = pNode->m_pNext->m_Data.m_vTran; float x1 = vEnd.y - vStart.y; float y1 = -(vEnd.x - vStart.x); float z1 = vStart.z - vEnd.z; float x2 = vStart.y - vPrev.y; float y2 = -(vStart.x - vPrev.x); float z2 = vPrev.z - vEnd.z; vBisector.x = (x1 + x2) / 2.0f; vBisector.y = (y1 + y2) / 2.0f; } pNode->m_Data.m_vBisector = vBisector; } LTFLOAT fWidth = CalcCurWidth(); pNode->m_Data.m_vBisector.Norm( fWidth ); // Setup the colour float r, g, b, a; CalcColour(pNode->m_Data.m_tmElapsed, GetProps()->m_tmSectionLifespan, &r, &g, &b, &a); int ir = (int)(r * 255.0f); int ig = (int)(g * 255.0f); int ib = (int)(b * 255.0f); int ia = (int)(a * 255.0f); pNode->m_Data.m_red = Clamp( ir, 0, 255 ); pNode->m_Data.m_green = Clamp( ig, 0, 255 ); pNode->m_Data.m_blue = Clamp( ib, 0, 255 ); pNode->m_Data.m_alpha = Clamp( ia, 0, 255 ); pNode = pNode->m_pNext; } pNode = m_collPathPts.GetHead(); pNode = m_collPathPts.GetHead(); // Delete any dead nodes while (pNode->m_pNext) { CLinkListNode<PT_TRAIL_SECTION> *pDelNode= NULL; if (pNode->m_Data.m_tmElapsed >= GetProps()->m_tmSectionLifespan) { pDelNode = pNode; } pNode = pNode->m_pNext; if (pDelNode) m_collPathPts.Remove(pDelNode); } // Increment the offset m_uOffset += tmFrameTime * GetProps()->m_uAdd; // Success !! return true; }
LTBOOL CParticleExplosionFX::Update() { if (!m_hObject || !m_pClientDE) return LTFALSE; if (!CBaseParticleSystemFX::Update()) return LTFALSE; LTFLOAT fTime = m_pClientDE->GetTime(); if (m_bFirstUpdate) { m_bFirstUpdate = LTFALSE; m_fStartTime = fTime; m_fLastTime = fTime; } // Check to see if we should start fading the system... if (fTime > m_fStartTime + m_fFadeTime) { LTFLOAT fEndTime = m_fStartTime + m_fLifeTime; if (fTime > fEndTime) { return LTFALSE; } LTFLOAT fScale = (fEndTime - fTime) / (m_fLifeTime - m_fFadeTime); LTFLOAT r, g, b, a; m_pClientDE->GetObjectColor(m_hObject, &r, &g, &b, &a); m_pClientDE->SetObjectColor(m_hObject, r, g, b, fScale); } // See if it is time to create a new Particle puff... if (fTime >= m_fLastTime + m_fOffsetTime) { // Loop over our list of Emitters, creating new particles... for (int i=0; i < m_nNumEmitters; i++) { if (m_ActiveEmitters[i]) { AddParticles(&m_Emitters[i]); } } m_fLastTime = fTime; } // Loop over our list of Emitters, updating the position of each for (int i=0; i < m_nNumEmitters; i++) { if (m_ActiveEmitters[i]) { LTBOOL bBounced = LTFALSE; if (bBounced = UpdateEmitter(&m_Emitters[i])) { if (!(m_Emitters[i].m_dwPhysicsFlags & MO_LIQUID) && (m_hDebris[i])) { /* char* pSound = GetDebrisBounceSound(DBT_STONE_BIG); // Play appropriate sound... g_pClientSoundMgr->PlaySoundFromPos(m_Emitters[i].m_Pos, pSound, 300.0f, SOUNDPRIORITY_MISC_LOW); */ } m_BounceCount[i]--; if (m_BounceCount[i] <= 0) { m_Emitters[i].m_dwPhysicsFlags |= MO_RESTING; } } if (m_Emitters[i].m_dwPhysicsFlags & MO_RESTING) { m_ActiveEmitters[i] = LTFALSE; if (m_hDebris[i]) { m_pClientDE->RemoveObject(m_hDebris[i]); m_hDebris[i] = LTNULL; } } else if (m_hDebris[i]) { g_pLTClient->SetObjectPos(m_hDebris[i], &(m_Emitters[i].m_vPos)); if (m_bRotateDebris) { if (bBounced) { // Adjust due to the bounce... m_fPitchVel = GetRandom(-MATH_CIRCLE, MATH_CIRCLE); m_fYawVel = GetRandom(-MATH_CIRCLE, MATH_CIRCLE); } if (m_fPitchVel != 0 || m_fYawVel != 0) { LTFLOAT fDeltaTime = g_pGameClientShell->GetFrameTime(); m_fPitch += m_fPitchVel * fDeltaTime; m_fYaw += m_fYawVel * fDeltaTime; LTRotation rRot; rRot.Rotate(rRot.Up(), m_fYaw); rRot.Rotate(rRot.Right(), m_fPitch); g_pLTClient->SetObjectRotation(m_hDebris[i], &rRot); } } } } } return LTTRUE; }