Hauptseite | Liste aller Namensbereiche | Klassenhierarchie | Alphabetische Liste | Datenstrukturen | Auflistung der Dateien | Datenstruktur-Elemente | Datei-Elemente

Opengl.cpp

gehe zur Dokumentation dieser Datei
00001 /*
00002 Autor: $Author: kunkel $ State: $State: Exp $
00003 Datum: $Date: 2005/05/30 12:35:25 $
00004 Version: $Revision: 1.1 $
00005 */
00006 
00011 #include <fstream>
00012 #include <sstream>
00013 #include <GL/glut.h>
00014 #include "glui/glui.h"
00015 
00016 #include "timer.h"
00017 #include "Opengl.h"
00018 #include "PhysikEngine.h"
00019 #include "ObjectManager.h"
00020 #include "Configuration.h"
00021 #include "Window.h"
00022 #include "Camera.h"
00023 
00024 Opengl ourOpengl;
00025 
00026 //Iniatisierung der statischen Klassenvariablen:
00027 int Opengl::freeLight=0;
00028 
00036 int Opengl::getNextLight() {
00037     if(freeLight == 8)
00038         freeLight = 0;
00039     freeLight++;
00040 
00041     // Die Opengl lichter sind im Header durchnummeriert
00042     return GL_LIGHT0+freeLight-1;
00043 }
00044 
00048 void Opengl::reloadWindow() {
00049     HandleReshape(0,0);
00050 }
00051 
00057 void Opengl::redraw() {
00058     glutSetWindow(Window::getMainWindow());
00059     glutPostRedisplay();
00060 }
00061 
00066 void Opengl::CreateEnvironment() {
00067 
00068     // Aktiviere Anti Aliasing fuer Linien
00069     glEnable(GL_LINE_SMOOTH);
00070 
00071     // Aktiviere Anti Aliasing fuer Polygone
00072     glEnable(GL_POLYGON_SMOOTH);
00073 
00074     //  Aktiviere Smooth-Shading (ist aber sowieso default)
00075     glShadeModel(GL_SMOOTH);
00076 
00077     /*
00078     * Aktiviere Dithering, 
00079     * Farben, die nicht vom Ausgabegeraetnicht unterstuetzt werden, werden 
00080     * durch unterschiedlich Farben direkt benachbarter Pixel angenaehert. 
00081     */
00082     glEnable(GL_DITHER);
00083 
00084 
00085     /*
00086     * Die Breite einer Linie auf 1 Pixel setzen. Nicht-ganzzahlige
00087      * Werte sind nur dann interessant, wenn Anti-Aliasing fuer Linien
00088      * aktiviert ist.
00089     */
00090     glLineWidth(1.0);
00091 
00092     // Den gerasterten Durchmesser eines Punktes auf 1 Pixel setzen.
00093     glPointSize(1.0);
00094 
00095     // Die Vorder- und Rueckseite aller Polygone gefuellt zeichnen:
00096     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00097 
00098     /*
00099     * CCW steht fuer clock-counter-wise und definiert die gegen den
00100      * Uhrzeigersinn gezeichneten Polygone (aus Bildschirm-Sicht) als
00101      * Vorderseiten; alle anderen werden als Rueckseiten angesehen. 
00102     * Dies ist wichtig fuer das Backface-Culling, dabei
00103      * sollen die dem Betrachter abgewandten
00104      * Polygone ausgeblendet werden.
00105      * "GL_CW" kehrt die Definition von Vorder und Rueckseiten fuer 
00106     * Polygone um.
00107     */
00108     glFrontFace(GL_CCW);
00109 
00110     // Hintergrundfarbe festlegen auf Schwarz
00111     glClearColor(0.0, 0.0, 0.0, 0.0);
00112 
00113     //  ermoegliche ein Faerben von Flaechen
00114     glEnable(GL_COLOR_MATERIAL);
00115 }
00116 
00120 void Opengl::RenderObjects() {
00121     // Einheitsmatrix laden
00122     glLoadIdentity();
00123 
00124     //Kamera Perspektive laden:
00125     ourCamera.loadCameraMatrix();
00126 
00127     //Licht einstellungen vornehmen:
00128     GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
00129     GLfloat mat_shininess[] = { 50.0 };
00130 
00131     //Materialeigenschaften festlegen:
00132     // enth�t vier ganzzahlige oder Flie�ommawerte welche den RGBA
00133     //Glanzlichtanteil repr�entieren, der vom Material reflektiert wird.
00134     glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
00135 
00136     // enth�t eine einzelne Ganz- oder Flie�ommazahl welche den
00137     // Glanzlichtexponent repr�entieren. (Specular Exponent)
00138     glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
00139 
00140     /*
00141     * Aktiviere Backface-Culling
00142     * Beim Backface-Culling werden verdeckte
00143     * Flaechen bzw. Linien nicht berechnet, da sie ja sowieso nicht
00144     * dargestellt werden muessen. OpenGL sieht eine verdeckte Flaeche
00145     * genau dann als verdeckt an, wenn das Skalarprodukt aus ihrem
00146     * Normalenvektor und der Blickrichtung der Kamera ein positives Ergebnis
00147     * liefert.
00148     */
00149     glEnable(GL_CULL_FACE);
00150 
00151     //Licht fuer den Naechsten Render Schritt Deaktivieren, die
00152     // Objekte die Lichtquellen sind schalten dies wieder an.
00153     for(int i=0; i < 8; i++)
00154         glDisable(getNextLight());
00155 
00156     //erstes zu vergebendes Licht festlegen:
00157     freeLight = 0;
00158 
00159     //Objekte Zeichnen:
00160     ourObjectManager.drawObjects();
00161 }
00162 
00166 void Opengl::RenderUniverse() {
00167     //Um die fps berechnen zu koennen werden Statisch Werte gespeichert.
00168     static timeval startTime_;
00169     timeval startRenderingTime_;
00170     static double frameTime_=1;
00171     static int framesCount=1;
00172 
00173     //jede Sekunde werden die fps aktualisiert:
00174     if( timediffNow(startTime_) > 1) {
00175         frameTime_=timediffNow(startTime_)/framesCount;
00176         gettimeofday(&startTime_,0);
00177         framesCount=1;
00178     } else
00179         framesCount++;
00180     gettimeofday(&startRenderingTime_,0);
00181 
00182 
00183     // Z-Buffer, Tiefenpuffer aktivieren
00184     glEnable(GL_DEPTH_TEST);
00185 
00186     /*
00187     * Verwende Double-Buffering. Der "Back-Buffer" wird mit Daten gefuellt,
00188      * nachdem alle Objekte gezeichnet wurden wird der Back-Buffer zum 
00189     * Front-Buffer gemacht, dies verhindert Flacker-Effekte. 
00190     */
00191     glDrawBuffer(GL_BACK);
00192 
00193     // Den Farb- und den Z-Puffer leeren. Sonst koennten alte Zeichendaten er
00194     // noch vorhanden sein
00195     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00196 
00197     //Art wie Gerenderte Objekte dargestellt werden sollen wird gewaehlt:
00198     if (ourConfiguration.viewModel == 0) {
00199         //Punkt Ansicht
00200         glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
00201     } else if (ourConfiguration.viewModel == 1) {
00202         //Drahtmodell-Ansicht
00203         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00204     } else {
00205         // viewModel == 2 Solide Objekte Anzeigen
00206         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00207     }
00208 
00209 
00210     // Den Projection-Matrix-Stack als Ziel weiterer Matrix Operationen
00211     // festlegen.
00212     glMatrixMode(GL_PROJECTION);
00213 
00214     // Einheitsmatrix auf den Stack laden
00215     glLoadIdentity();
00216 
00217     //Kamera einstellungen der Perspektive laden und mit der aktuellen
00218     //opengl Matrix multiplizieren
00219     ourCamera.loadCameraPerspective();
00220 
00221     // Die Modelview Matrix als Ziel weiterer Matrix-Operationen waehlen
00222     glMatrixMode(GL_MODELVIEW);
00223 
00224     //Festlegen ob Licht Effekte angezeigt werden sollen oder nicht
00225     if(! ourConfiguration.showLighting) {
00226         //Licht effekte nicht anzeigen:
00227         glDisable(GL_LIGHTING);
00228         glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
00229     } else {
00230         //Damit die Texturen mit Lichteffekten Gerendert werden:
00231         glEnable(GL_LIGHTING);
00232         glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
00233     }
00234 
00235     //Farbe der Objekte nicht bercksichtigen wenn texture daruebergelegt wird:
00236     // glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
00237 
00238     //Alle Objekte mit den aktuellen Opengl Einstellungen rendern:
00239     RenderObjects();
00240 
00241     //Licht deaktivieren
00242     glDisable(GL_LIGHTING);
00243 
00244     /* Den Back-Buffer zum Front-Buffer machen und so die Darstellung der
00245      * Szene aendern. Das naechste Bild wird aus dem aktualisierten
00246      * Puffer gezeichnet. Befehle, die direkt nach glutSwapBuffers() stehen,
00247      * werden erst bei naechstem Swapen ausgefuehrt.
00248     */
00249     glutSwapBuffers();
00250 
00251 
00252     //Rendering Details text festlegen und setzen:
00253     stringstream fps_;
00254     fps_.precision(3);
00255     fps_ << "fps: " << 1/frameTime_ << " Rt: " <<
00256     timediffNow(startRenderingTime_);
00257     Window::setRenderDetails(fps_.str());
00258 }
00259 
00260 
00268 void Opengl::HandleReshape(int w, int h) {
00269     // Den Farb- und den Tiefenpuffer leeren.
00270     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00271 
00272     // Noch nicht von GLUI ueberdeckte Breite und Hoehe ermitteln:
00273     int tx,ty,tw,th;
00274     GLUI_Master.get_viewport_area(&tx,&ty,&tw,&th);
00275 
00276     //Falls das Menu nicht angezeigt wird muessen die Werte angepasst
00277     //werden da GLUI das nicht selbst vornimmt
00278     if(! ourConfiguration.showMenu ) {
00279         tw +=tx;
00280         th +=ty;
00281         tx=0;
00282         ty=0;
00283     }
00284 
00285     //Die Breite und Hoehe des 3D Fenster festlegen:
00286     glViewport(tx, ty, tw, th);
00287 
00288     // Die Parameter der Kamera ebenfalls anpassen.
00289     ourCamera.setScreen(tw,th);
00290 }
00291 
00296 void Opengl::setAnimation(bool enable) {
00297     if(ourConfiguration.freezeAnimation && enable &&
00298             ourObjectManager.getObjectCount()!=0 &&
00299             ourConfiguration.constructMode == false) {
00300         //Animation starten falls moeglich und noch nicht gestartet
00301         Window::setAnimationControls(true);
00302         ourConfiguration.freezeAnimation = false;
00303         //Glut Timer fuehrt Callbackfunktion nach ablauf von
00304         // TIMERUPDATE msec aus
00305         glutTimerFunc(TIMERUPDATE,& Opengl::HandleTimer,0);
00306     } else if (! enable || ourObjectManager.getObjectCount()==0
00307                || ourConfiguration.constructMode) {
00308         //Animation stopen, glutTimer anhalten
00309         ourConfiguration.freezeAnimation = true;
00310         glutTimerFunc(0,& Opengl::HandleTimer,0);
00311         Window::setAnimationControls(false);
00312     }
00313 }
00314 
00320 void Opengl::singleStep() {
00321     //Falls es keine Objekte gibt muss nichts gemacht werden
00322     if( ourObjectManager.getObjectCount()==0)
00323         return;
00324     Vector oldpos_;
00325 
00326     //Following mode aktiv,um auf Objekt zoomen zu koennen
00327     //muss veraenderung der Position ermittelt werden
00328     if (ourConfiguration.clickedObject !=0)
00329         oldpos_= ourConfiguration.clickedObject->getScaledPos();
00330 
00331     //Aktuelle Positionen der Objekte speichern:
00332     ourObjectManager.nextTimeStep();
00333 
00334     //Integrator starten und Objekt positionen veraendern:
00335     PhysikEngine::simulateGravity(ourConfiguration.getTime());
00336 
00337     //Falls der Following Modus Aktiviert wurde:
00338     if (ourConfiguration.clickedObject !=0 && ourConfiguration.followObject) {
00339         Object * obj=ourConfiguration.clickedObject;
00340         //Neue Position des Objekts ermitteln
00341         Vector pos_ = obj->getScaledPos();
00342         if(ourConfiguration.viewToObjectsFlightDirection) {
00343             //beliebiger Abstand muss ermoeglicht werden:
00344             double r_ = obj->getScaledRadius();
00345             Vector projCenter_ = pos_ + obj->v.getNormalised() *  (r_+10.0);
00346             //Kamera Projektionszentrum auf Ojektposition setzen:
00347             ourCamera.setProjectionCenter(projCenter_);
00348             Vector newPos_ = pos_ + obj->v.getNormalised() *  (r_+1.0);
00349             //Kamera umsetzen:
00350             ourCamera.setPosition(newPos_);
00351 
00352             //neuen upper Vector bestimmen:
00353             Vector oldNormal_ = oldpos_.crossProduct(ourCamera.getUpper());
00354             Vector newUpper_ = oldNormal_.crossProduct(newPos_);
00355             if(newUpper_.length() == 0)
00356                 newUpper_ = Vector(1,0,0);
00357             ourCamera.setUpper(newUpper_);
00358         } else {
00359             //blicke auf objekt von selbem Abstand
00360             Vector diff(pos_-oldpos_ );
00361             Vector newPos_ = ourCamera.getPosition() +diff;
00362             //Kamera Position und Projektionszentrum relativ zur alten Position
00363             //veraendern.
00364             ourCamera.setProjectionCenter( ourCamera.getProjectionCenter() +
00365                                            diff);
00366             ourCamera.setPosition(newPos_);
00367         }
00368 
00369     }
00370 
00371     //Falls das Attribut Fenster gezeigt wird muss bei bewegung der Objekte der
00372     //Inhalt aktualisiert werden um Aktuelle Position und Geschwindigkeit des
00373     // Objekts anzuzeigen.
00374     if(Object::attributeWindowShown())
00375         ourConfiguration.clickedObject->refreshAttributes();
00376     else
00377         redraw();
00378 }
00379 
00380 
00390 int Opengl::getObjectID(int x, int y) {
00391     // Anzahl der Objekte die an Position sich befinden
00392     int objectsFound = 0;
00393     int viewportCoords[4] = {0};
00394 
00395     /* Dieser Array wird die Opengl Namen die Angeklickt wurden enthalten
00396      * Die Groesse ist willkuerlich auf 32 gesetzt. Opengl speichert neben dem 
00397      * Namen weitere Information die nicht benoetigt wird, fuer jedes Objekt
00398      * desses ID gespeichert wird werden 4 Speicherzellen benoetigt.
00399      */
00400     unsigned int selectBuffer[32] = {0};
00401 
00402     /*
00403      * Mit dieser Funktion wird die Puffergroesse mit dem Puffer als
00404      * Selectionspuffer registriert.
00405      */
00406     glSelectBuffer(32, selectBuffer);
00407 
00408     /*
00409      * Diese Funktion gibt einen Vektor von der gewuenschten Information zurueck.
00410      * In unserem Fall wird der Viewport vektor angefordert
00411      */
00412     glGetIntegerv(GL_VIEWPORT, viewportCoords);
00413 
00414     // Die zureuckgegeben werte muessen angepasst werden um die Groesse der
00415     // Nachrichtenleiste zu beruecksichtigen.
00416     y-=viewportCoords[1] ;
00417 
00418     // Im Folgenden wird nun die Szene gezeichnet und die Position der Objekte
00419     // mit der Position (X,Y) auf der Projektion verglichen.
00420     glMatrixMode(GL_PROJECTION);
00421 
00422     //Lege eine neue Matrix auf den Stack damit die 3D Projektion nicht
00423     // beeinflusst wird
00424     glPushMatrix();
00425 
00426     //Rendert die Objekte veraendert allerdings nicht den Frame Buffer
00427     //Die Namen aller gerenderten Objekte werden stattdessen ermittelt.
00428     glRenderMode(GL_SELECT);
00429     glLoadIdentity();
00430 
00431     /*
00432      *Erzeuge eine Projektionsmatrix die um die Position gelegt wird mit einer 
00433      *Toleranz von 2 Pixeln. Normalerweise erlaubt diese Funktion das Rendern in
00434      * der Ausgewaehlten Region, da wir GL_SELECT als Render Modus gewaehlt 
00435      * haben wird stattdessen die ID des Objekts gespeichert. (MAGIC)
00436      */
00437     gluPickMatrix(x, viewportCoords[3] - y, 2, 2, viewportCoords);
00438 
00439     //Kamera Matrix multiplizieren
00440     ourCamera.loadCameraPerspective();
00441 
00442     // Model ansicht laden
00443     glMatrixMode(GL_MODELVIEW);
00444 
00445     //Objekte Zeichnen:
00446     RenderObjects ();
00447 
00448     /*  Wenn in den GL_Render Modus gewechselt wird gibt dieser die Anzahl der
00449      * gefundenen Objekte in der Spezifizierten Region zurueck.
00450      */
00451     objectsFound = glRenderMode(GL_RENDER);
00452 
00453     //Matrix Modus auf normal zurueckstellen
00454     glMatrixMode(GL_PROJECTION);
00455     //Das entfernen der Manipulierten Matrix vom Stack verwirft alles.
00456     glPopMatrix();
00457     glMatrixMode(GL_MODELVIEW);
00458 
00459     if (objectsFound > 0) {
00460         /* Falls mehr als ein Objekt gefunden wurde muessen die Tiefen Werte
00461          * aller Objekte verglichen werden und das Objekt das am Naehsten ist
00462          * ausgewaehlt werden.
00463          * Fuer jedes Objekt gibt es 4 Werte. 
00464          * 2: Minimaler Tiefen wert
00465          * 4: Objektname
00466          */
00467         //Auswahl der Tiefe des ersten Objekts.
00468         unsigned int lowestDepth = selectBuffer[1];
00469 
00470         //Namen des ersten Objekts
00471         int selectedObject = selectBuffer[3];
00472 
00473         for(int i = 1; i < objectsFound; i++) {
00474             if(selectBuffer[(i * 4) + 1] < lowestDepth) {
00475                 //Das aktuelle Objekt ist naeher als das bereits ausgewaehlte.
00476                 lowestDepth = selectBuffer[(i * 4) + 1];
00477                 selectedObject = selectBuffer[(i * 4) + 3];
00478             }
00479         }
00480 
00481         //sicherheitscheck: es kommt evtl. vor das andere Objekte existieren
00482         // Diese duerfen nicht als Speicherort interpretiert werden.
00483         if (selectedObject < 100000)
00484             return 0;
00485         else
00486             // Gib namen des ausgewaehlten Objekts zurueck
00487             return selectedObject;
00488     }
00489 
00490     // Es wurde nicht auf ein Objekt geklickt:
00491     return 0;
00492 }
00493 
00499 void Opengl::HandleTimer(int value) {
00500     if(ourConfiguration.freezeAnimation || ourObjectManager.getObjectCount()==0)
00501         return;
00502 
00503     singleStep();
00504     glutTimerFunc(TIMERUPDATE,& Opengl::HandleTimer,0);
00505 }
00506 
00507 
00516 void Opengl::init(int & argc, char **argv) {
00517     /* Initialisierung der Glut-Bibliothek. Glut extrahiert dabei
00518     * Kommandozeilen-Optionen, die fuer sich selbst bestimmt sind
00519     * und aendert ggf. den Wert argc. Auf diese Optionen soll an
00520     */
00521     glutInit(&argc, argv);
00522 
00523     /* Darstellungsart fuer anschliessend erzeugte Fenster
00524     * festlegen. Dieser Methode werden Veroderungen von Bitmasken uebergeben.
00525      *  - GLUT_DOUBLE: Double-Buffering aktivieren
00526      *  - GLUT_RGB (= GLUT_RGB): RGB-Farbmodell
00527      * - GLUT_DEPTH: Tiefen-Puffer fuer das Fenster aktivieren 
00528     */
00529     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
00530 
00531     //Hauptfenstergroesse Festlegen:
00532     glutInitWindowSize( ourCamera.getScreenWidth(),
00533                         ourCamera.getScreenHeight() );
00534     //Fenster erzeugen
00535     int mainWindow=glutCreateWindow("Solar system construction kit");
00536 
00537     // "Callback-Funktionen" festlegen
00538     /* Setzt die Display-"Callback"-Funktion fuer das aktuelle Fenster.
00539      * Die Funktion "RenderUniverse" wird
00540      * von OpenGL aufgerufen, sobald die Szene neugezeichnet werden soll,
00541      * unter anderem bei Neuzeichnungsaufrufe des Window-Systems. 
00542     */
00543     glutDisplayFunc(& Opengl::RenderUniverse);
00544 
00545     /* Setzt die Reshape-Callback-Funktion fuer das aktuelle Fenster.
00546       * Die Funktion HandleReshape  wird von OpenGL aufgerufen, sobald 
00547     * (z. B. vom Benutzer) die Fenstergroesse
00548       * geaendert wird (auch direkt vor dem ersten Aufruf der Display-Funktion).
00549       */
00550     GLUI_Master.set_glutReshapeFunc(& Opengl::HandleReshape);
00551 
00552     //Weitere Fenster erzeugen, dafuer ist Window zustaendig:
00553     Window::CreateWindows(mainWindow);
00554 
00555     //Es gibt keinen Idle Callback => explizit auf NULL setzen
00556     GLUI_Master.set_glutIdleFunc(NULL);
00557 
00558     // Hier noch einige OpenGL-spezifische Initialisierungen
00559     CreateEnvironment();
00560 
00561     // Den Mauscursor des Window-Systems auch innerhalb des OpenGL-Fensters
00562     // nutzen.
00563     glutSetCursor(GLUT_CURSOR_INHERIT);
00564 
00565 }
00566 
00570 void Opengl::loop() {
00571     glutMainLoop();
00572 }

Erzeugt am Mon May 30 14:31:15 2005 für Sunsystembuildingandsimulation von doxygen 1.3.6