[LinuxFocus-icon]
Home  |  Map  |  Index  |  Zoek

Nieuws | Archieven | Links | Over LF
Dit document is beschikbaar in: English  Castellano  Deutsch  Francais  Nederlands  Portugues  Russian  Turkce  Korean  

convert to palmConvert to GutenPalm
or to PalmDoc

[Miguel Sepulveda]
door Miguel A Sepulveda
<Miguel.Sepulveda/at/disney.com>

Over de auteur:
Afgestudeerd aan de Universiteit van Washington (USA) in 1993. Werkzaam in wetenschappelijk onderzoek in Spanje, Israël, Japan en de VS. Ontdekte Linux voor het eerst rond kernel 0.98 (liefde op het eerste gezicht). Is Hoofd-redacteur van het LinuxFocus magazine in zijn vrije tijd.

Vertaald naar het Nederlands door:
Guus Snijders <ghs(at)linuxfocus.org>

Inhoud:

 

GLUT programmeren: Vensters en Animaties

Illustratie

Kort:

GLUT is de GL Utility Toolkit, ontwikkeld door Mark Kilgard. In dit artikel introduceerd de auteur GLUT en geeft een inleiding over het behandelen van windows (vensters) en animaties met GLUT.

_________________ _________________ _________________

 

Introductie

Om ontwerp redenen was de OpenGL specificatie geïsoleerd van afhankelijkheden van venster systemen. De resulterende interface is een overdraagbare, gestroomlijnde en efficiënte 2D en 3D rendering library. Het is aan het venster (window) systeem om de vensters te openen en te tekenen. De OpenGL library communiceerd met het onderliggende systeem door additionele hulp libraries. Zo beschrijft de GLX hulp library bijvoorbeeld de interactie tussen OpenGL en het X window System.

De OpenGL Utility Toolkit (GLUT) is een programmeer-interface met ANSI C en FORTRAN bindingen voor het schrijven OpenGL programma's die onafhankelijk zijn van het onderliggende window systeem. Het is geschreven door Mark J. Kilgard en vult een groot gat dat was opengelaten door de OpenGL specificatie. Dankzij de GLUT ontwikkelaars kunnen we een algemene window system interface gebruiken, onafhankelijk van het doelsysteem. OpenGL applicaties die GLUT gebruiken kunnen eenvoudig worden geport tussen platforms zonder veel veranderingen aan de broncode. GLUT vereenvoudigd zeker de productie van OpenGL code en vult de OpenGL library aan.

GLUT is relatief klein een eenvoudig te leren. Het is goed ontworpen en de auteur heeft er reeds goede documentatie voor geschreven. Daardoor lijkt het starten van een serie artikelen hier in LinuxFocus een beetje redundant. We moedigen iedere serieuze ontwikkelaar aan om Mark's documentatie te lezen. Het doel van het schrijven van deze reguliere GLUT column is om de GLUT library en het gebruik ervan te introduceren en stap voor stap met voorbeelden een begeleiding te vormen voor de OpenGL series van dit magazine. We hopen dat dit een nuttige bijdrage zal zijn en meer programmeurs te motiveren op de Open-GL-Linux trein te springen. Zorg er in ieder geval voor dat je een kopie van Mark's documentatie krijgt als een goede referentie.

De GLUT API is een status machine, net als OpenGL. Dit betekend dat GLUT een aantal status variabelen heeft die 'leven' tijdens het uitvoeren van de applicatie. De initiële staten van de GLUT machine zijn redelijk gekozen om aan te sluiten bij de meeste applicaties. Het programma kan de waarden van de status (state) variabelen aanpassen wanneer dat nodig is. Als een GLUT functie wordt aangeroepen, wordt zijn actie aangepast aan de hand van de waarden van de status variabelen. GLUT functies zijn simpel, ze nemen enkele parameters. Er worden geen pointers geretourneerd en de enige pointers die aan GLUT functies worden meegegeven zijn pointers naar karakter strings en onduidelijke font handles.

GLUT functies kunnen in verschillende sub-APIs worden geclassificeerd naar functionaliteit:

In dit artikel zullen we enkele van de initialisatie, gebeurtenis afhandeling en venster beheer functies verkennen die nodig zijn om een eenvoudig OpenGL programma te starten.  

Initialisaties

Ieder OpenGL programma dat gebruik maakt van GLUT moet beginnen met het initialiseren van de GLUT status machine. De glut initialisatie functies beginnen met glutInit-. De hoofd initialisatie functie is glutInit:
Gebruik: 
glutInit(int **argcp, char **argv);
argcp is een pointer naar de onveranderde argc programma variabele van main. Bij terugkeer wordt de waarde waarnaar argcp verwijst, geüpdate omdat glutInit commando regel opties relevant voor de GLUT library oppikt, bijvoorbeeld: onder de X Windows System omgeving, worden opties die relevant zijn voor X venster geaccosieerd met het GLUT venster.
argv is de ongewijzigde argv variabele van main.

glutInit zorgt voor het initialiseren van de GLUT status variabelen en onderhandeld de sessie met het windows systeem. Er zijn enkele routines die voor glutInit kunnen voorkomen; alleen routines die beginnen met glutInit-. Deze routines kunnen gebruikt worden om de default venster-initialisatie status te zetten. Bijvoorbeeld:
Gebruik: 
glutInitWindowPosition(int x, int **y);
glutInitWindowSize(int breedte, int **hoogte);
x,y  = schermpositie van het venster in pixels (linker bovenhoek)
breedte,hoogte  van het venster in pixels.

Er is nog een andere initialisatie routine alom aanwezig in iedere OpenGL applicatie, glutInitDisplayMode():
Gebruik: 
glutInitDisplayMode(unsigned int mode); 
mode is is de Display (weergave) mode, een bitsgewijze OR of GLUT display mode bit masker. De mogelijke bitmasker waarden zijn:

GLUT_RGBA Selecteer een RGBA mode venster. Dit is de standaard als geen GLUT_RGBA noch GLUT_INDEX is opgegeven.
GLUT_RGB zelfde als GLUT_RGBA.
GLUT_INDEX Selecteer kleur index venster mode. Dit overschrijft GLUT_RGBA.
GLUT_SINGLE Selecteer een enkel gebufferd venster. Dit is de standaard.
GLUT_DOUBLE Selecteer een dubbel gebuffered venster. Dit overschrijft GLUT_SINGLE.
GLUT_ACCUM Selecteer een venster met een accumulatie (verzamel) buffer.
GLUT_ALPHA Selecteer een venster met eenn alpha component in de kleuren buffer(s).
GLUT_DEPTH Selecteer een venster met een depth (diepte) buffer.
GLUT_STENCIL Selecteer een venster met een stencil buffer.
GLUT_MULTISAMPLE Selecteer een venster met multismapling ondersteuning.
GLUT_STEREO Selecteer een stereo venster.
GLUT_LUMINANCE Selecteer een stereo venster met een "luminance" kleur model.
Als sommige van deze features je niet bekend voorkomen, hoef je je geen zorgen te maken, vroeger of later zullen we hier over schrijven. Laten we eens een paar voorbeelden bekijken. Eerst een simpele initialisatie voor een applicatie om een momentopname te maken:

#include <GL/glut.h>

void main(int argcp, char **argv){

/* Geef venster grootte en locatie */
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);

/* Selecteer Display mode type: 
  Single buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE);

/* Initialiseer GLUT status */
glutInit(&argcp, argv); 

.....meer code

};

Ten tweede een voorbeeld van een animatie programma:

#include <GL/glut.h>

void main(int argcp, char **argv){

/* Geef venster grootte en locatie */
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);

/* Selecteer Display mode type:
  Dubbele buffer & RGBA kleur */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

/* Initialiseer GLUT status */
glutInit(&argcp, argv); 

.....meer code

};

We zullen terugkomen op deze twee voorbeelden terwijl we verdergaan met het leren over GLUT. Het grootste verschil is in het tweede geval het venster wordt geïnitialiseerd in een dubbele buffer modus, ideaal voor animaties omdat het flikkerende effecten elimineerd tijdens het veranderen van frames in de animatie serie.

 

Gebeurtenis Afhandeling

Zoals eerder genoemd is GLUT een status machine. Nu zullen we zien dat het ook ontworpen is als een gebeurtenis-gestuurde machine. Dit betekend dat er een "timer" of continue lus is die gestart wordt na de juiste initialisaties en die, een voor een, alle gebeurtenissen afhandeld die gedeclareerd zijn aan GLUT tijdens de initialisatie. Gebeurtenissen zijn: een muisklik, het sluiten van een venster, vergroten/verkleinen van een venster, verplaatsing van de cursor, indrukken van toetsen op het toetsenbord, en vooral bijzonder de "idle" gebeurtenis, oftewel als er niets gebeurd! Elk van de mogelijke gebeurtenissen moet geregistreerd worden in een van de GLUT status variabelen voor de "timer" of gebeurtenis-verwerkings lus van GLUT om periodiek te controleren of die gebeurtenis is gestart door de gebruiker.

Zo zouden we bijvoorbeeld een "klik met een muisknop" als een gebeurtenis kunnen registeren waar GLUT op dient te letten. Gebeurtenissen worden geregistreed via callback registration routines. Deze hebben de syntax glut[eenGebeurtenis]Func, in het geval van de muisklik zou het glutMouseFunc zijn. Een callback registratie verteld de GLUT engine welke gebruiker-gedefinieerde functie aangeroepen moet worden als de bijbehorende gebeurtenis wordt "getriggerd". Dus, als ik mijn eigen routine MyMouse schrijf, welke specificeerd wat er moet gebeuren als de linker muisknop wordt ingedrukt (of de rechter, enz.), dan kan ik mijn callback functie registreren na de glutInit() in main() met het statement "glutMouseFunc(MyMouse);".

Welke callback functies en gebeurtenissen zijn toegestaan in GLUT zullen we later bekijken. Het belangrijkste nu is dat nadat alle belangrijke gebeurtenissen in onze applicatie zijn geregistreerd, we de gebeurtenis-afhandelings routine van GLUT moeten starten, dit is glutMainLoop(). De functie komt niet meer terug, ons programma gaat in feite een oneindige lus in. Het zal callbacks die eerder zijn geregistreerd aanroepen wanneer nodig. Iedere main() voor een OpenGL applicatie dient te eindigen in een glutMainLoop() statement. In het geval van ons animatie voorbeeld wordt dit dus:

#include <GL/glut.h>

void main(int argcp, char **argv){

/* Initialiseer GLUT status */
glutInit(&argcp, argv); 
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);

/* Open een venster */
glutCreateWindow("Mijn OpenGL Applicatie");

/* Selecteer Display mode type:
  Double buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

/* Registreer Callback Functies */
.....

/* Start Gebeurtenis Afhandeling Engine */
glutMainLoop();
};

Merk op dat ik wat extra code heb toegevoegd die we nog niet eerder hebben genoemd. Het is een van GLUT's venster beheer routines, glutCreateWindow(char **name). Dit vind ik nu zo mooi aan de OpenGL & GLUT ontwerp filosofy, het is vrij duidelijk wat de routine doet, door alleen naar de naam te kijken! Het zorgt ook voor het doorgeven van de opdracht aan het onderliggende venster systeem om een venster te openen voor onze OpenGL applicatie. Het venster krijgt de naam "name" mee als een karakter string. In de X Window omgeving wordt deze naam op de linkerbovenhoek van het venster geschreven. Het venster beheer deel van GLUT heeft vele andere functies die we uiteindelijk zullen bekijken. Voor het moment is deze voldoende. Ik heb ook de initialisatie routines gesorteerd om te laten zien dat deze ook na glutInit() kunnen worden geplaatst.

Terug naar gebeurtenissen... Ik wil nu twee callback registratie functies introduceren die erg fundamenteel zijn in ieder animatie programma. De glutDisplayFunc welke de display functie voor het huidige venster zet en glutIdleFunc, welke de idle callback zet. Beide registratie routines verwachten een functie van het type void *(void). Stel dat we twee additionele callback functies voor ons animatie voorbeeld willen schrijven, void MyDisplay(void), welke zorgt voor het aanroepen van de OpenGL instructies die in feite onze scene op het venster schrijven en void MyIdle(void), een functie om aangeroepen te worden als er geen invoer van de gebruiker is, dat is, iedere keer als de gebeurtenis afhandelings machine van GLUT de oneindige lus rondt (glutMainLoop()) en geen nieuwe gebeurtenis start, verwerkt het MyIdle. Waarom zou ik een Idle callback functie willen registeren in een animatie programma? Omdat als we elk van de afbeeldingen (frames) willen weergeven tijdens de animatie, onafhankelijk van gebruikers-invoer, er een functie moet zijn (de idle callback functie) die telkens wordt aangeroepen tijdens het uitvoeren van het OpenGL programma en de frames veranderd, voordat deze worden getekend door Mydisplay().

 

Animatie Voorbeeld

Tenslotte is hier een eenvoudig voorbeeld voor een animatie programma:
#include <GL/glut.h>

void MyIdle(void){
/* Wat code om de variabelen aan te passen voor het volgende frame */
....
};

void MyDisplay(void){
/* Wat OpenGL code die een frame tekend */
....
/* Na het tekenen van het frame wisselen we de buffers */
glutSwapBuffers();
};

void main(int argcp, char **argv){

/* Initialiseer GLUT status */
glutInit(&argcp, argv); 
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);

/* Open een venster */
glutCreateWindow("Mijn OpenGL Applicatie");

/* Selecteer Display mode type:
  Double buffer & RGBA color */ 
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);

/* Registreer Callback Functies */
glutDisplayFunc(MyDisplay)
glutIdleFunc(MyIdle)

/* Start Gebeurtenis Afhandelings Engine */
glutMainLoop();
};

Merk op dat ik aan het eind van MyDisplay ik een nieuwe GLUT routine heb toegevoegd, glutSwapBuffers(). Dit is erg bruikbaar in animaties. We gebruiken een venster in DUBBELE buffer modus, een weergegeven en een verborgen. De tekenende OpenGL instructies renderen in dit geval altijd in de verborgen buffer. Het aanroepen van glutSwapBuffers verwisseld de buffers en geeft in het venster wat er was getekend. Deze techniek komt veel voor in computer animaties omdat het voorkomt dat het menselijk oog ziet hoe het frame lijn voor lijn wordt opgebouwd.

Er is reeds genoeg materiaal om te beginnen met het schrijven van OpenGL applicaties. Het enige dat mist zijn de OpenGL instructies in MyDisplay die zorgen voor eigenlijke tekenen...maar dat is een ander verhaal ;-).

In het volgende artikel over GLUT programmeren verkennen we de functionaliteit die ons beschikbaar wordt gesteld in het Window Management (venster beheer) deel van GLUT en hoe we meerdere scenes kunnen openen in hetzelfde venster. We zullen ook leren over het gebruik van menus, inclusief de voor- en nadelen ervan voor hun overdraagbaarheid (portability).



Voor meer informatie:

Site onderhouden door het LinuxFocus editors team
© Miguel A Sepulveda, FDL
LinuxFocus.org
Vertaling info:
en --> -- : Miguel A Sepulveda <Miguel.Sepulveda/at/disney.com>
en --> nl: Guus Snijders <ghs(at)linuxfocus.org>

2004-09-18, generated by lfparser version 2.36