Articles

opengl + fmod en mac

Todo lo que sigue a continuación lo he hecho en un powerbook g4, con tiger y usando xcode 2.1. Soy super novata en programar en Mac así que esto puede estar lleno de cosas mejorables o que se podrían hacer de una forma más sencilla. Se aceptan mejoras y sugerencias :-)

Creamos un nuevo proyecto (File > new project > Command Line Utility > C++ Tool), y especificamos el nombre del proyecto y donde queremos que esté. Como éste es mi segundo intento, le llamo test02. (Súper imaginativo!)

Probamos que funcione con "Build and go", deberíamos obtener un Hello World de los de toda la vida:

#include <iostream> int main (int argc, char * const argv[]) { // insert code here... std::cout << "Hello, World!\n"; return 0; }
A este proyecto le vamos a decir dónde buscar la glfw-2. Así que vamos a la lista de Targets, buscamos uno que se llame test02 (o como sea en tu caso), y con ctrl+click ... Get Info. En la opcion Build elegimos la colección Search Paths. Ahí en Header Search Paths le pones el path a donde tengas el directorio includes de la glfw-2. En mi caso es /Users/sole/code/glfw-2/includes/

Ahora hay que añadir los frameworks AGL, Carbon y OpenGl.

Asi que sobre el target test02 otra vez ctrl+click y Add >Existing frameworks, y añadimos esos 3. Le he dado a aceptar (bueno, add) sin cambiar que Reference Type = Relative to project y text encoding = Western (Mac OS Roman). Aseguraos de que Add to targets tiene test02 seleccionado...

Compilamos y ejecutamos y debería seguir funcionando :P

Ahora a cambiar un poco el main.cpp que tenemos, que es aburrido. Intentaremos rehacer el triangle.c que esta en el directorio de ejemplos, básicamente, pero compilando desde xcode y poniendo música de fondo con fmod :-)

Asi que lo abrimos y copiamos #include <GL/glfw.h> a nuestro main.cpp Prueba y error: compilo y sigue funcionando, eso es que encuentra la include de glfw-2 o bien pasa de mí.

Añadimos a main.cpp:

// Initialise GLFW glfwInit();
y
// Close OpenGL window and terminate GLFW glfwTerminate();
Si compilamos y ejecutamos ahora, nos dara el siguiente error: test02 has exited due to signal 6 (SIGABRT). [Session started at 2005-06-11 17:45:32 +0100.] ZeroLink: unknown symbol '_glfwInit'

Esto es porque no hemos añadido la biblioteca de glfw-2 al proyecto. Vamos a hacerlo ahora. Seleccionamos el proyecto en la izquierda, luego menú Project > Add to project y añadimos la biblioteca, que esta en el directorio lib/macosx de la glfw-2. Se llama libglfw.a, y al añadirla, aparecerá junto con los frameworks que hemos indicado antes, arriba de Source, Documentation y Products. Nos aseguramos de que Zero Link esté desactivado, abrimos las propiedades del target test02 una vez más y en Build > Linking, si ZeroLink está marcado, quitamos esa opción. Ahora si compilamos volvera a funcionar (Hello World de nuevo!!)

Como ya funciona todo, nos vamos a copiar todo el código del triangle a nuestro main.cpp, ya que no nos hace falta ningun hello world. Lo copiamos, lo pegamos y lo compilamos. Si zerolink se ha portado bien, deberiamos ver nuestro triángulo rotante en pantalla!! Atención, que para pararlo hay que irse al run log y parar la tarea desde ahí. No se por qué razón si la ventana pierde el foco no se puede volver a recuperar, y entonces no podéis salir con ESC.

Ahora vamos a por fmod! Nos habremos bajado el pack de su web... Y el proceso vamos a hacerlo similar a lo que hemos hecho para glfw-2: paso a paso. Abrimos un fichero de ejemplo de sus directorios, para ver la sintaxis de fmod y probar algo que funciona con seguridad. Y es el llamado simplest. Abrimos su main.c para ver que ficheros incluyen: fmod.h, fmod_errors.h y wincompat.h, todos en el directorio api/inc. Por tanto, vamos a añadir este directorio al proyecto, para que sepa dónde buscar. Los pasos son fáciles: target test02 > Build > search paths, y en header añadimos éste: /Users/sole/code/bases/fmodapi3741mac/api/inc (obviamente dependerá de donde lo hayáis puesto vosotros) Y cuidado con las mayúsculas, que estamos en un sistema *nix :-P

Para probar, añadimos a main.cpp los mismos includes que ellos ;) Pero como nosotros hemos añadido los paths de las librerías, no hace falta que lo pongamos con paths relativos (a lo "../../"). Simplemente añadimos esto:

#include <fmod.h> #include <fmod_errors.h> /* optional */ #include <wincompat.h>
Le damos a compilar y bueno, sigue funcionando. Probemos a añadir algo que utilice realmente FMOD para ver si peta, por ejemplo la siguiente linea de su main.c: FMUSIC_MODULE *mod = NULL;

Compilamos. Y albricias, no falla! Hemos podido crear una variable de tipo FMUSIC_MODULE, que está definida en los headers de fmod. Buena señal, pero aún no hemos utilizado realmente funcionalidades de la librería. Ah, y si ejecutamos ahora, todo deberia seguir igual que antes, con nuestro triángulo rotante.

Añadimos stdio.h y las siguientes líneas de código de su programa:

if (FSOUND_GetVersion() < FMOD_VERSION) { printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); exit(1); }
Probamos a compilar. Ahora ya se nos ha mareado, ya no funciona. No está encontrando el simbolo FSOUND_GetVersion, así que tenemos que añadir la biblioteca de fmod. Seguimos el mismo proceso que antes para anyadir la .a de glfw-2: Project > Add to project... y añadimos libfmod.a que está en el directorio lib de fmod. Aparecerá junto con libglfw.a y los otros frameworks, como era de esperar... Compilamos de nuevo, y ahora no debería fallar. Si ejecutamos, efectivamente deberíamos tener al triángulo rotante de vuelta. Si no te va... verifica que Zero Link no haya hecho acto de presencia (y si no, también, por si acaso!)

Seguimos anyadiendo codigo, en breve tendremos musica sonando!!

/* INITIALIZE */ if (!FSOUND_Init(44100, 64, FSOUND_INIT_GLOBALFOCUS)) { printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); exit(1); } /* LOAD SONG */

#if defined(MACH) || defined(WIN32) mod = FMUSIC_LoadSong("../../media/invtro94.s3m"); #else mod = FMUSIC_LoadSong(":::media:invtro94.s3m"); #endif if (!mod) { printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); exit(1); }

La cancion que utiliza (invtro94.s3m) nos la vamos a copiar a nuestro directorio. Pero para que quede más aseado (y para seguir mi costumbre), hago una carpeta llamada data en el directorio del proyecto, y copio ahi la canción.

Ahora cambio las rutas, y deberían quedar así:

/* LOAD SONG */

#if defined(MACH) || defined(WIN32) mod = FMUSIC_LoadSong("data/invtro94.s3m"); #else mod = FMUSIC_LoadSong("data:invtro94.s3m"); #endif if (!mod) { printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); exit(1); }

(Como nota interesante, las he puesto para win32 también ya que estaba, pero no lo he probado, me parece que así no funcionarán, y si alguien conoce alguna forma de que pueda utilizar los paths en la forma de unix, en lugar de con dos puntos, se lo agradeceré ;))

Aun así, si compiláis y ejecutáis, os va a decir que no encuentra la canción. Esto es porque por defecto, xcode le dice al ejecutable que su directorio de trabajo es el de Debug, y ahí, evidentemente, no está la canción. Haced ctrl+click sobre el executable test02, y elegid project directory en la opción Set the working directory. De esta forma, invtro94.s3m está en el directorio data del proyecto. Ahora al ejecutar ya no dará el error de que no encuentra la canción, volvemos a tener el triángulo pero aún no suena nada... tranquis ;)

Añadimos código para que suene:

/* PLAY SONG */ FMUSIC_PlaySong(mod);
Y tambien para que se pare!
/* FREE SONG AND SHUT DOWN */ FMUSIC_FreeSong(mod); FSOUND_Close();
Y si le damos a ejecutar.... YA FUNCIONA!!!!!!!! Triángulo rotando con la musica de fondo!!!!!!!

Y para que quede constancia... así se ha quedado el código finalmente:

#include <iostream> #include <stdio.h> #include <GL/glfw.h>

#include <fmod.h> #include <fmod_errors.h> /* optional */ #include <wincompat.h>

int main (int argc, char * const argv[]) { int width, height, running, frames, x, y; double t, t0, fps; char titlestr[ 200 ]; FMUSIC_MODULE mod = NULL; if (FSOUND_GetVersion() < FMOD_VERSION) { printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); exit(1); } / INITIALIZE / if (!FSOUND_Init(44100, 64, FSOUND_INIT_GLOBALFOCUS)) { printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); exit(1); } / LOAD SONG / #if defined(MACH) || defined(WIN32) mod = FMUSIC_LoadSong("data/invtro94.s3m"); #else mod = FMUSIC_LoadSong("data:invtro94.s3m"); #endif if (!mod) { printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); exit(1); } // Initialise GLFW glfwInit(); / PLAY SONG / FMUSIC_PlaySong(mod); // Open OpenGL window if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) ) { glfwTerminate(); return 0; } // Enable sticky keys glfwEnable( GLFW_STICKY_KEYS ); // Disable vertical sync (on cards that support it) glfwSwapInterval( 0 ); // Main loop running = GL_TRUE; frames = 0; t0 = glfwGetTime(); while( running ) { // Get time and mouse position t = glfwGetTime(); glfwGetMousePos( &x, &y ); // Calculate and display FPS (frames per second) if( (t-t0) > 1.0 || frames == 0 ) { fps = (double)frames / (t-t0); sprintf( titlestr, "Spinning Triangle (%.1f FPS)", fps ); glfwSetWindowTitle( titlestr ); t0 = t; frames = 0; } frames ++; // Get window size (may be different than the requested size) glfwGetWindowSize( &width, &height ); height = height > 0 ? height : 1; // Set viewport glViewport( 0, 0, width, height ); // Clear color buffer glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); glClear( GL_COLOR_BUFFER_BIT ); // Select and setup the projection matrix glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 65.0f, (GLfloat)width/(GLfloat)height, 1.0f, 100.0f ); // Select and setup the modelview matrix glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluLookAt( 0.0f, 1.0f, 0.0f, // Eye-position 0.0f, 20.0f, 0.0f, // View-point 0.0f, 0.0f, 1.0f ); // Up-vector // Draw a rotating colorful triangle glTranslatef( 0.0f, 14.0f, 0.0f ); glRotatef( 0.3(GLfloat)x + (GLfloat)t100.0f, 0.0f, 0.0f, 1.0f ); glBegin( GL_TRIANGLES ); glColor3f( 1.0f, 0.0f, 0.0f ); glVertex3f( -5.0f, 0.0f, -4.0f ); glColor3f( 0.0f, 1.0f, 0.0f ); glVertex3f( 5.0f, 0.0f, -4.0f ); glColor3f( 0.0f, 0.0f, 1.0f ); glVertex3f( 0.0f, 0.0f, 6.0f ); glEnd(); // Swap buffers glfwSwapBuffers(); // Check if the ESC key was pressed or the window was closed running = !glfwGetKey( GLFW_KEY_ESC ) && glfwGetWindowParam( GLFW_OPENED ); } // Close OpenGL window and terminate GLFW glfwTerminate(); / FREE SONG AND SHUT DOWN */ FMUSIC_FreeSong(mod); FSOUND_Close(); return 0; }