2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-13 18:17:49 -04:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
JWPlatt
2011-03-12 12:34:52 -05:00
commit a20a222fc2
3976 changed files with 1301356 additions and 0 deletions

View File

@ -0,0 +1,72 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef pfAnimationCreatable_inc
#define pfAnimationCreatable_inc
#include "../pnFactory/plCreator.h"
#include "plViewFaceModifier.h"
REGISTER_CREATABLE( plViewFaceModifier );
#include "plLineFollowMod.h"
REGISTER_CREATABLE( plLineFollowMod );
REGISTER_CREATABLE( plRailCameraMod );
#include "plLightModifier.h"
REGISTER_CREATABLE( plLightModifier );
REGISTER_CREATABLE( plOmniModifier );
REGISTER_CREATABLE( plSpotModifier );
REGISTER_CREATABLE( plLtdDirModifier );
#include "plRandomCommandMod.h"
REGISTER_NONCREATABLE( plRandomCommandMod );
#include "plFollowMod.h"
REGISTER_CREATABLE( plFollowMod );
#include "plBlower.h"
REGISTER_CREATABLE( plBlower );
#include "plFilterCoordInterface.h"
REGISTER_CREATABLE( plFilterCoordInterface );
#include "plStereizer.h"
REGISTER_CREATABLE( plStereizer );
#include "pfObjectFlocker.h"
REGISTER_CREATABLE( pfObjectFlocker );
#endif // pfAnimationCreatable_inc

View File

@ -0,0 +1,438 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef OBJECT_FLOCKER_H
#define OBJECT_FLOCKER_H
#include "../pnModifier/plSingleModifier.h"
class hsStream;
class hsResMgr;
class plRandom;
class pfObjectFlocker;
// Database tokens for our prox database
template <class T>
class pfTokenForProximityDatabase
{
public:
virtual ~pfTokenForProximityDatabase() {}
// call this when your position changes
virtual void UpdateWithNewPosition(const hsPoint3 &newPos) = 0;
// find all close-by objects (determined by center and radius)
virtual void FindNeighbors(const hsPoint3 &center, const float radius, std::vector<T> &results) = 0;
};
// A basic prox database (might need to be optimized in the future)
template <class T>
class pfBasicProximityDatabase
{
public:
class tokenType;
typedef std::vector<tokenType*> tokenVector;
typedef typename tokenVector::const_iterator tokenIterator;
// "token" to represent objects stored in the database
class tokenType: public pfTokenForProximityDatabase<T>
{
private:
tokenVector& fTokens;
T fParent;
hsPoint3 fPosition;
public:
// constructor
tokenType(T parentObject, tokenVector& tokens) : fParent(parentObject), fTokens(tokens)
{
fTokens.push_back(this);
}
// destructor
virtual ~tokenType()
{
// remove this token from the database's vector
fTokens.erase(std::find(fTokens.begin(), fTokens.end(), this));
}
// call this when your position changes
void UpdateWithNewPosition(const hsPoint3 &newPosition) {fPosition = newPosition;}
// find all close-by objects (determined by center and radius)
void FindNeighbors(const hsPoint3 &center, const float radius, std::vector<T> & results)
{
// take the slow way, loop and check every one
const float radiusSquared = radius * radius;
for (tokenIterator i = fTokens.begin(); i != fTokens.end(); i++)
{
const hsVector3 offset(&center, &((**i).fPosition));
const float distanceSquared = offset.MagnitudeSquared();
// push onto result vector when within given radius
if (distanceSquared < radiusSquared)
results.push_back((**i).fParent);
}
}
};
private:
// STL vector containing all tokens in database
tokenVector fGroup;
public:
// constructor
pfBasicProximityDatabase(void) {}
// destructor
virtual ~pfBasicProximityDatabase() {}
// allocate a token to represent a given client object in this database
tokenType *MakeToken(T parentObject) {return TRACKED_NEW tokenType(parentObject, fGroup);}
// return the number of tokens currently in the database
int Size(void) {return group.size();}
};
// A basic vehicle class that handles accelleration, braking, and turning
class pfVehicle
{
private:
hsPoint3 fPos; // position in meters
hsPoint3 fLastPos; // the last position we had
hsPoint3 fSmoothedPosition;
hsVector3 fVel; // velocity in meters/second
hsVector3 fSmoothedAcceleration;
hsVector3 fForward; // forward vector (unit length)
hsVector3 fLastForward; // the last forward vector we had
hsVector3 fSide; // side vector (unit length)
hsVector3 fUp; // up vector (unit length)
float fSpeed; // speed (length of velocity vector)
float fMass; // mass of the object (defaults to 1)
float fMaxForce; // the maximum steering force that can be applied
float fMaxSpeed; // the maximum speed of this vehicle
float fCurvature;
float fSmoothedCurvature;
float fRadius;
// measure the path curvature (1/turning radius), maintain smoothed version
void IMeasurePathCurvature(const float elapsedTime);
public:
pfVehicle() {Reset();}
virtual ~pfVehicle() {}
void Reset();
// get/set attributes
float Mass() const {return fMass;}
float SetMass(float m) {return fMass = m;}
hsVector3 Forward() const {return fForward;}
hsVector3 SetForward(hsVector3 forward) {return fForward = forward;}
hsVector3 Side() const {return fSide;}
hsVector3 SetSide(hsVector3 side) {return fSide = side;}
hsVector3 Up() const {return fUp;}
hsVector3 SetUp(hsVector3 up) {return fUp = up;}
hsPoint3 Position() const {return fPos;}
hsPoint3 SetPosition(hsPoint3 pos) {return fPos = pos;}
hsVector3 Velocity() const {return Forward() * fSpeed;}
float Speed() const {return fSpeed;}
float SetSpeed(float speed) {return fSpeed = speed;}
float MaxForce() const {return fMaxForce;}
float SetMaxForce(float maxForce) {return fMaxForce = maxForce;}
float MaxSpeed() const {return fMaxSpeed;}
float SetMaxSpeed(float maxSpeed) {return fMaxSpeed = maxSpeed;}
float Curvature() const {return fCurvature;}
float SmoothedCurvature() {return fSmoothedCurvature;}
float ResetSmoothedCurvature(float value = 0);
hsVector3 SmoothedAcceleration() {return fSmoothedAcceleration;}
hsVector3 ResetSmoothedAcceleration(const hsVector3 &value = hsVector3(0,0,0));
hsPoint3 SmoothedPosition() {return fSmoothedPosition;}
hsPoint3 ResetSmoothedPosition(const hsPoint3 &value = hsPoint3(0,0,0));
float Radius() const {return fRadius;}
float SetRadius(float radius) {return fRadius = radius;}
// Basic geometry functions
// Reset local space to identity
void ResetLocalSpace();
// Set the side vector to a normalized cross product of forward and up
void SetUnitSideFromForwardAndUp();
// Regenerate orthonormal basis vectors given a new forward vector (unit length)
void RegenerateOrthonormalBasisUF(const hsVector3 &newUnitForward);
// If the new forward is NOT known to have unit length
void RegenerateOrthonormalBasis(const hsVector3 &newForward)
{hsVector3 temp = newForward; temp.Normalize(); RegenerateOrthonormalBasisUF(temp);}
// For supplying both a new forward, and a new up
void RegenerateOrthonormalBasis(const hsVector3 &newForward, const hsVector3 &newUp)
{fUp = newUp; RegenerateOrthonormalBasis(newForward);}
// Keep forward parallel to velocity, change up as little as possible
virtual void RegenerateLocalSpace(const hsVector3 &newVelocity, const float elapsedTime);
// Keep forward parallel to velocity, but "bank" the up vector
void RegenerateLocalSpaceForBanking(const hsVector3 &newVelocity, const float elapsedTime);
// Vehicle physics functions
// apply a steering force to our momentum and adjust our
// orientation to match our velocity vector
void ApplySteeringForce(const hsVector3 &force, const float deltaTime);
// adjust the steering force passed to ApplySteeringForce (so sub-classes can refine)
// by default, we won't allow backward-facing steering at a low speed
virtual hsVector3 AdjustRawSteeringForce(const hsVector3 &force, const float deltaTime);
// apply a braking force
void ApplyBrakingForce(const float rate, const float deltaTime);
// predict the position of the vehicle (assumes constant velocity)
hsPoint3 PredictFuturePosition(const float predictionTime);
};
// A goal object, basically keeps track of a scene object so we can get velocity from it
class pfBoidGoal
{
private:
hsPoint3 fLastPos;
hsPoint3 fCurPos;
hsVector3 fForward;
float fSpeed; // in meters/sec
hsBool fHasLastPos; // does the last position make sense?
public:
pfBoidGoal();
~pfBoidGoal() {}
void Update(plSceneObject *goal, float deltaTime);
hsPoint3 Position() const {return fCurPos;}
float Speed() const {return fSpeed;}
hsVector3 Forward() const {return fForward;}
hsPoint3 PredictFuturePosition(const float predictionTime);
};
typedef pfTokenForProximityDatabase<pfVehicle*> pfProximityToken;
typedef pfBasicProximityDatabase<pfVehicle*> pfProximityDatabase;
// The actual "flocking following" (not really a boid, but whatever)
class pfBoid: public pfVehicle
{
private:
plKey fObjKey;
float fWanderSide;
float fWanderUp;
float fGoalWeight;
float fRandomWeight;
float fSeparationRadius;
float fSeparationAngle;
float fSeparationWeight;
float fCohesionRadius;
float fCohesionAngle;
float fCohesionWeight;
pfProximityToken* fProximityToken;
std::vector<pfVehicle*> fNeighbors;
// Set our flocking settings to default
void IFlockDefaults();
// Setup our prox database token
void ISetupToken(pfProximityDatabase &pd);
// Are we in the neighborhood of another boid?
hsBool IInBoidNeighborhood(const pfVehicle &other, const float minDistance, const float maxDistance, const float cosMaxAngle);
// Wander steering
hsVector3 ISteerForWander(float timeDelta);
// Seek the target point
hsVector3 ISteerForSeek(const hsPoint3 &target);
// Steer the boid toward our goal
hsVector3 ISteerToGoal(pfBoidGoal &goal, float maxPredictionTime);
// Steer to keep separation
hsVector3 ISteerForSeparation(const float maxDistance, const float cosMaxAngle, const std::vector<pfVehicle*> &flock);
// Steer to keep the flock together
hsVector3 ISteerForCohesion(const float maxDistance, const float cosMaxAngle, const std::vector<pfVehicle*> &flock);
public:
pfObjectFlocker *fFlockerPtr;
pfBoid(pfProximityDatabase &pd, pfObjectFlocker *flocker, plKey &key);
pfBoid(pfProximityDatabase &pd, pfObjectFlocker *flocker, plKey &key, hsPoint3 &pos);
pfBoid(pfProximityDatabase &pd, pfObjectFlocker *flocker, plKey &key, hsPoint3 &pos, float speed, hsVector3 &forward, hsVector3 &side, hsVector3 &up);
virtual ~pfBoid();
// Get/set functions
float GoalWeight() const {return fGoalWeight;}
float SetGoalWeight(float goalWeight) {return fGoalWeight = goalWeight;}
float WanderWeight() const {return fRandomWeight;}
float SetWanderWeight(float wanderWeight) {return fRandomWeight = wanderWeight;}
float SeparationWeight() const {return fSeparationWeight;}
float SetSeparationWeight(float weight) {return fSeparationWeight = weight;}
float SeparationRadius() const {return fSeparationRadius;}
float SetSeparationRadius(float radius) {return fSeparationRadius = radius;}
float CohesionWeight() const {return fCohesionWeight;}
float SetCohesionWeight(float weight) {return fCohesionWeight = weight;}
float CohesionRadius() const {return fCohesionRadius;}
float SetCohesionRadius(float radius) {return fCohesionRadius = radius;}
// Update the boid's data based on the goal and time delta
void Update(pfBoidGoal &goal, float deltaTime);
plKey &GetKey() {return fObjKey;}
// We're redirecting this to the "banking" function
virtual void RegenerateLocalSpace(const hsVector3 &newVelocity, const float elapsedTime);
};
class pfFlock
{
private:
std::vector<pfBoid*> fBoids;
pfBoidGoal fBoidGoal;
pfProximityDatabase *fDatabase;
// global values so when we add a boid we can set it's parameters
float fGoalWeight, fRandomWeight;
float fSeparationWeight, fSeparationRadius;
float fCohesionWeight, fCohesionRadius;
float fMaxForce; // max steering force
float fMaxSpeed, fMinSpeed;
public:
pfFlock();
~pfFlock();
// Get/set functions (affect the whole flock, and any new boids added)
float GoalWeight() const {return fGoalWeight;}
void SetGoalWeight(float goalWeight);
float WanderWeight() const {return fRandomWeight;}
void SetWanderWeight(float wanderWeight);
float SeparationWeight() const {return fSeparationWeight;}
void SetSeparationWeight(float weight);
float SeparationRadius() const {return fSeparationRadius;}
void SetSeparationRadius(float radius);
float CohesionWeight() const {return fCohesionWeight;}
void SetCohesionWeight(float weight);
float CohesionRadius() const {return fCohesionRadius;}
void SetCohesionRadius(float radius);
float MaxForce() const {return fMaxForce;}
void SetMaxForce(float force);
float MaxSpeed() const {return fMaxSpeed;}
void SetMaxSpeed(float speed);
float MinSpeed() const {return fMinSpeed;}
void SetMinSpeed(float minSpeed);
// setup/run functions
void AddBoid(pfObjectFlocker *flocker, plKey &key, hsPoint3 &pos);
void Update(plSceneObject *goal, float deltaTime);
pfBoid *GetBoid(int i);
friend class pfObjectFlocker;
};
class pfObjectFlocker : public plSingleModifier
{
public:
pfObjectFlocker();
~pfObjectFlocker();
CLASSNAME_REGISTER( pfObjectFlocker );
GETINTERFACE_ANY( pfObjectFlocker, plSingleModifier );
virtual void SetTarget(plSceneObject* so);
virtual hsBool MsgReceive(plMessage* msg);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void SetNumBoids(UInt8 val);
void SetBoidKey(plKey key) { fBoidKey = key; }
float GoalWeight() const {return fFlock.GoalWeight();}
void SetGoalWeight(float goalWeight) {fFlock.SetGoalWeight(goalWeight);}
float WanderWeight() const {return fFlock.WanderWeight();}
void SetWanderWeight(float wanderWeight) {fFlock.SetWanderWeight(wanderWeight);}
float SeparationWeight() const {return fFlock.SeparationWeight();}
void SetSeparationWeight(float weight) {fFlock.SetSeparationWeight(weight);}
float SeparationRadius() const {return fFlock.SeparationRadius();}
void SetSeparationRadius(float radius) {fFlock.SetSeparationRadius(radius);}
float CohesionWeight() const {return fFlock.CohesionWeight();}
void SetCohesionWeight(float weight) {fFlock.SetCohesionWeight(weight);}
float CohesionRadius() const {return fFlock.CohesionRadius();}
void SetCohesionRadius(float radius) {fFlock.SetCohesionRadius(radius);}
float MaxForce() const {return fFlock.MaxForce();}
void SetMaxForce(float force) {fFlock.SetMaxForce(force);}
float MaxSpeed() const {return fFlock.MaxSpeed();}
void SetMaxSpeed(float speed) {fFlock.SetMaxSpeed(speed);}
float MinSpeed() const {return fFlock.MinSpeed();}
void SetMinSpeed(float minSpeed) {fFlock.SetMinSpeed(minSpeed);}
hsBool RandomizeAnimStart() const {return fRandomizeAnimationStart;}
void SetRandomizeAnimStart(hsBool val) {fRandomizeAnimationStart = val;}
hsBool UseTargetRotation() const {return fUseTargetRotation;}
void SetUseTargetRotation(hsBool val) {fUseTargetRotation = val;}
protected:
const static int fFileVersion; // so we don't have to update the global version number when we change
pfFlock fFlock;
int fNumBoids;
plKey fBoidKey;
hsBool fUseTargetRotation;
hsBool fRandomizeAnimationStart;
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
};
#endif

View File

@ -0,0 +1,149 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsStlUtils.h"
#include "hsResMgr.h"
#include "hsTemplates.h"
#include "hsTimer.h"
#include "plAnimDebugList.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../plSurface/hsGMaterial.h"
#include "../plSurface/plLayerAnimation.h"
#include "../plAvatar/plAGMasterMod.h"
#include "../plAvatar/plAGAnimInstance.h"
#include "../plAvatar/plAGAnim.h"
#include "../plResMgr/plKeyFinder.h"
#include "../plPipeline/plDebugText.h"
void plAnimDebugList::AddObjects(char *subString)
{
std::vector<plKey> keys;
std::vector<plKey>::iterator i;
plKeyFinder::Instance().ReallyStupidSubstringSearch(subString, hsGMaterial::Index(), keys);
for (i = keys.begin(); i != keys.end(); i++)
{
if (fMaterialKeys.Find((*i)) == fMaterialKeys.kMissingIndex)
fMaterialKeys.Append((*i));
}
keys.clear();
plKeyFinder::Instance().ReallyStupidSubstringSearch(subString, plSceneObject::Index(), keys);
for (i = keys.begin(); i != keys.end(); i++)
{
plSceneObject *so = plSceneObject::ConvertNoRef((*i)->ObjectIsLoaded());
if (so)
{
const plAGMasterMod *agMod = plAGMasterMod::ConvertNoRef(so->GetModifierByType(plAGMasterMod::Index()));
if (agMod && fSOKeys.Find(so->GetKey()) == fSOKeys.kMissingIndex)
fSOKeys.Append(so->GetKey());
}
}
}
void plAnimDebugList::RemoveObjects(char *subString)
{
int i;
for (i = fMaterialKeys.GetCount() - 1; i >= 0; i--)
{
if (strstr(fMaterialKeys[i]->GetName(), subString))
fMaterialKeys.Remove(i);
}
for (i = fSOKeys.GetCount() - 1; i >= 0; i--)
{
if (strstr(fSOKeys[i]->GetName(), subString))
fSOKeys.Remove(i);
}
}
void plAnimDebugList::ShowReport()
{
if (!fEnabled)
return;
plDebugText &txt = plDebugText::Instance();
int y,x,i,j;
const int yOff=10, startY=40, startX=10;
char str[256];
x = startX;
y = startY;
txt.DrawString(x, y, "Material Animations:", 255, 255, 255, 255, plDebugText::kStyleBold);
y += yOff;
for (i = 0; i < fMaterialKeys.GetCount(); i++)
{
hsGMaterial *mat = hsGMaterial::ConvertNoRef(fMaterialKeys[i]->ObjectIsLoaded());
if (!mat)
continue;
for (j = 0; j < mat->GetNumLayers(); j++)
{
plLayerInterface *layer = mat->GetLayer(j)->BottomOfStack();
while (layer != nil)
{
plLayerAnimation *layerAnim = plLayerAnimation::ConvertNoRef(layer);
if (layerAnim)
{
sprintf(str, "%s: %s %.3f (%.3f)", mat->GetKeyName(), layerAnim->GetKeyName(),
layerAnim->GetTimeConvert().CurrentAnimTime(),
layerAnim->GetTimeConvert().WorldToAnimTimeNoUpdate(hsTimer::GetSysSeconds()));
txt.DrawString(x, y, str);
y += yOff;
}
layer = layer->GetOverLay();
}
}
}
y += yOff;
txt.DrawString(x, y, "AGMaster Anims", 255, 255, 255, 255, plDebugText::kStyleBold);
y += yOff;
for (i = 0; i < fSOKeys.GetCount(); i++)
{
plSceneObject *so = plSceneObject::ConvertNoRef(fSOKeys[i]->ObjectIsLoaded());
if (!so)
continue;
plAGMasterMod *mod = const_cast<plAGMasterMod*>(plAGMasterMod::ConvertNoRef(so->GetModifierByType(plAGMasterMod::Index())));
if (!mod)
continue;
sprintf(str, " %s", so->GetKeyName());
txt.DrawString(x, y, str);
y += yOff;
for (j = 0; j < mod->GetNumATCAnimations(); j++)
{
plAGAnimInstance *anim = mod->GetATCAnimInstance(j);
sprintf(str, " %s: %.3f (%.3f)", anim->GetAnimation()->GetName(),
anim->GetTimeConvert()->CurrentAnimTime(),
anim->GetTimeConvert()->WorldToAnimTimeNoUpdate(hsTimer::GetSysSeconds()));
txt.DrawString(x, y, str);
y += yOff;
}
}
}

View File

@ -0,0 +1,47 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plAnimDebugList_inc
#define plAnimDebugList_inc
// Simple debugging tool, everything is public
// This class collects a list of keyed objects that deal with
// animation, to report info on them when requested.
class plAnimDebugList
{
public:
hsBool fEnabled;
hsTArray<plKey> fSOKeys;
hsTArray<plKey> fMaterialKeys;
plAnimDebugList() : fEnabled(false) {}
~plAnimDebugList() {}
void AddObjects(char *subString);
void RemoveObjects(char *subString);
void ShowReport();
};
#endif

View File

@ -0,0 +1,224 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plBlower.h"
#include "plgDispatch.h"
#include "hsFastMath.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnMessage/plTimeMsg.h"
#include "hsTimer.h"
plRandom plBlower::fRandom;
static const hsScalar kDefaultMasterPower = 20.f;
static const hsScalar kDefaultMasterFrequency = 2.f;
static const hsScalar kDefaultDirectRate = 1.f;
static const hsScalar kDefaultImpulseRate = 1.e2f;
static const hsScalar kDefaultSpringKonst = 20.f;
static const hsScalar kDefaultBias = 0.25f;
static const hsScalar kInitialMaxOffDist = 1.f;
plBlower::plBlower()
:
fMasterPower(kDefaultMasterPower),
fMasterFrequency(kDefaultMasterFrequency),
fDirectRate(kDefaultDirectRate),
fImpulseRate(kDefaultImpulseRate),
fSpringKonst(kDefaultSpringKonst),
fBias(kDefaultBias),
fMaxOffsetDist(kInitialMaxOffDist),
fAccumTime(0)
{
fRestPos.Set(0,0,0);
fLocalRestPos.Set(0,0,0);
fCurrDel.Set(0,0,0);
fDirection.Set(fRandom.RandMinusOneToOne(), fRandom.RandMinusOneToOne(), 0);
hsFastMath::NormalizeAppr(fDirection);
}
plBlower::~plBlower()
{
}
void plBlower::IBlow(double secs, hsScalar delSecs)
{
hsPoint3 worldPos = fTarget->GetLocalToWorld().GetTranslate();
hsPoint3 localPos = fTarget->GetLocalToParent().GetTranslate();
// fast oscillation vs slow
// Completely random walk in the rotation
// Strength = Strength + rnd01 * (MaxStrength - Strength)
hsScalar t = (fAccumTime += delSecs);
hsScalar strength = 0;
int i;
for( i = 0; i < fOscillators.GetCount(); i++ )
{
hsScalar c, s;
t *= fOscillators[i].fFrequency * fMasterFrequency;
t += fOscillators[i].fPhase;
hsFastMath::SinCosAppr(t, s, c);
c += fBias;
strength += c * fOscillators[i].fPower;
}
strength *= fMasterPower;
if( strength < 0 )
strength = 0;
fDirection.fX += fRandom.RandMinusOneToOne() * delSecs * fDirectRate;
fDirection.fY += fRandom.RandMinusOneToOne() * delSecs * fDirectRate;
hsFastMath::NormalizeAppr(fDirection);
hsScalar offDist = hsVector3(&fRestPos, &worldPos).Magnitude();
if( offDist > fMaxOffsetDist )
fMaxOffsetDist = offDist;
hsVector3 force = fDirection * strength;
static hsScalar kOffsetDistFrac = 0.5f; // make me const
if( offDist > fMaxOffsetDist * kOffsetDistFrac )
{
offDist /= fMaxOffsetDist;
offDist *= fMasterPower;
hsScalar impulse = offDist * delSecs * fImpulseRate;
force.fX += impulse * fRandom.RandMinusOneToOne();
force.fY += impulse * fRandom.RandMinusOneToOne();
force.fZ += impulse * fRandom.RandMinusOneToOne();
}
const hsScalar kOffsetDistDecay = 0.999f;
fMaxOffsetDist *= kOffsetDistDecay;
hsVector3 accel = force;
accel += fSpringKonst * hsVector3(&fLocalRestPos, &localPos);
hsVector3 del = accel * (delSecs * delSecs);
fCurrDel = del;
}
hsBool plBlower::IEval(double secs, hsScalar delSecs, UInt32 dirty)
{
const hsScalar kMaxDelSecs = 0.1f;
if( delSecs > kMaxDelSecs )
delSecs = kMaxDelSecs;
IBlow(secs, delSecs);
ISetTargetTransform();
return true;
}
void plBlower::ISetTargetTransform()
{
plCoordinateInterface* ci = IGetTargetCoordinateInterface(0);
if( ci )
{
hsMatrix44 l2p = ci->GetLocalToParent();
hsMatrix44 p2l = ci->GetParentToLocal();
hsPoint3 pos = l2p.GetTranslate();
pos += fCurrDel;
l2p.SetTranslate(&pos);
p2l.SetTranslate(&-pos);
ci->SetLocalToParent(l2p, p2l);
}
}
void plBlower::SetTarget(plSceneObject* so)
{
plSingleModifier::SetTarget(so);
if( fTarget )
{
fRestPos = fTarget->GetLocalToWorld().GetTranslate();
fLocalRestPos = fTarget->GetLocalToParent().GetTranslate();
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
}
IInitOscillators();
}
void plBlower::Read(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Read(s, mgr);
fMasterPower = s->ReadSwapScalar();
fDirectRate = s->ReadSwapScalar();
fImpulseRate = s->ReadSwapScalar();
fSpringKonst = s->ReadSwapScalar();
}
void plBlower::Write(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Write(s, mgr);
s->WriteSwapScalar(fMasterPower);
s->WriteSwapScalar(fDirectRate);
s->WriteSwapScalar(fImpulseRate);
s->WriteSwapScalar(fSpringKonst);
}
void plBlower::IInitOscillators()
{
const hsScalar kBasePower = 5.f;
fOscillators.SetCount(5);
int i;
for( i = 0; i < fOscillators.GetCount(); i++ )
{
hsScalar fi = hsScalar(i+1);
fOscillators[i].fFrequency = fi / hsScalarPI * fRandom.RandRangeF(0.75f, 1.25f);
// fOscillators[i].fFrequency = 1.f / hsScalarPI * fRandom.RandRangeF(0.5f, 1.5f);
fOscillators[i].fPhase = fRandom.RandZeroToOne();
fOscillators[i].fPower = kBasePower * fRandom.RandRangeF(0.75f, 1.25f);
}
}
void plBlower::SetConstancy(hsScalar f)
{
if( f < 0 )
f = 0;
else if( f > 1.f )
f = 1.f;
fBias = f;
}
hsScalar plBlower::GetConstancy() const
{
return fBias;
}

View File

@ -0,0 +1,101 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plBlower_inc
#define plBlower_inc
#include "../pnModifier/plSingleModifier.h"
#include "hsGeometry3.h"
#include "../plMath/plRandom.h"
#include "hsTemplates.h"
class plSceneObject;
class hsStream;
class hsResMgr;
class plBlower : public plSingleModifier
{
protected:
class Oscillator
{
public:
hsScalar fFrequency;
hsScalar fPhase;
hsScalar fPower;
};
static plRandom fRandom;
// Parameters
hsScalar fMasterPower;
hsScalar fMasterFrequency;
hsScalar fDirectRate;
hsScalar fImpulseRate;
hsScalar fSpringKonst;
hsScalar fBias;
hsScalar fAccumTime;
hsTArray<Oscillator> fOscillators;
// CurrentState
hsVector3 fDirection;
hsPoint3 fRestPos;
hsPoint3 fLocalRestPos;
hsVector3 fCurrDel;
hsScalar fMaxOffsetDist;
void IInitOscillators();
void ISetTargetTransform();
void IBlow(double secs, hsScalar delSecs);
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
public:
~plBlower();
plBlower();
CLASSNAME_REGISTER( plBlower );
GETINTERFACE_ANY( plBlower, plSingleModifier );
virtual void SetTarget(plSceneObject* so);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void SetMasterPower(hsScalar f) { fMasterPower = f; }
void SetMasterFrequency(hsScalar f) { fMasterFrequency = f; }
void SetDirectRate(hsScalar f) { fDirectRate = f; }
void SetImpulseRate(hsScalar f) { fImpulseRate = f; }
void SetSpringKonst(hsScalar f) { fSpringKonst = f; }
void SetConstancy(hsScalar f);
hsScalar GetMasterPower() const { return fMasterPower; }
hsScalar GetMasterFrequency() const { return fMasterFrequency; }
hsScalar GetDirectRate() const { return fDirectRate; }
hsScalar GetImpulseRate() const { return fImpulseRate; }
hsScalar GetSpringKonst() const { return fSpringKonst; }
hsScalar GetConstancy() const;
};
#endif // plBlower_inc

View File

@ -0,0 +1,133 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plFilterCoordInterface.h"
#include "hsMatrix44.h"
#include "hsStream.h"
static hsMatrix44* InvTRS(const hsMatrix44& trs, hsMatrix44& inv)
{
inv.NotIdentity();
hsScalar invSSq[3];
invSSq[0] = 1.f / (trs.fMap[0][0] * trs.fMap[0][0] + trs.fMap[1][0] * trs.fMap[1][0] + trs.fMap[2][0] * trs.fMap[2][0]);
invSSq[1] = 1.f / (trs.fMap[0][1] * trs.fMap[0][1] + trs.fMap[1][1] * trs.fMap[1][1] + trs.fMap[2][1] * trs.fMap[2][1]);
invSSq[2] = 1.f / (trs.fMap[0][2] * trs.fMap[0][2] + trs.fMap[1][2] * trs.fMap[1][2] + trs.fMap[2][2] * trs.fMap[2][2]);
inv.fMap[0][0] = invSSq[0] * trs.fMap[0][0];
inv.fMap[0][1] = invSSq[0] * trs.fMap[1][0];
inv.fMap[0][2] = invSSq[0] * trs.fMap[2][0];
inv.fMap[0][3] = -(inv.fMap[0][0] * trs.fMap[0][3] + inv.fMap[0][1] * trs.fMap[1][3] + inv.fMap[0][2] * trs.fMap[2][3]);
inv.fMap[1][0] = invSSq[1] * trs.fMap[0][1];
inv.fMap[1][1] = invSSq[1] * trs.fMap[1][1];
inv.fMap[1][2] = invSSq[1] * trs.fMap[2][1];
inv.fMap[1][3] = -(inv.fMap[1][0] * trs.fMap[0][3] + inv.fMap[1][1] * trs.fMap[1][3] + inv.fMap[1][2] * trs.fMap[2][3]);
inv.fMap[2][0] = invSSq[2] * trs.fMap[0][2];
inv.fMap[2][1] = invSSq[2] * trs.fMap[1][2];
inv.fMap[2][2] = invSSq[2] * trs.fMap[2][2];
inv.fMap[2][3] = -(inv.fMap[2][0] * trs.fMap[0][3] + inv.fMap[2][1] * trs.fMap[1][3] + inv.fMap[2][2] * trs.fMap[2][3]);
inv.fMap[3][0] = inv.fMap[3][1] = inv.fMap[3][2] = 0;
inv.fMap[3][3] = 1.f;
return &inv;
}
plFilterCoordInterface::plFilterCoordInterface()
: fFilterMask(kNoRotation)
{
fRefParentLocalToWorld.Reset();
}
plFilterCoordInterface::~plFilterCoordInterface()
{
}
void plFilterCoordInterface::Read(hsStream* stream, hsResMgr* mgr)
{
plCoordinateInterface::Read(stream, mgr);
fFilterMask = stream->ReadSwap32();
fRefParentLocalToWorld.Read(stream);
}
void plFilterCoordInterface::Write(hsStream* stream, hsResMgr* mgr)
{
plCoordinateInterface::Write(stream, mgr);
stream->WriteSwap32(fFilterMask);
fRefParentLocalToWorld.Write(stream);
}
void plFilterCoordInterface::IRecalcTransforms()
{
if( !(fFilterMask && fParent) )
{
plCoordinateInterface::IRecalcTransforms();
return;
}
hsMatrix44 origL2W = fRefParentLocalToWorld * fLocalToParent;
fLocalToWorld = fParent->GetLocalToWorld() * fLocalToParent;
// Filter out the stuff we're discarding. Nothing fancy here,
// we're taking the simple (and fast) form and just stuffing in
// what we want to preserve based on our reference matrix.
if( fFilterMask & kNoTransX )
{
fLocalToWorld.fMap[0][3] = origL2W.fMap[0][3];
}
if( fFilterMask & kNoTransY )
{
fLocalToWorld.fMap[1][3] = origL2W.fMap[1][3];
}
if( fFilterMask & kNoTransZ )
{
fLocalToWorld.fMap[2][3] = origL2W.fMap[2][3];
}
if( fFilterMask & kNoRotation )
{
int i;
for( i = 0; i < 3; i++ )
{
int j;
for( j = 0; j < 3; j++ )
{
fLocalToWorld.fMap[i][j] = origL2W.fMap[i][j];
}
}
}
// Construct the inverse of local to world for world to local.
InvTRS(fLocalToWorld, fWorldToLocal);
}

View File

@ -0,0 +1,68 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plFilterCoordInterface_inc
#define plFilterCoordInterface_inc
#include "../pnSceneObject/plCoordinateInterface.h"
class plFilterCoordInterface : public plCoordinateInterface
{
public:
enum
{
kNoRotation = 0x1,
kNoTransX = 0x2,
kNoTransY = 0x4,
kNoTransZ = 0x8,
kNoMove = kNoTransX | kNoTransY | kNoTransZ,
kNoNothing = kNoRotation | kNoMove
};
protected:
UInt32 fFilterMask;
hsMatrix44 fRefParentLocalToWorld;
virtual void IRecalcTransforms();
public:
plFilterCoordInterface();
~plFilterCoordInterface();
CLASSNAME_REGISTER( plFilterCoordInterface );
GETINTERFACE_ANY( plFilterCoordInterface, plCoordinateInterface );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void SetFilterMask(UInt32 f) { fFilterMask = f; }
UInt32 GetFilterMask() const { return fFilterMask; }
void SetRefLocalToWorld(const hsMatrix44& m) { fRefParentLocalToWorld = m; }
const hsMatrix44& GetRefLocalToWorld() const { return fRefParentLocalToWorld; }
};
#endif // plFilterCoordInterface_inc

View File

@ -0,0 +1,282 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plFollowMod.h"
#include "plgDispatch.h"
#include "../pnNetCommon/plNetApp.h"
#include "../plMessage/plListenerMsg.h"
#include "../plMessage/plRenderMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnMessage/plRefMsg.h"
#include "hsResMgr.h"
#include "plPipeline.h"
plFollowMod::plFollowMod()
: fLeader(nil), fMode(kPosition), fLeaderType(kLocalPlayer), fLeaderSet(false)
{
}
plFollowMod::~plFollowMod()
{
}
#include "plProfile.h"
plProfile_CreateTimer("FollowMod", "RenderSetup", FollowMod);
hsBool plFollowMod::MsgReceive(plMessage* msg)
{
plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg);
if( rend )
{
plProfile_BeginLap(FollowMod, this->GetKey()->GetUoid().GetObjectName());
fLeaderL2W = rend->Pipeline()->GetCameraToWorld();
fLeaderW2L = rend->Pipeline()->GetWorldToCamera();
fLeaderSet = true;
plProfile_EndLap(FollowMod, this->GetKey()->GetUoid().GetObjectName());
return true;
}
plListenerMsg* list = plListenerMsg::ConvertNoRef(msg);
if( list )
{
hsVector3 pos;
pos.Set(list->GetPosition().fX, list->GetPosition().fY, list->GetPosition().fZ);
fLeaderL2W.MakeTranslateMat(&pos);
fLeaderW2L.MakeTranslateMat(&-pos);
fLeaderSet = true;
return true;
}
plGenRefMsg* ref = plGenRefMsg::ConvertNoRef(msg);
if( ref )
{
switch( ref->fType )
{
case kRefLeader:
if( ref->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
fLeader = plSceneObject::ConvertNoRef(ref->GetRef());
else if( ref->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
fLeader = nil;
return true;
default:
hsAssert(false, "Unknown ref type to FollowMod");
break;
}
}
return plSingleModifier::MsgReceive(msg);
}
hsBool plFollowMod::ICheckLeader()
{
switch( fLeaderType )
{
case kLocalPlayer:
{
plSceneObject* player = plSceneObject::ConvertNoRef(plNetClientApp::GetInstance()->GetLocalPlayer());
if( player )
{
fLeaderL2W = player->GetLocalToWorld();
fLeaderW2L = player->GetWorldToLocal();
fLeaderSet = true;
}
else
fLeaderSet = false;
}
break;
case kObject:
if( fLeader )
{
fLeaderL2W = fLeader->GetLocalToWorld();
fLeaderW2L = fLeader->GetWorldToLocal();
fLeaderSet = true;
}
else
fLeaderSet = false;
break;
case kCamera:
break;
case kListener:
break;
}
return fLeaderSet;
}
void plFollowMod::IMoveTarget()
{
if( fMode == kFullTransform )
{
GetTarget()->SetTransform(fLeaderL2W, fLeaderW2L);
return;
}
hsMatrix44 l2w = GetTarget()->GetLocalToWorld();
hsMatrix44 w2l = GetTarget()->GetWorldToLocal();
if( fMode & kRotate )
{
int i, j;
for( i = 0; i < 3; i++ )
{
for( j = 0; j < 3; j++ )
{
l2w.fMap[i][j] = fLeaderL2W.fMap[i][j];
w2l.fMap[i][j] = fLeaderW2L.fMap[i][j];
}
}
}
if( fMode & kPosition )
{
hsMatrix44 invMove;
invMove.Reset();
hsPoint3 newPos = fLeaderL2W.GetTranslate();
hsPoint3 newInvPos = fLeaderW2L.GetTranslate();
hsPoint3 oldPos = l2w.GetTranslate();
// l2w = newPosMat * -oldPosMat * l2w
// so w2l = w2l * inv-oldPosMat * invNewPosMat
if( fMode & kPositionX )
{
l2w.fMap[0][3] = newPos.fX;
invMove.fMap[0][3] = oldPos.fX - newPos.fX;
}
if( fMode & kPositionY )
{
l2w.fMap[1][3] = newPos.fY;
invMove.fMap[1][3] = oldPos.fY - newPos.fY;
}
if( fMode & kPositionZ )
{
l2w.fMap[2][3] = newPos.fZ;
invMove.fMap[2][3] = oldPos.fZ - newPos.fZ;
}
invMove.NotIdentity();
// InvMove must happen after rotation.
w2l = w2l * invMove;
}
l2w.NotIdentity();
w2l.NotIdentity();
#ifdef HS_DEBUGGING
//MFHORSE hackola
hsMatrix44 inv;
l2w.GetInverse(&inv);
#endif // HS_DEBUGGING
GetTarget()->SetTransform(l2w, w2l);
}
hsBool plFollowMod::IEval(double secs, hsScalar del, UInt32 dirty)
{
if( ICheckLeader() )
IMoveTarget();
return true;
}
void plFollowMod::SetTarget(plSceneObject* so)
{
plSingleModifier::SetTarget(so);
if( fTarget )
Activate();
else
Deactivate();
}
void plFollowMod::Activate()
{
switch( fLeaderType )
{
case kLocalPlayer:
break;
case kObject:
break;
case kCamera:
plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey());
break;
case kListener:
plgDispatch::Dispatch()->RegisterForExactType(plListenerMsg::Index(), GetKey());
break;
}
if( fTarget )
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
}
void plFollowMod::Deactivate()
{
switch( fLeaderType )
{
case kLocalPlayer:
if( fTarget )
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
break;
case kObject:
if( fTarget )
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
break;
case kCamera:
plgDispatch::Dispatch()->UnRegisterForExactType(plRenderMsg::Index(), GetKey());
break;
case kListener:
plgDispatch::Dispatch()->UnRegisterForExactType(plListenerMsg::Index(), GetKey());
break;
}
}
void plFollowMod::Read(hsStream* stream, hsResMgr* mgr)
{
plSingleModifier::Read(stream, mgr);
fLeaderType = FollowLeaderType(stream->ReadByte());
fMode = stream->ReadByte();
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefLeader), plRefFlags::kActiveRef);
// If active?
Activate();
}
void plFollowMod::Write(hsStream* stream, hsResMgr* mgr)
{
plSingleModifier::Write(stream, mgr);
stream->WriteByte(fLeaderType);
stream->WriteByte(fMode);
mgr->WriteKey(stream, fLeader);
}

View File

@ -0,0 +1,101 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plFollowMod_inc
#define plFollowMod_inc
#include "hsMatrix44.h"
#include "../pnModifier/plSingleModifier.h"
class plSceneObject;
class plMessage;
class hsStream;
class hsResMgr;
class plFollowMod : public plSingleModifier
{
public:
enum FollowRefs
{
kRefLeader
};
enum FollowLeaderType
{
kLocalPlayer,
kObject,
kCamera,
kListener
};
enum FollowModMode
{
kPositionX = 0x1,
kPositionY = 0x2,
kPositionZ = 0x4,
kPosition = (kPositionX | kPositionY | kPositionZ),
kRotate = 0x8,
kFullTransform = kPosition | kRotate
};
protected:
FollowLeaderType fLeaderType;
UInt8 fMode;
UInt8 fLeaderSet;
plSceneObject* fLeader; // may be nil if Leader isn't a sceneobject
hsMatrix44 fLeaderL2W;
hsMatrix44 fLeaderW2L;
hsBool ICheckLeader();
void IMoveTarget();
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
public:
plFollowMod();
~plFollowMod();
CLASSNAME_REGISTER( plFollowMod );
GETINTERFACE_ANY( plFollowMod, plSingleModifier );
virtual hsBool MsgReceive(plMessage* msg);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual void SetTarget(plSceneObject* so);
void SetType(FollowLeaderType t) { fLeaderType = t; }
FollowLeaderType GetType() const { return fLeaderType; }
void SetMode(UInt8 m) { fMode = m; }
UInt8 GetMode() const { return fMode; }
void Activate();
void Deactivate();
};
#endif // plFollowMod_inc

View File

@ -0,0 +1,413 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plLightModifier.h"
#include "../plGLight/plLightInfo.h"
#include "../plInterp/plController.h"
#include "hsStream.h"
#include "hsResMgr.h"
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Basic light
plLightModifier::plLightModifier()
: fLight(nil),
fColorCtl(nil),
fAmbientCtl(nil),
fSpecularCtl(nil)
{
}
plLightModifier::~plLightModifier()
{
delete fColorCtl;
fColorCtl = nil;
delete fAmbientCtl;
fAmbientCtl = nil;
delete fSpecularCtl;
fSpecularCtl = nil;
}
void plLightModifier::IClearCtls()
{
delete fColorCtl;
fColorCtl = nil;
delete fAmbientCtl;
fAmbientCtl = nil;
delete fSpecularCtl;
fSpecularCtl = nil;
}
void plLightModifier::AddTarget(plSceneObject* so)
{
plSimpleModifier::AddTarget(so);
if( so )
fLight = plLightInfo::ConvertNoRef(so->GetGenericInterface(plLightInfo::Index()));
else
fLight = nil;
}
void plLightModifier::RemoveTarget(plSceneObject* so)
{
if( so = fTarget )
fLight = nil;
plSimpleModifier::RemoveTarget(so);
}
void plLightModifier::Read(hsStream* s, hsResMgr* mgr)
{
plSimpleModifier::Read(s, mgr);
fColorCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
fAmbientCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
fSpecularCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
}
void plLightModifier::Write(hsStream* s, hsResMgr* mgr)
{
plSimpleModifier::Write(s, mgr);
mgr->WriteCreatable(s, fColorCtl);
mgr->WriteCreatable(s, fAmbientCtl);
mgr->WriteCreatable(s, fSpecularCtl);
}
void plLightModifier::IApplyDynamic()
{
hsColorRGBA col;
if( fLight != nil )
{
if( fColorCtl )
{
col.Set(0,0,0,1.f);
fColorCtl->Interp(fCurrentTime, &col);
fLight->SetDiffuse(col);
}
if( fAmbientCtl )
{
col.Set(0,0,0,1.f);
fAmbientCtl->Interp(fCurrentTime, &col);
fLight->SetAmbient(col);
}
if( fSpecularCtl )
{
col.Set(0,0,0,1.f);
fSpecularCtl->Interp(fCurrentTime, &col);
fLight->SetSpecular(col);
}
}
}
void plLightModifier::DefaultAnimation()
{
hsScalar len = MaxAnimLength(0);
fTimeConvert.SetBegin(0);
fTimeConvert.SetEnd(len);
fTimeConvert.SetLoopPoints(0, len);
fTimeConvert.Loop();
fTimeConvert.Start();
}
hsScalar plLightModifier::MaxAnimLength(hsScalar len) const
{
if( fColorCtl && (fColorCtl->GetLength() > len) )
len = fColorCtl->GetLength();
if( fAmbientCtl && (fAmbientCtl->GetLength() > len) )
len = fAmbientCtl->GetLength();
if( fSpecularCtl && (fSpecularCtl->GetLength() > len) )
len = fSpecularCtl->GetLength();
return len;
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Omni Lights
plOmniModifier::plOmniModifier()
: fOmni(nil),
fAttenCtl(nil)
{
}
plOmniModifier::~plOmniModifier()
{
delete fAttenCtl;
fAttenCtl = nil;
}
void plOmniModifier::AddTarget(plSceneObject* so)
{
plLightModifier::AddTarget(so);
if( fLight )
fOmni = plOmniLightInfo::ConvertNoRef(fLight);
else
fOmni = nil;
}
void plOmniModifier::RemoveTarget(plSceneObject* so)
{
plLightModifier::RemoveTarget(so);
if( !fLight )
fOmni = nil;
}
void plOmniModifier::IClearCtls()
{
plLightModifier::IClearCtls();
delete fAttenCtl;
fAttenCtl = nil;
}
void plOmniModifier::Read(hsStream* s, hsResMgr* mgr)
{
plLightModifier::Read(s, mgr);
fAttenCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
fInitAtten.Read(s);
}
void plOmniModifier::Write(hsStream* s, hsResMgr* mgr)
{
plLightModifier::Write(s, mgr);
mgr->WriteCreatable(s, fAttenCtl);
fInitAtten.Write(s);
}
void plOmniModifier::IApplyDynamic()
{
plLightModifier::IApplyDynamic();
if( fAttenCtl )
{
hsPoint3 p = fInitAtten;
fAttenCtl->Interp(fCurrentTime, &p);
fOmni->SetConstantAttenuation(p.fX);
fOmni->SetLinearAttenuation(p.fY);
fOmni->SetQuadraticAttenuation(p.fZ);
}
}
hsScalar plOmniModifier::MaxAnimLength(hsScalar len) const
{
len = plLightModifier::MaxAnimLength(len);
if( fAttenCtl && (fAttenCtl->GetLength() > len) )
len = fAttenCtl->GetLength();
return len;
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// Spot Lights
plSpotModifier::plSpotModifier()
: fSpot(nil),
fInnerCtl(nil),
fOuterCtl(nil)
{
}
plSpotModifier::~plSpotModifier()
{
delete fInnerCtl;
fInnerCtl = nil;
delete fOuterCtl;
fOuterCtl = nil;
}
void plSpotModifier::AddTarget(plSceneObject* so)
{
plOmniModifier::AddTarget(so);
if( fLight )
fSpot = plSpotLightInfo::ConvertNoRef(fLight);
else
fSpot = nil;
}
void plSpotModifier::RemoveTarget(plSceneObject* so)
{
plOmniModifier::RemoveTarget(so);
if( !fLight )
fSpot = nil;
}
void plSpotModifier::IClearCtls()
{
plOmniModifier::IClearCtls();
delete fInnerCtl;
fInnerCtl = nil;
delete fOuterCtl;
fOuterCtl = nil;
}
void plSpotModifier::Read(hsStream* s, hsResMgr* mgr)
{
plOmniModifier::Read(s, mgr);
fInnerCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
fOuterCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
}
void plSpotModifier::Write(hsStream* s, hsResMgr* mgr)
{
plOmniModifier::Write(s, mgr);
mgr->WriteCreatable(s, fInnerCtl);
mgr->WriteCreatable(s, fOuterCtl);
}
void plSpotModifier::IApplyDynamic()
{
plOmniModifier::IApplyDynamic();
hsScalar f;
if( fInnerCtl )
{
fInnerCtl->Interp(fCurrentTime, &f);
fSpot->SetSpotInner(hsScalarDegToRad(f)*0.5f);
}
if( fOuterCtl )
{
fOuterCtl->Interp(fCurrentTime, &f);
fSpot->SetSpotOuter(hsScalarDegToRad(f)*0.5f);
}
}
hsScalar plSpotModifier::MaxAnimLength(hsScalar len) const
{
len = plOmniModifier::MaxAnimLength(len);
if( fInnerCtl && (fInnerCtl->GetLength() > len) )
len = fInnerCtl->GetLength();
if( fOuterCtl && (fOuterCtl->GetLength() > len) )
len = fOuterCtl->GetLength();
return len;
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// LtdDir Lights
plLtdDirModifier::plLtdDirModifier()
: fLtdDir(nil),
fWidthCtl(nil),
fHeightCtl(nil),
fDepthCtl(nil)
{
}
plLtdDirModifier::~plLtdDirModifier()
{
delete fWidthCtl;
fWidthCtl = nil;
delete fHeightCtl;
fHeightCtl = nil;
delete fDepthCtl;
fDepthCtl = nil;
}
void plLtdDirModifier::AddTarget(plSceneObject* so)
{
plLightModifier::AddTarget(so);
if( fLight )
fLtdDir = plLimitedDirLightInfo::ConvertNoRef(fLight);
else
fLtdDir = nil;
}
void plLtdDirModifier::RemoveTarget(plSceneObject* so)
{
plLightModifier::RemoveTarget(so);
if( !fLight )
fLtdDir = nil;
}
void plLtdDirModifier::IClearCtls()
{
plLightModifier::IClearCtls();
delete fWidthCtl;
fWidthCtl = nil;
delete fHeightCtl;
fHeightCtl = nil;
delete fDepthCtl;
fDepthCtl = nil;
}
void plLtdDirModifier::Read(hsStream* s, hsResMgr* mgr)
{
plLightModifier::Read(s, mgr);
fWidthCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
fHeightCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
fDepthCtl = plController::ConvertNoRef(mgr->ReadCreatable(s));
}
void plLtdDirModifier::Write(hsStream* s, hsResMgr* mgr)
{
plLightModifier::Write(s, mgr);
mgr->WriteCreatable(s, fWidthCtl);
mgr->WriteCreatable(s, fHeightCtl);
mgr->WriteCreatable(s, fDepthCtl);
}
void plLtdDirModifier::IApplyDynamic()
{
plLightModifier::IApplyDynamic();
hsScalar f;
if( fWidthCtl )
{
fWidthCtl->Interp(fCurrentTime, &f);
fLtdDir->SetWidth(f);
}
if( fHeightCtl )
{
fHeightCtl->Interp(fCurrentTime, &f);
fLtdDir->SetHeight(f);
}
if( fDepthCtl )
{
fDepthCtl->Interp(fCurrentTime, &f);
fLtdDir->SetDepth(f);
}
}
hsScalar plLtdDirModifier::MaxAnimLength(hsScalar len) const
{
len = plLightModifier::MaxAnimLength(len);
if( fWidthCtl && (fWidthCtl->GetLength() > len) )
len = fWidthCtl->GetLength();
if( fHeightCtl && (fHeightCtl->GetLength() > len) )
len = fHeightCtl->GetLength();
if( fDepthCtl && (fDepthCtl->GetLength() > len) )
len = fDepthCtl->GetLength();
return len;
}

View File

@ -0,0 +1,181 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plLightModifier_inc
#define plLightModifier_inc
#include "../../PubUtilLib/plModifier/plSimpleModifier.h"
#include "hsGeometry3.h"
class plController;
class plController;
class plLightInfo;
class plOmniLightInfo;
class plSpotLightInfo;
class plLimitedDirLightInfo;
class plLightModifier : public plSimpleModifier
{
protected:
plController* fColorCtl;
plController* fAmbientCtl;
plController* fSpecularCtl;
plLightInfo* fLight;
virtual void IApplyDynamic();
virtual void IClearCtls();
public:
plLightModifier();
virtual ~plLightModifier();
CLASSNAME_REGISTER( plLightModifier );
GETINTERFACE_ANY( plLightModifier, plSimpleModifier );
virtual void AddTarget(plSceneObject* so);
virtual void RemoveTarget(plSceneObject* so);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual hsBool HasAnima() const { return fColorCtl || fAmbientCtl || fSpecularCtl; }
// Export only
void SetColorCtl(plController* ctl) { fColorCtl = ctl; }
void SetAmbientCtl(plController* ctl) { fAmbientCtl = ctl; }
void SetSpecularCtl(plController* ctl) { fSpecularCtl = ctl; }
virtual void DefaultAnimation();
virtual hsScalar MaxAnimLength(hsScalar len) const;
};
class plOmniModifier : public plLightModifier
{
protected:
plOmniLightInfo* fOmni;
plController* fAttenCtl;
hsPoint3 fInitAtten;
virtual void IApplyDynamic();
virtual void IClearCtls();
public:
plOmniModifier();
virtual ~plOmniModifier();
CLASSNAME_REGISTER( plOmniModifier );
GETINTERFACE_ANY( plOmniModifier, plLightModifier );
virtual void AddTarget(plSceneObject* so);
virtual void RemoveTarget(plSceneObject* so);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual hsBool HasAnima() const { return plLightModifier::HasAnima() || fAttenCtl; }
// Export Only
void SetAttenCtl(plController* ctl) { fAttenCtl = ctl; }
void SetInitAtten(const hsPoint3& p) { fInitAtten = p; }
virtual hsScalar MaxAnimLength(hsScalar len) const;
};
class plSpotModifier : public plOmniModifier
{
protected:
plSpotLightInfo* fSpot;
plController* fInnerCtl;
plController* fOuterCtl;
virtual void IApplyDynamic();
virtual void IClearCtls();
public:
plSpotModifier();
virtual ~plSpotModifier();
CLASSNAME_REGISTER( plSpotModifier );
GETINTERFACE_ANY( plSpotModifier, plLightModifier );
virtual void AddTarget(plSceneObject* so);
virtual void RemoveTarget(plSceneObject* so);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual hsBool HasAnima() const { return plOmniModifier::HasAnima() || fInnerCtl || fOuterCtl; }
// Export Only
void SetInnerCtl(plController* ctl) { fInnerCtl = ctl; }
void SetOuterCtl(plController* ctl) { fOuterCtl = ctl; }
virtual hsScalar MaxAnimLength(hsScalar len) const;
};
class plLtdDirModifier : public plLightModifier
{
protected:
plLimitedDirLightInfo* fLtdDir;
plController* fWidthCtl;
plController* fHeightCtl;
plController* fDepthCtl;
virtual void IApplyDynamic();
virtual void IClearCtls();
public:
plLtdDirModifier();
virtual ~plLtdDirModifier();
CLASSNAME_REGISTER( plLtdDirModifier );
GETINTERFACE_ANY( plLtdDirModifier, plLightModifier );
virtual void AddTarget(plSceneObject* so);
virtual void RemoveTarget(plSceneObject* so);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual hsBool HasAnima() const { return plLightModifier::HasAnima() || fWidthCtl || fHeightCtl || fDepthCtl; }
// Export Only
void SetWidthCtl(plController* ctl) { fWidthCtl = ctl; }
void SetHeightCtl(plController* ctl) { fHeightCtl = ctl; }
void SetDepthCtl(plController* ctl) { fDepthCtl = ctl; }
virtual hsScalar MaxAnimLength(hsScalar len) const;
};
#endif // plLightModifier_inc

View File

@ -0,0 +1,687 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plLineFollowMod.h"
#include "plStereizer.h"
#include "../plInterp/plAnimPath.h"
#include "hsResMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "plgDispatch.h"
#include "../plMessage/plListenerMsg.h"
#include "../plMessage/plRenderMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "hsBounds.h"
#include "plPipeline.h"
#include "hsFastMath.h"
#include "../pnMessage/plPlayerPageMsg.h"
#include "../pnNetCommon/plNetApp.h"
#include "../plNetClient/plNetClientMgr.h"
#include "hsTimer.h"
plLineFollowMod::plLineFollowMod()
: fPath(nil),
fPathParent(nil),
fRefObj(nil),
fFollowMode(kFollowListener),
fFollowFlags(kNone),
fOffset(0),
fOffsetClamp(0),
fSpeedClamp(0)
{
fSearchPos.Set(0,0,0);
}
plLineFollowMod::~plLineFollowMod()
{
delete fPath;
}
void plLineFollowMod::SetSpeedClamp(hsScalar fps)
{
fSpeedClamp = fps;
if( fSpeedClamp > 0 )
{
fFollowFlags |= kSpeedClamp;
}
else
{
fFollowFlags &= ~kSpeedClamp;
}
}
void plLineFollowMod::SetOffsetFeet(hsScalar f)
{
fOffset = f;
if( fOffset != 0 )
{
fFollowFlags &= ~kOffsetAng;
fFollowFlags |= kOffsetFeet;
}
else
{
fFollowFlags &= ~kOffset;
}
}
void plLineFollowMod::SetForceToLine(hsBool on)
{
if( on )
fFollowFlags |= kForceToLine;
else
fFollowFlags &= ~kForceToLine;
}
void plLineFollowMod::SetOffsetDegrees(hsScalar f)
{
fOffset = hsScalarDegToRad(f);
if( fOffset != 0 )
{
fFollowFlags &= ~kOffsetFeet;
fFollowFlags |= kOffsetAng;
fTanOffset = tanf(f);
}
else
{
fFollowFlags &= ~kOffset;
}
}
void plLineFollowMod::SetOffsetClamp(hsScalar f)
{
fOffsetClamp = f;
if( fOffsetClamp > 0 )
{
fFollowFlags |= kOffsetClamp;
}
else
{
fFollowFlags &= ~kOffsetClamp;
}
}
void plLineFollowMod::SetPath(plAnimPath* path)
{
delete fPath;
fPath = path;
}
void plLineFollowMod::Read(hsStream* stream, hsResMgr* mgr)
{
plMultiModifier::Read(stream, mgr);
fPath = plAnimPath::ConvertNoRef(mgr->ReadCreatable(stream));
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefParent), plRefFlags::kPassiveRef);
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefObject), plRefFlags::kPassiveRef);
int n = stream->ReadSwap32();
while(n--)
{
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefStereizer), plRefFlags::kPassiveRef);
}
UInt32 f = stream->ReadSwap32();
SetFollowMode(FollowMode(f & 0xffff));
fFollowFlags = (UInt16)((f >> 16) & 0xffff);
if( fFollowFlags & kOffset )
{
fOffset = stream->ReadSwapScalar();
}
if( fFollowFlags & kOffsetAng )
{
fTanOffset = tanf(fOffset);
}
if( fFollowFlags & kOffsetClamp )
{
fOffsetClamp = stream->ReadSwapScalar();
}
if( fFollowFlags & kSpeedClamp )
{
fSpeedClamp = stream->ReadSwapScalar();
}
}
void plLineFollowMod::Write(hsStream* stream, hsResMgr* mgr)
{
plMultiModifier::Write(stream, mgr);
mgr->WriteCreatable(stream, fPath);
mgr->WriteKey(stream, fPathParent);
mgr->WriteKey(stream, fRefObj);
stream->WriteSwap32(fStereizers.GetCount());
int i;
for( i = 0; i < fStereizers.GetCount(); i++ )
mgr->WriteKey(stream, fStereizers[i]->GetKey());
UInt32 f = UInt32(fFollowMode) | (UInt32(fFollowFlags) << 16);
stream->WriteSwap32(f);
if( fFollowFlags & kOffset )
stream->WriteSwapScalar(fOffset);
if( fFollowFlags & kOffsetClamp )
stream->WriteSwapScalar(fOffsetClamp);
if( fFollowFlags & kSpeedClamp )
stream->WriteSwapScalar(fSpeedClamp);
}
#include "plProfile.h"
plProfile_CreateTimer("LineFollow", "RenderSetup", LineFollow);
hsBool plLineFollowMod::MsgReceive(plMessage* msg)
{
plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef(msg);
if( refMsg )
{
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
plSceneObject* obj = plSceneObject::ConvertNoRef(refMsg->GetRef());
if( kRefParent == refMsg->fType )
fPathParent = obj;
else if( kRefObject == refMsg->fType )
fRefObj = obj;
else if( kRefStereizer == refMsg->fType )
{
plStereizer* ster = plStereizer::ConvertNoRef(refMsg->GetRef());
int idx = fStereizers.Find(ster);
if( idx == fStereizers.kMissingIndex )
fStereizers.Append(ster);
}
}
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
if( kRefParent == refMsg->fType )
fPathParent = nil;
else if( kRefObject == refMsg->fType )
fRefObj = nil;
else if( kRefStereizer == refMsg->fType )
{
plStereizer* ster = (plStereizer*)(refMsg->GetRef());
int idx = fStereizers.Find(ster);
if( idx != fStereizers.kMissingIndex )
fStereizers.Remove(idx);
}
}
return true;
}
plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg);
if( rend )
{
plProfile_BeginLap(LineFollow, this->GetKey()->GetUoid().GetObjectName());
hsPoint3 oldPos = fSearchPos;
fSearchPos = rend->Pipeline()->GetViewPositionWorld();
ICheckForPop(oldPos, fSearchPos);
plProfile_EndLap(LineFollow, this->GetKey()->GetUoid().GetObjectName());
return true;
}
plListenerMsg* list = plListenerMsg::ConvertNoRef(msg);
if( list )
{
hsPoint3 oldPos = fSearchPos;
fSearchPos = list->GetPosition();
ICheckForPop(oldPos, fSearchPos);
ISetupStereizers(list);
return true;
}
plPlayerPageMsg* pPMsg = plPlayerPageMsg::ConvertNoRef(msg);
if (pPMsg)
{
if (pPMsg->fPlayer == plNetClientMgr::GetInstance()->GetLocalPlayerKey() && !pPMsg->fUnload)
{
fRefObj = (plSceneObject*)pPMsg->fPlayer->GetObjectPtr();
}
return true;
}
return plMultiModifier::MsgReceive(msg);
}
void plLineFollowMod::SetFollowMode(FollowMode f)
{
IUnRegister();
fFollowMode = f;
IRegister();
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
}
void plLineFollowMod::IUnRegister()
{
switch( fFollowMode )
{
case kFollowObject:
break;
case kFollowListener:
plgDispatch::Dispatch()->UnRegisterForExactType(plListenerMsg::Index(), GetKey());
break;
case kFollowCamera:
plgDispatch::Dispatch()->UnRegisterForExactType(plRenderMsg::Index(), GetKey());
break;
case kFollowLocalAvatar:
plgDispatch::Dispatch()->UnRegisterForExactType(plPlayerPageMsg::Index(), GetKey());
break;
}
}
void plLineFollowMod::IRegister()
{
switch( fFollowMode )
{
case kFollowObject:
break;
case kFollowListener:
plgDispatch::Dispatch()->RegisterForExactType(plListenerMsg::Index(), GetKey());
break;
case kFollowCamera:
plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey());
break;
case kFollowLocalAvatar:
{
if (plNetClientApp::GetInstance() && plNetClientApp::GetInstance()->GetLocalPlayer())
fRefObj = ((plSceneObject*)plNetClientApp::GetInstance()->GetLocalPlayer());
plgDispatch::Dispatch()->RegisterForExactType(plPlayerPageMsg::Index(), GetKey());
break;
}
}
}
hsBool plLineFollowMod::IEval(double secs, hsScalar del, UInt32 dirty)
{
if( !fPath )
return false;
ISetPathTransform();
if( !IGetSearchPos() )
return false;
hsMatrix44 tgtXfm;
IGetTargetTransform(fSearchPos, tgtXfm);
if( fFollowFlags & kOffset )
IOffsetTargetTransform(tgtXfm);
int i;
for( i = 0; i < GetNumTargets(); i++ )
{
ISetTargetTransform(i, tgtXfm);
}
return true;
}
hsBool plLineFollowMod::IOffsetTargetTransform(hsMatrix44& tgtXfm)
{
hsPoint3 tgtPos = tgtXfm.GetTranslate();
hsVector3 tgt2src(&fSearchPos, &tgtPos);
hsScalar t2sLen = tgt2src.Magnitude();
hsFastMath::NormalizeAppr(tgt2src);
hsVector3 out;
out.Set(-tgt2src.fY, tgt2src.fX, 0); // (0,0,1) X (tgt2src)
if( fFollowFlags & kOffsetAng )
{
hsScalar del = t2sLen * fTanOffset;
if( fFollowFlags & kOffsetClamp )
{
if( del > fOffsetClamp )
del = fOffsetClamp;
else if( del < -fOffsetClamp )
del = -fOffsetClamp;
}
out *= del;
}
else if( fFollowFlags & kOffsetFeet )
{
out *= fOffset;
}
else
out.Set(0,0,0);
if( fFollowFlags & kForceToLine )
{
hsPoint3 newSearch = tgtPos;
newSearch += out;
IGetTargetTransform(newSearch, tgtXfm);
}
else
{
tgtXfm.fMap[0][3] += out[0];
tgtXfm.fMap[1][3] += out[1];
tgtXfm.fMap[2][3] += out[2];
}
return true;
}
hsBool plLineFollowMod::IGetTargetTransform(hsPoint3& searchPos, hsMatrix44& tgtXfm)
{
hsScalar t = fPath->GetExtremePoint(searchPos);
if( fFollowFlags & kFullMatrix )
{
fPath->SetCurTime(t, plAnimPath::kNone);
fPath->GetMatrix44(&tgtXfm);
}
else
{
fPath->SetCurTime(t, plAnimPath::kCalcPosOnly);
hsPoint3 pos;
fPath->GetPosition(&pos);
tgtXfm.MakeTranslateMat((hsVector3*)&pos);
}
return true;
}
void plLineFollowMod::ISetPathTransform()
{
if( fPathParent && fPathParent->GetCoordinateInterface() )
{
hsMatrix44 l2w = fPathParent->GetCoordinateInterface()->GetLocalToWorld();
hsMatrix44 w2l = fPathParent->GetCoordinateInterface()->GetWorldToLocal();
fPath->SetTransform(l2w, w2l);
}
}
void plLineFollowMod::ICheckForPop(const hsPoint3& oldPos, const hsPoint3& newPos)
{
hsVector3 del(&oldPos, &newPos);
hsScalar elapsed = hsTimer::GetDelSysSeconds();
hsScalar speedSq = 0.f;
if (elapsed > 0.f)
speedSq = del.MagnitudeSquared() / elapsed;
const hsScalar kMaxSpeedSq = 30.f * 30.f; // (feet per sec)^2
if( speedSq > kMaxSpeedSq )
fFollowFlags |= kSearchPosPop;
else
fFollowFlags &= ~kSearchPosPop;
}
hsBool plLineFollowMod::IGetSearchPos()
{
hsPoint3 oldPos = fSearchPos;
if( kFollowObject == fFollowMode )
{
if( !fRefObj )
return false;
if( fRefObj->GetCoordinateInterface() )
{
fSearchPos = fRefObj->GetCoordinateInterface()->GetWorldPos();
ICheckForPop(oldPos, fSearchPos);
return true;
}
else if( fRefObj->GetDrawInterface() )
{
fSearchPos = fRefObj->GetDrawInterface()->GetWorldBounds().GetCenter();
ICheckForPop(oldPos, fSearchPos);
return true;
}
return false;
}
else
if (fFollowMode == kFollowLocalAvatar)
{
if (!fRefObj)
return false;
if( fRefObj->GetCoordinateInterface() )
{
fSearchPos = fRefObj->GetCoordinateInterface()->GetWorldPos();
ICheckForPop(oldPos, fSearchPos);
return true;
}
else if( fRefObj->GetDrawInterface() )
{
fSearchPos = fRefObj->GetDrawInterface()->GetWorldBounds().GetCenter();
ICheckForPop(oldPos, fSearchPos);
return true;
}
return false;
}
return true;
}
hsMatrix44 plLineFollowMod::IInterpMatrices(const hsMatrix44& m0, const hsMatrix44& m1, hsScalar parm)
{
hsMatrix44 retVal;
int i, j;
for( i = 0; i < 3; i++ )
{
for( j = 0; j < 4; j++ )
{
retVal.fMap[i][j] = m0.fMap[i][j] * (1.f - parm) + m1.fMap[i][j] * parm;
}
}
retVal.fMap[3][0] = retVal.fMap[3][1] = retVal.fMap[3][2] = 0;
retVal.fMap[3][3] = 1.f;
retVal.NotIdentity();
return retVal;
}
hsMatrix44 plLineFollowMod::ISpeedClamp(plCoordinateInterface* ci, const hsMatrix44& unclTgtXfm)
{
// If our search position has popped, or delsysseconds is zero, just return as is.
if( (fFollowFlags & kSearchPosPop) || !(hsTimer::GetDelSysSeconds() > 0) )
return unclTgtXfm;
const hsMatrix44 currL2W = ci->GetLocalToWorld();
const hsPoint3 oldPos = currL2W.GetTranslate();
const hsPoint3 newPos = unclTgtXfm.GetTranslate();
const hsVector3 del(&newPos, &oldPos);
hsScalar elapsed = hsTimer::GetDelSysSeconds();
hsScalar speed = 0.f;
if (elapsed > 0.f)
speed = del.Magnitude() / elapsed;
if( speed > fSpeedClamp )
{
hsScalar parm = fSpeedClamp / speed;
hsMatrix44 clTgtXfm = IInterpMatrices(currL2W, unclTgtXfm, parm);
return clTgtXfm;
}
return unclTgtXfm;
}
void plLineFollowMod::ISetTargetTransform(int iTarg, const hsMatrix44& unclTgtXfm)
{
plCoordinateInterface* ci = IGetTargetCoordinateInterface(iTarg);
if( ci )
{
hsMatrix44 tgtXfm = fFollowFlags & kSpeedClamp ? ISpeedClamp(ci, unclTgtXfm) : unclTgtXfm;
if( fFollowFlags & kFullMatrix )
{
// This branch currently never gets taken. If it ever does,
// we should probably optimize out this GetInverse() (depending
// on how often it gets taken).
const hsMatrix44& l2w = tgtXfm;
hsMatrix44 w2l;
l2w.GetInverse(&w2l);
ci->SetTransform(l2w, w2l);
}
else
{
hsMatrix44 l2w = ci->GetLocalToWorld();
hsMatrix44 w2l = ci->GetWorldToLocal();
hsPoint3 pos = tgtXfm.GetTranslate();
hsPoint3 oldPos = l2w.GetTranslate();
l2w.SetTranslate(&pos);
hsMatrix44 xlate;
xlate.Reset();
xlate.SetTranslate(&oldPos);
w2l = w2l * xlate;
xlate.SetTranslate(&-pos);
w2l = w2l * xlate;
ci->SetTransform(l2w, w2l);
}
hsPoint3 newPos = tgtXfm.GetTranslate();
int i;
for( i = 0; i < fStereizers.GetCount(); i++ )
{
if( fStereizers[i] )
{
fStereizers[i]->SetWorldInitPos(newPos);
fStereizers[i]->Stereize();
}
}
}
}
void plLineFollowMod::ISetupStereizers(const plListenerMsg* listMsg)
{
int i;
for( i = 0; i < fStereizers.GetCount(); i++ )
{
if( fStereizers[i] )
fStereizers[i]->SetFromListenerMsg(listMsg);
}
}
void plLineFollowMod::AddTarget(plSceneObject* so)
{
plMultiModifier::AddTarget(so);
if( so )
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
}
void plLineFollowMod::RemoveTarget(plSceneObject* so)
{
plMultiModifier::RemoveTarget(so);
}
void plLineFollowMod::AddStereizer(const plKey& key)
{
hsgResMgr::ResMgr()->SendRef(plKey(key), TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefStereizer), plRefFlags::kPassiveRef);
}
void plLineFollowMod::RemoveStereizer(const plKey& key)
{
hsgResMgr::ResMgr()->SendRef(plKey(key), TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnRemove, 0, kRefStereizer), plRefFlags::kPassiveRef);
}
// derived version of this class for rail cameras
// the difference is the rail camera just calculates
// the desired position but does not move the target to
// it.
plRailCameraMod::plRailCameraMod() :
fCurrentTime(0.0f),
fTargetTime(0.0f),
fFarthest(false)
{
plLineFollowMod::plLineFollowMod();
fGoal.Set(0,0,0);
}
plRailCameraMod::~plRailCameraMod()
{
}
hsBool plRailCameraMod::IGetTargetTransform(hsPoint3& searchPos, hsMatrix44& tgtXfm)
{
if (fPath->GetFarthest())
{
fFarthest = true;
fPath->SetFarthest(false);
}
fTargetTime = fPath->GetExtremePoint(searchPos);
fPath->SetCurTime(fTargetTime, plAnimPath::kCalcPosOnly);
hsPoint3 pos;
fPath->GetPosition(&pos);
tgtXfm.MakeTranslateMat((hsVector3*)&pos);
return true;
}
hsPoint3 plRailCameraMod::GetGoal(double secs, hsScalar speed)
{
hsScalar delTime;
int dir;
if (fTargetTime == fCurrentTime)
return fGoal;
if (fTargetTime > fCurrentTime)
{
dir = 1;
delTime = fTargetTime - fCurrentTime;
}
else
{
dir = -1;
delTime = fCurrentTime - fTargetTime;
}
if (fPath->GetWrap() && delTime > fPath->GetLength() * 0.5f)
dir *= -1;
if (delTime <= (secs * speed))
fCurrentTime = fTargetTime;
else
fCurrentTime += (hsScalar)((secs * speed) * dir);
if (fPath->GetWrap())
{
if (fCurrentTime > fPath->GetLength())
fCurrentTime = (fCurrentTime - fPath->GetLength());
else
if (fCurrentTime < 0.0f)
fCurrentTime = fPath->GetLength() - fCurrentTime;
}
if (fFarthest)
fPath->SetCurTime((fPath->GetLength() - fCurrentTime), plAnimPath::kCalcPosOnly);
else
fPath->SetCurTime(fCurrentTime, plAnimPath::kCalcPosOnly);
fPath->GetPosition(&fGoal);
fPath->SetCurTime(fTargetTime, plAnimPath::kCalcPosOnly);
return fGoal;
}

View File

@ -0,0 +1,175 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plLineFollowMod_inc
#define plLineFollowMod_inc
#include "../pnModifier/plMultiModifier.h"
#include "hsGeometry3.h"
#include "hsMatrix44.h"
class plAnimPath;
class plSceneObject;
class plStereizer;
class plListenerMsg;
class plLineFollowMod : public plMultiModifier
{
public:
enum FollowMode {
kFollowObject,
kFollowListener,
kFollowCamera,
kFollowLocalAvatar,
};
enum RefType {
kRefParent,
kRefObject,
kRefStereizer
};
enum {
kNone = 0x0,
kFullMatrix = 0x1,
kOffsetFeet = 0x2,
kOffsetAng = 0x4,
kOffset = kOffsetFeet | kOffsetAng,
kOffsetClamp = 0x8,
kForceToLine = 0x10,
kSpeedClamp = 0x20,
kSearchPosPop = 0x40 // Temp flag, gets set every time the target pops in position
};
protected:
FollowMode fFollowMode;
UInt16 fFollowFlags;
plAnimPath* fPath;
plSceneObject* fPathParent;
plSceneObject* fRefObj;
mutable hsPoint3 fSearchPos;
hsTArray<plStereizer*> fStereizers;
hsScalar fTanOffset;
hsScalar fOffset;
hsScalar fOffsetClamp;
hsScalar fSpeedClamp;
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
virtual hsBool IGetSearchPos();
virtual void ISetTargetTransform(int iTarg, const hsMatrix44& tgtXfm);
virtual void ISetPathTransform();
virtual hsBool IGetTargetTransform(hsPoint3& searchPos, hsMatrix44& tgtXfm);
virtual hsBool IOffsetTargetTransform(hsMatrix44& tgtXfm);
virtual hsMatrix44 ISpeedClamp(plCoordinateInterface* ci, const hsMatrix44& unclTgtXfm);
hsMatrix44 IInterpMatrices(const hsMatrix44& m0, const hsMatrix44& m1, hsScalar parm);
void ICheckForPop(const hsPoint3& oldPos, const hsPoint3& newPos);
void ISetupStereizers(const plListenerMsg* listMsg);
void IUnRegister();
void IRegister();
public:
plLineFollowMod();
~plLineFollowMod();
CLASSNAME_REGISTER( plLineFollowMod );
GETINTERFACE_ANY( plLineFollowMod, plMultiModifier );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
// Export time stuff
void SetPath(plAnimPath* path);
const plAnimPath* GetPath() const { return fPath; }
void SetFollowMode(FollowMode f);
FollowMode GetFollowMode() const { return fFollowMode; }
hsBool HasOffsetFeet() const { return 0 != (fFollowFlags & kOffsetFeet); }
hsBool HasOffsetDegrees() const { return 0 != (fFollowFlags & kOffsetAng); }
hsBool HasOffset() const { return 0 != (fFollowFlags & kOffset); }
hsBool HasOffsetClamp() const { return 0 != (fFollowFlags & kOffsetClamp); }
hsBool HasSpeedClamp() const { return 0 != (fFollowFlags & kSpeedClamp); }
void SetOffsetFeet(hsScalar f);
hsScalar GetOffsetFeet() const { return fOffset; }
void SetOffsetDegrees(hsScalar f);
hsScalar GetOffsetDegrees() const { return hsScalarRadToDeg(fOffset); }
void SetOffsetClamp(hsScalar f);
hsScalar GetOffsetClamp() const { return fOffsetClamp; }
void SetForceToLine(hsBool on);
hsBool GetForceToLine() const { return 0 != (fFollowFlags & kForceToLine); }
void SetSpeedClamp(hsScalar feetPerSec);
hsScalar GetSpeedClamp() const { return fSpeedClamp; }
hsBool MsgReceive(plMessage* msg);
virtual void AddTarget(plSceneObject* so);
virtual void RemoveTarget(plSceneObject* so);
void AddStereizer(const plKey& sterKey);
void RemoveStereizer(const plKey& sterKey);
};
class plRailCameraMod : public plLineFollowMod
{
public:
plRailCameraMod();
~plRailCameraMod();
CLASSNAME_REGISTER( plRailCameraMod );
GETINTERFACE_ANY( plRailCameraMod, plLineFollowMod );
void Init() { fCurrentTime = -1; } // twiddle ourselves so we get ready to go...
hsPoint3 GetGoal(double secs, hsScalar speed);
protected:
virtual void ISetTargetTransform(int iTarg, const hsMatrix44& tgtXfm) {fDesiredMatrix = tgtXfm;}
virtual hsBool IGetTargetTransform(hsPoint3& searchPos, hsMatrix44& tgtXfm);
hsMatrix44 fDesiredMatrix;
hsScalar fCurrentTime;
hsScalar fTargetTime;
hsPoint3 fGoal;
hsBool fFarthest;
};
#endif // plLineFollowMod_inc

View File

@ -0,0 +1,290 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include <stdlib.h>
#include "hsTypes.h"
#include "plRandomCommandMod.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../pnMessage/plEventCallbackMsg.h"
#include "plgDispatch.h"
#include "hsTimer.h"
#include "hsUtils.h"
static const hsScalar kRandNormalize = 1.f / 32767.f;
plRandomCommandMod::plRandomCommandMod()
{
fState = 0;
fMode = kNormal;
fCurrent = -1;
fMinDelay = 0;
fMaxDelay = 0;
}
plRandomCommandMod::~plRandomCommandMod()
{
}
// return how many are left to choose from
int plRandomCommandMod::IExcludeSelections(int ncmds)
{
if( fMode & kCoverall )
{
int nLeft = ncmds;
fExcluded.SetBit(fCurrent);
// Count how many haven't been played.
int i;
for( i = ncmds-1; i >= 0; --i )
{
if( fExcluded.IsBitSet(i) )
nLeft--;
}
// If we're out of cmds, and OneCycle is set,
// we're out of cmds until the next play.
// Go ahead and reset for that.
// If we're out and OneCycle isn't set, then go ahead
// and set up for a new cycle.
if( !nLeft )
{
fExcluded.Clear();
if( fMode & kNoRepeats )
fExcluded.SetBit(fCurrent);
if( fMode & kOneCycle )
return 0;
nLeft = ncmds;
if( ( fMode & kNoRepeats ) && ncmds > 1 )
nLeft--;
}
return nLeft;
}
double currTime = hsTimer::GetSysSeconds();
fExcluded.Clear();
int i;
for( i = 0; i < fEndTimes.GetCount(); i++ )
{
if( fEndTimes[i] > currTime )
{
ncmds--;
fExcluded.SetBit(i);
}
}
if( fMode & kNoRepeats )
{
ncmds--;
fExcluded.SetBit(fCurrent);
return ncmds;
}
return ncmds;
}
hsScalar plRandomCommandMod::IGetDelay(hsScalar len) const
{
hsScalar r = float(hsRand() * kRandNormalize);
hsScalar delay = fMinDelay + (fMaxDelay - fMinDelay) * r;
if( fMode & kDelayFromEnd )
delay += len;
if( delay < 0 )
delay = fmodf(len, -delay);
return delay;
}
hsBool plRandomCommandMod::ISelectNext(int ncmds)
{
if( fMode & kSequential )
{
if( ++fCurrent >= ncmds )
{
if( fMode & kOneCycle )
{
fCurrent = -1;
return false;
}
fCurrent = 0;
}
return true;
}
hsScalar r = float(hsRand() * kRandNormalize);
int nSelect = ncmds;
if( fCurrent >= 0 )
nSelect = IExcludeSelections(ncmds);
if( !nSelect )
return false;
int nth = int(r * (float(nSelect)-1.e-3f));
int iNext = 0;
int i;
for( i = 0; i < ncmds; i++ )
{
if( !fExcluded.IsBitSet(i) )
{
if( !nth-- )
{
iNext = i;
break;
}
}
}
fCurrent = iNext;
return true;
}
void plRandomCommandMod::IStart()
{
if( !IStopped() )
return;
fState &= ~kStopped;
IPlayNextIfMaster();
}
void plRandomCommandMod::IStop()
{
fState |= kStopped;
}
hsBool plRandomCommandMod::IStopped() const
{
return 0 != (fState & kStopped);
}
void plRandomCommandMod::IPlayNextIfMaster()
{
if( !fTarget )
IRetry(2.f);
if( fTarget->IsLocallyOwned() == plSynchedObject::kNo ) // if this object is a proxy, it should just wait for network cmds
return;
if( IStopped() )
return;
IPlayNext();
}
hsBool plRandomCommandMod::MsgReceive(plMessage* msg)
{
// plAnimCmdMsg - interpret start/stop appropriately.
// could overinterpret set loop points to limit range of
// cmds we use to a window of the total set.
plAnimCmdMsg* anim = plAnimCmdMsg::ConvertNoRef(msg);
if( anim )
{
if( anim->GetSender() != GetKey() )
{
#if 0
hsStatusMessageF("someone triggered me, remote=%d\n",
msg->HasBCastFlag(plMessage::kNetNonLocal));
#endif
if( anim->Cmd(plAnimCmdMsg::kContinue) )
IStart();
if( anim->Cmd(plAnimCmdMsg::kStop) )
IStop();
if( anim->Cmd(plAnimCmdMsg::kToggleState) )
{
if( IStopped() )
IStart();
else
IStop();
}
}
else
{
#if 0
hsStatusMessageF("play next if master, remote=%d\n",
msg->HasBCastFlag(plMessage::kNetNonLocal));
#endif
IPlayNextIfMaster();
}
return true;
}
// Don't understand, pass on to base class.
return plSingleModifier::MsgReceive(msg);
}
void plRandomCommandMod::IReset()
{
fCurrent = -1;
fExcluded.Clear();
if( !IStopped() )
IRetry(0);
}
void plRandomCommandMod::Read(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Read(s, mgr);
fMode = s->ReadByte();
fState = s->ReadByte();
fMinDelay = s->ReadSwapScalar();
fMaxDelay = s->ReadSwapScalar();
IReset();
}
void plRandomCommandMod::Write(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Write(s, mgr);
s->WriteByte(fMode);
s->WriteByte(fState);
s->WriteSwapScalar(fMinDelay);
s->WriteSwapScalar(fMaxDelay);
}
void plRandomCommandMod::IRetry(hsScalar secs)
{
IStop();
double t = hsTimer::GetSysSeconds() + secs;
plAnimCmdMsg* msg = TRACKED_NEW plAnimCmdMsg(nil, GetKey(), &t);
msg->SetCmd(plAnimCmdMsg::kContinue);
plgDispatch::MsgSend(msg);
}

View File

@ -0,0 +1,111 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plRandomCommandMod_inc
#define plRandomCommandMod_inc
#include "../pnModifier/plSingleModifier.h"
#include "hsTemplates.h"
class plRandomCommandMod : public plSingleModifier
{
public:
enum {
kNormal = 0x0, // randomly select the next
kNoRepeats = 0x1, // random, but no cmd twice in a row
kCoverall = 0x2, // random, but no cmd played twice till all cmds played
kOneCycle = 0x4, // after playing through all cmds, stop
kOneCmd = 0x8, // after playing a random cmd, stop until started again.
kDelayFromEnd = 0x10,
kSequential = 0x20
};
enum {
kStopped = 0x1
};
protected:
// These are only lightly synched, the only synched state is whether
// they are currently active.
UInt8 fState;
hsBitVector fExcluded;
Int8 fCurrent;
UInt8 fMode; // static, if it becomes dynamic, move to SynchedValue
hsTArray<double> fEndTimes;
hsScalar fMinDelay;
hsScalar fMaxDelay;
void IStart();
virtual void IStop();
hsBool IStopped() const;
void IRetry(hsScalar secs);
virtual void IPlayNextIfMaster();
void IReset();
hsScalar IGetDelay(hsScalar len) const;
int IExcludeSelections(int ncmds);
hsBool ISelectNext(int nAnim); // return false if we should stop, else set fCurrent to next index
// Once fCurrent is set to the next animation index to play,
// IPlayNext() does whatever it takes to actually play it.
virtual void IPlayNext() = 0;
// We only act in response to messages.
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty) { return false; }
public:
plRandomCommandMod();
~plRandomCommandMod();
CLASSNAME_REGISTER( plRandomCommandMod );
GETINTERFACE_ANY( plRandomCommandMod, plSingleModifier );
virtual hsBool MsgReceive(plMessage* pMsg);
virtual void Read(hsStream* s, hsResMgr* mgr);
virtual void Write(hsStream* s, hsResMgr* mgr);
// Export only
void SetMode(UInt8 m) { fMode = m; }
UInt8 GetMode() const { return fMode; }
void SetState(UInt8 s) { fState = s; }
UInt8 GetState() const { return fState; }
void SetMinDelay(hsScalar f) { fMinDelay = f; }
hsScalar GetMinDelay() const { return fMinDelay; }
void SetMaxDelay(hsScalar f) { fMaxDelay = f; }
hsScalar GetMaxDelay() const { return fMaxDelay; }
};
#endif // plRandomCommandMod_inc

View File

@ -0,0 +1,294 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include <math.h>
#include "hsTypes.h"
#include "plStereizer.h"
#include "plLineFollowMod.h"
#include "../plMessage/plListenerMsg.h"
#include "plgDispatch.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "hsFastMath.h"
#include "hsGeometry3.h"
#include "hsMatrix44.h"
#include "hsStream.h"
plStereizer::plStereizer()
: fInitPos(0,0,0),
fListPos(0,0,0),
fListDirection(0,1.f,0),
fListUp(0,0,1.f)
{
}
plStereizer::~plStereizer()
{
if( !HasMaster() )
plgDispatch::Dispatch()->UnRegisterForExactType(plListenerMsg::Index(), GetKey());
}
void plStereizer::Read(hsStream* stream, hsResMgr* mgr)
{
plSingleModifier::Read(stream, mgr);
fAmbientDist = stream->ReadSwapScalar();
fTransition = stream->ReadSwapScalar();
fMaxSepDist = stream->ReadSwapScalar();
fMinSepDist = stream->ReadSwapScalar();
fTanAng = stream->ReadSwapScalar();
fInitPos.Read(stream);
if( !HasMaster() )
plgDispatch::Dispatch()->RegisterForExactType(plListenerMsg::Index(), GetKey());
}
void plStereizer::Write(hsStream* stream, hsResMgr* mgr)
{
plSingleModifier::Write(stream, mgr);
stream->WriteSwapScalar(fAmbientDist);
stream->WriteSwapScalar(fTransition);
stream->WriteSwapScalar(fMaxSepDist);
stream->WriteSwapScalar(fMinSepDist);
stream->WriteSwapScalar(fTanAng);
fInitPos.Write(stream);
}
hsBool plStereizer::MsgReceive(plMessage* msg)
{
plListenerMsg* listenMsg = plListenerMsg::ConvertNoRef(msg);
if( listenMsg )
{
SetFromListenerMsg(listenMsg);
return Stereize();
}
return plSingleModifier::MsgReceive(msg);
}
hsBool plStereizer::IEval(double secs, hsScalar del, UInt32 dirty)
{
return false;
}
hsBool plStereizer::Stereize()
{
plSceneObject* targ = GetTarget();
if( !targ )
return true;
targ->FlushTransform();
// Find distance to listener
hsPoint3 pos = IGetUnStereoPos();
hsVector3 posToList(&fListPos, &pos);
hsScalar dist = posToList.Magnitude();
// If distance less than ambient distance
// setup as pure ambient
// Else if distance greater than ambient distance + transition
// setup as pure localized
// Else
// Calc pure ambient position
// Calc pure localized position
// Interpolate between the two.
if( dist <= fAmbientDist )
{
ISetNewPos(IGetAmbientPos());
}
else if( dist >= fAmbientDist + fTransition )
{
ISetNewPos(IGetLocalizedPos(posToList, dist));
}
else
{
hsPoint3 ambPos = IGetAmbientPos();
hsPoint3 localizePos = IGetLocalizedPos(posToList, dist);
hsPoint3 newPos(ambPos);
newPos += (localizePos - ambPos) * ((dist - fAmbientDist) / fTransition);
ISetNewPos(newPos);
}
return true;
}
void plStereizer::ISetNewPos(const hsPoint3& newPos)
{
hsMatrix44 l2w = GetTarget()->GetLocalToWorld();
hsMatrix44 w2l = GetTarget()->GetWorldToLocal();
l2w.NotIdentity();
l2w.fMap[0][3] = newPos[0];
l2w.fMap[1][3] = newPos[1];
l2w.fMap[2][3] = newPos[2];
hsPoint3 invPos = -newPos;
w2l.fMap[0][3] = ((hsVector3*)&w2l.fMap[0][0])->InnerProduct(invPos);
w2l.fMap[1][3] = ((hsVector3*)&w2l.fMap[1][0])->InnerProduct(invPos);
w2l.fMap[2][3] = ((hsVector3*)&w2l.fMap[2][0])->InnerProduct(invPos);
IGetTargetCoordinateInterface(0)->SetTransform(l2w, w2l);
}
void plStereizer::SetFromListenerMsg(const plListenerMsg* listMsg)
{
fListPos = listMsg->GetPosition();
fListDirection = listMsg->GetDirection();
fListUp = listMsg->GetUp();
}
hsPoint3 plStereizer::IGetAmbientPos() const
{
hsPoint3 pos = fListPos;
hsVector3 axOut = fListDirection % fListUp;
hsFastMath::NormalizeAppr(axOut);
if( IsLeftChannel() )
axOut *= -fMinSepDist;
else
axOut *= fMinSepDist;
pos += axOut;
return pos;
}
hsPoint3 plStereizer::IGetLocalizedPos(const hsVector3& posToList, hsScalar distToList) const
{
hsPoint3 pos = IGetUnStereoPos();
hsVector3 axOut(-posToList.fY, posToList.fX, 0);
hsFastMath::NormalizeAppr(axOut);
hsScalar distOut = distToList * fTanAng;
if( distOut > fMaxSepDist )
distOut = fMaxSepDist;
else if( distOut < fMinSepDist )
distOut = fMinSepDist;
if( IsLeftChannel() )
distOut = -distOut;
axOut *= distOut;
pos += axOut;
return pos;
}
void plStereizer::SetSepAngle(hsScalar rads)
{
fTanAng = hsScalar(tan(rads));
}
hsScalar plStereizer::GetSepAngle() const
{
return atan(fTanAng);
}
hsPoint3 plStereizer::IGetUnStereoPos() const
{
return GetWorldInitPos();
}
void plStereizer::SetWorldInitPos(const hsPoint3& pos)
{
plCoordinateInterface* parent = IGetParent();
if( parent )
fInitPos = parent->GetWorldToLocal() * pos;
else
fInitPos = pos;
}
hsPoint3 plStereizer::GetWorldInitPos() const
{
plCoordinateInterface* parent = IGetParent();
if( parent )
return parent->GetLocalToWorld() * fInitPos;
return fInitPos;
}
plCoordinateInterface* plStereizer::IGetParent() const
{
plCoordinateInterface* coord = IGetTargetCoordinateInterface(0);
if( coord )
{
return coord->GetParent();
}
return nil;
}
// Note that (along with it's many other hacky defects), this
// will go down in flames if there are two potential masters.
// Of course, two line follow mods doesn't really make sense
// now anyway, but the point is that this is a simplified placeholder
// to get the job done. If and when a need is shown for sequencing of
// modifiers, this should be updated to follow that protocol. But
// the rationale is that one simple example of a need for sequencing
// doesn't give enough basis to decide what that protocol should be.
// Or in simpler terms, I want to do it one way, Brice wants to do
// it another, and since either would work for this, we're waiting
// for a tie breaker case that gives one way or the other an advantage.
hsBool plStereizer::CheckForMaster()
{
ISetHasMaster(false);
plSceneObject* targ = GetTarget();
if( !targ )
return false;
int n = targ->GetNumModifiers();
int i;
for( i = 0; i < n; i++ )
{
plLineFollowMod* line = plLineFollowMod::ConvertNoRef(IGetTargetModifier(0, i));
if( line )
{
ISetHasMaster(true);
line->AddStereizer(GetKey());
return true;
}
}
return false;
}

View File

@ -0,0 +1,124 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plStereizer_inc
#define plStereizer_inc
#include "../pnModifier/plSingleModifier.h"
#include "hsGeometry3.h"
#include "hsMatrix44.h"
class plListenerMsg;
class plMessage;
class plCoordinateInterface;
class hsStream;
class hsResMgr;
class plStereizer : public plSingleModifier
{
protected:
// Flags - in a plSingleModifier::hsBitVector.
enum
{
kLeftChannel,
kHasMaster
};
// Static properties
hsScalar fAmbientDist;
hsScalar fTransition;
hsScalar fMaxSepDist;
hsScalar fMinSepDist;
hsScalar fTanAng;
hsPoint3 fInitPos;
// Environmental properties, namely of the current listener
hsPoint3 fListPos;
hsVector3 fListDirection;
hsVector3 fListUp;
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
hsPoint3 IGetLocalizedPos(const hsVector3& posToList, hsScalar distToList) const;
hsPoint3 IGetAmbientPos() const;
void ISetNewPos(const hsPoint3& newPos);
hsPoint3 IGetUnStereoPos() const;
plCoordinateInterface* IGetParent() const;
void ISetHasMaster(hsBool on) { if(on)SetFlag(kHasMaster); else ClearFlag(kHasMaster); }
public:
plStereizer();
virtual ~plStereizer();
CLASSNAME_REGISTER( plStereizer );
GETINTERFACE_ANY( plStereizer, plSingleModifier );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual hsBool MsgReceive(plMessage* msg);
hsBool Stereize();
void SetFromListenerMsg(const plListenerMsg* listMsg);
void SetAmbientDist(hsScalar d) { fAmbientDist = d; }
hsScalar GetAmbientDist() const { return fAmbientDist; }
void SetTransition(hsScalar d) { fTransition = d; }
hsScalar GetTransition() const { return fTransition; }
void SetMaxSepDist(hsScalar d) { fMaxSepDist = d; }
hsScalar GetMaxSepDist() const { return fMaxSepDist; }
void SetMinSepDist(hsScalar d) { fMinSepDist = d; }
hsScalar GetMinSepDist() const { return fMinSepDist; }
void SetSepAngle(hsScalar rads);
hsScalar GetSepAngle() const;
void SetAsLeftChannel(hsBool on) { if(on)SetFlag(kLeftChannel); else ClearFlag(kLeftChannel); }
hsBool IsLeftChannel() const { return HasFlag(kLeftChannel); }
void SetParentInitPos(const hsPoint3& pos) { fInitPos = pos; }
const hsPoint3& GetParentInitPos() const { return fInitPos; }
void SetWorldInitPos(const hsPoint3& pos);
hsPoint3 GetWorldInitPos() const;
hsBool CheckForMaster();
hsBool HasMaster() const { return HasFlag(kHasMaster); }
};
#endif // plStereizer_inc

View File

@ -0,0 +1,432 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plViewFaceModifier.h"
#include "plgDispatch.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "hsFastMath.h"
#include "plPipeline.h"
#include "../plMessage/plRenderMsg.h"
#include "../plMessage/plListenerMsg.h"
#include "../plMessage/plAvatarMsg.h"
#include "../plAvatar/plAvBrainHuman.h"
#include "../plAvatar/plArmatureMod.h"
plViewFaceModifier::plViewFaceModifier()
: fFacePoint(0,0,0),
fLastDirY(0,1.f,0),
fScale(1.f,1.f,1.f),
fOffset(0,0,0)
{
fOrigLocalToParent.Reset();
fOrigParentToLocal.Reset();
SetFlag(kFaceCam); // default
}
plViewFaceModifier::~plViewFaceModifier()
{
}
void plViewFaceModifier::SetOrigTransform(const hsMatrix44& l2p, const hsMatrix44& p2l)
{
fOrigLocalToParent = l2p;
fOrigParentToLocal = p2l;
}
void plViewFaceModifier::Read(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Read(s, mgr);
fScale.Read(s);
fOrigLocalToParent.Read(s);
fOrigParentToLocal.Read(s);
if( HasFlag(kFaceObj) )
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefFaceObj), plRefFlags::kPassiveRef);
fOffset.Read(s);
if( HasFlag(kMaxBounds) )
fMaxBounds.Read(s);
}
void plViewFaceModifier::Write(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Write(s, mgr);
fScale.Write(s);
fOrigLocalToParent.Write(s);
fOrigParentToLocal.Write(s);
if( HasFlag(kFaceObj) )
mgr->WriteKey(s, fFaceObj);
fOffset.Write(s);
if( HasFlag(kMaxBounds) )
fMaxBounds.Write(s);
}
void plViewFaceModifier::SetMaxBounds(const hsBounds3Ext& bnd)
{
SetFlag(kMaxBounds);
fMaxBounds = bnd;
}
void plViewFaceModifier::SetTarget(plSceneObject* so)
{
plSingleModifier::SetTarget(so);
plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey());
if( HasFlag(kFaceList) )
plgDispatch::Dispatch()->RegisterForExactType(plListenerMsg::Index(), GetKey());
if( HasFlag(kFacePlay) )
plgDispatch::Dispatch()->RegisterForExactType(plArmatureUpdateMsg::Index(), GetKey());
}
hsBool plViewFaceModifier::IEval(double secs, hsScalar del, UInt32 dirty)
{
return false;
}
hsBool plViewFaceModifier::IFacePoint(plPipeline* pipe, const hsPoint3& at)
{
#if 1 // BOUNDSTEST
extern int mfCurrentTest;
if( mfCurrentTest != 101 )
if( HasFlag(kMaxBounds) )
{
if( !pipe->TestVisibleWorld(fMaxBounds) )
return false;
}
#endif // BOUNDSTEST
if( !(GetTarget() && GetTarget()->GetCoordinateInterface()) )
return false;
hsMatrix44 worldToLocal = fOrigParentToLocal; // parentToLocal
if( GetTarget()->GetCoordinateInterface()->GetParent() && GetTarget()->GetCoordinateInterface()->GetParent() )
{
hsMatrix44 m;
worldToLocal = worldToLocal * GetTarget()->GetCoordinateInterface()->GetParent()->GetWorldToLocal();
}
hsPoint3 localAt = worldToLocal * at;
hsScalar len = localAt.MagnitudeSquared();
if( len <= 0 )
return false;
len = -hsFastMath::InvSqrtAppr(len);
hsVector3 dirX, dirY, dirZ;
dirZ.Set(localAt.fX * len, localAt.fY * len, localAt.fZ * len);
if( HasFlag(kPivotFace) )
{
dirY.Set(0.f, 0.f, 1.f);
dirX = dirY % dirZ;
dirX = hsFastMath::NormalizeAppr(dirX);
dirY = dirZ % dirX;
}
else if( HasFlag(kPivotFavorY) )
{
dirY.Set(0.f, 1.f, 0.f);
dirX = dirY % dirZ;
dirX = hsFastMath::NormalizeAppr(dirX);
dirY = dirZ % dirX;
}
else if( HasFlag(kPivotY) )
{
dirY.Set(0.f, 1.f, 0.f);
dirX = dirY % dirZ;
dirX = hsFastMath::NormalizeAppr(dirX);
dirZ = dirX % dirY;
}
else if( HasFlag(kPivotTumble) )
{
dirY = fLastDirY;
dirX = dirY % dirZ;
dirX = hsFastMath::NormalizeAppr(dirX);
dirY = dirZ % dirX;
fLastDirY = dirY;
}
else
{
hsAssert(false, "I've no idea what you're getting at here in ViewFace land");
}
hsMatrix44 x;
hsMatrix44 xInv;
xInv.fMap[0][0] = x.fMap[0][0] = dirX[0];
xInv.fMap[1][0] = x.fMap[0][1] = dirY[0];
xInv.fMap[2][0] = x.fMap[0][2] = dirZ[0];
xInv.fMap[3][0] = x.fMap[0][3] = 0;
xInv.fMap[0][1] = x.fMap[1][0] = dirX[1];
xInv.fMap[1][1] = x.fMap[1][1] = dirY[1];
xInv.fMap[2][1] = x.fMap[1][2] = dirZ[1];
xInv.fMap[3][1] = x.fMap[1][3] = 0;
xInv.fMap[0][2] = x.fMap[2][0] = dirX[2];
xInv.fMap[1][2] = x.fMap[2][1] = dirY[2];
xInv.fMap[2][2] = x.fMap[2][2] = dirZ[2];
xInv.fMap[3][2] = x.fMap[2][3] = 0;
x.fMap[3][0] = x.fMap[3][1] = x.fMap[3][2] = 0;
xInv.fMap[0][3] = xInv.fMap[1][3] = xInv.fMap[2][3] = 0;
xInv.fMap[3][3] = x.fMap[3][3] = hsScalar1;
x.NotIdentity();
xInv.NotIdentity();
if( HasFlag(kScale) )
{
x.fMap[0][0] *= fScale.fX;
x.fMap[0][1] *= fScale.fX;
x.fMap[0][2] *= fScale.fX;
x.fMap[1][0] *= fScale.fY;
x.fMap[1][1] *= fScale.fY;
x.fMap[1][2] *= fScale.fY;
x.fMap[2][0] *= fScale.fZ;
x.fMap[2][1] *= fScale.fZ;
x.fMap[2][2] *= fScale.fZ;
hsScalar inv = 1.f / fScale.fX;
xInv.fMap[0][0] *= inv;
xInv.fMap[1][0] *= inv;
xInv.fMap[2][0] *= inv;
inv = 1.f / fScale.fY;
xInv.fMap[0][1] *= inv;
xInv.fMap[1][1] *= inv;
xInv.fMap[2][1] *= inv;
inv = 1.f / fScale.fZ;
xInv.fMap[0][2] *= inv;
xInv.fMap[1][2] *= inv;
xInv.fMap[2][2] *= inv;
}
hsMatrix44 l2p = fOrigLocalToParent * x;
hsMatrix44 p2l = xInv * fOrigParentToLocal;
if( l2p != IGetTargetCoordinateInterface(0)->GetLocalToParent() ) // TERRORDAN
{
IGetTargetCoordinateInterface(0)->SetLocalToParent(l2p, p2l);
IGetTargetCoordinateInterface(0)->FlushTransform(false);
}
return true;
}
#include "plProfile.h"
plProfile_CreateTimer("ViewFacing", "RenderSetup", ViewFace);
hsBool plViewFaceModifier::MsgReceive(plMessage* msg)
{
plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg);
if( rend )
{
plProfile_BeginLap(ViewFace, this->GetKey()->GetUoid().GetObjectName());
if( HasFlag(kFaceCam) )
{
fFacePoint = rend->Pipeline()->GetViewPositionWorld();
if( HasFlag(kOffset) )
{
if( HasFlag(kOffsetLocal) )
{
fFacePoint += rend->Pipeline()->GetViewAcrossWorld() * fOffset.fX;
fFacePoint += rend->Pipeline()->GetViewUpWorld() * fOffset.fY;
fFacePoint += rend->Pipeline()->GetViewDirWorld() * fOffset.fZ;
}
else
{
fFacePoint += fOffset;
}
}
}
else
if( HasFlag(kFaceObj) )
{
if( !fFaceObj )
return true;
fFacePoint = fFaceObj->GetLocalToWorld().GetTranslate();
if( HasFlag(kOffset) )
{
if( HasFlag(kOffsetLocal) )
fFacePoint += fFaceObj->GetLocalToWorld() * fOffset;
else
fFacePoint += fOffset;
}
}
IFacePoint(rend->Pipeline(), fFacePoint);
plProfile_EndLap(ViewFace, this->GetKey()->GetUoid().GetObjectName());
return true;
}
plArmatureUpdateMsg* armMsg = plArmatureUpdateMsg::ConvertNoRef(msg);
if( armMsg && armMsg->IsLocal() )
{
const plSceneObject* head = armMsg->fArmature->FindBone(plAvBrainHuman::Head);
if( head )
{
fFacePoint = head->GetLocalToWorld().GetTranslate();
if( HasFlag(kOffset) )
{
if( HasFlag(kOffsetLocal) )
fFacePoint += head->GetLocalToWorld() * fOffset;
else
fFacePoint += fOffset;
}
}
return true;
}
plListenerMsg* list = plListenerMsg::ConvertNoRef(msg);
if( list )
{
fFacePoint = list->GetPosition();
if( HasFlag(kOffset) )
{
if( HasFlag(kOffsetLocal) )
{
fFacePoint += (list->GetDirection() % list->GetUp()) * fOffset.fX;
fFacePoint += list->GetDirection() * fOffset.fY;
fFacePoint += list->GetUp() * fOffset.fZ;
}
else
{
fFacePoint += fOffset;
}
}
return true;
}
plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef(msg);
if( refMsg )
{
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
IOnReceive(refMsg);
else
IOnRemove(refMsg);
return true;
}
return plSingleModifier::MsgReceive(msg);
}
void plViewFaceModifier::IOnReceive(plGenRefMsg* refMsg)
{
switch(refMsg->fType)
{
case kRefFaceObj:
fFaceObj = plSceneObject::ConvertNoRef(refMsg->GetRef());
break;
}
}
void plViewFaceModifier::IOnRemove(plGenRefMsg* refMsg)
{
switch(refMsg->fType)
{
case kRefFaceObj:
fFaceObj = nil;
break;
}
}
void plViewFaceModifier::ISetObject(plKey soKey)
{
hsgResMgr::ResMgr()->SendRef(soKey, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnRequest, 0, kRefFaceObj), plRefFlags::kPassiveRef);
}
void plViewFaceModifier::SetFollowMode(FollowMode m, plKey soKey)
{
ClearFlag(kFaceCam);
ClearFlag(kFaceList);
ClearFlag(kFacePlay);
ClearFlag(kFaceObj);
switch(m)
{
case kFollowCamera:
SetFlag(kFaceCam);
break;
case kFollowListener:
SetFlag(kFaceList);
break;
case kFollowPlayer:
SetFlag(kFacePlay);
break;
case kFollowObject:
SetFlag(kFaceObj);
ISetObject(soKey);
break;
default:
hsAssert(false, "Unknown follow mode");
SetFlag(kFaceCam);
break;
}
}
plViewFaceModifier::FollowMode plViewFaceModifier::GetFollowMode() const
{
if( HasFlag(kFaceCam) )
return kFollowCamera;
if( HasFlag(kFaceList) )
return kFollowListener;
if( HasFlag(kFacePlay) )
return kFollowPlayer;
if( HasFlag(kFaceObj) )
return kFollowObject;
hsAssert(false, "Have no follow mode");
return kFollowCamera;
}
void plViewFaceModifier::SetOffset(const hsVector3& off, hsBool local)
{
fOffset = off;
if( local )
SetFlag(kOffsetLocal);
else
ClearFlag(kOffsetLocal);
}

View File

@ -0,0 +1,124 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plViewFaceModifier_inc
#define plViewFaceModifier_inc
#include "hsMatrix44.h"
#include "hsBounds.h"
#include "../pnModifier/plSingleModifier.h"
class plGenRefMsg;
class plPipeline;
class plViewFaceModifier : public plSingleModifier
{
public:
enum plVFFlags {
kPivotFace = 0,
kPivotFavorY,
kPivotY,
kPivotTumble,
kScale,
kFaceCam,
kFaceList,
kFacePlay,
kFaceObj,
kOffset,
kOffsetLocal,
kMaxBounds
};
protected:
hsVector3 fLastDirY;
hsVector3 fScale;
hsMatrix44 fOrigLocalToParent;
hsMatrix44 fOrigParentToLocal;
hsPoint3 fFacePoint;
plSceneObject* fFaceObj;
hsVector3 fOffset;
hsBounds3Ext fMaxBounds;
virtual hsBool IFacePoint(plPipeline* pipe, const hsPoint3& at);
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
enum RefType
{
kRefFaceObj
};
void IOnReceive(plGenRefMsg* refMsg);
void IOnRemove(plGenRefMsg* refMsg);
void ISetObject(plKey soKey);
public:
plViewFaceModifier();
virtual ~plViewFaceModifier();
CLASSNAME_REGISTER( plViewFaceModifier );
GETINTERFACE_ANY( plViewFaceModifier, plSingleModifier );
virtual void SetTarget(plSceneObject* so);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual hsBool MsgReceive(plMessage* msg);
// ViewFace specific
void SetScale(const hsVector3& s) { fScale = s; }
const hsVector3& GetScale() const { return fScale; }
void SetOrigTransform(const hsMatrix44& l2p, const hsMatrix44& p2l);
void SetMaxBounds(const hsBounds3Ext& bnd);
const hsBounds3Ext& GetMaxBounds() const { return fMaxBounds; }
hsBool HaveMaxBounds() const { return HasFlag(kMaxBounds); }
enum FollowMode
{
kFollowCamera = 0, // Follow the camera
kFollowListener,
kFollowPlayer,
kFollowObject
};
void SetFollowMode(FollowMode m, plKey soKey=nil); // For follow object, set obj, else it's ignored.
FollowMode GetFollowMode() const;
plSceneObject* GetFollowObject() const { return fFaceObj; }
void SetOffsetActive(hsBool on) { if(on) SetFlag(kOffset); else ClearFlag(kOffset); }
hsBool GetOffsetActive() const { return HasFlag(kOffset); }
void SetOffset(const hsVector3& off, hsBool local=true);
const hsVector3& GetOffset() const { return fOffset; }
hsBool GetOffsetLocal() const { return HasFlag(kOffsetLocal); }
};
#endif // plViewFaceModifier_inc