//----------------------------------------------// // Codigo del curso // // // // UnSitioWeb.com para programar juegos (cc) // // // // Capitulo 09a // //----------------------------------------------// // Estas directivas del preprocesador le dicen a el enlazador (linker o // linkador o ...) que incluya estas librerias. Esto se puede hacer en // la configuracion del proyecto en el Visual C++ pero esto me parece mas claro. #pragma comment( lib, "openGL32.lib" ) // Biblioteca de OpenGL #pragma comment( lib, "glu32.lib" ) // Biblioteca Glu32 (funciones GLU) #pragma comment( lib, "corona.lib" ) // Biblioteca Corona para graficos // Biblioteca GLAUX de funciones auxiliares. La usaremos solo // para poder usar objetos que vienen predefinidos, antes de que // podamos usar los que cargamos nosotros mismos. #pragma comment( lib, "glaux.lib" ) #include // Libreria standard de entrada y salida. #include // Fichero de inclusion para programas Windows. #include #include // Los ficheros de inclusion de OpenGL. #include // Estrictamente solo es necesario el primero. // El segundo es de funciones utiles que se podrian // hacer de otra manera. No nos vamos a complicar la // vida y la usaremos. // Incluimos la cabecera de la lbreria GLAUX. #include // Incluiremos las funciones de la libreria Corona. #include "corona/include/corona.h" HINSTANCE IdAplicacion; // Para guardar el identificador del programa HWND IdVentana; // Para guardar el identificador de la ventana HDC DevContex; // Device Context para conectar la ventana con OpenGL. HGLRC OGLrc; // Render Context para la ventana OpenGL. int AnchoVentana = 600; // Lo que dice el nombre de la variable int AltoVentana = 400; // Lo que dice el nombre de la variable // Definimos un rectangulo (programacion windows) // lo usaremos para almacenar el area cliente de nuestra ventana RECT rect; GLuint tex1, tex2; // Para los id's de texturas que genera OpenGL. // Matrices con los datos de iluminacion que vamos a usar. // Se podria definir localmente, en las funciones que se usan // pero yo lo pongo aqui. // Datos de las componentes ambiente, difusa y especular // de nuestra fuente de luz. GLfloat ambiente[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat difusa[] = { 0.5, 0.5, 0.5, 1.0 }; GLfloat especular[] = { 0.8, 0.8, 0.8, 1.0 }; // Datos de las componentes ambiente, difusa y especular // de el primer material. Todo 1.0 en difusa y especular sera blanco, // la luz ambiente se reflejara poco y la escena sera oscurilla. GLfloat mat1_ambiente[] = { 0.4, 0.4, 0.4, 1.0 }; GLfloat mat1_difusa[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat1_especular[] = { 1.0, 1.0, 1.0, 1.0 }; // Datos de las componentes ambiente, difusa y especular // de el segundo material. GLfloat mat2_ambiente[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat mat2_difusa[] = { 2.0, 2.0, 1.0, 1.0 }; GLfloat mat2_especular[] = { 1.0, 1.0, 1.0, 1.0 }; // Variable de tipo unsigned int para guardar // el identificativo de la "display list" GLuint Cubo; void GeneraLista() { // Genero una (1) lista y guardo el // identificativo en "Cubo" Cubo = glGenLists(1); // Esta funcion es la que marca el inicio // de la definicion de la lista. // Todas las funciones OpenGL entre esta // funcion y glEndList() se guardaran en la lista. glNewList(Cubo, GL_COMPILE); // Le digo a OpenGL que voy a pintar y con cuadrados: glBegin(GL_QUADS); // Cara de arriba // Quito (comento) los colores que puse en ejercicios anteriores // ya que uso texturas. //glColor3f(1,0,0); // rojo. // Coordenadas de textura para el primer vertice. // Le indico que punto de la textura se va a pintar en este // vertice. glTexCoord2d(1.0,0.0); // Por cada vertice o por cada cara, definimos el vector normal // a la superficie glNormal3f(0,1,0); // Ahora la coordenada del vertice. glVertex3f( 1.0f, 1.0f,-1.0f); // Repetimos operacion. Para cada vertice una funcion // glTexCoor, una glNormal y una glVertex ... glTexCoord2d(0.0,0.0); glNormal3f(0,1,0); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2d(0.0,1.0); glNormal3f(0,1,0); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2d(1.0,1.0); glNormal3f(0,1,0); glVertex3f( 1.0f, 1.0f, 1.0f); // Cara de abajo //glColor3f(1,0,0); // rojo glTexCoord2d(1.0,0.0); glNormal3f(0,-1,0); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2d(0.0,0.0); glNormal3f(0,-1,0); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2d(0.0,1.0); glNormal3f(0,-1,0); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2d(1.0,1.0); glNormal3f(0,-1,0); glVertex3f( 1.0f,-1.0f,-1.0f); // Cara frontal //glColor3f(0,0,1); // azul glTexCoord2d(1.0,0.0); // En esta definimos solo la primera normal para probar. // El resto de vertices usaran la misma. glNormal3f(0,0,1); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2d(0.0,0.0); //glNormal3f(0,0,1); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2d(0.0,1.0); //glNormal3f(0,0,1); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2d(1.0,1.0); //glNormal3f(0,0,1); glVertex3f( 1.0f,-1.0f, 1.0f); // Cara trasera //glColor3f(0,0,1); // azul glTexCoord2d(1.0,0.0); glNormal3f(0,0,-1); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2d(0.0,0.0); glNormal3f(0,0,-1); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2d(0.0,1.0); glNormal3f(0,0,-1); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2d(1.0,1.0); glNormal3f(0,0,-1); glVertex3f( 1.0f, 1.0f,-1.0f); // Cara izquierda //glColor3f(0,1,0); // verde glTexCoord2d(1.0,0.0); glNormal3f(-1,0,0); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2d(0.0,0.0); //glNormal3f(-1,0,0); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2d(0.0,1.0); //glNormal3f(-1,0,0); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2d(1.0,1.0); //glNormal3f(-1,0,0); glVertex3f(-1.0f,-1.0f, 1.0f); // Cara derecha //glColor3f(0,1,0); // verde glTexCoord2d(1.0,0.0); glNormal3f(1,0,0); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2d(0.0,0.0); glNormal3f(1,0,0); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2d(0.0,1.0); glNormal3f(1,0,0); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2d(1.0,1.0); glNormal3f(1,0,0); glVertex3f( 1.0f,-1.0f,-1.0f); glEnd(); // Fin de la creacion de la lista. glEndList(); } //-------------------------------------------------------------- // Funcion para pintar algo y que se repite continuamente. Se suele // llamar bucle de juego o principal. void Pinta() { // Borro el buffer de atras (BackBuffer), donde voy a pintar. // Tambien el buffer de profundidad para que no pinte lo que // esta detras de otra cosa. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Le digo a OpenGL que voy a cambiar la matriz de modelo glMatrixMode(GL_MODELVIEW); // Cargo la matriz identidad en la modelview, // con eso me aseguro de que ningun cambio anterior modifica // lo que voy ha hacer despues con esta matriz. Empiezo de cero. // (borramos posibles traslaciones, rotacions, ...) glLoadIdentity(); // Muevo para atras el objeto. El punto de vista esta // en la posicion 0,0,0 porque no lo he cambiado, asi que // alejo el objeto para poder verlo. glTranslatef(1,0,-4.0f); // Giro el objeto 30 grados en el eje x, luego otros // 30 en el eje y. Es para que quede bonito. glRotatef(30,1,0,0); glRotatef(30,0,1,0); // Definimos el material del objeto modificando la forma en // como refleja cada componente de la luz que le llega. glMaterialfv(GL_FRONT, GL_AMBIENT, mat1_ambiente); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat1_difusa); glMaterialfv(GL_FRONT, GL_SPECULAR, mat1_especular); // El brillo especular pequeño (de 0 a 255). glMaterialf(GL_FRONT, GL_SHININESS, 20); // y pinto el objeto con coordenadas genericas alrededor // del eje de coordenadas. Estas coordenadas que pongo // ahora son modificadas por las modificaciones que // hemos hecho en la matriz modelview (glTranslate, glRotate). // Le indico a OpenGL que voy a usar texturas para pintar el // objeto y que van a ser de 2 dimensiones (un dibujo normal). glEnable(GL_TEXTURE_2D); // Indico la textura que voy a usar (tex1) y que es de 2D. glBindTexture(GL_TEXTURE_2D, tex1); // En vez de pintar el cubo con todas las funciones // glVertex, glNormal y glTexCoord, solo tengo // que ejecutar la lista "Cubo". glCallList(Cubo); // Pinto otro cubo un poco mas lejos glTranslatef(0,0,-2.0f); glCallList(Cubo); // Desabilito pintar con texturas para pintar // otros dos cubos blancos glDisable(GL_TEXTURE_2D); // Pinto otro cubo, ya sin textura a un lado. glTranslatef(2,0,2.0f); glCallList(Cubo); // Pinto otro cubo mas lejano. glTranslatef(2,0,-4.0f); glCallList(Cubo); // Desabilito la aplicacion de texturas 2D. // Ya las habia desabilitado para pintar dos // cubos blancos asi que comento esta linea. //glDisable(GL_TEXTURE_2D); // Definimos el material del objeto modificando la forma en // como refleja cada componente de la luz que le llega. glMaterialfv(GL_FRONT, GL_AMBIENT, mat2_ambiente); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat2_difusa); glMaterialfv(GL_FRONT, GL_SPECULAR, mat2_especular); // El brillo especular pequeño (de 0 a 255). glMaterialf(GL_FRONT, GL_SHININESS, 20); // Cargo la matriz identidad en la matriz de modelo. // para colocar desde 0 el proximo objeto. glLoadIdentity(); // Traslado lo proximo que voy a dibujar // -2 en al eje X (2 a la izquierda) y -4 en // el eje Z ( 4 al fondo ). glTranslatef(-2.0,0,-4.0f); // y dibujo una esfera solida de 1 de radio // usando la libreria glaux, que para eso la // hemos cargado. auxSolidSphere(1); // Ahora vamos a pintar un cartel en pantalla tal y como // vimos en capitulos anteriores, ortogonalmente // Primero desabilito la iluminacion, para que // OpenGL no haga el calculo de luz al pintarlo. // Queremos simplemente que pinte en pantalla el // dibujo que hemos cargado de disco, tal cual. glDisable(GL_LIGHTING); // Le digo a OpenGL que voy a trabajar con la matriz // de proyeccion. glMatrixMode(GL_PROJECTION); // Guardo la actual matriz de proyeccion en la pila de matrices // para volver a la proyeccion actual cuando termine. glPushMatrix(); // Cargo la matriz identidad (inicializo). glLoadIdentity(); // Defino la proyeccion ortogonal, tal y como vimos en capitulos // anteriores glOrtho(0,rect.right,rect.bottom,0,-1,1); // Una vez puesta la proyeccion regreso a la matriz de modelo, // con la que pinto los objetos. glMatrixMode(GL_MODELVIEW); // Inicializo la matriz de modelo con la matriz identidad. glLoadIdentity(); // Habilito de nuevo la aplicacion de texturas. glEnable(GL_TEXTURE_2D); // Le indico la textura que voy a usar (tex2). glBindTexture(GL_TEXTURE_2D, tex2); // Habilito el blending para OpenGL (esta imagen sera un // .PNG con el fondo trasparente y quiero que se vea asi en mi // programa. glEnable(GL_BLEND); // Le indico como tiene que hacer el blending (para un .PNG // Con fondo transparente esta funcion va bien) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Muevo el cartel 10 pixels para abajo y 10 pixels a la // derecha del borde de la pantalla para que no este pegado. glTranslatef(10,10,0); // Y dibujo un cuadrado con sus correspondientes vertices // y sus coordenadas de textura. glBegin(GL_QUADS); glTexCoord2d(0.0,0.0); glVertex3i( 0, 0,0); glTexCoord2d(0.0,1.0); glVertex3i( 0, 75,0); glTexCoord2d(1.0,1.0); glVertex3i( 300,75,0); glTexCoord2d(1.0,0.0); glVertex3i( 300,0,0); glEnd(); // Desabilito el blending para que lo que haga despues no // me haga raros y me vuelva loco para saber porque. glDisable(GL_BLEND); // Cambio a la matriz de proyeccion glMatrixMode(GL_PROJECTION); // Recupero de la pila, la matriz de proyeccion original // asi no tengo que volver a indicar a OpenGL como quiero la // proyeccion. Sencillamente la restablezco. glPopMatrix(); // Cambio de nuevo a la matriz de modelo. glMatrixMode(GL_MODELVIEW); // Habilito la iluminacion que habia desabilitado // para pintar el cartel, no sea que lo siguiente // no se pinte como quiero. // Lo importante es no perder el control con los // sucesivos cambios y que en todo momento controlemos // como se pinta nuestra escena. glEnable(GL_LIGHTING); // Cambio los bufferes de modo que presento lo que he dibujado en pantalla: SwapBuffers(DevContex); } //-------------------------------------------------------------- // Funcion para inicializar OpenGL. void IniciaGL() { // Definimos una estructura de tipo PIXELFORMATDESCRIPTOR para definir // las caracteristicas graficas que queremos usar (dentro de las que nos // permite el OpenGL de nuestra tarjeta de video) static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Tamaño de este descriptor 1, // Número de versión PFD_DRAW_TO_WINDOW | // El formato debe soportar ventana PFD_SUPPORT_OPENGL | // El formato debe soportar OpenGL PFD_DOUBLEBUFFER | // Debe soportar Doble Buffer PFD_TYPE_RGBA, // También debe soportar RGBA 32, // Bits por pixels seleccionados 0,0,0,0,0,0, // Bits de color ignorados 0, // Sin buffer alpha 0, // Shift bit ignorado 0, // Buffer de acumulación ignorado 0,0,0,0, // Bits de acumulación ignorados 32, // Z-Buffer de 32 bits 0, // Sin buffer de pincel (Stencil) 0, // Sin buffer auxiliar PFD_MAIN_PLANE, // Layer de dibujo principal 0, // Reservado 0,0,0, // Layers de máscara ignorados }; // Estas funciones son las que hacen que la ventana acepte el modo grafico que // queremos dado el descriptor de pixel anterior. (en el que uno de los parametros // es que funcione con OpenGL). DevContex=GetDC(IdVentana); // Obtengo el "device context" de la ventana. int PixF=ChoosePixelFormat(DevContex,&pfd); // Busco un indice de una conbinacion // que coincida con mis especificaciones SetPixelFormat(DevContex,PixF,&pfd); // Pongo la ventana en el formato que quiero. // Dos funciones de OpenGL por fin (aunque sean especificas de windows). OGLrc=wglCreateContext(DevContex); // Indico a OpenGL que la ventana esta disponible para el. wglMakeCurrent(DevContex,OGLrc); // Le digo a OpenGL que nuestra ventana es donde tiene // que dibujar a partir de ahora. // A partir de ahora podemos considerar OpenGL inicializado. // Aun nos queda decirle los parametros del modo en que dibujar, aunque eso se puede, // y de hecho se hace continuamente, cambiar durante el programa. // Ahora pondremos algunos parametro puramente de OpenGL de inicio. glClearDepth(1.0f); // Profundidad del buffer de profundidad. Hace que lo que esta // mas cerca se vea (dibuje) encima de lo que esta mas lejos. glDepthFunc(GL_LEQUAL); // Comparacion del buffer de profundidad. glEnable(GL_DEPTH_TEST); // Habilita test de profundidad. A partir de ahora, lo que // esta mas cerca se pinta encima. glClearColor(0,0,0,1.0f); // Color del fondo. Color con el que se borra la pantalla, o la // ventana donde pintamos. Cuando usemos la funcion glClear. glShadeModel(GL_SMOOTH); // Renderizado suave. Cuanta mejor calidad mas lento. Nosotros // tenemos un ordenador reciente(+ o -) y queremos que se vea bien. // En realidad las opciones son ver facetados los objetos o verlos // con superficie suave, y podemos elegir una u otra opcion. glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // Calidad buena de perspectiva. // Extraemos el area cliente de nuestra ventana en rect. GetClientRect(IdVentana, &rect); // Usamos rect (el area cliente o espacio util dentro de los bordes de nuestra ventana) // para definir los limites del espacio que va a usar OpenGL para dibujar (viewport). // asi ajustamos nuestra ventana y OpenGL. glViewport(rect.left,rect.top,rect.right,rect.bottom); // Le dice a OpenGL el tamaño en el que va a pintar en pixels. // Coincidira, en principio, con el tamaño de nuestra ventana y // empezando por 0,0 (la esquina de nuestra ventana). // Le digo a OpenGL que voy a cambiar la matriz de proyeccion glMatrixMode(GL_PROJECTION); // Le digo a OpenGL que use proyeccion perspectiva. // Uso al ancho y alto de mi viewport para calcular el segundo parametro gluPerspective(60.0f, (float)rect.right/(float)rect.bottom, 0.5f, 50.0f); // Definimos una cadena de caracteres para poner en el titulo de nuestra ventana // el tamaño del area cliente (a mi me gusta saber el tamaño de mi ventana de dibujo) char cad[50]; // 50 seran suficientes caracteres. // Relleno mi cadena con lo que voy a poner en la ventana. sprintf(cad,"UnSitioWeb %i x %i",rect.right,rect.bottom); // Modifico el titulo de mi ventana. SetWindowTextA(IdVentana,cad); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Borramos la ventana con el color antes establecido // (en realidad solo el backbuffer (la pantalla oculta // donde en realidad estamos pintando) // y borramos tambien el buffer de profundidad SwapBuffers(DevContex); // Le digo a nuestro espacio de dibujo que cambie "muy rapido" el buffer de // dibujo por el de visualizacion y viceversa (suichear en Espanglish) // Inicio el uso de la libreria Corona para cargar los graficos. // Objeto de Corona para cargar imagenes corona::Image* imagen=NULL; // Funcion de Corona para cargar una imagen. En este caso es un PNG y // le decimos que lo carge con formato RGBA (Red Green Blue Alfa) de // 8 bits cada uno. La componente Alfa se usa para transparencias. imagen = corona::OpenImage("cuad.png", corona::PF_R8G8B8A8); // Genero una textura y cargo su identificativo en tex1 glGenTextures(1, &tex1); // Le indico a OpenGL que voy a trabajar con la textura tex1 glBindTexture(GL_TEXTURE_2D, tex1); // Genero los mipmaps a partir de las funciones del objeto imagen de Corona. // Uso la libreria GLU de nuevo para facilitarme la vida. // Con la funcion gluBuild2DMipmaps genero multiples niveles de detalle, // multiples texturas, cada una con un tamaño y nivel de detalle cada vez // menor y que luego OpenGL usara segun la distancia al punto de vista. // Es un metodo para mejorar el rendimieto. // Luego uso la textura como si fuera normal (simple). // Parametros: 1- Es en 2D; 2- 4 porque cada pixel ocupa 4 bytes con RGBA; // 3- Ancho de la imagen; 4- Alto de la imagen; 5- Tipo de imagen (RGBA); // 6- Como tratar los datos de la imagen; 7- Puntero a la imagen en si. gluBuild2DMipmaps( GL_TEXTURE_2D, 4, imagen->getWidth(), imagen->getHeight() , GL_RGBA, GL_UNSIGNED_BYTE, imagen->getPixels() ); // Indico como va a visualizarse los pixels en caso de encajar una imagen grande // en un cuadrado pequeño. GL_NEAREST_MIPMAP_LINEAR interpola y se ve bien. glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR ); // Indico como va a visualizarse los pixels en caso de encajar una imagen pequeña // en un cuadrado grande. GL_NEAREST_MIPMAP_LINEAR interpola y se ve bien. glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST_MIPMAP_LINEAR ); // Das dos funciones siguientes son por si quiero repetir la imagen // dentro del cuadrado. Tendria que cambiar las coordenadas de // textura. En este ejemplo no serian necesarias. glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT); // El modo en que se aplica la textura sobre el color del poligono. // DECAL y REPLACE simplemente de pone el dibujo. MODULATE y BLEND // se podrian usar con iluminacion una y para transparencia otra. glTexEnvf(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_MODULATE); // Como ya he cargado la imagen en la textura con gluBuild2DMipmaps // puedo liberar la memoria. if(imagen!=NULL) delete imagen; // Usamos de nuevo el objeto imagen para cargar otra imagen de disco. imagen = corona::OpenImage("uswg.png", corona::PF_R8G8B8A8); // Genero una textura y cargo su identificativo en tex2 glGenTextures(1, &tex2); // Le indico a OpenGL que voy a trabajar con la textura tex2 glBindTexture(GL_TEXTURE_2D, tex2); // Esta vez cargo la textura normal sin generar mipmaps. // Parametros: 1- Es de 2D; 2- Es para mipmaps manuales y no lo // usamos; 3- Tipo de imagen (de nuevo RBGA); 4- Ancho de la imagen; // 5- Alto de la imagen; 6- Borde. Nosotros 0; 7- El formato de nuevo // 8- Tipo en que almacena la textura; 9- Puntero a los pixels de // la imagen. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imagen->getWidth(), imagen->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, imagen->getPixels()); // Lo mismo que haciamos con la otra textura pero el parametro // es ahora GL_LINEAR. glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Lo mismo de antes. glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT); // Lo mismo de antes. glTexEnvf(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_DECAL); // Como ya he cargado la imagen en la textura con glTexImage2D // en la memoria grafica, puedo liberar la memoria. if(imagen!=NULL) delete imagen; // Modificamos la posicion de la luz 0 de OpenGL. // El cuarto parametro es un 1.0 para que sea una luz puntual. GLfloat posicion[] = { 0.5, 4.0, -3.0, 1.0 }; glLightfv(GL_LIGHT0, GL_POSITION, posicion); // Habilitamos el calculo de la iluminacion. glEnable(GL_LIGHTING); // Encendemos la luz 0. glEnable(GL_LIGHT0); // Definimos cada una de las componentes de la luz // que emite nuestra bombilla (la luz 0). glLightfv(GL_LIGHT0, GL_AMBIENT, ambiente); glLightfv(GL_LIGHT0, GL_DIFFUSE, difusa); glLightfv(GL_LIGHT0, GL_SPECULAR, especular); GeneraLista(); } // Fin IniciaGL //------------------------------------------------------------------ // Funcion para controlar lo que ocurre en la ventana segun los eventos // que vienen de Windows. Mas tarde se asocia a la ventana que crearemos. // De momento solo interceptamos la tecla ESC para poder salir del // programa cuando queramos y el evento de destruccion de ventana con el // que terminamos la aplicacion LRESULT FAR PASCAL ProcesaMensajes(HWND Ventana, UINT Mensaje, WPARAM wParam, LPARAM lParam) { switch(Mensaje) // Según el mensaje recibido { case WM_KEYDOWN: // Caso de mensaje de pulsación de una tecla switch(wParam) // y segun el contenido de la variable wParam { case VK_ESCAPE: // ESC causa la salida del programa // Funcion para enviar mensaje de cerrado a la ventana // y despues de la aplicacion PostMessage(Ventana, WM_CLOSE, 0, 0); break; } break; case WM_DESTROY: // Mensaje de destrucción de la ventana (provocado por // nosotros al pulsar ESC o cerrar la ventana. // Borro las texturas de memoria. No hay que dejar basura. glDeleteTextures( 1, &tex1 ); glDeleteTextures( 1, &tex2 ); PostQuitMessage(0); // Funcion para salir del programa break; } // Efectuar el proceso por defecto del mensaje (si viene cualquier mensaje // que no hemos usado, querremos que haga lo que suele hacer) return DefWindowProc(Ventana, Mensaje, wParam, lParam); } // fin ProcesaMansajes //------------------------------------------------------------------ // Funcion para crear la ventana de nuestro programa, que asociaremos // al OpenGL para pintar en ella void CreaVentana() { WNDCLASS ClaseVentana; // Declaramos un tipo de ventana, el nuestro. //Definimos nuestro tipo de ventana... ClaseVentana.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Se redibujara si // cambia el tamaño de la ventana horizontal y verticalmente, y un solo // DC (device context) para cada ventana (para cuando empezemos con OpenGL) ClaseVentana.lpfnWndProc = ProcesaMensajes; //La definimos antes para contolar // los mansajes como los del teclado ClaseVentana.cbClsExtra = 0; //Sin memoria extra para la clase ClaseVentana.cbWndExtra = 0; //Sin memoria extra para la ventana ClaseVentana.hInstance = IdAplicacion; // Identificador del programa para asociar // esta ventana con este programa. ClaseVentana.hIcon = NULL; // De momento pasamos de icono ClaseVentana.hCursor = LoadCursor(NULL, IDC_ARROW); // Flecha normal de raton ClaseVentana.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // Por ahora lo ponemos blanco ClaseVentana.lpszMenuName = NULL; // Pasamos de menu ClaseVentana.lpszClassName = L"UnSitioWeb"; // Nombre de la clase (la "L" antes de la cadena es // por que solo admite cadenas de caracteres // unicode -LPCWSTR o TCHAR- y con la "L" se convierte). RegisterClass(&ClaseVentana); // Registramos nuestro tipo de ventana IdVentana = CreateWindowEx( // Funcion que crea la ventana. Guardamos el identificativo. WS_EX_APPWINDOW, // estilo extendido de ventana L"UnSitioWeb", // Nombre de la clase puesto antes (la "L" antes para convertir a UNICODE) L"Un Sitio Web", // Titulo que aparecera en la ventana. WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX, // Parametros de como sera la ventana // se pueden combinar varios. 100, // Posicion Horizontal. 100, // Posicion Vertical. AnchoVentana, // Ancho de la ventana. AltoVentana, // Alto de la ventana. (HWND) NULL, // No depende de otra ventana. (HMENU) NULL, // No le damos un menu diferente al de la clase (que es ninguno). IdAplicacion, // Identificador del programa al que pertenece la ventana. Al // empezar lo guardamos en una variable para usarlo despues. (LPVOID) NULL ); // Puntero a "no se que" datos (pasamos del tema, es para // aplicaciones MIDI). ShowWindow(IdVentana, SW_SHOW); // Mostramos nuestra ventana. UpdateWindow(IdVentana); // La actualizo para que muestre lo que tenga que mostrar (ahora nada). } // Fin CreaVentana //------------------------------------------------------------------ // Funcion principal de un programa Windows (como main en C normal, aqui WinMain) // el prorama empieza a ejecutarse a partir de esta funcion. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(lpszCmdLine); // Para que no moleste al compilar, no lo usamos. IdAplicacion = hInstance; // Guardo el identificador del programa, luego lo usamos. CreaVentana(); // Funcion que crea la ventana. Definida mas arriba. IniciaGL(); // Funcion para inicializar OpenGL. Definida mas arriba. // Este es el bucle habitual de windows que se esta ejecutando continuamente hasta que recibe // el mensaje de acabar (ya lo hemos preparado en la funcion "ProcesaMensajes" asociada a // la ventana, tambien asociada a este programa atraves de su identificativo). MSG Mensaje; // Varible para contener los mensajes que van llegando. while(TRUE) // Se ejecuta continuamente. { Pinta(); // Funcion que pinta algo y se repite continuamente al estar aqui. if(PeekMessage(&Mensaje, NULL, 0, 0, PM_NOREMOVE)) // Exploramos la cola de mensajes. {// procesándolos adecuadamente if(!GetMessage(&Mensaje, NULL, 0, 0)) return (int)Mensaje.wParam; // En este caso terminamos. TranslateMessage(&Mensaje); DispatchMessage(&Mensaje); } else WaitMessage(); // en caso contrario esperamos un mensaje } } // fin WinMain //------------------------------------------------------------------