|
Grado en Ingeniería Informática
Realidad Virtual
Curso 2023/2024
|
Práctica 1
|
|
OpenGL sobre MS-Windows
|
|
Objetivos
|
|
El objetivo de esta práctica es construir la estructura básica de un
programa basado en OpenGL sobre MS-Windows de manera que en las prácticas
siguientes podamos centrarnos estrictamente en las características de OpenGL y no
en las características de la plataforma que estamos utilizando.
Para ello utilizaremos una biblioteca de manejo de ventanas llamada
GLFW con la que construiremos la ventana principal de la aplicación.
Esta biblioteca nos permite configurar las respuestas a diferentes
eventos de la ventana y utilizar OpenGL sobre el contexto gráfico de
la ventana.
|
|
OpenGL
|
|
OpenGL no es un lenguaje de programación, sino una biblioteca de funciones
escritas en C dedicadas a la generación de gráficos. Aunque existe una implementación
genérica de OpenGL sobre MS-Windows (que desarrolla el conjunto de funciones
de la biblioteca por medio de software), esta implementación genérica no ha sido
actualizada desde la versión 1.1 de OpenGL. En la práctica, la versión de OpenGL
que se utiliza realmente es la que se distribuye como driver de la tarjeta gráfica. Esta
biblioteca se denomina opengl32.dll y se encuentra en el directorio C:\Windows\System32\
junto al resto de librerías del sistema. Se trata de una librería que se
enlaza dinámicamente a todas las aplicaciones programadas con OpenGL.
El contenido de la biblioteca opengl32.dll depende de cada fabricante. En algunos
casos, cuando una determinada tarjeta gráfica no contiene algún proceso de aceleración
gráfica incluido en la especificación de OpenGL, el fabricante lo suple con una
implementación software de dicho proceso. Además, los fabricantes suelen incluir
sus propias opciones de aceleración que no se encuentran en el estándar de OpenGL.
La biblioteca contiene funciones para verificar si una cierta característica está soportada
o no por el driver suministrado por el fabricante. Normalmente los programas
basados en OpenGL suelen estudiar estas características e intentan aprovechar al
máximo las capacidades de las tarjetas.
La primera versión de OpenGL (OpenGL 1.0) fue presentada en 1992. Desde entonces
se han presentado numerosas versiones que han ido ampliando el estándar. Hasta
el momento, las versiones oficiales de OpenGL han sido las siguientes:1.0, 1.1,
1.2, 1.2.1, 1.3, 1.4, 1.5, 2.0, 2.1, 3.0, 3.1, 3.2, 3.3, 4.0, 4.1, 4.2, 4.3,
4.4, 4.5 y 4.6. Esta variedad de versiones provoca un problema a la hora de compilar
los proyectos desarrollados en OpenGL. Aunque en tiempo de ejecución la
aplicación se enlace dinámicamente con la biblioteca opengl32.dll
desarrollada por el fabricante de la tarjeta gráfica, pueden aparecer conflictos
si la versión utilizada en tiempo de compilación es diferente de la usada en
tiempo de ejecución. Para evitar estos problemas se suele utilizar la librería
OpenGL Extension Wrangler Library (GLEW). Se trata de una librería multiplataforma
escrita en C/C++, destinada a ayudar en la carga y consulta de extensiones de OpenGL.
La librería GLEW incluye métodos eficientes, en tiempo de ejecución, para determinar
qué extensiones de OpenGL son soportadas. Todas las extensiones de OpenGL son listadas
en un solo archivo de cabecera, que se genera automáticamente respecto la lista oficial
de extensiones.
Un aspecto fundamental de OpenGL es que no pretende ser un window manager.
Esto quiere decir que no contiene funciones de manejo de ventanas (creación, configuración,
etc) ni de control de eventos de la interfaz de usuario (control de teclado,
ratón, sonido) ni de interfaz de entrada/salida (acceso a ficheros, directorios, ...).
Corresponde al sistema operativo nativo la gestión de las ventanas y de estos eventos.
Las funciones incluidas en OpenGL se limitan a trabajar sobre un contexto gráfico
que permita dirigir las imágenes creadas por la tarjeta gráfica a un área determinada
de una ventana controlada por el sistema operativo nativo.
Para crear y manejar los aspectos de la ventana se suele utilizar
alguna biblioteca que permita trabajar con ventanas de una forma más
sencilla. Existen varias bibilotecas de este tipo, como GLUT,
FreeGLUT, CPW, FLTK, SDL o GLFW (la página oficial de OpenGL ofrece
un listado de estas bibliotecas). En estas prácticas vamos
a utilizar la biblioteca GLFW que hemos incluido en el directorio
\ComputerGraphics\Tools.
La programación gráfica requiere trabajar tanto sobre el procesador
principal (CPU) como sobre los procesadores de la tarjeta gráfica
(GPU). La programación de la tarjeta gráfica se realiza en un
lenguaje de programación denominado GLSL que utiliza un conjunto de
tipos de datos propio que incluye tipos de datos vectoriales y
matriciales, así como un conjunto de funciones predefinidas. Resulta
bastante útil realizar cálculos con estos tipos de datos en la CPU.
Para facilitar esto se utiliza la biblioteca GLM, que define sobre
C/C++ los tipos de datos utilizados en GLSL así como numerosas
funciones y operadores asociados a estos tipos de datos. La
biblioteca GLM también se ha incluido en el directorio
\ComputerGraphics\Tools.
Otra biblioteca incluida en el código de las prácticas es FreeImage.
Se trata de una biblioteca dedicada al tratamiento de imágenes que
utilizaremos a lo largo de las prácticas para cargar las texturas en
nuestras aplicaciones. Esta biblioteca se ha incluido también en el
directorio \ComputerGraphics\Tools.
|
|
Creación de un proyecto de aplicación gráfica
|
|
A lo largo de estas prácticas vamos a utilizar VisualStudio 2019
como entorno de desarrollo de aplicaciones gráficas para MS-Windows.
El primer paso para crear la aplicación es crear un nuevo proyecto
en lenguaje C++. La siguiente figura muestra la ventana de creación
del nuevo proyecto. Seleccionaremos la plantilla para la creación de
un proyecto vacío.
Al aceptar la plantilla se abre una ventana para seleccionar el
nombre del proyecto y el directorio de trabajo.
La plantilla de proyecto seleccionada no contiene ningún archivo de
código inicial. El primer paso va a ser crear un primer archivo de
código. Para eso hay que seleccionar el menú sobre la carpeta de
archivos de orígen (botón derecho) y seleccionar la opción de
agregar un nuevo elemento.
El primer fichero de código que vamos a añadir es el fichero "main.cpp"
donde incluiremos la función main de entrada de la aplicación..
Para poder utilizar
OpenGL y otras bibliotecas auxiliares, como FreeImage, GLFW
y GLM, es necesario realizar algunas modificaciones a las propieades
del proyecto. Las bibliotecas auxiliares se han incluido en el
código de la práctica en el directorio
C:\ComputerGraphics\Tools\.
Las propiedades del proyecto se configuran en la última opción del
menú Proyecto. Es importante que en la ventana de configuración se
seleccione "Todas las configuraciones" y "Todas las
plataformas" para la configuración se aplique a cualquier
plataforma a la que vayamos a compilar.
El primer paso es añadir los
directorios adecuados como directorios de archivos de inclusión (que
se utilizan para buscar los archivos indicados por las macros
#include) y directorios de archivos de bibliotecas (donde se
buscarán los ficheros .dll de estas herramientas).
Para añadir los directorios de inclusión de estas herramientas se
selecciona la opción "General" dentro del grupo de propiedades de
C/C++ y se pulsa en "<Editar>" sobre el campo "Directorios de
inclusión adicionales".
Los directorios de inclusión a añadir corresponden a las carpetas
Include de las herramientas GLEW, GLFW, GLM y FreeImage.
Para añadir los directorios de
bibliotecas de estas herramientas se
selecciona la opción "General" dentro del grupo de propiedades del
vinculador y se pulsa en "<Editar>" sobre el campo "Directorios de
bibliotecas adicionales".
Los directorios de bibliotecas a añadir corresponden a la
carpeta lib-vc2019 de la herramienta GLFW y la carpeta
Lib de la biblioteca FreeImage y la carpeta
lib\Release\x64 de la biblioteca GLEW. La biblioteca GLM se
distribuye como código fuente y solo requiere adaptar el directorio
de inclusión.
El siguiente paso consiste en indicar que nuestra aplicación va a utilizar las
bibliotecas de OpenGL (opengl32.dll), GLEW (glew32.dll),
FreeImage (FreeImage.dll) y de GLFW (glfw3.dll). Para ello es necesario expandir la opción Entrada dentro del
grupo de propiedades de vinculador y pulsar en "<Editar>" sobre el campo
Dependencias adicionales como muestra la siguiente figura.
En la ventana de edición de dependencias adicionales hay que añadir
las librerías "opengl32.lib", "glew32.lib",
"FreeImage.lib" y "glfw3.lib".
Para terminar la configuración del proyecto hay que indicar que la
versión del lenguaje a utilizar es el estándar ISO C++17. Esta
versión se define en la opción Idioma del grupo de propiedades de
C/C++, seleccionando esta versión en el campo Estándar de
lenguaje C++.
Por último es importante seleccionar la
plataforma x64 como plataforma de compilación del proyecto.
|
|
La biblioteca GLEW
|
|
La biblioteca GLEW desarrolla una pasarela para utilizar las
funciones de OpenGL adaptandose a la versión utilizada en
tiempo de ejecución de forma transparente para el programador.
Para utilizar en nuestro código las funciones de OpenGL debemos
incluir el fichero de cabecera GL\glew.h.
Para inicializar la biblioteca es necesario ejecutar el método
glewInit() después de crear la ventana y el contexto gráfico
sobre el que trabajarán las funciones de OpenGL.
Para distribuir las aplicaciones gráficas generadas con GLEW es
necesario incluir en la distribución el fichero glew.dll
que debe encontrarse en el directorio de ejecución de la aplicación.
|
|
La biblioteca GLFW
|
|
GLFW es una biblioteca de código abierto dedicada a la gestión de
ventanas con soporte para OpenGL, OpenGL ES y Vulkan. Se trata de
una biblioteca escrita en C adaptada a múltiples plataformas
(MS-Windows, MacOS, X11, Wayland). Las funciones de la biblioteca
dan soporte a múltiples ventanas, monitores y eventos de teclado,
ratón, joystick e incluso mando de consolas.
La web oficial de la biblioteca es
https://www.glfw.org/. En esta página se puede encontrar toda la
documentación de la biblioteca así como la zona de descarga. Para el
desarrollo de estas prácticas se ha incluido ya la distribución de
GLFW en el directorio
\ComputerGraphics\Tools.
Para utilizar GLFW hay que comenzar ejecutando la función
glfwInit(). Al terminar la aplicación debe ejecutarse
glfwTerminate() para liberar todos los recursos que pueda
haberse creado. La biblioteca define la estructura GLFWwindow
para describir las ventanas. Para crear una ventana se utiliza la
función glfwCreateWindow() y para destruirla se usa
glfwDestroyWindow(). Para que las funciones de OpenGL utilicen
el contexto gráfico de la ventana se utiliza la función
glfwMakeContextCurrent().
Las respuestas a los distintos eventos se configura por medio de
punteros a funciones. La respuesta al evento de modificación del
tamaño de la ventana se configura con la función
glfwSetFramebufferSizeCallback(). La respuesta a los eventos de
teclado se asigna con la función glfwSetKeyCallback(). La
respuesta a los movimientos del ratón se indica por medio de la
función glfwSetCursorPosCallback(). La respuesta a los
botones del ratón se asigna con la función
glfwSetMouseButtonCallback().
Típicamente las funciones de respuesta a eventos deben acceder a la
información de la aplicación que ha creado la ventana. Para ello se
utiliza la función glfwSetWindowUserPointer() que
permite almacenar una referencia a un objeto de cualquier tipo, lo
que permite acceder posteriormente a este objeto por medio de la
función glfwGetWindowUserPointer().
La biblioteca GLFW permite también utilizar ventanas a
pantalla completa. Para ello es necesario utilizar la función
glfwSetWindowMonitor(), que debe incluir la referencia al
monitor, el modo de vídeo utilizado, la posición y el tamaño de la
ventana. El monitor puede obtenerse mediante la función
glfwGetPrimaryMonitor(). El modo de vídeo utilizado en el
monitor se obtiene con la función glfwGetVideoMode(). La
posición y tamaño de una ventana se obtiene con las funciones
glfwGetWindowSize() y glfwGetWindowPos(). Para usar
una ventana normal se puede llamar a la función
glfwSetWindowMonitor() con los parámetros de monitor y modo de
vídeo a nulo, lo que asigna los valores por defecto. Para crear la
ventana a pantalla completa es necesario indicar tanto el monitor
como el modo de vídeo, así como el tamaño de la pantalla.
|
|
Generación de la aplicación gráfica
|
|
Una vez configurado el proyecto vamos a comenzar a desarrollar el
código de la aplicación. El primer paso es programar la función
principal, incluida en el fichero main.cpp.
#include "CGApplication.h"
#include <iostream>
#include <stdexcept>
//
//// PROYECTO: Project1
//// DESCRIPCIÓN: Creación de una ventana con GLFW y un modelo básico
// con las respuestas a los eventos de la ventana.
//
int main()
{
CGApplication app;
try
{
app.run();
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
|
El código que vamos a desarrollar se basa inicialmente en dos
clases. La clase CGApplication es la clase principal de la
aplicación y contienen un método run() que ejecutará la
aplicación completa. Los miembros privados de esta clase contienen
los métodos y campos necesarios para configurar el proceso de
representación gráfica sobre una
ventana creada con GLFW. La clase CGModel desarrolla el
modelo gráfico y contiene métodos para inicializar el modelo,
actualizarlo y modificarlo como respuestas a los eventos de teclado
o ratón.
|
|
La clase CGApplication
|
|
La clase CGApplication es la encargada de crear y gestionar
la ventana sobre la que generaremos los gráficos. Los campos
window y model permiten almacenar la referencia a la
ventana y al modelo gráfico. Los campos windowWidth,
windowHeight, windowXpos y windowYpos indican
el tamaño y la posición de la ventana. El campo fullScreen
indica si la ventana se está mostrando a pantalla completa. El campo limitFPS contiene la
frecuencia de muestreo utilizada (frames per second). Los
campos lastTime y deltaTime se usan para generar
esa frecuencia de muestreo. A continuación se muestra la declaración
de esta clase.
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "CGModel.h"
class CGApplication
{
public:
void run();
private:
GLFWwindow* window;
int windowWidth;
int windowHeight;
int windowXpos;
int windowYpos;
bool fullScreen;
CGModel model;
double limitFPS;
double lastTime;
double deltaTime;
// Métodos principales
void initWindow();
void initOpenGL();
void initModel();
void mainLoop();
void timing();
void cleanup();
void swapFullScreen();
// Respuesta a eventos
static void keyCallback(GLFWwindow* window, int key, int scan, int act, int mods);
static void mouseButtonCallback(GLFWwindow* window, int bt, int action, int mods);
static void cursorPositionCallback(GLFWwindow* window, double xpos, double ypos);
static void framebufferResizeCallback(GLFWwindow* window, int width, int height);
};
|
La clase CGApplication tiene un único método público
llamado run() que es el encargado de ejecutar la
aplicación. Este método consiste en inicializar la aplicación y
quedarse en un bucle de gestión de eventos de la ventana hasta
recibir la orden de cierre de la aplicación. El método
initWindow() es el encargado de crear y configurar la ventana
por medio de las funciones de la biblioteca GLFW. El método
initOpenGL() inicializa la biblioteca GLEW para poder comenzar
a utilizar las funciones de OpenGL. El método initModel()
se encarga de inicializar los campos de control de muestreo y de
crear el modelo gráfico. El método mainLoop() es el bucle
principal de la aplicación y consiste en un bucle infinito encargado
de recibir y gestionar los eventos de la ventana y actualizar y
mostrar la representación gráfica. El método timing() es el
encargado de la temporización del modelo gráfico. Ejecuta la
actualización del modelo en la tasa de muestreo indicada en
limitFPS y lanza la representación del modelo gráfico. El
método cleanup() se ejecuta al cierre de la aplicación y
consiste en liberar el modelo gráfico y la ventana de ejecución. El
método swapFullScreen() cambia el modo entre pantalla
completa o ventana normal y se lanza al pulsar en la tecla F12. Los
métodos Callback() son los encargados de dar respuesta a
los diferentes eventos de la ventana. Para ello se almacena en la
ventana una referencia al objeto CGApplication que se puede
obtener mediante la función glfwGetWindowUserPointer().
#include "CGApplication.h"
//
// FUNCIÓN: CGApplication::run()
//
// PROPÓSITO: Ejecuta la aplicación
//
void CGApplication::run()
{
initWindow();
initOpenGL();
initModel();
mainLoop();
cleanup();
}
//
// FUNCIÓN: CGApplication::initWindow()
//
// PROPÓSITO: Inicializa la ventana
//
void CGApplication::initWindow()
{
glfwInit();
windowWidth = 800;
windowHeight = 600;
fullScreen = false;
window = glfwCreateWindow(windowWidth, windowHeight, "Computer Graphics",
nullptr, nullptr);
glfwSetWindowUserPointer(window, this);
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
glfwSetKeyCallback(window, keyCallback);
glfwSetCursorPosCallback(window, cursorPositionCallback);
glfwSetMouseButtonCallback(window, mouseButtonCallback);
glfwMakeContextCurrent(window);
}
//
// FUNCIÓN: CGApplication::initOpenGL()
//
// PROPÓSITO: Inicializa el entorno gráfico
//
void CGApplication::initOpenGL()
{
glewInit();
}
//
// FUNCIÓN: CGApplication::initModel()
//
// PROPÓSITO: Inicializa el modelo
//
void CGApplication::initModel()
{
limitFPS = 1.0 / 60.0;
lastTime = glfwGetTime();
deltaTime = 0;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
model.initialize(width, height);
}
//
// FUNCIÓN: CGApplication::mainLoop()
//
// PROPÓSITO: Bucle principal que procesa los eventos de la aplicación
//
void CGApplication::mainLoop()
{
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
timing();
glfwSwapBuffers(window);
}
}
//
// FUNCIÓN: CGApplication::timing()
//
// PROPÓSITO: Renderizado
//
void CGApplication::timing()
{
double nowTime = glfwGetTime();
deltaTime += (nowTime - lastTime) / limitFPS;
lastTime = nowTime;
while (deltaTime >= 1.0)
{
model.update();
deltaTime--;
}
model.render();
}
//
// FUNCIÓN: CGApplication::cleanup()
//
// PROPÓSITO: Libera los recursos y finaliza la aplicación
//
void CGApplication::cleanup()
{
model.finalize();
glfwDestroyWindow(window);
glfwTerminate();
}
//
// FUNCIÓN: CGApplication::swapFullScreen()
//
// PROPÓSITO: Dibuja la ventana a pantalla completa o a tamaño configurable
//
void CGApplication::swapFullScreen()
{
if (!fullScreen)
{
glfwGetWindowSize(window, &windowWidth, &windowHeight);
glfwGetWindowPos(window, &windowXpos, &windowYpos);
fullScreen = true;
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height,
mode->refreshRate);
}
else
{
fullScreen = false;
glfwSetWindowMonitor(window, nullptr, windowXpos, windowYpos,
windowWidth, windowHeight, nullptr);
}
}
//
// FUNCIÓN: CGApplication::keyCallback(GLFWwindow* window, int key, int scancode,
// int action, int mods)
//
// PROPÓSITO: Respuesta a un evento de teclado sobre la aplicación
//
void CGApplication::keyCallback(GLFWwindow* window, int key, int scancode,
int action, int mods)
{
auto app = reinterpret_cast<CGApplication*>(glfwGetWindowUserPointer(window));
if (action == GLFW_PRESS || action == GLFW_REPEAT)
{
if (key == GLFW_KEY_F12) app->swapFullScreen();
else app->model.key_pressed(key);
}
}
//
// FUNCIÓN: CAApplication::mouseButtonCallback(GLFWwindow* window, int button,
// int action, int mods)
//
// PROPÓSITO: Respuesta a un evento de ratón sobre la aplicación
//
void CGApplication::mouseButtonCallback(GLFWwindow* window, int button,
int action, int mods)
{
auto app = reinterpret_cast<CGApplication*>(glfwGetWindowUserPointer(window));
app->model.mouse_button(button, action);
}
//
// FUNCIÓN: CGApplication::cursorPositionCallback(GLFWwindow* window, double xpos,
// double ypos)
//
// PROPÓSITO: Respuesta a un evento de movimiento del cursor sobre la aplicación
//
void CGApplication::cursorPositionCallback(GLFWwindow* window, double xpos,
double ypos)
{
auto app = reinterpret_cast<CGApplication*>(glfwGetWindowUserPointer(window));
app->model.mouse_move(xpos, ypos);
}
//
// FUNCIÓN: CGApplication::framebufferResizeCallback(GLFWwindow* window, int width,
// int height)
//
// PROPÓSITO: Respuesta a un evento de redimensionamiento de la ventana principal
//
void CGApplication::framebufferResizeCallback(GLFWwindow* window, int width,
int height)
{
auto app = reinterpret_cast<CGApplication*>(glfwGetWindowUserPointer(window));
if (height != 0) app->model.resize(width, height);
}
|
|
|
La clase CGModel
|
|
La clase CGModel contiene la descripción del modelo
gráfico. En las próximas prácticas esta clase se irá modificando
para añadir la proramación gráfica usando OpenGL. En este caso vamos
a desarrollar un modelo muy sencillo que tan solo va a utilizar tres
funciones básicas de OpenGL. La función glViewport()
establece el tamaño de la imagen a generar que debe coincidir con el
tamaño del área de dibujo de la ventana. La función glClear()
borra toda la imagen utilizando un color de borrado que se puede
asignar mediante la función glClearColor(). A continuación
se muestra el contenido de cabecera para la clase.
#pragma once
#include <GL/glew.h>
class CGModel
{
public:
void initialize(int w, int h);
void finalize();
void render();
void update();
void key_pressed(int key);
void mouse_button(int button, int action);
void mouse_move(double xpos, double ypos);
void resize(int w, int h);
};
|
El cuerpo de los métodos de la clase CGModel se incluye en
el fichero CGModel.cpp que se muestra a continuación. El
método initialize() asigna a blanco el color de fondo y
llama al método resize() que se encarga de establecer el
tamaño de la imagen. El método render() es el encargado de
lanzar el proceso de dibujo y se limita a limpiar la imagen con el
color de fondo establecido. El método key_pressed() es la
respuesta a los eventos de teclado y analiza la tecla pulsada para
modificar el color de fondo. El resto de métodos no tienen contenido
en este ejemplo.
#include "CGModel.h"
#include <GLFW\glfw3.h>
#include <iostream>
//
// FUNCIÓN: CGModel::initialize(int, int)
//
// PROPÓSITO: Initializa el modelo 3D
//
void CGModel::initialize(int w, int h)
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
resize(w, h);
}
//
// FUNCIÓN: CGModel::finalize()
//
// PROPÓSITO: Libera los recursos del modelo 3D
//
void CGModel::finalize()
{
}
//
// FUNCIÓN: CGModel::resize(int w, int h)
//
// PROPÓSITO: Asigna el viewport y el clipping volume
//
void CGModel::resize(int w, int h)
{
glViewport(0, 0, w, h);
}
//
// FUNCIÓN: CGModel::render()
//
// PROPÓSITO: Genera la imagen
//
void CGModel::render()
{
glClear(GL_COLOR_BUFFER_BIT);
}
//
// FUNCIÓN: CGModel::update()
//
// PROPÓSITO: Anima la escena
//
void CGModel::update()
{
}
//
// FUNCIÓN: CGModel::key_pressed(int)
//
// PROPÓSITO: Respuesta a acciones de teclado
//
void CGModel::key_pressed(int key)
{
switch (key)
{
case GLFW_KEY_R:
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
break;
case GLFW_KEY_G:
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
break;
case GLFW_KEY_B:
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
break;
case GLFW_KEY_W:
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
break;
}
}
//
// FUNCIÓN: CGModel:::mouse_button(int button, int action)
//
// PROPÓSITO: Respuesta del modelo a un click del ratón.
//
void CGModel::mouse_button(int button, int action)
{
}
//
// FUNCIÓN: CGModel::mouse_move(double xpos, double ypos)
//
// PROPÓSITO: Respuesta del modelo a un movimiento del ratón.
//
void CGModel::mouse_move(double xpos, double ypos)
{
}
|
|
|
Aspecto final
|
|
Una vez generado los ficheros anteriores la aplicación puede ser compilada y ejecutada.
Es importante tener en cuenta que la aplicación contiene llamadas a la librería glew.dll
que no se encuenta por defecto en el sistema. Para evitar errores de
ejecución es importante copiar esta librería en el directorio del
ejecutable de la aplicación. A continuación se muestra el aspecto de
la ventana principal de la aplicación.
El color de la ventana se modifica al pulsar sobre las teclas R
(rojo), G (verde), B (azul) y W (blanco).
|
|