2007 08 OpenKODE [Programowanie C C ]


Programowanie
C/C++
OpenKODE
Janusz Ganczarski
penKODE jest zbiorem funkcji (API) prze-
znaczonych do budowania aplikacji mul- Kody błędów
Otimedialnych i gier na urządzenia prze-
Kody błędów oparto o błędy zdefiniowane w standardach
nośne. Jednym z podstawowych założeń biblio-
C/BSD/POSIX: KD_EACCES (brak dostępu), KD_EADDRINU-
teki OpenKODE jest ułatwienie tworzenia aplika-
SE (adres jest używany), KD_EADDRNOTAVAIL (adres niedo-
cji na urządzeniach mobilnych i przenoszenia ich
stępny), KD_EAFNOSUPPORT (niewspierana rodzina adresów),
na różne platformy systemowe i sprzętowe. Doce-
KD_EAGAIN (zasoby chwilowo niedostępne), KD_EALREADY
lowo OpenKODE ma łączyć większość otwartych
(trwa połączenie), KD_EBADF (nieprawidłowy deskryptor pli-
standardów opracowanych przez Khronos Gro-
ku), KD_EBUSY (zajęte urządzenie lub zasób), KD_ECONNRE-
up  OpenGL ES (grafika trójwymiarowa), Ope-
FUSED (połączenie odrzucone), KD_ECONNRESET (połącze-
nVG (dwuwymiarowa grafika wektorowa), Open- nie zrestartowane), KD_EDESTADDRREQ (wymagany adres
MAX (multimedia) i OpenSL ES (dzwięk). Do two- docelowy), KD_EDOM (wartość argumentu funkcji poza dzie-
rzenia kontekstów graficznych w systemach udo- dziną), KD_ERANGE (wartość argumentu funkcji poza zakre-
sem), KD_EEXIST (plik istnieje), KD_EFBIG (zbyt duży rozmiar
stępniających mechanizm okien OpenKODE wyko-
pliku), KD_EHOSTUNREACH (węzeł niedostępny), KD_EINVAL
rzystuje bibliotekę EGL. Budowę aplikacji mobilnej
(błędny argument), KD_EIO (błąd wejścia-wyjścia), KD_EIL-
przed i po zastosowaniu OpenKODE przedstawia-
SEQ (niepoprawna sekwencja bajtów), KD_EISCONN (gniazdo
ją Rysunki 1 i 2.
jest już połączone), KD_EISDIR (katalog), KD_EMFILE (za du-
Artykuł został oparty o pierwszą korektę tymcza-
żo otwartych plików), KD_ENAMETOOLONG (zbyt długa nazwa
sowej specyfikacji OpenKODE, która została opubli-
pliku), KD_ENOENT (brak pliku lub katalogu), KD_ENOMEM (brak
kowana 30.03.2007r. Specyfikacja ta obecnie łączy
pamięci), KD_ENOSPC (brak wolnego miejsca na urządzeniu),
jedynie biblioteki OpenGL ES i OpenVG. Opracowa-
KD_ENOSYS (funkcja nie jest obsługiwana), KD_ENOTCONN
nie finalnej wersji standardu planowane jest na trzeci
(gniazdo nie jest połączone), KD_EOPNOTSUPP (operacja nie
kwartał 2007 roku. jest obsługiwana), KD_EOVERFLOW (nadmiar), KD_EPERM (ope-
racja nie jest możliwa), KD_EPIPE (gniazdo nie jest już połą-
czone), KD_ETIMEDOUT (przekroczony czas połączenia).
Podstawy API OpenKODE
Do opisu funkcji bibliotecznych specyfikacja OpenKO-
DE wykorzystuje język C. Znaczną część API stanowią
odpowiedniki funkcji języka C (zarówno standardu C89 nej wartości w przypadku wystąpienia błędu (ty-
jak i C99) oraz interfejsów programistycznych standar- powo jest to wartość  1 lub KD _ NULL). Ustawia-
dów BSD i POSIX. Funkcje zapożyczone z powyższych ny jest także globalny wskaznik ostatniego błędu,
standardów mają identyczne nazwy, poza charakte- który można odczytać przy pomocy funkcji kdGe-
rystycznym dla całej biblioteki OpenKODE przedrost- tError (kod błędu nie jest modyfikowany po od-
kiem kd. W głównej części artykułu skupimy się na naj- czycie) lub ustawić korzystając z funkcji kdSetEr-
ważniejszych elementach API OpenKODE, natomiast ror. Opis kodów błędów przedstawiono w ramce.
w ramkach czytelnik znajdzie krótkie opisy pozostałych Omawiana tymczasowa specyfikacja OpenKODE
funkcji, ze szczególnym uwzględnieniem elementów od- nie przewiduje wsparcia dla aplikacji wielowątko-
biegających od standardów C/BSD/POSIX. wych, dlatego obsługa błędów opiera się na glo-
Całość interfejsu programistycznego biblioteki balnym wskazniku błędu. W przypadku wprowa-
OpenKODE zawarto w pliku kd.h, który automatycznie dzenia w przyszłych wersjach OpenKODE wspar-
włącza także plik egl.h z biblioteki EGL. Podstawowe cia dla wielowątkowości, wskazniki błędu będą od-
stałe i typy danych przedstawiono w ramce. Definicje rębne dla każdego wątku.
stałych i zmiennych zależnych od platformy systemo-
wej umieszczono w odrębnym pliku kdplatform.h. Wersje i rozszerzenia
Odczyt wybranych właściwości implementacji biblio-
Obsługa błędów teki OpenKODE umożliwia funkcja:
Obsługa błędów w bibliotece OpenKODE spro-
wadza się do zwracania przez funkcje specjal- const KDchar *kdQueryAttribcv (KDint attribute)
której parametr attribute może przyjąć jedną z
Autor jest matematykiem i informatykiem
dwóch wartości: KD _ ATTRIB _ VENDOR  autor imple-
Kontakt z autorem: JanuszG@enter.net.pl
mentacji oraz KD _ ATTRIB _ VERSION  wersja bibliote-
Strona domowa: http://www.januszg.hg.pl
ki. Wersję biblioteki opisuje ciąg znaków w następu-
24
www.sdjournal.org
Software Developer s Journal 08/2007
OpenKODE
stępnych rozszerzeń biblioteki. Ilość atrybutów (w tym wypad-
ku rozszerzeń biblioteki) zwracana jest za pośrednictwem pa-
Podstawowe stałe i typy danych
rametru value.
Biblioteka OpenKODE udostępnia szereg typów liczb całkowitych o
W drugim etapie pobierane są kolejne wartości wybra-
precyzji od 8 do 64 bitów: KDchar, KDint32, KDuint32, KDint64, KDu-
nego atrybutu, do czego służy funkcja: const KDchar *kdQue-
int64, KDint16, KDuint16, KDint8, KDuint8, KDint, KDuint oraz licz-
ryIndexedAttribcv (KDint attribute, KDint index) Jak się Czy-
by zmiennoprzecinkowe KDfloat32 (standard IEEE 754). Typy KDint i
telnik domyśla, także tutaj parametr attribute może przy-
KDuint zakładają co najmniej 32 bitową precyzję. Dostępny jest tak-
jąć tylko jedną wartość KD _ ATTRIB _ EXTENSIONS określającą
że typ logiczny KDboolean, który opiera się na KDint. Warto zwrócić
pobieranie informacji o rozszerzeniach biblioteki. Numera-
uwagę na brak liczb zmiennoprzecinkowych podwójnej precyzji, co
cja poszczególnych wartości atrybutu, umieszczana w pa-
autorzy specyfikacji tłumaczą ich niewielką przydatnością w grach.
rametrze index, zaczyna się od zera. Używana w trakcie
Ponadto zdefiniowanych jest kilka typów pochodnych po ty-
pach podstawowych: KDuintptr (typ całkowity wielkości pozwa- testów biblioteka OpenKODE posiadała jedno rozszerze-
lającej na zmieszczenie wskaznika), KDsize i KDssize (typy całko- nie KD _ KHR _ staticdata. Jego dostępność oznacza, że im-
wite pozwalające na zmieszczenie rozmiaru największego obiektu
plementacja wspiera zmienne nieautomatyczne, czyli np.
w pamięci), KDsocklen (typ całkowity określający rozmiar struktu-
zmienne statyczne i globalne.
ry KDSockaddr), KDtime (typ KDint64 używany do określania liczby
Brak dostępności takich zmiennych może np. wystąpić
sekund), KDust (typ KDint64 używany do określania liczby nano-
w przypadku implementacji OpenKODE w prostych syste-
sekund), KDoff (typ KDint64 używany do określania wielkości pli-
mach wbudowanych w pamięci ROM. W trakcie opracowy-
ku lub pozycji w pliku) oraz KDmode (typ KDuint32 używany w polu
wania są dwa następne rozszerzenia biblioteki OpenKO-
st _ mode struktury KDStat).
DE: KD _ KHR _ performer i KD _ KHR _ crypto. Pierwsze roz-
Większość podstawowych stałych określa zakresy wartości
szerzenie wprowadza mechanizmy przekazujące informa-
typów podstawowych: KDINT _ MIN, KDINT _ MAX, KDUINT _ MAX,
cje o sprzęcie (np. procesor, pamięć, grafika) oraz określa-
KDINT32 _ MIN, KDINT32 _ MAX, KDUINT32 _ MAX, KDINT64 _ MIN,
KDINT64 _ MAX oraz KDUINT64 _ MAX. Zdefiniowano także odpo- jące jego wydajność.
wiedniki znanych stałych: KD _ TRUE, KD _ FALSE i KD _ NULL. Drugie z opracowywanych rozszerzeń zawiera szereg
funkcji kryptograficznych. Obsługiwany jest algorytm AES
(ang. Advanced Encryption Standard) z kluczami o długo-
jącym formacie: numer wersji, kropka, numer podwersji, spa- ści 128, 192 i 256 bitów.
cja, opcjonalne informacje o implementacji. Implementacja bi- Niektóre implementacje OpenKODE mogą wymagać po-
blioteki używana w trakcie testów zwracała następujące ciągi bierania wskazników do funkcji dostępnych w rozszerze-
znaków:  Acrodea OpenKODE / Windows oraz  1.0 Provisio- niach (podobna sytuacja ma miejsce także w przypadku bi-
nal build Feb 27 2007 . Odczyt dostępnych rozszerzeń biblio- blioteki EGL). Pobranie wskaznika do wybranej funkcji reali-
teki OpenKODE, a w przyszłości także innych atrybutów im- zuje funkcja:
plementacji, wymaga dwuetapowego działania. W pierwszym
kroku należy ustalić ilość wartości dostępnych dla danego atry- void *kdGetProcAddress (const KDchar *name)
butu, co wymaga wywołania funkcji:
Wejście i wyjście programu
KDint kdQueryAttribi (KDint attribute, KDint *value) Wejście programu realizowane jest przez funkcję:
Obecnie jedyną możliwą wartością parametru attribute jest KDint kdMain (KDint argc, const KDchar **argv)
KD _ ATTRIB _ NUM _ EXTENSIONS, który określa pobranie ilości do-
Rysunek 1. Aplikacja mobilna bez OpenKODE (zródło Rysunek 2. Aplikacja mobilna z OpenKODE (zródło Khronos
Khronos Group) Group)
Software Developer s Journal 08/2007 www.sdjournal.org
25
Programowanie
C/C++
której argumenty odpowiadają analogicznym argumentom
funkcji main w języku C. Wyjście z aplikacji zapewnia funkcja:
Funkcje narzędziowe
Do grupy funkcji narzędziowych należą funkcje w większości znane
void kdExit (KDint status)
z języka C: kdAbs, kdStrtof, kdStrtol, kdStrtoul, kdLtostr (kon-
wersja liczby całkowitej ze znakiem do ciągu znaków), kdUltostr
będąca odpowiednikiem funkcji exit z języka C.
(konwersja liczby całkowitej bez znaku do ciągu znaków), kdFtostr
(konwersja liczby zmiennoprzecinkowej do ciągu znaków) oraz
Obsługa zdarzeń
kdCryptoRandom (generowanie ciągu liczb losowych). Zauważmy,
Biblioteka OpenKODE korzysta z modelu zdarzeniowego,
że biblioteka OpenKODE nie zawiera odpowiednika funkcji sprintf
w którym aplikacja ma pojedynczy punkt wejścia zawierają-
oraz snprintf. Funkcje konwertujące liczby na ciągi znaków udostęp-
cy główną pętlę obsługi zdarzeń systemowych. Jednak moż- niają część ich możliwości. Maksymalną długość generowanych
liwe jest także korzystanie z mechanizmu funkcji wywoływa- ciągów znaków, łącznie z końcowym znakiem NULL, określają stałe:
nych zwrotnie, co ułatwia przenoszenie programów stosują- KD_LTOSTR_MAXLEN, KD_ULTOSTR_MAXLEN i KD_FTOSTR_MAXLEN.
cych tę technikę.
Przy przetwarzaniu zdarzeń wykorzystywana jest struk-
tura KDEvent, której zawartość zależy od rodzaju zdarzenia. NameLookup namelookup, KDEventWindowFocus windowfocus,
Struktura zawiera cztery pola: KDEventUser user).
" timestamp  czas wystąpienia zdarzenia (czas UST  Trzy podstawowe zdarzenia systemowe (globalne) identyfiko-
patrz ramka), wane są przez następujące stałe: KD _ EVENT _ QUIT  zakończe-
" type  rodzaj zdarzenia identyfikowany jedną ze stałych z nie działania aplikacji, KD _ EVENT _ PAUSE  zatrzymanie działa-
grupy KD _ EVENT _ *, nia aplikacji, KD _ EVENT _ RESUME  wznowienie działania aplika-
" userptr  wskaznik na dane przekazywane przy wywoła- cji. Do tej grupy należy także opisywane dalej zdarzenie wej-
niu zdarzenia, ścia-wyjścia KD _ IOGROUP _ EVENT związane z zasilaniem urządze-
" data  unia KDEventData zawierająca jedną ze struktur ob- nia. Biblioteka OpenKODE definiuje także szereg zdarzeń lokal-
sługujących konkretny rodzaj zdarzenia (KDEventInput in- nych związanych z obsługą procesów wejścia-wyjścia, gniazda-
put, KDEventInputPointer inputpointer, KDEventInput- mi sieciowymi, oknami oraz licznikiem czasu. Zdarzenia te omó-
Stick inputstick, KDEventSocketReadable socketreada- wimy nieco dalej, bądz są one przedstawione w ramkach. Obsłu-
ble, KDEventSocketWritable socketwritable; KDEventSoc- ga zdarzeń przebiega w pętli, w której zasadniczym elementem
ketError socketerror, KDEventSocketConnect socketcon- jest oczekiwanie na zajście zdarzenia. Realizuje to funkcja:
nect, KDEventSocketIncoming socketincoming, KDEvent-
const KDEvent *kdWaitEvent (KDust timeout)
która zwraca wskaznik na strukturę KDEvent opisującą zdarze-
nie. Parametr timeout określa maksymalny czas (w nanose-
kundach), w jakim następuje oczekiwanie na zdarzenie. Poda-
nie wartości -1 oznacza, że funkcja kdWaitEvent czeka tak dłu-
go, aż w kolejce zdarzeń pojawi się zdarzenie. W przypadku
wystąpienia błędu funkcja zwraca wartość KD _ NULL.
Domyślna obsługa zdarzenia nieprzetwarzanego przez
program sprowadza się do wywołania funkcji:
void kdDefaultEvent (const KDEvent *event)
Obsługa zdarzenia KD _ EVENT _ QUIT przez funkcję kdDefaultE-
vent jest równoważna wywołaniu funkcji kdExit z parametrem 0.
Zdarzenia globalne domyślnie nie generują żadnych da-
nych w polu userptr struktury KDEvent (umieszczana jest war-
tość KD _ NULL). Przekazywane za pośrednictwem tego pola
dane można określić korzystając z funkcji:
void kdSetEventUserptr (void *userptr)
Tworzenie zdarzeń
Program może umieszczać własne zdarzenia w kolejce zda-
rzeń. Mogą to być zarówno zdarzenia systemowe, jak i zda-
rzenia zdefiniowane przez użytkownika. Utworzenie zdarze-
nia wymaga wywołania funkcji:
Rysunek 3. Początkowe okno programu Tygrys KDEvent *kdCreateEvent (void)
26
www.sdjournal.org
Software Developer s Journal 08/2007
OpenKODE
Listing 1. Program Tygrys (fragmenty)
[...] break;
// program główny // obsługa wskaznika (np. myszki)
KDint kdMain (KDint argc, const KDchar **argv) { case KD_EVENT_INPUT_POINTER:
// utworzenie okna if (event -> data.inputpointer.select) {
KDWindow *window = kdCreateWindow (KD_NULL,KD_NULL); // przypadek, gdy przycisk wskaznika
// rozmiary okna // jest naciśnięty i jest w ruchu
kdSetWindowSize (window,(KDint)tigerMaxX, ż if (pointer_select) {
(KDint)tigerMaxY); // pobranie rozmiarów okna w pikselach
// tytuł okna int width,height;
kdSetWindowCaption (window,"Tygrys"); eglQuerySurface (display,window_
// wyświetlenie okna surface,EGL_WIDTH,&width);
kdShowWindow (window, KD_WINDOWSTATUS_VISIBLE); eglQuerySurface (display,window_
// sprawdzenie dostępności opcjonalnych przycisków gry surface,EGL_HEIGHT,&height);
KDint32 buffer; // przeliczenie wektora przesunięcia
kdInputPolli (KD_IO_GAMEKEYS_AVAILABILITY,9,&buffer); translatex += event ->
// włączenie obsługi przycisków gry (jeżeli przyciski data.inputpointer.x - pointer_x;
// są dostępne) translatey += pointer_y - event ->
if (buffer == 511) { data.inputpointer.y;
kdInputEventEnable (KD_IOGROUP_GAMEKEYSNC,KD_TRUE); // zapamiętanie współrzędnych położenia
} // wskaznika
// włączenie obsługi przycisków gry pointer_x = event -> data.inputpointer.x;
kdInputEventEnable (KD_IOGROUP_GAMEKEYSNC,KD_TRUE); pointer_y = event -> data.inputpointer.y;
// włączenie obsługi wskaznika } else {
kdInputEventEnable (KD_IOGROUP_POINTER,KD_TRUE); // przycisk wskaznika nie był wcześniej
[...] // naciśnięty
// struktura z opisem zdarzeń pointer_select = true;
const KDEvent *event; pointer_x = event -> data.inputpointer.x;
// dane do obsługi wskaznika pointer_y = event -> data.inputpointer.y;
KDint32 pointer_x,pointer_y; }
bool pointer_select = false; Display (display,window_surface,tiger);
// główna pętla obsługi zdarzeń } else
while ((event = kdWaitEvent (-1)) != KD_NULL) // przycisk wskaznika został zwolniony
switch (event -> type) { pointer_select = false;
// zakończenie działania aplikacji break;
case KD_EVENT_QUIT: // obsługa przycisków
case KD_EVENT_WINDOW_CLOSE: case KD_EVENT_INPUT: {
// usunięcie danych o ścieżkach // sprawdzenie stanu przycisków gry
PS_destruct (tiger); switch (event -> data.input.index) {
// porządki w bibliotece EGL // skalowanie obrazu
eglMakeCurrent (display,KD_NULL, case KD_IO_GAMEKEYSNC_A: scale = 1.0;
KD_NULL,KD_NULL); break;
eglDestroyContext (display,openvg_context); case KD_IO_GAMEKEYSNC_B: scale = 2.0;
eglDestroySurface (display,window_surface); break;
eglTerminate (display); case KD_IO_GAMEKEYSNC_C: scale = 3.0;
eglReleaseThread (); break;
// usunięcie okna case KD_IO_GAMEKEYSNC_D: scale = 4.0;
kdDestroyWindow (window); break
kdExit (0); }
break; Display (display,window_surface,tiger);
// zmiana rozmiaru okna }
case KD_EVENT_WINDOW_RESIZE: // domyślne przetworzenie pozostałych zdarzeń
Display (display,window_surface,tiger); default:
break; kdDefaultEvent (event);
// otrzymanie fokusa - odrysowanie okna break;
case KD_EVENT_WINDOW_FOCUS: }
if (event -> data.windowfocus.hasfocus) return 0; // wyjście
Display (display,window_surface,tiger); }
Software Developer s Journal 08/2007 www.sdjournal.org
27
Programowanie
C/C++
Po określeniu odpowiednich pól w strukturze KDEvent opisu-
jącej zdarzenie, umieszczenie zdarzenie w kolejce zdarzeń
Funkcje obsługujące czas
sprowadza się do wywołania funkcji:
Biblioteka OpenKODE wykorzystuje wewnętrznie czas UST (ang.
KDint kdPostEvent (KDEvent *event) unadjusted system time) zliczający ilość nanosekund, które upłynę-
ły od północy 1 stycznia 1970 roku. Odczyt bieżącego czasu UST
Usunięcie struktury KDEvent umożliwia funkcja:
umożliwia funkcja kdGetTimeUST. Czas UST przechowywany jest
void kdFreeEvent (KDEvent *event)
w liczbach typu KDust (czyli KDint64). Dostępna jest również funk-
cja kdTime, która pobiera uniwersalny czas koordynowany (UTC),
Dla zdarzeń tworzonych przez użytkownika biblioteka Open-
przechowywany w liczbach typu KDtime (także KDint64). Konwer-
KODE rezerwuje identyfikatory o wartościach z przedziału od
sję czasu UTC na czas uniwersalny GMT oraz czas lokalny reali-
KD _ EVENT _ USER do KDINT32 _ MAX. Dane zdarzenia użytkowni-
zują funkcje kdGmtime_r i kdLocaltime_r. Funkcje te korzystają
ka przechowywane są w strukturze typu KDEventUser. Struktu-
ze struktury KDtm, która zawiera pola: m_sec, tm_min, tm_hour, tm_
ra ta zawiera dwie unie value1 i value23, o wielkościach liczb
mday, tm_mon, tm_year, tm_wday, tm_yday i tm_isdst, w pełni od-
typu KDint64, których wewnętrzna budowa pozwala na różno-
powiadające polom struktury tm z języka C. Wszystkie pola są typu
rodne wykorzystanie.
całkowitego KDint32.
Ostatnią funkcją z opisywanej grupy jest kdUSTAtEpoch, która
zwraca czas UST odpowiadający początkowi epoki (czyli północy
Zdarzenia
1 stycznia 1970 roku) czasu UTC. Wynik (liczba typu KDust) mo-
a funkcje wywoływane zwrotnie
że mieć wartość ujemną. Funkcja kdUSTAtEpoch ułatwia konwer-
Dołączenie lub odłączenie funkcji wywoływanej zwrotnie, ob-
sję pomiędzy czasem UST i UTC.
sługującej wybraną grupę zdarzeń, wymaga użycia funkcji:
KDint kdInstallCallback (KDCallbackFunc *func, KDint eventtype,
void *eventuserptr) W sytuacji, gdy funkcja zwrotna nie obsługuje części otrzy-
mywanych zdarzeń, powinna zastosować domyślną obsługę
Przypadki, gdy do obsługi zdarzenia lub grupy zdarzeń będzie zdarzenia wywołując kdDefaultEvent. W przeciwnym wypadku
wywoływana funkcja zwrotna wskazana w parametrze func, informacja o danym zdarzeniu zostanie utracona i usunięta z
określa kombinacja wartości parametrów eventtype i eventu- kolejki zdarzeń.
serptr. Pierwszy z tych parametrów określa rodzaj zdarzenia, a Jeżeli jakieś zdarzenie lub grupa zdarzeń obsługiwana
drugi wartość wskaznika na dane przekazywane przy wywoły- jest przez funkcje wywoływane zwrotnie, nie są one zgłasza-
waniu zdarzeń (odpowiada to parametrowi eventuserptr przeka- ne przy wywołaniu kdWaitEvent. W przypadku, gdy wszystkie
zywanego np. przy niektórych funkcjach). Podanie wartości 0 w zdarzenia obsługiwane są w ten sposób, główna pętla prze-
miejscu parametru eventtype oznacza obsługę wszystkich zda- twarzania zdarzeń będzie wyglądała następująco:
rzeń, natomiast podanie wartości KD _ NULL dla parametru eventu-
serptr oznacza obsługę przez funkcję dowolnej wartości wskaz- KDEvent *event;
nika na dane przekazywane przy wywoływaniu zdarzeń. Ten pro- while ((event = kdWaitEvent (-1)) != KD_NULL)
sty mechanizm pozwala przykładowo na łatwe wyodrębnienie kdDefaultEvent (event);
funkcji zwrotnych obsługujących różne okna aplikacji. Funkcja wy-
woływana zwrotnie musi być zgodna z następującym typem: Usprawnienie obsługi zdarzeń przez funkcje wywoływane
zwrotnie umożliwia funkcja:
typedef void (KDCallbackFunc) (const KDEvent *event)
KDint kdPumpEvents (void)
która wykonuje takie przemieszczenie zdarzeń w kolejce (ang.
event pump), aby w pierwszej kolejności obsługiwane były zda-
rzenia odpowiadające zarejestrowanym funkcjom zwrotnym.
Pozostałe zdarzenia umieszczane są w dalszej części kolejki.
Zdarzenia wejścia-wyjścia
Biblioteka OpenKODE zawiera obsługę szeregu lokalnych
(działających na poziomie części API biblioteki) zdarzeń wej-
ścia-wyjścia umożliwiających interakcję z użytkownikiem.
Zdarzenia te są podzielone na grupy identyfikowane następu-
jącymi stałymi:
" KD _ IOGROUP _ GAMEKEYS  przyciski obsługujące gry (z ob-
sługą wielu przycisków jednocześnie),
" KD _ IOGROUP _ GAMEKEYSNC  przyciski obsługujące gry (bez
obsługi wielu przycisków jednocześnie),
" KD _ IOGROUP _ PHONEKEYPAD  przyciski telefonu,
Rysunek 4. Początkowe okno programu Sześcian " KD _ IOGROUP _ POINTER  wskaznik (np. myszka),
28
www.sdjournal.org
Software Developer s Journal 08/2007
OpenKODE
Grupa ta jest identyfikowana stałą KD _ IOGROUP _ EVENT i nale-
Funkcje narodowe i językowe żą do niej dwa zdarzenia wejściowe: KD _ IO _ EVENT _ USING _
BATTERY  informacja o pracy na bateriach (dane binarne, war-
Generalnie biblioteka OpenKODE nie zawiera wsparcia dla obsługi
tość 1  urządzenie korzysta z baterii, wartość 0  urządzenie
programów wielojęzycznych. Możliwe jest jednak odczytanie bieżą-
korzysta z zasilania głównego) oraz KD _ IO _ EVENT _ LOW _ BAT-
cego języka oraz kraju, a także strefy czasowej. Język (norma ISO
TERY  informacja o niskim poziomie naładowania baterii (dane
639-1) oraz kod kraju (norma ISO 3166-1 alpha 2), oddzielone zna-
binarne, wartość 1  niski stan naładowania baterii, wartość 0
kiem podkreślenia, zwraca funkcja kdGetLocale. Na przykład dla
 baterie naładowane).
Polski będzie to  pl_PL . Odczyt bieżącej strefy czasowej, określo-
Poza funkcjami z grup kdInputPoll dane związane ze zda-
nej jako przesunięcie w stosunku do uniwersalnego czasu koordy-
rzeniami wejściowymi można odczytywać korzystając z infor-
nowanego (UTC), umożliwia funkcja kdGetTzOffset.
macji umieszczanych w strukturze KDEvent. W tym celu wszyst-
kie zdarzenia podzielone są na trzy rodzaje: KD _ EVENT _ IN-
" KD _ IOGROUP _ JOGDIAL  pokrętło jog dial, PUT _ POINTER  zdarzenie związane ze wskaznikiem, KD _
" KD _ IOGROUP _ JOYSTICK  dżojstik, EVENT _ INPUT _ STICK  zdarzenie związane z dżojstikiem oraz
" KD _ IOGROUP _ VIBRATE  wibracja, KD _ EVENT _ INPUT  pozostałe zdarzenia wejściowe. Z każ-
" KD _ IOGROUP _ BACKLIGHT  podświetlenie. dym rodzajem zdarzenia wejściowego związane są inne da-
ne umieszczane w polu data (unii) struktury KDEvent. Są to od-
Dla zdarzeń wejścia-wyjścia zależnych od implementacji specy- powiednio struktury: KDEventInputPointer inputpointer, KDE-
fikacja OpenKODE rezerwuje indeksy z przedziału KD _ IO _ UN- ventInputStick inputstick oraz KDEventInput input. W każ-
DEFINED  KDINT32 _ MAX. Włączenie lub wyłączenie obsługi wy- dej z powyższych grup zdarzeń zawartość pola userptr struk-
branej grupy zdarzeń wejściowych wymaga wywołania funkcji: tury KDEvent zależy od tego, czy jedno z okien aplikacji posiada
fokus. Jeżeli tak, to przekazywana jest tam wartość parametru
KDint kdInputEventEnable (KDint idx, KDint enable) eventuserptr funkcji tworzącej okno. Jeżeli żadne okno nie po-
siada fokusa, przekazywana jest wartość KD _ NULL.
Parametr idx określa rodzaj grupy zdarzeń i przyjmuje jedną z Struktura KDEventInput zawiera dwa pola. Pierwsze pole index
wymienionych wcześniej wartości identyfikującą grupę, a para- (typ KDint32) określa rodzaj zdarzenia wejściowego. Drugie pole
metr enable określa czy obsługa wskazanej grupy zdarzeń ma value zawiera unię przechowującą jedną z liczb typu: KDint32 (po-
zostać włączona (KD _ TRUE) czy wyłączona (KD _ FALSE). Zdarze- le value.i), KDint64 (pole value.l) lub KDfloat32 (pole value.f), które
nia wejścia-wyjścia mogą generować cztery rodzaje informacji: są używane w zależności od rodzaju danych zwracanych przez
binarne (tylko wejście), KDint32 (wejście i wyjście), KDint64 (tyl- zdarzenie. Stałe opisujące zdarzenia wejściowe oraz zwracane
ko wejście) oraz KDfloat32 (wejście i wyjście). Próbkowanie stanu przez te zdarzenia dane opisano w dalszej części tekstu.
wybranych wejść z danej grupy zdarzeń wejścia-wyjścia umożli- Struktura KDEventInputPointer zawiera cztery liczby typu
wiają funkcje z grupy kdInputPoll (odrębnie dla każdego rodza- KDint32. Pole index określa rodzaj zdarzenia wejściowego, po-
ju danych wejściowych), pokazane są one na Listingu 2. Para- le select zawiera stan przycisku wskaznika (1  przycisk naci-
metr startidx określa numer pierwszego odpytywanego zdarze- śnięty, 0  przycisk zwolniony), a dwa ostatnie pola x i y prze-
nia, a parametr numidxs ilość kolejnych odpytywanych zdarzeń z chowują współrzędne położenia wskaznika.
danej grupy zdarzeń. Nie ma możliwości jednorazowego odczy- Ostatnia opisywana struktura KDEventInputStick także za-
tania danych zdarzeń pochodzących z różnych grup lub zdarzeń wiera cztery pola typu KDint32. Pole index zawiera numer (in-
z jednej grypy, które zwracają różnego rodzaju informacje. Od- deks) dżojstika, który wygenerował zdarzenie wejściowe, a
czytane dane umieszczane są w buforze wskazywanym w pa- trzy pozostałe pola x, y i z określają kąty obrotu drążka w kie-
rametrze buffer. Na programie ciąży obowiązek zapewnienia ta- runku osi X, Y i Z (opcjonalnie).
kiej ilości miejsca w buforze, aby pomieścić wszystkie pobierane
dane. Analogiczne parametry posiadają funkcje z grupy kdOut- Grupy zdarzeń wejścia-wyjścia
putSet, które odpowiadają za generowanie zdarzeń wyjściowych: Grupa zdarzeń KD _ IOGROUP _ GAMEKEYS związana jest z
przyciskami obsługującymi gry, przy czym możliwa jest ob-
KDint kdOutputSeti (KDint startidx, KDuint numidxs, ż sługa wielu jednocześnie naciśniętych przycisków. Biblio-
const KDint32 *buffer) teka OpenKODE implementuje przyciski dostępne w stan-
KDint kdOutputSetf (KDint startidx, KDuint numidxs, ż dardzie Java MIDP2, czyli w praktyce przyciski dostępne w
const KDfloat32 *buffer)
Listing 2. Funkcje z grupy kdInputPoll
Zestawienie zdarzeń związanych z poszczególnymi grupami
zdarzeń wejścia-wyjścia przedstawiono w dalszej części ar- KDint kdInputPollb (KDint startidx, KDuint numidxs, ż
tykułu. Oczywiście od implementacji i specyfiki systemu oraz KDint32 *buffer)
sprzętu zależy, które grupy zdarzeń wejścia-wyjścia są do- KDint kdInputPolli (KDint startidx, KDuint numidxs, ż
stępne dla programu. Także w ramach niektórych grup zda- KDint32 *buffer)
rzeń wejścia-wyjścia nie wszystkie zdarzenia muszą być ob- KDint kdInputPolll (KDint startidx, KDuint numidxs, ż
sługiwane przez implementację. Sprawdzenie wszystkich tych KDint64 *buffer)
zależności umożliwiają funkcji z grupy kdInputPoll. KDint kdInputPollf (KDint startidx, KDuint numidxs, ż
Ponadto jest jeszcze grupa zdarzeń wejścia-wyjścia na- KDfloat32 *buffer)
leżąca do zdarzeń występujących na poziomie całej aplikacji.
Software Developer s Journal 08/2007 www.sdjournal.org
29
Programowanie
C/C++
zane są dane binarne: 0 (przycisk zwolniony) i 1 (przy-
Funkcje obsługi pamięci oraz pamięci cisk naciśnięty). Zapytanie o dostępność przycisków tele-
fonu identyfikowane jest poprzez zdarzenie KD _ IO _ PHONE-
lokalnej wątków (TLS)
KEYPAD _ AVAILABILITY, a dane zwracane są w zmiennej typu
Obsługę pamięci w OpenKODE zapewniają funkcje: kdMalloc,
KDint32. Minimalna zwrócona wartość to 0xfff (dostępne
kdFree i kdRealloc, które są odpowiednikami funkcji malloc, free
przyciski podstawowe), wartość maksymalna 0x3fff (do-
i realloc z języka C. Jedyna różnica polega na zgłaszaniu przez
stępne wszystkie przyciski).
kdMalloc i kdRealloc błędu KD_ENOMEM przy braku pamięci (funkcje
Grupa zdarzeń związanych z wibracją, identyfikowana
C nie modyfikowały wartości errno).
stałą KD _ IOGROUP _ VIBRATE, zawiera zarówno zdarzenia wej-
Wprawdzie obecna tymczasowa specyfikacja OpenKODE nie
ściowe jak i wyjściowe.
wspiera wielowątkowości, to jednak zdefiniowane zostały dwie
Wyjście to głośność wibracji (stała KD _ IO _ VIBRATE _
funkcje obsługujące pamięć lokalną. Są to: kdGetTLS (pobranie
VOLUME) i dostępna opcjonalnie jej częstotliwość (stała KD _
wskaznika do pamięci lokalnej) i kdSetTLS (zapis wskaznika do
pamięci lokalnej). W przypadku wprowadzenia obsługi wielowąt- IO _ VIBRATE _ FREQUENCY). Obie wartości opisują dane ty-
kowości, obie funkcje będą działały w pamięci lokalnej wątków. pu KDint32, przy czym głośność wyrażana jest liczbami z
przedziału od 0 (cisza) do 1000 (maksymalna głośność), a
częstotliwość określana jest w mHz (przykładowo 25.000
urządzeniach przenośnych. Przyciski można podzielić na oznacza 25Hz). Zdarzenia wejściowe są opcjonalne i zwra-
dwie grupy: obowiązkowe (góra, lewo, prawo, dół, strzał) cają informacje o minimalnej (stała KD _ IO _ VIBRATE _ MIN-
oraz opcjonalne (A, B, C i D). Odpowiadają im następujące FREQUENCY) i maksymalnej (stała KD _ IO _ VIBRATE _ MAXFRE-
zdarzenia: KD _ IO _ GAMEKEYS _ UP, KD _ IO _ GAMEKEYS _ LEFT, QUENCY) dostępnej częstotliwości wibracji. Obie wartości
KD _ IO _ GAMEKEYS _ RIGHT, KD _ IO _ GAMEKEYS _ DOWN, KD _ IO _ opisywane są liczbami typu KDint32 i wyrażane w mHz.
GAMEKEYS _ FIRE, KD _ IO _ GAMEKEYS _ A, KD _ IO _ GAMEKEYS _ Zdarzenie związane z zapytaniem o dostępne zdarzenia z
B, KD _ IO _ GAMEKEYS _ C i KD _ IO _ GAMEKEYS _ D. Z przyciska- grupy KD _ IOGROUP _ VIBRATE identyfikowane jest stałą KD _
mi związane są dane binarne: 0 (przycisk zwolniony) i 1 IO _ VIBRATE _ AVAILABILITY. Ponieważ opcjonalne zdarzenia
(przycisk naciśnięty). Zapytanie o dostępność przycisków z tej grupy związane z częstotliwością wibracji muszą być
obsługujących gry identyfikowane jest poprzez zdarze- dostępne wspólnie (nie ma możliwości, aby implementacja
nie: KD _ IO _ GAMEKEYS _ AVAILABILITY, a dane zwracane są obsługiwała tylko jedno lub dwa), dane binarne zwracane
w zmiennej typu KDint32. Minimalna zwrócona wartość to w wyniku zdarzenia KD _ IO _ VIBRATE _ AVAILABILITY, zawar-
31, co odpowiada dostępności podstawowych przycisków, te w liczbie typu KDint32, mogą przyjąć wyłącznie wartość
maksymalna 511, gdy wszystkie przyciski są dostępne. 9 (brak obsługi częstotliwości wibracji) lub 31 (dostępność
Analogiczną funkcję do grupy KD _ IOGROUP _ GAMEKEYS obsługi częstotliwości wibracji).
spełnia następna grupa zdarzeń wejścia-wyjścia obsługu- Kolejną grupą zdarzeń wejścia-wyjścia są zdarzenia
jąca przyciski gry, która identyfikowana jest stałą KD _ IO- związane ze wskaznikiem (stała KD _ IOGROUP _ POINTER). Za
GROUP _ GAMEKEYSNC. Jedyna różnica w stosunku do pierwszej pośrednictwem zdarzeń z tej grupy mogą być obsługiwane
grupy polega na braku obsługi wielu przycisków jednocze- różnego rodzaju urządzenia wskazujące, np. ekran dotyko-
śnie. Zdarzenia związane z przyciskami, wśród których tak- wy, mysz albo gładzik (ang. trackpad). Warto zauważyć, że
że występuje podział na obowiązkowe i opcjonalne, iden- rozważane jest utworzenie wydzielonej grupy zdarzeń prze-
tyfikowane są stałymi: KD _ IO _ GAMEKEYSNC _ UP, KD _ IO _ GA- znaczonych wyłącznie do obsługi myszki. Z obsługą wskaz-
MEKEYSNC _ LEFT, KD _ IO _ GAMEKEYSNC _ RIGHT, KD _ IO _ GAME- nika związane są trzy zdarzenia wejściowe identyfikowane
KEYSNC _ DOWN, KD _ IO _ GAMEKEYSNC _ FIRE, KD _ IO _ GAMEKEY- stałymi: KD _ IO _ POINTER _ X, KD _ IO _ POINTER _ Y oraz KD _
SNC _ A, KD _ IO _ GAMEKEYSNC _ B, KD _ IO _ GAMEKEYSNC _ C i KD _ IO _ POINTER _ SELECT. Pierwsze dwa to współrzędne położe-
IO _ GAMEKEYSNC _ D. Zapytanie o dostępność przycisków z tej nia wskaznika określane liczbami typu KDint32. Używane są
grupy identyfikowane jest zdarzeniem KD _ IO _ GAMEKEYSNC _
AVAILABILITY. Zarówno zwracane dane związane z przyci-
skami, jak i z zapytaniem o ich dostępność są takie same
jak w przypadku poprzednio opisanej grupy zdarzeń KD _ IO-
GROUP _ GAMEKEYS.
Kolejną grupą zdarzeń wejścia-wyjścia są zdarze-
nia związane z przyciskami telefonu identyfikowane stałą
KD _ IOGROUP _ PHONEKEYPAD. Do przycisków telefonu zalicza
się klawisze 0  9, *, # oraz dwa opcjonalne przyciski (le-
wy i prawy) umieszczone pod wyświetlaczem. Wymienio-
ne przyciski związane są ze zdarzeniami opisanymi sta-
łymi: KD _ IO _ PHONEKEYPAD _ 0, KD _ IO _ PHONEKEYPAD _ 1, KD _
IO _ PHONEKEYPAD _ 2, KD _ IO _ PHONEKEYPAD _ 3, KD _ IO _ PHO-
NEKEYPAD _ 4, KD _ IO _ PHONEKEYPAD _ 5, KD _ IO _ PHONEKEYPAD _
6, KD _ IO _ PHONEKEYPAD _ 7, KD _ IO _ PHONEKEYPAD _ 8, KD _ IO _
PHONEKEYPAD _ 9, KD _ IO _ PHONEKEYPAD _ STAR, KD _ IO _ PHO-
NEKEYPAD _ HASH, KD _ IO _ PHONEKEYPAD _ LEFTSOFT oraz KD _
IO _ PHONEKEYPAD _ RIGHTSOFT. Z przyciskami telefonu zwią- Rysunek 5. Efekt działania programu Quadric
30
www.sdjournal.org
Software Developer s Journal 08/2007
OpenKODE
współrzędne kartezjańskie, gdzie przestrzeń robocza okna
odzwierciedla pierwszą ćwiartkę układu, a zakresy zwraca-
Funkcje matematyczne
nych współrzędnych zawierają się od zera do odpowiednio
pomniejszonej o jeden wysokości lub szerokości okna mie- OpenKODE udostępnia typowe funkcje matematyczne, w zdecy-
dowanej większości znane ze standardowych bibliotek języka C lub
rzonego w pikselach. Trzecie zdarzenie KD _ IO _ POINTER _ SE-
standardu POSIX: kdAcosf, kdAsinf, kdAtanf, kdAtan2f, kdCosf,
LECT zwraca stan przycisku wskaznika w postaci danej binar-
kdSinf, kdTanf, kdExpf, kdLogf, kdFabsf, kdPowf, kdSqrtf, kdCe-
nej o dwóch możliwych wartościach: 1 (przycisk wskaznika
ilf, kdFloorf, kdRoundf, kdInvsqrtf (odwrotność pierwiastka
przyciśnięty) i 0 (przycisk wskaznika zwolniony). Zauważmy,
kwadratowego) i kdFmodf. Wszystkie powyższe funkcje przyjmują i
że OpenKODE udostępnia obsługę tylko jednego przycisku
zwracają liczby typu KDfloat32. Ponadto API zawiera definicje wie-
wskaznika. Nie ma także możliwości sprawdzenia dostęp-
lu typowych stałych przydatnych w obliczeniach matematycznych:
ności wskaznika. Następna grupa zdarzeń wejścia-wyjścia to
KD_E_F, KD_PI_F, KD_PI_2_F, KD_2PI_F, KD_LOG2E_F, KD_LOG10E_
podświetlenie ekranu identyfikowane stałą KD _ IOGROUP _ BAC-
F, KD_LN2_F, KD_LN10_F, KD_PI_4_F, KD_1_PI_F, KD_2_PI_F, KD_2_
KLIGHT. W tej grupie znajduje się jedno zdarzenie wyjściowe
SQRTPI_F, KD_SQRT2_F, KD_SQRT1_2_F, KD_MAXFLOAT (największa
(stała KD _ IO _ BACKLIGHT _ FORCE), które określa stopień pod- liczba zmiennoprzecinkowa), KD_INFINITY (nieskończoność  ilo-
raz 1.0F/0.0F), KD_NAN (symbol nieoznaczony  iloraz 0.0F/0.0F),
świetlenia ekranu za pomocą liczby typu KDint32. Wartość 0
KD_HUGE_VALF (nieskończoność  iloraz 1.0F/0.0F), KD_DEG_TO_
oznacza domyślne podświetlenie (jest to wartość początko-
RAD_F i KD_RAD_TO_DEG_F.
wa), wartość niezerowa wymusza włączenie podświetlenia.
Nie ma możliwości sprawdzenia dostępności podświetlenia.
Obsługą pokrętła jog dial zajmują się zdarzenia z grupy KD _
IOGROUP _ JOGDIAL. Pokrętło opisane jest czterema przyciskami ciski, 1 kapturek oraz 1 kulkę. Ponadto zarezerwowane są
kierunkowymi: góra, lewo (opcjonalny), prawo (opcjonalny), numery indeksów zdarzeń umożliwiające obsługę dodatko-
dół oraz przyciskiem selekcji, które identyfikowane są po- wych 63 dżojstików, przy czym każdy może zawierać takie
przez następujące zdarzenia wejściowe: KD _ IO _ JOGDIAL _ UP, same ilości elementów jak pierwszy dżojstik. Odczyt danych
KD _ IO _ JOGDIAL _ LEFT, KD _ IO _ JOGDIAL _ RIGHT, KD _ IO _ JOG- dżojstika umożliwiają następujące zdarzenia wejściowe:
DIAL _ DOWN i KD _ IO _ JOGDIAL _ SELECT. Wszystkie te zdarzenia KD _ IO _ JOYSTICK _ NUMSTICKS, KD _ IO _ JOYSTICK _ NUMBUTTONS,
generują dane binarne, gdzie wartość 1 oznacza naciśnięcie KD _ IO _ JOYSTICK _ NUMHATS oraz KD _ IO _ JOYSTICK _ NUMBALLS,
przycisku, a 0 zwolnienie przycisku. Zapytanie o dostępność które zwracają dane w liczbach typu KDint32.
pokrętła jog dial identyfikowane jest poprzez zdarzenie: KD _ Kolejne zdarzenia wejściowe związane z obsługą po-
IO _ JOGDIAL _ AVAILABILITY, gdzie dane zwracane są w zmien- jedynczego drążka w dżojstiku opisują następujące stałe:
nej typu KDint32. Przy dostępności wszystkich przycisków KD _ IO _ JOYSTICK _ STICK _ NUMAXES  ilość osi obrotu drążka
zwracana jest wartość 31, w pozostałych przypadkach bę- (2 lub 3, liczba KDint32), KD _ IO _ JOYSTICK _ X, KD _ IO _ JOY-
dzie to wartość 25. STICK _ Y, KD _ IO _ JOYSTICK _ Z  kąty obrotu drążka w kie-
Ostatnią grupą zdarzeń wejścia-wyjścia są zdarzenia runku osi X, Y i opcjonalnie Z (liczby KDint32, zakres war-
związane z obsługą dżojstika (lub dżojstików) opisane stałą tości od -32768 do 32767), KD _ IO _ JOYSTICK _ HAT _ UP, KD _
KD _ IOGROUP _ JOYSTICK. W bibliotece OpenKODE dżojstik za- IO _ JOYSTICK _ HAT _ LEFT, KD _ IO _ JOYSTICK _ HAT _ RIGHT, KD _
wiera następujące elementy: jeden lub więcej drążków (ang. IO _ JOYSTICK _ HAT _ DOWN  stan przycisków kapturka (dane
sticks) z dwiema lub trzema osiami obrotu, jeden lub więcej binarne: wartość 1 przycisk naciśnięty, wartość 0 przycisk
przycisków (ang. buttons), zero lub więcej kapturków (ang. zwolniony), KD _ IO _ JOYSTICK _ BALL _ X, KD _ IO _ JOYSTICK _
hats) oraz zero lub więcej kulek (ang. balls). OpenKODE BALL _ Y  skumulowany obrót kulki w kierunku osi X i Y
może obsłużyć dżojstik posiadający maksymalnie 16 drąż- (dane KDint32 z przedziału od KDINT32 _ MIN do KDINT32 _
ków, 512 przycisków, 16 kapturków oraz 16 kulek, przy zało- MAX) oraz KD _ IO _ JOYSTICK _ BUTTON  stan pierwszego przy-
żeniu, że pojedynczy drążek posiada maksymalnie 32 przy- cisku (dane binarne: wartość 1 przycisk naciśnięty, war-
tość 0 przycisk zwolniony). Dane następnych przycisków
identyfikowane są zdarzeniami o kolejnych numerach za-
czynających się od stałej KD _ IO _ JOYSTICK _ BUTTON.
Zdarzenia związane z kolejnymi drążkami pierwszego
dżojstika identyfikowane są opisanymi wyżej stałymi powięk-
szonymi o wartość KD _ IO _ JOYSTICK _ STRIDE (wartość 64). Na-
tomiast zdarzenia związane z kolejnymi dżojstikami identyfi-
kowane będą także powyższymi stałymi, ale powiększonymi
o wartość 0x400.
Gniazda sieciowe
Model obsługi gniazd sieciowych biblioteka OpenKODE
przejęła ze standardów BSD i POSIX, przy czym zmieniono
składnię i nazwy części funkcji. Zasadnicza różnica polega
na wykorzystaniu zdarzeń przy obsłudze gniazd, stąd część
funkcji działa w trybie asynchronicznym (nie blokującym).
Mniejsza jest także ilość obsługiwanych protokołów komu-
Rysunek 6. Gra WakeBreaker nikacyjnych. Aktualnie OpenKODE wspiera wyłącznie ko-
Software Developer s Journal 08/2007 www.sdjournal.org
31
Programowanie
C/C++
munikację w dziedzinie Internetu  protokoły TCP (transmi-
sja połączeniowa) i UDP (transmisja bezpołączeniowa), oba
Funkcje operujące na ciągach znaków
działające na IPv4. Możliwe jednak, że w przyszłych wer-
Większość funkcji OpenKODE operujących na ciągach znaków
sjach biblioteka OpenKODE wzbogaci się o obsługę innych
ma swoje odpowiedniki w bibliotekach standardowych języka C:
protokołów komunikacyjnych.
kdMemchr, kdMemcmp, kdMemcpy, kdMemmove, kdMemset, kdStrchr,
Odpowiednikami funkcji obsługujących gniazda sieciowe
kdStrcmp, kdStrlen, kdStrnlen (długość ciągu znaków z ograni-
w standardach BSD/POSIX są następujące funkcje bibliote-
czeniem maksymalnym), kdStrncat_s (łączenie ciągów znaków
ki OpenKODE: kdNameLookup (gethostbyname), kdSocketCreate
z ograniczeniem maksymalnej długości), kdStrncmp, kdStrcpy_s i
(socket), kdSocketBind (bind), kdSocketGetName (getsockname),
kdStrncpy_s (kopiowanie ciągów znaków z ograniczeniem maksy-
kdSocketConnect (connect), kdSocketListen (listen), kdSocke-
malnym). Funkcje z przyrostkiem _s są bezpieczniejszymi wersjami
tAccept (accept), kdSocketSend (send), kdSocketSendTo (send- standardowych funkcji języka C.
to), kdSocketRecv (recv) oraz kdSocketRecvFrom (recvfrom).
W nawiasach podano nazwy funkcji BSD/POSIX. Bibliote-
ka OpenKODE zawiera także odpowiedniki wybranych funk- SOCK _ TCP  protokół TCP i KD _ SOCK _ UDP  protokół UDP.
cji narzędziowych BSD/POSIX przydatnych przy obsłudze Gniazdo w bibliotece OpenKODE identyfikowane jest po-
gniazd sieciowych. Są to: kdHtonl (htonl), kdHtons (htons), przez strukturę KDSocket. Struktura ta nie jest jednak zgod-
kdNtohl (ntohl), kdNtohs (ntohs), kdInetAton (inet _ aton) oraz na ze strukturą KDFile identyfikującą plik, stąd na gniazdach
kdInetNtoa (inet _ ntoa). W nawiasach znajdują się oczy- nie są dopuszczalne typowe operacje plikowe. Z tego także
wiście nazwy funkcji BSD/POSIX. Wspomniane wcześniej powodu OpenKODE zawiera odrębną funkcję kdSocketClose,
rodzaje protokołów połączeniowych określają stałe: KD _ której zadaniem jest zamknięcie gniazda. Drugą niestandar-
Listing 3. Program Sześcian (fragmenty)
[...] kdSetWindowCaption (window,"Sześcian");
// obsługa przycisków gry // wyświetlenie okna
void KeyHandler (const KDEvent *event) kdShowWindow (window,KD_WINDOWSTATUS_VISIBLE);
{ // włączenie obsługi przycisków gry
// pobranie stanu przycisków kierunkowych kdInputEventEnable (KD_IOGROUP_GAMEKEYSNC,KD_TRUE);
KDint32 keys; // dowiązanie funkcji zwrotnej obsługującej przyciski gry
kdInputPollb (KD_IO_GAMEKEYS_UP,4,&keys); kdInstallCallback (KeyHandler,KD_EVENT_INPUT,KD_NULL);
// KD_IO_GAMEKEYSNC_UP // włączenie obsługi wskaznika
if (keys & 0x01) kdInputEventEnable (KD_IOGROUP_POINTER,KD_TRUE);
rotatex -= 5.0; [...]
// KD_IO_GAMEKEYSNC_LEFT // utworzenie licznika czasu sterującego wyświetleniem
if (keys & 0x02) sceny 3D
rotatey -= 5.0; KDTimer *timer = kdSetTimer (0,KD_TIMER_ONESHOT,KD_NULL);
// KD_IO_GAMEKEYSNC_RIGHT // struktura z opisem zdarzeń
if (keys & 0x04) const KDEvent *event;
rotatey += 5.0; // dane do obsługi wskaznika
// KD_IO_GAMEKEYSNC_DOWN KDint32 pointer_x,pointer_y;
if (keys & 0x08) bool pointer_select = false;
rotatex += 5.0; // główna pętla obsługi zdarzeń
// przycisk strzału - wyjście z programu while ((event = kdWaitEvent (-1)) != KD_NULL)
if (event -> data.input.index == KD_IO_GAMEKEYSNC_FIRE) switch (event -> type)
{ {
// utworzenie i sygnalizacja zdarzenia [...]
KDEvent *ev = kdCreateEvent (); // wyświetlenie zawartości sceny 3D
ev -> type = KD_EVENT_QUIT; case KD_EVENT_TIMER:
kdPostEvent (ev); kdCancelTimer (timer);
} Reshape (display,window_surface);
} Display (display,window_surface);
// program główny timer = kdSetTimer (0,KD_TIMER_ONESHOT,KD_NULL);
KDint kdMain (KDint argc, const KDchar **argv) break;
{ [...]
// utworzenie okna }
KDWindow *window = kdCreateWindow (KD_NULL,KD_NULL); // wyjście
// rozmiary okna return 0;
kdSetWindowSize (window,500,500); }
// tytuł okna
32
www.sdjournal.org
Software Developer s Journal 08/2007
OpenKODE
" KD _ EVENT _ SOCKET _ CONNECT _ COMPLETE  zdarzenie gene-
rowane po ukończeniu połączenia gniazda (funkcje kdSoc-
Funkcje licznika czasu
ketConnect, kdSocketListen i kdSocketAccept),
" KD _ EVENT _ NAME _ LOOKUP _ COMPLETE  zakończenie pobie-
OpenKODE obsługuje wiele liczników czasu, zarówno wywoływa-
nych jednorazowo jak i periodycznie, z których każdy generuje zda- rania adresu węzła (funkcja kdNameLookup).
rzenie po upływie zaprogramowanego czasu. Utworzenie licznika
wymaga wywołania funkcji:
Funkcje kdSocketCreate, kdSocketAccept, kdNameLookup, kdNa-
meLookupCancel zawierają dodatkowy parametr eventuserptr,
KDTimer *kdSetTimer (KDint64 interval, KDint periodic, void
który jest przekazywany przy wystąpieniu zdarzenia związa-
*eventuserptr)
nego z gniazdem jako parametr userptr struktury KDEvent. Z
Sposób działania licznika określa parametr periodic, który przyjmu- czterema pierwszymi zdarzeniami przekazywane są dane za-
je jedną z trzech wartości: KD_TIMER_ONESHOT (licznik wywoływany
warte w następujących strukturach: KDEventSocketReadable,
jednokrotnie po upływie czasu nie krótszego niż określony w para-
KDEventSocketWritable, KDEventSocketError i KDEventSocketIn-
metrze interval), KD_TIMER_PERIODIC_AVERAGE (licznik wywoływa-
coming. Struktury te zawierają jedynie pole socket zawierające
ny periodycznie po upływie czasu zbliżonego do określonego w pa-
wskaznik na strukturę KDSocket identyfikującą gniazdo, z któ-
rametrze interval), KD_TIMER_PERIODIC_MINIMUM (licznik wywoły-
rym związane jest dane zdarzenie.
wany periodycznie po upływie czasu nie krótszego niż określony w
Przy zdarzeniu KD _ EVENT _ SOCKET _ CONNECT _ COMPLETE da-
parametrze interval). Czas reakcji licznika, zawarty w parametrze
ne przekazywane są w strukturze KDEventSocketConnect, któ-
interval, określany jest w nanosekundach, przy czym rzeczywista
ra oprócz pola socket, zawiera także pole error typu KDint32.
dokładność licznika zależy oczywiście od możliwości systemu ope-
racyjnego. W ostatnim parametrze można umieścić wskaznik na da- Pole to może przyjąć wartość jednego z następujących ko-
ne przekazywane wraz ze zdarzeniem licznika (pole userptr struk- dów błędów: KD _ EADDRINUSE, KD _ EAFNOSUPPORT, KD _ EALRE-
tury KDEvent), które identyfikowane jest stałą KD_EVENT_TIMER.
ADY, KD _ ECONNREFUSED, KD _ ECONNRESET, KD _ EHOSTUNREACH, KD _
Funkcja kdSetTimer zwraca wskaznik do struktury KDTimer
EINVAL, KD_EIO, KD _ EISCONN lub KD _ ETIMEDOUT. W przypadku
identyfikującej licznik. Struktura ta jest potrzebna do usunięcia
braku błędu pole error przyjmuje wartość 0. Z ostatnim zda-
licznika przy użyciu funkcji kdCancelTimer.
rzeniem KD _ EVENT _ NAME _ LOOKUP _ COMPLETE związane są da-
ne przekazywane w strukturze KDEventNameLookup. W przy-
padku poprawnego zakończenia funkcji, adres IP żądanego
dową funkcją jest kdNameLookupCancel, która przerywa po- węzła umieszczany jest w polu result będącym wskaznikiem
branie adresu IPv4 rozpoczęte wywołaniem asynchronicz- do struktury KDSockaddr (lub KDSockaddr _ in), a pole error ty-
nej funkcji kdNameLookup. pu KDint32 przyjmuje wartość 0. Wielkość zwróconej struk-
Podstawową strukturą opisującą adres sieciowy gniaz- tury zawiera pole resultlen typu KDint32. Struktura KDEvent-
da jest struktura KDSockaddr. Zawiera ona dwa pola: sa _ fa- NameLookup zawiera jeszcze pole more typu KDboolean, które
mily  rodzina protokołów (typ KDint16) oraz sa _ data  wła- wskazuje, czy w kolejce zdarzeń dostępne jest kolejne zda-
ściwy adres (typ KDuint8[14]). Ponieważ OpenKODE obsłu- rzenie zawierające następny pobrany adres IP. W przypadku
guje wyłącznie protokoły internetowe, pole sa _ family może wystąpienia błędu, wspomniane pole error przyjmuje jedną z
przyjąć jedynie wartość KD _ AF _ INET, która jest odpowied- wartości: KD _ HOST _ NOT _ FOUND  nie odnaleziono węzła, KD _
nikiem stałej AF _ INET z BSD/POSIX. Z tą rodziną protoko- NO _ DATA  nazwa węzła jest poprawna, ale nie posiada ad-
łów związana jest struktura KDSockaddr _ in, która w prakty- resu, KD _ NO _ RECOVERY  nienaprawialny błąd serwera nazw,
ce poprzez rzutowanie zastępuje strukturę bazową KDSoc- KD _ TRY _ AGAIN  tymczasowy błąd serwera nazw, możliwe
kaddr. Struktura KDSockaddr _ in posiada trzy pola: sin _ fa- ponowne zapytanie.
mily  rodzina protokołów (odpowiednik funkcjonalny pola
sa _ family struktury KDSockaddr, wartość KD _ AF _ INET, typ Obsługa okien
KDint16), sin _ address  adres IPv4 (typ KDuint32) oraz sin _ Jak już napisaliśmy na wstępie, biblioteka OpenKODE do two-
port  numer portu (typ KDuint16, sieciowa kolejność baj- rzenia kontekstów graficznych w systemach udostępniających
tów). Dostępna jest także stała KD _ INADDR _ ANY, będąca od- mechanizm okien wykorzystuje bibliotekę EGL. Okna w biblio-
powiednikiem stałej INADDR _ ANY standardów BSD/POSIX. Z tece OpenKODE identyfikowane są za pomocą uchwytów 
obsługą gniazd sieciowych w bibliotece OpenKODE związa- struktur KDWindow.
ne są następujące zdarzenia: Utworzenie okna dla wybranej płaszczyzny wyświetlania,
wygenerowanej przez bibliotekę EGL, sprowadza się do wy-
" KD _ EVENT _ SOCKET _ READABLE  sygnalizacja, że gniazdo wołania jednej z dwóch funkcji:
jest w trybie do odczytu (funkcje kdSockedBind i kdSocke-
tAccept), KDWindow *kdCreateFullScreenWindow (EGLDisplay ż
" KD _ EVENT _ SOCKET _ WRITABLE  sygnalizacja, że gniazdo jest display, const void *mode, void *eventuserptr)
w trybie do zapisu (funkcje kdSockedCreate i kdSocketAccept), KDWindow *kdCreateWindow ż
" KD _ EVENT _ SOCKET _ ERROR  sygnalizacja wystąpienia błę- (EGLDisplay display, void *eventuserptr)
du (funkcje kdSockedCreate, kdSocketAccept, kdSocketSend,
kdSocketRecv, kdSocketSendTo i kdSocketSendTo), Różnica w działaniu powyższych funkcji sprowadza się
" KD _ EVENT _ SOCKET _ INCOMING  gniazdo wykryło połącze- oczywiście do rodzaju utworzonego okna. Pierwsza z funk-
nie przychodzące lub wystąpił błąd (funkcje kdSocketLi- cji utworzy okno obejmujące cały ekran, które domyślnie
sten i kdSocketAccept), jest widoczne. Druga funkcja tworzy okno początkowo nie-
Software Developer s Journal 08/2007 www.sdjournal.org
33
Programowanie
C/C++
widoczne i jest dostępna wyłącznie w systemach obsługują- Z obsługą okien związane są następujące zdarzenia:
cych wiele okien.
Parametr display zawiera wskaznik na płaszczyznę wy- " KD _ EVENT _ WINDOW _ CLOSE  zamknięcie okna,
świetlenia utworzoną przez bibliotekę EGL. Wskaznik na " KD _ EVENT _ WINDOW _ RESIZE  zmiana rozmiaru okna,
dane, zawarty w parametrze eventuserptr, przekazywany " KD _ EVENT _ WINDOW _ FOCUS  uzyskanie, bądz utrata foku-
jest przy obsłudze zdarzeń związanych z oknami jako war- sa.
tość pola userptr struktury KDEvent. W przypadku podania
wartości KD _ NULL, pole userptr otrzyma wartość wskazni- Przy wystąpieniu dwóch pierwszych zdarzeń nie są przekazy-
ka na uchwyt okna, z którym związane jest zdarzenie. Pa- wane dodatkowe informacje, natomiast
rametr mode funkcji kdCreateFullScreenWindow może przyjąć z ostatnim zdarzeniem związana jest struktura KDEven-
jedynie wartość KD _ NULL. Usunięcie okna wymaga wywo- tWindowFocus, która zawiera jedno pole hasfocus (liczba typu
łania funkcji: KDint). Wartość 0 oznacza, że okno utraciło fokus, natomiast
uzyskanie fokusa sygnalizowane jest wartością 1. W każdym
void kdDestroyWindow (KDWindow *window) z trzech powyższych zdarzeń wartość pola userptr struktury
KDEvent zawiera dane przekazane w parametrze eventuserptr
Przy usuwaniu okna zwalniane są także wszystkie przydzie- przy wywołaniu funkcji kdCreateWindow lub kdCreateFullScre-
lone wraz z nim zasoby. Należy jednak pamiętać, aby zaso- enWindow lub wartość uchwytu okna, która jest przyjęta auto-
by przydzielone przez bibliotekę EGL zwolnić przed usunię- matycznie przez bibliotekę.
ciem okna.
Początkowe rozmiary i położenie okna utworzonego przy Programy przykładowe
użyciu funkcji kdCreateWindow są nieokreślone. Zmianę tych Programy przykładowe kompilowano w systemie operacyj-
parametrów umożliwiają funkcje: nym Microsoft Windows XP SP2 przy użyciu kompilatora Mi-
crosoft Visual C++ 2005 Express Edition z pakietem Micro-
KDint kdSetWindowPosition (KDWindow *window, KDint x, KDint y) soft Platform SDK for Windows Server 2003 R2. Wykorzysta-
KDint kdSetWindowSize (KDWindow *window, KDint width, ż no implementację OpenKODE autorstwa firmy Acrodea oraz
KDint height) implementację bibliotek EGL, OpenGL ES i OpenVG z pakie-
tu Rasteroid 3.1 firmy Hybrid Graphics. Użyta implementacja
Zmianę statusu widzialności okna utworzonego przy użyciu biblioteki OpenKODE została skompilowana jako jednowątko-
funkcji kdCreateWindow umożliwia funkcja: wa, stąd wymagana jest konsolidacja programu z jednowąt-
kowymi bibliotekami RTL. Wymaga to modyfikacji standar-
KDint kdShowWindow (KDWindow *window, KDint status) dowych ustawień w kompilatorze Visual C++ 2005 Express.
Przykładowe programy konstruowano z zamiarem ilustra-
której parametr status przyjmuje jedną z trzech wartości: KD _
WINDOWSTATUS _ HIDDEN  okno niewidoczne, KD _ WINDOWSTATUS _
VISIBLE  okno widoczne oraz KD _ WINDOWSTATUS _ MINIMIZED  Funkcje obsługujące system plików
okno zminimalizowane. Kolejne dwie funkcje umożliwiające
Zdecydowaną większość funkcji obsługujących system plików bi-
modyfikację stanu okna to:
blioteka OpenKODE przejęła bezpośrednio z języka C i standar-
du POSIX: kdFopen, kdFclose, kdFflush, kdFread, kdFwrite,
KDint kdActivateWindow (KDWindow *window)
kdGetc, kdPutc, kdFgets, kdFEOF, kdFerror, kdClearerr, kdFse-
KDint kdSetWindowCaption (KDWindow ż
ek, kdFtell, kdMkdir, kdRmdir, kdRename, kdRemove, kdTrunca-
*window, const KDchar *caption)
te, kdStat, kdFstat, kdOpenDir, kdReadDir, kdCloseDir, kdGet-
Free (zwolnienie pamięci przydzielonej na nazwę pliku lub katalo-
Pierwsza z nich zmienia status okna na aktywny (okno otrzy- gu), kdChdir oraz kdGetCwd.
muje fokus). Od implementacji zależy zachowanie okna  czy Funkcje obsługujące pliki korzystają ze struktury KDFile. Do-
stępne są także odpowiedniki stałych: KD _ EOF, KD _ SEEK _ SET,
jest ono w momencie wywołania tej funkcji ukryte, czy zminima-
KD _ SEEK _ CUR i KD _ SEEK _ END. Dane o pliku lub katalogu (lub
lizowane. Druga funkcja pozwala na zmianę tytułu okna na ciąg
urządzeniu identyfikowanym w systemie jako plik), pobierane
znaków umieszczony w parametrze caption (w formacie UTF-
przez funkcje kdStat i kdFstat, zwracane są w strukturze KDStat.
8). Od implementacji zależy gdzie i w jaki sposób wyświetlany
Struktura ta zawiera następujące pola: st _ size  rozmiar pliku w
jest tytuł okna, a także jaka jest jego maksymalna długość.
bajtach, st _ mtime  czas ostatniej modyfikacji oraz st _ mode 
Ostatnie funkcje operujące na oknach spełniają zadania
informacja o pliku/katalogu oraz prawach dostępu. Odczyt ostat-
pomocnicze. Pierwsza:
niego pola odbywa się za pośrednictwem makr: KD _ ISREG  czy
jest plik, KD _ ISDIR  czy jest katalog, KD _ READABLE  czy są pra-
void *kdGetWindowNativeType (KDWindow *window)
wa odczytu pliku/katalogu oraz KD _ WRITABLE  czy są prawa za-
pisu pliku/katalogu.
zwraca wskaznik do uchwytu okna specyficznego dla danego Funkcje obsługujące katalogi (kdOpenDir, kdReadDir i kdC-
loseDir) wykorzystują strukturę KDDir. Przy odczycie następne-
systemu. Uchwyt ten jest wymagany przez bibliotekę EGL przy
go pliku w wybranym katalogu funkcja kdReadDir zwraca struktu-
tworzeniu powierzchni  funkcja eglCreateWindowSurface. Dru-
rę KDDirent. Struktura ta zawiera jedno pole d _ name określające
ga funkcja zwraca położenie lewego górnego narożnika okna:
nazwę odczytanego pliku.
KDint kdGetWindowPosition (KDWindow *window, KDint *x, KDint *y)
34
www.sdjournal.org
Software Developer s Journal 08/2007
OpenKODE
określany jest na podstawie wartości pola data.input.index
struktury KDEvent. Wciśnięcie tego ostatniego przycisku po-
Asercje i dziennik komunikatów
woduje wygenerowanie zdarzenia KD _ EVENT _ QUIT i w konse-
Wzorem języka C biblioteka OpenKODE zawiera makro kdAssert kwencji zakończenie działania programu. Obroty sześcianu
obsługujące asercje. Programista może zmienić standardową ob-
umożliwia zarówno myszka, jak i wspomniane przyciski kie-
sługę asercji definiując funkcję:
runkowe gry. Cykliczne rysowanie sceny 3D reguluje licznik
czasowy uruchamiany każdorazowo po narysowaniu sceny.
void kdHandleAssertion (const KDchar *condition, const KDchar
Początkowy wygląd okna programu przedstawia Rysunek 4.
*filename, KDint linenumber)
Dodatkowo w ramach testów implementacji OpenKODE firmy
której parametrami są kolejno: generowany komunikat, nazwa pli-
Acrodea skompilowano dwa programy przykładowe pocho-
ku oraz numer linii programu, w którym został spełniony warunek
dzące z pakietu intent GamePlayer ADK firmy Tao Group. Pa-
asercji. Zapis informacji do dziennika komunikatów (logu) realizu-
kiet ten zawiera, oprócz bibliotek OpenGL ES i EGL, imple-
je funkcja:
mentację biblioteki OpenKODE. Pierwszym przetestowanym
w ten sposób programem był Quadric, który wyświetla kulę
void kdLogMessage (const KDchar *string)
pokrytą teksturą (Rysunek 5.). Podczas kompilacji i w trak-
Dezaktywacja obsługi asercji i dziennika komunikatów sprowadza
cie działania programu nie stwierdzono żadnych problemów.
się do zdefiniowania w programie makra KD_NDEBUG.
Drugim programem była prosta gra WakeBreaker. W tym wy-
padku kompilacja programu wymagała niewielkiej ingerencji
w kod zródłowy, ale nie było to związane z biblioteką Open-
cji wykorzystania biblioteki OpenKODE, stąd większość ele- KODE. Niestety wystąpiły problemy z prawidłową obsługą
mentów dotyczących OpenGL ES i OpenVG pochodzi z pro- przycisków, co jest najprawdopodobniej związane z błędami
gramów przykładowych dostępnych w wymienionych wyżej w implementacji biblioteki OpenKODE. Zrzut przykładowego
pakietach oraz w referencyjnej implementacji biblioteki Ope- ekranu gry przedstawiamy na Rysunku 6.
nVG autorstwa Khronos Group.
Program przedstawiony na Listingu 1. rysuje przy uży- Podsumowanie
ciu biblioteki OpenVG popularny rysunek głowy tygrysa. OpenKODE to najnowszy projekt Khronos Group, często okre-
Poruszanie wyświetlanym obrazem umożliwia przycisk ślany jako odpowiednik pakietu DirectX na urządzenia przeno-
wskaznika, czyli, w przypadku użytej implementacji, lewy śne. Jak wspomnieliśmy na wstępie, docelowo OpenKODE po-
przycisk myszki. Dodatkowo przyciski gry: KD _ IO _ GAME- łączy pięć otwartych standardów opracowywanych przez Khro-
KEYSNC _ A, KD _ IO _ GAMEKEYSNC _ B, KD _ IO _ GAMEKEYSNC _ C i nos Group: OpenGL ES, OpenVG, OpenMAX, OpenSL ES oraz
KD _ IO _ GAMEKEYSNC _ D (w stosowanej implementacji są to EGL. Pytanie może budzić celowość obecności w standardzie
przyciski 1, 2, 3 i 4) umożliwiają powiększenie obrazu od dwóch bibliotek graficznych: OpenGL ES i OpenVG. Jednak
jednego do czterech razy. Ponieważ są to przyciski opcjo- projektowano je dla tak odmiennych zastosowań, że rozdziele-
nalne, przed włączeniem obsługi związanej z nimi gru- nie grafiki trójwymiarowej od dwuwymiarowej na urządzeniach
py zdarzeń wejścia-wyjścia, program, korzystając z funk- mobilnych wydaje się być w pełni uzasadnione. Wystarczy za-
cji kdInputPolli, sprawdza ich dostępność. Warto zwrócić uważyć, że do implementacji na urządzeniu przenośnym prze-
uwagę na to, że umożliwienie programowi przetwarzania glądarki plików Flash i SVG, czy też wyświetlenia mapy drogo-
zdarzeń związanych ze wskaznikiem i przyciskami gry wy- wej w zupełności wystarczy biblioteka grafiki dwuwymiarowej.
magało dwukrotnego wywołania funkcji kdInputEventEna- Najbardziej rozpowszechnionym konkurentem OpenKO-
ble. Obsługa wszystkich zdarzeń zawarta jest w pojedyn- DE jest JavaME. Java jest stosunkowo łatwa w implementacji,
czej pętli umieszczonej w ciele funkcji kdMain. Początkowe a jej wersję opracowaną na potrzeby urządzeń przenośnych
okno programu przedstawia Rysunek 3. można w znacznym stopniu konfigurować. Jednak główną wa-
Drugi przykładowy program (Listing 3.) korzystając z bi- dą rozwiązań opartych o języki wykorzystujące kod pośredni,
blioteki OpenGL ES rysuje wielobarwny sześcian. W sto- jakim jest Java, jest ich mniejsza szybkość w stosunku do pro-
sunku do pierwszego przykładu zmieniono obsługę przyci- gramów kompilowanych.
sków gry tworząc wywoływaną zwrotnie funkcję KeyHandler. Także inne systemy operacyjne dostępne na urządzeniach
Stan przycisków kierunkowych gry odczytywany jest za po- przenośnych (Symbian, Palm OS, Windows Mobile) oferują
średnictwem pojedynczego wywołania funkcji kdInputPollb, a bezpośrednio lub pośrednio funkcjonalność biblioteki OpenKO-
stan przycisku  strzał (w stosowanej implementacji  spacja) DE. Jednak z samej definicji są to rozwiązania zależne od sys-
temu operacyjnego, co znacznie zmniejsza ich przenośność.
Za docelowym wyborem OpenKODE przemawia otwartość
W Sieci
standardu i możliwość kompleksowej obsługi wszystkich ele-
mentów urządzenia przenośnego. Nadzieję na rozpowszech-
" http://www.khronos.org  specyfikacje bibliotek OpenKODE,
nienie OpenKODE (bo pewności oczywiście nie ma) daje du-
OpenGL ES, OpenVG, EGL, OpenMAX i OpenSL ES,
ża ilość firm wspierających nowy standard, w tym obecność
" http://www.acrodea.co.jp/en/  implementacja biblioteki Open-
takich gigantów jak Nokia, NVIDIA, Samsung, Sony czy Sym-
KODE,
" http://www.hybrid.fi  pakiet Hybrid Rasteroid 3.1 z implemen- bian. OpenKODE pojawia się w odpowiednim momencie, gdy
tacjami bibliotek OpenGL ES, OpenVG i EGL, rozwiązania mobilne oferują coraz większe możliwości, a ich
" http://tao-group.com  pakiet intent GamePlayer ADK.
wykorzystanie zdaje się być prostsze, gdy mamy do czynienia
z otwartymi i wieloplatformowymi standardami. n
Software Developer s Journal 08/2007 www.sdjournal.org
35


Wyszukiwarka