Download
Overview
The goal of GameX is to solve the problems that are encountered when trying to write performance-oriented, real-time games on Windows CE devices. It is also useful for other applications that need to use the CE device in a way that isn’t supported by the operating system.
Goal |
Problem |
GameX solution |
Fast, animated graphics |
GDI is too slow. In some cases way too slow. |
Direct access to the display’s frame buffer memory. Every device is different so GameX defines them. |
Use the hardware buttons on a PSPC for game controls |
Not supported by OS, trying to coerce it leads to problems. Physical location of buttons different on every device. |
Takes control of the hardware buttons. Defines optimal key maps for each device. |
Sounds |
Screen tap and key click sounds provided by the OS disrupt game sounds. |
Turns them off when application is in foreground. |
Hide the taskbar |
OS resistance. Needs to be restored properly when game not running. |
Manages hiding the taskbar and restores it to proper state when quitting or losing focus. |
Don’t disrupt normal use of the device. |
Direct screen drawing can trash pop-up notification windows, user preferences for screen taps and etc. need to be respected when game not in focus. OS doesn’t generate correct focus messages. |
Manages focus issues. Provides simple calls such as IsForeground(). |
Use the vibrate alarm as a rumble pack. |
No OS support for this. Battery state needs to be considered. |
Under development. |
Flash the backlight for special effects. |
Default value needs to be restored. Battery state needs to be considered. |
Manages the problems and provides a simple API call. |
Technical notes
A simple example
Initialize:
GameX * gpgmx = new GameX;
if (!gpgmx->OpenGraphics() || !gpgmx->OpenButtons(NULL)) {
delete gpgmx;
return;
}
Draw:
if (gpgmx->GetFBAddress() == NULL) {
GDI DRAW
} else {
unsigned long * pl = (unsigned long *)gpgmx->GetFBAddress();
long cbWidth = gpgmx->GetFBModulo();
if (gpgmx->BeginDraw()) {
draw to framebuffer
gpgmx->EndDraw();
}
}
Buttons:
if (GetASyncKeyState(gpgmx->GetDefaultButtonID(2, kiRotate0)) {
// Left button down.
} else {
// Left button up.
}
Close:
delete gpgmx; // no need to close things individually.
API Reference
Globals:
Shouldn't be an issue. FUTURE: will use a namespace to prevent conflicts.
FUTURE: trying to get rid of the globals.
glpfnOldTaskBarWndProc;
ghwndButtonNotify;
TaskBarWndProc
Don’t go messing with them!
GameX::GameX()
Constructor. Detects machine properties and sets up internal state. Future: explicit Open() call will be required as constructor is too fat.
GameX::~GameX()
Destructor. Will deallocate all resources for you. No need to call Close() on various things.
bool GameX::OpenGraphics()
Required call before using graphics.
Returns: true for success, false otherwise.
bool GameX::OpenSound()
Required call before using sound.
Returns: true for success, false otherwise.
bool GameX::CloseGraphics()
If you want to close the graphics for some reason.
Returns: true for success, false otherwise.
bool GameX::CloseSound()
If you want to close the sound for some reason.
Returns: true for success, false otherwise.
int GameX::IsForeground()
0 = Some other app foreground.
1 = Your app is foreground.
2 = Shell is foreground.
bool GameX::OpenButtons(HWND hwndButtonNotify)
For PSPC only. Required call before using button functionality. Pass the window that is to receive the WM_ messages for the buttons. NULL if none (using GetASyncKeyState() instead).
Returns: true for success, false otherwise.
bool GameX::CloseButtons()
Releases the PSPC hardware buttons.
Returns: true for success, false otherwise.
HWND GameX::SetButtonNotificationWindow(HWND hWnd)
Changes which window gets WM_ messages from the PSPC hardware buttons.
Returns: previous window.
bool GameX::IsColor()
True if this is a color device, false if not. Color is assumed to be 8 bit or above at this point. All the 2 and 4 bit devices are monochrome.
bool GameX::IsPSPC()
Is this a Palm-sized PC? Generally speaking this means a small, portrait oriented display, no keyboard, a few buttons.
bool GameX::IsHPC()
Is this an HPC? Probably 640x240, crappy little keyboard.
bool GameX::IsHPCPro()
HPCPro? 640x480 (though check for 640x240), color, maybe a mouse, a decent processor.
bool GameX::HasMouse()
True if there is a mouse currently attached.
bool GameX::HasKeyboard()
True if there is a keyboard attached. This includes external keyboards such as the one you can get for the Jornadas.
bool GameX::HasRumble()- unimplemented
True if there is a rumble pack (vibration alarm).
bool GameX::HasTouch()
True if screen is touch sensitive. Some HPC Pros don’t have a touch screen.
bool GameX::Suspend()- unimplemented
Suspends GameX functionality until a resume is called. This means no button messages, etc. Traditionally called when your app loses focus. I’m going to try to make suspend and resume ‘nice’ so that if you call resume twice or without having called suspend, etc. it won’t cause problems. Don’t count on this though.
bool GameX::Resume()- unimplemented
Resumes GameX functionality. Call when your app gets focus again.
bool GameX::BeginDraw()
Required call before drawing to the frame buffer. Not a time consuming call, but generally just call it once per update. Don’t do a BeginDraw() at the start of your program and an EndDraw() at the end.
Returns: false if unable to secure frame buffer access.
bool GameX::EndDraw()
Required call after drawing to the frame buffer.
void * GameX::GetFBAddress()
Returns a void pointer to the address of the physical frame buffer. As of this writing all frame buffers support CPU style access of this memory as bytes, shorts or longs. Many devices have 16 bit frame buffer busses so 32 bit writes are no faster than 16 bit writes. Of course you save instruction overhead with 32 bit writes and some devices do have 32 bit busses. This info is for education only, it’s still best to do 32 bit writes.
Returns: NULL if no frame buffer access.
long GameX::GetFBModulo()
Returns the number of bytes between lines in the frame buffer. This should really be called GetFBWidth(). This is not the same as the number of visible bytes in the framebuffer! Some devices might have 160 bytes that are visible but 256 bytes between lines.
long GameX::GetFBBpp()
Returns the number of bits per pixel of the frame buffer.
bool GameX::GetScreenRect(RECT * prc)
Fills the rect structure with the rectangle values of the screen. This is defined as the coordinates of a rectangle drawn with the values given by the physical frame buffer calls. Don’t assume that the left and top coordinates are 0. There could be a device in the future (e.g. a CE based phone) that has a persistent bit of UI that always needs to be displayed. This rectangle will reflect that.
unsigned long GameX::GetDisplayProperties()
Determine if display is rotated: gpgmx->GetDisplayProperties() & kfDPFormatRot270.
bool GameX::GetButton(int VK) - unimplemented
Nab a button. Currently all buttons are grabbed.
unsigned short GameX::GetDefaultButtonID(long id, long rotate)
Returns the VK code for the best button for use as specified by need and rotation. Direction defines not done yet.
gpgmx->GetDefaultButtonID(4, kiRotate0); // currently
gpgmx->GetDefaultButtonID(kfUP, kiRotate0); // planned
bool GameX::ReleaseButton(int VK) - unimplemented
All done with button grabbed with GetButton()
bool GameX::BeginDetectButtons() - unimplemented
Poor choice of name. Grabs all buttons so that a config dialog can be displayed asking the user to press the button of their choice.
bool GameX::EndDetectButtons() - unimplemented
Releases all buttons except ones already grabbed with GetButton()
bool GameX::Rumble() - unimplemented
Unimplemented.
bool GameX::Backlight(bool fOn) - unimplemented
For flashing the backlight when the player gets hit by a photon torpedo.