mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
1151 lines
31 KiB
C++
1151 lines
31 KiB
C++
//**************************************************************************
|
|
//**
|
|
//** 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("<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 <int> - total number of beams in the system
|
|
// beamNodes <int> - total number of nodes per beam
|
|
//
|
|
// Per beam (end number specifies the beam):
|
|
//
|
|
// beamThickness0 <int> - Thickness
|
|
// beamTaperEndPoints0 <bool> - If the beam should have tapered end points
|
|
// beamShader0 <string> - Shader name
|
|
// beamSpline0 <bool> - 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<idAFEntity_Base *>( 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);
|
|
}
|
|
|