#include #include #include #include "image.cpp" //#include #ifndef M_PI // for Windows #define M_PI 3.14159265358979323846 #endif #ifndef SGN // Signum #define SGN(y) (((y) < 0) ? -1 : ((y) > 0)) #endif #ifndef MIN #define MIN(a,b) ((a) > (b))? (b) : (a) #endif #ifndef MAX #define MAX(a,b) ((a) > (b))? (a) : (b) #endif ////////////////////////////////////////////////////////////// // Fenster Initialisierung ////////////////////////////////////////////////////////////// //! Die Startposition des Fensters #define WIN_POS_X 0 #define WIN_POS_Y 0 //! Breite des Fensters #define WIN_WIDTH 1024 //! Hoehe des Fensters #define WIN_HEIGHT 768 // Uncomment, wenn man Stencil Buffer braucht //#define NEED_STENCIL // Uncomment, wenn man Accumulation Buffer braucht //#define NEED_ACCUM ////////////////////////////////////////////////////////////// // OpenGL Darstellungsmodus ////////////////////////////////////////////////////////////// //! Default OpenGL Modus: RGBA mit double Buffering und //! depth buffer (Z-Buffer) //! Verwendung der Stencil und Accumulation Buffers #if defined NEED_STENCIL && defined NEED_ACCUM #define USED_MODUS GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_STENCIL | GLUT_ACCUM #elif defined NEED_STENCIL #define USED_MODUS GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_STENCIL #elif defined NEED_ACCUM #define USED_MODUS GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_ACCUM #else #define USED_MODUS GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE #endif ///////////////////////////////////////////////////////////// // Texturdefinition ///////////////////////////////////////////////////////////// #define MAX_TEXTURES 50 #define READ_TEXTURES 0 char *charTextures[MAX_TEXTURES] = { "" }; GLuint textures[MAX_TEXTURES]; ///////////////////////////////////////////////////////////// // Menuelemente ///////////////////////////////////////////////////////////// #define MENU_OPEN "Open" #define MENU_SHADE "Shading" #define MENU_EXIT "Exit" enum MENU_IDs { ID_MENU_OPEN = 1, ID_MENU_SHADE, ID_MENU_EXIT }; ////////////////////////////////////////////////////////////// // Programanhaengige Konstanten und Variablen ///////////////////////////////////////////////////////////// #define PROG_NAME "Template for OpenGL" int MainWin; // Identifier vom Hauptfenster int MainMenu; // Identifier vom Hauptmenu //! Struktur fuer Bearbeitung der Mausevents struct MouseStruct { int LastState; int OldX; int OldY; int ScreenX; int ScreenY; int MoveX; int MoveY; double Radius; } globMouse; ///////////////////////////////////////////////////////////// // Funktionen und Prozeduren ///////////////////////////////////////////////////////////// void MenuFuncFile (int); void DisplayFunc (); void ReshapeFunc (int,int); void MouseFunc (int,int,int,int); void MouseMove (int,int); void KeyboardFunc (unsigned char,int,int); void SpecialKeyboardFunc (int,int,int); void IdleFunc (); void DrawKoordSystem (GLfloat,GLfloat,GLfloat,GLfloat,GLfloat,GLfloat); void InitTexture (); // Nutzerfunktionen void DrawTheObject(); void DrawUhr (); void DrawPfeil (); void DrawFuss(); void DrawGehaeuse(); void DrawZiffernblatt(); void DrawSekundenzeiger(); void DrawMinutenzeiger(); void DrawStundenzeiger(); void DrawZeigerwerk(); void DrawKopf(); void DrawUhrwerk(); void drawCylinder(double radius, double height, int sides); // Nutzervariablen float winkel1=0,winkel2=0,winkel3=0; double k; // // Anfang des OpenGL Programmes // int main (int argc,char **argv) { // Fensterinitialisierung glutInit (&argc,argv); glutInitWindowSize (WIN_WIDTH,WIN_HEIGHT); glutInitWindowPosition (WIN_POS_X,WIN_POS_Y); glutInitDisplayMode (USED_MODUS); MainWin = glutCreateWindow (PROG_NAME); // OpenGL Initialisierungen glEnable (GL_DEPTH_TEST); // Menu erzeugen MainMenu = glutCreateMenu (MenuFuncFile); glutAddMenuEntry (MENU_OPEN,ID_MENU_OPEN); glutAddMenuEntry (MENU_SHADE,ID_MENU_SHADE); glutAddMenuEntry (MENU_EXIT,ID_MENU_EXIT); glutAttachMenu (GLUT_RIGHT_BUTTON); // Menu ist mapped auf // rechte Maustaste // Callback funktion glutDisplayFunc (DisplayFunc); glutReshapeFunc (ReshapeFunc); glutMouseFunc (MouseFunc); glutMotionFunc (MouseMove); glutKeyboardFunc (KeyboardFunc); glutSpecialFunc (SpecialKeyboardFunc); glutIdleFunc (DisplayFunc); // Initiale Mauseigenschaften globMouse.LastState = -1; globMouse.MoveX = 0; globMouse.MoveY = 0; globMouse.Radius = 30; InitTexture (); // Die Hauptschleife glutMainLoop (); return 0; } // // Menu CALLBACK Funktion // void MenuFuncFile (int Item) { switch (Item) { case ID_MENU_EXIT: exit (0); break; case ID_MENU_SHADE: break; case ID_MENU_OPEN: break; } } void InitTexture () { int i; ImageRec *Tex; glGenTextures (MAX_TEXTURES, textures); for (i = 0;i < READ_TEXTURES;i++) { Tex = ReadTexture (charTextures[i]); if (Tex) { glBindTexture (GL_TEXTURE_2D,textures[i]); glTexImage2D (GL_TEXTURE_2D,0,Tex -> BPP >> 3,Tex -> sizeX,Tex -> sizeY,0, (Tex -> BPP == 24) ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE,Tex -> data); glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri (GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); delete Tex; } else printf ("Cannot load texture %s!\n",charTextures[i]); } } // // Display CALLBACK Funktion - wird immer aufgerufen, wenn der // Inhalt des Viewports aktualisiert werden muss (z.B. nach // Aufruf der Funktion 'glutPostRedisplay ()'). // void DisplayFunc () { // Buffer neu initialisieren glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Ansichtstransformationen double x,y,z, The,Phi; Phi = (double)globMouse.MoveX / (double)globMouse.ScreenX * M_PI * 2.0; The = (double)globMouse.MoveY / (double)globMouse.ScreenY * M_PI * 2.0; x = globMouse.Radius * cos (Phi) * cos (The); y = globMouse.Radius * sin (The); z = globMouse.Radius * sin (Phi) * cos (The); int Oben = (The <= 0.5 * M_PI || The > 1.5 * M_PI) * 2 - 1; gluLookAt (x,y,z, 0,2,0, 0, Oben, 0); // Modellierungstransformationen DrawKoordSystem (-15, 15, 0, 21, -15, 15); // Hier die Auswahl zeichnen DrawTheObject(); glFlush (); // Daten an Server (fuer die Darstellung) // schicken glutSwapBuffers(); // Buffers wechseln } // // Resize CALLBACK Funktion - wird aufgerufen, wenn sich die // Fenstergroesse aendert // w,h: neue Breite und Hoehe des Fensters // void ReshapeFunc (int w, int h) { glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (45, (double)w/(double)h, 1, 2000); glViewport (0, 0, w, h); glMatrixMode (GL_MODELVIEW); // Sicherheit halber glLoadIdentity (); // Modelierungsmatrix einstellen globMouse.ScreenX = w; globMouse.ScreenY = h; } // // Maus Button CALLBACK Funktion // button - Welche Taste betaetigt bzw. losgelassen wurde // state - Status der State (GL_DOWN, GL_UP) // x, y - Fensterkoordinaten des Mauszeigers // void MouseFunc (int button, int state, int x, int y) { globMouse.LastState = (state == GLUT_DOWN) ? button : -1; switch (button) { // Linke Taste - mit Rotation verknuepft case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) { globMouse.OldX = x; globMouse.OldY = y; } break; // Mittlere Taste - mit Skalierung verknuepft case GLUT_MIDDLE_BUTTON: if (state == GLUT_DOWN) globMouse.OldY = y; break; // Rechte Taste - reserviert fuer Menue case GLUT_RIGHT_BUTTON: break; } } // // Maus Movement CALLBACK Funktion, wenn das Mausbutton gedrueckt // wurde. Fuer reine Mausbewegung muss man GlutPassiveMotionFunc // einstellen. // void MouseMove (int x, int y) { switch (globMouse.LastState) { case GLUT_LEFT_BUTTON: globMouse.MoveX += x - globMouse.OldX; globMouse.MoveY += y - globMouse.OldY; if (globMouse.MoveX > globMouse.ScreenX) globMouse.MoveX -= globMouse.ScreenX; if (globMouse.MoveX < 0) globMouse.MoveX =+ globMouse.ScreenX; if (globMouse.MoveY > globMouse.ScreenY) globMouse.MoveY -= globMouse.ScreenY; if (globMouse.MoveY < 0) globMouse.MoveY =+ globMouse.ScreenY; globMouse.OldX = x; globMouse.OldY = y; glutPostRedisplay (); break; case GLUT_MIDDLE_BUTTON: globMouse.Radius += y - globMouse.OldY; globMouse.Radius = MAX (globMouse.Radius,1); globMouse.OldX = x; globMouse.OldY = y; glutPostRedisplay (); break; case GLUT_RIGHT_BUTTON: break; } } // // Tastatur CALLBACK Funktion // key: Wert der Taste die gedrueckt wurde // x,y: Position des Mauskursors auf dem Viewport // void KeyboardFunc (unsigned char key, int x, int y) { switch (key) { // Escape case 27: exit (0); // Initialisierung case 'i': case 'I': globMouse.MoveX = 0; globMouse.MoveY = 0; glutPostRedisplay (); break; } } // // CALLBACK Funktion fuer spezielle Tasten (Kursortasten, F-Tasten usw.) // key - Code der Taste (siehe glut Spezifikation) // void SpecialKeyboardFunc (int key, int x, int y) { switch (key) { case GLUT_KEY_UP: break; case GLUT_KEY_DOWN: break; case GLUT_KEY_LEFT: break; case GLUT_KEY_RIGHT: break; case GLUT_KEY_F1: break; } glutPostRedisplay (); } // // CALLBACK Funktion fuer Idle: wird aufgerufen, wenn die CPU nichts // anderes zu tun hat: oft fuer Animation verwendet // void IdleFunc () { } /////////////////////////////////////////////////////////////////////// // // Modellierungsfunktionen // /////////////////////////////////////////////////////////////////////// // // Prozedur fuer Zeichnen eines Koordinatensystemes // void DrawKoordSystem (GLfloat xmin, GLfloat xmax, GLfloat ymin, GLfloat ymax, GLfloat zmin, GLfloat zmax) { GLfloat i; GLfloat akt_color[4]; GLUquadricObj *spitze; GLint akt_mode; glPushAttrib(GL_ALL_ATTRIB_BITS); glGetFloatv(GL_CURRENT_COLOR, akt_color); glBegin(GL_LINES); glColor3f ( 1.0, 0.0, 0.0 ); glVertex3f (xmin,0,0); glVertex3f (xmax,0,0); for (i = xmin; i <= xmax; i++) { glVertex3f(i, -0.15, 0.0); glVertex3f(i, 0.15, 0.0); } glColor3f ( 0.0, 1.0, 0.0 ); glVertex3f (0,ymin,0); glVertex3f (0,ymax,0); for (i = ymin; i <= ymax; i++) { glVertex3f (-0.15, i, 0.0); glVertex3f (0.15, i, 0.0); } glColor3f ( 0.0, 0.0, 1.0 ); glVertex3f (0,0,zmin); glVertex3f (0,0,zmax); for (i = zmin; i <= zmax; i++) { glVertex3f(-0.15, 0.0, i); glVertex3f(0.15, 0.0, i); } glEnd(); // Ende Linienpaare glGetIntegerv(GL_MATRIX_MODE, &akt_mode); glMatrixMode(GL_MODELVIEW); // zuerst die X-Achse glPushMatrix(); glTranslatef(xmax, 0., 0.); glRotatef(90., 0., 1., 0.); glColor3f( 1.0, 0.0, 0.0 ); spitze = gluNewQuadric(); gluCylinder(spitze, 0.5, 0., 1., 10, 10); gluDeleteQuadric(spitze); glPopMatrix(); // dann die Y-Achse glPushMatrix(); glTranslatef(0., ymax, 0.); glRotatef(-90., 1., 0., 0.); glColor3f( 0.0, 1.0, 0.0 ); spitze = gluNewQuadric(); gluCylinder(spitze, 0.5, 0., 1., 10, 10); gluDeleteQuadric(spitze); glPopMatrix(); // zum Schluss die Z-Achse glPushMatrix(); glTranslatef(0., 0., zmax); // glRotatef(-90., 1., 0., 0.); glColor3f( 0.0, 0.0, 1.0 ); spitze = gluNewQuadric(); gluCylinder(spitze, 0.5, 0., 1., 10, 10); gluDeleteQuadric(spitze); glPopMatrix(); glMatrixMode(akt_mode); glColor4fv(akt_color); glPopAttrib(); } // // Zeichnet ein Pfeil // void DrawPfeil () { glBegin(GL_TRIANGLE_FAN); glVertex3f(3.0, 2.0, 0.0); glVertex3f(2.0, 3.0, 0.0); glVertex3f(2.0, 2.5, 0.0); glVertex3f(1.0, 2.5, 0.0); glVertex3f(1.0, 2.0, 0.0); glVertex3f(1.0, 1.5, 0.0); glVertex3f(2.0, 1.5, 0.0); glVertex3f(2.0, 1.0, 0.0); glEnd(); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void drawCylinder(double radius, double height, int sides) { double angle = 2 * M_PI / sides; glPushMatrix(); glScalef(radius,height,radius); // obere Kreisscheibe glPushMatrix(); glRotatef(90.0,1.0,0.0,0.0); glTranslatef(0.0,1.0,0.0); glBegin(GL_TRIANGLE_FAN); glVertex3d(0.0,0.0,0.0); for (int s=0; s<=sides; s++) { glVertex3d(0.5 * cos(s * angle),0.0,0.5 * sin(s * angle)); } glEnd(); glPopMatrix(); // mantel glPushMatrix(); glRotatef(90.0,1.0,0.0,0.0); glBegin(GL_QUAD_STRIP); for (int s=0; s<=sides; s++) { glVertex3d(0.5 * cos(s * angle),1.0,0.5 * sin(s * angle)); glVertex3d(0.5 * cos(s * angle),0.0,0.5 * sin(s * angle)); } glEnd(); glPopMatrix(); // untere Kreisscheibe glPushMatrix(); glRotatef(90.0,1.0,0.0,0.0); glBegin(GL_TRIANGLE_FAN); glVertex3d(0.0,0.0,0.0); for (int s=0; s<=sides; s++) { glVertex3d(0.5 * cos(s * angle),0.0,0.5 * sin(s * angle)); } glEnd(); glPopMatrix(); glPopMatrix(); } void DrawUhr () { glPushMatrix(); DrawFuss(); glPopMatrix(); glPushMatrix(); glRotatef(k,0.0,1.0,0.0); glTranslatef(0.0,15.0,0.0); DrawKopf(); glPopMatrix(); }; void DrawFuss() { glPushMatrix(); glRotatef(-90.0,1.0,0.0,0.0); glScalef(3.0,3.0,10.0); glColor4f(0.2,0.2,0.1,1.0); drawCylinder(1.0,1.0,10); glPopMatrix(); }; void DrawGehaeuse() { glPushMatrix(); glScalef(9.9,9.9,9.9); glColor4f(0.1,0.2,0.5,1.0); glutSolidCube(1.0); glPopMatrix(); glPushMatrix(); glScalef(9.91,9.91,9.91); glColor4f(0.0,0.0,0.0,1.0); glutWireCube(1.0); glPopMatrix(); }; void DrawZiffernblatt() { glPushMatrix(); glPushMatrix(); glColor4f(0.95,0.95,0.95,1.0); glRotatef(90.0,1.0,0.0,0.0); glScalef(8.0,0.0,8.0); glBegin(GL_TRIANGLE_FAN); glVertex3d(0.0,0.0,0.0); for (int s=0; s<=10; s++) { glVertex3d(0.5 * cos(s * (2*M_PI/10)),0.0,0.5 * sin(s * (2*M_PI/10))); } glEnd(); glPopMatrix(); glPushMatrix(); glColor4f(0.05,0.05,0.05,1.0); for (int n = 0; n < 12; n++) { glPushMatrix(); glRotatef(n * 30,0.0,0.0,1.0); glTranslatef(0.0,3.0,0.1); glBegin(GL_LINES); glVertex3d(0.0,0.0,0.0); glVertex3d(0.0,0.5,0.0); glEnd(); glPopMatrix(); } glPopMatrix(); glPopMatrix(); }; void DrawSekundenzeiger() { glPushMatrix(); glColor4f(0.1,0.1,0.1,1.0); glRotatef(90.0,0.0,0.0,1.0); glScalef(2.0,0.1,0.1); glTranslatef(-1.0,-2.0,0.0); DrawPfeil(); glPopMatrix(); }; void DrawMinutenzeiger() { glPushMatrix(); glColor4f(0.15,0.15,0.15,1.0); glRotatef(90.0,0.0,0.0,1.0); glScalef(1.75,0.2,1.0); glTranslatef(-1.0,-2.0,0.0); DrawPfeil(); glPopMatrix(); }; void DrawStundenzeiger() { glPushMatrix(); glColor4f(0.2,0.2,0.2,1.0); glRotatef(90.0,0.0,0.0,1.0); glScalef(1.3,0.5,1.0); glTranslatef(-1.0,-2.0,0.0); DrawPfeil(); glPopMatrix(); }; void DrawZeigerwerk() { // Sekundenzeiger zeichnen und transformieren glPushMatrix(); glTranslatef(0.0,0.0,0.2); glRotatef(-winkel1,0.0,0.0,1.0); DrawSekundenzeiger(); glPopMatrix(); // Minutenzeiger zeichnen und transformieren glPushMatrix(); glTranslatef(0.0,0.0,0.1); glRotatef(-winkel2,0.0,0.0,1.0); DrawMinutenzeiger(); glPopMatrix(); // Stundenzeiger zeichnen und transformieren glPushMatrix(); glRotatef(-winkel3,0.0,0.0,1.0); DrawStundenzeiger(); glPopMatrix(); }; void DrawKopf() { DrawGehaeuse(); glPushMatrix(); for (int m = 0; m < 4; m++) { glPushMatrix(); glRotatef(m * 90,0.0,1.0,0.0); glPushMatrix(); glTranslatef(0.0,0.0,5.0); DrawUhrwerk(); glPopMatrix(); glPopMatrix(); } glPopMatrix(); }; void DrawUhrwerk() { glPushMatrix(); DrawZiffernblatt(); glPushMatrix(); glTranslatef(0.0,0.0,0.1); DrawZeigerwerk(); glPopMatrix(); glPopMatrix(); }; void DrawTheObject() { if (k < 360.0) k += 0.05; else k = 0.0; if (winkel1 < 360.0) winkel1 += 1.0; else { winkel1 = 0.0; if (winkel2 < 359.0) winkel2 += 6.0; else { winkel2 = 0.0; if (winkel3 < 359.0) winkel3 += 30.0; else winkel3 = 0.0; } } DrawUhr (); }