Grafisk databehandling
IT, Høgskolen i Østfold
Velkommen > Utviklingsverktøy >OpenGL på Linux
../../common/gfx/prev.gif ../../common/gfx/home.gif ../../common/gfx/next.gif

OpenGL og OpenAL på Linux

Student Torstein Krause Johansen, 2002 OpenAl er et lydbibliotek. OpenGL materialet kan leses uavhengig av dette.

[ gl4Java ][ Mesa3D ][ OpenAL ][ C og CPP ][ Texture mapping ][ C programmet simple ][ Emacs ]

Hva:
Bruk av OpenGL under Linux

Lære det som skal til for å programmere med OpenGL på Linux, like godt som en ville på Windows. I tillegg skal vi se på programmering med lyd på Linux og hvordan koble dette til resten av OpenGL programmet vårt. Leseren ventes å kunne grunnleggende Linux, som for eksempel å hatt Unix kurset ved avdelingen, wwww.hiof.no/unix. Videre regner jeg med at leseren ikke har programmert C/C++ før, men er vant med lignende programmering i Java og er litt uredd for å prøve nye ting :-)

OpenGL er utviklet av Silicon Graphics som kjører operativsystemet IRIX som er en Unix variant. Det burde derfor være logisk at OpenGL programmering funker like bra på Linux, da dette er et Unix -like operativsystem. Men (som alltid) er det noe ekstra som gjøres for at ting skal opp og snurre på Linux. Jeg vil fokusere på å utvikle i C og C++, men også ta med oppsett av Gl4Java på Linux.

Disse hindrene skal vi forsere ved å lage en OpenGL applikasjon som også benytter OpenAL, et biblotek inspirert av OpenGL som er tenkt skal fungere sammen med OpenGL for å gi en åpen og portabel måte å programmere 3D lyd på.

Det er flere veier til Rom

En ting som kommer igjen og igjen på Linux, er at det er mange måter å få til en ting på. Dette kommer spesielt fram nå som vi skal installere og sette opp bibloteker slik at vi kan få begynt å programmert litt OpenGL og OpenAL her.

Den første tingen å tenke på, er at det er flere distribusjoner av Linux. Dette er viktig, fordi de forskjellige distribusjonene har forskjellige måter å installere programmer på og har sine konfigurasjonsfiler på forskjellige steder i filstrukturen sin.

Primært er det to måter å installere ting på Linux: Det ene er å bruke et pakkesystem som RPM, DEB eller tgz. Dette er ferdigkompilerte programmer, som bare kan kjøres direkte inn i systemet. Den andre måten er å laste ned kildekoden selv, og så kompilere denne på vår egen maskin. Begge måter har sine fordeler og ulemper. Vi vil under bruke begge fremgangsmåter for å sette opp OpenGL og OpenAL på to Linux varianter, Debian Linux og RedHat Linux.

Debian

Debian er den 100% idealistiske distribusjonen, drevet uten konversielle hensyn av frivillige Debianere verden over. Debian blir foretrukket av eksperter og andre fanatiske Linux tilhengere da denne brukeren full kontroll over alt som kjøres og installeres på systemet. Dette resulterer dog i en del høyere brukerterskel enn de fleste andre Linux distribusjonene. Dette gjelder spesielt installasjonen av OSet.

RedHat

RedHat er mer verdens mest utpredte Linux distribusjon og er meget populær da den har en fin balanse mellom nettopp brukervenlighet og tilpasning. RedHat kan i tillegg tilby profesjonell support og oppfølging, noe som naturlig nok verdsettes av firmer med ansvar for dusinvis med servere. Men RedHat foretrekkes også ofte som desktop Linux, da den har ganske oppdaterte programmer hva grafisk grensesnitt, multimedia og produksjonsprogrammer angår.

gl4Java

gl4java fungerer i grunn helt likt på Linux som på Windows. Vi kan dele inn prosessen i 5 steg:

  1. Last ned installeren fra
    www.jausoft.com/Files/Java/1.1.X/GL4Java/binpkg/gl4java-INSTALLER.zip
  2. Pakk den ut og kjør installasjons scriptet:
       unzip gl4java-INSTALLER.zip
       cd GL4Java/Installer/
       sh install.sh
    
  3. Det er nå kommet endel jar filer i GL4Java/binpkg/, du trenger i allefall å legge gl4java2.8.2.0-jar.zip et sted hvor CLASSPATH finner den, f.eks. din egen ~/minejavapakker/ katalog:
       cd ../binpkg/
       unzip gl4java2.8.2.0-jar.zip -d ~/minejavapakker
    
  4. Oppdatere CLASSPATH variablen slik at at Java finner gl4java bibloteket. (Antar at du bruker BASH shellet)
       emacs ~/.bashrc
    
       Legg til i linjen med CLASSPATH:
       $HOME/javapakker/gl4java.jar
    
       F.eks.:
       export CLASSPATH="$CLASSPATH:$HOME/javapakker"
    
  5. Kjør ~/.bashrc fila di for at den skal laste sine nye settings, f.eks. ved å åpne opp en ny xterm.

Mesa3D

Mesa3D er et grafisk biblotek som tilbyr en API som er nær identisk med SGI sin OpenGL. Bibloteket er frigitt under Lesser GNU Public Licence og er gratis å laste ned fra www.mesa3d.org. De fleste som programmerer OpenGL på Linux benytter dette biblioteket. Det er også mulig å bruke Utah GLX istedenfor GLX modulen som Mesa leverer, noe som skal gi god hardware akselerasjon. Det er dog enklest å bruke alt fra Mesa pakken, så det er det jeg går ut ifra her.

Mesa3D på RedHat Linux

Dersom du kjører RedHat Linux 7.2, er alt som skal til installert og satt opp. Du behøver ikke å gjøre noen ting med andre ord :-)

For å sjekke dette, kan du ta en titt i /usr/include/GL, der skal du bl.a. finne header filene gl.h, glu.h og glx.h, samt diverse header filer startende med 'Mesa' eller 'xmesa'. Sjekk også /usr/lib/ hvor du bør finne bl.a. libGL.so, libGLcore.so libGLU.so.

   cd /usr/include/
   ls | grep -i ^gl

   cd /usr/lib/
   ls | grep GL

Dersom du ikke finner det du ønsker, mangler du mest sansynligvis pakkene Mesa-3.4.2-7 og Mesa-devel-3.4.2-7. Disse finner du på CDROMene til RedHat 7.2 eller på www.rpmfind.net.

   rpm -Uvh Mesa-3.4.2-7.rpm
   rpm -Uvh Mesa-devel-3.4.2-7.rpm

Mesa3D på Debian Linux

Alle Debian systemer har en fil, /etc/apt/sources.list, som inneholder alle mirrors med Debian program pakker maskinen kan hente fra. Du trenger altså ikke å surfe på webben for å finne det du skal ha. Bare gi beskjed om hvilken pakke du vil ha, og installer denne. Eventuelle avhengigheter vil bli løst for deg.

Hver sikker på at du har minst et sett med testing kilder /etc/apt/sources.list fila di, f.eks.

   deb http://http.us.debian.org/debian testing main contrib non-free
   deb http://non-us.debian.org/debian-non-US testing/non-US main contrib non-free

Oppdater apts database over hvilke pakker som er tilgjengelig og installer følgende pakker:

   apt-get update

   apt-get install mesag-dev
   apt-get install mesag-widgets-dev
   apt-get install mesag3-widgets
   apt-get install mesag3
   apt-get install xlibmesa-dev
   apt-get install xlibmesa3

   apt-get install glutg3-dev
   apt-get install glutg3

Mest sansynlig må du gi almenne brukere tilgang til en del devicer som ikke er default. Det samme kan være med Mesa moduler. F.eks. kan det være nødvendig å gjøre følgende for at vanlige brukere skal få tilgang til de devicer vi ønsker.

   su -
   chmod 666 /dev/mixer
   chmod 666 /dev/dsp
openal

OpenAL

OpenAL er et biblotek du kan bruke for å programmere med høykvalitets lyd, som har støtte for avanserte momenter som sample hastighet, tonehøyde, forsterkning av lydnivå, forskjellige rom og lyd retning.

OpenAL er en platform for lyd, som er tenkt brukt sammen med OpenGL, da den både har lik syntax som OpenGL og er like portabel som sin grafiske bror. I tillegg er OpenAL open source, noe som blant annet gjør at det er kun en implementasjon av APIen for lyd, i motsetning til OpenGL som har mange tilnærmede APIer (gl4java, Mesa, Magician)i tillegg til SGIs egen. Dette gjør at utviklere kan være sikre på at deres kode vil garantert fungere på alle platformer hvor OpenAL finnes.

OpenAL ble startet som et open source prosjekt av firmaet Loki Entertainment Software, som drev med porting av spill fra Windows til Linux platformen. De fikk med seg Creative Labs som nå har tatt over CVS basen til prosjektet (les mer om CVS her). Dette stod det derimot ikke noe om på de offisiell sidene til OpenAL, noe som brakte stor frustrasjon hos undertegnede.

Det er tre ting å huske på når en skal programmere med OpenAL. Den opperer to viktige begreper, nemlig "source" som er lydkilden, og "listener" som er lytteren, dvs. brukeren av programmet i dette tilfellet. Hver source trenger en "buffer" å få lyden sin fra, så f.eks. en musikk fil må leses inn i "lyd bufferen" først og så dedikeres til en eller flere "sourcer".

Den beste måten å lære hvordan OpenAL skal brukes er å lese testkoden som følger med i CVS treet. Den ene tutorialen jeg fant på nettet inneholdt direkte feil og var like mye med til å ødelegge som å hjelpe til på veien til denne modulen. Testkoden til OpenAL er dog ikke kommentert, men det går ann å gjette seg fram til det meste med litt fantasi :-)

OpenAL på alle Linux/Unix

Sjekk ut siste versjon av kildekoden fra CVS basen som nå ligger på opensource.creative.com (den ligger ikke lenger på http://www.openal.org), bruk "guest" som passord.

   cvs -d:pserver:guest@opensource.creative.com:/usr/local/cvs-repository login
   cvs -d:pserver:guest@opensource.creative.com:/usr/local/cvs-repository co openal

Kompiler og installer OpenAL, ved vanlig bruk av scripts og GCC, C kompilatoren på maskinen din:

   su
   cd openal/linux

   sh ./autogen.sh
   ./configure --enable-prefix=/usr/local
   make
   make install

Dersom det ikke skjedde noen feil under kompileringen, skal nå finne velkjente filer i henholdsvis /usr/local/lib og /usr/local/include.

   cd /usr/local/lib
   ls | grep -i openal

   cd /usr/local/include/AL
   ls | grep ^al

Du må muligens, (det kommer ann på systemet ditt), oppdatere LD_LIBRARY_PATH variabelen din, slik at programmet "simple" finner OpenAL bibloteket vi nettop installerte. Derso du får error med at "simple" ikke finner libopenal.so.0 eller lignende, så er det LD_LIBRARY_PATH som ikke er satt riktig.

Sett da linjen under enten i ~/.bashrc fila, slik at det vil fungere "i all framtid", eller bare skriv den i en xterm for effekt akkurat nå, du må da starte programmet "simple" fra samme xterm.

   export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

OpenAL på Debian Linux

Dersom ting var mer omstendelige på Debian kontra RedHat når det gjaldt OpenGL er det ditto lettere når det gjelder OpenAL. Hver sikker på å ha noen "testing" mirrors i /etc/apt/sources.list og installer følgende:

   apt-get install libopenal-dev
   apt-get install libopenal0

Du skal nå ha OpenAL biblotek installert og dermed ha tilgjengelig ønskede moduler og headere i henholdsvis /usr/lib og /usr/include/AL.

C og CPP

Generelt

De fleste headrene som er tilgjengelige på systemet ditt, vil du enten finne i /usr/include eller i /usr/local/include. Som ellers i Linux, så legger ting som du har kompilert selv seg under /usr/local treet, og ting som er prekompilert og bare installert (med et pakkesystem som RPM eller DEB) blir lagt under /usr treet.

GNUs C kompilator startes med 'gcc' og GNUs C++ komilator startes med 'g++'. Det er ikke noe farlig å bruke g++ på C kode, dersom du skulle lure :-). Begge kompilatorene skjønner de samme "flagsene", som du vil se i Makfilen vi skal lage under. En kjekk option er '-O3' som gir opptimalisert kode kompilering.

'-I', stor i, står for 'include' og er for å inkludere kataloger med header filer som ikke ligger i standard stedene, /usr/include og /usr/local/include.

'-l' linker til bibliotekers som du måtte bruke i koden din. F.eks. vil du helt sikker å ha bruk for '-lGL -lGLU -lglut '.

Makefiler

Kildekoden til Makefile: Makefile .

Makefiler er en genial ting når en utvikler på Linux. Dette er ganske enkelt noe veldig enkle tekst filer med noen instruksjoner om hva 'make' programmet skal gjøre når den blir eksekvert. Make sjekker også om det er noen endringer på noen av kildefilene spesifisert her med 'TARGETS'. Kun de som er endret siden siste kompilering, vil bli kompilert på nytt.

Hele vitsen her, er å slippe å skrive de værste, lengste kompilerings kommandoenen hver gang en skal se hva den siste endringen i koden gjorde.

Dette eksemplet på en Makefile, ønsker vi å jobbe med fire C filer, nemlig openaltest.c, simple.c, texturetest.c og speakers.c. Vi angir derfor hvert av fornavnene i 'TARGETS' variablen. Vi lister også de sammen under 'clean:' seksjonen i fila.

Resten av fila er ganske standard. Vi lister hvilken kompilator vi vil bruke i 'CC' variablen, nemlig C++ kompilatoren til GNU, g++. Så oppgir vi alle opsjoner vi vil gi til g++, så alle opsjoner til LD, biblotekslinkeren i Linux. Dernest er det 'INCS', alle stier til biblioteker utenom /usr/include og /usr/local/include, 'LIBS' er alle biblioteker vi ønsker å bruke. Her har vi strengt tatt tatt med litt vel mye, men så kan vi også bruke denne Makefila på andre applikasjoner. De som vi i allefall trenger, er '-lopenal -lGL -lGLU -lglut '.

Det som vil skje når vi bare skriver 'make', er at openaltest.c, simple.c, texturetest.c og speakers.c vil bli kompilert med alle flags og opsjoner spesifisert i CFLAGS, LDFLAGS, INCS og LIBS og de ferdige kompilerte programmene vil bli hetende fornavnet til sine respektive C filer. Dersom noen av kildefilene ikke er blitt endret siden sist, vil ikke disse bli kompilert på nytt. Ganske smart, ikke sant?

Vi kan også skrive 'make clean' for å slette alle kompilerte versjoner av programmene. En veldig viktig ting, er at 'make' programmet bruker [TAB] characters for å finne fram i Makfilen din. For å få til dette, kan du f.eks. starte emacs med kommandoen 'emacs -q' for å ikke laste configurasjonsfilen din, som muligens inneholder kode som erstatter [TAB] med [SPACE]s.

   CC=g++
   CFLAGS=-g -O2 -DLINUX -Wall -Wshadow -Wimplicit-functions -Wstrict-prototypes
   LDFLAGS=-g -O2 -DLINUX
   INCS=-I/usr/local/include -I/usr/X11R6/include/X11
   LIBS= -L/usr/X11R6/lib -lXt -lX11 -lXmu -lXext -lXi -L/usr/local/lib -lopenal -lGL -lGLU -lglut
   TARGETS=simple


   % : %.c
      $(CC) $(INCS) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LIBS)

   all: $(TARGETS)

   clean:
      -rm -f *.o simple

Texture mapping

En av de første tingene en lurer på når en begynner med OpenGL er, "hvordan får jeg lagt et bilde på en eller annen figur?". I gl4java er dette gjort ganske elegant, mens i C/C++ verden er det mange rare løsninger på dette som jeg syntes var vanskelig å forstå.

Den framgangs måten jeg fant lettest forståelig og enklest og gjøre generisk, var å bruke grafikk i "rått" format, det vil si at det bare er rene RGB verdier i filen. Dette gjøres med å konvertere fra f.eks. JPG, PNG eller GIF til RGB format. Det er ikke alle grafikk programmer som har støtte for dette formatet, eller de kaller det noe annet. Image Magic gjorde i alle fall jobben.

Under er en funksjon jeg brukte for å gjøre jobben. Jeg har deklarer to globale pekere, henholdsvis "floor_bitmap" og "speaker_bitmap", som fylles i loadTextures() som kjøres i myInit(), når prorammet startes. Disse globale pekerene til texturemappene blir så brukt til å generere MipMaps i henholdsvis getFloorTexture() og getSpeakerTexture() som kjøres til stadighet i drawFloor() og drawSpeaker().

   ...

   FILE *file;

   /* The floor bitmap */
   if( ( file = fopen( "floor.rgb", "rb" ) ) == NULL )
   {
      printf( "File not found : %s\n", "floor.rgb" );
      exit( 1 );
   }

   floor_bitmap = ( GLubyte * ) malloc( 64 * 64 * 7 * ( sizeof( GLubyte ) ) );

   if( floor_bitmap == NULL )
   {
      printf( "Cannot allocate memory for texture\n" );
      fclose( file );
      exit( 1 );
   }

   fread( floor_bitmap , 64 * 64 * 7, 1 , file );
   fclose( file );
   ...

For å texturemappe gulvet, kjører jeg da bare metoden under, istedenfor å lese inn texturen på nytt for hver gang. Mipmaps gjør en del ting for oss. For det første fikser den problemet som oppstår dersom ikke formatet er et resultat av 2n.

Den lager flere versjoner av det orginale bitmappet, f.eks. dersom det orginale er på 64x64 pixels, vil den lage mipmaps versjoner på 32x32, 16x16, 8x8, 4x4, 2x2 og 1x1. Når dette er gjort koster det ikke noe ekstra minnekraft å bytte imellom disse.

Dernest velger den automatisk ut det mipmappet som passer best i forhold til avstanden vi er til objektet som er texture mappet. Derfor blir det en mer virkelighetstro LOD når vi beveger oss i rommet, da OpenGL eller ville bare skalert det orginale bitmappet når vi beveget oss i framover og bakover i rommet.

void getFloorTexture( void )
{
   gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB, 64, 64,
                      GL_RGB, GL_UNSIGNED_BYTE, floor_bitmap );

}

C programmet simple

simple.c Kildekoden til 'simple'.
Dokumentasjon av kildekoden

Alt du trenger for å kjøre programmet, everything.tar.gz,
bortsett fra en musikk fil kalt "art.wav".
Du trenger en wav fil, som heter "art.wav" og ligger i samme katalog som resten av filene (anbefaler litt rocka musikk). Dette gjøres gjerne med at du tar en MP3 fil du vil bruke, og konvertere denne til WAV. F.eks. i XMMS kan dette gjøre med å sette ouput til å være diskwriter, Options->Preferences->Output Plugin->Disk Writer Plugin, og så spille MP3 fila. Du vil da få generert en fil hetenes navnpåmp3fila.wav.

Dette programmet er skrevet i C og demonstrerer hvordan du kan bruke OpenAL sammen med OpenGL for å oppnå både tre dimensjonal grafikk og lyd.

Den store utfordringen var å få lyden til å oppføre seg som du ville tro, når du går mot venstre eller høyre, se avsnittet OpenAL. Løsningen var å sette lydkildene, høytalerne til å være retningsbestemte, et sted like foran dem, på midten. Ved så å la lytterens orientering, det vil si oppmerksomhet, til å være festet like foran høytalernes orientering, oppnådde jeg den ønskede fram, tilbake, venstre og høyre effekten, også når en gikk nærme, eller helt inntil en av høytalerne.

Et annet poeng er jo også at begge kildene skal ha den samme lyden i sine respektive lydbuffere, og at disse startes samtidig, ellers blir det jo ikke en så god simulering av et høytalersett :-)

   ALfloat source0Direction[] = { 0.0, 0.0, 1.0 };
   ALfloat source1Direction[] = { 0.0, 0.0, 1.0 };
   ALfloat listenerOrientation[] = { 0.0, 0.0, 2.0,
                                     0.0, 1.0, 0.0 };

   ...

   void initSound( void )
   {
      alListenerfv( AL_POSITION, listenerPosition );
      alListenerfv( AL_VELOCITY, listenerVelocity );
      alListenerfv( AL_ORIENTATION, listenerOrientation );
      ...

      alBufferData( buffer[ 0 ], format, data, size, freq );
      alBufferData( buffer[ 1 ], format, data, size, freq );
      free( data );
      ...

      alSourcef( source[ 0 ], AL_PITCH, 1.0f );
      alSourcef( source[ 0 ], AL_GAIN, 1.0f );
      alSourcefv( source[ 0 ], AL_POSITION, source0Position );
      alSourcefv( source[ 0 ], AL_VELOCITY, source0Velocity );
      alSourcei( source[ 0 ], AL_BUFFER, buffer[ 0 ] );
      alSourcei( source[ 0 ], AL_LOOPING, AL_TRUE );
      alSourcefv( source[ 0 ], AL_DIRECTION, source0Direction );

      ....
   }

   void myKeyboard( unsigned char key, int x, int y )
   {
      switch( key )
      {
      case '1':
         alSourcePlay( source[ 0 ] );
         alSourcePlay( source[ 1 ] );
         break;
      ...
   }

Emacs

Emacs

dotemacs Min .emacs fil

Litt eLisp for å få Emacs til å oppføre seg som vi vil. Dette er eLisp kode som du skriver direkte inn i din egen Emacs settings fil som ligger som .emacs på hjemmeområdet ditt.

For flere Emacs konfigurasjoner og instruksjoner besøk Emacs sidene mine eller Emacs' offisielle sider.

   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; Vi vil ikke ha dusinvis filnavn.fil~ filer, vil vi vel?
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   (setq make-backup-files nil)
   (setq backup-by-copying-when-mismatch t
         backup-by-copying-when-linked t)

   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; Farger på koden vår!
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   (global-font-lock-mode t)

   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; Funksjonen under gir oss to ting:
   ;; 3 spacers TAB og krøllparanteser på neste linje som ser slik ut:
   ;; for( .. )
   ;; {
   ;;    code...
   ;; }
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   (defun my-c-mode-hook ()
        (setq c-basic-offset 3)
        (c-set-offset 'substatement-open 0))
   (add-hook 'c-mode-common-hook 'my-c-mode-hook)

Referanser og eksempler:
Programeksempelet

Produksjon, kontroll og vedlikehold:
Modulen er skrevet av Torstein Krause Johansen, 3.klasse 2002.
Kun redaksjonelle endringer, Børre Stenseth juni 2002.

Grafisk databehandling fra Høgskolen i Østfold: http://www.ia.hiof.no/~borres/gb/

../../common/gfx/prev.gif ../../common/gfx/home.gif ../../common/gfx/next.gif
skjema popup

Valid XHTML
popup card
Bygget med WXT : 22.mai.2006