Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych. Autor artykułu: mgr Jerzy Wałaszek, wersja1.0 |
©2011 mgr
Jerzy Wałaszek
|
Tworzenie definicji obiektów 3D można wykonać poza programem graficznym. W takim przypadku wyniki umieszcza się w pliku o ściśle określonej strukturze. Otrzymane pliki można następnie używać wielokrotnie w różnych programach graficznych - nawet da się w ten sposób utworzyć własną bibliotekę obiektów 3D. Oczywiście ma to większy sens tylko wtedy, gdy poznamy wszystkie właściwości OpenGL i będziemy potrafili z nich korzystać. Dlatego na początek napiszemy proste programy tworzące takie pliki dla obiektów, które wykorzystują tylko kolorowanie wierzchołków lub ścian. Później rozszerzymy je na tekstury i modelowanie oświetlenia.
Najpierw określmy zawartość pliku definiującego obiekt 3D. Będzie to zwykły plik tekstowy, który można edytować nawet w Notatniku Windows lub w dowolnym innym edytorze tekstowym. Plik będzie się składał z ciągu liczb całkowitych i rzeczywistych.
Zawartość | Opis |
VN | Liczba całkowita określająca ilość wierzchołków w obiekcie 3D. |
(x y z) x VN | VN trójek liczb rzeczywistych, które są współrzędnymi kolejnych wierzchołków figury. |
CN | Liczba całkowita określająca ilość definicji kolorów. Kolory mogą się odnosić do wierzchołków lub do ścian. |
(r g b) x CN | CN trójek liczb całkowitych, które określają poszczególne składowe kolorów. |
SN | Liczba całkowita określająca liczbę wierzchołków definiujących ściany. |
v x SN | SN liczb całkowitych, które określają numery wierzchołków tworzących ściany. |
FN | Liczba całkowita określająca ilość ścian |
(typ n poz) x FN | FN trójek liczb całkowitych, które określają
kolejno: typ – typ ściany n – ilość wierzchołków w ścianie poz – pozycja definicji ściany w zbiorze S |
Umówmy się dodatkowo, iż definicje figur będą tak tworzone, aby środek figury znajdował się w środku układu współrzędnych.
Pierwszy program utworzy definicję prostopadłościanu. Figura taka zbudowana jest z sześciu ścian będącymi prostokątami.
Specjalnie na początek wybraliśmy prostopadłościan, aby skupić się na cechach programu edycyjnego, a nie na samej figurze. Aplikacja, którą napiszemy, będzie wzorcem do tworzenia dalszych edytorów. Przy okazji pokażemy obsługę plików w Borland C++ Builder oraz sposób wyświetlania grafiki OpenGL w innym komponencie graficznym okna, mianowicie w panelu. Na początek tworzymy interfejs graficzny.
Utwórz nowy projekt OpenGL.
W oknie aplikacji umieść następujące komponenty (oprócz komponentu Timer, który powinien już być obecny):
2 x Button z palety Standard
1 x ColorDialog z palety Dialogs
3 x Edit z palety Standard
15 x Label z palety Standard
9 x Panel z palety Standard
2 x RadioGroup z palety Standard
1 x SaveDialog z palety Dialogs
4 x ScrollBar z palety Standard
Uważnie ustaw własności poszczególnych komponentów:
Form1
Button1
Button2
ColorDialog1
Edit1
Edit2
Edit3
Label1
Label2
Label3
Label4
Label5
Label6
Label7
Label8
Label9
Label10
Label11
Label12
Label13
Label14
Label15
Panel1
Panel2
Panel3
Panel4
Panel5
Panel6
Panel7
Panel8
Panel9
RadioGroup1
RadioGroup2
ScrollBar1
ScrollBar2
ScrollBar3
ScrollBar4
SaveDialog1
Timer1
Jeśli wszystko wpisałeś poprawnie, to twój interfejs powinien wyglądać następująco (w Windows XP):
Suwaki u góry będą umożliwiały obracanie obiektu w wybranych osiach oraz oddalanie lub przybliżanie go do obserwatora. W polach tekstowych będzie można wpisywać pożądane długości boków. Poniżej określimy kolory ścian lub wierzchołków. Dalej ustalimy, czy kolory będą się odnosiły do ścian, czy do wierzchołków. Widok będzie zmieniał sposób prezentacji naszej figury. Przycisk Zapisz pozwoli zapisać w pliku definicję obiektu. Główny panel będzie używany do wyświetlania sceny OpenGL.
Teraz musimy dokonać kilku zmian w naszym kodzie, aby biblioteka OpenGL wyświetlała grafikę nie na obszarze okna, lecz w panelu pnlGL. Na szczęście jest to bardzo proste do uzyskania. Dwie poniższe funkcje wymagają drobnej modyfikacji:
//--------------------------------------------------------------------------- void __fastcall Tfrm3D::FormCreate(TObject *Sender) { hdc = GetDC(pnlGL->Handle); // Zmiana !!! SetPixelFormatDescriptor(); hrc = wglCreateContext(hdc); wglMakeCurrent(hdc, hrc); SetupRC(); } //---------------------------------------------------------------------------
... //--------------------------------------------------------------------------- void __fastcall Tfrm3D::FormResize(TObject *Sender) { glViewport(0, 0, pnlGL->Width, pnlGL->Height); // Zmiana !!! glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)pnlGL->Width/(GLfloat)pnlGL->Height,0.1f,300.0f); // Zmiana !!! glMatrixMode(GL_MODELVIEW); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // kolor tła glEnable(GL_DEPTH_TEST); // włącza bufor głębokości glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); // włącza opcję eliminacji ścian glFrontFace(GL_CW); // ściany o wierzchołkach ułożonych zgodnie z ruchem wskazówek // zegara będą traktowane jako zwrócone przodem glCullFace(GL_BACK); // pomija rysowanie ścian odwróconych tyłem } //---------------------------------------------------------------------------
W pierwszej funkcji FormCreate() zmieniamy kontekst z powierzchni rysunkowej okna na powierzchnię rysunkową panelu pnlGL. Od tego momentu operacje graficzne OpenGL będą wykonywane w obszarze zajętym przez panel.
W drugiej funkcji FormResize() (w tym programie jest ona wykonywana tylko jeden raz, ponieważ okno ma zablokowany rozmiar) dokonujemy dwóch zmian, które uwzględniają rozmiar panelu.
Jeśli teraz skompilujesz program, to po uruchomieniu w panelu powinien pojawić się biały trójkąt na czarnym tle:
Jeśli otrzymałeś taki jak powyżej obraz, to jesteś gotowy do wprowadzania kodu. W przeciwnym razie wróć na początek i sprawdź krok po kroku kolejne czynności.
Ponieważ dane figury muszą być dostępne w kilku miejscach, zdefiniujemy je globalnie na początku programu. Umówmy się, że wierzchołki będą określone następująco:
Początkowo niech wszystkie boki będą równe 1. Wtedy współrzędne punktów są następujące (pamiętaj, że środek figury jest w środku układu współrzędnych):
v0 = { 0.5f,-0.5f, 0.5f}
v1 = {-0.5f,-0.5f, 0.5f}
v2 = {-0.5f, 0.5f, 0.5f}
v3 = { 0.5f, 0.5f, 0.5f}
v4 = { 0.5f,-0.5f,-0.5f}
v5 = {-0.5f,-0.5f,-0.5f}
v6 = {-0.5f, 0.5f,-0.5f}
v7 = { 0.5f, 0.5f,-0.5f}
Definicje kolorów początkowych będą podane jako tablica wartości RGB. Każdy kolor będzie się składał z trzech bajtów, po jednym dla kolejnych barw składowych R, G i B.
c0 = {0x80, 0x00, 0x00}
clMaroon
c1 = {0x00, 0x80, 0x00} clGreen
c2 = {0x80, 0x80, 0x00} clOlive
c3 = {0x00, 0x00, 0x80} clNavy
c4 = {0x80, 0x00, 0x80} clPurple
c5 = {0x00, 0x80, 0x80} clTeal
c6 = {0xFF, 0x00, 0x00} clRed
c7 = {0x00, 0xFF, 0xFF} clAqua
Figura będzie posiadała 6 ścian. Każda ściana zawiera 4 wierzchołki (to się nie będzie zmieniać)
s0 ...s3 = {0,1,2,3}
przednia
s4 ...s7 = {3,2,6,7} górna
s8 ...s11 = {7,6,5,4} tylnia
s12...s15 = {4,5,1,0} spodnia
s16...s19 = {0,3,7,4} prawa
s20...s23 = {1,5,6,2} lewa
Definicje ścian (to się nie będzie zmieniać)
f0 = { GL_QUADS, 4, 0} przednia
f1 = { GL_QUADS, 4, 4} górna
f2 = { GL_QUADS, 4, 8} tylnia
f3 = { GL_QUADS, 4,12} spodnia
f4 = { GL_QUADS, 4,16} prawa
f5 = { GL_QUADS, 4,20} lewa
Dodaj na samym początku programu:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <fstream>
using namespace std;
#pragma hdrstop
#include "glunit.h"
//---------------------------------------------------------------------------
Wprowadź na początek programu (tzn. przed wszystkimi funkcjami) definicje następujących zmiennych globalnych:
// Zmienne globalne // Wierzchołki GLfloat V[][3] = {{ 0.5f,-0.5f, 0.5f}, {-0.5f,-0.5f, 0.5f}, {-0.5f, 0.5f, 0.5f}, { 0.5f, 0.5f, 0.5f}, { 0.5f,-0.5f,-0.5f}, {-0.5f,-0.5f,-0.5f}, {-0.5f, 0.5f,-0.5f}, { 0.5f, 0.5f,-0.5f}}; // Kolory GLubyte C[][3] = {{0x80, 0x00, 0x00}, // clMaroon {0x00, 0x80, 0x00}, // clGreen {0x80, 0x80, 0x00}, // clOlive {0x00, 0x00, 0x80}, // clNavy {0x80, 0x00, 0x80}, // clPurple {0x00, 0x80, 0x80}, // clTeal {0xFF, 0x00, 0x00}, // clRed {0x00, 0xFF, 0xFF}}; // clAqua // Wierzchołki ścian int S[] = {0,1,2,3, // przednia 3,2,6,7, // górna 7,6,5,4, // tylna 4,5,1,0, // spodnia 0,3,7,4, // prawa 1,5,6,2}; // lewa // Definicje ścian int F[][3] = {{GL_QUADS, 4, 0}, // przednia {GL_QUADS, 4, 4}, // górna {GL_QUADS, 4, 8}, // tylnia {GL_QUADS, 4,12}, // spodnia {GL_QUADS, 4,16}, // prawa {GL_QUADS, 4,20}}; // lewa
Teraz umieść również na początku programu funkcję rysującą obiekt:
//--------------------------------------------------------------------------- void Figure3D(int n, bool cmode, GLfloat v[][3], int s[], GLubyte c[][3], int f[][3]) { for(int i = 0; i < n; i++) { if(cmode) glColor3ubv(c[i]); glBegin(f[i][0]); for(int j = 0; j < f[i][1]; j++) { if(!cmode) glColor3ubv(c[s[f[i][2]+j]]); glVertex3fv(v[s[f[i][2]+j]]); } glEnd(); } } //---------------------------------------------------------------------------
Wykorzystujemy w niej nową funkcję glColor3ubv(), której argumentem jest wskaźnik do obszaru pamięci przechowującego trzy składowe kolorów w postaci bajtów, czyli liczb o zakresie od 0 do 255. Wskaźnikiem tym jest wiersz tablicy kolorów C. Poza tym szczegółem funkcja niczym nie różni się od swojej poprzedniczki.
Zmieniamy treść funkcji Timera, która zajmuje się rysowaniem obiektu w OpenGL.
// Tutaj umieszczamy program dla OpenGL if(rdgView->ItemIndex) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); glTranslatef(0,0,-2 - scbD->Position/10.0); glRotatef(scbX->Position,1,0,0); glRotatef(scbY->Position,0,1,0); glRotatef(scbZ->Position,0,0,1); Figure3D(6,!rdgColor->ItemIndex,V,S,C,F); // Koniec kodu dla OpenGL
Teraz umieścimy w programie funkcje obsługujące zdarzenia komponentów. Pamiętaj, że należy najpierw utworzyć odpowiednią funkcję obsługi zdarzenia za pomocą Object Inspector na zakładce Events, a dopiero wtedy można wprowadzać podany przez nas kod. Inaczej nie będzie to chciało działać.
Wybierz panel pnlC0 i utwórz dla niego funkcję obsługi zdarzenia OnClick. Wprowadź do niej poniższy kod:
//--------------------------------------------------------------------------- void __fastcall Tfrm3D::pnlC0Click(TObject *Sender) { cldColor->Color = ((TPanel *) Sender)->Color; if(cldColor->Execute()) { ((TPanel *) Sender)->Color = cldColor->Color; C[((TPanel *) Sender)-> Tag][0] = cldColor->Color & 0xff; C[((TPanel *) Sender)-> Tag][1] = ((cldColor->Color) >> 8) & 0xff; C[((TPanel *) Sender)-> Tag][2] = ((cldColor->Color) >> 16) & 0xff; } } //---------------------------------------------------------------------------
Funkcja ta wywołuje okienko dialogowe kolorów, w którym użytkownik wybiera dowolny kolor dla ściany lub wierzchołka. Wybrany kolor jest zamieniany na trzy barwy składowe, które są następnie umieszczane w odpowiednim wierszu tablicy kolorów C. Numer wiersza tablicy jest pobierany z pola Tag, ponieważ ta sama funkcja obsługuje pozostałe panele kolorów.
Teraz w Object TreeView kliknij raz myszką w pnlC1. Spowoduje to zaznaczenie komponentu. Wciśnij klawisz Shift, przytrzymaj go wciśniętym i kliknij myszką w pnlC7. Zostaną zaznaczone komponenty od pnlC1 do pnlC7. W Object Inspector na zakładce Events kliknij w strzałkę w dół przy zdarzeniu OnClick i wybierz pnlC0Click. Po tej operacji wszystkie panele od plnC0 do pnlC7 będą wykorzystywały tę samą funkcję obsługi zdarzenia OnClick. Rozróżnienie panelu jest zakodowane w funkcji.
Wybierz komponent edtA i utwórz w Object Inspector obsługę zdarzenia OnKeyPress. Zdarzenie to powstaje, gdy w trakcie wpisywania danych do komponentu został naciśnięty klawisz. Wpisz kod do funkcji obsługującej to zdarzenie:
//--------------------------------------------------------------------------- void __fastcall Tfrm3D::edtAKeyPress(TObject *Sender, char &Key) { if(Key == 13) { GLfloat a = StrToFloat(edtA->Text) / 2; if(a > 0) for(int i = 0; i < 8; i++) switch(i) { case 0: ; case 3: ; case 4: ; case 7: V[i][0] = a; break; default: V[i][0] = -a; break; } } } //---------------------------------------------------------------------------
W obsłudze zdarzenia sprawdzamy, czy został naciśnięty klawisz Enter. Jeśli tak, to odczytujemy tekst z komponentu, zamieniamy go na liczbę, czyli długość boku a i modyfikujemy odpowiednio współrzędne wierzchołków w figurze.
Uwaga: część ułamkowa musi być oddzielona przecinkiem od części całkowitej liczby, ponieważ funkcja StrToFloat() korzysta z ustawień narodowych przy odczytywaniu liczb. W Polsce obowiązuje przecinek dziesiętny, natomiast w krajach anglosaskich używa się kropki dziesiętnej.
W podobny sposób utwórz funkcję obsługi zdarzenia OnKeyPress dla komponentu edtB i wpisz kod:
//--------------------------------------------------------------------------- void __fastcall Tfrm3D::edtBKeyPress(TObject *Sender, char &Key) { if(Key == 13) { GLfloat b = StrToFloat(edtB->Text) / 2; if(b > 0) for(int i = 0; i < 8; i++) switch(i) { case 2: ; case 3: ; case 6: ; case 7: V[i][1] = b; break; default: V[i][1] = -b; break; } } } //---------------------------------------------------------------------------
I tak samo dla edtC:
//--------------------------------------------------------------------------- void __fastcall Tfrm3D::edtCKeyPress(TObject *Sender, char &Key) { if(Key == 13) { GLfloat c = StrToFloat(edtC->Text) / 2; if(c > 0) for(int i = 0; i < 8; i++) switch(i) { case 0: ; case 1: ; case 2: ; case 3: V[i][2] = c; break; default: V[i][2] = -c; break; } } } //---------------------------------------------------------------------------
Kliknij szybko myszką w przycisk Koniec i wpisz do funkcji obsługi zdarzenia OnClick:
//--------------------------------------------------------------------------- void __fastcall Tfrm3D::btnQuitClick(TObject *Sender) { Close(); } //---------------------------------------------------------------------------
Tak samo zrób z przyciskiem Zapisz:
//--------------------------------------------------------------------------- void __fastcall Tfrm3D::btnSaveClick(TObject *Sender) { if(svdSave->Execute()) { ofstream f(svdSave->FileName.c_str()); int i; // V f << 8 << endl; for(i = 0; i < 8; i++) f << V[i][0] << " " << V[i][1] << " " << V[i][2] << endl; // C f << 8 << endl; for(i = 0; i < 8; i++) f << (int)C[i][0] << " " << (int)C[i][1] << " " << (int)C[i][2] << endl; // S f << 24 << endl; for(i = 0; i < 24; i += 4) f << S[i] << " " << S[i+1] << " " << S[i+2] << " " << S[i+3] << endl; // F f << 6 << endl; for(i = 0; i < 6; i++) f << F[i][0] << " " << F[i][1] << " " << F[i][2] << endl; f.close(); } } //---------------------------------------------------------------------------
W tej funkcji wywołujemy komponent okna dialogowego zapisu, który umożliwia użytkownikowi określenie lokalizacji oraz nazwy pliku do zapisu. Zapis dokonujemy za pomocą strumienia plikowego ofstream. Jest to strumień wyjściowy. Otwieramy go, wykorzystując nazwę pliku z komponentu svdSave. Następnie zapisujemy do strumienia kolejne elementy zgodnie z definicją, którą podaliśmy na początku rozdziału. Na końcu strumień zamykamy.
Program jest gotowy.
Przykładowa treść pliku produkowanego przez program (program standardowo tworzy plik w katalogu uruchomieniowym pod nazwą cube0001.txt):
8 0.25 -1 0.5 -0.25 -1 0.5 -0.25 1 0.5 0.25 1 0.5 0.25 -1 -0.5 -0.25 -1 -0.5 -0.25 1 -0.5 0.25 1 -0.5 8 255 255 0 255 0 0 255 128 64 128 255 128 0 0 255 0 128 0 255 0 0 0 255 255 24 0 1 2 3 3 2 6 7 7 6 5 4 4 5 1 0 0 3 7 4 1 5 6 2 6 7 4 0 7 4 4 7 4 8 7 4 12 7 4 16 7 4 20 |
V – liczba wierzchołków współrzędne 8 kolejnych wierzchołków C – liczba definicji kolorów poszczególne kolory jako 3 kolejne składowe R, G i B. 0 oznacza brak składowej 255 oznacza pełną wartość składowej S – liczba wierzchołków powiązanych w ściany wierzchołki tworzące kolejne ściany F – liczba ścian kolejne definicje ścian: 7 – GL_QUADS 4 – liczba wierzchołków na ścianę x – pozycja definicji ściany w S |
Gdy mamy gotowy edytor figury, stworzymy prostą aplikację, która wczyta obiekt z pliku i wyświetli go w oknie. Do tego celu najlepsza będzie klasa języka C++, którą zdefiniujemy w osobnym pliku. Takie rozwiązanie pozwoli na załadowanie wielu różnych obiektów. Dostęp do funkcji klasy uzyskamy poprzez odpowiedni plik nagłówkowy.
W nowym katalogu utwórz nowy projekt OpenGL. Przekopiuj do tego katalogu plik cube0001.txt z poprzedniego projektu.
Wybierz opcję menu: File → New → Unit. Utworzy ona nowy moduł programu. Program może się składać z wielu modułów. Moduły zwykle realizują osobne zadania. Dodatkowo modułu mogą być wykorzystywane w innych programach. Utworzony moduł zapisz pod nazwą glclass.
W oknie edytora wybierz zakładkę glclass.cpp i wciśnij Ctrl-F6. Spowoduje to zastąpienie w edytorze pliku glclass.cpp jego plikiem nagłówkowym glclass.h. Umieść w tym pliku poniższy kod:
//--------------------------------------------------------------------------- #ifndef glclassH #define glclassH #include <Classes.hpp> //--------------------------------------------------------------------------- class ObjectGL { public: float * V; // wierzchołki unsigned char * C; // kolory int * S; // ściany int * F; // ściany int nv,nc,ns,nf; ObjectGL(AnsiString fn); ~ObjectGL(); void Load(AnsiString fn); void Show(bool cmode); private: void Clear(); }; #endif
Ponownie wciśnij klawisze Ctrl-F6, aby powrócić w edytorze do pliku glclass.cpp. Wprowadź kod:
//--------------------------------------------------------------------------- #pragma hdrstop #include "glclass.h" #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> #include <gl/gl.h> #include <gl/glu.h> #include <fstream> using namespace std; //--------------------------------------------------------------------------- #pragma package(smart_init) // Konstruktor ObjectGL::ObjectGL(AnsiString fn) { nv = nc = ns = nf = 0; Load(fn); } // Destruktor ObjectGL::~ObjectGL() { Clear(); } // Ładuje obiekt z pliku void ObjectGL::Load(AnsiString fn) { Clear(); ifstream f(fn.c_str(),ios_base::in); int i, n, c; if(f.good()) { f >> nv; n = 3 * nv; V = new float [n]; for(i = 0; i < n; i++) f >> V[i]; f >> nc; n = 3 * nc; C = new unsigned char[n]; for(i = 0; i < n; i++) { f >> c; C[i] = c; } f >> ns; S = new int[ns]; for(i = 0; i < ns; i++) f >> S[i]; f >> nf; n = 3 * nf; F = new int[n]; for(i = 0; i < n; i++) f >> F[i]; } f.close(); } // Wyświetla obiekt void ObjectGL::Show(bool cmode) { for(int i = 0; i < nf; i++) { if(cmode) glColor3ubv(&C[3*i]); int ftyp = F[3 * i]; int fnum = F[3 * i + 1]; int fpos = F[3 * i + 2]; glBegin(ftyp); for(int j = 0; j < fnum; j++) { int pos = 3 * S[fpos + j]; if(!cmode) glColor3ubv(&C[pos]); glVertex3fv(&V[pos]); } glEnd(); } } // Usuwa zawartość tablic void ObjectGL::Clear() { if(nv) { delete [] V; nv = 0; } if(nc) { delete [] C; nc = 0; } if(ns) { delete [] S; ns = 0; } if(nf) { delete [] F; nf = 0; } }
Konstruktor tworzy obiekt trójwymiarowy. Parametrem konstruktora jest nazwa pliku z definicją obiektu.
Destruktor jest wywoływany, gdy klasa przestaje istnieć w programie. Usuwa on tablice dynamiczne, które zawierają definicję obiektu.
Funkcja Load() ładuje definicję obiektu z pliku, którego nazwę przekazano jako argument.
Funkcja Show() wyświetla obiekt w aktualnym oknie OpenGL. Zasadniczo funkcja ta nie różni się w działaniu od podanych wcześniej funkcji.
Funkcja Clear() usuwa tablice dynamiczne.
Dane są przechowywane we wewnętrznych tablicach V, C, S i F.
W kolejnym kroku przyłączymy moduł do programu głównego. Przejdź do zakładki glunit.cpp i na początku programu dopisz:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "glunit.h"
#include "glclass.h"
//---------------------------------------------------------------------------
W ten sposób moduł podstawowy uzyska dostęp do klasy ObjectGL zdefiniowanej w module glclass.cpp. W zmiennych globalnych umieść:
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
Tfrm3D *frm3D;
ObjectGL fig("cube0001.txt");
//---------------------------------------------------------------------------
Wpis ten tworzy zmienną fig klasy ObjectGL. Konstruktor klasy automatycznie odczyta definicję obiektu z podanego pliku. Ostatnią rzeczą w testowym programie jest wpisanie kodu OpenGL w funkcji obsługi Timera:
// Tutaj umieszczamy program dla OpenGL static GLfloat alphax = 0; static GLfloat alphay = 0; static GLfloat alphaz = 0; glTranslatef(0.0f,0.0f,-3.0f); glRotatef(alphax,1,0,0); glRotatef(alphay,0,1,0); glRotatef(alphaz,0,0,1); // glPolygonMode(GL_FRONT,GL_LINE); fig.Show(true); alphax += 0.5; if(alphax >= 360) alphax = 0; alphay += 0.2; if(alphay >= 360) alphay = 0; alphaz += 0.3; if(alphaz >= 360) alphaz = 0; // Koniec kodu dla OpenGL
Skompiluj i uruchom program.
I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe