Что такое GAPI
GAPI (Game API)- специальный API , предназначенный для разработки приложений, которым необходим быстрый доступ к экрану , в частности, игр. GAPI позволяет получить полный доступ к видеобуферу и очереди хардверных клавиш.
На сегодняшний день, технология использования GAPI считается устаревшей, в девайсах под WM5 и WM6 используется DirectDraw Mobile и Direct3D Mobile, однако многие производители игр до сих пор используют библиотеки-надстройки над GAPI для построения своих игр.
И, поскольку поддержка GAPI в новых версиях OS сохраняется, то изучение функций GAPI не будет являться лишним.
Итак, посмотрим на список функций GAPI:
Функция | Назначение |
GXGetDisplayProperties | возвращает структуру, описывающую параметры экрана девайса |
GXGetDefaultKeys | возвращает список виртуальных кодов клавиш, используемых в девайсе |
GXOpenDisplay | открывает экран для полного доступа |
GXOpenInput | включает режим прямого доступа к сообщениям от клавиш |
GXCloseDiaplay | закрывает режим прямого досупа к экрану |
GXCloseInput | закрывает режим прямого доступа к сообщениям |
GXSuspend | останавливает работу GAPI при потере фокуса |
GXResume | продолжает работу операций GAPI при возврате фокуса |
GXBeginDraw | подготавливает экран для записи |
GXEndDraw | вызывается после завершения цикла записи |
Общий цикл работы выглядит следующим образом:
Посмотрим на реальном примере, как это делается.
1. Получение свойств экрана и начальная инициализация
// display properties
GXDisplayProperties gx_props = {0};
// keycodes list
GXKeyList g_KeyList;
// ptr to screen buffer
byte* g_pScreen = NULL;
// handle to main window
HWND hWnd;
//... InitInstance
if (GXOpenDisplay( hWnd, GX_FULLSCREEN) == 0)return FALSE;
gx_props = GXGetDisplayProperties();
GXOpenInput();
g_KeyList = GXGetDefaultKeys(GX_NORMALKEYS);
gx_props - структура описания свойств экрана. ее состав:
struct GXDisplayProperties {
DWORD cxWidth; // ширина экрана в пикселях
DWORD cyHeight; // высота экрана в пикселях
long cbxPitch; // количество байт для смещения на один пиксел
long cbyPitch; // количество байт в строке экрана
long cBPP; // число бит в пикселе
DWORD ffFormat; // цветовой формат
};
Основные форматы - RGB888 RGB555 и RGB565
Большинство девайсов используют формат RGB565 что дает максимальное количество цветов при 16 битах на пиксель.
В дальнейшем будем ориентироваться на него.
2. Деинициализация
Операции деинициализации осуществляются обычно в обработчике события WM_DESTROY:
case WM_DESTROY:
KillTimer(hWnd,100);
GXCloseInput();
GXCloseDisplay();
PostQuitMessage(0);
break;
3. Обработка клавиш
При использовании прямого доступа к сообщениям клавиш, виртуальные коды клавиш приходят в сообщении WM_KEYDOWN
case WM_KEYDOWN:
{
short vkKey = (short)wParam;
if (vkKey == g_KeyList.vkUp) MoveSprite(0,-1);
if (vkKey == g_KeyList.vkDown) MoveSprite(0,1);
if (vkKey == g_KeyList.vkLeft) MoveSprite(-1,0);
if (vkKey == g_KeyList.vkRight) MoveSprite(1,0);
if (vkKey == g_KeyList.vkStart) SendMessage (hWnd, WM_CLOSE, 0, 0);
break;
}
4. Фокус
При потере и возврате фокуса необходимо вызвать функции GAPI. Это нужно для снижения энергопотреления во время простоя.
case WM_KILLFOCUS:
GXSuspend();
break;
case WM_SETFOCUS:
GXResume();
break;
5. Рисование
Процедура рисования в самом простом случае заключается в следующем:
- Получение адреса буфера экрана
- Рассчет адреса точки
- Заполнение нужным цветом
- Уведомление системы о завершении цикла рисования
Адрес точки экрана вычисляется по формуле: address = pb + (x * cbxPitch) + (y * cbyPitch);
, где pb - адрес начала экрана; x,y - координаты точки; cbxPitch, cbyPitch - параметры экрана
Цвет точки определяется по формуле :
nColor = (WORD)(((r & 0xf8) << 8) | ((g & 0xfc)<< 3) | (b & 0xf8));
Таким образом, рисование в простейшем случае происходит так:
void PutPixel(int x, int y, int r, int g, int b)
{
WORD nColor = (WORD)(((r & 0xf8) << 8) | ((g & 0xfc)<< 3) | (b & 0xf8));
WORD* ptr = (WORD*) (g_pScreen + x * gx_props.cbxPitch + y * gx_props.cbyPitch);
*ptr = nColor;
}
void DrawFrame()
{
g_pScreen = (byte*)GXBeginDraw();
if (NULL == g_pScreen) return;
int i=1000;
while (--i)
{
int y = (rand()*gx_props.cyHeight)/RAND_MAX;
int x = (rand()*gx_props.cxWidth)/RAND_MAX;
PutPixel(x,y,rand()%255,rand()%255,rand()%255);
}
GXEndDraw();
}
Функцию DrawFrame можно вызывать по таймеру, в цикле выборки сообщений WinMain или в отдельном потоке.
Естесвенно, такой подход не оптимален и не дает высокий fps. В реальных приложениях используется технология буферизации, когда изображение подгатавливается в экранном буфере,
а затем копируется на экран одним memcpy.
Небольшим минусом работы с GAPi является отсутствие поддержки функций GDI, но в интернете существует масса библиотек-надстроек над GAPI, в которых реализованы все необходимые функции рисования.
|