Files
itgmania212121/stepmania/src/Actor.cpp
T

953 lines
28 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h" // testing updates
2003-07-07 18:22:36 +00:00
/*
-----------------------------------------------------------------------------
2002-05-19 01:59:48 +00:00
Class: Actor
2002-05-19 01:59:48 +00:00
Desc: See header.
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-03 10:52:42 +00:00
#include "Actor.h"
#include <math.h>
2002-05-19 01:59:48 +00:00
#include "RageDisplay.h"
#include "PrefsManager.h"
#include "RageUtil.h"
#include "RageMath.h"
#include "GameConstantsAndTypes.h"
2003-03-02 01:43:33 +00:00
#include "RageLog.h"
#include "arch/ArchHooks/ArchHooks.h"
2001-11-03 10:52:42 +00:00
2003-12-18 10:31:42 +00:00
#include "GameState.h" /* XXX: ugly dependency */
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-10-07 04:26:14 +00:00
m_pTempState = NULL;
m_baseRotation = RageVector3( 0, 0, 0 );
m_baseScale = RageVector3( 1, 1, 1 );
m_start.Init();
m_current.Init();
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;
2004-01-20 23:25:38 +00:00
m_fEffectDelay = 0;
m_fEffectOffset = 0;
2003-12-18 10:31:42 +00:00
m_EffectClock = CLOCK_TIMER;
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);
m_bHidden = false;
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;
m_bTextureWrapping = false;
m_BlendMode = BLEND_NORMAL;
2003-07-07 20:24:51 +00:00
m_bClearZBuffer = false;
2003-11-18 20:33:18 +00:00
m_bZTest = false;
m_bZWrite = false;
m_bUseBackfaceCull = false;
2001-11-03 10:52:42 +00:00
}
2003-04-02 05:41:22 +00:00
Actor::Actor()
{
2003-10-22 09:44:27 +00:00
m_size = RageVector2( 1, 1 );
2003-04-02 05:41:22 +00:00
Reset();
m_bFirstUpdate = true;
}
2002-08-19 20:02:30 +00:00
void Actor::Draw()
{
if( m_bHidden )
return; // early abort
2002-08-19 20:02:30 +00:00
// 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
//
// set temporary drawing properties based on Effects
//
2003-10-07 04:26:14 +00:00
if( m_Effect == no_effect )
2001-11-28 20:26:45 +00:00
{
2003-10-07 04:26:14 +00:00
m_pTempState = &m_current;
2001-11-28 20:26:45 +00:00
}
2003-10-07 04:26:14 +00:00
else
{
m_pTempState = &m_tempState;
m_tempState = m_current;
2004-01-20 23:25:38 +00:00
/* EffectPeriodSeconds is the total time of the effect (including delay).
* m_fEffectDelay is the amount of time to stick on 0%. Offset shifts the
* entire thing forwards. For example, if m_fEffectPeriodSeconds is 1,
* the effect can happen from .40 to .55 by setting offset to .40 and
* delay to .85. */
const float fTotalPeriod = m_fEffectPeriodSeconds + m_fEffectDelay;
const float fSecsIntoPeriod = fmodfp( m_fSecsIntoEffect+m_fEffectOffset, fTotalPeriod );
2003-12-18 10:31:42 +00:00
2004-01-20 23:25:38 +00:00
float fPercentThroughEffect = SCALE( fSecsIntoPeriod, 0, m_fEffectPeriodSeconds, 0, 1 );
fPercentThroughEffect = clamp( fPercentThroughEffect, 0, 1 );
bool bBlinkOn = fPercentThroughEffect > 0.5f;
2004-01-10 02:56:04 +00:00
float fPercentBetweenColors = sinf( (fPercentThroughEffect + 0.25f) * 2 * PI ) / 2 + 0.5f;
2003-10-07 04:26:14 +00:00
ASSERT( fPercentBetweenColors >= 0 && fPercentBetweenColors <= 1 );
float fOriginalAlpha = m_tempState.diffuse[0].a;
2001-11-28 20:26:45 +00:00
2003-10-07 04:26:14 +00:00
int i;
2003-10-07 04:26:14 +00:00
switch( m_Effect )
{
case diffuse_blink:
/* XXX: Should diffuse_blink and diffuse_shift multiply the tempState color?
* (That would have the same effect with 1,1,1,1, and allow tweening the diffuse
* while blinking and shifting.) */
2003-10-07 04:26:14 +00:00
for(i=0; i<4; i++)
m_tempState.diffuse[i] = bBlinkOn ? m_effectColor1 : m_effectColor2;
break;
case diffuse_shift:
for(i=0; i<4; i++)
m_tempState.diffuse[i] = m_effectColor1*fPercentBetweenColors + m_effectColor2*(1.0f-fPercentBetweenColors);
break;
case glow_blink:
m_tempState.glow = bBlinkOn ? m_effectColor1 : m_effectColor2;
m_tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent!
break;
case glow_shift:
m_tempState.glow = m_effectColor1*fPercentBetweenColors + m_effectColor2*(1.0f-fPercentBetweenColors);
m_tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent!
break;
case rainbow:
m_tempState.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_tempState.diffuse[i] = m_tempState.diffuse[0];
break;
case wag:
m_tempState.rotation += m_vEffectMagnitude * sinf( fPercentThroughEffect * 2.0f * PI );
2003-10-07 04:26:14 +00:00
break;
case spin:
// nothing needs to be here
break;
case vibrate:
m_tempState.pos.x += m_vEffectMagnitude.x * randomf(-1.0f, 1.0f) * GetZoom();
m_tempState.pos.y += m_vEffectMagnitude.y * randomf(-1.0f, 1.0f) * GetZoom();
m_tempState.pos.z += m_vEffectMagnitude.z * randomf(-1.0f, 1.0f) * GetZoom();
break;
case bounce:
{
float fPercentOffset = sinf( fPercentThroughEffect*PI );
m_tempState.pos += m_vEffectMagnitude * fPercentOffset;
m_tempState.pos.x = roundf( m_tempState.pos.x );
m_tempState.pos.y = roundf( m_tempState.pos.y );
m_tempState.pos.z = roundf( m_tempState.pos.z );
}
break;
case bob:
{
float fPercentOffset = sinf( fPercentThroughEffect*PI*2 );
m_tempState.pos += m_vEffectMagnitude * fPercentOffset;
m_tempState.pos.x = roundf( m_tempState.pos.x );
m_tempState.pos.y = roundf( m_tempState.pos.y );
m_tempState.pos.z = roundf( m_tempState.pos.z );
}
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_tempState.scale *= fZoom;
2003-10-07 04:26:14 +00:00
}
break;
default:
ASSERT(0); // invalid Effect
}
}
2002-01-16 10:01:32 +00:00
2003-10-07 04:26:14 +00:00
DISPLAY->Translate(
m_pTempState->pos.x,
m_pTempState->pos.y,
m_pTempState->pos.z );
DISPLAY->Scale(
m_pTempState->scale.x * m_baseScale.x,
m_pTempState->scale.y * m_baseScale.y,
m_pTempState->scale.z * m_baseScale.z );
2002-01-16 10:01:32 +00:00
/* The only time rotation and quat should normally be used simultaneously
* is for m_baseRotation. */
2003-10-07 04:26:14 +00:00
if( m_pTempState->rotation.x + m_baseRotation.x != 0 )
DISPLAY->RotateX( m_pTempState->rotation.x + m_baseRotation.x );
if( m_pTempState->rotation.y + m_baseRotation.y != 0 )
DISPLAY->RotateY( m_pTempState->rotation.y + m_baseRotation.y );
if( m_pTempState->rotation.z + m_baseRotation.z != 0 )
DISPLAY->RotateZ( m_pTempState->rotation.z + m_baseRotation.z );
if( m_pTempState->quat.x != 0 || m_pTempState->quat.y != 0 || m_pTempState->quat.z != 0 || m_pTempState->quat.w != 1 )
{
RageMatrix mat;
2003-10-07 04:26:14 +00:00
RageMatrixFromQuat( &mat, m_pTempState->quat );
DISPLAY->MultMatrix(mat);
}
2002-08-19 20:02:30 +00:00
}
2002-01-16 10:01:32 +00:00
void Actor::SetRenderStates()
{
// set Actor-defined render states
DISPLAY->SetTextureWrapping( m_bTextureWrapping );
DISPLAY->SetBlendMode( m_BlendMode );
2003-11-18 20:33:18 +00:00
DISPLAY->SetZWrite( m_bZWrite );
DISPLAY->SetZTest( m_bZTest );
2003-07-07 20:24:51 +00:00
if( m_bClearZBuffer )
DISPLAY->ClearZBuffer();
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 )
{
2003-05-16 21:09:26 +00:00
while( 1 )
{
if( m_TweenStates.empty() ) // nothing to do
return;
2002-09-04 21:53:43 +00:00
2003-05-16 21:09:26 +00:00
if( fDeltaTime == 0 ) // nothing will change
return;
2002-09-04 21:53:43 +00:00
2003-05-16 21:09:26 +00:00
// update current tween state
TweenState &TS = m_TweenStates[0]; // earliest tween
TweenInfo &TI = m_TweenInfo[0]; // earliest tween
2002-09-04 21:53:43 +00:00
2003-05-16 21:09:26 +00:00
if( TI.m_fTimeLeftInTween == TI.m_fTweenTime ) // we are just beginning this tween
m_start = m_current; // set the start position
2002-09-04 21:53:43 +00:00
2003-05-16 21:09:26 +00:00
float fSecsToSubtract = min( TI.m_fTimeLeftInTween, fDeltaTime );
TI.m_fTimeLeftInTween -= fSecsToSubtract;
fDeltaTime -= fSecsToSubtract;
if( TI.m_fTimeLeftInTween == 0 ) // Current tween is over. Stop.
2002-09-04 21:53:43 +00:00
{
2003-05-16 21:09:26 +00:00
m_current = TS;
// delete the head tween
m_TweenStates.erase( m_TweenStates.begin() );
m_TweenInfo.erase( m_TweenInfo.begin() );
}
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
float fPercentAlongPath = 0.f;
switch( TI.m_TweenType )
{
case TWEEN_LINEAR: fPercentAlongPath = fPercentThroughTween; break;
case TWEEN_ACCELERATE: fPercentAlongPath = fPercentThroughTween * fPercentThroughTween; break;
case TWEEN_DECELERATE: fPercentAlongPath = 1 - (1-fPercentThroughTween) * (1-fPercentThroughTween); break;
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;
default: ASSERT(0);
}
TweenState::MakeWeightedAverage( m_current, m_start, TS, fPercentAlongPath );
2002-09-04 21:53:43 +00:00
}
}
}
2001-11-28 20:26:45 +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
{
// 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-12-18 10:31:42 +00:00
switch( m_EffectClock )
{
case CLOCK_TIMER:
m_fSecsIntoEffect += fDeltaTime;
2004-01-20 23:25:38 +00:00
m_fSecsIntoEffect = fmodfp( m_fSecsIntoEffect, m_fEffectPeriodSeconds + m_fEffectDelay );
2003-12-18 10:31:42 +00:00
break;
case CLOCK_BGM:
m_fSecsIntoEffect = GAMESTATE->m_fSongBeat;
break;
}
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;
2001-11-03 10:52:42 +00:00
}
2002-01-16 10:01:32 +00:00
void Actor::BeginTweening( float time, TweenType tt )
2001-11-03 10:52:42 +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 );
DEBUG_ASSERT( m_TweenStates.size() < 50 ); // there's no reason for the number of tweens to ever go this large
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 );
2003-03-05 23:35:43 +00:00
ASSERT( m_TweenStates.size() == m_TweenInfo.size() );
2002-01-16 10:01:32 +00:00
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.
TS = m_current;
2002-03-09 06:19:40 +00:00
}
2002-01-16 10:01:32 +00:00
TI.m_TweenType = tt;
TI.m_fTweenTime = time;
TI.m_fTimeLeftInTween = time;
2001-11-03 10:52:42 +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
}
2003-06-16 17:33:28 +00:00
void Actor::FinishTweening()
{
m_current = DestTweenState();
StopTweening();
}
2002-05-28 20:01:22 +00:00
2003-11-18 17:50:50 +00:00
void Actor::HurryTweening( float factor )
{
for( unsigned i = 0; i < m_TweenInfo.size(); ++i )
{
m_TweenInfo[i].m_fTimeLeftInTween *= factor;
m_TweenInfo[i].m_fTweenTime *= factor;
}
}
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
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();
2003-11-05 05:10:19 +00:00
if (s=="left") SetHorizAlign( align_left ); /* call derived */
else if(s=="center") SetHorizAlign( align_center );
else if(s=="right") SetHorizAlign( align_right );
2003-04-02 05:41:22 +00:00
else ASSERT(0);
}
void Actor::SetVertAlign( CString s )
{
s.MakeLower();
2003-11-05 05:10:19 +00:00
if (s=="top") SetVertAlign( align_top ); /* call derived */
else if(s=="middle") SetVertAlign( align_middle );
else if(s=="bottom") SetVertAlign( align_bottom );
2003-04-02 05:41:22 +00:00
else ASSERT(0);
}
2003-12-18 10:31:42 +00:00
void Actor::SetEffectClock( CString s )
{
s.MakeLower();
if (s=="timer") SetEffectClock( CLOCK_TIMER );
else if(s=="bgm") SetEffectClock( CLOCK_BGM );
else ASSERT(0);
}
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
void Actor::StretchTo( const RectF &r )
2001-11-03 10:52:42 +00:00
{
// width and height of rectangle
float width = r.GetWidth();
float height = r.GetHeight();
2001-11-03 10:52:42 +00:00
// center of the rectangle
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
float fNewZoomX = width / m_size.x;
float fNewZoomY = height / m_size.y;
2001-11-03 10:52:42 +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
{
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
{
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
{
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
{
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;
m_fEffectPeriodSeconds = fPeriod;
m_vEffectMagnitude = vect;
m_fSecsIntoEffect = 0;
2002-01-16 10:01:32 +00:00
}
2003-03-02 01:43:33 +00:00
void Actor::SetEffectBounce( float fPeriod, RageVector3 vect )
2002-01-16 10:01:32 +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-07-27 19:29:51 +00:00
}
2003-03-02 01:43:33 +00:00
void Actor::SetEffectBob( float fPeriod, RageVector3 vect )
2002-07-27 19:29:51 +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;
}
2003-03-02 01:43:33 +00:00
void Actor::SetEffectSpin( RageVector3 vect )
{
2003-03-02 01:43:33 +00:00
m_Effect = spin;
m_vEffectMagnitude = vect;
}
2003-03-02 01:43:33 +00:00
void Actor::SetEffectVibrate( RageVector3 vect )
{
m_Effect = vibrate;
m_vEffectMagnitude = vect;
}
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;
}
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 )
{
sFadeString.MakeLower();
2003-03-02 01:43:33 +00:00
sFadeString.Replace( ' ', ',' );
TweenState original = m_current;
TweenState mod = m_current;
CStringArray asBits;
2003-03-02 01:43:33 +00:00
split( sFadeString, ",", asBits );
#define CONTAINS(needle) (find( asBits.begin(), asBits.end(), needle ) != asBits.end())
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;
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);
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);
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;
}
}
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) );
}
float Actor::Command( CString sCommands )
2003-03-02 01:43:33 +00:00
{
sCommands.MakeLower();
2003-03-02 01:43:33 +00:00
vector<ParsedCommand> vCommands;
ParseCommands( sCommands, vCommands );
2004-01-11 08:26:42 +00:00
for( unsigned i=0; i<vCommands.size(); i++ )
this->HandleCommand( vCommands[i] );
return GetTweenTimeLeft();
}
void Actor::HandleCommand( const ParsedCommand &command )
{
HandleParams;
const CString& sName = sParam(0);
// Commands that go in the tweening queue:
if ( sName=="sleep" ) { BeginTweening( fParam(1), TWEEN_LINEAR ); BeginTweening( 0, 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-10-24 08:50:35 +00:00
else if( sName=="stoptweening" ) { StopTweening(); BeginTweening( 0.0001f, TWEEN_LINEAR ); } // Why BeginT again? -Chris
else if( sName=="finishtweening" ) FinishTweening();
else if( sName=="x" ) SetX( fParam(1) );
else if( sName=="y" ) SetY( fParam(1) );
else if( sName=="z" ) SetZ( fParam(1) );
else if( sName=="addx" ) SetX( GetX()+fParam(1) );
else if( sName=="addy" ) SetY( GetY()+fParam(1) );
else if( sName=="addz" ) SetZ( GetZ()+fParam(1) );
else if( sName=="zoom" ) SetZoom( fParam(1) );
else if( sName=="zoomx" ) SetZoomX( fParam(1) );
else if( sName=="zoomy" ) SetZoomY( fParam(1) );
2003-11-13 18:05:40 +00:00
else if( sName=="zoomz" ) SetZoomZ( fParam(1) );
else if( sName=="zoomtowidth" ) ZoomToWidth( fParam(1) );
else if( sName=="zoomtoheight" ) ZoomToHeight( fParam(1) );
2003-11-08 20:37:40 +00:00
else if( sName=="stretchto" ) StretchTo( RectF( fParam(1), fParam(2), fParam(3), fParam(4) ) );
else if( sName=="cropleft" ) SetCropLeft( fParam(1) );
else if( sName=="croptop" ) SetCropTop( fParam(1) );
else if( sName=="cropright" ) SetCropRight( fParam(1) );
else if( sName=="cropbottom" ) SetCropBottom( fParam(1) );
2003-11-08 19:23:40 +00:00
else if( sName=="fadeleft" ) SetFadeLeft( fParam(1) );
else if( sName=="fadetop" ) SetFadeTop( fParam(1) );
else if( sName=="faderight" ) SetFadeRight( fParam(1) );
else if( sName=="fadebottom" ) SetFadeBottom( fParam(1) );
2003-11-18 04:07:30 +00:00
else if( sName=="fadecolor" ) SetFadeDiffuseColor( cParam(1) );
else if( sName=="diffuse" ) SetDiffuse( cParam(1) );
else if( sName=="diffuseleftedge" ) SetDiffuseLeftEdge( cParam(1) );
else if( sName=="diffuserightedge" ) SetDiffuseRightEdge( cParam(1) );
else if( sName=="diffusetopedge" ) SetDiffuseTopEdge( cParam(1) );
else if( sName=="diffusebottomedge" ) SetDiffuseBottomEdge( cParam(1) );
/* Add left/right/top/bottom for alpha if needed. */
else if( sName=="diffusealpha" ) SetDiffuseAlpha( fParam(1) );
2003-11-18 04:07:30 +00:00
else if( sName=="diffusecolor" ) SetDiffuseColor( cParam(1) );
else if( sName=="glow" ) SetGlow( cParam(1) );
else if( sName=="glowmode" ) {
if(!sParam(1).CompareNoCase("whiten"))
SetGlowMode( GLOW_WHITEN );
else if(!sParam(1).CompareNoCase("brighten"))
SetGlowMode( GLOW_BRIGHTEN );
else ASSERT(0);
}
else if( sName=="rotationx" ) SetRotationX( fParam(1) );
else if( sName=="rotationy" ) SetRotationY( fParam(1) );
else if( sName=="rotationz" ) SetRotationZ( fParam(1) );
else if( sName=="heading" ) AddRotationH( fParam(1) );
else if( sName=="pitch" ) AddRotationP( fParam(1) );
else if( sName=="roll" ) AddRotationR( fParam(1) );
else if( sName=="shadowlength" ) SetShadowLength( fParam(1) );
else if( sName=="horizalign" ) SetHorizAlign( sParam(1) );
else if( sName=="vertalign" ) SetVertAlign( sParam(1) );
else if( sName=="diffuseblink" ) SetEffectDiffuseBlink();
else if( sName=="diffuseshift" ) SetEffectDiffuseShift();
else if( sName=="glowblink" ) SetEffectGlowBlink();
else if( sName=="glowshift" ) SetEffectGlowShift();
else if( sName=="rainbow" ) SetEffectRainbow();
else if( sName=="wag" ) SetEffectWag();
else if( sName=="bounce" ) SetEffectBounce();
else if( sName=="bob" ) SetEffectBob();
else if( sName=="pulse" ) SetEffectPulse();
else if( sName=="spin" ) SetEffectSpin();
else if( sName=="vibrate" ) SetEffectVibrate();
else if( sName=="stopeffect" ) SetEffectNone();
2003-11-18 04:07:30 +00:00
else if( sName=="effectcolor1" ) SetEffectColor1( cParam(1) );
else if( sName=="effectcolor2" ) SetEffectColor2( cParam(1) );
else if( sName=="effectperiod" ) SetEffectPeriod( fParam(1) );
2003-12-18 10:31:42 +00:00
else if( sName=="effectoffset" ) SetEffectOffset( fParam(1) );
2004-01-20 23:25:38 +00:00
else if( sName=="effectdelay" ) SetEffectDelay( fParam(1) );
2003-12-18 10:31:42 +00:00
else if( sName=="effectclock" ) SetEffectClock( sParam(1) );
else if( sName=="effectmagnitude" ) SetEffectMagnitude( RageVector3(fParam(1),fParam(2),fParam(3)) );
else if( sName=="scaletocover" ) { RectI R(iParam(1), iParam(2), iParam(3), iParam(4)); ScaleToCover(R); }
2003-12-17 09:40:51 +00:00
else if( sName=="scaletofit" ) { RectI R(iParam(1), iParam(2), iParam(3), iParam(4)); ScaleToFitInside(R); }
// Commands that take effect immediately (ignoring the tweening queue):
else if( sName=="animate" ) EnableAnimation( bParam(1) );
2003-11-14 01:43:33 +00:00
else if( sName=="setstate" ) SetState( iParam(1) );
else if( sName=="texturewrapping" ) SetTextureWrapping( bParam(1) );
else if( sName=="additiveblend" ) SetBlendMode( bParam(1) ? BLEND_ADD : BLEND_NORMAL );
else if( sName=="blend" ) SetBlendMode( sParam(1) );
else if( sName=="zbuffer" ) SetUseZBuffer( bParam(1) );
2003-11-18 20:33:18 +00:00
else if( sName=="ztest" ) SetZTest( bParam(1) );
else if( sName=="zwrite" ) SetZWrite( bParam(1) );
2003-07-07 20:24:51 +00:00
else if( sName=="clearzbuffer" ) SetClearZBuffer( bParam(1) );
2003-11-06 07:18:11 +00:00
else if( sName=="hidden" ) SetHidden( bParam(1) );
2003-10-31 02:01:55 +00:00
else if( sName=="playcommand" ) sParam(1); /* nop: only BGAnimation handles this but everyone receives it */
2004-01-20 23:30:12 +00:00
else if( sName=="customtexturerect" || sName=="texcoordvelocity" || sName=="scaletoclipped" ||
sName=="stretchtexcoords" || sName=="position" || sName=="loop" || sName=="play" ||
sName=="pause" || sName=="rate" )
; /* sprite commands */
else
{
CString sError = ssprintf( "Actor::HandleCommand: Unrecognized command name '%s'.", sName.c_str() );
LOG->Warn( sError );
HOOKS->MessageBoxOK( sError );
2003-03-02 01:43:33 +00:00
}
CheckHandledParams;
}
2003-03-19 19:56:27 +00:00
float Actor::GetCommandLength( CString command )
{
Actor temp;
2003-03-19 19:56:27 +00:00
temp.Command(command);
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
/* This is a hack to change all tween states while leaving existing tweens alone.
*
* Perhaps the regular Set methods should also take an optional parameter, eg.
* "SET_TWEEN" (normal behavior) or "SET_GLOBAL" to set regardless of tweens.
* That might be ugly, too.
*/
void Actor::SetGlobalDiffuseColor( RageColor c )
{
for(int i=0; i<4; i++) /* color, not alpha */
{
for( unsigned ts = 0; ts < m_TweenStates.size(); ++ts )
{
m_TweenStates[ts].diffuse[i].r = c.r;
m_TweenStates[ts].diffuse[i].g = c.g;
m_TweenStates[ts].diffuse[i].b = c.b;
}
m_current.diffuse[i].r = c.r;
m_current.diffuse[i].g = c.g;
m_current.diffuse[i].b = c.b;
m_start.diffuse[i].r = c.r;
m_start.diffuse[i].g = c.g;
m_start.diffuse[i].b = c.b;
}
}
void Actor::SetGlobalX( float x )
{
for( unsigned ts = 0; ts < m_TweenStates.size(); ++ts )
m_TweenStates[ts].pos.x = x;
m_current.pos.x = x;
m_start.pos.x = x;
}
void Actor::SetDiffuseColor( RageColor c )
{
for(int i=0; i<4; i++)
{
DestTweenState().diffuse[i].r = c.r;
DestTweenState().diffuse[i].g = c.g;
DestTweenState().diffuse[i].b = c.b;
}
}
2003-04-02 05:41:22 +00:00
void Actor::TweenState::Init()
{
pos = RageVector3( 0, 0, 0 );
rotation = RageVector3( 0, 0, 0 );
quat = RageVector4( 0, 0, 0, 1 );
2003-04-02 05:41:22 +00:00
scale = RageVector3( 1, 1, 1 );
crop = RectF( 0,0,0,0 );
2003-11-08 19:23:40 +00:00
fade = RectF( 0,0,0,0 );
fadecolor = RageColor( 1, 1, 1, 0 );
2003-04-02 05:41:22 +00:00
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;
RageQuatSlerp(&average_out.quat, ts1.quat, ts2.quat, fPercentBetween);
average_out.crop.left = ts1.crop.left + (ts2.crop.left - ts1.crop.left )*fPercentBetween;
average_out.crop.top = ts1.crop.top + (ts2.crop.top - ts1.crop.top )*fPercentBetween;
average_out.crop.right = ts1.crop.right + (ts2.crop.right - ts1.crop.right )*fPercentBetween;
average_out.crop.bottom = ts1.crop.bottom+ (ts2.crop.bottom - ts1.crop.bottom)*fPercentBetween;
2003-11-08 19:23:40 +00:00
average_out.fade.left = ts1.fade.left + (ts2.fade.left - ts1.fade.left )*fPercentBetween;
average_out.fade.top = ts1.fade.top + (ts2.fade.top - ts1.fade.top )*fPercentBetween;
average_out.fade.right = ts1.fade.right + (ts2.fade.right - ts1.fade.right )*fPercentBetween;
average_out.fade.bottom = ts1.fade.bottom+ (ts2.fade.bottom - ts1.fade.bottom)*fPercentBetween;
average_out.fadecolor = ts1.fadecolor + (ts2.fadecolor - ts1.fadecolor )*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;
}
2003-07-05 21:36:47 +00:00
void Actor::SetBlendMode( CString s )
{
s.MakeLower();
if (s=="normal") SetBlendMode( BLEND_NORMAL );
else if(s=="add") SetBlendMode( BLEND_ADD );
else if(s=="noeffect") SetBlendMode( BLEND_NO_EFFECT );
else ASSERT(0);
}
void Actor::CopyTweening( const Actor &from )
{
m_current = from.m_current;
m_start = from.m_start;
m_TweenStates = from.m_TweenStates;
m_TweenInfo = from.m_TweenInfo;
}