2014-04-14 21:29:19 -05:00
#include "global.h"
#include <cassert>
#include "ActorMultiVertex.h"
#include "RageTextureManager.h"
#include "XmlFile.h"
#include "RageLog.h"
#include "RageDisplay.h"
#include "RageTexture.h"
2014-12-27 21:41:55 -07:00
#include "RageTimer.h"
2014-04-14 21:29:19 -05:00
#include "RageUtil.h"
#include "ActorUtil.h"
#include "Foreach.h"
#include "LuaBinding.h"
#include "LuaManager.h"
#include "LocalizedString.h"
2015-02-01 17:01:15 -07:00
const float min_state_delay = 0.0001f ;
2014-04-14 21:29:19 -05:00
static const char * DrawModeNames [] = {
"Quads" ,
"QuadStrip" ,
"Fan" ,
"Strip" ,
"Triangles" ,
"LineStrip" ,
"SymmetricQuadStrip" ,
};
static const int DrawModeVertexGroupSizes [] = {
4 , // Quads
2 , // QuadStrip
1 , // Fan
1 , // Strip
3 , // Triangles
1 , // LineStrip
3 , // SymmetricQuadStrip
1 , // NUM_DrawMode
1 , // DrawMode_Invalid
};
static const int DrawModeMinimumToDraw [] = {
4 , // Quads
4 , // QuadStrip
3 , // Fan
3 , // Strip
3 , // Triangles
2 , // LineStrip
6 , // SymmetricQuadStrip
1 , // NUM_DrawMode
1 , // DrawMode_Invalid
};
XToString ( DrawMode );
XToLocalizedString ( DrawMode );
LuaXType ( DrawMode );
REGISTER_ACTOR_CLASS ( ActorMultiVertex );
ActorMultiVertex :: ActorMultiVertex ()
{
// Use blank texture by default.
RageTextureID ID = TEXTUREMAN -> GetDefaultTextureID ();
_Texture = TEXTUREMAN -> LoadTexture ( ID );
_EffectMode = EffectMode_Normal ;
_TextureMode = TextureMode_Modulate ;
2015-01-06 20:14:59 -07:00
_splines . resize ( num_vert_splines );
for ( size_t i = 0 ; i < num_vert_splines ; ++ i )
{
_splines [ i ]. redimension ( 3 );
_splines [ i ]. m_owned_by_actor = true ;
}
2015-02-01 17:01:15 -07:00
_skip_next_update = true ;
2015-02-02 23:28:33 -07:00
_decode_movie = true ;
2015-02-01 17:01:15 -07:00
_use_animation_state = false ;
_secs_into_state = 0.0f ;
_cur_state = 0 ;
2014-04-14 21:29:19 -05:00
}
ActorMultiVertex ::~ ActorMultiVertex ()
{
UnloadTexture ();
}
ActorMultiVertex :: ActorMultiVertex ( const ActorMultiVertex & cpy ) :
Actor ( cpy )
{
#define CPY(a) a = cpy.a
CPY ( AMV_Tweens );
CPY ( AMV_current );
CPY ( AMV_start );
CPY ( _EffectMode );
CPY ( _TextureMode );
2015-01-06 20:14:59 -07:00
CPY ( _splines );
2015-02-01 17:01:15 -07:00
CPY ( _skip_next_update );
CPY ( _use_animation_state );
CPY ( _secs_into_state );
CPY ( _cur_state );
CPY ( _states );
2014-04-14 21:29:19 -05:00
#undef CPY
if ( cpy . _Texture != NULL )
{
_Texture = TEXTUREMAN -> CopyTexture ( cpy . _Texture );
}
else
{
_Texture = NULL ;
}
}
void ActorMultiVertex :: LoadFromNode ( const XNode * Node )
{
RString path ;
Node -> GetAttrValue ( "Texture" , path );
if ( ! path . empty () && ! TEXTUREMAN -> IsTextureRegistered ( RageTextureID ( path ) ) )
{
ActorUtil :: GetAttrPath ( Node , "Texture" , path );
}
if ( ! path . empty () )
{
LoadFromTexture ( path );
}
Actor :: LoadFromNode ( Node );
}
void ActorMultiVertex :: SetTexture ( RageTexture * Texture )
{
if ( _Texture != Texture )
{
UnloadTexture ();
_Texture = Texture ;
}
}
void ActorMultiVertex :: LoadFromTexture ( RageTextureID ID )
{
RageTexture * Texture = NULL ;
if ( _Texture && _Texture -> GetID () == ID )
{
return ;
}
Texture = TEXTUREMAN -> LoadTexture ( ID );
SetTexture ( Texture );
}
void ActorMultiVertex :: UnloadTexture ()
{
if ( _Texture != NULL )
{
TEXTUREMAN -> UnloadTexture ( _Texture );
_Texture = NULL ;
}
}
void ActorMultiVertex :: SetNumVertices ( size_t n )
{
if ( n == 0 )
{
for ( size_t i = 0 ; i < AMV_Tweens . size (); ++ i )
{
AMV_Tweens [ i ]. vertices . clear ();
}
AMV_current . vertices . clear ();
AMV_start . vertices . clear ();
}
else
{
for ( size_t i = 0 ; i < AMV_Tweens . size (); ++ i )
{
AMV_Tweens [ i ]. vertices . resize ( n );
}
AMV_current . vertices . resize ( n );
AMV_start . vertices . resize ( n );
}
}
void ActorMultiVertex :: AddVertex ()
{
for ( size_t i = 0 ; i < AMV_Tweens . size (); ++ i )
{
AMV_Tweens [ i ]. vertices . push_back ( RageSpriteVertex () );
}
AMV_current . vertices . push_back ( RageSpriteVertex () );
AMV_start . vertices . push_back ( RageSpriteVertex () );
}
void ActorMultiVertex :: AddVertices ( int Add )
{
int size = AMV_DestTweenState (). vertices . size ();
size += Add ;
for ( size_t i = 0 ; i < AMV_Tweens . size (); ++ i )
{
AMV_Tweens [ i ]. vertices . resize ( size );
}
AMV_current . vertices . resize ( size );
AMV_start . vertices . resize ( size );
}
void ActorMultiVertex :: SetVertexPos ( int index , float x , float y , float z )
{
AMV_DestTweenState (). vertices [ index ]. p = RageVector3 ( x , y , z );
}
void ActorMultiVertex :: SetVertexColor ( int index , RageColor c )
{
AMV_DestTweenState (). vertices [ index ]. c = c ;
}
void ActorMultiVertex :: SetVertexCoords ( int index , float TexCoordX , float TexCoordY )
{
AMV_DestTweenState (). vertices [ index ]. t = RageVector2 ( TexCoordX , TexCoordY );
}
void ActorMultiVertex :: DrawPrimitives ()
{
Actor :: SetGlobalRenderStates (); // set Actor-specified render states
DISPLAY -> ClearAllTextures ();
DISPLAY -> SetTexture ( TextureUnit_1 , _Texture -> GetTexHandle () );
Actor :: SetTextureRenderStates ();
DISPLAY -> SetEffectMode ( _EffectMode );
// set temporary diffuse and glow
static AMV_TweenState TS ;
AMV_TempState = & TS ;
TS = AMV_current ;
// skip if no change or fully transparent
if ( m_pTempState -> diffuse [ 0 ] != RageColor ( 1 , 1 , 1 , 1 ) && m_pTempState -> diffuse [ 0 ]. a > 0 )
{
for ( size_t i = 0 ; i < TS . vertices . size (); i ++ )
{
// RageVColor * RageColor
TS . vertices [ i ]. c . b *= m_pTempState -> diffuse [ 0 ]. b ;
TS . vertices [ i ]. c . r *= m_pTempState -> diffuse [ 0 ]. r ;
TS . vertices [ i ]. c . g *= m_pTempState -> diffuse [ 0 ]. g ;
TS . vertices [ i ]. c . a *= m_pTempState -> diffuse [ 0 ]. a ;
}
}
// Draw diffuse pass.
if ( m_pTempState -> diffuse [ 0 ]. a > 0 )
{
DISPLAY -> SetTextureMode ( TextureUnit_1 , _TextureMode );
DrawInternal ( AMV_TempState );
}
// Draw the glow pass
if ( m_pTempState -> glow . a > 0 )
{
for ( size_t i = 0 ; i < TS . vertices . size (); i ++ )
{
TS . vertices [ i ]. c = m_pTempState -> glow ;
}
DISPLAY -> SetTextureMode ( TextureUnit_1 , TextureMode_Glow );
DrawInternal ( AMV_TempState );
}
}
void ActorMultiVertex :: DrawInternal ( const AMV_TweenState * TS )
{
int FirstToDraw = TS -> FirstToDraw ;
int NumToDraw = TS -> GetSafeNumToDraw ( TS -> _DrawMode , TS -> NumToDraw );
if ( NumToDraw == 0 )
{
// Nothing to draw.
return ;
}
switch ( TS -> _DrawMode )
{
case DrawMode_Quads :
{
DISPLAY -> DrawQuads ( & TS -> vertices [ FirstToDraw ], NumToDraw );
break ;
}
case DrawMode_QuadStrip :
{
DISPLAY -> DrawQuadStrip ( & TS -> vertices [ FirstToDraw ], NumToDraw );
break ;
}
case DrawMode_Fan :
{
DISPLAY -> DrawFan ( & TS -> vertices [ FirstToDraw ], NumToDraw );
break ;
}
case DrawMode_Strip :
{
DISPLAY -> DrawStrip ( & TS -> vertices [ FirstToDraw ], NumToDraw );
break ;
}
case DrawMode_Triangles :
{
DISPLAY -> DrawTriangles ( & TS -> vertices [ FirstToDraw ], NumToDraw );
break ;
}
case DrawMode_LineStrip :
{
DISPLAY -> DrawLineStrip ( & TS -> vertices [ FirstToDraw ], NumToDraw , TS -> line_width );
break ;
}
case DrawMode_SymmetricQuadStrip :
{
DISPLAY -> DrawSymmetricQuadStrip ( & TS -> vertices [ FirstToDraw ], NumToDraw );
break ;
}
}
DISPLAY -> SetEffectMode ( EffectMode_Normal );
}
bool ActorMultiVertex :: EarlyAbortDraw () const
{
if ( AMV_current . FirstToDraw >= ( int ) AMV_current . vertices . size () || AMV_current . _DrawMode >= NUM_DrawMode )
{
return true ;
}
return false ;
}
2015-01-06 20:14:59 -07:00
void ActorMultiVertex :: SetVertsFromSplinesInternal ( size_t num_splines , size_t offset )
{
vector < RageSpriteVertex >& verts = AMV_DestTweenState (). vertices ;
size_t first = AMV_DestTweenState (). FirstToDraw + offset ;
2015-01-08 04:26:39 -07:00
size_t num_verts = AMV_DestTweenState (). GetSafeNumToDraw ( AMV_DestTweenState (). _DrawMode , AMV_DestTweenState (). NumToDraw ) - offset ;
2015-01-06 22:00:06 -07:00
vector < float > tper ( num_splines , 0.0f );
2015-06-08 10:07:17 -06:00
float num_parts = ( static_cast < float > ( num_verts ) /
static_cast < float > ( num_splines )) - 1.0f ;
2015-01-06 20:14:59 -07:00
for ( size_t i = 0 ; i < num_splines ; ++ i )
{
tper [ i ] = _splines [ i ]. get_max_t () / num_parts ;
}
for ( size_t v = 0 ; v < num_verts ; ++ v )
{
vector < float > pos ;
const int spi = v % num_splines ;
2015-01-20 12:38:31 -07:00
float part = static_cast < float > ( v / num_splines );
_splines [ spi ]. evaluate ( part * tper [ spi ], pos );
2015-01-06 20:14:59 -07:00
verts [ v + first ]. p . x = pos [ 0 ];
verts [ v + first ]. p . y = pos [ 1 ];
verts [ v + first ]. p . z = pos [ 2 ];
}
}
void ActorMultiVertex :: SetVertsFromSplines ()
{
if ( AMV_DestTweenState (). vertices . empty ()) { return ; }
switch ( AMV_DestTweenState (). _DrawMode )
{
case DrawMode_Quads :
SetVertsFromSplinesInternal ( 4 , 0 );
break ;
case DrawMode_QuadStrip :
case DrawMode_Strip :
SetVertsFromSplinesInternal ( 2 , 0 );
break ;
case DrawMode_Fan :
// Skip the first vert because it is the center of the fan. -Kyz
SetVertsFromSplinesInternal ( 1 , 1 );
break ;
case DrawMode_Triangles :
case DrawMode_SymmetricQuadStrip :
SetVertsFromSplinesInternal ( 3 , 0 );
break ;
case DrawMode_LineStrip :
SetVertsFromSplinesInternal ( 1 , 0 );
break ;
}
}
CubicSplineN * ActorMultiVertex :: GetSpline ( size_t i )
{
ASSERT ( i < num_vert_splines );
return & ( _splines [ i ]);
}
2015-02-01 17:01:15 -07:00
void ActorMultiVertex :: SetState ( size_t i )
{
ASSERT ( i < _states . size ());
_cur_state = i ;
_secs_into_state = 0.0f ;
}
void ActorMultiVertex :: SetAllStateDelays ( float delay )
{
FOREACH ( State , _states , s )
{
s -> delay = delay ;
}
}
float ActorMultiVertex :: GetAnimationLengthSeconds () const
{
float tot = 0.0f ;
FOREACH_CONST ( State , _states , s )
{
tot += s -> delay ;
}
return tot ;
}
void ActorMultiVertex :: SetSecondsIntoAnimation ( float seconds )
{
SetState ( 0 );
if ( _Texture )
{
_Texture -> SetPosition ( seconds );
}
_secs_into_state = seconds ;
UpdateAnimationState ( true );
}
void ActorMultiVertex :: UpdateAnimationState ( bool force_update )
{
AMV_TweenState & dest = AMV_DestTweenState ();
vector < RageSpriteVertex >& verts = dest . vertices ;
vector < size_t >& qs = dest . quad_states ;
if ( ! _use_animation_state || _states . empty () ||
dest . _DrawMode == DrawMode_LineStrip || qs . empty ())
{ return ; }
bool state_changed = force_update ;
if ( _states . size () > 1 )
{
while ( _states [ _cur_state ]. delay > min_state_delay &&
_secs_into_state + min_state_delay > _states [ _cur_state ]. delay )
{
_secs_into_state -= _states [ _cur_state ]. delay ;
_cur_state = ( _cur_state + 1 ) % _states . size ();
state_changed = true ;
}
}
if ( state_changed )
{
size_t first = dest . FirstToDraw ;
size_t last = first + dest . GetSafeNumToDraw ( dest . _DrawMode , dest . NumToDraw );
#define STATE_ID const size_t state_id= (_cur_state + qs[quad_id % qs.size()]) % _states.size();
switch ( AMV_DestTweenState (). _DrawMode )
{
case DrawMode_Quads :
for ( size_t i = first ; i < last ; ++ i )
{
const size_t quad_id = ( i - first ) / 4 ;
STATE_ID ;
switch (( i - first ) % 4 )
{
case 0 :
verts [ i ]. t . x = _states [ state_id ]. rect . left ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
break ;
case 1 :
verts [ i ]. t . x = _states [ state_id ]. rect . right ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
break ;
case 2 :
verts [ i ]. t . x = _states [ state_id ]. rect . right ;
verts [ i ]. t . y = _states [ state_id ]. rect . bottom ;
break ;
case 3 :
verts [ i ]. t . x = _states [ state_id ]. rect . left ;
verts [ i ]. t . y = _states [ state_id ]. rect . bottom ;
break ;
}
}
break ;
case DrawMode_QuadStrip :
for ( size_t i = first ; i < last ; ++ i )
{
const size_t quad_id = ( i - first ) / 2 ;
STATE_ID ;
switch (( i - first ) % 2 )
{
case 0 :
verts [ i ]. t . x = _states [ state_id ]. rect . left ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
break ;
case 1 :
verts [ i ]. t . x = _states [ state_id ]. rect . left ;
verts [ i ]. t . y = _states [ state_id ]. rect . bottom ;
break ;
}
}
break ;
case DrawMode_Strip :
case DrawMode_Fan :
for ( size_t i = first ; i < last ; ++ i )
{
const size_t quad_id = ( i - first );
STATE_ID ;
verts [ i ]. t . x = _states [ state_id ]. rect . left ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
}
break ;
case DrawMode_Triangles :
for ( size_t i = first ; i < last ; ++ i )
{
const size_t quad_id = ( i - first ) / 3 ;
STATE_ID ;
switch (( i - first ) % 3 )
{
case 0 :
verts [ i ]. t . x = _states [ state_id ]. rect . left ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
break ;
case 1 :
verts [ i ]. t . x = _states [ state_id ]. rect . right ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
break ;
case 2 :
verts [ i ]. t . x = _states [ state_id ]. rect . right ;
verts [ i ]. t . y = _states [ state_id ]. rect . bottom ;
break ;
}
}
break ;
case DrawMode_SymmetricQuadStrip :
for ( size_t i = first ; i < last ; ++ i )
{
const size_t quad_id = ( i - first ) / 3 ;
STATE_ID ;
switch (( i - first ) % 3 )
{
case 0 :
case 2 :
verts [ i ]. t . x = _states [ state_id ]. rect . left ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
break ;
case 1 :
verts [ i ]. t . x = _states [ state_id ]. rect . right ;
verts [ i ]. t . y = _states [ state_id ]. rect . top ;
break ;
}
}
break ;
}
}
#undef STATE_ID
}
void ActorMultiVertex :: EnableAnimation ( bool bEnable )
{
bool bWasEnabled = m_bIsAnimating ;
Actor :: EnableAnimation ( bEnable );
if ( bEnable && ! bWasEnabled )
{
_skip_next_update = true ;
}
}
void ActorMultiVertex :: Update ( float fDelta )
{
Actor :: Update ( fDelta ); // do tweening
const bool skip_this_movie_update = _skip_next_update ;
_skip_next_update = false ;
if ( ! m_bIsAnimating ) { return ; }
if ( ! _Texture ) { return ; }
float time_passed = GetEffectDeltaTime ();
_secs_into_state += time_passed ;
if ( _secs_into_state < 0 )
{
wrap ( _secs_into_state , GetAnimationLengthSeconds ());
}
UpdateAnimationState ();
2015-02-02 23:28:33 -07:00
if ( ! skip_this_movie_update && _decode_movie )
2015-02-01 17:01:15 -07:00
{
_Texture -> DecodeSeconds ( max ( 0 , time_passed ));
}
}
2014-04-14 21:29:19 -05:00
void ActorMultiVertex :: SetCurrentTweenStart ()
{
AMV_start = AMV_current ;
}
void ActorMultiVertex :: EraseHeadTween ()
{
AMV_current = AMV_Tweens [ 0 ];
AMV_Tweens . erase ( AMV_Tweens . begin ());
}
void ActorMultiVertex :: UpdatePercentThroughTween ( float PercentThroughTween )
{
AMV_TweenState :: MakeWeightedAverage ( AMV_current , AMV_start , AMV_Tweens [ 0 ], PercentThroughTween );
}
void ActorMultiVertex :: BeginTweening ( float time , ITween * pTween )
{
Actor :: BeginTweening ( time , pTween );
if ( AMV_Tweens . size () >= 1 ) // if there was already a TS on the stack
{
AMV_Tweens . push_back ( AMV_Tweens . back () );
}
else
{
AMV_Tweens . push_back ( AMV_current );
}
}
void ActorMultiVertex :: StopTweening ()
{
AMV_Tweens . clear ();
Actor :: StopTweening ();
}
void ActorMultiVertex :: FinishTweening ()
{
if ( ! AMV_Tweens . empty () )
{
AMV_current = AMV_DestTweenState ();
}
Actor :: FinishTweening ();
}
void ActorMultiVertex :: AMV_TweenState :: SetDrawState ( DrawMode dm , int first , int num )
{
if ( first >= ( int ) vertices . size () && vertices . size () > 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex:SetDrawState: FirstToDraw > vertices.size(), %d > %u" , FirstToDraw + 1 , ( unsigned int ) vertices . size () );
2014-04-14 21:29:19 -05:00
return ;
}
int safe_num = GetSafeNumToDraw ( dm , num );
if ( num != safe_num && num != - 1 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex:SetDrawState: NumToDraw %d is not valid for %u vertices with DrawMode %s" , num , ( unsigned int ) vertices . size (), DrawModeNames [ dm ] );
2014-04-14 21:29:19 -05:00
return ;
}
_DrawMode = dm ;
FirstToDraw = first ;
NumToDraw = num ;
}
void ActorMultiVertex :: AMV_TweenState :: MakeWeightedAverage ( AMV_TweenState & average_out , const AMV_TweenState & ts1 , const AMV_TweenState & ts2 , float percent_between )
{
average_out . line_width = lerp ( percent_between , ts1 . line_width , ts2 . line_width );
for ( size_t v = 0 ; v < average_out . vertices . size (); ++ v )
{
WeightedAvergeOfRSVs ( average_out . vertices [ v ], ts1 . vertices [ v ], ts2 . vertices [ v ], percent_between );
}
}
int ActorMultiVertex :: AMV_TweenState :: GetSafeNumToDraw ( DrawMode dm , int num ) const
{
int max = vertices . size () - FirstToDraw ;
// NumToDraw == -1 draws all vertices
if ( num == - 1 || num > max )
{
num = max ;
}
num -= ( num % DrawModeVertexGroupSizes [ dm ]);
if ( num < DrawModeMinimumToDraw [ dm ])
{
num = 0 ;
}
return num ;
}
// lua start
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the ActorMultiVertex. */
class LunaActorMultiVertex : public Luna < ActorMultiVertex >
{
public :
static int SetNumVertices ( T * p , lua_State * L )
{
p -> SetNumVertices ( IArg ( 1 ) );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
static int GetNumVertices ( T * p , lua_State * L ) { lua_pushnumber ( L , p -> GetNumVertices () ); return 1 ; }
static void SetVertexFromStack ( T * p , lua_State * L , size_t VertexIndex , int DataStackIndex )
{
// Use the number of arguments to determine which property a table is for
if ( lua_type ( L , DataStackIndex ) != LUA_TTABLE )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex::SetVertex: non-table parameter supplied. Table of tables of vertex data expected." );
2014-04-14 21:29:19 -05:00
return ;
}
size_t NumDataParts = lua_objlen ( L , DataStackIndex );
for ( size_t i = 0 ; i < NumDataParts ; ++ i )
{
lua_pushnumber ( L , i + 1 );
lua_gettable ( L , DataStackIndex );
int DataPieceIndex = lua_gettop ( L );
size_t DataPieceElements = lua_objlen ( L , DataPieceIndex );
if ( lua_type ( L , DataPieceIndex ) != LUA_TTABLE )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex::SetVertex: non-table parameter %u supplied inside table of parameters, table expected." , ( unsigned int ) i );
2014-04-14 21:29:19 -05:00
return ;
}
int pushes = 1 ;
if ( DataPieceElements == 2 )
{
pushes += 2 ;
lua_rawgeti ( L , DataPieceIndex , 1 );
float x = FArg ( - 1 );
lua_rawgeti ( L , DataPieceIndex , 2 );
float y = FArg ( - 1 );
p -> SetVertexCoords ( VertexIndex , x , y );
}
else if ( DataPieceElements == 3 )
{
pushes += 3 ;
lua_rawgeti ( L , DataPieceIndex , 1 );
float x = FArg ( - 1 );
lua_rawgeti ( L , DataPieceIndex , 2 );
float y = FArg ( - 1 );
lua_rawgeti ( L , DataPieceIndex , 3 );
float z = FArg ( - 1 );
p -> SetVertexPos ( VertexIndex , x , y , z );
}
else if ( DataPieceElements == 4 )
{
// RageColor pops the things it pushes onto the stack, so we don't need to.
RageColor c ;
// Does not use FromStackCompat because we are not compatible with passing a color in non-table form.
c . FromStack ( L , DataPieceIndex );
p -> SetVertexColor ( VertexIndex , c );
}
else
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex::SetVertex: Parameter %u has %u elements supplied. 2, 3, or 4 expected." , ( unsigned int ) i , ( unsigned int ) DataPieceElements );
2014-04-14 21:29:19 -05:00
}
// Avoid a stack underflow by only popping the amount we pushed.
lua_pop ( L , pushes );
}
return ;
}
static int SetVertex ( T * p , lua_State * L )
{
// Indices from Lua are one-indexed. -1 to adjust.
int Index = IArg ( 1 ) - 1 ;
if ( Index < 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex::SetVertex: index %d provided, cannot set Index < 1" , Index + 1 );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
else if ( Index == ( int ) p -> GetNumVertices () )
{
p -> AddVertices ( 1 );
}
else if ( Index > ( int ) p -> GetNumVertices () )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex::SetVertex: Cannot set vertex %d if there is no vertex %d, only %u vertices." , Index + 1 , Index , ( unsigned int ) p -> GetNumVertices () );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
SetVertexFromStack ( p , L , Index , lua_gettop ( L ));
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
static int SetVertices ( T * p , lua_State * L )
{
int First = 0 ;
int StackIndex = lua_gettop ( L );
// Allow the user to just pass a table without specifying a starting point.
if ( lua_type ( L , 1 ) == LUA_TNUMBER )
{
// Indices from Lua are one-indexed. -1 to adjust.
First = IArg ( 1 ) - 1 ;
if ( First < 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex::SetVertices: index %d provided, cannot set Index < 1" , First + 1 );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
}
int Last = First + lua_objlen ( L , StackIndex );
if ( Last > ( int ) p -> GetNumVertices ())
{
p -> AddVertices ( Last - p -> GetNumVertices () );
}
for ( int n = First ; n < Last ; ++ n )
{
lua_pushnumber ( L , n - First + 1 );
lua_gettable ( L , StackIndex );
SetVertexFromStack ( p , L , n , lua_gettop ( L ));
lua_pop ( L , 1 );
}
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
static int SetEffectMode ( T * p , lua_State * L )
{
EffectMode em = Enum :: Check < EffectMode > ( L , 1 );
p -> SetEffectMode ( em );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
static int SetTextureMode ( T * p , lua_State * L )
{
TextureMode tm = Enum :: Check < TextureMode > ( L , 1 );
p -> SetTextureMode ( tm );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
static int SetLineWidth ( T * p , lua_State * L )
{
float Width = FArg ( 1 );
if ( Width < 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex::SetLineWidth: cannot set negative width." );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
p -> SetLineWidth ( Width );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
static int SetDrawState ( T * p , lua_State * L )
{
DrawMode dm = p -> GetDestDrawMode ();
int first = p -> GetDestFirstToDraw ();
int num = p -> GetDestNumToDraw ();
int ArgsIndex = 1 ;
if ( ! lua_istable ( L , ArgsIndex ) )
{
2014-07-07 00:39:27 -06:00
LuaHelpers :: ReportScriptErrorFmt ( "ActorMultiVertex:SetDrawState: Table expected, something else recieved. Doing nothing." );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
// Fetch the draw mode, if provided.
lua_getfield ( L , ArgsIndex , "Mode" );
if ( ! lua_isnil ( L , - 1 ) )
{
dm = Enum :: Check < DrawMode > ( L , - 1 );
}
lua_pop ( L , 1 );
// Fetch FirstToDraw, if provided.
lua_getfield ( L , ArgsIndex , "First" );
if ( ! lua_isnil ( L , - 1 ) )
{
// Indices from Lua are one-indexed. -1 to adjust.
first = IArg ( - 1 ) - 1 ;
}
lua_pop ( L , 1 );
// Fetch NumToDraw, if provided.
lua_getfield ( L , ArgsIndex , "Num" );
if ( ! lua_isnil ( L , - 1 ) )
{
num = IArg ( - 1 );
}
lua_pop ( L , 1 );
p -> SetDrawState ( dm , first , num );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
static int GetDestDrawMode ( T * p , lua_State * L )
{
Enum :: Push ( L , p -> GetDestDrawMode ());
return 1 ;
}
static int GetDestFirstToDraw ( T * p , lua_State * L )
{
// Indices in Lua are one-indexed. +1 to adjust.
lua_pushnumber ( L , p -> GetDestFirstToDraw () + 1 );
return 1 ;
}
static int GetDestNumToDraw ( T * p , lua_State * L )
{
lua_pushnumber ( L , p -> GetDestNumToDraw ());
return 1 ;
}
static int GetCurrDrawMode ( T * p , lua_State * L )
{
Enum :: Push ( L , p -> GetCurrDrawMode ());
return 1 ;
}
static int GetCurrFirstToDraw ( T * p , lua_State * L )
{
// Indices in Lua are one-indexed. +1 to adjust.
lua_pushnumber ( L , p -> GetCurrFirstToDraw () + 1 );
return 1 ;
}
static int GetCurrNumToDraw ( T * p , lua_State * L )
{
lua_pushnumber ( L , p -> GetCurrNumToDraw ());
return 1 ;
}
static int LoadTexture ( T * p , lua_State * L )
{
if ( lua_isnil ( L , 1 ) )
{
p -> UnloadTexture ();
2015-02-02 23:28:33 -07:00
p -> LoadFromTexture ( TEXTUREMAN -> GetDefaultTextureID ());
2014-04-14 21:29:19 -05:00
}
else
{
RageTextureID ID ( SArg ( 1 ) );
2015-02-02 23:28:33 -07:00
TEXTUREMAN -> DisableOddDimensionWarning ();
2014-04-14 21:29:19 -05:00
p -> LoadFromTexture ( ID );
2015-02-02 23:28:33 -07:00
TEXTUREMAN -> EnableOddDimensionWarning ();
2014-04-14 21:29:19 -05:00
}
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
2015-01-06 20:14:59 -07:00
static int GetSpline ( T * p , lua_State * L )
{
size_t i = static_cast < size_t > ( IArg ( 1 ) - 1 );
if ( i >= ActorMultiVertex :: num_vert_splines )
{
luaL_error ( L , "Spline index must be greater than 0 and less than or equal to %zu." , ActorMultiVertex :: num_vert_splines );
}
p -> GetSpline ( i ) -> PushSelf ( L );
return 1 ;
}
static int SetVertsFromSplines ( T * p , lua_State * L )
{
p -> SetVertsFromSplines ();
COMMON_RETURN_SELF ;
}
2015-02-01 17:01:15 -07:00
DEFINE_METHOD ( GetUseAnimationState , _use_animation_state );
static int SetUseAnimationState ( T * p , lua_State * L )
{
p -> _use_animation_state = BArg ( 1 );
COMMON_RETURN_SELF ;
}
static int GetNumStates ( T * p , lua_State * L )
{
lua_pushnumber ( L , p -> GetNumStates ());
return 1 ;
}
static void FillStateFromLua ( lua_State * L , ActorMultiVertex :: State & state ,
RageTexture * tex , int index )
{
if ( tex == NULL )
{
luaL_error ( L , "The texture must be set before adding states." );
}
// State looks like this:
// {{left, top, right, bottom}, delay}
#define DATA_ERROR(i) \
if(!lua_istable(L, i)) \
{ \
luaL_error(L, "The state data must be in a table like this: {{left, top, right, bottom}, delay}"); \
}
#define SET_SIDE(i, side) \
lua_rawgeti(L, -1, i); \
state.side= FArg(-1); \
lua_pop(L, 1);
DATA_ERROR ( index );
lua_rawgeti ( L , index , 1 );
DATA_ERROR ( - 1 );
SET_SIDE ( 1 , rect . left );
SET_SIDE ( 2 , rect . top );
SET_SIDE ( 3 , rect . right );
SET_SIDE ( 4 , rect . bottom );
lua_pop ( L , 1 );
SET_SIDE ( 2 , delay );
const float width_ratio = tex -> GetImageToTexCoordsRatioX ();
const float height_ratio = tex -> GetImageToTexCoordsRatioY ();
state . rect . left = state . rect . left * width_ratio ;
state . rect . top = state . rect . top * height_ratio ;
// Pixel centers are at .5, so add an extra pixel to the size to adjust.
state . rect . right = ( state . rect . right * width_ratio ) + width_ratio ;
state . rect . bottom = ( state . rect . bottom * height_ratio ) + height_ratio ;
#undef SET_SIDE
#undef DATA_ERROR
}
static int AddState ( T * p , lua_State * L )
{
ActorMultiVertex :: State s ;
FillStateFromLua ( L , s , p -> GetTexture (), 1 );
p -> AddState ( s );
COMMON_RETURN_SELF ;
}
static size_t ValidStateIndex ( T * p , lua_State * L , int pos )
{
int index = IArg ( pos ) - 1 ;
if ( index < 0 || static_cast < size_t > ( index ) >= p -> GetNumStates ())
{
luaL_error ( L , "Invalid state index %d." , index + 1 );
}
return static_cast < size_t > ( index );
}
static int RemoveState ( T * p , lua_State * L )
{
p -> RemoveState ( ValidStateIndex ( p , L , 1 ));
COMMON_RETURN_SELF ;
}
static int GetState ( T * p , lua_State * L )
{
lua_pushnumber ( L , p -> GetState () + 1 );
return 1 ;
}
static int SetState ( T * p , lua_State * L )
{
p -> SetState ( ValidStateIndex ( p , L , 1 ));
COMMON_RETURN_SELF ;
}
static int GetStateData ( T * p , lua_State * L )
{
RageTexture * tex = p -> GetTexture ();
if ( tex == NULL )
{
luaL_error ( L , "The texture must be set before adding states." );
}
const float width_pix = tex -> GetImageToTexCoordsRatioX ();
const float height_pix = tex -> GetImageToTexCoordsRatioY ();
const float width_ratio = 1.0f / tex -> GetImageToTexCoordsRatioX ();
const float height_ratio = 1.0f / tex -> GetImageToTexCoordsRatioY ();
const ActorMultiVertex :: State & state =
p -> GetStateData ( ValidStateIndex ( p , L , 1 ));
lua_createtable ( L , 2 , 0 );
lua_createtable ( L , 4 , 0 );
lua_pushnumber ( L , state . rect . left * width_ratio );
lua_rawseti ( L , - 2 , 1 );
lua_pushnumber ( L , state . rect . top * height_ratio );
lua_rawseti ( L , - 2 , 2 );
lua_pushnumber ( L , ( state . rect . right - width_pix ) * width_ratio );
lua_rawseti ( L , - 2 , 3 );
lua_pushnumber ( L , ( state . rect . bottom + height_pix ) * height_ratio );
lua_rawseti ( L , - 2 , 4 );
lua_rawseti ( L , - 2 , 1 );
lua_pushnumber ( L , state . delay );
lua_rawseti ( L , - 2 , 2 );
return 1 ;
}
static int SetStateData ( T * p , lua_State * L )
{
ActorMultiVertex :: State & state = p -> GetStateData ( ValidStateIndex ( p , L , 1 ));
FillStateFromLua ( L , state , p -> GetTexture (), 2 );
COMMON_RETURN_SELF ;
}
static int SetStateProperties ( T * p , lua_State * L )
{
if ( ! lua_istable ( L , 1 ))
{
luaL_error ( L , "The states must be inside a table." );
}
RageTexture * tex = p -> GetTexture ();
if ( tex == NULL )
{
luaL_error ( L , "The texture must be set before adding states." );
}
vector < ActorMultiVertex :: State > new_states ;
size_t num_states = lua_objlen ( L , 1 );
new_states . resize ( num_states );
for ( size_t i = 0 ; i < num_states ; ++ i )
{
2015-02-02 23:28:33 -07:00
lua_rawgeti ( L , 1 , i + 1 );
2015-02-01 17:01:15 -07:00
FillStateFromLua ( L , new_states [ i ], tex , - 1 );
lua_pop ( L , 1 );
}
p -> SetStateProperties ( new_states );
COMMON_RETURN_SELF ;
}
static int SetAllStateDelays ( T * p , lua_State * L )
{
p -> SetAllStateDelays ( FArg ( 1 ));
COMMON_RETURN_SELF ;
}
DEFINE_METHOD ( GetAnimationLengthSeconds , GetAnimationLengthSeconds ());
static int SetSecondsIntoAnimation ( T * p , lua_State * L )
{
p -> SetSecondsIntoAnimation ( FArg ( 1 ));
COMMON_RETURN_SELF ;
}
static int GetNumQuadStates ( T * p , lua_State * L )
{
lua_pushnumber ( L , p -> GetNumQuadStates ());
return 1 ;
}
static size_t QuadStateIndex ( T * p , lua_State * L , int pos )
{
int index = IArg ( pos ) - 1 ;
if ( index < 0 || static_cast < size_t > ( index ) >= p -> GetNumQuadStates ())
{
luaL_error ( L , "Invalid state index %d." , index + 1 );
}
return static_cast < size_t > ( index );
}
static int AddQuadState ( T * p , lua_State * L )
{
p -> AddQuadState ( IArg ( 1 ) - 1 );
COMMON_RETURN_SELF ;
}
static int RemoveQuadState ( T * p , lua_State * L )
{
p -> RemoveQuadState ( QuadStateIndex ( p , L , 1 ));
COMMON_RETURN_SELF ;
}
static int GetQuadState ( T * p , lua_State * L )
{
lua_pushnumber ( L , p -> GetQuadState ( QuadStateIndex ( p , L , 1 )) + 1 );
return 1 ;
}
static int SetQuadState ( T * p , lua_State * L )
{
2015-02-02 23:28:33 -07:00
p -> SetQuadState ( QuadStateIndex ( p , L , 1 ), IArg ( 2 ) - 1 );
COMMON_RETURN_SELF ;
}
static int ForceStateUpdate ( T * p , lua_State * L )
{
p -> UpdateAnimationState ( true );
COMMON_RETURN_SELF ;
}
2015-02-05 00:37:08 -07:00
DEFINE_METHOD ( GetDecodeMovie , _decode_movie );
2015-02-02 23:28:33 -07:00
static int SetDecodeMovie ( T * p , lua_State * L )
{
p -> _decode_movie = BArg ( 1 );
2015-02-01 17:01:15 -07:00
COMMON_RETURN_SELF ;
}
2014-04-14 21:29:19 -05:00
static int SetTexture ( T * p , lua_State * L )
{
RageTexture * Texture = Luna < RageTexture >:: check ( L , 1 );
Texture = TEXTUREMAN -> CopyTexture ( Texture );
p -> SetTexture ( Texture );
2014-12-01 22:31:30 -07:00
COMMON_RETURN_SELF ;
2014-04-14 21:29:19 -05:00
}
2014-09-02 05:18:29 -06:00
static int GetTexture ( T * p , lua_State * L )
{
RageTexture * texture = p -> GetTexture ();
if ( texture != NULL )
{
texture -> PushSelf ( L );
}
else
{
lua_pushnil ( L );
}
return 1 ;
}
2014-04-14 21:29:19 -05:00
LunaActorMultiVertex ()
{
ADD_METHOD ( SetVertex );
ADD_METHOD ( SetVertices );
ADD_METHOD ( SetEffectMode );
ADD_METHOD ( SetTextureMode );
ADD_METHOD ( SetLineWidth );
ADD_METHOD ( SetDrawState );
ADD_METHOD ( SetNumVertices );
ADD_METHOD ( GetNumVertices );
ADD_METHOD ( GetDestDrawMode );
ADD_METHOD ( GetDestFirstToDraw );
ADD_METHOD ( GetDestNumToDraw );
ADD_METHOD ( GetCurrDrawMode );
ADD_METHOD ( GetCurrFirstToDraw );
ADD_METHOD ( GetCurrNumToDraw );
2015-01-06 20:14:59 -07:00
ADD_METHOD ( GetSpline );
ADD_METHOD ( SetVertsFromSplines );
2014-12-27 21:41:55 -07:00
2015-02-01 17:01:15 -07:00
ADD_METHOD ( GetUseAnimationState );
ADD_METHOD ( SetUseAnimationState );
ADD_METHOD ( GetNumStates );
ADD_METHOD ( GetNumQuadStates );
ADD_METHOD ( AddState );
ADD_METHOD ( RemoveState );
ADD_METHOD ( GetState );
ADD_METHOD ( SetState );
ADD_METHOD ( GetStateData );
ADD_METHOD ( SetStateData );
ADD_METHOD ( SetStateProperties );
ADD_METHOD ( SetAllStateDelays );
ADD_METHOD ( SetSecondsIntoAnimation );
ADD_METHOD ( AddQuadState );
ADD_METHOD ( RemoveQuadState );
ADD_METHOD ( GetQuadState );
ADD_METHOD ( SetQuadState );
2015-02-02 23:28:33 -07:00
ADD_METHOD ( ForceStateUpdate );
2015-02-05 00:37:08 -07:00
ADD_METHOD ( GetDecodeMovie );
2015-02-02 23:28:33 -07:00
ADD_METHOD ( SetDecodeMovie );
2015-02-01 17:01:15 -07:00
2014-04-14 21:29:19 -05:00
// Copy from RageTexture
ADD_METHOD ( SetTexture );
2014-09-02 05:18:29 -06:00
ADD_METHOD ( GetTexture );
2014-04-14 21:29:19 -05:00
// Load from file path
ADD_METHOD ( LoadTexture );
}
};
LUA_REGISTER_DERIVED_CLASS ( ActorMultiVertex , Actor )
/*
* (c) 2014 Matthew Gardner and Eric Reese
* All rights reserved.
*
* 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, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* 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 OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/