diff --git a/src/Actor.cpp b/src/Actor.cpp index 919980dc53..ddb3ee62bb 100644 --- a/src/Actor.cpp +++ b/src/Actor.cpp @@ -84,7 +84,7 @@ void Actor::SetBGMLight( int iLightNumber, float fCabinetLights ) void Actor::InitState() { - StopTweening(); + this->StopTweening(); m_pTempState = NULL; @@ -615,14 +615,9 @@ void Actor::EndDraw() void Actor::UpdateTweening( float fDeltaTime ) { - while( 1 ) + while( !m_Tweens.empty() // something to do + && fDeltaTime > 0 ) // something will change { - if( m_Tweens.empty() ) // nothing to do - return; - - if( fDeltaTime == 0 ) // nothing will change - return; - // update current tween state // earliest tween TweenState &TS = m_Tweens[0]->state; @@ -636,7 +631,10 @@ void Actor::UpdateTweening( float fDeltaTime ) RString sCommand = TI.m_sCommandName; if( bBeginning ) // we are just beginning this tween + { m_start = m_current; // set the start position + SetCurrentTweenStart(); + } if( TI.m_fTimeLeftInTween == 0 ) // Current tween is over. Stop. { @@ -645,6 +643,7 @@ void Actor::UpdateTweening( float fDeltaTime ) // delete the head tween delete m_Tweens.front(); m_Tweens.erase( m_Tweens.begin() ); + EraseHeadTween(); } else // in the middle of tweening. Recalcute the current position. { @@ -653,6 +652,7 @@ void Actor::UpdateTweening( float fDeltaTime ) // distort the percentage if appropriate float fPercentAlongPath = TI.m_pTween->Tween( fPercentThroughTween ); TweenState::MakeWeightedAverage( m_current, m_start, TS, fPercentAlongPath ); + UpdatePercentThroughTween(fPercentAlongPath); } if( bBeginning ) @@ -772,7 +772,7 @@ void Actor::UpdateInternal( float fDeltaTime ) default: break; } - UpdateTweening( fDeltaTime ); + this->UpdateTweening( fDeltaTime ); } RString Actor::GetLineage() const @@ -797,7 +797,7 @@ void Actor::BeginTweening( float time, ITween *pTween ) LOG->Warn( "%s", sError.c_str() ); Dialog::OK( sError ); - FinishTweening(); + this->FinishTweening(); } // add a new TweenState to the tail, and initialize it @@ -829,7 +829,7 @@ void Actor::BeginTweening( float time, TweenType tt ) ASSERT( time >= 0 ); ITween *pTween = ITween::CreateFromType( tt ); - BeginTweening( time, pTween ); + this->BeginTweening( time, pTween ); } void Actor::StopTweening() @@ -843,7 +843,7 @@ void Actor::FinishTweening() { if( !m_Tweens.empty() ) m_current = DestTweenState(); - StopTweening(); + this->StopTweening(); } void Actor::HurryTweening( float factor ) diff --git a/src/Actor.h b/src/Actor.h index 9e69fc0fc7..87b98c36b9 100644 --- a/src/Actor.h +++ b/src/Actor.h @@ -270,6 +270,10 @@ public: virtual void Update( float fDeltaTime ); // this can short circuit UpdateInternal virtual void UpdateInternal( float fDeltaTime ); // override this void UpdateTweening( float fDeltaTime ); + // These next functions should all be overridden by a derived class that has its own tweening states to handl. + virtual void SetCurrentTweenStart() {} + virtual void EraseHeadTween() {} + virtual void UpdatePercentThroughTween( float PercentThroughTween ) {} /** * @brief Retrieve the Actor's name. @@ -449,9 +453,9 @@ public: void SetAux( float f ) { DestTweenState().aux = f; } float GetAux() const { return m_current.aux; } - void BeginTweening( float time, ITween *pInterp ); + virtual void BeginTweening( float time, ITween *pInterp ); void BeginTweening( float time, TweenType tt = TWEEN_LINEAR ); - void StopTweening(); + virtual void StopTweening(); void Sleep( float time ); void QueueCommand( const RString& sCommandName ); void QueueMessage( const RString& sMessageName ); diff --git a/src/ActorMultiVertex.cpp b/src/ActorMultiVertex.cpp new file mode 100644 index 0000000000..879b5f7a2a --- /dev/null +++ b/src/ActorMultiVertex.cpp @@ -0,0 +1,701 @@ +#include "global.h" +#include + +#include "ActorMultiVertex.h" +#include "RageTextureManager.h" +#include "XmlFile.h" +#include "RageLog.h" +#include "RageDisplay.h" +#include "RageTexture.h" +#include "RageUtil.h" +#include "ActorUtil.h" +#include "Foreach.h" +#include "LuaBinding.h" +#include "LuaManager.h" +#include "LocalizedString.h" + +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; +} + +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 ); +#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; +} + +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) + { + LOG->Warn("ActorMultiVertex:SetDrawState: FirstToDraw > vertices.size(), %d > %u", FirstToDraw + 1, (unsigned int)vertices.size() ); + return; + } + int safe_num= GetSafeNumToDraw( dm, num ); + if( num != safe_num && num != -1 ) + { + LOG->Warn("ActorMultiVertex:SetDrawState: NumToDraw %d is not valid for %u vertices with DrawMode %s", num, (unsigned int)vertices.size(), DrawModeNames[dm] ); + 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 +{ +public: + static int SetNumVertices( T* p, lua_State *L ) + { + p->SetNumVertices( IArg(1) ); + return 0; + } + 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) + { + LOG->Warn("ActorMultiVertex::SetVertex: non-table parameter supplied. Table of tables of vertex data expected."); + 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) + { + LOG->Warn( "ActorMultiVertex::SetVertex: non-table parameter %u supplied inside table of parameters, table expected.", (unsigned int)i ); + 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 + { + LOG->Warn( "ActorMultiVertex::SetVertex: Parameter %u has %u elements supplied. 2, 3, or 4 expected.", (unsigned int)i, (unsigned int)DataPieceElements ); + + } + // 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 ) + { + LOG->Warn( "ActorMultiVertex::SetVertex: index %d provided, cannot set Index < 1", Index+1 ); + return 0; + } + else if( Index == (int) p->GetNumVertices() ) + { + p->AddVertices( 1 ); + } + else if( Index > (int) p->GetNumVertices() ) + { + LOG->Warn( "ActorMultiVertex::SetVertex: Cannot set vertex %d if there is no vertex %d, only %u vertices.", Index+1 , Index, (unsigned int)p->GetNumVertices() ); + return 0; + } + SetVertexFromStack(p, L, Index, lua_gettop(L)); + return 0; + } + + 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 ) + { + LOG->Warn( "ActorMultiVertex::SetVertices: index %d provided, cannot set Index < 1", First+1 ); + return 0; + } + } + 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); + } + return 0; + } + + static int SetEffectMode( T* p, lua_State *L ) + { + EffectMode em = Enum::Check(L, 1); + p->SetEffectMode( em ); + return 0; + } + + static int SetTextureMode( T* p, lua_State *L ) + { + TextureMode tm = Enum::Check(L, 1); + p->SetTextureMode( tm ); + return 0; + } + + static int SetLineWidth( T* p, lua_State *L ) + { + float Width = FArg(1); + if( Width < 0 ) + { + LOG->Warn( "ActorMultiVertex::SetLineWidth: cannot set negative width." ); + return 0; + } + p->SetLineWidth(Width); + return 0; + } + + 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) ) + { + LOG->Warn( "ActorMultiVertex:SetDrawState: Table expected, something else recieved. Doing nothing."); + return 0; + } + // Fetch the draw mode, if provided. + lua_getfield(L, ArgsIndex, "Mode"); + if( !lua_isnil(L, -1) ) + { + dm= Enum::Check(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); + return 0; + } + + 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(); + } + else + { + RageTextureID ID( SArg(1) ); + p->LoadFromTexture( ID ); + } + return 0; + } + + static int SetTexture( T* p, lua_State *L ) + { + RageTexture *Texture = Luna::check(L, 1); + Texture = TEXTUREMAN->CopyTexture( Texture ); + p->SetTexture( Texture ); + return 0; + } + + 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 ); + + // Copy from RageTexture + ADD_METHOD( SetTexture ); + // 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. + */ diff --git a/src/ActorMultiVertex.h b/src/ActorMultiVertex.h new file mode 100644 index 0000000000..58d4158889 --- /dev/null +++ b/src/ActorMultiVertex.h @@ -0,0 +1,146 @@ +/** @brief ActorMultiVertex - A texture created from multiple textures. */ + +#include "Actor.h" +#include "RageDisplay.h" +#include "RageTextureID.h" + +enum DrawMode +{ + DrawMode_Quads = 0, + DrawMode_QuadStrip, + DrawMode_Fan, + DrawMode_Strip, + DrawMode_Triangles, + DrawMode_LineStrip, + DrawMode_SymmetricQuadStrip, + NUM_DrawMode, + DrawMode_Invalid +}; + +const RString& DrawModeToString( DrawMode cat ); +const RString& DrawModeToLocalizedString( DrawMode cat ); +LuaDeclareType( DrawMode ); + +class RageTexture; + +class ActorMultiVertex: public Actor +{ +public: + ActorMultiVertex(); + ActorMultiVertex( const ActorMultiVertex &cpy ); + virtual ~ActorMultiVertex(); + + void LoadFromNode( const XNode* Node ); + virtual ActorMultiVertex *Copy() const; + + struct AMV_TweenState + { + AMV_TweenState(): _DrawMode(DrawMode_Invalid), FirstToDraw(0), NumToDraw(-1), line_width(1.0f) {} + static void MakeWeightedAverage(AMV_TweenState& average_out, const AMV_TweenState& ts1, const AMV_TweenState& ts2, float percent_between); + bool operator==(const AMV_TweenState& other) const; + bool operator!=(const AMV_TweenState& other) const { return !operator==(other); } + + void SetDrawState( DrawMode dm, int first, int num ); + int GetSafeNumToDraw( DrawMode dm, int num ) const; + + vector vertices; + + DrawMode _DrawMode; + int FirstToDraw; + int NumToDraw; + + // needed for DrawMode_LineStrip + float line_width; + }; + + AMV_TweenState& AMV_DestTweenState() + { + if(AMV_Tweens.empty()) + { return AMV_current; } + else + { return AMV_Tweens.back(); } + } + const AMV_TweenState& AMV_DestTweenState() const { return const_cast(this)->AMV_DestTweenState(); } + + virtual bool EarlyAbortDraw() const; + virtual void DrawPrimitives(); + virtual void DrawInternal( const AMV_TweenState *TS ); + + void SetCurrentTweenStart(); + void EraseHeadTween(); + void UpdatePercentThroughTween( float PercentThroughTween ); + void BeginTweening( float time, ITween *pInterp ); + + void StopTweening(); + void FinishTweening(); + + void SetTexture( RageTexture *Texture ); + void LoadFromTexture( RageTextureID ID ); + + void UnloadTexture(); + void SetNumVertices( size_t n ); + + void AddVertex(); + void AddVertices( int Add ); + + void SetEffectMode( EffectMode em) { _EffectMode = em; } + void SetTextureMode( TextureMode tm) { _TextureMode = tm; } + void SetLineWidth( float width) { AMV_DestTweenState().line_width = width; } + + void SetDrawState( DrawMode dm, int first, int num ) { AMV_DestTweenState().SetDrawState(dm, first, num); } + + DrawMode GetDestDrawMode() const { return AMV_DestTweenState()._DrawMode; } + int GetDestFirstToDraw() const { return AMV_DestTweenState().FirstToDraw; } + int GetDestNumToDraw() const { return AMV_DestTweenState().NumToDraw; } + DrawMode GetCurrDrawMode() const { return AMV_current._DrawMode; } + int GetCurrFirstToDraw() const { return AMV_current.FirstToDraw; } + int GetCurrNumToDraw() const { return AMV_current.NumToDraw; } + size_t GetNumVertices() { return AMV_DestTweenState().vertices.size(); } + + void SetVertexPos( int index , float x , float y , float z ); + void SetVertexColor( int index , RageColor c ); + void SetVertexCoords( int index , float TexCoordX , float TexCoordY ); + + virtual void PushSelf( lua_State *L ); + +private: + RageTexture* _Texture; + + vector _Vertices; + vector AMV_Tweens; + AMV_TweenState AMV_current; + AMV_TweenState AMV_start; + + // required to handle diffuse and glow + AMV_TweenState *AMV_TempState; + + EffectMode _EffectMode; + TextureMode _TextureMode; +}; + +/** + * @file + * @author Matthew Gardner and Eric Reese (c) 2014 + * @section LICENSE + * 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. + */ diff --git a/src/RageTypes.cpp b/src/RageTypes.cpp index 2bfb3ed743..b3d96215a2 100644 --- a/src/RageTypes.cpp +++ b/src/RageTypes.cpp @@ -73,6 +73,18 @@ RString RageColor::NormalizeColorString( RString sColor ) return ""; return c.ToString(); } + +void WeightedAvergeOfRSVs(RageSpriteVertex& average_out, RageSpriteVertex const& rsv1, RageSpriteVertex const& rsv2, float percent_between) +{ + average_out.p= lerp(percent_between, rsv1.p, rsv2.p); + average_out.n= lerp(percent_between, rsv1.n, rsv2.n); + average_out.c.b= lerp(percent_between, rsv1.c.b, rsv2.c.b); + average_out.c.g= lerp(percent_between, rsv1.c.g, rsv2.c.g); + average_out.c.r= lerp(percent_between, rsv1.c.r, rsv2.c.r); + average_out.c.a= lerp(percent_between, rsv1.c.a, rsv2.c.a); + average_out.t= lerp(percent_between, rsv1.t, rsv2.t); +} + /** @brief Utilities for working with Lua. */ namespace LuaHelpers { diff --git a/src/RageTypes.h b/src/RageTypes.h index da74c15db6..0a5d51a1c9 100644 --- a/src/RageTypes.h +++ b/src/RageTypes.h @@ -342,6 +342,7 @@ struct RageSpriteVertex // has color RageVector2 t; // texture coordinates }; +void WeightedAvergeOfRSVs(RageSpriteVertex& average_out, RageSpriteVertex const& rsv1, RageSpriteVertex const& rsv2, float percent_between); struct RageModelVertex // doesn't have color. Relies on material color {