2003-02-16 04:01:45 +00:00
#include "global.h" // testing updates
2001-11-04 19:34:28 +00:00
/*
-----------------------------------------------------------------------------
2002-05-19 01:59:48 +00:00
Class: Actor
2001-11-04 19:34:28 +00:00
2002-05-19 01:59:48 +00:00
Desc: See header.
2001-11-04 19:34:28 +00:00
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
2001-11-04 19:34:28 +00:00
-----------------------------------------------------------------------------
*/
2001-11-03 10:52:42 +00:00
#include "Actor.h"
#include <math.h>
2002-05-19 01:59:48 +00:00
#include "RageDisplay.h"
2002-03-30 20:00:13 +00:00
#include "PrefsManager.h"
2002-11-11 04:53:31 +00:00
#include "RageUtil.h"
2003-04-14 22:01:57 +00:00
#include "RageMath.h"
2002-11-11 04:53:31 +00:00
#include "GameConstantsAndTypes.h"
2003-03-02 01:43:33 +00:00
#include "RageLog.h"
2001-11-03 10:52:42 +00:00
2003-04-02 05:41:22 +00:00
/* This is Reset instead of Init since many derived classes have Init() functions
* that shouldn't change the position of the actor. */
void Actor :: Reset ()
2001-11-03 10:52:42 +00:00
{
2003-04-02 05:41:22 +00:00
m_TweenStates . clear ();
m_TweenInfo . clear ();
2003-01-10 02:22:07 +00:00
2003-02-06 07:32:57 +00:00
m_baseRotation = RageVector3 ( 0 , 0 , 0 );
m_baseScale = RageVector3 ( 1 , 1 , 1 );
2002-10-28 05:30:45 +00:00
m_size = RageVector2 ( 1 , 1 );
2002-09-02 21:59:58 +00:00
m_start . Init ();
m_current . Init ();
2002-03-30 20:00:13 +00:00
m_HorizAlign = align_center ;
m_VertAlign = align_middle ;
2003-02-17 12:19:42 +00:00
m_Effect = no_effect ;
m_fSecsIntoEffect = 0 ;
m_fEffectPeriodSeconds = 1 ;
2003-03-02 01:43:33 +00:00
m_vEffectMagnitude = RageVector3 ( 0 , 0 , 10 );
m_effectColor1 = RageColor ( 1 , 1 , 1 , 1 );
m_effectColor2 = RageColor ( 1 , 1 , 1 , 1 );
2002-03-30 20:00:13 +00:00
2002-05-01 19:14:55 +00:00
m_bShadow = false ;
2002-04-16 17:31:00 +00:00
m_fShadowLength = 4 ;
2003-03-05 02:52:40 +00:00
m_bIsAnimating = true ;
2003-05-15 22:43:02 +00:00
m_bTextureWrapping = false ;
2003-05-15 06:09:19 +00:00
m_BlendMode = BLEND_NORMAL ;
m_bUseZBuffer = false ;
2003-05-15 22:43:02 +00:00
m_bUseBackfaceCull = false ;
2001-11-03 10:52:42 +00:00
}
2003-04-02 05:41:22 +00:00
Actor :: Actor ()
{
Reset ();
m_bFirstUpdate = true ;
}
2002-08-19 20:02:30 +00:00
void Actor :: Draw ()
{
// call the most-derived versions
this -> BeginDraw ();
this -> DrawPrimitives (); // call the most-derived version of DrawPrimitives();
this -> EndDraw ();
}
void Actor :: BeginDraw () // set the world matrix and calculate actor properties
2001-11-28 20:26:45 +00:00
{
2002-05-19 01:59:48 +00:00
DISPLAY -> PushMatrix (); // we're actually going to do some drawing in this function
2002-01-16 10:01:32 +00:00
2002-03-30 20:00:13 +00:00
int i ;
2002-09-02 21:59:58 +00:00
m_temp = m_current ;
2001-11-28 20:26:45 +00:00
2002-03-30 20:00:13 +00:00
2003-04-14 22:01:57 +00:00
/* XXX: recheck rotations in here (all in degrees?) */
2002-03-30 20:00:13 +00:00
//
// set temporary drawing properties based on Effects
//
2003-03-02 01:43:33 +00:00
float fPercentThroughEffect = m_fSecsIntoEffect / m_fEffectPeriodSeconds ;
bool bBlinkOn = fPercentThroughEffect > 0.5f ;
float fPercentBetweenColors = sinf ( fPercentThroughEffect * 2 * PI ) / 2 + 0.5f ;
2003-02-17 12:19:42 +00:00
ASSERT ( fPercentBetweenColors >= 0 && fPercentBetweenColors <= 1 );
float fOriginalAlpha = m_temp . diffuse [ 0 ]. a ;
2001-11-28 20:26:45 +00:00
switch ( m_Effect )
{
case no_effect :
break ;
2003-03-02 01:43:33 +00:00
case diffuse_blink :
2002-03-30 20:00:13 +00:00
for ( i = 0 ; i < 4 ; i ++ )
2003-02-17 12:19:42 +00:00
m_temp . diffuse [ i ] = bBlinkOn ? m_effectColor1 : m_effectColor2 ;
2001-11-28 20:26:45 +00:00
break ;
2003-02-18 23:15:38 +00:00
case diffuse_shift :
2002-03-30 20:00:13 +00:00
for ( i = 0 ; i < 4 ; i ++ )
2003-02-17 12:19:42 +00:00
m_temp . diffuse [ i ] = m_effectColor1 * fPercentBetweenColors + m_effectColor2 * ( 1.0f - fPercentBetweenColors );
2001-11-28 20:26:45 +00:00
break ;
2003-03-02 01:43:33 +00:00
case glow_blink :
2003-02-17 12:19:42 +00:00
m_temp . glow = bBlinkOn ? m_effectColor1 : m_effectColor2 ;
m_temp . glow . a *= fOriginalAlpha ; // don't glow if the Actor is transparent!
break ;
2003-02-18 23:15:38 +00:00
case glow_shift :
2003-02-17 12:19:42 +00:00
m_temp . glow = m_effectColor1 * fPercentBetweenColors + m_effectColor2 * ( 1.0f - fPercentBetweenColors );
m_temp . glow . a *= fOriginalAlpha ; // don't glow if the Actor is transparent!
2001-11-28 20:26:45 +00:00
break ;
2003-03-05 02:52:40 +00:00
case rainbow :
m_temp . diffuse [ 0 ] = RageColor (
cosf ( fPercentBetweenColors * 2 * PI ) * 0.5f + 0.5f ,
cosf ( fPercentBetweenColors * 2 * PI + PI * 2.0f / 3.0f ) * 0.5f + 0.5f ,
cosf ( fPercentBetweenColors * 2 * PI + PI * 4.0f / 3.0f ) * 0.5f + 0.5f ,
fOriginalAlpha );
for ( i = 1 ; i < 4 ; i ++ )
m_temp . diffuse [ i ] = m_temp . diffuse [ 0 ];
break ;
2003-03-02 01:43:33 +00:00
case wag :
m_temp . rotation = m_vEffectMagnitude * sinf ( fPercentThroughEffect * 2.0f * PI );
2001-11-28 20:26:45 +00:00
break ;
2003-03-02 01:43:33 +00:00
case spin :
2002-09-02 21:59:58 +00:00
// nothing needs to be here
2001-11-28 20:26:45 +00:00
break ;
2003-03-02 01:43:33 +00:00
case vibrate :
m_temp . pos . x += m_vEffectMagnitude . x * randomf ( - 1.0f , 1.0f ) * GetZoom ();
m_temp . pos . y += m_vEffectMagnitude . y * randomf ( - 1.0f , 1.0f ) * GetZoom ();
m_temp . pos . z += m_vEffectMagnitude . z * randomf ( - 1.0f , 1.0f ) * GetZoom ();
2001-11-28 20:26:45 +00:00
break ;
2003-03-02 01:43:33 +00:00
case bounce :
2002-03-30 20:00:13 +00:00
{
2003-03-02 01:43:33 +00:00
float fPercentOffset = sinf ( fPercentThroughEffect * PI );
m_temp . pos += m_vEffectMagnitude * fPercentOffset ;
2003-02-23 23:29:22 +00:00
m_temp . pos . x = roundf ( m_temp . pos . x );
m_temp . pos . y = roundf ( m_temp . pos . y );
m_temp . pos . z = roundf ( m_temp . pos . z );
2002-03-30 20:00:13 +00:00
}
2002-01-16 10:01:32 +00:00
break ;
2003-03-02 01:43:33 +00:00
case bob :
2002-07-27 19:29:51 +00:00
{
2003-03-02 01:43:33 +00:00
float fPercentOffset = sinf ( fPercentThroughEffect * PI * 2 );
m_temp . pos += m_vEffectMagnitude * fPercentOffset ;
2003-02-23 23:29:22 +00:00
m_temp . pos . x = roundf ( m_temp . pos . x );
m_temp . pos . y = roundf ( m_temp . pos . y );
m_temp . pos . z = roundf ( m_temp . pos . z );
2003-03-05 02:52:40 +00:00
}
break ;
case pulse :
{
float fMinZoom = m_vEffectMagnitude [ 0 ];
float fMaxZoom = m_vEffectMagnitude [ 1 ];
float fPercentOffset = sinf ( fPercentThroughEffect * PI );
float fZoom = SCALE ( fPercentOffset , 0.f , 1.f , fMinZoom , fMaxZoom );
m_temp . scale = RageVector3 ( fZoom , fZoom , fZoom );
}
2002-07-27 19:29:51 +00:00
break ;
2002-03-30 20:00:13 +00:00
default :
2002-07-27 19:29:51 +00:00
ASSERT ( 0 ); // invalid Effect
2001-11-28 20:26:45 +00:00
}
2002-03-30 20:00:13 +00:00
2003-02-06 07:32:57 +00:00
m_temp . scale . x *= m_baseScale . x ;
m_temp . scale . y *= m_baseScale . y ;
m_temp . scale . z *= m_baseScale . z ;
m_temp . rotation . x += m_baseRotation . x ;
m_temp . rotation . y += m_baseRotation . y ;
m_temp . rotation . z += m_baseRotation . z ;
2001-11-28 20:26:45 +00:00
2003-02-06 07:32:57 +00:00
2002-11-14 01:48:48 +00:00
DISPLAY -> Translate ( m_temp . pos . x , m_temp . pos . y , m_temp . pos . z );
2003-02-06 07:32:57 +00:00
DISPLAY -> Scale ( m_temp . scale . x , m_temp . scale . y , m_temp . scale . z );
2001-11-28 20:26:45 +00:00
2003-04-14 22:01:57 +00:00
/* The only time rotation and quat should normally be used simultaneously
* is for m_baseRotation. */
2003-02-22 00:22:27 +00:00
if ( m_temp . rotation . x != 0 )
2003-02-20 10:41:43 +00:00
DISPLAY -> RotateX ( m_temp . rotation . x );
2003-02-22 00:22:27 +00:00
if ( m_temp . rotation . y != 0 )
2003-02-20 10:41:43 +00:00
DISPLAY -> RotateY ( m_temp . rotation . y );
2003-02-22 00:22:27 +00:00
if ( m_temp . rotation . z != 0 )
2003-02-20 10:41:43 +00:00
DISPLAY -> RotateZ ( m_temp . rotation . z );
2003-04-14 22:01:57 +00:00
if ( m_temp . quat . x != 0 || m_temp . quat . y != 0 || m_temp . quat . z != 0 || m_temp . quat . w != 1 )
{
RageMatrix mat ;
RageMatrixFromQuat ( & mat , m_temp . quat );
DISPLAY -> MultMatrix ( mat );
}
2002-08-19 20:02:30 +00:00
}
2002-01-16 10:01:32 +00:00
2003-05-15 06:09:19 +00:00
void Actor :: SetRenderStates ()
{
// set Actor-defined render states
DISPLAY -> SetTextureWrapping ( m_bTextureWrapping );
DISPLAY -> SetBlendMode ( m_BlendMode );
DISPLAY -> SetZBuffer ( m_bUseZBuffer );
DISPLAY -> SetBackfaceCull ( m_bUseBackfaceCull );
}
2002-08-19 20:02:30 +00:00
void Actor :: EndDraw ()
{
2002-05-19 01:59:48 +00:00
DISPLAY -> PopMatrix ();
2001-11-28 20:26:45 +00:00
}
2002-09-04 21:53:43 +00:00
void Actor :: UpdateTweening ( float fDeltaTime )
{
// update tweening
2003-02-25 02:51:04 +00:00
if ( m_TweenStates . empty () )
2002-09-04 21:53:43 +00:00
return ;
// we are performing a tween
TweenState & TS = m_TweenStates [ 0 ]; // earliest tween
TweenInfo & TI = m_TweenInfo [ 0 ]; // earliest tween
if ( TI . m_fTimeLeftInTween == TI . m_fTweenTime ) // we are just beginning this tween
{
// set the start position
m_start = m_current ;
}
TI . m_fTimeLeftInTween -= fDeltaTime ;
if ( TI . m_fTimeLeftInTween <= 0 ) // The tweening is over. Stop the tweening
{
m_current = TS ;
// delete the head tween
2003-02-25 02:51:04 +00:00
m_TweenStates . erase ( m_TweenStates . begin () );
m_TweenInfo . erase ( m_TweenInfo . begin () );
2002-09-04 21:53:43 +00:00
}
else // in the middle of tweening. Recalcute the current position.
{
const float fPercentThroughTween = 1 - ( TI . m_fTimeLeftInTween / TI . m_fTweenTime );
// distort the percentage if appropriate
2002-09-07 10:11:00 +00:00
float fPercentAlongPath = 0.f ;
2002-09-04 21:53:43 +00:00
switch ( TI . m_TweenType )
{
2002-10-28 05:30:45 +00:00
case TWEEN_LINEAR : fPercentAlongPath = fPercentThroughTween ; break ;
2003-03-02 01:43:33 +00:00
case TWEEN_ACCELERATE : fPercentAlongPath = fPercentThroughTween * fPercentThroughTween ; break ;
case TWEEN_DECELERATE : fPercentAlongPath = 1 - ( 1 - fPercentThroughTween ) * ( 1 - fPercentThroughTween ); break ;
2002-10-28 05:30:45 +00:00
case TWEEN_BOUNCE_BEGIN : fPercentAlongPath = 1 - sinf ( 1.1f + fPercentThroughTween * ( PI - 1.1f ) ) / 0.89f ; break ;
case TWEEN_BOUNCE_END : fPercentAlongPath = sinf ( 1.1f + ( 1 - fPercentThroughTween ) * ( PI - 1.1f ) ) / 0.89f ; break ;
case TWEEN_SPRING : fPercentAlongPath = 1 - cosf ( fPercentThroughTween * PI * 2.5f ) / ( 1 + fPercentThroughTween * 3 ); break ;
2002-09-04 21:53:43 +00:00
default : ASSERT ( 0 );
}
2003-03-02 01:43:33 +00:00
TweenState :: MakeWeightedAverage ( m_current , m_start , TS , fPercentAlongPath );
2002-09-04 21:53:43 +00:00
}
}
2001-11-28 20:26:45 +00:00
2003-01-10 02:22:07 +00:00
bool Actor :: IsFirstUpdate ()
{
return m_bFirstUpdate ;
}
2002-01-16 10:01:32 +00:00
void Actor :: Update ( float fDeltaTime )
2001-11-03 10:52:42 +00:00
{
2002-07-31 19:40:40 +00:00
// LOG->Trace( "Actor::Update( %f )", fDeltaTime );
2001-11-03 10:52:42 +00:00
2001-11-28 20:26:45 +00:00
// update effect
switch ( m_Effect )
{
case no_effect :
break ;
2003-03-02 01:43:33 +00:00
case diffuse_blink :
2003-02-18 23:15:38 +00:00
case diffuse_shift :
2003-03-02 01:43:33 +00:00
case glow_blink :
2003-02-18 23:15:38 +00:00
case glow_shift :
2003-03-05 02:52:40 +00:00
case rainbow :
2003-03-02 01:43:33 +00:00
case wag :
case bounce :
case bob :
2003-03-05 02:52:40 +00:00
case pulse :
2003-02-17 12:19:42 +00:00
m_fSecsIntoEffect += fDeltaTime ;
while ( m_fSecsIntoEffect >= m_fEffectPeriodSeconds )
m_fSecsIntoEffect -= m_fEffectPeriodSeconds ;
2001-11-28 20:26:45 +00:00
break ;
2003-03-02 01:43:33 +00:00
case spin :
2003-03-05 02:52:40 +00:00
m_current . rotation += fDeltaTime * m_vEffectMagnitude ;
2003-04-21 02:35:16 +00:00
if ( m_current . rotation . x > 360 ) m_current . rotation . x -= 360 ;
if ( m_current . rotation . y > 360 ) m_current . rotation . y -= 360 ;
if ( m_current . rotation . z > 360 ) m_current . rotation . z -= 360 ;
if ( m_current . rotation . x < - 360 ) m_current . rotation . x += 360 ;
if ( m_current . rotation . y < - 360 ) m_current . rotation . y += 360 ;
if ( m_current . rotation . z < - 360 ) m_current . rotation . z += 360 ;
2001-11-28 20:26:45 +00:00
break ;
2003-03-02 01:43:33 +00:00
case vibrate :
2001-11-28 20:26:45 +00:00
break ;
}
2002-09-04 21:53:43 +00:00
UpdateTweening ( fDeltaTime );
2003-01-19 04:44:22 +00:00
if ( m_bFirstUpdate )
m_bFirstUpdate = false ;
2003-05-11 22:19:40 +00:00
2001-11-03 10:52:42 +00:00
}
2001-11-28 20:26:45 +00:00
void Actor :: BeginTweening ( float time , TweenType tt )
2002-01-16 10:01:32 +00:00
{
2002-04-16 17:31:00 +00:00
ASSERT ( time >= 0 );
2002-01-16 10:01:32 +00:00
2003-03-09 00:55:49 +00:00
time = max ( time , 0 );
2003-02-25 02:51:04 +00:00
ASSERT ( m_TweenStates . size () < 50 ); // there's no reason for the number of tweens to ever go this large
2002-11-11 04:53:31 +00:00
2002-03-09 06:19:40 +00:00
// add a new TweenState to the tail, and initialize it
2003-02-25 02:51:04 +00:00
m_TweenStates . resize ( m_TweenStates . size () + 1 );
m_TweenInfo . resize ( m_TweenInfo . size () + 1 );
2002-01-16 10:01:32 +00:00
2003-03-05 23:35:43 +00:00
ASSERT ( m_TweenStates . size () == m_TweenInfo . size () );
2003-02-25 02:51:04 +00:00
TweenState & TS = m_TweenStates . back (); // latest
TweenInfo & TI = m_TweenInfo . back (); // latest
if ( m_TweenStates . size () >= 2 ) // if there was already a TS on the stack
2002-03-09 06:19:40 +00:00
{
// initialize the new TS from the last TS in the list
2003-02-25 02:51:04 +00:00
TS = m_TweenStates [ m_TweenStates . size () - 2 ];
2002-03-09 06:19:40 +00:00
}
else
{
// This new TS is the only TS.
// Set our tween starting and ending values to the current position.
2002-09-02 21:59:58 +00:00
TS = m_current ;
2002-03-09 06:19:40 +00:00
}
2002-01-16 10:01:32 +00:00
2002-09-02 21:59:58 +00:00
TI . m_TweenType = tt ;
TI . m_fTweenTime = time ;
TI . m_fTimeLeftInTween = time ;
2002-01-16 10:01:32 +00:00
}
2002-05-28 20:01:22 +00:00
void Actor :: StopTweening ()
{
2003-02-25 02:51:04 +00:00
m_TweenStates . clear ();
m_TweenInfo . clear ();
2003-03-02 01:43:33 +00:00
ASSERT ( m_TweenStates . empty () );
ASSERT ( m_TweenInfo . empty () );
2002-05-28 20:01:22 +00:00
}
2001-11-03 10:52:42 +00:00
2002-11-01 20:01:59 +00:00
void Actor :: ScaleTo ( const RectI & rect , StretchType st )
2001-11-03 10:52:42 +00:00
{
// width and height of rectangle
2002-12-17 06:25:03 +00:00
float rect_width = ( float ) rect . GetWidth ();
float rect_height = ( float ) rect . GetHeight ();
2001-11-03 10:52:42 +00:00
2003-04-02 06:02:55 +00:00
if ( rect_width < 0 ) SetRotationY ( 180 );
if ( rect_height < 0 ) SetRotationX ( 180 );
2001-11-25 10:49:31 +00:00
2001-11-03 10:52:42 +00:00
// center of the rectangle
2002-11-01 20:01:59 +00:00
float rect_cx = rect . left + rect_width / 2 ;
float rect_cy = rect . top + rect_height / 2 ;
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
// zoom fActor needed to scale the Actor to fill the rectangle
2002-02-24 01:43:11 +00:00
float fNewZoomX = fabsf ( rect_width / m_size . x );
float fNewZoomY = fabsf ( rect_height / m_size . y );
2001-11-03 10:52:42 +00:00
2002-09-07 10:11:00 +00:00
float fNewZoom = 0.f ;
2001-11-03 10:52:42 +00:00
switch ( st )
{
case cover :
fNewZoom = fNewZoomX > fNewZoomY ? fNewZoomX : fNewZoomY ; // use larger zoom
break ;
case fit_inside :
fNewZoom = fNewZoomX > fNewZoomY ? fNewZoomY : fNewZoomX ; // use smaller zoom
break ;
}
2001-11-25 04:31:44 +00:00
SetXY ( rect_cx , rect_cy );
2001-11-03 10:52:42 +00:00
SetZoom ( fNewZoom );
}
2003-04-02 05:41:22 +00:00
void Actor :: SetHorizAlign ( CString s )
{
s . MakeLower ();
if ( s == "left" ) m_HorizAlign = align_left ;
else if ( s == "center" ) m_HorizAlign = align_center ;
else if ( s == "right" ) m_HorizAlign = align_right ;
else ASSERT ( 0 );
}
void Actor :: SetVertAlign ( CString s )
{
s . MakeLower ();
if ( s == "top" ) m_VertAlign = align_top ;
else if ( s == "middle" ) m_VertAlign = align_middle ;
else if ( s == "bottom" ) m_VertAlign = align_bottom ;
else ASSERT ( 0 );
}
2003-02-19 07:59:00 +00:00
void Actor :: StretchTo ( const RectI & r )
{
RectF r2 ( ( float ) r . left , ( float ) r . top , ( float ) r . right , ( float ) r . bottom );
StretchTo ( r2 );
}
2001-11-03 10:52:42 +00:00
2003-02-19 07:59:00 +00:00
void Actor :: StretchTo ( const RectF & r )
2001-11-03 10:52:42 +00:00
{
// width and height of rectangle
2003-02-19 07:59:00 +00:00
float width = r . GetWidth ();
float height = r . GetHeight ();
2001-11-03 10:52:42 +00:00
// center of the rectangle
2003-02-19 07:59:00 +00:00
float cx = r . left + width / 2.0f ;
float cy = r . top + height / 2.0f ;
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
// zoom fActor needed to scale the Actor to fill the rectangle
2003-02-19 07:59:00 +00:00
float fNewZoomX = width / m_size . x ;
float fNewZoomY = height / m_size . y ;
2001-11-03 10:52:42 +00:00
2003-02-19 07:59:00 +00:00
SetXY ( cx , cy );
2002-01-16 10:01:32 +00:00
SetZoomX ( fNewZoomX );
SetZoomY ( fNewZoomY );
2001-11-03 10:52:42 +00:00
}
2001-11-28 20:26:45 +00:00
2003-03-02 01:43:33 +00:00
// effect "macros"
2001-11-28 20:26:45 +00:00
2003-03-02 01:43:33 +00:00
void Actor :: SetEffectDiffuseBlink ( float fEffectPeriodSeconds , RageColor c1 , RageColor c2 )
2001-11-28 20:26:45 +00:00
{
2003-03-24 21:37:13 +00:00
if ( m_Effect != diffuse_blink )
{
m_Effect = diffuse_blink ;
m_fEffectPeriodSeconds = fEffectPeriodSeconds ;
m_fSecsIntoEffect = 0 ;
}
2003-02-17 12:19:42 +00:00
m_effectColor1 = c1 ;
m_effectColor2 = c2 ;
2001-11-28 20:26:45 +00:00
}
2003-02-18 23:15:38 +00:00
void Actor :: SetEffectDiffuseShift ( float fEffectPeriodSeconds , RageColor c1 , RageColor c2 )
2001-11-28 20:26:45 +00:00
{
2003-03-24 21:37:13 +00:00
if ( m_Effect != diffuse_shift )
{
m_Effect = diffuse_shift ;
m_fEffectPeriodSeconds = fEffectPeriodSeconds ;
m_fSecsIntoEffect = 0 ;
}
2003-02-17 12:19:42 +00:00
m_effectColor1 = c1 ;
m_effectColor2 = c2 ;
2001-11-28 20:26:45 +00:00
}
2003-03-02 01:43:33 +00:00
void Actor :: SetEffectGlowBlink ( float fEffectPeriodSeconds , RageColor c1 , RageColor c2 )
2001-11-28 20:26:45 +00:00
{
2003-03-24 21:37:13 +00:00
if ( m_Effect != glow_blink )
{
m_Effect = glow_blink ;
m_fEffectPeriodSeconds = fEffectPeriodSeconds ;
m_fSecsIntoEffect = 0 ;
}
2003-02-17 12:19:42 +00:00
m_effectColor1 = c1 ;
m_effectColor2 = c2 ;
}
2002-01-16 10:01:32 +00:00
2003-02-18 23:15:38 +00:00
void Actor :: SetEffectGlowShift ( float fEffectPeriodSeconds , RageColor c1 , RageColor c2 )
2003-02-17 12:19:42 +00:00
{
2003-03-24 21:37:13 +00:00
if ( m_Effect != glow_shift )
{
m_Effect = glow_shift ;
m_fEffectPeriodSeconds = fEffectPeriodSeconds ;
m_fSecsIntoEffect = 0 ;
}
2003-02-17 12:19:42 +00:00
m_effectColor1 = c1 ;
m_effectColor2 = c2 ;
2001-11-28 20:26:45 +00:00
}
2003-03-05 02:52:40 +00:00
void Actor :: SetEffectRainbow ( float fEffectPeriodSeconds )
{
m_Effect = rainbow ;
m_fEffectPeriodSeconds = fEffectPeriodSeconds ;
m_fSecsIntoEffect = 0 ;
}
2003-03-02 01:43:33 +00:00
void Actor :: SetEffectWag ( float fPeriod , RageVector3 vect )
2001-11-28 20:26:45 +00:00
{
2003-03-02 01:43:33 +00:00
m_Effect = wag ;
2003-02-17 12:19:42 +00:00
m_fEffectPeriodSeconds = fPeriod ;
2003-03-02 01:43:33 +00:00
m_vEffectMagnitude = vect ;
2003-02-17 12:19:42 +00:00
m_fSecsIntoEffect = 0 ;
2002-07-27 19:29:51 +00:00
}
2003-03-02 01:43:33 +00:00
void Actor :: SetEffectBounce ( float fPeriod , RageVector3 vect )
2002-07-27 19:29:51 +00:00
{
2003-03-02 01:43:33 +00:00
m_Effect = bounce ;
2003-02-17 12:19:42 +00:00
m_fEffectPeriodSeconds = fPeriod ;
2003-03-02 01:43:33 +00:00
m_vEffectMagnitude = vect ;
2003-02-17 12:19:42 +00:00
m_fSecsIntoEffect = 0 ;
2002-09-02 21:59:58 +00:00
}
2003-03-02 01:43:33 +00:00
void Actor :: SetEffectBob ( float fPeriod , RageVector3 vect )
2002-09-02 21:59:58 +00:00
{
2003-04-21 22:26:07 +00:00
if ( m_Effect != bob || m_fEffectPeriodSeconds != fPeriod )
{
m_Effect = bob ;
m_fEffectPeriodSeconds = fPeriod ;
m_fSecsIntoEffect = 0 ;
}
2003-03-02 01:43:33 +00:00
m_vEffectMagnitude = vect ;
2002-09-02 21:59:58 +00:00
}
2003-03-02 01:43:33 +00:00
void Actor :: SetEffectSpin ( RageVector3 vect )
{
m_Effect = spin ;
m_vEffectMagnitude = vect ;
}
void Actor :: SetEffectVibrate ( RageVector3 vect )
{
m_Effect = vibrate ;
m_vEffectMagnitude = vect ;
}
2002-09-02 21:59:58 +00:00
2003-03-05 02:52:40 +00:00
void Actor :: SetEffectPulse ( float fPeriod , float fMinZoom , float fMaxZoom )
{
m_Effect = pulse ;
m_fEffectPeriodSeconds = fPeriod ;
m_vEffectMagnitude [ 0 ] = fMinZoom ;
m_vEffectMagnitude [ 1 ] = fMaxZoom ;
}
2002-09-02 21:59:58 +00:00
2003-04-02 05:41:22 +00:00
void Actor :: SetShadowLength ( float fLength )
{
if ( fLength == 0 )
m_bShadow = false ;
else
{
m_fShadowLength = fLength ;
m_bShadow = true ;
}
}
2003-02-24 00:47:13 +00:00
void Actor :: Fade ( float fSleepSeconds , CString sFadeString , float fFadeSeconds , bool bFadingOff )
2002-09-02 21:59:58 +00:00
{
sFadeString . MakeLower ();
2003-03-02 01:43:33 +00:00
sFadeString . Replace ( ' ' , ',' );
2002-09-02 21:59:58 +00:00
TweenState original = m_current ;
TweenState mod = m_current ;
2003-02-23 23:29:22 +00:00
CStringArray asBits ;
2003-03-02 01:43:33 +00:00
split ( sFadeString , "," , asBits );
2003-02-23 23:29:22 +00:00
#define CONTAINS(needle) (find( asBits.begin(), asBits.end(), needle ) != asBits.end())
2002-09-02 21:59:58 +00:00
TweenType tt ;
if ( CONTAINS ( "linear" ) ) tt = TWEEN_LINEAR ;
2003-03-02 01:43:33 +00:00
else if ( CONTAINS ( "accelerate" ) ) tt = bFadingOff ? TWEEN_ACCELERATE : TWEEN_DECELERATE ;
2003-02-24 00:47:13 +00:00
else if ( CONTAINS ( "bounce" ) ) tt = bFadingOff ? TWEEN_BOUNCE_BEGIN : TWEEN_BOUNCE_END ;
2002-09-02 21:59:58 +00:00
else if ( CONTAINS ( "spring" ) ) tt = TWEEN_SPRING ;
else tt = TWEEN_LINEAR ;
2003-01-26 20:49:05 +00:00
float fDeltaX = ( float )( CONTAINS ( "left" ) ?- SCREEN_WIDTH : 0 ) + ( CONTAINS ( "right" ) ?+ SCREEN_HEIGHT : 0 );
float fDeltaY = ( float )( CONTAINS ( "top" ) ?- SCREEN_WIDTH : 0 ) + ( CONTAINS ( "bottom" ) ?+ SCREEN_HEIGHT : 0 );
float fDeltaZ = ( float ) 0 ;
if ( CONTAINS ( "far" ) )
{
fDeltaX *= 2 ;
fDeltaY *= 2 ;
fDeltaZ *= 2 ;
}
mod . pos . x += fDeltaX ;
mod . pos . y += fDeltaY ;
mod . pos . z += fDeltaZ ;
2003-04-21 02:35:16 +00:00
mod . rotation . x += ( CONTAINS ( "spinx" ) ?- 360 : 0 );
mod . rotation . y += ( CONTAINS ( "spiny" ) ?- 360 : 0 );
mod . rotation . z += ( CONTAINS ( "spinz" ) ?- 360 : 0 );
2003-02-23 23:29:22 +00:00
mod . scale . x *= ( CONTAINS ( "foldx" ) ? 0 : 1 ) * ( CONTAINS ( "zoomx" ) || CONTAINS ( "zoom" ) ? 3 : 1 );
mod . scale . y *= ( CONTAINS ( "foldy" ) ? 0 : 1 ) * ( CONTAINS ( "zoomy" ) || CONTAINS ( "zoom" ) ? 3 : 1 );
2002-09-02 21:59:58 +00:00
for ( int i = 0 ; i < 4 ; i ++ )
{
mod . diffuse [ i ] = GetDiffuse ();
mod . diffuse [ i ]. a *= CONTAINS ( "fade" ) ? 0 : 1 ;
}
mod . glow = GetGlow ();
mod . glow . a *= CONTAINS ( "glow" ) ? 1 : 0 ;
2003-03-02 01:43:33 +00:00
TweenState & start = bFadingOff ? original : mod ;
TweenState & end = bFadingOff ? mod : original ;
// apply tweens
2003-01-26 20:49:05 +00:00
StopTweening ();
2003-03-02 01:43:33 +00:00
if ( CONTAINS ( "ghost" ) )
{
// start with no glow, no alpha
start . glow . a = 0 ;
2003-03-05 23:35:43 +00:00
int i ;
for ( i = 0 ; i < 4 ; i ++ )
2003-03-02 01:43:33 +00:00
start . diffuse [ i ]. a = 0 ;
m_current = start ;
TweenState mid ;
TweenState :: MakeWeightedAverage ( mid , start , end , 0.5 );
// tween to full glow, no alpha
mid . glow . a = 1 ;
for ( i = 0 ; i < 4 ; i ++ )
mid . diffuse [ i ]. a = 0 ;
BeginTweening ( fFadeSeconds / 2 , tt );
LatestTween () = mid ;
// snap to full alpha
for ( i = 0 ; i < 4 ; i ++ )
mid . diffuse [ i ]. a = 1 ;
BeginTweening ( 0.0001f , tt );
LatestTween () = mid ;
// tween to no glow
mid . glow . a = 0 ;
BeginTweening ( fFadeSeconds / 2 , tt );
LatestTween () = mid ;
}
else
{
m_current = start ;
BeginTweening ( fSleepSeconds );
BeginTweening ( fFadeSeconds , tt );
LatestTween () = end ;
}
2002-09-02 21:59:58 +00:00
}
2003-04-02 21:58:56 +00:00
static CString GetParam ( const CStringArray & sParams , int iIndex , int & iMaxIndexAccessed )
2003-03-24 21:37:13 +00:00
{
iMaxIndexAccessed = max ( iIndex , iMaxIndexAccessed );
2003-03-25 01:38:05 +00:00
if ( iIndex < int ( sParams . size ()) )
2003-03-24 21:37:13 +00:00
return sParams [ iIndex ];
else
return "" ;
}
2003-04-14 22:01:57 +00:00
void Actor :: AddRotationH ( float rot )
{
RageQuatMultiply ( & DestTweenState (). quat , DestTweenState (). quat , RageQuatFromH ( rot ) );
}
void Actor :: AddRotationP ( float rot )
{
RageQuatMultiply ( & DestTweenState (). quat , DestTweenState (). quat , RageQuatFromP ( rot ) );
}
void Actor :: AddRotationR ( float rot )
{
RageQuatMultiply ( & DestTweenState (). quat , DestTweenState (). quat , RageQuatFromR ( rot ) );
}
2003-03-02 01:43:33 +00:00
void Actor :: Command ( CString sCommandString )
{
2003-03-24 21:37:13 +00:00
// OPTIMIZATION OPPORTUNITY: sCommandString could be parsed more efficiently.
2003-03-02 01:43:33 +00:00
CStringArray asCommands ;
split ( sCommandString , ";" , asCommands , true );
for ( unsigned c = 0 ; c < asCommands . size (); c ++ )
{
CStringArray asTokens ;
split ( asCommands [ c ], "," , asTokens , true );
2003-05-07 04:03:46 +00:00
for ( unsigned d = 0 ; d < asTokens . size (); d ++ )
{
TrimLeft ( asTokens [ d ]); TrimRight ( asTokens [ d ]);
}
2003-03-24 21:37:13 +00:00
int iMaxIndexAccessed = 0 ;
2003-03-02 01:43:33 +00:00
2003-03-24 21:37:13 +00:00
#define sParam(i) (GetParam(asTokens,i,iMaxIndexAccessed))
2003-03-02 01:43:33 +00:00
#define fParam(i) ((float)atof(sParam(i)))
#define iParam(i) (atoi(sParam(i)))
#define bParam(i) (iParam(i)!=0)
2003-03-24 21:37:13 +00:00
CString & sName = asTokens [ 0 ];
sName . MakeLower ();
2003-05-08 22:07:24 +00:00
if ( sName . size () == 0 )
continue ;
2003-05-11 22:19:40 +00:00
2003-04-22 22:11:18 +00:00
// Commands that go in the tweening queue:
2003-03-24 21:37:13 +00:00
if ( sName == "sleep" ) BeginTweening ( fParam ( 1 ), TWEEN_LINEAR );
else if ( sName == "linear" ) BeginTweening ( fParam ( 1 ), TWEEN_LINEAR );
else if ( sName == "accelerate" ) BeginTweening ( fParam ( 1 ), TWEEN_ACCELERATE );
else if ( sName == "decelerate" ) BeginTweening ( fParam ( 1 ), TWEEN_DECELERATE );
else if ( sName == "bouncebegin" ) BeginTweening ( fParam ( 1 ), TWEEN_BOUNCE_BEGIN );
else if ( sName == "bounceend" ) BeginTweening ( fParam ( 1 ), TWEEN_BOUNCE_END );
else if ( sName == "spring" ) BeginTweening ( fParam ( 1 ), TWEEN_SPRING );
2003-03-02 01:43:33 +00:00
else if ( sName == "stoptweening" ) { StopTweening (); BeginTweening ( 0.0001f , TWEEN_LINEAR ); }
2003-03-24 21:37:13 +00:00
else if ( sName == "x" ) SetX ( fParam ( 1 ) );
else if ( sName == "y" ) SetY ( fParam ( 1 ) );
2003-04-02 18:15:35 +00:00
else if ( sName == "z" ) SetZ ( fParam ( 1 ) );
2003-04-11 21:51:28 +00:00
else if ( sName == "addx" ) SetX ( GetX () + fParam ( 1 ) );
else if ( sName == "addy" ) SetY ( GetY () + fParam ( 1 ) );
else if ( sName == "addz" ) SetZ ( GetZ () + fParam ( 1 ) );
2003-03-24 21:37:13 +00:00
else if ( sName == "zoom" ) SetZoom ( fParam ( 1 ) );
else if ( sName == "zoomx" ) SetZoomX ( fParam ( 1 ) );
else if ( sName == "zoomy" ) SetZoomY ( fParam ( 1 ) );
2003-04-02 18:15:35 +00:00
// else if( sName=="zoomz" ) SetZoomZ( fParam(1) );
2003-03-24 21:37:13 +00:00
else if ( sName == "zoomtowidth" ) ZoomToWidth ( fParam ( 1 ) );
else if ( sName == "zoomtoheight" ) ZoomToHeight ( fParam ( 1 ) );
else if ( sName == "diffuse" ) SetDiffuse ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
else if ( sName == "diffuseleftedge" ) SetDiffuseLeftEdge ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
else if ( sName == "diffuserightedge" ) SetDiffuseRightEdge ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
else if ( sName == "diffusetopedge" ) SetDiffuseTopEdge ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
else if ( sName == "diffusebottomedge" ) SetDiffuseBottomEdge ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
2003-03-19 21:02:50 +00:00
/* Add left/right/top/bottom for alpha if needed. */
2003-03-24 21:43:15 +00:00
else if ( sName == "diffusealpha" ) { for ( int i = 0 ; i < 4 ; ++ i ) { RageColor c = GetDiffuses ( i ); c . a = fParam ( 1 ); SetDiffuses ( i , c ); } }
2003-03-24 21:37:13 +00:00
else if ( sName == "glow" ) SetGlow ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
2003-05-04 22:35:42 +00:00
else if ( sName == "glowmode" ) {
if ( ! sParam ( 1 ). CompareNoCase ( "whiten" ))
SetGlowMode ( GLOW_WHITEN );
else if ( ! sParam ( 1 ). CompareNoCase ( "brighten" ))
SetGlowMode ( GLOW_BRIGHTEN );
else ASSERT ( 0 );
}
2003-03-24 21:37:13 +00:00
else if ( sName == "rotationx" ) SetRotationX ( fParam ( 1 ) );
else if ( sName == "rotationy" ) SetRotationY ( fParam ( 1 ) );
else if ( sName == "rotationz" ) SetRotationZ ( fParam ( 1 ) );
2003-04-14 22:01:57 +00:00
else if ( sName == "heading" ) AddRotationH ( fParam ( 1 ) );
else if ( sName == "pitch" ) AddRotationP ( fParam ( 1 ) );
else if ( sName == "roll" ) AddRotationR ( fParam ( 1 ) );
2003-03-24 21:37:13 +00:00
else if ( sName == "shadowlength" ) SetShadowLength ( fParam ( 1 ) );
else if ( sName == "horizalign" ) SetHorizAlign ( sParam ( 1 ) );
else if ( sName == "vertalign" ) SetVertAlign ( sParam ( 1 ) );
2003-03-02 01:43:33 +00:00
else if ( sName == "diffuseblink" ) SetEffectDiffuseBlink ();
else if ( sName == "diffuseshift" ) SetEffectDiffuseShift ();
else if ( sName == "glowblink" ) SetEffectGlowBlink ();
else if ( sName == "glowshift" ) SetEffectGlowShift ();
2003-03-05 02:52:40 +00:00
else if ( sName == "rainbow" ) SetEffectRainbow ();
2003-03-02 01:43:33 +00:00
else if ( sName == "wag" ) SetEffectWag ();
else if ( sName == "bounce" ) SetEffectBounce ();
else if ( sName == "bob" ) SetEffectBob ();
2003-03-05 02:52:40 +00:00
else if ( sName == "pulse" ) SetEffectPulse ();
2003-03-02 01:43:33 +00:00
else if ( sName == "spin" ) SetEffectSpin ();
else if ( sName == "vibrate" ) SetEffectVibrate ();
else if ( sName == "stopeffect" ) SetEffectNone ();
2003-03-24 21:37:13 +00:00
else if ( sName == "effectcolor1" ) SetEffectColor1 ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
else if ( sName == "effectcolor2" ) SetEffectColor2 ( RageColor ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 ), fParam ( 4 )) );
else if ( sName == "effectperiod" ) SetEffectPeriod ( fParam ( 1 ) );
else if ( sName == "effectmagnitude" ) SetEffectMagnitude ( RageVector3 ( fParam ( 1 ), fParam ( 2 ), fParam ( 3 )) );
2003-04-22 22:25:07 +00:00
else if ( sName == "scaletocover" ) { RectI R ( iParam ( 1 ), iParam ( 2 ), iParam ( 3 ), iParam ( 4 )); ScaleToCover ( R ); }
2003-04-22 22:11:18 +00:00
// Commands that take effect immediately (ignoring the tweening queue):
2003-03-24 21:37:13 +00:00
else if ( sName == "animate" ) EnableAnimation ( bParam ( 1 ) );
2003-05-15 06:09:19 +00:00
else if ( sName == "texturewrapping" ) SetTextureWrapping ( bParam ( 1 ) );
else if ( sName == "additiveblend" ) SetBlendMode ( bParam ( 1 ) ? BLEND_ADD : BLEND_NORMAL );
2003-03-02 01:43:33 +00:00
else
{
2003-04-25 00:01:35 +00:00
CString sError = ssprintf ( "Unrecognized command name '%s' in command string '%s'." , sName . c_str (), sCommandString . c_str () );
2003-03-09 00:55:49 +00:00
LOG -> Warn ( sError );
#if defined(WIN32) // XXX arch?
if ( DISPLAY -> IsWindowed () )
MessageBox ( NULL , sError , "Actor::Command" , MB_OK );
#endif
2003-03-24 21:37:13 +00:00
}
2003-03-09 00:55:49 +00:00
2003-03-24 21:37:13 +00:00
if ( iMaxIndexAccessed != ( int ) asTokens . size () - 1 )
{
2003-04-25 00:01:35 +00:00
CString sError = ssprintf ( "Wrong number of parameters in command '%s'. Expected %d but there are %d." , join ( "," , asTokens ). c_str (), iMaxIndexAccessed + 1 , ( int ) asTokens . size () );
2003-03-24 21:37:13 +00:00
LOG -> Warn ( sError );
#if defined(WIN32) // XXX arch?
if ( DISPLAY -> IsWindowed () )
MessageBox ( NULL , sError , "Actor::Command" , MB_OK );
#endif
2003-03-02 01:43:33 +00:00
}
}
}
2003-03-19 19:56:27 +00:00
float Actor :: GetCommandLength ( CString command )
{
2003-03-28 00:49:01 +00:00
Actor temp ;
2003-03-19 19:56:27 +00:00
temp . Command ( command );
2003-03-28 00:49:01 +00:00
2003-03-19 19:56:27 +00:00
return temp . GetTweenTimeLeft ();
}
2003-03-02 01:43:33 +00:00
float Actor :: GetTweenTimeLeft () const
2003-01-01 09:05:21 +00:00
{
float tot = 0 ;
2003-02-25 02:51:04 +00:00
for ( unsigned i = 0 ; i < m_TweenInfo . size (); ++ i )
2003-01-01 09:05:21 +00:00
tot += m_TweenInfo [ i ]. m_fTimeLeftInTween ;
return tot ;
}
2003-04-02 05:41:22 +00:00
void Actor :: TweenState :: Init ()
{
pos = RageVector3 ( 0 , 0 , 0 );
rotation = RageVector3 ( 0 , 0 , 0 );
2003-04-14 22:01:57 +00:00
quat = RageVector4 ( 0 , 0 , 0 , 1 );
2003-04-02 05:41:22 +00:00
scale = RageVector3 ( 1 , 1 , 1 );
for ( int i = 0 ; i < 4 ; i ++ )
diffuse [ i ] = RageColor ( 1 , 1 , 1 , 1 );
glow = RageColor ( 1 , 1 , 1 , 0 );
2003-05-04 22:35:42 +00:00
glowmode = GLOW_WHITEN ;
2003-04-02 05:41:22 +00:00
}
void Actor :: TweenState :: MakeWeightedAverage ( TweenState & average_out , const TweenState & ts1 , const TweenState & ts2 , float fPercentBetween )
{
average_out . pos = ts1 . pos + ( ts2 . pos - ts1 . pos ) * fPercentBetween ;
average_out . scale = ts1 . scale + ( ts2 . scale - ts1 . scale ) * fPercentBetween ;
average_out . rotation = ts1 . rotation + ( ts2 . rotation - ts1 . rotation ) * fPercentBetween ;
2003-04-14 22:01:57 +00:00
RageQuatSlerp ( & average_out . quat , ts1 . quat , ts2 . quat , fPercentBetween );
2003-04-02 05:41:22 +00:00
for ( int i = 0 ; i < 4 ; i ++ )
average_out . diffuse [ i ] = ts1 . diffuse [ i ] + ( ts2 . diffuse [ i ] - ts1 . diffuse [ i ]) * fPercentBetween ;
average_out . glow = ts1 . glow + ( ts2 . glow - ts1 . glow ) * fPercentBetween ;
}