Bruk av C/C++ og GLUT
Et minimumsprogram
Følgende er et komplett, kjørbart c-program som viser fram en gul kule på grå bakgrunn.
/* simple.c - displaying a yellow cube * Børre Stenseth 98 */ #include < stdlib.h> #include < GL/glut.h> /* spec of material */ GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.0f, 1.0f }; /* spec for light */ GLfloat ambient[] = {0.2f,0.2f,0.2f,1.0f }; GLfloat diffuse[] = {1.0f,1.0f,1.0f,1.0f }; GLfloat position[] = {200.0f,300.0f,100.0f,0.0f }; void Draw(void) { /* Set up for scene */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* Clear the color and depth buffers. */ glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT| GL_STENCIL_BUFFER_BIT); // position the eye relative to scene gluLookAt(4.0f,0.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f); /* Draw the construction */ /* set up material */ glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); /* draw the cube */ glRotatef(45.0f,1.0f,0.0f,0.0f); glRotatef(45.0f,0.0f,0.0f,1.0f); glutSolidCube(1.5f); glutSwapBuffers(); } void myinit(void) { /* Here we set the attributes that will be constant * during the rendering contexts lifetime */ glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); /* prepare ligthsource */ glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_POSITION, position); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); /* smooth the drawing */ glShadeModel(GL_SMOOTH); glEnable(GL_NORMALIZE); /* set background to light gray */ glClearColor(0.8f, 0.8f, 0.8f, 0.0f); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } void myReshape(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0f, (GLdouble)w/h, 0.1f, 70.0f); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, w, h); } int main(int argc, char *argv[]) { glutInit(& argc, argv); glutInitDisplayMode(GLUT_DEPTH| GLUT_RGB| GLUT_DOUBLE| GLUT_MULTISAMPLE| GLUT_STENCIL); glutCreateWindow("Ball"); glutDisplayFunc(Draw); glutInitWindowPosition(200, 0); glutInitWindowSize(300, 300); glutReshapeFunc(myReshape); myinit(); glutSwapBuffers(); glutMainLoop(); return 0; }
Bygging i Visual Studio
Hele vitsen med GLUT er som sagt at det skal være et verktøy for utvikling av programmer som skal kunne kompileres og kjøres på mange plattformer. Nedenfor er en oppskrift for hvordan GLUT-programmer kan bygges i Visual Studio.
- Etabler et prosjekt av typen Win32 Console Application
- Skriv eller kopier en kildefil, feks. main.c som ovenfor, inn i den katalogen som er etablert for prosjektet.
- Velg menyen Project - Add To Project - Files, og velg filen laget under punktet ovenfor.
- Velg menyen Project - Add To Project - Files, og velg biblioteksfilene glut32.lib, glu32.lib og opengl32.lib
- Kompiler og kjør
Biblioteksfilen glut32.lib kan for enkelhets skyld legges samme sted som glu32.lib og opengl32.lib. I en normal implementasjon av Visual Studio legges disse i katalogen: Program Files\Microsoft Visual Studio\Vc98\Lib og tilsvarende for en eldre versjon av Developers Studio: Progam Files\DevStudio\vc\lib.
Merk at det finnes to versjoner av OpenGL-biblioteker, Microsofts og Silicon Graphics. Microsofts er merket med 32. Silicon Graphics tilsvarende er altså: glut.lib, glu.lib og opengl.lib
Pass på at glut32.dll (og glut.dll) er palssert i systemkatalogen, samme sted som opengl32.dll.
Du kan laste ned .lib, .h og .dll filene her, hvis du ikke har dem allerede.
I linksamlingen, se venstre kolonne,finner du tilgang til alt GLUT-materiale, eksempler, dokumentasjon etc.
Prinsipper
Strukturen i glut-programmer er ganske enkel og rett fram. Programeksempelet ovenfor inneholder de tre typiske basisrutinene som vil inngå i de fleste (alle) GLUT-programmer:
- main, som alle c-programmer skal inneholde. main vil i vanlige c-programmer inneholde programmets hovedløkke. I GLUT-programmer er denne skjult i glutMainLoop(). Vi ser dessuten at main gjør noen basisoperasjoner for å sette opp OpenGL, samt at det defineres noen callback-funksjoner, se nedenfor.
- myInit som foretar en gangs initialisering av tegneomgivelsene.
- draw som foretar den egentlige uttegningen av scenen.
- myReshape som kalles hver gang vinduet endrer størrelse.
Callback-rutiner
Siden ansvaret for hovedløkka er overlatt til GLUT, må vi ha en mekanisme for å fange opp og behandle de meldingene vi er interesserte i. glutMainLoop() må ha noen funksjoner å kalle når det inntreffer begivenheter som vi er interesserte i. Dette gjøres ved å angi callback-funkjsoner, dvs. at vi angir hvilke av våre egendefinerte funksjoner som skal kalles ved de aktuelle begivenhetene. Det finnes en rekke slike begivenheter vi kan fange opp. Noen av de viktigste er listet nedenfor. De er ikke komplett forklart og lista er bare tatt med som en kort orientering.
glutDisplayFunc(void(*func)(void)) | Uttegning i det aktuelle vinduet |
glutMouseFunc(void(*func)(int button, int state, int x, int y)) | Museaksjon |
glutMotionFunc(void(*func)(int x, int y)) | Musebevegelse i det aktive vinduet |
glutKeyboardFunc(void(*func)(unsigned char key, int x, int y)) | Plukker opp tastetrykk som ascii. Museposisjon i x,y |
glutVisibilityFunc(void(*func)(int state)) | Når vinduets synlighet endres |
glutIdleFunc(void(*func)(void)) | For å kunne foreta bakgrunnsoperasjoner |
glutTimerFunc(unsigned int msecs,void(*func)(int value),value)) | For å plukke opp tidsbestemte begivenheter |
Det finnes mange flere. Kilder for en komplett funksjonsliste for GLUT finnes i Kilgaard: OpenGL Programnming for the X Window System eller i den dokumentasjone du kan laste ned.
Interaktivitet
Vi lager et enkelt program som tegner ut en boks som kan roteres ved å trykke ned venstre museknapp og dra: rotbox.c
Dersom vi ønsker å la boksen fortsette å spinne med den hastigheten vi gir den når vi slipper opp knappen kan vi skrive slik: spinbox.c
Vi bruker altså idle event til å drive animasjonen. Når vi ikke vil ha animasjon sier vi at vi ikke bryr oss om å ta vare på idle-events. Vi skrur idle-event handteringen på og av med: glutIdleFunc(idle); og glutIdleFunc(NULL);
Menyer
Vi kan lett legge til enkle pop-up menyer og lese av valget. Eksempelet nedenfor har en meny som tegner en boks enten med tette flater eller som en "ståltrådsboks" med bare kanter. Menyen popper opp ved klikk på høyre museknapp: menubox.c
Identifisering
Et sentralt problem i interaktive løsninger er å identifisere deler av en scene ved å peke på den. Denne problematikken er behandlet i modulen Identifikasjon.
Dette programmet demonstrerer hvordan denne mekanismen kan implementeres: hitbox.c