wirtualny model instytutu informatyki praca inzynierska QGITVZE3MZYAIKEXBD56NSDMW4CVTRV2KNN7HII


Spis treści

  1. Wprowadzenie

    1. Kontekst przedsięwzięcia

Komputery odgrywają ważną rolę w życiu każdego człowieka. Poziom zaawansowania cywilizacyjnego doprowadził do stanu, w którym każdy obywatel, żyjący w kraju uprzemysłowionym, jest w pewien sposób zależny od komputera.

Nawet ludzie unikający tej dziedziny, próbujący oddzielić się od wszelkiej informatyzacji lub na pierwszy rzut oka niemający z nią nic wspólnego, są na komputery skazani. Informatyzacja jest coraz bardziej powszechna w administracji, medycynie, szkolnictwie, sztuce, motoryzacji, komunikacji, rozrywce. Dotyka praktycznie każdej dziedziny codziennego życia.

Wraz z rozwojem technologii komunikacja człowieka z komputerem przyjmuje bardziej typowy dla ludzi charakter. Dzisiejsza młodzież (i nie tylko) chętnie wykorzystuje Internet do zdobycia interesujących informacji, wypierane zostają tradycyjne nośniki muzyki, grafika komputerowa staje się bardziej realistyczna. Standardem staje się przenoszenie filmów adresowanych do młodzieży na ekrany komputerów i konsol do gier.

Jaki jest powód takiego działania? Otóż poziom realizmu gier komputerowych stał się wystarczający, aby gracz poczuł się jak bohater uczestniczący w akcji. W dużej mierze jest to zasługa prężnie rozwijającej się dziedziny informatyki jaką jest grafika komputerowa. Jednakże rozrywka to nie jedyne zastosowanie dla nowości w zakresie multimediów.

Did not finish!

    1. Cel i zakres pracy

Celem naszej pracy jest stworzenie interaktywnej aplikacji graficznej, która ma służyć studentom pierwszego roku informatyki jako narzędzie pomocne w zapoznaniu się z Instytutem Informatyki. Ma to być narzędzie o przyjemnym interfejsie użytkownika umożliwiające przechadzkę po korytarzu, bibliotece, gabinetach pracowników, pomieszczeniach administracyjnych i salach laboratoryjnych a także zapoznanie się z informacjami o poszczególnych pomieszczeniach i pracownikach.

Zakres pracy:

Na potrzeby projektu powstały następujące programy pomocnicze:

Szerszy opis ww. aplikacji znajduje się w dalszej części pracy.

    1. Zespół zarządzający i wykonawczy

    2. promotor

      Dr inż. Maciej Zakrzewisz

      koreferent

      Dr inż. Marek Wojciechowski

      projekt / wykonanie

      Michał Kaftański

      Jakub Malicki

      Bartosz Rudnicki

      Marcin Tucholski

        1. Podziękowania

      Podziękowania kierujemy przede wszystkim do dr inż. Macieja Zakrzewicza za odkrycie przed nami arkan grafiki komputerowej, za bardzo ciekawe przekazanie swojej wiedzy, za wzorowe prowadzenie naszej pracy inżynierskiej, za cierpliwość, dobry humor i uśmiech na twarzy oraz do dr inż. Marka Wojciechowskiego za jego bardzo cenne uwagi podczas prac związanych z powstawaniem projektu.

      Osobne podziękowania kierujemy do mgr inż. Dawida Weissa za pracę włożoną w sprawne działanie repozytorium CVS, bez którego nasza praca byłaby znacznie utrudniona i powstawałaby znacznie dłużej.

      Dziękujemy również wszystkim pracownikom Instytutu Informatyki, którzy niejednokrotnie tolerowali nasze wizyty, zaglądanie w zakamarki sal i fotografowanie ich stanowisk pracy.

      Dziękujemy również naszym rodzicom i dziewczynom za wsparcie duchowe i wyrozumiałość.

      1. Opis technologii

        1. OpenGL - historia i rozwój

      Pierwsze wzmianki o OpenGL pojawiły się już w 1992 roku na konferencji Win32 Developers Conference w San Francisco. Firma Silicon Graphics, Inc. niepodważalny do dzisiaj lider w grafice i animacji komputerowej, przy okazji prezentacji swoich nowych stacji graficznych, na których powstawały efekty specjalne do znanych filmów przedstawiła zupełnie nowy wtedy standard graficzny - OpenGL. Tego samego dnia Microsoft potwierdził wsparcie dla OpenGL na swoich Windows`ach. Podstawą do opracowania nowego standardu był własny język GL firmy Silicon Graphics - IRIS GL. Był on wówczas interfejsem API grafiki 3D dla profesjonalnych stacji roboczych IRIS. Nie były to w powszechnym rozumieniu normalne komputery osobiste, lecz superszybkie i drogie zarazem stacje graficzne zoptymalizowane od początku do końca tylko pod kątem generowania grafiki. Wykorzystywany sprzęt pozwalał wówczas na rekordowo szybkie obliczania różnych działań macierzowych, co jest podstawą grafiki trójwymiarowej. Nowy standard nie jest do końca „otwarty”, jest kontrolowany przez OpenGL Architecture Review Board w skład, którego wchodzą twórcy języka - Silicon Graphics oraz także Digital Equipment Corporation, IBM, Intel i Microsoft. Rada zbiera się najczęściej dwa razy w roku w celu zatwierdzenia nowych pomysłów czy zaktualizowania poprawek. Owe spotkania są publiczne i wiele czołowych firm komputerowych udziela głosu w rozmowach. W samym Internecie powstała grupa dyskusyjna comp.graphics.api.open.gl gdzie każdy może wysłać swoje uwagi i spostrzeżenia. Taka forma publikacji bardzo korzystnie wpływa na rozwój standardu OpenGL, bowiem staje się bardziej „otwarty”.

      OpenGL nigdy nie był dostępny dla 16-bitowych wersji Windows (tyczy się 3.1 oraz 3.11 itp.). W Windows NT 3.1 była już zaimplementowana wersja alfa (a później beta), a wkrótce podczas wydania wersji beta Windows`a NT 3.5 można było pierwszy raz podziwiać efekty grafiki 3D w środowisku OpenGL na domowych komputerach (były to wówczas prymitywne wygaszacze ekranu). Ten pierwszy zestaw bibliotek obejmował wówczas wszystkie funkcje OpenGL 1.0. W Windows NT 4.0 zostały zaktualizowane do wersji 1.1. Obecna wersja wydana 29 lipca 2003 roku jest już piątą wersją od momentu wydania pierwszej i nosi numer 1.5. Poprawki odnoszą się do polepszania dotychczas stworzonych algorytmów, ale w większości obejmują one dodawanie nowych technologii w grafice 3D - w OpenGL 1.5 dla przykładu zostaje usprawniona obsługa PixelShader oraz VertexShader, która dla porównania w DirectX występowała już w wersji 8.0, a w najnowszej 9.0 zaimplementowano najnowsze rozkazy PixelShader oraz VertexShader 2.0.

      Wielką zaletą OpenGL jest jego niezależność implementacji na praktycznie wszystkich możliwych platformach i systemach. Począwszy od Windows`ów (NT 3.5 i wzwyż), przez X Window gdzie jest obsługiwany przez praktycznie wszystkie dystrybucje Linux`a oraz na większości stacjach UNIX`a (SUN Solaris, IBM muliprocessor AIX, HP - UX, SGI IRIX, Compaq Tru64 Unix i inne). OpenGL zaimplementowany został również w Java (najnowsza wersja JavaOpenGL 1.0a3), w Fortranie (f90gl), w Perl`u (OpenGL Perl Module), w Pike, w Python`ie (PyOpenGL), w Ada. Do ciekawostek można zaliczyć mniej lub bardziej stabilne implementacje na konsoli do gier PlayStation2 czy do poczciwej Amigi (OpenGL for Amiga pod kierunkiem StormMesa oraz Amiga MiniGL)

        1. OpenGL - zakres i zastosowania

      OpenGL jest zoptymalizowany pod kątem wyświetlania i manipulowania grafiką trójwymiarową. Można powiedzieć, iż OpenGL jest językiem proceduralnym - programista opisuje kroki, które są wymagane, aby uzyskać żądany efekt. Ma do dyspozycji ponad 300 poleceń i funkcji za pomocą, których może stworzyć między innymi najprostsze figury i obiekty trójwymiarowe. Oczywiście dozwolona jest manipulacja wieloma różnymi niezbędnymi rzeczami w rzeczywistości trójwymiarowej takimi jak na przykład ustawianie kamery i oświetlenia czy mapowanie tekstur.

      OpenGL od samego początku był przeznaczony do pracy na systemach z akceleracją sprzętową. Oczywiście jest możliwa i programowa akceleracja jednakże spadek wydajności jest ogromny. Wywołania OpenGL przekazywane są poprzez sterownik klienta OpenGL oraz interfejs producenta do interfejsu sterownika grafiki trójwymiarowej (3D DDI), który z kolei jest tak zaprojektowany, aby umożliwić akcelerację sprzętową. Renomowani producenci kart graficznych od samego początku obiecywali sprzętowe wsparcie i do dzisiaj prześcigają się w szybkości generowania obiektów. Dostawcy różnych chipsetów graficznych mogą instalować własne sterowniki klienta OpenGL oraz interfejsu producenta, aby w pełni wykorzystać swoje układy.

      OpenGL wkroczył w wiele dziedzin komputerowych - od programów CAD`owskich i aplikacji architektonicznych przez najnowsze gry komputerowe kończąc na zaawansowanych środowiskach graficznych za pomocą, których powstają efekty specjalne do najnowszych filmów.

        1. OpenGL jako interfejs API

      Jak już zostało wspomniane OpenGL nie jest odrębnym językiem programowania można go najbardziej traktować jako interfejs programowania aplikacji - API (Application Programming Interface). Tak, więc pisząc program w OpenGL korzystamy z dowolnego języka programowania (np. C++ czy VisualBasic) i dopiero bezpośredniego z niego wywołujemy funkcje czy procedury biblioteki OpenGL. Standardowo zostały one podzielone na trzy osobne biblioteki.

      Pierwsza z nich - opengl32.dll zawiera oficjalne funkcje zdefiniowane według zasad Architecture Review Board. Nazwy kolejnych funkcji zaczynają się od przedrostka gl.

      Druga z nich - glaux.lib, czyli Auxiliary (zwana pomocniczą) zawiera w sobie funkcje, które nie są de-facto napisane według oficjalnej specyfikacji. Nazwy kolejnych funkcji zaczynają się od przedrostka aux. Stanowią jedynie pomoc dla początkujących programistów, można za ich pomocą w szybkim czasie uzyskać gotowy projekt. Najczęściej można z niej skorzystać przy obsłudze okien, myszy lub klawiatury czy rysowaniu najprostszych figur. Wspomnieć należy bowiem, iż sam OpenGL nie potrafi obsługiwać okien czy urządzeń zewnętrznych, zająć się tym musi sam system operacyjny - w przypadku pisania programu - język programowania, w którym tworzony jest projekt. Biblioteka AUX, mimo że stała się popularna i w związku z tym często zostaje zaimplementowana na innych platformach niż Windows, korzystanie jednak z niej sprawia, że program staje się mniej „przenośny”.

      Z kolei trzecia z dołączanych bibliotek - glu32.dll czyli Utility Library (zwana potocznie narzędziowa) jest oparta o oficjalne funkcje OpenGL, co sprawia, że będzie poprawnie działać na wszystkich systemach. Nazwy kolejnych funkcji zaczynają się od przedrostka glu. Ma w sobie oszczędzające wiele czasu pomocnicze funkcje - miedzy innymi obsługę rysowania kwadryg.

        1. Typy danych

      W OpenGL istnieją typy danych podobne do tych spotykanych w C. I tak odpowiednio:

      GLbyte

      8-bitowa liczba całkowita

      GLshort

      16-bitowa liczba całkowita

      GLint, GLsizei

      32-bitowa liczba całkowita

      GLfloat, GLclampf

      32-bitowa liczba zmiennoprzecinkowa

      GLdouble, GLclampd

      64-bitowa liczba zmiennoprzecinkowa

      GLubyte, GLboolean

      8-bitowa liczba całkowita bez znaku

      GLushort

      16-bitowa liczba całkowita bez znaku

      GLuint, Glenum, GLbitfield

      32-bitowa liczba całkowita bez znaku

      Wszystkie typy rozpoczynają się od przedrostka GL. Jak widać nazwy są adekwatne do tych, co są używane w języku C.

        1. Prymitywy

      Każdy obiekt, mniej lub bardziej złożony stworzony w OpenGL składa się z

      wielu małych i prostych kształtów. Są one rozmaicie ułożone i połączone, razem dają efekt w postaci żądanego obiektu. Właśnie te „klocki” figur nazywane są inaczej prymitywami - jedno- lub dwu-wymiarowe obiekty od prostych linii po skomplikowane wielokąty.

          1. Wierzchołek

      Implementacja wierzchołka ma różne postacie, najczęściej używana to

      glVertex3f(xf,yf,zf)

      gdzie parametrami są jak można łatwo rozpoznać po przyrostku 3f - 3 współrzędne w postaci liczb typu float.

          1. Pozostałe prymitywy

      Szkielet kodu można przedstawić następująco:

      glBegin (Glenum mode)

      glVertex(xf,yf,zf);

      //(w tej części definiuje się współrzędne wierzchołków, a także różne opcje np. ustawianie grubości linii czy określanie krawędzi wielokąta jako wewnętrzne czy zewnętrzne)

      glEnd

      GLenum mode określa się rodzaj prymitywu. Najczęściej korzystane to:

      GL_POINTS

      Każdy wierzchołek staje się pojedynczym punktem

      GL_LINES

      Tworzy linie pomiędzy kolejnymi parami wierzchołków

      GL_LINE_STRIP, GL_LINE_LOOP

      Tworzy linię łamaną (wersja LOOP daje łamaną zamkniętą)

      GL_TRIANGLES

      Tworzy trójkąty pomiędzy kolejnymi 3-ma wierzchołkami

      GL_QUAD

      Tworzy czworokąty pomiędzy kolejnymi 4-ma wierzchołkami

      GL_POLYGON

      Tworzy wielokąt wypukły ze wszystkich podanych wierzchołków

        1. Bufor głębokości, ukrywanie niewidocznych powierzchni

      Przy tworzeniu trójwymiarowych obiektów ważną kwestią staje się ustalenie tzw. stron tylnych (czyli niewidocznych) oraz przednich. Dzięki temu przy renderowaniu obiektu na ekran wyświetlana jest tylko widoczna część. Aby włączyć testowanie głębokości należy wywołać:

      glEnable(GL_DEPTH_TEST)

      W tym momencie przed renderowaniem tego samego piksela należącego do kolejnego obiektu porównywana jest wcześniejsza odległość tego piksela od obserwatora. Jeżeli jest odległość nowego piksela jest mniejsza to jest on na nowo renderowany.

      Na duży wzrost wydajności ma wpływ mechanizm nie rysowania tylnych ścian prymitywów. Poprzez definiowanie punktów prymitywu w określonej kolejności (zgodnie lub przeciwnie do ruchu wskazówek zegara) samemu określamy strony wewnętrzne i zewnętrzne.

      Mechanizm pomijania tylnych ścian jest aktywowany za pomocą funkcji:

      glEnable(GL_CULL_FACE)

      Do samego określenia przedniej strony wielokątu służy funkcja:

      glFrontFace(GLenum mode)

      gdzie kierunek jest wyznaczany zgodnie z ruchem wskazówek zegara (glFrontFace(GL_CW)) lub przeciwnie (glFrontFace(GL_CCW)).

        1. Optymalizacja renderowania

      Ze względu, iż najnowsze akceleratory graficzne są konstruowane najczęściej pod kątem szybkości renderowania trójkątów radzi się korzystanie tylko z nich, bowiem inne wymyślne kształty po prostu będą dłużej obliczane.

        1. Przekształcenia

      W OpenGL, aby uzyskać żądany widok sceny tak naprawdę musimy dokonać wielu przekształceń. Można je podzielić na przekształcenia:

      Punktu Obserwatora

      Określa położenie kamery

      Modelu

      Określa położenie obiektów w rzeczywistości trójwymiarowej

      Rzutowania

      Określa rozmiary bryły widzenia

      Widoku okna

      Określa rozmiary końcowych wymiarów okna

          1. Przekształcenia punktu obserwatora

      Implementacja:

      gluLookAt(x,y,z)

      Współrzędne punktu obserwatora można inaczej interpretować jako układ odniesienia w rzeczywistości. Domyślną wartością jest początek układu współrzędnych a kierunek patrzenie pokrywa się z osią Z w kierunku do „ekranu monitora”.

          1. Przekształcenia modelu

      Implementacja:

      glScale

      glTranslate

      glRotate

      Przekształcenia służą do ustawienia modelu i jego odrębnych obiektów. Można w ten sposób dany obiekt zarówno przesunąć (glTranslate), obrócić (glRotate) jak i zmienić rozmiar (glScale). Przy czym zmiana rozmiaru nie musi być wprost proporcjonalna w każdym kierunku - istnieje możliwość rozciągnięcia lub ściśnięcia obiektu. W przypadku wielu różnych przekształceń ważna jest kolejność wykonywanych przekształceń, bowiem efekt końcowy będzie inny - z powodów czysto matematycznych - nieprzemienności działań mnożenia macierz, o czym będzie dalej mowa.

          1. Przekształcenia rzutowania

      Implementacja:

      gluOrtho2D(left,right,bottom,top) //rzut. równoległe

      gluPerspective(fovy,aspect,zNear,zFar) //rzut. perspektywiczne

      Stosuje się w końcowym etapie tworzenia sceny. Określa bryłę widzenia - ustawia płaszczyzny obcinania widoku.

          1. Przekształcenia okna

      Mając wykonany dwuwymiarowy rzut sceny pozostaje na koniec przekształcenie okna, w którym rzut jest wyświetlany.

          1. Macierze, kolejka przekształceń

      Wszystkie wyżej wymienione przekształcenia są obliczane w OpenGL w postaci macierzy (względnie wektorów). Zanim dany wierzchołek z oryginalnych współrzędnych trafi na ekran w wyznaczone miejsce czeka go wiele obliczeń. Matematyczną drogę przedstawia poniżej rysunek:

      0x01 graphic

      Rysunek 1.Kolejność przekształceń w OpenGL

      Gdzie [x y z w] to wektor wierzchołka o współrzędnych (x,y,z) oraz skali w.

          1. Macierz tożsamościowa, stosy macierzy

      Należy pamiętać, iż każde przekształcenie jest kumulowane w macierzy widoku. Dla przykładu: po przesunięciu danego obiektu o pewne współrzędne, dla kolejnego obiektu, układem odniesienia będzie układ już po wcześniejszych przekształceniach. W celu uniknięcia tych niedogodności należy załadować macierz tożsamościową, która spowoduje powrót punktu odniesienia do początkowego układu obserwatora. Implementacja wygląda następująco:

      glMatrixMode(GL_MODELVIEW); //odwołanie do macierzy widoku modelu

      glLoadIdentity(); //załadowanie macierzy tożsamościowej do bieżącej macierzy

      Jednak nie zawsze załadowanie macierzy tożsamościowej jest korzystne - w przypadku, gdy punkt obserwacji nie znajduje się na początku układu współrzędnych. W takich przypadkach można skorzystać z mechanizmu stosu macierzy. Umieszcza się wtedy aktualną macierz na stosie. Następnie dokonuje się niezbędnych przekształceń, a na samym końcu odtwarza się stan macierzy zdejmując ją ze stosu. Przykład:

      glPushMatrix(); //Zapisanie dotychczasowych przekształceń

      //Nowe przekształcenia

      glPopMatrix(); //Odtworzenie początkowych przekształceń

        1. Rzutowania

      W ogólności mamy do czynienia z dwoma rodzajami rzutowań. W zależności od zastosowań - równoległe oraz perspektywistyczne.

          1. Rzutowanie perspektywistyczne

      Efekt jaki się uzyskuje przy tym rzutowaniu najbardziej oddaje rzeczywiste rozmiary i położenia. Obiekty wprost proporcjonalnie do odległości od punktu obserwatora zmniejszają swoje rozmiary oraz nabierają prawdziwych kształtów. Niżej podany rysunek przedstawia w jaki sposób jest renderowana scena :

      0x01 graphic

      Rysunek 2.Rzutowanie perspektywiczne

      Zasięg widoku można porównać do bryły geometrycznej - ostrosłupa. Do określenia parametrów rzutowania używamy funkcji :

      gluPerspective(GLdouble fov, GLdouble aspect, GLdouble zNear, GLdouble zFar);

      gdzie: fov - kąt widzenia

      aspect - stosunek wysokości bliższej płaszczyzny do jej szerokości

      zNear, zFar - określają odległość bliższą i dalszą płaszczyznę obcinania

          1. Rzutowanie równoległe

      W tym przypadku zasięg widoku nabiera kształtu prostopadłościanu. W związku z tym nie jest brana pod uwagę odległość obiektów od obserwatora. Wszystkie figury zachowują swoje oryginalne kształty i rozmiary. Wykorzystują takie rzutowanie najczęściej programy CAD`owskie oraz wszelakiego rodzaju aplikacje architektoniczne.

        1. Kolory

          1. Podstawowe głębokości kolorów

      W komputerach osobistych możemy spotkać się z różnymi głębokościami kolorów. Najczęściej używane to 8-bitowy (256 kolorów), 16-bitowy (high color) oraz 32-bitowy (true color). Jednakże paleta 256 kolorów praktycznie nie już jest wykorzystywana, ponieważ jest to zbyt mała liczba żeby móc sensownie przedstawić obraz czy animację.

      Tryb 16-bitowy potrafi wyświetlić na ekranie 65 536 dostępnych kolorów i jak się okazuje w praktyce jest to wystarczająca ilość.

      Z kolei tryb 32-bitowy tak naprawdę wykorzystuje 24-bity, bowiem tylko tyle można wyświetlić na ekranie - ponad 16 milionów kolorów. Jednak ze względu na optymalizację 32-bitowych procesorów - dostęp do adresów w pamięci jest szybszy po dołożeniu dodatkowych bitów.

      W OpenGL mamy do dyspozycji dwa rodzaje trybów obsługiwania kolorów.

          1. Tryb koloru RGBA

      Można w nim precyzyjnie określić barwę koloru przez podanie nasycenia każdego ze składników (RGB - czerwony, zielony oraz niebieski) na wzór powszechnie wykorzystywanego sposobu w GDI Windows`a.

      Czwartym, opcjonalnym składnikiem jest współczynnik przejrzystości alpha .

      Implementacja :

      glColorPR(red, green, blue, alpha)

      Gdzie:

      P - liczba parametrów - 3 lub 4 (w przypadku podawania współczynnika alpha)

      R - rodzaj parametrów - integer, float , double i inne

      Najczęściej wykorzystywana jest wersja glColor3f gdzie natężenie kolejnych składowych koloru podaje się w zakresie <0,1>.

      Pomocna jest również odmiana glColor3ub, w której podanie nasycenie każdego składnika jest podobne jak w gamie Windows`a - od 0 do 255.

          1. Tryb z indeksem koloru

      W tym przypadku podaje się wskaźnik na wybraną barwę w palecie zdefiniowanych już kolorów. Najczęściej jest on wykorzystywany w przypadku 8-bitowej głębokości kolorów. Istnieje, bowiem większa „elastyczność” wyboru kolorów - można uzyskać takie, które za pomocą standardowego RGB 8-bitowego nie można by było osiągnąć. Poza tym jest trochę szybszy gdyż wymaga mniejszej ilości obliczeń ze względu na mniejszą ilość bitów.

      Niestety nałożonych na niego jest wiele ograniczeń - nie można wykorzystywać pewnych efektów specjalnych w OpenGL na przykład antyaliazingu, alpha blendingu czy kilku efektów oświetlenia i cieniowania.

        1. Światła i oświetlenia

      Oświetlenie to jedna z najciekawszych i najefektywniejszych funkcji zaimplementowanych w OpenGL. W rzeczywistości obiekty i sceny nabierają dopiero uroku przy dobrze skonfigurowanych źródłach światłach i przeróżnych efektach wspieranych przez OpenGL.

      Na każdy obiekt tak naprawdę przypadają trzy rodzaje świateł światło otaczające, światło rozproszone, światło odbłyskowe.

      Światło otaczające - nie pochodzi z żadnego określonego kierunku - jest wszechobecne na scenie. Tak więc dany obiekt odbija promienie światła z każdej strony równomiernie.

      Światło rozproszone już ma swój określony kierunek - oświetla tym mocniej powierzchnie im mniejszy kąt tworzy z kierunkiem padania światła (najmocniej gdy pada bezpośrednio pod kątem prostym) i jest odbijane od powierzchni równomiernie w każdym kierunku.

      Na koniec pozostaje trzeci rodzaj światła - odbłyskowe - podobne do rozproszonego z taką różnicą, że jest odbijane w jedną określoną stronę.

      Praktycznie każde źródło światła w OpenGL jest zdefiniowane za pomocą każdego z wyżej wymienionych składowych rodzajów światła. Podobnie jak kolor, światło jest określone przez wartości w skali RGBA.

          1. Oświetlenie w OpenGL

      W celu włączenia obliczeń oświetleń należy wywołać funkcję :

      glEnable(GL_LIGHTING);

          1. Model oświetlenia

      Następnie należy określić model oświetlenia za pomocą funkcji :

      glLightModel();

      Posiada ona różne odmiany w zależności od określania rodzaju parametru, na przykład podstawowa używana do ustawienia domyślnego światła otaczającego scenę to :

      glLightModelfv(GLenum pname, const GLfloat *p)

      gdzie jako parametr :

      pname - decyduje się na rodzaj parametru (w tym przypadku GL_LIGHT_MODEL_AMBIENT)

      *p - wskaźnik do tablicy określający dany parametr (w tym przypadku element będący składowymi RGBA)

          1. Właściwości materiału

      Aby dany obiekt odbijał w odpowiedni sposób światło należy zdefiniować materiał.

      Wykorzystuje się najczęściej do tego funkcję :

      glMaterialfv(GLenum side, GLenum pname, const GLfloat *p)

      gdzie :

      side - podaje się stronę wielokąta do której odnoszą się właściwości (GL_FRONT, GL_BACK albo GL_FRONT_AND_BLACK)

      pname - podaje się żądaną właściwość odbicia światła (na przykład GL_AMBIENT_AND_DIFFUSE czyli światła rozpraszającego oraz otaczającego)

      *p - jest tablicą zawierająca wartości w standardzie RGBA

      Istnieje alternatywny sposób określania materiału - bardziej praktyczny z - nazywa się „śledzeniem kolorów”. W tym przypadku ustala się właściwości materiału tak, aby były aktywne przy każdym wywołaniu fukcji glColor. Do poprawnego działania należy najpierw włączyć obsługę :

      glEnable(GL_COLOR_MATERIAL);

      Oraz ustalić rodzaj materiału podobnie do wyżej wspomnianej funkcji :

      glColorMaterial(GLenum side, GLenum pname);

          1. Źródła światła

      Aby zrozumieć mechanizm oświetlenia w OpenGL należałoby zapoznać się pojęciem wektora normalnego, czyli w ogólnym mniemaniu półprostej prostopadłej do określonej płaszczyzny. Jednakże kąt padania nie zawsze musi być prosty - można nim manipulować, co stwarza wrażenie wypukłości linii czy płaszczyzny bowiem kąt padania i odbicia światła jest załamywany pod określonym innym kątem. Zwrot jest skierowany ku „górze” określając przednią stronę wielokąta. Standardowo przyjęto, iż przednia strona jest określona w miejscu, w którym wierzchołki są ułożone w kierunku przeciwnym do ruchu wskazówek zegara.

      OpenGL obsługuje maksymalnie osiem niezależnych źródeł światła. Implementacja przykładowego wygląda następująco :

      glLightfv(GL_LIGHT0,GL_AMBIENT,a); // „a” to jest wartości w skali RGBA

      glLightfv(GL_LIGHT0,GL_POSITION,b); // “b” to współrzędne

      glEnable(GL_LIGHT0); // włączenie światła

          1. Efekty oświetlenia - odbłyski

      Jest to efekt często dostrzegany na wodzie lub powierzchniach metalicznych. W języku OpenGL jest określany mianem specular i wygląda to następująco :

      • w przypadku źródła światła należy dodać własność GL_SPECULAR:

      glLightfv(GL_LIGHT0,GL_SPECULAR,rgba_specular);

      • podobnie należy także dodać własność materiału danego obiektu :

      glMaterialfv(GL_FRONT, GL_SPECULAR, rgba_specular);

      • dodatkowo można określić połysk :

      glMaterialfv(GL_FRONT, GL_SHININESS,shine_scale);

      gdzie shine_scale jest w zakresie <0,128>

          1. Światła punktowe

      Aby promienie światła nie rozchodziły się we wszystkich kierunkach równomiernie potrzebne jest sprecyzowanie źródła światła jako punktowe. W takim przypadku światło rozchodzi się na kształt stożka jak w poniższym rysunku :

      GL_SPOT_CUTOFF wyznacza kąt rozwarcia figury (w przypadku pozycyjnego wynosi 180˚). W kodzie definicji źródła światła należy zatem dodać :

      glLightf(GL_LIGHT0, GL_SPOT_CUTOFF,kat_f);

      Aby uzyskać efekt świecącego punktu :

      glLightf(GL_LIGHT0, GL_SPOT_EXPONENT,size_f);

        1. Listy wyświetlania

      Tworzy się w celu optymalizacji projektu - w szczególności przy złożonych aplikacjach gdzie występuje duża liczba wielokątów. Jest również pomocna przy „katalogowaniu” obiektów w klasy. Listą wyświetlania możemy nazwać określoną grupę operacji OpenGL, która może być później wielokrotnie wykorzystywana w kodzie programu. Zaoszczędza się w ten sposób zużycie procesora na dodatkowe te same obliczenia.

          1. Implementacja

      Mechanizm działania jest bardzo podobny budowy prymitywów :

      glNewList(id, GL_COMPILE)

      // kod OpenGL

      glEndList();

      Gdzie:

      id - podajemy identyfikator listy, natomiast dyrektywę GL_COMPILE można zmienić na GL_COMPILE_AND_EXECUTE co dodatkowo po kompilacji spowoduje wykonanie danych komend.

      Wywołać daną listę można przez :

      glCallList(id);

      Listy wyświetlania mogą mieć dodatkową strukturę zagnieżdżoną. W MS Windows jest ona dozwolona do maksymalnie 64 poziomów.

        1. Mapowanie tekstur

          1. Pliki bitmap

      Najpopularniejszy format BMP używany w MS Windows jest zarazem najprostszym w użyciu w programach. OpenGL ma wbudowane funkcje obsługi bitmap, tak więc implementacja wszelakich operacji następuje dosłownie krok po kroku. Najczęściej nie występuje w nim żadna kompresja przez co łatwo jest odczytać poszczególne piksele obrazu. Generalnie występują dwa rodzaje organizacji pliku BMP - z kolorem RGB oraz z gotową paletą kolorów.

          1. Pojęcie teksturowania

      Mapowanie tekstur to nic innego jak nakładanie obrazów na wielokąty tudzież obiekty. W ten sposób obrazy stają się bardziej realistyczne i nabierają bardziej prawdziwych kształtów. W pierwszych programach czy grach był stosowany tzw. raycasting gdzie sam mechanizm nakładania tekstur jest wydajniejszy od OpenGL jednak jest pozbawiony wielu cech. Musi być na przykład nakładany na gładkie 2-wymiarowe powierzchnie. Zastosowany w OpenGL mechanizm jest bardziej elastyczny, posiada więcej opcji do jak najdokładniejszego rozmieszczenia tekstur. Dzisiejsze chipsety kart graficznych w pełni już wspierają sprzętowo ów mechanizm, więc procesor jest w coraz bardziej znacznym stopniu odciążony.

          1. Definiowanie tekstur

      Najczęściej używany rodzaj tekstur to obrazy dwuwymiarowe. Dostępne są również jedno- i 3-wymiarowe ale są rzadko spotykane. Przykład implementacji samej definicji dwuwymiarowej tekstury :

      void glTexImage2D(GL_TEXTURE_2D, GLint poziom, GLint komponenty, GLsizei w, GLsizei h, GLint border, GLenum format, GLenum typ, const GLvoid *pixels)

      gdzie :

      poziom - poziom szczegółów mipmapy

      komponenty - ilość komponentów koloru w zakresie <1,4>

      w i h - wymiary tekstury (w najogólniejszym przypadku muszą być potęgą liczby 2)

      order­ - szerokość ramki dookoła tekstury w zakresie <0,2>

      format - format danych pikseli (najpopularniejszy to GL_RGBA)

      typ - typ danych dla wartości pikseli

      pixels - dane pikseli

      Inną pomocną funkcją jest glTexCoord dzięki której określa się współrzędne tekstury na wielokącie.

      Do przechowywania obrazów tekstur najłatwiej używać list wyświetlania. Przyspiesza to działania statycznych rozkazów operacji na teksturach.

      Poza tym w nadchodzących nowych wersjach OpenGL mechanizm ten ma być coraz bardziej polepszony - załadowanie kolejnych tekstur odbywać się będzie bezpośrednio w pamięci karty graficznej.

      Przy pisaniu kodu należy pamiętać o uaktywnieniu funkcji gl_Enable(GL_TEXTURE_2D). Następnie o wywołaniu z listy wyświetlania danej definicji tekstury glCallList(Jakas_tekstura). Od tej chwili każdy wielokąt będzie automatycznie pokrywany daną teksturą. Na koniec należy wyłączyć obsługę tekstur gl_Disable(GL_TEXTURE_2D).

          1. Mipmaping

      Specyfikacja OpenGL obsługuje standardowo mipmaping tekstur. Jest to technika tym bardziej pomocna gdzie 3-wymiarowa scena, którą tworzymy będzie służyła jako świat po którym obserwator będzie się poruszał. Podczas ruchu kamery niepotrzebne bowiem jest dokładne renderowanie wszystkich obiektów w zasięgu wzroku. Można najbliższe obiekty dokładnie odświeżać natomiast dalsze, które są daleko „na horyzoncie” widoku kamery wyświetlać w mniejszej rozdzielczości. Biblioteka narzędziowa GLUT posiada dwie bardzo pomocne funkcje, które w pełni zajmują się generowaniem mipmap w oparciu o tekstury o wysokiej rozdzielczości. Dla obrazów dwuwymiarowych jest to gluBuild2DMipmaps.

        1. Kwadryki

      W bibliotece narzędziowej GLUT możemy znaleźć definicję kilku figur geometrycznych, bez których trudno byłoby modelować złożone obiekty. Są to między innymi sfery, cylindry i dyski.

          1. Definiowanie i rysowanie kwadryk

      Aby móc utworzyć gotową kwadrykę należy najpierw zainicjalizować stan Kwadryki która jest zmienną swojego typu opisującą różne charakterystyki figury. Służy do tego funkcja :

      GLUquadricObj *obj;

      obj = gluNewQuadric();

      Można kontrolować sposób rysowania kwadryki - dzięki funkcji :

      gluQuadricDrawStyle (GLUquadric *obj, GLenum drawStyle)

      gdzie za drawStyle można przyjąć :

      GLU_FILL

      Wypełnianie za pomocą wielokątów i pasków prymitywów

      GLU_LINE

      Tworzona jest jedynie siatka z odcinków

      GLU_SILHOUTTE

      Rysowane są tylko zewnętrzne krawędzie

      GLU_POINT

      Rysowane jako zbiór punktów

      Obliczanie wektorów normalnych jest w pełni zautomatyzowane - można dodatkowo zdefiniować dokładnie sposób ich tworzenia poprzez podanie parametru normals funkcji :

      gluQuadricNormals(GLUquadricObj *obj, GLenum normals);

      GLU_NONE

      Normalne nie są generowane

      GLU_FLAT

      Normalne są generowane dla całych wielokątów

      GLU_SMOOTH

      Normalne są generowane indywidualnie dla każdego z wierzchołków

          1. Cylindry

      Do tworzenia cylindrów służy funkcja :

      gluCylinder(GLUquadric *obj, GLdouble bRadius, GLdouble tRadius, GLdouble h, GLint slices, GLint stacks)

      gdzie za parametry :

      bRadius i tRadius - promień cylindra na górnej i dolnej podstawie

      h - to wysokość cylindra

      slices i stacks - określa z ilu ścian oraz z ilu segmentów będzie generowany cylinder (zwykle często używaną wartością jest 15 do 20 ścian)

      W ten sposób powstaje tuba cylindra (bez podstaw). Za pomocą tej funkcji można również otrzymać stożek bez podstawy podając jedynie za jeden z promieni podstaw wartość 0.

          1. Dyski

      Dyski zaimplementowane w GLUT mogą posiadać wewnątrz. dodatkowo „dziurę”:

      gluDisk(GLUquadricObj *obj, GLdouble inRadius, GLdouble outRadius, GLint slices, GLint loops)

      gdzie :

      inRadius / outRadius - promień dysku oraz dziury zawartej w środku (w przypadku inRadius równego 0 rysowany jest bez dziury)

      slices - określa z ilu ścian się składa (dla poprawnych rezultatów wizualnych powinna to być wartość <15,20>)

      loops - określa ilość segmentów pomiędzy wewnętrznym a zewnętrznym promieniem (wystarczy 1 dla dysków oraz 2 dla pierścieni)

      Dodatkowo istnieje funkcja rysowania tylko określonej części dysku czy cylindru - gluPartialDisk - składnia jest podobna do wyżej wymienionej z wyjątkiem, że dwa ostatnie dodatkowe parametry określają początkowy i końcowy kąt rysowania.

          1. Sfery

      Rysowanie kul odbywa się za pomocą funkcji :

      gluShpere(GLUquadric *obj, GLdouble radius, GLint slices, GLint stacks)

      podając promień kuli (radius) oraz dokładność - interpretując slices jako liczbę południków oraz stacks jako liczbę równoleżników.

          1. Renderowanie kwadryk

      Odbywa się zawsze względem początku układu współrzędnych, tak więc przed ich rysowaniem należy przesunąć układ odniesienia.

      1. Ogólne zasady działania engine'a

        1. Wczytywanie danych

      Dane wczytywane są z szeregu plików oraz przez różne mechanizmy:

          1. Pliki *.lev

      Pliki te przechowują dane o całym malowanym poziomie - ilość i rozmieszczenie pomieszczeń oraz nazwy plików, w których są one zdefiniowane. Każde pomieszczenie jest opisane przez dwa rodzaje plików: rom i dyn.

          1. Pliki *.rom

      Pliki te przechowują informacje o ścianach oraz wszystkich obiektach statycznych znajdujących się w danym pomieszczeniu.

          1. Pliki *.dyn

      Pliki te przechowują informacje o obiektach dynamicznych znajdujących się w danym pomieszczeniu.

          1. Pliki *.ld

      Pliki te przechowują informacje obiektach i elementach, z którymi zachodzi interakcja, czyli o: punktach informacyjnych, drzwiach i punktach wycieczki.

        1. Umieszczanie danych w pamięci

      Po wczytaniu ściany oraz obiekty statyczne są umieszczane w listach wyświetlania, a następnie usuwane z pamięci. Obiekty dynamiczne oraz wszystkie dane wczytane z plików ld są przechowywane w odpowiednio dostosowanych strukturach danych.

      Obiekty umieszczane są w tablicy jednowymiarowej i opisane przez typ i podtyp obiektu. Typ obiektu oznacza, czy jest to np.: zegarek, biurko, czy inny element, natomiast podtyp określa jego rodzaj, np.: biurko duże drewniane, czy małe metalowe.

      Dane o drzwiach i punktach wycieczki również umieszczane są w odpowiednich tablicach.

      Inaczej jest w przypadku punktów informacyjnych - są one umieszczone w tablicach zagnieżdżonych - jedna tablica zawiera wskaźniki do struktur (klas) CInfoPoint, natomiast te (każda sobie) przechowują informacje o ekranach, które znowu (każdy sobie) informacje o ramkach.

        1. Malowanie obiektów w listach wyświetlania

      Po wczytaniu obiektów statycznych i ścian z danego pokoju są one malowane w listach wyświetlania.

      Mechanizm do tego użyty wygląda następująco:

      Zdefiniowana jest tablica o elementach typu CObject, natomiast każdy z nich inicjowany jest jako konkretny obiekt, który dziedziczy z klasy CObject, np.: n-ty element tej tablicy jest inicjowany jako obiekt typu CKrzeslo. Tak więc wcześniej omawiany typ tutaj jest indeksem w tablicy obiektów, podczas gdy podtyp jest argumentem funkcji malującej dany obiekt.

      Obsługa animacji drzwi zaimplementowana jest w klasie CDoor. Na podstawie zadanego stanu wylicza ona kąt pod jakim w danej klatce animacji mają być wyświetlane drzwi oraz czy są otwarte, otwierane, zamknięte czy zamykane. Tak więc procedury malujące drzwi wywołują tylko metodę malowania, nie interesując się, co się aktualnie z drzwiami dzieje.

        1. Malowanie sceny

      Malowanie sceny odbywa się w dwóch głównych procedurach: DrawLevel oraz DrawGLScene.

      Procedura DrawLevel odpowiedzialna jest za umieszczenie w scenie wszystkich ścian i obiektów (zarówno statycznych, jak i dynamicznych) oraz za optymalizacje szybkości wyświetlania. Pierwsze z tych zadań realizowane jest przez przeglądnięcie wszystkich obiektów i umieszczenie ich w scenie. Optymalizacja polega na ograniczeniu przeglądanego zbioru obiektów do obiektów (mówimy cały czas również o ścianach) spełniających jeden z dwóch warunków:

      • obiekt znajduje się w tym samym pomieszczeniu, co obserwator,

      • obiekt znajduje się w pomieszczeniu, w którym chociaż jedne drzwi są otwarte.

      Do sprawdzenia pierwszego warunku wykorzystywany jest detektor kolizji. Ponieważ tworzona przez niego mapa kolizji była tylko częściowo wykorzystywana, mechanizm otrzymał drugą funkcję - podczas wczytywania obiektów, z którymi zachodzi kolizja, na mapie, w miejscach, gdzie nie ma żadnych obiektów kolizyjnych, zaznacza się numer pomieszczenia. W ten sposób, odwołując się do mapy kolizji, otrzymujemy praktycznie bez żadnych wyliczeń numer listy wyświetlania, która zawiera w sobie wszystkie obiekty z danego pomieszczenia. W ten sposób otrzymujemy numer listy wyświetlania, która musi być wyświetlona.

      Drugi warunek sprawdzany jest na podstawie stanu drzwi. Każde drzwi mają przypisany numer listy wyświetlania - pomieszczenia do którego prowadzą. Jeżeli chociaż jedne drzwi do pomieszczenia są otwarte, to malowane jest całe pomieszczenie.

      Należy przy tym wspomnieć, iż każde drzwi mają w sobie mechanizm, który regularnie sprawdza, czy drzwi są otwarte i, jeżeli tak, to jak długo są otwarte. Jeżeli są otwarte dłużej niż 10 sekund, to automatycznie wywoływana jest procedura ich zamknięcia.

      Procedura DrawGLScene decyduje, czy w danym momencie wyświetlany jest poziom, czy menu początkowe. Jeżeli wyświetlany jest wczytany poziom, to rozpatrywany jest tryb oglądania (malowanie sceny rozumiane jest tutaj jako wywołanie funkcji DrawLevel):

      • wycieczka - należy obliczyć kolejne współrzędne obserwatora (funkcja CalculateTripPositions) oraz namalować scenę,

      • punkt informacyjny podczas wycieczki - należy namalować scenę oraz wyświetlić konkrety punkt informacyjny,

      • otwieranie/zamykanie drzwi podczas wycieczki - należy namalować scenę oraz animację otwieranych/zamykanych drzwi,

      • zwiedzanie - należy obliczyć kolejne współrzędne obserwatora (funkcja CalculatePositions) oraz namalować scenę,

      • punkt informacyjny podczas zwiedzania - należy namalować scenę oraz wyświetlić odpowiedni punkt informacyjny,

      • otwieranie/zamykanie drzwi podczas zwiedzania - należy namalować scenę oraz wyświetlić animację otwieranych/zamykanych drzwi.

      Ponadto do poszczególnych trybów przypisana jest obsługa klawiszy sterujących.

        1. Wycieczka

      Funkcja CalculateTripPositions pobiera z obiektu klasy CTrip dane dotyczące następnego punktu, w którym obserwator powinien się znaleźć. Dane punktu zawierają w sobie również indeks akcji, jaka ma być podjęta w tym punkcie (przemieszczenie z lub bez efektu ruchu, otwieranie/zamykanie drzwi, wyświetlanie punktów informacyjnych, zakończenie wycieczki). W zależności od położenia obserwatora w osi Y odtwarzane są dźwięki chodzenia.

        1. Przemiszczanie obserwatora

      Funkcja CalculatePositions oblicza współrzędne obserwatora w zależności od sygnałów dochodzących z klawiatury. Na podstawie detektora kolizji sprawdzane jest, czy przemieszczenie może się odbyć. Osobno przeprowadzana jest detekcja kolizji z drzwiami, lecz na podobnych zasadach. Ponadto, w razie potrzeby, odtwarzane są odgłosy chodzenia. Zwrócić należy również uwagę na zmienną speed, która na podstawie czasu pomiędzy poszczególnymi klatkami określa prędkość przemieszczania się, co w rezultacie pozwala zachować podobną prędkość na mniej i bardziej wydajnych komputerach.

        1. Punkty informacyjne (InfoPoints)

      Wyświetlanie InfoPoint'ów polega na zmianie trybu wyświetlania na wyświetlanie InfoPoint'ów i wywoływania metody malowania zawartej w klasie DCcd. Ona przechowuje w sobie dane o punktach informacyjnych i to ona zarządza, który aktualnie ma być wyświetlany.

      Punkty informacyjne składają się z ekranów, z których każdy ma określony czas, po którym musi zniknąć (chyba, że będzie to przyspieszone naciśnięciem klawisza <enter>). Każdy ekran składa się z ramek. Ramka określona jest przez typ i położenie na ekranie. Ramka może być ramką tekstową, obrazkową lub muzyczną.

      Wyświetlanie ramek na ekranie realizuje obiekt klasy CTextWriter. Implementuje ona w sobie metody wyświetlające każdy typ ramek, a teksty pobiera z obiektu klasy CTextHandler lub odbiera z parametru wywołania funkcji.

      Obiekt klasy CTextHandler przechowuje wszystkie teksty, które są wyświetlane na ekranie podczas podróży po modelowanym świecie. Została ona wprowadzona, aby ułatwić edycję tych tekstów oraz obsługę wielu języków.

        1. Obsługa klawiatury

      Obsługa klawiatury polega na odczytywaniu wartości w tablicy jednowymiarowej, indeksowanej kodami ASCII klawiszy. Wartość true oznacza, że dany klawisz jest aktualnie wciśnięty. Tablica ta jest aktualizowana przez procedurę obsługującą komunikaty odbierane przez okno programu.

      1. Klasy i moduły

      Projekt ma formę modularną. Składa się z wielu funkcjonalnie spójnych części, z których każda może zostać ponownie wykorzystana bez konieczności wprowadzania żadnych przeróbek.

      Każdy moduł jest zdefiniowany jako oddzielna klasa i udostępnia pewne publiczne metody.

      Funkcjonalność i sposób wykorzystania poszczególnych modułów została opisana poniżej.

        1. Klasa: CAnimationModule

      Klasa CAnimationModule odpowiada za animowanie obiektów na scenie. Animację w rozumieniu tego modułu rozumieć należy jako zestaw przekształceń (obrót, przesunięcie, skalowanie, zmiana koloru) wykonywanych na danym obiekcie. De facto nie jest przesuwany obiekt tylko cały układ współrzędnych.

      Każda animacja zdefiniowana jest jako zbiór klatek. Każda klatka jest strukturą przechowującą informacje o przesunięciu, obrocie, skalowaniu, kolorze oraz czasie trwania:

      struct frame {

      GLfloat translate[3];

      GLfloat rotate[4];

      GLfloat scale[3];

      GLfloat color[4];

      unsigned long durration;

      bool makeT, makeR, makeS, makeC;

      }

      Definiowanie animacji rozpoczynamy od wywołania konstruktora i podania liczby klatek. Następnie dodajemy kolejne klatki przy użyciu metody addFrame.

      Mechanizm animacji jest następujący:

      • w momencie wykonania metody animate sprawdzany jest czas jaki upłynął od chwili rozpoczęcia animacji do chwili obecnej. Animację rozpoczyna metoda start,

      • w przypadku klatek niezależnych wszystkie klatki, których sumaryczny czas jest mniejszy od obliczonej różnicy są pomijane. W przypadku klatek zależnych wszystkie klatki, których sumaryczny czas jest mniejszy od obliczonej różnicy są wykonywane. Wykonanie pojedynczej klatki polega na przeprowadzeniu kolejno przekształceń: transformacja, obrót, skalowanie i zmiana koloru).

      Może się zdarzyć, że niecała klatka mieści się w ramie czasowej, np. gdy zdefiniowana długość klatki to 5 sekund, a od początku animacji minęła zaledwie sekunda. Wtedy wszystkie przekształcenia są proporcjonalnie mniejsze. Najlepiej obrazuje to poniższy przykład:

      Klatki zależne; klatka1: długość 1 sek, przesunięcie o [1, 0, 0]; klatka2: długość 4 sek, przesunięcie o [0,4,0].

      t = 1 sek - układ współrzędnych zostanie przesunięty o wektor [1, 0, 0],

      t = 2 sek - układ współrzędnych zostanie przesunięty o wektor [1, 1, 0] (wektor [1, 0, 0] - 1 klatka i 1/4 wektora [0, 4, 0] - 2 klatka)

      t = 5 sek - układ zostanie przesunięty o wektor [1,4,0].

      W celu ułatwienia definiowania animacji można stworzyć plik tekstowy z animacją. Format pliku opisany poniżej.

          1. CAnimationModule (int numberOfFrames, bool indep)

      Autor

      Marcin Tucholski

      Opis metody

      Konstruktor obiektu klasy CAnimationModule

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      numberOfFrames

      liczba klatek animacji

      bool

      indep

      true - kolejne klatki animacji nie zależą od siebie (wszelkie transformacje odbywają się względem stanu początkowego)

      false - klatki zależne - transformacja odpowiadająca n-tej klatce animacji poprzedzana jest przez transformacje odpowiadające klatkom 1..n-1

      Argumenty wyjściowe

      Brak

          1. CAnimationModule (char *fileName)

      Autor

      Marcin Tucholski

      Opis metody

      Konstruktor obiektu klasy CAnimationModule. Konstruktor tworzy animację na podstawie parametrów zapisanych w pliku. Format pliku:

      LiczbaKlatek KlatkiNiezalezne

      tX1 tY1 tZ1

      rA1 rX1 rY1 rZ1

      sX1 sY1 sZ1

      cR1 cG1 cB1 cA1

      Czas1

      mT1 mR1 mS1 mC1

      ... ... ... ...

      tXn tYn tZn

      rAn rXn rYn rZn

      sXn sYn sZn

      cRn cGn cBn cAn

      Czasn

      mTn mRn mSn mCn

      Oznaczenia:

      • tXn tYn tZn - współrzędne X, Y i Z przesunięcia odpowiadającego n-tej klatce animacji,

      • rAn rXn rYn rZn- kąt i wektor obrotu odpowiadającego n-tej klatce aniamacji,

      • sXn sYn sZn - współczynniki skalowania X, Y i Z dla n-tej klatki animacji,

      • cRn cGn cBn cAn-składowe R,G, B i współczynnik alfa dla n-tej klatki animacji,

      • Czasn -czas trwania n-tej klatki animacji,

      • mTn mRn mSn mCn-wskazuje, które ze składowych animacji będą przetwarzane (transformacja, obrót, skalowanie i zmiana koloru - 1 1 1 1 oznacza wszystkie, 0 0 0 0 - żadne),

      W pliku nagłówkowym zdefiniowana jest stała ANIMATIONDIR. Konstruktor przyjmuje, że podany jako argument plik znajduje się we wskazanym przez ANIMATIONDIR katalogu.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      fileName

      nazwa pliku przechowującego animację.

      Argumenty wyjściowe

      Brak

          1. void addFrame(frame *frame_)

      Autor

      Marcin Tucholski

      Opis metody

      Dodaje klatkę do animacji

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      frame*

      frame_

      wskaźnik na klatkę, która ma być dodana

      Argumenty wyjściowe

      Brak

          1. void start()

      Autor

      Marcin Tucholski

      Opis metody

      Rozpoczyna odtwarzanie animacji. Animacja ustawiana jest na początku.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. void reset()

      Autor

      Marcin Tucholski

      Opis metody

      Ustawia animację na początku.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. void stop()

      Autor

      Marcin Tucholski

      Opis metody

      Zatrzymuje animację

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. bool finished()

      Autor

      Marcin Tucholski

      Opis metody

      Zwraca status animacji.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      true

      animacja się zakończyła

      false

      animacja jeszcze trwa

          1. void animate()

      Autor

      Marcin Tucholski

      Opis metody

      Przekształca układ współrzędnych zgodnie z postępem odtwarzania animacji.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. void animate(int delay)

      Autor

      Marcin Tucholski

      Opis metody

      Przekształca układ współrzędnych zgodnie z postępem odtwarzania animacji. Początek animacji zostaje opóźniony o wskazaną ilość milisekund.

      Argumenty wejściowe

      int

      delay

      opóźnienie odwarzania animacji w milisekundach

      Argumenty wyjściowe

      Brak

        1. Klasa: CAudioCtrl

      Obiekty tej klasy zarządzają dźwiękiem odtwarzanym podczas działania programu.

      Klasa ta korzysta ze struktury:

      struct MusicFile

      {

      HWND hAudioWnd;

      bool bLoop;

      char FileName[100];

      };

      Struktura MusicFile przechowuje informacje o dźwiękach. Jej elementami są: uchwyt do okna odtwarzającego dźwięk, określenie zapętlenia oraz ścieżkę do pliku i jego nazwę.

      Klasa ta przechowuje informacje o ośmiu plikach jednocześnie plus melodia odtwarzana w tle. Dane o dźwięku, po jego odtworzeniu, pozostają w pamięci tak długo, jak długo nie zaistnieje potrzeba zastąpienia jego danych danymi innego dźwięku, który dopiero ma być odtworzony.

      Dźwięki w tle są odtwarzane losowo, przy czym żadna melodia nie będzie odtwarzana zaraz po swoim zakończeniu.

          1. CAudioCtrl(bool SoundOn)

      Autor

      Bartosz Rudnicki

      Opis metody

      Konstruktor obiektu klasy CAudioCtrl.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      bool

      SoundOn

      Zmienna określająca, czy dźwięk ma być włączony

      Argumenty wyjściowe

      Brak

          1. ~CAudioCtrl()

      Autor

      Bartosz Rudnicki

      Opis metody

      Destruktor obiektu klasy CAudioCtrl.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. Play(char *FileName, bool bLoop, int iMode)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda odtwarza dźwięk.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      FileName

      Nazwa pliku do odtworzenia

      bool

      bLoop

      Wartość określająca, czy dźwięk ma być zapętlony

      int

      iMode

      Tryb odtwarzania

      Argumenty wyjściowe

      Brak.

          1. Stop(char *FileName)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda zatrzymuje odtwarzany dźwięk.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      FileName

      Nazwa pliku do zatrzymania

      Argumenty wyjściowe

      Brak.

          1. Manage()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda zarządza odtwarzanymi dźwiękami - sprawdza, czy nieodtwarzany dźwięk ma ustawione zapętlenie i, jeżeli tak, to odtwarza go ponownie.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. HandleBackgroundMusic()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda zarządza dźwiękami odtwarzanymi w tle.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. PlayMenu()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda odtwarza melodię w menu.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. PlayTrip()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda odtwarza melodię podczas trwania wycieczki.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. PlayFree()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda odtwarza melodię podczas trwania zwiedzania.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. InitBackgroundMusic()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda inicjalizuje melodie odtwarzane w tle.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. StopMenu()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda zatrzymuje odtwarzanie melodii w menu.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

        1. Klasa: CBkgMenuModule

      Klasa bkgMenuModule odpowiada za wyświetlanie zmieniających się obrazów tła podczas wyświetlania menu. Może znaleźć szerokie zastosowanie wszędzie tam, gdzie mają być wyświetlane w kolejności obrazy z efektami przejścia.

          1. CBkgMenuModule (int liczbaObrazow, char *animation, int delay)

      Autor

      Marcin Tucholski

      Opis metody

      Konstruktor obiektu klasy CBkgMenuModule

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      liczbaObrazów

      liczba obrazów tła

      char*

      animation

      plik definiujący animację przejść między obrazami tła

      int

      delay

      czas przez który dany obraz jest wyświetlany

      Argumenty wyjściowe

      Brak

          1. void addImage(char *fileName)

      Autor

      Marcin Tucholski

      Opis metody

      Funkcja dodaje obraz do puli obrazów.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      fileName

      nazwa pliku z obrazem

      Argumenty wyjściowe

      Brak

          1. void paint()

      Autor

      Marcin Tucholski

      Opis metody

      Metoda rysuje aktualny obraz.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

        1. Klasa: CCd

      Klasa CCd początkowo miała być mechanizmem odpowiadającym za detekcję kolizji, jednakże wykorzystane w niej struktury okazały się niezwykle pomocne w detekcji pomieszczenia, w którym się znajdujemy.

      Klasa ta przechowuje informacje o scenie w postaci dwuwymiarowej mapy, w której wartości większe od zera oznaczają ściany, natomiast elementy ujemne oznaczają numer pomieszczenia, w którym się znajdujemy (wartość bezwzględna plus jeden daje nam numer listy wyświetlania danego pomieszczenia).

      Mechanizm wykrywania kolizji działa następująco: dla podanych dwóch punktów (początkowy i końcowy punkt przemieszczenia) sprawdzamy, czy nie ma między nimi żadnego obiektu ograniczającego ruch. Jeżeli nie, to przemieszczenie jest prawidłowe. W przeciwnym wypadku sprawdzamy, czy można się przemieścić tylko w jednym wymiarze (w X lub w Y). Jeżeli tak, to przemieszczenie następuje tylko w tym wymiarze. Jeżeli żadne z przemieszczeń nie może być dokonane, przemieszczenie jest anulowane.

          1. CCd(char *LevelName)

      Autor

      Bartosz Rudnicki

      Opis metody

      Konstruktor obiektu klasy CCd. Metoda przegląda podany plik i odczytuje z niego pozycje obiektów, które ograniczają przemieszczenia, a następnie nanosi te obiekty na dwuwymiarową mapę.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      Char*

      LevelName

      Nazwa pliku przechowującego dane o poziomie.

      Argumenty wyjściowe

      Brak

          1. ~CCd()

      Autor

      Bartosz Rudnicki

      Opis metody

      Destruktor obiektu klasy CCd

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. void CreateRoom(int iRoom)

      Autor

      Bartosz Rudnicki

      Opis metody

      Nanosi na mapę teren zajmowany przez pokój (listę wyświetlania) o indeksie iRoom

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      iRoom

      Index pokoju

      Argumenty wyjściowe

      Brak

          1. void RoomSize(Swall W, bool bMode)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda sprawdza, czy podana ściana leży wewnątrz aktualnie analizowanego pokoju. Jeżeli nie, to zwiększany jest prostokąt opisujący powierzchnię danego pokoju.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      SWall

      W

      Struktura opisująca ścianę

      bool

      bMode

      Wartość logiczna objaśniająca, czy jest to pierwsza ściana w tym pokoju.

      Argumenty wyjściowe

      Brak

          1. void SetTranslation(float *NewTranslation)

      Autor

      Bartosz Rudnicki

      Opis metody

      Ustala przesunięcie pomieszczenia względem środka sceny.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      *NewTranslation

      Wskaźnik na dwuwymiarową tablicę typu float, określającą przesunięcie

      Argumenty wyjściowe

      Brak

          1. int min(int a, int b)

      Autor

      Bartosz Rudnicki

      Opis metody

      Wyznacza mniejszą z dwóch wartości

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      a

      Pierwsza wartość

      int

      b

      Druga wartość

      Argumenty wyjściowe

      Mniejsza z dwóch podanych wartości.

          1. int max(int a, int b)

      Autor

      Bartosz Rudnicki

      Opis metody

      Wyznacza większą z dwóch wartości

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      a

      Pierwsza wartość

      int

      b

      Druga wartość

      Argumenty wyjściowe

      Większa z dwóch podanych wartości.

          1. int GetRoomNumber(float fX, float fZ)

      Autor

      Bartosz Rudnicki

      Opis metody

      Zwraca indeks pomieszczenia, w którym znajduje się zadany punkt.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      fX

      Współrzędna X

      float

      fY

      Współrzędna Y

      Argumenty wyjściowe

      Indeks pomieszczenia.

          1. void AddObject(SWall W, int iRoom)

      Autor

      Bartosz Rudnicki

      Opis metody

      Dodaje ścianę do mapy kolizji.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      SWall

      W

      Dane ściany

      int

      iRoom

      Indeks pomieszczenia

      Argumenty wyjściowe

      Brak

          1. int isCollision(int X1, int Y1, int X2, int Y2)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda, dla podanych dwóch punktów, sprawdza, czy możliwe jest przemieszczenie z jednego punktu do drugiego.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      X1

      Współrzędna X punktu początkowego

      int

      Y1

      Współrzędna Y punktu początkowego

      Int

      X2

      Współrzędna X punktu docelowego

      int

      Y2

      Współrzędna Y punktu docelowego

      Argumenty wyjściowe

      Typ

      Wartość

      Znaczenie

      int

      0

      Przemieszczenie jest możliwe

      int

      1

      Przemieszczenie jest możliwe tylko wzdłuż osi Y

      int

      2

      Przemieszczenie jest możliwe tylko wzdłuż osi X

      int

      3

      Przemieszczenie nie jest możliwe

          1. int isCollision(float xp, float yp, float oxp, float oyp)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda działa identycznie, jak poprzednia, ale przyjmuje parametry typu float.

        1. Klasa: CObiekt

      Klasa CObiekt jest klasą abstrakcyjną z której dziedziczą wszystkie obiekty rysowane na scenie. Klasa uzgadnia wspólny interfejs dla różnych obiektów oraz udostępnia zestaw metod wspomagających modelowanie.

          1. void glMyCube(float size)

      Autor

      Jakub Malicki

      Opis metody

      Funkcja rysuje sześcian o zadanej krawędzi.

      Została stworzona w celu zastąpienia standardowej funkcji glutSolidCube() ze względu na trudności z nanoszeniem tekstur na obiekty stworzone przy jej pomocy.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      size

      długość krawędzi sześciana

      Argumenty wyjściowe

      Brak

          1. void glMyCube(float x, float y, float z)

      Autor

      Jakub Malicki

      Opis metody

      Funkcja rysuje prostopadłościan o zadanych krawędziach.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      x

      długość krawędzi leżącej na osi X prostopadłościanu

      float

      y

      długość krawędzi leżącej na osi Y prostopadłościanu

      float

      z

      długość krawędzi leżącej na osi Z prostopadłościanu

      Argumenty wyjściowe

      Brak

          1. void glMyCube(float x, float y, float z, float rozmiarTekstury)

      Autor

      Jakub Malicki

      Opis metody

      Funkcja rysuje prostopadłościan o zadanych krawędziach. Umożliwia również rozciąganie tekstury nakładanej na prostopadłościan.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      x

      długość krawędzi leżącej na osi X prostopadłościanu

      float

      y

      długość krawędzi leżącej na osi Y prostopadłościanu

      float

      z

      długość krawędzi leżącej na osi Z prostopadłościanu

      float

      rozmiarTekstury

      rozmiar nakładanej na ściany tekstury

      Argumenty wyjściowe

      Brak

          1. void glMyCube(float x, float y, float z, char *Fr, char *Le,
            char *Pr, char *Go, char *Do, char *Ty, float rozmiarTekstury,
            bool smudge=false)

      Autor

      Jakub Malicki, Marcin Tucholski

      Opis metody

      Funkcja rysuje prostopadłościan o zadanych krawędziach. Umożliwia również nałożenie różnych tekstur na poszczególne jego boki i wygładzanie krawędzi metodą manipulacji normalnymi.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      x

      długość krawędzi leżącej na osi X prostopadłościanu

      float

      y

      długość krawędzi leżącej na osi Y prostopadłościanu

      float

      z

      długość krawędzi leżącej na osi Z prostopadłościanu

      char*

      Fr

      nazwa tekstury na przednią ścianę

      char*

      Le

      nazwa tekstury na lewą ścianę

      char*

      Pr

      nazwa tekstury na prawą ścianę

      char*

      Go

      nazwa tekstury na górną ścianę

      char*

      Do

      nazwa tekstury na dolną ścianę

      char*

      Ty

      nazwa tekstury na tylną ścianę

      float

      rozmiarTekstury

      rozmiar nakładanej na ściany tekstury

      bool

      smudge

      czy mają być zaokrąglane krawędzie poprzez uśrednianie normalnych

      Argumenty wyjściowe

      Brak

          1. void glMyKula(float promien, float czescKuli,
            int rozdzielczoscPionowa, int rozdzielczoscPozioma, bool strona)

      Autor

      Jakub Malicki

      Opis metody

      Funkcja rysuje fragment lub całość sfery o zadanych parametrach

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      promien

      promień rysowanego pierścienia

      float

      czescKuli

      wyrażona w procentach cześć rysowanej sfery

      int

      rozdzielczoscPionowa

      szczegółowość w pionie

      int

      rozdzielczoscPozioma

      szczegółowość w poziomie

      bool

      strona

      rysowanie wewnętrznej lub zewnętrznej części

      Argumenty wyjściowe

      Brak

          1. void glMyRing(float promien, int kat, double rozmiar, int stacks)

      Autor

      Jakub Malicki

      Opis metody

      Funkcja rysuje fragment lub całość pierścienia o zadanych parametrach

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      promien

      promień rysowanego pierścienia

      int

      kat

      kąt rysowanego fragmentu pierścienia

      double

      rozmiar

      grubość pierścienia

      int

      stacks

      szczegółowość

      Argumenty wyjściowe

      Brak

          1. void glMyWalec(float promien, int kat, float wysokosc, bool podstawa,
            bool scianyBoczne, int st
            acks, bool strona)

      Autor

      Jakub Malicki

      Opis metody

      Funkcja rysuje fragment lub całość walca o zadanych parametrach.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      promien

      promień rysowanego walca

      int

      kat

      kąt rysowanego fragmentu

      float

      wysokość

      wysokość walca

      bool

      podstawa

      parametr określa, czy maja być rysowane podstawy odpowiadające rysowanemu fragmentowi walca

      bool

      scianyBoczne

      parametr określa, czy maja być rysowane ściany boczne dla danego fragmentu walca (jeżeli parametr kat ma wartość 360, to ściany boczne nie będą widoczne

      int

      stacks

      szczegółowość

      bool

      strona

      paramert określa, czy ma być rysowane wnętrze czy zewnętrze walca

      Argumenty wyjściowe

      Brak

          1. void glMyWalec(float promien, int kat, float wysokosc, bool podstawa,
            bool scianyBoczne, int poz
            iomZmniejszeniaRozdzielnosci, int stacks,
            bool strona)

      Autor

      Jakub Malicki

      Opis metody

      Funkcja rysuje fragment lub całość walca o zadanych parametrach. Dodatkowy atrybut poziomZmniejszeniaRozdzielnosci umożliwia generowanie obiektów o mniejszej ilości szczegółów i, dzięki temu, zwiększa się szybkość działania projektu.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      float

      promien

      promień rysowanego walca

      int

      kat

      kąt rysowanego fragmentu

      float

      wysokość

      wysokość walca

      bool

      podstawa

      parametr określa, czy maja być rysowane podstawy odpowiadające rysowanemu fragmentowi walca

      bool

      scianyBoczne

      parametr określa, czy maja być rysowane ściany boczne dla danego fragmentu walca (jeżeli parametr kat ma wartość 360, to ściany boczne nie będą widoczne

      int

      poziomZmniejszeniaRozdzielnosci

      parametr określa jak bardzo szczegółowo ma być rysowany obiekt - umożliwia zmniejszenie szczegółowości

      int

      stacks

      szczegółowość

      bool

      strona

      parametr określa, czy ma być rysowane wnętrze czy zewnętrze walca

      Argumenty wyjściowe

      Brak

        1. Klasa: CSoundModule

      Klasa CSoundModule odpowiada za odtwarzanie dźwięków w projekcie.

      Implementuje ona dwa sposoby odtwarzania dźwięków: wykorzystując bibliotekę DirectSound (biblioteka DirectSound wchodzi w skład pakietu DirectX) oraz wykorzystując bibliotekę VfW (Video For Windows).

      Możliwe jest jednoczesne odtwarzanie wielu dźwięków. Jest to ograniczone przez możliwości sprzętowe i system operacyjny.

      Klasa obsługuje wszystkie standardowe formaty dźwięków. Możliwe jest również odtworzenie dźwięków w niestandardowym formacie. Trzeba wówczas zainstalować wymagane kodeki w systemie operacyjnym.

          1. CSoundModule *getSoundModule()

      Autor

      Marcin Tucholski

      Opis metody

      Metoda zwraca instancję klasy CSoundModule.

      Jeżeli został już wcześniej utworzony obiekt tej klasy, to zwracany jest tylko adres tego obiektu. Jeżeli jest pierwsze wykorzystanie menadżera dźwięków, to zostanie utworzony obiekt klasy CSoundModule i zwrócony wskaźnik do utworzonego obiektu.

      Ponieważ konstruktor klasy CSoundModule jest konstruktorem prywatnym, to jest to jedyny mechanizm pozwalający utworzyć / skorzystać z menadżera dźwięków.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Typ

      Opis

      CSoundModule*

      wskaźnik na instancję obiektu klasy CSoundModule

          1. void play(char *fileName)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda odtwarza dźwięk przy wykorzystaniu biblioteki DirectSound.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      fileName

      nazwa pliku dźwiękowego

      Argumenty wyjściowe

      Brak

          1. void play2(char *fileName)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda odtwarza dźwięk przy wykorzystaniu biblioteki VfW.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      fileName

      nazwa pliku dźwiękowego

      Argumenty wyjściowe

      Brak

        1. Klasa: CTekst2DModule

      Klasa tekst2DModule umożliwia wyświetlanie tekstów dwuwymiarowych.

          1. int init(HDC hDC_, char *fontName, double fontSize_)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda inicjuje daną czcionkę, tworzy odpowiadające jej listy wyświetlania i zwraca numer bazowy dla danej czcionki. Jeżeli czcionka została już wcześniej użyta zwracany jest tylko numer bazowy bez ponownego tworzenia listy wyświetlania. Maksymalna liczba fontów z których można skorzystać zdefiniowana jest w stałej MAXFONTNUM w pliku tekst2DModule.h.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      HDC

      hDC_

      uchwyt urządzenia wyświetlającego

      char*

      fontName

      nazwa czcionki

      double

      fontSize_

      wysokość czcionki

      Argumenty wyjściowe

      Typ

      Opis

      int

      numer bazowy danej czcionki

          1. void PrintString(unsigned int base, char *str, double xPos, double yPos)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda wypisuje na ekranie tekst przy użyciu wybranej czcionki.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      unsigned int

      base

      numer bazowy czcionki

      char*

      str

      tekst do wypisania

      double

      xPos

      współrzędna X napisu

      double

      yPos

      współrzędna Y napisu

      Argumenty wyjściowe

      Brak

          1. void PrintLines(int base, char *str, double xPos, double yPos, double vOdl)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda wypisuje na ekranie tekst przy użyciu wybranej czcionki. W przypadku napotkania znaku nowej linii pozostała część wypisywana jest niżej. Przesunięcie między kolejnymi liniami zdefiniowane jest przez argument vOdl.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      unsigned int

      base

      numer bazowy czcionki

      char*

      str

      tekst do wypisania

      double

      xPos

      współrzędna X napisu

      double

      yPos

      współrzędna Y napisu

      double

      vOdl

      odległość między kolejnymi liniami tekstu

      Argumenty wyjściowe

      Brak

        1. Klasa: CTekst3DModule

      Klasa CTekst3DModule umożliwia wyświetlanie tekstów trójwymiarowych.

      Moduł tworzy listy wyświetlania dla każdej litery. Zapewnia również to, że jeżeli dana czcionka została wcześniej użyta, to nie zostaną ponownie wygenerowane listy wyświetlania.

          1. int init(HDC hDC_, char *fontName, double fontDepth)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda inicjuje daną czcionkę, tworzy odpowiadające jej listy wyświetlania i zwraca numer bazowy dla danej czcionki. Jeżeli czcionka została już wcześniej użyta zwracany jest tylko numer bazowy bez ponownego tworzenia listy wyświetlania. Maksymalna liczba fontów z których można skorzystać zdefiniowana jest w stałej MAXFONTNUM w pliku tekst3DModule.h.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      HDC

      hDC_

      uchwyt urządzenia wyświetlającego

      char*

      fontName

      nazwa czcionki

      double

      fontDepth

      głębokość czcionki

      Argumenty wyjściowe

      Typ

      Opis

      int

      numer bazowy danej czcionki

          1. void PrintString(unsigned int base, char *str)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda wypisuje tekst na ekranie przy użyciu wcześniej zainicjowanej czcionki.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      unsigned int

      base

      numer bazowy czcionki, która ma być użyta

      char*

      str

      tekst do wypisania

      Argumenty wyjściowe

      Brak

        1. Klasa: CTextHandler

      Obiekty tej klasy przechowują teksty wyświetlane na ekranie podczas zwiedzania / wycieczki. Mechanizm ten został wprowadzony, aby usprawnić edycję tekstów i ułatwić obsługę wielu języków.

          1. CTextHandler(char *filename)

      Autor

      Bartosz Rudnicki

      Opis metody

      Konstruktor obiektu klasy.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      filename

      Nazwa pliku, z którego należy wczytać dane (teksty)

      Argumenty wyjściowe

      Brak

          1. ~CTextHandler()

      Autor

      Bartosz Rudnicki

      Opis metody

      Destruktor obiektu klasy.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. char *ReadString(FILE *F)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda odczytuje segment tekstu z pliku.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      FILE*

      F

      Strumień, z którego należy odczytać

      Argumenty wyjściowe

      Typ

      Opis

      char*

      Odczytany fragment

          1. CreateEmptyFile()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda tworzy nowy, pusty plik z tekstami. Obecnie nieużywana, lecz była pomocna przy tworzeniu całego mechanizmu.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. LoadFromFile()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda wczytuje teksty z pliku.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. SaveToFile()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda zapisuje teksty do pliku. Metoda jest używana tylko w edytorze tekstów.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Brak.

          1. SetText(int iNumber, char *string)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda zapisuje podany ciąg znaków na określoną pozycję w tablicy. Używana jest tylko w edytorze tekstów.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      iNumber

      Indeks w tablicy

      char*

      string

      Ciąg znaków do zapisania

      Argumenty wyjściowe

      Brak.

          1. Char *GetText(int iNumber)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda pobiera z tablicy tekst o zadanym indeksie.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      iNumber

      Indeks w tablicy

      Argumenty wyjściowe

      Typ

      Opis

      char*

      Zadany tekst

          1. char * GetFileName()

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda zwraca nazwę pliku powiązanego z obiektem.

      Argumenty wejściowe

      Brak.

      Argumenty wyjściowe

      Typ

      Opis

      char*

      Nazwa pliku

        1. Klasa: CTextureManager

      Klasa CTextureManager wspomaga zarządzanie teksturami i ułatwia ich wykorystywanie. Korzystanie z obiektu tej klasy zwalnia programistę z konieczności wczytywania bitmap, konwertowania ich na tekstury i pamiętania które bitmapy zostały już wcześniej wczytane. Mechanizm menadżera tekstur zapobiega sytuacjom w których jakaś tekstura byłaby wielokrotnie wczytywana i tworzona (np. w wyniku wykorzystania tej samej tekstury w różnych obiektach przez różnych członków zespołu).

      Menadżer tekstur obsługuje również 3 różne tryby dokładności tekstur. Jakość tworzonych tekstur zależy od tego w jakim trybie dokładności został uruchomiony projekt.

      Konstruktor klasy jest prywatny. W celu uzyskania instancji klasy należy skorzystać z metody getTextureManager. Gwarantuje ona wystąpienie tylko 1 instancji obiektu w całym projekcie.

          1. static CTextureManager* getTextureManager()

      Autor

      Marcin Tucholski

      Opis metody

      Metoda zwraca instancję klasy CTextureManager.

      Jeżeli został już wcześniej utworzona instancja tej klasy, to zwracany jest tylko adres tego obiektu.

      Jeżeli jest to pierwsze wykorzystanie menadżera tekstur, to zostanie utworzony obiekt klasy CTextureManager i zwrócony wskaźnik do utworzonego obiektu.

      Ponieważ konstuktor klasy CTextureManager jest konstruktorem prywatnym, to jest to jedyny mechanizm pozwalający utworzyć / skorzystać z menadżera tekstur.

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Typ

      Opis

      CTextureManager*

      wskaźnik na instancję obiektu klasy CTextureManager

          1. void setMode(int mode)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda ustawia tryb działania menadżera tekstur.

      W pliku nagłówkowym TextureManager.h zdefiniowane są obecnie 3 tryby:

      #define MODELOW 3

      #define MODEMEDIUM 2

      #define MODEHIGH 1

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      int

      mode

      tryb pracy menadżera tekstur

      Argumenty wyjściowe

      Brak

          1. int getMode()

      Autor

      Marcin Tucholski

      Opis metody

      Metoda zwraca tryb pracy menadżera tekstur.

      W pliku nagłówkowym TextureManager.h zdefiniowane są obecnie 3 tryby:

      #define MODELOW 3

      #define MODEMEDIUM 2

      #define MODEHIGH 1

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Typ

      Opis

      int

      tryb pracy menadżera tekstur

          1. unsigned int useTexture(char *name)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda ustawia bieżącą teksturę odpowiadającą nazwie pliku podanego jako argument.

      Jeżeli tekstura jest użyta po raz pierwszy, to następuje jej wczytanie i utworzenie.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      name

      nazwa pliku z teksturą

      Argumenty wyjściowe

      Typ

      Opis

      unsigned int

      id tekstury przydzielonej przez OpenGL

          1. unsigned int initTexture(char *name)

      Autor

      Marcin Tucholski

      Opis metody

      Metoda inicjuje daną teksturę.

      Metoda sprawdza, czy tekstura odpowiadająca plikowi podanemu jako argument, została już wcześniej utworzona.

      Jeżeli tak, to zwracany jest tylko identyfikator tekstury.

      Jeżeli nie, to tekstura jest wczytywana i zwracany jest identyfikator tekstury.

      Metoda nie ustawia wczytanej tekstury jako bieżącej (tak jak robi to metoda useTexture).

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      name

      nazwa pliku z teksturą

      Argumenty wyjściowe

      Typ

      Opis

      unsigned int

      id tekstury przydzielonej przez OpenGL

        1. Plik winapi.h

      Plik ten przechowuje metody używane do tworzenia i zarządzania oknem.

          1. GLvoid ReSizeGLScene(GLsizei width, GLsizei height)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda odpowiada za zmianę rozmiaru okna.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      GLsizei

      width

      Nowa szerokość okna

      GLsizei

      height

      Nowa wysokość okna

      Argumenty wyjściowe

      Brak

          1. GLvoid KillGLWindow(GLvoid)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda wywoływana przy zamknięciu okna. Niszczy ona okno oraz wywołuje procedury niszczące wszystkie obiekty w programie

      Argumenty wejściowe

      Brak

      Argumenty wyjściowe

      Brak

          1. BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda tworzy nowe okno.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      char*

      title

      Tytuł nowego okna

      int

      width

      Szerokość okna

      int

      height

      Wysokość okna

      int

      bits

      Określa paletę kolorów (8, 16, 24 lub 32 bitowa)

      bool

      fullscreenflag

      Określa stan okna (false - okno, true - cały ekran)

      Argumenty wyjściowe

      Wartość logiczna określająca, czy powiodło się utworzenie nowego okna.

          1. LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam)

      Autor

      Bartosz Rudnicki

      Opis metody

      Metoda obsługująca komunikaty odbierane przez okno.

      Argumenty wejściowe

      Typ

      Nazwa

      Opis

      HWND

      hWnd

      Uchwyt do okna

      UNIT

      uMsg

      Odbierana wiadomość

      WPARAM

      wParam

      Dodatkowa informacja do wiadomości

      LPARAM

      lParam

      Dodatkowa informacja do wiadomości

      Argumenty wyjściowe

      Wynik domyślnej obsługi komunikatu.

      1. Narzędzia pomocnicze

      Na potrzeby projektu powstał zestaw narzędzi mających na celu usprawnienie procesu modelowania obiektów i pomieszczeń. Dzięki ich zastosowaniu udało się znacznie przyspieszyć te procesy.

        1. Edytor detali

      Ogromna większość obiektów wykorzystywanych w projekcie jest modelowana przy wykorzystaniu funkcji biblioteki GLu32. Zawiera ona funkcje wspomagające rysowanie takich obiektów jak: kule, walce, dyski. Oprócz tego powstał zestaw bibliotek rysujących teksturowane prostopadłościany, wycinki walca i obcięte kule.

      Wykorzystanie tych funkcji znacznie przyspieszyło modelowanie poszczególnych obiektów. Jak wiadomo, podstawową figurą geometryczna wykorzystywaną w OpenGL'u jest trójkąt. Modelowanie złożonych obiektów przy wykorzystaniu pojedynczych trójkątów byłoby bardzo żmudne, czasochłonne i w wielu przypadkach bezcelowe.

      Dla przykładu:

      Aby zamodelować nogę od stołu za pomocą trójkątów (GL_TRIANGLES) trzeba zdefiniować 10 trójkątów. Jak wiemy definicja każdego trójkąta składa się z określenia 3 punktów w przestrzeni. Definicja pojedynczej nogi zajęłaby zatem ok. 30 linii kodu i wymagałaby żmudnych obliczeń współrzędnych punktów. Gdyby do tego doliczyć definiowanie wektorów normalnych dla każdej ściany i nałożenie na każdą ścianę innej tekstury liczba linii kodu wzrosłaby do ok. 40.

      W celu zamodelowania nogi można by również wykorzystać mechanizm czworokątów (GL_QUADS). Wówczas potrzebowalibyśmy 5 czworokątów, a co za tym idzie, definicji 20 punktów. Daje to ok. 20 linii kodu.

      Tą samą rzecz można zamodelować w jednej linii kodu - wykorzystując zdefiniowane w bibliotece GLu32 i utworzone przez nas funkcje pomocnicze. W tym celu można np. wykorzystać funkcję glMyCube która stworzy prostopadłościan o zadanych wymiarach. Co więcej - dla każdej wygenerowanej ściany zostaną obliczone i wygenerowane wektory normalne, a ściany zostaną pokryte zadaną teksturą.

      Jak dowodzi powyższy przykład, wykorzystanie wbudowanych funkcji okazało się znacznie pomocne.

      W praktyce okazało się jednak, że nie wszystko da się zaprojektować przy użyciu prostopadłościanów, cylindrów, walców itp. Czasami trzeba zejść na niższy poziom szczegółowości i modelować przy użyciu prymitywów.

      Właśnie taki był cel powstania edytora detali.

      Głównym zadaniem edytora detali było wspomaganie modelowania szczegółów przy użyciu trójkątów i czworokątów.

          1. Interfejs Edytora detali

      0x01 graphic

      Rysunek 3. Interfejs Edytora detali

          1. Tworzenie, otwieranie, zapisywanie, eksport:

      0x01 graphic

      Rysunek 4. Przyciski podstawowe

      Nowy - tworzy nowy obiekt edytora detali;

      Otwórz - otwiera zapisany obiekt edytora detali ;

      Zapisz - zapisuje bieżący obiekt do pliku;

      Eksportuj - generuje kod C++ i eksportuje go do pliku tekstowego obiekt.tmp;

      Generuj normalne - generuje normalne dla każdego zdefiniowanego trójkąta i czworokąta;

          1. Opcje podglądu

      0x01 graphic

      Rysunek 5. Opcje podglądu

      Pokaż wybrany obiekt - po wybraniu tej opcji wyświetla się okno z podglądem rysowanego obiektu w OpenGL'u.

      0x01 graphic

      Rysunek 6.Okno podglądu

      Wszystkie punkty, trójkąty i czworokąty rysowane są w kolorze zielonym.

      Aktualnie zaznaczony punkt rysowany jest w kolorze czerwonym.

      Wybrany trójkąt i wybrany czworokąt rysowane są w kolorze niebieskim.

      Dzięki temu łatwo można zidentyfikować i zmodyfikować żądaną część.

      Gdy aktywne jest okno z podglądem działają następujące klawisze:

      a/z

      obrót obiektu względem osi OX

      q/w

      obrót obiektu względem osi OY

      s/d

      obrót obiektu względem osi OZ

      g/j

      przesunięcie obiektu wzdłuż osi OX

      h/y

      przesunięcie obiektu wzdłuż osi OY

      -/=

      przesunięcie obiektu wzdłuż osi OZ (zbliżenie/oddalenie)

      Q

      włączenie / wyłączenie trybu automatycznego obracania

      Przezroczystość - po wybraniu tej opcji formatka staje się półprzezroczysta. Dzięki temu możemy umieścić okno edytora detali nad zdjęciem obiektu. W niektórych sytuacjach może ułatwić to modelowanie (wymagany jest system Windows XP).

          1. Zaznaczanie punktów

      0x01 graphic

      Rysunek 7.Zaznaczanie punktów

      Po naciśnięciu przycisku Zaznacz przechodzimy w tryb zaznaczania punktów. Aby zaznaczyć punkty najeżdżamy w wybrane miejsce okna edycyjnego i trzymając wciśnięty lewy klawisz przemieszczamy wskaźnik myszy definiując punkty zaznaczone.

      W danej chwili w oknie edycji widoczne są punkty z bieżącej warstwy (kolor zielony) i z warstwy poprzednio wybranej (kolor niebieski).

      Jeżeli opcja All jest nieaktywna, wówczas zaznaczane są tylko widoczne punkty.

      Jeżeli opcja All jest aktywna, wtedy zaznaczone zostaną punkty wszystkich warstw, również te niewidoczne.

      Zaznaczone punkty można dowolnie przesuwać.

          1. Nawigacja

      0x01 graphic

      Rysunek 8.Przyciski nawigacyjne

      Przyciski te służą do nawigowania po obszarze edycji. Umożliwiają powiększanie i pomniejszanie skali, a także przesuwanie obiektu w poziomie i pionie.

          1. Dodawanie elementów

      0x01 graphic

      Rysunek 9.Przyciski edycyjne

      Przyciski umożliwiają definiowanie odpowiednio punktów, trójkątów i czworokątów. Po wybraniu któregoś z przycisków edytor przechodzi w odpowiedni tryb.

      Przy dodawaniu punktów każde naciśnięcie lewego przycisku myszy na obszarze edycyjnym powoduje dodanie punktu na bieżącej warstwie.

      Przy dodawaniu trójkątów każde naciśnięcie przycisku na punkcie powoduje dodanie punktu do trójkąta. Po wybraniu 3 punktów program automatycznie przechodzi do definiowania kolejnego trójkąta.

      Podobnie wygląda definiowanie czworokątów. Różnica polega wyłącznie na tym, że przy definiowaniu czworokątów wybieramy 4, a nie 3 punkty.

      Obok przycisków widnieją liczby wskazujące ile elementów danego typu występuje w projekcie.

          1. Warstwy

      0x01 graphic

      Rysunek 10.Lista warstw

      Komponent ten służy do zarządzania warstwami w projekcie. Widoczne są tu wszystkie zdefiniowane warstwy. Wybór bieżącej warstwy odbywa się przez naciśnięcie lewego przycisku myszy na nazwie warstwy.

      Poniżej listy wyświetlana jest wysokość wybranej warstwy. Można ją modyfikować albo przy użyciu strzałek (wówczas można obserwować płynną zmianę wysokości warstwy) albo przez wpisanie odpowiedniej wartości i naciśnięciu przycisku Odswiez.

      Istnieje możliwość skopiowania danej warstwy wraz z wszystkimi jej punktami (przycisk Kopiuj).

      Aby dodać nową warstwę należy przycisnąć przycisk +.

          1. Listy prymitywów

      0x01 graphic

      Rysunek 11.Lista trójkątów

      0x01 graphic

      Rysunek 12.Lista czworokątów

      Nieco poniżej listy warstw znajduje się lista zdefiniowanych trójkątów i czworokątów. Po wybraniu trójkąta lub czworokąta odpowiadające mu punkty na obszarze edycji zostają wyróżnione.

      0x01 graphic

      Rysunek 13. Zaznaczony czworokąt

      W oknie podglądu wybrany trójkąt/czworokąt jest rysowany w kolorze niebieskim.

      Możliwe jest usunięcie trójkąta/czworokąta (przycisk Usun).

      Edycja danego trójkąta/czworokąta jest możliwa jedynie poprzez przesuwanie danej warstwy lub przez zmianę położenia punktu należącego do niego.

          1. Statusbar

      0x01 graphic

      Rysunek 14. Statusbar edytora detali

      Bardzo pomocne w modelowaniu są informacje wyświetlane są na Statusbarze. Mamy tu informacje nt.:

      • Pixels - nad jakim pikselem formatki znajduje się wskaźnik myszy,

      • Coord - jakim współrzędnym OpenGL'a odpowiada miejsce pod wskaźnikiem myszy,

      • MODE - w jakim trybie znajduje się program,

      • SELECTED - nad którym punktem znajduje się wskaźnik myszy.

          1. Modelowanie detali przy użyciu Edytora detali

      Każdy obiekt zamodelowany za pomocą edytora składa się z trójkątów (GL_TRIANGLES) i czworokątów (GL_QUADS). Końcowym produktem działania edytora jest kod w C++ opisujący modelowany obiekt. Kod ten jest eksportowany do pliku tekstowego obiekt.tmp dzięki czemu możliwe jest jego "przeklejenie" kodu do projektu.

      Modelowanie obiektu rozpoczynamy od zdefiniowania płaszczyzn. Na płaszczyznach umieszczamy punkty. Liczba zdefiniowanych płaszczyzn i punktów zależy tylko i wyłącznie od poziomu szczegółowości jaki chcemy w rezultacie uzyskać.

      Płaszczyzny umieszczone są na różnych wysokościach. Płaszczyznę należy traktować jako przekrój poprzeczny modelowanego przedmiotu na danej wysokości. Punkty znajdujące się na płaszczyźnie powinny definiować brzegi obiektu w danym przekroju.

      Po zdefiniowaniu płaszczyzn i punktów można przystąpić do definiowania trójkątów i czworokątów. Każdy trójkąt definiujemy przez wskazanie 3 kolejnych punktów. Czworokąt definiujemy przez wskazanie 4 kolejnych punktów.

      Trzeba przy tym pamiętać, że kolejność definiowanych punktów ma duże znaczenie ze względu na generowanie normalnych do powierzchni. Główna zasada jest taka, że punkty figury wskazujemy w kierunku odwrotnym do ruchu wskazówek zegara.

      Przed wyeksportowaniem obiektu możemy nacisnąć przycisk Generuj normalne. Wówczas dla każdego punktu każdego zdefiniowanego trójkąta i czworokąta zostanie wygenerowana normalna. Normalna dla danego punktu obliczana jest jako średnia wszystkich normalnych figur które zawierają dany punkt. Dzięki temu krawędzie i zgięcia nie są ostre lecz wygładzone.

      Wektory normalne nie podlegają jednak normalizacji w edytorze detali. Dlatego wykorzystując obiekty wygenerowane przez edytor detali należy włączyć opcje GL_NORMALIZE.

        1. Edytor pokoi

      Każdy pokój występujący w projekcie jest zdefiniowany w osobnym pliku .rom i .dyn. Plik .rom jest plikiem binarnym przechowującym informacje o:

      • liczbie, położeniu i teksturze ścian,

      • liczbie, rodzaju, skali, obrocie obiektów,

      • liczbie i charakterystyce źródeł światła.

      Plik .dyn przechowuje natomiast informacje o obiektach dynamicznych i obiektach przezroczystych, które nie mogą być umieszczone w liście wyświetlania.

      Ponieważ pliki .rom i .dyn są plikami binarnymi praktycznie niemożliwa byłaby ich edycja z poziomu edytora tekstu np. notatnika. Nawet, gdyby pliki te miały strukturę XML'a to i tak edycja pokoju byłaby bardzo uciążliwa.

      W każdym pokoju znajduje się średnio 50 obiektów (w niektórych jest ich 30, a w niektórych 150). Ręczne definiowanie dla każdego obiektu położenia, obrotu, skali byłoby bardzo żmudne i miałoby charakter metody "prób i błędów".

      Aby usprawnić proces modelowania pomieszczeń powstał program Edytor pokoi.

      Główne funkcje edytora:

      • dodawanie, usuwanie i modyfikacja ścian,

      • dodawanie, usuwanie i modyfikacja podłóg i sufitów,

      • dodawanie, usuwanie, przeskalowanie, obracanie obiektów,

      • podgląd wybranego obiektu w oknie OpenGL,

      • podgląd pokoju w OpenGL (rzut równoległy i perspektywiczny),

      • generowanie plików z obiektami dynamicznymi,

      • możliwość definiowania źródeł światła dla pomieszczenia,

      • możliwość dodawania i definiowania tekstur dla ścian.

      Niewątpliwie jedną z większych zalet edytora jest możliwość podglądu pokoju w OpenGLu. Dzięki temu każda zmiana w położeniu obiektu lub ściany jest od razu widoczna. Pociąga to za sobą ogromną oszczędność czasu, gdyż nie trzeba za każdym razem od nowa uruchamiać projektu, żeby zobaczyć, czy np. szafa stoi na dobrym miejscu.

      Edytor pokoi nie wprowadza żadnego nowego formaty pliku. Obsługuje on pliki .rom i .dyn.

          1. Interfejs Edytora pokoi

      0x01 graphic

      Rysunek 15. Interfejs Edytora pokoi

          1. Tworzenie, otwieranie i zapisywanie

      0x01 graphic

      Rysunek 16. Funkcje podstawowe

      Nowy pokój - tworzy nowy pokój o wskazanej nazwie;

      Otworz - otwiera pokój z pliku;

      Zapisz - zapisuje pokój do pliku;

          1. Wybór obiektu

      0x01 graphic

      Rysunek 17.Wybieranie obiektu

      Do wyboru obiektu służą dwie rozwijane listy. Pierwsza z list przechowuje typ obiektu. Po wybraniu typu obiektu lista druga zostaje wypełniona rodzajami obiektów wybranego typu.

      Jeżeli mamy włączony podgląd obiektu, to zostanie on uaktualniony zaraz po zmianie wyboru. Wybrany obiekt staje się obiektem bieżącym i może być umieszczony w pokoju. Również w momencie przeglądania obiektów znajdujących się w pokoju listy przyjmują wartości odpowiadające aktualnie zaznaczonego obiektu.

          1. Dodawanie elementów pokoju

      0x01 graphic

      Rysunek 18. Dodawanie elementów

      Do dodawania elementów do pokoju służą trzy powyżej przedstawione przyciski.

      Dodawanie obiektu

      Aby dodać obiekt klikamy na przycisk Dodaj obiekt, a następnie wskazujemy miejsce gdzie chcemy aby obiekt był dodany. Po naciśnięciu lewego klawisza myszy obiekt zostanie dodany we wskazanym miejscu.

      Dodawanie ściany

      Aby dodać ścianę klikamy na przycisk Dodaj sciane, a następnie wskazujemy początek i koniec ściany. Początek ściany wskazujemy przez naciśnięcie i przytrzymanie lewego klawisza myszki. Następnie ustawiamy mysz na końcu ściany i puszczamy lewy klawisz. Ściana zostanie dodana.

      Należy jednak pamiętać, że obowiązuje zasada ukrywania niewidocznych ścian. Ściany należy więc definiować w kierunku odwrotnym do ruchu wskazówek zegara.

      Dodawanie podłogi

      Aby dodać podłogę (lub sufit) wybieramy przycisk Dodaj podloge a następnie wskazujemy 4 punkty definiujące podłogę. Każde lewe kliknięcie oznacza 1 punkt. Punkty podłogi również definiujemy w kolejności odwrotnej do ruchu wskazówek zegara.

      Odwrotnie ma się sytuacja z sufitem. Tutaj ścianą widoczną powinna być druga ściana aniżeli w przypadku podłogi. Dlatego punkty sufitu definiujemy w kolejności zgodnej z ruchem wskazówek zegara.

          1. Opcje podglądu pokoju

      0x01 graphic

      Rysunek 19. Opcje podglądu

      Pokaż wybrany obiekt - po wybraniu tej opcji zostanie utworzone okno OpenGL z wyświetlonym aktualnie wybranym obiektem. Okno powinno się zamykać poprzez ponowne przełączenie przełącznika, a nie przez klikanie na "X", gdyż może to spowodować niestabilną pracę edytora.

      Podgląd w OpenGL - po wybraniu tej opcji zostanie utworzone okno OpenGL z podglądem pokoju. Nowe okno podglądu zostanie nakryte starym oknem z ustawionym wysokim współczynnikiem przezroczystości. Dzięki temu możliwe jest ustawianie obiektów z jednoczesnym podglądem. Nie można jednak przesuwać okien.

      0x01 graphic

      Rysunek 20.Podgląd pokoju w OpenGL

      Przezroczystość - po wybraniu tej opcji formatka z podglądem pokoju staje się przezroczysta. Zastosowanie tej opcji jest następujące: w momencie włączenia podglądu w OpenGL formatka automatycznie staje się przezroczysta. Podgląd pokoju w OpenGLu jest bardzo funkcjonalny, nie jest jednak pozbawiony wad. Główną wadą jest to, że nie widać numeracji obiektów. Jeżeli więc chcemy zmodyfikować jakiś obiekt możemy wyłączyć przezroczystość i powrócić do starego podglądu pokoju.

      0x01 graphic

      Rysunek 21.Stary podgląd pokoju

      0x01 graphic

      Rysunek 22. Podgląd pokoju

      Wszystkie obiekty w podglądzie reprezentowane są przez okręgi z wpisanym w środku numerem. Numer ten służy do szybkiej identyfikacji obiektu na liście.

      Okrąg czerwony oznacza aktualnie wybrany obiekt.

      Okrąg żółty oznacza obiekt dynamiczny.

      Ściany reprezentowane są przez niebieskie linie.

      Podłogi i sufity przez niebieskie koperty.

      Wybrana ściana i podłoga, podobnie jak wybrany obiekt, rysowana jest w kolorze czerwonym.

          1. Nawigacja po pokoju

      0x01 graphic

      Rysunek 23.Przyciski nawigacyjne

      Przyciski nawigacyjne służą do poruszania się po pokoju i do przybliżania/oddalania.

          1. Edycja parametrów obiektów i ścian

      0x01 graphic

      Rysunek 24.Lista obiektów

      Wszystkie obiekty i ściany występujące w pokoju są zebrane w przewijanej liście. Wybrany element listy jest malowany dla odróżnienia w kolorze czerwonym.

      W zależności od tego czy wybrany zostało obiekt, czy ściana dostępne są różne opcje.

      Parametry obiektu

      W przypadku wyboru obiektu dostępne są następujące opcje:

      0x01 graphic

      Rysunek 25.Opcje dla obiektu

      xPos, yPos, zPos - współrzędne X, Y, Z obiektu;

      xScale, yScale, zScale - parametry przeskalowania obiektu;

      Kat, xWektor, yWektor, zWektor - kąt i wektor obrotu obiektu;

      Po naciśnięciu przycisku Free move obiekt zostaje "przyklejony" do wskaźnika myszy i możliwe jest jego swobodne przesuwanie po pokoju. Aby upuścić obiekt należy nacisnąć lewy klawisz myszy.

      Aby skopiować obiekt należy nacisnąć przycisk Kopiuj.

      Po zmianie któregokolwiek parametru trzeba zatwierdzić zmiany przez naciśnięcie przycisku Zapisz. Zasada ta nie dotyczy jednak opcji Free move.

      W celu usunięcia obiektu należy nacisnąć przycisk Usun.

      Parametry ściany

      W przypadku, gdy wybranym obiektem jest ściana, wówczas opcje wyglądają następująco:

      0x01 graphic

      Rysunek 26.Opcje dla ściany

      Widzimy tu współrzędne X, Y i Z dla 4 punktów opisujących ścianę P1, P2, P3, P4. Poza tym dla ściany określony jest kolor RGB.

      Przełącznik Collision detection mówi o tym, czy dana ściana ma być brana pod uwagę przy detekcji kolizji, czy ma być pomijana.

      Opcja tekstura pozwala zmieniać teksturę ściany. W rozwijanej liście dostępne są wszystkie tekstury wykorzystane do tej pory w danym pokoju. Jeżeli chcemy dodać nową teksturę należy skorzystać z przycisku +.

      Poniżej wyświetlany jest obraz bieżącej tekstury. Obok niego po prawej stronie i na dole są dwie wartości. Wskazują one ile razy dana tekstura ma być odłożona na ścianie w poziomie i pionie. W tym przypadku tekstura zostanie odłożona 10 razy w pionie i raz w poziomie.

      Podobnie jak miało to miejsce przy edycji obiektu, wszelkie zmiany należy zatwierdzić przyciskiem Zapisz parametry.

      Przycisk Usun służy do usuwania ściany.

          1. Definiowanie źródeł światła

      0x01 graphic

      Rysunek 27.Definiowanie światła

      Aby zdefiniować źródła światła najprościej skorzystać z przycisku Definiuj swiatla. Po naciśnięciu na niego pokaże się nowy dialog, który umożliwia definiowanie i edycję źródeł światła w pokoju.

      0x01 graphic

      Rysunek 28. Dialog definiujący światła

      Dla każdego z ośmiu źródeł światła możemy zdefiniować jego położenie, a także parametry specyficzne dla światła, czyli: światło otoczenia, światło rozproszone, światło odbicia. Możemy również określić czy światło jest kierunkowe, czy nie i ew. określić jego właściwości. Możemy również włączyć i wyłączyć wybrane źródła światła.

      Informacja o źródłach światła zostaje dopisana na końcu pliku .rom.

        1. Edytor poziomów

      Każdy poziom składa się z 1 lub więcej pokoi. Plik zawierający opis poziomu ma rozszerzenie .lev i składa się ze zbioru rekordów. Każdy z rekordów określa nazwę pliku opisującego pokój i przesunięcie pokoju względem punktu (0, 0).

      Istnieje założenie, że wszystkie pokoje na danym poziomie znajdują się na jednakowej wysokości, dlatego przy określaniu przesunięcia pokoju posługujemy się tylko 2 współrzędnymi.

      Edytor poziomów jest w gruncie rzeczy bardzo prostym programem. Powstał po to, aby umożliwić generowanie binarnych plików .lev.

          1. Interfejs Edytora poziomów

      0x01 graphic

      Rysunek 29. Interfejs Edytora pokoi

      Po lewej stronie Edytora pokoi znajduje się lista zdefiniowanych pokoi dla danego poziomu. Po wybraniu któregoś z pokoi po prawej stronie okna wyświetlane są informacje o jego przesunięciu.

      Możliwa jest zmiana przesunięcia pokoju oraz nazwy pliku opisującego dany pokój. Każdą zmianę należy zatwierdzić przyciskiem Zapisz.

      Aby dodać nowy pokój do poziomu należy uzupełnić pola wpisując nazwę pliku opisującego pokój oraz jego przesunięcie a następnie nacisnąć przycisk Dodaj.

      Do zapisywania i wczytywania poziomu służą przyciski Zapisz poziom i Otworz poziom.

        1. Inspektor obiektów

      Kolejnym narzędziem wspomagającym modelowanie pokoi i poziomów jest Inspektor obiektów.

      Podczas modelowania pokoi pojawił się następujący problem: ponieważ różne obiekty były modelowane przez różne osoby, więc po wstawieniu obiektów do pokoju okazało się, że niektóre z nich wymagają przeskalowania. Co więcej - okazało się, że niektóre obiekty mogą być wielokrotnie wykorzystane, tylko muszą być np. inaczej przeskalowane.

      Oczywiste jest, że przeskalowanie obiektu najlepiej robić na poziomie kodu, gdyż wówczas znajduje się ono w obrębie listy wyświetlania danego obiektu. Zyskuje się dzięki temu wydajność.

      Alternatywnym sposobem jest skalowanie obiektu przez zapisanie w jego parametrach na poziomie pliku .rom informacji o skali.

      Dla obiektów które występują w różnej skali jedynym rozwiązaniem jest podejście 2. Natomiast obiekty które w obrębie całego projektu są identycznych rozmiarów sensowne jest wykorzystanie podejścia 1-go.

      Jak się okazało, po stworzeniu kilku pokoi, bardzo łatwo stracić rachubę w tym, które obiekty zostały już wykorzystane, a które jeszcze nie. Oczywistym jest, że jeżeli jakiś obiekt został już umieszczony w którymś z pokoi to wszelkie jego modyfikacje będą miały wpływ na wszystkie pokoje w których się on znajduje.

      Aby usprawnić ten proces powstał Inspektor obiektów. Jest to narzędzie, które sprawdza w jakich pokojach jakie obiekty występują. Co ważne, wyniki są grupowane po typie obiektu a nie numerze pokoju. Dzięki temu łatwo i szybko można znaleźć odpowiedź na szukane pytanie.

      Plik wykonywalny programu należy przed uruchomieniem umieścić w katalogu zawierającego wszystkie pokoje i poziomy. Dopiero wtedy można go uruchomić.

          1. Interfejs Inspektora obiektów

      0x01 graphic

      Rysunek 30. Interfejs Inspektora obiektów

      Po naciśnięciu przycisku Szukaj obszar tekstowy zostaje wypełniony wynikami poszukiwań. Wyniki prezentowane są w następującej postaci:

      rodzaj obiektu, typ obiektu, pokoje, w których występuje ...

      Wynika stąd, że każdemu obiektowi odpowiada 1 linijka tekstu.

      Program znalazł szerokie zastosowanie w projekcie.

        1. TextEditor

      0x01 graphic

      TextEditor powstał z myślą o edycji tekstów używanych w programie.

      Elementy tekstowe (lewy i prawy) służą do edycji tekstów. W lewym widzimy wybrany tekst w języku polskim, w prawym w języku angielskim (jedyne dotychczasowo obsługiwane języki):

      0x01 graphic

      Funkcje przycisków:

      • Load - wczytanie danych z pliku. UWAGA! Po naciśnięciu przycisku pojawi się okienko dialogowe z prośbą o wybranie pliku. Wybrany plik będzie otworzony w lewym elemencie tekstowym. W prawym zostanie odtworzony plik, którego nazwa będzie miała postać pliku z lewej strony z zamienionymi literkami (5 i 6 od końca) na „en”.

      • Save - zapisanie zmian do pliku.

      • Save field - zapisanie wprowadzonych w danym rekordzie zmian do pamięci (nie jest to czynione automatycznie, zapisywane są teksty z obu pól tekstowych).

      Umieszczony u dołu okna suwak służy do przemieszczania się pomiędzy rekordami tekstowymi.

        1. Trip Editor v.2.0

      0x01 graphic

      Trip Editor powstał z myślą o edytorze elementów znajdujących się w pliku ld, czyli: drzwi, punkty informacyjne i punkty wycieczki.

      Program składa się z kilku części: Pasek główny, Mapa, Edytor drzwi, Edytor Punktów Wycieczki oraz Edytor Punktów Informacyjnych.

          1. Pasek główny

      0x01 graphic

      • 1 - nowy plik ld (opcja nieaktywna)

      • 2 - otwórz plik ld

      • 3 - zapisz plik ld

      • 4 - wyświetl drzwi na mapie

      • 5 - odśwież mapę

      • 6 - pokaż punkty informacyjne na mapie

      • 7 - pokaż punkty wycieczki na mapie (przycisk nieaktywny; opcja aktywuje się po wybraniu dowolnego punktu wycieczki).

          1. Mapa

    0x01 graphic

    Wyświetlana jest tutaj mapa edytowanego poziomu.

    UWAGA! Istnieje tutaj poważne ograniczenie: mapa ta nie jest generowana podczas wczytywania pliku, lecz wczytywana z pliku wyeksportowanego z obiektu klasy CCd (zapisana na dysku mapa kolizji).

    Podczas przesuwania kursora nad mapą możemy na pasku stanu odczytać współrzędne danego punktu w przeliczeniu na współrzędne bezwzględne stosowane w projekcie.

    Suwak pod mapą umożliwia przesuwanie mapy.

        1. Edytor drzwi

    0x08 graphic
    Edytor drzwi umożliwia edycje wszystkich parametrów umiejscowienia drzwi.

    Wszystkie drzwi wyświetlone są na liście. Zaznaczenie dowolnego elementu listy powoduje wyświetlenie jego danych poniżej przycisków sterujących.

    Dodawanie drzwi

    Przycisk „Add” powoduje dodanie nowych drzwi o wartościach wpisanych w odpowiednie pola tekstowe.

    Modyfikowanie parametrów drzwi

    Przycisk „Update” powoduje nadpisanie danych zaznaczonego elementu danymi z pól tekstowych.

    Usuwanie drzwi

    Przycisk „Remove” powoduje usunięcie zaznaczonych drzwi.

    UWAGA! Ponieważ drzwi zostały zdefiniowane przed powstaniem edytora, możliwości dodawania i usuwania drzwi nie zostały należycie przetestowane.

    Przeglądanie drzwi na mapie

    Gdy włączone zaznaczanie drzwi na mapie, kliknięcie na dowolnym elemencie listy powoduje podświetlenie go na mapie.

        1. Edytor Punktów Wycieczki

    0x08 graphic
    Edytor punktów wycieczki powstał z myślą tworzeniu i edycji punktów wycieczki.

    Edycja punktów wycieczki

    Po wybraniu dowolnego elementu z listy wyświetlającej wszystkie punkty dany element zostaje podświetlony na mapie, a w polach tekstowych u dołu okna widać jego dane.

    Modyfikowanie punktów wycieczki

    Aby zmodyfikować parametry punktu wycieczki należy wybrać dany element z listy, wprowadzić nowe dane w pola tekstowe, a następnie nacisnąć przycisk „Update”.

    Dodawanie punktów wycieczki

    Aby dodać nowy punkt wycieczki, należy wybrać z listy odpowiedni element, a następnie kliknąć na przycisk „Insert before” (wstaw przed elementem) lub „Insert after” (wstaw po elemencie) (gdy na liście nie ma żadnego elementu, należy wybrać przycisk „Insert before”). Następnie na mapie należy nacisnąć lewy przycisk myszki w miejscu, gdzie chcemy ustawić nowy punkt, a następnie (nie puszczając lewego przycisku myszki) wskazać kąt, pod którym obserwator ma patrzeć na otaczający go wirtualny świat. Kąt będzie ustalony automatycznie: punkt wycieczki będzie w miejscu, gdzie naciśnięty zostanie lewy przycisk myszki, a obserwator będzie patrzył w kierunku punktu, w którym puścimy lewy przycisk myszki. W międzyczasie na pasku stanu będzie wyświetlany kąt, pod którym obserwator będzie patrzył:

    0x01 graphic

    Następnie wyświetli się okienko, w którym należy podać pozostałe dane punktu:

    0x01 graphic

    Parametry X i Z określają współrzędne punktu. Angle oznacza kąt patrzenia. Time oznacza czas (w klatkach, później pomnożony przez stałą zdefiniowaną w pliku constant.h) w jakim do punktu należy dojść od punktu poprzedniego, Action oznacza akcję przeprowadzaną w tym punkcie (-1 - nic, 1 - otwórz drzwi, 2 - zamknij drzwi, 3 - wyświetl punkt informacyjny, 4 - zakończ wycieczkę), a Object interpretowany jest jako indeks obiektu, na którym ma być przeprowadzona dana operacja.

    Po kliknięciu na przycisk „OK.” punkt zostanie dodany.

    Usuwanie punktu wycieczki

    Aby usunąć punkt wycieczki należy wybrać go z listy i kliknąć na przycisk „Remove”.

        1. Edytor Punktów Informacyjnych

    Edytor Punktów Informacyjnych powstał z myślą o ich tworzeniu i edycji.

    0x01 graphic

    Dodawanie punktów informacyjnych

    Aby dodać punkt informacyjny należy kliknąć na przycisku „Add”, a następnie na mapie, w punkcie, w którym ma znajdować się nowy punkt. Dalej będzie on utworzony automatycznie, bez żadnych ekranów.

    Usuwanie punktów informacyjnych

    Aby usunąć punkt informacyjny wybrać go z listy, a następnie kliknąć na przycisku „Remove”.

    Zmiana położenia punktów informacyjnych

    Aby zmienić położenie punktu informacyjnego należy wybrać go z listy, kliknąć na przycisku „Location”, a następnie na mapie w miejscu, gdzie ma się on teraz znajdować.

    Edycja i modyfikacje punktów informacyjnych

    Aby edytować punkt informacyjny należy wybrać go z listy.

    Pierwszą rzeczą do modyfikacji jest określenie, czy punkt jest dostępny w trybie zwiedzania. Jeżeli zaznaczone będzie pole „Trip Only”, to punkt będzie niedostępny podczas zwiedzania.

    Aby edytować bardziej zaawansowane właściwości należy wybrać przycisk z listy i kliknąć na przycisku „Edit” (lub dwukrotnie kliknąć na obiekt na liście). Ukaże się nam wtedy okienko edycji Ekranów.

    0x01 graphic

    Możemy teraz zarządzać ekranami. Klawisze „Insert before” i „Insert After” służą odpowiednio do wstawiania ekranu przed i po wybranym elemencie (działają identycznie, gdy punkt nie ma żadnych ekranów). „Exit” powoduje zamknięcie okna (i zapamiętanie aktualnego stanu danych), „Remove” usuwa wybrany ekran, a „Edit” edytuje wybrany ekran, co powoduje otwarcie kolejnego okienka:

    0x01 graphic

    Jest okienko edycji ramek. Ramki dodajemy przyciskiem „Add”, a usuwamy przyciskiem „Remove”. Przycisk „Exit” powoduje zamknięcie okna i zapamiętanie wszystkich danych. Pole „Delay Time” określa czas wyświetlania ekranu w sekundach. Aby zmienić wartość, należy wpisać nową wartość i kliknąć na przycisku „Update”.

    Przycisk „Preview” docelowo ma generować podgląd edytowanego ekranu, jednakże nie jest on oprogramowany.

    Wybierając element z listy otrzymujemy jego parametry.

    Typ ramki określamy wybierając „Text” (tekst, okno 1), „Image” (obrazek, okno 2) lub „Audio” (dźwięk, okno 3).

    Gdy wybierzemy ramkę tekstową, należy podać jej współrzędne na ekranie (X, Y) oraz numer (indeks) tekstu (teksty możemy przeglądać przy użyciu narzędzia TextEditor).

    Po wybraniu ramki z obrazkiem należy podać współrzędne ramki na ekranie (X, Y), wielkość obrazka w pixelach (jest to wielkość obrazka po wyświetleniu, a nie zapisanego w pliku) (wielkość podajemy przez podanie szerokośći („width”) oraz wysokości („height)), a następnie nazwy obrazka (bez ścieżki dostępu; obrazek jest traktowany jako tekstura i powinien się znaleźć w odpowiednich katalogach z teksturami).

    Gdy wybierzemy ramkę dźwiękową należy podać tylko nazwę pliku do odtworzenie (również bez ścieżki dostępu; plik z dźwiękiem powinien być w odpowiednim podkatalogu katalogu „data\audio”).

    Na koniec należy kliknąć na przycisku „Update frame” aby zapamiętać wprowadzone zmiany.

        1. Uwagi dotyczące użytkowania edytorów

    1. Należy pamiętać, iż dodawanie i usuwanie obiektów powoduje przeindeksowanie pozostałych, co może prowadzić do niepoprawnego działania powiązanych ze sobą obiektów.

    czerwonej książki - strona 207 rysunek 7.8

    czerwonej książki - strona 219 rysunek 7.22

    Metoda biblioteki glut

    Wirtualny model Instytutu Informatyki w grafice trójwymiarowej

    44/94

    0x01 graphic

    0x01 graphic



    Wyszukiwarka

    Podobne podstrony:
    praca inzynierska-ExtremeProgramming, rok III, Zarządzanie Projektami Informatycznymi
    model OSI, Informatyka, Sieci Komputerowe
    Praca inżynierska
    Egz dyplom 2012b, szkoła, praca inżynierska
    Projekt i załoŻenia techniczne budowy małej stacji paliw płynnych praca inzynierska budownictwox
    19.01.2015 PRACA INŻYNIERSKA MIODYŃSKA, Studia- ochrona środowiska
    ~$kadiusz Przytuła praca inzynierska
    Egz dyplom 2012d, szkoła, praca inżynierska
    Model komputera, Informatyka, SO
    Model 3LZ, Informatyka i Ekonometria 2 rok, badania operacyjne, sciagniete z internetu
    Praca inżynierska, Studia, Ochrona środowiska
    praca inzynierska(1)
    praca inzynierska rozproszona platforma algorytmów VSYTKQGVRMWJJ5DGL3TQNPLS7KYX7KBMBLRCT7A
    MODEL 5 wykład, Informatyka i Ekonometria 2 rok, badania operacyjne, sciagniete z internetu
    Model 4 wykład, Informatyka i Ekonometria 2 rok, badania operacyjne, sciagniete z internetu
    Model 3 wykład, Informatyka i Ekonometria 2 rok, badania operacyjne, sciagniete z internetu
    Model 2 wykład, Informatyka i Ekonometria 2 rok, badania operacyjne, sciagniete z internetu

    więcej podobnych podstron