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:
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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 ¢er, 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 ¢er, 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(¢er, &((**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
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
Reference in New Issue
Block a user