From 72524997ef7c7f98e1163ca20bc56fa0f7db198c Mon Sep 17 00:00:00 2001 From: lhark Date: Sun, 26 Nov 2017 00:47:29 -0500 Subject: [PATCH] Add FBO and util implementation --- FBO.cpp | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ FBO.h | 66 ++++++++++++++++ util.cpp | 141 ++++++++++++++++++++++++++++++++++ util.h | 18 +++++ 4 files changed, 449 insertions(+) create mode 100644 FBO.cpp create mode 100644 FBO.h create mode 100644 util.cpp create mode 100644 util.h diff --git a/FBO.cpp b/FBO.cpp new file mode 100644 index 0000000..99c01dd --- /dev/null +++ b/FBO.cpp @@ -0,0 +1,224 @@ +/////////////////////////////////////////////////////////////////////////////// +/// @file FBO.cpp +/// @author Olivier Dionne +/// @brief Définit la classe FBO implémentant un Frame Buffer Object simple +/// pour openGL +/// @date 2008-10-19 +/// @version 1.0 +/// +/////////////////////////////////////////////////////////////////////////////// +#include "FBO.h" + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////// +/// public overloaded constructor FBO \n +/// +/// Crée un FBO très simple où tous les membres privés sont à 0. +/// +/// @return Aucune +/// +/// @author Olivier Dionne +/// @date 2008-10-19 +/// +/////////////////////////////////////////////////////////////////////////////// +FBO::FBO() : +m_FBO( 0 ), +m_Texture( 0 ), +m_InternalFormat( 0 ), +m_Target( GL_TEXTURE_2D ), +m_TextureW( 0 ), +m_TextureH( 0 ) +{ +} + +/////////////////////////////////////////////////////////////////////////////// +/// public destructor ~FBO \n +/// +/// Détruit un objet FBO +/// +/// @return Aucune +/// +/// @author Olivier Dionne +/// @date 2008-10-19 +/// +/////////////////////////////////////////////////////////////////////////////// +FBO::~FBO() +{ + Liberer(); +} + + +/////////////////////////////////////////////////////////////////////////////// +/// public Init \n +/// +/// Cette méthode initialise le FBO en créant les noms de texture à l'interne. +/// Pour une mise à jour du FBO à chaque image, cette fonction NE DEVRAIT PAS +/// être appelée constamment, parce qu'elle consomme de la mémoire et est +/// relativement lente. On conseille donc d'appeler Init() une seule fois au début +/// de l'application, puis simplement d'utiliser la paire CommencerCapture() et +/// TerminerCapture() afin de mettre à jour le contenu interne du FBO en tout temps. +/// Évidemment, parce qu'il est important que la taille du FBO soit la même que le +/// viewport courant, si la taille du viewport change en cours d'exécution, il est +/// impératif d'appeler Init() à nouveau (avec les nouvelles valeurs de w et de h), mais +/// en ayant pris soin au préalable de LIBERER la mémoire du FBO. +/// +/// @param [in] w int La largeur du viewport / de la texture interne +/// @param [in] h int La hauteur du viewport / de la texture interne +/// @param [in] format int Le format interne de la texture du FBO (communément GL_RGB) +/// +/// @return Aucune +/// +/// @author Olivier Dionne +/// @date 2008-10-19 +/// +/////////////////////////////////////////////////////////////////////////////// +void FBO::Init( int w, int h ) +{ + // Dimensions + m_TextureW = w; + m_TextureH = h; + + // TODO: Remplir la fonction d'initialisation d'un FBO: + + // Créer et lier un nouveau frame buffer avec l'ID m_fbo: + glGenFramebuffers(1, &m_FBO); + glBindFramebuffer(GL_FRAMEBUFFER, m_FBO); + + // Créer une texture RGB pour les couleurs avec L'ID m_Texture: + // Pour échantillionner plus tard des valeurs exactes + // on veut des filtres de mignification et magnification de tpe NEAREST! + glGenTextures(1, &m_Texture); + glBindTexture(m_Target, m_Texture); + glTexParameteri(m_Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(m_Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(m_Target, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + // Créer une texture de profondeurs pour les couleurs avec L'ID m_Profondeur: + glGenTextures(1, &m_Profondeur); + glBindTexture(m_Target, m_Profondeur); + glTexParameteri(m_Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(m_Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(m_Target, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + + + // Attacher nos deux textures au frame buffer à des fin d'affichage (DRAW): + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_Target, m_Texture, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_Target, m_Profondeur, 0); + + // Vérification des erreurs FBO + // Nous vous fournissons cette vérification d'erreurs + // pour que vous arriviez plus aisément à déboguer votre code. + GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER ); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // On vérifie les erreurs à la suite de la création du FBO + switch( status ) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + cerr << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT" << endl; + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + cerr << "GL_FRAMEBUFFER_UNSUPPORTED_EXT" << endl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + cerr << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT" << endl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + cerr << "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT" << endl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + cerr << "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT" << endl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + cerr << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT" << endl; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + cerr << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT" << endl; + break; + default: + cerr << "ERREUR INCONNUE" << endl; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/// public Liberer \n +/// +/// Cette fonction libère l'espace mémoire interne du FBO +/// +/// @return Aucune +/// +/// @author Olivier Dionne +/// @date 2008-10-19 +/// +/////////////////////////////////////////////////////////////////////////////// +void FBO::Liberer() +{ + if ( m_Texture ) + { + glDeleteTextures( 1, &m_Texture ); + m_Texture = 0; + } + + if ( m_FBO ) + { + glDeleteFramebuffers( 1, &m_FBO ); + m_FBO = 0; + } + if(m_Profondeur) + { + glDeleteTextures( 1, &m_Profondeur ); + m_Profondeur = 0; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/// public CommencerCapture \n +/// +/// Cette fonction débute la définition du contenu du FBO. Son utilisation est +/// très simple et intuitive. Une fois le FBO construit et initialiser avec new () +/// et Init(), on n'a qu'à insérer les commandes openGL produisant le rendu externe +/// voulu (qui sera enregistré dans le FBO) entre les commandes CommencerCapture() et +/// TerminerCapture(); +/// +/// @return Aucune +/// +/// @author Olivier Dionne, Frédéric Plourde +/// @date 2008-10-19 +/// +/////////////////////////////////////////////////////////////////////////////// +void FBO::CommencerCapture() +{ + // TODO: + // Activer l'utilisation du FBO + // Attention à la résolution avec laquelle on veut afficher! + glBindFramebuffer(GL_FRAMEBUFFER, m_FBO); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glPushAttrib(GL_VIEWPORT_BIT); + glViewport(0,0,m_TextureW, m_TextureH); +} + +/////////////////////////////////////////////////////////////////////////////// +/// public TerminerCapture \n +/// +/// Cette fonction termine la définition du contenu du FBO. Son utilisation est +/// très simple et intuitive. Une fois le FBO construit et initialiser avec new () +/// et Init(), on n'a qu'à insérer les commandes openGL produisant le rendu externe +/// voulu (qui sera enregistré dans le FBO) entre les commandes CommencerCapture() et +/// TerminerCapture(); +/// +/// @return Aucune +/// +/// @author Olivier Dionne +/// @date 2008-10-19 +/// +/////////////////////////////////////////////////////////////////////////////// +void FBO::TerminerCapture() +{ + // TODO: + // Remettre OpenGL dans l'état par défaut + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glPopAttrib(); +} diff --git a/FBO.h b/FBO.h new file mode 100644 index 0000000..9bb0ca9 --- /dev/null +++ b/FBO.h @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +/// @file FBO.h +/// @author Olivier Dionne +/// @brief Déclare une classe implémentant un "frame buffer object" +/// @date 2008-10-19 +/// @version 1.0 +/// +/////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +/// @class FBO +/// @brief Cette classe encapsule un FBO (Frame Buffer Object) openGL +/// +/// @author Olivier Dionne +/// @date 2008-10-19 +/// +/////////////////////////////////////////////////////////////////////////////// +class FBO +{ +public: + /// Constructeur par défaut + FBO(); + /// destructeur par défaut + ~FBO(); + + /// Initialise le FBO et crée une texture de rendu pour RGB et pour DepthBuffer + void Init( int w, int h ); + + /// Libère la mémoire openGL + void Liberer(); + /// Commencement de la capture des instruction openGL réalisant le contenu du FBO + void CommencerCapture(); + /// fin de la description du contenu du FBO + void TerminerCapture(); + /// Retourne la largeur de la texture + inline int GetWidth() const { return m_TextureW; } + /// Retourne la hauteur de la texture + inline int GetHeight() const { return m_TextureH; } + /// Retourne l'ID de texture de couleur + inline GLuint GetRGBTex() const { return m_Texture; } + /// Retourne la hauteur de la texture + inline GLuint GetDepthTex() const { return m_Profondeur; } + +private: + + /// l'ID du FBO + GLuint m_FBO; + /// l'ID de la texture RGB + GLuint m_Texture; + /// l'ID de la texture profondeur + GLuint m_Profondeur; + /// le format interne (communément GL_RGB) + GLint m_InternalFormat; + /// la cible de la texture (communément GL_TEXTURE2D) + GLenum m_Target; + + /// la largeur de la texture + int m_TextureW; + /// la hauteur de la texture + int m_TextureH; +}; + diff --git a/util.cpp b/util.cpp new file mode 100644 index 0000000..49fa815 --- /dev/null +++ b/util.cpp @@ -0,0 +1,141 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include + +#include "util.h" + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} + +void +infogl(const int verbose) +{ +#define PBYTE(CHAINE) ( (CHAINE) != NULL ? (CHAINE) : (const GLubyte *) "????" ) +#define PCHAR(CHAINE) ( (CHAINE) != NULL ? (CHAINE) : (const char *) "????" ) + SDL_version linked; + SDL_GetVersion( &linked ); + printf("// SDL %u.%u.%u\n", linked.major, linked.minor, linked.patch); + + printf("// OpenGL %s%s\n", PBYTE(glGetString(GL_VERSION)), PBYTE(glGetString(GL_VENDOR))); + printf("// GPU %s\n", PBYTE(glGetString(GL_RENDERER))); + printf("// GLSL %s\n", PBYTE(glGetString(GL_SHADING_LANGUAGE_VERSION))); + + if (verbose) + printf("// extensions = %s\n", PBYTE(glGetString(GL_EXTENSIONS))); +#undef PBYTE +#undef PCHAR +} + +void +sdldie(const char *msg) +{ + fprintf(stderr, "sdldie: %s: %s\n",msg, SDL_GetError()); + SDL_Quit(); + exit(1); +} + +void +sdlerrcheck(int line) +{ + const char *sdlerror = SDL_GetError(); + if ( *sdlerror != '\0' ) + { + fprintf(stderr,"SDL Error: l.%d: %s\n",line, sdlerror); + SDL_ClearError(); + } +} + +int +checkglerr(const char *msg, const int line) +{ + const char *errors[7] = { + "GL_INVALID_ENUM", + "GL_INVALID_VALUE", + "GL_INVALID_OPERATION", + "GL_STACK_OVERFLOW", + "GL_STACK_UNDERFLOW", + "GL_OUT_OF_MEMORY", + "GL_INVALID_FRAMEBUFFER_OPERATION", + }; + int rc = 0; + GLenum err; + while ((err = glGetError()) != GL_NO_ERROR) + { + if (err >= GL_INVALID_ENUM && err <= GL_INVALID_FRAMEBUFFER_OPERATION) + fprintf(stderr, "%s l.%d\n", errors[err - GL_INVALID_ENUM], line); + else + fprintf(stderr, "Unknown error l.%d\n", line); + ++rc; + } + return rc; +} + +void +printcomplog(GLuint shaderobj) +{ + int logl; + char *log; + + glGetShaderiv(shaderobj, GL_INFO_LOG_LENGTH, &logl); + if (logl > 0) { + log = (char*)malloc(sizeof(char) * logl); + if (!log) + die("Cannot allocate %d bytes for shader log\n", logl); + glGetShaderInfoLog(shaderobj, logl, NULL, log); + fprintf(stderr, "\n%s\n", log); + free(log); + } +} + +void +printprogramlog(GLuint prog) +{ + int logl; + char *log; + + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logl); + if (logl > 0) { + log = (char*)malloc(sizeof(char) * logl); + if (!log) + die("Cannot allocate %d bytes for program log\n", logl); + glGetProgramInfoLog(prog, logl, NULL, log); + fprintf(stderr, "\n%s\n", log); + free(log); + } +} + +void +debugcallback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +{ + printf("%s\n", message); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..8ab0998 --- /dev/null +++ b/util.h @@ -0,0 +1,18 @@ +#include +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) +#define LENGTH(X) (sizeof X / sizeof X[0]) + +int checkglerr(const char *msg, const int line); +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); +void infogl(const int verbose); +void sdldie(const char *msg); +void sdlerrcheck(int line); +void printcomplog(GLuint shaderobj); +void printprogramlog(GLuint prog); +void debugcallback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, const GLchar* message, const void* userParam);