Torque3D/Engine/source/T3D/lightAnimData.cpp

313 lines
9.6 KiB
C++
Raw Normal View History

2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "lightAnimData.h"
#include "console/consoleTypes.h"
#include "T3D/lightBase.h"
#include "math/mRandom.h"
#include "math/mathIO.h"
#include "T3D/gameBase/processList.h"
#include "core/stream/bitStream.h"
LightAnimData::LightAnimData()
{
}
LightAnimData::~LightAnimData()
{
}
IMPLEMENT_CO_DATABLOCK_V1( LightAnimData );
ConsoleDocClass( LightAnimData,
"@brief A datablock which defines and performs light animation, such as rotation, brightness fade, and colorization.\n\n"
"@tsexample\n"
"datablock LightAnimData( SubtlePulseLightAnim )\n"
"{\n"
" brightnessA = 0.5;\n"
" brightnessZ = 1;\n"
" brightnessPeriod = 1;\n"
" brightnessKeys = \"aza\";\n"
" brightnessSmooth = true;\n"
"};\n"
"@endtsexample\n\n"
"@see LightBase\n\n"
"@see LightDescription\n\n"
"@ingroup FX\n"
"@ingroup Lighting\n"
);
void LightAnimData::initPersistFields()
{
addGroup( "Offset",
"The XYZ translation animation state relative to the light position." );
addField( "offsetA", TypeF32, Offset( mOffset.value1, LightAnimData ), 3,
"The value of the A key in the keyframe sequence." );
addField( "offsetZ", TypeF32, Offset( mOffset.value2, LightAnimData ), 3,
"The value of the Z key in the keyframe sequence." );
addField( "offsetPeriod", TypeF32, Offset( mOffset.period, LightAnimData ), 3,
"The animation time for keyframe sequence." );
addField( "offsetKeys", TypeString, Offset( mOffset.keys, LightAnimData ), 3,
"The keyframe sequence encoded into a string where characters from A to Z define "
"a position between the two animation values." );
addField( "offsetSmooth", TypeBool, Offset( mOffset.smooth, LightAnimData ), 3,
"If true the transition between keyframes will be smooth." );
endGroup( "Offset" );
addGroup( "Rotation",
"The XYZ rotation animation state relative to the light orientation." );
addField( "rotA", TypeF32, Offset( mRot.value1, LightAnimData ), 3,
"The value of the A key in the keyframe sequence." );
addField( "rotZ", TypeF32, Offset( mRot.value2, LightAnimData ), 3,
"The value of the Z key in the keyframe sequence." );
addField( "rotPeriod", TypeF32, Offset( mRot.period, LightAnimData ), 3,
"The animation time for keyframe sequence." );
addField( "rotKeys", TypeString, Offset( mRot.keys, LightAnimData ), 3,
"The keyframe sequence encoded into a string where characters from A to Z define "
"a position between the two animation values." );
addField( "rotSmooth", TypeBool, Offset( mRot.smooth, LightAnimData ), 3,
"If true the transition between keyframes will be smooth." );
endGroup( "Rotation" );
addGroup( "Color",
"The RGB color animation state." );
addField( "colorA", TypeF32, Offset( mColor.value1, LightAnimData ), 3,
"The value of the A key in the keyframe sequence." );
addField( "colorZ", TypeF32, Offset( mColor.value2, LightAnimData ), 3,
"The value of the Z key in the keyframe sequence." );
addField( "colorPeriod", TypeF32, Offset( mColor.period, LightAnimData ), 3,
"The animation time for keyframe sequence." );
addField( "colorKeys", TypeString, Offset( mColor.keys, LightAnimData ), 3,
"The keyframe sequence encoded into a string where characters from A to Z define "
"a position between the two animation values." );
addField( "colorSmooth", TypeBool, Offset( mColor.smooth, LightAnimData ), 3,
"If true the transition between keyframes will be smooth." );
endGroup( "Color" );
addGroup( "Brightness",
"The brightness animation state." );
addField( "brightnessA", TypeF32, Offset( mBrightness.value1, LightAnimData ),
"The value of the A key in the keyframe sequence." );
addField( "brightnessZ", TypeF32, Offset( mBrightness.value2, LightAnimData ),
"The value of the Z key in the keyframe sequence." );
addField( "brightnessPeriod", TypeF32, Offset( mBrightness.period, LightAnimData ),
"The animation time for keyframe sequence." );
addField( "brightnessKeys", TypeString, Offset( mBrightness.keys, LightAnimData ),
"The keyframe sequence encoded into a string where characters from A to Z define "
"a position between the two animation values." );
addField( "brightnessSmooth", TypeBool, Offset( mBrightness.smooth, LightAnimData ),
"If true the transition between keyframes will be smooth." );
endGroup( "Brightness" );
Parent::initPersistFields();
}
bool LightAnimData::preload( bool server, String &errorStr )
{
if ( !Parent::preload( server, errorStr ) )
return false;
_updateKeys();
return true;
}
void LightAnimData::inspectPostApply()
{
Parent::inspectPostApply();
_updateKeys();
}
void LightAnimData::_updateKeys()
{
mOffset.updateKey();
mRot.updateKey();
mColor.updateKey();
mBrightness.updateKey();
}
template<U32 COUNT>
void LightAnimData::AnimValue<COUNT>::updateKey()
{
for ( U32 i=0; i < COUNT; i++ )
{
timeScale[i] = 0.0f;
keyLen[i] = 0.0f;
if ( keys[i] && keys[i][0] && period[i] > 0.0f )
{
keyLen[i] = dStrlen( keys[i] );
timeScale[i] = (F32)( keyLen[i] - 1 ) / period[i];
}
}
}
template<U32 COUNT>
bool LightAnimData::AnimValue<COUNT>::animate(F32 time, F32 *output, bool multiply)
2012-09-19 15:15:01 +00:00
{
F32 scaledTime, lerpFactor, valueRange, keyFrameLerp;
U32 posFrom, posTo;
S32 keyFrameFrom, keyFrameTo;
F32 initialValue = *output;
if (!multiply)
initialValue = 1;
2012-09-19 15:15:01 +00:00
bool wasAnimated = false;
for ( U32 i=0; i < COUNT; i++ )
{
if ( mIsZero( timeScale[i] ) )
continue;
wasAnimated = true;
scaledTime = mFmod( time, period[i] ) * timeScale[i];
posFrom = mFloor( scaledTime );
posTo = mCeil( scaledTime );
keyFrameFrom = dToupper( keys[i][posFrom] ) - 65;
keyFrameTo = dToupper( keys[i][posTo] ) - 65;
valueRange = ( value2[i] - value1[i] ) / 25.0f;
if ( !smooth[i] )
output[i] = (value1[i] + (keyFrameFrom * valueRange)) * initialValue;
2012-09-19 15:15:01 +00:00
else
{
lerpFactor = scaledTime - posFrom;
keyFrameLerp = ( keyFrameTo - keyFrameFrom ) * lerpFactor;
output[i] = (value1[i] + ((keyFrameFrom + keyFrameLerp) * valueRange)) * initialValue;
2012-09-19 15:15:01 +00:00
}
}
return wasAnimated;
}
template<U32 COUNT>
void LightAnimData::AnimValue<COUNT>::write( BitStream *stream ) const
{
for ( U32 i=0; i < COUNT; i++ )
{
stream->write( value1[i] );
stream->write( value2[i] );
stream->write( period[i] );
stream->writeString( keys[i] );
}
}
template<U32 COUNT>
void LightAnimData::AnimValue<COUNT>::read( BitStream *stream )
{
for ( U32 i=0; i < COUNT; i++ )
{
stream->read( &value1[i] );
stream->read( &value2[i] );
stream->read( &period[i] );
keys[i] = stream->readSTString();
}
}
void LightAnimData::packData( BitStream *stream )
{
Parent::packData( stream );
mOffset.write( stream );
mRot.write( stream );
mColor.write( stream );
mBrightness.write( stream );
}
void LightAnimData::unpackData( BitStream *stream )
{
Parent::unpackData( stream );
mOffset.read( stream );
mRot.read( stream );
mColor.read( stream );
mBrightness.read( stream );
}
void LightAnimData::animate( LightInfo *lightInfo, LightAnimState *state )
{
PROFILE_SCOPE( LightAnimData_animate );
// Calculate the input time for animation.
F32 time = state->animationPhase +
( (F32)Sim::getCurrentTime() * 0.001f ) /
state->animationPeriod;
MatrixF transform( state->transform );
EulerF euler( Point3F::Zero );
if ( mRot.animate( time, euler ) )
{
euler.x = mDegToRad( euler.x );
euler.y = mDegToRad( euler.y );
euler.z = mDegToRad( euler.z );
MatrixF rot( euler );
transform.mul( rot );
}
Point3F offset( Point3F::Zero );
if ( mOffset.animate( time, offset ) )
transform.displace( offset );
lightInfo->setTransform( transform );
ColorF color = state->color;
mColor.animate( time, color );
lightInfo->setColor( color );
F32 brightness = state->brightness;
mBrightness.animate( time, &brightness, true );
2012-09-19 15:15:01 +00:00
lightInfo->setBrightness( brightness );
}