Primer commit y entrega

parents
cmake_minimum_required(VERSION 4.0)
project(PAG_p1)
set(CMAKE_CXX_STANDARD 20)
file( GLOB MY_FILES *.cpp )
file( GLOB GLAD_FILES glad/src/*.c )
add_executable(PAG_p1 ${MY_FILES} ${GLAD_FILES})
target_include_directories(PAG_p1 PUBLIC glad/include)
find_package(opengl_system)
find_package(glfw3)
target_link_libraries(PAG_p1 opengl::opengl)
target_link_libraries(PAG_p1 glfw)
\ No newline at end of file
# Solución a la segunda parte de la práctica 1
Por Diego Pérez Peña
Para la asignatura Programación de Aplicaciones Gráficas
La solución que propongo al problema propuesto sería llamar al método de clase `PAG::Renderer::refrescarVentana()` en la función de C llamada `refresh_window_callback()` que tenemos actualmente en el archivo `main.cpp` de nuestro proyecto de C++. Así, estaríamos encapsulando un método incompatible para la orden `glSetWindowRefreshCallback()` dentro de una función compatible como la que ya hemos mencionado.
Se puede ver que funciona perfectamente porque ya la hemos enlazado sin problemas. Al fin y al cabo, la orden `glSetWindowRefreshCallback()` solo requiere que se le pase una función de C compatible pero, más allá de eso, no comprueba el contenido de `refresh_window_callback()`, simplemente llama a su ejecución lo mismo que haría una llamada directa en el código principal, y mientras el entorno de OpenGL/C++ pueda ejecutar su contenido (cosa que evidentemente puede hacer), no debería haber traba alguna.
Para implementar esta solución, deberíamos crear una clase `PAG::Renderer` con, entre otros atributos, el puntero a la ventana `GLFWwindow *window` y el método `refrescarVentana()`, que implementaría el actual método de refresco de ventana, esto es:
``` cpp
void refrescarVentana() {
// Borra el buffer actual
glClear(...);
// Intercambia el buffer actual con el oculto (ya dibujado)
// para la ventana. "window" es el atributo de clase.
glfwSwapBuffers(window);
// El mensaje de salida (prescindible)
std::cout << "Refresh callback called" << std::endl;
}
```
Luego, a la hora de ejecutar el main, se debería crear una instancia del objeto en este entorno. **Nótese** que:
* El objeto debe de ser una instancia global (dentro de un puntero) que se cree dinámicamente y se destruya al terminar el programa.
* La función `refresh_window_callback()` debe poder acceder a este puntero y a su objeto interno, comprobando que este exista, en cuyo caso se llamaría al método.
Dejo aquí un UML detallando el diagrama de clases de la aplicación y el archivo main:
```mermaid
classDiagram
PAG <|-- Renderer
Renderer o-- main
class Renderer {
- window
+ refrescarVentana()
}
class main {
+ yPos
+ renderer
+ error_callback()
+ refresh_window_callback()
+ framebuffer_size_callback()
+ key_callback()
+ mouse_button_callback()
+ scroll_callback()
+ main()
}
```
# This file is managed by Conan, contents will be overwritten.
# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements
requirements:
- "glfw/3.3.8"
- "opengl/system"
\ No newline at end of file
# This file is managed by Conan, contents will be overwritten.
# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements
from conan import ConanFile
from conan.tools.cmake import cmake_layout, CMakeToolchain
class ConanApplication(ConanFile):
package_type = "application"
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeDeps"
def layout(self):
cmake_layout(self)
def generate(self):
tc = CMakeToolchain(self)
tc.user_presets_path = False
tc.generate()
def requirements(self):
requirements = self.conan_data.get('requirements', [])
for requirement in requirements:
self.requires(requirement)
\ No newline at end of file
This diff could not be displayed because it is too large.
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
double* yPos = nullptr;
// - Esta función callback será llamada cuando GLFW produzca algún error
void error_callback(int errno, const char* desc) {
std::string aux(desc);
std::cout << "Error de GLFW número " << errno << ": " << aux << std::endl;
}
// - Esta función callback será llamada cada vez que el área de dibujo
// OpenGL deba ser redibujada.
void refresh_window_callback(GLFWwindow *window) {
// - Borra los buffers (color y profundidad)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// - GLFW usa un doble buffer para que no haya parpadeo. Esta orden
// intercambia el buffer back (en el que se ha estado dibujando) por el
// que se mostraba hasta ahora (front).
glfwSwapBuffers(window);
std::cout << "Refresh callback called" << std::endl;
}
// - Esta función callback será llamada cada vez que se cambie el tamaño
// del área de dibujo OpenGL.
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
glViewport(0, 0, width, height);
std::cout << "Resize callback called" << std::endl;
}
// - Esta función callback será llamada cada vez que se pulse una tecla
// dirigida al área de dibujo OpenGL.
void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
std::cout << "Key callback called" << std::endl;
}
// - Esta función callback será llamada cada vez que se pulse algún botón
// del ratón sobre el área de dibujo OpenGL.
void mouse_button_callback(GLFWwindow *window, int button, int action, int mods) {
if (action == GLFW_PRESS) {
std::cout << "Pulsado el botón " << button << std::endl;
}
else if (action == GLFW_RELEASE) {
std::cout << "Soltado el botón " << button << std::endl;
}
}
// - Esta función callback será llamada cada vez que se mueva la rueda
// del ratón sobre el área de dibujo OpenGL.
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
if (yPos) {
if(((*yPos)+yoffset*0.1) >= 0 && ((*yPos)+yoffset*0.1) <= 1) {
(*yPos) += yoffset*0.1;
}
glClearColor((*yPos), (*yPos), (*yPos), 1.0);
refresh_window_callback(window);
}
std::cout << "Movida la rueda del ratón " << xoffset
<< " unidades en horizontal y " << yoffset
<< " unidades en vertical" << std::endl;
}
int main() {
std::cout << "Starting application PAG - Prueba 01" << std::endl;
glfwSetErrorCallback( (GLFWerrorfun) error_callback );
// - Inicializa GLFW. Es un proceso que sólo debe realizarse una vez en la aplicación
if (glfwInit() != GLFW_TRUE) {
return -1;
}
// - Definimos las características que queremos que tenga el contexto gráfico
// OpenGL de la ventana que vamos a crear. Por ejemplo, el número de muestras o el
// modo Core Profile.
glfwWindowHint ( GLFW_SAMPLES, 4 ); // - Activa antialiasing con 4 muestras.
glfwWindowHint ( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); // - Esta y las 2
glfwWindowHint ( GLFW_CONTEXT_VERSION_MAJOR, 4 ); // siguientes activan un contexto
glfwWindowHint ( GLFW_CONTEXT_VERSION_MINOR, 1 ); // OpenGL Core Profile 4.1.
// - Definimos el puntero para guardar la dirección de la ventana de la aplicación y
// la creamos
GLFWwindow *window;
// - Tamaño, título de la ventana, en ventana y no en pantalla completa,
// sin compartir recursos con otras ventanas.
window = glfwCreateWindow ( 1024, 576, "PAG Introduction", nullptr, nullptr );
// - Comprobamos si la creación de la ventana ha tenido éxito.
if ( window == nullptr ) {
std::cout << "Failed to open GLFW window" << std::endl;
glfwTerminate (); // - Liberamos los recursos que ocupaba GLFW.
return -2;
}
// - Hace que el contexto OpenGL asociado a la ventana que acabamos de crear pase a
// ser el contexto actual de OpenGL para las siguientes llamadas a la biblioteca
glfwMakeContextCurrent ( window );
// - Ahora inicializamos GLAD.
if ( !gladLoadGLLoader ( (GLADloadproc) glfwGetProcAddress ) ) {
std::cout << "GLAD initialization failed" << std::endl;
glfwDestroyWindow ( window ); // - Liberamos los recursos que ocupaba GLFW.
window = nullptr;
glfwTerminate ();
return -3;
}
// - Interrogamos a OpenGL para que nos informe de las propiedades del contexto
// 3D construido.
std::cout << glGetString ( GL_RENDERER ) << std::endl
<< glGetString ( GL_VENDOR ) << std::endl
<< glGetString ( GL_VERSION ) << std::endl
<< glGetString ( GL_SHADING_LANGUAGE_VERSION ) << std::endl;
// - Registramos los callbacks que responderán a los eventos principales
glfwSetWindowRefreshCallback(window, refresh_window_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetKeyCallback(window, key_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetScrollCallback(window, scroll_callback);
// - Establecemos un gris medio como color con el que se borrará el frame buffer.
// No tiene por qué ejecutarse en cada paso por el ciclo de eventos.
glClearColor ( 0.6, 0.6, 0.6, 1.0 );
// - Le decimos a OpenGL que tenga en cuenta la profundidad a la hora de dibujar.
// No tiene por qué ejecutarse en cada paso por el ciclo de eventos.
glEnable ( GL_DEPTH_TEST );
// Inicializamos la variable yPos que controla la posición actual de la rueda del
// ratón para mostrar el color correspondiente
yPos = new double;
(*yPos) = 0.6;
// - Ciclo de eventos de la aplicación. La condición de parada es que la
// ventana principal deba cerrarse. Por ejemplo, si el usuario pulsa el
// botón de cerrar la ventana (la X).
while (!glfwWindowShouldClose(window)) {
// - Obtiene y organiza los eventos pendientes, tales como pulsaciones de
// teclas o de ratón, etc. Siempre al final de cada iteración del ciclo
// de eventos y después de glfwSwapBuffers(window);
glfwPollEvents();
}
// - Una vez terminado el ciclo de eventos, liberar recursos, etc.
std::cout << "Finishing application pag prueba" << std::endl;
// Liberamos el puntero yPos
if (yPos) {
delete yPos;
yPos = nullptr;
}
glfwDestroyWindow ( window ); // - Cerramos y destruimos la ventana de la aplicación.
window = nullptr;
glfwTerminate (); // - Liberamos los recursos que ocupaba GLFW.
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment