//************************************************************************** //** //** PREY_BEAM.CPP //** //** Code for Prey-specific beams //** //************************************************************************** // HEADER FILES ------------------------------------------------------------ #include "precompiled.h" #pragma hdrstop // Game code includes #include "prey_local.h" #define DEBUG_BEAMS 0 static idVec3 CurveExtractSpline(idVec3 *cPoints, int cPointCount, float alpha, bool bThruCtrlPnts); const idEventDef EV_ToggleBeamLength("", "d"); const idEventDef EV_SetBeamPhaseScale( "setBeamPhaseScale", "f" ); // bg const idEventDef EV_SetBeamOffsetScale( "setBeamOffsetScale", "f" ); // bg CLASS_DECLARATION(idEntity, hhBeamSystem) EVENT( EV_Activate, hhBeamSystem::Event_Activate ) EVENT( EV_SetBeamPhaseScale, hhBeamSystem::Event_SetBeamPhaseScale) // bg EVENT( EV_SetBeamOffsetScale, hhBeamSystem::Event_SetBeamOffsetScale) // bg END_CLASS hhBeamSystem::hhBeamSystem() { beamList = NULL; offsetScale = 1.0f; phaseScale = 1.0f; bActive = false; targetLocation = vec3_origin; decl = NULL; } hhBeamSystem::~hhBeamSystem() { if(renderEntity.beamNodes) { Mem_Free( renderEntity.beamNodes ); renderEntity.beamNodes = NULL; } if(beamList) { delete [] beamList; beamList = NULL; } } void hhBeamSystem::Spawn(void) { beamList = NULL; if (!gameLocal.isClient || fl.clientEntity) { //rww - for client in mp this gets done after the first snapshot is read... InitSystem( spawnArgs.GetString("model") ); } beamLength = spawnArgs.GetFloat( "lengthBeam" ); bRigidBeamLength = spawnArgs.GetBool( "rigidBeamLength" ); targetEntity = NULL; targetEntityId = 0; targetEntityOffset.Zero(); SetArcVector( vec3_origin ); bActive = spawnArgs.GetBool( "start_off" ); Activate( !bActive ); } void hhBeamSystem::Activate( const bool bActivate ) { if( bActive != bActivate ) { bActive = bActivate; if( bActive ) { BecomeActive( TH_UPDATEPARTICLES ); Show(); }else { BecomeInactive( TH_UPDATEPARTICLES ); Hide(); } } } hhBeamSystem* hhBeamSystem::SpawnBeam( const idVec3& start, const char* modelName, const idMat3& axis, bool pureLocal ) { idDict Args; hhBeamSystem* beamSystem = NULL; idStr modelString; #if !GOLD //rww - checking for creation of beams at nan location assert(!FLOAT_IS_NAN(start.x)); assert(!FLOAT_IS_NAN(start.y)); assert(!FLOAT_IS_NAN(start.z)); assert(!FLOAT_IS_NAN(axis[0].x)); assert(!FLOAT_IS_NAN(axis[0].y)); assert(!FLOAT_IS_NAN(axis[0].z)); assert(!FLOAT_IS_NAN(axis[1].x)); assert(!FLOAT_IS_NAN(axis[1].y)); assert(!FLOAT_IS_NAN(axis[1].z)); assert(!FLOAT_IS_NAN(axis[2].x)); assert(!FLOAT_IS_NAN(axis[2].y)); assert(!FLOAT_IS_NAN(axis[2].z)); #endif if ( !modelName || !modelName[0] ) { return NULL; } // Ensure that the modelname ends with a valid .beam extention modelString = modelName; modelString.DefaultFileExtension( ".beam" ); Args.Set( "spawnclass", "hhBeamSystem" ); Args.Set( "model", modelString.c_str() ); Args.SetVector( "origin", start ); Args.SetMatrix( "rotation", axis ); HH_ASSERT(!gameLocal.isClient || pureLocal); beamSystem = (hhBeamSystem *)gameLocal.SpawnEntityTypeClient( hhBeamSystem::Type, &Args ); if (beamSystem) { //make sure it's sync'd beamSystem->fl.networkSync = !pureLocal; } HH_ASSERT( beamSystem ); beamSystem->SetTargetEntity( NULL ); beamSystem->SetTargetLocation( start ); // Necessary in case the beam starts out hidden beamSystem->beamAxis = mat3_identity; return beamSystem; } //========================================================================== // // hhBeamSystem::InitSystem // // Reads beam system information from the entity definition // // Commands: // beamNum - total number of beams in the system // beamNodes - total number of nodes per beam // // Per beam (end number specifies the beam): // // beamThickness0 - Thickness // beamTaperEndPoints0 - If the beam should have tapered end points // beamShader0 - Shader name // beamSpline0 - if this beam system uses splines //========================================================================== void hhBeamSystem::InitSystem( const char* modelName ) { int i; HH_ASSERT( modelName ); if(renderEntity.beamNodes) { // Delete the previous version before initializing Mem_Free(renderEntity.beamNodes); renderEntity.beamNodes = NULL; } // Initialize beam data from the beam file declName = modelName; decl = (const hhDeclBeam*)declManager->FindType(DECL_BEAM, modelName, false); renderEntity.declBeam = decl; // Get new model loaded if( !renderEntity.hModel || idStr::Icmp( renderEntity.hModel->Name(), modelName ) ) { renderEntity.hModel = renderModelManager->FindModel( modelName ); } // Allocate the beams if( beamList ) { delete[] beamList; } beamList = new hhBeam[decl->numBeams]; // Allocate the number of beam infos (used for rendering) renderEntity.beamNodes = (hhBeamNodes_t *)Mem_ClearedAlloc(sizeof(hhBeamNodes_t) * decl->numBeams); beamAxis = GetPhysics()->GetAxis(); // Initialize each beam with specific info for(i = 0; i < decl->numBeams; i++) { beamList[i].Init( this, &renderEntity.beamNodes[i] ); } random.SetSeed( gameLocal.time ); beamTime = gameLocal.time + random.RandomInt( 5000 ); // Don't let any beams stay in sync. } //========================================================================== // // hhBeamSystem::SetTargetLocation // //========================================================================== void hhBeamSystem::SetTargetLocation(idVec3 newLoc) { targetLocation = newLoc; beamLength = (targetLocation - GetPhysics()->GetOrigin()).Length(); } //========================================================================== // // hhBeamSystem::SetTargetEntity // // Sets the entity to target from this beam. If joint is INVALID_JOINT, // then the origin of the entity will be used. // // Passing in a NULL entity will clear the target entity, and set the targetLocation to offset // // NOTE: The offset passed in should be in world coordinates relative to the model. // NOTE: The offset can be used as an offset from the joint as well. //========================================================================== void hhBeamSystem::SetTargetEntity( idEntity *ent, int traceId, idVec3 &offset ) { idVec3 origin; idMat3 axis; targetEntity = ent; if ( ent == NULL ) { targetEntityId = 0; targetEntityOffset.Zero(); SetTargetLocation( offset ); return; } targetEntityId = traceId; targetEntityOffset = offset; // Update the targetLocation GetTargetLocation(); // Calculate the beam length from the new target location beamLength = (targetLocation - GetPhysics()->GetOrigin()).Length(); } //========================================================================== // // hhBeamSystem::SetTargetEntity // // Bone name version //========================================================================== void hhBeamSystem::SetTargetEntity( idEntity *ent, const char *boneName, idVec3 &offset ) { idVec3 origin; idMat3 axis; targetEntity = ent; if ( ent == NULL || boneName == NULL ) { targetEntityId = 0; targetEntityOffset.Zero(); SetTargetLocation( offset ); return; } targetEntityId = ent->GetAnimator()->GetJointHandle( boneName ); targetEntityOffset = offset; // Update the targetLocation GetTargetLocation(); // Calculate the beam length from the new target location beamLength = (targetLocation - GetPhysics()->GetOrigin()).Length(); } //========================================================================== // // hhBeamSystem::GetTargetLocation // //========================================================================== idVec3 hhBeamSystem::GetTargetLocation( void ) { idVec3 origin; idMat3 axis; idVec3 boneOrigin; idMat3 boneAxis; jointHandle_t joint; idAFEntity_Base *af = NULL; if ( targetEntity.IsValid() ) { // Has a target entity, so compute the offset if ( targetEntityId > 0 ) { // This is a specific joint: joint = (jointHandle_t)targetEntityId; } else { // This is a collision handle joint = CLIPMODEL_ID_TO_JOINT_HANDLE( targetEntityId ); } if ( targetEntity->IsType( idAFEntity_Base::Type ) ) { af = static_cast( targetEntity.GetEntity() ); } axis = targetEntity->GetAxis(); origin = targetEntity->GetOrigin(); // Calculate the targetLocation, based upon the type of entity if ( af && af->IsActiveAF() ) { // AF, use the clip model id for the origin int body = af->BodyForClipModelId( targetEntityId ); origin = af->GetPhysics()->GetOrigin( body ); targetLocation = origin + axis * targetEntityOffset; //rww - added check for targetEntity->GetAnimator() not being null, in case targetEntity is not animated } else if ( joint != INVALID_JOINT && targetEntity->GetAnimator() && targetEntity->GetAnimator()->GetJointTransform( joint, gameLocal.time, boneOrigin, boneAxis ) ) { // Joint-based targetLocation = origin + axis * boneOrigin; } else { // Default - use origin of the entity targetLocation = origin + axis * targetEntityOffset; } } return targetLocation; } //========================================================================== // // hhBeamSystem::SetAxis // //========================================================================== void hhBeamSystem::SetAxis( const idMat3 &axis ) { if (!GetPhysics()->GetAxis().Compare(axis)) { idEntity::SetAxis(axis); } } //========================================================================== // // hhBeamSystem::SetBeamLength // //========================================================================== void hhBeamSystem::SetBeamLength( const float length ) { beamLength = length; if( bRigidBeamLength && beamLength > VECTOR_EPSILON ) { SetTargetLocation( GetPhysics()->GetOrigin() + GetPhysics()->GetAxis()[0] * beamLength ); } } /* ================= hhBeamSystem::WriteToSnapshot rww - write applicable beam values to snapshot ================= */ void hhBeamSystem::WriteToSnapshot( idBitMsgDelta &msg ) const { #if !GOLD gameLocal.Warning("Beam %i being sync'd by server!\n", entityNumber); #endif GetPhysics()->WriteToSnapshot( msg ); msg.WriteFloat(beamTime); //handle this. //hhBeam *beamList; //this is the common method, but doing WriteDirs might be more efficient? idCQuat quat = beamAxis.ToCQuat(); msg.WriteFloat(quat.x); msg.WriteFloat(quat.y); msg.WriteFloat(quat.z); msg.WriteFloat(arcVector[0]); msg.WriteFloat(arcVector[1]); msg.WriteFloat(arcVector[2]); msg.WriteFloat(targetLocation[0]); msg.WriteFloat(targetLocation[1]); msg.WriteFloat(targetLocation[2]); if (targetEntity.IsValid()) { msg.WriteBits(1, 1); msg.WriteBits(targetEntity->entityNumber, GENTITYNUM_BITS); } else { msg.WriteBits(0, 1); } msg.WriteFloat(targetEntityOffset[0]); msg.WriteFloat(targetEntityOffset[1]); msg.WriteFloat(targetEntityOffset[2]); //do i care about this? //int targetEntityId; msg.WriteFloat(beamLength); msg.WriteBits(bRigidBeamLength, 1); msg.WriteFloat(phaseScale); msg.WriteFloat(offsetScale); msg.WriteBits(bActive, 1); //rwwFIXME this is horrible. oh so very horrible. all those calls to SpawnBeam in code need to be removed, //and they must all use seperate entity defs, or there is no alternative to sending a real string. =| msg.WriteString(spawnArgs.GetString("model")); } /* ================= hhBeamSystem::ReadFromSnapshot rww - read applicable beam values from snapshot ================= */ void hhBeamSystem::ReadFromSnapshot( const idBitMsgDelta &msg ) { GetPhysics()->ReadFromSnapshot( msg ); beamTime = msg.ReadFloat(); idCQuat quat; quat.x = msg.ReadFloat(); quat.y = msg.ReadFloat(); quat.z = msg.ReadFloat(); beamAxis = quat.ToMat3(); arcVector[0] = msg.ReadFloat(); arcVector[1] = msg.ReadFloat(); arcVector[2] = msg.ReadFloat(); targetLocation[0] = msg.ReadFloat(); targetLocation[1] = msg.ReadFloat(); targetLocation[2] = msg.ReadFloat(); int hasEnt = msg.ReadBits(1); if (hasEnt) { int entNum = msg.ReadBits(GENTITYNUM_BITS); targetEntity = gameLocal.entities[entNum]; } else { targetEntity = NULL; } targetEntityOffset[0] = msg.ReadFloat(); targetEntityOffset[1] = msg.ReadFloat(); targetEntityOffset[2] = msg.ReadFloat(); beamLength = msg.ReadFloat(); bRigidBeamLength = !!msg.ReadBits(1); phaseScale = msg.ReadFloat(); offsetScale = msg.ReadFloat(); bool active = !!msg.ReadBits(1); if (active != bActive) { Activate(active); } char modelName[128]; msg.ReadString(modelName, 128); if (!beamList) { //then init the system. InitSystem(modelName); } } /* ================= hhBeamSystem::ClientPredictionThink rww - minimal think on client ================= */ void hhBeamSystem::ClientPredictionThink( void ) { if (fl.clientEntity && snapshotOwner.IsValid()) { if (!bActive || !gameLocal.EntInClientSnapshot(snapshotOwner->entityNumber)) { //if the snapshot entity i'm associated with is not in the snapshot, i hide Hide(); } else { Show(); } } if (gameLocal.isNewFrame) { Think(); } } //========================================================================== // // hhBeamSystem::Think // // NOTE: Beams will not think AT ALL if they are hidden or not visible //========================================================================== void hhBeamSystem::Think( void ) { RunPhysics(); if (thinkFlags & TH_UPDATEPARTICLES) { if( targets.Num() > 0 ) { SetTargetEntity( targets[0].GetEntity(), NULL ); } // Update the beamAxis to correctly reflect the target if( !bRigidBeamLength ) { idVec3 vec = (GetTargetLocation() - GetPhysics()->GetOrigin()); beamLength = vec.Normalize(); if ( beamLength <= 0 ) { // Ignore beams with no length return; } if( GetBindMaster() && fl.bindOrientated ) { beamAxis = GetAxis(); } else { beamAxis = vec.ToMat3(); if ( targets.Num() > 0 ) { SetAxis( beamAxis ); // Target beams should update renderEntity information } else { GetPhysics()->SetAxis( beamAxis ); // Normal beams don't need to update render entity information } } } else { SetTargetLocation( GetPhysics()->GetOrigin() + GetPhysics()->GetAxis()[0] * beamLength ); beamAxis = GetPhysics()->GetAxis(); } assert(decl); for( int i = 0; i < decl->numBeams; i++) { ExecuteBeam( i, &beamList[i] ); beamList[i].TransformNodes(); } } Present(); } //========================================================================== // // hhBeamSystem::Event_Activate // // Triggering a beam will toggle its visibility //========================================================================== void hhBeamSystem::Event_Activate( idEntity *activator ) { Activate( !IsActivated() ); } //========================================================================== // // hhBeamSystem::Event_SetBeamPhaseScale // //========================================================================== void hhBeamSystem::Event_SetBeamPhaseScale( float scale ) { SetBeamPhaseScale( scale ); } //========================================================================== // // hhBeamSystem::Event_SetBeamOffsetScale // //========================================================================== void hhBeamSystem::Event_SetBeamOffsetScale( float scale ) { SetBeamOffsetScale( scale ); } //========================================================================== // // hhBeamSystem::UpdateModel // //========================================================================== void hhBeamSystem::UpdateModel( void ) { if( renderEntity.hModel && !this->fl.hidden ) { // Only calculate the bounds if the model is valid and the model is visible renderEntity.bounds = renderEntity.hModel->Bounds( &renderEntity ); } else { renderEntity.bounds.Zero(); renderEntity.bounds.AddPoint(idVec3(-16,-16,-16)); renderEntity.bounds.AddPoint(idVec3( 16, 16, 16)); } idEntity::UpdateModel(); } // BEAM CODE --------------------------------------------------------------------- //========================================================================== // // hhBeam::hhBeam // //========================================================================== hhBeam::hhBeam() { nodeList = NULL; } //========================================================================== // // hhBeam::~hhBeam // //========================================================================== hhBeam::~hhBeam() { nodeList = NULL; } //========================================================================== // // hhBeam::Init // //========================================================================== void hhBeam::Init( hhBeamSystem *newSystem, hhBeamNodes_t *newInfo ) { int i; system = newSystem; nodeList = newInfo->nodes; for(i = 0; i < MAX_BEAM_SPLINE_CONTROLS + EXTRA_SPLINE_CONTROLS; i++) { splineList[i] = idVec3(0, 0, 0); } } //========================================================================== // // hhBeam::VerifyNodeIndex // //========================================================================== void hhBeam::VerifyNodeIndex(int index, const char *functionName) { #if DEBUG_BEAMS if(index < 0 || index >= system->decl->numNodes) { gameLocal.Error("%s: %d\n", functionName, index); } #endif } //========================================================================== // // hhBeam::VerifySplineIndex // //========================================================================== void hhBeam::VerifySplineIndex(int index, const char *functionName) { #if DEBUG_BEAMS if(index < 0 || index >= MAX_BEAM_SPLINE_CONTROLS) { gameLocal.Error("%s: %d\n", functionName, index); } #endif } //========================================================================== // // hhBeam::NodeGet // // Returns the node location in world space //========================================================================== idVec3 hhBeam::NodeGet(int index) { #if DEBUG_BEAMS VerifyNodeIndex(index, "hhBeam::NodeGet"); #endif return( nodeList[index] ); } //========================================================================== // // hhBeam::NodeSet // //========================================================================== void hhBeam::NodeSet(int index, idVec3 value) { #if DEBUG_BEAMS VerifyNodeIndex(index, "hhBeam::NodeSet"); #endif nodeList[index] = value; } //========================================================================== // // hhBeam::SplineGet // //========================================================================== idVec3 hhBeam::SplineGet(int index) { #if DEBUG_BEAMS VerifySplineIndex(index, "hhBeam::SplineSet"); #endif return(splineList[index]); } //========================================================================== // // hhBeam::SplineSet // //========================================================================== void hhBeam::SplineSet(int index, idVec3 value) { #if DEBUG_BEAMS VerifySplineIndex(index, "hhBeam::SplineSet"); #endif splineList[index] = value; } //========================================================================== // // hhBeam::SplineLinear // //========================================================================== void hhBeam::SplineLinear(idVec3 start, idVec3 end) { int i; idVec3 loc; idVec3 delta; loc = start; delta = (end - start) * BEAM_SPLINE_CONTROL_STEP; for(i = 0; i < MAX_BEAM_SPLINE_CONTROLS; i++) { splineList[i] = loc; loc += delta; } } //========================================================================== // // hhBeam::SplineLinearToTarget // //========================================================================== void hhBeam::SplineLinearToTarget( void ) { SplineLinear( system->GetRenderEntity()->origin, system->GetTargetLocation() ); } //========================================================================== // // hhBeam::SplineArc // //========================================================================== void hhBeam::SplineArc( idVec3 start, idVec3 end, idVec3 startVec ) { int i; idMat3 axis; idVec3 loc; idVec3 delta; idVec3 temp = startVec; temp.Normalize(); // Calculate the translation matrix axis[0] = ( end - start ); float dist = axis[0].Normalize(); axis[2] = temp.Cross( axis[0] ); axis[1] = axis[2].Cross( axis[0] ); float dp = temp * axis[0]; loc = start; delta = (end - start) * BEAM_SPLINE_CONTROL_STEP; float x = 0; for( i = 0; i < MAX_BEAM_SPLINE_CONTROLS; i++, x += BEAM_SPLINE_CONTROL_STEP ) { float temp = -dist * dp * x * ( 1 - x ); splineList[i] = loc + axis[1] * temp; loc += delta; } } //========================================================================== // // hhBeam::SplineArcToTarget // //========================================================================== void hhBeam::SplineArcToTarget( void ) { SplineArc( system->GetRenderEntity()->origin, system->GetTargetLocation(), system->GetArcVector() ); } //========================================================================== // // hhBeam::SplineAddSin // //========================================================================== void hhBeam::SplineAddSin(int index, float phaseX, float phaseY, float phaseZ, float offsetX, float offsetY, float offsetZ) { idVec3 sinOffset; #if DEBUG_BEAMS VerifySplineIndex(index, "hhBeam::SplineAddSin"); #endif sinOffset.x = offsetX * idMath::Sin(phaseX); sinOffset.y = offsetY * idMath::Sin(phaseY); sinOffset.z = offsetZ * idMath::Sin(phaseZ); splineList[index] += sinOffset * system->GetBeamAxis(); } //========================================================================== // // hhBeam::SplineAddSinTime // // Multiplies the sin value by the current game time //========================================================================== void hhBeam::SplineAddSinTime(int index, float phaseX, float phaseY, float phaseZ, float offsetX, float offsetY, float offsetZ) { float t; t = (gameLocal.time - system->GetBeamTime()) * 0.01f; SplineAddSin( index, phaseX * t, phaseY * t, phaseZ * t, offsetX, offsetY, offsetZ ); } //========================================================================== // // hhBeam::SplineAddSinTimeScaled // // Multiplies the sin value by the current game time //========================================================================== void hhBeam::SplineAddSinTimeScaled(int index, float phaseX, float phaseY, float phaseZ, float offsetX, float offsetY, float offsetZ) { float t; float offsetScale = system->GetBeamOffsetScale(); t = system->GetBeamPhaseScale() * (gameLocal.time - system->GetBeamTime()) * 0.01f; SplineAddSin( index, phaseX * t, phaseY * t, phaseZ * t, offsetX * offsetScale, offsetY * offsetScale, offsetZ * offsetScale ); } //========================================================================== // // hhBeam::SplineAdd // //========================================================================== void hhBeam::SplineAdd(int index, idVec3 offset) { #if DEBUG_BEAMS VerifySplineIndex(index, "hhBeam::SplineAdd"); #endif float offsetScale = system->GetBeamOffsetScale(); splineList[index] += offset * offsetScale; } //========================================================================== // // hhBeam::ConvertSplineToNodes // //========================================================================== void hhBeam::ConvertSplineToNodes(void) { int i; // Copy the last spline point into the extra "slop" points // The extra points are necessary to calculate the final spline segment for(i = 0; i < EXTRA_SPLINE_CONTROLS; i++) { splineList[MAX_BEAM_SPLINE_CONTROLS + i] = splineList[MAX_BEAM_SPLINE_CONTROLS - 1]; } // Construct the beam nodes from the spline points float inc = (float)(MAX_BEAM_SPLINE_CONTROLS) / system->decl->numNodes; float alpha = 0; for(i = 0; i < system->decl->numNodes; i++) { nodeList[i] = CurveExtractSpline(splineList, MAX_BEAM_SPLINE_CONTROLS + EXTRA_SPLINE_CONTROLS, alpha, true); alpha += inc; } } //========================================================================== // // hhBeam::NodeLinear // //========================================================================== void hhBeam::NodeLinear(idVec3 start, idVec3 end) { int i; idVec3 sLoc = start; idVec3 sDelta = (end - start) / (system->decl->numNodes - 1); for(i = 0; i < system->decl->numNodes; i++) { nodeList[i] = sLoc; sLoc += sDelta; } } //========================================================================== // // hhBeam::NodeLinearToTarget // //========================================================================== void hhBeam::NodeLinearToTarget( void ) { NodeLinear( system->GetRenderEntity()->origin, system->GetTargetLocation() ); } //========================================================================== // // hhBeam::NodeAdd // //========================================================================== void hhBeam::NodeAdd(int index, idVec3 offset) { #if DEBUG_BEAMS VerifyNodeIndex(index,"hhBeam::NodeAdd"); #endif nodeList[index] += offset; } //========================================================================== // // hhBeam::NodeElectric // //========================================================================== void hhBeam::NodeElectric(float x, float y, float z, bool bNotEnds) { int i; int start = 0; int end = system->decl->numNodes; if(bNotEnds) { start = 1; end = system->decl->numNodes - 1; } for(i = start; i < end; i++) { nodeList[i].x += system->random.CRandomFloat() * x; nodeList[i].y += system->random.CRandomFloat() * y; nodeList[i].z += system->random.CRandomFloat() * z; } } //========================================================================== // // hhBeam::TransformNodes // // Transform the worldspace nodes into model local space //========================================================================== void hhBeam::TransformNodes(void) { idVec3 origin = system->GetRenderEntity()->origin; idMat3 axis = system->GetRenderEntity()->axis.Transpose(); for(int i = 0; i < system->decl->numNodes; i++) { nodeList[i] = ( nodeList[i] - origin ) * axis; } } //========================================================================== // // hhBeam::GetBounds // // Get local bounds of beam //========================================================================== idBounds hhBeam::GetBounds() { idBounds bounds; if( !nodeList ) { return bounds_zero; } for( int ix = 0; ix < system->decl->numNodes; ++ix ) { bounds.AddPoint( nodeList[ix] ); } return bounds; } //================ //hhBeam::Save //================ void hhBeam::Save( idSaveGame *savefile ) const { for( int i = 0; i < MAX_BEAM_SPLINE_CONTROLS + EXTRA_SPLINE_CONTROLS; i++ ) { savefile->WriteVec3( splineList[i] ); } } //================ //hhBeam::Restore //================ void hhBeam::Restore( idRestoreGame *savefile, hhBeamSystem *newSystem, hhBeamNodes_t *newInfo) { system = newSystem; nodeList = newInfo->nodes; for( int i = 0; i < MAX_BEAM_SPLINE_CONTROLS + EXTRA_SPLINE_CONTROLS; i++ ) { savefile->ReadVec3( splineList[i] ); } } //============================================================================= // // CurveExtractSpline // //============================================================================= static idVec3 CurveExtractSpline(idVec3 *cPoints, int cPointCount, float alpha, bool bThruCtrlPnts ) { float t, t2, t3, w1, w2, w3, w4; int p1, p2, p3, p4, intAlpha; idVec3 result; intAlpha = alpha; p2 = intAlpha; p1 = (p2 == 0) ? p2 : p2-1; p3 = p2+1; p4 = (p3 == cPointCount-1) ? p3 : p3+1; t = alpha-intAlpha; t2 = t * t; t3 = t2 * t; if(!bThruCtrlPnts) { w1 = (1-t) * (1-t) * (1-t); w2 = 3.0f * t3 - 6.0f * t2 + 4; w3 = -3.0f * t3 + 3.0f * t2 + 3.0f * t + 1; w4 = t3; return ( w1 * cPoints[p1] + w2 * cPoints[p2] + w3 * cPoints[p3] + w4 * cPoints[p4]) * (1.0f/6.0f); } // Uses Catmull-Rom to pass thru the control points. if((cPoints[p3] - cPoints[p2]).Length() <= 4.0f) // was 16 { // If points are close enough, just linearly interpolate result = cPoints[p2] + t * (cPoints[p3] - cPoints[p2]); } else { result = 0.5f * ((-cPoints[p1] + 3 * cPoints[p2] - 3 * cPoints[p3] + cPoints[p4]) * t3 + (2 * cPoints[p1] - 5 * cPoints[p2]+ 4 * cPoints[p3] - cPoints[p4]) * t2 + (-cPoints[p1] + cPoints[p3]) * t + 2 * cPoints[p2]); } return(result); } //============================================================================= // // hhBeamSystem::ExecuteBeam // // Applies the commands to the specified beam //============================================================================= void hhBeamSystem::ExecuteBeam( int index, hhBeam *beam ) { int i; const beamCmd_t *cmd; for(i = 0; i < decl->cmds[index].Num(); i++) { cmd = &decl->cmds[index][i]; switch( cmd->type ) { case BEAMCMD_SplineLinearToTarget: beam->SplineLinearToTarget(); break; case BEAMCMD_SplineArcToTarget: beam->SplineArcToTarget(); break; case BEAMCMD_SplineAdd: beam->SplineAdd( cmd->index, cmd->offset ); break; case BEAMCMD_SplineAddSin: beam->SplineAddSin( cmd->index, cmd->phase.x, cmd->phase.y, cmd->phase.z, cmd->offset.x, cmd->offset.y, cmd->offset.z ); break; case BEAMCMD_SplineAddSinTim: beam->SplineAddSinTime( cmd->index, cmd->phase.x, cmd->phase.y, cmd->phase.z, cmd->offset.x, cmd->offset.y, cmd->offset.z ); break; case BEAMCMD_SplineAddSinTimeScaled: beam->SplineAddSinTimeScaled( cmd->index, cmd->phase.x, cmd->phase.y, cmd->phase.z, cmd->offset.x, cmd->offset.y, cmd->offset.z ); break; case BEAMCMD_ConvertSplineToNodes: beam->ConvertSplineToNodes(); break; case BEAMCMD_NodeLinearToTarget: beam->NodeLinearToTarget(); break; case BEAMCMD_NodeElectric: beam->NodeElectric( cmd->offset.x, cmd->offset.y, cmd->offset.z, true ); break; } } } //================ //hhBeamSystem::Save //================ void hhBeamSystem::Save( idSaveGame *savefile ) const { savefile->WriteString( declName ); savefile->WriteInt( random.GetSeed() ); savefile->WriteFloat( beamTime ); for( int i = 0; i < decl->numBeams; i++) { beamList[i].Save( savefile ); } savefile->WriteMat3( beamAxis ); savefile->WriteVec3( arcVector ); savefile->WriteVec3( targetLocation ); targetEntity.Save( savefile ); savefile->WriteVec3( targetEntityOffset ); savefile->WriteInt( targetEntityId ); savefile->WriteFloat( beamLength ); savefile->WriteBool( bRigidBeamLength ); savefile->WriteFloat( phaseScale ); savefile->WriteFloat( offsetScale ); savefile->WriteBool( bActive ); } //================ //hhBeamSystem::Restore //================ void hhBeamSystem::Restore( idRestoreGame *savefile ) { savefile->ReadString( declName ); // Initialize beam data from the beam file decl = (const hhDeclBeam*)declManager->FindType(DECL_BEAM, declName, false); HH_ASSERT( renderEntity.declBeam == decl ); // Initialize the random number generator int seed; savefile->ReadInt( seed ); random.SetSeed( seed ); savefile->ReadFloat( beamTime ); // Allocate the beams if( beamList ) { delete[] beamList; } beamList = new hhBeam[decl->numBeams]; for( int i = 0; i < decl->numBeams; i++) { beamList[i].Restore( savefile, this, &renderEntity.beamNodes[i]); } savefile->ReadMat3( beamAxis ); savefile->ReadVec3( arcVector ); savefile->ReadVec3( targetLocation ); targetEntity.Restore( savefile ); savefile->ReadVec3( targetEntityOffset ); savefile->ReadInt( targetEntityId ); savefile->ReadFloat( beamLength ); savefile->ReadBool( bRigidBeamLength ); savefile->ReadFloat( phaseScale ); savefile->ReadFloat( offsetScale ); savefile->ReadBool( bActive ); Activate(bActive); }