You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
6.0 KiB

/*==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;
}