Add FBO and util implementation

This commit is contained in:
lhark 2017-11-26 00:47:29 -05:00
parent 0e71905c8b
commit 72524997ef
4 changed files with 449 additions and 0 deletions

224
FBO.cpp Normal file
View file

@ -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();
}

66
FBO.h Normal file
View file

@ -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 <iostream>
#include <GL/glew.h>
///////////////////////////////////////////////////////////////////////////////
/// @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;
};

141
util.cpp Normal file
View file

@ -0,0 +1,141 @@
/* See LICENSE file for copyright and license details. */
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}

18
util.h Normal file
View file

@ -0,0 +1,18 @@
#include <GL/glew.h>
/* 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);