diff --git a/stepmania/Themes/default/metrics.ini b/stepmania/Themes/default/metrics.ini index 45ba93781b..5ac9e0edc5 100644 --- a/stepmania/Themes/default/metrics.ini +++ b/stepmania/Themes/default/metrics.ini @@ -15,6 +15,9 @@ OverlayScreens=ScreenSystemLayer EditMode=2 MaxCourseEntriesBeforeShowVarious=6 +[Screen] +InitCommand= + [ModeSwitcher] PrevModeX=-200 PrevModeY=-170 @@ -75,8 +78,7 @@ Choice8=screen,ScreenTest NumIconParts=0 ShowScroller=1 -ScrollerSpacingX=0 -ScrollerSpacingY=50 +ScrollerTransform=function(self,offset,itemIndex,numItems) self:y(50*offset) end ScrollerSecondsPerItem=0 ScrollerNumItemsToDraw=20 ScrollerX=SCREEN_CENTER_X @@ -2232,6 +2234,7 @@ MemoryCardIcons=0 TimerSeconds=0 [ScreenSystemLayer] +Fallback=Screen Class=ScreenSystemLayer StatsX=SCREEN_RIGHT-8 StatsY=SCREEN_TOP+10 @@ -2976,8 +2979,7 @@ PreSwitchPageSeconds=0 PostSwitchPageSeconds=0 ScrollerSecondsPerItem=0 ScrollerNumItemsToDraw=0 -ScrollerSpacingX=0 -ScrollerSpacingY=0 +ScrollerTransform=function(self,offset,itemIndex,numItems) end OverrideLockInputSeconds=0 LockInputSeconds=0 OverrideSleepAfterTweenOffSeconds=0 @@ -3268,8 +3270,7 @@ PreSwitchPageSeconds=0 PostSwitchPageSeconds=0 ScrollerSecondsPerItem=0 ScrollerNumItemsToDraw=0 -ScrollerSpacingX=0 -ScrollerSpacingY=0 +ScrollerTransform=function(self,offset,itemIndex,numItems) end StyleIcon=1 MemoryCardIcons=1 OverrideSleepAfterTweenOffSeconds=0 diff --git a/stepmania/src/ActorFrame.cpp b/stepmania/src/ActorFrame.cpp index f8ac72416a..706d70b83b 100644 --- a/stepmania/src/ActorFrame.cpp +++ b/stepmania/src/ActorFrame.cpp @@ -27,6 +27,7 @@ ActorFrame::ActorFrame() { m_bPropagateCommands = false; m_bDeleteChildren = false; + m_bDrawByZPosition = false; m_fUpdateRate = 1; m_fFOV = -1; m_bOverrideLighting = false; @@ -161,8 +162,18 @@ void ActorFrame::DrawPrimitives() // Actor::DrawPrimitives(); // draw all sub-ActorFrames while we're in the ActorFrame's local coordinate space - for( unsigned i=0; iDraw(); + if( m_bDrawByZPosition ) + { + vector subs = m_SubActors; + ActorUtil::SortByZPosition( subs ); + for( unsigned i=0; iDraw(); + } + else + { + for( unsigned i=0; iDraw(); + } @@ -258,7 +269,7 @@ float ActorFrame::GetTweenTimeLeft() const } -bool CompareActorsByDrawOrder(const Actor *p1, const Actor *p2) +static bool CompareActorsByDrawOrder(const Actor *p1, const Actor *p2) { return p1->GetDrawOrder() < p2->GetDrawOrder(); } @@ -350,6 +361,11 @@ void ActorFrame::PlayCommand( const CString &sCommandName ) } } +void ActorFrame::SetDrawByZPosition( bool b ) +{ + m_bDrawByZPosition = b; +} + /* * (c) 2001-2004 Chris Danford * All rights reserved. diff --git a/stepmania/src/ActorFrame.h b/stepmania/src/ActorFrame.h index d2602fbb20..23f3cf54d2 100644 --- a/stepmania/src/ActorFrame.h +++ b/stepmania/src/ActorFrame.h @@ -11,10 +11,10 @@ class LunaActorFrame : public LunaActor public: LunaActorFrame() { LUA->Register( Register ); } - static int propagate( T* p, lua_State *L ) { p->SetPropagateCommands( !!IArg(1) ); return 0; } - static int fov( T* p, lua_State *L ) { p->SetFOV( FArg(1) ); return 0; } - static int SetUpdateRate( T* p, lua_State *L ) { p->SetUpdateRate( FArg(1) ); return 0; } - static int SetFOV( T* p, lua_State *L ) { p->SetFOV( FArg(1) ); return 0; } + static int propagate( T* p, lua_State *L ) { p->SetPropagateCommands( !!IArg(1) ); return 0; } + static int fov( T* p, lua_State *L ) { p->SetFOV( FArg(1) ); return 0; } + static int SetUpdateRate( T* p, lua_State *L ) { p->SetUpdateRate( FArg(1) ); return 0; } + static int SetFOV( T* p, lua_State *L ) { p->SetFOV( FArg(1) ); return 0; } static int GetChild( T* p, lua_State *L ) { Actor *pChild = p->GetChild( SArg(1) ); @@ -24,7 +24,8 @@ public: lua_pushnil( L ); return 1; } - static int GetNumChildren( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumChildren() ); return 1; } + static int GetNumChildren( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumChildren() ); return 1; } + static int SetDrawByZPosition( T* p, lua_State *L ) { p->SetDrawByZPosition( BArg(1) ); return 1; } static void Register(lua_State *L) { @@ -34,6 +35,7 @@ public: ADD_METHOD( SetFOV ) ADD_METHOD( GetChild ) ADD_METHOD( GetNumChildren ) + ADD_METHOD( SetDrawByZPosition ) LunaActor::Register( L ); } }; @@ -56,6 +58,7 @@ public: void MoveToTail( Actor* pActor ); void MoveToHead( Actor* pActor ); void SortByDrawOrder(); + void SetDrawByZPosition( bool b ); void DeleteChildrenWhenDone( bool bDelete=true ) { m_bDeleteChildren = bDelete; } void DeleteAllChildren(); @@ -97,6 +100,7 @@ protected: vector m_SubActors; bool m_bPropagateCommands; bool m_bDeleteChildren; + bool m_bDrawByZPosition; // state effects float m_fUpdateRate; diff --git a/stepmania/src/ActorScroller.cpp b/stepmania/src/ActorScroller.cpp index 948c6d4774..d7f1560ace 100644 --- a/stepmania/src/ActorScroller.cpp +++ b/stepmania/src/ActorScroller.cpp @@ -7,6 +7,7 @@ #include "arch/Dialog/Dialog.h" #include "RageLog.h" #include "ActorUtil.h" +#include // lua start LUA_REGISTER_CLASS( ActorScroller ) @@ -40,11 +41,6 @@ ActorScroller::ActorScroller() m_quadMask.SetBlendMode( BLEND_NO_EFFECT ); // don't change color values m_quadMask.SetUseZBuffer( true ); // we want to write to the Zbuffer m_quadMask.SetHidden( true ); - - m_vRotationDegrees = RageVector3(0,0,0); - m_vTranslateTerm0 = RageVector3(0,0,0); - m_vTranslateTerm1 = RageVector3(0,0,0); - m_vTranslateTerm2 = RageVector3(0,0,0); } void ActorScroller::Load( @@ -59,10 +55,25 @@ void ActorScroller::Load( { m_fSecondsPerItem = fSecondsPerItem; m_fNumItemsToDraw = fNumItemsToDraw; - m_vRotationDegrees = vRotationDegrees; - m_vTranslateTerm0 = vTranslateTerm0; - m_vTranslateTerm1 = vTranslateTerm1; - m_vTranslateTerm2 = vTranslateTerm2; + + + // Note: Rotation is applied before translation. + // rot = m_vRotationDegrees*itemOffset^1 + // trans = m_vTranslateTerm0*itemOffset^0 + + // m_vTranslateTerm1*itemOffset^1 + + // m_vTranslateTerm2*itemOffset^2 + ostringstream s; + s << + "function(self,offset,itemIndex,numItems) " << + "self:x(" << vTranslateTerm0.x << " + " << vTranslateTerm1.x << "*offset + " << vTranslateTerm2.x << "*offset*offset); " << + "self:y(" << vTranslateTerm0.y << " + " << vTranslateTerm1.y << "*offset + " << vTranslateTerm2.y << "*offset*offset); " << + "self:z(" << vTranslateTerm0.z << " + " << vTranslateTerm1.z << "*offset + " << vTranslateTerm2.z << "*offset*offset); " << + "self:rotationx(" << vRotationDegrees.x << "*offset); " << + "self:rotationy(" << vRotationDegrees.y << "*offset); " << + "self:rotationz(" << vRotationDegrees.z << "*offset); " << + "end"; + m_exprTransform.SetFromExpression( s.str() ); + m_fQuantizePixels = 0; m_bUseMask = bUseMask; @@ -86,7 +97,11 @@ void ActorScroller::Load2( m_fNumItemsToDraw = fNumItemsToDraw; m_fMaskWidth = fItemWidth; m_fMaskHeight = fItemHeight; - m_vTranslateTerm1 = RageVector3( 0, fItemHeight, 0 ); + + m_exprTransform.SetFromExpression( + ssprintf("function(self,offset,itemIndex,numItems) return %f*fOffsetFromCenter end",fItemHeight) + ); + m_bLoop = bLoop; m_fSecondsPerItem = fSecondsPerItem; m_fSecondsPauseBetweenItems = fSecondsPauseBetweenItems; @@ -109,6 +124,19 @@ void ActorScroller::Load2( m_bLoaded = true; } +void ActorScroller::Load3( + float fSecondsPerItem, + float fNumItemsToDraw, + const CString &sExprTransform + ) +{ + m_fSecondsPerItem = fSecondsPerItem; + m_fNumItemsToDraw = fNumItemsToDraw; + m_exprTransform.SetFromExpression( sExprTransform ); + m_fQuantizePixels = 0; + m_bLoaded = true; +} + float ActorScroller::GetSecondsForCompleteScrollThrough() { float fTotalItems = m_fNumItemsToDraw + m_SubActors.size(); @@ -212,25 +240,17 @@ void ActorScroller::Update( float fDeltaTime ) m_fCurrentItem = fmodf( m_fCurrentItem, m_fNumItemsToDraw+1 ); } -#define PUSH_AND_TRANSFORM_FOR_ITEM( fPosition ) { \ - DISPLAY->PushMatrix(); \ - if( m_vRotationDegrees.x ) DISPLAY->RotateX( m_vRotationDegrees.x*fPosition ); \ - if( m_vRotationDegrees.y ) DISPLAY->RotateY( m_vRotationDegrees.y*fPosition ); \ - if( m_vRotationDegrees.z ) DISPLAY->RotateZ( m_vRotationDegrees.z*fPosition ); \ - RageVector3 vTranslation = \ - m_vTranslateTerm0 + /* m_vTranslateTerm0*fPosition^0 */ \ - m_vTranslateTerm1 * fPosition + /* m_vTranslateTerm1*fPosition^1 */ \ - m_vTranslateTerm2 * fPosition*fPosition; /* m_vTranslateTerm2*fPosition^2 */ \ - if( m_fQuantizePixels > 0 ) { \ - vTranslation.x = Quantize( vTranslation.x, m_fQuantizePixels ); \ - vTranslation.y = Quantize( vTranslation.y, m_fQuantizePixels ); \ - vTranslation.z = Quantize( vTranslation.z, m_fQuantizePixels ); \ - } \ - DISPLAY->Translate( \ - vTranslation.x, \ - vTranslation.y, \ - vTranslation.z ); \ - } + +void ActorScroller::PositionItem( Actor *pActor, float fPositionOffsetFromCenter, int iItemIndex, int iNumItems ) +{ + m_exprTransform.PushSelf( LUA->L ); + ASSERT( !lua_isnil(LUA->L, -1) ); + pActor->PushSelf( LUA->L ); + LuaHelpers::Push( fPositionOffsetFromCenter, LUA->L ); + LuaHelpers::Push( iItemIndex, LUA->L ); + LuaHelpers::Push( iNumItems, LUA->L ); + lua_call( LUA->L, 4, 0 ); // 4 args, 0 results +} void ActorScroller::DrawPrimitives() { @@ -238,56 +258,66 @@ void ActorScroller::DrawPrimitives() if( !m_bLoaded ) { ActorFrame::DrawPrimitives(); + return; + } + + if( m_SubActors.empty() ) + return; + + // write to z buffer so that top and bottom are clipped + float fPositionFullyOnScreenTop = -(m_fNumItemsToDraw-1)/2.f; + float fPositionFullyOnScreenBottom = (m_fNumItemsToDraw-1)/2.f; + float fPositionFullyOffScreenTop = fPositionFullyOnScreenTop - 1; + float fPositionFullyOffScreenBottom = fPositionFullyOnScreenBottom + 1; + float fPositionOnEdgeOfScreenTop = -(m_fNumItemsToDraw)/2.f; + float fPositionOnEdgeOfScreenBottom = (m_fNumItemsToDraw)/2.f; + + float fFirstItemToDraw = 0; + float fLastItemToDraw = 0; + + if( m_bUseMask ) + { + PositionItem( &m_quadMask, fPositionFullyOffScreenTop, -1, m_SubActors.size() ); + m_quadMask.Draw(); + + PositionItem( &m_quadMask, fPositionFullyOffScreenBottom, m_SubActors.size(), m_SubActors.size() ); + m_quadMask.Draw(); + + fFirstItemToDraw = fPositionFullyOffScreenTop + m_fCurrentItem; + fLastItemToDraw = fPositionFullyOffScreenBottom + m_fCurrentItem; } else { - if( m_SubActors.empty() ) - return; + fFirstItemToDraw = fPositionOnEdgeOfScreenTop + m_fCurrentItem; + fLastItemToDraw = fPositionOnEdgeOfScreenBottom + m_fCurrentItem; + } - // write to z buffer so that top and bottom are clipped - float fPositionFullyOnScreenTop = -(m_fNumItemsToDraw-1)/2.f; - float fPositionFullyOnScreenBottom = (m_fNumItemsToDraw-1)/2.f; - float fPositionFullyOffScreenTop = fPositionFullyOnScreenTop - 1; - float fPositionFullyOffScreenBottom = fPositionFullyOnScreenBottom + 1; - float fPositionOnEdgeOfScreenTop = -(m_fNumItemsToDraw)/2.f; - float fPositionOnEdgeOfScreenBottom = (m_fNumItemsToDraw)/2.f; - - float fFirstItemToDraw = 0; - float fLastItemToDraw = 0; + bool bDelayedDraw = m_bDrawByZPosition && !m_bLoop; + vector subs; + if( bDelayedDraw ) + subs = m_SubActors; - if( m_bUseMask ) - { - PUSH_AND_TRANSFORM_FOR_ITEM( fPositionFullyOffScreenTop ) - m_quadMask.Draw(); - DISPLAY->PopMatrix(); + for( int iItem=(int)truncf(ceilf(fFirstItemToDraw)); iItem<=fLastItemToDraw; iItem++ ) + { + float fPosition = iItem - m_fCurrentItem; + int iIndex = iItem; + if( m_bLoop ) + wrap( iIndex, m_SubActors.size()-1 ); + else if( iIndex < 0 || iIndex >= (int)m_SubActors.size() ) + continue; - PUSH_AND_TRANSFORM_FOR_ITEM( fPositionFullyOffScreenBottom ) - m_quadMask.Draw(); - DISPLAY->PopMatrix(); - - fFirstItemToDraw = fPositionFullyOffScreenTop + m_fCurrentItem; - fLastItemToDraw = fPositionFullyOffScreenBottom + m_fCurrentItem; - } + PositionItem( m_SubActors[iIndex], fPosition, iIndex, m_SubActors.size() ); + if( bDelayedDraw ) + subs.push_back( m_SubActors[iIndex] ); else - { - fFirstItemToDraw = fPositionOnEdgeOfScreenTop + m_fCurrentItem; - fLastItemToDraw = fPositionOnEdgeOfScreenBottom + m_fCurrentItem; - } - - - for( int iItem=(int)truncf(ceilf(fFirstItemToDraw)); iItem<=fLastItemToDraw; iItem++ ) - { - float fPosition = iItem - m_fCurrentItem; - int iIndex = iItem; - if( m_bLoop ) - wrap( iIndex, m_SubActors.size()-1 ); - else if( iIndex < 0 || iIndex >= (int)m_SubActors.size() ) - continue; - - PUSH_AND_TRANSFORM_FOR_ITEM( fPosition ) m_SubActors[iIndex]->Draw(); - DISPLAY->PopMatrix(); - } + } + + if( bDelayedDraw ) + { + ActorUtil::SortByZPosition( subs ); + FOREACH( Actor*, subs, a ) + (*a)->Draw(); } } diff --git a/stepmania/src/ActorScroller.h b/stepmania/src/ActorScroller.h index 77bbb43734..bed11589c5 100644 --- a/stepmania/src/ActorScroller.h +++ b/stepmania/src/ActorScroller.h @@ -44,6 +44,11 @@ public: float fSecondsPerItem, float fSecondsPauseBetweenItems ); + void Load3( + float fSecondsPerItem, + float fNumItemsToDraw, + const CString &sExprTransform ); + virtual void Update( float fDelta ); virtual void DrawPrimitives(); // DOES draw @@ -62,6 +67,8 @@ public: void PushSelf( lua_State *L ); protected: + void PositionItem( Actor *pActor, float fPositionOffsetFromCenter, int iItemIndex, int iNumItems ); + bool m_bLoaded; float m_fCurrentItem; // Item at top of list, usually between 0 and m_SubActors.size(), approaches destination float m_fDestinationItem; @@ -77,17 +84,7 @@ protected: float m_fMaskHeight; Quad m_quadMask; - // Note: Rotation is applied before translation. - - // rot = m_vRotationDegrees*itemOffset^1 - RageVector3 m_vRotationDegrees; - - // trans = m_vTranslateTerm0*itemOffset^0 + - // m_vTranslateTerm1*itemOffset^1 + - // m_vTranslateTerm2*itemOffset^2 - RageVector3 m_vTranslateTerm0; - RageVector3 m_vTranslateTerm1; - RageVector3 m_vTranslateTerm2; + LuaExpression m_exprTransform; // params: self,offset,itemIndex,numItems }; class ActorScrollerAutoDeleteChildren : public ActorScroller diff --git a/stepmania/src/ActorUtil.cpp b/stepmania/src/ActorUtil.cpp index 42fbbf2ee1..0fa50d5149 100644 --- a/stepmania/src/ActorUtil.cpp +++ b/stepmania/src/ActorUtil.cpp @@ -399,6 +399,18 @@ void ActorUtil::LoadAllCommands( Actor& actor, const CString &sType ) } } +static bool CompareActorsByZPosition(const Actor *p1, const Actor *p2) +{ + return p1->GetZ() < p2->GetZ(); +} + +void ActorUtil::SortByZPosition( vector &vActors ) +{ + // Preserve ordering of Actors with equal Z positions. + stable_sort( vActors.begin(), vActors.end(), CompareActorsByZPosition ); +} + + /* * (c) 2003-2004 Chris Danford * All rights reserved. diff --git a/stepmania/src/ActorUtil.h b/stepmania/src/ActorUtil.h index 0b6b5742a4..fa78fd9fb2 100644 --- a/stepmania/src/ActorUtil.h +++ b/stepmania/src/ActorUtil.h @@ -57,6 +57,8 @@ namespace ActorUtil Actor* MakeActor( const RageTextureID &ID ); void ResolvePath( CString &sPath, const CString &sName ); + + void SortByZPosition( vector &vActors ); }; #define SET_XY( actor ) ActorUtil::SetXY( actor, m_sName ) diff --git a/stepmania/src/ScreenSelectMaster.cpp b/stepmania/src/ScreenSelectMaster.cpp index 51142231a3..f0f53b0a74 100644 --- a/stepmania/src/ScreenSelectMaster.cpp +++ b/stepmania/src/ScreenSelectMaster.cpp @@ -42,8 +42,7 @@ ScreenSelectMaster::ScreenSelectMaster( CString sClassName ) : ScreenSelect( sCl SHOW_SCROLLER(m_sName,"ShowScroller"), SCROLLER_SECONDS_PER_ITEM(m_sName,"ScrollerSecondsPerItem"), SCROLLER_NUM_ITEMS_TO_DRAW(m_sName,"ScrollerNumItemsToDraw"), - SCROLLER_SPACING_X(m_sName,"ScrollerSpacingX"), - SCROLLER_SPACING_Y(m_sName,"ScrollerSpacingY"), + SCROLLER_TRANSFORM(m_sName,"ScrollerTransform"), DEFAULT_CHOICE(m_sName,"DefaultChoice") { } @@ -99,13 +98,11 @@ void ScreenSelectMaster::Init() { if( SHARED_PREVIEW_AND_CURSOR ) { - m_Scroller[0].Load( + m_Scroller[0].Load3( SCROLLER_SECONDS_PER_ITEM, SCROLLER_NUM_ITEMS_TO_DRAW, - RageVector3( 0, 0, 0 ), - RageVector3( 0, 0, 0 ), - RageVector3( SCROLLER_SPACING_X, SCROLLER_SPACING_Y, 0 ), - RageVector3( 0, 0, 0 ) ); + SCROLLER_TRANSFORM + ); m_Scroller[0].SetName( "Scroller" ); this->AddChild( &m_Scroller[0] ); @@ -122,13 +119,11 @@ void ScreenSelectMaster::Init() { FOREACH_HumanPlayer( p ) { - m_Scroller[p].Load( + m_Scroller[p].Load3( SCROLLER_SECONDS_PER_ITEM, SCROLLER_NUM_ITEMS_TO_DRAW, - RageVector3( 0, 0, 0 ), - RageVector3( 0, 0, 0 ), - RageVector3( SCROLLER_SPACING_X, SCROLLER_SPACING_Y, 0 ), - RageVector3( 0, 0, 0 ) ); + SCROLLER_TRANSFORM + ); m_Scroller[p].SetName( ssprintf("ScrollerP%d",p+1) ); this->AddChild( &m_Scroller[p] ); diff --git a/stepmania/src/ScreenSelectMaster.h b/stepmania/src/ScreenSelectMaster.h index 2009f10394..d8f2743d25 100644 --- a/stepmania/src/ScreenSelectMaster.h +++ b/stepmania/src/ScreenSelectMaster.h @@ -56,8 +56,7 @@ protected: ThemeMetric SHOW_SCROLLER; ThemeMetric SCROLLER_SECONDS_PER_ITEM; ThemeMetric SCROLLER_NUM_ITEMS_TO_DRAW; - ThemeMetric SCROLLER_SPACING_X; - ThemeMetric SCROLLER_SPACING_Y; + ThemeMetric SCROLLER_TRANSFORM; ThemeMetric DEFAULT_CHOICE; int m_Next[NUM_MENU_DIRS][MAX_CHOICES];