From f8409a0dba984fedebdfff83064559e5b0401ea6 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Tue, 20 Sep 2011 16:51:20 -0500 Subject: [PATCH 01/30] add PlayerJoinedMessageCommand to PaneDisplay elements on ScreenSelectMusic; fixes issue 534 --- Themes/default/metrics.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Themes/default/metrics.ini b/Themes/default/metrics.ini index 4876a901d2..d345bdc396 100644 --- a/Themes/default/metrics.ini +++ b/Themes/default/metrics.ini @@ -940,24 +940,28 @@ PaneDisplayFrameP1X=SCREEN_CENTER_X-160 PaneDisplayFrameP1Y=SCREEN_BOTTOM-112-2 PaneDisplayFrameP1OnCommand=player,PLAYER_1;diffuse,Color("Orange");zoomy,0;sleep,0.5;decelerate,0.25;zoomy,1 PaneDisplayFrameP1OffCommand=bouncebegin,0.15;zoomx,0; +PaneDisplayFrameP1PlayerJoinedMessageCommand=%function(self,params) if params.Player == PLAYER_1 then self:playcommand("On") end end # ShowPaneDisplayTextP1=true PaneDisplayTextP1X=SCREEN_CENTER_X-160 PaneDisplayTextP1Y=SCREEN_BOTTOM-122-2 PaneDisplayTextP1OnCommand=player,PLAYER_1;zoomy,0;sleep,0.5;decelerate,0.25;zoomy,1 PaneDisplayTextP1OffCommand=bouncebegin,0.15;zoomx,0; +PaneDisplayTextP1PlayerJoinedMessageCommand=%function(self,params) if params.Player == PLAYER_1 then self:playcommand("On") end end # ShowPaneDisplayFrameP2=true PaneDisplayFrameP2X=SCREEN_CENTER_X+160 PaneDisplayFrameP2Y=SCREEN_BOTTOM-112-2 PaneDisplayFrameP2OnCommand=player,PLAYER_2;diffuse,Color("Orange");zoomy,0;sleep,0.5;decelerate,0.25;zoomy,1 PaneDisplayFrameP2OffCommand=bouncebegin,0.15;zoomx,0; +PaneDisplayFrameP2PlayerJoinedMessageCommand=%function(self,params) if params.Player == PLAYER_2 then self:playcommand("On") end end # ShowPaneDisplayTextP2=true PaneDisplayTextP2X=SCREEN_CENTER_X+160 PaneDisplayTextP2Y=SCREEN_BOTTOM-122-2 PaneDisplayTextP2OnCommand=player,PLAYER_2;zoomy,0;sleep,0.5;decelerate,0.25;zoomy,1 PaneDisplayTextP2OffCommand=bouncebegin,0.15;zoomx,0; +PaneDisplayTextP2PlayerJoinedMessageCommand=%function(self,params) if params.Player == PLAYER_2 then self:playcommand("On") end end # ShowCourseContentsList=false CourseContentsListX=SCREEN_CENTER_X-160 From 15ace8c0ef31b429c732946883b18a1e61693f04 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Tue, 20 Sep 2011 17:34:42 -0500 Subject: [PATCH 02/30] hide stage display on gameplay during course mode --- Themes/default/metrics.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Themes/default/metrics.ini b/Themes/default/metrics.ini index d345bdc396..415c7bad86 100644 --- a/Themes/default/metrics.ini +++ b/Themes/default/metrics.ini @@ -1340,7 +1340,7 @@ BPMDisplayY=SCREEN_BOTTOM-16 BPMDisplayOnCommand=draworder,101 BPMDisplayOffCommand=bounceend,0.25;zoom,0 # -ShowStageDisplay=true +ShowStageDisplay=not GAMESTATE:IsCourseMode() StageDisplayX=SCREEN_CENTER_X StageDisplayY=SCREEN_TOP+24 StageDisplayOnCommand=zoom,0.675; From 02d1250b9574ea804591db69c8b4896542ba886c Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Tue, 20 Sep 2011 17:35:51 -0500 Subject: [PATCH 03/30] small comment change --- Themes/default/Graphics/ScreenGameplay BPMDisplay.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua b/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua index 4230191d44..f0fbe7818e 100644 --- a/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua +++ b/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua @@ -11,7 +11,7 @@ local function UpdateSingleBPM(self) end local displaySingle = Def.ActorFrame{ - -- manual bpm displays + -- manual bpm display LoadFont("BPMDisplay", "bpm")..{ Name="BPMDisplay"; InitCommand=cmd(zoom,0.675;shadowlength,1); From d3634e343f03ca01131ad79e26aaba46b0dfc9ca Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Tue, 20 Sep 2011 17:40:07 -0500 Subject: [PATCH 04/30] remove unneeded logging --- src/CourseLoaderCRS.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CourseLoaderCRS.cpp b/src/CourseLoaderCRS.cpp index 76013b06be..92b3b190b6 100644 --- a/src/CourseLoaderCRS.cpp +++ b/src/CourseLoaderCRS.cpp @@ -165,7 +165,6 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou // todo: make sure these aren't generating bogus entries due // to a lack of songs. -aj int iNumSongs = SONGMAN->GetNumSongs(); - LOG->Trace("[CourseLoaderCRS] sParams[1] = %s",sParams[1].c_str()); // most played if( sParams[1].Left(strlen("BEST")) == "BEST" ) { From 2811f6887ae3bdbb78aea0a30905340345142b56 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Tue, 20 Sep 2011 23:54:00 -0500 Subject: [PATCH 05/30] sorry me, this isn't gonna work. --- Docs/Luadoc/LuaDocumentation.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index cea772098f..a2e1c28d65 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -1972,8 +1972,8 @@ Returns the current Premium. - - Kind of does what it says on the tin. + + Returns the smallest number of stages left for any human player. [01 compat.lua] Returns the current beat of the song. From 6d4b5c8e76b5948846d35cb1e1b59370b4432e76 Mon Sep 17 00:00:00 2001 From: Marcio Barrientos Date: Wed, 21 Sep 2011 16:21:23 -0600 Subject: [PATCH 06/30] Add one new Lua binding to add one more stage to player (bonus) AddStageToPlayer(pn) --- src/GameState.cpp | 8 ++++++++ src/GameState.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/GameState.cpp b/src/GameState.cpp index d9caa4f9b6..22cea682f3 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -1459,6 +1459,12 @@ void GameState::RemoveAllActiveAttacks() // called on end of song m_pPlayerState[p]->RemoveActiveAttacks(); } +void GameState::AddStageToPlayer( PlayerNumber pn ) +{ + // Add one stage more to player (bonus) -cerbo + ++m_iPlayerStageTokens[pn]; +} + template void setmin( T &a, const T &b ) { @@ -2430,6 +2436,7 @@ public: lua_pushboolean(L, p->m_bDopefish); return 1; } + static int AddStageToPlayer( T* p, lua_State *L ) { p->AddStageToPlayer(Enum::Check(L, 1)); return 0; } LunaGameState() { @@ -2531,6 +2538,7 @@ public: ADD_METHOD( SetCharacter ); ADD_METHOD( GetExpandedSectionName ); ADD_METHOD( Dopefish ); + ADD_METHOD( AddStageToPlayer ); } }; diff --git a/src/GameState.h b/src/GameState.h index c78f4ce7f2..fadb709559 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -62,6 +62,7 @@ public: bool HaveProfileToLoad(); bool HaveProfileToSave(); void SaveLocalData(); + void AddStageToPlayer( PlayerNumber pn ); void LoadCurrentSettingsFromProfile( PlayerNumber pn ); /** * @brief Save the specified player's settings to his/her profile. From 9b4c2a4b71877117292b8d23661c7a4690467725 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Wed, 21 Sep 2011 22:24:32 -0500 Subject: [PATCH 07/30] [FadingBanner] Added LoadRandom(), LoadRoulette(), LoadFallback(), LoadCourseFallback(), GetBanner(int) Lua bindings. --- Docs/Changelog_sm5.txt | 8 ++++++-- src/FadingBanner.cpp | 10 ++++++++++ src/FadingBanner.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 2ed3ac9132..9ab22c7af5 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,10 +8,14 @@ ________________________________________________________________________________ StepMania 5.0 $next | 2011???? -------------------------------------------------------------------------------- +2011/09/21 +---------- +* [FadingBanner] Added LoadRandom(), LoadRoulette(), LoadFallback(), + LoadCourseFallback(), and GetBanner(int) Lua bindings. [AJ] + 2011/09/18 ---------- -* [Song] Added GetSampleStart() and GetSampleLength() - Lua bindings. [Wolfman2000] +* [Song] Added GetSampleStart() and GetSampleLength() Lua bindings. [Wolfman2000] 2011/09/16 ---------- diff --git a/src/FadingBanner.cpp b/src/FadingBanner.cpp index b64b8850d3..b2375eb293 100644 --- a/src/FadingBanner.cpp +++ b/src/FadingBanner.cpp @@ -295,6 +295,10 @@ public: return 0; } static int LoadFromSongGroup( T* p, lua_State *L ) { p->LoadFromSongGroup( SArg(1) ); return 0; } + static int LoadRandom( T* p, lua_State *L ) { p->LoadRandom(); return 0; } + static int LoadRoulette( T* p, lua_State *L ) { p->LoadRoulette(); return 0; } + static int LoadCourseFallback( T* p, lua_State *L ) { p->LoadCourseFallback(); return 0; } + static int LoadFallback( T* p, lua_State *L ) { p->LoadFallback(); return 0; } static int GetLatestIndex( T* p, lua_State *L ){ lua_pushnumber( L, p->GetLatestIndex() ); return 1; } LunaFadingBanner() @@ -306,7 +310,13 @@ public: ADD_METHOD( LoadFromCourse ); ADD_METHOD( LoadIconFromCharacter ); ADD_METHOD( LoadCardFromCharacter ); + ADD_METHOD( LoadRandom ); + ADD_METHOD( LoadRoulette ); + ADD_METHOD( LoadCourseFallback ); + ADD_METHOD( LoadFallback ); + //ADD_METHOD( LoadFromSortOrder ); ADD_METHOD( GetLatestIndex ); + //ADD_METHOD( GetBanner ); } }; diff --git a/src/FadingBanner.h b/src/FadingBanner.h index 4770eefd24..0389f42602 100644 --- a/src/FadingBanner.h +++ b/src/FadingBanner.h @@ -39,6 +39,7 @@ public: virtual void DrawPrimitives(); int GetLatestIndex(){ return m_iIndexLatest; } + Banner GetBanner(int i){ return m_Banner[i]; } // Lua void PushSelf( lua_State *L ); From 561bdeeeb8d0df5ea5da72ea1da6894e820a8553 Mon Sep 17 00:00:00 2001 From: Mark Cannon Date: Thu, 22 Sep 2011 09:19:20 -0400 Subject: [PATCH 08/30] fix unnecessary vector copy --- src/TimingData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 84f95877aa..cb20d14022 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -21,7 +21,7 @@ void TimingData::Copy( const TimingData& cpy ) FOREACH_TimingSegmentType( tst ) { - const vector vpSegs = cpy.m_avpTimingSegments[tst]; + const vector &vpSegs = cpy.m_avpTimingSegments[tst]; for( unsigned i = 0; i < vpSegs.size(); ++i ) AddSegment( vpSegs[i] ); From 8ae8bab984099da1bdae467f3f139ce90a89ad40 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Thu, 22 Sep 2011 19:09:58 -0500 Subject: [PATCH 09/30] [ScreenDebugOverlay] Replaced hardcoded toggle command with ButtonTextToggledCommand metric. --- Docs/Changelog_sm5.txt | 5 +++++ Themes/_fallback/metrics.ini | 3 +-- src/ScreenDebugOverlay.cpp | 12 ++---------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 9ab22c7af5..be36c2b166 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,6 +8,11 @@ ________________________________________________________________________________ StepMania 5.0 $next | 2011???? -------------------------------------------------------------------------------- +2011/09/22 +---------- +* [ScreenDebugOverlay] Replaced hardcoded toggle command with + ButtonTextToggledCommand metric. [AJ] + 2011/09/21 ---------- * [FadingBanner] Added LoadRandom(), LoadRoulette(), LoadFallback(), diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index 65fed6206f..c4f289c381 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -1355,6 +1355,7 @@ LineButtonX=SCREEN_CENTER_X-50 LineFunctionX=SCREEN_CENTER_X-30 ButtonTextOnCommand=NoStroke;zoom,0.8 +ButtonTextToggledCommand=accelerate,0.025;glow,color("1,0,0,1");sleep,0.125;decelerate,0.2;glow,color("1,0,0,0"); FunctionTextOnCommand=NoStroke;zoom,0.8 PageStartX=SCREEN_CENTER_X-100 @@ -1372,8 +1373,6 @@ HeaderTextX=SCREEN_LEFT+80 HeaderTextY=SCREEN_TOP+18 HeaderTextOnCommand=diffusebottomedge,color("0.5,0.5,0.5,1");strokecolor,color("0,0,0,0.5") HeaderTextOffCommand= - -LineOnCommand=zoom,0.75 # [ScreenSystemLayer] diff --git a/src/ScreenDebugOverlay.cpp b/src/ScreenDebugOverlay.cpp index 4b698123b7..1ca2b3c179 100644 --- a/src/ScreenDebugOverlay.cpp +++ b/src/ScreenDebugOverlay.cpp @@ -496,18 +496,10 @@ bool ScreenDebugOverlay::OverlayInput( const InputEventPlus &input ) // update text to show the effect of what changed above UpdateText(); - // blink the text to show what changed + // show what changed BitmapText &bt = *m_vptextButton[i]; bt.FinishTweening(); - // blink 5 times instead of 8 - // TODO: make this all metrics instead -aj - for( i=0; i<5; i++ ) - { - bt.SetGlow( RageColor(1,0,0,1) ); - bt.Sleep(0.1f); - bt.SetGlow( RageColor(1,0,0,0) ); - bt.Sleep(0.1f); - } + bt.PlayCommand("Toggled"); return true; } From 1adbad77138434867f68241f9b5ed384865373e2 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Thu, 22 Sep 2011 19:25:18 -0500 Subject: [PATCH 10/30] redir to _blank in an attempt to fix issue 530 --- .../_fallback/Graphics/MusicWheelItem Portal NormalPart.redir | 2 +- Themes/_fallback/Graphics/MusicWheelItem Portal OverPart.redir | 2 +- .../_fallback/Graphics/MusicWheelItem Random NormalPart.redir | 2 +- Themes/_fallback/Graphics/MusicWheelItem Random OverPart.redir | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Themes/_fallback/Graphics/MusicWheelItem Portal NormalPart.redir b/Themes/_fallback/Graphics/MusicWheelItem Portal NormalPart.redir index c94ae9b2f3..04b2ead777 100644 --- a/Themes/_fallback/Graphics/MusicWheelItem Portal NormalPart.redir +++ b/Themes/_fallback/Graphics/MusicWheelItem Portal NormalPart.redir @@ -1 +1 @@ -MusicWheelItem Roulette NormalPart \ No newline at end of file +_blank \ No newline at end of file diff --git a/Themes/_fallback/Graphics/MusicWheelItem Portal OverPart.redir b/Themes/_fallback/Graphics/MusicWheelItem Portal OverPart.redir index c94ae9b2f3..04b2ead777 100644 --- a/Themes/_fallback/Graphics/MusicWheelItem Portal OverPart.redir +++ b/Themes/_fallback/Graphics/MusicWheelItem Portal OverPart.redir @@ -1 +1 @@ -MusicWheelItem Roulette NormalPart \ No newline at end of file +_blank \ No newline at end of file diff --git a/Themes/_fallback/Graphics/MusicWheelItem Random NormalPart.redir b/Themes/_fallback/Graphics/MusicWheelItem Random NormalPart.redir index c94ae9b2f3..04b2ead777 100644 --- a/Themes/_fallback/Graphics/MusicWheelItem Random NormalPart.redir +++ b/Themes/_fallback/Graphics/MusicWheelItem Random NormalPart.redir @@ -1 +1 @@ -MusicWheelItem Roulette NormalPart \ No newline at end of file +_blank \ No newline at end of file diff --git a/Themes/_fallback/Graphics/MusicWheelItem Random OverPart.redir b/Themes/_fallback/Graphics/MusicWheelItem Random OverPart.redir index c94ae9b2f3..04b2ead777 100644 --- a/Themes/_fallback/Graphics/MusicWheelItem Random OverPart.redir +++ b/Themes/_fallback/Graphics/MusicWheelItem Random OverPart.redir @@ -1 +1 @@ -MusicWheelItem Roulette NormalPart \ No newline at end of file +_blank \ No newline at end of file From 8d528625de9e9d700c15c294102a15abb46e08d3 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Thu, 22 Sep 2011 20:19:27 -0500 Subject: [PATCH 11/30] [LoadingWindow_Win32] Make the StepMania window gain focus after the loading window closes. Fixes issue 424. --- Docs/Changelog_sm5.txt | 2 + .../LoadingWindow/LoadingWindow_Win32.cpp | 160 +++--------------- src/arch/LoadingWindow/LoadingWindow_Win32.h | 23 +-- 3 files changed, 24 insertions(+), 161 deletions(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index be36c2b166..0d55728394 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -12,6 +12,8 @@ StepMania 5.0 $next | 2011???? ---------- * [ScreenDebugOverlay] Replaced hardcoded toggle command with ButtonTextToggledCommand metric. [AJ] +* [LoadingWindow_Win32] Make the StepMania window gain focus after the + loading window closes. Fixes issue 424. [AJ] 2011/09/21 ---------- diff --git a/src/arch/LoadingWindow/LoadingWindow_Win32.cpp b/src/arch/LoadingWindow/LoadingWindow_Win32.cpp index 80aef89071..bbc4c05efe 100644 --- a/src/arch/LoadingWindow/LoadingWindow_Win32.cpp +++ b/src/arch/LoadingWindow/LoadingWindow_Win32.cpp @@ -19,9 +19,7 @@ #include "RageSurfaceUtils_Zoom.h" static HBITMAP g_hBitmap = NULL; -#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") - -// Load a RageSurface into a GDI surface. +/* Load a RageSurface into a GDI surface. */ static HBITMAP LoadWin32Surface( RageSurface *&s ) { RageSurfaceUtils::ConvertSurface( s, s->w, s->h, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0 ); @@ -35,14 +33,14 @@ static HBITMAP LoadWin32Surface( RageSurface *&s ) HDC BitmapDC = CreateCompatibleDC( hScreen ); SelectObject( BitmapDC, bitmap ); - // This is silly, but simple. We only do this once, on a small image. + /* This is silly, but simple. We only do this once, on a small image. */ for( int y = 0; y < s->h; ++y ) { unsigned const char *line = ((unsigned char *) s->pixels) + (y * s->pitch); for( int x = 0; x < s->w; ++x ) { unsigned const char *data = line + (x*s->format->BytesPerPixel); - + SetPixelV( BitmapDC, x, y, RGB( data[3], data[2], data[1] ) ); } } @@ -62,7 +60,7 @@ static HBITMAP LoadWin32Surface( RString sFile, HWND hWnd ) if( pSurface == NULL ) return NULL; - /* Resize the splash image to fit the dialog. Stretch to fit horizontally, + /* Resize the splash image to fit the dialog. Stretch to fit horizontally, * maintaining aspect ratio. */ { RECT r; @@ -80,43 +78,8 @@ static HBITMAP LoadWin32Surface( RString sFile, HWND hWnd ) return ret; } -INT_PTR CALLBACK LoadingWindow_Win32::DlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +BOOL CALLBACK LoadingWindow_Win32::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { - LoadingWindow_Win32 *self; - - if(msg==WM_INITDIALOG) { - self=(LoadingWindow_Win32 *)lParam; - SetWindowLong(hWnd,DWL_USER,(LONG)self); - } else { - self=(LoadingWindow_Win32 *)GetWindowLong(hWnd,DWL_USER); - } - -/* -#if WINVER >= 0x0601 - if (self && msg == self->taskbarCreatedEvent && !self->pTaskbarList) { - HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&self->pTaskbarList)); - if (SUCCEEDED(hr)) { - self->pTaskbarList->HrInit(); - if (FAILED(hr)) { - self->pTaskbarList->Release(); - self->pTaskbarList = NULL; - } else { - - - if(self->m_indeterminate) { - self->pTaskbarList->SetProgressState(hWnd, TBPF_INDETERMINATE); - } else { - self->pTaskbarList->SetProgressState(hWnd, TBPF_NORMAL); - self->pTaskbarList->SetProgressValue(hWnd, self->m_progress, self->m_totalWork); - } - } - } - - - } -#endif -*/ - switch( msg ) { case WM_INITDIALOG: @@ -134,36 +97,11 @@ INT_PTR CALLBACK LoadingWindow_Win32::DlgProc( HWND hWnd, UINT msg, WPARAM wPara (WPARAM) IMAGE_BITMAP, (LPARAM) (HANDLE) g_hBitmap ); SetWindowTextA( hWnd, PRODUCT_ID ); - break; - case WM_CLOSE: - HOOKS->SetUserQuit(); - return FALSE; - case WM_DESTROY: - -/* -#if(WINVER >= 0x0601) - if (self->pTaskbarList) { - self->pTaskbarList->Release(); - self->pTaskbarList = NULL; - } -#endif -*/ - DeleteObject( g_hBitmap ); g_hBitmap = NULL; - self->runMessageLoop=false; - self->hwnd=NULL; - return TRUE; - break; - - case WM_APP: - DestroyWindow(hWnd); - self->runMessageLoop=false; - ExitThread(0); - return TRUE; break; } @@ -172,7 +110,7 @@ INT_PTR CALLBACK LoadingWindow_Win32::DlgProc( HWND hWnd, UINT msg, WPARAM wPara void LoadingWindow_Win32::SetIcon( const RageSurface *pIcon ) { - if( g_hBitmap != NULL ) + if( m_hIcon != NULL ) DestroyIcon( m_hIcon ); m_hIcon = IconFromSurface( pIcon ); @@ -201,64 +139,35 @@ void LoadingWindow_Win32::SetSplash( const RString sPath ) } LoadingWindow_Win32::LoadingWindow_Win32() -{ - - INITCOMMONCONTROLSEX cceData; - cceData.dwSize=sizeof(INITCOMMONCONTROLSEX); - cceData.dwICC=ICC_PROGRESS_CLASS; - InitCommonControlsEx(&cceData); - -/* -#if(WINVER >= 0x0601) - pTaskbarList=NULL; - - taskbarCreatedEvent=RegisterWindowMessage("TaskbarButtonCreated"); -#endif -*/ - +{ m_hIcon = NULL; - - runMessageLoop=true; - - guiReadyEvent=CreateEvent(NULL,FALSE,FALSE,NULL); - - pumpThread=CreateThread(NULL, NULL, MessagePump, (void *)this, 0, &pumpThreadId); - - WaitForSingleObject(guiReadyEvent,INFINITE); - + hwnd = CreateDialog( handle.Get(), MAKEINTRESOURCE(IDD_LOADING_DIALOG), NULL, WndProc ); for( unsigned i = 0; i < 3; ++i ) text[i] = "ABC"; /* always set on first call */ SetText( "" ); + Paint(); } LoadingWindow_Win32::~LoadingWindow_Win32() { - SendMessage(hwnd,WM_APP,0,0); - //SendMessage(hwnd,WM_NULL,0,0); - WaitForSingleObject(pumpThread,INFINITE); - if(guiReadyEvent) - CloseHandle(guiReadyEvent); + if( hwnd ) + DestroyWindow( hwnd ); if( m_hIcon != NULL ) DestroyIcon( m_hIcon ); } -DWORD WINAPI LoadingWindow_Win32::MessagePump(LPVOID thisAsVoidPtr) +void LoadingWindow_Win32::Paint() { - LoadingWindow_Win32 *self=(LoadingWindow_Win32 *)thisAsVoidPtr; + SendMessage( hwnd, WM_PAINT, 0, 0 ); - self->hwnd = CreateDialogParam( self->handle.Get(), MAKEINTRESOURCE(IDD_LOADING_DIALOG), NULL, DlgProc, (LPARAM)thisAsVoidPtr); - - SetEvent(self->guiReadyEvent); - - // Run the message loop in a separate thread to keep the gui responsive during the loading + /* Process all queued messages since the last paint. This allows the window to + * come back if it loses focus during load. */ MSG msg; - while(self->runMessageLoop && GetMessage(&msg, self->hwnd, 0, 0 ) ) + while( PeekMessage( &msg, hwnd, 0, 0, PM_NOREMOVE ) ) { - if(IsDialogMessage(self->hwnd,&msg)) continue; + GetMessage(&msg, hwnd, 0, 0 ); DispatchMessage( &msg ); } - - return msg.wParam; } void LoadingWindow_Win32::SetText( RString sText ) @@ -267,7 +176,7 @@ void LoadingWindow_Win32::SetText( RString sText ) split( sText, "\n", asMessageLines, false ); while( asMessageLines.size() < 3 ) asMessageLines.push_back( "" ); - + const int msgid[] = { IDC_STATIC_MESSAGE1, IDC_STATIC_MESSAGE2, IDC_STATIC_MESSAGE3 }; for( unsigned i = 0; i < 3; ++i ) { @@ -276,7 +185,6 @@ void LoadingWindow_Win32::SetText( RString sText ) text[i] = asMessageLines[i]; HWND hwndItem = ::GetDlgItem( hwnd, msgid[i] ); - ::SetWindowText( hwndItem, ConvertUTF8ToACP(asMessageLines[i]).c_str() ); } } @@ -286,13 +194,6 @@ void LoadingWindow_Win32::SetProgress(const int progress) m_progress=progress; HWND hwndItem = ::GetDlgItem( hwnd, IDC_PROGRESS ); ::SendMessage(hwndItem,PBM_SETPOS,progress,0); -/* -#if(WINVER >= 0x0601) - if(pTaskbarList) { - pTaskbarList->SetProgressValue(hwnd, m_progress, m_totalWork); - } -#endif -*/ } void LoadingWindow_Win32::SetTotalWork(const int totalWork) @@ -300,42 +201,21 @@ void LoadingWindow_Win32::SetTotalWork(const int totalWork) m_totalWork=totalWork; HWND hwndItem = ::GetDlgItem( hwnd, IDC_PROGRESS ); SendMessage(hwndItem,PBM_SETRANGE32,0,totalWork); -/* -#if(WINVER >= 0x0601) - if(pTaskbarList) { - pTaskbarList->SetProgressValue(hwnd, m_progress, m_totalWork); - } -#endif -*/ } -void LoadingWindow_Win32::SetIndeterminate(bool indeterminate) { +void LoadingWindow_Win32::SetIndeterminate(bool indeterminate) +{ m_indeterminate=indeterminate; HWND hwndItem = ::GetDlgItem( hwnd, IDC_PROGRESS ); if(indeterminate) { -/* -#if(WINVER >= 0x0601) - if(pTaskbarList) { - pTaskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE); - } -#endif -*/ SetWindowLong(hwndItem,GWL_STYLE, PBS_MARQUEE | GetWindowLong(hwndItem,GWL_STYLE)); SendMessage(hwndItem,PBM_SETMARQUEE,1,0); } else { SendMessage(hwndItem,PBM_SETMARQUEE,0,0); SetWindowLong(hwndItem,GWL_STYLE, (~PBS_MARQUEE) & GetWindowLong(hwndItem,GWL_STYLE)); -/* -#if(WINVER >= 0x0601) - if(pTaskbarList) { - pTaskbarList->SetProgressState(hwnd, TBPF_NORMAL); - } -#endif -*/ } - } /* diff --git a/src/arch/LoadingWindow/LoadingWindow_Win32.h b/src/arch/LoadingWindow/LoadingWindow_Win32.h index cac230bfcb..f2131f1bf7 100644 --- a/src/arch/LoadingWindow/LoadingWindow_Win32.h +++ b/src/arch/LoadingWindow/LoadingWindow_Win32.h @@ -3,22 +3,17 @@ #ifndef LOADING_WINDOW_WIN32_H #define LOADING_WINDOW_WIN32_H -#include "global.h" - #include "LoadingWindow.h" #include #include "archutils/Win32/AppInstance.h" -#if(WINVER >= 0x0601) -#include "Shobjidl.h" -#endif - class LoadingWindow_Win32: public LoadingWindow { public: LoadingWindow_Win32(); ~LoadingWindow_Win32(); + void Paint(); void SetText( RString sText ); void SetIcon( const RageSurface *pIcon ); void SetSplash( const RString sPath ); @@ -31,22 +26,8 @@ private: HWND hwnd; RString text[3]; HICON m_hIcon; - HANDLE pumpThread; - DWORD pumpThreadId; - HANDLE guiReadyEvent; -/* -#if WINVER >= 0x0601 - UINT taskbarCreatedEvent; - ITaskbarList3 *pTaskbarList; -#endif -*/ - - volatile bool runMessageLoop; - - static DWORD WINAPI MessagePump(LPVOID thisAsVoidPtr); - - static INT_PTR CALLBACK DlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); + static BOOL CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); }; #define USE_LOADING_WINDOW_WIN32 From d782518c14c2d848693b75c3dd6a593711dcdb81 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Fri, 23 Sep 2011 01:26:53 -0500 Subject: [PATCH 12/30] [ScreenEvaluation] Added RollingNumbersMaxComboClass metric. (also removed unused MaxComboNumDigits metric from C++-side) --- Docs/Changelog_sm5.txt | 4 ++++ Themes/_fallback/metrics.ini | 4 ++++ src/ScreenEvaluation.cpp | 7 +++++-- src/ScreenEvaluation.h | 1 + src/TimingData.cpp | 4 ++-- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 0d55728394..0e0cbe5da2 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,6 +8,10 @@ ________________________________________________________________________________ StepMania 5.0 $next | 2011???? -------------------------------------------------------------------------------- +2011/09/23 +---------- +* [ScreenEvaluation] Added RollingNumbersMaxComboClass metric. [AJ] + 2011/09/22 ---------- * [ScreenDebugOverlay] Replaced hardcoded toggle command with diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index c4f289c381..c4632c8e81 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -1085,6 +1085,9 @@ TextFormat="%04.0f" ApproachSeconds=1 Commify=false +[RollingNumbersMaxCombo] +Fallback="RollingNumbersJudgment" + [ScoreDisplayNormal] FrameX= FrameY= @@ -3232,6 +3235,7 @@ MaxComboNumDigits=4 # ShowBannerArea=true RollingNumbersClass="RollingNumbersJudgment" +RollingNumbersMaxComboClass="RollingNumbersMaxCombo" # ShowSharedJudgmentLineLabels=false ShowJudgmentLineW1=false diff --git a/src/ScreenEvaluation.cpp b/src/ScreenEvaluation.cpp index a75413fb9d..6ce6976bd3 100644 --- a/src/ScreenEvaluation.cpp +++ b/src/ScreenEvaluation.cpp @@ -66,7 +66,6 @@ XToString( DetailLine ); #define SHOW_SCORE_AREA THEME->GetMetricB(m_sName,"ShowScoreArea") #define SHOW_TIME_AREA THEME->GetMetricB(m_sName,"ShowTimeArea") #define SHOW_RECORDS_AREA THEME->GetMetricB(m_sName,"ShowRecordsArea") -#define MAX_COMBO_NUM_DIGITS THEME->GetMetricI(m_sName,"MaxComboNumDigits") #define PLAYER_OPTIONS_HIDE_FAIL_TYPE THEME->GetMetricB(m_sName,"PlayerOptionsHideFailType") #define PLAYER_OPTIONS_SEPARATOR THEME->GetMetric (m_sName,"PlayerOptionsSeparator") #define CHECKPOINTS_WITH_JUDGMENTS THEME->GetMetricB(m_sName,"CheckpointsWithJudgments") @@ -460,6 +459,7 @@ void ScreenEvaluation::Init() // init judgment area ROLLING_NUMBERS_CLASS.Load( m_sName, "RollingNumbersClass" ); + ROLLING_NUMBERS_MAX_COMBO_CLASS.Load( m_sName, "RollingNumbersMaxComboClass" ); FOREACH_ENUM( JudgmentLine, l ) { if( l == JudgmentLine_W1 && !GAMESTATE->ShowW1() ) @@ -481,7 +481,10 @@ void ScreenEvaluation::Init() { m_textJudgmentLineNumber[l][p].LoadFromFont( THEME->GetPathF(m_sName, "JudgmentLineNumber") ); m_textJudgmentLineNumber[l][p].SetName( JudgmentLineToString(l)+ssprintf("NumberP%d",p+1) ); - m_textJudgmentLineNumber[l][p].Load( ROLLING_NUMBERS_CLASS ); + if( JudgmentLineToString(l) == "MaxCombo" ) + m_textJudgmentLineNumber[l][p].Load( ROLLING_NUMBERS_MAX_COMBO_CLASS ); + else + m_textJudgmentLineNumber[l][p].Load( ROLLING_NUMBERS_CLASS ); ActorUtil::LoadAllCommands( m_textJudgmentLineNumber[l][p], m_sName ); SET_XY( m_textJudgmentLineNumber[l][p] ); this->AddChild( &m_textJudgmentLineNumber[l][p] ); diff --git a/src/ScreenEvaluation.h b/src/ScreenEvaluation.h index 5e14e159f1..454cb34b75 100644 --- a/src/ScreenEvaluation.h +++ b/src/ScreenEvaluation.h @@ -115,6 +115,7 @@ protected: ThemeMetric SUMMARY; ThemeMetric ROLLING_NUMBERS_CLASS; + ThemeMetric ROLLING_NUMBERS_MAX_COMBO_CLASS; /** @brief Did a player save a screenshot of their score? */ bool m_bSavedScreenshot[NUM_PLAYERS]; }; diff --git a/src/TimingData.cpp b/src/TimingData.cpp index cb20d14022..fa4adf89d6 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -36,7 +36,7 @@ void TimingData::Clear() vector &vSegs = m_avpTimingSegments[tst]; for( unsigned i = 0; i < vSegs.size(); ++i ) { - LOG->Trace( "deleting %p", vSegs[i] ); + //LOG->Trace( "deleting %p", vSegs[i] ); SAFE_DELETE( vSegs[i] ); } vSegs.clear(); @@ -323,7 +323,7 @@ static void EraseSegment( vector &vSegs, int index, TimingSegmen // so we must deep-copy it (with ::Copy) for new allocations. void TimingData::AddSegment( const TimingSegment *seg ) { - LOG->Trace( "AddSegment( %s )", TimingSegmentTypeToString(seg->GetType()).c_str() ); + //LOG->Trace( "AddSegment( %s )", TimingSegmentTypeToString(seg->GetType()).c_str() ); seg->DebugPrint(); TimingSegmentType tst = seg->GetType(); From 7010666e73d24f8988c2d231d71fe7169170b52d Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Fri, 23 Sep 2011 14:39:03 -0500 Subject: [PATCH 13/30] add ScreenNoise --- Themes/_fallback/metrics.ini | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index c4632c8e81..df37650ed5 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -4131,11 +4131,13 @@ BodyHeight=38 [ComboGraph] BodyWidth=140 -# Arcade +# Arcade ################################# [ScreenLogo] Fallback="ScreenAttract" PrevScreen=Branch.Init() -NextScreen="ScreenHowToPlay" +# crashes! +#NextScreen="ScreenHowToPlay" +NextScreen="ScreenDemonstration" StartScreen=Branch.TitleMenu() TimerSeconds=5 ForceTimer=true @@ -4179,19 +4181,10 @@ SongBPM=100 NumW2s=4 NumMisses=6 -[ScreenTitleJoin] -Fallback="ScreenTitleMenu" -ChoiceNames="GameStart" - -# ScrollerOnCommand=visible,false -IdleCommentSeconds=-1 -IdleTimeoutSeconds=-1 -IdleTimeoutScreen=Branch.AfterInit() - [ScreenDemonstration] Fallback="ScreenGameplay" Class="ScreenDemonstration" -NextScreen="ScreenInit" +NextScreen=Branch.NoiseTrigger() StartScreen=Branch.TitleMenu() PlayMusic=false SecondsToShow=60 @@ -4205,6 +4198,24 @@ AllowStyleTypes="TwoPlayersTwoSides" MinSecondsToStep=0 MinSecondsToMusic=0 +[ScreenNoise] +Fallback="ScreenAttract" +Class="ScreenAttract" +NextScreen="ScreenInit" +PrevScreen="ScreenInit" +TimerSeconds=10800 +ShowCreditDisplay=false + +[ScreenTitleJoin] +Fallback="ScreenTitleMenu" +ChoiceNames="GameStart" + +# ScrollerOnCommand=visible,false +IdleCommentSeconds=-1 +IdleTimeoutSeconds=-1 +IdleTimeoutScreen=Branch.AfterInit() + +# Jukebox ################### [ScreenJukeboxMenu] Class="ScreenOptionsMaster" Fallback="ScreenPlayerOptions" From fbc4a02b8fa63f40238aa041a12d72e056fd2a20 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Fri, 23 Sep 2011 14:40:11 -0500 Subject: [PATCH 14/30] forgot branch --- Themes/_fallback/Scripts/02 Branches.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Themes/_fallback/Scripts/02 Branches.lua b/Themes/_fallback/Scripts/02 Branches.lua index 05c7ebc05e..cc2a816ea8 100644 --- a/Themes/_fallback/Scripts/02 Branches.lua +++ b/Themes/_fallback/Scripts/02 Branches.lua @@ -40,6 +40,10 @@ Branch = { return "ScreenLogo" end end, + NoiseTrigger = function() + local hour = Hour() + return hour > 3 and hour < 6 and "ScreenNoise" or "ScreenInit" + end, TitleMenu = function() -- home mode is the most assumed use of sm-ssc. if GAMESTATE:GetCoinMode() == "CoinMode_Home" then From 210e88f45b221f7fb372c915b098514ce61c847f Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Fri, 23 Sep 2011 16:00:10 -0500 Subject: [PATCH 15/30] forgot to add ScreenNoise background :( --- .../ScreenNoise background/default.lua | 17 +++++++++++++++++ .../ScreenNoise background/noise.png | Bin 0 -> 312705 bytes 2 files changed, 17 insertions(+) create mode 100644 Themes/_fallback/BGAnimations/ScreenNoise background/default.lua create mode 100644 Themes/_fallback/BGAnimations/ScreenNoise background/noise.png diff --git a/Themes/_fallback/BGAnimations/ScreenNoise background/default.lua b/Themes/_fallback/BGAnimations/ScreenNoise background/default.lua new file mode 100644 index 0000000000..172373c4c1 --- /dev/null +++ b/Themes/_fallback/BGAnimations/ScreenNoise background/default.lua @@ -0,0 +1,17 @@ +local t = Def.ActorFrame{ + LoadActor("noise")..{ + Name="Noise"; + InitCommand=cmd(Center;texturewrapping,true;SetTextureFiltering,false;zoom,2;diffusealpha,0;); + OnCommand=cmd(linear,1;diffusealpha,1); + }; +}; + +local function Update(self) + local c = self:GetChild("Noise"); + local x = math.random(); + local y = math.random(); + c:customtexturerect(0+x,0+y,2+x,2+y); +end; +t.InitCommand = cmd(SetUpdateFunction,Update); + +return t; diff --git a/Themes/_fallback/BGAnimations/ScreenNoise background/noise.png b/Themes/_fallback/BGAnimations/ScreenNoise background/noise.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf9a395af6e7da065bd01009d618b50eb89e3e3 GIT binary patch literal 312705 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%0A1(;}ZVC|>vP3i20QK?U=6ctw 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 Date: Fri, 23 Sep 2011 16:00:23 -0500 Subject: [PATCH 16/30] attempt to fix the resolution problem by going back to the old code --- src/StepMania.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/StepMania.cpp b/src/StepMania.cpp index ac059341b1..def1d4ff86 100644 --- a/src/StepMania.cpp +++ b/src/StepMania.cpp @@ -80,10 +80,14 @@ static Preference g_bAllowMultipleInstances( "AllowMultipleInstances", fal void StepMania::GetPreferredVideoModeParams( VideoModeParams ¶msOut ) { - // unsure if this is still going to cause first run issues. -aj - float fAspectRatio = PREFSMAN->m_fDisplayAspectRatio; - int iHeight = PREFSMAN->m_iDisplayHeight; - int iWidth = ceilf(iHeight * fAspectRatio); + // resolution handling code that probably needs fixing + int iWidth = PREFSMAN->m_iDisplayWidth; + if( PREFSMAN->m_bWindowed ) + { + //float fRatio = PREFSMAN->m_iDisplayHeight; + //iWidth = PREFSMAN->m_iDisplayHeight * fRatio; + iWidth = static_cast(ceilf(PREFSMAN->m_iDisplayHeight * PREFSMAN->m_fDisplayAspectRatio)); + } // todo: allow for PRODUCT_ID + "-" + CommonMetrics::WINDOW_TITLE as // a theme option (Midi requested it, AJ had the idea for making it optional) From 6fed94a21069e8e66dcf08f4cc5478612f069703 Mon Sep 17 00:00:00 2001 From: Colby Klein Date: Fri, 23 Sep 2011 15:39:54 -0700 Subject: [PATCH 17/30] Move Actors into a folder. The very beginning of organizing things. This WILL break compile. --- src/Actors/Actor.cpp | 1746 ++++++++++++++++++++++++++++++ src/Actors/Actor.h | 755 +++++++++++++ src/Actors/ActorFrame.cpp | 633 +++++++++++ src/Actors/ActorFrame.h | 164 +++ src/Actors/ActorFrameTexture.cpp | 127 +++ src/Actors/ActorFrameTexture.h | 88 ++ src/Actors/ActorMultiTexture.cpp | 215 ++++ src/Actors/ActorMultiTexture.h | 73 ++ src/Actors/ActorProxy.cpp | 90 ++ src/Actors/ActorProxy.h | 54 + src/Actors/ActorScroller.cpp | 397 +++++++ src/Actors/ActorScroller.h | 123 +++ src/Actors/ActorSound.cpp | 103 ++ src/Actors/ActorSound.h | 56 + 14 files changed, 4624 insertions(+) create mode 100644 src/Actors/Actor.cpp create mode 100644 src/Actors/Actor.h create mode 100644 src/Actors/ActorFrame.cpp create mode 100644 src/Actors/ActorFrame.h create mode 100644 src/Actors/ActorFrameTexture.cpp create mode 100644 src/Actors/ActorFrameTexture.h create mode 100644 src/Actors/ActorMultiTexture.cpp create mode 100644 src/Actors/ActorMultiTexture.h create mode 100644 src/Actors/ActorProxy.cpp create mode 100644 src/Actors/ActorProxy.h create mode 100644 src/Actors/ActorScroller.cpp create mode 100644 src/Actors/ActorScroller.h create mode 100644 src/Actors/ActorSound.cpp create mode 100644 src/Actors/ActorSound.h diff --git a/src/Actors/Actor.cpp b/src/Actors/Actor.cpp new file mode 100644 index 0000000000..917f4cc45f --- /dev/null +++ b/src/Actors/Actor.cpp @@ -0,0 +1,1746 @@ +#include "global.h" +#include "Actor.h" +#include "RageDisplay.h" +#include "RageUtil.h" +#include "RageMath.h" +#include "RageLog.h" +#include "arch/Dialog/Dialog.h" +#include "Foreach.h" +#include "XmlFile.h" +#include "LuaBinding.h" +#include "ThemeManager.h" +#include "LuaReference.h" +#include "MessageManager.h" +#include "LightsManager.h" // for NUM_CabinetLight +#include "ActorUtil.h" +#include "Preference.h" +#include + +static Preference g_bShowMasks("ShowMasks", false); + +/** + * @brief Set up a hidden Actor that won't be drawn. + * + * It's useful to be able to construct a basic Actor in XML, in + * order to simply delay a Transition, or receive and send broadcasts. + * Since these actors will never draw, set them hidden by default. */ +class HiddenActor: public Actor +{ +public: + HiddenActor() { SetVisible(false); } + virtual HiddenActor *Copy() const; +}; +REGISTER_ACTOR_CLASS_WITH_NAME( HiddenActor, Actor ); + +float Actor::g_fCurrentBGMTime = 0, Actor::g_fCurrentBGMBeat; +float Actor::g_fCurrentBGMTimeNoOffset = 0, Actor::g_fCurrentBGMBeatNoOffset = 0; +vector Actor::g_vfCurrentBGMBeatPlayer(NUM_PlayerNumber, 0); +vector Actor::g_vfCurrentBGMBeatPlayerNoOffset(NUM_PlayerNumber, 0); + + +Actor *Actor::Copy() const { return new Actor(*this); } + +static float g_fCabinetLights[NUM_CabinetLight]; + +static const char *HorizAlignNames[] = { + "Left", + "Center", + "Right" +}; +XToString( HorizAlign ); +LuaXType( HorizAlign ); + +static const char *VertAlignNames[] = { + "Top", + "Middle", + "Bottom" +}; +XToString( VertAlign ); +LuaXType( VertAlign ); + +void Actor::SetBGMTime( float fTime, float fBeat, float fTimeNoOffset, float fBeatNoOffset ) +{ + g_fCurrentBGMTime = fTime; + g_fCurrentBGMBeat = fBeat; + + /* This timer is generally only used for effects tied to the background music + * when GameSoundManager is aligning music beats. Alignment doesn't handle + * g_fVisualDelaySeconds. */ + g_fCurrentBGMTimeNoOffset = fTimeNoOffset; + g_fCurrentBGMBeatNoOffset = fBeatNoOffset; +} + +void Actor::SetPlayerBGMBeat( PlayerNumber pn, float fBeat, float fBeatNoOffset ) +{ + g_vfCurrentBGMBeatPlayer[pn] = fBeat; + g_vfCurrentBGMBeatPlayerNoOffset[pn] = fBeatNoOffset; +} + +void Actor::SetBGMLight( int iLightNumber, float fCabinetLights ) +{ + ASSERT( iLightNumber < NUM_CabinetLight ); + g_fCabinetLights[iLightNumber] = fCabinetLights; +} + +void Actor::InitState() +{ + StopTweening(); + + m_pTempState = NULL; + + m_baseRotation = RageVector3( 0, 0, 0 ); + m_baseScale = RageVector3( 1, 1, 1 ); + m_fBaseAlpha = 1; + + m_start.Init(); + m_current.Init(); + + m_fHorizAlign = 0.5f; + m_fVertAlign = 0.5f; +#if defined(SSC_FUTURES) + for( unsigned i = 0; i < m_Effects.size(); ++i ) + m_Effects[i] = no_effect; +#else + m_Effect = no_effect; +#endif + m_fSecsIntoEffect = 0; + m_fEffectDelta = 0; + m_fEffectRampUp = 0.5f; + m_fEffectHoldAtHalf = 0; + m_fEffectRampDown = 0.5f; + m_fEffectHoldAtZero = 0; + m_fEffectOffset = 0; + m_EffectClock = CLOCK_TIMER; + m_vEffectMagnitude = RageVector3(0,0,10); + m_effectColor1 = RageColor(1,1,1,1); + m_effectColor2 = RageColor(1,1,1,1); + + m_bVisible = true; + m_fShadowLengthX = 0; + m_fShadowLengthY = 0; + m_ShadowColor = RageColor(0,0,0,0.5f); + m_bIsAnimating = true; + m_fHibernateSecondsLeft = 0; + m_iDrawOrder = 0; + + m_bTextureWrapping = false; + m_bTextureFiltering = true; + + m_BlendMode = BLEND_NORMAL; + m_fZBias = 0; + m_bClearZBuffer = false; + m_ZTestMode = ZTEST_OFF; + m_bZWrite = false; + m_CullMode = CULL_NONE; +} + +static bool GetMessageNameFromCommandName( const RString &sCommandName, RString &sMessageNameOut ) +{ + if( sCommandName.Right(7) == "Message" ) + { + sMessageNameOut = sCommandName.Left(sCommandName.size()-7); + return true; + } + else + { + return false; + } +} + +Actor::Actor() +{ + m_pLuaInstance = new LuaClass; + Lua *L = LUA->Get(); + m_pLuaInstance->PushSelf( L ); + lua_newtable( L ); + lua_pushvalue( L, -1 ); + lua_setmetatable( L, -2 ); + lua_setfield( L, -2, "ctx" ); + lua_pop( L, 1 ); + LUA->Release( L ); + + m_size = RageVector2( 1, 1 ); + InitState(); + m_pParent = NULL; + m_bFirstUpdate = true; +} + +Actor::~Actor() +{ + StopTweening(); + UnsubscribeAll(); +} + +Actor::Actor( const Actor &cpy ): + MessageSubscriber( cpy ) +{ + /* Don't copy an Actor in the middle of rendering. */ + ASSERT( cpy.m_pTempState == NULL ); + m_pTempState = NULL; + +#define CPY(x) x = cpy.x + CPY( m_sName ); + CPY( m_pParent ); + CPY( m_pLuaInstance ); + + CPY( m_baseRotation ); + CPY( m_baseScale ); + CPY( m_fBaseAlpha ); + + + CPY( m_size ); + CPY( m_current ); + CPY( m_start ); + for( unsigned i = 0; i < cpy.m_Tweens.size(); ++i ) + m_Tweens.push_back( new TweenStateAndInfo(*cpy.m_Tweens[i]) ); + + CPY( m_bFirstUpdate ); + + CPY( m_fHorizAlign ); + CPY( m_fVertAlign ); +#if defined(SSC_FUTURES) + // I'm a bit worried about this -aj + for( unsigned i = 0; i < cpy.m_Effects.size(); ++i ) + m_Effects.push_back( (*cpy.m_Effects[i]) ); +#else + CPY( m_Effect ); +#endif + CPY( m_fSecsIntoEffect ); + CPY( m_fEffectDelta ); + CPY( m_fEffectRampUp ); + CPY( m_fEffectHoldAtHalf ); + CPY( m_fEffectRampDown ); + CPY( m_fEffectHoldAtZero ); + CPY( m_fEffectOffset ); + CPY( m_EffectClock ); + + CPY( m_effectColor1 ); + CPY( m_effectColor2 ); + CPY( m_vEffectMagnitude ); + + CPY( m_bVisible ); + CPY( m_fHibernateSecondsLeft ); + CPY( m_fShadowLengthX ); + CPY( m_fShadowLengthY ); + CPY( m_ShadowColor ); + CPY( m_bIsAnimating ); + CPY( m_iDrawOrder ); + + CPY( m_bTextureWrapping ); + CPY( m_bTextureFiltering ); + CPY( m_BlendMode ); + CPY( m_bClearZBuffer ); + CPY( m_ZTestMode ); + CPY( m_bZWrite ); + CPY( m_fZBias ); + CPY( m_CullMode ); + + CPY( m_mapNameToCommands ); +#undef CPY +} + +/* XXX: This calls InitCommand, which must happen after all other + * initialization (eg. ActorFrame loading children). However, it + * also loads input variables, which should happen first. The + * former is more important. */ +void Actor::LoadFromNode( const XNode* pNode ) +{ + Lua *L = LUA->Get(); + FOREACH_CONST_Attr( pNode, pAttr ) + { + // Load Name, if any. + const RString &sKeyName = pAttr->first; + const XNodeValue *pValue = pAttr->second; + if( sKeyName == "Name" ) SetName( pValue->GetValue() ); + else if( sKeyName == "BaseRotationX" ) SetBaseRotationX( pValue->GetValue() ); + else if( sKeyName == "BaseRotationY" ) SetBaseRotationY( pValue->GetValue() ); + else if( sKeyName == "BaseRotationZ" ) SetBaseRotationZ( pValue->GetValue() ); + else if( sKeyName == "BaseZoomX" ) SetBaseZoomX( pValue->GetValue() ); + else if( sKeyName == "BaseZoomY" ) SetBaseZoomY( pValue->GetValue() ); + else if( sKeyName == "BaseZoomZ" ) SetBaseZoomZ( pValue->GetValue() ); + else if( EndsWith(sKeyName,"Command") ) + { + LuaReference *pRef = new LuaReference; + pValue->PushValue( L ); + pRef->SetFromStack( L ); + RString sCmdName = sKeyName.Left( sKeyName.size()-7 ); + AddCommand( sCmdName, apActorCommands( pRef ) ); + } + } + + LUA->Release( L ); + + // Don't recurse Init. It gets called once for every Actor when the + // Actor is loaded, and we don't want to call it again. + PlayCommandNoRecurse( Message("Init") ); +} + +void Actor::Draw() +{ + if( !m_bVisible ) + return; // early abort + if( m_fHibernateSecondsLeft > 0 ) + return; // early abort + if( this->EarlyAbortDraw() ) + return; + + // 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 +{ + DISPLAY->PushMatrix(); // we're actually going to do some drawing in this function + + // Somthing below may set m_pTempState to tempState + m_pTempState = &m_current; + + // set temporary drawing properties based on Effects + static TweenState tempState; + + // todo: account for SSC_FUTURES -aj + if( m_Effect == no_effect ) + { + } + else + { + m_pTempState = &tempState; + tempState = m_current; + + const float fTotalPeriod = GetEffectPeriod(); + ASSERT( fTotalPeriod > 0 ); + const float fTimeIntoEffect = fmodfp( m_fSecsIntoEffect+m_fEffectOffset, fTotalPeriod ); + + float fPercentThroughEffect; + if( fTimeIntoEffect < m_fEffectRampUp ) + { + fPercentThroughEffect = SCALE( + fTimeIntoEffect, + 0, + m_fEffectRampUp, + 0.0f, + 0.5f ); + } + else if( fTimeIntoEffect < m_fEffectRampUp + m_fEffectHoldAtHalf ) + { + fPercentThroughEffect = 0.5f; + } + else if( fTimeIntoEffect < m_fEffectRampUp + m_fEffectHoldAtHalf + m_fEffectRampDown ) + { + fPercentThroughEffect = SCALE( + fTimeIntoEffect, + m_fEffectRampUp + m_fEffectHoldAtHalf, + m_fEffectRampUp + m_fEffectHoldAtHalf + m_fEffectRampDown, + 0.5f, + 1.0f ); + } + else + { + fPercentThroughEffect = 0; + } + ASSERT_M( fPercentThroughEffect >= 0 && fPercentThroughEffect <= 1, + ssprintf("PercentThroughEffect: %f", fPercentThroughEffect) ); + + bool bBlinkOn = fPercentThroughEffect > 0.5f; + float fPercentBetweenColors = RageFastSin( (fPercentThroughEffect + 0.25f) * 2 * PI ) / 2 + 0.5f; + ASSERT_M( fPercentBetweenColors >= 0 && fPercentBetweenColors <= 1, + ssprintf("PercentBetweenColors: %f, PercentThroughEffect: %f", fPercentBetweenColors, fPercentThroughEffect) ); + float fOriginalAlpha = tempState.diffuse[0].a; + + // todo: account for SSC_FUTURES -aj + 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.) */ + for(int i=0; i<4; i++) + { + tempState.diffuse[i] = bBlinkOn ? m_effectColor1 : m_effectColor2; + tempState.diffuse[i].a *= fOriginalAlpha; // multiply the alphas so we can fade even while an effect is playing + } + break; + case diffuse_shift: + for(int i=0; i<4; i++) + { + tempState.diffuse[i] = m_effectColor1*fPercentBetweenColors + m_effectColor2*(1.0f-fPercentBetweenColors); + tempState.diffuse[i].a *= fOriginalAlpha; // multiply the alphas so we can fade even while an effect is playing + } + break; + case diffuse_ramp: + for(int i=0; i<4; i++) + { + tempState.diffuse[i] = m_effectColor1*fPercentThroughEffect + m_effectColor2*(1.0f-fPercentThroughEffect); + tempState.diffuse[i].a *= fOriginalAlpha; // multiply the alphas so we can fade even while an effect is playing + } + break; + case glow_blink: + tempState.glow = bBlinkOn ? m_effectColor1 : m_effectColor2; + tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent! + break; + case glow_shift: + tempState.glow = m_effectColor1*fPercentBetweenColors + m_effectColor2*(1.0f-fPercentBetweenColors); + tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent! + break; + case glow_ramp: + tempState.glow = m_effectColor1*fPercentThroughEffect + m_effectColor2*(1.0f-fPercentThroughEffect); + tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent! + break; + case rainbow: + tempState.diffuse[0] = RageColor( + RageFastCos( fPercentBetweenColors*2*PI ) * 0.5f + 0.5f, + RageFastCos( fPercentBetweenColors*2*PI + PI * 2.0f / 3.0f ) * 0.5f + 0.5f, + RageFastCos( fPercentBetweenColors*2*PI + PI * 4.0f / 3.0f) * 0.5f + 0.5f, + fOriginalAlpha ); + for( int i=1; i<4; i++ ) + tempState.diffuse[i] = tempState.diffuse[0]; + break; + case wag: + tempState.rotation += m_vEffectMagnitude * RageFastSin( fPercentThroughEffect * 2.0f * PI ); + break; + case spin: + // nothing needs to be here + break; + case vibrate: + tempState.pos.x += m_vEffectMagnitude.x * randomf(-1.0f, 1.0f) * GetZoom(); + tempState.pos.y += m_vEffectMagnitude.y * randomf(-1.0f, 1.0f) * GetZoom(); + tempState.pos.z += m_vEffectMagnitude.z * randomf(-1.0f, 1.0f) * GetZoom(); + break; + case bounce: + { + float fPercentOffset = RageFastSin( fPercentThroughEffect*PI ); + tempState.pos += m_vEffectMagnitude * fPercentOffset; + tempState.pos.x = roundf( tempState.pos.x ); + tempState.pos.y = roundf( tempState.pos.y ); + tempState.pos.z = roundf( tempState.pos.z ); + } + break; + case bob: + { + float fPercentOffset = RageFastSin( fPercentThroughEffect*PI*2 ); + tempState.pos += m_vEffectMagnitude * fPercentOffset; + tempState.pos.x = roundf( tempState.pos.x ); + tempState.pos.y = roundf( tempState.pos.y ); + tempState.pos.z = roundf( tempState.pos.z ); + } + break; + case pulse: + { + float fMinZoom = m_vEffectMagnitude[0]; + float fMaxZoom = m_vEffectMagnitude[1]; + float fPercentOffset = RageFastSin( fPercentThroughEffect*PI ); + float fZoom = SCALE( fPercentOffset, 0.f, 1.f, fMinZoom, fMaxZoom ); + tempState.scale *= fZoom; + + // Use the color as a Vector3 to scale the effect for added control + RageColor c = SCALE( fPercentOffset, 0.f, 1.f, m_effectColor1, m_effectColor2 ); + tempState.scale.x *= c.r; + tempState.scale.y *= c.g; + tempState.scale.z *= c.b; + } + break; + default: + ASSERT(0); // invalid Effect + } + } + + if( m_fBaseAlpha != 1 ) + { + if( m_pTempState != &tempState ) + { + m_pTempState = &tempState; + tempState = m_current; + } + + for( int i=0; i<4; i++ ) + tempState.diffuse[i].a *= m_fBaseAlpha; + } + + if( m_pTempState->pos.x != 0 || m_pTempState->pos.y != 0 || m_pTempState->pos.z != 0 ) + { + RageMatrix m; + RageMatrixTranslate( + &m, + m_pTempState->pos.x, + m_pTempState->pos.y, + m_pTempState->pos.z + ); + DISPLAY->PreMultMatrix( m ); + } + + { + /* The only time rotation and quat should normally be used simultaneously + * is for m_baseRotation. Most objects aren't rotated at all, so optimize + * that case. */ + const float fRotateX = m_pTempState->rotation.x + m_baseRotation.x; + const float fRotateY = m_pTempState->rotation.y + m_baseRotation.y; + const float fRotateZ = m_pTempState->rotation.z + m_baseRotation.z; + + if( fRotateX != 0 || fRotateY != 0 || fRotateZ != 0 ) + { + RageMatrix m; + RageMatrixRotationXYZ( &m, fRotateX, fRotateY, fRotateZ ); + DISPLAY->PreMultMatrix( m ); + } + } + + // handle scaling + { + const float fScaleX = m_pTempState->scale.x * m_baseScale.x; + const float fScaleY = m_pTempState->scale.y * m_baseScale.y; + const float fScaleZ = m_pTempState->scale.z * m_baseScale.z; + + if( fScaleX != 1 || fScaleY != 1 || fScaleZ != 1 ) + { + RageMatrix m; + RageMatrixScale( + &m, + fScaleX, + fScaleY, + fScaleZ ); + DISPLAY->PreMultMatrix( m ); + } + } + + // handle alignment; most actors have default alignment. + if( unlikely(m_fHorizAlign != 0.5f || m_fVertAlign != 0.5f) ) + { + float fX = SCALE( m_fHorizAlign, 0.0f, 1.0f, +m_size.x/2.0f, -m_size.x/2.0f ); + float fY = SCALE( m_fVertAlign, 0.0f, 1.0f, +m_size.y/2.0f, -m_size.y/2.0f ); + RageMatrix m; + RageMatrixTranslate( + &m, + fX, + fY, + 0 + ); + DISPLAY->PreMultMatrix( m ); + } + + if( m_pTempState->quat.x != 0 || m_pTempState->quat.y != 0 || m_pTempState->quat.z != 0 || m_pTempState->quat.w != 1 ) + { + RageMatrix mat; + RageMatrixFromQuat( &mat, m_pTempState->quat ); + + DISPLAY->MultMatrix(mat); + } + + // handle skews + if( m_pTempState->fSkewX != 0 ) + { + DISPLAY->SkewX( m_pTempState->fSkewX ); + } + + if( m_pTempState->fSkewY != 0 ) + { + DISPLAY->SkewY( m_pTempState->fSkewY ); + } + +} + +void Actor::SetGlobalRenderStates() +{ + // set Actor-defined render states + if( !g_bShowMasks.Get() || m_BlendMode != BLEND_NO_EFFECT ) + DISPLAY->SetBlendMode( m_BlendMode ); + DISPLAY->SetZWrite( m_bZWrite ); + DISPLAY->SetZTestMode( m_ZTestMode ); + + // BLEND_NO_EFFECT is used to draw masks to the Z-buffer, which always wants + // Z-bias enabled. + if( m_fZBias == 0 && m_BlendMode == BLEND_NO_EFFECT ) + DISPLAY->SetZBias( 1.0f ); + else + DISPLAY->SetZBias( m_fZBias ); + + if( m_bClearZBuffer ) + DISPLAY->ClearZBuffer(); + DISPLAY->SetCullMode( m_CullMode ); +} + +void Actor::SetTextureRenderStates() +{ + DISPLAY->SetTextureWrapping( TextureUnit_1, m_bTextureWrapping ); + DISPLAY->SetTextureFiltering( TextureUnit_1, m_bTextureFiltering ); +} + +void Actor::EndDraw() +{ + DISPLAY->PopMatrix(); + m_pTempState = NULL; +} + +void Actor::UpdateTweening( float fDeltaTime ) +{ + while( 1 ) + { + 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; + TweenInfo &TI = m_Tweens[0]->info; + + bool bBeginning = TI.m_fTimeLeftInTween == TI.m_fTweenTime; + + float fSecsToSubtract = min( TI.m_fTimeLeftInTween, fDeltaTime ); + TI.m_fTimeLeftInTween -= fSecsToSubtract; + fDeltaTime -= fSecsToSubtract; + + RString sCommand = TI.m_sCommandName; + if( bBeginning ) // we are just beginning this tween + m_start = m_current; // set the start position + + if( TI.m_fTimeLeftInTween == 0 ) // Current tween is over. Stop. + { + m_current = TS; + + // delete the head tween + delete m_Tweens.front(); + m_Tweens.erase( m_Tweens.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 = TI.m_pTween->Tween( fPercentThroughTween ); + TweenState::MakeWeightedAverage( m_current, m_start, TS, fPercentAlongPath ); + } + + if( bBeginning ) + { + // Execute the command in this tween (if any). Do this last, and don't + // access TI or TS after, since this may modify the tweening queue. + if( !sCommand.empty() ) + { + if( sCommand.Left(1) == "!" ) + MESSAGEMAN->Broadcast( sCommand.substr(1) ); + else + this->PlayCommand( sCommand ); + } + } + } +} + +bool Actor::IsFirstUpdate() const +{ + return m_bFirstUpdate; +} + +void Actor::Update( float fDeltaTime ) +{ +// LOG->Trace( "Actor::Update( %f )", fDeltaTime ); + ASSERT_M( fDeltaTime >= 0, ssprintf("DeltaTime: %f",fDeltaTime) ); + + if( m_fHibernateSecondsLeft > 0 ) + { + m_fHibernateSecondsLeft -= fDeltaTime; + if( m_fHibernateSecondsLeft > 0 ) + return; + + // Grab the leftover time. + fDeltaTime = -m_fHibernateSecondsLeft; + m_fHibernateSecondsLeft = 0; + } + + this->UpdateInternal( fDeltaTime ); +} + +void Actor::UpdateInternal( float fDeltaTime ) +{ + if( m_bFirstUpdate ) + m_bFirstUpdate = false; + + switch( m_EffectClock ) + { + case CLOCK_TIMER: + m_fSecsIntoEffect += fDeltaTime; + m_fEffectDelta = fDeltaTime; + + /* Wrap the counter, so it doesn't increase indefinitely (causing loss + * of precision if a screen is left to sit for a day). */ + if( m_fSecsIntoEffect >= GetEffectPeriod() ) + m_fSecsIntoEffect -= GetEffectPeriod(); + break; + + case CLOCK_TIMER_GLOBAL: + { + float fTime = RageTimer::GetTimeSinceStartFast(); + m_fEffectDelta = fTime - m_fSecsIntoEffect; + m_fSecsIntoEffect = fTime; + break; + } + + case CLOCK_BGM_BEAT: + m_fEffectDelta = g_fCurrentBGMBeat - m_fSecsIntoEffect; + m_fSecsIntoEffect = g_fCurrentBGMBeat; + break; + + case CLOCK_BGM_BEAT_PLAYER1: + m_fEffectDelta = g_vfCurrentBGMBeatPlayer[PLAYER_1] - m_fSecsIntoEffect; + m_fSecsIntoEffect = g_vfCurrentBGMBeatPlayerNoOffset[PLAYER_1]; + break; + + case CLOCK_BGM_BEAT_PLAYER2: + m_fEffectDelta = g_vfCurrentBGMBeatPlayer[PLAYER_2] - m_fSecsIntoEffect; + m_fSecsIntoEffect = g_vfCurrentBGMBeatPlayerNoOffset[PLAYER_2]; + break; + + case CLOCK_BGM_TIME: + m_fEffectDelta = g_fCurrentBGMTime - m_fSecsIntoEffect; + m_fSecsIntoEffect = g_fCurrentBGMTime; + break; + + case CLOCK_BGM_BEAT_NO_OFFSET: + m_fEffectDelta = g_fCurrentBGMBeatNoOffset - m_fSecsIntoEffect; + m_fSecsIntoEffect = g_fCurrentBGMBeatNoOffset; + break; + + case CLOCK_BGM_TIME_NO_OFFSET: + m_fEffectDelta = g_fCurrentBGMTimeNoOffset - m_fSecsIntoEffect; + m_fSecsIntoEffect = g_fCurrentBGMTimeNoOffset; + break; + + default: + if( m_EffectClock >= CLOCK_LIGHT_1 && m_EffectClock <= CLOCK_LIGHT_LAST ) + { + int i = m_EffectClock - CLOCK_LIGHT_1; + m_fEffectDelta = g_fCabinetLights[i] - m_fSecsIntoEffect; + m_fSecsIntoEffect = g_fCabinetLights[i]; + } + break; + } + + // update effect + // todo: account for SSC_FUTURES -aj + switch( m_Effect ) + { + case spin: + m_current.rotation += m_fEffectDelta*m_vEffectMagnitude; + wrap( m_current.rotation.x, 360 ); + wrap( m_current.rotation.y, 360 ); + wrap( m_current.rotation.z, 360 ); + break; + default: break; + } + + UpdateTweening( fDeltaTime ); +} + +RString Actor::GetLineage() const +{ + RString sPath; + + if( m_pParent ) + sPath = m_pParent->GetLineage() + '/'; + sPath += ssprintf( "<%s> %s", typeid(*this).name(), m_sName.c_str() ); + return sPath; +} + +void Actor::BeginTweening( float time, ITween *pTween ) +{ + ASSERT( time >= 0 ); + + time = max( time, 0 ); + + // If the number of tweens to ever gets this large, there's probably an infinitely + // recursing ActorCommand. + if( m_Tweens.size() > 50 ) + { + RString sError = ssprintf( "Tween overflow: \"%s\"; infinitely recursing ActorCommand?", GetLineage().c_str() ); + + LOG->Warn( "%s", sError.c_str() ); + Dialog::OK( sError ); + FinishTweening(); + } + + // add a new TweenState to the tail, and initialize it + m_Tweens.push_back( new TweenStateAndInfo ); + + // latest + TweenState &TS = m_Tweens.back()->state; + TweenInfo &TI = m_Tweens.back()->info; + + if( m_Tweens.size() >= 2 ) // if there was already a TS on the stack + { + // initialize the new TS from the last TS in the list + TS = m_Tweens[m_Tweens.size()-2]->state; + } + else + { + // This new TS is the only TS. + // Set our tween starting and ending values to the current position. + TS = m_current; + } + + TI.m_pTween = pTween; + TI.m_fTweenTime = time; + TI.m_fTimeLeftInTween = time; +} + +void Actor::BeginTweening( float time, TweenType tt ) +{ + ITween *pTween = ITween::CreateFromType( tt ); + BeginTweening( time, pTween ); +} + +void Actor::StopTweening() +{ + for( unsigned i = 0; i < m_Tweens.size(); ++i ) + delete m_Tweens[i]; + m_Tweens.clear(); +} + +void Actor::FinishTweening() +{ + if( !m_Tweens.empty() ) + m_current = DestTweenState(); + StopTweening(); +} + +void Actor::HurryTweening( float factor ) +{ + for( unsigned i = 0; i < m_Tweens.size(); ++i ) + { + m_Tweens[i]->info.m_fTimeLeftInTween *= factor; + m_Tweens[i]->info.m_fTweenTime *= factor; + } +} + +void Actor::ScaleTo( const RectF &rect, StretchType st ) +{ + // width and height of rectangle + float rect_width = rect.GetWidth(); + float rect_height = rect.GetHeight(); + + if( rect_width < 0 ) SetRotationY( 180 ); + if( rect_height < 0 ) SetRotationX( 180 ); + + // zoom fActor needed to scale the Actor to fill the rectangle + float fNewZoomX = fabsf(rect_width / m_size.x); + float fNewZoomY = fabsf(rect_height / m_size.y); + + float fNewZoom = 0.f; + 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; + } + + SetX( rect.left + rect_width * m_fHorizAlign ); + SetY( rect.top + rect_height * m_fVertAlign ); + + SetZoom( fNewZoom ); +} + +void Actor::SetEffectClockString( const RString &s ) +{ + if (s.EqualsNoCase("timer")) this->SetEffectClock( CLOCK_TIMER ); + if (s.EqualsNoCase("timerglobal")) this->SetEffectClock( CLOCK_TIMER_GLOBAL ); + else if(s.EqualsNoCase("beat")) this->SetEffectClock( CLOCK_BGM_BEAT ); + else if(s.EqualsNoCase("music")) this->SetEffectClock( CLOCK_BGM_TIME ); + else if(s.EqualsNoCase("bgm")) this->SetEffectClock( CLOCK_BGM_BEAT ); // compat, deprecated + else if(s.EqualsNoCase("musicnooffset"))this->SetEffectClock( CLOCK_BGM_TIME_NO_OFFSET ); + else if(s.EqualsNoCase("beatnooffset")) this->SetEffectClock( CLOCK_BGM_BEAT_NO_OFFSET ); + else + { + CabinetLight cl = StringToCabinetLight( s ); + if( cl != CabinetLight_Invalid ) + { + this->SetEffectClock( (EffectClock) (cl + CLOCK_LIGHT_1) ); + return; + } + else + ASSERT(0); + } +} + +void Actor::StretchTo( const RectF &r ) +{ + // width and height of rectangle + float width = r.GetWidth(); + float height = r.GetHeight(); + + // center of the rectangle + float cx = r.left + width/2.0f; + float cy = r.top + height/2.0f; + + // zoom fActor needed to scale the Actor to fill the rectangle + float fNewZoomX = width / m_size.x; + float fNewZoomY = height / m_size.y; + + SetXY( cx, cy ); + SetZoomX( fNewZoomX ); + SetZoomY( fNewZoomY ); +} + + +void Actor::SetEffectPeriod( float fTime ) +{ + ASSERT( fTime > 0 ); + m_fEffectRampUp = fTime/2; + m_fEffectHoldAtHalf = 0; + m_fEffectRampDown = fTime/2; + m_fEffectHoldAtZero = 0; +} + +float Actor::GetEffectPeriod() const +{ + return m_fEffectRampUp + m_fEffectHoldAtHalf + m_fEffectRampDown + m_fEffectHoldAtZero; +} + +void Actor::SetEffectTiming( float fRampUp, float fAtHalf, float fRampDown, float fAtZero ) +{ + m_fEffectRampUp = fRampUp; + m_fEffectHoldAtHalf = fAtHalf; + m_fEffectRampDown = fRampDown; + m_fEffectHoldAtZero = fAtZero; + ASSERT( GetEffectPeriod() > 0 ); +} + +// effect "macros" + +void Actor::SetEffectDiffuseBlink( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != diffuse_blink ) + { + m_Effect = diffuse_blink; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fEffectPeriodSeconds ); + m_effectColor1 = c1; + m_effectColor2 = c2; +} + +void Actor::SetEffectDiffuseShift( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != diffuse_shift ) + { + m_Effect = diffuse_shift; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fEffectPeriodSeconds ); + m_effectColor1 = c1; + m_effectColor2 = c2; +} + +void Actor::SetEffectDiffuseRamp( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != diffuse_ramp ) + { + m_Effect = diffuse_ramp; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fEffectPeriodSeconds ); + m_effectColor1 = c1; + m_effectColor2 = c2; +} + +void Actor::SetEffectGlowBlink( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != glow_blink ) + { + m_Effect = glow_blink; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fEffectPeriodSeconds ); + m_effectColor1 = c1; + m_effectColor2 = c2; +} + +void Actor::SetEffectGlowShift( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != glow_shift ) + { + m_Effect = glow_shift; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fEffectPeriodSeconds ); + m_effectColor1 = c1; + m_effectColor2 = c2; +} + +void Actor::SetEffectGlowRamp( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != glow_ramp ) + { + m_Effect = glow_ramp; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fEffectPeriodSeconds ); + m_effectColor1 = c1; + m_effectColor2 = c2; +} + +void Actor::SetEffectRainbow( float fEffectPeriodSeconds ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != rainbow ) + { + m_Effect = rainbow; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fEffectPeriodSeconds ); +} + +void Actor::SetEffectWag( float fPeriod, RageVector3 vect ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect != wag ) + { + m_Effect = wag; + m_fSecsIntoEffect = 0; + } + SetEffectPeriod( fPeriod ); + m_vEffectMagnitude = vect; +} + +void Actor::SetEffectBounce( float fPeriod, RageVector3 vect ) +{ + // todo: account for SSC_FUTURES -aj + m_Effect = bounce; + SetEffectPeriod( fPeriod ); + m_vEffectMagnitude = vect; + m_fSecsIntoEffect = 0; +} + +void Actor::SetEffectBob( float fPeriod, RageVector3 vect ) +{ + // todo: account for SSC_FUTURES -aj + if( m_Effect!=bob || GetEffectPeriod() != fPeriod ) + { + m_Effect = bob; + SetEffectPeriod( fPeriod ); + m_fSecsIntoEffect = 0; + } + m_vEffectMagnitude = vect; +} + +void Actor::SetEffectSpin( RageVector3 vect ) +{ + // todo: account for SSC_FUTURES -aj + m_Effect = spin; + m_vEffectMagnitude = vect; +} + +void Actor::SetEffectVibrate( RageVector3 vect ) +{ + // todo: account for SSC_FUTURES -aj + m_Effect = vibrate; + m_vEffectMagnitude = vect; +} + +void Actor::SetEffectPulse( float fPeriod, float fMinZoom, float fMaxZoom ) +{ + // todo: account for SSC_FUTURES -aj + m_Effect = pulse; + SetEffectPeriod( fPeriod ); + m_vEffectMagnitude[0] = fMinZoom; + m_vEffectMagnitude[1] = fMaxZoom; +} + + +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) ); +} + +void Actor::RunCommands( const LuaReference& cmds, const LuaReference *pParamTable ) +{ + Lua *L = LUA->Get(); + + // function + cmds.PushSelf( L ); + ASSERT( !lua_isnil(L, -1) ); + + // 1st parameter + this->PushSelf( L ); + + // 2nd parameter + if( pParamTable == NULL ) + lua_pushnil( L ); + else + pParamTable->PushSelf( L ); + + // call function with 2 arguments and 0 results + RString sError; + if( !LuaHelpers::RunScriptOnStack(L, sError, 2, 0) ) + LOG->Warn( "Error playing command: %s", sError.c_str() ); + + LUA->Release(L); +} + +float Actor::GetTweenTimeLeft() const +{ + float tot = 0; + + tot += m_fHibernateSecondsLeft; + + for( unsigned i=0; iinfo.m_fTimeLeftInTween; + + return tot; +} + +/* This is a hack to change all tween states while leaving existing tweens alone. + * + * Hmm. Most commands actually act on a TweenStateAndInfo, not the Actor itself. + * Conceptually, it wouldn't be hard to give TweenState a presence in Lua, so + * we can simply say eg. "for x in states(Actor) do x.SetDiffuseColor(c) end". + * However, we'd then have to give every TweenState a userdata in Lua while it's + * being manipulated, which would add overhead ... */ +void Actor::SetGlobalDiffuseColor( RageColor c ) +{ + for( int i=0; i<4; i++ ) // color, not alpha + { + for( unsigned ts = 0; ts < m_Tweens.size(); ++ts ) + { + m_Tweens[ts]->state.diffuse[i].r = c.r; + m_Tweens[ts]->state.diffuse[i].g = c.g; + m_Tweens[ts]->state.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::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; + } +} + + +void Actor::TweenState::Init() +{ + pos = RageVector3( 0, 0, 0 ); + rotation = RageVector3( 0, 0, 0 ); + quat = RageVector4( 0, 0, 0, 1 ); + scale = RageVector3( 1, 1, 1 ); + fSkewX = 0; + fSkewY = 0; + crop = RectF( 0,0,0,0 ); + fade = RectF( 0,0,0,0 ); + for( int i=0; i<4; i++ ) + diffuse[i] = RageColor( 1, 1, 1, 1 ); + glow = RageColor( 1, 1, 1, 0 ); + aux = 0; +} + +bool Actor::TweenState::operator==( const TweenState &other ) const +{ +#define COMPARE( x ) if( x != other.x ) return false; + COMPARE( pos ); + COMPARE( rotation ); + COMPARE( quat ); + COMPARE( scale ); + COMPARE( fSkewX ); + COMPARE( fSkewY ); + COMPARE( crop ); + COMPARE( fade ); + for( unsigned i=0; iinfo; + TI.m_sCommandName = sCommandName; +} + +void Actor::QueueMessage( const RString& sMessageName ) +{ + // Hack: use "!" as a marker to broadcast a command, instead of playing a + // command, so we don't have to add yet another element to every tween + // state for this rarely-used command. + BeginTweening( 0, TWEEN_LINEAR ); + TweenInfo &TI = m_Tweens.back()->info; + TI.m_sCommandName = "!" + sMessageName; +} + +void Actor::AddCommand( const RString &sCmdName, apActorCommands apac ) +{ + if( HasCommand(sCmdName) ) + { + RString sWarning = GetLineage()+"'s command '"+sCmdName+"' defined twice"; + Dialog::OK( sWarning, "COMMAND_DEFINED_TWICE" ); + } + + RString sMessage; + if( GetMessageNameFromCommandName(sCmdName, sMessage) ) + { + SubscribeToMessage( sMessage ); + m_mapNameToCommands[sMessage] = apac; // sCmdName w/o "Message" at the end + } + else + { + m_mapNameToCommands[sCmdName] = apac; + } +} + +bool Actor::HasCommand( const RString &sCmdName ) const +{ + return GetCommand(sCmdName) != NULL; +} + +const apActorCommands *Actor::GetCommand( const RString &sCommandName ) const +{ + map::const_iterator it = m_mapNameToCommands.find( sCommandName ); + if( it == m_mapNameToCommands.end() ) + return NULL; + return &it->second; +} + +void Actor::HandleMessage( const Message &msg ) +{ + PlayCommandNoRecurse( msg ); +} + +void Actor::PlayCommandNoRecurse( const Message &msg ) +{ + const apActorCommands *pCmd = GetCommand( msg.GetName() ); + if( pCmd != NULL ) + RunCommands( *pCmd, &msg.GetParamTable() ); +} + +void Actor::PushContext( lua_State *L ) +{ + // self.ctx should already exist + m_pLuaInstance->PushSelf( L ); + lua_getfield( L, -1, "ctx" ); + lua_remove( L, -2 ); +} + +void Actor::SetParent( Actor *pParent ) +{ + m_pParent = pParent; + + Lua *L = LUA->Get(); + int iTop = lua_gettop( L ); + + this->PushContext( L ); + lua_pushstring( L, "__index" ); + pParent->PushContext( L ); + lua_settable( L, -3 ); + + lua_settop( L, iTop ); + LUA->Release( L ); +} + +Actor::TweenInfo::TweenInfo() +{ + m_pTween = NULL; +} + +Actor::TweenInfo::~TweenInfo() +{ + delete m_pTween; +} + +Actor::TweenInfo::TweenInfo( const TweenInfo &cpy ) +{ + m_pTween = NULL; + *this = cpy; +} + +Actor::TweenInfo &Actor::TweenInfo::operator=( const TweenInfo &rhs ) +{ + delete m_pTween; + m_pTween = (rhs.m_pTween? rhs.m_pTween->Copy():NULL); + m_fTimeLeftInTween = rhs.m_fTimeLeftInTween; + m_fTweenTime = rhs.m_fTweenTime; + m_sCommandName = rhs.m_sCommandName; + return *this; +} + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the Actor. */ +class LunaActor : public Luna +{ +public: + static int name( T* p, lua_State *L ) { p->SetName(SArg(1)); return 0; } + static int sleep( T* p, lua_State *L ) { p->Sleep(FArg(1)); return 0; } + static int linear( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_LINEAR); return 0; } + static int accelerate( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_ACCELERATE); return 0; } + static int decelerate( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_DECELERATE); return 0; } + static int spring( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_SPRING); return 0; } + static int tween( T* p, lua_State *L ) + { + ITween *pTween = ITween::CreateFromStack( L, 2 ); + p->BeginTweening( FArg(1), pTween ); + return 0; + } + static int stoptweening( T* p, lua_State *L ) { p->StopTweening(); return 0; } + static int finishtweening( T* p, lua_State *L ) { p->FinishTweening(); return 0; } + static int hurrytweening( T* p, lua_State *L ) { p->HurryTweening(FArg(1)); return 0; } + static int GetTweenTimeLeft( T* p, lua_State *L ) { lua_pushnumber( L, p->GetTweenTimeLeft() ); return 1; } + static int x( T* p, lua_State *L ) { p->SetX(FArg(1)); return 0; } + static int y( T* p, lua_State *L ) { p->SetY(FArg(1)); return 0; } + static int z( T* p, lua_State *L ) { p->SetZ(FArg(1)); return 0; } + static int addx( T* p, lua_State *L ) { p->AddX(FArg(1)); return 0; } + static int addy( T* p, lua_State *L ) { p->AddY(FArg(1)); return 0; } + static int addz( T* p, lua_State *L ) { p->AddZ(FArg(1)); return 0; } + static int zoom( T* p, lua_State *L ) { p->SetZoom(FArg(1)); return 0; } + static int zoomx( T* p, lua_State *L ) { p->SetZoomX(FArg(1)); return 0; } + static int zoomy( T* p, lua_State *L ) { p->SetZoomY(FArg(1)); return 0; } + static int zoomz( T* p, lua_State *L ) { p->SetZoomZ(FArg(1)); return 0; } + static int zoomto( T* p, lua_State *L ) { p->ZoomTo(FArg(1), FArg(2)); return 0; } + static int zoomtowidth( T* p, lua_State *L ) { p->ZoomToWidth(FArg(1)); return 0; } + static int zoomtoheight( T* p, lua_State *L ) { p->ZoomToHeight(FArg(1)); return 0; } + static int setsize( T* p, lua_State *L ) { p->SetWidth(FArg(1)); p->SetHeight(FArg(2)); return 0; } + static int SetWidth( T* p, lua_State *L ) { p->SetWidth(FArg(1)); return 0; } + static int SetHeight( T* p, lua_State *L ) { p->SetHeight(FArg(1)); return 0; } + static int basealpha( T* p, lua_State *L ) { p->SetBaseAlpha(FArg(1)); return 0; } + static int basezoom( T* p, lua_State *L ) { p->SetBaseZoom(FArg(1)); return 0; } + static int basezoomx( T* p, lua_State *L ) { p->SetBaseZoomX(FArg(1)); return 0; } + static int basezoomy( T* p, lua_State *L ) { p->SetBaseZoomY(FArg(1)); return 0; } + static int basezoomz( T* p, lua_State *L ) { p->SetBaseZoomZ(FArg(1)); return 0; } + static int stretchto( T* p, lua_State *L ) { p->StretchTo( RectF(FArg(1),FArg(2),FArg(3),FArg(4)) ); return 0; } + static int cropleft( T* p, lua_State *L ) { p->SetCropLeft(FArg(1)); return 0; } + static int croptop( T* p, lua_State *L ) { p->SetCropTop(FArg(1)); return 0; } + static int cropright( T* p, lua_State *L ) { p->SetCropRight(FArg(1)); return 0; } + static int cropbottom( T* p, lua_State *L ) { p->SetCropBottom(FArg(1)); return 0; } + static int fadeleft( T* p, lua_State *L ) { p->SetFadeLeft(FArg(1)); return 0; } + static int fadetop( T* p, lua_State *L ) { p->SetFadeTop(FArg(1)); return 0; } + static int faderight( T* p, lua_State *L ) { p->SetFadeRight(FArg(1)); return 0; } + static int fadebottom( T* p, lua_State *L ) { p->SetFadeBottom(FArg(1)); return 0; } + static int diffuse( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuse( c ); return 0; } + static int diffuseupperleft( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseUpperLeft( c ); return 0; } + static int diffuseupperright( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseUpperRight( c ); return 0; } + static int diffuselowerleft( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLowerLeft( c ); return 0; } + static int diffuselowerright( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLowerRight( c ); return 0; } + static int diffuseleftedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLeftEdge( c ); return 0; } + static int diffuserightedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseRightEdge( c ); return 0; } + static int diffusetopedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseTopEdge( c ); return 0; } + static int diffusebottomedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseBottomEdge( c ); return 0; } + static int diffusealpha( T* p, lua_State *L ) { p->SetDiffuseAlpha(FArg(1)); return 0; } + static int diffusecolor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseColor( c ); return 0; } + static int glow( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetGlow( c ); return 0; } + static int aux( T* p, lua_State *L ) { p->SetAux( FArg(1) ); return 0; } + static int getaux( T* p, lua_State *L ) { lua_pushnumber( L, p->GetAux() ); return 1; } + static int rotationx( T* p, lua_State *L ) { p->SetRotationX(FArg(1)); return 0; } + static int rotationy( T* p, lua_State *L ) { p->SetRotationY(FArg(1)); return 0; } + static int rotationz( T* p, lua_State *L ) { p->SetRotationZ(FArg(1)); return 0; } + static int addrotationx( T* p, lua_State *L ) { p->AddRotationX(FArg(1)); return 0; } + static int addrotationy( T* p, lua_State *L ) { p->AddRotationY(FArg(1)); return 0; } + static int addrotationz( T* p, lua_State *L ) { p->AddRotationZ(FArg(1)); return 0; } + static int getrotation( T* p, lua_State *L ) { lua_pushnumber(L, p->GetRotationX()); lua_pushnumber(L, p->GetRotationY()); lua_pushnumber(L, p->GetRotationZ()); return 3; } + static int baserotationx( T* p, lua_State *L ) { p->SetBaseRotationX(FArg(1)); return 0; } + static int baserotationy( T* p, lua_State *L ) { p->SetBaseRotationY(FArg(1)); return 0; } + static int baserotationz( T* p, lua_State *L ) { p->SetBaseRotationZ(FArg(1)); return 0; } + static int skewx( T* p, lua_State *L ) { p->SetSkewX(FArg(1)); return 0; } + static int skewy( T* p, lua_State *L ) { p->SetSkewY(FArg(1)); return 0; } + static int heading( T* p, lua_State *L ) { p->AddRotationH(FArg(1)); return 0; } + static int pitch( T* p, lua_State *L ) { p->AddRotationP(FArg(1)); return 0; } + static int roll( T* p, lua_State *L ) { p->AddRotationR(FArg(1)); return 0; } + static int shadowlength( T* p, lua_State *L ) { p->SetShadowLength(FArg(1)); return 0; } + static int shadowlengthx( T* p, lua_State *L ) { p->SetShadowLengthX(FArg(1)); return 0; } + static int shadowlengthy( T* p, lua_State *L ) { p->SetShadowLengthY(FArg(1)); return 0; } + static int shadowcolor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetShadowColor( c ); return 0; } + static int horizalign( T* p, lua_State *L ) { p->SetHorizAlign(Enum::Check(L, 1)); return 0; } + static int vertalign( T* p, lua_State *L ) { p->SetVertAlign(Enum::Check(L, 1)); return 0; } + static int halign( T* p, lua_State *L ) { p->SetHorizAlign(FArg(1)); return 0; } + static int valign( T* p, lua_State *L ) { p->SetVertAlign(FArg(1)); return 0; } + static int diffuseblink( T* p, lua_State *L ) { p->SetEffectDiffuseBlink(); return 0; } + static int diffuseshift( T* p, lua_State *L ) { p->SetEffectDiffuseShift(); return 0; } + static int diffuseramp( T* p, lua_State *L ) { p->SetEffectDiffuseRamp(); return 0; } + static int glowblink( T* p, lua_State *L ) { p->SetEffectGlowBlink(); return 0; } + static int glowshift( T* p, lua_State *L ) { p->SetEffectGlowShift(); return 0; } + static int glowramp( T* p, lua_State *L ) { p->SetEffectGlowRamp(); return 0; } + static int rainbow( T* p, lua_State *L ) { p->SetEffectRainbow(); return 0; } + static int wag( T* p, lua_State *L ) { p->SetEffectWag(); return 0; } + static int bounce( T* p, lua_State *L ) { p->SetEffectBounce(); return 0; } + static int bob( T* p, lua_State *L ) { p->SetEffectBob(); return 0; } + static int pulse( T* p, lua_State *L ) { p->SetEffectPulse(); return 0; } + static int spin( T* p, lua_State *L ) { p->SetEffectSpin(); return 0; } + static int vibrate( T* p, lua_State *L ) { p->SetEffectVibrate(); return 0; } + static int stopeffect( T* p, lua_State *L ) { p->StopEffect(); return 0; } + static int effectcolor1( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetEffectColor1( c ); return 0; } + static int effectcolor2( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetEffectColor2( c ); return 0; } + static int effectperiod( T* p, lua_State *L ) { p->SetEffectPeriod(FArg(1)); return 0; } + static int effecttiming( T* p, lua_State *L ) { p->SetEffectTiming(FArg(1),FArg(2),FArg(3),FArg(4)); return 0; } + static int effectoffset( T* p, lua_State *L ) { p->SetEffectOffset(FArg(1)); return 0; } + static int effectclock( T* p, lua_State *L ) { p->SetEffectClockString(SArg(1)); return 0; } + static int effectmagnitude( T* p, lua_State *L ) { p->SetEffectMagnitude( RageVector3(FArg(1),FArg(2),FArg(3)) ); return 0; } + static int geteffectmagnitude( T* p, lua_State *L ) { RageVector3 v = p->GetEffectMagnitude(); lua_pushnumber(L, v[0]); lua_pushnumber(L, v[1]); lua_pushnumber(L, v[2]); return 3; } + static int scaletocover( T* p, lua_State *L ) { p->ScaleToCover( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) ); return 0; } + static int scaletofit( T* p, lua_State *L ) { p->ScaleToFitInside( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) ); return 0; } + static int animate( T* p, lua_State *L ) { p->EnableAnimation(BIArg(1)); return 0; } + static int play( T* p, lua_State *L ) { p->EnableAnimation(true); return 0; } + static int pause( T* p, lua_State *L ) { p->EnableAnimation(false); return 0; } + static int setstate( T* p, lua_State *L ) { p->SetState(IArg(1)); return 0; } + static int GetNumStates( T* p, lua_State *L ) { LuaHelpers::Push( L, p->GetNumStates() ); return 1; } + static int texturewrapping( T* p, lua_State *L ) { p->SetTextureWrapping(BIArg(1)); return 0; } + static int SetTextureFiltering( T* p, lua_State *L ) { p->SetTextureFiltering(BArg(1)); return 0; } + static int blend( T* p, lua_State *L ) { p->SetBlendMode( Enum::Check(L, 1) ); return 0; } + static int zbuffer( T* p, lua_State *L ) { p->SetUseZBuffer(BIArg(1)); return 0; } + static int ztest( T* p, lua_State *L ) { p->SetZTestMode((BIArg(1))?ZTEST_WRITE_ON_PASS:ZTEST_OFF); return 0; } + static int ztestmode( T* p, lua_State *L ) { p->SetZTestMode( Enum::Check(L, 1) ); return 0; } + static int zwrite( T* p, lua_State *L ) { p->SetZWrite(BIArg(1)); return 0; } + static int zbias( T* p, lua_State *L ) { p->SetZBias(FArg(1)); return 0; } + static int clearzbuffer( T* p, lua_State *L ) { p->SetClearZBuffer(BIArg(1)); return 0; } + static int backfacecull( T* p, lua_State *L ) { p->SetCullMode((BIArg(1)) ? CULL_BACK : CULL_NONE); return 0; } + static int cullmode( T* p, lua_State *L ) { p->SetCullMode( Enum::Check(L, 1)); return 0; } + static int visible( T* p, lua_State *L ) { p->SetVisible(BIArg(1)); return 0; } + static int hibernate( T* p, lua_State *L ) { p->SetHibernate(FArg(1)); return 0; } + static int draworder( T* p, lua_State *L ) { p->SetDrawOrder(IArg(1)); return 0; } + static int playcommand( T* p, lua_State *L ) + { + if( !lua_istable(L, 2) && !lua_isnoneornil(L, 2) ) + luaL_typerror( L, 2, "table or nil" ); + + LuaReference ParamTable; + lua_pushvalue( L, 2 ); + ParamTable.SetFromStack( L ); + + Message msg( SArg(1), ParamTable ); + p->HandleMessage( msg ); + + return 0; + } + static int queuecommand( T* p, lua_State *L ) { p->QueueCommand(SArg(1)); return 0; } + static int queuemessage( T* p, lua_State *L ) { p->QueueMessage(SArg(1)); return 0; } + static int addcommand( T* p, lua_State *L ) + { + LuaReference *pRef = new LuaReference; + pRef->SetFromStack( L ); + p->AddCommand( SArg(1), apActorCommands(pRef) ); + return 0; + } + static int GetCommand( T* p, lua_State *L ) + { + const apActorCommands *pCommand = p->GetCommand(SArg(1)); + if( pCommand == NULL ) + lua_pushnil( L ); + else + (*pCommand)->PushSelf(L); + + return 1; + } + static int RunCommandsRecursively( T* p, lua_State *L ) + { + luaL_checktype( L, 1, LUA_TFUNCTION ); + if( !lua_istable(L, 2) && !lua_isnoneornil(L, 2) ) + luaL_typerror( L, 2, "table or nil" ); + + LuaReference ref; + lua_pushvalue( L, 1 ); + ref.SetFromStack( L ); + + LuaReference ParamTable; + lua_pushvalue( L, 2 ); + ParamTable.SetFromStack( L ); + + p->RunCommandsRecursively( ref, &ParamTable ); + return 0; + } + + static int GetX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetX() ); return 1; } + static int GetY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetY() ); return 1; } + static int GetZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZ() ); return 1; } + static int GetWidth( T* p, lua_State *L ) { lua_pushnumber( L, p->GetUnzoomedWidth() ); return 1; } + static int GetHeight( T* p, lua_State *L ) { lua_pushnumber( L, p->GetUnzoomedHeight() ); return 1; } + static int GetZoomedWidth( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomedWidth() ); return 1; } + static int GetZoomedHeight( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomedHeight() ); return 1; } + static int GetZoom( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoom() ); return 1; } + static int GetZoomX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomX() ); return 1; } + static int GetZoomY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomY() ); return 1; } + static int GetZoomZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomZ() ); return 1; } + static int GetBaseZoomX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetBaseZoomX() ); return 1; } + static int GetBaseZoomY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetBaseZoomY() ); return 1; } + static int GetBaseZoomZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetBaseZoomZ() ); return 1; } + static int GetRotationX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetRotationX() ); return 1; } + static int GetRotationY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetRotationY() ); return 1; } + static int GetRotationZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetRotationZ() ); return 1; } + static int GetSecsIntoEffect( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecsIntoEffect() ); return 1; } + static int GetEffectDelta( T* p, lua_State *L ) { lua_pushnumber( L, p->GetEffectDelta() ); return 1; } + DEFINE_METHOD( GetDiffuse, GetDiffuse() ) + DEFINE_METHOD( GetGlow, GetGlow() ) + static int GetDiffuseAlpha( T* p, lua_State *L ) { lua_pushnumber( L, p->GetDiffuseAlpha() ); return 1; } + static int GetVisible( T* p, lua_State *L ) { lua_pushboolean( L, p->GetVisible() ); return 1; } + static int GetHAlign( T* p, lua_State *L ) { lua_pushnumber( L, p->GetHorizAlign() ); return 1; } + static int GetVAlign( T* p, lua_State *L ) { lua_pushnumber( L, p->GetVertAlign() ); return 1; } + + static int GetName( T* p, lua_State *L ) { lua_pushstring( L, p->GetName() ); return 1; } + static int GetParent( T* p, lua_State *L ) + { + Actor *pParent = p->GetParent(); + if( pParent == NULL ) + lua_pushnil( L ); + else + pParent->PushSelf(L); + return 1; + } + static int Draw( T* p, lua_State *L ) + { + LUA->YieldLua(); + p->Draw(); + LUA->UnyieldLua(); + return 0; + } + + LunaActor() + { + ADD_METHOD( name ); + ADD_METHOD( sleep ); + ADD_METHOD( linear ); + ADD_METHOD( accelerate ); + ADD_METHOD( decelerate ); + ADD_METHOD( spring ); + ADD_METHOD( tween ); + ADD_METHOD( stoptweening ); + ADD_METHOD( finishtweening ); + ADD_METHOD( hurrytweening ); + ADD_METHOD( GetTweenTimeLeft ); + ADD_METHOD( x ); + ADD_METHOD( y ); + ADD_METHOD( z ); + ADD_METHOD( addx ); + ADD_METHOD( addy ); + ADD_METHOD( addz ); + ADD_METHOD( zoom ); + ADD_METHOD( zoomx ); + ADD_METHOD( zoomy ); + ADD_METHOD( zoomz ); + ADD_METHOD( zoomto ); + ADD_METHOD( zoomtowidth ); + ADD_METHOD( zoomtoheight ); + ADD_METHOD( setsize ); + ADD_METHOD( SetWidth ); + ADD_METHOD( SetHeight ); + ADD_METHOD( basealpha ); + ADD_METHOD( basezoom ); + ADD_METHOD( basezoomx ); + ADD_METHOD( basezoomy ); + ADD_METHOD( basezoomz ); + ADD_METHOD( stretchto ); + ADD_METHOD( cropleft ); + ADD_METHOD( croptop ); + ADD_METHOD( cropright ); + ADD_METHOD( cropbottom ); + ADD_METHOD( fadeleft ); + ADD_METHOD( fadetop ); + ADD_METHOD( faderight ); + ADD_METHOD( fadebottom ); + ADD_METHOD( diffuse ); + ADD_METHOD( diffuseupperleft ); + ADD_METHOD( diffuseupperright ); + ADD_METHOD( diffuselowerleft ); + ADD_METHOD( diffuselowerright ); + ADD_METHOD( diffuseleftedge ); + ADD_METHOD( diffuserightedge ); + ADD_METHOD( diffusetopedge ); + ADD_METHOD( diffusebottomedge ); + ADD_METHOD( diffusealpha ); + ADD_METHOD( diffusecolor ); + ADD_METHOD( glow ); + ADD_METHOD( aux ); + ADD_METHOD( getaux ); + ADD_METHOD( rotationx ); + ADD_METHOD( rotationy ); + ADD_METHOD( rotationz ); + ADD_METHOD( addrotationx ); + ADD_METHOD( addrotationy ); + ADD_METHOD( addrotationz ); + ADD_METHOD( getrotation ); + ADD_METHOD( baserotationx ); + ADD_METHOD( baserotationy ); + ADD_METHOD( baserotationz ); + ADD_METHOD( skewx ); + ADD_METHOD( skewy ); + ADD_METHOD( heading ); + ADD_METHOD( pitch ); + ADD_METHOD( roll ); + ADD_METHOD( shadowlength ); + ADD_METHOD( shadowlengthx ); + ADD_METHOD( shadowlengthy ); + ADD_METHOD( shadowcolor ); + ADD_METHOD( horizalign ); + ADD_METHOD( vertalign ); + ADD_METHOD( halign ); + ADD_METHOD( valign ); + ADD_METHOD( diffuseblink ); + ADD_METHOD( diffuseshift ); + ADD_METHOD( diffuseramp ); + ADD_METHOD( glowblink ); + ADD_METHOD( glowshift ); + ADD_METHOD( glowramp ); + ADD_METHOD( rainbow ); + ADD_METHOD( wag ); + ADD_METHOD( bounce ); + ADD_METHOD( bob ); + ADD_METHOD( pulse ); + ADD_METHOD( spin ); + ADD_METHOD( vibrate ); + ADD_METHOD( stopeffect ); + ADD_METHOD( effectcolor1 ); + ADD_METHOD( effectcolor2 ); + ADD_METHOD( effectperiod ); + ADD_METHOD( effecttiming ); + ADD_METHOD( effectoffset ); + ADD_METHOD( effectclock ); + ADD_METHOD( effectmagnitude ); + ADD_METHOD( geteffectmagnitude ); + ADD_METHOD( scaletocover ); + ADD_METHOD( scaletofit ); + ADD_METHOD( animate ); + ADD_METHOD( play ); + ADD_METHOD( pause ); + ADD_METHOD( setstate ); + ADD_METHOD( GetNumStates ); + ADD_METHOD( texturewrapping ); + ADD_METHOD( SetTextureFiltering ); + ADD_METHOD( blend ); + ADD_METHOD( zbuffer ); + ADD_METHOD( ztest ); + ADD_METHOD( ztestmode ); + ADD_METHOD( zwrite ); + ADD_METHOD( zbias ); + ADD_METHOD( clearzbuffer ); + ADD_METHOD( backfacecull ); + ADD_METHOD( cullmode ); + ADD_METHOD( visible ); + ADD_METHOD( hibernate ); + ADD_METHOD( draworder ); + ADD_METHOD( playcommand ); + ADD_METHOD( queuecommand ); + ADD_METHOD( queuemessage ); + ADD_METHOD( addcommand ); + ADD_METHOD( GetCommand ); + ADD_METHOD( RunCommandsRecursively ); + + ADD_METHOD( GetX ); + ADD_METHOD( GetY ); + ADD_METHOD( GetZ ); + ADD_METHOD( GetWidth ); + ADD_METHOD( GetHeight ); + ADD_METHOD( GetZoomedWidth ); + ADD_METHOD( GetZoomedHeight ); + ADD_METHOD( GetZoom ); + ADD_METHOD( GetZoomX ); + ADD_METHOD( GetZoomY ); + ADD_METHOD( GetZoomZ ); + ADD_METHOD( GetRotationX ); + ADD_METHOD( GetRotationY ); + ADD_METHOD( GetRotationZ ); + ADD_METHOD( GetBaseZoomX ); + ADD_METHOD( GetBaseZoomY ); + ADD_METHOD( GetBaseZoomZ ); + ADD_METHOD( GetSecsIntoEffect ); + ADD_METHOD( GetEffectDelta ); + ADD_METHOD( GetDiffuse ); + ADD_METHOD( GetDiffuseAlpha ); + ADD_METHOD( GetGlow ); + ADD_METHOD( GetVisible ); + ADD_METHOD( GetHAlign ); + ADD_METHOD( GetVAlign ); + + ADD_METHOD( GetName ); + ADD_METHOD( GetParent ); + + ADD_METHOD( Draw ); + } +}; + +LUA_REGISTER_INSTANCED_BASE_CLASS( Actor ) +// lua end + + +/* + * (c) 2001-2004 Chris Danford + * 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/Actors/Actor.h b/src/Actors/Actor.h new file mode 100644 index 0000000000..919d4994f7 --- /dev/null +++ b/src/Actors/Actor.h @@ -0,0 +1,755 @@ +#ifndef ACTOR_H +#define ACTOR_H + +#include "PlayerNumber.h" +#include "RageTypes.h" +#include "RageUtil_AutoPtr.h" +#include "LuaReference.h" +#include "EnumHelper.h" +#include +class XNode; +struct lua_State; +class LuaClass; +#include "MessageManager.h" +#include "Tween.h" + +typedef AutoPtrCopyOnWrite apActorCommands; + +/** @brief The background layer. */ +#define DRAW_ORDER_BEFORE_EVERYTHING -200 +/** @brief The underlay layer. */ +#define DRAW_ORDER_UNDERLAY -100 +/** @brief The decorations layer. */ +#define DRAW_ORDER_DECORATIONS 0 +/** @brief The overlay layer. + * + * Normal screen elements go here. */ +#define DRAW_ORDER_OVERLAY +100 +/** @brief The transitions layer. */ +#define DRAW_ORDER_TRANSITIONS +200 +/** @brief The over everything layer. */ +#define DRAW_ORDER_AFTER_EVERYTHING +300 + +/** @brief The different horizontal alignments. */ +enum HorizAlign +{ + HorizAlign_Left, /**< Align to the left. */ + HorizAlign_Center, /**< Align to the center. */ + HorizAlign_Right, /**< Align to the right. */ + NUM_HorizAlign, /**< The number of horizontal alignments. */ + HorizAlign_Invalid +}; +LuaDeclareType( HorizAlign ); + +/** @brief The different vertical alignments. */ +enum VertAlign +{ + VertAlign_Top, /**< Align to the top. */ + VertAlign_Middle, /**< Align to the middle. */ + VertAlign_Bottom, /**< Align to the bottom. */ + NUM_VertAlign, /**< The number of vertical alignments. */ + VertAlign_Invalid +}; +LuaDeclareType( VertAlign ); + +/** @brief The left horizontal alignment constant. */ +#define align_left 0.0f +/** @brief The center horizontal alignment constant. */ +#define align_center 0.5f +/** @brief The right horizontal alignment constant. */ +#define align_right 1.0f +/** @brief The top vertical alignment constant. */ +#define align_top 0.0f +/** @brief The middle vertical alignment constant. */ +#define align_middle 0.5f +/** @brief The bottom vertical alignment constant. */ +#define align_bottom 1.0f + +// ssc futures: +/* +enum EffectAction +{ + EffectAction_None, // no_effect + // [Diffuse] + EffectAction_DiffuseBlink, // diffuse_blink + EffectAction_DiffuseShift, // diffuse_shift + EffectAction_DiffuseRamp, // diffuse_ramp + EffectAction_Rainbow, // rainbow + // [Glow] + EffectAction_GlowBlink, // glow_blink + EffectAction_GlowShift, // glow_shift + EffectAction_GlowRamp, // glow_ramp + // [Translate] + EffectAction_Bob, + EffectAction_Bounce, + EffectAction_Vibrate, + // [Rotate] + EffectAction_Spin, + EffectAction_Wag, + // [Zoom] + EffectAction_Pulse, + NUM_EffectAction, + EffectAction_Invalid +}; +LuaDeclareType( EffectAction ); +*/ + +/** @brief Base class for all objects that appear on the screen. */ +class Actor : public MessageSubscriber +{ +public: + /** @brief Set up the Actor with its initial settings. */ + Actor(); + /** + * @brief Copy a new Actor to the old one. + * @param cpy the new Actor to use in place of this one. */ + Actor( const Actor &cpy ); + virtual ~Actor(); + virtual Actor *Copy() const; + virtual void InitState(); + virtual void LoadFromNode( const XNode* pNode ); + + static void SetBGMTime( float fTime, float fBeat, float fTimeNoOffset, float fBeatNoOffset ); + static void SetPlayerBGMBeat( PlayerNumber pn, float fBeat, float fBeatNoOffset ); + static void SetBGMLight( int iLightNumber, float fCabinetLights ); + + /** + * @brief The list of the different effects. + * + * todo: split out into diffuse effects and translation effects, or + * create an effect stack instead. -aj */ + enum Effect { no_effect, + diffuse_blink, diffuse_shift, diffuse_ramp, + glow_blink, glow_shift, glow_ramp, rainbow, + wag, bounce, bob, pulse, spin, vibrate + }; + + /** @brief Various values an Actor's effect can be tied to. */ + enum EffectClock + { + CLOCK_TIMER, + CLOCK_TIMER_GLOBAL, + CLOCK_BGM_TIME, + CLOCK_BGM_BEAT, + CLOCK_BGM_TIME_NO_OFFSET, + CLOCK_BGM_BEAT_NO_OFFSET, + CLOCK_BGM_BEAT_PLAYER1, + CLOCK_BGM_BEAT_PLAYER2, + CLOCK_LIGHT_1 = 1000, + CLOCK_LIGHT_LAST = 1100, + NUM_CLOCKS + }; + + /* + * @brief What type of Effect this is. + * + * This is an internal enum for checking if an effect can be run; + * You can't have more than one of most EffectTypes in the Effect list. (You + * might be able to have mutliple EffectType_Translates; not sure yet.) -aj */ + /* + enum EffectType { + EffectType_Diffuse, + EffectType_Glow, + EffectType_Translate, + EffectType_Rotate, + EffectType_Zoom, + NUM_EffectType, + EffectType_Invalid + }; + */ + + // todo: use this instead of the Effect enum -aj + /* + // This is similar to Attributes in BitmapText as far as implementation. + struct Effect + { + Effect() : m_Action(EffectAction_None), m_Type(EffectType_Invalid), m_fSecsIntoEffect(0), + m_fEffectDelta(0), m_fEffectRampUp(0.5f), m_fEffectHoldAtHalf(0), + m_fEffectRampDown(0.5f), m_fEffectHoldAtZero(0), m_fEffectOffset(0), + m_EffectClock(CLOCK_TIMER), m_vEffectMagnitude(RageVector3(0,0,10)), + m_effectColor1(RageColor(1,1,1,1)), m_effectColor2(RageColor(1,1,1,1)) + { } + + RString m_sName; // friendly name + EffectAction m_Action; // replaces the old Effect enum + EffectType m_Type; // determined by EffectAction + float m_fSecsIntoEffect; + float m_fEffectDelta; + RageColor m_EffectColor1; + RageColor m_EffectColor2; + RageVector3 m_vEffectMagnitude; + EffectClock m_EffectClock; + // units depend on m_EffectClock + float m_fEffectRampUp; + float m_fEffectHoldAtHalf; + float m_fEffectRampDown; + float m_fEffectHoldAtZero; + float m_fEffectOffset; + }; + */ + + /** + * @brief The present state for the Tween. + */ + struct TweenState + { + void Init(); + static void MakeWeightedAverage( TweenState& average_out, const TweenState& ts1, const TweenState& ts2, float fPercentBetween ); + bool operator==( const TweenState &other ) const; + bool operator!=( const TweenState &other ) const { return !operator==(other); } + + // start and end position for tweening + RageVector3 pos; + RageVector3 rotation; + RageVector4 quat; + RageVector3 scale; + float fSkewX, fSkewY; + /** + * @brief The amount of cropping involved. + * + * If 0, there is no cropping. If 1, it's fully cropped. */ + RectF crop; + /** + * @brief The amount of fading involved. + * + * If 0, there is no fade. If 1, it's fully faded. */ + RectF fade; + /** + * @brief Four values making up the diffuse in this TweenState. + * + * 0 = UpperLeft, 1 = UpperRight, 2 = LowerLeft, 3 = LowerRight */ + RageColor diffuse[4]; + /** @brief The glow color for this TweenState. */ + RageColor glow; + /** @brief A magical value that nobody really knows the use for. ;) */ + float aux; + }; + + /** + * @brief Calls multiple functions for drawing the Actors. + * + * It calls the following in order: + * -# EarlyAbortDraw + * -# BeginDraw + * -# DrawPrimitives + * -# EndDraw + */ + void Draw(); + /** + * @brief Allow the Actor to be aborted early. + * + * Subclasses may wish to overwrite this to allow for + * aborted actors. + * @return false, as by default Actors shouldn't be aborted on drawing. */ + virtual bool EarlyAbortDraw() const { return false; } + /** @brief Start the drawing and push the transform on the world matrix stack. */ + virtual void BeginDraw(); + /** + * @brief Set the global rendering states of this Actor. + * + * This should be called at the beginning of an Actor's DrawPrimitives() call. */ + virtual void SetGlobalRenderStates(); + /** + * @brief Set the texture rendering states of this Actor. + * + * This should be called after setting a texture for the Actor. */ + virtual void SetTextureRenderStates(); + /** + * @brief Draw the primitives of the Actor. + * + * Derivative classes should override this function. */ + virtual void DrawPrimitives() {}; + /** @brief Pop the transform from the world matrix stack. */ + virtual void EndDraw(); + + // TODO: make Update non virtual and change all classes to override UpdateInternal + // instead. + bool IsFirstUpdate() const; + virtual void Update( float fDeltaTime ); // this can short circuit UpdateInternal + virtual void UpdateInternal( float fDeltaTime ); // override this + void UpdateTweening( float fDeltaTime ); + + /** + * @brief Retrieve the Actor's name. + * @return the Actor's name. */ + const RString &GetName() const { return m_sName; } + /** + * @brief Set the Actor's name to a new one. + * @param sName the new name for the Actor. */ + virtual void SetName( const RString &sName ) { m_sName = sName; } + /** + * @brief Give this Actor a new parent. + * @param pParent the new parent Actor. */ + void SetParent( Actor *pParent ); + /** + * @brief Retrieve the Actor's parent. + * @return the Actor's parent. */ + Actor *GetParent() { return m_pParent; } + /** + * @brief Retrieve the Actor's lineage. + * @return the Actor's lineage. */ + RString GetLineage() const; + + /** + * @brief Retrieve the Actor's x position. + * @return the Actor's x position. */ + float GetX() const { return m_current.pos.x; }; + /** + * @brief Retrieve the Actor's y position. + * @return the Actor's y position. */ + float GetY() const { return m_current.pos.y; }; + /** + * @brief Retrieve the Actor's z position. + * @return the Actor's z position. */ + float GetZ() const { return m_current.pos.z; }; + float GetDestX() const { return DestTweenState().pos.x; }; + float GetDestY() const { return DestTweenState().pos.y; }; + float GetDestZ() const { return DestTweenState().pos.z; }; + void SetX( float x ) { DestTweenState().pos.x = x; }; + void SetY( float y ) { DestTweenState().pos.y = y; }; + void SetZ( float z ) { DestTweenState().pos.z = z; }; + void SetXY( float x, float y ) { DestTweenState().pos.x = x; DestTweenState().pos.y = y; }; + /** + * @brief Add to the x position of this Actor. + * @param x the amount to add to the Actor's x position. */ + void AddX( float x ) { SetX( GetDestX()+x ); } + /** + * @brief Add to the y position of this Actor. + * @param y the amount to add to the Actor's y position. */ + void AddY( float y ) { SetY( GetDestY()+y ); } + /** + * @brief Add to the z position of this Actor. + * @param z the amount to add to the Actor's z position. */ + void AddZ( float z ) { SetZ( GetDestZ()+z ); } + + // height and width vary depending on zoom + float GetUnzoomedWidth() const { return m_size.x; } + float GetUnzoomedHeight() const { return m_size.y; } + float GetZoomedWidth() const { return m_size.x * m_baseScale.x * DestTweenState().scale.x; } + float GetZoomedHeight() const { return m_size.y * m_baseScale.y * DestTweenState().scale.y; } + void SetWidth( float width ) { m_size.x = width; } + void SetHeight( float height ) { m_size.y = height; } + + // Base values + float GetBaseZoomX() const { return m_baseScale.x; } + void SetBaseZoomX( float zoom ) { m_baseScale.x = zoom; } + float GetBaseZoomY() const { return m_baseScale.y; } + void SetBaseZoomY( float zoom ) { m_baseScale.y = zoom; } + float GetBaseZoomZ() const { return m_baseScale.z; } + void SetBaseZoomZ( float zoom ) { m_baseScale.z = zoom; } + void SetBaseZoom( float zoom ) { m_baseScale = RageVector3(zoom,zoom,zoom); } + void SetBaseRotationX( float rot ) { m_baseRotation.x = rot; } + void SetBaseRotationY( float rot ) { m_baseRotation.y = rot; } + void SetBaseRotationZ( float rot ) { m_baseRotation.z = rot; } + void SetBaseRotation( const RageVector3 &rot ) { m_baseRotation = rot; } + virtual void SetBaseAlpha( float fAlpha ) { m_fBaseAlpha = fAlpha; } + + /** + * @brief Retrieve the general zoom factor, using the x coordinate of the Actor. + * + * Note that this is not accurate in some cases. + * @return the zoom factor for the x coordinate of the Actor. */ + float GetZoom() const { return DestTweenState().scale.x; } + /** + * @brief Retrieve the zoom factor for the x coordinate of the Actor. + * @return the zoom factor for the x coordinate of the Actor. */ + float GetZoomX() const { return DestTweenState().scale.x; } + /** + * @brief Retrieve the zoom factor for the y coordinate of the Actor. + * @return the zoom factor for the y coordinate of the Actor. */ + float GetZoomY() const { return DestTweenState().scale.y; } + /** + * @brief Retrieve the zoom factor for the z coordinate of the Actor. + * @return the zoom factor for the z coordinate of the Actor. */ + float GetZoomZ() const { return DestTweenState().scale.z; } + /** + * @brief Set the zoom factor for all dimensions of the Actor. + * @param zoom the zoom factor for all dimensions. */ + void SetZoom( float zoom ) + { + DestTweenState().scale.x = zoom; + DestTweenState().scale.y = zoom; + DestTweenState().scale.z = zoom; + } + /** + * @brief Set the zoom factor for the x dimension of the Actor. + * @param zoom the zoom factor for the x dimension. */ + void SetZoomX( float zoom ) { DestTweenState().scale.x = zoom; } + /** + * @brief Set the zoom factor for the y dimension of the Actor. + * @param zoom the zoom factor for the y dimension. */ + void SetZoomY( float zoom ) { DestTweenState().scale.y = zoom; } + /** + * @brief Set the zoom factor for the z dimension of the Actor. + * @param zoom the zoom factor for the z dimension. */ + void SetZoomZ( float zoom ) { DestTweenState().scale.z = zoom; } + void ZoomTo( float fX, float fY ) { ZoomToWidth(fX); ZoomToHeight(fY); } + void ZoomToWidth( float zoom ) { SetZoomX( zoom / GetUnzoomedWidth() ); } + void ZoomToHeight( float zoom ) { SetZoomY( zoom / GetUnzoomedHeight() ); } + + float GetRotationX() const { return DestTweenState().rotation.x; } + float GetRotationY() const { return DestTweenState().rotation.y; } + float GetRotationZ() const { return DestTweenState().rotation.z; } + void SetRotationX( float rot ) { DestTweenState().rotation.x = rot; } + void SetRotationY( float rot ) { DestTweenState().rotation.y = rot; } + void SetRotationZ( float rot ) { DestTweenState().rotation.z = rot; } + // added in StepNXA, now available in sm-ssc: + void AddRotationX( float rot ) { DestTweenState().rotation.x += rot; }; + void AddRotationY( float rot ) { DestTweenState().rotation.y += rot; }; + void AddRotationZ( float rot ) { DestTweenState().rotation.z += rot; }; + // and these were normally in SM: + void AddRotationH( float rot ); + void AddRotationP( float rot ); + void AddRotationR( float rot ); + + void SetSkewX( float fAmount ) { DestTweenState().fSkewX = fAmount; } + float GetSkewX( float fAmount ) const { return DestTweenState().fSkewX; } + void SetSkewY( float fAmount ) { DestTweenState().fSkewY = fAmount; } + float GetSkewY( float fAmount ) const { return DestTweenState().fSkewY; } + + float GetCropLeft() const { return DestTweenState().crop.left; } + float GetCropTop() const { return DestTweenState().crop.top; } + float GetCropRight() const { return DestTweenState().crop.right; } + float GetCropBottom() const { return DestTweenState().crop.bottom; } + void SetCropLeft( float percent ) { DestTweenState().crop.left = percent; } + void SetCropTop( float percent ) { DestTweenState().crop.top = percent; } + void SetCropRight( float percent ) { DestTweenState().crop.right = percent; } + void SetCropBottom( float percent ) { DestTweenState().crop.bottom = percent; } + + void SetFadeLeft( float percent ) { DestTweenState().fade.left = percent; } + void SetFadeTop( float percent ) { DestTweenState().fade.top = percent; } + void SetFadeRight( float percent ) { DestTweenState().fade.right = percent; } + void SetFadeBottom( float percent ) { DestTweenState().fade.bottom = percent; } + + void SetGlobalDiffuseColor( RageColor c ); + + virtual void SetDiffuse( RageColor c ) { for(int i=0; i<4; i++) DestTweenState().diffuse[i] = c; }; + virtual void SetDiffuseAlpha( float f ) { for(int i = 0; i < 4; ++i) { RageColor c = GetDiffuses( i ); c.a = f; SetDiffuses( i, c ); } } + float GetCurrentDiffuseAlpha() const { return m_current.diffuse[0].a; } + void SetDiffuseColor( RageColor c ); + void SetDiffuses( int i, RageColor c ) { DestTweenState().diffuse[i] = c; }; + void SetDiffuseUpperLeft( RageColor c ) { DestTweenState().diffuse[0] = c; }; + void SetDiffuseUpperRight( RageColor c ) { DestTweenState().diffuse[1] = c; }; + void SetDiffuseLowerLeft( RageColor c ) { DestTweenState().diffuse[2] = c; }; + void SetDiffuseLowerRight( RageColor c ) { DestTweenState().diffuse[3] = c; }; + void SetDiffuseTopEdge( RageColor c ) { DestTweenState().diffuse[0] = DestTweenState().diffuse[1] = c; }; + void SetDiffuseRightEdge( RageColor c ) { DestTweenState().diffuse[1] = DestTweenState().diffuse[3] = c; }; + void SetDiffuseBottomEdge( RageColor c ) { DestTweenState().diffuse[2] = DestTweenState().diffuse[3] = c; }; + void SetDiffuseLeftEdge( RageColor c ) { DestTweenState().diffuse[0] = DestTweenState().diffuse[2] = c; }; + RageColor GetDiffuse() const { return DestTweenState().diffuse[0]; }; + RageColor GetDiffuses( int i ) const { return DestTweenState().diffuse[i]; }; + float GetDiffuseAlpha() const { return DestTweenState().diffuse[0].a; }; + void SetGlow( RageColor c ) { DestTweenState().glow = c; }; + RageColor GetGlow() const { return DestTweenState().glow; }; + + void SetAux( float f ) { DestTweenState().aux = f; } + float GetAux() const { return m_current.aux; } + + void BeginTweening( float time, ITween *pInterp ); + void BeginTweening( float time, TweenType tt = TWEEN_LINEAR ); + void StopTweening(); + void Sleep( float time ); + void QueueCommand( const RString& sCommandName ); + void QueueMessage( const RString& sMessageName ); + virtual void FinishTweening(); + virtual void HurryTweening( float factor ); + // Let ActorFrame and BGAnimation override + virtual float GetTweenTimeLeft() const; // Amount of time until all tweens have stopped + TweenState& DestTweenState() // where Actor will end when its tween finish + { + if( m_Tweens.empty() ) // not tweening + return m_current; + else + return m_Tweens.back()->state; + } + const TweenState& DestTweenState() const { return const_cast(this)->DestTweenState(); } + + /** @brief How do we handle stretching the Actor? */ + enum StretchType + { + fit_inside, /**< Have the Actor fit inside its parent, using the smaller zoom. */ + cover /**< Have the Actor cover its parent, using the larger zoom. */ + }; + + void ScaleToCover( const RectF &rect ) { ScaleTo( rect, cover ); } + void ScaleToFitInside( const RectF &rect ) { ScaleTo( rect, fit_inside); }; + void ScaleTo( const RectF &rect, StretchType st ); + + void StretchTo( const RectF &rect ); + + // Alignment settings. These need to be virtual for BitmapText + virtual void SetHorizAlign( float f ) { m_fHorizAlign = f; } + virtual void SetVertAlign( float f ) { m_fVertAlign = f; } + void SetHorizAlign( HorizAlign ha ) { SetHorizAlign( (ha == HorizAlign_Left)? 0.0f: (ha == HorizAlign_Center)? 0.5f: +1.0f ); } + void SetVertAlign( VertAlign va ) { SetVertAlign( (va == VertAlign_Top)? 0.0f: (va == VertAlign_Middle)? 0.5f: +1.0f ); } + virtual float GetHorizAlign() { return m_fHorizAlign; } + virtual float GetVertAlign() { return m_fVertAlign; } + + // effects +#if defined(SSC_FUTURES) + void StopEffects(); + Effect GetEffect( int i ) const { return m_Effects[i]; } +#else + void StopEffect() { m_Effect = no_effect; } + Effect GetEffect() const { return m_Effect; } +#endif + float GetSecsIntoEffect() const { return m_fSecsIntoEffect; } + float GetEffectDelta() const { return m_fEffectDelta; } + + // todo: account for SSC_FUTURES by adding an effect as an arg to each one -aj + void SetEffectColor1( RageColor c ) { m_effectColor1 = c; } + void SetEffectColor2( RageColor c ) { m_effectColor2 = c; } + void SetEffectPeriod( float fTime ); + float GetEffectPeriod() const; + void SetEffectTiming( float fRampUp, float fAtHalf, float fRampDown, float fAtZero ); + void SetEffectOffset( float fTime ) { m_fEffectOffset = fTime; } + void SetEffectClock( EffectClock c ) { m_EffectClock = c; } + void SetEffectClockString( const RString &s ); // convenience + + void SetEffectMagnitude( RageVector3 vec ) { m_vEffectMagnitude = vec; } + RageVector3 GetEffectMagnitude() const { return m_vEffectMagnitude; } + + void SetEffectDiffuseBlink( + float fEffectPeriodSeconds = 1.0f, + RageColor c1 = RageColor(0.5f,0.5f,0.5f,1), + RageColor c2 = RageColor(1,1,1,1) ); + void SetEffectDiffuseShift( float fEffectPeriodSeconds = 1.f, + RageColor c1 = RageColor(0,0,0,1), + RageColor c2 = RageColor(1,1,1,1) ); + void SetEffectDiffuseRamp( float fEffectPeriodSeconds = 1.f, + RageColor c1 = RageColor(0,0,0,1), + RageColor c2 = RageColor(1,1,1,1) ); + void SetEffectGlowBlink( float fEffectPeriodSeconds = 1.f, + RageColor c1 = RageColor(1,1,1,0.2f), + RageColor c2 = RageColor(1,1,1,0.8f) ); + void SetEffectGlowShift( + float fEffectPeriodSeconds = 1.0f, + RageColor c1 = RageColor(1,1,1,0.2f), + RageColor c2 = RageColor(1,1,1,0.8f) ); + void SetEffectGlowRamp( + float fEffectPeriodSeconds = 1.0f, + RageColor c1 = RageColor(1,1,1,0.2f), + RageColor c2 = RageColor(1,1,1,0.8f) ); + void SetEffectRainbow( + float fEffectPeriodSeconds = 2.0f ); + void SetEffectWag( + float fPeriod = 2.f, + RageVector3 vect = RageVector3(0,0,20) ); + void SetEffectBounce( + float fPeriod = 2.f, + RageVector3 vect = RageVector3(0,20,0) ); + void SetEffectBob( + float fPeriod = 2.f, + RageVector3 vect = RageVector3(0,20,0) ); + void SetEffectPulse( + float fPeriod = 2.f, + float fMinZoom = 0.5f, + float fMaxZoom = 1.f ); + void SetEffectSpin( RageVector3 vect = RageVector3(0,0,180) ); + void SetEffectVibrate( RageVector3 vect = RageVector3(10,10,10) ); + + + // other properties + /** + * @brief Determine if the Actor is visible at this time. + * @return true if it's visible, false otherwise. */ + bool GetVisible() const { return m_bVisible; } + void SetVisible( bool b ) { m_bVisible = b; } + void SetShadowLength( float fLength ) { m_fShadowLengthX = fLength; m_fShadowLengthY = fLength; } + void SetShadowLengthX( float fLengthX ) { m_fShadowLengthX = fLengthX; } + void SetShadowLengthY( float fLengthY ) { m_fShadowLengthY = fLengthY; } + void SetShadowColor( RageColor c ) { m_ShadowColor = c; } + // TODO: Implement hibernate as a tween type? + void SetHibernate( float fSecs ) { m_fHibernateSecondsLeft = fSecs; } + void SetDrawOrder( int iOrder ) { m_iDrawOrder = iOrder; } + int GetDrawOrder() const { return m_iDrawOrder; } + + virtual void EnableAnimation( bool b ) { m_bIsAnimating = b; } // Sprite needs to overload this + void StartAnimating() { this->EnableAnimation(true); } + void StopAnimating() { this->EnableAnimation(false); } + + // render states + void SetBlendMode( BlendMode mode ) { m_BlendMode = mode; } + void SetTextureWrapping( bool b ) { m_bTextureWrapping = b; } + void SetTextureFiltering( bool b ) { m_bTextureFiltering = b; } + void SetClearZBuffer( bool b ) { m_bClearZBuffer = b; } + void SetUseZBuffer( bool b ) { SetZTestMode(b?ZTEST_WRITE_ON_PASS:ZTEST_OFF); SetZWrite(b); } + virtual void SetZTestMode( ZTestMode mode ) { m_ZTestMode = mode; } + virtual void SetZWrite( bool b ) { m_bZWrite = b; } + void SetZBias( float f ) { m_fZBias = f; } + virtual void SetCullMode( CullMode mode ) { m_CullMode = mode; } + + // Lua + virtual void PushSelf( lua_State *L ); + virtual void PushContext( lua_State *L ); + + // Named commands + void AddCommand( const RString &sCmdName, apActorCommands apac ); + bool HasCommand( const RString &sCmdName ) const; + const apActorCommands *GetCommand( const RString &sCommandName ) const; + void PlayCommand( const RString &sCommandName ) { HandleMessage( Message(sCommandName) ); } // convenience + void PlayCommandNoRecurse( const Message &msg ); + + // Commands by reference + virtual void RunCommands( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); + void RunCommands( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommands( *cmds, pParamTable ); } // convenience + virtual void RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable = NULL ) { RunCommands(cmds, pParamTable); } + // If we're a leaf, then execute this command. + virtual void RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable = NULL ) { RunCommands(cmds, pParamTable); } + + // Messages + virtual void HandleMessage( const Message &msg ); + + // Animation + virtual int GetNumStates() const { return 1; } + virtual void SetState( int iNewState ) {} + virtual float GetAnimationLengthSeconds() const { return 0; } + virtual void SetSecondsIntoAnimation( float fSeconds ) {} + virtual void SetUpdateRate( float fRate ) {} + + HiddenPtr m_pLuaInstance; + +protected: + /** @brief the name of the Actor. */ + RString m_sName; + /** @brief the current parent of this Actor if it exists. */ + Actor *m_pParent; + + /** @brief Some general information about the Tween. */ + struct TweenInfo + { + // counters for tweening + TweenInfo(); + ~TweenInfo(); + TweenInfo( const TweenInfo &cpy ); + TweenInfo &operator=( const TweenInfo &rhs ); + + ITween *m_pTween; + /** @brief How far into the tween are we? */ + float m_fTimeLeftInTween; + /** @brief The number of seconds between Start and End positions/zooms. */ + float m_fTweenTime; + /** @brief The command to execute when this TweenState goes into effect. */ + RString m_sCommandName; + }; + + RageVector3 m_baseRotation; + RageVector3 m_baseScale; + float m_fBaseAlpha; + + RageVector2 m_size; + TweenState m_current; + TweenState m_start; + struct TweenStateAndInfo + { + TweenState state; + TweenInfo info; + }; + vector m_Tweens; + + /** @brief Temporary variables that are filled just before drawing */ + TweenState *m_pTempState; + + bool m_bFirstUpdate; + + // Stuff for alignment + /** @brief The particular horizontal alignment. + * + * Use the defined constant values for best effect. */ + float m_fHorizAlign; + /** @brief The particular vertical alignment. + * + * Use the defined constant values for best effect. */ + float m_fVertAlign; + + // Stuff for effects +#if defined(SSC_FUTURES) // be able to stack effects + vector m_Effects; +#else // compatibility + Effect m_Effect; +#endif + float m_fSecsIntoEffect; + float m_fEffectDelta; + + // units depend on m_EffectClock + float m_fEffectRampUp; + float m_fEffectHoldAtHalf; + float m_fEffectRampDown; + float m_fEffectHoldAtZero; + float m_fEffectOffset; + EffectClock m_EffectClock; + + /* This can be used in lieu of the fDeltaTime parameter to Update() to + * follow the effect clock. Actor::Update must be called first. */ + float GetEffectDeltaTime() const { return m_fEffectDelta; } + + // todo: account for SSC_FUTURES by having these be vectors too -aj + RageColor m_effectColor1; + RageColor m_effectColor2; + RageVector3 m_vEffectMagnitude; + + // other properties + bool m_bVisible; + bool m_bIsAnimating; + float m_fHibernateSecondsLeft; + float m_fShadowLengthX; + float m_fShadowLengthY; + RageColor m_ShadowColor; + /** @brief The draw order priority. + * + * The lower this number is, the sooner it is drawn. */ + int m_iDrawOrder; + + // render states + BlendMode m_BlendMode; + ZTestMode m_ZTestMode; + CullMode m_CullMode; + bool m_bTextureWrapping; + bool m_bTextureFiltering; + bool m_bClearZBuffer; + bool m_bZWrite; + /** + * @brief The amount of bias. + * + * If 0, there is no bias. If 1, there is a full bias. */ + float m_fZBias; + + // global state + static float g_fCurrentBGMTime, g_fCurrentBGMBeat; + static float g_fCurrentBGMTimeNoOffset, g_fCurrentBGMBeatNoOffset; + static vector g_vfCurrentBGMBeatPlayer; + static vector g_vfCurrentBGMBeatPlayerNoOffset; + +private: + // commands + map m_mapNameToCommands; +}; + +#endif + +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @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/Actors/ActorFrame.cpp b/src/Actors/ActorFrame.cpp new file mode 100644 index 0000000000..bb94b5b025 --- /dev/null +++ b/src/Actors/ActorFrame.cpp @@ -0,0 +1,633 @@ +#include "global.h" +#include "ActorFrame.h" +#include "arch/Dialog/Dialog.h" +#include "RageUtil.h" +#include "RageLog.h" +#include "XmlFile.h" +#include "ActorUtil.h" +#include "LuaBinding.h" +#include "ActorUtil.h" +#include "RageDisplay.h" +#include "ScreenDimensions.h" +#include "Foreach.h" + +/* Tricky: We need ActorFrames created in Lua to auto delete their children. + * We don't want classes that derive from ActorFrame to auto delete their + * children. The name "ActorFrame" is widely used in Lua, so we'll have + * that string instead create an ActorFrameAutoDeleteChildren object. + */ +//REGISTER_ACTOR_CLASS( ActorFrame ); +REGISTER_ACTOR_CLASS_WITH_NAME( ActorFrameAutoDeleteChildren, ActorFrame ); +ActorFrame *ActorFrame::Copy() const { return new ActorFrame(*this); } + + +ActorFrame::ActorFrame() +{ + m_bPropagateCommands = false; + m_bDeleteChildren = false; + m_bDrawByZPosition = false; + m_DrawFunction.SetFromNil(); + m_UpdateFunction.SetFromNil(); + m_fUpdateRate = 1; + m_fFOV = -1; + m_fVanishX = SCREEN_CENTER_X; + m_fVanishY = SCREEN_CENTER_Y; + m_bOverrideLighting = false; + m_bLighting = false; + m_ambientColor = RageColor(1,1,1,1); + m_diffuseColor = RageColor(1,1,1,1); + m_specularColor = RageColor(1,1,1,1); + m_lightDirection = RageVector3(0,0,1); +} + +ActorFrame::~ActorFrame() +{ + if( m_bDeleteChildren ) + DeleteAllChildren(); +} + +ActorFrame::ActorFrame( const ActorFrame &cpy ): + Actor( cpy ) +{ +#define CPY(x) this->x = cpy.x; + CPY( m_bPropagateCommands ); + CPY( m_bDeleteChildren ); + CPY( m_bDrawByZPosition ); + CPY( m_DrawFunction ); + CPY( m_UpdateFunction ); + CPY( m_fUpdateRate ); + CPY( m_fFOV ); + CPY( m_fVanishX ); + CPY( m_fVanishY ); + CPY( m_bOverrideLighting ); + CPY( m_bLighting ); + CPY( m_ambientColor ); + CPY( m_diffuseColor ); + CPY( m_specularColor ); + CPY( m_lightDirection ); +#undef CPY + + /* If m_bDeleteChildren, we own our children and it's up to us to copy + * them. If not, the derived class owns the children. This must preserve + * the current order of m_SubActors. */ + if( m_bDeleteChildren ) + { + for( unsigned i = 0; i < cpy.m_SubActors.size(); ++i ) + { + Actor *pActor = cpy.m_SubActors[i]->Copy(); + this->AddChild( pActor ); + } + } +} + +void ActorFrame::InitState() +{ + FOREACH( Actor*, m_SubActors, a ) + (*a)->InitState(); + Actor::InitState(); +} + +void ActorFrame::LoadFromNode( const XNode* pNode ) +{ + if( AutoLoadChildren() ) + LoadChildrenFromNode( pNode ); + + Actor::LoadFromNode( pNode ); + + pNode->GetAttrValue( "UpdateRate", m_fUpdateRate ); + pNode->GetAttrValue( "FOV", m_fFOV ); + pNode->GetAttrValue( "VanishX", m_fVanishX ); + pNode->GetAttrValue( "VanishY", m_fVanishY ); + m_bOverrideLighting = pNode->GetAttrValue( "Lighting", m_bLighting ); + // new lighting values (only ambient color seems to work?) -aj + RString sTemp1,sTemp2,sTemp3; + pNode->GetAttrValue( "AmbientColor", sTemp1 ); + m_ambientColor.FromString(sTemp1); + pNode->GetAttrValue( "DiffuseColor", sTemp2 ); + m_diffuseColor.FromString(sTemp2); + pNode->GetAttrValue( "SpecularColor", sTemp3 ); + m_specularColor.FromString(sTemp3); + // Values need to be converted into a RageVector3, so more work needs to be done... + //pNode->GetAttrValue( "LightDirection", m_lightDirection ); +} + +void ActorFrame::LoadChildrenFromNode( const XNode* pNode ) +{ + // Shouldn't be calling this unless we're going to delete our children. + ASSERT( m_bDeleteChildren ); + + // Load children + const XNode* pChildren = pNode->GetChild("children"); + bool bArrayOnly = false; + if( pChildren == NULL ) + { + bArrayOnly = true; + pChildren = pNode; + } + + FOREACH_CONST_Child( pChildren, pChild ) + { + if( bArrayOnly && !IsAnInt(pChild->GetName()) ) + continue; + + Actor* pChildActor = ActorUtil::LoadFromNode( pChild, this ); + if( pChildActor ) + AddChild( pChildActor ); + } + SortByDrawOrder(); +} + +void ActorFrame::AddChild( Actor *pActor ) +{ +#ifdef DEBUG + // check that this Actor isn't already added. + vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); + if( iter != m_SubActors.end() ) + Dialog::OK( ssprintf("Actor \"%s\" adds child \"%s\" more than once", GetLineage().c_str(), pActor->GetName().c_str()) ); +#endif + + ASSERT( pActor ); + ASSERT( (void*)pActor != (void*)0xC0000005 ); + m_SubActors.push_back( pActor ); + + pActor->SetParent( this ); +} + +void ActorFrame::RemoveChild( Actor *pActor ) +{ + vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); + if( iter != m_SubActors.end() ) + m_SubActors.erase( iter ); +} + +void ActorFrame::TransferChildren( ActorFrame *pTo ) +{ + FOREACH( Actor*, m_SubActors, i ) + pTo->AddChild( *i ); + RemoveAllChildren(); +} + +Actor* ActorFrame::GetChild( const RString &sName ) +{ + FOREACH( Actor*, m_SubActors, a ) + { + if( (*a)->GetName() == sName ) + return *a; + } + return NULL; +} + +void ActorFrame::RemoveAllChildren() +{ + m_SubActors.clear(); +} + +void ActorFrame::MoveToTail( Actor* pActor ) +{ + vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); + if( iter == m_SubActors.end() ) // didn't find + { + ASSERT(0); // called with a pActor that doesn't exist + return; + } + + m_SubActors.erase( iter ); + m_SubActors.push_back( pActor ); +} + +void ActorFrame::MoveToHead( Actor* pActor ) +{ + vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); + if( iter == m_SubActors.end() ) // didn't find + { + ASSERT(0); // called with a pActor that doesn't exist + return; + } + + m_SubActors.erase( iter ); + m_SubActors.insert( m_SubActors.begin(), pActor ); +} + +void ActorFrame::BeginDraw() +{ + Actor::BeginDraw(); + if( m_fFOV != -1 ) + { + DISPLAY->CameraPushMatrix(); + DISPLAY->LoadMenuPerspective( m_fFOV, SCREEN_WIDTH, SCREEN_HEIGHT, m_fVanishX, m_fVanishY ); + } + + if( m_bOverrideLighting ) + { + DISPLAY->SetLighting( m_bLighting ); + if( m_bLighting ) + DISPLAY->SetLightDirectional( 0,m_ambientColor,m_diffuseColor,m_specularColor,m_lightDirection ); + } +} + + +void ActorFrame::DrawPrimitives() +{ + ASSERT_M( !m_bClearZBuffer, "ClearZBuffer not supported on ActorFrames" ); + + // Don't set Actor-defined render states because we won't be drawing + // any geometry that belongs to this object. + // Actor::DrawPrimitives(); + + if( unlikely(!m_DrawFunction.IsNil()) ) + { + Lua *L = LUA->Get(); + m_DrawFunction.PushSelf( L ); + ASSERT( !lua_isnil(L, -1) ); + this->PushSelf( L ); + RString sError; + if( !LuaHelpers::RunScriptOnStack(L, sError, 1, 0) ) // 1 arg, 0 results + LOG->Warn( "Error running DrawFunction: %s", sError.c_str() ); + LUA->Release(L); + return; + } + + // draw all sub-ActorFrames while we're in the ActorFrame's local coordinate space + if( m_bDrawByZPosition ) + { + vector subs = m_SubActors; + ActorUtil::SortByZPosition( subs ); + for( unsigned i=0; iDraw(); + } + else + { + for( unsigned i=0; iDraw(); + } +} + + +void ActorFrame::EndDraw() +{ + if( m_bOverrideLighting ) + { + // TODO: pop state instead of turning lighting off + DISPLAY->SetLightOff( 0 ); + DISPLAY->SetLighting( false ); + } + + if( m_fFOV != -1 ) + { + DISPLAY->CameraPopMatrix(); + } + Actor::EndDraw(); +} + +void ActorFrame::PushChildrenTable( lua_State *L ) +{ + lua_newtable( L ); + FOREACH( Actor*, m_SubActors, a ) + { + LuaHelpers::Push( L, (*a)->GetName() ); + (*a)->PushSelf( L ); + lua_rawset( L, -3 ); + } +} + +void ActorFrame::PlayCommandOnChildren( const RString &sCommandName, const LuaReference *pParamTable ) +{ + const apActorCommands *pCmd = GetCommand( sCommandName ); + if( pCmd != NULL ) + RunCommandsOnChildren( *pCmd, pParamTable ); +} + +void ActorFrame::PlayCommandOnLeaves( const RString &sCommandName, const LuaReference *pParamTable ) +{ + const apActorCommands *pCmd = GetCommand( sCommandName ); + if( pCmd != NULL ) + RunCommandsOnLeaves( **pCmd, pParamTable ); +} + +void ActorFrame::RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable ) +{ + for( unsigned i=0; iRunCommandsRecursively( cmds, pParamTable ); + Actor::RunCommandsRecursively( cmds, pParamTable ); +} + +void ActorFrame::RunCommandsOnChildren( const LuaReference& cmds, const LuaReference *pParamTable ) +{ + for( unsigned i=0; iRunCommands( cmds, pParamTable ); +} + +void ActorFrame::RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable ) +{ + for( unsigned i=0; iRunCommandsOnLeaves( cmds, pParamTable ); +} + +void ActorFrame::UpdateInternal( float fDeltaTime ) +{ +// LOG->Trace( "ActorFrame::Update( %f )", fDeltaTime ); + + fDeltaTime *= m_fUpdateRate; + + Actor::UpdateInternal( fDeltaTime ); + + // update all sub-Actors + for( vector::iterator it=m_SubActors.begin(); it!=m_SubActors.end(); it++ ) + { + Actor *pActor = *it; + pActor->Update(fDeltaTime); + } + + if( unlikely(!m_UpdateFunction.IsNil()) ) + { + Lua *L = LUA->Get(); + m_UpdateFunction.PushSelf( L ); + ASSERT( !lua_isnil(L, -1) ); + this->PushSelf( L ); + lua_pushnumber( L, fDeltaTime ); + RString sError; + + if( !LuaHelpers::RunScriptOnStack(L, sError, 2, 0) ) // 1 args, 0 results + LOG->Warn( "Error running m_UpdateFunction: %s", sError.c_str() ); + LUA->Release(L); + } +} + +#define PropagateActorFrameCommand( cmd ) \ + void ActorFrame::cmd() \ + { \ + Actor::cmd(); \ + \ + /* set all sub-Actors */ \ + for( unsigned i=0; icmd(); \ + } + +#define PropagateActorFrameCommand1Param( cmd, type ) \ + void ActorFrame::cmd( type f ) \ + { \ + Actor::cmd( f ); \ + \ + /* set all sub-Actors */ \ + for( unsigned i=0; icmd( f ); \ + } + +PropagateActorFrameCommand( FinishTweening ) +PropagateActorFrameCommand1Param( SetDiffuse, RageColor ) +PropagateActorFrameCommand1Param( SetZTestMode, ZTestMode ) +PropagateActorFrameCommand1Param( SetZWrite, bool ) +PropagateActorFrameCommand1Param( HurryTweening, float ) +PropagateActorFrameCommand1Param( SetDiffuseAlpha, float ) +PropagateActorFrameCommand1Param( SetBaseAlpha, float ) + + +float ActorFrame::GetTweenTimeLeft() const +{ + float m = Actor::GetTweenTimeLeft(); + + for( unsigned i=0; iGetTweenTimeLeft()); + } + + return m; + +} + +static bool CompareActorsByDrawOrder(const Actor *p1, const Actor *p2) +{ + return p1->GetDrawOrder() < p2->GetDrawOrder(); +} + +void ActorFrame::SortByDrawOrder() +{ + // Preserve ordering of Actors with equal DrawOrders. + stable_sort( m_SubActors.begin(), m_SubActors.end(), CompareActorsByDrawOrder ); +} + +void ActorFrame::DeleteAllChildren() +{ + for( unsigned i=0; iHandleMessage( msg ); + } +} + +void ActorFrame::SetDrawByZPosition( bool b ) +{ + m_bDrawByZPosition = b; +} + + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the ActorFrame. */ +class LunaActorFrame : public Luna +{ +public: + static int playcommandonchildren( T* p, lua_State *L ) { p->PlayCommandOnChildren(SArg(1)); return 0; } + static int playcommandonleaves( T* p, lua_State *L ) { p->PlayCommandOnLeaves(SArg(1)); return 0; } + static int runcommandsonleaves( T* p, lua_State *L ) + { + luaL_checktype( L, 1, LUA_TFUNCTION ); + LuaReference cmds; + cmds.SetFromStack( L ); + + p->RunCommandsOnLeaves( cmds ); + return 0; + } + static int RunCommandsOnChildren( T* p, lua_State *L ) + { + luaL_checktype( L, 1, LUA_TFUNCTION ); + lua_pushvalue( L, 2 ); + LuaReference ParamTable; + ParamTable.SetFromStack( L ); + + lua_pushvalue( L, 1 ); + LuaReference cmds; + cmds.SetFromStack( L ); + + p->RunCommandsOnChildren( cmds, &ParamTable ); + return 0; + } + static int propagate( T* p, lua_State *L ) { p->SetPropagateCommands( BIArg(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 vanishpoint( T* p, lua_State *L ) { p->SetVanishPoint( FArg(1), FArg(2) ); return 0; } + static int GetChild( T* p, lua_State *L ) + { + Actor *pChild = p->GetChild( SArg(1) ); + if( pChild ) + pChild->PushSelf( L ); + else + lua_pushnil( L ); + return 1; + } + static int GetChildren( T* p, lua_State *L ) + { + p->PushChildrenTable( L ); + 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 int SetDrawFunction( T* p, lua_State *L ) + { + luaL_checktype( L, 1, LUA_TFUNCTION ); + + LuaReference ref; + lua_pushvalue( L, 1 ); + ref.SetFromStack( L ); + p->SetDrawFunction( ref ); + return 0; + } + static int GetDrawFunction( T* p, lua_State *L ) + { + p->GetDrawFunction().PushSelf(L); + return 1; + } + static int SetUpdateFunction( T* p, lua_State *L ) + { + luaL_checktype( L, 1, LUA_TFUNCTION ); + + LuaReference ref; + lua_pushvalue( L, 1 ); + ref.SetFromStack( L ); + p->SetUpdateFunction( ref ); + return 0; + } + static int SortByDrawOrder( T* p, lua_State *L ) { p->SortByDrawOrder(); return 0; } + + //static int CustomLighting( T* p, lua_State *L ) { p->SetCustomLighting(BArg(1)); return 0; } + static int SetAmbientLightColor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetAmbientLightColor( c ); return 0; } + static int SetDiffuseLightColor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLightColor( c ); return 0; } + static int SetSpecularLightColor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetSpecularLightColor( c ); return 0; } + static int SetLightDirection( T* p, lua_State *L ) + { + luaL_checktype( L, 1, LUA_TTABLE ); + lua_pushvalue( L, 1 ); + vector coords; + LuaHelpers::ReadArrayFromTable( coords, L ); + lua_pop( L, 1 ); + if( coords.size() !=3 ) + { + //error + } + RageVector3 vTmp = RageVector3( coords[0], coords[1], coords[2] ); + p->SetLightDirection( vTmp ); + return 0; + } + + static int AddChildFromPath( T* p, lua_State *L ) + { + // this one is tricky, we need to get an Actor from Lua. + Actor *pActor = ActorUtil::MakeActor( SArg(1) ); + if ( pActor == NULL ) + { + lua_pushboolean( L, 0 ); + return 1; + } + p->AddChild( pActor ); + lua_pushboolean( L, 1 ); + return 1; + } + + static int RemoveChild( T* p, lua_State *L ) + { + Actor *pChild = p->GetChild( SArg(1) ); + if( pChild ) + p->RemoveChild( pChild ); + else + lua_pushnil( L ); + return 1; + } + static int RemoveAllChildren( T* p, lua_State *L ) { p->RemoveAllChildren( ); return 0; } + + LunaActorFrame() + { + ADD_METHOD( playcommandonchildren ); + ADD_METHOD( playcommandonleaves ); + ADD_METHOD( runcommandsonleaves ); + ADD_METHOD( RunCommandsOnChildren ); + ADD_METHOD( propagate ); // deprecated + ADD_METHOD( fov ); + ADD_METHOD( SetUpdateRate ); + ADD_METHOD( SetFOV ); + ADD_METHOD( vanishpoint ); + ADD_METHOD( GetChild ); + ADD_METHOD( GetChildren ); + ADD_METHOD( GetNumChildren ); + ADD_METHOD( SetDrawByZPosition ); + ADD_METHOD( SetDrawFunction ); + ADD_METHOD( GetDrawFunction ); + ADD_METHOD( SetUpdateFunction ); + ADD_METHOD( SortByDrawOrder ); + //ADD_METHOD( CustomLighting ); + ADD_METHOD( SetAmbientLightColor ); + ADD_METHOD( SetDiffuseLightColor ); + ADD_METHOD( SetSpecularLightColor ); + ADD_METHOD( SetLightDirection ); + ADD_METHOD( AddChildFromPath ); + ADD_METHOD( RemoveChild ); + ADD_METHOD( RemoveAllChildren ); + + } +}; + +LUA_REGISTER_DERIVED_CLASS( ActorFrame, Actor ) +// lua end + +/* + * (c) 2001-2004 Chris Danford + * 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/Actors/ActorFrame.h b/src/Actors/ActorFrame.h new file mode 100644 index 0000000000..ba377ffcfb --- /dev/null +++ b/src/Actors/ActorFrame.h @@ -0,0 +1,164 @@ +#ifndef ACTORFRAME_H +#define ACTORFRAME_H + +#include "Actor.h" + +/** @brief A container for other Actors. */ +class ActorFrame : public Actor +{ +public: + ActorFrame(); + ActorFrame( const ActorFrame &cpy ); + virtual ~ActorFrame(); + + /** @brief Set up the initial state. */ + virtual void InitState(); + void LoadFromNode( const XNode* pNode ); + virtual ActorFrame *Copy() const; + + /** + * @brief Add a new child to the ActorFrame. + * @param pActor the new Actor to add. */ + virtual void AddChild( Actor *pActor ); + /** + * @brief Remove the specified child from the ActorFrame. + * @param pActor the Actor to remove. */ + virtual void RemoveChild( Actor *pActor ); + void TransferChildren( ActorFrame *pTo ); + Actor* GetChild( const RString &sName ); + vector GetChildren() { return m_SubActors; } + int GetNumChildren() const { return m_SubActors.size(); } + + /** @brief Remove all of the children from the frame. */ + void RemoveAllChildren(); + /** + * @brief Move a particular actor to the tail. + * @param pActor the actor to go to the tail. + */ + void MoveToTail( Actor* pActor ); + /** + * @brief Move a particular actor to the head. + * @param pActor the actor to go to the head. + */ + void MoveToHead( Actor* pActor ); + void SortByDrawOrder(); + void SetDrawByZPosition( bool b ); + + void SetDrawFunction( const LuaReference &DrawFunction ) { m_DrawFunction = DrawFunction; } + void SetUpdateFunction( const LuaReference &UpdateFunction ) { m_UpdateFunction = UpdateFunction; } + + LuaReference GetDrawFunction() const { return m_DrawFunction; } + virtual bool AutoLoadChildren() const { return false; } // derived classes override to automatically LoadChildrenFromNode + void DeleteChildrenWhenDone( bool bDelete=true ) { m_bDeleteChildren = bDelete; } + void DeleteAllChildren(); + + // Commands + virtual void PushSelf( lua_State *L ); + void PushChildrenTable( lua_State *L ); + void PlayCommandOnChildren( const RString &sCommandName, const LuaReference *pParamTable = NULL ); + void PlayCommandOnLeaves( const RString &sCommandName, const LuaReference *pParamTable = NULL ); + + virtual void RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); + virtual void RunCommandsOnChildren( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */ + void RunCommandsOnChildren( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommandsOnChildren( *cmds, pParamTable ); } // convenience + virtual void RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */ + + virtual void UpdateInternal( float fDeltaTime ); + virtual void BeginDraw(); + virtual void DrawPrimitives(); + virtual void EndDraw(); + + // propagated commands + virtual void SetDiffuse( RageColor c ); + virtual void SetDiffuseAlpha( float f ); + virtual void SetBaseAlpha( float f ); + virtual void SetZTestMode( ZTestMode mode ); + virtual void SetZWrite( bool b ); + virtual void FinishTweening(); + virtual void HurryTweening( float factor ); + + void SetUpdateRate( float fUpdateRate ) { m_fUpdateRate = fUpdateRate; } + void SetFOV( float fFOV ) { m_fFOV = fFOV; } + void SetVanishPoint( float fX, float fY) { m_fVanishX = fX; m_fVanishY = fY; } + + void SetCustomLighting( bool bCustomLighting ) { m_bOverrideLighting = bCustomLighting; } + void SetAmbientLightColor( RageColor c ) { m_ambientColor = c; } + void SetDiffuseLightColor( RageColor c ) { m_diffuseColor = c; } + void SetSpecularLightColor( RageColor c ) { m_specularColor = c; } + void SetLightDirection( RageVector3 vec ) { m_lightDirection = vec; } + + virtual void SetPropagateCommands( bool b ); + + /** @brief Amount of time until all tweens (and all children's tweens) have stopped: */ + virtual float GetTweenTimeLeft() const; + + virtual void HandleMessage( const Message &msg ); + virtual void RunCommands( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); + void RunCommands( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommands( *cmds, pParamTable ); } // convenience + +protected: + void LoadChildrenFromNode( const XNode* pNode ); + + /** @brief The children Actors used by the ActorFrame. */ + vector m_SubActors; + bool m_bPropagateCommands; + bool m_bDeleteChildren; + bool m_bDrawByZPosition; + LuaReference m_UpdateFunction; + LuaReference m_DrawFunction; + + // state effects + float m_fUpdateRate; + float m_fFOV; // -1 = no change + float m_fVanishX; + float m_fVanishY; + /** + * @brief A flad to see if an override for the lighting is needed. + * + * If true, set lightning to m_bLightning. */ + bool m_bOverrideLighting; + bool m_bLighting; + + // lighting variables + RageColor m_ambientColor; + RageColor m_diffuseColor; + RageColor m_specularColor; + RageVector3 m_lightDirection; +}; +/** @brief an ActorFrame that handles deleting children Actors automatically. */ +class ActorFrameAutoDeleteChildren : public ActorFrame +{ +public: + ActorFrameAutoDeleteChildren() { DeleteChildrenWhenDone(true); } + virtual bool AutoLoadChildren() const { return true; } + virtual ActorFrameAutoDeleteChildren *Copy() const; +}; + +#endif + +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @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/Actors/ActorFrameTexture.cpp b/src/Actors/ActorFrameTexture.cpp new file mode 100644 index 0000000000..4a907f7611 --- /dev/null +++ b/src/Actors/ActorFrameTexture.cpp @@ -0,0 +1,127 @@ +#include "global.h" +#include "ActorFrameTexture.h" +#include "RageTextureRenderTarget.h" +#include "RageTextureManager.h" +#include "ActorUtil.h" + +REGISTER_ACTOR_CLASS_WITH_NAME( ActorFrameTextureAutoDeleteChildren, ActorFrameTexture ); +ActorFrameTexture *ActorFrameTexture::Copy() const { return new ActorFrameTexture(*this); } + +ActorFrameTexture::ActorFrameTexture() +{ + m_bDepthBuffer = false; + m_bAlphaBuffer = false; + m_bFloat = false; + m_bPreserveTexture = false; + static uint64_t i = 0; + ++i; + m_sTextureName = ssprintf( ConvertI64FormatString("ActorFrameTexture %lli"), i ); + + m_pRenderTarget = NULL; +} + +ActorFrameTexture::ActorFrameTexture( const ActorFrameTexture &cpy ): + ActorFrame(cpy) +{ + FAIL_M( "ActorFrameTexture copy not implemented" ); +} + +ActorFrameTexture::~ActorFrameTexture() +{ + /* Release our reference to the texture. */ + TEXTUREMAN->UnloadTexture( m_pRenderTarget ); +} + +void ActorFrameTexture::Create() +{ + ASSERT( m_pRenderTarget == NULL ); + RageTextureID id( m_sTextureName ); + id.Policy = RageTextureID::TEX_VOLATILE; + + RenderTargetParam param; + param.bWithDepthBuffer = m_bDepthBuffer; + param.bWithAlpha = m_bAlphaBuffer; + param.bFloat = m_bFloat; + param.iWidth = (int) m_size.x; + param.iHeight = (int) m_size.y; + m_pRenderTarget = new RageTextureRenderTarget( id, param ); + m_pRenderTarget->m_bWasUsed = true; + + /* This passes ownership of m_pRenderTarget to TEXTUREMAN, but we retain + * our reference to it until we call TEXTUREMAN->UnloadTexture. */ + TEXTUREMAN->RegisterTexture( id, m_pRenderTarget ); +} + +void ActorFrameTexture::DrawPrimitives() +{ + if( m_pRenderTarget == NULL ) + return; + + m_pRenderTarget->BeginRenderingTo( m_bPreserveTexture ); + + ActorFrame::DrawPrimitives(); + + m_pRenderTarget->FinishRenderingTo(); +} + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the ActorFrameTexture. */ +class LunaActorFrameTexture : public Luna +{ +public: + static int Create( T* p, lua_State *L ) { p->Create(); return 0; } + static int EnableDepthBuffer( T* p, lua_State *L ) { p->EnableDepthBuffer(BArg(1)); return 0; } + static int EnableAlphaBuffer( T* p, lua_State *L ) { p->EnableAlphaBuffer(BArg(1)); return 0; } + static int EnableFloat( T* p, lua_State *L ) { p->EnableFloat(BArg(1)); return 0; } + static int EnablePreserveTexture( T* p, lua_State *L ) { p->EnablePreserveTexture(BArg(1)); return 0; } + static int SetTextureName( T* p, lua_State *L ) { p->SetTextureName(SArg(1)); return 0; } + static int GetTexture( T* p, lua_State *L ) + { + RageTexture *pTexture = p->GetTexture(); + if( pTexture == NULL ) + return 0; + pTexture->PushSelf(L); + return 1; + } + + LunaActorFrameTexture() + { + ADD_METHOD( Create ); + ADD_METHOD( EnableDepthBuffer ); + ADD_METHOD( EnableAlphaBuffer ); + ADD_METHOD( EnableFloat ); + ADD_METHOD( EnablePreserveTexture ); + ADD_METHOD( SetTextureName ); + ADD_METHOD( GetTexture ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ActorFrameTexture, ActorFrame ) +// lua end + +/* + * (c) 2006 Glenn Maynard + * 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/Actors/ActorFrameTexture.h b/src/Actors/ActorFrameTexture.h new file mode 100644 index 0000000000..3997b7dcde --- /dev/null +++ b/src/Actors/ActorFrameTexture.h @@ -0,0 +1,88 @@ +#ifndef ACTOR_FRAME_TEXTURE_H +#define ACTOR_FRAME_TEXTURE_H + +#include "ActorFrame.h" +class RageTextureRenderTarget; + +class ActorFrameTexture: public ActorFrame +{ +public: + ActorFrameTexture(); + ActorFrameTexture( const ActorFrameTexture &cpy ); + virtual ~ActorFrameTexture(); + virtual ActorFrameTexture *Copy() const; + + /** + * @brief Set the texture name. + * + * This can be used with RageTextureManager (and users, eg. Sprite) + * to load the texture. If no name is supplied, a unique one will + * be generated. In that case, the only way to access the texture + * is via GetTextureName. + * @param sName the new name. */ + void SetTextureName( const RString &sName ) { m_sTextureName = sName; } + /** + * @brief Retrieve the texture name. + * @return the texture name. */ + RString GetTextureName() const { return m_sTextureName; } + RageTextureRenderTarget *GetTexture() { return m_pRenderTarget; } + + void EnableDepthBuffer( bool b ) { m_bDepthBuffer = b; } + void EnableAlphaBuffer( bool b ) { m_bAlphaBuffer = b; } + void EnableFloat( bool b ) { m_bFloat = b; } + void EnablePreserveTexture( bool b ) { m_bPreserveTexture = b; } + + void Create(); + + virtual void DrawPrimitives(); + + // Commands + virtual void PushSelf( lua_State *L ); + +private: + RageTextureRenderTarget *m_pRenderTarget; + + bool m_bDepthBuffer; + bool m_bAlphaBuffer; + bool m_bFloat; + bool m_bPreserveTexture; + /** @brief the name of this ActorFrameTexture. */ + RString m_sTextureName; +}; + +class ActorFrameTextureAutoDeleteChildren : public ActorFrameTexture +{ +public: + ActorFrameTextureAutoDeleteChildren() { DeleteChildrenWhenDone(true); } + virtual bool AutoLoadChildren() const { return true; } + virtual ActorFrameTextureAutoDeleteChildren *Copy() const; +}; + +#endif + +/** + * @file + * @author Glenn Maynard (c) 2006 + * @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/Actors/ActorMultiTexture.cpp b/src/Actors/ActorMultiTexture.cpp new file mode 100644 index 0000000000..af2685f420 --- /dev/null +++ b/src/Actors/ActorMultiTexture.cpp @@ -0,0 +1,215 @@ +#include "global.h" +#include + +#include "ActorMultiTexture.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" + +REGISTER_ACTOR_CLASS( ActorMultiTexture ); + + +ActorMultiTexture::ActorMultiTexture() +{ + m_EffectMode = EffectMode_Normal; +} + + +ActorMultiTexture::~ActorMultiTexture() +{ + ClearTextures(); +} + +ActorMultiTexture::ActorMultiTexture( const ActorMultiTexture &cpy ): + Actor( cpy ) +{ +#define CPY(a) a = cpy.a + CPY( m_Rect ); + CPY( m_aTextureUnits ); +#undef CPY + + FOREACH( TextureUnitState, m_aTextureUnits, tex ) + tex->m_pTexture = TEXTUREMAN->CopyTexture( tex->m_pTexture ); +} + +void ActorMultiTexture::SetTextureCoords( const RectF &r ) +{ + m_Rect = r; +} + +void ActorMultiTexture::LoadFromNode( const XNode* pNode ) +{ + m_Rect = RectF( 0, 0, 1, 1 ); + Actor::LoadFromNode( pNode ); +} + +void ActorMultiTexture::SetSizeFromTexture( RageTexture *pTexture ) +{ + ActorMultiTexture::m_size.x = pTexture->GetSourceWidth(); + ActorMultiTexture::m_size.y = pTexture->GetSourceHeight(); +} + +void ActorMultiTexture::ClearTextures() +{ + FOREACH( TextureUnitState, m_aTextureUnits, tex ) + TEXTUREMAN->UnloadTexture( tex->m_pTexture ); + m_aTextureUnits.clear(); +} + +int ActorMultiTexture::AddTexture( RageTexture *pTexture ) +{ + ASSERT( pTexture != NULL ); + LOG->Trace( "ActorMultiTexture::AddTexture( %s )", pTexture->GetID().filename.c_str() ); + + m_aTextureUnits.push_back( TextureUnitState() ); + m_aTextureUnits.back().m_pTexture = TEXTUREMAN->CopyTexture( pTexture ); + return m_aTextureUnits.size() - 1; +} + +void ActorMultiTexture::SetTextureMode( int iIndex, TextureMode tm ) +{ + ASSERT( iIndex < (int) m_aTextureUnits.size() ); + m_aTextureUnits[iIndex].m_TextureMode = tm; +} + +void ActorMultiTexture::DrawPrimitives() +{ + Actor::SetGlobalRenderStates(); // set Actor-specified render states + + RectF quadVerticies; + quadVerticies.left = -m_size.x/2.0f; + quadVerticies.right = +m_size.x/2.0f; + quadVerticies.top = -m_size.y/2.0f; + quadVerticies.bottom = +m_size.y/2.0f; + + DISPLAY->ClearAllTextures(); + for( size_t i = 0; i < m_aTextureUnits.size(); ++i ) + { + TextureUnit tu = enum_add2(TextureUnit_1, i); + DISPLAY->SetTexture( tu, m_aTextureUnits[i].m_pTexture->GetTexHandle() ); + DISPLAY->SetTextureWrapping( tu, m_bTextureWrapping ); + DISPLAY->SetTextureMode( tu, m_aTextureUnits[i].m_TextureMode ); + } + + DISPLAY->SetEffectMode( m_EffectMode ); + + static RageSpriteVertex v[4]; + v[0].p = RageVector3( quadVerticies.left, quadVerticies.top, 0 ); // top left + v[1].p = RageVector3( quadVerticies.left, quadVerticies.bottom, 0 ); // bottom left + v[2].p = RageVector3( quadVerticies.right, quadVerticies.bottom, 0 ); // bottom right + v[3].p = RageVector3( quadVerticies.right, quadVerticies.top, 0 ); // top right + + const RectF *pTexCoordRect = &m_Rect; + v[0].t = RageVector2( pTexCoordRect->left, pTexCoordRect->top ); // top left + v[1].t = RageVector2( pTexCoordRect->left, pTexCoordRect->bottom ); // bottom left + v[2].t = RageVector2( pTexCoordRect->right, pTexCoordRect->bottom ); // bottom right + v[3].t = RageVector2( pTexCoordRect->right, pTexCoordRect->top ); // top right + + v[0].c = m_pTempState->diffuse[0]; // top left + v[1].c = m_pTempState->diffuse[2]; // bottom left + v[2].c = m_pTempState->diffuse[3]; // bottom right + v[3].c = m_pTempState->diffuse[1]; // top right + + DISPLAY->DrawQuad( v ); + + for( size_t i = 0; i < m_aTextureUnits.size(); ++i ) + DISPLAY->SetTexture( enum_add2(TextureUnit_1, i), 0 ); + + DISPLAY->SetEffectMode( EffectMode_Normal ); +} + +bool ActorMultiTexture::EarlyAbortDraw() const +{ + return m_aTextureUnits.empty(); +} + + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the ActorMultiTexture. */ +class LunaActorMultiTexture: public Luna +{ +public: + static int ClearTextures( T* p, lua_State *L ) + { + p->ClearTextures(); + return 0; + } + static int AddTexture( T* p, lua_State *L ) + { + RageTexture *pTexture = Luna::check(L, 1); + int iRet = p->AddTexture( pTexture ); + lua_pushinteger( L, iRet ); + return 1; + } + static int SetTextureMode( T* p, lua_State *L ) + { + int iIndex = IArg(1); + TextureMode tm = Enum::Check(L, 2); + p->SetTextureMode( iIndex, tm ); + return 0; + } + static int SetTextureCoords( T* p, lua_State *L ) + { + p->SetTextureCoords( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) ); + return 0; + } + static int SetSizeFromTexture( T* p, lua_State *L ) + { + RageTexture *pTexture = Luna::check(L, 1); + p->SetSizeFromTexture( pTexture ); + return 0; + } + static int SetEffectMode( T* p, lua_State *L ) + { + EffectMode em = Enum::Check(L, 1); + p->SetEffectMode( em ); + return 0; + } + + LunaActorMultiTexture() + { + ADD_METHOD( ClearTextures ); + ADD_METHOD( AddTexture ); + ADD_METHOD( SetTextureMode ); + ADD_METHOD( SetTextureCoords ); + ADD_METHOD( SetSizeFromTexture ); + ADD_METHOD( SetEffectMode ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ActorMultiTexture, Actor ) +// lua end + +/* + * (c) 2001-2007 Glenn Maynard, Chris Danford + * 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/Actors/ActorMultiTexture.h b/src/Actors/ActorMultiTexture.h new file mode 100644 index 0000000000..6f4d793361 --- /dev/null +++ b/src/Actors/ActorMultiTexture.h @@ -0,0 +1,73 @@ +/** @brief ActorMultiTexture - A texture created from multiple textures. */ + +#ifndef ACTOR_MULTI_TEXTURE_H +#define ACTOR_MULTI_TEXTURE_H + +#include "Actor.h" +#include "RageDisplay.h" + +class RageTexture; + +class ActorMultiTexture: public Actor +{ +public: + ActorMultiTexture(); + ActorMultiTexture( const ActorMultiTexture &cpy ); + virtual ~ActorMultiTexture(); + + void LoadFromNode( const XNode* pNode ); + virtual ActorMultiTexture *Copy() const; + + virtual bool EarlyAbortDraw() const; + virtual void DrawPrimitives(); + + void ClearTextures(); + int AddTexture( RageTexture *pTexture ); + void SetTextureMode( int iIndex, TextureMode tm ); + + void SetSizeFromTexture( RageTexture *pTexture ); + void SetTextureCoords( const RectF &r ); + void SetEffectMode( EffectMode em ) { m_EffectMode = em; } + + virtual void PushSelf( lua_State *L ); + +private: + EffectMode m_EffectMode; + struct TextureUnitState + { + TextureUnitState(): m_pTexture(NULL), m_TextureMode(TextureMode_Modulate) {} + RageTexture *m_pTexture; + TextureMode m_TextureMode; + }; + vector m_aTextureUnits; + RectF m_Rect; +}; + +#endif + +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @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/Actors/ActorProxy.cpp b/src/Actors/ActorProxy.cpp new file mode 100644 index 0000000000..92f721f9b9 --- /dev/null +++ b/src/Actors/ActorProxy.cpp @@ -0,0 +1,90 @@ +#include "global.h" +#include "ActorProxy.h" +#include "ActorUtil.h" + +REGISTER_ACTOR_CLASS( ActorProxy ); + +ActorProxy::ActorProxy() +{ + m_pActorTarget = NULL; +} + +bool ActorProxy::EarlyAbortDraw() const +{ + return m_pActorTarget == NULL || Actor::EarlyAbortDraw(); +} + +void ActorProxy::DrawPrimitives() +{ + if( m_pActorTarget != NULL ) + { + bool bVisible = m_pActorTarget->GetVisible(); + m_pActorTarget->SetVisible( true ); + m_pActorTarget->Draw(); + m_pActorTarget->SetVisible( bVisible ); + } +} + +void ActorProxy::LoadFromNode( const XNode* pNode ) +{ + Actor::LoadFromNode( pNode ); +} + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the ActorProxy. */ +class LunaActorProxy: public Luna +{ +public: + static int SetTarget( T* p, lua_State *L ) + { + Actor *pTarget = Luna::check( L, 1 ); + p->SetTarget( pTarget ); + return 0; + } + + static int GetTarget( T* p, lua_State *L ) + { + Actor *pTarget = p->GetTarget(); + if( pTarget != NULL ) + pTarget->PushSelf( L ); + else + lua_pushnil( L ); + return 1; + } + + LunaActorProxy() + { + ADD_METHOD( SetTarget ); + ADD_METHOD( GetTarget ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ActorProxy, Actor ) +// lua end + +/* + * (c) 2006 Glenn Maynard + * 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/Actors/ActorProxy.h b/src/Actors/ActorProxy.h new file mode 100644 index 0000000000..763ea74599 --- /dev/null +++ b/src/Actors/ActorProxy.h @@ -0,0 +1,54 @@ +#ifndef ACTOR_PROXY_H +#define ACTOR_PROXY_H + +#include "Actor.h" + +struct lua_State; +/** @brief Renders another actor. */ +class ActorProxy: public Actor +{ +public: + ActorProxy(); + + virtual bool EarlyAbortDraw() const; + virtual void DrawPrimitives(); + + void LoadFromNode( const XNode* pNode ); + virtual ActorProxy *Copy() const; + + Actor *GetTarget() { return m_pActorTarget; } + void SetTarget( Actor *pTarget ) { m_pActorTarget = pTarget; } + + // Lua + virtual void PushSelf( lua_State *L ); + +private: + Actor *m_pActorTarget; +}; + +#endif + +/* + * (c) 2006 Glenn Maynard + * 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/Actors/ActorScroller.cpp b/src/Actors/ActorScroller.cpp new file mode 100644 index 0000000000..e463af73b3 --- /dev/null +++ b/src/Actors/ActorScroller.cpp @@ -0,0 +1,397 @@ +#include "global.h" +#include "ActorScroller.h" +#include "Foreach.h" +#include "RageUtil.h" +#include "XmlFile.h" +#include "arch/Dialog/Dialog.h" +#include "RageLog.h" +#include "ActorUtil.h" +#include "LuaBinding.h" + +/* Tricky: We need ActorFrames created in Lua to auto delete their children. + * We don't want classes that derive from ActorFrame to auto delete their + * children. The name "ActorFrame" is widely used in Lua, so we'll have + * that string instead create an ActorFrameAutoDeleteChildren object. */ +//REGISTER_ACTOR_CLASS( ActorScroller ); +REGISTER_ACTOR_CLASS_WITH_NAME( ActorScrollerAutoDeleteChildren, ActorScroller ); +ActorScroller *ActorScroller::Copy() const { return new ActorScroller(*this); } + + +ActorScroller::ActorScroller() +{ + m_iNumItems = 0; + m_fCurrentItem = 0; + m_fDestinationItem = 0; + m_fSecondsPerItem = 1; + m_fSecondsPauseBetweenItems = 0; + m_fNumItemsToDraw = 7; + m_iFirstSubActorIndex = 0; + m_bLoop = false; + m_bFastCatchup = false; + m_bFunctionDependsOnPositionOffset = true; + m_bFunctionDependsOnItemIndex = true; + m_fPauseCountdownSeconds = 0; + m_fQuantizePixels = 0; + + m_quadMask.SetBlendMode( BLEND_NO_EFFECT ); // don't change color values + m_quadMask.SetUseZBuffer( true ); // we want to write to the Zbuffer + m_fMaskWidth = 0; + m_fMaskHeight = 0; + DisableMask(); +} + +void ActorScroller::Load2() +{ + m_iNumItems = m_SubActors.size(); + + Lua *L = LUA->Get(); + for( unsigned i = 0; i < m_SubActors.size(); ++i ) + { + lua_pushnumber( L, i ); + this->m_SubActors[i]->m_pLuaInstance->Set( L, "ItemIndex" ); + } + LUA->Release( L ); +} + +void ActorScroller::SetTransformFromReference( const LuaReference &ref ) +{ + m_exprTransformFunction.SetFromReference( ref ); + + // Probe to find which of the parameters are used. +#define GP(a,b) m_exprTransformFunction.GetTransformCached( a, b, 2 ) + m_bFunctionDependsOnPositionOffset = (GP(0,0) != GP(1,0)) && (GP(0,1) != GP(1,1)); + m_bFunctionDependsOnItemIndex = (GP(0,0) != GP(0,1)) && (GP(1,0) != GP(1,1)); + m_exprTransformFunction.ClearCache(); +} + +void ActorScroller::SetTransformFromExpression( const RString &sTransformFunction ) +{ + LuaReference ref; + ref.SetFromExpression( sTransformFunction ); + SetTransformFromReference( ref ); +} + +void ActorScroller::SetTransformFromWidth( float fItemWidth ) +{ + SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:x(%f*offset) end",fItemWidth) ); +} + +void ActorScroller::SetTransformFromHeight( float fItemHeight ) +{ + SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:y(%f*offset) end",fItemHeight) ); +} + +void ActorScroller::EnableMask( float fWidth, float fHeight ) +{ + m_quadMask.SetVisible( fWidth != 0 && fHeight != 0 ); + m_quadMask.SetWidth( fWidth ); + m_fMaskWidth = fWidth; + m_quadMask.SetHeight( fHeight ); + m_fMaskHeight = fHeight; +} + +void ActorScroller::DisableMask() +{ + m_quadMask.SetVisible( false ); +} + +void ActorScroller::ScrollThroughAllItems() +{ + m_fCurrentItem = m_bLoop ? +m_fNumItemsToDraw/2.0f : -(m_fNumItemsToDraw/2.0f)-1; + m_fDestinationItem = (float)(m_iNumItems+m_fNumItemsToDraw/2.0f+1); +} + +void ActorScroller::ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd ) +{ + m_fCurrentItem = -fItemPaddingStart; + m_fDestinationItem = m_iNumItems-1+fItemPaddingEnd; +} + +float ActorScroller::GetSecondsForCompleteScrollThrough() const +{ + float fTotalItems = m_fNumItemsToDraw + m_iNumItems; + return fTotalItems * (m_fSecondsPerItem + m_fSecondsPauseBetweenItems ); +} + +float ActorScroller::GetSecondsToDestination() const +{ + float fTotalItemsToMove = fabsf(m_fCurrentItem - m_fDestinationItem); + return fTotalItemsToMove * m_fSecondsPerItem; +} + +void ActorScroller::LoadFromNode( const XNode *pNode ) +{ + ActorFrame::LoadFromNode( pNode ); + + Load2(); + + float fNumItemsToDraw = 0; + if( pNode->GetAttrValue("NumItemsToDraw", fNumItemsToDraw) ) + SetNumItemsToDraw( fNumItemsToDraw ); + + float fSecondsPerItem = 0; + if( pNode->GetAttrValue("SecondsPerItem", fSecondsPerItem) ) + ActorScroller::SetSecondsPerItem( fSecondsPerItem ); + + Lua *L = LUA->Get(); + pNode->PushAttrValue( L, "TransformFunction" ); + { + LuaReference ref; + ref.SetFromStack( L ); + if( !ref.IsNil() ) + SetTransformFromReference( ref ); + } + LUA->Release( L ); + + int iSubdivisions = 1; + if( pNode->GetAttrValue("Subdivisions", iSubdivisions) ) + ActorScroller::SetNumSubdivisions( iSubdivisions ); + + bool bUseMask = false; + pNode->GetAttrValue( "UseMask", bUseMask ); + + if( bUseMask ) + { + pNode->GetAttrValue( "MaskWidth", m_fMaskWidth ); + pNode->GetAttrValue( "MaskHeight", m_fMaskHeight ); + EnableMask( m_fMaskWidth, m_fMaskHeight ); + } + + pNode->GetAttrValue( "QuantizePixels", m_fQuantizePixels ); +} + +void ActorScroller::UpdateInternal( float fDeltaTime ) +{ + ActorFrame::UpdateInternal( fDeltaTime ); + + // If we have no children, the code below will busy loop. + if( !m_SubActors.size() ) + return; + + // handle pause + if( fDeltaTime > m_fPauseCountdownSeconds ) + { + fDeltaTime -= m_fPauseCountdownSeconds; + m_fPauseCountdownSeconds = 0; + } + else + { + m_fPauseCountdownSeconds -= fDeltaTime; + fDeltaTime = 0; + return; + } + + + if( m_fCurrentItem == m_fDestinationItem ) + return; // done scrolling + + + float fOldItemAtTop = m_fCurrentItem; + if( m_fSecondsPerItem > 0 ) + { + float fApproachSpeed = fDeltaTime/m_fSecondsPerItem; + if( m_bFastCatchup ) + { + float fDistanceToMove = fabsf(m_fCurrentItem - m_fDestinationItem); + if( fDistanceToMove > 1 ) + fApproachSpeed *= fDistanceToMove*fDistanceToMove; + } + + fapproach( m_fCurrentItem, m_fDestinationItem, fApproachSpeed ); + } + + // if items changed, then pause + if( (int)fOldItemAtTop != (int)m_fCurrentItem ) + m_fPauseCountdownSeconds = m_fSecondsPauseBetweenItems; + + if( m_bLoop ) + m_fCurrentItem = fmodf( m_fCurrentItem, (float) m_iNumItems ); +} + +void ActorScroller::DrawPrimitives() +{ + PositionItemsAndDrawPrimitives( true ); +} + +void ActorScroller::PositionItems() +{ + PositionItemsAndDrawPrimitives( false ); +} + +/* Shift m_SubActors forward by iDist. This will place item m_iFirstSubActorIndex + * in m_SubActors[0]. */ +void ActorScroller::ShiftSubActors( int iDist ) +{ + if( iDist != INT_MAX ) + CircularShift( m_SubActors, iDist ); +} + +void ActorScroller::PositionItemsAndDrawPrimitives( bool bDrawPrimitives ) +{ + if( m_SubActors.empty() ) + return; + + float fNumItemsToDraw = m_fNumItemsToDraw; + if( m_quadMask.GetVisible() ) + { + // write to z buffer so that top and bottom are clipped + // Draw an extra item; this is the one that will be masked. + fNumItemsToDraw++; + float fPositionFullyOffScreenTop = -(fNumItemsToDraw)/2.f; + float fPositionFullyOffScreenBottom = (fNumItemsToDraw)/2.f; + + m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenTop, -1, m_iNumItems ); + if( bDrawPrimitives ) m_quadMask.Draw(); + + m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenBottom, m_iNumItems, m_iNumItems ); + if( bDrawPrimitives ) m_quadMask.Draw(); + } + + float fFirstItemToDraw = m_fCurrentItem - fNumItemsToDraw/2.f; + float fLastItemToDraw = m_fCurrentItem + fNumItemsToDraw/2.f; + int iFirstItemToDraw = (int) ceilf( fFirstItemToDraw ); + int iLastItemToDraw = (int) ceilf( fLastItemToDraw ); + if( !m_bLoop ) + { + iFirstItemToDraw = clamp( iFirstItemToDraw, 0, m_iNumItems ); + iLastItemToDraw = clamp( iLastItemToDraw, 0, m_iNumItems ); + } + + bool bDelayedDraw = m_bDrawByZPosition && !m_bLoop; + vector subs; + + { + // Shift m_SubActors so iFirstItemToDraw is at the beginning. + int iNewFirstIndex = iFirstItemToDraw; + int iDist = iNewFirstIndex - m_iFirstSubActorIndex; + m_iFirstSubActorIndex = iNewFirstIndex; + ShiftSubActors( iDist ); + } + + int iNumToDraw = iLastItemToDraw - iFirstItemToDraw; + for( int i = 0; i < iNumToDraw; ++i ) + { + int iItem = i + iFirstItemToDraw; + float fPosition = iItem - m_fCurrentItem; + int iIndex = i; // index into m_SubActors + if( m_bLoop ) + wrap( iIndex, m_SubActors.size() ); + else if( iIndex < 0 || iIndex >= (int)m_SubActors.size() ) + continue; + + // Optimization: Zero out unused parameters so that they don't create new, + // unnecessary entries in the position cache. On scrollers with lots of + // items, especially with Subdivisions > 1, m_exprTransformFunction uses + // too much memory. + if( !m_bFunctionDependsOnPositionOffset ) + fPosition = 0; + if( !m_bFunctionDependsOnItemIndex ) + iItem = 0; + + m_exprTransformFunction.TransformItemCached( *m_SubActors[iIndex], fPosition, iItem, m_iNumItems ); + if( bDrawPrimitives ) + { + if( bDelayedDraw ) + subs.push_back( m_SubActors[iIndex] ); + else + m_SubActors[iIndex]->Draw(); + } + } + + if( bDelayedDraw ) + { + ActorUtil::SortByZPosition( subs ); + FOREACH( Actor*, subs, a ) + (*a)->Draw(); + } +} + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the ActorScroller. */ +class LunaActorScroller: public Luna +{ +public: + static int PositionItems( T* p, lua_State *L ) { p->PositionItems(); return 0; } + static int SetTransformFromFunction( T* p, lua_State *L ) + { + LuaReference ref; + LuaHelpers::FromStack( L, ref, 1 ); + p->SetTransformFromReference( ref ); + return 0; + } + static int SetTransformFromHeight( T* p, lua_State *L ) { p->SetTransformFromHeight(FArg(1)); return 0; } + static int SetTransformFromWidth( T* p, lua_State *L ) { p->SetTransformFromWidth(FArg(1)); return 0; } + static int SetCurrentAndDestinationItem( T* p, lua_State *L ) { p->SetCurrentAndDestinationItem( FArg(1) ); return 0; } + static int SetDestinationItem( T* p, lua_State *L ) { p->SetDestinationItem( FArg(1) ); return 0; } + static int GetSecondsToDestination( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsToDestination() ); return 1; } + static int SetSecondsPerItem( T* p, lua_State *L ) { p->SetSecondsPerItem(FArg(1)); return 0; } + static int SetSecondsPauseBetweenItems( T* p, lua_State *L ) { p->SetSecondsPauseBetweenItems(FArg(1)); return 0; } + static int SetPauseCountdownSeconds( T* p, lua_State *L ) { p->SetPauseCountdownSeconds(FArg(1)); return 0; } + static int SetNumSubdivisions( T* p, lua_State *L ) { p->SetNumSubdivisions(IArg(1)); return 0; } + static int ScrollThroughAllItems( T* p, lua_State *L ) { p->ScrollThroughAllItems(); return 0; } + static int ScrollWithPadding( T* p, lua_State *L ) { p->ScrollWithPadding(FArg(1),FArg(2)); return 0; } + static int SetFastCatchup( T* p, lua_State *L ) { p->SetFastCatchup(BArg(1)); return 0; } + static int SetLoop( T* p, lua_State *L ) { p->SetLoop(BArg(1)); return 0; } + static int SetMask( T* p, lua_State *L ) { p->EnableMask(FArg(1), FArg(2)); return 0; } + + static int SetNumItemsToDraw( T* p, lua_State *L ) { p->SetNumItemsToDraw(FArg(1)); return 0; } + static int GetFullScrollLengthSeconds( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsForCompleteScrollThrough() ); return 1; } + static int GetCurrentItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetCurrentItem() ); return 1; } + static int GetDestinationItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetDestinationItem() ); return 1; } + static int GetNumItems( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumItems() ); return 1; } + + LunaActorScroller() + { + ADD_METHOD( PositionItems ); + ADD_METHOD( SetTransformFromFunction ); + ADD_METHOD( SetTransformFromHeight ); + ADD_METHOD( SetTransformFromWidth ); + ADD_METHOD( SetCurrentAndDestinationItem ); + ADD_METHOD( SetDestinationItem ); + ADD_METHOD( GetSecondsToDestination ); + ADD_METHOD( SetSecondsPerItem ); + ADD_METHOD( SetSecondsPauseBetweenItems ); + ADD_METHOD( SetPauseCountdownSeconds ); + ADD_METHOD( SetNumSubdivisions ); + ADD_METHOD( ScrollThroughAllItems ); + ADD_METHOD( ScrollWithPadding ); + ADD_METHOD( SetFastCatchup ); + ADD_METHOD( SetLoop ); + ADD_METHOD( SetMask ); + ADD_METHOD( SetNumItemsToDraw ); + ADD_METHOD( GetFullScrollLengthSeconds ); + ADD_METHOD( GetCurrentItem ); + ADD_METHOD( GetDestinationItem ); + ADD_METHOD( GetNumItems ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ActorScroller, ActorFrame ) +// lua end + +/* + * (c) 2003-2004 Chris Danford + * 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/Actors/ActorScroller.h b/src/Actors/ActorScroller.h new file mode 100644 index 0000000000..2a195dcde2 --- /dev/null +++ b/src/Actors/ActorScroller.h @@ -0,0 +1,123 @@ +#ifndef ActorScroller_H +#define ActorScroller_H + +#include "ActorFrame.h" +#include "Quad.h" +class XNode; +#include "LuaExpressionTransform.h" +/** @brief ActorFrame that moves its children. */ +class ActorScroller : public ActorFrame +{ +public: + ActorScroller(); + + void SetTransformFromReference( const LuaReference &ref ); + void SetTransformFromExpression( const RString &sTransformFunction ); + void SetTransformFromWidth( float fItemWidth ); + void SetTransformFromHeight( float fItemHeight ); + + void Load2(); + + void EnableMask( float fWidth, float fHeight ); + void DisableMask(); + + virtual void UpdateInternal( float fDelta ); + virtual void DrawPrimitives(); // handles drawing and doesn't call ActorFrame::DrawPrimitives + + void PositionItems(); + + void LoadFromNode( const XNode *pNode ); + virtual ActorScroller *Copy() const; + + void SetLoop( bool bLoop ) { m_bLoop = bLoop; } + void SetNumItemsToDraw( float fNumItemsToDraw ) { m_fNumItemsToDraw = fNumItemsToDraw; } + void SetDestinationItem( float fItemIndex ) { m_fDestinationItem = fItemIndex; } + void SetCurrentAndDestinationItem( float fItemIndex ) { m_fCurrentItem = m_fDestinationItem = fItemIndex; } + float GetCurrentItem() const { return m_fCurrentItem; } + float GetDestinationItem() const { return m_fDestinationItem; } + void ScrollThroughAllItems(); + void ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd ); + void SetPauseCountdownSeconds( float fSecs ) { m_fPauseCountdownSeconds = fSecs; } + void SetFastCatchup( bool bOn ) { m_bFastCatchup = bOn; } + void SetSecondsPerItem( float fSeconds ) { m_fSecondsPerItem = fSeconds; } + void SetSecondsPauseBetweenItems( float fSeconds ) { m_fSecondsPauseBetweenItems = fSeconds; } + void SetNumSubdivisions( int iNumSubdivisions ) { m_exprTransformFunction.SetNumSubdivisions( iNumSubdivisions ); } + float GetSecondsForCompleteScrollThrough() const; + float GetSecondsToDestination() const; + int GetNumItems() const { return m_iNumItems; } + + // Commands + void PushSelf( lua_State *L ); + +protected: + void PositionItemsAndDrawPrimitives( bool bDrawPrimitives ); + virtual void ShiftSubActors( int iDist ); + + int m_iNumItems; + /** + * @brief the current item we are focused on. + * + * An item at the center of the list, usually between 0 and m_SubActors.size(), + * will approach its destination. + * + * The above comment was paraphrased from what was here previously. It could use + * some clearing up. -Wolfman2000 */ + float m_fCurrentItem; + float m_fDestinationItem; + /** + * @brief How many seconds are there per item? + * + * If this is less than zero, then we are not scrolling. */ + float m_fSecondsPerItem; + float m_fSecondsPauseBetweenItems; + float m_fNumItemsToDraw; + int m_iFirstSubActorIndex; + bool m_bLoop; + bool m_bFastCatchup; + bool m_bFunctionDependsOnPositionOffset; + bool m_bFunctionDependsOnItemIndex; + float m_fPauseCountdownSeconds; + float m_fQuantizePixels; + + Quad m_quadMask; + float m_fMaskWidth, m_fMaskHeight; + + LuaExpressionTransform m_exprTransformFunction; // params: self,offset,itemIndex,numItems +}; + +class ActorScrollerAutoDeleteChildren : public ActorScroller +{ +public: + ActorScrollerAutoDeleteChildren() { DeleteChildrenWhenDone(true); } + virtual bool AutoLoadChildren() const { return true; } + virtual ActorScrollerAutoDeleteChildren *Copy() const; +}; + +#endif + +/** + * @file + * @author Chris Danford (c) 2003-2004 + * @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/Actors/ActorSound.cpp b/src/Actors/ActorSound.cpp new file mode 100644 index 0000000000..588a6635af --- /dev/null +++ b/src/Actors/ActorSound.cpp @@ -0,0 +1,103 @@ +#include "global.h" +#include "ActorSound.h" +#include "ActorUtil.h" +#include "LuaManager.h" +#include "XmlFile.h" +#include "RageUtil.h" + +REGISTER_ACTOR_CLASS_WITH_NAME( ActorSound, Sound ); + +void ActorSound::Load( const RString &sPath ) +{ + m_Sound.Load( sPath, true ); +} + +void ActorSound::Play() +{ + // This fix makes it possible to stop and pause ActorSounds. (Also, + // sometimes stacking sounds is annoying.) -DaisuMaster + if( m_Sound.IsPlaying() ) + { + m_Sound.PlayCopy(); + return; + } + m_Sound.StartPlaying(); +} + +void ActorSound::Pause( bool bPause ) +{ + m_Sound.Pause(bPause); +} + +void ActorSound::Stop() +{ + m_Sound.Stop(); +} + +void ActorSound::LoadFromNode( const XNode* pNode ) +{ + RageSoundLoadParams params; + pNode->GetAttrValue("SupportPan", params.m_bSupportPan); + pNode->GetAttrValue("SupportRateChanging", params.m_bSupportRateChanging); + + bool bPrecache = true; + pNode->GetAttrValue( "Precache", bPrecache ); + + Actor::LoadFromNode( pNode ); + + RString sFile; + if( ActorUtil::GetAttrPath(pNode, "File", sFile) ) + m_Sound.Load( sFile, bPrecache, ¶ms ); +} + +// lua start +#include "LuaBinding.h" + +/** @brief Allow Lua to have access to the ActorSound. */ +class LunaActorSound: public Luna +{ +public: + static int load( T* p, lua_State *L ) { p->Load(SArg(1)); return 0; } + static int play( T* p, lua_State *L ) { p->Play(); return 0; } + static int pause( T* p, lua_State *L ) { p->Pause(BArg(1)); return 0; } + static int stop( T* p, lua_State *L ) { p->Stop(); return 0; } + static int get( T* p, lua_State *L ) { p->PushSound( L ); return 1; } + + LunaActorSound() + { + ADD_METHOD( load ); + ADD_METHOD( play ); + ADD_METHOD( pause ); + ADD_METHOD( stop ); + ADD_METHOD( get ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ActorSound, Actor ) +// lua end + + +/* + * (c) 2005 Glenn Maynard + * 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/Actors/ActorSound.h b/src/Actors/ActorSound.h new file mode 100644 index 0000000000..8b1d29d90a --- /dev/null +++ b/src/Actors/ActorSound.h @@ -0,0 +1,56 @@ +#ifndef ACTOR_SOUND_H +#define ACTOR_SOUND_H + +#include "Actor.h" +#include "RageSound.h" +/** @brief RageSound Actor interface. */ +class ActorSound: public Actor +{ +public: + virtual ~ActorSound() { } + virtual ActorSound *Copy() const; + + void Load( const RString &sPath ); + void Play(); + void Pause( bool bPause ); + void Stop(); + void LoadFromNode( const XNode* pNode ); + void PushSound( lua_State *L ) { m_Sound.PushSelf( L ); } + + // + // Lua + // + virtual void PushSelf( lua_State *L ); + +private: + RageSound m_Sound; +}; + +#endif + +/** + * @file + * @author Glenn Maynard (c) 2005 + * @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. + */ From 69431604e34df10c5c6a0a35a22e2d47c6cdf66f Mon Sep 17 00:00:00 2001 From: Colby Klein Date: Fri, 23 Sep 2011 15:44:01 -0700 Subject: [PATCH 18/30] Remove the old files. (also I am very sorry for nuking the line by line history, this has been pissing me off for ages) --- src/Actor.cpp | 1746 ------------------------------------- src/Actor.h | 755 ---------------- src/ActorFrame.cpp | 633 -------------- src/ActorFrame.h | 164 ---- src/ActorFrameTexture.cpp | 127 --- src/ActorFrameTexture.h | 88 -- src/ActorMultiTexture.cpp | 215 ----- src/ActorMultiTexture.h | 73 -- src/ActorProxy.cpp | 90 -- src/ActorProxy.h | 54 -- src/ActorScroller.cpp | 397 --------- src/ActorScroller.h | 123 --- src/ActorSound.cpp | 103 --- src/ActorSound.h | 56 -- 14 files changed, 4624 deletions(-) delete mode 100644 src/Actor.cpp delete mode 100644 src/Actor.h delete mode 100644 src/ActorFrame.cpp delete mode 100644 src/ActorFrame.h delete mode 100644 src/ActorFrameTexture.cpp delete mode 100644 src/ActorFrameTexture.h delete mode 100644 src/ActorMultiTexture.cpp delete mode 100644 src/ActorMultiTexture.h delete mode 100644 src/ActorProxy.cpp delete mode 100644 src/ActorProxy.h delete mode 100644 src/ActorScroller.cpp delete mode 100644 src/ActorScroller.h delete mode 100644 src/ActorSound.cpp delete mode 100644 src/ActorSound.h diff --git a/src/Actor.cpp b/src/Actor.cpp deleted file mode 100644 index 917f4cc45f..0000000000 --- a/src/Actor.cpp +++ /dev/null @@ -1,1746 +0,0 @@ -#include "global.h" -#include "Actor.h" -#include "RageDisplay.h" -#include "RageUtil.h" -#include "RageMath.h" -#include "RageLog.h" -#include "arch/Dialog/Dialog.h" -#include "Foreach.h" -#include "XmlFile.h" -#include "LuaBinding.h" -#include "ThemeManager.h" -#include "LuaReference.h" -#include "MessageManager.h" -#include "LightsManager.h" // for NUM_CabinetLight -#include "ActorUtil.h" -#include "Preference.h" -#include - -static Preference g_bShowMasks("ShowMasks", false); - -/** - * @brief Set up a hidden Actor that won't be drawn. - * - * It's useful to be able to construct a basic Actor in XML, in - * order to simply delay a Transition, or receive and send broadcasts. - * Since these actors will never draw, set them hidden by default. */ -class HiddenActor: public Actor -{ -public: - HiddenActor() { SetVisible(false); } - virtual HiddenActor *Copy() const; -}; -REGISTER_ACTOR_CLASS_WITH_NAME( HiddenActor, Actor ); - -float Actor::g_fCurrentBGMTime = 0, Actor::g_fCurrentBGMBeat; -float Actor::g_fCurrentBGMTimeNoOffset = 0, Actor::g_fCurrentBGMBeatNoOffset = 0; -vector Actor::g_vfCurrentBGMBeatPlayer(NUM_PlayerNumber, 0); -vector Actor::g_vfCurrentBGMBeatPlayerNoOffset(NUM_PlayerNumber, 0); - - -Actor *Actor::Copy() const { return new Actor(*this); } - -static float g_fCabinetLights[NUM_CabinetLight]; - -static const char *HorizAlignNames[] = { - "Left", - "Center", - "Right" -}; -XToString( HorizAlign ); -LuaXType( HorizAlign ); - -static const char *VertAlignNames[] = { - "Top", - "Middle", - "Bottom" -}; -XToString( VertAlign ); -LuaXType( VertAlign ); - -void Actor::SetBGMTime( float fTime, float fBeat, float fTimeNoOffset, float fBeatNoOffset ) -{ - g_fCurrentBGMTime = fTime; - g_fCurrentBGMBeat = fBeat; - - /* This timer is generally only used for effects tied to the background music - * when GameSoundManager is aligning music beats. Alignment doesn't handle - * g_fVisualDelaySeconds. */ - g_fCurrentBGMTimeNoOffset = fTimeNoOffset; - g_fCurrentBGMBeatNoOffset = fBeatNoOffset; -} - -void Actor::SetPlayerBGMBeat( PlayerNumber pn, float fBeat, float fBeatNoOffset ) -{ - g_vfCurrentBGMBeatPlayer[pn] = fBeat; - g_vfCurrentBGMBeatPlayerNoOffset[pn] = fBeatNoOffset; -} - -void Actor::SetBGMLight( int iLightNumber, float fCabinetLights ) -{ - ASSERT( iLightNumber < NUM_CabinetLight ); - g_fCabinetLights[iLightNumber] = fCabinetLights; -} - -void Actor::InitState() -{ - StopTweening(); - - m_pTempState = NULL; - - m_baseRotation = RageVector3( 0, 0, 0 ); - m_baseScale = RageVector3( 1, 1, 1 ); - m_fBaseAlpha = 1; - - m_start.Init(); - m_current.Init(); - - m_fHorizAlign = 0.5f; - m_fVertAlign = 0.5f; -#if defined(SSC_FUTURES) - for( unsigned i = 0; i < m_Effects.size(); ++i ) - m_Effects[i] = no_effect; -#else - m_Effect = no_effect; -#endif - m_fSecsIntoEffect = 0; - m_fEffectDelta = 0; - m_fEffectRampUp = 0.5f; - m_fEffectHoldAtHalf = 0; - m_fEffectRampDown = 0.5f; - m_fEffectHoldAtZero = 0; - m_fEffectOffset = 0; - m_EffectClock = CLOCK_TIMER; - m_vEffectMagnitude = RageVector3(0,0,10); - m_effectColor1 = RageColor(1,1,1,1); - m_effectColor2 = RageColor(1,1,1,1); - - m_bVisible = true; - m_fShadowLengthX = 0; - m_fShadowLengthY = 0; - m_ShadowColor = RageColor(0,0,0,0.5f); - m_bIsAnimating = true; - m_fHibernateSecondsLeft = 0; - m_iDrawOrder = 0; - - m_bTextureWrapping = false; - m_bTextureFiltering = true; - - m_BlendMode = BLEND_NORMAL; - m_fZBias = 0; - m_bClearZBuffer = false; - m_ZTestMode = ZTEST_OFF; - m_bZWrite = false; - m_CullMode = CULL_NONE; -} - -static bool GetMessageNameFromCommandName( const RString &sCommandName, RString &sMessageNameOut ) -{ - if( sCommandName.Right(7) == "Message" ) - { - sMessageNameOut = sCommandName.Left(sCommandName.size()-7); - return true; - } - else - { - return false; - } -} - -Actor::Actor() -{ - m_pLuaInstance = new LuaClass; - Lua *L = LUA->Get(); - m_pLuaInstance->PushSelf( L ); - lua_newtable( L ); - lua_pushvalue( L, -1 ); - lua_setmetatable( L, -2 ); - lua_setfield( L, -2, "ctx" ); - lua_pop( L, 1 ); - LUA->Release( L ); - - m_size = RageVector2( 1, 1 ); - InitState(); - m_pParent = NULL; - m_bFirstUpdate = true; -} - -Actor::~Actor() -{ - StopTweening(); - UnsubscribeAll(); -} - -Actor::Actor( const Actor &cpy ): - MessageSubscriber( cpy ) -{ - /* Don't copy an Actor in the middle of rendering. */ - ASSERT( cpy.m_pTempState == NULL ); - m_pTempState = NULL; - -#define CPY(x) x = cpy.x - CPY( m_sName ); - CPY( m_pParent ); - CPY( m_pLuaInstance ); - - CPY( m_baseRotation ); - CPY( m_baseScale ); - CPY( m_fBaseAlpha ); - - - CPY( m_size ); - CPY( m_current ); - CPY( m_start ); - for( unsigned i = 0; i < cpy.m_Tweens.size(); ++i ) - m_Tweens.push_back( new TweenStateAndInfo(*cpy.m_Tweens[i]) ); - - CPY( m_bFirstUpdate ); - - CPY( m_fHorizAlign ); - CPY( m_fVertAlign ); -#if defined(SSC_FUTURES) - // I'm a bit worried about this -aj - for( unsigned i = 0; i < cpy.m_Effects.size(); ++i ) - m_Effects.push_back( (*cpy.m_Effects[i]) ); -#else - CPY( m_Effect ); -#endif - CPY( m_fSecsIntoEffect ); - CPY( m_fEffectDelta ); - CPY( m_fEffectRampUp ); - CPY( m_fEffectHoldAtHalf ); - CPY( m_fEffectRampDown ); - CPY( m_fEffectHoldAtZero ); - CPY( m_fEffectOffset ); - CPY( m_EffectClock ); - - CPY( m_effectColor1 ); - CPY( m_effectColor2 ); - CPY( m_vEffectMagnitude ); - - CPY( m_bVisible ); - CPY( m_fHibernateSecondsLeft ); - CPY( m_fShadowLengthX ); - CPY( m_fShadowLengthY ); - CPY( m_ShadowColor ); - CPY( m_bIsAnimating ); - CPY( m_iDrawOrder ); - - CPY( m_bTextureWrapping ); - CPY( m_bTextureFiltering ); - CPY( m_BlendMode ); - CPY( m_bClearZBuffer ); - CPY( m_ZTestMode ); - CPY( m_bZWrite ); - CPY( m_fZBias ); - CPY( m_CullMode ); - - CPY( m_mapNameToCommands ); -#undef CPY -} - -/* XXX: This calls InitCommand, which must happen after all other - * initialization (eg. ActorFrame loading children). However, it - * also loads input variables, which should happen first. The - * former is more important. */ -void Actor::LoadFromNode( const XNode* pNode ) -{ - Lua *L = LUA->Get(); - FOREACH_CONST_Attr( pNode, pAttr ) - { - // Load Name, if any. - const RString &sKeyName = pAttr->first; - const XNodeValue *pValue = pAttr->second; - if( sKeyName == "Name" ) SetName( pValue->GetValue() ); - else if( sKeyName == "BaseRotationX" ) SetBaseRotationX( pValue->GetValue() ); - else if( sKeyName == "BaseRotationY" ) SetBaseRotationY( pValue->GetValue() ); - else if( sKeyName == "BaseRotationZ" ) SetBaseRotationZ( pValue->GetValue() ); - else if( sKeyName == "BaseZoomX" ) SetBaseZoomX( pValue->GetValue() ); - else if( sKeyName == "BaseZoomY" ) SetBaseZoomY( pValue->GetValue() ); - else if( sKeyName == "BaseZoomZ" ) SetBaseZoomZ( pValue->GetValue() ); - else if( EndsWith(sKeyName,"Command") ) - { - LuaReference *pRef = new LuaReference; - pValue->PushValue( L ); - pRef->SetFromStack( L ); - RString sCmdName = sKeyName.Left( sKeyName.size()-7 ); - AddCommand( sCmdName, apActorCommands( pRef ) ); - } - } - - LUA->Release( L ); - - // Don't recurse Init. It gets called once for every Actor when the - // Actor is loaded, and we don't want to call it again. - PlayCommandNoRecurse( Message("Init") ); -} - -void Actor::Draw() -{ - if( !m_bVisible ) - return; // early abort - if( m_fHibernateSecondsLeft > 0 ) - return; // early abort - if( this->EarlyAbortDraw() ) - return; - - // 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 -{ - DISPLAY->PushMatrix(); // we're actually going to do some drawing in this function - - // Somthing below may set m_pTempState to tempState - m_pTempState = &m_current; - - // set temporary drawing properties based on Effects - static TweenState tempState; - - // todo: account for SSC_FUTURES -aj - if( m_Effect == no_effect ) - { - } - else - { - m_pTempState = &tempState; - tempState = m_current; - - const float fTotalPeriod = GetEffectPeriod(); - ASSERT( fTotalPeriod > 0 ); - const float fTimeIntoEffect = fmodfp( m_fSecsIntoEffect+m_fEffectOffset, fTotalPeriod ); - - float fPercentThroughEffect; - if( fTimeIntoEffect < m_fEffectRampUp ) - { - fPercentThroughEffect = SCALE( - fTimeIntoEffect, - 0, - m_fEffectRampUp, - 0.0f, - 0.5f ); - } - else if( fTimeIntoEffect < m_fEffectRampUp + m_fEffectHoldAtHalf ) - { - fPercentThroughEffect = 0.5f; - } - else if( fTimeIntoEffect < m_fEffectRampUp + m_fEffectHoldAtHalf + m_fEffectRampDown ) - { - fPercentThroughEffect = SCALE( - fTimeIntoEffect, - m_fEffectRampUp + m_fEffectHoldAtHalf, - m_fEffectRampUp + m_fEffectHoldAtHalf + m_fEffectRampDown, - 0.5f, - 1.0f ); - } - else - { - fPercentThroughEffect = 0; - } - ASSERT_M( fPercentThroughEffect >= 0 && fPercentThroughEffect <= 1, - ssprintf("PercentThroughEffect: %f", fPercentThroughEffect) ); - - bool bBlinkOn = fPercentThroughEffect > 0.5f; - float fPercentBetweenColors = RageFastSin( (fPercentThroughEffect + 0.25f) * 2 * PI ) / 2 + 0.5f; - ASSERT_M( fPercentBetweenColors >= 0 && fPercentBetweenColors <= 1, - ssprintf("PercentBetweenColors: %f, PercentThroughEffect: %f", fPercentBetweenColors, fPercentThroughEffect) ); - float fOriginalAlpha = tempState.diffuse[0].a; - - // todo: account for SSC_FUTURES -aj - 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.) */ - for(int i=0; i<4; i++) - { - tempState.diffuse[i] = bBlinkOn ? m_effectColor1 : m_effectColor2; - tempState.diffuse[i].a *= fOriginalAlpha; // multiply the alphas so we can fade even while an effect is playing - } - break; - case diffuse_shift: - for(int i=0; i<4; i++) - { - tempState.diffuse[i] = m_effectColor1*fPercentBetweenColors + m_effectColor2*(1.0f-fPercentBetweenColors); - tempState.diffuse[i].a *= fOriginalAlpha; // multiply the alphas so we can fade even while an effect is playing - } - break; - case diffuse_ramp: - for(int i=0; i<4; i++) - { - tempState.diffuse[i] = m_effectColor1*fPercentThroughEffect + m_effectColor2*(1.0f-fPercentThroughEffect); - tempState.diffuse[i].a *= fOriginalAlpha; // multiply the alphas so we can fade even while an effect is playing - } - break; - case glow_blink: - tempState.glow = bBlinkOn ? m_effectColor1 : m_effectColor2; - tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent! - break; - case glow_shift: - tempState.glow = m_effectColor1*fPercentBetweenColors + m_effectColor2*(1.0f-fPercentBetweenColors); - tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent! - break; - case glow_ramp: - tempState.glow = m_effectColor1*fPercentThroughEffect + m_effectColor2*(1.0f-fPercentThroughEffect); - tempState.glow.a *= fOriginalAlpha; // don't glow if the Actor is transparent! - break; - case rainbow: - tempState.diffuse[0] = RageColor( - RageFastCos( fPercentBetweenColors*2*PI ) * 0.5f + 0.5f, - RageFastCos( fPercentBetweenColors*2*PI + PI * 2.0f / 3.0f ) * 0.5f + 0.5f, - RageFastCos( fPercentBetweenColors*2*PI + PI * 4.0f / 3.0f) * 0.5f + 0.5f, - fOriginalAlpha ); - for( int i=1; i<4; i++ ) - tempState.diffuse[i] = tempState.diffuse[0]; - break; - case wag: - tempState.rotation += m_vEffectMagnitude * RageFastSin( fPercentThroughEffect * 2.0f * PI ); - break; - case spin: - // nothing needs to be here - break; - case vibrate: - tempState.pos.x += m_vEffectMagnitude.x * randomf(-1.0f, 1.0f) * GetZoom(); - tempState.pos.y += m_vEffectMagnitude.y * randomf(-1.0f, 1.0f) * GetZoom(); - tempState.pos.z += m_vEffectMagnitude.z * randomf(-1.0f, 1.0f) * GetZoom(); - break; - case bounce: - { - float fPercentOffset = RageFastSin( fPercentThroughEffect*PI ); - tempState.pos += m_vEffectMagnitude * fPercentOffset; - tempState.pos.x = roundf( tempState.pos.x ); - tempState.pos.y = roundf( tempState.pos.y ); - tempState.pos.z = roundf( tempState.pos.z ); - } - break; - case bob: - { - float fPercentOffset = RageFastSin( fPercentThroughEffect*PI*2 ); - tempState.pos += m_vEffectMagnitude * fPercentOffset; - tempState.pos.x = roundf( tempState.pos.x ); - tempState.pos.y = roundf( tempState.pos.y ); - tempState.pos.z = roundf( tempState.pos.z ); - } - break; - case pulse: - { - float fMinZoom = m_vEffectMagnitude[0]; - float fMaxZoom = m_vEffectMagnitude[1]; - float fPercentOffset = RageFastSin( fPercentThroughEffect*PI ); - float fZoom = SCALE( fPercentOffset, 0.f, 1.f, fMinZoom, fMaxZoom ); - tempState.scale *= fZoom; - - // Use the color as a Vector3 to scale the effect for added control - RageColor c = SCALE( fPercentOffset, 0.f, 1.f, m_effectColor1, m_effectColor2 ); - tempState.scale.x *= c.r; - tempState.scale.y *= c.g; - tempState.scale.z *= c.b; - } - break; - default: - ASSERT(0); // invalid Effect - } - } - - if( m_fBaseAlpha != 1 ) - { - if( m_pTempState != &tempState ) - { - m_pTempState = &tempState; - tempState = m_current; - } - - for( int i=0; i<4; i++ ) - tempState.diffuse[i].a *= m_fBaseAlpha; - } - - if( m_pTempState->pos.x != 0 || m_pTempState->pos.y != 0 || m_pTempState->pos.z != 0 ) - { - RageMatrix m; - RageMatrixTranslate( - &m, - m_pTempState->pos.x, - m_pTempState->pos.y, - m_pTempState->pos.z - ); - DISPLAY->PreMultMatrix( m ); - } - - { - /* The only time rotation and quat should normally be used simultaneously - * is for m_baseRotation. Most objects aren't rotated at all, so optimize - * that case. */ - const float fRotateX = m_pTempState->rotation.x + m_baseRotation.x; - const float fRotateY = m_pTempState->rotation.y + m_baseRotation.y; - const float fRotateZ = m_pTempState->rotation.z + m_baseRotation.z; - - if( fRotateX != 0 || fRotateY != 0 || fRotateZ != 0 ) - { - RageMatrix m; - RageMatrixRotationXYZ( &m, fRotateX, fRotateY, fRotateZ ); - DISPLAY->PreMultMatrix( m ); - } - } - - // handle scaling - { - const float fScaleX = m_pTempState->scale.x * m_baseScale.x; - const float fScaleY = m_pTempState->scale.y * m_baseScale.y; - const float fScaleZ = m_pTempState->scale.z * m_baseScale.z; - - if( fScaleX != 1 || fScaleY != 1 || fScaleZ != 1 ) - { - RageMatrix m; - RageMatrixScale( - &m, - fScaleX, - fScaleY, - fScaleZ ); - DISPLAY->PreMultMatrix( m ); - } - } - - // handle alignment; most actors have default alignment. - if( unlikely(m_fHorizAlign != 0.5f || m_fVertAlign != 0.5f) ) - { - float fX = SCALE( m_fHorizAlign, 0.0f, 1.0f, +m_size.x/2.0f, -m_size.x/2.0f ); - float fY = SCALE( m_fVertAlign, 0.0f, 1.0f, +m_size.y/2.0f, -m_size.y/2.0f ); - RageMatrix m; - RageMatrixTranslate( - &m, - fX, - fY, - 0 - ); - DISPLAY->PreMultMatrix( m ); - } - - if( m_pTempState->quat.x != 0 || m_pTempState->quat.y != 0 || m_pTempState->quat.z != 0 || m_pTempState->quat.w != 1 ) - { - RageMatrix mat; - RageMatrixFromQuat( &mat, m_pTempState->quat ); - - DISPLAY->MultMatrix(mat); - } - - // handle skews - if( m_pTempState->fSkewX != 0 ) - { - DISPLAY->SkewX( m_pTempState->fSkewX ); - } - - if( m_pTempState->fSkewY != 0 ) - { - DISPLAY->SkewY( m_pTempState->fSkewY ); - } - -} - -void Actor::SetGlobalRenderStates() -{ - // set Actor-defined render states - if( !g_bShowMasks.Get() || m_BlendMode != BLEND_NO_EFFECT ) - DISPLAY->SetBlendMode( m_BlendMode ); - DISPLAY->SetZWrite( m_bZWrite ); - DISPLAY->SetZTestMode( m_ZTestMode ); - - // BLEND_NO_EFFECT is used to draw masks to the Z-buffer, which always wants - // Z-bias enabled. - if( m_fZBias == 0 && m_BlendMode == BLEND_NO_EFFECT ) - DISPLAY->SetZBias( 1.0f ); - else - DISPLAY->SetZBias( m_fZBias ); - - if( m_bClearZBuffer ) - DISPLAY->ClearZBuffer(); - DISPLAY->SetCullMode( m_CullMode ); -} - -void Actor::SetTextureRenderStates() -{ - DISPLAY->SetTextureWrapping( TextureUnit_1, m_bTextureWrapping ); - DISPLAY->SetTextureFiltering( TextureUnit_1, m_bTextureFiltering ); -} - -void Actor::EndDraw() -{ - DISPLAY->PopMatrix(); - m_pTempState = NULL; -} - -void Actor::UpdateTweening( float fDeltaTime ) -{ - while( 1 ) - { - 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; - TweenInfo &TI = m_Tweens[0]->info; - - bool bBeginning = TI.m_fTimeLeftInTween == TI.m_fTweenTime; - - float fSecsToSubtract = min( TI.m_fTimeLeftInTween, fDeltaTime ); - TI.m_fTimeLeftInTween -= fSecsToSubtract; - fDeltaTime -= fSecsToSubtract; - - RString sCommand = TI.m_sCommandName; - if( bBeginning ) // we are just beginning this tween - m_start = m_current; // set the start position - - if( TI.m_fTimeLeftInTween == 0 ) // Current tween is over. Stop. - { - m_current = TS; - - // delete the head tween - delete m_Tweens.front(); - m_Tweens.erase( m_Tweens.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 = TI.m_pTween->Tween( fPercentThroughTween ); - TweenState::MakeWeightedAverage( m_current, m_start, TS, fPercentAlongPath ); - } - - if( bBeginning ) - { - // Execute the command in this tween (if any). Do this last, and don't - // access TI or TS after, since this may modify the tweening queue. - if( !sCommand.empty() ) - { - if( sCommand.Left(1) == "!" ) - MESSAGEMAN->Broadcast( sCommand.substr(1) ); - else - this->PlayCommand( sCommand ); - } - } - } -} - -bool Actor::IsFirstUpdate() const -{ - return m_bFirstUpdate; -} - -void Actor::Update( float fDeltaTime ) -{ -// LOG->Trace( "Actor::Update( %f )", fDeltaTime ); - ASSERT_M( fDeltaTime >= 0, ssprintf("DeltaTime: %f",fDeltaTime) ); - - if( m_fHibernateSecondsLeft > 0 ) - { - m_fHibernateSecondsLeft -= fDeltaTime; - if( m_fHibernateSecondsLeft > 0 ) - return; - - // Grab the leftover time. - fDeltaTime = -m_fHibernateSecondsLeft; - m_fHibernateSecondsLeft = 0; - } - - this->UpdateInternal( fDeltaTime ); -} - -void Actor::UpdateInternal( float fDeltaTime ) -{ - if( m_bFirstUpdate ) - m_bFirstUpdate = false; - - switch( m_EffectClock ) - { - case CLOCK_TIMER: - m_fSecsIntoEffect += fDeltaTime; - m_fEffectDelta = fDeltaTime; - - /* Wrap the counter, so it doesn't increase indefinitely (causing loss - * of precision if a screen is left to sit for a day). */ - if( m_fSecsIntoEffect >= GetEffectPeriod() ) - m_fSecsIntoEffect -= GetEffectPeriod(); - break; - - case CLOCK_TIMER_GLOBAL: - { - float fTime = RageTimer::GetTimeSinceStartFast(); - m_fEffectDelta = fTime - m_fSecsIntoEffect; - m_fSecsIntoEffect = fTime; - break; - } - - case CLOCK_BGM_BEAT: - m_fEffectDelta = g_fCurrentBGMBeat - m_fSecsIntoEffect; - m_fSecsIntoEffect = g_fCurrentBGMBeat; - break; - - case CLOCK_BGM_BEAT_PLAYER1: - m_fEffectDelta = g_vfCurrentBGMBeatPlayer[PLAYER_1] - m_fSecsIntoEffect; - m_fSecsIntoEffect = g_vfCurrentBGMBeatPlayerNoOffset[PLAYER_1]; - break; - - case CLOCK_BGM_BEAT_PLAYER2: - m_fEffectDelta = g_vfCurrentBGMBeatPlayer[PLAYER_2] - m_fSecsIntoEffect; - m_fSecsIntoEffect = g_vfCurrentBGMBeatPlayerNoOffset[PLAYER_2]; - break; - - case CLOCK_BGM_TIME: - m_fEffectDelta = g_fCurrentBGMTime - m_fSecsIntoEffect; - m_fSecsIntoEffect = g_fCurrentBGMTime; - break; - - case CLOCK_BGM_BEAT_NO_OFFSET: - m_fEffectDelta = g_fCurrentBGMBeatNoOffset - m_fSecsIntoEffect; - m_fSecsIntoEffect = g_fCurrentBGMBeatNoOffset; - break; - - case CLOCK_BGM_TIME_NO_OFFSET: - m_fEffectDelta = g_fCurrentBGMTimeNoOffset - m_fSecsIntoEffect; - m_fSecsIntoEffect = g_fCurrentBGMTimeNoOffset; - break; - - default: - if( m_EffectClock >= CLOCK_LIGHT_1 && m_EffectClock <= CLOCK_LIGHT_LAST ) - { - int i = m_EffectClock - CLOCK_LIGHT_1; - m_fEffectDelta = g_fCabinetLights[i] - m_fSecsIntoEffect; - m_fSecsIntoEffect = g_fCabinetLights[i]; - } - break; - } - - // update effect - // todo: account for SSC_FUTURES -aj - switch( m_Effect ) - { - case spin: - m_current.rotation += m_fEffectDelta*m_vEffectMagnitude; - wrap( m_current.rotation.x, 360 ); - wrap( m_current.rotation.y, 360 ); - wrap( m_current.rotation.z, 360 ); - break; - default: break; - } - - UpdateTweening( fDeltaTime ); -} - -RString Actor::GetLineage() const -{ - RString sPath; - - if( m_pParent ) - sPath = m_pParent->GetLineage() + '/'; - sPath += ssprintf( "<%s> %s", typeid(*this).name(), m_sName.c_str() ); - return sPath; -} - -void Actor::BeginTweening( float time, ITween *pTween ) -{ - ASSERT( time >= 0 ); - - time = max( time, 0 ); - - // If the number of tweens to ever gets this large, there's probably an infinitely - // recursing ActorCommand. - if( m_Tweens.size() > 50 ) - { - RString sError = ssprintf( "Tween overflow: \"%s\"; infinitely recursing ActorCommand?", GetLineage().c_str() ); - - LOG->Warn( "%s", sError.c_str() ); - Dialog::OK( sError ); - FinishTweening(); - } - - // add a new TweenState to the tail, and initialize it - m_Tweens.push_back( new TweenStateAndInfo ); - - // latest - TweenState &TS = m_Tweens.back()->state; - TweenInfo &TI = m_Tweens.back()->info; - - if( m_Tweens.size() >= 2 ) // if there was already a TS on the stack - { - // initialize the new TS from the last TS in the list - TS = m_Tweens[m_Tweens.size()-2]->state; - } - else - { - // This new TS is the only TS. - // Set our tween starting and ending values to the current position. - TS = m_current; - } - - TI.m_pTween = pTween; - TI.m_fTweenTime = time; - TI.m_fTimeLeftInTween = time; -} - -void Actor::BeginTweening( float time, TweenType tt ) -{ - ITween *pTween = ITween::CreateFromType( tt ); - BeginTweening( time, pTween ); -} - -void Actor::StopTweening() -{ - for( unsigned i = 0; i < m_Tweens.size(); ++i ) - delete m_Tweens[i]; - m_Tweens.clear(); -} - -void Actor::FinishTweening() -{ - if( !m_Tweens.empty() ) - m_current = DestTweenState(); - StopTweening(); -} - -void Actor::HurryTweening( float factor ) -{ - for( unsigned i = 0; i < m_Tweens.size(); ++i ) - { - m_Tweens[i]->info.m_fTimeLeftInTween *= factor; - m_Tweens[i]->info.m_fTweenTime *= factor; - } -} - -void Actor::ScaleTo( const RectF &rect, StretchType st ) -{ - // width and height of rectangle - float rect_width = rect.GetWidth(); - float rect_height = rect.GetHeight(); - - if( rect_width < 0 ) SetRotationY( 180 ); - if( rect_height < 0 ) SetRotationX( 180 ); - - // zoom fActor needed to scale the Actor to fill the rectangle - float fNewZoomX = fabsf(rect_width / m_size.x); - float fNewZoomY = fabsf(rect_height / m_size.y); - - float fNewZoom = 0.f; - 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; - } - - SetX( rect.left + rect_width * m_fHorizAlign ); - SetY( rect.top + rect_height * m_fVertAlign ); - - SetZoom( fNewZoom ); -} - -void Actor::SetEffectClockString( const RString &s ) -{ - if (s.EqualsNoCase("timer")) this->SetEffectClock( CLOCK_TIMER ); - if (s.EqualsNoCase("timerglobal")) this->SetEffectClock( CLOCK_TIMER_GLOBAL ); - else if(s.EqualsNoCase("beat")) this->SetEffectClock( CLOCK_BGM_BEAT ); - else if(s.EqualsNoCase("music")) this->SetEffectClock( CLOCK_BGM_TIME ); - else if(s.EqualsNoCase("bgm")) this->SetEffectClock( CLOCK_BGM_BEAT ); // compat, deprecated - else if(s.EqualsNoCase("musicnooffset"))this->SetEffectClock( CLOCK_BGM_TIME_NO_OFFSET ); - else if(s.EqualsNoCase("beatnooffset")) this->SetEffectClock( CLOCK_BGM_BEAT_NO_OFFSET ); - else - { - CabinetLight cl = StringToCabinetLight( s ); - if( cl != CabinetLight_Invalid ) - { - this->SetEffectClock( (EffectClock) (cl + CLOCK_LIGHT_1) ); - return; - } - else - ASSERT(0); - } -} - -void Actor::StretchTo( const RectF &r ) -{ - // width and height of rectangle - float width = r.GetWidth(); - float height = r.GetHeight(); - - // center of the rectangle - float cx = r.left + width/2.0f; - float cy = r.top + height/2.0f; - - // zoom fActor needed to scale the Actor to fill the rectangle - float fNewZoomX = width / m_size.x; - float fNewZoomY = height / m_size.y; - - SetXY( cx, cy ); - SetZoomX( fNewZoomX ); - SetZoomY( fNewZoomY ); -} - - -void Actor::SetEffectPeriod( float fTime ) -{ - ASSERT( fTime > 0 ); - m_fEffectRampUp = fTime/2; - m_fEffectHoldAtHalf = 0; - m_fEffectRampDown = fTime/2; - m_fEffectHoldAtZero = 0; -} - -float Actor::GetEffectPeriod() const -{ - return m_fEffectRampUp + m_fEffectHoldAtHalf + m_fEffectRampDown + m_fEffectHoldAtZero; -} - -void Actor::SetEffectTiming( float fRampUp, float fAtHalf, float fRampDown, float fAtZero ) -{ - m_fEffectRampUp = fRampUp; - m_fEffectHoldAtHalf = fAtHalf; - m_fEffectRampDown = fRampDown; - m_fEffectHoldAtZero = fAtZero; - ASSERT( GetEffectPeriod() > 0 ); -} - -// effect "macros" - -void Actor::SetEffectDiffuseBlink( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != diffuse_blink ) - { - m_Effect = diffuse_blink; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fEffectPeriodSeconds ); - m_effectColor1 = c1; - m_effectColor2 = c2; -} - -void Actor::SetEffectDiffuseShift( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != diffuse_shift ) - { - m_Effect = diffuse_shift; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fEffectPeriodSeconds ); - m_effectColor1 = c1; - m_effectColor2 = c2; -} - -void Actor::SetEffectDiffuseRamp( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != diffuse_ramp ) - { - m_Effect = diffuse_ramp; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fEffectPeriodSeconds ); - m_effectColor1 = c1; - m_effectColor2 = c2; -} - -void Actor::SetEffectGlowBlink( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != glow_blink ) - { - m_Effect = glow_blink; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fEffectPeriodSeconds ); - m_effectColor1 = c1; - m_effectColor2 = c2; -} - -void Actor::SetEffectGlowShift( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != glow_shift ) - { - m_Effect = glow_shift; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fEffectPeriodSeconds ); - m_effectColor1 = c1; - m_effectColor2 = c2; -} - -void Actor::SetEffectGlowRamp( float fEffectPeriodSeconds, RageColor c1, RageColor c2 ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != glow_ramp ) - { - m_Effect = glow_ramp; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fEffectPeriodSeconds ); - m_effectColor1 = c1; - m_effectColor2 = c2; -} - -void Actor::SetEffectRainbow( float fEffectPeriodSeconds ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != rainbow ) - { - m_Effect = rainbow; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fEffectPeriodSeconds ); -} - -void Actor::SetEffectWag( float fPeriod, RageVector3 vect ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect != wag ) - { - m_Effect = wag; - m_fSecsIntoEffect = 0; - } - SetEffectPeriod( fPeriod ); - m_vEffectMagnitude = vect; -} - -void Actor::SetEffectBounce( float fPeriod, RageVector3 vect ) -{ - // todo: account for SSC_FUTURES -aj - m_Effect = bounce; - SetEffectPeriod( fPeriod ); - m_vEffectMagnitude = vect; - m_fSecsIntoEffect = 0; -} - -void Actor::SetEffectBob( float fPeriod, RageVector3 vect ) -{ - // todo: account for SSC_FUTURES -aj - if( m_Effect!=bob || GetEffectPeriod() != fPeriod ) - { - m_Effect = bob; - SetEffectPeriod( fPeriod ); - m_fSecsIntoEffect = 0; - } - m_vEffectMagnitude = vect; -} - -void Actor::SetEffectSpin( RageVector3 vect ) -{ - // todo: account for SSC_FUTURES -aj - m_Effect = spin; - m_vEffectMagnitude = vect; -} - -void Actor::SetEffectVibrate( RageVector3 vect ) -{ - // todo: account for SSC_FUTURES -aj - m_Effect = vibrate; - m_vEffectMagnitude = vect; -} - -void Actor::SetEffectPulse( float fPeriod, float fMinZoom, float fMaxZoom ) -{ - // todo: account for SSC_FUTURES -aj - m_Effect = pulse; - SetEffectPeriod( fPeriod ); - m_vEffectMagnitude[0] = fMinZoom; - m_vEffectMagnitude[1] = fMaxZoom; -} - - -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) ); -} - -void Actor::RunCommands( const LuaReference& cmds, const LuaReference *pParamTable ) -{ - Lua *L = LUA->Get(); - - // function - cmds.PushSelf( L ); - ASSERT( !lua_isnil(L, -1) ); - - // 1st parameter - this->PushSelf( L ); - - // 2nd parameter - if( pParamTable == NULL ) - lua_pushnil( L ); - else - pParamTable->PushSelf( L ); - - // call function with 2 arguments and 0 results - RString sError; - if( !LuaHelpers::RunScriptOnStack(L, sError, 2, 0) ) - LOG->Warn( "Error playing command: %s", sError.c_str() ); - - LUA->Release(L); -} - -float Actor::GetTweenTimeLeft() const -{ - float tot = 0; - - tot += m_fHibernateSecondsLeft; - - for( unsigned i=0; iinfo.m_fTimeLeftInTween; - - return tot; -} - -/* This is a hack to change all tween states while leaving existing tweens alone. - * - * Hmm. Most commands actually act on a TweenStateAndInfo, not the Actor itself. - * Conceptually, it wouldn't be hard to give TweenState a presence in Lua, so - * we can simply say eg. "for x in states(Actor) do x.SetDiffuseColor(c) end". - * However, we'd then have to give every TweenState a userdata in Lua while it's - * being manipulated, which would add overhead ... */ -void Actor::SetGlobalDiffuseColor( RageColor c ) -{ - for( int i=0; i<4; i++ ) // color, not alpha - { - for( unsigned ts = 0; ts < m_Tweens.size(); ++ts ) - { - m_Tweens[ts]->state.diffuse[i].r = c.r; - m_Tweens[ts]->state.diffuse[i].g = c.g; - m_Tweens[ts]->state.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::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; - } -} - - -void Actor::TweenState::Init() -{ - pos = RageVector3( 0, 0, 0 ); - rotation = RageVector3( 0, 0, 0 ); - quat = RageVector4( 0, 0, 0, 1 ); - scale = RageVector3( 1, 1, 1 ); - fSkewX = 0; - fSkewY = 0; - crop = RectF( 0,0,0,0 ); - fade = RectF( 0,0,0,0 ); - for( int i=0; i<4; i++ ) - diffuse[i] = RageColor( 1, 1, 1, 1 ); - glow = RageColor( 1, 1, 1, 0 ); - aux = 0; -} - -bool Actor::TweenState::operator==( const TweenState &other ) const -{ -#define COMPARE( x ) if( x != other.x ) return false; - COMPARE( pos ); - COMPARE( rotation ); - COMPARE( quat ); - COMPARE( scale ); - COMPARE( fSkewX ); - COMPARE( fSkewY ); - COMPARE( crop ); - COMPARE( fade ); - for( unsigned i=0; iinfo; - TI.m_sCommandName = sCommandName; -} - -void Actor::QueueMessage( const RString& sMessageName ) -{ - // Hack: use "!" as a marker to broadcast a command, instead of playing a - // command, so we don't have to add yet another element to every tween - // state for this rarely-used command. - BeginTweening( 0, TWEEN_LINEAR ); - TweenInfo &TI = m_Tweens.back()->info; - TI.m_sCommandName = "!" + sMessageName; -} - -void Actor::AddCommand( const RString &sCmdName, apActorCommands apac ) -{ - if( HasCommand(sCmdName) ) - { - RString sWarning = GetLineage()+"'s command '"+sCmdName+"' defined twice"; - Dialog::OK( sWarning, "COMMAND_DEFINED_TWICE" ); - } - - RString sMessage; - if( GetMessageNameFromCommandName(sCmdName, sMessage) ) - { - SubscribeToMessage( sMessage ); - m_mapNameToCommands[sMessage] = apac; // sCmdName w/o "Message" at the end - } - else - { - m_mapNameToCommands[sCmdName] = apac; - } -} - -bool Actor::HasCommand( const RString &sCmdName ) const -{ - return GetCommand(sCmdName) != NULL; -} - -const apActorCommands *Actor::GetCommand( const RString &sCommandName ) const -{ - map::const_iterator it = m_mapNameToCommands.find( sCommandName ); - if( it == m_mapNameToCommands.end() ) - return NULL; - return &it->second; -} - -void Actor::HandleMessage( const Message &msg ) -{ - PlayCommandNoRecurse( msg ); -} - -void Actor::PlayCommandNoRecurse( const Message &msg ) -{ - const apActorCommands *pCmd = GetCommand( msg.GetName() ); - if( pCmd != NULL ) - RunCommands( *pCmd, &msg.GetParamTable() ); -} - -void Actor::PushContext( lua_State *L ) -{ - // self.ctx should already exist - m_pLuaInstance->PushSelf( L ); - lua_getfield( L, -1, "ctx" ); - lua_remove( L, -2 ); -} - -void Actor::SetParent( Actor *pParent ) -{ - m_pParent = pParent; - - Lua *L = LUA->Get(); - int iTop = lua_gettop( L ); - - this->PushContext( L ); - lua_pushstring( L, "__index" ); - pParent->PushContext( L ); - lua_settable( L, -3 ); - - lua_settop( L, iTop ); - LUA->Release( L ); -} - -Actor::TweenInfo::TweenInfo() -{ - m_pTween = NULL; -} - -Actor::TweenInfo::~TweenInfo() -{ - delete m_pTween; -} - -Actor::TweenInfo::TweenInfo( const TweenInfo &cpy ) -{ - m_pTween = NULL; - *this = cpy; -} - -Actor::TweenInfo &Actor::TweenInfo::operator=( const TweenInfo &rhs ) -{ - delete m_pTween; - m_pTween = (rhs.m_pTween? rhs.m_pTween->Copy():NULL); - m_fTimeLeftInTween = rhs.m_fTimeLeftInTween; - m_fTweenTime = rhs.m_fTweenTime; - m_sCommandName = rhs.m_sCommandName; - return *this; -} - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the Actor. */ -class LunaActor : public Luna -{ -public: - static int name( T* p, lua_State *L ) { p->SetName(SArg(1)); return 0; } - static int sleep( T* p, lua_State *L ) { p->Sleep(FArg(1)); return 0; } - static int linear( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_LINEAR); return 0; } - static int accelerate( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_ACCELERATE); return 0; } - static int decelerate( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_DECELERATE); return 0; } - static int spring( T* p, lua_State *L ) { p->BeginTweening(FArg(1),TWEEN_SPRING); return 0; } - static int tween( T* p, lua_State *L ) - { - ITween *pTween = ITween::CreateFromStack( L, 2 ); - p->BeginTweening( FArg(1), pTween ); - return 0; - } - static int stoptweening( T* p, lua_State *L ) { p->StopTweening(); return 0; } - static int finishtweening( T* p, lua_State *L ) { p->FinishTweening(); return 0; } - static int hurrytweening( T* p, lua_State *L ) { p->HurryTweening(FArg(1)); return 0; } - static int GetTweenTimeLeft( T* p, lua_State *L ) { lua_pushnumber( L, p->GetTweenTimeLeft() ); return 1; } - static int x( T* p, lua_State *L ) { p->SetX(FArg(1)); return 0; } - static int y( T* p, lua_State *L ) { p->SetY(FArg(1)); return 0; } - static int z( T* p, lua_State *L ) { p->SetZ(FArg(1)); return 0; } - static int addx( T* p, lua_State *L ) { p->AddX(FArg(1)); return 0; } - static int addy( T* p, lua_State *L ) { p->AddY(FArg(1)); return 0; } - static int addz( T* p, lua_State *L ) { p->AddZ(FArg(1)); return 0; } - static int zoom( T* p, lua_State *L ) { p->SetZoom(FArg(1)); return 0; } - static int zoomx( T* p, lua_State *L ) { p->SetZoomX(FArg(1)); return 0; } - static int zoomy( T* p, lua_State *L ) { p->SetZoomY(FArg(1)); return 0; } - static int zoomz( T* p, lua_State *L ) { p->SetZoomZ(FArg(1)); return 0; } - static int zoomto( T* p, lua_State *L ) { p->ZoomTo(FArg(1), FArg(2)); return 0; } - static int zoomtowidth( T* p, lua_State *L ) { p->ZoomToWidth(FArg(1)); return 0; } - static int zoomtoheight( T* p, lua_State *L ) { p->ZoomToHeight(FArg(1)); return 0; } - static int setsize( T* p, lua_State *L ) { p->SetWidth(FArg(1)); p->SetHeight(FArg(2)); return 0; } - static int SetWidth( T* p, lua_State *L ) { p->SetWidth(FArg(1)); return 0; } - static int SetHeight( T* p, lua_State *L ) { p->SetHeight(FArg(1)); return 0; } - static int basealpha( T* p, lua_State *L ) { p->SetBaseAlpha(FArg(1)); return 0; } - static int basezoom( T* p, lua_State *L ) { p->SetBaseZoom(FArg(1)); return 0; } - static int basezoomx( T* p, lua_State *L ) { p->SetBaseZoomX(FArg(1)); return 0; } - static int basezoomy( T* p, lua_State *L ) { p->SetBaseZoomY(FArg(1)); return 0; } - static int basezoomz( T* p, lua_State *L ) { p->SetBaseZoomZ(FArg(1)); return 0; } - static int stretchto( T* p, lua_State *L ) { p->StretchTo( RectF(FArg(1),FArg(2),FArg(3),FArg(4)) ); return 0; } - static int cropleft( T* p, lua_State *L ) { p->SetCropLeft(FArg(1)); return 0; } - static int croptop( T* p, lua_State *L ) { p->SetCropTop(FArg(1)); return 0; } - static int cropright( T* p, lua_State *L ) { p->SetCropRight(FArg(1)); return 0; } - static int cropbottom( T* p, lua_State *L ) { p->SetCropBottom(FArg(1)); return 0; } - static int fadeleft( T* p, lua_State *L ) { p->SetFadeLeft(FArg(1)); return 0; } - static int fadetop( T* p, lua_State *L ) { p->SetFadeTop(FArg(1)); return 0; } - static int faderight( T* p, lua_State *L ) { p->SetFadeRight(FArg(1)); return 0; } - static int fadebottom( T* p, lua_State *L ) { p->SetFadeBottom(FArg(1)); return 0; } - static int diffuse( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuse( c ); return 0; } - static int diffuseupperleft( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseUpperLeft( c ); return 0; } - static int diffuseupperright( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseUpperRight( c ); return 0; } - static int diffuselowerleft( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLowerLeft( c ); return 0; } - static int diffuselowerright( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLowerRight( c ); return 0; } - static int diffuseleftedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLeftEdge( c ); return 0; } - static int diffuserightedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseRightEdge( c ); return 0; } - static int diffusetopedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseTopEdge( c ); return 0; } - static int diffusebottomedge( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseBottomEdge( c ); return 0; } - static int diffusealpha( T* p, lua_State *L ) { p->SetDiffuseAlpha(FArg(1)); return 0; } - static int diffusecolor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseColor( c ); return 0; } - static int glow( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetGlow( c ); return 0; } - static int aux( T* p, lua_State *L ) { p->SetAux( FArg(1) ); return 0; } - static int getaux( T* p, lua_State *L ) { lua_pushnumber( L, p->GetAux() ); return 1; } - static int rotationx( T* p, lua_State *L ) { p->SetRotationX(FArg(1)); return 0; } - static int rotationy( T* p, lua_State *L ) { p->SetRotationY(FArg(1)); return 0; } - static int rotationz( T* p, lua_State *L ) { p->SetRotationZ(FArg(1)); return 0; } - static int addrotationx( T* p, lua_State *L ) { p->AddRotationX(FArg(1)); return 0; } - static int addrotationy( T* p, lua_State *L ) { p->AddRotationY(FArg(1)); return 0; } - static int addrotationz( T* p, lua_State *L ) { p->AddRotationZ(FArg(1)); return 0; } - static int getrotation( T* p, lua_State *L ) { lua_pushnumber(L, p->GetRotationX()); lua_pushnumber(L, p->GetRotationY()); lua_pushnumber(L, p->GetRotationZ()); return 3; } - static int baserotationx( T* p, lua_State *L ) { p->SetBaseRotationX(FArg(1)); return 0; } - static int baserotationy( T* p, lua_State *L ) { p->SetBaseRotationY(FArg(1)); return 0; } - static int baserotationz( T* p, lua_State *L ) { p->SetBaseRotationZ(FArg(1)); return 0; } - static int skewx( T* p, lua_State *L ) { p->SetSkewX(FArg(1)); return 0; } - static int skewy( T* p, lua_State *L ) { p->SetSkewY(FArg(1)); return 0; } - static int heading( T* p, lua_State *L ) { p->AddRotationH(FArg(1)); return 0; } - static int pitch( T* p, lua_State *L ) { p->AddRotationP(FArg(1)); return 0; } - static int roll( T* p, lua_State *L ) { p->AddRotationR(FArg(1)); return 0; } - static int shadowlength( T* p, lua_State *L ) { p->SetShadowLength(FArg(1)); return 0; } - static int shadowlengthx( T* p, lua_State *L ) { p->SetShadowLengthX(FArg(1)); return 0; } - static int shadowlengthy( T* p, lua_State *L ) { p->SetShadowLengthY(FArg(1)); return 0; } - static int shadowcolor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetShadowColor( c ); return 0; } - static int horizalign( T* p, lua_State *L ) { p->SetHorizAlign(Enum::Check(L, 1)); return 0; } - static int vertalign( T* p, lua_State *L ) { p->SetVertAlign(Enum::Check(L, 1)); return 0; } - static int halign( T* p, lua_State *L ) { p->SetHorizAlign(FArg(1)); return 0; } - static int valign( T* p, lua_State *L ) { p->SetVertAlign(FArg(1)); return 0; } - static int diffuseblink( T* p, lua_State *L ) { p->SetEffectDiffuseBlink(); return 0; } - static int diffuseshift( T* p, lua_State *L ) { p->SetEffectDiffuseShift(); return 0; } - static int diffuseramp( T* p, lua_State *L ) { p->SetEffectDiffuseRamp(); return 0; } - static int glowblink( T* p, lua_State *L ) { p->SetEffectGlowBlink(); return 0; } - static int glowshift( T* p, lua_State *L ) { p->SetEffectGlowShift(); return 0; } - static int glowramp( T* p, lua_State *L ) { p->SetEffectGlowRamp(); return 0; } - static int rainbow( T* p, lua_State *L ) { p->SetEffectRainbow(); return 0; } - static int wag( T* p, lua_State *L ) { p->SetEffectWag(); return 0; } - static int bounce( T* p, lua_State *L ) { p->SetEffectBounce(); return 0; } - static int bob( T* p, lua_State *L ) { p->SetEffectBob(); return 0; } - static int pulse( T* p, lua_State *L ) { p->SetEffectPulse(); return 0; } - static int spin( T* p, lua_State *L ) { p->SetEffectSpin(); return 0; } - static int vibrate( T* p, lua_State *L ) { p->SetEffectVibrate(); return 0; } - static int stopeffect( T* p, lua_State *L ) { p->StopEffect(); return 0; } - static int effectcolor1( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetEffectColor1( c ); return 0; } - static int effectcolor2( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetEffectColor2( c ); return 0; } - static int effectperiod( T* p, lua_State *L ) { p->SetEffectPeriod(FArg(1)); return 0; } - static int effecttiming( T* p, lua_State *L ) { p->SetEffectTiming(FArg(1),FArg(2),FArg(3),FArg(4)); return 0; } - static int effectoffset( T* p, lua_State *L ) { p->SetEffectOffset(FArg(1)); return 0; } - static int effectclock( T* p, lua_State *L ) { p->SetEffectClockString(SArg(1)); return 0; } - static int effectmagnitude( T* p, lua_State *L ) { p->SetEffectMagnitude( RageVector3(FArg(1),FArg(2),FArg(3)) ); return 0; } - static int geteffectmagnitude( T* p, lua_State *L ) { RageVector3 v = p->GetEffectMagnitude(); lua_pushnumber(L, v[0]); lua_pushnumber(L, v[1]); lua_pushnumber(L, v[2]); return 3; } - static int scaletocover( T* p, lua_State *L ) { p->ScaleToCover( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) ); return 0; } - static int scaletofit( T* p, lua_State *L ) { p->ScaleToFitInside( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) ); return 0; } - static int animate( T* p, lua_State *L ) { p->EnableAnimation(BIArg(1)); return 0; } - static int play( T* p, lua_State *L ) { p->EnableAnimation(true); return 0; } - static int pause( T* p, lua_State *L ) { p->EnableAnimation(false); return 0; } - static int setstate( T* p, lua_State *L ) { p->SetState(IArg(1)); return 0; } - static int GetNumStates( T* p, lua_State *L ) { LuaHelpers::Push( L, p->GetNumStates() ); return 1; } - static int texturewrapping( T* p, lua_State *L ) { p->SetTextureWrapping(BIArg(1)); return 0; } - static int SetTextureFiltering( T* p, lua_State *L ) { p->SetTextureFiltering(BArg(1)); return 0; } - static int blend( T* p, lua_State *L ) { p->SetBlendMode( Enum::Check(L, 1) ); return 0; } - static int zbuffer( T* p, lua_State *L ) { p->SetUseZBuffer(BIArg(1)); return 0; } - static int ztest( T* p, lua_State *L ) { p->SetZTestMode((BIArg(1))?ZTEST_WRITE_ON_PASS:ZTEST_OFF); return 0; } - static int ztestmode( T* p, lua_State *L ) { p->SetZTestMode( Enum::Check(L, 1) ); return 0; } - static int zwrite( T* p, lua_State *L ) { p->SetZWrite(BIArg(1)); return 0; } - static int zbias( T* p, lua_State *L ) { p->SetZBias(FArg(1)); return 0; } - static int clearzbuffer( T* p, lua_State *L ) { p->SetClearZBuffer(BIArg(1)); return 0; } - static int backfacecull( T* p, lua_State *L ) { p->SetCullMode((BIArg(1)) ? CULL_BACK : CULL_NONE); return 0; } - static int cullmode( T* p, lua_State *L ) { p->SetCullMode( Enum::Check(L, 1)); return 0; } - static int visible( T* p, lua_State *L ) { p->SetVisible(BIArg(1)); return 0; } - static int hibernate( T* p, lua_State *L ) { p->SetHibernate(FArg(1)); return 0; } - static int draworder( T* p, lua_State *L ) { p->SetDrawOrder(IArg(1)); return 0; } - static int playcommand( T* p, lua_State *L ) - { - if( !lua_istable(L, 2) && !lua_isnoneornil(L, 2) ) - luaL_typerror( L, 2, "table or nil" ); - - LuaReference ParamTable; - lua_pushvalue( L, 2 ); - ParamTable.SetFromStack( L ); - - Message msg( SArg(1), ParamTable ); - p->HandleMessage( msg ); - - return 0; - } - static int queuecommand( T* p, lua_State *L ) { p->QueueCommand(SArg(1)); return 0; } - static int queuemessage( T* p, lua_State *L ) { p->QueueMessage(SArg(1)); return 0; } - static int addcommand( T* p, lua_State *L ) - { - LuaReference *pRef = new LuaReference; - pRef->SetFromStack( L ); - p->AddCommand( SArg(1), apActorCommands(pRef) ); - return 0; - } - static int GetCommand( T* p, lua_State *L ) - { - const apActorCommands *pCommand = p->GetCommand(SArg(1)); - if( pCommand == NULL ) - lua_pushnil( L ); - else - (*pCommand)->PushSelf(L); - - return 1; - } - static int RunCommandsRecursively( T* p, lua_State *L ) - { - luaL_checktype( L, 1, LUA_TFUNCTION ); - if( !lua_istable(L, 2) && !lua_isnoneornil(L, 2) ) - luaL_typerror( L, 2, "table or nil" ); - - LuaReference ref; - lua_pushvalue( L, 1 ); - ref.SetFromStack( L ); - - LuaReference ParamTable; - lua_pushvalue( L, 2 ); - ParamTable.SetFromStack( L ); - - p->RunCommandsRecursively( ref, &ParamTable ); - return 0; - } - - static int GetX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetX() ); return 1; } - static int GetY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetY() ); return 1; } - static int GetZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZ() ); return 1; } - static int GetWidth( T* p, lua_State *L ) { lua_pushnumber( L, p->GetUnzoomedWidth() ); return 1; } - static int GetHeight( T* p, lua_State *L ) { lua_pushnumber( L, p->GetUnzoomedHeight() ); return 1; } - static int GetZoomedWidth( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomedWidth() ); return 1; } - static int GetZoomedHeight( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomedHeight() ); return 1; } - static int GetZoom( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoom() ); return 1; } - static int GetZoomX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomX() ); return 1; } - static int GetZoomY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomY() ); return 1; } - static int GetZoomZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetZoomZ() ); return 1; } - static int GetBaseZoomX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetBaseZoomX() ); return 1; } - static int GetBaseZoomY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetBaseZoomY() ); return 1; } - static int GetBaseZoomZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetBaseZoomZ() ); return 1; } - static int GetRotationX( T* p, lua_State *L ) { lua_pushnumber( L, p->GetRotationX() ); return 1; } - static int GetRotationY( T* p, lua_State *L ) { lua_pushnumber( L, p->GetRotationY() ); return 1; } - static int GetRotationZ( T* p, lua_State *L ) { lua_pushnumber( L, p->GetRotationZ() ); return 1; } - static int GetSecsIntoEffect( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecsIntoEffect() ); return 1; } - static int GetEffectDelta( T* p, lua_State *L ) { lua_pushnumber( L, p->GetEffectDelta() ); return 1; } - DEFINE_METHOD( GetDiffuse, GetDiffuse() ) - DEFINE_METHOD( GetGlow, GetGlow() ) - static int GetDiffuseAlpha( T* p, lua_State *L ) { lua_pushnumber( L, p->GetDiffuseAlpha() ); return 1; } - static int GetVisible( T* p, lua_State *L ) { lua_pushboolean( L, p->GetVisible() ); return 1; } - static int GetHAlign( T* p, lua_State *L ) { lua_pushnumber( L, p->GetHorizAlign() ); return 1; } - static int GetVAlign( T* p, lua_State *L ) { lua_pushnumber( L, p->GetVertAlign() ); return 1; } - - static int GetName( T* p, lua_State *L ) { lua_pushstring( L, p->GetName() ); return 1; } - static int GetParent( T* p, lua_State *L ) - { - Actor *pParent = p->GetParent(); - if( pParent == NULL ) - lua_pushnil( L ); - else - pParent->PushSelf(L); - return 1; - } - static int Draw( T* p, lua_State *L ) - { - LUA->YieldLua(); - p->Draw(); - LUA->UnyieldLua(); - return 0; - } - - LunaActor() - { - ADD_METHOD( name ); - ADD_METHOD( sleep ); - ADD_METHOD( linear ); - ADD_METHOD( accelerate ); - ADD_METHOD( decelerate ); - ADD_METHOD( spring ); - ADD_METHOD( tween ); - ADD_METHOD( stoptweening ); - ADD_METHOD( finishtweening ); - ADD_METHOD( hurrytweening ); - ADD_METHOD( GetTweenTimeLeft ); - ADD_METHOD( x ); - ADD_METHOD( y ); - ADD_METHOD( z ); - ADD_METHOD( addx ); - ADD_METHOD( addy ); - ADD_METHOD( addz ); - ADD_METHOD( zoom ); - ADD_METHOD( zoomx ); - ADD_METHOD( zoomy ); - ADD_METHOD( zoomz ); - ADD_METHOD( zoomto ); - ADD_METHOD( zoomtowidth ); - ADD_METHOD( zoomtoheight ); - ADD_METHOD( setsize ); - ADD_METHOD( SetWidth ); - ADD_METHOD( SetHeight ); - ADD_METHOD( basealpha ); - ADD_METHOD( basezoom ); - ADD_METHOD( basezoomx ); - ADD_METHOD( basezoomy ); - ADD_METHOD( basezoomz ); - ADD_METHOD( stretchto ); - ADD_METHOD( cropleft ); - ADD_METHOD( croptop ); - ADD_METHOD( cropright ); - ADD_METHOD( cropbottom ); - ADD_METHOD( fadeleft ); - ADD_METHOD( fadetop ); - ADD_METHOD( faderight ); - ADD_METHOD( fadebottom ); - ADD_METHOD( diffuse ); - ADD_METHOD( diffuseupperleft ); - ADD_METHOD( diffuseupperright ); - ADD_METHOD( diffuselowerleft ); - ADD_METHOD( diffuselowerright ); - ADD_METHOD( diffuseleftedge ); - ADD_METHOD( diffuserightedge ); - ADD_METHOD( diffusetopedge ); - ADD_METHOD( diffusebottomedge ); - ADD_METHOD( diffusealpha ); - ADD_METHOD( diffusecolor ); - ADD_METHOD( glow ); - ADD_METHOD( aux ); - ADD_METHOD( getaux ); - ADD_METHOD( rotationx ); - ADD_METHOD( rotationy ); - ADD_METHOD( rotationz ); - ADD_METHOD( addrotationx ); - ADD_METHOD( addrotationy ); - ADD_METHOD( addrotationz ); - ADD_METHOD( getrotation ); - ADD_METHOD( baserotationx ); - ADD_METHOD( baserotationy ); - ADD_METHOD( baserotationz ); - ADD_METHOD( skewx ); - ADD_METHOD( skewy ); - ADD_METHOD( heading ); - ADD_METHOD( pitch ); - ADD_METHOD( roll ); - ADD_METHOD( shadowlength ); - ADD_METHOD( shadowlengthx ); - ADD_METHOD( shadowlengthy ); - ADD_METHOD( shadowcolor ); - ADD_METHOD( horizalign ); - ADD_METHOD( vertalign ); - ADD_METHOD( halign ); - ADD_METHOD( valign ); - ADD_METHOD( diffuseblink ); - ADD_METHOD( diffuseshift ); - ADD_METHOD( diffuseramp ); - ADD_METHOD( glowblink ); - ADD_METHOD( glowshift ); - ADD_METHOD( glowramp ); - ADD_METHOD( rainbow ); - ADD_METHOD( wag ); - ADD_METHOD( bounce ); - ADD_METHOD( bob ); - ADD_METHOD( pulse ); - ADD_METHOD( spin ); - ADD_METHOD( vibrate ); - ADD_METHOD( stopeffect ); - ADD_METHOD( effectcolor1 ); - ADD_METHOD( effectcolor2 ); - ADD_METHOD( effectperiod ); - ADD_METHOD( effecttiming ); - ADD_METHOD( effectoffset ); - ADD_METHOD( effectclock ); - ADD_METHOD( effectmagnitude ); - ADD_METHOD( geteffectmagnitude ); - ADD_METHOD( scaletocover ); - ADD_METHOD( scaletofit ); - ADD_METHOD( animate ); - ADD_METHOD( play ); - ADD_METHOD( pause ); - ADD_METHOD( setstate ); - ADD_METHOD( GetNumStates ); - ADD_METHOD( texturewrapping ); - ADD_METHOD( SetTextureFiltering ); - ADD_METHOD( blend ); - ADD_METHOD( zbuffer ); - ADD_METHOD( ztest ); - ADD_METHOD( ztestmode ); - ADD_METHOD( zwrite ); - ADD_METHOD( zbias ); - ADD_METHOD( clearzbuffer ); - ADD_METHOD( backfacecull ); - ADD_METHOD( cullmode ); - ADD_METHOD( visible ); - ADD_METHOD( hibernate ); - ADD_METHOD( draworder ); - ADD_METHOD( playcommand ); - ADD_METHOD( queuecommand ); - ADD_METHOD( queuemessage ); - ADD_METHOD( addcommand ); - ADD_METHOD( GetCommand ); - ADD_METHOD( RunCommandsRecursively ); - - ADD_METHOD( GetX ); - ADD_METHOD( GetY ); - ADD_METHOD( GetZ ); - ADD_METHOD( GetWidth ); - ADD_METHOD( GetHeight ); - ADD_METHOD( GetZoomedWidth ); - ADD_METHOD( GetZoomedHeight ); - ADD_METHOD( GetZoom ); - ADD_METHOD( GetZoomX ); - ADD_METHOD( GetZoomY ); - ADD_METHOD( GetZoomZ ); - ADD_METHOD( GetRotationX ); - ADD_METHOD( GetRotationY ); - ADD_METHOD( GetRotationZ ); - ADD_METHOD( GetBaseZoomX ); - ADD_METHOD( GetBaseZoomY ); - ADD_METHOD( GetBaseZoomZ ); - ADD_METHOD( GetSecsIntoEffect ); - ADD_METHOD( GetEffectDelta ); - ADD_METHOD( GetDiffuse ); - ADD_METHOD( GetDiffuseAlpha ); - ADD_METHOD( GetGlow ); - ADD_METHOD( GetVisible ); - ADD_METHOD( GetHAlign ); - ADD_METHOD( GetVAlign ); - - ADD_METHOD( GetName ); - ADD_METHOD( GetParent ); - - ADD_METHOD( Draw ); - } -}; - -LUA_REGISTER_INSTANCED_BASE_CLASS( Actor ) -// lua end - - -/* - * (c) 2001-2004 Chris Danford - * 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/Actor.h b/src/Actor.h deleted file mode 100644 index 919d4994f7..0000000000 --- a/src/Actor.h +++ /dev/null @@ -1,755 +0,0 @@ -#ifndef ACTOR_H -#define ACTOR_H - -#include "PlayerNumber.h" -#include "RageTypes.h" -#include "RageUtil_AutoPtr.h" -#include "LuaReference.h" -#include "EnumHelper.h" -#include -class XNode; -struct lua_State; -class LuaClass; -#include "MessageManager.h" -#include "Tween.h" - -typedef AutoPtrCopyOnWrite apActorCommands; - -/** @brief The background layer. */ -#define DRAW_ORDER_BEFORE_EVERYTHING -200 -/** @brief The underlay layer. */ -#define DRAW_ORDER_UNDERLAY -100 -/** @brief The decorations layer. */ -#define DRAW_ORDER_DECORATIONS 0 -/** @brief The overlay layer. - * - * Normal screen elements go here. */ -#define DRAW_ORDER_OVERLAY +100 -/** @brief The transitions layer. */ -#define DRAW_ORDER_TRANSITIONS +200 -/** @brief The over everything layer. */ -#define DRAW_ORDER_AFTER_EVERYTHING +300 - -/** @brief The different horizontal alignments. */ -enum HorizAlign -{ - HorizAlign_Left, /**< Align to the left. */ - HorizAlign_Center, /**< Align to the center. */ - HorizAlign_Right, /**< Align to the right. */ - NUM_HorizAlign, /**< The number of horizontal alignments. */ - HorizAlign_Invalid -}; -LuaDeclareType( HorizAlign ); - -/** @brief The different vertical alignments. */ -enum VertAlign -{ - VertAlign_Top, /**< Align to the top. */ - VertAlign_Middle, /**< Align to the middle. */ - VertAlign_Bottom, /**< Align to the bottom. */ - NUM_VertAlign, /**< The number of vertical alignments. */ - VertAlign_Invalid -}; -LuaDeclareType( VertAlign ); - -/** @brief The left horizontal alignment constant. */ -#define align_left 0.0f -/** @brief The center horizontal alignment constant. */ -#define align_center 0.5f -/** @brief The right horizontal alignment constant. */ -#define align_right 1.0f -/** @brief The top vertical alignment constant. */ -#define align_top 0.0f -/** @brief The middle vertical alignment constant. */ -#define align_middle 0.5f -/** @brief The bottom vertical alignment constant. */ -#define align_bottom 1.0f - -// ssc futures: -/* -enum EffectAction -{ - EffectAction_None, // no_effect - // [Diffuse] - EffectAction_DiffuseBlink, // diffuse_blink - EffectAction_DiffuseShift, // diffuse_shift - EffectAction_DiffuseRamp, // diffuse_ramp - EffectAction_Rainbow, // rainbow - // [Glow] - EffectAction_GlowBlink, // glow_blink - EffectAction_GlowShift, // glow_shift - EffectAction_GlowRamp, // glow_ramp - // [Translate] - EffectAction_Bob, - EffectAction_Bounce, - EffectAction_Vibrate, - // [Rotate] - EffectAction_Spin, - EffectAction_Wag, - // [Zoom] - EffectAction_Pulse, - NUM_EffectAction, - EffectAction_Invalid -}; -LuaDeclareType( EffectAction ); -*/ - -/** @brief Base class for all objects that appear on the screen. */ -class Actor : public MessageSubscriber -{ -public: - /** @brief Set up the Actor with its initial settings. */ - Actor(); - /** - * @brief Copy a new Actor to the old one. - * @param cpy the new Actor to use in place of this one. */ - Actor( const Actor &cpy ); - virtual ~Actor(); - virtual Actor *Copy() const; - virtual void InitState(); - virtual void LoadFromNode( const XNode* pNode ); - - static void SetBGMTime( float fTime, float fBeat, float fTimeNoOffset, float fBeatNoOffset ); - static void SetPlayerBGMBeat( PlayerNumber pn, float fBeat, float fBeatNoOffset ); - static void SetBGMLight( int iLightNumber, float fCabinetLights ); - - /** - * @brief The list of the different effects. - * - * todo: split out into diffuse effects and translation effects, or - * create an effect stack instead. -aj */ - enum Effect { no_effect, - diffuse_blink, diffuse_shift, diffuse_ramp, - glow_blink, glow_shift, glow_ramp, rainbow, - wag, bounce, bob, pulse, spin, vibrate - }; - - /** @brief Various values an Actor's effect can be tied to. */ - enum EffectClock - { - CLOCK_TIMER, - CLOCK_TIMER_GLOBAL, - CLOCK_BGM_TIME, - CLOCK_BGM_BEAT, - CLOCK_BGM_TIME_NO_OFFSET, - CLOCK_BGM_BEAT_NO_OFFSET, - CLOCK_BGM_BEAT_PLAYER1, - CLOCK_BGM_BEAT_PLAYER2, - CLOCK_LIGHT_1 = 1000, - CLOCK_LIGHT_LAST = 1100, - NUM_CLOCKS - }; - - /* - * @brief What type of Effect this is. - * - * This is an internal enum for checking if an effect can be run; - * You can't have more than one of most EffectTypes in the Effect list. (You - * might be able to have mutliple EffectType_Translates; not sure yet.) -aj */ - /* - enum EffectType { - EffectType_Diffuse, - EffectType_Glow, - EffectType_Translate, - EffectType_Rotate, - EffectType_Zoom, - NUM_EffectType, - EffectType_Invalid - }; - */ - - // todo: use this instead of the Effect enum -aj - /* - // This is similar to Attributes in BitmapText as far as implementation. - struct Effect - { - Effect() : m_Action(EffectAction_None), m_Type(EffectType_Invalid), m_fSecsIntoEffect(0), - m_fEffectDelta(0), m_fEffectRampUp(0.5f), m_fEffectHoldAtHalf(0), - m_fEffectRampDown(0.5f), m_fEffectHoldAtZero(0), m_fEffectOffset(0), - m_EffectClock(CLOCK_TIMER), m_vEffectMagnitude(RageVector3(0,0,10)), - m_effectColor1(RageColor(1,1,1,1)), m_effectColor2(RageColor(1,1,1,1)) - { } - - RString m_sName; // friendly name - EffectAction m_Action; // replaces the old Effect enum - EffectType m_Type; // determined by EffectAction - float m_fSecsIntoEffect; - float m_fEffectDelta; - RageColor m_EffectColor1; - RageColor m_EffectColor2; - RageVector3 m_vEffectMagnitude; - EffectClock m_EffectClock; - // units depend on m_EffectClock - float m_fEffectRampUp; - float m_fEffectHoldAtHalf; - float m_fEffectRampDown; - float m_fEffectHoldAtZero; - float m_fEffectOffset; - }; - */ - - /** - * @brief The present state for the Tween. - */ - struct TweenState - { - void Init(); - static void MakeWeightedAverage( TweenState& average_out, const TweenState& ts1, const TweenState& ts2, float fPercentBetween ); - bool operator==( const TweenState &other ) const; - bool operator!=( const TweenState &other ) const { return !operator==(other); } - - // start and end position for tweening - RageVector3 pos; - RageVector3 rotation; - RageVector4 quat; - RageVector3 scale; - float fSkewX, fSkewY; - /** - * @brief The amount of cropping involved. - * - * If 0, there is no cropping. If 1, it's fully cropped. */ - RectF crop; - /** - * @brief The amount of fading involved. - * - * If 0, there is no fade. If 1, it's fully faded. */ - RectF fade; - /** - * @brief Four values making up the diffuse in this TweenState. - * - * 0 = UpperLeft, 1 = UpperRight, 2 = LowerLeft, 3 = LowerRight */ - RageColor diffuse[4]; - /** @brief The glow color for this TweenState. */ - RageColor glow; - /** @brief A magical value that nobody really knows the use for. ;) */ - float aux; - }; - - /** - * @brief Calls multiple functions for drawing the Actors. - * - * It calls the following in order: - * -# EarlyAbortDraw - * -# BeginDraw - * -# DrawPrimitives - * -# EndDraw - */ - void Draw(); - /** - * @brief Allow the Actor to be aborted early. - * - * Subclasses may wish to overwrite this to allow for - * aborted actors. - * @return false, as by default Actors shouldn't be aborted on drawing. */ - virtual bool EarlyAbortDraw() const { return false; } - /** @brief Start the drawing and push the transform on the world matrix stack. */ - virtual void BeginDraw(); - /** - * @brief Set the global rendering states of this Actor. - * - * This should be called at the beginning of an Actor's DrawPrimitives() call. */ - virtual void SetGlobalRenderStates(); - /** - * @brief Set the texture rendering states of this Actor. - * - * This should be called after setting a texture for the Actor. */ - virtual void SetTextureRenderStates(); - /** - * @brief Draw the primitives of the Actor. - * - * Derivative classes should override this function. */ - virtual void DrawPrimitives() {}; - /** @brief Pop the transform from the world matrix stack. */ - virtual void EndDraw(); - - // TODO: make Update non virtual and change all classes to override UpdateInternal - // instead. - bool IsFirstUpdate() const; - virtual void Update( float fDeltaTime ); // this can short circuit UpdateInternal - virtual void UpdateInternal( float fDeltaTime ); // override this - void UpdateTweening( float fDeltaTime ); - - /** - * @brief Retrieve the Actor's name. - * @return the Actor's name. */ - const RString &GetName() const { return m_sName; } - /** - * @brief Set the Actor's name to a new one. - * @param sName the new name for the Actor. */ - virtual void SetName( const RString &sName ) { m_sName = sName; } - /** - * @brief Give this Actor a new parent. - * @param pParent the new parent Actor. */ - void SetParent( Actor *pParent ); - /** - * @brief Retrieve the Actor's parent. - * @return the Actor's parent. */ - Actor *GetParent() { return m_pParent; } - /** - * @brief Retrieve the Actor's lineage. - * @return the Actor's lineage. */ - RString GetLineage() const; - - /** - * @brief Retrieve the Actor's x position. - * @return the Actor's x position. */ - float GetX() const { return m_current.pos.x; }; - /** - * @brief Retrieve the Actor's y position. - * @return the Actor's y position. */ - float GetY() const { return m_current.pos.y; }; - /** - * @brief Retrieve the Actor's z position. - * @return the Actor's z position. */ - float GetZ() const { return m_current.pos.z; }; - float GetDestX() const { return DestTweenState().pos.x; }; - float GetDestY() const { return DestTweenState().pos.y; }; - float GetDestZ() const { return DestTweenState().pos.z; }; - void SetX( float x ) { DestTweenState().pos.x = x; }; - void SetY( float y ) { DestTweenState().pos.y = y; }; - void SetZ( float z ) { DestTweenState().pos.z = z; }; - void SetXY( float x, float y ) { DestTweenState().pos.x = x; DestTweenState().pos.y = y; }; - /** - * @brief Add to the x position of this Actor. - * @param x the amount to add to the Actor's x position. */ - void AddX( float x ) { SetX( GetDestX()+x ); } - /** - * @brief Add to the y position of this Actor. - * @param y the amount to add to the Actor's y position. */ - void AddY( float y ) { SetY( GetDestY()+y ); } - /** - * @brief Add to the z position of this Actor. - * @param z the amount to add to the Actor's z position. */ - void AddZ( float z ) { SetZ( GetDestZ()+z ); } - - // height and width vary depending on zoom - float GetUnzoomedWidth() const { return m_size.x; } - float GetUnzoomedHeight() const { return m_size.y; } - float GetZoomedWidth() const { return m_size.x * m_baseScale.x * DestTweenState().scale.x; } - float GetZoomedHeight() const { return m_size.y * m_baseScale.y * DestTweenState().scale.y; } - void SetWidth( float width ) { m_size.x = width; } - void SetHeight( float height ) { m_size.y = height; } - - // Base values - float GetBaseZoomX() const { return m_baseScale.x; } - void SetBaseZoomX( float zoom ) { m_baseScale.x = zoom; } - float GetBaseZoomY() const { return m_baseScale.y; } - void SetBaseZoomY( float zoom ) { m_baseScale.y = zoom; } - float GetBaseZoomZ() const { return m_baseScale.z; } - void SetBaseZoomZ( float zoom ) { m_baseScale.z = zoom; } - void SetBaseZoom( float zoom ) { m_baseScale = RageVector3(zoom,zoom,zoom); } - void SetBaseRotationX( float rot ) { m_baseRotation.x = rot; } - void SetBaseRotationY( float rot ) { m_baseRotation.y = rot; } - void SetBaseRotationZ( float rot ) { m_baseRotation.z = rot; } - void SetBaseRotation( const RageVector3 &rot ) { m_baseRotation = rot; } - virtual void SetBaseAlpha( float fAlpha ) { m_fBaseAlpha = fAlpha; } - - /** - * @brief Retrieve the general zoom factor, using the x coordinate of the Actor. - * - * Note that this is not accurate in some cases. - * @return the zoom factor for the x coordinate of the Actor. */ - float GetZoom() const { return DestTweenState().scale.x; } - /** - * @brief Retrieve the zoom factor for the x coordinate of the Actor. - * @return the zoom factor for the x coordinate of the Actor. */ - float GetZoomX() const { return DestTweenState().scale.x; } - /** - * @brief Retrieve the zoom factor for the y coordinate of the Actor. - * @return the zoom factor for the y coordinate of the Actor. */ - float GetZoomY() const { return DestTweenState().scale.y; } - /** - * @brief Retrieve the zoom factor for the z coordinate of the Actor. - * @return the zoom factor for the z coordinate of the Actor. */ - float GetZoomZ() const { return DestTweenState().scale.z; } - /** - * @brief Set the zoom factor for all dimensions of the Actor. - * @param zoom the zoom factor for all dimensions. */ - void SetZoom( float zoom ) - { - DestTweenState().scale.x = zoom; - DestTweenState().scale.y = zoom; - DestTweenState().scale.z = zoom; - } - /** - * @brief Set the zoom factor for the x dimension of the Actor. - * @param zoom the zoom factor for the x dimension. */ - void SetZoomX( float zoom ) { DestTweenState().scale.x = zoom; } - /** - * @brief Set the zoom factor for the y dimension of the Actor. - * @param zoom the zoom factor for the y dimension. */ - void SetZoomY( float zoom ) { DestTweenState().scale.y = zoom; } - /** - * @brief Set the zoom factor for the z dimension of the Actor. - * @param zoom the zoom factor for the z dimension. */ - void SetZoomZ( float zoom ) { DestTweenState().scale.z = zoom; } - void ZoomTo( float fX, float fY ) { ZoomToWidth(fX); ZoomToHeight(fY); } - void ZoomToWidth( float zoom ) { SetZoomX( zoom / GetUnzoomedWidth() ); } - void ZoomToHeight( float zoom ) { SetZoomY( zoom / GetUnzoomedHeight() ); } - - float GetRotationX() const { return DestTweenState().rotation.x; } - float GetRotationY() const { return DestTweenState().rotation.y; } - float GetRotationZ() const { return DestTweenState().rotation.z; } - void SetRotationX( float rot ) { DestTweenState().rotation.x = rot; } - void SetRotationY( float rot ) { DestTweenState().rotation.y = rot; } - void SetRotationZ( float rot ) { DestTweenState().rotation.z = rot; } - // added in StepNXA, now available in sm-ssc: - void AddRotationX( float rot ) { DestTweenState().rotation.x += rot; }; - void AddRotationY( float rot ) { DestTweenState().rotation.y += rot; }; - void AddRotationZ( float rot ) { DestTweenState().rotation.z += rot; }; - // and these were normally in SM: - void AddRotationH( float rot ); - void AddRotationP( float rot ); - void AddRotationR( float rot ); - - void SetSkewX( float fAmount ) { DestTweenState().fSkewX = fAmount; } - float GetSkewX( float fAmount ) const { return DestTweenState().fSkewX; } - void SetSkewY( float fAmount ) { DestTweenState().fSkewY = fAmount; } - float GetSkewY( float fAmount ) const { return DestTweenState().fSkewY; } - - float GetCropLeft() const { return DestTweenState().crop.left; } - float GetCropTop() const { return DestTweenState().crop.top; } - float GetCropRight() const { return DestTweenState().crop.right; } - float GetCropBottom() const { return DestTweenState().crop.bottom; } - void SetCropLeft( float percent ) { DestTweenState().crop.left = percent; } - void SetCropTop( float percent ) { DestTweenState().crop.top = percent; } - void SetCropRight( float percent ) { DestTweenState().crop.right = percent; } - void SetCropBottom( float percent ) { DestTweenState().crop.bottom = percent; } - - void SetFadeLeft( float percent ) { DestTweenState().fade.left = percent; } - void SetFadeTop( float percent ) { DestTweenState().fade.top = percent; } - void SetFadeRight( float percent ) { DestTweenState().fade.right = percent; } - void SetFadeBottom( float percent ) { DestTweenState().fade.bottom = percent; } - - void SetGlobalDiffuseColor( RageColor c ); - - virtual void SetDiffuse( RageColor c ) { for(int i=0; i<4; i++) DestTweenState().diffuse[i] = c; }; - virtual void SetDiffuseAlpha( float f ) { for(int i = 0; i < 4; ++i) { RageColor c = GetDiffuses( i ); c.a = f; SetDiffuses( i, c ); } } - float GetCurrentDiffuseAlpha() const { return m_current.diffuse[0].a; } - void SetDiffuseColor( RageColor c ); - void SetDiffuses( int i, RageColor c ) { DestTweenState().diffuse[i] = c; }; - void SetDiffuseUpperLeft( RageColor c ) { DestTweenState().diffuse[0] = c; }; - void SetDiffuseUpperRight( RageColor c ) { DestTweenState().diffuse[1] = c; }; - void SetDiffuseLowerLeft( RageColor c ) { DestTweenState().diffuse[2] = c; }; - void SetDiffuseLowerRight( RageColor c ) { DestTweenState().diffuse[3] = c; }; - void SetDiffuseTopEdge( RageColor c ) { DestTweenState().diffuse[0] = DestTweenState().diffuse[1] = c; }; - void SetDiffuseRightEdge( RageColor c ) { DestTweenState().diffuse[1] = DestTweenState().diffuse[3] = c; }; - void SetDiffuseBottomEdge( RageColor c ) { DestTweenState().diffuse[2] = DestTweenState().diffuse[3] = c; }; - void SetDiffuseLeftEdge( RageColor c ) { DestTweenState().diffuse[0] = DestTweenState().diffuse[2] = c; }; - RageColor GetDiffuse() const { return DestTweenState().diffuse[0]; }; - RageColor GetDiffuses( int i ) const { return DestTweenState().diffuse[i]; }; - float GetDiffuseAlpha() const { return DestTweenState().diffuse[0].a; }; - void SetGlow( RageColor c ) { DestTweenState().glow = c; }; - RageColor GetGlow() const { return DestTweenState().glow; }; - - void SetAux( float f ) { DestTweenState().aux = f; } - float GetAux() const { return m_current.aux; } - - void BeginTweening( float time, ITween *pInterp ); - void BeginTweening( float time, TweenType tt = TWEEN_LINEAR ); - void StopTweening(); - void Sleep( float time ); - void QueueCommand( const RString& sCommandName ); - void QueueMessage( const RString& sMessageName ); - virtual void FinishTweening(); - virtual void HurryTweening( float factor ); - // Let ActorFrame and BGAnimation override - virtual float GetTweenTimeLeft() const; // Amount of time until all tweens have stopped - TweenState& DestTweenState() // where Actor will end when its tween finish - { - if( m_Tweens.empty() ) // not tweening - return m_current; - else - return m_Tweens.back()->state; - } - const TweenState& DestTweenState() const { return const_cast(this)->DestTweenState(); } - - /** @brief How do we handle stretching the Actor? */ - enum StretchType - { - fit_inside, /**< Have the Actor fit inside its parent, using the smaller zoom. */ - cover /**< Have the Actor cover its parent, using the larger zoom. */ - }; - - void ScaleToCover( const RectF &rect ) { ScaleTo( rect, cover ); } - void ScaleToFitInside( const RectF &rect ) { ScaleTo( rect, fit_inside); }; - void ScaleTo( const RectF &rect, StretchType st ); - - void StretchTo( const RectF &rect ); - - // Alignment settings. These need to be virtual for BitmapText - virtual void SetHorizAlign( float f ) { m_fHorizAlign = f; } - virtual void SetVertAlign( float f ) { m_fVertAlign = f; } - void SetHorizAlign( HorizAlign ha ) { SetHorizAlign( (ha == HorizAlign_Left)? 0.0f: (ha == HorizAlign_Center)? 0.5f: +1.0f ); } - void SetVertAlign( VertAlign va ) { SetVertAlign( (va == VertAlign_Top)? 0.0f: (va == VertAlign_Middle)? 0.5f: +1.0f ); } - virtual float GetHorizAlign() { return m_fHorizAlign; } - virtual float GetVertAlign() { return m_fVertAlign; } - - // effects -#if defined(SSC_FUTURES) - void StopEffects(); - Effect GetEffect( int i ) const { return m_Effects[i]; } -#else - void StopEffect() { m_Effect = no_effect; } - Effect GetEffect() const { return m_Effect; } -#endif - float GetSecsIntoEffect() const { return m_fSecsIntoEffect; } - float GetEffectDelta() const { return m_fEffectDelta; } - - // todo: account for SSC_FUTURES by adding an effect as an arg to each one -aj - void SetEffectColor1( RageColor c ) { m_effectColor1 = c; } - void SetEffectColor2( RageColor c ) { m_effectColor2 = c; } - void SetEffectPeriod( float fTime ); - float GetEffectPeriod() const; - void SetEffectTiming( float fRampUp, float fAtHalf, float fRampDown, float fAtZero ); - void SetEffectOffset( float fTime ) { m_fEffectOffset = fTime; } - void SetEffectClock( EffectClock c ) { m_EffectClock = c; } - void SetEffectClockString( const RString &s ); // convenience - - void SetEffectMagnitude( RageVector3 vec ) { m_vEffectMagnitude = vec; } - RageVector3 GetEffectMagnitude() const { return m_vEffectMagnitude; } - - void SetEffectDiffuseBlink( - float fEffectPeriodSeconds = 1.0f, - RageColor c1 = RageColor(0.5f,0.5f,0.5f,1), - RageColor c2 = RageColor(1,1,1,1) ); - void SetEffectDiffuseShift( float fEffectPeriodSeconds = 1.f, - RageColor c1 = RageColor(0,0,0,1), - RageColor c2 = RageColor(1,1,1,1) ); - void SetEffectDiffuseRamp( float fEffectPeriodSeconds = 1.f, - RageColor c1 = RageColor(0,0,0,1), - RageColor c2 = RageColor(1,1,1,1) ); - void SetEffectGlowBlink( float fEffectPeriodSeconds = 1.f, - RageColor c1 = RageColor(1,1,1,0.2f), - RageColor c2 = RageColor(1,1,1,0.8f) ); - void SetEffectGlowShift( - float fEffectPeriodSeconds = 1.0f, - RageColor c1 = RageColor(1,1,1,0.2f), - RageColor c2 = RageColor(1,1,1,0.8f) ); - void SetEffectGlowRamp( - float fEffectPeriodSeconds = 1.0f, - RageColor c1 = RageColor(1,1,1,0.2f), - RageColor c2 = RageColor(1,1,1,0.8f) ); - void SetEffectRainbow( - float fEffectPeriodSeconds = 2.0f ); - void SetEffectWag( - float fPeriod = 2.f, - RageVector3 vect = RageVector3(0,0,20) ); - void SetEffectBounce( - float fPeriod = 2.f, - RageVector3 vect = RageVector3(0,20,0) ); - void SetEffectBob( - float fPeriod = 2.f, - RageVector3 vect = RageVector3(0,20,0) ); - void SetEffectPulse( - float fPeriod = 2.f, - float fMinZoom = 0.5f, - float fMaxZoom = 1.f ); - void SetEffectSpin( RageVector3 vect = RageVector3(0,0,180) ); - void SetEffectVibrate( RageVector3 vect = RageVector3(10,10,10) ); - - - // other properties - /** - * @brief Determine if the Actor is visible at this time. - * @return true if it's visible, false otherwise. */ - bool GetVisible() const { return m_bVisible; } - void SetVisible( bool b ) { m_bVisible = b; } - void SetShadowLength( float fLength ) { m_fShadowLengthX = fLength; m_fShadowLengthY = fLength; } - void SetShadowLengthX( float fLengthX ) { m_fShadowLengthX = fLengthX; } - void SetShadowLengthY( float fLengthY ) { m_fShadowLengthY = fLengthY; } - void SetShadowColor( RageColor c ) { m_ShadowColor = c; } - // TODO: Implement hibernate as a tween type? - void SetHibernate( float fSecs ) { m_fHibernateSecondsLeft = fSecs; } - void SetDrawOrder( int iOrder ) { m_iDrawOrder = iOrder; } - int GetDrawOrder() const { return m_iDrawOrder; } - - virtual void EnableAnimation( bool b ) { m_bIsAnimating = b; } // Sprite needs to overload this - void StartAnimating() { this->EnableAnimation(true); } - void StopAnimating() { this->EnableAnimation(false); } - - // render states - void SetBlendMode( BlendMode mode ) { m_BlendMode = mode; } - void SetTextureWrapping( bool b ) { m_bTextureWrapping = b; } - void SetTextureFiltering( bool b ) { m_bTextureFiltering = b; } - void SetClearZBuffer( bool b ) { m_bClearZBuffer = b; } - void SetUseZBuffer( bool b ) { SetZTestMode(b?ZTEST_WRITE_ON_PASS:ZTEST_OFF); SetZWrite(b); } - virtual void SetZTestMode( ZTestMode mode ) { m_ZTestMode = mode; } - virtual void SetZWrite( bool b ) { m_bZWrite = b; } - void SetZBias( float f ) { m_fZBias = f; } - virtual void SetCullMode( CullMode mode ) { m_CullMode = mode; } - - // Lua - virtual void PushSelf( lua_State *L ); - virtual void PushContext( lua_State *L ); - - // Named commands - void AddCommand( const RString &sCmdName, apActorCommands apac ); - bool HasCommand( const RString &sCmdName ) const; - const apActorCommands *GetCommand( const RString &sCommandName ) const; - void PlayCommand( const RString &sCommandName ) { HandleMessage( Message(sCommandName) ); } // convenience - void PlayCommandNoRecurse( const Message &msg ); - - // Commands by reference - virtual void RunCommands( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); - void RunCommands( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommands( *cmds, pParamTable ); } // convenience - virtual void RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable = NULL ) { RunCommands(cmds, pParamTable); } - // If we're a leaf, then execute this command. - virtual void RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable = NULL ) { RunCommands(cmds, pParamTable); } - - // Messages - virtual void HandleMessage( const Message &msg ); - - // Animation - virtual int GetNumStates() const { return 1; } - virtual void SetState( int iNewState ) {} - virtual float GetAnimationLengthSeconds() const { return 0; } - virtual void SetSecondsIntoAnimation( float fSeconds ) {} - virtual void SetUpdateRate( float fRate ) {} - - HiddenPtr m_pLuaInstance; - -protected: - /** @brief the name of the Actor. */ - RString m_sName; - /** @brief the current parent of this Actor if it exists. */ - Actor *m_pParent; - - /** @brief Some general information about the Tween. */ - struct TweenInfo - { - // counters for tweening - TweenInfo(); - ~TweenInfo(); - TweenInfo( const TweenInfo &cpy ); - TweenInfo &operator=( const TweenInfo &rhs ); - - ITween *m_pTween; - /** @brief How far into the tween are we? */ - float m_fTimeLeftInTween; - /** @brief The number of seconds between Start and End positions/zooms. */ - float m_fTweenTime; - /** @brief The command to execute when this TweenState goes into effect. */ - RString m_sCommandName; - }; - - RageVector3 m_baseRotation; - RageVector3 m_baseScale; - float m_fBaseAlpha; - - RageVector2 m_size; - TweenState m_current; - TweenState m_start; - struct TweenStateAndInfo - { - TweenState state; - TweenInfo info; - }; - vector m_Tweens; - - /** @brief Temporary variables that are filled just before drawing */ - TweenState *m_pTempState; - - bool m_bFirstUpdate; - - // Stuff for alignment - /** @brief The particular horizontal alignment. - * - * Use the defined constant values for best effect. */ - float m_fHorizAlign; - /** @brief The particular vertical alignment. - * - * Use the defined constant values for best effect. */ - float m_fVertAlign; - - // Stuff for effects -#if defined(SSC_FUTURES) // be able to stack effects - vector m_Effects; -#else // compatibility - Effect m_Effect; -#endif - float m_fSecsIntoEffect; - float m_fEffectDelta; - - // units depend on m_EffectClock - float m_fEffectRampUp; - float m_fEffectHoldAtHalf; - float m_fEffectRampDown; - float m_fEffectHoldAtZero; - float m_fEffectOffset; - EffectClock m_EffectClock; - - /* This can be used in lieu of the fDeltaTime parameter to Update() to - * follow the effect clock. Actor::Update must be called first. */ - float GetEffectDeltaTime() const { return m_fEffectDelta; } - - // todo: account for SSC_FUTURES by having these be vectors too -aj - RageColor m_effectColor1; - RageColor m_effectColor2; - RageVector3 m_vEffectMagnitude; - - // other properties - bool m_bVisible; - bool m_bIsAnimating; - float m_fHibernateSecondsLeft; - float m_fShadowLengthX; - float m_fShadowLengthY; - RageColor m_ShadowColor; - /** @brief The draw order priority. - * - * The lower this number is, the sooner it is drawn. */ - int m_iDrawOrder; - - // render states - BlendMode m_BlendMode; - ZTestMode m_ZTestMode; - CullMode m_CullMode; - bool m_bTextureWrapping; - bool m_bTextureFiltering; - bool m_bClearZBuffer; - bool m_bZWrite; - /** - * @brief The amount of bias. - * - * If 0, there is no bias. If 1, there is a full bias. */ - float m_fZBias; - - // global state - static float g_fCurrentBGMTime, g_fCurrentBGMBeat; - static float g_fCurrentBGMTimeNoOffset, g_fCurrentBGMBeatNoOffset; - static vector g_vfCurrentBGMBeatPlayer; - static vector g_vfCurrentBGMBeatPlayerNoOffset; - -private: - // commands - map m_mapNameToCommands; -}; - -#endif - -/** - * @file - * @author Chris Danford (c) 2001-2004 - * @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/ActorFrame.cpp b/src/ActorFrame.cpp deleted file mode 100644 index bb94b5b025..0000000000 --- a/src/ActorFrame.cpp +++ /dev/null @@ -1,633 +0,0 @@ -#include "global.h" -#include "ActorFrame.h" -#include "arch/Dialog/Dialog.h" -#include "RageUtil.h" -#include "RageLog.h" -#include "XmlFile.h" -#include "ActorUtil.h" -#include "LuaBinding.h" -#include "ActorUtil.h" -#include "RageDisplay.h" -#include "ScreenDimensions.h" -#include "Foreach.h" - -/* Tricky: We need ActorFrames created in Lua to auto delete their children. - * We don't want classes that derive from ActorFrame to auto delete their - * children. The name "ActorFrame" is widely used in Lua, so we'll have - * that string instead create an ActorFrameAutoDeleteChildren object. - */ -//REGISTER_ACTOR_CLASS( ActorFrame ); -REGISTER_ACTOR_CLASS_WITH_NAME( ActorFrameAutoDeleteChildren, ActorFrame ); -ActorFrame *ActorFrame::Copy() const { return new ActorFrame(*this); } - - -ActorFrame::ActorFrame() -{ - m_bPropagateCommands = false; - m_bDeleteChildren = false; - m_bDrawByZPosition = false; - m_DrawFunction.SetFromNil(); - m_UpdateFunction.SetFromNil(); - m_fUpdateRate = 1; - m_fFOV = -1; - m_fVanishX = SCREEN_CENTER_X; - m_fVanishY = SCREEN_CENTER_Y; - m_bOverrideLighting = false; - m_bLighting = false; - m_ambientColor = RageColor(1,1,1,1); - m_diffuseColor = RageColor(1,1,1,1); - m_specularColor = RageColor(1,1,1,1); - m_lightDirection = RageVector3(0,0,1); -} - -ActorFrame::~ActorFrame() -{ - if( m_bDeleteChildren ) - DeleteAllChildren(); -} - -ActorFrame::ActorFrame( const ActorFrame &cpy ): - Actor( cpy ) -{ -#define CPY(x) this->x = cpy.x; - CPY( m_bPropagateCommands ); - CPY( m_bDeleteChildren ); - CPY( m_bDrawByZPosition ); - CPY( m_DrawFunction ); - CPY( m_UpdateFunction ); - CPY( m_fUpdateRate ); - CPY( m_fFOV ); - CPY( m_fVanishX ); - CPY( m_fVanishY ); - CPY( m_bOverrideLighting ); - CPY( m_bLighting ); - CPY( m_ambientColor ); - CPY( m_diffuseColor ); - CPY( m_specularColor ); - CPY( m_lightDirection ); -#undef CPY - - /* If m_bDeleteChildren, we own our children and it's up to us to copy - * them. If not, the derived class owns the children. This must preserve - * the current order of m_SubActors. */ - if( m_bDeleteChildren ) - { - for( unsigned i = 0; i < cpy.m_SubActors.size(); ++i ) - { - Actor *pActor = cpy.m_SubActors[i]->Copy(); - this->AddChild( pActor ); - } - } -} - -void ActorFrame::InitState() -{ - FOREACH( Actor*, m_SubActors, a ) - (*a)->InitState(); - Actor::InitState(); -} - -void ActorFrame::LoadFromNode( const XNode* pNode ) -{ - if( AutoLoadChildren() ) - LoadChildrenFromNode( pNode ); - - Actor::LoadFromNode( pNode ); - - pNode->GetAttrValue( "UpdateRate", m_fUpdateRate ); - pNode->GetAttrValue( "FOV", m_fFOV ); - pNode->GetAttrValue( "VanishX", m_fVanishX ); - pNode->GetAttrValue( "VanishY", m_fVanishY ); - m_bOverrideLighting = pNode->GetAttrValue( "Lighting", m_bLighting ); - // new lighting values (only ambient color seems to work?) -aj - RString sTemp1,sTemp2,sTemp3; - pNode->GetAttrValue( "AmbientColor", sTemp1 ); - m_ambientColor.FromString(sTemp1); - pNode->GetAttrValue( "DiffuseColor", sTemp2 ); - m_diffuseColor.FromString(sTemp2); - pNode->GetAttrValue( "SpecularColor", sTemp3 ); - m_specularColor.FromString(sTemp3); - // Values need to be converted into a RageVector3, so more work needs to be done... - //pNode->GetAttrValue( "LightDirection", m_lightDirection ); -} - -void ActorFrame::LoadChildrenFromNode( const XNode* pNode ) -{ - // Shouldn't be calling this unless we're going to delete our children. - ASSERT( m_bDeleteChildren ); - - // Load children - const XNode* pChildren = pNode->GetChild("children"); - bool bArrayOnly = false; - if( pChildren == NULL ) - { - bArrayOnly = true; - pChildren = pNode; - } - - FOREACH_CONST_Child( pChildren, pChild ) - { - if( bArrayOnly && !IsAnInt(pChild->GetName()) ) - continue; - - Actor* pChildActor = ActorUtil::LoadFromNode( pChild, this ); - if( pChildActor ) - AddChild( pChildActor ); - } - SortByDrawOrder(); -} - -void ActorFrame::AddChild( Actor *pActor ) -{ -#ifdef DEBUG - // check that this Actor isn't already added. - vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); - if( iter != m_SubActors.end() ) - Dialog::OK( ssprintf("Actor \"%s\" adds child \"%s\" more than once", GetLineage().c_str(), pActor->GetName().c_str()) ); -#endif - - ASSERT( pActor ); - ASSERT( (void*)pActor != (void*)0xC0000005 ); - m_SubActors.push_back( pActor ); - - pActor->SetParent( this ); -} - -void ActorFrame::RemoveChild( Actor *pActor ) -{ - vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); - if( iter != m_SubActors.end() ) - m_SubActors.erase( iter ); -} - -void ActorFrame::TransferChildren( ActorFrame *pTo ) -{ - FOREACH( Actor*, m_SubActors, i ) - pTo->AddChild( *i ); - RemoveAllChildren(); -} - -Actor* ActorFrame::GetChild( const RString &sName ) -{ - FOREACH( Actor*, m_SubActors, a ) - { - if( (*a)->GetName() == sName ) - return *a; - } - return NULL; -} - -void ActorFrame::RemoveAllChildren() -{ - m_SubActors.clear(); -} - -void ActorFrame::MoveToTail( Actor* pActor ) -{ - vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); - if( iter == m_SubActors.end() ) // didn't find - { - ASSERT(0); // called with a pActor that doesn't exist - return; - } - - m_SubActors.erase( iter ); - m_SubActors.push_back( pActor ); -} - -void ActorFrame::MoveToHead( Actor* pActor ) -{ - vector::iterator iter = find( m_SubActors.begin(), m_SubActors.end(), pActor ); - if( iter == m_SubActors.end() ) // didn't find - { - ASSERT(0); // called with a pActor that doesn't exist - return; - } - - m_SubActors.erase( iter ); - m_SubActors.insert( m_SubActors.begin(), pActor ); -} - -void ActorFrame::BeginDraw() -{ - Actor::BeginDraw(); - if( m_fFOV != -1 ) - { - DISPLAY->CameraPushMatrix(); - DISPLAY->LoadMenuPerspective( m_fFOV, SCREEN_WIDTH, SCREEN_HEIGHT, m_fVanishX, m_fVanishY ); - } - - if( m_bOverrideLighting ) - { - DISPLAY->SetLighting( m_bLighting ); - if( m_bLighting ) - DISPLAY->SetLightDirectional( 0,m_ambientColor,m_diffuseColor,m_specularColor,m_lightDirection ); - } -} - - -void ActorFrame::DrawPrimitives() -{ - ASSERT_M( !m_bClearZBuffer, "ClearZBuffer not supported on ActorFrames" ); - - // Don't set Actor-defined render states because we won't be drawing - // any geometry that belongs to this object. - // Actor::DrawPrimitives(); - - if( unlikely(!m_DrawFunction.IsNil()) ) - { - Lua *L = LUA->Get(); - m_DrawFunction.PushSelf( L ); - ASSERT( !lua_isnil(L, -1) ); - this->PushSelf( L ); - RString sError; - if( !LuaHelpers::RunScriptOnStack(L, sError, 1, 0) ) // 1 arg, 0 results - LOG->Warn( "Error running DrawFunction: %s", sError.c_str() ); - LUA->Release(L); - return; - } - - // draw all sub-ActorFrames while we're in the ActorFrame's local coordinate space - if( m_bDrawByZPosition ) - { - vector subs = m_SubActors; - ActorUtil::SortByZPosition( subs ); - for( unsigned i=0; iDraw(); - } - else - { - for( unsigned i=0; iDraw(); - } -} - - -void ActorFrame::EndDraw() -{ - if( m_bOverrideLighting ) - { - // TODO: pop state instead of turning lighting off - DISPLAY->SetLightOff( 0 ); - DISPLAY->SetLighting( false ); - } - - if( m_fFOV != -1 ) - { - DISPLAY->CameraPopMatrix(); - } - Actor::EndDraw(); -} - -void ActorFrame::PushChildrenTable( lua_State *L ) -{ - lua_newtable( L ); - FOREACH( Actor*, m_SubActors, a ) - { - LuaHelpers::Push( L, (*a)->GetName() ); - (*a)->PushSelf( L ); - lua_rawset( L, -3 ); - } -} - -void ActorFrame::PlayCommandOnChildren( const RString &sCommandName, const LuaReference *pParamTable ) -{ - const apActorCommands *pCmd = GetCommand( sCommandName ); - if( pCmd != NULL ) - RunCommandsOnChildren( *pCmd, pParamTable ); -} - -void ActorFrame::PlayCommandOnLeaves( const RString &sCommandName, const LuaReference *pParamTable ) -{ - const apActorCommands *pCmd = GetCommand( sCommandName ); - if( pCmd != NULL ) - RunCommandsOnLeaves( **pCmd, pParamTable ); -} - -void ActorFrame::RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable ) -{ - for( unsigned i=0; iRunCommandsRecursively( cmds, pParamTable ); - Actor::RunCommandsRecursively( cmds, pParamTable ); -} - -void ActorFrame::RunCommandsOnChildren( const LuaReference& cmds, const LuaReference *pParamTable ) -{ - for( unsigned i=0; iRunCommands( cmds, pParamTable ); -} - -void ActorFrame::RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable ) -{ - for( unsigned i=0; iRunCommandsOnLeaves( cmds, pParamTable ); -} - -void ActorFrame::UpdateInternal( float fDeltaTime ) -{ -// LOG->Trace( "ActorFrame::Update( %f )", fDeltaTime ); - - fDeltaTime *= m_fUpdateRate; - - Actor::UpdateInternal( fDeltaTime ); - - // update all sub-Actors - for( vector::iterator it=m_SubActors.begin(); it!=m_SubActors.end(); it++ ) - { - Actor *pActor = *it; - pActor->Update(fDeltaTime); - } - - if( unlikely(!m_UpdateFunction.IsNil()) ) - { - Lua *L = LUA->Get(); - m_UpdateFunction.PushSelf( L ); - ASSERT( !lua_isnil(L, -1) ); - this->PushSelf( L ); - lua_pushnumber( L, fDeltaTime ); - RString sError; - - if( !LuaHelpers::RunScriptOnStack(L, sError, 2, 0) ) // 1 args, 0 results - LOG->Warn( "Error running m_UpdateFunction: %s", sError.c_str() ); - LUA->Release(L); - } -} - -#define PropagateActorFrameCommand( cmd ) \ - void ActorFrame::cmd() \ - { \ - Actor::cmd(); \ - \ - /* set all sub-Actors */ \ - for( unsigned i=0; icmd(); \ - } - -#define PropagateActorFrameCommand1Param( cmd, type ) \ - void ActorFrame::cmd( type f ) \ - { \ - Actor::cmd( f ); \ - \ - /* set all sub-Actors */ \ - for( unsigned i=0; icmd( f ); \ - } - -PropagateActorFrameCommand( FinishTweening ) -PropagateActorFrameCommand1Param( SetDiffuse, RageColor ) -PropagateActorFrameCommand1Param( SetZTestMode, ZTestMode ) -PropagateActorFrameCommand1Param( SetZWrite, bool ) -PropagateActorFrameCommand1Param( HurryTweening, float ) -PropagateActorFrameCommand1Param( SetDiffuseAlpha, float ) -PropagateActorFrameCommand1Param( SetBaseAlpha, float ) - - -float ActorFrame::GetTweenTimeLeft() const -{ - float m = Actor::GetTweenTimeLeft(); - - for( unsigned i=0; iGetTweenTimeLeft()); - } - - return m; - -} - -static bool CompareActorsByDrawOrder(const Actor *p1, const Actor *p2) -{ - return p1->GetDrawOrder() < p2->GetDrawOrder(); -} - -void ActorFrame::SortByDrawOrder() -{ - // Preserve ordering of Actors with equal DrawOrders. - stable_sort( m_SubActors.begin(), m_SubActors.end(), CompareActorsByDrawOrder ); -} - -void ActorFrame::DeleteAllChildren() -{ - for( unsigned i=0; iHandleMessage( msg ); - } -} - -void ActorFrame::SetDrawByZPosition( bool b ) -{ - m_bDrawByZPosition = b; -} - - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the ActorFrame. */ -class LunaActorFrame : public Luna -{ -public: - static int playcommandonchildren( T* p, lua_State *L ) { p->PlayCommandOnChildren(SArg(1)); return 0; } - static int playcommandonleaves( T* p, lua_State *L ) { p->PlayCommandOnLeaves(SArg(1)); return 0; } - static int runcommandsonleaves( T* p, lua_State *L ) - { - luaL_checktype( L, 1, LUA_TFUNCTION ); - LuaReference cmds; - cmds.SetFromStack( L ); - - p->RunCommandsOnLeaves( cmds ); - return 0; - } - static int RunCommandsOnChildren( T* p, lua_State *L ) - { - luaL_checktype( L, 1, LUA_TFUNCTION ); - lua_pushvalue( L, 2 ); - LuaReference ParamTable; - ParamTable.SetFromStack( L ); - - lua_pushvalue( L, 1 ); - LuaReference cmds; - cmds.SetFromStack( L ); - - p->RunCommandsOnChildren( cmds, &ParamTable ); - return 0; - } - static int propagate( T* p, lua_State *L ) { p->SetPropagateCommands( BIArg(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 vanishpoint( T* p, lua_State *L ) { p->SetVanishPoint( FArg(1), FArg(2) ); return 0; } - static int GetChild( T* p, lua_State *L ) - { - Actor *pChild = p->GetChild( SArg(1) ); - if( pChild ) - pChild->PushSelf( L ); - else - lua_pushnil( L ); - return 1; - } - static int GetChildren( T* p, lua_State *L ) - { - p->PushChildrenTable( L ); - 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 int SetDrawFunction( T* p, lua_State *L ) - { - luaL_checktype( L, 1, LUA_TFUNCTION ); - - LuaReference ref; - lua_pushvalue( L, 1 ); - ref.SetFromStack( L ); - p->SetDrawFunction( ref ); - return 0; - } - static int GetDrawFunction( T* p, lua_State *L ) - { - p->GetDrawFunction().PushSelf(L); - return 1; - } - static int SetUpdateFunction( T* p, lua_State *L ) - { - luaL_checktype( L, 1, LUA_TFUNCTION ); - - LuaReference ref; - lua_pushvalue( L, 1 ); - ref.SetFromStack( L ); - p->SetUpdateFunction( ref ); - return 0; - } - static int SortByDrawOrder( T* p, lua_State *L ) { p->SortByDrawOrder(); return 0; } - - //static int CustomLighting( T* p, lua_State *L ) { p->SetCustomLighting(BArg(1)); return 0; } - static int SetAmbientLightColor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetAmbientLightColor( c ); return 0; } - static int SetDiffuseLightColor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetDiffuseLightColor( c ); return 0; } - static int SetSpecularLightColor( T* p, lua_State *L ) { RageColor c; c.FromStackCompat( L, 1 ); p->SetSpecularLightColor( c ); return 0; } - static int SetLightDirection( T* p, lua_State *L ) - { - luaL_checktype( L, 1, LUA_TTABLE ); - lua_pushvalue( L, 1 ); - vector coords; - LuaHelpers::ReadArrayFromTable( coords, L ); - lua_pop( L, 1 ); - if( coords.size() !=3 ) - { - //error - } - RageVector3 vTmp = RageVector3( coords[0], coords[1], coords[2] ); - p->SetLightDirection( vTmp ); - return 0; - } - - static int AddChildFromPath( T* p, lua_State *L ) - { - // this one is tricky, we need to get an Actor from Lua. - Actor *pActor = ActorUtil::MakeActor( SArg(1) ); - if ( pActor == NULL ) - { - lua_pushboolean( L, 0 ); - return 1; - } - p->AddChild( pActor ); - lua_pushboolean( L, 1 ); - return 1; - } - - static int RemoveChild( T* p, lua_State *L ) - { - Actor *pChild = p->GetChild( SArg(1) ); - if( pChild ) - p->RemoveChild( pChild ); - else - lua_pushnil( L ); - return 1; - } - static int RemoveAllChildren( T* p, lua_State *L ) { p->RemoveAllChildren( ); return 0; } - - LunaActorFrame() - { - ADD_METHOD( playcommandonchildren ); - ADD_METHOD( playcommandonleaves ); - ADD_METHOD( runcommandsonleaves ); - ADD_METHOD( RunCommandsOnChildren ); - ADD_METHOD( propagate ); // deprecated - ADD_METHOD( fov ); - ADD_METHOD( SetUpdateRate ); - ADD_METHOD( SetFOV ); - ADD_METHOD( vanishpoint ); - ADD_METHOD( GetChild ); - ADD_METHOD( GetChildren ); - ADD_METHOD( GetNumChildren ); - ADD_METHOD( SetDrawByZPosition ); - ADD_METHOD( SetDrawFunction ); - ADD_METHOD( GetDrawFunction ); - ADD_METHOD( SetUpdateFunction ); - ADD_METHOD( SortByDrawOrder ); - //ADD_METHOD( CustomLighting ); - ADD_METHOD( SetAmbientLightColor ); - ADD_METHOD( SetDiffuseLightColor ); - ADD_METHOD( SetSpecularLightColor ); - ADD_METHOD( SetLightDirection ); - ADD_METHOD( AddChildFromPath ); - ADD_METHOD( RemoveChild ); - ADD_METHOD( RemoveAllChildren ); - - } -}; - -LUA_REGISTER_DERIVED_CLASS( ActorFrame, Actor ) -// lua end - -/* - * (c) 2001-2004 Chris Danford - * 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/ActorFrame.h b/src/ActorFrame.h deleted file mode 100644 index ba377ffcfb..0000000000 --- a/src/ActorFrame.h +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef ACTORFRAME_H -#define ACTORFRAME_H - -#include "Actor.h" - -/** @brief A container for other Actors. */ -class ActorFrame : public Actor -{ -public: - ActorFrame(); - ActorFrame( const ActorFrame &cpy ); - virtual ~ActorFrame(); - - /** @brief Set up the initial state. */ - virtual void InitState(); - void LoadFromNode( const XNode* pNode ); - virtual ActorFrame *Copy() const; - - /** - * @brief Add a new child to the ActorFrame. - * @param pActor the new Actor to add. */ - virtual void AddChild( Actor *pActor ); - /** - * @brief Remove the specified child from the ActorFrame. - * @param pActor the Actor to remove. */ - virtual void RemoveChild( Actor *pActor ); - void TransferChildren( ActorFrame *pTo ); - Actor* GetChild( const RString &sName ); - vector GetChildren() { return m_SubActors; } - int GetNumChildren() const { return m_SubActors.size(); } - - /** @brief Remove all of the children from the frame. */ - void RemoveAllChildren(); - /** - * @brief Move a particular actor to the tail. - * @param pActor the actor to go to the tail. - */ - void MoveToTail( Actor* pActor ); - /** - * @brief Move a particular actor to the head. - * @param pActor the actor to go to the head. - */ - void MoveToHead( Actor* pActor ); - void SortByDrawOrder(); - void SetDrawByZPosition( bool b ); - - void SetDrawFunction( const LuaReference &DrawFunction ) { m_DrawFunction = DrawFunction; } - void SetUpdateFunction( const LuaReference &UpdateFunction ) { m_UpdateFunction = UpdateFunction; } - - LuaReference GetDrawFunction() const { return m_DrawFunction; } - virtual bool AutoLoadChildren() const { return false; } // derived classes override to automatically LoadChildrenFromNode - void DeleteChildrenWhenDone( bool bDelete=true ) { m_bDeleteChildren = bDelete; } - void DeleteAllChildren(); - - // Commands - virtual void PushSelf( lua_State *L ); - void PushChildrenTable( lua_State *L ); - void PlayCommandOnChildren( const RString &sCommandName, const LuaReference *pParamTable = NULL ); - void PlayCommandOnLeaves( const RString &sCommandName, const LuaReference *pParamTable = NULL ); - - virtual void RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); - virtual void RunCommandsOnChildren( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */ - void RunCommandsOnChildren( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommandsOnChildren( *cmds, pParamTable ); } // convenience - virtual void RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */ - - virtual void UpdateInternal( float fDeltaTime ); - virtual void BeginDraw(); - virtual void DrawPrimitives(); - virtual void EndDraw(); - - // propagated commands - virtual void SetDiffuse( RageColor c ); - virtual void SetDiffuseAlpha( float f ); - virtual void SetBaseAlpha( float f ); - virtual void SetZTestMode( ZTestMode mode ); - virtual void SetZWrite( bool b ); - virtual void FinishTweening(); - virtual void HurryTweening( float factor ); - - void SetUpdateRate( float fUpdateRate ) { m_fUpdateRate = fUpdateRate; } - void SetFOV( float fFOV ) { m_fFOV = fFOV; } - void SetVanishPoint( float fX, float fY) { m_fVanishX = fX; m_fVanishY = fY; } - - void SetCustomLighting( bool bCustomLighting ) { m_bOverrideLighting = bCustomLighting; } - void SetAmbientLightColor( RageColor c ) { m_ambientColor = c; } - void SetDiffuseLightColor( RageColor c ) { m_diffuseColor = c; } - void SetSpecularLightColor( RageColor c ) { m_specularColor = c; } - void SetLightDirection( RageVector3 vec ) { m_lightDirection = vec; } - - virtual void SetPropagateCommands( bool b ); - - /** @brief Amount of time until all tweens (and all children's tweens) have stopped: */ - virtual float GetTweenTimeLeft() const; - - virtual void HandleMessage( const Message &msg ); - virtual void RunCommands( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); - void RunCommands( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommands( *cmds, pParamTable ); } // convenience - -protected: - void LoadChildrenFromNode( const XNode* pNode ); - - /** @brief The children Actors used by the ActorFrame. */ - vector m_SubActors; - bool m_bPropagateCommands; - bool m_bDeleteChildren; - bool m_bDrawByZPosition; - LuaReference m_UpdateFunction; - LuaReference m_DrawFunction; - - // state effects - float m_fUpdateRate; - float m_fFOV; // -1 = no change - float m_fVanishX; - float m_fVanishY; - /** - * @brief A flad to see if an override for the lighting is needed. - * - * If true, set lightning to m_bLightning. */ - bool m_bOverrideLighting; - bool m_bLighting; - - // lighting variables - RageColor m_ambientColor; - RageColor m_diffuseColor; - RageColor m_specularColor; - RageVector3 m_lightDirection; -}; -/** @brief an ActorFrame that handles deleting children Actors automatically. */ -class ActorFrameAutoDeleteChildren : public ActorFrame -{ -public: - ActorFrameAutoDeleteChildren() { DeleteChildrenWhenDone(true); } - virtual bool AutoLoadChildren() const { return true; } - virtual ActorFrameAutoDeleteChildren *Copy() const; -}; - -#endif - -/** - * @file - * @author Chris Danford (c) 2001-2004 - * @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/ActorFrameTexture.cpp b/src/ActorFrameTexture.cpp deleted file mode 100644 index 4a907f7611..0000000000 --- a/src/ActorFrameTexture.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "global.h" -#include "ActorFrameTexture.h" -#include "RageTextureRenderTarget.h" -#include "RageTextureManager.h" -#include "ActorUtil.h" - -REGISTER_ACTOR_CLASS_WITH_NAME( ActorFrameTextureAutoDeleteChildren, ActorFrameTexture ); -ActorFrameTexture *ActorFrameTexture::Copy() const { return new ActorFrameTexture(*this); } - -ActorFrameTexture::ActorFrameTexture() -{ - m_bDepthBuffer = false; - m_bAlphaBuffer = false; - m_bFloat = false; - m_bPreserveTexture = false; - static uint64_t i = 0; - ++i; - m_sTextureName = ssprintf( ConvertI64FormatString("ActorFrameTexture %lli"), i ); - - m_pRenderTarget = NULL; -} - -ActorFrameTexture::ActorFrameTexture( const ActorFrameTexture &cpy ): - ActorFrame(cpy) -{ - FAIL_M( "ActorFrameTexture copy not implemented" ); -} - -ActorFrameTexture::~ActorFrameTexture() -{ - /* Release our reference to the texture. */ - TEXTUREMAN->UnloadTexture( m_pRenderTarget ); -} - -void ActorFrameTexture::Create() -{ - ASSERT( m_pRenderTarget == NULL ); - RageTextureID id( m_sTextureName ); - id.Policy = RageTextureID::TEX_VOLATILE; - - RenderTargetParam param; - param.bWithDepthBuffer = m_bDepthBuffer; - param.bWithAlpha = m_bAlphaBuffer; - param.bFloat = m_bFloat; - param.iWidth = (int) m_size.x; - param.iHeight = (int) m_size.y; - m_pRenderTarget = new RageTextureRenderTarget( id, param ); - m_pRenderTarget->m_bWasUsed = true; - - /* This passes ownership of m_pRenderTarget to TEXTUREMAN, but we retain - * our reference to it until we call TEXTUREMAN->UnloadTexture. */ - TEXTUREMAN->RegisterTexture( id, m_pRenderTarget ); -} - -void ActorFrameTexture::DrawPrimitives() -{ - if( m_pRenderTarget == NULL ) - return; - - m_pRenderTarget->BeginRenderingTo( m_bPreserveTexture ); - - ActorFrame::DrawPrimitives(); - - m_pRenderTarget->FinishRenderingTo(); -} - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the ActorFrameTexture. */ -class LunaActorFrameTexture : public Luna -{ -public: - static int Create( T* p, lua_State *L ) { p->Create(); return 0; } - static int EnableDepthBuffer( T* p, lua_State *L ) { p->EnableDepthBuffer(BArg(1)); return 0; } - static int EnableAlphaBuffer( T* p, lua_State *L ) { p->EnableAlphaBuffer(BArg(1)); return 0; } - static int EnableFloat( T* p, lua_State *L ) { p->EnableFloat(BArg(1)); return 0; } - static int EnablePreserveTexture( T* p, lua_State *L ) { p->EnablePreserveTexture(BArg(1)); return 0; } - static int SetTextureName( T* p, lua_State *L ) { p->SetTextureName(SArg(1)); return 0; } - static int GetTexture( T* p, lua_State *L ) - { - RageTexture *pTexture = p->GetTexture(); - if( pTexture == NULL ) - return 0; - pTexture->PushSelf(L); - return 1; - } - - LunaActorFrameTexture() - { - ADD_METHOD( Create ); - ADD_METHOD( EnableDepthBuffer ); - ADD_METHOD( EnableAlphaBuffer ); - ADD_METHOD( EnableFloat ); - ADD_METHOD( EnablePreserveTexture ); - ADD_METHOD( SetTextureName ); - ADD_METHOD( GetTexture ); - } -}; - -LUA_REGISTER_DERIVED_CLASS( ActorFrameTexture, ActorFrame ) -// lua end - -/* - * (c) 2006 Glenn Maynard - * 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/ActorFrameTexture.h b/src/ActorFrameTexture.h deleted file mode 100644 index 3997b7dcde..0000000000 --- a/src/ActorFrameTexture.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef ACTOR_FRAME_TEXTURE_H -#define ACTOR_FRAME_TEXTURE_H - -#include "ActorFrame.h" -class RageTextureRenderTarget; - -class ActorFrameTexture: public ActorFrame -{ -public: - ActorFrameTexture(); - ActorFrameTexture( const ActorFrameTexture &cpy ); - virtual ~ActorFrameTexture(); - virtual ActorFrameTexture *Copy() const; - - /** - * @brief Set the texture name. - * - * This can be used with RageTextureManager (and users, eg. Sprite) - * to load the texture. If no name is supplied, a unique one will - * be generated. In that case, the only way to access the texture - * is via GetTextureName. - * @param sName the new name. */ - void SetTextureName( const RString &sName ) { m_sTextureName = sName; } - /** - * @brief Retrieve the texture name. - * @return the texture name. */ - RString GetTextureName() const { return m_sTextureName; } - RageTextureRenderTarget *GetTexture() { return m_pRenderTarget; } - - void EnableDepthBuffer( bool b ) { m_bDepthBuffer = b; } - void EnableAlphaBuffer( bool b ) { m_bAlphaBuffer = b; } - void EnableFloat( bool b ) { m_bFloat = b; } - void EnablePreserveTexture( bool b ) { m_bPreserveTexture = b; } - - void Create(); - - virtual void DrawPrimitives(); - - // Commands - virtual void PushSelf( lua_State *L ); - -private: - RageTextureRenderTarget *m_pRenderTarget; - - bool m_bDepthBuffer; - bool m_bAlphaBuffer; - bool m_bFloat; - bool m_bPreserveTexture; - /** @brief the name of this ActorFrameTexture. */ - RString m_sTextureName; -}; - -class ActorFrameTextureAutoDeleteChildren : public ActorFrameTexture -{ -public: - ActorFrameTextureAutoDeleteChildren() { DeleteChildrenWhenDone(true); } - virtual bool AutoLoadChildren() const { return true; } - virtual ActorFrameTextureAutoDeleteChildren *Copy() const; -}; - -#endif - -/** - * @file - * @author Glenn Maynard (c) 2006 - * @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/ActorMultiTexture.cpp b/src/ActorMultiTexture.cpp deleted file mode 100644 index af2685f420..0000000000 --- a/src/ActorMultiTexture.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include "global.h" -#include - -#include "ActorMultiTexture.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" - -REGISTER_ACTOR_CLASS( ActorMultiTexture ); - - -ActorMultiTexture::ActorMultiTexture() -{ - m_EffectMode = EffectMode_Normal; -} - - -ActorMultiTexture::~ActorMultiTexture() -{ - ClearTextures(); -} - -ActorMultiTexture::ActorMultiTexture( const ActorMultiTexture &cpy ): - Actor( cpy ) -{ -#define CPY(a) a = cpy.a - CPY( m_Rect ); - CPY( m_aTextureUnits ); -#undef CPY - - FOREACH( TextureUnitState, m_aTextureUnits, tex ) - tex->m_pTexture = TEXTUREMAN->CopyTexture( tex->m_pTexture ); -} - -void ActorMultiTexture::SetTextureCoords( const RectF &r ) -{ - m_Rect = r; -} - -void ActorMultiTexture::LoadFromNode( const XNode* pNode ) -{ - m_Rect = RectF( 0, 0, 1, 1 ); - Actor::LoadFromNode( pNode ); -} - -void ActorMultiTexture::SetSizeFromTexture( RageTexture *pTexture ) -{ - ActorMultiTexture::m_size.x = pTexture->GetSourceWidth(); - ActorMultiTexture::m_size.y = pTexture->GetSourceHeight(); -} - -void ActorMultiTexture::ClearTextures() -{ - FOREACH( TextureUnitState, m_aTextureUnits, tex ) - TEXTUREMAN->UnloadTexture( tex->m_pTexture ); - m_aTextureUnits.clear(); -} - -int ActorMultiTexture::AddTexture( RageTexture *pTexture ) -{ - ASSERT( pTexture != NULL ); - LOG->Trace( "ActorMultiTexture::AddTexture( %s )", pTexture->GetID().filename.c_str() ); - - m_aTextureUnits.push_back( TextureUnitState() ); - m_aTextureUnits.back().m_pTexture = TEXTUREMAN->CopyTexture( pTexture ); - return m_aTextureUnits.size() - 1; -} - -void ActorMultiTexture::SetTextureMode( int iIndex, TextureMode tm ) -{ - ASSERT( iIndex < (int) m_aTextureUnits.size() ); - m_aTextureUnits[iIndex].m_TextureMode = tm; -} - -void ActorMultiTexture::DrawPrimitives() -{ - Actor::SetGlobalRenderStates(); // set Actor-specified render states - - RectF quadVerticies; - quadVerticies.left = -m_size.x/2.0f; - quadVerticies.right = +m_size.x/2.0f; - quadVerticies.top = -m_size.y/2.0f; - quadVerticies.bottom = +m_size.y/2.0f; - - DISPLAY->ClearAllTextures(); - for( size_t i = 0; i < m_aTextureUnits.size(); ++i ) - { - TextureUnit tu = enum_add2(TextureUnit_1, i); - DISPLAY->SetTexture( tu, m_aTextureUnits[i].m_pTexture->GetTexHandle() ); - DISPLAY->SetTextureWrapping( tu, m_bTextureWrapping ); - DISPLAY->SetTextureMode( tu, m_aTextureUnits[i].m_TextureMode ); - } - - DISPLAY->SetEffectMode( m_EffectMode ); - - static RageSpriteVertex v[4]; - v[0].p = RageVector3( quadVerticies.left, quadVerticies.top, 0 ); // top left - v[1].p = RageVector3( quadVerticies.left, quadVerticies.bottom, 0 ); // bottom left - v[2].p = RageVector3( quadVerticies.right, quadVerticies.bottom, 0 ); // bottom right - v[3].p = RageVector3( quadVerticies.right, quadVerticies.top, 0 ); // top right - - const RectF *pTexCoordRect = &m_Rect; - v[0].t = RageVector2( pTexCoordRect->left, pTexCoordRect->top ); // top left - v[1].t = RageVector2( pTexCoordRect->left, pTexCoordRect->bottom ); // bottom left - v[2].t = RageVector2( pTexCoordRect->right, pTexCoordRect->bottom ); // bottom right - v[3].t = RageVector2( pTexCoordRect->right, pTexCoordRect->top ); // top right - - v[0].c = m_pTempState->diffuse[0]; // top left - v[1].c = m_pTempState->diffuse[2]; // bottom left - v[2].c = m_pTempState->diffuse[3]; // bottom right - v[3].c = m_pTempState->diffuse[1]; // top right - - DISPLAY->DrawQuad( v ); - - for( size_t i = 0; i < m_aTextureUnits.size(); ++i ) - DISPLAY->SetTexture( enum_add2(TextureUnit_1, i), 0 ); - - DISPLAY->SetEffectMode( EffectMode_Normal ); -} - -bool ActorMultiTexture::EarlyAbortDraw() const -{ - return m_aTextureUnits.empty(); -} - - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the ActorMultiTexture. */ -class LunaActorMultiTexture: public Luna -{ -public: - static int ClearTextures( T* p, lua_State *L ) - { - p->ClearTextures(); - return 0; - } - static int AddTexture( T* p, lua_State *L ) - { - RageTexture *pTexture = Luna::check(L, 1); - int iRet = p->AddTexture( pTexture ); - lua_pushinteger( L, iRet ); - return 1; - } - static int SetTextureMode( T* p, lua_State *L ) - { - int iIndex = IArg(1); - TextureMode tm = Enum::Check(L, 2); - p->SetTextureMode( iIndex, tm ); - return 0; - } - static int SetTextureCoords( T* p, lua_State *L ) - { - p->SetTextureCoords( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) ); - return 0; - } - static int SetSizeFromTexture( T* p, lua_State *L ) - { - RageTexture *pTexture = Luna::check(L, 1); - p->SetSizeFromTexture( pTexture ); - return 0; - } - static int SetEffectMode( T* p, lua_State *L ) - { - EffectMode em = Enum::Check(L, 1); - p->SetEffectMode( em ); - return 0; - } - - LunaActorMultiTexture() - { - ADD_METHOD( ClearTextures ); - ADD_METHOD( AddTexture ); - ADD_METHOD( SetTextureMode ); - ADD_METHOD( SetTextureCoords ); - ADD_METHOD( SetSizeFromTexture ); - ADD_METHOD( SetEffectMode ); - } -}; - -LUA_REGISTER_DERIVED_CLASS( ActorMultiTexture, Actor ) -// lua end - -/* - * (c) 2001-2007 Glenn Maynard, Chris Danford - * 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/ActorMultiTexture.h b/src/ActorMultiTexture.h deleted file mode 100644 index 6f4d793361..0000000000 --- a/src/ActorMultiTexture.h +++ /dev/null @@ -1,73 +0,0 @@ -/** @brief ActorMultiTexture - A texture created from multiple textures. */ - -#ifndef ACTOR_MULTI_TEXTURE_H -#define ACTOR_MULTI_TEXTURE_H - -#include "Actor.h" -#include "RageDisplay.h" - -class RageTexture; - -class ActorMultiTexture: public Actor -{ -public: - ActorMultiTexture(); - ActorMultiTexture( const ActorMultiTexture &cpy ); - virtual ~ActorMultiTexture(); - - void LoadFromNode( const XNode* pNode ); - virtual ActorMultiTexture *Copy() const; - - virtual bool EarlyAbortDraw() const; - virtual void DrawPrimitives(); - - void ClearTextures(); - int AddTexture( RageTexture *pTexture ); - void SetTextureMode( int iIndex, TextureMode tm ); - - void SetSizeFromTexture( RageTexture *pTexture ); - void SetTextureCoords( const RectF &r ); - void SetEffectMode( EffectMode em ) { m_EffectMode = em; } - - virtual void PushSelf( lua_State *L ); - -private: - EffectMode m_EffectMode; - struct TextureUnitState - { - TextureUnitState(): m_pTexture(NULL), m_TextureMode(TextureMode_Modulate) {} - RageTexture *m_pTexture; - TextureMode m_TextureMode; - }; - vector m_aTextureUnits; - RectF m_Rect; -}; - -#endif - -/** - * @file - * @author Chris Danford (c) 2001-2004 - * @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/ActorProxy.cpp b/src/ActorProxy.cpp deleted file mode 100644 index 92f721f9b9..0000000000 --- a/src/ActorProxy.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "global.h" -#include "ActorProxy.h" -#include "ActorUtil.h" - -REGISTER_ACTOR_CLASS( ActorProxy ); - -ActorProxy::ActorProxy() -{ - m_pActorTarget = NULL; -} - -bool ActorProxy::EarlyAbortDraw() const -{ - return m_pActorTarget == NULL || Actor::EarlyAbortDraw(); -} - -void ActorProxy::DrawPrimitives() -{ - if( m_pActorTarget != NULL ) - { - bool bVisible = m_pActorTarget->GetVisible(); - m_pActorTarget->SetVisible( true ); - m_pActorTarget->Draw(); - m_pActorTarget->SetVisible( bVisible ); - } -} - -void ActorProxy::LoadFromNode( const XNode* pNode ) -{ - Actor::LoadFromNode( pNode ); -} - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the ActorProxy. */ -class LunaActorProxy: public Luna -{ -public: - static int SetTarget( T* p, lua_State *L ) - { - Actor *pTarget = Luna::check( L, 1 ); - p->SetTarget( pTarget ); - return 0; - } - - static int GetTarget( T* p, lua_State *L ) - { - Actor *pTarget = p->GetTarget(); - if( pTarget != NULL ) - pTarget->PushSelf( L ); - else - lua_pushnil( L ); - return 1; - } - - LunaActorProxy() - { - ADD_METHOD( SetTarget ); - ADD_METHOD( GetTarget ); - } -}; - -LUA_REGISTER_DERIVED_CLASS( ActorProxy, Actor ) -// lua end - -/* - * (c) 2006 Glenn Maynard - * 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/ActorProxy.h b/src/ActorProxy.h deleted file mode 100644 index 763ea74599..0000000000 --- a/src/ActorProxy.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef ACTOR_PROXY_H -#define ACTOR_PROXY_H - -#include "Actor.h" - -struct lua_State; -/** @brief Renders another actor. */ -class ActorProxy: public Actor -{ -public: - ActorProxy(); - - virtual bool EarlyAbortDraw() const; - virtual void DrawPrimitives(); - - void LoadFromNode( const XNode* pNode ); - virtual ActorProxy *Copy() const; - - Actor *GetTarget() { return m_pActorTarget; } - void SetTarget( Actor *pTarget ) { m_pActorTarget = pTarget; } - - // Lua - virtual void PushSelf( lua_State *L ); - -private: - Actor *m_pActorTarget; -}; - -#endif - -/* - * (c) 2006 Glenn Maynard - * 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/ActorScroller.cpp b/src/ActorScroller.cpp deleted file mode 100644 index e463af73b3..0000000000 --- a/src/ActorScroller.cpp +++ /dev/null @@ -1,397 +0,0 @@ -#include "global.h" -#include "ActorScroller.h" -#include "Foreach.h" -#include "RageUtil.h" -#include "XmlFile.h" -#include "arch/Dialog/Dialog.h" -#include "RageLog.h" -#include "ActorUtil.h" -#include "LuaBinding.h" - -/* Tricky: We need ActorFrames created in Lua to auto delete their children. - * We don't want classes that derive from ActorFrame to auto delete their - * children. The name "ActorFrame" is widely used in Lua, so we'll have - * that string instead create an ActorFrameAutoDeleteChildren object. */ -//REGISTER_ACTOR_CLASS( ActorScroller ); -REGISTER_ACTOR_CLASS_WITH_NAME( ActorScrollerAutoDeleteChildren, ActorScroller ); -ActorScroller *ActorScroller::Copy() const { return new ActorScroller(*this); } - - -ActorScroller::ActorScroller() -{ - m_iNumItems = 0; - m_fCurrentItem = 0; - m_fDestinationItem = 0; - m_fSecondsPerItem = 1; - m_fSecondsPauseBetweenItems = 0; - m_fNumItemsToDraw = 7; - m_iFirstSubActorIndex = 0; - m_bLoop = false; - m_bFastCatchup = false; - m_bFunctionDependsOnPositionOffset = true; - m_bFunctionDependsOnItemIndex = true; - m_fPauseCountdownSeconds = 0; - m_fQuantizePixels = 0; - - m_quadMask.SetBlendMode( BLEND_NO_EFFECT ); // don't change color values - m_quadMask.SetUseZBuffer( true ); // we want to write to the Zbuffer - m_fMaskWidth = 0; - m_fMaskHeight = 0; - DisableMask(); -} - -void ActorScroller::Load2() -{ - m_iNumItems = m_SubActors.size(); - - Lua *L = LUA->Get(); - for( unsigned i = 0; i < m_SubActors.size(); ++i ) - { - lua_pushnumber( L, i ); - this->m_SubActors[i]->m_pLuaInstance->Set( L, "ItemIndex" ); - } - LUA->Release( L ); -} - -void ActorScroller::SetTransformFromReference( const LuaReference &ref ) -{ - m_exprTransformFunction.SetFromReference( ref ); - - // Probe to find which of the parameters are used. -#define GP(a,b) m_exprTransformFunction.GetTransformCached( a, b, 2 ) - m_bFunctionDependsOnPositionOffset = (GP(0,0) != GP(1,0)) && (GP(0,1) != GP(1,1)); - m_bFunctionDependsOnItemIndex = (GP(0,0) != GP(0,1)) && (GP(1,0) != GP(1,1)); - m_exprTransformFunction.ClearCache(); -} - -void ActorScroller::SetTransformFromExpression( const RString &sTransformFunction ) -{ - LuaReference ref; - ref.SetFromExpression( sTransformFunction ); - SetTransformFromReference( ref ); -} - -void ActorScroller::SetTransformFromWidth( float fItemWidth ) -{ - SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:x(%f*offset) end",fItemWidth) ); -} - -void ActorScroller::SetTransformFromHeight( float fItemHeight ) -{ - SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:y(%f*offset) end",fItemHeight) ); -} - -void ActorScroller::EnableMask( float fWidth, float fHeight ) -{ - m_quadMask.SetVisible( fWidth != 0 && fHeight != 0 ); - m_quadMask.SetWidth( fWidth ); - m_fMaskWidth = fWidth; - m_quadMask.SetHeight( fHeight ); - m_fMaskHeight = fHeight; -} - -void ActorScroller::DisableMask() -{ - m_quadMask.SetVisible( false ); -} - -void ActorScroller::ScrollThroughAllItems() -{ - m_fCurrentItem = m_bLoop ? +m_fNumItemsToDraw/2.0f : -(m_fNumItemsToDraw/2.0f)-1; - m_fDestinationItem = (float)(m_iNumItems+m_fNumItemsToDraw/2.0f+1); -} - -void ActorScroller::ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd ) -{ - m_fCurrentItem = -fItemPaddingStart; - m_fDestinationItem = m_iNumItems-1+fItemPaddingEnd; -} - -float ActorScroller::GetSecondsForCompleteScrollThrough() const -{ - float fTotalItems = m_fNumItemsToDraw + m_iNumItems; - return fTotalItems * (m_fSecondsPerItem + m_fSecondsPauseBetweenItems ); -} - -float ActorScroller::GetSecondsToDestination() const -{ - float fTotalItemsToMove = fabsf(m_fCurrentItem - m_fDestinationItem); - return fTotalItemsToMove * m_fSecondsPerItem; -} - -void ActorScroller::LoadFromNode( const XNode *pNode ) -{ - ActorFrame::LoadFromNode( pNode ); - - Load2(); - - float fNumItemsToDraw = 0; - if( pNode->GetAttrValue("NumItemsToDraw", fNumItemsToDraw) ) - SetNumItemsToDraw( fNumItemsToDraw ); - - float fSecondsPerItem = 0; - if( pNode->GetAttrValue("SecondsPerItem", fSecondsPerItem) ) - ActorScroller::SetSecondsPerItem( fSecondsPerItem ); - - Lua *L = LUA->Get(); - pNode->PushAttrValue( L, "TransformFunction" ); - { - LuaReference ref; - ref.SetFromStack( L ); - if( !ref.IsNil() ) - SetTransformFromReference( ref ); - } - LUA->Release( L ); - - int iSubdivisions = 1; - if( pNode->GetAttrValue("Subdivisions", iSubdivisions) ) - ActorScroller::SetNumSubdivisions( iSubdivisions ); - - bool bUseMask = false; - pNode->GetAttrValue( "UseMask", bUseMask ); - - if( bUseMask ) - { - pNode->GetAttrValue( "MaskWidth", m_fMaskWidth ); - pNode->GetAttrValue( "MaskHeight", m_fMaskHeight ); - EnableMask( m_fMaskWidth, m_fMaskHeight ); - } - - pNode->GetAttrValue( "QuantizePixels", m_fQuantizePixels ); -} - -void ActorScroller::UpdateInternal( float fDeltaTime ) -{ - ActorFrame::UpdateInternal( fDeltaTime ); - - // If we have no children, the code below will busy loop. - if( !m_SubActors.size() ) - return; - - // handle pause - if( fDeltaTime > m_fPauseCountdownSeconds ) - { - fDeltaTime -= m_fPauseCountdownSeconds; - m_fPauseCountdownSeconds = 0; - } - else - { - m_fPauseCountdownSeconds -= fDeltaTime; - fDeltaTime = 0; - return; - } - - - if( m_fCurrentItem == m_fDestinationItem ) - return; // done scrolling - - - float fOldItemAtTop = m_fCurrentItem; - if( m_fSecondsPerItem > 0 ) - { - float fApproachSpeed = fDeltaTime/m_fSecondsPerItem; - if( m_bFastCatchup ) - { - float fDistanceToMove = fabsf(m_fCurrentItem - m_fDestinationItem); - if( fDistanceToMove > 1 ) - fApproachSpeed *= fDistanceToMove*fDistanceToMove; - } - - fapproach( m_fCurrentItem, m_fDestinationItem, fApproachSpeed ); - } - - // if items changed, then pause - if( (int)fOldItemAtTop != (int)m_fCurrentItem ) - m_fPauseCountdownSeconds = m_fSecondsPauseBetweenItems; - - if( m_bLoop ) - m_fCurrentItem = fmodf( m_fCurrentItem, (float) m_iNumItems ); -} - -void ActorScroller::DrawPrimitives() -{ - PositionItemsAndDrawPrimitives( true ); -} - -void ActorScroller::PositionItems() -{ - PositionItemsAndDrawPrimitives( false ); -} - -/* Shift m_SubActors forward by iDist. This will place item m_iFirstSubActorIndex - * in m_SubActors[0]. */ -void ActorScroller::ShiftSubActors( int iDist ) -{ - if( iDist != INT_MAX ) - CircularShift( m_SubActors, iDist ); -} - -void ActorScroller::PositionItemsAndDrawPrimitives( bool bDrawPrimitives ) -{ - if( m_SubActors.empty() ) - return; - - float fNumItemsToDraw = m_fNumItemsToDraw; - if( m_quadMask.GetVisible() ) - { - // write to z buffer so that top and bottom are clipped - // Draw an extra item; this is the one that will be masked. - fNumItemsToDraw++; - float fPositionFullyOffScreenTop = -(fNumItemsToDraw)/2.f; - float fPositionFullyOffScreenBottom = (fNumItemsToDraw)/2.f; - - m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenTop, -1, m_iNumItems ); - if( bDrawPrimitives ) m_quadMask.Draw(); - - m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenBottom, m_iNumItems, m_iNumItems ); - if( bDrawPrimitives ) m_quadMask.Draw(); - } - - float fFirstItemToDraw = m_fCurrentItem - fNumItemsToDraw/2.f; - float fLastItemToDraw = m_fCurrentItem + fNumItemsToDraw/2.f; - int iFirstItemToDraw = (int) ceilf( fFirstItemToDraw ); - int iLastItemToDraw = (int) ceilf( fLastItemToDraw ); - if( !m_bLoop ) - { - iFirstItemToDraw = clamp( iFirstItemToDraw, 0, m_iNumItems ); - iLastItemToDraw = clamp( iLastItemToDraw, 0, m_iNumItems ); - } - - bool bDelayedDraw = m_bDrawByZPosition && !m_bLoop; - vector subs; - - { - // Shift m_SubActors so iFirstItemToDraw is at the beginning. - int iNewFirstIndex = iFirstItemToDraw; - int iDist = iNewFirstIndex - m_iFirstSubActorIndex; - m_iFirstSubActorIndex = iNewFirstIndex; - ShiftSubActors( iDist ); - } - - int iNumToDraw = iLastItemToDraw - iFirstItemToDraw; - for( int i = 0; i < iNumToDraw; ++i ) - { - int iItem = i + iFirstItemToDraw; - float fPosition = iItem - m_fCurrentItem; - int iIndex = i; // index into m_SubActors - if( m_bLoop ) - wrap( iIndex, m_SubActors.size() ); - else if( iIndex < 0 || iIndex >= (int)m_SubActors.size() ) - continue; - - // Optimization: Zero out unused parameters so that they don't create new, - // unnecessary entries in the position cache. On scrollers with lots of - // items, especially with Subdivisions > 1, m_exprTransformFunction uses - // too much memory. - if( !m_bFunctionDependsOnPositionOffset ) - fPosition = 0; - if( !m_bFunctionDependsOnItemIndex ) - iItem = 0; - - m_exprTransformFunction.TransformItemCached( *m_SubActors[iIndex], fPosition, iItem, m_iNumItems ); - if( bDrawPrimitives ) - { - if( bDelayedDraw ) - subs.push_back( m_SubActors[iIndex] ); - else - m_SubActors[iIndex]->Draw(); - } - } - - if( bDelayedDraw ) - { - ActorUtil::SortByZPosition( subs ); - FOREACH( Actor*, subs, a ) - (*a)->Draw(); - } -} - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the ActorScroller. */ -class LunaActorScroller: public Luna -{ -public: - static int PositionItems( T* p, lua_State *L ) { p->PositionItems(); return 0; } - static int SetTransformFromFunction( T* p, lua_State *L ) - { - LuaReference ref; - LuaHelpers::FromStack( L, ref, 1 ); - p->SetTransformFromReference( ref ); - return 0; - } - static int SetTransformFromHeight( T* p, lua_State *L ) { p->SetTransformFromHeight(FArg(1)); return 0; } - static int SetTransformFromWidth( T* p, lua_State *L ) { p->SetTransformFromWidth(FArg(1)); return 0; } - static int SetCurrentAndDestinationItem( T* p, lua_State *L ) { p->SetCurrentAndDestinationItem( FArg(1) ); return 0; } - static int SetDestinationItem( T* p, lua_State *L ) { p->SetDestinationItem( FArg(1) ); return 0; } - static int GetSecondsToDestination( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsToDestination() ); return 1; } - static int SetSecondsPerItem( T* p, lua_State *L ) { p->SetSecondsPerItem(FArg(1)); return 0; } - static int SetSecondsPauseBetweenItems( T* p, lua_State *L ) { p->SetSecondsPauseBetweenItems(FArg(1)); return 0; } - static int SetPauseCountdownSeconds( T* p, lua_State *L ) { p->SetPauseCountdownSeconds(FArg(1)); return 0; } - static int SetNumSubdivisions( T* p, lua_State *L ) { p->SetNumSubdivisions(IArg(1)); return 0; } - static int ScrollThroughAllItems( T* p, lua_State *L ) { p->ScrollThroughAllItems(); return 0; } - static int ScrollWithPadding( T* p, lua_State *L ) { p->ScrollWithPadding(FArg(1),FArg(2)); return 0; } - static int SetFastCatchup( T* p, lua_State *L ) { p->SetFastCatchup(BArg(1)); return 0; } - static int SetLoop( T* p, lua_State *L ) { p->SetLoop(BArg(1)); return 0; } - static int SetMask( T* p, lua_State *L ) { p->EnableMask(FArg(1), FArg(2)); return 0; } - - static int SetNumItemsToDraw( T* p, lua_State *L ) { p->SetNumItemsToDraw(FArg(1)); return 0; } - static int GetFullScrollLengthSeconds( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsForCompleteScrollThrough() ); return 1; } - static int GetCurrentItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetCurrentItem() ); return 1; } - static int GetDestinationItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetDestinationItem() ); return 1; } - static int GetNumItems( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumItems() ); return 1; } - - LunaActorScroller() - { - ADD_METHOD( PositionItems ); - ADD_METHOD( SetTransformFromFunction ); - ADD_METHOD( SetTransformFromHeight ); - ADD_METHOD( SetTransformFromWidth ); - ADD_METHOD( SetCurrentAndDestinationItem ); - ADD_METHOD( SetDestinationItem ); - ADD_METHOD( GetSecondsToDestination ); - ADD_METHOD( SetSecondsPerItem ); - ADD_METHOD( SetSecondsPauseBetweenItems ); - ADD_METHOD( SetPauseCountdownSeconds ); - ADD_METHOD( SetNumSubdivisions ); - ADD_METHOD( ScrollThroughAllItems ); - ADD_METHOD( ScrollWithPadding ); - ADD_METHOD( SetFastCatchup ); - ADD_METHOD( SetLoop ); - ADD_METHOD( SetMask ); - ADD_METHOD( SetNumItemsToDraw ); - ADD_METHOD( GetFullScrollLengthSeconds ); - ADD_METHOD( GetCurrentItem ); - ADD_METHOD( GetDestinationItem ); - ADD_METHOD( GetNumItems ); - } -}; - -LUA_REGISTER_DERIVED_CLASS( ActorScroller, ActorFrame ) -// lua end - -/* - * (c) 2003-2004 Chris Danford - * 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/ActorScroller.h b/src/ActorScroller.h deleted file mode 100644 index 2a195dcde2..0000000000 --- a/src/ActorScroller.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef ActorScroller_H -#define ActorScroller_H - -#include "ActorFrame.h" -#include "Quad.h" -class XNode; -#include "LuaExpressionTransform.h" -/** @brief ActorFrame that moves its children. */ -class ActorScroller : public ActorFrame -{ -public: - ActorScroller(); - - void SetTransformFromReference( const LuaReference &ref ); - void SetTransformFromExpression( const RString &sTransformFunction ); - void SetTransformFromWidth( float fItemWidth ); - void SetTransformFromHeight( float fItemHeight ); - - void Load2(); - - void EnableMask( float fWidth, float fHeight ); - void DisableMask(); - - virtual void UpdateInternal( float fDelta ); - virtual void DrawPrimitives(); // handles drawing and doesn't call ActorFrame::DrawPrimitives - - void PositionItems(); - - void LoadFromNode( const XNode *pNode ); - virtual ActorScroller *Copy() const; - - void SetLoop( bool bLoop ) { m_bLoop = bLoop; } - void SetNumItemsToDraw( float fNumItemsToDraw ) { m_fNumItemsToDraw = fNumItemsToDraw; } - void SetDestinationItem( float fItemIndex ) { m_fDestinationItem = fItemIndex; } - void SetCurrentAndDestinationItem( float fItemIndex ) { m_fCurrentItem = m_fDestinationItem = fItemIndex; } - float GetCurrentItem() const { return m_fCurrentItem; } - float GetDestinationItem() const { return m_fDestinationItem; } - void ScrollThroughAllItems(); - void ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd ); - void SetPauseCountdownSeconds( float fSecs ) { m_fPauseCountdownSeconds = fSecs; } - void SetFastCatchup( bool bOn ) { m_bFastCatchup = bOn; } - void SetSecondsPerItem( float fSeconds ) { m_fSecondsPerItem = fSeconds; } - void SetSecondsPauseBetweenItems( float fSeconds ) { m_fSecondsPauseBetweenItems = fSeconds; } - void SetNumSubdivisions( int iNumSubdivisions ) { m_exprTransformFunction.SetNumSubdivisions( iNumSubdivisions ); } - float GetSecondsForCompleteScrollThrough() const; - float GetSecondsToDestination() const; - int GetNumItems() const { return m_iNumItems; } - - // Commands - void PushSelf( lua_State *L ); - -protected: - void PositionItemsAndDrawPrimitives( bool bDrawPrimitives ); - virtual void ShiftSubActors( int iDist ); - - int m_iNumItems; - /** - * @brief the current item we are focused on. - * - * An item at the center of the list, usually between 0 and m_SubActors.size(), - * will approach its destination. - * - * The above comment was paraphrased from what was here previously. It could use - * some clearing up. -Wolfman2000 */ - float m_fCurrentItem; - float m_fDestinationItem; - /** - * @brief How many seconds are there per item? - * - * If this is less than zero, then we are not scrolling. */ - float m_fSecondsPerItem; - float m_fSecondsPauseBetweenItems; - float m_fNumItemsToDraw; - int m_iFirstSubActorIndex; - bool m_bLoop; - bool m_bFastCatchup; - bool m_bFunctionDependsOnPositionOffset; - bool m_bFunctionDependsOnItemIndex; - float m_fPauseCountdownSeconds; - float m_fQuantizePixels; - - Quad m_quadMask; - float m_fMaskWidth, m_fMaskHeight; - - LuaExpressionTransform m_exprTransformFunction; // params: self,offset,itemIndex,numItems -}; - -class ActorScrollerAutoDeleteChildren : public ActorScroller -{ -public: - ActorScrollerAutoDeleteChildren() { DeleteChildrenWhenDone(true); } - virtual bool AutoLoadChildren() const { return true; } - virtual ActorScrollerAutoDeleteChildren *Copy() const; -}; - -#endif - -/** - * @file - * @author Chris Danford (c) 2003-2004 - * @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/ActorSound.cpp b/src/ActorSound.cpp deleted file mode 100644 index 588a6635af..0000000000 --- a/src/ActorSound.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "global.h" -#include "ActorSound.h" -#include "ActorUtil.h" -#include "LuaManager.h" -#include "XmlFile.h" -#include "RageUtil.h" - -REGISTER_ACTOR_CLASS_WITH_NAME( ActorSound, Sound ); - -void ActorSound::Load( const RString &sPath ) -{ - m_Sound.Load( sPath, true ); -} - -void ActorSound::Play() -{ - // This fix makes it possible to stop and pause ActorSounds. (Also, - // sometimes stacking sounds is annoying.) -DaisuMaster - if( m_Sound.IsPlaying() ) - { - m_Sound.PlayCopy(); - return; - } - m_Sound.StartPlaying(); -} - -void ActorSound::Pause( bool bPause ) -{ - m_Sound.Pause(bPause); -} - -void ActorSound::Stop() -{ - m_Sound.Stop(); -} - -void ActorSound::LoadFromNode( const XNode* pNode ) -{ - RageSoundLoadParams params; - pNode->GetAttrValue("SupportPan", params.m_bSupportPan); - pNode->GetAttrValue("SupportRateChanging", params.m_bSupportRateChanging); - - bool bPrecache = true; - pNode->GetAttrValue( "Precache", bPrecache ); - - Actor::LoadFromNode( pNode ); - - RString sFile; - if( ActorUtil::GetAttrPath(pNode, "File", sFile) ) - m_Sound.Load( sFile, bPrecache, ¶ms ); -} - -// lua start -#include "LuaBinding.h" - -/** @brief Allow Lua to have access to the ActorSound. */ -class LunaActorSound: public Luna -{ -public: - static int load( T* p, lua_State *L ) { p->Load(SArg(1)); return 0; } - static int play( T* p, lua_State *L ) { p->Play(); return 0; } - static int pause( T* p, lua_State *L ) { p->Pause(BArg(1)); return 0; } - static int stop( T* p, lua_State *L ) { p->Stop(); return 0; } - static int get( T* p, lua_State *L ) { p->PushSound( L ); return 1; } - - LunaActorSound() - { - ADD_METHOD( load ); - ADD_METHOD( play ); - ADD_METHOD( pause ); - ADD_METHOD( stop ); - ADD_METHOD( get ); - } -}; - -LUA_REGISTER_DERIVED_CLASS( ActorSound, Actor ) -// lua end - - -/* - * (c) 2005 Glenn Maynard - * 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/ActorSound.h b/src/ActorSound.h deleted file mode 100644 index 8b1d29d90a..0000000000 --- a/src/ActorSound.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef ACTOR_SOUND_H -#define ACTOR_SOUND_H - -#include "Actor.h" -#include "RageSound.h" -/** @brief RageSound Actor interface. */ -class ActorSound: public Actor -{ -public: - virtual ~ActorSound() { } - virtual ActorSound *Copy() const; - - void Load( const RString &sPath ); - void Play(); - void Pause( bool bPause ); - void Stop(); - void LoadFromNode( const XNode* pNode ); - void PushSound( lua_State *L ) { m_Sound.PushSelf( L ); } - - // - // Lua - // - virtual void PushSelf( lua_State *L ); - -private: - RageSound m_Sound; -}; - -#endif - -/** - * @file - * @author Glenn Maynard (c) 2005 - * @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. - */ From b3add3fa065b486e316a90d956613c665567160c Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Fri, 23 Sep 2011 19:34:58 -0400 Subject: [PATCH 19/30] Restore Xcode 3 compilation. --- Xcode/stepmania.xcodeproj/project.pbxproj | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Xcode/stepmania.xcodeproj/project.pbxproj b/Xcode/stepmania.xcodeproj/project.pbxproj index 030389f833..62810e1c50 100644 --- a/Xcode/stepmania.xcodeproj/project.pbxproj +++ b/Xcode/stepmania.xcodeproj/project.pbxproj @@ -1996,8 +1996,8 @@ 36CA531B0F91564A0063D59D /* ScreenOptionsCourseOverview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenOptionsCourseOverview.h; path = ../src/ScreenOptionsCourseOverview.h; sourceTree = SOURCE_ROOT; }; 36CA531E0F9156860063D59D /* ScreenOptionsEditCourse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScreenOptionsEditCourse.cpp; path = ../src/ScreenOptionsEditCourse.cpp; sourceTree = SOURCE_ROOT; }; 36CA531F0F9156860063D59D /* ScreenOptionsEditCourse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenOptionsEditCourse.h; path = ../src/ScreenOptionsEditCourse.h; sourceTree = SOURCE_ROOT; }; - AA059ABA0B8CCFB5006F8139 /* ActorMultiTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ActorMultiTexture.cpp; path = ../src/ActorMultiTexture.cpp; sourceTree = ""; }; - AA059ABB0B8CCFB5006F8139 /* ActorMultiTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ActorMultiTexture.h; path = ../src/ActorMultiTexture.h; sourceTree = ""; }; + AA059ABA0B8CCFB5006F8139 /* ActorMultiTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ActorMultiTexture.cpp; path = ../src/Actors/ActorMultiTexture.cpp; sourceTree = ""; }; + AA059ABB0B8CCFB5006F8139 /* ActorMultiTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ActorMultiTexture.h; path = ../src/Actors/ActorMultiTexture.h; sourceTree = ""; }; AA059E2A0B8F0C66006F8139 /* libz_link.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libz_link.a; sourceTree = ""; }; AA05A0AE0BA2EFF3006F8139 /* OptionsList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionsList.cpp; path = ../src/OptionsList.cpp; sourceTree = ""; }; AA05A0AF0BA2EFF3006F8139 /* OptionsList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionsList.h; path = ../src/OptionsList.h; sourceTree = ""; }; @@ -2141,8 +2141,8 @@ AA5C73FC0637A5F000AFB891 /* StepsUtil.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = StepsUtil.h; path = ../src/StepsUtil.h; sourceTree = ""; }; AA5D16550A79805C00F17E86 /* RageTextureRenderTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RageTextureRenderTarget.cpp; path = ../src/RageTextureRenderTarget.cpp; sourceTree = ""; }; AA5D16560A79805C00F17E86 /* RageTextureRenderTarget.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = RageTextureRenderTarget.h; path = ../src/RageTextureRenderTarget.h; sourceTree = ""; }; - AA5D166A0A798C0E00F17E86 /* ActorFrameTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ActorFrameTexture.cpp; path = ../src/ActorFrameTexture.cpp; sourceTree = ""; }; - AA5D166B0A798C0E00F17E86 /* ActorFrameTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ActorFrameTexture.h; path = ../src/ActorFrameTexture.h; sourceTree = ""; }; + AA5D166A0A798C0E00F17E86 /* ActorFrameTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ActorFrameTexture.cpp; path = ../src/Actors/ActorFrameTexture.cpp; sourceTree = ""; }; + AA5D166B0A798C0E00F17E86 /* ActorFrameTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ActorFrameTexture.h; path = ../src/Actors/ActorFrameTexture.h; sourceTree = ""; }; AA608EBF0B0F85E400B39AC4 /* DialogDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DialogDriver.cpp; sourceTree = ""; }; AA608FAC0B0F9A4E00B39AC4 /* RageSoundDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RageSoundDriver.cpp; sourceTree = ""; }; AA6090E40B141D1C00B39AC4 /* GamePreferences.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = GamePreferences.cpp; path = ../src/GamePreferences.cpp; sourceTree = ""; }; @@ -2426,12 +2426,12 @@ AA6EFF3004770F63005F316C /* ScoreKeeper.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScoreKeeper.h; path = ../src/ScoreKeeper.h; sourceTree = ""; }; AA6EFF7004770F86005F316C /* Transition.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Transition.cpp; path = ../src/Transition.cpp; sourceTree = ""; }; AA6EFF7104770F86005F316C /* Transition.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Transition.h; path = ../src/Transition.h; sourceTree = ""; }; - AA6EFF7504770FFD005F316C /* Actor.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Actor.cpp; path = ../src/Actor.cpp; sourceTree = ""; }; - AA6EFF7604770FFD005F316C /* Actor.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Actor.h; path = ../src/Actor.h; sourceTree = ""; }; - AA6EFF7704770FFD005F316C /* ActorFrame.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ActorFrame.cpp; path = ../src/ActorFrame.cpp; sourceTree = ""; }; - AA6EFF7804770FFD005F316C /* ActorFrame.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ActorFrame.h; path = ../src/ActorFrame.h; sourceTree = ""; }; - AA6EFF7904770FFD005F316C /* ActorScroller.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ActorScroller.cpp; path = ../src/ActorScroller.cpp; sourceTree = ""; }; - AA6EFF7A04770FFD005F316C /* ActorScroller.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ActorScroller.h; path = ../src/ActorScroller.h; sourceTree = ""; }; + AA6EFF7504770FFD005F316C /* Actor.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Actor.cpp; path = ../src/Actors/Actor.cpp; sourceTree = ""; }; + AA6EFF7604770FFD005F316C /* Actor.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Actor.h; path = ../src/Actors/Actor.h; sourceTree = ""; }; + AA6EFF7704770FFD005F316C /* ActorFrame.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ActorFrame.cpp; path = ../src/Actors/ActorFrame.cpp; sourceTree = ""; }; + AA6EFF7804770FFD005F316C /* ActorFrame.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ActorFrame.h; path = ../src/Actors/ActorFrame.h; sourceTree = ""; }; + AA6EFF7904770FFD005F316C /* ActorScroller.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ActorScroller.cpp; path = ../src/Actors/ActorScroller.cpp; sourceTree = ""; }; + AA6EFF7A04770FFD005F316C /* ActorScroller.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ActorScroller.h; path = ../src/Actors/ActorScroller.h; sourceTree = ""; }; AA6EFFB904770FFD005F316C /* BitmapText.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = BitmapText.cpp; path = ../src/BitmapText.cpp; sourceTree = ""; }; AA6EFFBA04770FFD005F316C /* BitmapText.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = BitmapText.h; path = ../src/BitmapText.h; sourceTree = ""; }; AA6EFFBD04770FFD005F316C /* Model.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Model.cpp; path = ../src/Model.cpp; sourceTree = ""; }; @@ -2974,8 +2974,8 @@ AACA592C07B5E23400763545 /* RageUtil_AutoPtr.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = RageUtil_AutoPtr.h; path = ../src/RageUtil_AutoPtr.h; sourceTree = ""; }; AACA592D07B5E23400763545 /* RageUtil_WorkerThread.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = RageUtil_WorkerThread.cpp; path = ../src/RageUtil_WorkerThread.cpp; sourceTree = ""; }; AACA592E07B5E23400763545 /* RageUtil_WorkerThread.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = RageUtil_WorkerThread.h; path = ../src/RageUtil_WorkerThread.h; sourceTree = ""; }; - AACFBE2608E7D793005087FC /* ActorSound.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ActorSound.cpp; path = ../src/ActorSound.cpp; sourceTree = ""; }; - AACFBE2708E7D793005087FC /* ActorSound.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ActorSound.h; path = ../src/ActorSound.h; sourceTree = ""; }; + AACFBE2608E7D793005087FC /* ActorSound.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ActorSound.cpp; path = ../src/Actors/ActorSound.cpp; sourceTree = ""; }; + AACFBE2708E7D793005087FC /* ActorSound.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ActorSound.h; path = ../src/Actors/ActorSound.h; sourceTree = ""; }; AACFBE3908E7D832005087FC /* InputEventPlus.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = InputEventPlus.h; path = ../src/InputEventPlus.h; sourceTree = ""; }; AACFBE4908E7D893005087FC /* ScreenGameplayLesson.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ScreenGameplayLesson.cpp; path = ../src/ScreenGameplayLesson.cpp; sourceTree = ""; }; AACFBE4A08E7D893005087FC /* ScreenGameplayLesson.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenGameplayLesson.h; path = ../src/ScreenGameplayLesson.h; sourceTree = ""; }; @@ -3094,8 +3094,8 @@ AAFC7FF00513A67700D02EE9 /* RageSoundReader_FileReader.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = RageSoundReader_FileReader.cpp; path = ../src/RageSoundReader_FileReader.cpp; sourceTree = ""; }; AAFC7FF10513A67700D02EE9 /* RageSoundReader_MP3.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = RageSoundReader_MP3.cpp; path = ../src/RageSoundReader_MP3.cpp; sourceTree = ""; }; AAFC7FF20513A67700D02EE9 /* RageSoundReader_MP3.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = RageSoundReader_MP3.h; path = ../src/RageSoundReader_MP3.h; sourceTree = ""; }; - AAFE71090A91ADE6005F2290 /* ActorProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ActorProxy.cpp; path = ../src/ActorProxy.cpp; sourceTree = ""; }; - AAFE710A0A91ADE6005F2290 /* ActorProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ActorProxy.h; path = ../src/ActorProxy.h; sourceTree = ""; }; + AAFE71090A91ADE6005F2290 /* ActorProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ActorProxy.cpp; path = ../src/Actors/ActorProxy.cpp; sourceTree = ""; }; + AAFE710A0A91ADE6005F2290 /* ActorProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ActorProxy.h; path = ../src/Actors/ActorProxy.h; sourceTree = ""; }; AAFE711C0A91B551005F2290 /* RageSurface_Save_PNG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RageSurface_Save_PNG.cpp; path = ../src/RageSurface_Save_PNG.cpp; sourceTree = ""; }; AAFE711D0A91B551005F2290 /* RoomInfoDisplay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RoomInfoDisplay.cpp; path = ../src/RoomInfoDisplay.cpp; sourceTree = ""; }; AAFE711E0A91B551005F2290 /* RoomInfoDisplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RoomInfoDisplay.h; path = ../src/RoomInfoDisplay.h; sourceTree = ""; }; From b04438a546e8d46c3178bf78e908b81a4087aaaf Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Fri, 23 Sep 2011 19:41:46 -0400 Subject: [PATCH 20/30] These Windows builds should be good. --- src/StepMania-net2003.vcproj | 28 ++++++++++++++-------------- src/StepMania-net2005.vcproj | 28 ++++++++++++++-------------- src/StepMania-net2008.vcproj | 28 ++++++++++++++-------------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/StepMania-net2003.vcproj b/src/StepMania-net2003.vcproj index d9228ee33f..e716c59613 100644 --- a/src/StepMania-net2003.vcproj +++ b/src/StepMania-net2003.vcproj @@ -2956,46 +2956,46 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ Name="Actors" Filter=""> + RelativePath="Actors\Actor.cpp"> + RelativePath="Actors\Actor.h"> + RelativePath="Actors\ActorFrame.cpp"> + RelativePath="Actors\ActorFrame.h"> + RelativePath="Actors\ActorFrameTexture.cpp"> + RelativePath="Actors\ActorFrameTexture.h"> + RelativePath="Actors\ActorMultiTexture.cpp"> + RelativePath="Actors\ActorMultiTexture.h"> + RelativePath="Actors\ActorProxy.cpp"> + RelativePath="Actors\ActorProxy.h"> + RelativePath="Actors\ActorScroller.cpp"> + RelativePath="Actors\ActorScroller.h"> + RelativePath="Actors\ActorSound.cpp"> + RelativePath="Actors\ActorSound.h"> diff --git a/src/StepMania-net2005.vcproj b/src/StepMania-net2005.vcproj index fe091bd4a3..9f0042087e 100644 --- a/src/StepMania-net2005.vcproj +++ b/src/StepMania-net2005.vcproj @@ -4654,59 +4654,59 @@ Name="Actors" > Date: Fri, 23 Sep 2011 19:41:54 -0400 Subject: [PATCH 21/30] These windows builds...well, hopefully are good. --- src/StepMania-net2010.vcxproj | 30 +++++++++++++-------------- src/StepMania-net2010.vcxproj.filters | 28 ++++++++++++------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/StepMania-net2010.vcxproj b/src/StepMania-net2010.vcxproj index 984e7164a3..213ae062f2 100644 --- a/src/StepMania-net2010.vcxproj +++ b/src/StepMania-net2010.vcxproj @@ -762,14 +762,14 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) - - - - - - - - + + + + + + + + @@ -2084,13 +2084,13 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) - - - - - - - + + + + + + + diff --git a/src/StepMania-net2010.vcxproj.filters b/src/StepMania-net2010.vcxproj.filters index 23b5698cf5..1ce13dfe16 100644 --- a/src/StepMania-net2010.vcxproj.filters +++ b/src/StepMania-net2010.vcxproj.filters @@ -1242,25 +1242,25 @@ Rage - + Actors - + Actors - + Actors - + Actors - + Actors - + Actors - + Actors @@ -2777,25 +2777,25 @@ Rage - + Actors - + Actors - + Actors - + Actors - + Actors - + Actors - + Actors From 3bd53a5cb44c1058a0f65b627d05dea2303717a4 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Fri, 23 Sep 2011 19:43:05 -0400 Subject: [PATCH 22/30] Hopefully linux is caught up. --- src/Makefile.am | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 8eb50d2100..17d251d7dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -454,12 +454,12 @@ RageUtil_AutoPtr.h \ RageUtil_WorkerThread.cpp RageUtil_WorkerThread.h Actors = \ -Actor.cpp Actor.h ActorFrame.cpp ActorFrame.h \ -ActorFrameTexture.cpp ActorFrameTexture.h \ -ActorMultiTexture.cpp ActorMultiTexture.h \ -ActorProxy.cpp ActorProxy.h \ -ActorScroller.cpp ActorScroller.h ActorUtil.cpp ActorUtil.h \ -ActorSound.cpp ActorSound.h \ +Actors/Actor.cpp Actors/Actor.h Actors/ActorFrame.cpp Actors/ActorFrame.h \ +Actors/ActorFrameTexture.cpp Actors/ActorFrameTexture.h \ +Actors/ActorMultiTexture.cpp Actors/ActorMultiTexture.h \ +Actors/ActorProxy.cpp Actors/ActorProxy.h \ +Actors/ActorScroller.cpp Actors/ActorScroller.h ActorUtil.cpp ActorUtil.h \ +Actors/ActorSound.cpp Actors/ActorSound.h \ AutoActor.cpp AutoActor.h \ BitmapText.cpp BitmapText.h Model.cpp Model.h \ DynamicActorScroller.cpp DynamicActorScroller.h \ From 83c3899c00648e488ae6de58266399959f31043c Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Fri, 23 Sep 2011 22:06:43 -0400 Subject: [PATCH 23/30] Fix loading of steps from .sm files. Some files were using non standard difficulty names that weren't being caught properly. --- Docs/Changelog_sm5.txt | 2 ++ src/NotesLoaderSM.cpp | 5 +++-- src/Song.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 0e0cbe5da2..c2a29d7965 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -11,6 +11,8 @@ StepMania 5.0 $next | 2011???? 2011/09/23 ---------- * [ScreenEvaluation] Added RollingNumbersMaxComboClass metric. [AJ] +* [NotesLoaderSM] Fix loading .sm files with non standard difficulty names. + It should be Hard, not Heavy. [Wolfman2000] 2011/09/22 ---------- diff --git a/src/NotesLoaderSM.cpp b/src/NotesLoaderSM.cpp index dd16e698e1..574a00e401 100644 --- a/src/NotesLoaderSM.cpp +++ b/src/NotesLoaderSM.cpp @@ -88,7 +88,7 @@ void SMLoader::LoadFromTokens( out.SetDescription( sDescription ); out.SetCredit( sDescription ); // this is often used for both. out.SetChartName(sDescription); // yeah, one more for good measure. - out.SetDifficulty( StringToDifficulty(sDifficulty) ); + out.SetDifficulty( OldStyleStringToDifficulty(sDifficulty) ); // Handle hacks that originated back when StepMania didn't have // Difficulty_Challenge. (At least v1.64, possibly v3.0 final...) @@ -669,7 +669,8 @@ bool SMLoader::LoadNoteDataFromSimfile( const RString &path, Steps &out ) if(!(out.m_StepsType == GAMEMAN->StringToStepsType( stepsType ) && out.GetDescription() == description && - out.GetDifficulty() == StringToDifficulty(difficulty))) + (out.GetDifficulty() == StringToDifficulty(difficulty) || + out.GetDifficulty() == OldStyleStringToDifficulty(difficulty)))) { continue; } diff --git a/src/Song.cpp b/src/Song.cpp index 181f552d83..042ac9592c 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -41,7 +41,7 @@ * @brief The internal version of the cache for StepMania. * * Increment this value to invalidate the current cache. */ -const int FILE_CACHE_VERSION = 205; +const int FILE_CACHE_VERSION = 206; /** @brief How long does a song sample last by default? */ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; From c6fff6099847e9a76f3bf4d712de0e73d3bc2159 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Fri, 23 Sep 2011 22:33:46 -0400 Subject: [PATCH 24/30] Finish the 3 decimal write out. Observation: we have two ways of writing out timing tags in NotesWriterSSC. Perhaps these should be unified soon. --- src/NotesWriterSSC.cpp | 22 +++++++++++----------- src/Song.cpp | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index a86f2f4e6a..905fb91dda 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -180,27 +180,27 @@ static void GetTimingTags( vector &lines, const TimingData &timing, boo static void WriteTimingTags( RageFile &f, const TimingData &timing, bool bIsSong = false ) { f.PutLine(ssprintf("#BPMS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_BPM)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_BPM, 3)).c_str())); f.PutLine(ssprintf("#STOPS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_STOP)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_STOP, 3)).c_str())); f.PutLine(ssprintf("#DELAYS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_DELAY)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_DELAY, 3)).c_str())); f.PutLine(ssprintf("#WARPS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_WARP)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_WARP, 3)).c_str())); f.PutLine(ssprintf("#TIMESIGNATURES:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_TIME_SIG)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_TIME_SIG, 3)).c_str())); f.PutLine(ssprintf("#TICKCOUNTS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_TICKCOUNT)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_TICKCOUNT, 3)).c_str())); f.PutLine(ssprintf("#COMBOS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_COMBO)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_COMBO, 3)).c_str())); f.PutLine(ssprintf("#SPEEDS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_SPEED)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_SPEED, 3)).c_str())); f.PutLine(ssprintf("#SCROLLS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_SCROLL)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_SCROLL, 3)).c_str())); f.PutLine(ssprintf("#FAKES:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_FAKE)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_FAKE, 3)).c_str())); f.PutLine(ssprintf("#LABELS:%s;", - join(",\r\n", timing.ToVectorString(SEGMENT_LABEL)).c_str())); + join(",\r\n", timing.ToVectorString(SEGMENT_LABEL, 3)).c_str())); } diff --git a/src/Song.cpp b/src/Song.cpp index 042ac9592c..3833519ffa 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -41,7 +41,7 @@ * @brief The internal version of the cache for StepMania. * * Increment this value to invalidate the current cache. */ -const int FILE_CACHE_VERSION = 206; +const int FILE_CACHE_VERSION = 207; /** @brief How long does a song sample last by default? */ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; From 041d59f315c61c0d2ee10976682970efab1be2fb Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Fri, 23 Sep 2011 22:51:06 -0400 Subject: [PATCH 25/30] Anyone recall WHY I had this code? Remove forced timing data copying if only one Step. --- src/Song.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Song.cpp b/src/Song.cpp index 3833519ffa..9ab0a661ac 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -920,12 +920,6 @@ void Song::Save() ReCalculateRadarValuesAndLastSecond(); TranslateTitles(); - - // TODO: Figure out a better way to save to Song's timing data. - if( m_vpSteps.size() == 1 ) - { - m_SongTiming = m_vpSteps[0]->m_Timing; - } // Save the new files. These calls make backups on their own. if( !SaveToSSCFile(GetSongFilePath(), false) ) From cdcb917e769b38cdff600c6940f923c2c0bdb51d Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Sat, 24 Sep 2011 02:01:46 -0400 Subject: [PATCH 26/30] Stop some beat 0 crash bugs in the editor. I suspect that the removal of shifting timing changes at beat 0 will stay in regardless. It is the removal of converting measures to stops/delays that may be fought against. That is fine. The bugs attached to these issues, 415 and 525, will only be resolved when enough devs agree this is a fair fix. --- Docs/Changelog_sm5.txt | 7 +++++++ src/ScreenEdit.cpp | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index c2a29d7965..b88da6b204 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,6 +8,13 @@ ________________________________________________________________________________ StepMania 5.0 $next | 2011???? -------------------------------------------------------------------------------- +2011/09/24 +---------- +* [ScreenEdit] Disable shifting timing changes down one beat if starting on + beat 0. Important information must stay on that beat. [Wolfman2000] +* [ScreenEdit] Disable converting rows to a stop or beat starting on beat 0. + There should be no reason for this at this time. [Wolfman2000] + 2011/09/23 ---------- * [ScreenEvaluation] Added RollingNumbersMaxComboClass metric. [AJ] diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 6fe4859305..5b4b637ff8 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -1739,7 +1739,8 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) break; case EDIT_BUTTON_OPEN_AREA_MENU: { - // update enabled/disabled in g_AreaMenu + // TODO: Improve behavior if timing changes are shifted down on beat 0. + g_AreaMenu.rows[shift_pauses_forward].bEnabled = (GetBeat() != 0); g_AreaMenu.rows[paste_at_current_beat].bEnabled = !m_Clipboard.IsEmpty(); g_AreaMenu.rows[paste_at_begin_marker].bEnabled = !m_Clipboard.IsEmpty() != 0 && m_NoteFieldEdit.m_iBeginMarker!=-1; g_AreaMenu.rows[paste_partial_timing_at_beat].bEnabled = !this->clipboardTiming.empty(); @@ -1757,6 +1758,9 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } else { + // TODO: Improve interaction when field is 0. + g_AlterMenu.rows[convert_to_delay].bEnabled = (m_NoteFieldEdit.m_iBeginMarker > 0); + g_AlterMenu.rows[convert_to_pause].bEnabled = (m_NoteFieldEdit.m_iBeginMarker > 0); bool isRoutine = (m_InputPlayerNumber != PLAYER_INVALID); g_AlterMenu.rows[routine_invert_notes].bEnabled = isRoutine; g_AlterMenu.rows[routine_mirror_1_to_2].bEnabled = isRoutine; From dbba5bd9347e9bb715dfec16f9e013344d13bf61 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sat, 24 Sep 2011 01:57:19 -0500 Subject: [PATCH 27/30] fix visual studio 2008 compile; will check other vs versions soonish --- src/StepMania-net2008.vcproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/StepMania-net2008.vcproj b/src/StepMania-net2008.vcproj index b416271fe8..77fd98a0e2 100644 --- a/src/StepMania-net2008.vcproj +++ b/src/StepMania-net2008.vcproj @@ -50,7 +50,7 @@ Date: Sat, 24 Sep 2011 02:18:48 -0500 Subject: [PATCH 28/30] attempt to fix ShowHoldJudgments --- Themes/_fallback/Scripts/03 Gameplay.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Themes/_fallback/Scripts/03 Gameplay.lua b/Themes/_fallback/Scripts/03 Gameplay.lua index 12254b9632..ed245c2ec7 100644 --- a/Themes/_fallback/Scripts/03 Gameplay.lua +++ b/Themes/_fallback/Scripts/03 Gameplay.lua @@ -181,11 +181,13 @@ function HoldTiming() end function ShowHoldJudgments() - return not GAMESTATE:GetCurrentGame():GetName() == "pump" + local isPump = GAMESTATE:GetCurrentGame():GetName() == "pump" + return isPump and false or true end function HoldHeadStep() - return not GAMESTATE:GetCurrentGame():GetName() == "pump" + local isPump = GAMESTATE:GetCurrentGame():GetName() == "pump" + return isPump and false or true end function InitialHoldLife() From 8dc35d157e41d023730df1bf6ebac19c4081c883 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sat, 24 Sep 2011 12:13:34 -0500 Subject: [PATCH 29/30] fix crash on ScreenRanking --- Themes/_fallback/metrics.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index df37650ed5..e03c8603e6 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -2918,7 +2918,7 @@ PageFadeSeconds=1.0 CoursesToShow=GetCoursesToShowRanking() SecondsPerPage=5 # -RankingType="Category" +RankingType="RankingType_Category" # RowSpacingX=0 RowSpacingY=60 From e1ccf9be94bc7a82b38db00d4cd07aabf11927a2 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Sat, 24 Sep 2011 15:25:17 -0400 Subject: [PATCH 30/30] How long must we support this "hack"? --- src/NotesLoaderSM.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/NotesLoaderSM.cpp b/src/NotesLoaderSM.cpp index 574a00e401..e32485ddca 100644 --- a/src/NotesLoaderSM.cpp +++ b/src/NotesLoaderSM.cpp @@ -667,6 +667,19 @@ bool SMLoader::LoadNoteDataFromSimfile( const RString &path, Steps &out ) difficulty = "Challenge"; } + /* Handle hacks that originated back when StepMania didn't have + * Difficulty_Challenge. TODO: Remove the need for said hacks. */ + if( difficulty.CompareNoCase("hard") == 0 ) + { + /* HACK: Both SMANIAC and CHALLENGE used to be Difficulty_Hard. + * They were differentiated via aspecial description. + * Account for the rogue charts that do this. */ + // HACK: SMANIAC used to be Difficulty_Hard with a special description. + if (description.CompareNoCase("smaniac") == 0 || + description.CompareNoCase("challenge") == 0) + difficulty = "Challenge"; + } + if(!(out.m_StepsType == GAMEMAN->StringToStepsType( stepsType ) && out.GetDescription() == description && (out.GetDifficulty() == StringToDifficulty(difficulty) ||