Initial commit: ROW Client source code
Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,871 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDrawXcl.cpp
|
||||
//
|
||||
// Desc: DirectShow sample code - DDraw Exclusive Mode Video Playback
|
||||
// test/sample application.
|
||||
//
|
||||
// Copyright (c) 1993-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
|
||||
#include <DVDEvCod.h>
|
||||
#include "VidPlay.h"
|
||||
#include "DDrawObj.h"
|
||||
#include "DDrawXcl.h"
|
||||
|
||||
//
|
||||
// WinMain(): Entry point to our sample app.
|
||||
//
|
||||
int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
MSG msg ;
|
||||
HACCEL hAccelTable ;
|
||||
|
||||
DbgInitialise(hInstance) ;
|
||||
|
||||
CoInitialize(NULL) ;
|
||||
|
||||
ghInstance = hInstance ;
|
||||
LoadString(ghInstance, IDS_APP_TITLE, gszAppTitle, 100) ;
|
||||
LoadString(ghInstance, IDS_APP_NAME, gszAppName, 10) ;
|
||||
|
||||
if (! InitApplication() )
|
||||
{
|
||||
DbgTerminate() ;
|
||||
return FALSE ;
|
||||
}
|
||||
|
||||
if (! InitInstance(nCmdShow) )
|
||||
{
|
||||
DbgTerminate() ;
|
||||
return FALSE ;
|
||||
}
|
||||
|
||||
hAccelTable = LoadAccelerators(hInstance, gszAppName) ;
|
||||
|
||||
//
|
||||
// Create a DDraw object and init it
|
||||
//
|
||||
gpDDrawObj = new CDDrawObject(ghWndApp) ;
|
||||
if (NULL == gpDDrawObj)
|
||||
{
|
||||
DbgTerminate() ;
|
||||
return FALSE ;
|
||||
}
|
||||
|
||||
gpPlayer = NULL ; // Init Video playback object pointer to NULL
|
||||
geVideoType = Unspecified ; // no video type specified on start up
|
||||
gbAppActive = TRUE ; // app is activated on start up
|
||||
|
||||
// Main message loop:
|
||||
while (GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
if (! TranslateAccelerator(msg.hwnd, hAccelTable, &msg) )
|
||||
{
|
||||
TranslateMessage(&msg) ;
|
||||
DispatchMessage(&msg) ;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Release the video playback object, if any
|
||||
//
|
||||
if (gpPlayer)
|
||||
delete gpPlayer ;
|
||||
|
||||
//
|
||||
// Release DDraw now
|
||||
//
|
||||
delete gpDDrawObj ;
|
||||
|
||||
CoUninitialize() ;
|
||||
|
||||
DbgTerminate() ;
|
||||
return (int) (msg.wParam) ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// InitApplication(): Registers the class if no other instance of this app is
|
||||
// already running.
|
||||
//
|
||||
BOOL InitApplication(void)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's InitApplication() entered"))) ;
|
||||
|
||||
WNDCLASSEX wc ;
|
||||
|
||||
// Win32 will always set hPrevInstance to NULL, so lets check
|
||||
// things a little closer. This is because we only want a single
|
||||
// version of this app to run at a time
|
||||
ghWndApp = FindWindow (gszAppName, gszAppTitle) ;
|
||||
if (ghWndApp) {
|
||||
// We found another version of ourself. Lets defer to it:
|
||||
if (IsIconic(ghWndApp)) {
|
||||
ShowWindow(ghWndApp, SW_RESTORE);
|
||||
}
|
||||
SetForegroundWindow(ghWndApp);
|
||||
|
||||
// If this app actually had any functionality, we would
|
||||
// also want to communicate any action that our 'twin'
|
||||
// should now perform based on how the user tried to
|
||||
// execute us.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Register the app main window class
|
||||
wc.cbSize = sizeof(wc) ;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW ;
|
||||
wc.lpfnWndProc = (WNDPROC) WndProc ;
|
||||
wc.cbClsExtra = 0 ;
|
||||
wc.cbWndExtra = 0 ;
|
||||
wc.hInstance = ghInstance ;
|
||||
wc.hIcon = LoadIcon(ghInstance, gszAppName) ;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
|
||||
wc.lpszMenuName = gszAppName ;
|
||||
wc.lpszClassName = gszAppName ;
|
||||
wc.hIconSm = NULL ;
|
||||
if (0 == RegisterClassEx(&wc))
|
||||
{
|
||||
DbgLog((LOG_ERROR, 0,
|
||||
TEXT("ERROR: RegisterClassEx() for app class failed (Error %ld)"),
|
||||
GetLastError())) ;
|
||||
return FALSE ;
|
||||
}
|
||||
|
||||
return TRUE ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// InitInstance(): Starts this instance of the app (creates the window).
|
||||
//
|
||||
BOOL InitInstance(int nCmdShow)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's InitInstance() entered"))) ;
|
||||
|
||||
ghWndApp = CreateWindowEx(0, gszAppName, gszAppTitle,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
0, 0,
|
||||
DEFAULT_WIDTH, DEFAULT_HEIGHT,
|
||||
NULL, NULL, ghInstance, NULL);
|
||||
|
||||
if (! ghWndApp ) {
|
||||
return FALSE ;
|
||||
}
|
||||
|
||||
ShowWindow(ghWndApp, nCmdShow);
|
||||
UpdateWindow(ghWndApp) ;
|
||||
|
||||
return TRUE ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MenuProc(): Handles menu choices picked by the user.
|
||||
//
|
||||
LRESULT CALLBACK MenuProc(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HMENU hMenu = GetMenu(hWnd) ;
|
||||
int wmId = LOWORD(wParam);
|
||||
// int wmEvent = HIWORD(wParam);
|
||||
|
||||
//Parse the menu selections:
|
||||
switch (wmId) {
|
||||
|
||||
case IDM_SELECTDVD:
|
||||
if (FileSelect(hWnd, DVD)) // selection changed
|
||||
{
|
||||
CheckMenuItem(hMenu, IDM_SELECTDVD, MF_CHECKED) ;
|
||||
CheckMenuItem(hMenu, IDM_SELECTFILE, MF_UNCHECKED) ;
|
||||
}
|
||||
break;
|
||||
|
||||
case IDM_SELECTFILE:
|
||||
if (FileSelect(hWnd, File)) // selection changed
|
||||
{
|
||||
CheckMenuItem(hMenu, IDM_SELECTDVD, MF_UNCHECKED) ;
|
||||
CheckMenuItem(hMenu, IDM_SELECTFILE, MF_CHECKED) ;
|
||||
}
|
||||
break;
|
||||
|
||||
case IDM_ABOUT:
|
||||
DialogBox(ghInstance, TEXT("AboutBox"), ghWndApp, (DLGPROC) About);
|
||||
break;
|
||||
|
||||
case IDM_EXIT:
|
||||
DestroyWindow(ghWndApp);
|
||||
break;
|
||||
|
||||
case IDM_STARTPLAY:
|
||||
if (StartPlay(hWnd)) // playback started successfully
|
||||
gbAppActive = TRUE ; // if we are playing, we must be active
|
||||
else // playback failed due to some reason
|
||||
MessageBox(hWnd,
|
||||
STR_EXCLUSIVE_MODE_FAILURE,
|
||||
TEXT("Error"), MB_OK | MB_ICONINFORMATION) ;
|
||||
break;
|
||||
|
||||
default:
|
||||
break ;
|
||||
}
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FileSelect(): Lets the user specify the file to play.
|
||||
//
|
||||
BOOL FileSelect(HWND hWnd, VIDEO_TYPE eType)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's FileSelect(%s) entered"),
|
||||
DVD == eType ? "DVD" : "File")) ;
|
||||
|
||||
OPENFILENAME ofn ;
|
||||
TCHAR achFileName[MAX_PATH] ;
|
||||
|
||||
// Init the filename buffer with either a filename or *.ifo
|
||||
if (DVD == eType)
|
||||
lstrcpy(achFileName, TEXT("*.ifo")) ;
|
||||
else
|
||||
lstrcpy(achFileName, TEXT("*.avi")) ;
|
||||
|
||||
ZeroMemory(&ofn, sizeof(OPENFILENAME)) ;
|
||||
ofn.lStructSize = sizeof(OPENFILENAME) ;
|
||||
ofn.hwndOwner = hWnd ;
|
||||
if (DVD == eType)
|
||||
{
|
||||
ofn.lpstrTitle = TEXT("Select DVD-Video Volume\0") ;
|
||||
ofn.lpstrFilter = TEXT("IFO Files\0*.ifo\0All Files\0*.*\0\0") ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ofn.lpstrTitle = TEXT("Select Video file\0") ;
|
||||
ofn.lpstrFilter = TEXT("AVI Files\0*.avi\0MPEG Files\0*.mpg\0All Files\0*.*\0\0") ;
|
||||
}
|
||||
ofn.nFilterIndex = 1 ;
|
||||
ofn.lpstrFile = achFileName ;
|
||||
ofn.nMaxFile = sizeof(achFileName) ;
|
||||
ofn.lpstrFileTitle = NULL ;
|
||||
ofn.nMaxFileTitle = 0 ;
|
||||
ofn.lpstrInitialDir = NULL ;
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY ;
|
||||
|
||||
if (GetOpenFileName(&ofn)) // user specified a file
|
||||
{
|
||||
if (! CreatePlayer(eType) || // creating player failed!!
|
||||
NULL == gpPlayer ) // how!?!
|
||||
{
|
||||
DbgLog((LOG_ERROR, 0, TEXT("ERROR: Couldn't create %s player"),
|
||||
DVD == eType ? "DVD" : "File")) ;
|
||||
return FALSE ;
|
||||
}
|
||||
gpPlayer->SetFileName(achFileName) ;
|
||||
return TRUE ; // user specified file name
|
||||
}
|
||||
|
||||
// Either failed or user hit Esc.
|
||||
DbgLog((LOG_TRACE, 3, TEXT("GetOpenFileName() cancelled/failed (Error %lu)"),
|
||||
CommDlgExtendedError())) ;
|
||||
return FALSE ; // DVD-Video volume not changed
|
||||
}
|
||||
|
||||
|
||||
BOOL IsVideoTypeKnown(void)
|
||||
{
|
||||
return (Unspecified != geVideoType) ;
|
||||
}
|
||||
|
||||
|
||||
VIDEO_TYPE GetVideoType(void)
|
||||
{
|
||||
return geVideoType ;
|
||||
}
|
||||
|
||||
|
||||
BOOL CreatePlayer(VIDEO_TYPE eType)
|
||||
{
|
||||
if (geVideoType == eType) // same type as before
|
||||
{
|
||||
if (gpPlayer) // we have already have the player
|
||||
return TRUE ; // we'll use the same one; everything is OK
|
||||
}
|
||||
else // video type has changed
|
||||
{
|
||||
if (gpPlayer) // we created a player before...
|
||||
{
|
||||
delete gpPlayer ; // release it now
|
||||
gpPlayer = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are here, we need to create a new player of the specified type
|
||||
if (DVD == eType)
|
||||
gpPlayer = new CDVDPlayer ;
|
||||
else if (File == eType)
|
||||
gpPlayer = new CFilePlayer ;
|
||||
else // what then??
|
||||
{
|
||||
ASSERT(FALSE) ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
geVideoType = eType ; // this our current video type
|
||||
|
||||
return TRUE ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// OnEndOfPlayback(): Releases everything on end of playback (but checks to
|
||||
// avoid doing it too many times) as it "may be" called a little more than
|
||||
// we would like to.
|
||||
//
|
||||
void OnEndOfPlayback(HWND hWndApp)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's OnEndOfPlayback() entered"))) ;
|
||||
|
||||
if (0 != guTimerID) // if any timer is still set
|
||||
{
|
||||
BOOL bRes = KillTimer(hWndApp, TIMER_ID) ; // don't need that timer anymore
|
||||
ASSERT(bRes) ; bRes = bRes; // Suppress C4189 warning
|
||||
guTimerID = 0 ; // timer released
|
||||
}
|
||||
|
||||
if (gpPlayer && gpPlayer->IsGraphReady())
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Turn off color keying before stopping the graph"))) ;
|
||||
gpDDrawObj->SetOverlayState(FALSE) ; // don't paint color key in video's position
|
||||
#ifndef NOFLIP
|
||||
gpDDrawObj->UpdateAndFlipSurfaces() ; // flip the surface so that video doesn't show anymore
|
||||
#endif // NOFLIP
|
||||
|
||||
gpPlayer->Stop() ;
|
||||
|
||||
// Remove the overlay callback interface for OverlayMixer
|
||||
HRESULT hr = gpPlayer->SetOverlayCallback(NULL) ;
|
||||
ASSERT(SUCCEEDED(hr)) ; hr = hr; // Suppress C4189 warning
|
||||
|
||||
gpPlayer->ClearGraph() ;
|
||||
}
|
||||
|
||||
if (gpDDrawObj->IsInExclusiveMode())
|
||||
{
|
||||
gpDDrawObj->StopExclusiveMode(hWndApp) ;
|
||||
|
||||
// Resize main window to default size
|
||||
SetWindowPos(ghWndApp, HWND_TOP, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// WndPorc(): Message handles for our sample app.
|
||||
//
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static HDC hDC ;
|
||||
static PAINTSTRUCT ps ;
|
||||
|
||||
switch (message) {
|
||||
|
||||
case WM_ACTIVATEAPP:
|
||||
//
|
||||
// NOTE: We don't try to recover playback on switching back into focus.
|
||||
//
|
||||
gbAppActive = (BOOL) wParam ;
|
||||
if (! gbAppActive ) // losing activation
|
||||
{
|
||||
DbgLog((LOG_TRACE, 2, TEXT("Got a WM_ACTIVATEAPP message with Active = %s"),
|
||||
gbAppActive ? "TRUE" : "FALSE")) ;
|
||||
OnEndOfPlayback(hWnd) ; // should stop playback now
|
||||
}
|
||||
break ;
|
||||
|
||||
case WM_TIMER:
|
||||
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_TIMER message with ID = %ld (Active = %s)"),
|
||||
wParam, gbAppActive ? "T" : "F")) ;
|
||||
if ( TIMER_ID != wParam || // this is not the timer we have set or
|
||||
! gbAppActive || // the app isn't active anymore or
|
||||
! gpPlayer->IsGraphReady() ) // the graph is not currently ready
|
||||
// (...but we should have turned timer off then anyway!!)
|
||||
break ; // don't do anything
|
||||
|
||||
//
|
||||
// We could do some status update here that could be used by the
|
||||
// UpdateAndFlipSurfaces() call below.
|
||||
//
|
||||
#ifndef NOFLIP
|
||||
gpDDrawObj->UpdateAndFlipSurfaces() ;
|
||||
#endif // NOFLIP
|
||||
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_COMMAND message with wParam = %ld"), wParam)) ;
|
||||
MenuProc(hWnd, wParam, lParam) ;
|
||||
break;
|
||||
|
||||
case WM_PLAY_EVENT:
|
||||
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_PLAY_EVENT message with wParam = %ld"), wParam)) ;
|
||||
if (1 == OnPlaybackEvent(hWnd, wParam, lParam)) // playback ended
|
||||
OnEndOfPlayback(hWnd) ; // do the necessary things
|
||||
break ;
|
||||
|
||||
case WM_SIZE_CHANGE:
|
||||
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_SIZE_CHANGE message"))) ;
|
||||
if (gpPlayer->IsGraphReady()) // ONLY if the graph is ready
|
||||
SetVideoPosition(FALSE) ;
|
||||
else
|
||||
DbgLog((LOG_TRACE, 1, TEXT("WARNING: Got a WM_SIZE_CHANGE message after graph was released!!"))) ;
|
||||
break ;
|
||||
|
||||
case WM_KEYUP:
|
||||
DbgLog((LOG_TRACE, 4, TEXT("Got a WM_KEYUP message with wParam = %ld"), wParam)) ;
|
||||
KeyProc(hWnd, wParam, lParam) ;
|
||||
break ;
|
||||
|
||||
case WM_DESTROY:
|
||||
OnEndOfPlayback(hWnd) ; // must stop playback before quitting
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (DefWindowProc(hWnd, message, wParam, lParam));
|
||||
}
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// KeyProc(): Handles key presses to exit playback (on Esc) or move the ball
|
||||
// using arrow keys.
|
||||
//
|
||||
LRESULT CALLBACK KeyProc(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's KeyProc() entered"))) ;
|
||||
|
||||
switch (wParam)
|
||||
{
|
||||
case VK_ESCAPE:
|
||||
OnEndOfPlayback(hWnd) ;
|
||||
break ;
|
||||
|
||||
case VK_UP:
|
||||
gpDDrawObj->MoveBallPosition(0, -BALL_STEP) ;
|
||||
break ;
|
||||
|
||||
case VK_DOWN:
|
||||
gpDDrawObj->MoveBallPosition(0, BALL_STEP) ;
|
||||
break ;
|
||||
|
||||
case VK_LEFT:
|
||||
gpDDrawObj->MoveBallPosition(-BALL_STEP, 0) ;
|
||||
break ;
|
||||
|
||||
case VK_RIGHT:
|
||||
gpDDrawObj->MoveBallPosition(BALL_STEP, 0) ;
|
||||
break ;
|
||||
|
||||
default:
|
||||
break ;
|
||||
}
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// About(): Dialog box code for the About box.
|
||||
//
|
||||
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's About() entered"))) ;
|
||||
|
||||
switch (message) {
|
||||
case WM_INITDIALOG:
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
|
||||
{
|
||||
EndDialog(hDlg, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break ;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// OnPlaybackEvent(): Handles playback events, specially completed/stopped-on-error.
|
||||
//
|
||||
// Returns 0 if playback is continuing.
|
||||
// Returns 1 if playback is over for any reason.
|
||||
//
|
||||
LRESULT OnPlaybackEvent(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5,
|
||||
TEXT("App's OnPlaybackEvent(0x%lx, 0x%lx) entered"),
|
||||
wParam, lParam)) ;
|
||||
|
||||
IMediaEventEx *pME = (IMediaEventEx *) lParam ;
|
||||
if (NULL == pME || Playing != gpPlayer->GetState())
|
||||
{
|
||||
DbgLog((LOG_TRACE, 1, TEXT("Either pME = NULL or not playing anymore. Skip everything."))) ;
|
||||
return 0 ; // or 1 ??
|
||||
}
|
||||
|
||||
LONG lEvent ;
|
||||
LONG_PTR lParam1, lParam2 ;
|
||||
|
||||
//
|
||||
// Because the message mode for IMediaEvent may not be set before
|
||||
// we get the first event it's important to read all the events
|
||||
// pending when we get a window message to say there are events pending.
|
||||
// GetEvent() returns E_ABORT when no more event is left.
|
||||
//
|
||||
while (SUCCEEDED(pME->GetEvent(&lEvent, &lParam1, &lParam2, 0))) // no wait
|
||||
{
|
||||
switch (lEvent)
|
||||
{
|
||||
//
|
||||
// First the DVD related events
|
||||
//
|
||||
case EC_DVD_STILL_ON:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_STILL_ON"))) ;
|
||||
break ;
|
||||
|
||||
case EC_DVD_STILL_OFF:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_STILL_OFF"))) ;
|
||||
break ;
|
||||
|
||||
case EC_DVD_DOMAIN_CHANGE:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_DOMAIN_CHANGE, %ld"), lParam1)) ;
|
||||
switch (lParam1)
|
||||
{
|
||||
case DVD_DOMAIN_FirstPlay: // = 1
|
||||
case DVD_DOMAIN_Stop: // = 5
|
||||
break ;
|
||||
|
||||
case DVD_DOMAIN_VideoManagerMenu: // = 2
|
||||
case DVD_DOMAIN_VideoTitleSetMenu: // = 3
|
||||
// Inform the app to update the menu option to show "Resume" now
|
||||
break ;
|
||||
|
||||
case DVD_DOMAIN_Title: // = 4
|
||||
// Inform the app to update the menu option to show "Menu" again
|
||||
break ;
|
||||
|
||||
default: // hmmmm...
|
||||
break ;
|
||||
}
|
||||
break ;
|
||||
|
||||
case EC_DVD_BUTTON_CHANGE:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("DVD Event: Button Changed to %d out of %d"),
|
||||
lParam2, lParam1));
|
||||
break;
|
||||
|
||||
case EC_DVD_TITLE_CHANGE:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_TITLE_CHANGE"))) ;
|
||||
break ;
|
||||
|
||||
case EC_DVD_CHAPTER_START:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_CHAPTER_START"))) ;
|
||||
break ;
|
||||
|
||||
case EC_DVD_CURRENT_TIME:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: EC_DVD_CURRENT_TIME"))) ;
|
||||
break ;
|
||||
|
||||
//
|
||||
// Then the general DirectShow related events
|
||||
//
|
||||
case EC_COMPLETE:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: Playback complete"))) ;
|
||||
MessageBeep(MB_OK) ; // just to inform that the playback is over
|
||||
|
||||
// Remember to free the event params
|
||||
pME->FreeEventParams(lEvent, lParam1, lParam2) ;
|
||||
|
||||
// We don't do the release part here. That will be done in WndProc()
|
||||
// after return from this function.
|
||||
return 1 ; // playback over
|
||||
|
||||
case EC_USERABORT:
|
||||
case EC_ERRORABORT:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Playback Event: 0x%lx"), lEvent)) ;
|
||||
MessageBeep(MB_ICONEXCLAMATION) ; // to inform that the playback has errored out
|
||||
|
||||
// Remember to free the event params
|
||||
pME->FreeEventParams(lEvent, lParam1, lParam2) ;
|
||||
|
||||
// We don't do the release part here. That will be done in WndProc()
|
||||
// after return from this function.
|
||||
return 1 ; // playback over
|
||||
|
||||
default:
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Ignored unknown playback event: 0x%lx"), lEvent)) ;
|
||||
break ;
|
||||
}
|
||||
|
||||
//
|
||||
// Remember to free the event params
|
||||
//
|
||||
pME->FreeEventParams(lEvent, lParam1, lParam2) ;
|
||||
|
||||
} // end of while (GetEvent()) loop
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
typedef enum _AM_TRANSFORM
|
||||
{
|
||||
AM_SHRINK,
|
||||
AM_STRETCH
|
||||
} AM_TRANSFORM ;
|
||||
|
||||
void TransformRect(RECT *prRect, double dPictAspectRatio, AM_TRANSFORM transform)
|
||||
{
|
||||
double dWidth, dHeight, dNewWidth, dNewHeight ;
|
||||
|
||||
double dResolutionRatio = 0.0, dTransformRatio = 0.0 ;
|
||||
|
||||
ASSERT(transform == AM_SHRINK || transform == AM_STRETCH) ;
|
||||
|
||||
dNewWidth = dWidth = prRect->right - prRect->left ;
|
||||
dNewHeight = dHeight = prRect->bottom - prRect->top ;
|
||||
|
||||
dResolutionRatio = dWidth / dHeight ;
|
||||
dTransformRatio = dPictAspectRatio / dResolutionRatio ;
|
||||
|
||||
// shrinks one dimension to maintain the coorect aspect ratio
|
||||
if (transform == AM_SHRINK)
|
||||
{
|
||||
if (dTransformRatio > 1.0)
|
||||
{
|
||||
dNewHeight = dNewHeight / dTransformRatio ;
|
||||
}
|
||||
else if (dTransformRatio < 1.0)
|
||||
{
|
||||
dNewWidth = dNewWidth * dTransformRatio ;
|
||||
}
|
||||
}
|
||||
// stretches one dimension to maintain the coorect aspect ratio
|
||||
else if (transform == AM_STRETCH)
|
||||
{
|
||||
if (dTransformRatio > 1.0)
|
||||
{
|
||||
dNewWidth = dNewWidth * dTransformRatio ;
|
||||
}
|
||||
else if (dTransformRatio < 1.0)
|
||||
{
|
||||
dNewHeight = dNewHeight / dTransformRatio ;
|
||||
}
|
||||
}
|
||||
|
||||
if (transform == AM_SHRINK)
|
||||
{
|
||||
ASSERT(dNewHeight <= dHeight) ;
|
||||
ASSERT(dNewWidth <= dWidth) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(dNewHeight >= dHeight) ;
|
||||
ASSERT(dNewWidth >= dWidth) ;
|
||||
}
|
||||
|
||||
// cut or add equal portions to the changed dimension
|
||||
|
||||
prRect->left += (LONG)(dWidth - dNewWidth)/2 ;
|
||||
prRect->right = prRect->left + (LONG)dNewWidth ;
|
||||
|
||||
prRect->top += (LONG)(dHeight - dNewHeight)/2 ;
|
||||
prRect->bottom = prRect->top + (LONG)dNewHeight ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SetVideoPosition(): Gets the original video size and positions it at the center.
|
||||
//
|
||||
void SetVideoPosition(BOOL bSetBallPosition)
|
||||
{
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's SetVideoPosition() entered"))) ;
|
||||
|
||||
DWORD dwVideoWidth, dwVideoHeight ;
|
||||
DWORD dwARX, dwARY ;
|
||||
gpPlayer->GetNativeVideoData(&dwVideoWidth, &dwVideoHeight, &dwARX, &dwARY) ;
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Native video size: %lu x %lu, Aspect Ratio: %lu x %lu"),
|
||||
dwVideoWidth, dwVideoHeight, dwARX, dwARY)) ;
|
||||
|
||||
// Update output size to make it aspect ratio corrected
|
||||
RECT rectCorrected ;
|
||||
SetRect(&rectCorrected, 0, 0, dwVideoWidth, dwVideoHeight) ;
|
||||
TransformRect(&rectCorrected, (double)dwARX / (double)dwARY, AM_STRETCH) ;
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Updated video size: %ld x %ld"),
|
||||
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected))) ;
|
||||
|
||||
RECT ScrnRect ;
|
||||
gpDDrawObj->GetScreenRect(&ScrnRect) ;
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Screen size is %ld x %ld"),
|
||||
RECTWIDTH(ScrnRect), RECTHEIGHT(ScrnRect))) ;
|
||||
|
||||
DWORD dwVideoTop ;
|
||||
DWORD dwVideoLeft ;
|
||||
if (RECTWIDTH(rectCorrected) <= RECTWIDTH(ScrnRect) && // video width less than screen
|
||||
RECTHEIGHT(rectCorrected) <= RECTHEIGHT(ScrnRect)) // video height less than screen
|
||||
{
|
||||
dwVideoLeft = (RECTWIDTH(ScrnRect) - RECTWIDTH(rectCorrected)) / 2 ;
|
||||
dwVideoTop = (RECTHEIGHT(ScrnRect) - RECTHEIGHT(rectCorrected)) / 2 ;
|
||||
}
|
||||
else // video width more than screen
|
||||
{
|
||||
rectCorrected = ScrnRect ;
|
||||
TransformRect(&rectCorrected, (double)dwARX / (double)dwARY, AM_SHRINK) ;
|
||||
dwVideoLeft = rectCorrected.left ;
|
||||
dwVideoTop = rectCorrected.top ;
|
||||
}
|
||||
gpDDrawObj->SetVideoPosition(dwVideoLeft, dwVideoTop,
|
||||
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected)) ;
|
||||
if (bSetBallPosition) // if ball position should be (re)set
|
||||
gpDDrawObj->SetBallPosition(dwVideoLeft, dwVideoTop,
|
||||
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected)) ;
|
||||
else // don't reset the ball position, just...
|
||||
gpDDrawObj->MoveBallPosition(0, 0) ; // ... make sure it's in the new video area
|
||||
gpPlayer->SetVideoPosition(dwVideoLeft, dwVideoTop,
|
||||
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected)) ;
|
||||
DbgLog((LOG_TRACE, 5, TEXT("Video is %ld x %ld at (%ld x %ld)"),
|
||||
RECTWIDTH(rectCorrected), RECTHEIGHT(rectCorrected), dwVideoLeft, dwVideoTop)) ;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// StartPlay(): Switches to fulscreen exclusive mode, sets up for selected media
|
||||
// playback, gets the video size and positions video at the center, starts playing
|
||||
// and sets a timer to tell WndProc() every 1/10 second.
|
||||
//
|
||||
LRESULT StartPlay(HWND hWndApp)
|
||||
{
|
||||
HRESULT hr ;
|
||||
|
||||
DbgLog((LOG_TRACE, 5, TEXT("App's StartPlay() entered"))) ;
|
||||
|
||||
if (! IsVideoTypeKnown() )
|
||||
{
|
||||
MessageBox(hWndApp,
|
||||
TEXT("No playback option (DVD/File) has been specified through the menu option yet.\nCan't run test."),
|
||||
TEXT("Sorry"), MB_OK | MB_ICONINFORMATION) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure that DShow components are installed etc so that
|
||||
// the graph building can be init-ed
|
||||
//
|
||||
if (! gpPlayer->Initialize() )
|
||||
{
|
||||
MessageBox(hWndApp,
|
||||
TEXT("DShow components couldn't be initialized.\n\nCan't run test.\nPlease check DxMedia installation"),
|
||||
TEXT("Sorry"), MB_OK | MB_ICONSTOP) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
//
|
||||
// Go into fullscreen exclusive mode
|
||||
//
|
||||
hr = gpDDrawObj->StartExclusiveMode(hWndApp) ;
|
||||
if (FAILED(hr)) // error message shown by the above method
|
||||
{
|
||||
gpPlayer->ClearGraph() ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
//
|
||||
// Build video playback graph
|
||||
//
|
||||
hr = gpPlayer->BuildGraph(hWndApp, gpDDrawObj->GetDDObject(), gpDDrawObj->GetDDPrimary()) ;
|
||||
if (FAILED(hr))
|
||||
{
|
||||
gpPlayer->ClearGraph() ;
|
||||
gpDDrawObj->StopExclusiveMode(hWndApp) ; // get out of exclusive mode
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
//
|
||||
// Specify the overlay callback interface for OverlayMixer to notify us
|
||||
//
|
||||
hr = gpPlayer->SetOverlayCallback(gpDDrawObj->GetCallbackInterface()) ;
|
||||
ASSERT(SUCCEEDED(hr)) ;
|
||||
|
||||
//
|
||||
// Pause the video playback graph to get it ready to play
|
||||
//
|
||||
BOOL bSuccess = gpPlayer->Pause() ;
|
||||
if (!bSuccess)
|
||||
{
|
||||
gpPlayer->SetOverlayCallback(NULL) ; // first remove overlay callback
|
||||
gpPlayer->ClearGraph() ; // then remove graph
|
||||
gpDDrawObj->StopExclusiveMode(hWndApp) ; // then get out of exclusive mode
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the color key info from the Player object and pass it to the DDraw object
|
||||
//
|
||||
DWORD dwVideoColorKey ;
|
||||
gpPlayer->GetColorKey(&dwVideoColorKey) ;
|
||||
gpDDrawObj->SetColorKey(dwVideoColorKey) ;
|
||||
|
||||
//
|
||||
// Get the video width and height, center it and pass the coordinates to
|
||||
// the player and the DDraw object
|
||||
//
|
||||
SetVideoPosition(TRUE) ;
|
||||
|
||||
//
|
||||
// Create the first screen on back buffer and then flip
|
||||
//
|
||||
#ifndef NOFLIP
|
||||
gpDDrawObj->UpdateAndFlipSurfaces() ;
|
||||
#endif // NOFLIP
|
||||
|
||||
//
|
||||
// Play video now...
|
||||
//
|
||||
if (! gpPlayer->Play() )
|
||||
{
|
||||
gpPlayer->SetOverlayCallback(NULL) ; // first remove overlay callback
|
||||
gpPlayer->ClearGraph() ; // then remove graph
|
||||
gpDDrawObj->StopExclusiveMode(hWndApp) ; // then get out of exclusive mode
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
//
|
||||
// Now set a timer based on which we'll update the buffers and flip
|
||||
//
|
||||
guTimerID = (UINT) SetTimer(hWndApp, TIMER_ID, TIMER_RATE, NULL) ;
|
||||
ASSERT(0 != guTimerID) ;
|
||||
|
||||
// We are done with starting the playback. WndProc will stop the playback on
|
||||
// playback event messages or user hitting Esc key as well the timer based
|
||||
// actions will be taken in WM_TIMER handler there.
|
||||
|
||||
return 1 ;
|
||||
}
|
||||
Reference in New Issue
Block a user