Grafika 3D
 
  Zarejestruj się
::  Newsy  ::  Pliki  ::  Twoje Konto  ::  Forum  ::
Menu
· Strona główna
· Forum
· Linki
· Lista u?ytkowników
· O nas...
· Pliki
· Statystyki
· Twoje Konto
Tutoriale
· API
· Matematyka
· Teoria
· Direct3D
· OpenGL
· Techniki
Kto Jest Online
Aktualnie jest 41 gość(ci) i 0 użytkownik(ów) online.

Jesteś anonimowym użytkownikiem. Możesz się zarejestrować za darmo klikając tutaj
Tutoriale - OpenGL - Szablon

No i cóż. Skoro już wiemy mniej więcej, co to takiego ten cały OpenGL i po co nam to będzie potrzebne, możemy przystąpić do tworzenia. W pierwszej praktycznej lekcji zajmiemy się stworzeniem sobie pewnej podstawowej części aplikacji, która potem posłuży nam do dalszych zabaw z OpenGL. W każdej następnej lekcji będziemy wykorzystywać pewien zestaw stałych funkcji, które pozwolą stworzyć okno, ustawić odpowiednie konteksty renderowania i tym podobne rzeczy. Będziemy pisać pod Windows, ale nie będziemy korzystać na razie z żadnej biblioteki narzędziowej. Mam do nich taką niejasną niechęć a poza tym lubię wiedzieć, co mi się w programie dzieje. Z tego też względu nasze programy będą trochę nieprzenośne na inne systemy, ale co bardziej zaradni na pewno sobie poradzą i z zaadoptowaniem kodu nie będą mieli najmniejszych problemów. W sumie dla nas to i tak nie będzie ważne, bo my chcemy się tylko nauczyć jak manipulować urządzeniem a nie tworzyć okna. Podobnie jak w przypadku DirectX, będziemy omawiać tylko najważniejsze, nowe części kodu a te powtarzające się będziemy utrwalać, ale nie powtarzać w kółko. Ponieważ ta lekcja jest pierwszą praktyczną, więc tutaj będzie sporo nowości i omówimy sobie pokrótce wszystko. Tworzenie okien, obsługa pętli komunikatów i tym podobne rzeczy są na pewno już doskonale znane, ale tak dla pamięci nie będziemy o nich zapominać. Po utworzeniu okna, ale zanim je pokażemy musimy je przygotować dla OpenGL w pewien sposób. Aby zrobić to przed jego pokazaniem, wszystko powinno się odbyć w naszej procedurze obsługi, w obsłudze komunikatu WM_CREATE. Zacznijmy więc omawianie. W funkcji obsługującej nasze komunikaty (WndProc()) na samym początku możemy znaleźć taki oto fragment z wywołaniem kilku tajemniczych, nowych dla nas funkcji i dwie zmienne:
static HGLRC hRC;
static HDC   hDC;

switch( message )
{
    case WM_CREATE:
        hDC = GetDC( hWnd );
        SetDCPixelFormat( hDC );
        hRC = wglCreateContext( hDC );
        wglMakeCurrent( hDC, hRC );
        break;
    ...
}
Sam komunikat WM_CREATE powinniśmy już znać i wiedzieć do czego służy. Jest on wywoływany podczas tworzenia okna, w którym będziemy rysować. Dokładniej mówiąc, komunikat ten wysyłany przez system podczas wywołania funkcji CreateWindow(). Procedura naszego nowo tworzonego okna otrzymuje ten komunikat po tym jak okno zostało stworzone, ale (co bardzo ważne) zanim stanie się ono widoczne. Skoro okno zostanie już utworzone i posiada pętlę obsługi komunikatów, więc może przystąpić do ich przetwarzania. No i na sam początek dostaje naszego WM_CREATE.

hDC = GetDC( hWnd );

Pierwsza funkcja powinna być nam już trochę znana. Jest to pobieranie kontekstu urządzenia. Nie będziemy sobie tutaj tłumaczyć tego, jeśli ktoś nie wie, to zapraszam do działu poświeconego API - tak swoją drogą to właśnie od niego powinniście zaczynać naszą naukę. Funkcja zawraca uchwyt kontekstu urządzenia w zmiennej typu HDC, czyli służącej właśnie do tego celu. Następnie mamy wywołanie tajemniczej, nowej funkcji o nazwie brzmiącej dosyć groźnie:

SetDCPixelFormat( hDC )

Jest to funkcja, która będzie nam niezbędna w naszej dalszej pracy z OpenGL i bez której to wszystko nie będzie działać. Ponieważ jest to funkcja napisana przez nas, więc w zasadzie moglibyśmy ją nazwać dowolnie, ale dobrym zwyczajem jest nazywać funkcje zgodnie z ich przeznaczeniem, więc w tym przypadku też tak będzie. A cóż taka funkcja nam będzie robić? Przyjrzyjmy się jej bliżej:

// setup pixel format
void SetDCPixelFormat( HDC hDC )
{
    int nPixelFormat;
    
    static PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof( PIXELFORMATDESCRIPTOR ),  // struct size
        1,                                // struct version
        PFD_DRAW_TO_WINDOW |              // drawing in window
        PFD_SUPPORT_OPENGL |              // support OpenGL
        PFD_DOUBLEBUFFER,                 // double buffering
        PFD_TYPE_RGBA,                    // RGBA color mode
        8,                                // 8 - bit color mode
        0,0,0,0,0,0,                      // not used to chooose mode
        0,0,                              // not used to chooose mode
        0,0,0,0,0,                        // not used to chooose mode
        16,                               // size of depth buffer
        0,                                // not used to chooose mode
        0,                                // not used to chooose mode
        PFD_MAIN_PLANE,                   // draw on main plane
        0,                                // not used to chooose mode
        0,0,0                             // not used to chooose mode
    }

    nPixelFormat = ChoosePixelFormat( hDC, &pfd );
    SetPixelFormat( hDC, nPixelFormat, &pfd );
}
Jak sama nazwa wskazuje, funkcja ustawiać będzie format pikseli dla danego kontekstu urządzenia. Pytanie oczywiste - co to za cholera? W Direct3D malowanie odbywało się na powierzchniach o czym wiadomo nie od dziś. Ponieważ OpenGL jest trochę do D3D podobny, więc on sam też nie będzie malował bezpośrednio na oknie, bo gdyby to robił to musiałby korzystać z GDI (Graphics Device Interface). On też potrzebuje pewnej powierzchni, a właściwie i dokładnie mówiąc, potrzebuje okna, które trzeba specjalnie dla niego przygotować, aby mógł w nim rysować. Każde okno rysowane w Windows, jak wiemy, zbudowane jest oczywiście z pikseli. Nas to nigdy nie zajmowało, bo korzystaliśmy być może z funkcji GDI, które same wszystkim się zajmowały. Jeśli chcemy korzystać zaś z mocy naszego akceleratora grafiki to okno, w którym będziemy rysować za pomocą funkcji OpenGL, musi być specjalne. Musi posiadać swój własny, specyficzny format pikseli, z których jest zbudowane. Dlatego też tylko kontekst urządzenia, który uzyskaliśmy dla naszego okna - klienta, w którym będziemy malować będzie miał prawo zapisywać w tym oknie. Brzmi to trochę skomplikowanie, bez ładu i składu, ale zaraz się wszystko może wyjaśni. Po prostu aby funkcje OpenGL rysowały coś na oknie, okno to musi mieć kontekst urządzenia z odpowiednio ustawionym formatem pikseli - o tak może będzie bardziej zrozumiale. Aby to zrobić, będziemy potrzebować oczywiście uchwytu do kontekstu urządzenia naszego okna (to już mamy w zmiennej hDC) oraz formatu pikseli. I teraz właśnie zdefiniujemy sobie format pikseli. Będzie go opisywała uwieczniona powyżej struktura typu PIXELFORMATDESCRIPTOR. Cóż ona będzie zawierać... oczywiście mnóstwo mniej lub bardziej potrzebnych pól, ale, że jest ona bardzo ważna, omówmy je po kolei:

  1. nSize - oczywiście będzie zawierać rozmiar tej struktury. Czyli zawiera rozmiar samej siebie.
  2. nVersion - wersja naszej struktury, powinna zawierać wartość 1
  3. dwFlags - zbiór flag opisujących bufor, w którym będzie OpenGL umieszczał malowane piksele. Dokładny opis możecie znaleźć w helpie oczywiście, ale u nas występują pewne flagi, które trzeba niewątpliwie omówić.
      - PFD_DRAW_TO_WINDOW - czyli, w skrócie mówiąc, zawartość naszego bufora będzie się pojawiać na oknie, które specjalnie do tego celu stworzymy,
      - PFD_SUPPORT_OPENGL - bufor możemy być zapisywany przez funkcje OpenGL,
      - PFD_DOUBLEBUFFER - obszar, w którym umieszczane będą dane będzie buforowany podwójnie,
Opis tych flag brzmi równie enigmatycznie jak cały format pikseli, ale powiedzmy sobie tak. Bufor, o którym mowa, będzie zapewne znajdował się gdzieś w pamięci karty grafiki. To do niego procesor graficzny będzie zapisywał dane bardzo szybko, przez co uzyskamy oczywiście efekt sprzętowego wspomagania naszego renderingu. Potem ten bufor będzie przerzucany do naszego okna, dzięki czemu uzyskamy nasz obraz na monitorze. Zaś w dalszej części naszej struktury, pozostałe pola do omówienia to:

  1. iPixelType - określa jak zbudowane będą nasze wyświetlane piksele,
    - PFD_TYPE_RGBA - każdy piksel przechowywany w buforze jest złożony z czterech bajtów, po jednym odpowiedzialnym za kolor i jednym, który będzie przechowywał wartości kanału alfa.
  2. cColorBits - pole określa ile map bitowych będzie umieszczonych w każdym z buforów kolorów. Dla typu pikseli RGBA, którego będziemy używać jest to rozmiar bufora koloru wyłączając z tego kanał alfa.
Potem natomiast następuje seria pól, które jak widzimy po komentarzu, nie biorą wielkiego udziału przy tworzeniu naszego nowego formatu pikseli. Dlatego może odpuścimy sobie ich omawianie, bo i tak wszystkie ustawione są na zero.

  1. cDepthBits - pole to będzie zawierać głębokość (liczbę możliwych wartości mówiąc inaczej) bufora głębokości. Jeśli nie pamiętacie za bardzo, o co chodzi, to zajrzyjcie do lekcji w dziale DirectX, gdzie omówiliśmy to sobie dokładnie. U nas wartość 16 mówi tyle, że mamy 2^16 możliwych wartości dla bufora głębokości, więc dosyć sporo i powinno nam to na początek zupełnie wystarczyć. Następnie mamy znowu dwie wartości w tym przypadku dla nas bez znaczenia, więc sobie je darujemy. Dosyć tajemniczo wygląda pole:
  2. Reserved - mówi ono coś o powierzchniach typu Over and Underlay. U nas natomiast mamy zaznaczone, że malujemy na powierzchni głównej. Co to są powierzchnie Overlay i Underlay, to może innym razem, my natomiast przyjmijmy do wiadomości, że ta flaga nakazuje po prostu malować naszej karcie w głównym buforze, tak żeby po przerzuceniu go na nasze okno było od razu wszystko widać. Cztery ostatnie parametry są także nie używane przez nas w tym przykładzie, więc darujmy sobie dalsze zaciemnienie. Jeśli chcecie się dowiedzieć więcej o tej strukturze, odsyłam Was do jakiejkolwiek dokumentacji, której mnóstwo się wala po całym Internecie.

nPixelFormat = ChoosePixelFormat( hDC, &pfd );

Skoro już wypełnimy sobie strukturę opisującą format pikseli, możemy przystąpić do następnej rzeczy. Będzie nią dopasowanie dostępnych dla danego kontekstu urządzenia formatów pikseli do tego, jaki my określimy w naszej strukturze. Kontekst urządzenia gdzieś sobie pamięta jaki tryb jest aktualnie ustawiony dla karty grafiki. Funkcja ChoosePixelFormat() próbuje dopasować najodpowiedniejszy format pikseli, który będzie posiadał nasz kontekst z tym, który my dostarczymy w naszej strukturze typu PIXELFORMATDESCRIPTOR. Kontekst urządzenia zawiera pewną listę formatów pikseli, które może obsługiwać w danej chwili. Jeśli nasza funkcja się powiedzie i dopasuje ona dostarczony przez nas format pikseli z takim, który może obsługiwać kontekst urządzenia, zwróci ona nam numer tego formatu. Jeśli taki format się nie znajdzie, to funkcja zwróci nam wartość zero. Musimy także pamiętać, że funkcja nie zawsze zwróci nam taki indeks formatu, jaki sobie zażyczymy. Na przykład jeśli będziemy chcieli format z 24-bitową głębią koloru a kontekst urządzenia nie będzie miał dokładnie takiego, to funkcja zwróci nam ten, który akurat będzie najmniej odbiegał od naszego wymarzonego. To tak ku pamięci, żebyśmy czasem nie byli zaskoczeni rezultatami jej działania.

SetPixelFormat( hDC, nPixelFormat, &pfd );

Jeśli już określimy sobie który format pikseli z kontekstu pasuje nam najbardziej do naszego wybranego, to czas ustawić go dla naszego urządzenia. Robi nam to funkcja SetPixelFormat(). Jako pierwszy parametr pobiera ona kontekst, dla którego ustawia format pikseli o indeksie zawartym w drugim parametrze. Ponieważ my dopasowywaliśmy format z kontekstu dokładnie tego, dla którego chcemy go teraz ustawić, więc nie powinno być problemów :-). Ostatni parametr to nasza struktura typu PIXELFORMATDESCRIPTOR określająca jaki w zasadzie mieliśmy zamiar ustawić ten nasz format i z tego korzystają jakieś tam wewnętrzne mechanizmy Windows, dla nas w tej chwili nie za bardzo istotne. Tym sposobem oto wybraliśmy sobie i ustawiliśmy dla naszego okna najbardziej odpowiedni format pikseli, który to umożliwi współpracę z buforami OpenGL i możliwość ich wyświetlania na naszym oknie. Czas powrócić do obsługi komunikatu WM_CREATE. Jak widać dzieje się tutaj bardzo wiele, a to jeszcze nie wszystko. Po ustawieniu formatu pikseli dla danego kontekstu musimy stworzyć tak zwany kontekst renderingu dla OpenGL. Cóż to jest takiego? Ano taki kontekst renderingu będzie nam umożliwiał w zasadzie rysowanie, a dokładniej mówiąc rysowanie za pomocą kontekstu urządzenia, z którym mieliśmy do czynienia przed momentem. Oczywiście aby było to możliwe, nasz kontekst renderingu posiadał będzie taki sam format pikseli jak kontekst urządzenia, bo kilka linii wyżej dopasowywaliśmy je. W tym miejscu oczywiście należy nadmienić, że jest to operacja typowa dla systemu Windows i związana z dostępem do ekranu. Jak wiemy wszystko co robimy zwyczajnie musi się odbywać poprzez kontekst urządzenia powiązany z konkretnym oknem a z OpenGL sprawa jest jak widać trochę bardziej skomplikowana. Ponieważ system specyficzny, więc i nie może się też obejść bez specyficznych dla systemu funkcji. W pierwszej lekcji wspomniałem o rozszerzeniu "wgl" dla Windows i właśnie w tym momencie z takowego skorzystamy.

hRC = wglCreateContext( hDC );

Funkcja pochodzi z rozszerzenia "wgl" co widać jasno po przedrostku. Cóż ona takiego wykonuje? Tworzy kontekst renderingu dla OpenGL, o którym wspomniałem wyżej, bazując na kontekście, który aktualnie mamy dla naszego okna. Kontekst renderingu będzie identyfikowany przez uchwyt, podobnie jak kontekst urządzenia, tylko, że dla niego typem będzie nie HDC, ale HGLRC, analizując poszczególne literki można łatwo sobie oczywiście skojarzyć. Po wywołaniu tej funkcji będziemy mieć już dostępny kontekst renderingu o formacie pikseli takim samym jak nasz kontekst urządzenia dla naszego okna. Aby przystąpić do malowania za pomocą OpenGL, musimy jeszcze dokonać jednej rzeczy. Ustawić otrzymany właśnie przed chwilą kontekst renderowania jako aktualny dla aplikacji, która będzie malować. Aplikację tę będziemy identyfikować poprzez uchwyt kontekstu urządzenia, który przypisany jest do jej okna. Czyli pokrótce - stworzyliśmy okno, mamy kolejkę komunikatów, wybraliśmy odpowiedni dla nas format pikseli dla bieżącego kontekstu i teraz chcemy aby każde wywołanie funkcji OpenGL było przeniesione na nasze właśnie okno. Robi się to za pomocą znowu funkcji rozszerzenia "wgl":

wglMakeCurrent( hDC, hRC );

Jako pierwszy parametr podajemy kontekst urządzenia, na którym będą wizualizowane wszystkie wywołania komend OpenGL. Oczywiście przed tym musimy dokonać tych wszystkich operacji, o których mowa powyżej. Jako drugi parametr podajemy kontekst renderingu, który będzie odpowiedzialny za generowanie obrazu wyświetlanego w naszym okienku. Staram się to Wam oczywiście wyjaśnić najprościej jak można, wszystko przez to, że tak a nie inaczej działa system Windows. Gdybyśmy korzystali z aplikacji konsolowych albo biblioteki GLUT (The OpenGL Utility ToolKit), nie byłoby takich problemów. Ale dobrze jest wiedzieć co i jak robić, żeby zmusić to do działania bo na pewno nam się to przyda a przy okazji można znowu się dowiedzieć jakichś szczegółów o samym Windows. Mając przygotowane okno dla renderingu możemy przystąpić do malowania za pomocą funkcji OpenGL.
Podobnie jak było to w przypadku malowania za pomocą Direct3D naszą funkcję malującą będziemy wywoływać najczęściej jak się da, czyli bezpośrednio w funkcji obsługi komunikatów. W dzisiejszym tutorialku nie namalujemy wiele a w zasadzie to tylko wyczyścimy sobie ekran, żeby mieć gotowy do rysowania w przyszłości. Nasza funkcja, która będzie rysować scenę, będzie się nazywać cały czas tak samo, niech będzie to funkcja o nazwie Render(). I cóż możemy takiego tam znaleźć:

void Render()
{
    glClearColor( 0.0f, 0.0f, 1.0f, 1.0f );
    glClear( GL_COLOR_BUFFER_BIT );
    glFlush();
    SwapBuffers( hDC );
}
Tutaj po raz pierwszy będziemy mieć do czynienia z funkcjami OpenGL, które są w standardzie uznawanym powszechnie na wszystkich platformach sprzętowych i systemowych. Wszystkie funkcje OpenGL, które są wszędzie dostępne, mają nazwy zaczynające się od przedrostka "gl", co łatwo da się zauważyć w funkcji powyżej, natomiast reszta nazwy jest powiązana mniej lub bardziej z czynnościami przez nie pełnionymi. I może po kolei:

glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );

Funkcja ta określa jakie wartości zostaną wpisane do buforów kolorów podczas ich czyszczenia specjalizowaną do tego celu funkcją. Nie ma tutaj aż takiej wielkiej filozofii, żeby nie dało się tego zrozumieć. Wartości podajemy jako składowe RGBA w przedziale od 0 do 1 jako liczby rzeczywiste. Jeśli podamy te wartości większe, to zostaną one przez tę funkcję obcięte do przedziału (0, 1), więc lepiej o tym pamiętać. Domyślnymi wartościami dla funkcji czyszczącej bufory są wartości zero.

glClear( GL_COLOR_BUFFER_BIT );

Po ustawieniu koloru jakim będziemy czyścić nasze bufory koloru należy je... no tak, oczywiście trzeba je wyczyścić. Robimy to właśnie wyżej pokazaną funkcją. Jako parametr przyjmuje ona identyfikator (jako pole bitowe) bufora, który ma zostać wyczyszczony. Jeśli uczestniczyliście w poprzednich lekcjach a może po prostu wiecie, że rodzajów buforów mamy bardzo wiele. Ponieważ na razie raczkujemy w grafice, więc będziemy poznawać je po kolei. W naszym przykładzie na razie używamy tylko bufora kolorów, oznaczonego stałą GL_COLOR_BUFFER_BIT. Jeśli podamy tę stałą jako parametr naszej funkcji, tylko bufor koloru zostanie wyczyszczony. Inne bufory także będziemy czyścić (jak na przykład bufor Z), ale to w przyszłych lekcjach. Funkcji tej możemy podać kilka buforów do wyczyszczenia, wtedy łączymy te wartości operatorem sumy logicznej (|).

glFlush();

W skrócie mówiąc i nie zagłębiając się w sieciowy rendering ;-) za pomocą OpenGL możemy powiedzieć, że funkcja glFlush() powoduje natychmiastowe wykonanie wszystkich wcześniej wydanych poleceń. Precyzując - powoduje ona opróżnienie wszystkich buforów, co w efekcie powoduje powstanie obrazu na ekranie a bufory są już przygotowywane na przyjęcie następnej dawki danych. My na razie jednak zapamiętajmy najważniejszą rzecz - aby wykonały się nasze operacje i żebyśmy mogli je zobaczyć, trzeba wywołać tę funkcję na samym końcu w ciągu instrukcji OpenGL.

SwapBuffers( hDC );

Wywołanie funkcji glFlush() spowoduje to, że dane ze wszystkich buforów zostaną po odpowiednim przemieleniu przez OpenGL umieszczone w jednym, który będzie zawierał naszą scenę już narysowaną, ale jeszcze niewidoczną. Niewidoczną, bo dane te zostaną wrzucone do bufora tylnego. W formacie pikseli, który ustawialiśmy, wyraźnie zażyczyliśmy sobie za pomocą flagi PFD_DOUBLEBUFFER, że nasz obszar pamięci, który będzie przechowywał rysowane dane, będzie buforowany podwójnie. Zapobiega nam to oczywiście miganiu obrazu podczas rysowania. Aby jednak nasze dane nie pozostały w tylnym buforze i aby można było cokolwiek zobaczyć, należy zmusić je, aby powędrowały do bufora, który będzie wyświetlany na ekranie. Robimy to właśnie funkcją SwapBuffers(), która powoduje skopiowanie danych z bufora tylnego (Back Buffer) do przedniego (Front Buffer). Jeśli tej funkcji nie wywołamy, to niestety, ale nic nie zobaczymy. Jako parametr podajemy oczywiście uchwyt naszego kontekstu urządzenia, który ma format pikseli, umożliwiający podwójne buforowanie, jak zapewnia to struktura PIXELFORMATDESCRIPTOR.

I z rysowania byłoby to w zasadzie tyle. Nie ukrywam, że będę przy omawianiu technik postępował zgodnie z tym, co jest robione w części poświęconej Direct3D. Tutoriale będą więc o podobnej tematyce i będą wykorzystywać nierzadko te same modele i tekstury. Niektórych części nie da się uwspólnić oczywiście, więc wtedy sobie powiemy inaczej. Ale ogólnie będzie właśnie tak. W części Direct3D sprawdziło się nam to bardzo dobrze, więc sądzę, że teraz też nie będzie wielkich problemów. No i cóż. Naszaleliśmy i nabałaganiliśmy trochę pośród okien, namieszaliśmy naszemu urządzeniu, które teraz tak naprawdę nie wie co jest czym, więc trzeba posprzątać:

case WM_DESTROY:
    wglMakeCurrent(hDC,NULL);
    wglDeleteContext(hDC);
    PostQuitMessage(0);
    break;
Komunikat WM_DESTROY zostanie wysłany do aplikacji, kiedy będziemy niszczyli nasze okno, a w zasadzie kiedy nie będzie go już na ekranie. Ponieważ przy tworzeniu naszego okna narobiliśmy niezłego zamieszania z kontekstami urządzenia i renderingu, musimy to teraz poodkręcać tak, żeby nie zaczęły nam się pojawiać na ekranie jakieś tajemnicze śmieci, które będzie można uznać za sygnały z kosmosu. A więc lecimy po kolei:

wglMakeCurrent( hDC, NULL );

Tę funkcję już zdaje się znamy, prawda? Funkcja powodowała to, że wszystkie rysunki, które wygenerowało urządzenie OpenGL identyfikowane przez uchwyt kontekstu renderingu pojawiały się w kontekście urządzenia identyfikowanego przez uchwyt HDC czyli przez uchwyt naszego okna - jednym słowem malowaliśmy za pomocą OpenGL na oknie. Teraz już nie chcemy malować dłużej, więc nie jest nam potrzebny kontekst renderingu. Podanie NULL jako drugiego parametru powoduje to, że kontekst renderowania OpenGL nie jest już bieżący dla danego wątku (czyli naszej aplikacji). Zwalnia ona w takim przypadku kontekst urządzenia, (HDC) który był używany przez kontekst renderingu. W takim też przypadku pierwszy paramter jest ignorowany przez tę funkcję.

wglDeleteContext( hRC );

Funkcja ta, jak łatwo się domyśleć, kasuje nam kontekst renderingu, który stworzyliśmy za pomocą funkcji wglCreateContext(). Jako parametr pobiera ona oczywiście uchwyt kontekstu, który chcemy skasować. Nie będziemy też się tutaj wgłębiać w jakieś zmiany kontekstów czy inne takie. Po prostu przyjmijmy do wiadomości, że tak już jest i tak powinno być. Reszta komunikatów i funkcji powinna być raczej dla nas zupełnie oczywista. Wszystkie widzieliście (mam nadzieję), już wiele razy i znacie doskonale ich znaczenie. W ten właśnie sposób dotarliśmy powoli do końca naszej pierwszej, praktycznej przygody z biblioteką OpenGL i już wkrótce będziemy brnąć dalej. Wzorując się nie tylko na kursie Direct3D, ale także na tutorialach z nehe powiemy sobie o tym jak tworzyć figury, bryły, jak posługiwać się teksturami, blendingiem no i jak wykorzystywać rozszerzenia do coraz to bardziej wymyślnych efektów. No ale to długa droga przed nami. W międzyczasie oczywiście będą lekcje matematyki i Direct3D, więc nie przegapcie żadnej ;-). A obrazek Wam się zgadza?



Kod źródłowy

©Copyright by Robal   



Tutoriale - OpenGL
Nasze newsy s� w RSS: backend.php
PHP-Nuke Copyright © 2005 by Francisco Burzi. This is free software, and you may redistribute it under the GPL. PHP-Nuke comes with absolutely no warranty, for details, see the license.
Tworzenie strony: 0.04 sekund

:: Layout strony został stworzony przez www.nukemods.com w oparciu o styl phpbb2 Helius, którego autorem jest Cyberalien ::