background image

24

Programowanie

C/C++

www.sdjournal.org

 Software Developer’s Journal   08/2007

OpenKODE

O

penKODE jest zbiorem funkcji (API) prze-

znaczonych  do  budowania  aplikacji  mul-

timedialnych  i  gier  na  urządzenia  prze-

nośne.  Jednym  z  podstawowych  założeń  biblio-

teki  OpenKODE  jest  ułatwienie  tworzenia  aplika-

cji  na  urządzeniach  mobilnych  i  przenoszenia  ich 

na różne platformy systemowe i sprzętowe. Doce-

lowo  OpenKODE  ma  łączyć  większość  otwartych 

standardów  opracowanych  przez  Khronos  Gro-

up  –  OpenGL  ES  (grafika  trójwymiarowa),  Ope-

nVG  (dwuwymiarowa  grafika  wektorowa),  Open-

MAX (multimedia) i OpenSL ES (dźwięk). Do two-

rzenia  kontekstów  graficznych  w  systemach  udo-

stępniających mechanizm okien OpenKODE wyko-

rzystuje bibliotekę EGL. Budowę aplikacji mobilnej 

przed i po zastosowaniu OpenKODE przedstawia-

ją Rysunki 1 i 2.

Artykuł został oparty o pierwszą korektę tymcza-

sowej specyfikacji OpenKODE, która została opubli-

kowana  30.03.2007r.  Specyfikacja  ta  obecnie  łączy 

jedynie biblioteki OpenGL ES i OpenVG. Opracowa-

nie finalnej wersji standardu planowane jest na trzeci 

kwartał 2007 roku.

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 

jak i C99) oraz interfejsów programistycznych standar-

dów BSD i POSIX. Funkcje zapożyczone z powyższych 

standardów  mają  identyczne  nazwy,  poza  charakte-

rystycznym  dla  całej  biblioteki  OpenKODE  przedrost-

kiem kd. W głównej części artykułu skupimy się na naj-

ważniejszych  elementach  API  OpenKODE,  natomiast 

w ramkach czytelnik znajdzie krótkie opisy pozostałych 

funkcji, ze szczególnym uwzględnieniem elementów od-

biegających od standardów C/BSD/POSIX.

Całość  interfejsu  programistycznego  biblioteki 

OpenKODE zawarto w pliku 

kd.h

, który automatycznie 

włącza także plik 

egl.h

 z biblioteki EGL. Podstawowe 

stałe i typy danych przedstawiono w ramce. Definicje 

stałych i zmiennych zależnych od platformy systemo-

wej umieszczono w odrębnym pliku 

kdplatform.h

.

Obsługa błędów

Obsługa  błędów  w  bibliotece  OpenKODE  spro-

wadza  się  do  zwracania  przez  funkcje  specjal-

nej  wartości  w  przypadku  wystąpienia  błędu  (ty-

powo  jest  to  wartość  – 

1

  lub 

KD _ NULL

).  Ustawia-

ny jest także globalny wskaźnik ostatniego błędu, 

który  można  odczytać  przy  pomocy  funkcji 

kdGe-

tError

  (kod  błędu  nie  jest  modyfikowany  po  od-

czycie)  lub  ustawić  korzystając  z  funkcji 

kdSetEr-

ror

.  Opis  kodów  błędów  przedstawiono  w  ramce. 

Omawiana  tymczasowa  specyfikacja  OpenKODE 

nie  przewiduje  wsparcia  dla  aplikacji  wielowątko-

wych,  dlatego  obsługa  błędów  opiera  się  na  glo-

balnym  wskaźniku  błędu.  W  przypadku  wprowa-

dzenia w przyszłych wersjach OpenKODE wspar-

cia dla wielowątkowości, wskaźniki błędu będą od-

rębne dla każdego wątku.

Wersje i rozszerzenia

Odczyt wybranych właściwości implementacji biblio-

teki OpenKODE umożliwia funkcja:

const KDchar *kdQueryAttribcv (KDint attribute)

której  parametr 

attribute

  może  przyjąć  jedną  z 

dwóch  wartości: 

KD _ ATTRIB _ VENDOR

  –  autor  imple-

mentacji  oraz 

KD _ ATTRIB _ VERSION

  –  wersja  bibliote-

ki. Wersję biblioteki opisuje ciąg znaków w następu-

Janusz Ganczarski

Autor jest matematykiem i informatykiem
Kontakt z autorem: JanuszG@enter.net.pl
Strona domowa: http://www.januszg.hg.pl

Kody błędów

Kody błędów oparto o błędy zdefiniowane w standardach 
C/BSD/POSIX: 

KD_EACCES

  (brak  dostępu), 

KD_EADDRINU-

SE

 (adres jest używany), 

KD_EADDRNOTAVAIL

 (adres niedo-

stępny), 

KD_EAFNOSUPPORT

 (niewspierana rodzina adresów), 

KD_EAGAIN

  (zasoby  chwilowo  niedostępne), 

KD_EALREADY

 

(trwa połączenie), 

KD_EBADF

 (nieprawidłowy deskryptor pli-

ku), 

KD_EBUSY

 (zajęte urządzenie lub zasób), 

KD_ECONNRE-

FUSED

  (połączenie  odrzucone), 

KD_ECONNRESET

  (połącze-

nie  zrestartowane), 

KD_EDESTADDRREQ

  (wymagany  adres 

docelowy), 

KD_EDOM

 (wartość argumentu funkcji poza dzie-

dziną), 

KD_ERANGE

 (wartość argumentu funkcji poza zakre-

sem), 

KD_EEXIST

 (plik istnieje), 

KD_EFBIG

 (zbyt duży rozmiar 

pliku), 

KD_EHOSTUNREACH

  (węzeł  niedostępny), 

KD_EINVAL

 

(błędny argument), 

KD_EIO

 (błąd wejścia-wyjścia), 

KD_EIL-

SEQ

 (niepoprawna sekwencja bajtów), 

KD_EISCONN

 (gniazdo 

jest już połączone), 

KD_EISDIR

 (katalog), 

KD_EMFILE

 (za du-

żo otwartych plików), 

KD_ENAMETOOLONG

 (zbyt długa nazwa 

pliku), 

KD_ENOENT

 (brak pliku lub katalogu), 

KD_ENOMEM

 (brak 

pamięci), 

KD_ENOSPC

 (brak wolnego miejsca na urządzeniu), 

KD_ENOSYS

  (funkcja  nie  jest  obsługiwana), 

KD_ENOTCONN

 

(gniazdo nie jest połączone), 

KD_EOPNOTSUPP

 (operacja nie 

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).

background image

OpenKODE

25

www.sdjournal.org

Software Developer’s Journal   08/2007

jącym formacie: numer wersji, kropka, numer podwersji, spa-

cja, opcjonalne informacje o implementacji. Implementacja bi-

blioteki używana w trakcie testów zwracała następujące ciągi 

znaków: „Acrodea OpenKODE / Windows” oraz „1.0 Provisio-

nal build Feb 27 2007”. Odczyt dostępnych rozszerzeń biblio-

teki OpenKODE, a w przyszłości także innych atrybutów im-

plementacji, wymaga dwuetapowego działania. W pierwszym 

kroku należy ustalić ilość wartości dostępnych dla danego atry-

butu, co wymaga wywołania funkcji:

KDint kdQueryAttribi (KDint attribute, KDint *value)

Obecnie  jedyną  możliwą  wartością  parametru  attribute  jest 

KD _ ATTRIB _ NUM _ EXTENSIONS

, który określa pobranie ilości do-

stępnych rozszerzeń biblioteki. Ilość atrybutów (w tym wypad-

ku rozszerzeń biblioteki) zwracana jest za pośrednictwem pa-

rametru 

value

.

W drugim etapie pobierane są kolejne wartości wybra-

nego atrybutu, do czego służy funkcja: 

const KDchar *kdQue-

ryIndexedAttribcv (KDint attribute, KDint index) 

Jak się Czy-

telnik domyśla, także tutaj parametr 

attribute

 może przy-

jąć tylko jedną wartość 

KD _ ATTRIB _ EXTENSIONS

 określającą 

pobieranie informacji o rozszerzeniach biblioteki. Numera-

cja poszczególnych wartości atrybutu, umieszczana w pa-

rametrze 

index

,  zaczyna  się  od  zera.  Używana  w  trakcie 

testów  biblioteka  OpenKODE  posiadała  jedno  rozszerze-

nie 

KD _ KHR _ staticdata

. Jego dostępność oznacza, że im-

plementacja  wspiera  zmienne  nieautomatyczne,  czyli  np. 

zmienne statyczne i globalne. 

Brak dostępności takich zmiennych może np. wystąpić 

w przypadku implementacji OpenKODE w prostych syste-

mach wbudowanych w pamięci ROM. W trakcie opracowy-

wania  są  dwa  następne  rozszerzenia  biblioteki  OpenKO-

DE: 

KD _ KHR _ performer

  i 

KD _ KHR _ crypto

.  Pierwsze  roz-

szerzenie  wprowadza  mechanizmy  przekazujące  informa-

cje o sprzęcie (np. procesor, pamięć, grafika) oraz określa-

jące jego wydajność. 

Drugie  z  opracowywanych  rozszerzeń  zawiera  szereg 

funkcji kryptograficznych. Obsługiwany jest algorytm AES 

(ang. Advanced Encryption Standard) z kluczami o długo-

ści 128, 192 i 256 bitów.

Niektóre implementacje OpenKODE mogą wymagać po-

bierania  wskaźników  do  funkcji  dostępnych  w  rozszerze-

niach (podobna sytuacja ma miejsce także w przypadku bi-

blioteki EGL). Pobranie wskaźnika do wybranej funkcji reali-

zuje funkcja:

void *kdGetProcAddress (const KDchar *name)

Wejście i wyjście programu

Wejście programu realizowane jest przez funkcję:

KDint kdMain (KDint argc, const KDchar **argv)

Rysunek 2. 

Aplikacja mobilna z OpenKODE (źródło Khronos 

Group)

Rysunek 1. 

Aplikacja mobilna bez OpenKODE (źródło 

Khronos Group)

Podstawowe stałe i typy danych

Biblioteka  OpenKODE  udostępnia  szereg  typów  liczb  całkowitych  o 
precyzji od 8 do 64 bitów: 

KDchar

KDint32

KDuint32

KDint64

KDu-

int64

KDint16

KDuint16

KDint8

KDuint8

KDint

KDuint

 oraz licz-

by zmiennoprzecinkowe 

KDfloat32

 (standard IEEE 754). Typy 

KDint

 i 

KDuint

 zakładają co najmniej 32 bitową precyzję. Dostępny jest tak-

że typ logiczny 

KDboolean

, który opiera się na 

KDint

. Warto zwrócić 

uwagę  na  brak  liczb  zmiennoprzecinkowych  podwójnej  precyzji,  co 
autorzy specyfikacji tłumaczą ich niewielką przydatnością w grach.

Ponadto  zdefiniowanych  jest  kilka  typów  pochodnych  po  ty-

pach  podstawowych: 

KDuintptr

  (typ  całkowity  wielkości  pozwa-

lającej na zmieszczenie wskaźnika), 

KDsize

 i 

KDssize

 (typy całko-

wite pozwalające na zmieszczenie rozmiaru największego obiektu 
w pamięci), 

KDsocklen

 (typ całkowity określający rozmiar struktu-

ry 

KDSockaddr

), 

KDtime

 (typ 

KDint64

 używany do określania liczby 

sekund), 

KDust

 (typ 

KDint64

 używany do określania liczby nano-

sekund), 

KDoff

 (typ 

KDint64

 używany do określania wielkości pli-

ku lub pozycji w pliku) oraz 

KDmode

 (typ 

KDuint32

 używany w polu 

st _ mode

 struktury 

KDStat

).

Większość  podstawowych  stałych  określa  zakresy  wartości 

typów  podstawowych: 

KDINT _ MIN

KDINT _ MAX

KDUINT _ MAX

KDINT32 _ MIN

KDINT32 _ MAX

KDUINT32 _ MAX

KDINT64 _ MIN

KDINT64 _ MAX

  oraz 

KDUINT64 _ MAX

.  Zdefiniowano  także  odpo-

wiedniki znanych stałych: 

KD _ TRUE

KD _ FALSE

 i 

KD _ NULL

.

background image

26

Programowanie

C/C++

www.sdjournal.org

 Software Developer’s Journal   08/2007

której  argumenty  odpowiadają  analogicznym  argumentom 

funkcji main w języku C. Wyjście z aplikacji zapewnia funkcja:

void kdExit (KDint status)

będąca odpowiednikiem funkcji exit z języka C.

Obsługa zdarzeń

Biblioteka  OpenKODE  korzysta  z  modelu  zdarzeniowego, 

w  którym  aplikacja  ma  pojedynczy  punkt  wejścia  zawierają-

cy główną pętlę obsługi zdarzeń systemowych. Jednak moż-

liwe  jest  także  korzystanie  z  mechanizmu  funkcji  wywoływa-

nych  zwrotnie,  co  ułatwia  przenoszenie  programów  stosują-

cych tę technikę. 

Przy  przetwarzaniu  zdarzeń  wykorzystywana  jest  struk-

tura 

KDEvent

,  której  zawartość  zależy  od  rodzaju  zdarzenia. 

Struktura zawiera cztery pola:

•   timestamp  –  czas  wystąpienia  zdarzenia  (czas  UST  – 

patrz ramka),

•   type – rodzaj zdarzenia identyfikowany jedną ze stałych z 

grupy 

KD _ EVENT _ *

,

•   userptr – wskaźnik na dane przekazywane przy wywoła-

niu zdarzenia,

•   data – unia 

KDEventData

 zawierająca jedną ze struktur ob-

sługujących konkretny rodzaj zdarzenia (

KDEventInput in-

put,  KDEventInputPointer  inputpointer,  KDEventInput-
Stick  inputstick,  KDEventSocketReadable  socketreada-
ble,  KDEventSocketWritable  socketwritable;  KDEventSoc-
ketError  socketerror,  KDEventSocketConnect  socketcon-
nect,  KDEventSocketIncoming  socketincoming,  KDEvent-

NameLookup  namelookup,  KDEventWindowFocus  windowfocus, 
KDEventUser user

).

Trzy  podstawowe  zdarzenia  systemowe  (globalne)  identyfiko-

wane są przez następujące stałe: 

KD _ EVENT _ QUIT

 – zakończe-

nie  działania  aplikacji, 

KD _ EVENT _ PAUSE

  –  zatrzymanie  działa-

nia  aplikacji, 

KD _ EVENT _ RESUME

  –  wznowienie  działania  aplika-

cji.  Do  tej  grupy  należy  także  opisywane  dalej  zdarzenie  wej-

ścia-wyjścia 

KD _ IOGROUP _ EVENT

 związane z zasilaniem urządze-

nia. Biblioteka OpenKODE definiuje także szereg zdarzeń lokal-

nych związanych z obsługą procesów wejścia-wyjścia, gniazda-

mi sieciowymi, oknami oraz licznikiem czasu. Zdarzenia te omó-

wimy nieco dalej, bądź są one przedstawione w ramkach. Obsłu-

ga zdarzeń przebiega w pętli, w której zasadniczym elementem 

jest oczekiwanie na zajście zdarzenia. Realizuje to funkcja:

const KDEvent *kdWaitEvent (KDust timeout)

która zwraca wskaźnik 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:

KDEvent *kdCreateEvent (void)

Rysunek 3. 

Początkowe okno programu Tygrys

Funkcje narzędziowe

Do grupy funkcji narzędziowych należą funkcje w większości znane 
z języka C: 

kdAbs

kdStrtof

kdStrtol

kdStrtoul

kdLtostr

 (kon-

wersja liczby całkowitej ze znakiem do ciągu znaków), 

kdUltostr

 

(konwersja liczby całkowitej bez znaku do ciągu znaków), 

kdFtostr

 

(konwersja  liczby  zmiennoprzecinkowej  do  ciągu  znaków)  oraz 

kdCryptoRandom

  (generowanie  ciągu  liczb  losowych).  Zauważmy, 

że biblioteka OpenKODE nie zawiera odpowiednika funkcji 

sprintf

 

oraz snprintf. Funkcje konwertujące liczby na ciągi znaków udostęp-
niają  część  ich  możliwości.  Maksymalną  długość  generowanych 
ciągów znaków, łącznie z końcowym znakiem 

NULL

, określają stałe: 

KD_LTOSTR_MAXLEN

KD_ULTOSTR_MAXLEN

 i 

KD_FTOSTR_MAXLEN

.

background image

OpenKODE

27

www.sdjournal.org

Software Developer’s Journal   08/2007

Listing 1. 

Program Tygrys (fragmenty)

[

...

]

// program główny

KDint

 

kdMain

 

(

KDint

 

argc

const

 

KDchar

 

**

argv

{

  

 // utworzenie okna

   

KDWindow

 

*

window

 

=

 

kdCreateWindow

 

(

KD_NULL

,

KD_NULL

);

  

 // rozmiary okna

   

kdSetWindowSize

 

(

window

,

(

KDint

)

tigerMaxX

, §

         

(

KDint

)

tigerMaxY

);

  

 // tytuł okna

   

kdSetWindowCaption

 

(

window

,

"Tygrys"

);

  

 // wyświetlenie okna

   

kdShowWindow

 

(

window

KD_WINDOWSTATUS_VISIBLE

);

  

 // sprawdzenie dostępności opcjonalnych przycisków gry

   

KDint32

 

buffer

;

   

kdInputPolli

 

(

KD_IO_GAMEKEYS_AVAILABILITY

,9,

&

buffer

);

  

 // włączenie obsługi przycisków gry (jeżeli przyciski 

   // są dostępne)

   

if

 

(

buffer

 

==

 511

)

 

{

      

kdInputEventEnable

 

(

KD_IOGROUP_GAMEKEYSNC

,

KD_TRUE

);

   

}

  

 // włączenie obsługi przycisków gry

   

kdInputEventEnable

 

(

KD_IOGROUP_GAMEKEYSNC

,

KD_TRUE

);

  

 // włączenie obsługi wskaźnika

   

kdInputEventEnable

 

(

KD_IOGROUP_POINTER

,

KD_TRUE

);

[

...

]

  

 // struktura z opisem zdarzeń

   

const

 

KDEvent

 

*

event

;

  

 // dane do obsługi wskaźnika

   

KDint32

 

pointer_x

,

pointer_y

;

   

bool

 

pointer_select

 

=

 

false

;

  

 // główna pętla obsługi zdarzeń

   

while

 

((

event

 

=

 

kdWaitEvent

 

(-

1

))

 

!=

 

KD_NULL

)

      

switch

 

(

event

 

->

 

type

{

         

// zakończenie działania aplikacji

         

case

 

KD_EVENT_QUIT

:

         

case

 

KD_EVENT_WINDOW_CLOSE

:

           

 // usunięcie danych o ścieżkach

            

PS_destruct

 

(

tiger

);

           

 // porządki w bibliotece EGL

            

eglMakeCurrent

 

(

display

,

KD_NULL

,

                  

KD_NULL

,

KD_NULL

);

            

eglDestroyContext

 

(

display

,

openvg_context

);

            

eglDestroySurface

 

(

display

,

window_surface

);

            

eglTerminate

 

(

display

);

            

eglReleaseThread

 

();

           

 // usunięcie okna

            

kdDestroyWindow

 

(

window

);

            

kdExit

 

(

0

);

            

break

;

           

 // zmiana rozmiaru okna

         

case

 

KD_EVENT_WINDOW_RESIZE

:

            

Display

 

(

display

,

window_surface

,

tiger

);

            

break

;

           

 // otrzymanie fokusa - odrysowanie okna

         

case

 

KD_EVENT_WINDOW_FOCUS

:

            

if

 

(

event

 

->

 

data

.

windowfocus

.

hasfocus

)

               

Display

 

(

display

,

window_surface

,

tiger

);

            

break

;

           

 // obsługa wskaźnika (np. myszki)

         

case

 

KD_EVENT_INPUT_POINTER

:

            

if

 

(

event

 

->

 

data

.

inputpointer

.

select

{

              

 // przypadek, gdy przycisk wskaźnika 

               // jest naciśnięty i jest w ruchu

               

if

 

(

pointer_select

{

                 

 // pobranie rozmiarów okna w pikselach

                  

int

 

width

,

height

;

                  

eglQuerySurface

 

(

display

,

window_

surface

,

EGL_WIDTH

,

&

width

);

                  

eglQuerySurface

 

(

display

,

window_

surface

,

EGL_HEIGHT

,

&

height

);

                 

 // przeliczenie wektora przesunięcia

                  

translatex

 

+=

 

event

 

->

 

                        

data

.

inputpointer

.

x

 

-

 

pointer_x

;

                  

translatey

 

+=

 

pointer_y

 

-

 

event

 

->

  

data

.

inputpointer

.

y

;

                 

 // zapamiętanie współrzędnych położenia 

                  // wskaźnika

                  

pointer_x

 

=

 

event

 

->

 

data

.

inputpointer

.

x

;

                  

pointer_y

 

=

 

event

 

->

 

data

.

inputpointer

.

y

;

               

else 

{

                 

 // przycisk wskaźnika nie był wcześniej 

                  // naciśnięty

                  

pointer_select

 

=

 

true

;

                  

pointer_x

 

=

 

event

 

->

 

data

.

inputpointer

.

x

;

                  

pointer_y

 

=

 

event

 

->

 

data

.

inputpointer

.

y

;

               

}

               

Display

 

(

display

,

window_surface

,

tiger

);

            

else

              

 // przycisk wskaźnika został zwolniony

               

pointer_select

 

=

 

false

;

            

break

;

           

 // obsługa przycisków

         

case

 

KD_EVENT_INPUT

{

              

 // sprawdzenie stanu przycisków gry

               

switch

 

(

event

 

->

 

data

.

input

.

index

{

                    

 // skalowanie obrazu

                  

case

 

KD_IO_GAMEKEYSNC_A

scale

 

=

 1.0

;

                     

break

;

                  

case

 

KD_IO_GAMEKEYSNC_B

scale

 

=

 2.0

;

                     

break

;

                  

case

 

KD_IO_GAMEKEYSNC_C

scale

 

=

 3.0

;

                     

break

;

                  

case

 

KD_IO_GAMEKEYSNC_D

scale

 

=

 4.0

;

                     

break

               

}

               

Display

 

(

display

,

window_surface

,

tiger

);

            

}

           

 // domyślne przetworzenie pozostałych zdarzeń

         

default

            

kdDefaultEvent

 

(

event

);

            

break

;

      

}

   

return

 0

// wyjście

}

background image

28

Programowanie

C/C++

www.sdjournal.org

 Software Developer’s Journal   08/2007

Po  określeniu  odpowiednich  pól  w  strukturze 

KDEvent

  opisu-

jącej  zdarzenie,  umieszczenie  zdarzenie  w  kolejce  zdarzeń 

sprowadza się do wywołania funkcji:

KDint kdPostEvent (KDEvent *event)
Usunięcie struktury KDEvent umożliwia funkcja:
void kdFreeEvent (KDEvent *event)

Dla zdarzeń tworzonych przez użytkownika biblioteka Open-

KODE rezerwuje identyfikatory o wartościach z przedziału od 

KD _ EVENT _ USER

 do 

KDINT32 _ MAX

. Dane zdarzenia użytkowni-

ka przechowywane są w strukturze typu 

KDEventUser

. Struktu-

ra ta zawiera dwie unie 

value1

 i 

value23

, o wielkościach liczb 

typu 

KDint64

, których wewnętrzna budowa pozwala na różno-

rodne wykorzystanie.

Zdarzenia 

a funkcje wywoływane zwrotnie

Dołączenie lub odłączenie funkcji wywoływanej zwrotnie, ob-

sługującej wybraną grupę zdarzeń, wymaga użycia funkcji:

KDint kdInstallCallback (KDCallbackFunc *func, KDint eventtype, 

void *eventuserptr)

Przypadki,  gdy  do  obsługi  zdarzenia  lub  grupy  zdarzeń  będzie 

wywoływana  funkcja  zwrotna  wskazana  w  parametrze 

func

określa  kombinacja  wartości  parametrów 

eventtype

  i 

eventu-

serptr

. Pierwszy z tych parametrów określa rodzaj zdarzenia, a 

drugi  wartość  wskaźnika  na  dane  przekazywane  przy  wywoły-

waniu zdarzeń (odpowiada to parametrowi 

eventuserptr

 przeka-

zywanego np. przy niektórych funkcjach). Podanie wartości 

0

 w 

miejscu parametru 

eventtype

 oznacza obsługę wszystkich zda-

rzeń, natomiast podanie wartości 

KD _ NULL

 dla parametru 

eventu-

serptr

 oznacza obsługę przez funkcję dowolnej wartości wskaź-

nika na dane przekazywane przy wywoływaniu zdarzeń. Ten pro-

sty  mechanizm  pozwala  przykładowo  na  łatwe  wyodrębnienie 

funkcji zwrotnych obsługujących różne okna aplikacji. Funkcja wy-

woływana zwrotnie musi być zgodna z następującym typem:

typedef void (KDCallbackFunc) (const KDEvent *event)

W  sytuacji,  gdy  funkcja  zwrotna  nie  obsługuje  części  otrzy-

mywanych  zdarzeń,  powinna  zastosować  domyślną  obsługę 

zdarzenia wywołując 

kdDefaultEvent

. W przeciwnym wypadku 

informacja o danym zdarzeniu zostanie utracona i usunięta z 

kolejki zdarzeń.

Jeżeli  jakieś  zdarzenie  lub  grupa  zdarzeń  obsługiwana 

jest przez funkcje wywoływane zwrotnie, nie są one zgłasza-

ne przy wywołaniu 

kdWaitEvent

. W przypadku, gdy wszystkie 

zdarzenia obsługiwane są w ten sposób, główna pętla prze-

twarzania zdarzeń będzie wyglądała następująco:

KDEvent *event;
while ((event = kdWaitEvent (-1)) != KD_NULL)
   kdDefaultEvent (event);

Usprawnienie  obsługi  zdarzeń  przez  funkcje  wywoływane 

zwrotnie umożliwia funkcja:

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,

•  

KD _ IOGROUP _ POINTER

 – wskaźnik (np. myszka),

Rysunek 4. 

Początkowe okno programu Sześcian

Funkcje obsługujące czas

Biblioteka  OpenKODE  wykorzystuje  wewnętrznie  czas  UST  (ang. 
unadjusted system time) zliczający ilość nanosekund, które upłynę-
ły od północy 1 stycznia 1970 roku. Odczyt bieżącego czasu UST 
umożliwia  funkcja 

kdGetTimeUST

.  Czas  UST  przechowywany  jest 

w liczbach typu 

KDust

 (czyli 

KDint64

). Dostępna jest również funk-

cja 

kdTime

, która pobiera uniwersalny czas koordynowany (UTC), 

przechowywany w liczbach typu 

KDtime

 (także 

KDint64

). Konwer-

sję czasu UTC na czas uniwersalny GMT oraz czas lokalny reali-
zują  funkcje 

kdGmtime_r

  i 

kdLocaltime_r

.  Funkcje  te  korzystają 

ze struktury 

KDtm

, która zawiera pola: 

m_sec

tm_min

tm_hour

tm_

mday

tm_mon

tm_year

tm_wday

tm_yday

 i 

tm_isdst

, w pełni od-

powiadające polom struktury 

tm

 z języka C. Wszystkie pola są typu 

całkowitego 

KDint32

.

Ostatnią funkcją z opisywanej grupy jest 

kdUSTAtEpoch

, która 

zwraca czas UST odpowiadający początkowi epoki (czyli północy 
1 stycznia 1970 roku) czasu UTC. Wynik (liczba typu 

KDust

) mo-

że mieć wartość ujemną. Funkcja 

kdUSTAtEpoch

 ułatwia konwer-

sję pomiędzy czasem UST i UTC.

background image

29

OpenKODE

www.sdjournal.org

Software Developer’s Journal   08/2007

•  

KD _ IOGROUP _ JOGDIAL

 – pokrętło jog dial,

•  

KD _ IOGROUP _ JOYSTICK

 – dżojstik,

•  

KD _ IOGROUP _ VIBRATE

 – wibracja,

•  

KD _ IOGROUP _ BACKLIGHT

 – podświetlenie.

Dla zdarzeń wejścia-wyjścia zależnych od implementacji specy-

fikacja OpenKODE rezerwuje indeksy z przedziału 

KD _ IO _ UN-

DEFINED

 – 

KDINT32 _ MAX

. Włączenie lub wyłączenie obsługi wy-

branej grupy zdarzeń wejściowych wymaga wywołania funkcji:

KDint kdInputEventEnable (KDint idx, KDint enable)

Parametr 

idx

 określa rodzaj grupy zdarzeń i przyjmuje jedną z 

wymienionych wcześniej wartości identyfikującą grupę, a para-

metr 

enable

 określa czy obsługa wskazanej grupy zdarzeń ma 

zostać włączona (

KD _ TRUE

) czy wyłączona (

KD _ FALSE

). Zdarze-

nia wejścia-wyjścia mogą generować cztery rodzaje informacji: 

binarne (tylko wejście), 

KDint32

 (wejście i wyjście), 

KDint64

 (tyl-

ko wejście) oraz 

KDfloat32

 (wejście i wyjście). Próbkowanie stanu 

wybranych wejść z danej grupy zdarzeń wejścia-wyjścia umożli-

wiają funkcje z grupy 

kdInputPoll

 (odrębnie dla każdego rodza-

ju danych wejściowych), pokazane są one na Listingu 2. Para-

metr 

startidx

 określa numer pierwszego odpytywanego zdarze-

nia, a parametr 

numidxs

 ilość kolejnych odpytywanych zdarzeń z 

danej grupy zdarzeń. Nie ma możliwości jednorazowego odczy-

tania danych zdarzeń pochodzących z różnych grup lub zdarzeń 

z jednej grypy, które zwracają różnego rodzaju informacje. Od-

czytane dane umieszczane są w buforze wskazywanym w pa-

rametrze 

buffer

. Na programie ciąży obowiązek zapewnienia ta-

kiej ilości miejsca w buforze, aby pomieścić wszystkie pobierane 

dane. Analogiczne parametry posiadają funkcje z grupy 

kdOut-

putSet

, które odpowiadają za generowanie zdarzeń wyjściowych:

KDint kdOutputSeti (KDint startidx, KDuint numidxs,  §
 const KDint32 *buffer)
KDint kdOutputSetf (KDint startidx, KDuint numidxs,  §
 const KDfloat32 *buffer)

Zestawienie  zdarzeń  związanych  z  poszczególnymi  grupami 

zdarzeń  wejścia-wyjścia  przedstawiono  w  dalszej  części  ar-

tykułu. Oczywiście od implementacji i specyfiki systemu oraz 

sprzętu  zależy,  które  grupy  zdarzeń  wejścia-wyjścia  są  do-

stępne dla programu. Także w ramach niektórych grup zda-

rzeń wejścia-wyjścia nie wszystkie zdarzenia muszą być ob-

sługiwane przez implementację. Sprawdzenie wszystkich tych 

zależności umożliwiają funkcji z grupy 

kdInputPoll

.

Ponadto  jest  jeszcze  grupa  zdarzeń  wejścia-wyjścia  na-

leżąca do zdarzeń występujących na poziomie całej aplikacji. 

Grupa ta jest identyfikowana stałą 

KD _ IOGROUP _ EVENT

 i nale-

żą  do  niej  dwa  zdarzenia  wejściowe: 

KD _ IO _ EVENT _ USING _

BATTERY

 – informacja o pracy na bateriach (dane binarne, war-

tość 

1

 – urządzenie korzysta z baterii, wartość 

0

 – urządzenie 

korzysta z zasilania głównego) oraz 

KD _ IO _ EVENT _ LOW _ BAT-

TERY

 – informacja o niskim poziomie naładowania baterii (dane 

binarne, wartość 

1

 – niski stan naładowania baterii, wartość 

0

 

– baterie naładowane).

Poza funkcjami z grup 

kdInputPoll

 dane związane ze zda-

rzeniami wejściowymi można odczytywać korzystając z infor-

macji umieszczanych w strukturze 

KDEvent

. W tym celu wszyst-

kie  zdarzenia  podzielone  są  na  trzy  rodzaje: 

KD _ EVENT _ IN-

PUT _ POINTER

  –  zdarzenie  związane  ze  wskaźnikiem, 

KD _

EVENT _ INPUT _ STICK

 – zdarzenie związane z dżojstikiem oraz 

KD _ EVENT _ INPUT

  –  pozostałe  zdarzenia  wejściowe.  Z  każ-

dym  rodzajem  zdarzenia  wejściowego  związane  są  inne  da-

ne umieszczane w polu 

data

 (unii) struktury 

KDEvent

. Są to od-

powiednio  struktury: 

KDEventInputPointer  inputpointer

KDE-

ventInputStick  inputstick

  oraz 

KDEventInput  input

.  W  każ-

dej z powyższych grup zdarzeń zawartość pola 

userptr

 struk-

tury 

KDEvent

 zależy od tego, czy jedno z okien aplikacji posiada 

fokus. Jeżeli tak, to przekazywana jest tam wartość parametru 

eventuserptr

 funkcji tworzącej okno. Jeżeli żadne okno nie po-

siada fokusa, przekazywana jest wartość 

KD _ NULL

.

Struktura 

KDEventInput

 zawiera dwa pola. Pierwsze pole 

index

 

(typ 

KDint32

) określa rodzaj zdarzenia wejściowego. Drugie pole 

value

 zawiera unię przechowującą jedną z liczb typu: 

KDint32

 (po-

le 

value.i

), 

KDint64

 (pole 

value.l

) lub 

KDfloat32

 (pole 

value.f

), które 

są używane w zależności od rodzaju danych zwracanych przez 

zdarzenie.  Stałe  opisujące  zdarzenia  wejściowe  oraz  zwracane 

przez te zdarzenia dane opisano w dalszej części tekstu.

Struktura 

KDEventInputPointer

  zawiera  cztery  liczby  typu 

KDint32

. Pole 

index

 określa rodzaj zdarzenia wejściowego, po-

le 

select

 zawiera stan przycisku wskaźnika (

1

 – przycisk naci-

śnięty, 

0

 – przycisk zwolniony), a dwa ostatnie pola 

x

 i 

y

 prze-

chowują współrzędne położenia wskaźnika.

Ostatnia opisywana struktura 

KDEventInputStick

 także za-

wiera cztery pola typu 

KDint32

. Pole 

index

 zawiera numer (in-

deks)  dżojstika,  który  wygenerował  zdarzenie  wejściowe,  a 

trzy pozostałe pola 

x

y

 i 

z

 określają kąty obrotu drążka w kie-

runku osi X, Y i Z (opcjonalnie).

Grupy zdarzeń wejścia-wyjścia

Grupa  zdarzeń 

KD _ IOGROUP _ GAMEKEYS

  związana  jest  z 

przyciskami obsługującymi gry, przy czym możliwa jest ob-

sługa  wielu  jednocześnie  naciśniętych  przycisków.  Biblio-

teka OpenKODE implementuje przyciski dostępne w stan-

dardzie Java MIDP2, czyli w praktyce przyciski dostępne w 

Listing 2. 

Funkcje z grupy kdInputPoll

KDint

 

kdInputPollb

 

(

KDint

 

startidx

KDuint

 

numidxs

,  §

KDint32

 

*

buffer

)

KDint

 

kdInputPolli

 

(

KDint

 

startidx

KDuint

 

numidxs

,  §

 

KDint32

 

*

buffer

)

KDint

 

kdInputPolll

 

(

KDint

 

startidx

KDuint

 

numidxs

,  §

 

KDint64

 

*

buffer

)

KDint

 

kdInputPollf

 

(

KDint

 

startidx

KDuint

 

numidxs

,  §

 

KDfloat32

 

*

buffer

)

Funkcje narodowe i językowe

Generalnie biblioteka OpenKODE nie zawiera wsparcia dla obsługi 
programów wielojęzycznych. Możliwe jest jednak odczytanie bieżą-
cego języka oraz kraju, a także strefy czasowej. Język (norma ISO 
639-1) oraz kod kraju (norma ISO 3166-1 alpha 2), oddzielone zna-
kiem  podkreślenia,  zwraca  funkcja 

kdGetLocale

.  Na  przykład  dla 

Polski będzie to „pl_PL”. Odczyt bieżącej strefy czasowej, określo-
nej jako przesunięcie w stosunku do uniwersalnego czasu koordy-
nowanego (UTC), umożliwia funkcja 

kdGetTzOffset

.

background image

30

Programowanie

C/C++

www.sdjournal.org

 Software Developer’s Journal   08/2007

urządzeniach  przenośnych.  Przyciski  można  podzielić  na 

dwie  grupy:  obowiązkowe  (góra,  lewo,  prawo,  dół,  strzał) 

oraz opcjonalne (A, B, C i D). Odpowiadają im następujące 

zdarzenia: 

KD _ IO _ GAMEKEYS _ UP

KD _ IO _ GAMEKEYS _ LEFT

KD _ IO _ GAMEKEYS _ RIGHT

KD _ IO _ GAMEKEYS _ DOWN

KD _ IO _

GAMEKEYS _ FIRE

KD _ IO _ GAMEKEYS _ A

KD _ IO _ GAMEKEYS _

B

KD _ IO _ GAMEKEYS _ C

  i 

KD _ IO _ GAMEKEYS _ D

.  Z  przyciska-

mi  związane  są  dane  binarne:  0  (przycisk  zwolniony)  i  1 

(przycisk  naciśnięty).  Zapytanie  o  dostępność  przycisków 

obsługujących  gry  identyfikowane  jest  poprzez  zdarze-

nie: 

KD _ IO _ GAMEKEYS _ AVAILABILITY

,  a  dane  zwracane  są 

w  zmiennej  typu 

KDint32

.  Minimalna  zwrócona  wartość  to 

31, co odpowiada dostępności podstawowych przycisków, 

maksymalna 511, gdy wszystkie przyciski są dostępne.

Analogiczną  funkcję  do  grupy 

KD _ IOGROUP _ GAMEKEYS

 

spełnia  następna  grupa  zdarzeń  wejścia-wyjścia  obsługu-

jąca  przyciski  gry,  która  identyfikowana  jest  stałą 

KD _ IO-

GROUP _ GAMEKEYSNC

. Jedyna różnica w stosunku do pierwszej 

grupy polega na braku obsługi wielu przycisków jednocze-

śnie. Zdarzenia związane z przyciskami, wśród których tak-

że  występuje  podział  na  obowiązkowe  i  opcjonalne,  iden-

tyfikowane  są  stałymi: 

KD _ IO _ GAMEKEYSNC _ UP

KD _ IO _ GA-

MEKEYSNC _ LEFT

KD _ IO _ GAMEKEYSNC _ RIGHT

KD _ IO _ GAME-

KEYSNC _ DOWN

KD _ IO _ GAMEKEYSNC _ FIRE

KD _ IO _ GAMEKEY-

SNC _ A

KD _ IO _ GAMEKEYSNC _ B

KD _ IO _ GAMEKEYSNC _ C

  i 

KD _

IO _ GAMEKEYSNC _ D

. Zapytanie o dostępność przycisków z tej 

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ą-

zane  są  dane  binarne:  0  (przycisk  zwolniony)  i  1  (przy-

cisk  naciśnięty).  Zapytanie  o  dostępność  przycisków  tele-

fonu identyfikowane jest poprzez zdarzenie 

KD _ IO _ PHONE-

KEYPAD _ AVAILABILITY

, a dane zwracane są w zmiennej typu 

KDint32.  Minimalna  zwrócona  wartość  to  0xfff  (dostępne 

przyciski  podstawowe),  wartość  maksymalna  0x3fff  (do-

stępne wszystkie przyciski).

Grupa  zdarzeń  związanych  z  wibracją,  identyfikowana 

stałą 

KD _ IOGROUP _ VIBRATE

,  zawiera  zarówno  zdarzenia  wej-

ściowe jak i wyjściowe.

Wyjście  to  głośność  wibracji  (stała 

KD _ IO _ VIBRATE _

VOLUME

) i dostępna opcjonalnie jej częstotliwość (stała 

KD _

IO _ VIBRATE _ FREQUENCY

).  Obie  wartości  opisują  dane  ty-

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 

oznacza 25Hz). Zdarzenia wejściowe są opcjonalne i zwra-

cają  informacje  o  minimalnej  (stała 

KD _ IO _ VIBRATE _ MIN-

FREQUENCY

)  i  maksymalnej  (stała 

KD _ IO _ VIBRATE _ MAXFRE-

QUENCY

)  dostępnej  częstotliwości  wibracji.  Obie  wartości 

opisywane  są  liczbami  typu  KDint32  i  wyrażane  w  mHz. 

Zdarzenie związane z zapytaniem o dostępne zdarzenia z 

grupy 

KD _ IOGROUP _ VIBRATE

  identyfikowane  jest  stałą 

KD _

IO _ VIBRATE _ AVAILABILITY

. Ponieważ opcjonalne zdarzenia 

z tej grupy związane z częstotliwością wibracji muszą być 

dostępne wspólnie (nie ma możliwości, aby implementacja 

obsługiwała tylko jedno lub dwa), dane binarne zwracane 

w wyniku zdarzenia 

KD _ IO _ VIBRATE _ AVAILABILITY

, zawar-

te w liczbie typu 

KDint32

, mogą przyjąć wyłącznie wartość 

9 (brak obsługi częstotliwości wibracji) lub 31 (dostępność 

obsługi częstotliwości wibracji).

Kolejną  grupą  zdarzeń  wejścia-wyjścia  są  zdarzenia 

związane  ze  wskaźnikiem  (stała 

KD _ IOGROUP _ POINTER

).  Za 

pośrednictwem  zdarzeń  z  tej  grupy  mogą  być  obsługiwane 

różnego  rodzaju  urządzenia  wskazujące,  np.  ekran  dotyko-

wy,  mysz  albo  gładzik  (ang.  trackpad).  Warto  zauważyć,  że 

rozważane jest utworzenie wydzielonej grupy zdarzeń prze-

znaczonych wyłącznie do obsługi myszki. Z obsługą wskaź-

nika  związane  są  trzy  zdarzenia  wejściowe  identyfikowane 

stałymi: 

KD _ IO _ POINTER _ X

KD _ IO _ POINTER _ Y

  oraz 

KD _

IO _ POINTER _ SELECT

.  Pierwsze  dwa  to  współrzędne  położe-

nia wskaźnika określane liczbami typu 

KDint32

. Używane są 

Rysunek 5. 

Efekt działania programu Quadric

Funkcje obsługi pamięci oraz pamięci 

lokalnej wątków (TLS)

Obsługę  pamięci  w  OpenKODE  zapewniają  funkcje: 

kdMalloc

kdFree

 i 

kdRealloc

, które są odpowiednikami funkcji 

malloc

free

 

realloc

 z języka C. Jedyna różnica polega na zgłaszaniu przez 

kdMalloc

 i 

kdRealloc

 błędu 

KD_ENOMEM

 przy braku pamięci (funkcje 

C nie modyfikowały wartości 

errno

).

Wprawdzie obecna tymczasowa specyfikacja OpenKODE nie 

wspiera  wielowątkowości,  to  jednak  zdefiniowane  zostały  dwie 
funkcje  obsługujące  pamięć  lokalną.  Są  to: 

kdGetTLS

  (pobranie 

wskaźnika  do  pamięci  lokalnej)  i 

kdSetTLS

  (zapis  wskaźnika  do 

pamięci lokalnej). W przypadku wprowadzenia obsługi wielowąt-
kowości, obie funkcje będą działały w pamięci lokalnej wątków.

background image

31

OpenKODE

www.sdjournal.org

Software Developer’s Journal   08/2007

współrzędne  kartezjańskie,  gdzie  przestrzeń  robocza  okna 

odzwierciedla  pierwszą  ćwiartkę  układu,  a  zakresy  zwraca-

nych  współrzędnych  zawierają  się  od  zera  do  odpowiednio 

pomniejszonej  o  jeden  wysokości  lub  szerokości  okna  mie-

rzonego w pikselach. Trzecie zdarzenie 

KD _ IO _ POINTER _ SE-

LECT

 zwraca stan przycisku wskaźnika w postaci danej binar-

nej  o  dwóch  możliwych  wartościach:  1  (przycisk  wskaźnika 

przyciśnięty) i 0 (przycisk wskaźnika zwolniony). Zauważmy, 

że  OpenKODE  udostępnia  obsługę  tylko  jednego  przycisku 

wskaźnika.  Nie  ma  także  możliwości  sprawdzenia  dostęp-

ności wskaźnika. Następna grupa zdarzeń wejścia-wyjścia to 

podświetlenie ekranu identyfikowane stałą 

KD _ IOGROUP _ BAC-

KLIGHT

. W tej grupie znajduje się jedno zdarzenie wyjściowe 

(stała 

KD _ IO _ BACKLIGHT _ FORCE

),  które  określa  stopień  pod-

świetlenia ekranu za pomocą liczby typu 

KDint32

. Wartość 0 

oznacza domyślne podświetlenie (jest to wartość początko-

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 

kierunkowymi:  góra,  lewo  (opcjonalny),  prawo  (opcjonalny), 

dół  oraz  przyciskiem  selekcji,  które  identyfikowane  są  po-

przez następujące zdarzenia wejściowe: 

KD _ IO _ JOGDIAL _ UP

KD _ IO _ JOGDIAL _ LEFT

KD _ IO _ JOGDIAL _ RIGHT

KD _ IO _ JOG-

DIAL _ DOWN

 i 

KD _ IO _ JOGDIAL _ SELECT

. Wszystkie te zdarzenia 

generują dane binarne, gdzie wartość 1 oznacza naciśnięcie 

przycisku, a 0 zwolnienie przycisku. Zapytanie o dostępność 

pokrętła jog dial identyfikowane jest poprzez zdarzenie: 

KD _

IO _ JOGDIAL _ AVAILABILITY

, gdzie dane zwracane są w zmien-

nej  typu 

KDint32

.  Przy  dostępności  wszystkich  przycisków 

zwracana  jest  wartość  31,  w  pozostałych  przypadkach  bę-

dzie to wartość 25.

Ostatnią  grupą  zdarzeń  wejścia-wyjścia  są  zdarzenia 

związane z obsługą dżojstika (lub dżojstików) opisane stałą 

KD _ IOGROUP _ JOYSTICK

. W bibliotece OpenKODE dżojstik za-

wiera następujące elementy: jeden lub więcej drążków (ang. 
sticks) z dwiema lub trzema osiami obrotu, jeden lub więcej 

przycisków (ang.  buttons), zero lub więcej kapturków (ang. 
hats)  oraz  zero  lub  więcej  kulek  (ang.  balls).  OpenKODE 

może  obsłużyć  dżojstik  posiadający  maksymalnie  16  drąż-

ków, 512 przycisków, 16 kapturków oraz 16 kulek, przy zało-

żeniu, że pojedynczy drążek posiada maksymalnie 32 przy-

ciski, 1 kapturek oraz 1 kulkę. Ponadto zarezerwowane są 

numery indeksów zdarzeń umożliwiające obsługę dodatko-

wych 63 dżojstików, przy czym każdy może zawierać takie 

same ilości elementów jak pierwszy dżojstik. Odczyt danych 

dżojstika  umożliwiają  następujące  zdarzenia  wejściowe: 

KD _ IO _ JOYSTICK _ NUMSTICKS

KD _ IO _ JOYSTICK _ NUMBUTTONS

KD _ IO _ JOYSTICK _ NUMHATS

  oraz 

KD _ IO _ JOYSTICK _ NUMBALLS

które zwracają dane w liczbach typu 

KDint32

.

Kolejne  zdarzenia  wejściowe  związane  z  obsługą  po-

jedynczego  drążka  w  dżojstiku  opisują  następujące  stałe: 

KD _ IO _ JOYSTICK _ STICK _ NUMAXES

 – ilość osi obrotu drążka 

(2  lub  3,  liczba 

KDint32

), 

KD _ IO _ JOYSTICK _ X

KD _ IO _ JOY-

STICK _ Y

KD _ IO _ JOYSTICK _ Z

  –  kąty  obrotu  drążka  w  kie-

runku osi X, Y i opcjonalnie Z (liczby 

KDint32

, zakres war-

tości od -32768 do 32767), 

KD _ IO _ JOYSTICK _ HAT _ UP

KD _

IO _ JOYSTICK _ HAT _ LEFT

KD _ IO _ JOYSTICK _ HAT _ RIGHT

KD _

IO _ JOYSTICK _ HAT _ DOWN

 – stan przycisków kapturka (dane 

binarne: wartość 1 przycisk naciśnięty, wartość 0 przycisk 

zwolniony), 

KD _ IO _ JOYSTICK _ BALL _ X

KD _ IO _ JOYSTICK _

BALL _ Y

  –  skumulowany  obrót  kulki  w  kierunku  osi  X  i  Y 

(dane 

KDint32

  z  przedziału  od 

KDINT32 _ MIN

  do 

KDINT32 _

MAX

) oraz 

KD _ IO _ JOYSTICK _ BUTTON

 – stan pierwszego 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-

nikacyjnych.  Aktualnie  OpenKODE  wspiera  wyłącznie  ko-

Rysunek 6. 

Gra WakeBreaker

Funkcje matematyczne

OpenKODE  udostępnia  typowe  funkcje  matematyczne,  w  zdecy-
dowanej większości znane ze standardowych bibliotek języka C lub 
standardu POSIX: 

kdAcosf

kdAsinf

kdAtanf

kdAtan2f

kdCosf

kdSinf

kdTanf

kdExpf

kdLogf

kdFabsf

kdPowf

kdSqrtf

kdCe-

ilf

kdFloorf

kdRoundf

kdInvsqrtf

  (odwrotność  pierwiastka 

kwadratowego) i 

kdFmodf

. Wszystkie powyższe funkcje przyjmują i 

zwracają liczby typu 

KDfloat32

. Ponadto API zawiera definicje wie-

lu typowych stałych przydatnych w obliczeniach matematycznych: 

KD_E_F

,

  KD_PI_F

KD_PI_2_F

KD_2PI_F

KD_LOG2E_F

KD_LOG10E_

F

KD_LN2_F

KD_LN10_F

KD_PI_4_F

KD_1_PI_F

KD_2_PI_F

KD_2_

SQRTPI_F

KD_SQRT2_F

KD_SQRT1_2_F

KD_MAXFLOAT

  (największa 

liczba  zmiennoprzecinkowa), 

KD_INFINITY

  (nieskończoność  –  ilo-

raz 

1.0F/0.0F

), 

KD_NAN

 (symbol nieoznaczony – iloraz 

0.0F/0.0F

), 

KD_HUGE_VALF

  (nieskończoność  –  iloraz 

1.0F/0.0F

), 

KD_DEG_TO_

RAD_F

 i 

KD_RAD_TO_DEG_F

.

background image

32

Programowanie

C/C++

www.sdjournal.org

 Software Developer’s Journal   08/2007

Listing 3. 

Program Sześcian (fragmenty)

[

...

]

// obsługa przycisków gry

void

 

KeyHandler

 

(

const

 

KDEvent

 

*

event

)

{

  

 // pobranie stanu przycisków kierunkowych

   

KDint32

 

keys

;

   

kdInputPollb

 

(

KD_IO_GAMEKEYS_UP

,4,

&

keys

);

  

 // KD_IO_GAMEKEYSNC_UP

   

if

 

(

keys

 

&

 0x01

)

      

rotatex

 

-=

 5.0

;

  

 // KD_IO_GAMEKEYSNC_LEFT

   

if

 

(

keys

 

&

 0x02

)

      

rotatey

 

-=

 5.0

;

  

 // KD_IO_GAMEKEYSNC_RIGHT

   

if

 

(

keys

 

&

 0x04

)

      

rotatey

 

+=

 5.0

;

  

 // KD_IO_GAMEKEYSNC_DOWN

   

if

 

(

keys

 

&

 0x08

)

      

rotatex

 

+=

 5.0

;

  

 // przycisk strzału - wyjście z programu

   

if

 

(

event

 

->

 

data

.

input

.

index

 

==

 

KD_IO_GAMEKEYSNC_FIRE

)

   

{

     

 // utworzenie i sygnalizacja zdarzenia

      

KDEvent

 

*

ev

 

=

 

kdCreateEvent

 

();

      

ev

 

->

 

type

 

=

 

KD_EVENT_QUIT

;

      

kdPostEvent

 

(

ev

);

   

}

}

// program główny

KDint

 

kdMain

 

(

KDint

 

argc

const

 

KDchar

 

**

argv

)

{

  

 // utworzenie okna

   

KDWindow

 

*

window

 

=

 

kdCreateWindow

 

(

KD_NULL

,

KD_NULL

);

  

 // rozmiary okna

   

kdSetWindowSize

 

(

window

,500,500

);

  

 // tytuł okna

   

kdSetWindowCaption

 

(

window

,

"Sześcian"

);

  

 // wyświetlenie okna

   

kdShowWindow

 

(

window

,

KD_WINDOWSTATUS_VISIBLE

);

  

 // włączenie obsługi przycisków gry

   

kdInputEventEnable

 

(

KD_IOGROUP_GAMEKEYSNC

,

KD_TRUE

);

  

 // dowiązanie funkcji zwrotnej obsługującej przyciski gry

   

kdInstallCallback

 

(

KeyHandler

,

KD_EVENT_INPUT

,

KD_NULL

);

  

 // włączenie obsługi wskaźnika

   

kdInputEventEnable

 

(

KD_IOGROUP_POINTER

,

KD_TRUE

);

[

...

]

  

 // utworzenie licznika czasu sterującego wyświetleniem 

sceny 3D

   

KDTimer

 

*

timer

 

=

 

kdSetTimer

 

(

0,

KD_TIMER_ONESHOT

,

KD_NULL

);

  

 // struktura z opisem zdarzeń

   

const

 

KDEvent

 

*

event

;

  

 // dane do obsługi wskaźnika

   

KDint32

 

pointer_x

,

pointer_y

;

   

bool

 

pointer_select

 

=

 

false

;

  

 // główna pętla obsługi zdarzeń

   

while

 

((

event

 

=

 

kdWaitEvent

 

(-

1

))

 

!=

 

KD_NULL

)

      

switch

 

(

event

 

->

 

type

)

      

{

[

...

]

           

 // wyświetlenie zawartości sceny 3D

         

case

 

KD_EVENT_TIMER

:

            

kdCancelTimer

 

(

timer

);

                  

Reshape

 

(

display

,

window_surface

);

            

Display

 

(

display

,

window_surface

);

            

timer

 

=

 

kdSetTimer

 

(

0,

KD_TIMER_ONESHOT

,

KD_NULL

);

            

break

;

[

...

]

      

}

  

 // wyjście

   

return

 0

;

}

Funkcje operujące na ciągach znaków

Większość  funkcji  OpenKODE  operujących  na  ciągach  znaków 
ma  swoje  odpowiedniki  w  bibliotekach  standardowych  języka  C: 

kdMemchr

kdMemcmp

kdMemcpy

kdMemmove

kdMemset

kdStrchr

kdStrcmp

kdStrlen

kdStrnlen

  (długość  ciągu  znaków  z  ograni-

czeniem  maksymalnym), 

kdStrncat_s

  (łączenie  ciągów  znaków 

z ograniczeniem maksymalnej długości), 

kdStrncmp

kdStrcpy_s

 i 

kdStrncpy_s

 (kopiowanie ciągów znaków z ograniczeniem maksy-

malnym). Funkcje z przyrostkiem 

_s

 są bezpieczniejszymi wersjami 

standardowych funkcji języka C.

munikację w dziedzinie Internetu – protokoły TCP (transmi-

sja połączeniowa) i UDP (transmisja bezpołączeniowa), oba 

działające  na  IPv4.  Możliwe  jednak,  że  w  przyszłych  wer-

sjach biblioteka OpenKODE wzbogaci się o obsługę innych 

protokołów komunikacyjnych.

Odpowiednikami funkcji obsługujących gniazda sieciowe 

w standardach BSD/POSIX są następujące funkcje bibliote-

ki OpenKODE: 

kdNameLookup

 (

gethostbyname

), 

kdSocketCreate

 

(

socket

), 

kdSocketBind

 (

bind

), 

kdSocketGetName

 (

getsockname

), 

kdSocketConnect

  (

connect

), 

kdSocketListen

  (

listen

), 

kdSocke-

tAccept

  (

accept

), 

kdSocketSend

  (

send

), 

kdSocketSendTo

  (

send-

to

), 

kdSocketRecv

  (

recv

)  oraz 

kdSocketRecvFrom

  (

recvfrom

). 

W  nawiasach  podano  nazwy  funkcji  BSD/POSIX.  Bibliote-

ka OpenKODE zawiera także odpowiedniki wybranych funk-

cji  narzędziowych  BSD/POSIX  przydatnych  przy  obsłudze 

gniazd  sieciowych.  Są  to: 

kdHtonl

  (

htonl

), 

kdHtons

  (

htons

), 

kdNtohl

 (

ntohl

), 

kdNtohs

 (

ntohs

), 

kdInetAton

 (

inet _ aton

) oraz 

kdInetNtoa

  (

inet _ ntoa

).  W  nawiasach  znajdują  się  oczy-

wiście  nazwy  funkcji  BSD/POSIX.  Wspomniane  wcześniej 

rodzaje  protokołów  połączeniowych  określają  stałe: 

KD _

SOCK _ TCP

  –  protokół  TCP  i 

KD _ SOCK _ UDP

  –  protokół  UDP. 

Gniazdo  w  bibliotece  OpenKODE  identyfikowane  jest  po-

przez strukturę 

KDSocket

. Struktura ta nie jest jednak zgod-

na ze strukturą 

KDFile

 identyfikującą plik, stąd na gniazdach 

nie są dopuszczalne typowe operacje plikowe. Z tego także 

powodu OpenKODE zawiera odrębną funkcję 

kdSocketClose

której zadaniem jest zamknięcie gniazda. Drugą niestandar-

background image

OpenKODE

33

www.sdjournal.org

Software Developer’s Journal   08/2007

dową  funkcją  jest 

kdNameLookupCancel

,  która  przerywa  po-

branie  adresu  IPv4  rozpoczęte  wywołaniem  asynchronicz-

nej funkcji 

kdNameLookup

.

Podstawową  strukturą  opisującą  adres  sieciowy  gniaz-

da jest struktura 

KDSockaddr

. Zawiera ona dwa pola: 

sa _ fa-

mily

 – rodzina protokołów (typ 

KDint16

) oraz 

sa _ data

 – wła-

ściwy adres (typ 

KDuint8[14]

). Ponieważ OpenKODE obsłu-

guje wyłącznie protokoły internetowe, pole 

sa _ family

 może 

przyjąć  jedynie  wartość 

KD _ AF _ INET

,  która  jest  odpowied-

nikiem stałej 

AF _ INET

 z BSD/POSIX. Z tą rodziną protoko-

łów związana jest struktura 

KDSockaddr _ in

, która w prakty-

ce  poprzez  rzutowanie  zastępuje  strukturę  bazową 

KDSoc-

kaddr

. Struktura 

KDSockaddr _ in

 posiada trzy pola: 

sin _ fa-

mily

  –  rodzina  protokołów  (odpowiednik  funkcjonalny  pola 

sa _ family

  struktury 

KDSockaddr

,  wartość 

KD _ AF _ INET

,  typ 

KDint16

), 

sin _ address

 – adres IPv4 (typ 

KDuint32

) oraz 

sin _

port

  –  numer  portu  (typ 

KDuint16

,  sieciowa  kolejność  baj-

tów). Dostępna jest także stała 

KD _ INADDR _ ANY

, będąca od-

powiednikiem stałej 

INADDR _ ANY

 standardów BSD/POSIX. Z 

obsługą gniazd sieciowych w bibliotece OpenKODE związa-

ne są następujące zdarzenia:

•  

KD _ EVENT _ SOCKET _ READABLE

  –  sygnalizacja,  że  gniazdo 

jest  w  trybie  do  odczytu  (funkcje 

kdSockedBind

  i 

kdSocke-

tAccept

),

•  

KD _ EVENT _ SOCKET _ WRITABLE

 – sygnalizacja, że gniazdo jest 

w trybie do zapisu (funkcje 

kdSockedCreate

 i 

kdSocketAccept

),

•  

KD _ EVENT _ SOCKET _ ERROR

 – sygnalizacja wystąpienia błę-

du  (funkcje 

kdSockedCreate

kdSocketAccept

kdSocketSend

kdSocketRecv

kdSocketSendTo

 i 

kdSocketSendTo

),

•  

KD _ EVENT _ SOCKET _ INCOMING

  –  gniazdo  wykryło  połącze-

nie  przychodzące  lub  wystąpił  błąd  (funkcje  kdSocketLi-

sten i 

kdSocketAccept

),

•  

KD _ EVENT _ SOCKET _ CONNECT _ COMPLETE

  –  zdarzenie  gene-

rowane po ukończeniu połączenia gniazda (funkcje 

kdSoc-

ketConnect

kdSocketListen

 i 

kdSocketAccept

),

•  

KD _ EVENT _ NAME _ LOOKUP _ COMPLETE

  –  zakończenie  pobie-

rania adresu węzła (funkcja 

kdNameLookup

).

Funkcje 

kdSocketCreate

kdSocketAccept

kdNameLookup

kdNa-

meLookupCancel

  zawierają  dodatkowy  parametr 

eventuserptr

który jest przekazywany przy wystąpieniu zdarzenia związa-

nego z gniazdem jako parametr 

userptr

 struktury 

KDEvent

. Z 

czterema pierwszymi zdarzeniami przekazywane są dane za-

warte  w  następujących  strukturach: 

KDEventSocketReadable

KDEventSocketWritable

KDEventSocketError

  i 

KDEventSocketIn-

coming

. Struktury te zawierają jedynie pole 

socket

 zawierające 

wskaźnik na strukturę 

KDSocket

 identyfikującą gniazdo, z któ-

rym związane jest dane zdarzenie.

Przy zdarzeniu 

KD _ EVENT _ SOCKET _ CONNECT _ COMPLETE

 da-

ne przekazywane są w strukturze 

KDEventSocketConnect

, któ-

ra oprócz pola 

socket

, zawiera także pole 

error

 typu 

KDint32

Pole  to  może  przyjąć  wartość  jednego  z  następujących  ko-

dów  błędów: 

KD _ EADDRINUSE

KD _ EAFNOSUPPORT

KD _ EALRE-

ADY

KD _ ECONNREFUSED

KD _ ECONNRESET

KD _ EHOSTUNREACH

KD _

EINVAL

, KD_EIO, 

KD _ EISCONN

 lub 

KD _ ETIMEDOUT

. W przypadku 

braku błędu pole 

error

 przyjmuje wartość 0. Z ostatnim zda-

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 

węzła umieszczany jest w polu 

result

 będącym wskaźnikiem 

do struktury 

KDSockaddr

 (lub 

KDSockaddr _ in

), a pole 

error

 ty-

pu 

KDint32

  przyjmuje  wartość  0.  Wielkość  zwróconej  struk-

tury zawiera pole 

resultlen

 typu 

KDint32

. Struktura 

KDEvent-

NameLookup

 zawiera jeszcze pole more typu 

KDboolean

, które 

wskazuje, czy w kolejce zdarzeń dostępne jest kolejne zda-

rzenie zawierające następny pobrany adres IP. W przypadku 

wystąpienia błędu, wspomniane pole 

error

 przyjmuje jedną z 

wartości: 

KD _ HOST _ NOT _ FOUND

 – nie odnaleziono węzła, 

KD _

NO _ DATA

 – nazwa węzła jest poprawna, ale nie posiada ad-

resu, 

KD _ NO _ RECOVERY

 – nienaprawialny błąd serwera nazw, 

KD _ TRY _ AGAIN

  –  tymczasowy  błąd  serwera  nazw,  możliwe 

ponowne zapytanie.

Obsługa okien

Jak już napisaliśmy na wstępie, biblioteka OpenKODE do two-

rzenia kontekstów graficznych w systemach udostępniających 

mechanizm okien wykorzystuje bibliotekę EGL. Okna w biblio-

tece  OpenKODE  identyfikowane  są  za  pomocą  uchwytów  – 

struktur 

KDWindow

.

Utworzenie okna dla wybranej płaszczyzny wyświetlania, 

wygenerowanej przez bibliotekę EGL, sprowadza się do wy-

wołania jednej z dwóch funkcji:

KDWindow *kdCreateFullScreenWindow (EGLDisplay  §
 display, const void *mode, void *eventuserptr)
KDWindow *kdCreateWindow  §
 (EGLDisplay display, void *eventuserptr)

Różnica  w  działaniu  powyższych  funkcji  sprowadza  się 

oczywiście do rodzaju utworzonego okna. Pierwsza z funk-

cji  utworzy  okno  obejmujące  cały  ekran,  które  domyślnie 

jest widoczne. Druga funkcja tworzy okno początkowo nie-

Funkcje licznika czasu

OpenKODE  obsługuje  wiele  liczników  czasu,  zarówno  wywoływa-
nych jednorazowo jak i periodycznie, z których każdy generuje zda-
rzenie  po  upływie  zaprogramowanego  czasu.  Utworzenie  licznika 
wymaga wywołania funkcji:

KDTimer *kdSetTimer (KDint64 interval, KDint periodic, void 

*eventuserptr)

Sposób działania licznika określa parametr 

periodic

, który przyjmu-

je jedną z trzech wartości: 

KD_TIMER_ONESHOT

 (licznik wywoływany 

jednokrotnie po upływie czasu nie krótszego niż określony w para-
metrze 

interval

), 

KD_TIMER_PERIODIC_AVERAGE

 (licznik wywoływa-

ny periodycznie po upływie czasu zbliżonego do określonego w pa-
rametrze 

interval

), 

KD_TIMER_PERIODIC_MINIMUM

 (licznik wywoły-

wany periodycznie po upływie czasu nie krótszego niż określony w 
parametrze 

interval

). Czas reakcji licznika, zawarty w parametrze 

interval

, określany jest w nanosekundach, przy czym rzeczywista 

dokładność licznika zależy oczywiście od możliwości systemu ope-
racyjnego. W ostatnim parametrze można umieścić wskaźnik na da-
ne przekazywane wraz ze zdarzeniem licznika (pole 

userptr

 struk-

tury 

KDEvent

), które identyfikowane jest stałą 

KD_EVENT_TIMER

.

Funkcja 

kdSetTimer

  zwraca  wskaźnik  do  struktury 

KDTimer

 

identyfikującej  licznik.  Struktura  ta  jest  potrzebna  do  usunięcia 
licznika przy użyciu funkcji 

kdCancelTimer

.

background image

34

Programowanie

C/C++

www.sdjournal.org

 Software Developer’s Journal   08/2007

widoczne i jest dostępna wyłącznie w systemach obsługują-

cych wiele okien.

Parametr display zawiera wskaźnik na płaszczyznę wy-

świetlenia  utworzoną  przez  bibliotekę  EGL.  Wskaźnik  na 

dane,  zawarty  w  parametrze 

eventuserptr

,  przekazywany 

jest przy obsłudze zdarzeń związanych z oknami jako war-

tość  pola 

userptr

  struktury 

KDEvent

.  W  przypadku  podania 

wartości 

KD _ NULL

,  pole 

userptr

  otrzyma  wartość  wskaźni-

ka na uchwyt okna, z którym związane jest zdarzenie. Pa-

rametr 

mode

  funkcji 

kdCreateFullScreenWindow

  może  przyjąć 

jedynie  wartość 

KD _ NULL

.  Usunięcie  okna  wymaga  wywo-

łania funkcji:

void kdDestroyWindow (KDWindow *window)

Przy usuwaniu okna zwalniane są także wszystkie przydzie-

lone wraz z nim zasoby. Należy jednak pamiętać, aby zaso-

by  przydzielone  przez  bibliotekę  EGL  zwolnić  przed  usunię-

ciem okna.

Początkowe rozmiary i położenie okna utworzonego przy 

użyciu  funkcji 

kdCreateWindow

  są  nieokreślone.  Zmianę  tych 

parametrów umożliwiają funkcje:

KDint kdSetWindowPosition (KDWindow *window, KDint x, KDint y)
KDint kdSetWindowSize (KDWindow *window, KDint width,  §
 KDint height)

Zmianę  statusu  widzialności  okna  utworzonego  przy  użyciu 

funkcji 

kdCreateWindow

 umożliwia funkcja:

KDint kdShowWindow (KDWindow *window, KDint status)

której parametr status przyjmuje jedną z trzech wartości: 

KD _

WINDOWSTATUS _ HIDDEN

 – okno niewidoczne, 

KD _ WINDOWSTATUS _

VISIBLE

 – okno widoczne oraz 

KD _ WINDOWSTATUS _ MINIMIZED

 – 

okno  zminimalizowane.  Kolejne  dwie  funkcje  umożliwiające 

modyfikację stanu okna to:

KDint kdActivateWindow (KDWindow *window)
KDint kdSetWindowCaption (KDWindow  §
 *window, const KDchar *caption)

Pierwsza z nich zmienia status okna na aktywny (okno otrzy-

muje fokus). Od implementacji zależy zachowanie okna – czy 

jest ono w momencie wywołania tej funkcji ukryte, czy zminima-

lizowane. Druga funkcja pozwala na zmianę tytułu okna na ciąg 

znaków umieszczony w parametrze 

caption

 (w formacie UTF-

8). Od implementacji zależy gdzie i w jaki sposób wyświetlany 

jest tytuł okna, a także jaka jest jego maksymalna długość.

Ostatnie  funkcje  operujące  na  oknach  spełniają  zadania 

pomocnicze. Pierwsza:

void *kdGetWindowNativeType (KDWindow *window)

zwraca wskaźnik do uchwytu okna specyficznego dla danego 

systemu. Uchwyt ten jest wymagany przez bibliotekę EGL przy 

tworzeniu powierzchni – funkcja 

eglCreateWindowSurface

. Dru-

ga funkcja zwraca położenie lewego górnego narożnika okna:

KDint kdGetWindowPosition (KDWindow *window, KDint *x, KDint *y)

Z obsługą okien związane są następujące zdarzenia:

•  

KD _ EVENT _ WINDOW _ CLOSE

 – zamknięcie okna,

•  

KD _ EVENT _ WINDOW _ RESIZE

 – zmiana rozmiaru okna,

•  

KD _ EVENT _ WINDOW _ FOCUS

  –  uzyskanie,  bądź  utrata  foku-

sa.

Przy wystąpieniu dwóch pierwszych zdarzeń nie są przekazy-

wane dodatkowe informacje, natomiast 

z  ostatnim  zdarzeniem  związana  jest  struktura 

KDEven-

tWindowFocus

,  która  zawiera  jedno  pole 

hasfocus

  (liczba  typu 

KDint

). Wartość 

0

 oznacza, że okno utraciło fokus, natomiast 

uzyskanie fokusa sygnalizowane jest wartością 

1

. W każdym 

z trzech powyższych zdarzeń wartość pola userptr struktury 

KDEvent

 zawiera dane przekazane w parametrze 

eventuserptr

 

przy  wywołaniu  funkcji 

kdCreateWindow

  lub 

kdCreateFullScre-

enWindow

 lub wartość uchwytu okna, która jest przyjęta auto-

matycznie przez bibliotekę.

Programy przykładowe

Programy  przykładowe  kompilowano  w  systemie  operacyj-

nym Microsoft Windows XP SP2 przy użyciu kompilatora Mi-

crosoft  Visual  C++  2005  Express  Edition  z  pakietem  Micro-

soft Platform SDK for Windows Server 2003 R2. Wykorzysta-

no implementację OpenKODE autorstwa firmy Acrodea oraz 

implementację bibliotek EGL, OpenGL ES i OpenVG z pakie-

tu Rasteroid 3.1 firmy Hybrid Graphics. Użyta implementacja 

biblioteki OpenKODE została skompilowana jako jednowątko-

wa, stąd wymagana jest konsolidacja programu z jednowąt-

kowymi  bibliotekami  RTL.  Wymaga  to  modyfikacji  standar-

dowych ustawień w kompilatorze Visual C++ 2005 Express. 

Przykładowe  programy  konstruowano  z  zamiarem  ilustra-

Funkcje obsługujące system plików

Zdecydowaną  większość  funkcji  obsługujących  system  plików  bi-
blioteka  OpenKODE  przejęła  bezpośrednio  z  języka  C  i  standar-
du  POSIX: 

kdFopen

kdFclose

kdFflush

kdFread

kdFwrite

kdGetc

kdPutc

kdFgets

kdFEOF

kdFerror

kdClearerr

kdFse-

ek

kdFtell

kdMkdir

kdRmdir

kdRename

kdRemove

kdTrunca-

te

kdStat

kdFstat

kdOpenDir

kdReadDir

kdCloseDir

kdGet-

Free

 (zwolnienie pamięci przydzielonej na nazwę pliku lub katalo-

gu), 

kdChdir

 oraz 

kdGetCwd

.

Funkcje obsługujące pliki korzystają ze struktury 

KDFile

. Do-

stępne  są  także  odpowiedniki  stałych: 

KD _ EOF

KD _ SEEK _ SET

KD _ SEEK _ CUR

 i 

KD _ SEEK _ END

. Dane o pliku lub katalogu (lub 

urządzeniu  identyfikowanym  w  systemie  jako  plik),  pobierane 
przez funkcje 

kdStat

 i 

kdFstat

, zwracane są w strukturze 

KDStat

Struktura ta zawiera następujące pola: 

st _ size

 – rozmiar pliku w 

bajtach, 

st _ mtime

 – czas ostatniej modyfikacji oraz 

st _ mode

 – 

informacja o pliku/katalogu oraz prawach dostępu. Odczyt ostat-
niego pola odbywa się za pośrednictwem makr: 

KD _ ISREG

 – czy 

jest plik, 

KD _ ISDIR

 – czy jest katalog, 

KD _ READABLE

 – czy są pra-

wa odczytu pliku/katalogu oraz 

KD _ WRITABLE

 – czy są prawa za-

pisu pliku/katalogu.

Funkcje  obsługujące  katalogi  (

kdOpenDir

kdReadDir

  i 

kdC-

loseDir

) wykorzystują strukturę 

KDDir

. Przy odczycie następne-

go pliku w wybranym katalogu funkcja 

kdReadDir

 zwraca struktu-

rę 

KDDirent

. Struktura ta zawiera jedno pole 

d _ name

 określające 

nazwę odczytanego pliku.

background image

35

OpenKODE

www.sdjournal.org

Software Developer’s Journal   08/2007

cji wykorzystania biblioteki OpenKODE, stąd większość ele-

mentów dotyczących OpenGL ES i OpenVG pochodzi z pro-

gramów  przykładowych  dostępnych  w  wymienionych  wyżej 

pakietach oraz w referencyjnej implementacji biblioteki Ope-

nVG autorstwa Khronos Group.

Program przedstawiony na Listingu 1. rysuje przy uży-

ciu  biblioteki  OpenVG  popularny  rysunek  głowy  tygrysa. 

Poruszanie  wyświetlanym  obrazem  umożliwia  przycisk 

wskaźnika,  czyli,  w  przypadku  użytej  implementacji,  lewy 

przycisk  myszki.  Dodatkowo  przyciski  gry: 

KD _ IO _ GAME-

KEYSNC _ A

KD _ IO _ GAMEKEYSNC _ B

KD _ IO _ GAMEKEYSNC _ C

  i 

KD _ IO _ GAMEKEYSNC _ D

  (w  stosowanej  implementacji  są  to 

przyciski  1,  2,  3  i  4)  umożliwiają  powiększenie  obrazu  od 

jednego do czterech razy. Ponieważ są to przyciski opcjo-

nalne,  przed  włączeniem  obsługi  związanej  z  nimi  gru-

py  zdarzeń  wejścia-wyjścia,  program,  korzystając  z  funk-

cji 

kdInputPolli

,  sprawdza  ich  dostępność.  Warto  zwrócić 

uwagę  na  to,  że  umożliwienie  programowi  przetwarzania 

zdarzeń związanych ze wskaźnikiem i przyciskami gry wy-

magało  dwukrotnego  wywołania  funkcji 

kdInputEventEna-

ble

. Obsługa wszystkich zdarzeń zawarta jest w pojedyn-

czej pętli umieszczonej w ciele funkcji 

kdMain

. Początkowe 

okno programu przedstawia Rysunek 3.

Drugi przykładowy program (Listing 3.) korzystając z bi-

blioteki  OpenGL  ES  rysuje  wielobarwny  sześcian.  W  sto-

sunku  do  pierwszego  przykładu  zmieniono  obsługę  przyci-

sków gry tworząc wywoływaną zwrotnie funkcję 

KeyHandler

Stan przycisków kierunkowych gry odczytywany jest za po-

średnictwem pojedynczego wywołania funkcji 

kdInputPollb

, a 

stan przycisku „strzał” (w stosowanej implementacji – spacja) 

określany  jest  na  podstawie  wartości  pola 

data.input.index

 

struktury 

KDEvent

.  Wciśnięcie  tego  ostatniego  przycisku  po-

woduje wygenerowanie zdarzenia 

KD _ EVENT _ QUIT

 i w konse-

kwencji  zakończenie  działania  programu.  Obroty  sześcianu 

umożliwia zarówno myszka, jak i wspomniane przyciski kie-

runkowe gry. Cykliczne rysowanie sceny 3D reguluje licznik 

czasowy  uruchamiany  każdorazowo  po  narysowaniu  sceny. 

Początkowy wygląd okna programu przedstawia Rysunek 4. 

Dodatkowo w ramach testów implementacji OpenKODE firmy 

Acrodea  skompilowano  dwa  programy  przykładowe  pocho-

dzące z pakietu intent GamePlayer ADK firmy Tao Group. Pa-

kiet ten zawiera, oprócz bibliotek OpenGL ES i EGL, imple-

mentację biblioteki OpenKODE. Pierwszym przetestowanym 

w ten sposób programem był Quadric, który wyświetla kulę 

pokrytą  teksturą  (Rysunek  5.).  Podczas  kompilacji  i  w  trak-

cie działania programu nie stwierdzono żadnych problemów. 

Drugim programem była prosta gra WakeBreaker. W tym wy-

padku  kompilacja  programu  wymagała  niewielkiej  ingerencji 

w kod źródłowy, ale nie było to związane z biblioteką Open-

KODE.  Niestety  wystąpiły  problemy  z  prawidłową  obsługą 

przycisków, co jest najprawdopodobniej związane z błędami 

w implementacji biblioteki OpenKODE. Zrzut przykładowego 

ekranu gry przedstawiamy na Rysunku 6.

Podsumowanie

OpenKODE to najnowszy projekt Khronos Group, często okre-

ślany jako odpowiednik pakietu DirectX na urządzenia przeno-

śne. Jak wspomnieliśmy na wstępie, docelowo OpenKODE po-

łączy pięć otwartych standardów opracowywanych przez Khro-

nos Group: OpenGL ES, OpenVG, OpenMAX, OpenSL ES oraz 

EGL. Pytanie może budzić celowość obecności w standardzie 

dwóch  bibliotek  graficznych:  OpenGL  ES  i  OpenVG.  Jednak 

projektowano je dla tak odmiennych zastosowań, że rozdziele-

nie grafiki trójwymiarowej od dwuwymiarowej na urządzeniach 

mobilnych wydaje się być w pełni uzasadnione. Wystarczy za-

uważyć, że do implementacji na urządzeniu przenośnym prze-

glądarki plików Flash i SVG, czy też wyświetlenia mapy drogo-

wej w zupełności wystarczy biblioteka grafiki dwuwymiarowej.

Najbardziej  rozpowszechnionym  konkurentem  OpenKO-

DE jest JavaME. Java jest stosunkowo łatwa w implementacji, 

a jej wersję opracowaną na potrzeby urządzeń przenośnych 

można w znacznym stopniu konfigurować. Jednak główną wa-

dą rozwiązań opartych o języki wykorzystujące kod pośredni, 

jakim jest Java, jest ich mniejsza szybkość w stosunku do pro-

gramów kompilowanych.

Także inne systemy operacyjne dostępne na urządzeniach 

przenośnych  (Symbian,  Palm  OS,  Windows  Mobile)  oferują 

bezpośrednio lub pośrednio funkcjonalność biblioteki OpenKO-

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ść 

standardu i możliwość kompleksowej obsługi wszystkich ele-

mentów urządzenia przenośnego. Nadzieję na rozpowszech-

nienie OpenKODE (bo pewności oczywiście nie ma) daje du-

ża  ilość  firm  wspierających  nowy  standard,  w  tym  obecność 

takich gigantów jak Nokia, NVIDIA, Samsung, Sony czy Sym-

bian. OpenKODE pojawia się w odpowiednim momencie, gdy 

rozwiązania  mobilne  oferują  coraz  większe  możliwości,  a  ich 

wykorzystanie zdaje się być prostsze, gdy mamy do czynienia 

z otwartymi i wieloplatformowymi standardami. n

Asercje i dziennik komunikatów

Wzorem języka C biblioteka OpenKODE zawiera makro 

kdAssert

 

obsługujące  asercje.  Programista  może  zmienić  standardową  ob-
sługę asercji definiując funkcję:

void kdHandleAssertion (const KDchar *condition, const KDchar 

*filename, KDint linenumber)

której parametrami są kolejno: generowany komunikat, nazwa pli-
ku oraz numer linii programu, w którym został spełniony warunek 
asercji.  Zapis  informacji  do  dziennika  komunikatów  (logu)  realizu-
je funkcja:

void kdLogMessage (const KDchar *string)

Dezaktywacja  obsługi  asercji  i  dziennika  komunikatów  sprowadza 
się do zdefiniowania w programie makra 

KD_NDEBUG

.

W Sieci

•   http://www.khronos.org  –  specyfikacje  bibliotek  OpenKODE, 

OpenGL ES, OpenVG, EGL, OpenMAX i OpenSL ES,

•   http://www.acrodea.co.jp/en/ – implementacja biblioteki Open-

KODE,

•   http://www.hybrid.fi – pakiet Hybrid Rasteroid 3.1 z implemen-

tacjami bibliotek OpenGL ES, OpenVG i EGL,

•   http://tao-group.com – pakiet intent GamePlayer ADK.