Oprogramowanie i wykorzystanie stacji roboczych Wykład 10
Transkrypt
Oprogramowanie i wykorzystanie stacji roboczych Wykład 10
Oprogramowanie i wykorzystanie stacji roboczych Wykład 10 Dr inż. Tomasz Olas [email protected] Instytut Informatyki Teoretycznej i Stosowanej Politechnika Cz˛estochowska Wykład 10 – p. 1/4 Wieloteksturowanie (I) Wieloteksturowanie (multiteksturowanie) to technika pozwalajaca ˛ na jednoczesnego nakładania na obiekt wiecej ˛ niż jednej tekstury. Wieloteksturowanie wprowadzono w wersji 1.3 biblioteki OpenGL. We wcześniejszych implementacjach podobny efekt można uzyskać przy użyciu techniki teksturowania wieloprzebiegowego, które jest jednak bardziej skomplikowane (wymaga stosowania mieszania kolorów oraz wielokrotnego przeliczania geometrii renderowanego obiektu) oraz znacznie wolniejsze. Wykład 10 – p. 2/4 Wieloteksturowanie (II) Wybór aktualnej jednostki teksturujacej ˛ umożliwia funkcja: void glActiveTexture (GLenum texture); gdzie: texture - określa numer wybranej jednostki teksturujacej ˛ (GL_TEXTUREi, gdzie i przyjmuje wartość od 0 do 31). W przypadku wieloteksturowania definiowanie współrz˛ednych tekstur przy użyciu funkcji z grupy glTexCoord daje efekt tylko dla pierwszej jednostki teksturujacej ˛ (GL_TEXTURE0). Definiowane współrzednych tekstur dla dowolnej jednostki teksturujacej umozliwiajaja˛ funkcje z grupy glMultiTexCoord (posiadaja˛ dodatkowy parametr target określajacy ˛ numer jednostki teksturujacej). ˛ Przykład: void glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); Wykład 10 – p. 3/4 Pozostałe funkcje Kopiowanie tekstury z bufora kolorów Zmiana cz˛eści danych tekstury Tekstury zastepcze ˛ (proxy) Kompresja tekstur Automatyczne generowanie współrz˛ednych tekstur Tekstury głebi ˛ Wykład 10 – p. 4/4 Mapowanie nierówności Mapowanie nierówności (ang. bump mapping) jest technika˛ polegajac ˛ a˛ na wykorzystaniu tekstury do modyfikacji wektora normalnego. Wykład 10 – p. 5/4 Mapowanie tekstur - liniowe Wykład 10 – p. 6/4 Mapowanie tekstur - cylindryczne Wykład 10 – p. 7/4 Mapowanie tekstur - sferyczne Wykład 10 – p. 8/4 Selekcja obiektów Selekcja jest w rzeczywistości trybem renderowania, w którym żadne piksele nie sa˛ kopiowane do bufora ramki. Zamiast tego prymitywy sa˛ rysowane w bryle widzenia (tak jak normalnie pojawiłyby sie˛ w buforze ramki) w wyniku czego tworza˛ rekordy trafień w buforze selekcji. Przed przystapieniem ˛ do selekcji obiektów wcześniej należy utworzyć bufor selekcji oraz oznaczyć (nazwać) prymitywy lub grupy primitywów tak, aby można je było zidentyfikować w buforze selekcji. Nastepnie ˛ przetwarza sie˛ bufor selekcji w celu wyznaczenia, które obiekty przecinaja˛ bryłe˛ widzenia. Najcz˛eściej określa sie˛ bryłe˛ widzenia odpowiadajac ˛ a˛ wskaźnikowi myszy, a nastepnie ˛ sprawdza, które z obiektów zostały wskazane przez kursor myszy. Wykład 10 – p. 9/4 Zmiana trybu renderowania Do zmiany trybu renderowania służy funkcja: GLint glRenderMode (GLenum mode); gdzie: mode - przyjmuje nastepuj ˛ ace ˛ wartości: GL_RENDER - tryb renderowania (domyślny), GL_SELECT - tryb selekcji, GL_FEEDBACK - tryb sprz˛eżenia zwrotnego. Wykład 10 – p. 10/4 Stos nazw obiektów Nazwy obiektów, które moga˛ zostać wybrane w trakcie selekcji sa˛ przechowywane na stosie nazw. Nazwy obiektów, nie sa˛ niczym innym jak cyfrowymi identyfikatorami w postaci liczb całkowitych bez znaku. Pojedyncza nazwa może zostać przypisana zarówno pojedynczemu prymitywowi, jak również bardziej złożonemu obiektowi. Wielkość stosu nazw nie może być mniejsza niż 64 (jest zależna od implementacji). Przed użyciem stosu nazw obiektów należy go zainicjować: void glInitNames(); Do nadania nazw poszczególnym obiektom służy funkcja: void glLoadName (GLuint name); gdzie: name - identyfikator (nazwa) obiektu. Wykład 10 – p. 11/4 Obiekty hierarchiczne W przypadku, gdy obiekty maja˛ strukture˛ hierarchiczna˛ (obiekty złożone), to konieczne jest umieszczanie kolejnych nazw obiektów na bierzacym ˛ stosie: void glPushName(GLuint name); Po dodaniu obiektu podrz˛ednego należy zdiać ˛ nazwe˛ obiektu ze stosu: void glPushName(GLuint name); Wykład 10 – p. 12/4 Nazwanie obiektów - przykład void MyGLWidget::paintGL() { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -20.0f); glInitNames(); glPushName(0); glLoadName(redRectangle); glColor3f(1.0f, 0.0f, 0.0f); glRectf(1.0f, 1.0f, 5.0f, 5.0f); glLoadName(blueRectangle); glColor3f(0.0f, 0.0f, 1.0f); glRectf(-5.0f, -5.0f, -1.0f, -1.0f); glFlush(); } Wykład 10 – p. 13/4 Ustawienie bufora selekcji Aby skorzystać z bufora selekcji należy utworzyć bufor selekcji i ustawić go, przed przejściem w tryb selekcji, przy pomocy funkcji: void glSelectBuffer (GLsizei size, GLuint *buffer); gdzie: size - rozmiar bufora selekcji, buffer - utworzony bufor selekcji, w którym przechowywane sa˛ nazwy obiektów wybranych w trakcie selekcji - bufor powinien być na tyle duży, aby zmieścić informacje o wszystkich obiektach wybranych w trybie selekcji. Ilość wybranych obiektów zwracana jest przez funkcje˛ glRenderMode w momencie powrotu do trybu renderowania GL_RENDER (po zakończeniu pracy w trybie selekcji). Wykład 10 – p. 14/4 Rekordy trafień Informacje o wybranych obiektach zawarte sa˛ w rekordach trafień znajujacych ˛ sie˛ w buforze selekcji. Każdy rekord trafień zawiera przynajmniej cztery elementy (kolejne liczby całkowite): [0] - liczba identyfikatorów obiektów znajdujacych ˛ sie˛ na stosie nazw w momencie trafienia, [1] - minimalna wartość współrz˛ednych z prymitywów graficznych wchodzacych ˛ w skład wybranego obiektu (wartość współrz˛ednej z jest przekształcana z zakresu < 0, 1 > poprzez mnożenie jej przez 232 − 1 i zaokraglenie ˛ do najbliższej liczby całkowitej), [2] - maksymalna wartość współrz˛ednych z prymitywów graficznych wchodzacych ˛ w skład wybranego obiektu (wartość ta jest wyliczana analogicznie jak powyżej), [3] - najniższy element stosu nazw obiektów (pierwszy odłożony na stos), [3] - najwyższy element stosu nazw obiektów (ostatni odłożony na stos), Wykład 10 – p. 15/4 Modyfikacja bryły widzenia Podczas tworzenia macierzy opisujacej ˛ nowa˛ bryłe˛ widzenia bardzo przydaje sie˛ funkcja: void gluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, const GLint viewport[4]); gdzie: x i y - środek żadanej ˛ bryły widzenia we współrz˛ednych okna, width i height - określaja˛ szerokość i wysokość bryły widzenia w pikselach okna. viewport - zawiera współrz˛edne okna dla aktualnie zdefiniowanego widoku. Można je łatwo odczytać wywołujac: ˛ glGetIntegerv(GL_VIEWPORT, viewport); Przed wywołaniem funkcji gluPickMatrix najpierw zachować bieżacy ˛ stan macierzy rzutowania (czyli zachować bieżac ˛ a˛ bryłe˛ widzenia). Wykład 10 – p. 16/4 Wybór obiektów - przykład (I) void MyGLWidget::mousePressEvent(QMouseEvent* event) { qDebug("mouse (%d, %d)\n", event->x(), event->y()); const int BUFFER_LENGTH = 128; GLuint selectBuff[BUFFER_LENGTH]; glSelectBuffer(BUFFER_LENGTH, selectBuff); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix(event->x(), viewport[3] - event->y(), 2, 2, viewport); gluPerspective(45.0f, 1.0, 1.0, 400.0); Wykład 10 – p. 17/4 Wybór obiektów - przykład (II) glRenderMode(GL_SELECT); glMatrixMode(GL_MODELVIEW); paintGL(); GLint hits = glRenderMode(GL_RENDER); qDebug("Hits: %d", hits); if (hits == 1) qDebug("Selection object: %d", selectBuff[3]); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } Wykład 10 – p. 18/4 Sprzeżenie ˛ zwrotne Sprz˛eżenie zwrotne, podobnie jak selekcja, jest trybem renderowania, w którym nic nie jest rysowane na ekranie. Zamiast tego, do bufora sprz˛eżenia zwrotnego wpisywane sa˛ informacje na temat sposobu renderowania sceny. Te informacje obejmuja˛ współrz˛edne okna przetransformowanych wierzchołków, kolory wierzchołków już po oświetleniu, a także dane tekstury. Przejście do trybu sprz˛eżenia zwrotnego odbywa sie˛ podobnie jak przejście do trybu selekcji, poprzez wywołanie funkcji glRenderMode z parametrem GL_FEEDBACK. W celu wypełnienia bufora sprz˛eżenia zwrotnego i powrotu do normalnego trybu renderowania musisz wywołać funkcje˛ glRenderMode(GL_RENDER). Wykład 10 – p. 19/4 Bufor sprzeżenia ˛ zwrotnego Bufor sprz˛eżenia zwrotnego jest tablica˛ wartości zmiennoprzecinkowych, tworzona˛ za pomoca˛ funkcji glFeedbackBuffer: void glFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer); gdzie: size - maksymalna ilość pozycji zaalokowanych w buforze buffer, type - określa rodzaj danych o wierzchołkach, umieszczanych w buforze sprz˛eżenia zwrotnego, buffer - buforz, w którym zapisane zostana˛ informacje dotyczace ˛ wierzchołków. Dla każdego wierzchołka, w buforze umieszczany jest osobny blok danych. Wykład 10 – p. 20/4 Typy danych typ współrz˛edne dane koloru dane tekstury liczba wartości GL_2D x, y - - 2 GL_3D x, y, z - - 3 GL_3D_COLOR x, y, z C - 3+C GLJD_COLOR_TEXTURE x, y, z C 4 7+C GL_4D_COLOR_TEXTURE x, y, z, w C 4 8+C Wykład 10 – p. 21/4 Dane sprzeżenia ˛ zwrotnego Bufor sprz˛eżenia zwrotnego zawiera liste˛ elementów, po których nastepuj ˛ a˛ dane wierzchołków i ewentualnie koloru i tekstury. Element Prymityw GL_POINT_TOKEN Punkty GL_LINE_TOKEN Linie GL_LINE_RESET_TOKEN Segment linii po wyzerowaniu wzorca linii GL_POLYGON_TOKEN Wielokat ˛ GL_BITMAP_TOKEN Bitmapa GL_DRAW_PIXEL_TOKEN Narysowany prostokat ˛ piksela GL_COPY_PIXEL_TOKEN Skopiowany prostokat ˛ piksela GL_PASS_THROUGH_TOKEN Znacznik zdefiniowany przez użytkownika Wykład 10 – p. 22/4 Konstrukcja wielomodułowa programów Zapewnia logiczna˛ strukture˛ i poprawia czytelność programu. Niezależne moduły moga˛ być oddzielnie testowane i po kompilacji wykorzystywane w różnych programach. Umożliwia wykorzystywanie w programie w jezyku ˛ C/C++ procedur napisanych w innych jezykach ˛ programowania. Zwieksza ˛ szybkość kompilacji w trakcie modyfikowania programu. Wykład 10 – p. 23/4 Make Make jest narz˛edziem automatycznie określajacym, ˛ które fragmenty kodu wymagaja˛ ponownej kompilacji i wykonuje ich kompilacje. ˛ Plik makefile (Makefile) - opisuje relacje pomiedzy ˛ plikami w projekcie oraz polecenia służace ˛ do uaktualniania poszczególnych plików. wywołanie: make make -f makefile_name make nazwa_reguly Reguły, dyrektywy i definicje makr powinny rozpoczynać sie˛ w pierwszej kolumnie tekstu, natomiast polecenia musza˛ być poprzedzone co najmniej jednym znakiem pustym. Wykład 10 – p. 24/4 Make - reguły Reguły (rules) opisuja˛ kiedy i w jaki sposób należy „odświeżać” pliki. Można rozróżnić dwa rodzaje reguł: Reguły jawne: zbiór_uakt [zbiór_uakt [...]]: {{ścieżki}][zbiór-uzal ...] polecenie przykład: foo.o : foo.c defs.h gcc -c -g foo.c Reguły niejawne: [katalog_źródł]\%.rozsz_źródł: [katalog_docelowy]\%.rozsz_docelow polecenie przykład: %.o: %.c gcc -c $< Wykład 10 – p. 25/4 Make - makrodefinicje Definicja: nazwa_makrodefinicji=tekst_rozwini˛ ecia przykład: PROGRAM=bierki OBJS=foo.c Rozwiniecie: ˛ $(nazwa_makrodefinicji) przykład: $(PROGRAM): $(OBJS) g++ -c $(OBJS) -o $(PROGRAM) Wykład 10 – p. 26/4 Make - makrodefinicje predefiniowane $* - makro to rozwija sie˛ w nazwe˛ zbioru uzależniajacego ˛ (ze ścieżka˛ dostepu, ˛ lecz bez rozszerzenia), $< - działa tak jak $*, z ta˛ różnica, ˛ że uzyskana nazwa zbioru zawiera rozszerzenie, $@ - rozwija sie˛ w nazwe˛ zbioru uzależnianego (wraz z jego rozszerzeniem), $: - rozwija sie˛ w ścieżk˛e dostepu ˛ do zbioru, ale bez jego nazwy. Jeśli wystepuje ˛ w regułach jawnych, to uzyskana zostanie ścieżka zbioru docelowego, w niejawnych zaś ścieżka zbioru przetwarzanego. Wykład 10 – p. 27/4 Make - przykład PROJECT = bierki INC = ./include INSTALLBIN = $(HOME)/opt/bin CXX = g++-2.95 CXXFLAGS += -I$(INC) OBJS = $(PROJECT).o okno.o all: $(PROJECT) %.o: %.cpp $(CXX) $(CXXFLAGS) -c -o $@ $< $(PROJECT): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) clean: -rm -rf *.o realclean: clean -rm -rf $(PROJECT) Wykład 10 – p. 28/4 Automatyczne generowanie zależności Kompilator gcc posiada opcje -M, -MM, które generuja˛ zależności od plików nagłówkowych dla przetwarzanego pliku źródłowego. Przykład: depend: $(CXX) -MM $(CXXFLAGS) *.cpp > depend.mk ... include depend.mk Przykład wygenerowanych zależności: domain.o: src/domain.cpp include/domain.h include/fxdrstream.h \ include/except.h fxdrstream.o: src/fxdrstream.cpp include/fxdrstream.h mpi_wrapper.o: src/mpi_wrapper.cpp include/mpi_wrapper.h Wykład 10 – p. 29/4 Make - reguły standardowe Istnieje zbiór reguł, których stosowanie powoduje, że pliki makefile sa˛ znacznie prostsze do zrozumienia i stosowania: all, test, clean, dist, distclean, realclean, install, uninstal. Wykład 10 – p. 30/4 Narzedzia ˛ wspierajace ˛ program make - służy do automatycznego generowania zależności pomiedzy ˛ plikami w projekcie (dostarczany razem z systemem X Window), makedepend - służy do mechanicznego generowania plików makefile dla systemu X. Opiera sie˛ na wywołaniu programu makedepend, Imake - generuje skrypt powłoki configure dopasowany do projektu, autoconf - narz˛edzie podobny do autoconf - umożliwia generowanie plików makefile, posiadajacy ˛ jednak wbudowane mechanizmy badania zależności (podobna˛ do programu Imake), automake - narz˛edzie firmy TrollTech pierwotnie utworzone dla biblioteki Qt, ale może być wykorzystywane również w innych projektach. tmake Wykład 10 – p. 31/4 GNU Autoconf (I) Autoconf jest narz˛edziem (zestawem makr M4) służacym ˛ do generownia skryptów powłoki, które pozwalaja˛ na automatyczne dostosowanie pakietów oprogramowania (w postaci kodu źródłowego) do specyfiki wielu różnych systemów operacyjnych. Wygenerowane skrypt konfiguracyjny (configure) jest niezależny od narz˛edzia Autoconf i podczas kompilacji pakietu nie jest ono wymagane. Skrypt configure wykonuje szereg testów majacych ˛ na celu sprawdzenie, czy i ewentualnie gdzie w systemie znajduja˛ sie˛ narz˛edzia, biblioteki, pliki nagłówkowe niezbedne ˛ do poprawnego utworzenia programu. Po określeniu środowiska w którym kompilowany jest program skrypt ten powinien wygenerować odpowiednie definicje i opcje kompilacji. Cz˛esto narz˛edzie Autoconf jest stosowany w połaczeniu ˛ z programami Automake i Autoheader. Wykład 10 – p. 32/4 GNU Autoconf (II) Szczególnie ważna˛ kwestia˛ przy tworzeniu plików wejściowych dla programu Autoconf jest określenie, co należy sprawdzać przy kompilacji programu na różnych platformach systemowych. Plik konfiguracyjny tworzy sie˛ w oparciu o makra sprawdzajace: ˛ Autoconf zawiera zbiór makr sprawdzajacych ˛ dla teypowych elementów, w przypadku braku gotowego testu dla danego elementu (pliku nagłówkowego, bibilioteki, funkcji) można wykorzystać test ogólny (np. na obecność pliku w systemie plików), w ostateczności należy utworzyć fragment testujacy ˛ w jezyku ˛ Bourne shella. Wykład 10 – p. 33/4 Tworzenie skryptu configure W celu wygenerowania skryptu configure należy utworzyć plik konfiguracyjny dla programu Autoconf: configure.ac (lub configure.in). Przykładowa struktura pliku configure.ac: Uworzenie pliku configure nastapi ˛ po uruchomieniu programu autoconf. Wykład 10 – p. 34/4 Autoconf - przykład (I) AC_INIT(sample,0.1) AC_PROG_CXX # Checks for performing tests CPPUNIT="no" AC_ARG_ENABLE(test, [--enable-test enable test suite [default=yes]], ,enable_test="yes") if test ! "x$enable_test" = "xno"; then AC_PATH_PROG(CPPUNIT_CONFIG,cppunit-config,no) if test "x$CPPUNIT_CONFIG" = "xno"; then AC_MSG_ERROR([cppunit is needed but not found.]) fi CPPUNIT="yes" CPPUNIT_CFLAGS=‘$CPPUNIT_CONFIG --cflags‘ CPPUNIT_LIBS=‘$CPPUNIT_CONFIG --libs‘ AC_SUBST(CPPUNIT_CFLAGS) AC_SUBST(CPPUNIT_LIBS) fi AC_SUBST(CPPUNIT) AC_CONFIG_FILES(Makefile) AC_OUTPUT Wykład 10 – p. 35/4 Autoconf - przykład (II) Plik Makefile.in: ... # CppUnit flags ifeq ($(CPPUNIT), yes) CXXFLAGS += @CPPUNIT_CFLAGS@ LDFLAGS += @CPPUNIT_LIBS@ endif $(OBJ)/%.o: $(SRC)/%.cpp $(CXX) -c $(CXXFLAGS) -o $@ $< $(PROGRAM): $(OBJS) $(CXX) -o $(PROGRAM) $(LDFLAGS) $(OBJ) Wykład 10 – p. 36/4 Jam Jednym z ciekawszych projektów, które w przyszłości moga˛ zastapić ˛ program make jest Jam. Zalety: Zwiekszenie ˛ projektu nie prowadzi do tak drastycznego zwiekszania ˛ sie˛ pliku konfiguracyjnego jak ma to miejsce w przypadku programu make. Automatycznie generowane sa˛ zależności od plików nagłówkowych. Jam buduje duże projekty rozmieszczone w wielu katalogach za jednym podejściem, bez rekursywnego nawracania jak to robi make, śledzac ˛ wszystkie pliki jednocześnie. Może pracować na wielu procesorach. Jam jest mały (np. 92 kB), praktycznie nie obciaża ˛ procesora, i nie tworzy dodatkowych plików (jak np. nmake, SunOS make). Może być dowolnie konfigurowany poprzez tzw. reguły (Jamrules). Wykład 10 – p. 37/4 Jam kontra Make Plik konfiguracyjny dla programu Make: progam: data.o main.o io.o gcc data.o main.o io.o -o progam data.o: data.c gcc -c data.c main.o: main.c gcc -c main.c io.o: io.c gcc -c io.c io.o: io.h main.o: io.h data.h data.o: data.h io.h Plik konfiguracyjny dla programu Jam: Main progam : data.c main.c io.c ; Wykład 10 – p. 38/4 Apache Ant (I) Apache Ant jest cz˛eścia˛ projektu Apache Jakarta. Opiera sie˛ na podobnym założeniu co make jeżeli chodzi o zależności i reguły, ale nie zakłada że sa˛ to pliki i że głównym celem reguł jest uaktualnienie zadań. Używa jezyka ˛ XML. Jest w pełni niezależny od platformy. Został napisany z myśla˛ o Javie, ale posiada również wsparcie do tworzenia projektu w innych jezykach ˛ programowania (również w C++). Ant jest napisany całkowicie w Javie. Wykład 10 – p. 39/4 Apache Ant (II) Plik konfiguracyjny dla programu Ant jest plikiem w formacie XML. Zazwyczaj nosi nazwe˛ build.xml. Składa sie˛ on z różnej ilości różnych tagów, zwanych <target> (cel). Może to być np. kompilacja, utworzenie archiwum, utworzenie dokumentacji czy też wysłanie poczty elektronicznej. Każdy cel składa sie˛ z dowolnej ilości wykonywanych zadań <task>. Jest to prosta czynność, która bedzie ˛ wykonywana, np. tworzenie katalogu, kopiowanie pliku, kompilacja kodu źródłowego. Każde zadanie może posiadać parametry i być zależne od innych zadań. Wykład 10 – p. 40/4 Apache Ant - przykładowy plik build.xml <?xml version="1.0" encoding="iso-8859-2"?> <project name="first" basedir="." default="compile"> <path id="log4jclasspath"> <pathelement location="${basedir}"/> <pathelement location="/../wspolne.jar"/> </path> <target name="compile"> <javac srcdir="." classpathref="classpath" /> </target> <target name="run"> <java classpathref="" classname="org.gridwise.Simple" /> </target> </project> Wykład 10 – p. 41/4