First of all, I forgot to include the MainWin32 class before, so it

really didn't compile :)

And now for the changes.

1) I've updated the DirectInput class to DirectInput 8, and moved
to an event-based system, somewhat similar to SDL.  Only the
keyboard is supported for now, but adding joystick and mouse should
be quite easy.

2) I've (almost completely) moved the FrameBuffer stuff out of
MainWin32 and into FrameBufferWin32, where it actually belongs.

Next, I'll work on more code cleanups, and then I'll attempt
to switch to the experimental DirectDraw code (so we have
windowed *and* fullscreen modes dynamically).

All things considered, its coming together faster than I thought ...


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@205 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2003-11-13 00:25:07 +00:00
parent 9d2e1cfcc0
commit 24968d9976
10 changed files with 1384 additions and 964 deletions

View File

@ -13,12 +13,14 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.cxx,v 1.18 2003-11-06 22:22:32 stephena Exp $
// $Id: EventHandler.cxx,v 1.19 2003-11-13 00:25:07 stephena Exp $
//============================================================================
#include <algorithm>
#include <sstream>
#include "pch.hxx"
#include "Console.hxx"
#include "Event.hxx"
#include "EventHandler.hxx"
@ -155,7 +157,7 @@ void EventHandler::sendEvent(Event::Type event, Int32 state)
else if(event == Event::Quit)
{
myQuitStatus = !myQuitStatus;
myConsole->settings().saveConfig();
// myConsole->settings().saveConfig();
return;
}

View File

@ -50,7 +50,7 @@ LPCTSTR g_ctszDebugLog = _T("stella.log");
BOOL CCyberstellaApp::InitInstance()
{
// Delete previous Debug Log
(void)::DeleteFile(g_ctszDebugLog);
(void)::DeleteFile(g_ctszDebugLog);
// Avoid Second instance
CreateMutex(NULL,TRUE,_T("StellaXMutex"));

View File

@ -39,7 +39,7 @@
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="dxguid.lib ddraw.lib dsound.lib"
AdditionalDependencies="dxguid.lib ddraw.lib dsound.lib dinput8.lib"
OutputFile=".\Debug/Cyberstella.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"

View File

@ -118,9 +118,9 @@ BOOL CCyberstellaView::PreCreateWindow(CREATESTRUCT& cs)
void CCyberstellaView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
// Init ListControl, parse stella.pro
PostMessage(MSG_VIEW_INITIALIZE);
@ -318,65 +318,3 @@ void CCyberstellaView::playRom(LONG gameID)
// Set focus back to the rom list
m_List.SetFocus();
}
#if 0 // MainWin32
try
{
// If this throws an exception, then it's probably a bad cartridge
pConsole = new Console( pImage, dwActualSize, pszFileName, *pSettings,
*thePropertiesSet, 31400 );
if ( pConsole == NULL )
goto exit;
}
catch (...)
{
// FIXME ::MessageBox(GetModuleHandle(NULL),
// NULL, IDS_CANTSTARTCONSOLE);
goto exit;
}
#ifdef USE_FS
pwnd = new CDirectXFullScreen( m_pGlobalData, pConsole, pSound );
#else
pwnd = new CDirectXWindow( m_pGlobalData, pConsole, pSound );
#endif
if( pwnd == NULL )
goto exit;
HRESULT hr;
#ifdef USE_FS
if (m_pGlobalData->bAutoSelectVideoMode)
{
hr = pwnd->Initialize( );
}
else
{
//
// Initialize with 640 x 480
//
hr = pwnd->Initialize( FORCED_VIDEO_CX, FORCED_VIDEO_CY );
}
#else
hr = pwnd->Initialize(*this, m_List.getCurrentName());
#endif
if ( FAILED(hr) )
{
TRACE( "CWindow::Initialize failed, err = %X", hr );
goto exit;
}
if(!m_pGlobalData->bNoSound)
{
SoundWin32* pSoundWin32 = static_cast<SoundWin32*>( pSound );
hr = pSoundWin32->Initialize(*pwnd);
if(FAILED(hr))
{
TRACE( "Sndwin32 Initialize failed, err = %X", hr );
}
}
#endif

View File

@ -13,174 +13,141 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DirectInput.cxx,v 1.2 2003-11-11 18:55:39 stephena Exp $
// $Id: DirectInput.cxx,v 1.3 2003-11-13 00:25:07 stephena Exp $
//============================================================================
#define DIRECTINPUT_VERSION 0x700
#include "pch.hxx"
#include "resource.h"
#include "DirectInput.hxx"
//
// DirectInput
//
DirectInput::DirectInput(HWND hwnd, DWORD dwDevType, int nButtonCount)
: m_hwnd( hwnd )
, m_piDID(NULL)
, m_piDI(NULL)
, m_dwDevType(dwDevType)
, m_nButtonCount(nButtonCount)
, m_pButtons(NULL)
, m_lX(0)
, m_lY(0)
, m_fInitialized( FALSE )
DirectInput::DirectInput()
: myHWND(NULL),
mylpdi(NULL),
myKeyboard(NULL),
myMouse(NULL),
myLeftJoystick(NULL),
myRightJoystick(NULL)
{
TRACE("DirectInput::DirectInput");
}
DirectInput::~DirectInput(
)
DirectInput::~DirectInput()
{
TRACE("DirectInput::~DirectInput");
Cleanup();
cleanup();
}
HRESULT DirectInput::Initialize(
void
)
bool DirectInput::initialize(HWND hwnd)
{
TRACE("DirectInput::Initialize");
// FIXME - this should move to the constructor
if(FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
IID_IDirectInput8, (void**)&mylpdi, NULL)))
return false;
HINSTANCE hInstance = (HINSTANCE)::GetWindowLong( m_hwnd, GWL_HINSTANCE );
// initialize the keyboard
if(FAILED(mylpdi->CreateDevice(GUID_SysKeyboard, &myKeyboard, NULL)))
return false;
if(FAILED(myKeyboard->SetDataFormat(&c_dfDIKeyboard)))
return false;
if(FAILED(myKeyboard->SetCooperativeLevel(hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
return false;
if ( m_fInitialized )
{
return S_OK;
}
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 256;
if(FAILED(myKeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
return false;
if ( m_hwnd == NULL )
{
// This is for CDisabledJoystick
if(FAILED(myKeyboard->Acquire()))
return false;
return S_OK;
}
// Make sure to reset the event buffer
myEventBufferPos = 0;
HRESULT hr = S_OK;
UINT uMsg = 0; // if ( FAILED(hr) )
hr = ::CoCreateInstance( CLSID_DirectInput,
NULL,
CLSCTX_SERVER,
IID_IDirectInput,
(void**)&m_piDI );
if ( FAILED(hr) )
{
TRACE( "WARNING: CCI on DirectInput failed, error=%X", hr );
//
// Note -- I don't fail here so that machines with NT4 (which doesn't
// have DirectX 5.0) don't fail
//
// For this to work, Update() must begin with
// if (GetDevice() == NULL) { return E_FAIL; }
//
// uMsg = IDS_NODIRECTINPUT;
hr = S_FALSE;
goto cleanup;
}
//
// Initialize it
//
hr = m_piDI->Initialize( hInstance, DIRECTINPUT_VERSION );
if ( FAILED(hr) )
{
TRACE("IDI::Initialize failed");
uMsg = IDS_DI_INIT_FAILED;
goto cleanup;
}
//
// enumerate to find proper device
// The callback will set m_piDID
//
TRACE("\tCalling EnumDevices");
hr = m_piDI->EnumDevices( m_dwDevType,
EnumDevicesProc,
this,
DIEDFL_ATTACHEDONLY );
if ( m_piDID )
{
TRACE("\tGot a device!");
(void)m_piDID->SetCooperativeLevel( m_hwnd,
DISCL_NONEXCLUSIVE
| DISCL_FOREGROUND);
hr = GetDevice()->Acquire();
if ( hr == DIERR_OTHERAPPHASPRIO )
{
return S_FALSE;
}
}
m_pButtons = new BYTE[GetButtonCount()];
if ( m_pButtons == NULL )
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
m_fInitialized = TRUE;
cleanup:
if ( FAILED(hr) )
{
Cleanup();
if ( uMsg != 0 )
{
MessageBox( hInstance, m_hwnd, uMsg );
}
}
return hr;
return true;
}
void DirectInput::Cleanup(
void
)
void DirectInput::update()
{
TRACE("DirectInput::Cleanup");
HRESULT hr;
delete[] m_pButtons;
if(myKeyboard != NULL)
{
DIDEVICEOBJECTDATA keyEvents[256];
DWORD numKeyEvents = 256;
if (m_piDID)
{
m_piDID->Unacquire();
m_piDID->Release();
m_piDID = NULL;
}
hr = myKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
keyEvents, &numKeyEvents, 0 );
if (m_piDI)
{
m_piDI->Release();
m_piDI = NULL;
}
if(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED)
{
hr = myKeyboard->Acquire();
if(hr == DIERR_OTHERAPPHASPRIO)
return;
m_fInitialized = FALSE;
hr = myKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
keyEvents, &numKeyEvents, 0 );
}
// add these new key events to the event buffer
for(unsigned int i = 0; i < numKeyEvents; i++ )
{
uInt32 j = myEventBufferPos;
if(j < 100)
{
myEventBuffer[j].type = (keyEvents[i].dwData & 0x80) ? KEY_DOWN : KEY_UP;
myEventBuffer[j].key.key = keyEvents[i].dwOfs;
myEventBuffer[j].key.state = (myEventBuffer[j].type == KEY_DOWN) ? 1 : 0;
myEventBufferPos++;
}
else // if we run out of room, then ignore new events
{
myEventBufferPos = 100;
break;
}
}
}
// else check mouse
}
bool DirectInput::pollEvent(DI_Event* event)
{
// Pump the event buffer and return if a new event is found
if(myEventBufferPos > 0)
{
*event = myEventBuffer[--myEventBufferPos];
return true;
}
else
return false;
}
void DirectInput::cleanup()
{
if(myMouse)
{
myMouse->Unacquire();
myMouse->Release();
myMouse = NULL;
}
if(myKeyboard)
{
myKeyboard->Unacquire();
myKeyboard->Release();
myKeyboard = NULL;
}
if(mylpdi)
{
mylpdi->Release();
mylpdi = NULL;
}
}
/*
BOOL CALLBACK DirectInput::EnumDevicesProc
(
const DIDEVICEINSTANCE* lpddi,
@ -271,46 +238,6 @@ BOOL DirectInput::IsButtonPressed
// ---------------------------------------------------------------------------
DirectKeyboard::DirectKeyboard(
HWND hwnd
) : \
DirectInput( hwnd, DIDEVTYPE_KEYBOARD, 256 )
{
TRACE( "DirectKeyboard::DirectKeyboard" );
}
HRESULT DirectKeyboard::Update(
void
)
{
if ( GetDevice() == NULL )
{
return E_FAIL;
}
HRESULT hr;
GetDevice()->Poll();
hr = GetDevice()->GetDeviceState( GetButtonCount(), m_pButtons );
if ( hr == DIERR_INPUTLOST ||
hr == DIERR_NOTACQUIRED )
{
hr = GetDevice()->Acquire();
if ( hr == DIERR_OTHERAPPHASPRIO )
{
return S_FALSE;
}
TRACE( "Acquire = %X", hr );
GetDevice()->Poll();
hr = GetDevice()->GetDeviceState( GetButtonCount(), m_pButtons );
}
ASSERT(hr == S_OK && "Keyboard GetDeviceState failed");
return hr;
}
// ---------------------------------------------------------------------------
@ -546,3 +473,70 @@ HRESULT DirectMouse::Update(
return hr;
}
*/
///////////////////////////////////////
// The following was part of initialize
///////////////////////////////////////
/*
// initialize the mouse
if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &m_mouse, NULL)))
return false;
if (FAILED(m_mouse->SetCooperativeLevel(hWnd, DISCL_BACKGROUND |
DISCL_NONEXCLUSIVE)))
return false;
if (FAILED(m_mouse->SetDataFormat(&c_dfDIMouse)))
return false;
if (FAILED(m_mouse->Acquire()))
return false;
*/
/*
//
// enumerate to find proper device
// The callback will set m_piDID
//
TRACE("\tCalling EnumDevices");
hr = m_piDI->EnumDevices( m_dwDevType,
EnumDevicesProc,
this,
DIEDFL_ATTACHEDONLY );
if ( m_piDID )
{
TRACE("\tGot a device!");
(void)m_piDID->SetCooperativeLevel( m_hwnd,
DISCL_NONEXCLUSIVE
| DISCL_FOREGROUND);
hr = GetDevice()->Acquire();
if ( hr == DIERR_OTHERAPPHASPRIO )
{
return S_FALSE;
}
}
m_pButtons = new BYTE[GetButtonCount()];
if ( m_pButtons == NULL )
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
m_fInitialized = TRUE;
cleanup:
if ( FAILED(hr) )
{
Cleanup();
if ( uMsg != 0 )
{
MessageBox( hInstance, m_hwnd, uMsg );
}
}
return hr;
*/

View File

@ -13,162 +13,60 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DirectInput.hxx,v 1.3 2003-11-11 18:55:39 stephena Exp $
// $Id: DirectInput.hxx,v 1.4 2003-11-13 00:25:07 stephena Exp $
//============================================================================
#ifndef DIRECT_INPUT_HXX
#define DIRECT_INPUT_HXX
#include "bspf.hxx"
#include "dinput.h"
class DirectInput
{
public:
DirectInput( HWND hwnd, DWORD dwDevType, int nButtonCount );
virtual ~DirectInput( );
DirectInput();
~DirectInput();
public:
virtual HRESULT Initialize( void );
enum type_tt { KEY_DOWN, KEY_UP };
virtual HRESULT Update( void ) = 0;
struct KeyboardEvent
{
uInt32 key;
uInt8 state;
};
void GetPos( LONG* pX, LONG* pY ) const;
struct DI_Event
{
type_tt type;
union
{
KeyboardEvent key;
};
};
virtual BOOL IsButtonPressed( int nButton ) const;
virtual int GetButtonCount( void ) const;
bool initialize(HWND hwnd);
// I need IDID2 for the Poll method
void update();
IDirectInputDevice2* GetDevice( void ) const;
bool pollEvent(DI_Event* event);
protected:
private:
DI_Event myEventBuffer[100];
uInt32 myEventBufferPos;
LONG m_lX;
LONG m_lY;
BYTE* m_pButtons;
void cleanup();
private:
static BOOL CALLBACK EnumDevicesProc(const DIDEVICEINSTANCE* lpddi, LPVOID pvRef );
void Cleanup();
static BOOL CALLBACK EnumDevicesProc( const DIDEVICEINSTANCE* lpddi,
LPVOID pvRef );
IDirectInput* m_piDI;
HWND m_hwnd;
IDirectInputDevice2* m_piDID;
DWORD m_dwDevType;
const int m_nButtonCount;
BOOL m_fInitialized;
DirectInput( const DirectInput& ); // no implementation
void operator=( const DirectInput& ); // no implementation
};
inline int DirectInput::GetButtonCount(
void
) const
{
return m_nButtonCount;
}
inline IDirectInputDevice2* DirectInput::GetDevice(
void
) const
{
// 060499: Dont assert here, as it's okay if a device isn't available
// (client must check for NULL return)
return m_piDID;
}
inline void DirectInput::GetPos(
LONG* pX,
LONG* pY
) const
{
if (pX != NULL)
{
*pX = m_lX;
}
if (pY != NULL)
{
*pY = m_lY;
}
}
// ---------------------------------------------------------------------------
class DirectMouse : public DirectInput
{
public:
DirectMouse( HWND hwnd );
HRESULT Update( void );
private:
DirectMouse( const DirectMouse& ); // no implementation
void operator=( const DirectMouse& ); // no implementation
};
// ---------------------------------------------------------------------------
class DirectJoystick : public DirectInput
{
public:
DirectJoystick( HWND hwnd );
HRESULT Initialize( void );
HRESULT Update( void );
private:
DirectJoystick( const DirectJoystick& ); // no implementation
void operator=( const DirectJoystick& ); // no implementation
};
class CDisabledJoystick : public DirectInput
{
public:
CDisabledJoystick( HWND hwnd );
HRESULT Update( void );
private:
CDisabledJoystick( const CDisabledJoystick& ); // no implementation
void operator=( const CDisabledJoystick& ); // no implementation
};
// ---------------------------------------------------------------------------
class DirectKeyboard : public DirectInput
{
public:
DirectKeyboard( HWND hwnd );
HRESULT Update( void );
private:
DirectKeyboard( const DirectKeyboard& ); // no implementation
void operator=( const DirectKeyboard& ); // no implementation
HWND myHWND;
LPDIRECTINPUT8 mylpdi;
LPDIRECTINPUTDEVICE8 myKeyboard;
LPDIRECTINPUTDEVICE8 myMouse;
LPDIRECTINPUTDEVICE8 myLeftJoystick;
LPDIRECTINPUTDEVICE8 myRightJoystick;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferWin32.hxx,v 1.1 2003-11-11 18:55:39 stephena Exp $
// $Id: FrameBufferWin32.hxx,v 1.2 2003-11-13 00:25:07 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_WIN32_HXX
@ -25,7 +25,12 @@
class Console;
class MediaSource;
/**
This class implements a DirectX software framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferWin32.hxx,v 1.2 2003-11-13 00:25:07 stephena Exp $
*/
class FrameBufferWin32 : public FrameBuffer
{
public:
@ -39,6 +44,9 @@ class FrameBufferWin32 : public FrameBuffer
*/
virtual ~FrameBufferWin32();
HWND hwnd() const { return myHWND; }
bool windowActive() { return m_fActiveWindow; }
/**
This routine should be called once the console is created to setup
the video system for us to use. Return false if any operation fails,
@ -92,12 +100,12 @@ class FrameBufferWin32 : public FrameBuffer
virtual void postFrameUpdate();
/**
This routine is called when the emulation has been paused.
This routine is called when the emulation has received
a pause event.
@param status Toggle pause based on status
@param status The received pause status
*/
virtual void pause(bool status);
virtual void pauseEvent(bool status);
/**
Toggles between fullscreen and window mode. Grabmouse and hidecursor
activated when in fullscreen mode.
@ -114,72 +122,49 @@ class FrameBufferWin32 : public FrameBuffer
*/
void resize(int mode);
/**
Shows or hides the cursor based on the given boolean value.
*/
void showCursor(bool show);
/**
Grabs or ungrabs the mouse based on the given boolean value.
*/
void grabMouse(bool grab);
/**
Answers if the display is currently in fullscreen mode.
*/
bool fullScreen() { return isFullscreen; }
/**
Answers the current zoom level of the SDL
Answers the current zoom level of the window
*/
uInt32 zoomLevel() { return theZoomLevel; }
/**
This routine is called whenever the screen needs to be recreated.
It updates the global screen variable.
*/
bool createScreen();
/**
Calculate the maximum window size that the current screen can hold.
Only works in X11 for now. If not running under X11, always return 4.
*/
uInt32 maxWindowSizeForScreen();
/**
Set up the palette for a screen of any depth > 8.
Scales the palette by 'shade'.
*/
void setupPalette(float shade);
private:
// The SDL video buffer
// SDL_Surface* myScreen;
static LRESULT CALLBACK StaticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
static HRESULT WINAPI EnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext);
void cleanup();
HWND myHWND;
bool m_fActiveWindow;
RECT m_rectScreen;
POINT m_ptBlitOffset;
// Stella objects
SIZE mySizeGame;
BYTE myPalette[256];
//
// DirectX
//
IDirectDraw* m_piDD;
IDirectDrawSurface* m_piDDSPrimary;
IDirectDrawSurface* m_piDDSBack;
IDirectDrawPalette* m_piDDPalette;
static LPCTSTR pszClassName;
// Used in the dirty update of the SDL surface
// RectList* myRectList;
// SDL initialization flags
// uInt32 mySDLFlags;
// SDL palette
// Uint32 palette[256];
// Used to get window-manager specifics
// SDL_SysWMinfo myWMInfo;
// Indicates the current zoom level of the SDL screen
// Indicates the current zoom level of the window
uInt32 theZoomLevel;
// Indicates the maximum zoom of the SDL screen
// Indicates the maximum zoom of the window
uInt32 theMaxZoomLevel;
// Indicates if the mouse should be grabbed
bool theGrabMouseIndicator;
// Indicates if the mouse cursor should be hidden
bool theHideCursorIndicator;
// Indicates whether the game is currently in fullscreen
bool isFullscreen;
};

View File

@ -0,0 +1,427 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2002 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MainWin32.cxx,v 1.1 2003-11-13 00:25:07 stephena Exp $
//============================================================================
#define STRICT
#include "pch.hxx"
#include "resource.h"
#include "DirectInput.hxx"
#include "bspf.hxx"
#include "Console.hxx"
#include "EventHandler.hxx"
#include "FrameBuffer.hxx"
#include "FrameBufferWin32.hxx"
#include "Settings.hxx"
#include "SettingsWin32.hxx"
#include "Sound.hxx"
#include "SoundWin32.hxx"
#include "StellaEvent.hxx"
#include "MainWin32.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MainWin32::MainWin32(const uInt8* image, uInt32 size, const char* filename,
Settings& settings, PropertiesSet& properties)
: theSettings(settings),
thePropertiesSet(properties),
myIsInitialized(false),
theDisplay(NULL),
theSound(NULL),
theInput(NULL)
{
// Setup the DirectX window
theDisplay = new FrameBufferWin32();
if(!theDisplay)
{
cleanup();
return;
}
// Create a sound object for playing audio
// string driver = theSettings.getString("sound");
// if(driver != "0")
// theSound = new SoundWin32();
// else
theSound = new Sound();
/*
if(!theSound)
{
cleanup();
return;
}
*/
// theSound->setSoundVolume(theSettings.getInt("volume"));
// Create the 2600 game console
theConsole = new Console(image, size, filename, theSettings, thePropertiesSet,
*theDisplay, *theSound);
// We can now initialize the sound and directinput classes with
// the handle to the current window.
// This must be done after the console is created, since at this
// point we know that the FrameBuffer has been fully initialized
// Initialize DirectInput
theInput = new DirectInput();
if(!theInput)
{
cleanup();
return;
}
theInput->initialize(theDisplay->hwnd());
myIsInitialized = true;
}
MainWin32::~MainWin32()
{
cleanup();
}
void MainWin32::cleanup()
{
ShowCursor(TRUE);
if(theDisplay)
delete theDisplay;
if(theSound)
delete theSound;
if(theInput)
delete theInput;
if(theConsole)
delete theConsole;
myIsInitialized = false;
}
DWORD MainWin32::run()
{
if(!myIsInitialized)
return 0;
// Get the initial tick count
UINT uFrameCount = 0;
unsigned __int64 uiStartRun;
QueryPerformanceCounter( (LARGE_INTEGER*)&uiStartRun );
// Find out how many ticks occur per second
unsigned __int64 uiCountsPerSecond;
QueryPerformanceFrequency( (LARGE_INTEGER*)&uiCountsPerSecond );
const unsigned __int64 uiCountsPerFrame =
( uiCountsPerSecond / 60);// FIXME m_rGlobalData->desiredFrameRate);
unsigned __int64 uiFrameStart;
unsigned __int64 uiFrameCurrent;
// Main message loop
MSG msg;
for(;;)
{
if( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT )
{
// theConsole->eventHandler().sendEvent(Event::Quit, 1);
break;
}
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
else if (theDisplay->windowActive())
{
// idle time -- do stella updates
++uFrameCount;
::QueryPerformanceCounter( (LARGE_INTEGER*)&uiFrameStart );
UpdateEvents();
theDisplay->update();
theSound->updateSound(*theDisplay->mediaSource());
// waste time to to meet desired frame rate
for(;;)
{
QueryPerformanceCounter( (LARGE_INTEGER*)&uiFrameCurrent );
if((uiFrameCurrent - uiFrameStart) >= uiCountsPerFrame)
break;
//FIXME else
// WaitMessage();
}
}
}
// Main message loop done
/*
if ( m_rGlobalData->bShowFPS)
{
// get number of scanlines in last frame
uInt32 uScanLines = rMediaSource.scanlines();
// Get the final tick count
unsigned __int64 uiEndRun;
::QueryPerformanceCounter( (LARGE_INTEGER*)&uiEndRun );
// Get number of ticks
DWORD secs = (DWORD)( ( uiEndRun - uiStartRun ) / uiCountsPerSecond );
DWORD fps = (secs == 0) ? 0 : (uFrameCount / secs);
TCHAR pszBuf[1024];
wsprintf( pszBuf, _T("Frames drawn: %ld\nFPS: %ld\nScanlines in last frame: %ld\n"),
uFrameCount,
fps,
uScanLines );
MessageBox( NULL, pszBuf, _T("Statistics"), MB_OK );
}*/
return msg.wParam;
}
void MainWin32::UpdateEvents()
{
// Update the input devices, and gather all pending events
theInput->update();
const int nSize = _countof(keyList);
DirectInput::DI_Event event;
while(theInput->pollEvent(&event))
{
switch(event.type)
{
case DirectInput::KEY_DOWN:
case DirectInput::KEY_UP:
uInt32 key = event.key.key;
uInt8 state = event.key.state;
for(uInt32 i = 0; i < sizeof(keyList) / sizeof(Switches); ++i)
{
if(keyList[i].nVirtKey == key)
theConsole->eventHandler().sendKeyEvent(keyList[i].keyCode, state);
}
break;
}
}
//
// I do this because an event may appear multiple times in the map
// and I don't want to undo a set i may have done earlier in the loop
//
// long rgKeyEventState[ nSize ];
// ZeroMemory( rgKeyEventState, nSize * sizeof(StellaEvent::KeyCode) );
// Update keyboard
/*
if(m_pDirectKeyboard->Update() == S_OK)
{
for(int i = 0; i < nSize; ++i)
{
int state = (m_pDirectKeyboard->IsButtonPressed(keyList[i].nVirtKey)) ? 1 : 0;
theConsole->eventHandler().sendKeyEvent(keyList[i].keyCode, state);
}
}
*/
/*
//
// Update joystick
//
FIXME - add multiple joysticks
if (m_pDirectJoystick->Update() == S_OK)
{
rgEventState[Event::JoystickZeroFire] |=
m_pDirectJoystick->IsButtonPressed(0);
LONG x;
LONG y;
m_pDirectJoystick->GetPos( &x, &y );
if (x < 0)
{
rgEventState[Event::JoystickZeroLeft] = 1;
}
else if (x > 0)
{
rgEventState[Event::JoystickZeroRight] = 1;
}
if (y < 0)
{
rgEventState[Event::JoystickZeroUp] = 1;
}
else if (y > 0)
{
rgEventState[Event::JoystickZeroDown] = 1;
}
}
//
// Update mouse
//
if (m_pDirectMouse->Update() == S_OK)
{
// NOTE: Mouse::GetPos returns a value from 0..999
LONG x;
m_pDirectMouse->GetPos( &x, NULL );
// Mouse resistance is measured between 0...1000000
// rgEventState[ m_rGlobalData->PaddleResistanceEvent() ] = (999-x)*1000;
// rgEventState[ m_rGlobalData->PaddleFireEvent() ] |= m_pDirectMouse->IsButtonPressed(0);
}
//
// Write new event state
//
// for (i = 0; i < nEventCount; ++i)
// {
// m_rEvent.set( (Event::Type)i, rgEventState[i] );
// }
*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MainWin32::Switches MainWin32::keyList[StellaEvent::LastKCODE] = {
{ DIK_F1, StellaEvent::KCODE_F1 },
{ DIK_F2, StellaEvent::KCODE_F2 },
{ DIK_F3, StellaEvent::KCODE_F3 },
{ DIK_F4, StellaEvent::KCODE_F4 },
{ DIK_F5, StellaEvent::KCODE_F5 },
{ DIK_F6, StellaEvent::KCODE_F6 },
{ DIK_F7, StellaEvent::KCODE_F7 },
{ DIK_F8, StellaEvent::KCODE_F8 },
{ DIK_F9, StellaEvent::KCODE_F9 },
{ DIK_F10, StellaEvent::KCODE_F10 },
{ DIK_F11, StellaEvent::KCODE_F11 },
{ DIK_F12, StellaEvent::KCODE_F12 },
{ DIK_F13, StellaEvent::KCODE_F13 },
{ DIK_F14, StellaEvent::KCODE_F14 },
{ DIK_F15, StellaEvent::KCODE_F15 },
{ DIK_UP, StellaEvent::KCODE_UP },
{ DIK_DOWN, StellaEvent::KCODE_DOWN },
{ DIK_LEFT, StellaEvent::KCODE_LEFT },
{ DIK_RIGHT, StellaEvent::KCODE_RIGHT },
{ DIK_SPACE, StellaEvent::KCODE_SPACE },
{ DIK_LCONTROL, StellaEvent::KCODE_LCTRL },
{ DIK_RCONTROL, StellaEvent::KCODE_RCTRL },
{ DIK_LMENU, StellaEvent::KCODE_LALT },
{ DIK_RMENU, StellaEvent::KCODE_RALT },
{ DIK_LWIN, StellaEvent::KCODE_LWIN },
{ DIK_RWIN, StellaEvent::KCODE_RWIN },
{ DIK_APPS, StellaEvent::KCODE_MENU },
{ DIK_A, StellaEvent::KCODE_a },
{ DIK_B, StellaEvent::KCODE_b },
{ DIK_C, StellaEvent::KCODE_c },
{ DIK_D, StellaEvent::KCODE_d },
{ DIK_E, StellaEvent::KCODE_e },
{ DIK_F, StellaEvent::KCODE_f },
{ DIK_G, StellaEvent::KCODE_g },
{ DIK_H, StellaEvent::KCODE_h },
{ DIK_I, StellaEvent::KCODE_i },
{ DIK_J, StellaEvent::KCODE_j },
{ DIK_K, StellaEvent::KCODE_k },
{ DIK_L, StellaEvent::KCODE_l },
{ DIK_M, StellaEvent::KCODE_m },
{ DIK_N, StellaEvent::KCODE_n },
{ DIK_O, StellaEvent::KCODE_o },
{ DIK_P, StellaEvent::KCODE_p },
{ DIK_Q, StellaEvent::KCODE_q },
{ DIK_R, StellaEvent::KCODE_r },
{ DIK_S, StellaEvent::KCODE_s },
{ DIK_T, StellaEvent::KCODE_t },
{ DIK_U, StellaEvent::KCODE_u },
{ DIK_V, StellaEvent::KCODE_v },
{ DIK_W, StellaEvent::KCODE_w },
{ DIK_X, StellaEvent::KCODE_x },
{ DIK_Y, StellaEvent::KCODE_y },
{ DIK_Z, StellaEvent::KCODE_z },
{ DIK_0, StellaEvent::KCODE_0 },
{ DIK_1, StellaEvent::KCODE_1 },
{ DIK_2, StellaEvent::KCODE_2 },
{ DIK_3, StellaEvent::KCODE_3 },
{ DIK_4, StellaEvent::KCODE_4 },
{ DIK_5, StellaEvent::KCODE_5 },
{ DIK_6, StellaEvent::KCODE_6 },
{ DIK_7, StellaEvent::KCODE_7 },
{ DIK_8, StellaEvent::KCODE_8 },
{ DIK_9, StellaEvent::KCODE_9 },
{ DIK_NUMPAD0, StellaEvent::KCODE_KP0 },
{ DIK_NUMPAD1, StellaEvent::KCODE_KP1 },
{ DIK_NUMPAD2, StellaEvent::KCODE_KP2 },
{ DIK_NUMPAD3, StellaEvent::KCODE_KP3 },
{ DIK_NUMPAD4, StellaEvent::KCODE_KP4 },
{ DIK_NUMPAD5, StellaEvent::KCODE_KP5 },
{ DIK_NUMPAD6, StellaEvent::KCODE_KP6 },
{ DIK_NUMPAD7, StellaEvent::KCODE_KP7 },
{ DIK_NUMPAD8, StellaEvent::KCODE_KP8 },
{ DIK_NUMPAD9, StellaEvent::KCODE_KP9 },
{ DIK_DECIMAL, StellaEvent::KCODE_KP_PERIOD },
{ DIK_DIVIDE, StellaEvent::KCODE_KP_DIVIDE },
{ DIK_MULTIPLY, StellaEvent::KCODE_KP_MULTIPLY },
{ DIK_SUBTRACT, StellaEvent::KCODE_KP_MINUS },
{ DIK_ADD, StellaEvent::KCODE_KP_PLUS },
{ DIK_NUMPADENTER, StellaEvent::KCODE_KP_ENTER },
// { SDLK_KP_EQUALS, StellaEvent::KCODE_KP_EQUALS },
{ DIK_BACK, StellaEvent::KCODE_BACKSPACE },
{ DIK_TAB, StellaEvent::KCODE_TAB },
// { SDLK_CLEAR, StellaEvent::KCODE_CLEAR },
{ DIK_RETURN, StellaEvent::KCODE_RETURN },
{ DIK_ESCAPE, StellaEvent::KCODE_ESCAPE },
{ DIK_COMMA, StellaEvent::KCODE_COMMA },
{ DIK_MINUS, StellaEvent::KCODE_MINUS },
{ DIK_PERIOD, StellaEvent::KCODE_PERIOD },
{ DIK_SLASH, StellaEvent::KCODE_SLASH },
{ DIK_BACKSLASH, StellaEvent::KCODE_BACKSLASH },
{ DIK_SEMICOLON, StellaEvent::KCODE_SEMICOLON },
{ DIK_EQUALS, StellaEvent::KCODE_EQUALS },
{ DIK_APOSTROPHE, StellaEvent::KCODE_QUOTE },
{ DIK_GRAVE, StellaEvent::KCODE_BACKQUOTE },
{ DIK_LBRACKET, StellaEvent::KCODE_LEFTBRACKET },
{ DIK_RBRACKET, StellaEvent::KCODE_RIGHTBRACKET },
{ DIK_SYSRQ, StellaEvent::KCODE_PRTSCREEN },
{ DIK_SCROLL, StellaEvent::KCODE_SCRLOCK },
{ DIK_PAUSE, StellaEvent::KCODE_PAUSE },
{ DIK_INSERT, StellaEvent::KCODE_INSERT },
{ DIK_HOME, StellaEvent::KCODE_HOME },
{ DIK_PRIOR, StellaEvent::KCODE_PAGEUP },
{ DIK_DELETE, StellaEvent::KCODE_DELETE },
{ DIK_END, StellaEvent::KCODE_END },
{ DIK_NEXT, StellaEvent::KCODE_PAGEDOWN }
};

View File

@ -0,0 +1,211 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2002 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MainWin32.hxx,v 1.1 2003-11-13 00:25:07 stephena Exp $
//============================================================================
#ifndef MAIN_WIN32_HXX
#define MAIN_WIN32_HXX
class Console;
class FrameBufferWin32;
class MediaSource;
class PropertiesSet;
class Sound;
class Settings;
class DirectInput;
#include "GlobalData.hxx"
#include "FrameBuffer.hxx"
#include "Event.hxx"
#include "StellaEvent.hxx"
/**
This class implements a main-like method where all per-game
instantiation is done. Event gathering is also done here.
This class is meant to be quite similar to the mainDOS or mainSDL
classes so that all platforms have a main-like method as described
in the Porting.txt document
@author Stephen Anthony
@version $Id: MainWin32.hxx,v 1.1 2003-11-13 00:25:07 stephena Exp $
*/
class MainWin32
{
public:
/**
Create a new instance of the emulation core for the specified
rom image.
@param image The ROM image of the game to emulate
@param size The size of the ROM image
@param filename The name of the file that contained the ROM image
@param settings The settings object to use
@param properties The game profiles object to use
*/
MainWin32(const uInt8* image, uInt32 size, const char* filename,
Settings& settings, PropertiesSet& properties);
/**
Destructor
*/
virtual ~MainWin32();
// Start the main emulation loop
DWORD run();
private:
void UpdateEvents();
private:
// Pointer to the console object
Console* theConsole;
// Reference to the settings object
Settings& theSettings;
// Reference to the properties set object
PropertiesSet& thePropertiesSet;
// Pointer to the display object
FrameBufferWin32* theDisplay;
// Pointer to the sound object
Sound* theSound;
// Pointer to the input object
DirectInput* theInput;
struct Switches
{
uInt32 nVirtKey;
StellaEvent::KeyCode keyCode;
};
static Switches keyList[StellaEvent::LastKCODE];
/////////////////////////////////////////////////////////
//
// These will move into a separate Framebuffer class soon
//
/////////////////////////////////////////////////////////
#if 0
public:
HWND hwnd() const { return myHWND; }
//////////////////////////////////////////////////////////////////////
// The following methods are derived from FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
/**
This routine should be called once the console is created to setup
the video system for us to use. Return false if any operation fails,
otherwise return true.
*/
bool init();
/**
This routine should be called anytime the MediaSource needs to be redrawn
to the screen.
*/
void drawMediaSource();
/**
This routine should be called to draw a rectangular box with sides
at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param w The width of the box
@param h The height of the box
*/
void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
/**
This routine should be called to draw text at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param message The message text
*/
void drawText(uInt32 x, uInt32 y, const string& message);
/**
This routine should be called to draw character 'c' at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param c The character to draw
*/
void drawChar(uInt32 x, uInt32 y, uInt32 c);
/**
This routine is called before any drawing is done (per-frame).
*/
void preFrameUpdate();
/**
This routine is called after any drawing is done (per-frame).
*/
void postFrameUpdate();
/**
This routine is called when the emulation has received
a pause event.
@param status The received pause status
*/
virtual void pauseEvent(bool status);
#endif
//////////////////////////////////////////////////
// Some of this will stay here, some will go to
// the FrameBufferWin32 class
//////////////////////////////////////////////////
private:
const CGlobalData* m_rGlobalData;
bool myIsInitialized;
void cleanup();
#if 0
static LRESULT CALLBACK StaticWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
BOOL WndProc( UINT uMsg, WPARAM wParam, LPARAM lParam );
static HRESULT WINAPI EnumModesCallback( LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext);
void cleanup();
HWND myHWND;
bool m_fActiveWindow;
RECT m_rectScreen;
POINT m_ptBlitOffset;
// Stella objects
SIZE mySizeGame;
BYTE myPalette[256];
//
// DirectX
//
IDirectDraw* m_piDD;
IDirectDrawSurface* m_piDDSPrimary;
IDirectDrawSurface* m_piDDSBack;
IDirectDrawPalette* m_piDDPalette;
static LPCTSTR pszClassName;
#endif
};
#endif