2007 08 OpenKODE [Programowanie C C ]

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

i

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-

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.


Wyszukiwarka

Podobne podstrony:
K1 2007 08 zad 5 id 229626
08 Zastosowanie programow kompu Nieznany (2)
egzamin 2007 08
2007 08 Szkola konstruktorowid Nieznany
Test dla studentów V roku 2007-08, Lekarski, Pulmonologia
2007 08 KOL2 G, I
multilingwistyczny sędzia krajowy eps 2007 08 001
koło1 2007 08
2007-08-małopolski-Ietap
2007 08 trendy
Kolokwium 2 2007 08
Kolokwium zaliczeniowe sem 1 2007 08 b w
08 technologia programowaniaid Nieznany
2007 10 Extreme Programming (XP) i CMMI – Kreatywność, czy Dyscyplina [Inzynieria Oprogramowania]
K2 2007 08 zad 3 id 229670
K2 2007 08 zad 4 id 229671
Kolokwium Zal Pr Strukturalne 2007-08, Studia, Systemy operacyjne
Histologia - egzamin 2007-08, LEKARSKO-DENTYSTYCZNY GUMED, I ROK, Histologia, Giełda

więcej podobnych podstron