3071 lines
100 KiB
C
3071 lines
100 KiB
C
|
// Version: mar nov 21 12:54:32 EST 2017
|
|||
|
#ifndef INF2705_MATRICE_H
|
|||
|
#define INF2705_MATRICE_H
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// Classe pour les matrices du pipeline
|
|||
|
// (INF2705, Benoît Ozell)
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <GL/glew.h>
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
#define GLM_SWIZZLE
|
|||
|
// (à compter de GLM 9.8, c'est plutôt la variable ci-dessous qu'il faut définir)
|
|||
|
#define GLM_FORCE_SWIZZLE
|
|||
|
#define GLM_FORCE_RADIANS 1
|
|||
|
#include <glm/glm.hpp>
|
|||
|
#include <glm/gtc/type_ptr.hpp>
|
|||
|
#include <glm/gtc/matrix_transform.hpp>
|
|||
|
#include <glm/gtx/string_cast.hpp>
|
|||
|
#include <stack>
|
|||
|
|
|||
|
class MatricePipeline
|
|||
|
{
|
|||
|
public:
|
|||
|
MatricePipeline()
|
|||
|
{ matr_.push( glm::mat4(1.0) ); }
|
|||
|
|
|||
|
operator glm::mat4() const { return matr_.top(); }
|
|||
|
operator const GLfloat*() const { return glm::value_ptr(matr_.top()); }
|
|||
|
|
|||
|
void LoadIdentity()
|
|||
|
{ matr_.top() = glm::mat4(1.0); }
|
|||
|
// Note: la librairie glm s’occupe de convertir les glm::vec3 en glm::vec4 pour la multiplication par glm::mat4 matr_.
|
|||
|
void Scale( GLfloat sx, GLfloat sy, GLfloat sz )
|
|||
|
{ matr_.top() = glm::scale( matr_.top(), glm::vec3(sx,sy,sz) ); }
|
|||
|
void Translate( GLfloat tx, GLfloat ty, GLfloat tz )
|
|||
|
{ matr_.top() = glm::translate( matr_.top(), glm::vec3(tx,ty,tz) ); }
|
|||
|
void Rotate( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
|
|||
|
{ matr_.top() = glm::rotate( matr_.top(), (GLfloat)glm::radians(angle), glm::vec3(x,y,z) ); }
|
|||
|
|
|||
|
void LookAt( GLdouble obsX, GLdouble obsY, GLdouble obsZ, GLdouble versX, GLdouble versY, GLdouble versZ, GLdouble upX, GLdouble upY, GLdouble upZ )
|
|||
|
{ matr_.top() = glm::lookAt( glm::vec3( obsX, obsY, obsZ ), glm::vec3( versX, versY, versZ ), glm::vec3( upX, upY, upZ ) ); }
|
|||
|
void Frustum( GLdouble gauche, GLdouble droite, GLdouble bas, GLdouble haut, GLdouble planAvant, GLdouble planArriere )
|
|||
|
{ matr_.top() = glm::frustum( gauche, droite, bas, haut, planAvant, planArriere ); }
|
|||
|
void Perspective( GLdouble fovy, GLdouble aspect, GLdouble planAvant, GLdouble planArriere )
|
|||
|
{ matr_.top() = glm::perspective( glm::radians(fovy), aspect, planAvant, planArriere );}
|
|||
|
void Ortho( GLdouble gauche, GLdouble droite, GLdouble bas, GLdouble haut, GLdouble planAvant, GLdouble planArriere )
|
|||
|
{ matr_.top() = glm::ortho( gauche, droite, bas, haut, planAvant, planArriere ); }
|
|||
|
void Ortho2D( GLdouble gauche, GLdouble droite, GLdouble bas, GLdouble haut )
|
|||
|
{ matr_.top() = glm::ortho( gauche, droite, bas, haut ); }
|
|||
|
|
|||
|
void PushMatrix()
|
|||
|
{ matr_.push( matr_.top() ); }
|
|||
|
void PopMatrix()
|
|||
|
{ matr_.pop(); }
|
|||
|
|
|||
|
glm::mat4 getMatr()
|
|||
|
{ return matr_.top(); }
|
|||
|
glm::mat4 setMatr( glm::mat4 m )
|
|||
|
{ return( matr_.top() = m ); }
|
|||
|
|
|||
|
friend std::ostream& operator<<( std::ostream& o, const MatricePipeline& mp )
|
|||
|
{
|
|||
|
//return o << glm::to_string(mp.matr_.top());
|
|||
|
glm::mat4 m = mp.matr_.top(); //o.precision(3); o.width(6);
|
|||
|
return o << std::endl
|
|||
|
<< " " << m[0][0] << " " << m[1][0] << " " << m[2][0] << " " << m[3][0] << std::endl
|
|||
|
<< " " << m[0][1] << " " << m[1][1] << " " << m[2][1] << " " << m[3][1] << std::endl
|
|||
|
<< " " << m[0][2] << " " << m[1][2] << " " << m[2][2] << " " << m[3][2] << std::endl
|
|||
|
<< " " << m[0][3] << " " << m[1][3] << " " << m[2][3] << " " << m[3][3] << std::endl;
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
std::stack<glm::mat4> matr_;
|
|||
|
};
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef INF2705_NUANCEUR_H
|
|||
|
#define INF2705_NUANCEUR_H
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// Classe pour charger les nuanceurs
|
|||
|
// (INF2705, Benoît Ozell)
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <GL/glew.h>
|
|||
|
#include <iostream>
|
|||
|
#include <string.h>
|
|||
|
#include <errno.h>
|
|||
|
#include <fstream>
|
|||
|
#include <sstream>
|
|||
|
|
|||
|
class ProgNuanceur
|
|||
|
{
|
|||
|
public:
|
|||
|
ProgNuanceur( ) : prog_(0), etiquette_("vide") { }
|
|||
|
~ProgNuanceur( ) { /* glDeleteShader(); */ glDeleteProgram( prog_ ); }
|
|||
|
operator GLuint() const { return prog_; }
|
|||
|
ProgNuanceur& operator=( GLuint prog ) { prog_ = prog; return *this; }
|
|||
|
|
|||
|
// Demander à OpenGL de créer un programme de nuanceur
|
|||
|
void creer( const std::string etiquette = "" )
|
|||
|
{
|
|||
|
if ( prog_ ) glDeleteProgram( prog_ );
|
|||
|
prog_ = glCreateProgram();
|
|||
|
etiquette_ = etiquette;
|
|||
|
if ( etiquette_ == "" ) { std::ostringstream oss; oss << prog_; etiquette_ += oss.str(); }
|
|||
|
}
|
|||
|
|
|||
|
// Charger en mémoire le contenu du fichier
|
|||
|
static const GLchar *lireNuanceur( const GLchar *fich )
|
|||
|
{
|
|||
|
// Ouvrir le fichier
|
|||
|
std::ifstream fichier( fich );
|
|||
|
if ( fichier.fail() )
|
|||
|
{
|
|||
|
std::cerr << "!!! " << fich << ": " << strerror(errno) << std::endl;
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
// Lire le fichier
|
|||
|
std::stringstream contenuFichier;
|
|||
|
contenuFichier << fichier.rdbuf();
|
|||
|
fichier.close();
|
|||
|
|
|||
|
// Obtenir le contenu du fichier
|
|||
|
std::string contenu = contenuFichier.str();
|
|||
|
const int taille = contenu.size();
|
|||
|
|
|||
|
// Retourner une chaîne pour le nuanceur
|
|||
|
char *source = new char[taille+1];
|
|||
|
strcpy( source, contenu.c_str() );
|
|||
|
return source;
|
|||
|
}
|
|||
|
|
|||
|
// Afficher le log de la compilation
|
|||
|
static bool afficherLogCompile( GLuint nuanceurObj )
|
|||
|
{
|
|||
|
// afficher le message d'erreur, le cas échéant
|
|||
|
int infologLength = 0;
|
|||
|
glGetShaderiv( nuanceurObj, GL_INFO_LOG_LENGTH, &infologLength );
|
|||
|
if ( infologLength > 1 )
|
|||
|
{
|
|||
|
char* infoLog = new char[infologLength+1];
|
|||
|
int charsWritten = 0;
|
|||
|
glGetShaderInfoLog( nuanceurObj, infologLength, &charsWritten, infoLog );
|
|||
|
std::cout << std::endl << infoLog << std::endl;
|
|||
|
delete[] infoLog;
|
|||
|
return( false );
|
|||
|
}
|
|||
|
return( true );
|
|||
|
}
|
|||
|
|
|||
|
// Compiler et attacher le nuanceur
|
|||
|
bool attacher( GLuint type, GLsizei nbChaine, const GLchar **chaines, const GLint *longueur = NULL )
|
|||
|
{
|
|||
|
GLuint nuanceurObj = glCreateShader( type );
|
|||
|
glShaderSource( nuanceurObj, nbChaine, chaines, longueur );
|
|||
|
glCompileShader( nuanceurObj );
|
|||
|
glAttachShader( prog_, nuanceurObj );
|
|||
|
return ( afficherLogCompile(nuanceurObj) );
|
|||
|
}
|
|||
|
bool attacher( GLuint type, const GLchar *fich )
|
|||
|
{
|
|||
|
bool rc = false;
|
|||
|
const GLchar *fichChaine = lireNuanceur( fich );
|
|||
|
if ( fichChaine != NULL )
|
|||
|
{
|
|||
|
rc = attacher( type, 1, &fichChaine, NULL );
|
|||
|
delete [] fichChaine;
|
|||
|
}
|
|||
|
return( rc );
|
|||
|
}
|
|||
|
bool attacher( GLuint type, const GLchar *preambule, const GLchar *fich )
|
|||
|
{
|
|||
|
bool rc = false;
|
|||
|
if ( fich == NULL ) // le nuanceur complet est dans le préambule
|
|||
|
rc = attacher( type, 1, &preambule, NULL );
|
|||
|
else
|
|||
|
{
|
|||
|
const GLchar *chaines[2] = { preambule, lireNuanceur( fich ) };
|
|||
|
if ( chaines[1] != NULL )
|
|||
|
{
|
|||
|
rc = attacher( type, 2, chaines, NULL );
|
|||
|
delete [] chaines[1];
|
|||
|
}
|
|||
|
}
|
|||
|
return( rc );
|
|||
|
}
|
|||
|
bool attacher( GLuint type, const std::string preambule, const GLchar *fich )
|
|||
|
{ return attacher( type, preambule.c_str(), fich ); }
|
|||
|
|
|||
|
// Afficher le log de l'édition des liens
|
|||
|
static bool afficherLogLink( GLuint progObj )
|
|||
|
{
|
|||
|
// afficher le message d'erreur, le cas échéant
|
|||
|
int infologLength = 0;
|
|||
|
glGetProgramiv( progObj, GL_INFO_LOG_LENGTH, &infologLength );
|
|||
|
if ( infologLength > 1 )
|
|||
|
{
|
|||
|
char* infoLog = new char[infologLength+1];
|
|||
|
int charsWritten = 0;
|
|||
|
glGetProgramInfoLog( progObj, infologLength, &charsWritten, infoLog );
|
|||
|
std::cout << "progObj" << std::endl << infoLog << std::endl;
|
|||
|
delete[] infoLog;
|
|||
|
return( false );
|
|||
|
}
|
|||
|
return( true );
|
|||
|
}
|
|||
|
|
|||
|
// Faire l'édition des liens du programme
|
|||
|
bool lier( )
|
|||
|
{
|
|||
|
glLinkProgram( prog_ );
|
|||
|
return( afficherLogLink(prog_) );
|
|||
|
}
|
|||
|
|
|||
|
// le nuanceur de sommets minimal
|
|||
|
static const GLchar *chainesSommetsMinimal;
|
|||
|
// le nuanceur de fragments minimal
|
|||
|
static const GLchar *chainesFragmentsMinimal;
|
|||
|
|
|||
|
private:
|
|||
|
GLuint prog_; // LE programme
|
|||
|
std::string etiquette_; // une étiquette pour identifier le programme
|
|||
|
};
|
|||
|
|
|||
|
// le nuanceur de sommets minimal
|
|||
|
const GLchar *ProgNuanceur::chainesSommetsMinimal =
|
|||
|
{
|
|||
|
"#version 410\n"
|
|||
|
"uniform mat4 matrModel;\n"
|
|||
|
"uniform mat4 matrVisu;\n"
|
|||
|
"uniform mat4 matrProj;\n"
|
|||
|
"layout(location=0) in vec4 Vertex;\n"
|
|||
|
"layout(location=3) in vec4 Color;\n"
|
|||
|
"out vec4 couleur;\n"
|
|||
|
"void main( void )\n"
|
|||
|
"{\n"
|
|||
|
" // transformation standard du sommet\n"
|
|||
|
" gl_Position = matrProj * matrVisu * matrModel * Vertex;\n"
|
|||
|
" // couleur du sommet\n"
|
|||
|
" couleur = Color;\n"
|
|||
|
"}\n"
|
|||
|
};
|
|||
|
// le nuanceur de fragments minimal
|
|||
|
const GLchar *ProgNuanceur::chainesFragmentsMinimal =
|
|||
|
{
|
|||
|
"#version 410\n"
|
|||
|
"in vec4 couleur;\n"
|
|||
|
"out vec4 FragColor;\n"
|
|||
|
"void main( void )\n"
|
|||
|
"{\n"
|
|||
|
" // la couleur du fragment est la couleur interpolée\n"
|
|||
|
" FragColor = couleur;\n"
|
|||
|
"}\n"
|
|||
|
};
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef INF2705_FENETRE_H
|
|||
|
#define INF2705_FENETRE_H
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// Classe pour créer une fenêtre
|
|||
|
// (INF2705, Benoît Ozell)
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <GL/glew.h>
|
|||
|
#include <iostream>
|
|||
|
#include <fstream>
|
|||
|
#include <sstream>
|
|||
|
|
|||
|
#if defined( __APPLE__ )
|
|||
|
#define FENETRE_LIB_GLFW 1
|
|||
|
#else
|
|||
|
#define FENETRE_LIB_SDL 1
|
|||
|
#endif
|
|||
|
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
# include <GLFW/glfw3.h>
|
|||
|
#else
|
|||
|
# include <SDL.h>
|
|||
|
#endif
|
|||
|
#include <string.h>
|
|||
|
#include <stdlib.h>
|
|||
|
|
|||
|
typedef enum {
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
|
|||
|
TP_ECHAP = GLFW_KEY_ESCAPE,
|
|||
|
TP_BAS = GLFW_KEY_UP,
|
|||
|
TP_HAUT = GLFW_KEY_DOWN,
|
|||
|
TP_PAGEPREC = GLFW_KEY_PAGE_UP,
|
|||
|
TP_PAGESUIV = GLFW_KEY_PAGE_DOWN,
|
|||
|
TP_DEBUT = GLFW_KEY_HOME,
|
|||
|
TP_FIN = GLFW_KEY_END,
|
|||
|
TP_EGAL = '=', // GLFW_KEY_EQUALS,
|
|||
|
TP_SUPERIEUR = '>', // GLFW_KEY_GREATER,
|
|||
|
TP_INFERIEUR = '<', // GLFW_KEY_LESS,
|
|||
|
TP_DROITE = GLFW_KEY_RIGHT,
|
|||
|
TP_GAUCHE = GLFW_KEY_LEFT,
|
|||
|
TP_PLUS = '+', // GLFW_KEY_PLUS,
|
|||
|
TP_MOINS = GLFW_KEY_MINUS,
|
|||
|
TP_CROCHETDROIT = GLFW_KEY_RIGHT_BRACKET,
|
|||
|
TP_CROCHETGAUCHE = GLFW_KEY_LEFT_BRACKET,
|
|||
|
TP_POINT = GLFW_KEY_PERIOD,
|
|||
|
TP_VIRGULE = GLFW_KEY_COMMA,
|
|||
|
TP_POINTVIRGULE = GLFW_KEY_SEMICOLON,
|
|||
|
TP_BARREOBLIQUE = GLFW_KEY_SLASH,
|
|||
|
TP_ESPACE = GLFW_KEY_SPACE,
|
|||
|
TP_SOULIGNE = '_', // GLFW_KEY_UNDERSCORE,
|
|||
|
|
|||
|
TP_0 = GLFW_KEY_0,
|
|||
|
TP_1 = GLFW_KEY_1,
|
|||
|
TP_2 = GLFW_KEY_2,
|
|||
|
TP_3 = GLFW_KEY_3,
|
|||
|
TP_4 = GLFW_KEY_4,
|
|||
|
TP_5 = GLFW_KEY_5,
|
|||
|
TP_6 = GLFW_KEY_6,
|
|||
|
TP_7 = GLFW_KEY_7,
|
|||
|
TP_8 = GLFW_KEY_8,
|
|||
|
TP_9 = GLFW_KEY_9,
|
|||
|
|
|||
|
TP_a = GLFW_KEY_A,
|
|||
|
TP_b = GLFW_KEY_B,
|
|||
|
TP_c = GLFW_KEY_C,
|
|||
|
TP_d = GLFW_KEY_D,
|
|||
|
TP_e = GLFW_KEY_E,
|
|||
|
TP_f = GLFW_KEY_F,
|
|||
|
TP_g = GLFW_KEY_G,
|
|||
|
TP_h = GLFW_KEY_H,
|
|||
|
TP_i = GLFW_KEY_I,
|
|||
|
TP_j = GLFW_KEY_J,
|
|||
|
TP_k = GLFW_KEY_K,
|
|||
|
TP_l = GLFW_KEY_L,
|
|||
|
TP_m = GLFW_KEY_M,
|
|||
|
TP_n = GLFW_KEY_N,
|
|||
|
TP_o = GLFW_KEY_O,
|
|||
|
TP_p = GLFW_KEY_P,
|
|||
|
TP_q = GLFW_KEY_Q,
|
|||
|
TP_r = GLFW_KEY_R,
|
|||
|
TP_s = GLFW_KEY_S,
|
|||
|
TP_t = GLFW_KEY_T,
|
|||
|
TP_u = GLFW_KEY_U,
|
|||
|
TP_v = GLFW_KEY_V,
|
|||
|
TP_w = GLFW_KEY_W,
|
|||
|
TP_x = GLFW_KEY_X,
|
|||
|
TP_y = GLFW_KEY_Y,
|
|||
|
TP_z = GLFW_KEY_Z,
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
TP_ECHAP = SDLK_ESCAPE,
|
|||
|
TP_BAS = SDLK_UP,
|
|||
|
TP_HAUT = SDLK_DOWN,
|
|||
|
TP_PAGEPREC = SDLK_PAGEUP,
|
|||
|
TP_PAGESUIV = SDLK_PAGEDOWN,
|
|||
|
TP_DEBUT = SDLK_HOME,
|
|||
|
TP_FIN = SDLK_END,
|
|||
|
TP_EGAL = SDLK_EQUALS,
|
|||
|
TP_SUPERIEUR = SDLK_GREATER,
|
|||
|
TP_INFERIEUR = SDLK_LESS,
|
|||
|
TP_DROITE = SDLK_RIGHT,
|
|||
|
TP_GAUCHE = SDLK_LEFT,
|
|||
|
TP_PLUS = SDLK_PLUS,
|
|||
|
TP_MOINS = SDLK_MINUS,
|
|||
|
TP_CROCHETDROIT = SDLK_RIGHTBRACKET,
|
|||
|
TP_CROCHETGAUCHE = SDLK_LEFTBRACKET,
|
|||
|
TP_POINT = SDLK_PERIOD,
|
|||
|
TP_VIRGULE = SDLK_COMMA,
|
|||
|
TP_POINTVIRGULE = SDLK_SEMICOLON,
|
|||
|
TP_BARREOBLIQUE = SDLK_SLASH,
|
|||
|
TP_ESPACE = SDLK_SPACE,
|
|||
|
TP_SOULIGNE = SDLK_UNDERSCORE,
|
|||
|
|
|||
|
TP_0 = SDLK_0,
|
|||
|
TP_1 = SDLK_1,
|
|||
|
TP_2 = SDLK_2,
|
|||
|
TP_3 = SDLK_3,
|
|||
|
TP_4 = SDLK_4,
|
|||
|
TP_5 = SDLK_5,
|
|||
|
TP_6 = SDLK_6,
|
|||
|
TP_7 = SDLK_7,
|
|||
|
TP_8 = SDLK_8,
|
|||
|
TP_9 = SDLK_9,
|
|||
|
|
|||
|
TP_a = SDLK_a,
|
|||
|
TP_b = SDLK_b,
|
|||
|
TP_c = SDLK_c,
|
|||
|
TP_d = SDLK_d,
|
|||
|
TP_e = SDLK_e,
|
|||
|
TP_f = SDLK_f,
|
|||
|
TP_g = SDLK_g,
|
|||
|
TP_h = SDLK_h,
|
|||
|
TP_i = SDLK_i,
|
|||
|
TP_j = SDLK_j,
|
|||
|
TP_k = SDLK_k,
|
|||
|
TP_l = SDLK_l,
|
|||
|
TP_m = SDLK_m,
|
|||
|
TP_n = SDLK_n,
|
|||
|
TP_o = SDLK_o,
|
|||
|
TP_p = SDLK_p,
|
|||
|
TP_q = SDLK_q,
|
|||
|
TP_r = SDLK_r,
|
|||
|
TP_s = SDLK_s,
|
|||
|
TP_t = SDLK_t,
|
|||
|
TP_u = SDLK_u,
|
|||
|
TP_v = SDLK_v,
|
|||
|
TP_w = SDLK_w,
|
|||
|
TP_x = SDLK_x,
|
|||
|
TP_y = SDLK_y,
|
|||
|
TP_z = SDLK_z,
|
|||
|
|
|||
|
#endif
|
|||
|
} TP_touche;
|
|||
|
|
|||
|
typedef enum {
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
TP_BOUTON_GAUCHE = GLFW_MOUSE_BUTTON_1,
|
|||
|
TP_BOUTON_MILIEU = GLFW_MOUSE_BUTTON_3,
|
|||
|
TP_BOUTON_DROIT = GLFW_MOUSE_BUTTON_2,
|
|||
|
TP_RELACHE = GLFW_RELEASE,
|
|||
|
TP_PRESSE = GLFW_PRESS,
|
|||
|
#else
|
|||
|
TP_BOUTON_GAUCHE = SDL_BUTTON_LEFT,
|
|||
|
TP_BOUTON_MILIEU = SDL_BUTTON_MIDDLE,
|
|||
|
TP_BOUTON_DROIT = SDL_BUTTON_RIGHT,
|
|||
|
TP_RELACHE = SDL_RELEASED,
|
|||
|
TP_PRESSE = SDL_PRESSED,
|
|||
|
#endif
|
|||
|
} TP_bouton;
|
|||
|
|
|||
|
|
|||
|
// la fenêtre graphique
|
|||
|
class FenetreTP
|
|||
|
{
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
static void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods )
|
|||
|
{
|
|||
|
FenetreTP *fen = (FenetreTP*) glfwGetWindowUserPointer( window );
|
|||
|
if ( action == GLFW_PRESS )
|
|||
|
fen->clavier( (TP_touche) key );
|
|||
|
}
|
|||
|
static void mouse_button_callback( GLFWwindow* window, int button, int action, int mods )
|
|||
|
{
|
|||
|
FenetreTP *fen = (FenetreTP*) glfwGetWindowUserPointer( window );
|
|||
|
double xpos, ypos; glfwGetCursorPos( window, &xpos, &ypos );
|
|||
|
fen->sourisClic( button, action, xpos, ypos );
|
|||
|
}
|
|||
|
static void cursor_position_callback( GLFWwindow* window, double xpos, double ypos )
|
|||
|
{
|
|||
|
FenetreTP *fen = (FenetreTP*) glfwGetWindowUserPointer( window );
|
|||
|
fen->sourisMouvement( xpos, ypos );
|
|||
|
}
|
|||
|
static void scroll_callback( GLFWwindow* window, double xoffset, double yoffset )
|
|||
|
{
|
|||
|
FenetreTP *fen = (FenetreTP*) glfwGetWindowUserPointer( window );
|
|||
|
fen->sourisWheel( xoffset, yoffset );
|
|||
|
}
|
|||
|
static void window_refresh_callback( GLFWwindow* window )
|
|||
|
{
|
|||
|
FenetreTP *fen = (FenetreTP*) glfwGetWindowUserPointer( window );
|
|||
|
// int left, top, right, bottom;
|
|||
|
// glfwGetWindowFrameSize( window, &left, &top, &right, &bottom );
|
|||
|
// fen->redimensionner( right-left, top-bottom );
|
|||
|
int width, height;
|
|||
|
glfwGetWindowSize( window, &width, &height );
|
|||
|
fen->redimensionner( width, height );
|
|||
|
fen->afficherScene();
|
|||
|
fen->swap();
|
|||
|
}
|
|||
|
#else
|
|||
|
#endif
|
|||
|
|
|||
|
public:
|
|||
|
FenetreTP( std::string nom = "INF2705 TP",
|
|||
|
int largeur = 900, int hauteur = 600,
|
|||
|
int xpos = 100, int ypos = 100 )
|
|||
|
: fenetre_(NULL),
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
#else
|
|||
|
contexte_(NULL),
|
|||
|
#endif
|
|||
|
largeur_(largeur), hauteur_(hauteur)
|
|||
|
{
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
// initialiser GLFW
|
|||
|
if ( !glfwInit() )
|
|||
|
{
|
|||
|
glfwdie( "ERREUR: Incapable d'initialiser GLFW3\n");
|
|||
|
}
|
|||
|
|
|||
|
// demander certaines caractéristiques:
|
|||
|
glfwWindowHint( GLFW_RED_BITS, 8 );
|
|||
|
glfwWindowHint( GLFW_GREEN_BITS, 8 );
|
|||
|
glfwWindowHint( GLFW_BLUE_BITS, 8 );
|
|||
|
glfwWindowHint( GLFW_ALPHA_BITS, 8 );
|
|||
|
//glfwWindowHint( GLFW_DOUBLEBUFFER, GL_TRUE );
|
|||
|
glfwWindowHint( GLFW_DEPTH_BITS, 24 );
|
|||
|
glfwWindowHint( GLFW_STENCIL_BITS, 8 );
|
|||
|
#if defined( __APPLE__ )
|
|||
|
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 4 );
|
|||
|
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 1 );
|
|||
|
glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
|
|||
|
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
|
|||
|
#endif
|
|||
|
|
|||
|
// créer la fenêtre
|
|||
|
fenetre_ = glfwCreateWindow( largeur, hauteur, nom.c_str(), NULL, NULL );
|
|||
|
if ( !fenetre_ )
|
|||
|
{
|
|||
|
glfwdie( "ERROR: Incapable de créer la fenêtre GLFW3\n");
|
|||
|
}
|
|||
|
glfwMakeContextCurrent( fenetre_ );
|
|||
|
glfwSwapInterval(1);
|
|||
|
|
|||
|
glfwSetWindowUserPointer( fenetre_, this );
|
|||
|
glfwSetKeyCallback( fenetre_, key_callback );
|
|||
|
glfwSetMouseButtonCallback( fenetre_, mouse_button_callback );
|
|||
|
glfwSetCursorPosCallback( fenetre_, cursor_position_callback );
|
|||
|
glfwSetScrollCallback( fenetre_, scroll_callback );
|
|||
|
glfwSetWindowRefreshCallback( fenetre_, window_refresh_callback );
|
|||
|
#else
|
|||
|
// initialiser SDL
|
|||
|
const Uint32 flags = SDL_INIT_VIDEO | SDL_INIT_EVENTS;
|
|||
|
if ( SDL_WasInit( flags ) == 0 )
|
|||
|
{
|
|||
|
if ( SDL_Init( flags ) < 0 ) sdldie( "ERREUR: Incapable d'initialiser SDL" );
|
|||
|
atexit( SDL_Quit );
|
|||
|
}
|
|||
|
|
|||
|
// demander certaines caractéristiques: https://wiki.libsdl.org/SDL_GL_SetAttribute
|
|||
|
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
|
|||
|
//SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
|
|||
|
//SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
|
|||
|
#if 0
|
|||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
|
|||
|
//SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 4 );
|
|||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
|
|||
|
#endif
|
|||
|
|
|||
|
// créer la fenêtre
|
|||
|
fenetre_ = SDL_CreateWindow( nom.c_str(), xpos, ypos, largeur, hauteur,
|
|||
|
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
|
|||
|
if ( !fenetre_ ) sdldie( "ERREUR: Incapable de créer la fenêtre SDL" );
|
|||
|
verifierErreurSDL(__LINE__);
|
|||
|
|
|||
|
// créer le contexte OpenGL
|
|||
|
contexte_ = SDL_GL_CreateContext( fenetre_ );
|
|||
|
verifierErreurSDL(__LINE__);
|
|||
|
|
|||
|
// s'assurer que les réaffichage seront synchronisés avec le rafraîchissement de l'écran
|
|||
|
SDL_GL_SetSwapInterval( 1 );
|
|||
|
verifierErreurSDL(__LINE__);
|
|||
|
#endif
|
|||
|
|
|||
|
// initiliaser GLEW
|
|||
|
initialiserGLEW( );
|
|||
|
|
|||
|
// imprimer un peu d'information OpenGL
|
|||
|
imprimerInfosGL( );
|
|||
|
}
|
|||
|
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
void quit( )
|
|||
|
{
|
|||
|
glfwDestroyWindow( fenetre_ );
|
|||
|
glfwTerminate();
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
~FenetreTP( )
|
|||
|
{
|
|||
|
quit();
|
|||
|
}
|
|||
|
#else
|
|||
|
void quit( )
|
|||
|
{
|
|||
|
SDL_Event sdlevent; sdlevent.type = SDL_QUIT;
|
|||
|
SDL_PushEvent( &sdlevent );
|
|||
|
}
|
|||
|
~FenetreTP( )
|
|||
|
{
|
|||
|
SDL_GL_DeleteContext( contexte_ ); contexte_ = NULL;
|
|||
|
SDL_DestroyWindow( fenetre_ ); fenetre_ = NULL;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// mettre à jour la fenêtre OpenGL: le tampon arrière devient le tampon avant et vice-versa
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
void swap( ) { glfwSwapBuffers( fenetre_ ); }
|
|||
|
#else
|
|||
|
void swap( ) { SDL_GL_SwapWindow( fenetre_ ); }
|
|||
|
#endif
|
|||
|
|
|||
|
// fonction appelée pour tracer la scène
|
|||
|
void afficherScene( );
|
|||
|
// fonction appelée lors d'un événement de redimensionnement
|
|||
|
void redimensionner( GLsizei w, GLsizei h );
|
|||
|
// fonction appelée lors d'un événement de clavier
|
|||
|
void clavier( TP_touche touche );
|
|||
|
// fonctions appelées lors d'un événement de souris
|
|||
|
void sourisClic( int button, int state, int x, int y );
|
|||
|
void sourisWheel( int x, int y );
|
|||
|
void sourisMouvement( int x, int y );
|
|||
|
|
|||
|
// fonction de gestion de la boucle des événements
|
|||
|
bool gererEvenement( )
|
|||
|
{
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
glfwPollEvents();
|
|||
|
return( !glfwWindowShouldClose( fenetre_ ) );
|
|||
|
#else
|
|||
|
SDL_Event e;
|
|||
|
while ( SDL_PollEvent( &e ) )
|
|||
|
{
|
|||
|
switch ( e.type )
|
|||
|
{
|
|||
|
case SDL_QUIT: // c'est la fin
|
|||
|
return( false );
|
|||
|
break;
|
|||
|
case SDL_WINDOWEVENT:
|
|||
|
if ( e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ) // redimensionnement
|
|||
|
{
|
|||
|
largeur_ = e.window.data1;
|
|||
|
hauteur_ = e.window.data2;
|
|||
|
redimensionner( largeur_, hauteur_ );
|
|||
|
}
|
|||
|
else if ( e.window.event == SDL_WINDOWEVENT_SHOWN ) // affichage
|
|||
|
{
|
|||
|
SDL_GetWindowSize( fenetre_, &largeur_, &hauteur_ );
|
|||
|
redimensionner( largeur_, hauteur_ );
|
|||
|
}
|
|||
|
//else
|
|||
|
// std::cout << "//@FenetreTP,WINDOWEVENT;" << " e.window.event=" << e.window.event << std::endl;
|
|||
|
break;
|
|||
|
case SDL_KEYDOWN: // une touche est pressée
|
|||
|
clavier( (TP_touche) e.key.keysym.sym );
|
|||
|
break;
|
|||
|
case SDL_KEYUP: // une touche est relâchée
|
|||
|
break;
|
|||
|
case SDL_MOUSEBUTTONDOWN: // un bouton de la souris est pressé
|
|||
|
case SDL_MOUSEBUTTONUP: // un bouton de la souris est relâché
|
|||
|
sourisClic( e.button.button, e.button.state, e.button.x, e.button.y );
|
|||
|
break;
|
|||
|
case SDL_MOUSEMOTION: // la souris est déplacée
|
|||
|
sourisMouvement( e.motion.x, e.motion.y );
|
|||
|
break;
|
|||
|
case SDL_MOUSEWHEEL: // la molette de la souris est tournée
|
|||
|
sourisWheel( e.wheel.x, e.wheel.y );
|
|||
|
break;
|
|||
|
default:
|
|||
|
//std::cerr << "//@FenetreTP," << __LINE__ << ";" << " e.type=" << e.type << std::endl;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return( true );
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Quelques fonctions utilitaires
|
|||
|
//
|
|||
|
|
|||
|
// Charger en mémoire le contenu du fichier
|
|||
|
static void imprimerTouches( )
|
|||
|
{
|
|||
|
// Ouvrir le fichier
|
|||
|
std::ifstream fichier( "touches.txt" );
|
|||
|
if ( fichier.fail() ) return;
|
|||
|
|
|||
|
// Lire le fichier
|
|||
|
std::stringstream contenuFichier;
|
|||
|
contenuFichier << fichier.rdbuf();
|
|||
|
fichier.close();
|
|||
|
|
|||
|
// Ecrire le contenu du fichier
|
|||
|
std::cout << " touches possibles :" << std::endl
|
|||
|
<< contenuFichier.str() << std::endl;
|
|||
|
}
|
|||
|
|
|||
|
// afficher les versions des éléments du pipeline OpenGL
|
|||
|
static void imprimerInfosGL( const int verbose = 1 )
|
|||
|
{
|
|||
|
#define PBYTE(CHAINE) ( (CHAINE) != NULL ? (CHAINE) : (const GLubyte *) "????" )
|
|||
|
#define PCHAR(CHAINE) ( (CHAINE) != NULL ? (CHAINE) : (const char *) "????" )
|
|||
|
|
|||
|
if ( verbose >= 1 )
|
|||
|
{
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
int major, minor, rev; glfwGetVersion( &major, &minor, &rev );
|
|||
|
std::cout << "// GLFW " << major << "." << minor << "." << rev << std::endl;
|
|||
|
#else
|
|||
|
SDL_version linked; SDL_GetVersion( &linked );
|
|||
|
std::cout << "// SDL " << (int) linked.major << "." << (int) linked.minor << "." << (int) linked.patch << std::endl;
|
|||
|
#endif
|
|||
|
|
|||
|
const GLubyte *glVersion = glGetString( GL_VERSION );
|
|||
|
const GLubyte *glVendor = glGetString( GL_VENDOR );
|
|||
|
const GLubyte *glRenderer = glGetString( GL_RENDERER );
|
|||
|
const GLubyte *glslVersion = glGetString( GL_SHADING_LANGUAGE_VERSION );
|
|||
|
std::cout << "// OpenGL " << PBYTE(glVersion) << PBYTE(glVendor) << std::endl;
|
|||
|
std::cout << "// GPU " << PBYTE(glRenderer) << std::endl;
|
|||
|
std::cout << "// GLSL " << PBYTE(glslVersion) << std::endl;
|
|||
|
|
|||
|
if ( verbose >= 2 )
|
|||
|
{
|
|||
|
const GLubyte *glExtensions = glGetString( GL_EXTENSIONS );
|
|||
|
std::cout << "// extensions = " << PBYTE(glExtensions) << std::endl;
|
|||
|
}
|
|||
|
}
|
|||
|
#undef PBYTE
|
|||
|
#undef PCHAR
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
// donner une message et mourir...
|
|||
|
static void glfwdie( const char *msg )
|
|||
|
{
|
|||
|
//const char *sdlerror = SDL_GetError();
|
|||
|
//std::cout << "glfwdie " << msg << " " << sdlerror << std::endl;
|
|||
|
std::cout << "glfwdie " << msg << " " << std::endl;
|
|||
|
//glfwTerminate();
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
#else
|
|||
|
// donner une message et mourir...
|
|||
|
static void sdldie( const char *msg )
|
|||
|
{
|
|||
|
const char *sdlerror = SDL_GetError();
|
|||
|
std::cout << "sdldie " << msg << " " << sdlerror << std::endl;
|
|||
|
SDL_Quit();
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
// vérifier les erreurs
|
|||
|
static void verifierErreurSDL( int line = -1 )
|
|||
|
{
|
|||
|
const char *sdlerror = SDL_GetError();
|
|||
|
if ( *sdlerror != '\0' )
|
|||
|
{
|
|||
|
std::cout << "SDL Error: " << sdlerror << std::endl;
|
|||
|
if ( line != -1 )
|
|||
|
std::cout << "line: " << line;
|
|||
|
std::cout << std::endl;
|
|||
|
SDL_ClearError();
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
// La fonction glGetError() permet de savoir si une erreur est survenue depuis le dernier appel à cette fonction.
|
|||
|
static int VerifierErreurGL( const std::string message )
|
|||
|
{
|
|||
|
int rc = 0;
|
|||
|
GLenum err;
|
|||
|
while ( ( err = glGetError() ) != GL_NO_ERROR )
|
|||
|
{
|
|||
|
std::cerr << "Erreur OpenGL, " << message << " " << std::endl;
|
|||
|
switch ( err )
|
|||
|
{
|
|||
|
case GL_INVALID_ENUM:
|
|||
|
std::cerr << "GL_INVALID_ENUM: Valeur d'une énumération hors limite.";
|
|||
|
break;
|
|||
|
case GL_INVALID_VALUE:
|
|||
|
std::cerr << "GL_INVALID_VALUE: Valeur numérique hors limite.";
|
|||
|
break;
|
|||
|
case GL_INVALID_OPERATION:
|
|||
|
std::cerr << "GL_INVALID_OPERATION: Opération non permise dans l'état courant.";
|
|||
|
break;
|
|||
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
|||
|
std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION: L'objet est incomplet.";
|
|||
|
break;
|
|||
|
case GL_OUT_OF_MEMORY:
|
|||
|
std::cerr << "GL_OUT_OF_MEMORY: Pas assez de mémoire pour exécuter la commande.";
|
|||
|
break;
|
|||
|
case GL_STACK_UNDERFLOW:
|
|||
|
std::cerr << "GL_STACK_UNDERFLOW: Une opération entraînerait un débordement de pile interne.";
|
|||
|
break;
|
|||
|
case GL_STACK_OVERFLOW:
|
|||
|
std::cerr << "GL_STACK_OVERFLOW: Une opération entraînerait un débordement de pile interne.";
|
|||
|
break;
|
|||
|
default:
|
|||
|
std::cerr << "err = " << err << ": Erreur inconnue!";
|
|||
|
break;
|
|||
|
}
|
|||
|
std::cerr << std::endl;
|
|||
|
++rc;
|
|||
|
}
|
|||
|
return( rc );
|
|||
|
}
|
|||
|
|
|||
|
// La fonction afficherAxes affiche des axes qui représentent l'orientation courante du repère
|
|||
|
// Les axes sont colorés ainsi: X = Rouge, Y = Vert, Z = Bleu
|
|||
|
static void afficherAxes( const GLfloat longueurAxe = 1.0, const GLfloat largeurLigne = 2.0 )
|
|||
|
{
|
|||
|
#if !defined( __APPLE__ )
|
|||
|
glPushAttrib( GL_ENABLE_BIT | GL_LINE_BIT );
|
|||
|
glLineWidth( largeurLigne );
|
|||
|
|
|||
|
const GLfloat coo[] = { 0., 0., 0.,
|
|||
|
longueurAxe, 0., 0.,
|
|||
|
0., longueurAxe, 0.,
|
|||
|
0., 0., longueurAxe };
|
|||
|
const GLfloat couleur[] = { 1., 1., 1.,
|
|||
|
1., 0., 0.,
|
|||
|
0., 1., 0.,
|
|||
|
0., 0., 1. };
|
|||
|
|
|||
|
#if 0
|
|||
|
const GLuint connec[] = { 0, 1, 0, 2, 0, 3 };
|
|||
|
GLint locVertex = 0;
|
|||
|
glVertexAttribPointer( locVertex, 3, GL_FLOAT, GL_FALSE, 0, coo );
|
|||
|
glEnableVertexAttribArray(locVertex);
|
|||
|
GLint locColor = 3;
|
|||
|
glVertexAttribPointer( locColor, 3, GL_FLOAT, GL_FALSE, 0, couleur );
|
|||
|
glEnableVertexAttribArray(locColor);
|
|||
|
glDrawElements( GL_LINES, sizeof(connec)/sizeof(GLuint), GL_UNSIGNED_INT, connec );
|
|||
|
#else
|
|||
|
glBegin( GL_LINES );{
|
|||
|
glColor3fv( &(couleur[3]) ); glVertex3fv( &(coo[0]) ); glVertex3fv( &(coo[3]) );
|
|||
|
glColor3fv( &(couleur[6]) ); glVertex3fv( &(coo[0]) ); glVertex3fv( &(coo[6]) );
|
|||
|
glColor3fv( &(couleur[9]) ); glVertex3fv( &(coo[0]) ); glVertex3fv( &(coo[9]) );
|
|||
|
}glEnd( );
|
|||
|
#endif
|
|||
|
|
|||
|
glPopAttrib( );
|
|||
|
#endif
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
void initialiserGLEW( )
|
|||
|
{
|
|||
|
//#if defined(_GLEW_H__)
|
|||
|
glewExperimental = GL_TRUE;
|
|||
|
GLenum rev = glewInit();
|
|||
|
if ( rev != GLEW_OK )
|
|||
|
{
|
|||
|
std::cout << "Error: " << glewGetErrorString(rev) << std::endl;
|
|||
|
exit( 1 );
|
|||
|
}
|
|||
|
glGetError(); // Afin d'ignorer l'erreur générée par GLEW. Voir https://www.opengl.org/wiki/OpenGL_Loading_Library#GLEW_.28OpenGL_Extension_Wrangler.29
|
|||
|
//#endif
|
|||
|
}
|
|||
|
|
|||
|
#if defined(FENETRE_LIB_GLFW)
|
|||
|
GLFWwindow *fenetre_;
|
|||
|
#else
|
|||
|
SDL_Window *fenetre_;
|
|||
|
SDL_GLContext contexte_;
|
|||
|
#endif
|
|||
|
GLsizei largeur_; // la largeur de la fenêtre
|
|||
|
GLsizei hauteur_; // la hauteur de la fenêtre
|
|||
|
};
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef INF2705_TEXTURE_H
|
|||
|
#define INF2705_TEXTURE_H
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// Fonctions pour charger une texture
|
|||
|
// (INF2705, Benoît Ozell)
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <GL/glew.h>
|
|||
|
#include <iostream>
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
/*
|
|||
|
* Windows Bitmap File Loader
|
|||
|
* Version 1.2.5 (20120929)
|
|||
|
*
|
|||
|
* Supported Formats: 1, 4, 8, 16, 24, 32 Bit Images
|
|||
|
* Alpha Bitmaps are also supported.
|
|||
|
* Supported compression types: RLE 8, BITFIELDS
|
|||
|
*
|
|||
|
* Created by: Benjamin Kalytta, 2006 - 2012
|
|||
|
* Thanks for bug fixes goes to: Chris Campbell
|
|||
|
*
|
|||
|
* Licence: Free to use, URL to my source and my name is required in your source code.
|
|||
|
*
|
|||
|
* Source can be found at http://www.kalytta.com/bitmap.h
|
|||
|
*
|
|||
|
* Warning: This code should not be used in unmodified form in a production environment.
|
|||
|
* It should only serve as a basis for your own development.
|
|||
|
* There is only a minimal error handling in this code. (Notice added 20111211)
|
|||
|
*/
|
|||
|
|
|||
|
#include <fstream>
|
|||
|
#include <string>
|
|||
|
|
|||
|
#ifndef __LITTLE_ENDIAN__
|
|||
|
# ifndef __BIG_ENDIAN__
|
|||
|
# define __LITTLE_ENDIAN__
|
|||
|
# endif
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef __LITTLE_ENDIAN__
|
|||
|
# define BITMAP_SIGNATURE 0x4d42
|
|||
|
#else
|
|||
|
# define BITMAP_SIGNATURE 0x424d
|
|||
|
#endif
|
|||
|
|
|||
|
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
|||
|
typedef unsigned __int32 uint32_t;
|
|||
|
typedef unsigned __int16 uint16_t;
|
|||
|
typedef unsigned __int8 uint8_t;
|
|||
|
typedef __int32 int32_t;
|
|||
|
#elif defined(__GNUC__) || defined(__CYGWIN__) || defined(__MWERKS__) || defined(__WATCOMC__) || defined(__PGI) || defined(__LCC__)
|
|||
|
# include <stdint.h>
|
|||
|
#else
|
|||
|
typedef unsigned int uint32_t;
|
|||
|
typedef unsigned short int uint16_t;
|
|||
|
typedef unsigned char uint8_t;
|
|||
|
typedef int int32_t;
|
|||
|
#endif
|
|||
|
|
|||
|
#pragma pack(push, 1)
|
|||
|
|
|||
|
typedef struct _BITMAP_FILEHEADER {
|
|||
|
uint16_t Signature;
|
|||
|
uint32_t Size;
|
|||
|
uint32_t Reserved;
|
|||
|
uint32_t BitsOffset;
|
|||
|
} BITMAP_FILEHEADER;
|
|||
|
|
|||
|
#define BITMAP_FILEHEADER_SIZE 14
|
|||
|
|
|||
|
typedef struct _BITMAP_HEADER {
|
|||
|
uint32_t HeaderSize;
|
|||
|
int32_t Width;
|
|||
|
int32_t Height;
|
|||
|
uint16_t Planes;
|
|||
|
uint16_t BitCount;
|
|||
|
uint32_t Compression;
|
|||
|
uint32_t SizeImage;
|
|||
|
int32_t PelsPerMeterX;
|
|||
|
int32_t PelsPerMeterY;
|
|||
|
uint32_t ClrUsed;
|
|||
|
uint32_t ClrImportant;
|
|||
|
uint32_t RedMask;
|
|||
|
uint32_t GreenMask;
|
|||
|
uint32_t BlueMask;
|
|||
|
uint32_t AlphaMask;
|
|||
|
uint32_t CsType;
|
|||
|
uint32_t Endpoints[9]; // see http://msdn2.microsoft.com/en-us/library/ms536569.aspx
|
|||
|
uint32_t GammaRed;
|
|||
|
uint32_t GammaGreen;
|
|||
|
uint32_t GammaBlue;
|
|||
|
} BITMAP_HEADER;
|
|||
|
|
|||
|
typedef struct _RGBA {
|
|||
|
uint8_t Red;
|
|||
|
uint8_t Green;
|
|||
|
uint8_t Blue;
|
|||
|
uint8_t Alpha;
|
|||
|
} RGBA;
|
|||
|
|
|||
|
typedef struct _BGRA {
|
|||
|
uint8_t Blue;
|
|||
|
uint8_t Green;
|
|||
|
uint8_t Red;
|
|||
|
uint8_t Alpha;
|
|||
|
} BGRA;
|
|||
|
|
|||
|
#pragma pack(pop)
|
|||
|
|
|||
|
class CBitmap {
|
|||
|
private:
|
|||
|
BITMAP_FILEHEADER m_BitmapFileHeader;
|
|||
|
BITMAP_HEADER m_BitmapHeader;
|
|||
|
RGBA *m_BitmapData;
|
|||
|
unsigned int m_BitmapSize;
|
|||
|
|
|||
|
// Masks and bit counts shouldn't exceed 32 Bits
|
|||
|
public:
|
|||
|
class CColor {
|
|||
|
public:
|
|||
|
static inline unsigned int BitCountByMask(unsigned int Mask) {
|
|||
|
unsigned int BitCount = 0;
|
|||
|
while (Mask) {
|
|||
|
Mask &= Mask - 1;
|
|||
|
BitCount++;
|
|||
|
}
|
|||
|
return BitCount;
|
|||
|
}
|
|||
|
|
|||
|
static inline unsigned int BitPositionByMask(unsigned int Mask) {
|
|||
|
return BitCountByMask((Mask & (~Mask + 1)) - 1);
|
|||
|
}
|
|||
|
|
|||
|
static inline unsigned int ComponentByMask(unsigned int Color, unsigned int Mask) {
|
|||
|
unsigned int Component = Color & Mask;
|
|||
|
return Component >> BitPositionByMask(Mask);
|
|||
|
}
|
|||
|
|
|||
|
static inline unsigned int BitCountToMask(unsigned int BitCount) {
|
|||
|
return (BitCount == 32) ? 0xFFFFFFFF : (1 << BitCount) - 1;
|
|||
|
}
|
|||
|
|
|||
|
static unsigned int Convert(unsigned int Color, unsigned int FromBitCount, unsigned int ToBitCount) {
|
|||
|
if (ToBitCount < FromBitCount) {
|
|||
|
Color >>= (FromBitCount - ToBitCount);
|
|||
|
} else {
|
|||
|
Color <<= (ToBitCount - FromBitCount);
|
|||
|
if (Color > 0) {
|
|||
|
Color |= BitCountToMask(ToBitCount - FromBitCount);
|
|||
|
}
|
|||
|
}
|
|||
|
return Color;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
CBitmap() : m_BitmapData(0), m_BitmapSize(0) {
|
|||
|
Dispose();
|
|||
|
}
|
|||
|
|
|||
|
CBitmap(const char* Filename) : m_BitmapData(0), m_BitmapSize(0) {
|
|||
|
Load(Filename);
|
|||
|
}
|
|||
|
|
|||
|
~CBitmap() {
|
|||
|
Dispose();
|
|||
|
}
|
|||
|
|
|||
|
void Dispose() {
|
|||
|
if (m_BitmapData) {
|
|||
|
delete[] m_BitmapData;
|
|||
|
m_BitmapData = 0;
|
|||
|
}
|
|||
|
memset(&m_BitmapFileHeader, 0, sizeof(m_BitmapFileHeader));
|
|||
|
memset(&m_BitmapHeader, 0, sizeof(m_BitmapHeader));
|
|||
|
}
|
|||
|
|
|||
|
/* Load specified Bitmap and stores it as RGBA in an internal buffer */
|
|||
|
|
|||
|
bool Load(const char *Filename) {
|
|||
|
std::ifstream file(Filename, std::ios::binary | std::ios::in);
|
|||
|
|
|||
|
if (file.bad()) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (file.is_open() == false) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
Dispose();
|
|||
|
|
|||
|
file.read((char*) &m_BitmapFileHeader, BITMAP_FILEHEADER_SIZE);
|
|||
|
if (m_BitmapFileHeader.Signature != BITMAP_SIGNATURE) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
file.read((char*) &m_BitmapHeader, sizeof(BITMAP_HEADER));
|
|||
|
|
|||
|
/* Load Color Table */
|
|||
|
|
|||
|
file.seekg(BITMAP_FILEHEADER_SIZE + m_BitmapHeader.HeaderSize, std::ios::beg);
|
|||
|
|
|||
|
unsigned int ColorTableSize = 0;
|
|||
|
|
|||
|
if (m_BitmapHeader.BitCount == 1) {
|
|||
|
ColorTableSize = 2;
|
|||
|
} else if (m_BitmapHeader.BitCount == 4) {
|
|||
|
ColorTableSize = 16;
|
|||
|
} else if (m_BitmapHeader.BitCount == 8) {
|
|||
|
ColorTableSize = 256;
|
|||
|
}
|
|||
|
|
|||
|
// Always allocate full sized color table
|
|||
|
|
|||
|
BGRA* ColorTable = new BGRA[ColorTableSize]; // std::bad_alloc exception should be thrown if memory is not available
|
|||
|
|
|||
|
file.read((char*) ColorTable, sizeof(BGRA) * m_BitmapHeader.ClrUsed);
|
|||
|
|
|||
|
/* ... Color Table for 16 bits images are not supported yet */
|
|||
|
|
|||
|
m_BitmapSize = GetWidth() * GetHeight();
|
|||
|
m_BitmapData = new RGBA[m_BitmapSize];
|
|||
|
|
|||
|
unsigned int LineWidth = ((GetWidth() * GetBitCount() / 8) + 3) & ~3;
|
|||
|
uint8_t *Line = new uint8_t[LineWidth];
|
|||
|
|
|||
|
file.seekg(m_BitmapFileHeader.BitsOffset, std::ios::beg);
|
|||
|
|
|||
|
int Index = 0;
|
|||
|
bool Result = true;
|
|||
|
|
|||
|
if (m_BitmapHeader.Compression == 0) {
|
|||
|
for (unsigned int i = 0; i < GetHeight(); i++) {
|
|||
|
file.read((char*) Line, LineWidth);
|
|||
|
|
|||
|
uint8_t *LinePtr = Line;
|
|||
|
|
|||
|
for (unsigned int j = 0; j < GetWidth(); j++) {
|
|||
|
if (m_BitmapHeader.BitCount == 1) {
|
|||
|
uint32_t Color = *((uint8_t*) LinePtr);
|
|||
|
for (int k = 0; k < 8; k++) {
|
|||
|
m_BitmapData[Index].Red = ColorTable[Color & 0x80 ? 1 : 0].Red;
|
|||
|
m_BitmapData[Index].Green = ColorTable[Color & 0x80 ? 1 : 0].Green;
|
|||
|
m_BitmapData[Index].Blue = ColorTable[Color & 0x80 ? 1 : 0].Blue;
|
|||
|
m_BitmapData[Index].Alpha = ColorTable[Color & 0x80 ? 1 : 0].Alpha;
|
|||
|
Index++;
|
|||
|
Color <<= 1;
|
|||
|
}
|
|||
|
LinePtr++;
|
|||
|
j += 7;
|
|||
|
} else if (m_BitmapHeader.BitCount == 4) {
|
|||
|
uint32_t Color = *((uint8_t*) LinePtr);
|
|||
|
m_BitmapData[Index].Red = ColorTable[(Color >> 4) & 0x0f].Red;
|
|||
|
m_BitmapData[Index].Green = ColorTable[(Color >> 4) & 0x0f].Green;
|
|||
|
m_BitmapData[Index].Blue = ColorTable[(Color >> 4) & 0x0f].Blue;
|
|||
|
m_BitmapData[Index].Alpha = ColorTable[(Color >> 4) & 0x0f].Alpha;
|
|||
|
Index++;
|
|||
|
m_BitmapData[Index].Red = ColorTable[Color & 0x0f].Red;
|
|||
|
m_BitmapData[Index].Green = ColorTable[Color & 0x0f].Green;
|
|||
|
m_BitmapData[Index].Blue = ColorTable[Color & 0x0f].Blue;
|
|||
|
m_BitmapData[Index].Alpha = ColorTable[Color & 0x0f].Alpha;
|
|||
|
Index++;
|
|||
|
LinePtr++;
|
|||
|
j++;
|
|||
|
} else if (m_BitmapHeader.BitCount == 8) {
|
|||
|
uint32_t Color = *((uint8_t*) LinePtr);
|
|||
|
m_BitmapData[Index].Red = ColorTable[Color].Red;
|
|||
|
m_BitmapData[Index].Green = ColorTable[Color].Green;
|
|||
|
m_BitmapData[Index].Blue = ColorTable[Color].Blue;
|
|||
|
m_BitmapData[Index].Alpha = ColorTable[Color].Alpha;
|
|||
|
Index++;
|
|||
|
LinePtr++;
|
|||
|
} else if (m_BitmapHeader.BitCount == 16) {
|
|||
|
uint32_t Color = *((uint16_t*) LinePtr);
|
|||
|
m_BitmapData[Index].Red = ((Color >> 10) & 0x1f) << 3;
|
|||
|
m_BitmapData[Index].Green = ((Color >> 5) & 0x1f) << 3;
|
|||
|
m_BitmapData[Index].Blue = (Color & 0x1f) << 3;
|
|||
|
m_BitmapData[Index].Alpha = 255;
|
|||
|
Index++;
|
|||
|
LinePtr += 2;
|
|||
|
} else if (m_BitmapHeader.BitCount == 24) {
|
|||
|
uint32_t Color = *((uint32_t*) LinePtr);
|
|||
|
m_BitmapData[Index].Blue = Color & 0xff;
|
|||
|
m_BitmapData[Index].Green = (Color >> 8) & 0xff;
|
|||
|
m_BitmapData[Index].Red = (Color >> 16) & 0xff;
|
|||
|
m_BitmapData[Index].Alpha = 255;
|
|||
|
Index++;
|
|||
|
LinePtr += 3;
|
|||
|
} else if (m_BitmapHeader.BitCount == 32) {
|
|||
|
uint32_t Color = *((uint32_t*) LinePtr);
|
|||
|
m_BitmapData[Index].Blue = Color & 0xff;
|
|||
|
m_BitmapData[Index].Green = (Color >> 8) & 0xff;
|
|||
|
m_BitmapData[Index].Red = (Color >> 16) & 0xff;
|
|||
|
m_BitmapData[Index].Alpha = Color >> 24;
|
|||
|
Index++;
|
|||
|
LinePtr += 4;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} else if (m_BitmapHeader.Compression == 1) { // RLE 8
|
|||
|
uint8_t Count = 0;
|
|||
|
uint8_t ColorIndex = 0;
|
|||
|
int x = 0, y = 0;
|
|||
|
|
|||
|
while (file.eof() == false) {
|
|||
|
file.read((char*) &Count, sizeof(uint8_t));
|
|||
|
file.read((char*) &ColorIndex, sizeof(uint8_t));
|
|||
|
|
|||
|
if (Count > 0) {
|
|||
|
Index = x + y * GetWidth();
|
|||
|
for (int k = 0; k < Count; k++) {
|
|||
|
m_BitmapData[Index + k].Red = ColorTable[ColorIndex].Red;
|
|||
|
m_BitmapData[Index + k].Green = ColorTable[ColorIndex].Green;
|
|||
|
m_BitmapData[Index + k].Blue = ColorTable[ColorIndex].Blue;
|
|||
|
m_BitmapData[Index + k].Alpha = ColorTable[ColorIndex].Alpha;
|
|||
|
}
|
|||
|
x += Count;
|
|||
|
} else if (Count == 0) {
|
|||
|
int Flag = ColorIndex;
|
|||
|
if (Flag == 0) {
|
|||
|
x = 0;
|
|||
|
y++;
|
|||
|
} else if (Flag == 1) {
|
|||
|
break;
|
|||
|
} else if (Flag == 2) {
|
|||
|
char rx = 0;
|
|||
|
char ry = 0;
|
|||
|
file.read((char*) &rx, sizeof(char));
|
|||
|
file.read((char*) &ry, sizeof(char));
|
|||
|
x += rx;
|
|||
|
y += ry;
|
|||
|
} else {
|
|||
|
Count = Flag;
|
|||
|
Index = x + y * GetWidth();
|
|||
|
for (int k = 0; k < Count; k++) {
|
|||
|
file.read((char*) &ColorIndex, sizeof(uint8_t));
|
|||
|
m_BitmapData[Index + k].Red = ColorTable[ColorIndex].Red;
|
|||
|
m_BitmapData[Index + k].Green = ColorTable[ColorIndex].Green;
|
|||
|
m_BitmapData[Index + k].Blue = ColorTable[ColorIndex].Blue;
|
|||
|
m_BitmapData[Index + k].Alpha = ColorTable[ColorIndex].Alpha;
|
|||
|
}
|
|||
|
x += Count;
|
|||
|
// Attention: Current Microsoft STL implementation seems to be buggy, tellg() always returns 0.
|
|||
|
if (file.tellg() & 1) {
|
|||
|
file.seekg(1, std::ios::cur);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} else if (m_BitmapHeader.Compression == 2) { // RLE 4
|
|||
|
/* RLE 4 is not supported */
|
|||
|
Result = false;
|
|||
|
} else if (m_BitmapHeader.Compression == 3) { // BITFIELDS
|
|||
|
|
|||
|
/* We assumes that mask of each color component can be in any order */
|
|||
|
|
|||
|
uint32_t BitCountRed = CColor::BitCountByMask(m_BitmapHeader.RedMask);
|
|||
|
uint32_t BitCountGreen = CColor::BitCountByMask(m_BitmapHeader.GreenMask);
|
|||
|
uint32_t BitCountBlue = CColor::BitCountByMask(m_BitmapHeader.BlueMask);
|
|||
|
uint32_t BitCountAlpha = CColor::BitCountByMask(m_BitmapHeader.AlphaMask);
|
|||
|
|
|||
|
for (unsigned int i = 0; i < GetHeight(); i++) {
|
|||
|
file.read((char*) Line, LineWidth);
|
|||
|
|
|||
|
uint8_t *LinePtr = Line;
|
|||
|
|
|||
|
for (unsigned int j = 0; j < GetWidth(); j++) {
|
|||
|
|
|||
|
uint32_t Color = 0;
|
|||
|
|
|||
|
if (m_BitmapHeader.BitCount == 16) {
|
|||
|
Color = *((uint16_t*) LinePtr);
|
|||
|
LinePtr += 2;
|
|||
|
} else if (m_BitmapHeader.BitCount == 32) {
|
|||
|
Color = *((uint32_t*) LinePtr);
|
|||
|
LinePtr += 4;
|
|||
|
} else {
|
|||
|
// Other formats are not valid
|
|||
|
}
|
|||
|
m_BitmapData[Index].Red = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.RedMask), BitCountRed, 8);
|
|||
|
m_BitmapData[Index].Green = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.GreenMask), BitCountGreen, 8);
|
|||
|
m_BitmapData[Index].Blue = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.BlueMask), BitCountBlue, 8);
|
|||
|
m_BitmapData[Index].Alpha = CColor::Convert(CColor::ComponentByMask(Color, m_BitmapHeader.AlphaMask), BitCountAlpha, 8);
|
|||
|
|
|||
|
Index++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
delete [] ColorTable;
|
|||
|
delete [] Line;
|
|||
|
|
|||
|
file.close();
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
bool Save(const char* Filename, unsigned int BitCount = 32) {
|
|||
|
bool Result = true;
|
|||
|
|
|||
|
std::ofstream file(Filename, std::ios::out | std::ios::binary);
|
|||
|
|
|||
|
if (file.is_open() == false) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
BITMAP_FILEHEADER bfh;
|
|||
|
BITMAP_HEADER bh;
|
|||
|
memset(&bfh, 0, sizeof(bfh));
|
|||
|
memset(&bh, 0, sizeof(bh));
|
|||
|
|
|||
|
bfh.Signature = BITMAP_SIGNATURE;
|
|||
|
bfh.BitsOffset = BITMAP_FILEHEADER_SIZE + sizeof(BITMAP_HEADER);
|
|||
|
bfh.Size = (GetWidth() * GetHeight() * BitCount) / 8 + bfh.BitsOffset;
|
|||
|
|
|||
|
bh.HeaderSize = sizeof(BITMAP_HEADER);
|
|||
|
bh.BitCount = BitCount;
|
|||
|
|
|||
|
if (BitCount == 32) {
|
|||
|
bh.Compression = 3; // BITFIELD
|
|||
|
bh.AlphaMask = 0xff000000;
|
|||
|
bh.BlueMask = 0x00ff0000;
|
|||
|
bh.GreenMask = 0x0000ff00;
|
|||
|
bh.RedMask = 0x000000ff;
|
|||
|
} else if (BitCount == 16) {
|
|||
|
bh.Compression = 3; // BITFIELD
|
|||
|
bh.AlphaMask = 0x00000000;
|
|||
|
bh.BlueMask = 0x0000001f;
|
|||
|
bh.GreenMask = 0x000007E0;
|
|||
|
bh.RedMask = 0x0000F800;
|
|||
|
} else {
|
|||
|
bh.Compression = 0; // RGB
|
|||
|
}
|
|||
|
|
|||
|
unsigned int LineWidth = (GetWidth() + 3) & ~3;
|
|||
|
|
|||
|
bh.Planes = 1;
|
|||
|
bh.Height = GetHeight();
|
|||
|
bh.Width = GetWidth();
|
|||
|
bh.SizeImage = (LineWidth * BitCount * GetHeight()) / 8;
|
|||
|
bh.PelsPerMeterX = 3780;
|
|||
|
bh.PelsPerMeterY = 3780;
|
|||
|
|
|||
|
if (BitCount == 32) {
|
|||
|
file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER));
|
|||
|
file.write((char*) &bh, sizeof(BITMAP_HEADER));
|
|||
|
file.write((char*) m_BitmapData, bh.SizeImage);
|
|||
|
} else if (BitCount < 16) {
|
|||
|
uint8_t* Bitmap = new uint8_t[bh.SizeImage];
|
|||
|
|
|||
|
BGRA *Palette = 0;
|
|||
|
unsigned int PaletteSize = 0;
|
|||
|
|
|||
|
if (GetBitsWithPalette(Bitmap, bh.SizeImage, BitCount, Palette, PaletteSize)) {
|
|||
|
bfh.BitsOffset += PaletteSize * sizeof(BGRA);
|
|||
|
|
|||
|
file.write((char*) &bfh, BITMAP_FILEHEADER_SIZE);
|
|||
|
file.write((char*) &bh, sizeof(BITMAP_HEADER));
|
|||
|
file.write((char*) Palette, PaletteSize * sizeof(BGRA));
|
|||
|
file.write((char*) Bitmap, bh.SizeImage);
|
|||
|
}
|
|||
|
delete [] Bitmap;
|
|||
|
delete [] Palette;
|
|||
|
} else {
|
|||
|
uint32_t RedMask = 0;
|
|||
|
uint32_t GreenMask = 0;
|
|||
|
uint32_t BlueMask = 0;
|
|||
|
uint32_t AlphaMask = 0;
|
|||
|
|
|||
|
if (BitCount == 16) {
|
|||
|
RedMask = 0x0000F800;
|
|||
|
GreenMask = 0x000007E0;
|
|||
|
BlueMask = 0x0000001F;
|
|||
|
AlphaMask = 0x00000000;
|
|||
|
} else if (BitCount == 24) {
|
|||
|
RedMask = 0x00FF0000;
|
|||
|
GreenMask = 0x0000FF00;
|
|||
|
BlueMask = 0x000000FF;
|
|||
|
} else {
|
|||
|
// Other color formats are not valid
|
|||
|
Result = false;
|
|||
|
}
|
|||
|
|
|||
|
if (Result) {
|
|||
|
if (GetBits(NULL, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) {
|
|||
|
uint8_t* Bitmap = new uint8_t[bh.SizeImage];
|
|||
|
if (GetBits(Bitmap, bh.SizeImage, RedMask, GreenMask, BlueMask, AlphaMask)) {
|
|||
|
file.write((char*) &bfh, sizeof(BITMAP_FILEHEADER));
|
|||
|
file.write((char*) &bh, sizeof(BITMAP_HEADER));
|
|||
|
file.write((char*) Bitmap, bh.SizeImage);
|
|||
|
}
|
|||
|
delete [] Bitmap;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
file.close();
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
unsigned int GetWidth() {
|
|||
|
/* Add plausibility test */
|
|||
|
// if (abs(m_BitmapHeader.Width) > 8192) {
|
|||
|
// m_BitmapHeader.Width = 8192;
|
|||
|
// }
|
|||
|
return m_BitmapHeader.Width < 0 ? -m_BitmapHeader.Width : m_BitmapHeader.Width;
|
|||
|
}
|
|||
|
|
|||
|
unsigned int GetHeight() {
|
|||
|
/* Add plausibility test */
|
|||
|
// if (abs(m_BitmapHeader.Height) > 8192) {
|
|||
|
// m_BitmapHeader.Height = 8192;
|
|||
|
// }
|
|||
|
return m_BitmapHeader.Height < 0 ? -m_BitmapHeader.Height : m_BitmapHeader.Height;
|
|||
|
}
|
|||
|
|
|||
|
unsigned int GetBitCount() {
|
|||
|
/* Add plausibility test */
|
|||
|
// if (m_BitmapHeader.BitCount > 32) {
|
|||
|
// m_BitmapHeader.BitCount = 32;
|
|||
|
// }
|
|||
|
return m_BitmapHeader.BitCount;
|
|||
|
}
|
|||
|
|
|||
|
/* Copies internal RGBA buffer to user specified buffer */
|
|||
|
|
|||
|
bool GetBits(void* Buffer, unsigned int &Size) {
|
|||
|
bool Result = false;
|
|||
|
if (Size == 0 || Buffer == 0) {
|
|||
|
Size = m_BitmapSize * sizeof(RGBA);
|
|||
|
Result = m_BitmapSize != 0;
|
|||
|
} else {
|
|||
|
memcpy(Buffer, m_BitmapData, Size);
|
|||
|
Result = true;
|
|||
|
}
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
/* Returns internal RGBA buffer */
|
|||
|
|
|||
|
void* GetBits() {
|
|||
|
return m_BitmapData;
|
|||
|
}
|
|||
|
|
|||
|
/* Copies internal RGBA buffer to user specified buffer and converts it into destination
|
|||
|
* bit format specified by component masks.
|
|||
|
*
|
|||
|
* Typical Bitmap color formats (BGR/BGRA):
|
|||
|
*
|
|||
|
* Masks for 16 bit (5-5-5): ALPHA = 0x00000000, RED = 0x00007C00, GREEN = 0x000003E0, BLUE = 0x0000001F
|
|||
|
* Masks for 16 bit (5-6-5): ALPHA = 0x00000000, RED = 0x0000F800, GREEN = 0x000007E0, BLUE = 0x0000001F
|
|||
|
* Masks for 24 bit: ALPHA = 0x00000000, RED = 0x00FF0000, GREEN = 0x0000FF00, BLUE = 0x000000FF
|
|||
|
* Masks for 32 bit: ALPHA = 0xFF000000, RED = 0x00FF0000, GREEN = 0x0000FF00, BLUE = 0x000000FF
|
|||
|
*
|
|||
|
* Other color formats (RGB/RGBA):
|
|||
|
*
|
|||
|
* Masks for 32 bit (RGBA): ALPHA = 0xFF000000, RED = 0x000000FF, GREEN = 0x0000FF00, BLUE = 0x00FF0000
|
|||
|
*
|
|||
|
* Bit count will be rounded to next 8 bit boundary. If IncludePadding is true, it will be ensured
|
|||
|
* that line width is a multiple of 4. padding bytes are included if necessary.
|
|||
|
*
|
|||
|
* NOTE: systems with big endian byte order may require masks in inversion order.
|
|||
|
*/
|
|||
|
|
|||
|
bool GetBits(void* Buffer, unsigned int &Size, unsigned int RedMask, unsigned int GreenMask, unsigned int BlueMask, unsigned int AlphaMask, bool IncludePadding = true) {
|
|||
|
bool Result = false;
|
|||
|
|
|||
|
uint32_t BitCountRed = CColor::BitCountByMask(RedMask);
|
|||
|
uint32_t BitCountGreen = CColor::BitCountByMask(GreenMask);
|
|||
|
uint32_t BitCountBlue = CColor::BitCountByMask(BlueMask);
|
|||
|
uint32_t BitCountAlpha = CColor::BitCountByMask(AlphaMask);
|
|||
|
|
|||
|
unsigned int BitCount = (BitCountRed + BitCountGreen + BitCountBlue + BitCountAlpha + 7) & ~7;
|
|||
|
|
|||
|
if (BitCount > 32) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
unsigned int w = GetWidth();
|
|||
|
//unsigned int LineWidth = (w + 3) & ~3;
|
|||
|
unsigned int dataBytesPerLine = (w * BitCount + 7) / 8;
|
|||
|
unsigned int LineWidth = (dataBytesPerLine + 3) & ~3;
|
|||
|
|
|||
|
if (Size == 0 || Buffer == 0) {
|
|||
|
//Size = (LineWidth * GetHeight() * BitCount) / 8 + sizeof(unsigned int);
|
|||
|
Size = (GetWidth() * GetHeight() * BitCount) / 8 + sizeof(unsigned int);
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
uint8_t* BufferPtr = (uint8_t*) Buffer;
|
|||
|
|
|||
|
Result = true;
|
|||
|
|
|||
|
uint32_t BitPosRed = CColor::BitPositionByMask(RedMask);
|
|||
|
uint32_t BitPosGreen = CColor::BitPositionByMask(GreenMask);
|
|||
|
uint32_t BitPosBlue = CColor::BitPositionByMask(BlueMask);
|
|||
|
uint32_t BitPosAlpha = CColor::BitPositionByMask(AlphaMask);
|
|||
|
|
|||
|
unsigned int j = 0;
|
|||
|
|
|||
|
for (unsigned int i = 0; i < m_BitmapSize; i++) {
|
|||
|
*(uint32_t*) BufferPtr =
|
|||
|
(CColor::Convert(m_BitmapData[i].Blue, 8, BitCountBlue) << BitPosBlue) |
|
|||
|
(CColor::Convert(m_BitmapData[i].Green, 8, BitCountGreen) << BitPosGreen) |
|
|||
|
(CColor::Convert(m_BitmapData[i].Red, 8, BitCountRed) << BitPosRed) |
|
|||
|
(CColor::Convert(m_BitmapData[i].Alpha, 8, BitCountAlpha) << BitPosAlpha);
|
|||
|
|
|||
|
if (IncludePadding) {
|
|||
|
j++;
|
|||
|
if (j >= w) {
|
|||
|
for (unsigned int k = 0; k < LineWidth - dataBytesPerLine; k++) {
|
|||
|
BufferPtr += (BitCount >> 3);
|
|||
|
}
|
|||
|
j = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BufferPtr += (BitCount >> 3);
|
|||
|
}
|
|||
|
|
|||
|
Size -= sizeof(unsigned int);
|
|||
|
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
/* See GetBits().
|
|||
|
* It creates a corresponding color table (palette) which have to be destroyed by the user after usage.
|
|||
|
*
|
|||
|
* Supported Bit depths are: 4, 8
|
|||
|
*
|
|||
|
* Todo: Optimize, use optimized palette, do ditehring (see my dithering class), support padding for 4 bit bitmaps
|
|||
|
*/
|
|||
|
|
|||
|
bool GetBitsWithPalette(void* Buffer, unsigned int &Size, unsigned int BitCount, BGRA* &Palette, unsigned int &PaletteSize, bool OptimalPalette = false, bool IncludePadding = true) {
|
|||
|
bool Result = false;
|
|||
|
|
|||
|
if (BitCount > 16) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
unsigned int w = GetWidth();
|
|||
|
unsigned int dataBytesPerLine = (w * BitCount + 7) / 8;
|
|||
|
unsigned int LineWidth = (dataBytesPerLine + 3) & ~3;
|
|||
|
|
|||
|
if (Size == 0 || Buffer == 0) {
|
|||
|
Size = (LineWidth * GetHeight() * BitCount) / 8;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (OptimalPalette) {
|
|||
|
PaletteSize = 0;
|
|||
|
// Not implemented
|
|||
|
} else {
|
|||
|
if (BitCount == 1) {
|
|||
|
PaletteSize = 2;
|
|||
|
// Not implemented: Who need that?
|
|||
|
} else if (BitCount == 4) { // 2:2:1
|
|||
|
PaletteSize = 16;
|
|||
|
Palette = new BGRA[PaletteSize];
|
|||
|
for (int r = 0; r < 4; r++) {
|
|||
|
for (int g = 0; g < 2; g++) {
|
|||
|
for (int b = 0; b < 2; b++) {
|
|||
|
Palette[r | g << 2 | b << 3].Red = r ? (r << 6) | 0x3f : 0;
|
|||
|
Palette[r | g << 2 | b << 3].Green = g ? (g << 7) | 0x7f : 0;
|
|||
|
Palette[r | g << 2 | b << 3].Blue = b ? (b << 7) | 0x7f : 0;
|
|||
|
Palette[r | g << 2 | b << 3].Alpha = 0xff;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} else if (BitCount == 8) { // 3:3:2
|
|||
|
PaletteSize = 256;
|
|||
|
Palette = new BGRA[PaletteSize];
|
|||
|
for (int r = 0; r < 8; r++) {
|
|||
|
for (int g = 0; g < 8; g++) {
|
|||
|
for (int b = 0; b < 4; b++) {
|
|||
|
Palette[r | g << 3 | b << 6].Red = r ? (r << 5) | 0x1f : 0;
|
|||
|
Palette[r | g << 3 | b << 6].Green = g ? (g << 5) | 0x1f : 0;
|
|||
|
Palette[r | g << 3 | b << 6].Blue = b ? (b << 6) | 0x3f : 0;
|
|||
|
Palette[r | g << 3 | b << 6].Alpha = 0xff;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} else if (BitCount == 16) { // 5:5:5
|
|||
|
// Not implemented
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
unsigned int j = 0;
|
|||
|
uint8_t* BufferPtr = (uint8_t*) Buffer;
|
|||
|
|
|||
|
for (unsigned int i = 0; i < m_BitmapSize; i++) {
|
|||
|
if (BitCount == 1) {
|
|||
|
// Not implemented: Who needs that?
|
|||
|
} else if (BitCount == 4) {
|
|||
|
*BufferPtr = ((m_BitmapData[i].Red >> 6) | (m_BitmapData[i].Green >> 7) << 2 | (m_BitmapData[i].Blue >> 7) << 3) << 4;
|
|||
|
i++;
|
|||
|
*BufferPtr |= (m_BitmapData[i].Red >> 6) | (m_BitmapData[i].Green >> 7) << 2 | (m_BitmapData[i].Blue >> 7) << 3;
|
|||
|
} else if (BitCount == 8) {
|
|||
|
*BufferPtr = (m_BitmapData[i].Red >> 5) | (m_BitmapData[i].Green >> 5) << 3 | (m_BitmapData[i].Blue >> 5) << 6;
|
|||
|
} else if (BitCount == 16) {
|
|||
|
// Not implemented
|
|||
|
}
|
|||
|
|
|||
|
if (IncludePadding) {
|
|||
|
j++;
|
|||
|
if (j >= w) {
|
|||
|
for (unsigned int k = 0; k < (LineWidth - dataBytesPerLine); k++) {
|
|||
|
BufferPtr += BitCount / 8;
|
|||
|
}
|
|||
|
j = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BufferPtr++;
|
|||
|
}
|
|||
|
|
|||
|
Result = true;
|
|||
|
|
|||
|
return Result;
|
|||
|
}
|
|||
|
|
|||
|
/* Set Bitmap Bits. Will be converted to RGBA internally */
|
|||
|
|
|||
|
bool SetBits(void* Buffer, unsigned int Width, unsigned int Height, unsigned int RedMask, unsigned int GreenMask, unsigned int BlueMask, unsigned int AlphaMask = 0) {
|
|||
|
if (Buffer == 0) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
uint8_t *BufferPtr = (uint8_t*) Buffer;
|
|||
|
|
|||
|
Dispose();
|
|||
|
|
|||
|
m_BitmapHeader.Width = Width;
|
|||
|
m_BitmapHeader.Height = Height;
|
|||
|
m_BitmapHeader.BitCount = 32;
|
|||
|
m_BitmapHeader.Compression = 3;
|
|||
|
|
|||
|
m_BitmapSize = GetWidth() * GetHeight();
|
|||
|
m_BitmapData = new RGBA[m_BitmapSize];
|
|||
|
|
|||
|
/* Find bit count by masks (rounded to next 8 bit boundary) */
|
|||
|
|
|||
|
unsigned int BitCount = (CColor::BitCountByMask(RedMask | GreenMask | BlueMask | AlphaMask) + 7) & ~7;
|
|||
|
|
|||
|
uint32_t BitCountRed = CColor::BitCountByMask(RedMask);
|
|||
|
uint32_t BitCountGreen = CColor::BitCountByMask(GreenMask);
|
|||
|
uint32_t BitCountBlue = CColor::BitCountByMask(BlueMask);
|
|||
|
uint32_t BitCountAlpha = CColor::BitCountByMask(AlphaMask);
|
|||
|
|
|||
|
for (unsigned int i = 0; i < m_BitmapSize; i++) {
|
|||
|
unsigned int Color = 0;
|
|||
|
if (BitCount <= 8) {
|
|||
|
Color = *((uint8_t*) BufferPtr);
|
|||
|
BufferPtr += 1;
|
|||
|
} else if (BitCount <= 16) {
|
|||
|
Color = *((uint16_t*) BufferPtr);
|
|||
|
BufferPtr += 2;
|
|||
|
} else if (BitCount <= 24) {
|
|||
|
Color = *((uint32_t*) BufferPtr);
|
|||
|
BufferPtr += 3;
|
|||
|
} else if (BitCount <= 32) {
|
|||
|
Color = *((uint32_t*) BufferPtr);
|
|||
|
BufferPtr += 4;
|
|||
|
} else {
|
|||
|
/* unsupported */
|
|||
|
BufferPtr += 1;
|
|||
|
}
|
|||
|
m_BitmapData[i].Alpha = CColor::Convert(CColor::ComponentByMask(Color, AlphaMask), BitCountAlpha, 8);
|
|||
|
m_BitmapData[i].Red = CColor::Convert(CColor::ComponentByMask(Color, RedMask), BitCountRed, 8);
|
|||
|
m_BitmapData[i].Green = CColor::Convert(CColor::ComponentByMask(Color, GreenMask), BitCountGreen, 8);
|
|||
|
m_BitmapData[i].Blue = CColor::Convert(CColor::ComponentByMask(Color, BlueMask), BitCountBlue, 8);
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// Fonction pour charger une texture
|
|||
|
//
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <string.h>
|
|||
|
#include <stdio.h>
|
|||
|
//#include <SDL_surface.h>
|
|||
|
|
|||
|
unsigned char *ChargerImage( std::string fichier, GLsizei &largeur, GLsizei &hauteur )
|
|||
|
{
|
|||
|
// vérifier la présence du fichier BMP en essayant de l'ouvrir
|
|||
|
FILE *img = fopen( fichier.c_str(), "r" );
|
|||
|
if ( !img )
|
|||
|
{
|
|||
|
std::cerr << "Fichier de texture manquant: " << fichier << std::endl;
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
fclose( img );
|
|||
|
|
|||
|
// lire le fichier dans un objet CBitmap
|
|||
|
CBitmap image( fichier.c_str() );
|
|||
|
// obtenir la taille de l'image et les composantes RGBA
|
|||
|
largeur = image.GetWidth();
|
|||
|
hauteur = image.GetHeight();
|
|||
|
unsigned int taille = largeur * hauteur * 4; // l * h * 4 composantes
|
|||
|
unsigned char *pixels = new unsigned char[taille];
|
|||
|
image.GetBits( (void*) pixels, taille, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 );
|
|||
|
|
|||
|
//SDL_Surface* surface = SDL_LoadBMP( fichier.c_str() );
|
|||
|
// https://wiki.libsdl.org/SDL_LoadBMP
|
|||
|
// largeur = surface->w;
|
|||
|
// hauteur = surface->h;
|
|||
|
// pixels = surface->pixels;
|
|||
|
|
|||
|
return pixels;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef INF2705_FORME_H
|
|||
|
#define INF2705_FORME_H
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// Fonctions variées pour afficher des formes connues
|
|||
|
// (INF2705, Benoît Ozell)
|
|||
|
////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <GL/glew.h>
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
#if !defined( __APPLE__ )
|
|||
|
|
|||
|
/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
|
|||
|
|
|||
|
/**
|
|||
|
(c) Copyright 1993, Silicon Graphics, Inc.
|
|||
|
|
|||
|
ALL RIGHTS RESERVED
|
|||
|
|
|||
|
Permission to use, copy, modify, and distribute this software
|
|||
|
for any purpose and without fee is hereby granted, provided
|
|||
|
that the above copyright notice appear in all copies and that
|
|||
|
both the copyright notice and this permission notice appear in
|
|||
|
supporting documentation, and that the name of Silicon
|
|||
|
Graphics, Inc. not be used in advertising or publicity
|
|||
|
pertaining to distribution of the software without specific,
|
|||
|
written prior permission.
|
|||
|
|
|||
|
THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
|
|||
|
"AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
|
|||
|
OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
|
|||
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO
|
|||
|
EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE
|
|||
|
ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
|
|||
|
CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
|
|||
|
INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
|
|||
|
SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
|
|||
|
NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY
|
|||
|
OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|||
|
ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
|
|||
|
PERFORMANCE OF THIS SOFTWARE.
|
|||
|
|
|||
|
US Government Users Restricted Rights
|
|||
|
|
|||
|
Use, duplication, or disclosure by the Government is subject to
|
|||
|
restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
|
|||
|
(c)(1)(ii) of the Rights in Technical Data and Computer
|
|||
|
Software clause at DFARS 252.227-7013 and/or in similar or
|
|||
|
successor clauses in the FAR or the DOD or NASA FAR
|
|||
|
Supplement. Unpublished-- rights reserved under the copyright
|
|||
|
laws of the United States. Contractor/manufacturer is Silicon
|
|||
|
Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA
|
|||
|
94039-7311.
|
|||
|
|
|||
|
OpenGL(TM) is a trademark of Silicon Graphics, Inc.
|
|||
|
*/
|
|||
|
|
|||
|
#include <math.h>
|
|||
|
#include <stdio.h>
|
|||
|
|
|||
|
static GLfloat dodec[20][3];
|
|||
|
|
|||
|
static void initDodecahedron(void)
|
|||
|
{
|
|||
|
GLfloat alpha, beta;
|
|||
|
|
|||
|
alpha = sqrt(2.0 / (3.0 + sqrt(5.0)));
|
|||
|
beta = 1.0 + sqrt(6.0 / (3.0 + sqrt(5.0)) - 2.0 + 2.0 * sqrt(2.0 / (3.0 + sqrt(5.0))));
|
|||
|
dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
|
|||
|
dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
|
|||
|
dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
|
|||
|
dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
|
|||
|
dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
|
|||
|
dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
|
|||
|
dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
|
|||
|
dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
|
|||
|
dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
|
|||
|
dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
|
|||
|
dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
|
|||
|
dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
|
|||
|
dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
|
|||
|
dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
|
|||
|
dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
|
|||
|
dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
|
|||
|
dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
|
|||
|
dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
|
|||
|
dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
|
|||
|
dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#define DIFF3(_a,_b,_c) { \
|
|||
|
(_c)[0] = (_a)[0] - (_b)[0]; \
|
|||
|
(_c)[1] = (_a)[1] - (_b)[1]; \
|
|||
|
(_c)[2] = (_a)[2] - (_b)[2]; \
|
|||
|
}
|
|||
|
|
|||
|
static void crossprod(GLfloat v1[3], GLfloat v2[3], GLfloat prod[3])
|
|||
|
{
|
|||
|
GLfloat p[3]; /* in case prod == v1 or v2 */
|
|||
|
|
|||
|
p[0] = v1[1] * v2[2] - v2[1] * v1[2];
|
|||
|
p[1] = v1[2] * v2[0] - v2[2] * v1[0];
|
|||
|
p[2] = v1[0] * v2[1] - v2[0] * v1[1];
|
|||
|
prod[0] = p[0];
|
|||
|
prod[1] = p[1];
|
|||
|
prod[2] = p[2];
|
|||
|
}
|
|||
|
|
|||
|
static void normalize(GLfloat v[3])
|
|||
|
{
|
|||
|
GLfloat d;
|
|||
|
|
|||
|
d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|||
|
if (d == 0.0)
|
|||
|
{
|
|||
|
printf("normalize: zero length vector");
|
|||
|
v[0] = d = 1.0;
|
|||
|
}
|
|||
|
d = 1 / d;
|
|||
|
v[0] *= d;
|
|||
|
v[1] *= d;
|
|||
|
v[2] *= d;
|
|||
|
}
|
|||
|
|
|||
|
static void pentagon(int a, int b, int c, int d, int e, GLenum shadeType)
|
|||
|
{
|
|||
|
GLfloat n0[3], d1[3], d2[3];
|
|||
|
|
|||
|
DIFF3(dodec[a], dodec[b], d1);
|
|||
|
DIFF3(dodec[b], dodec[c], d2);
|
|||
|
crossprod(d1, d2, n0);
|
|||
|
normalize(n0);
|
|||
|
|
|||
|
glBegin(shadeType);
|
|||
|
glNormal3fv(n0);
|
|||
|
glVertex3fv(&dodec[a][0]);
|
|||
|
glVertex3fv(&dodec[b][0]);
|
|||
|
glVertex3fv(&dodec[c][0]);
|
|||
|
glVertex3fv(&dodec[d][0]);
|
|||
|
glVertex3fv(&dodec[e][0]);
|
|||
|
glEnd();
|
|||
|
}
|
|||
|
|
|||
|
static void dodecahedron(GLenum type)
|
|||
|
{
|
|||
|
static int inited = 0;
|
|||
|
|
|||
|
if (inited == 0)
|
|||
|
{
|
|||
|
inited = 1;
|
|||
|
initDodecahedron();
|
|||
|
}
|
|||
|
pentagon(0, 1, 9, 16, 5, type);
|
|||
|
pentagon(1, 0, 3, 18, 7, type);
|
|||
|
pentagon(1, 7, 11, 10, 9, type);
|
|||
|
pentagon(11, 7, 18, 19, 6, type);
|
|||
|
pentagon(8, 17, 16, 9, 10, type);
|
|||
|
pentagon(2, 14, 15, 6, 19, type);
|
|||
|
pentagon(2, 13, 12, 4, 14, type);
|
|||
|
pentagon(2, 19, 18, 3, 13, type);
|
|||
|
pentagon(3, 0, 5, 12, 13, type);
|
|||
|
pentagon(6, 15, 8, 10, 11, type);
|
|||
|
pentagon(4, 17, 8, 15, 14, type);
|
|||
|
pentagon(4, 12, 5, 16, 17, type);
|
|||
|
}
|
|||
|
|
|||
|
void shapesWireDodecahedron(void)
|
|||
|
{
|
|||
|
dodecahedron(GL_LINE_LOOP);
|
|||
|
}
|
|||
|
|
|||
|
void shapesSolidDodecahedron(void)
|
|||
|
{
|
|||
|
dodecahedron(GL_TRIANGLE_FAN);
|
|||
|
}
|
|||
|
|
|||
|
static void recorditem(GLfloat * n1, GLfloat * n2, GLfloat * n3,
|
|||
|
GLenum shadeType)
|
|||
|
{
|
|||
|
GLfloat q0[3], q1[3];
|
|||
|
|
|||
|
DIFF3(n1, n2, q0);
|
|||
|
DIFF3(n2, n3, q1);
|
|||
|
crossprod(q0, q1, q1);
|
|||
|
normalize(q1);
|
|||
|
|
|||
|
glBegin(shadeType);
|
|||
|
glNormal3fv(q1);
|
|||
|
glVertex3fv(n1);
|
|||
|
glVertex3fv(n2);
|
|||
|
glVertex3fv(n3);
|
|||
|
glEnd();
|
|||
|
}
|
|||
|
|
|||
|
static void subdivide(GLfloat * v0, GLfloat * v1, GLfloat * v2,
|
|||
|
GLenum shadeType)
|
|||
|
{
|
|||
|
int depth = 1;
|
|||
|
for (int i = 0; i < depth; i++)
|
|||
|
{
|
|||
|
for (int j = 0; i + j < depth; j++)
|
|||
|
{
|
|||
|
GLfloat w0[3], w1[3], w2[3];
|
|||
|
int k = depth - i - j;
|
|||
|
for (int n = 0; n < 3; n++)
|
|||
|
{
|
|||
|
w0[n] = (i * v0[n] + j * v1[n] + k * v2[n]) / depth;
|
|||
|
w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n]) / depth;
|
|||
|
w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n]) / depth;
|
|||
|
}
|
|||
|
GLfloat l;
|
|||
|
l = sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]);
|
|||
|
w0[0] /= l;
|
|||
|
w0[1] /= l;
|
|||
|
w0[2] /= l;
|
|||
|
l = sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]);
|
|||
|
w1[0] /= l;
|
|||
|
w1[1] /= l;
|
|||
|
w1[2] /= l;
|
|||
|
l = sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]);
|
|||
|
w2[0] /= l;
|
|||
|
w2[1] /= l;
|
|||
|
w2[2] /= l;
|
|||
|
recorditem(w1, w0, w2, shadeType);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void drawtriangle(int i, GLfloat data[][3], int ndx[][3],
|
|||
|
GLenum shadeType)
|
|||
|
{
|
|||
|
GLfloat *x0 = data[ndx[i][0]];
|
|||
|
GLfloat *x1 = data[ndx[i][1]];
|
|||
|
GLfloat *x2 = data[ndx[i][2]];
|
|||
|
subdivide(x0, x1, x2, shadeType);
|
|||
|
}
|
|||
|
|
|||
|
/* octahedron data: The octahedron produced is centered at the
|
|||
|
origin and has radius 1.0 */
|
|||
|
static GLfloat odata[6][3] =
|
|||
|
{
|
|||
|
{1.0, 0.0, 0.0},
|
|||
|
{-1.0, 0.0, 0.0},
|
|||
|
{0.0, 1.0, 0.0},
|
|||
|
{0.0, -1.0, 0.0},
|
|||
|
{0.0, 0.0, 1.0},
|
|||
|
{0.0, 0.0, -1.0}
|
|||
|
};
|
|||
|
|
|||
|
static int ondex[8][3] =
|
|||
|
{
|
|||
|
{0, 4, 2},
|
|||
|
{1, 2, 4},
|
|||
|
{0, 3, 4},
|
|||
|
{1, 4, 3},
|
|||
|
{0, 2, 5},
|
|||
|
{1, 5, 2},
|
|||
|
{0, 5, 3},
|
|||
|
{1, 3, 5}
|
|||
|
};
|
|||
|
|
|||
|
static void octahedron(GLenum shadeType)
|
|||
|
{
|
|||
|
for (int i = 7; i >= 0; i--)
|
|||
|
{
|
|||
|
drawtriangle(i, odata, ondex, shadeType);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void shapesWireOctahedron(void)
|
|||
|
{
|
|||
|
octahedron(GL_LINE_LOOP);
|
|||
|
}
|
|||
|
|
|||
|
void shapesSolidOctahedron(void)
|
|||
|
{
|
|||
|
octahedron(GL_TRIANGLES);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* icosahedron data: These numbers are rigged to make an
|
|||
|
icosahedron of radius 1.0 */
|
|||
|
|
|||
|
#define X .525731112119133606
|
|||
|
#define Z .850650808352039932
|
|||
|
|
|||
|
static GLfloat idata[12][3] =
|
|||
|
{
|
|||
|
{-X, 0, Z},
|
|||
|
{X, 0, Z},
|
|||
|
{-X, 0, -Z},
|
|||
|
{X, 0, -Z},
|
|||
|
{0, Z, X},
|
|||
|
{0, Z, -X},
|
|||
|
{0, -Z, X},
|
|||
|
{0, -Z, -X},
|
|||
|
{Z, X, 0},
|
|||
|
{-Z, X, 0},
|
|||
|
{Z, -X, 0},
|
|||
|
{-Z, -X, 0}
|
|||
|
};
|
|||
|
|
|||
|
static int connectivity[20][3] =
|
|||
|
{
|
|||
|
{0, 4, 1},
|
|||
|
{0, 9, 4},
|
|||
|
{9, 5, 4},
|
|||
|
{4, 5, 8},
|
|||
|
{4, 8, 1},
|
|||
|
{8, 10, 1},
|
|||
|
{8, 3, 10},
|
|||
|
{5, 3, 8},
|
|||
|
{5, 2, 3},
|
|||
|
{2, 7, 3},
|
|||
|
{7, 10, 3},
|
|||
|
{7, 6, 10},
|
|||
|
{7, 11, 6},
|
|||
|
{11, 0, 6},
|
|||
|
{0, 1, 6},
|
|||
|
{6, 1, 10},
|
|||
|
{9, 0, 11},
|
|||
|
{9, 11, 2},
|
|||
|
{9, 2, 5},
|
|||
|
{7, 2, 11},
|
|||
|
};
|
|||
|
|
|||
|
static void icosahedron(GLenum shadeType)
|
|||
|
{
|
|||
|
for (int i = 19; i >= 0; i--)
|
|||
|
{
|
|||
|
drawtriangle(i, idata, connectivity, shadeType);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void shapesWireIcosahedron(void)
|
|||
|
{
|
|||
|
icosahedron(GL_LINE_LOOP);
|
|||
|
}
|
|||
|
|
|||
|
void shapesSolidIcosahedron(void)
|
|||
|
{
|
|||
|
icosahedron(GL_TRIANGLES);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* tetrahedron data: */
|
|||
|
|
|||
|
#define T 1.73205080756887729
|
|||
|
|
|||
|
static GLfloat tdata[4][3] =
|
|||
|
{
|
|||
|
{T, T, T},
|
|||
|
{T, -T, -T},
|
|||
|
{-T, T, -T},
|
|||
|
{-T, -T, T}
|
|||
|
};
|
|||
|
#undef T
|
|||
|
|
|||
|
static int tndex[4][3] =
|
|||
|
{
|
|||
|
{0, 1, 3},
|
|||
|
{2, 1, 0},
|
|||
|
{3, 2, 0},
|
|||
|
{1, 2, 3}
|
|||
|
};
|
|||
|
|
|||
|
static void tetrahedron(GLenum shadeType)
|
|||
|
{
|
|||
|
for (int i = 3; i >= 0; i--)
|
|||
|
drawtriangle(i, tdata, tndex, shadeType);
|
|||
|
}
|
|||
|
|
|||
|
void shapesWireTetrahedron(void)
|
|||
|
{
|
|||
|
tetrahedron(GL_LINE_LOOP);
|
|||
|
}
|
|||
|
|
|||
|
void shapesSolidTetrahedron(void)
|
|||
|
{
|
|||
|
tetrahedron(GL_TRIANGLES);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Rim, body, lid, and bottom data must be reflected in x and
|
|||
|
y; handle and spout data across the y axis only. */
|
|||
|
|
|||
|
static int patchdata[][16] =
|
|||
|
{
|
|||
|
/* rim */
|
|||
|
{102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
|||
|
/* body */
|
|||
|
{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27},
|
|||
|
{24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40},
|
|||
|
/* lid */
|
|||
|
{96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3,},
|
|||
|
{0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117},
|
|||
|
/* bottom */
|
|||
|
{118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37},
|
|||
|
/* handle */
|
|||
|
{41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56},
|
|||
|
{53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67},
|
|||
|
/* spout */
|
|||
|
{68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83},
|
|||
|
{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}
|
|||
|
};
|
|||
|
|
|||
|
static float cpdata[][3] =
|
|||
|
{
|
|||
|
{0.2,0,2.7}, {0.2,-0.112,2.7}, {0.112,-0.2,2.7}, {0,-0.2,2.7},
|
|||
|
{1.3375,0,2.53125}, {1.3375,-0.749,2.53125}, {0.749,-1.3375,2.53125},
|
|||
|
{0,-1.3375,2.53125}, {1.4375,0,2.53125}, {1.4375,-0.805, 2.53125},
|
|||
|
{0.805,-1.4375,2.53125}, {0,-1.4375,2.53125}, {1.5,0,2.4}, {1.5,-0.84,2.4},
|
|||
|
{0.84,-1.5,2.4}, {0,-1.5,2.4}, {1.75,0, 1.875}, {1.75,-0.98,1.875},
|
|||
|
{0.98,-1.75,1.875}, {0,-1.75,1.875}, {2,0,1.35}, {2,-1.12,1.35},
|
|||
|
{1.12,-2,1.35}, {0,-2,1.35}, {2,0,0.9}, {2,-1.12,0.9}, {1.12,-2,0.9},
|
|||
|
{0,-2,0.9}, {-2,0,0.9}, {2, 0,0.45}, {2,-1.12,0.45}, {1.12,-2,0.45},
|
|||
|
{0,-2,0.45}, {1.5,0,0.225}, {1.5,-0.84,0.225}, {0.84,-1.5,0.225},
|
|||
|
{0,-1.5,0.225}, {1.5, 0,0.15}, {1.5,-0.84,0.15}, {0.84,-1.5,0.15},
|
|||
|
{0,-1.5,0.15}, {-1.6,0,2.025}, {-1.6,-0.3,2.025}, {-1.5,-0.3,2.25},
|
|||
|
{-1.5,0,2.25}, {-2.3,0,2.025}, {-2.3,-0.3,2.025}, {-2.5,-0.3,2.25},
|
|||
|
{-2.5,0,2.25}, {-2.7,0,2.025}, {-2.7,-0.3,2.025}, {-3,-0.3,2.25},
|
|||
|
{-3,0,2.25}, {-2.7,0,1.8}, {-2.7,-0.3,1.8}, {-3,-0.3,1.8}, {-3,0,1.8},
|
|||
|
{-2.7,0,1.575}, {-2.7,-0.3,1.575}, {-3,-0.3,1.35}, {-3,0,1.35},
|
|||
|
{-2.5,0,1.125}, {-2.5,-0.3,1.125}, {-2.65,-0.3,0.9375}, {-2.65,0, 0.9375},
|
|||
|
{-2,-0.3,0.9}, {-1.9,-0.3,0.6}, {-1.9,0,0.6}, {1.7,0, 1.425},
|
|||
|
{1.7,-0.66,1.425}, {1.7,-0.66,0.6}, {1.7,0,0.6}, {2.6,0, 1.425},
|
|||
|
{2.6,-0.66,1.425}, {3.1,-0.66,0.825}, {3.1,0,0.825}, {2.3, 0,2.1},
|
|||
|
{2.3,-0.25,2.1}, {2.4,-0.25,2.025}, {2.4,0,2.025}, {2.7, 0,2.4},
|
|||
|
{2.7,-0.25,2.4}, {3.3,-0.25,2.4}, {3.3,0,2.4}, {2.8,0, 2.475},
|
|||
|
{2.8,-0.25,2.475}, {3.525,-0.25,2.49375}, {3.525,0, 2.49375}, {2.9,0,2.475},
|
|||
|
{2.9,-0.15,2.475}, {3.45,-0.15,2.5125}, {3.45,0,2.5125}, {2.8,0,2.4},
|
|||
|
{2.8,-0.15,2.4}, {3.2,-0.15,2.4}, {3.2,0,2.4}, {0,0,3.15}, {0.8,0,3.15},
|
|||
|
{0.8,-0.45,3.15}, {0.45, -0.8,3.15}, {0,-0.8,3.15}, {0,0,2.85}, {1.4,0,2.4},
|
|||
|
{1.4,-0.784, 2.4}, {0.784,-1.4,2.4}, {0,-1.4,2.4}, {0.4,0,2.55},
|
|||
|
{0.4,-0.224, 2.55}, {0.224,-0.4,2.55}, {0,-0.4,2.55}, {1.3,0,2.55},
|
|||
|
{1.3,-0.728,2.55}, {0.728,-1.3,2.55}, {0,-1.3,2.55}, {1.3,0,2.4},
|
|||
|
{1.3,-0.728,2.4}, {0.728,-1.3,2.4}, {0,-1.3,2.4}, {0,0,0}, {1.425,-0.798,0},
|
|||
|
{1.5,0,0.075}, {1.425,0,0}, {0.798,-1.425,0}, {0,-1.5, 0.075}, {0,-1.425,0},
|
|||
|
{1.5,-0.84,0.075}, {0.84,-1.5,0.075}
|
|||
|
};
|
|||
|
|
|||
|
static float tex[2][2][2] =
|
|||
|
{
|
|||
|
{ {0, 0},
|
|||
|
{1, 0}},
|
|||
|
{ {0, 1},
|
|||
|
{1, 1}}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
static void teapot(GLint grid, GLenum type)
|
|||
|
{
|
|||
|
float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3];
|
|||
|
|
|||
|
glPushAttrib(GL_ENABLE_BIT | GL_EVAL_BIT);
|
|||
|
glEnable(GL_AUTO_NORMAL);
|
|||
|
glEnable(GL_MAP2_VERTEX_3);
|
|||
|
glEnable(GL_MAP2_TEXTURE_COORD_2);
|
|||
|
for (int i = 0; i < 10; i++)
|
|||
|
{
|
|||
|
for (int j = 0; j < 4; j++)
|
|||
|
{
|
|||
|
for (int k = 0; k < 4; k++)
|
|||
|
{
|
|||
|
for (int l = 0; l < 3; l++)
|
|||
|
{
|
|||
|
p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
|||
|
q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
|||
|
if (l == 1) q[j][k][l] *= -1.0;
|
|||
|
if (i < 6)
|
|||
|
{
|
|||
|
r[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
|||
|
if (l == 0) r[j][k][l] *= -1.0;
|
|||
|
s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
|||
|
if (l == 0) s[j][k][l] *= -1.0;
|
|||
|
if (l == 1) s[j][k][l] *= -1.0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &tex[0][0][0]);
|
|||
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &p[0][0][0]);
|
|||
|
glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0);
|
|||
|
glEvalMesh2(type, 0, grid, 0, grid);
|
|||
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &q[0][0][0]);
|
|||
|
glEvalMesh2(type, 0, grid, 0, grid);
|
|||
|
if (i < 6)
|
|||
|
{
|
|||
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &r[0][0][0]);
|
|||
|
glEvalMesh2(type, 0, grid, 0, grid);
|
|||
|
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &s[0][0][0]);
|
|||
|
glEvalMesh2(type, 0, grid, 0, grid);
|
|||
|
}
|
|||
|
}
|
|||
|
glPopAttrib();
|
|||
|
}
|
|||
|
|
|||
|
void shapesSolidTeapot()
|
|||
|
{
|
|||
|
teapot(14, GL_FILL);
|
|||
|
}
|
|||
|
|
|||
|
void shapesWireTeapot()
|
|||
|
{
|
|||
|
teapot(10, GL_LINE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//////////////////////////////////////////////////////////
|
|||
|
|
|||
|
class FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeBase2705( bool plein = true )
|
|||
|
: plein_(plein),
|
|||
|
vao(0), locVertex(-1), locNormal(-1), locTexCoord(-1)
|
|||
|
{
|
|||
|
glGenVertexArrays( 1, &vao );
|
|||
|
}
|
|||
|
~FormeBase2705()
|
|||
|
{
|
|||
|
glDeleteVertexArrays( 1, &vao );
|
|||
|
}
|
|||
|
protected:
|
|||
|
bool obtenirAttributs( )
|
|||
|
{
|
|||
|
GLint prog = 0; glGetIntegerv( GL_CURRENT_PROGRAM, &prog );
|
|||
|
if ( prog <= 0 )
|
|||
|
{
|
|||
|
std::cerr << "Pas de programme actif!" << std::endl;
|
|||
|
return(false);
|
|||
|
}
|
|||
|
|
|||
|
locVertex = glGetAttribLocation( prog, "Vertex" );
|
|||
|
if ( locVertex == -1 )
|
|||
|
{
|
|||
|
std::cerr << "Pas de nuanceur de sommets!" << std::endl;
|
|||
|
return(false);
|
|||
|
}
|
|||
|
locNormal = glGetAttribLocation( prog, "Normal" );
|
|||
|
locTexCoord = glGetAttribLocation( prog, "TexCoord" );
|
|||
|
if ( locTexCoord < 0 ) locTexCoord = glGetAttribLocation( prog, "TexCoord0" );
|
|||
|
if ( locTexCoord < 0 ) locTexCoord = glGetAttribLocation( prog, "MultiTexCoord0" );
|
|||
|
return(true);
|
|||
|
}
|
|||
|
|
|||
|
bool plein_;
|
|||
|
GLuint vao;
|
|||
|
GLint locVertex, locNormal, locTexCoord;
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
#define AJOUTE(X,Y,Z,NX,NY,NZ,S,T) \
|
|||
|
{ \
|
|||
|
if ( locTexCoord >= 0 ) \
|
|||
|
{ texcoord[2*nsommets+0] = (S); texcoord[2*nsommets+1] = (T); } \
|
|||
|
if ( locNormal >= 0 ) \
|
|||
|
{ normales[3*nsommets+0] = (NX); normales[3*nsommets+1] = (NY); normales[3*nsommets+2] = (NZ); } \
|
|||
|
{ sommets[3*nsommets+0] = (X); sommets[3*nsommets+1] = (Y); sommets[3*nsommets+2] = (Z); ++nsommets; } \
|
|||
|
}
|
|||
|
|
|||
|
class FormeCube : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeCube( GLfloat taille = 1.0,
|
|||
|
bool plein = true )
|
|||
|
: FormeBase2705( plein )
|
|||
|
{
|
|||
|
/* +Y */
|
|||
|
/* 3+-----------+2 */
|
|||
|
/* |\ |\ */
|
|||
|
/* | \ | \ */
|
|||
|
/* | \ | \ */
|
|||
|
/* | 7+-----------+6 */
|
|||
|
/* | | | | */
|
|||
|
/* | | | | */
|
|||
|
/* 0+---|-------+1 | */
|
|||
|
/* \ | \ | +X */
|
|||
|
/* \ | \ | */
|
|||
|
/* \| \| */
|
|||
|
/* 4+-----------+5 */
|
|||
|
/* +Z */
|
|||
|
|
|||
|
static GLint faces[6][4] =
|
|||
|
{
|
|||
|
{ 3, 2, 1, 0 },
|
|||
|
{ 5, 4, 0, 1 },
|
|||
|
{ 6, 5, 1, 2 },
|
|||
|
{ 7, 6, 2, 3 },
|
|||
|
{ 4, 7, 3, 0 },
|
|||
|
{ 4, 5, 6, 7 }
|
|||
|
};
|
|||
|
static GLfloat n[6][3] =
|
|||
|
{
|
|||
|
{ 0.0, 0.0, -1.0 },
|
|||
|
{ 0.0, -1.0, 0.0 },
|
|||
|
{ 1.0, 0.0, 0.0 },
|
|||
|
{ 0.0, 1.0, 0.0 },
|
|||
|
{ -1.0, 0.0, 0.0 },
|
|||
|
{ 0.0, 0.0, 1.0 }
|
|||
|
};
|
|||
|
GLfloat v[8][3];
|
|||
|
v[4][0] = v[7][0] = v[3][0] = v[0][0] = -taille / 2.;
|
|||
|
v[6][0] = v[5][0] = v[1][0] = v[2][0] = +taille / 2.;
|
|||
|
v[5][1] = v[4][1] = v[0][1] = v[1][1] = -taille / 2.;
|
|||
|
v[7][1] = v[6][1] = v[2][1] = v[3][1] = +taille / 2.;
|
|||
|
v[3][2] = v[2][2] = v[1][2] = v[0][2] = -taille / 2.;
|
|||
|
v[4][2] = v[5][2] = v[6][2] = v[7][2] = +taille / 2.;
|
|||
|
GLfloat t[8][2];
|
|||
|
t[4][0] = t[7][0] = t[3][0] = t[0][0] = 0.;
|
|||
|
t[6][0] = t[5][0] = t[1][0] = t[2][0] = 1.;
|
|||
|
t[5][1] = t[4][1] = t[0][1] = t[1][1] = 0.;
|
|||
|
t[7][1] = t[6][1] = t[2][1] = t[3][1] = 1.;
|
|||
|
|
|||
|
if ( obtenirAttributs( ) )
|
|||
|
{
|
|||
|
// initialisation
|
|||
|
const int TAILLEMAX = 6*6;
|
|||
|
GLfloat sommets[3*TAILLEMAX], normales[3*TAILLEMAX], texcoord[2*TAILLEMAX];
|
|||
|
int nsommets = 0;
|
|||
|
|
|||
|
if ( plein_ )
|
|||
|
{
|
|||
|
for ( int i = 0 ; i < 6 ; ++i )
|
|||
|
{
|
|||
|
AJOUTE( v[faces[i][0]][0], v[faces[i][0]][1], v[faces[i][0]][2], n[i][0], n[i][1], n[i][2], t[faces[i][0]][0], t[faces[i][0]][1] );
|
|||
|
AJOUTE( v[faces[i][1]][0], v[faces[i][1]][1], v[faces[i][1]][2], n[i][0], n[i][1], n[i][2], t[faces[i][1]][0], t[faces[i][1]][1] );
|
|||
|
AJOUTE( v[faces[i][2]][0], v[faces[i][2]][1], v[faces[i][2]][2], n[i][0], n[i][1], n[i][2], t[faces[i][2]][0], t[faces[i][2]][1] );
|
|||
|
AJOUTE( v[faces[i][2]][0], v[faces[i][2]][1], v[faces[i][2]][2], n[i][0], n[i][1], n[i][2], t[faces[i][2]][0], t[faces[i][2]][1] );
|
|||
|
AJOUTE( v[faces[i][3]][0], v[faces[i][3]][1], v[faces[i][3]][2], n[i][0], n[i][1], n[i][2], t[faces[i][3]][0], t[faces[i][3]][1] );
|
|||
|
AJOUTE( v[faces[i][0]][0], v[faces[i][0]][1], v[faces[i][0]][2], n[i][0], n[i][1], n[i][2], t[faces[i][0]][0], t[faces[i][0]][1] );
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for ( int i = 0 ; i < 6 ; ++i )
|
|||
|
{
|
|||
|
AJOUTE( v[faces[i][0]][0], v[faces[i][0]][1], v[faces[i][0]][2], n[i][0], n[i][1], n[i][2], t[faces[i][0]][0], t[faces[i][0]][1] );
|
|||
|
AJOUTE( v[faces[i][1]][0], v[faces[i][1]][1], v[faces[i][1]][2], n[i][0], n[i][1], n[i][2], t[faces[i][1]][0], t[faces[i][1]][1] );
|
|||
|
AJOUTE( v[faces[i][2]][0], v[faces[i][2]][1], v[faces[i][2]][2], n[i][0], n[i][1], n[i][2], t[faces[i][2]][0], t[faces[i][2]][1] );
|
|||
|
AJOUTE( v[faces[i][3]][0], v[faces[i][3]][1], v[faces[i][3]][2], n[i][0], n[i][1], n[i][2], t[faces[i][3]][0], t[faces[i][3]][1] );
|
|||
|
}
|
|||
|
}
|
|||
|
nsommets_ = nsommets;
|
|||
|
|
|||
|
// remplir VBOs
|
|||
|
glBindVertexArray( vao );
|
|||
|
glGenBuffers( 3, vbo );
|
|||
|
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[0] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), sommets );
|
|||
|
glVertexAttribPointer( locVertex, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locVertex);
|
|||
|
|
|||
|
if ( locNormal >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[1] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), normales );
|
|||
|
glVertexAttribPointer( locNormal, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locNormal);
|
|||
|
}
|
|||
|
|
|||
|
if ( locTexCoord >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[2] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 2*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 2*nsommets*sizeof(GLfloat), texcoord );
|
|||
|
glVertexAttribPointer( locTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locTexCoord);
|
|||
|
}
|
|||
|
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
~FormeCube()
|
|||
|
{
|
|||
|
glDeleteBuffers( 3, vbo );
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
glBindVertexArray( vao );
|
|||
|
if ( plein_ )
|
|||
|
glDrawArrays( GL_TRIANGLES, 0, nsommets_ );
|
|||
|
else
|
|||
|
for ( int i = 0 ; i < 6 ; ++i ) glDrawArrays( GL_LINE_LOOP, 4*i, 4 );
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
private:
|
|||
|
GLint nsommets_;
|
|||
|
GLuint vbo[3];
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
class FormeSphere : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeSphere( GLdouble radius, GLint slices, GLint stacks,
|
|||
|
bool plein = true, bool entiere = true )
|
|||
|
: FormeBase2705( plein )
|
|||
|
{
|
|||
|
if ( obtenirAttributs( ) )
|
|||
|
{
|
|||
|
// initialisation
|
|||
|
const int TAILLEMAX = 2*(slices+1)*(stacks+2);
|
|||
|
GLfloat sommets[3*TAILLEMAX], normales[3*TAILLEMAX], texcoord[2*TAILLEMAX];
|
|||
|
int nsommets = 0;
|
|||
|
|
|||
|
// variables locales
|
|||
|
const GLfloat drho = M_PI / (GLfloat) stacks;
|
|||
|
const GLfloat dtheta = 2.0 * M_PI / (GLfloat) slices;
|
|||
|
|
|||
|
GLint imin, imax;
|
|||
|
if ( locTexCoord >= 0 ) { imin = 0; imax = stacks; } else { imin = 1; imax = stacks - 1; }
|
|||
|
if ( !entiere ) imax = imax/2 + 1; // pour se rendre seulement à la moitié supérieure
|
|||
|
|
|||
|
/* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
|
|||
|
/* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
|
|||
|
/* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */
|
|||
|
|
|||
|
nsommets = 0;
|
|||
|
{
|
|||
|
GLfloat t = 1.0;
|
|||
|
GLfloat ds = 1.0 / slices;
|
|||
|
GLfloat dt = 1.0 / stacks;
|
|||
|
for ( GLint i = imin; i < imax; i++ )
|
|||
|
{
|
|||
|
GLfloat rho = i * drho;
|
|||
|
GLfloat s = 0.0;
|
|||
|
for ( GLint j = 0; j <= slices; j++ )
|
|||
|
{
|
|||
|
GLfloat x, y, z;
|
|||
|
GLfloat theta = (j == slices) ? 0.0 : j * dtheta;
|
|||
|
x = -sin(theta) * sin(rho);
|
|||
|
y = cos(theta) * sin(rho);
|
|||
|
z = cos(rho);
|
|||
|
AJOUTE( x * radius, y * radius, z * radius, x, y, z, s, t );
|
|||
|
|
|||
|
x = -sin(theta) * sin(rho + drho);
|
|||
|
y = cos(theta) * sin(rho + drho);
|
|||
|
z = cos(rho + drho);
|
|||
|
AJOUTE( x * radius, y * radius, z * radius, x, y, z, s, t-dt );
|
|||
|
s += ds;
|
|||
|
}
|
|||
|
t -= dt;
|
|||
|
}
|
|||
|
}
|
|||
|
nsommetsStrip_ = nsommets;
|
|||
|
|
|||
|
if ( !(locTexCoord >= 0) )
|
|||
|
{
|
|||
|
AJOUTE( 0.0, 0.0, radius, 0.0, 0.0, 1.0, 0, 0 );
|
|||
|
for ( GLint j = 0; j <= slices; j++ )
|
|||
|
{
|
|||
|
GLfloat x, y, z;
|
|||
|
GLfloat theta = (j == slices) ? 0.0 : j * dtheta;
|
|||
|
x = -sin(theta) * sin(drho);
|
|||
|
y = cos(theta) * sin(drho);
|
|||
|
z = cos(drho);
|
|||
|
AJOUTE( x * radius, y * radius, z * radius, x, y, z, 0, 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
nsommetsFan_ = nsommets - nsommetsStrip_;
|
|||
|
|
|||
|
if ( !(locTexCoord >= 0) && entiere )
|
|||
|
{
|
|||
|
AJOUTE( 0.0, 0.0, -radius, 0.0, 0.0, -1.0, 0, 0 );
|
|||
|
GLfloat rho = M_PI - drho;
|
|||
|
for ( GLint j = slices; j >= 0; j-- )
|
|||
|
{
|
|||
|
GLfloat x, y, z;
|
|||
|
GLfloat theta = (j == slices) ? 0.0 : j * dtheta;
|
|||
|
x = -sin(theta) * sin(rho);
|
|||
|
y = cos(theta) * sin(rho);
|
|||
|
z = cos(rho);
|
|||
|
AJOUTE( x * radius, y * radius, z * radius, x, y, z, 0, 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// remplir VBOs
|
|||
|
glBindVertexArray( vao );
|
|||
|
glGenBuffers( 3, vbo );
|
|||
|
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[0] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), sommets );
|
|||
|
glVertexAttribPointer( locVertex, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locVertex);
|
|||
|
|
|||
|
if ( locNormal >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[1] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), normales );
|
|||
|
glVertexAttribPointer( locNormal, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locNormal);
|
|||
|
}
|
|||
|
|
|||
|
if ( locTexCoord >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[2] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 2*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 2*nsommets*sizeof(GLfloat), texcoord );
|
|||
|
glVertexAttribPointer( locTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locTexCoord);
|
|||
|
}
|
|||
|
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
~FormeSphere()
|
|||
|
{
|
|||
|
glDeleteBuffers( 3, vbo );
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
glBindVertexArray( vao );
|
|||
|
glDrawArrays( GL_TRIANGLE_STRIP, 0, nsommetsStrip_ );
|
|||
|
if ( !(locTexCoord >= 0) )
|
|||
|
{
|
|||
|
glDrawArrays( GL_TRIANGLE_FAN, nsommetsStrip_, nsommetsFan_ );
|
|||
|
glDrawArrays( GL_TRIANGLE_FAN, nsommetsStrip_+nsommetsFan_, nsommetsFan_ );
|
|||
|
}
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
private:
|
|||
|
GLint nsommetsStrip_, nsommetsFan_;
|
|||
|
GLuint vbo[3];
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
class FormeTore : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeTore( GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings,
|
|||
|
bool plein = true )
|
|||
|
: FormeBase2705( plein )
|
|||
|
{
|
|||
|
if ( obtenirAttributs( ) )
|
|||
|
{
|
|||
|
// initialisation
|
|||
|
const int TAILLEMAX = 2*(nsides+1)*(rings);
|
|||
|
GLfloat sommets[3*TAILLEMAX], normales[3*TAILLEMAX], texcoord[2*TAILLEMAX];
|
|||
|
int nsommets = 0;
|
|||
|
|
|||
|
// variables locales
|
|||
|
const GLfloat ringDelta = 2.0 * M_PI / rings;
|
|||
|
const GLfloat sideDelta = 2.0 * M_PI / nsides;
|
|||
|
|
|||
|
GLfloat theta = 0.0;
|
|||
|
GLfloat cosTheta = 1.0;
|
|||
|
GLfloat sinTheta = 0.0;
|
|||
|
for ( int i = rings - 1; i >= 0; i-- )
|
|||
|
{
|
|||
|
GLfloat theta1 = theta + ringDelta;
|
|||
|
GLfloat cosTheta1 = cos(theta1);
|
|||
|
GLfloat sinTheta1 = sin(theta1);
|
|||
|
GLfloat phi = 0.0;
|
|||
|
for ( int j = nsides; j >= 0; j-- )
|
|||
|
{
|
|||
|
phi += sideDelta;
|
|||
|
GLfloat cosPhi = cos(phi);
|
|||
|
GLfloat sinPhi = sin(phi);
|
|||
|
GLfloat dist = outerRadius + innerRadius * cosPhi;
|
|||
|
|
|||
|
AJOUTE( cosTheta1 * dist, -sinTheta1 * dist, innerRadius * sinPhi,
|
|||
|
cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi,
|
|||
|
(4.0*(i+1))/rings, (4.0*j)/nsides );
|
|||
|
|
|||
|
AJOUTE( cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi,
|
|||
|
cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi,
|
|||
|
(4.0*i)/rings, (4.0*j)/nsides );
|
|||
|
}
|
|||
|
theta = theta1;
|
|||
|
cosTheta = cosTheta1;
|
|||
|
sinTheta = sinTheta1;
|
|||
|
}
|
|||
|
nsommets_ = nsommets;
|
|||
|
|
|||
|
// remplir VBOs
|
|||
|
glBindVertexArray( vao );
|
|||
|
glGenBuffers( 3, vbo );
|
|||
|
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[0] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), sommets );
|
|||
|
glVertexAttribPointer( locVertex, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locVertex);
|
|||
|
|
|||
|
if ( locNormal >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[1] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), normales );
|
|||
|
glVertexAttribPointer( locNormal, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locNormal);
|
|||
|
}
|
|||
|
|
|||
|
if ( locTexCoord >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[2] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 2*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 2*nsommets*sizeof(GLfloat), texcoord );
|
|||
|
glVertexAttribPointer( locTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locTexCoord);
|
|||
|
}
|
|||
|
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
~FormeTore()
|
|||
|
{
|
|||
|
glDeleteBuffers( 3, vbo );
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
glBindVertexArray( vao );
|
|||
|
glDrawArrays( GL_TRIANGLE_STRIP, 0, nsommets_ );
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
private:
|
|||
|
GLint nsommets_;
|
|||
|
GLuint vbo[3];
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
class FormeCylindre : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeCylindre( GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks,
|
|||
|
bool plein = true )
|
|||
|
: FormeBase2705( plein )
|
|||
|
{
|
|||
|
if ( obtenirAttributs( ) )
|
|||
|
{
|
|||
|
// initialisation
|
|||
|
const int TAILLEMAX = 2*(slices+1)*(stacks) + 2*(slices+1) + 2;
|
|||
|
GLfloat sommets[3*TAILLEMAX], normales[3*TAILLEMAX], texcoord[2*TAILLEMAX];
|
|||
|
int nsommets = 0;
|
|||
|
|
|||
|
// variables locales
|
|||
|
const GLdouble da = 2.0 * M_PI / slices;
|
|||
|
{
|
|||
|
// le cylindre
|
|||
|
const GLdouble dr = (top - base) / stacks;
|
|||
|
const GLdouble nz = (base - top) / height;
|
|||
|
const GLdouble dz = height / stacks;
|
|||
|
const GLfloat ds = 1.0 / slices;
|
|||
|
const GLfloat dt = 1.0 / stacks;
|
|||
|
GLfloat t = 0.0;
|
|||
|
GLfloat z = 0.0;
|
|||
|
GLfloat r = base;
|
|||
|
for ( int j = 0; j < stacks; j++ )
|
|||
|
{
|
|||
|
GLfloat s = 0.0;
|
|||
|
for ( int i = 0; i <= slices; i++ )
|
|||
|
{
|
|||
|
GLfloat a = ( i == slices ) ? 0.0 : i * da;
|
|||
|
GLfloat x = sin( a );
|
|||
|
GLfloat y = cos( a );
|
|||
|
AJOUTE( x * r, y * r, z, x, y, nz, s, t );
|
|||
|
AJOUTE( x * (r + dr), y * (r + dr), z + dz, x, y, nz, s, t + dt );
|
|||
|
s += ds;
|
|||
|
}
|
|||
|
r += dr;
|
|||
|
t += dt;
|
|||
|
z += dz;
|
|||
|
}
|
|||
|
nsommetsCyl_ = nsommets;
|
|||
|
}
|
|||
|
{
|
|||
|
// les deux bouts avec des disques
|
|||
|
/* texture of a shapesDisk is a cut out of the texture unit square
|
|||
|
* x, y in [-outerRadius, +outerRadius]; s, t in [0, 1] (linear mapping) */
|
|||
|
AJOUTE( 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.5, 0.5 );
|
|||
|
for ( int i = slices; i >= 0; i-- )
|
|||
|
{
|
|||
|
GLfloat a = ( i == slices ) ? 0.0 : i * -da;
|
|||
|
GLfloat x = sin( a );
|
|||
|
GLfloat y = cos( a );
|
|||
|
AJOUTE( base*x, base*y, 0.0, 0.0, 0.0, -1.0, 0.5*(1.0-x), 0.5*(1.0+y) );
|
|||
|
}
|
|||
|
nsommetsBout_ = nsommets - nsommetsCyl_;
|
|||
|
AJOUTE( 0.0, 0.0, height, 0.0, 0.0, +1.0, 0.5, 0.5 );
|
|||
|
for ( int i = slices; i >= 0; i-- )
|
|||
|
{
|
|||
|
GLfloat a = ( i == slices ) ? 0.0 : i * da;
|
|||
|
GLfloat x = sin( a );
|
|||
|
GLfloat y = cos( a );
|
|||
|
AJOUTE( top*x, top*y, height, 0.0, 0.0, +1.0, 0.5*(1.0-x), 0.5*(1.0+y) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// remplir VBOs
|
|||
|
glBindVertexArray( vao );
|
|||
|
glGenBuffers( 3, vbo );
|
|||
|
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[0] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), sommets );
|
|||
|
glVertexAttribPointer( locVertex, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locVertex);
|
|||
|
|
|||
|
if ( locNormal >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[1] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), normales );
|
|||
|
glVertexAttribPointer( locNormal, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locNormal);
|
|||
|
}
|
|||
|
|
|||
|
if ( locTexCoord >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[2] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 2*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 2*nsommets*sizeof(GLfloat), texcoord );
|
|||
|
glVertexAttribPointer( locTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locTexCoord);
|
|||
|
}
|
|||
|
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
~FormeCylindre()
|
|||
|
{
|
|||
|
glDeleteBuffers( 3, vbo );
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
glBindVertexArray( vao );
|
|||
|
glDrawArrays( GL_TRIANGLE_STRIP, 0, nsommetsCyl_ );
|
|||
|
glDrawArrays( GL_TRIANGLE_FAN, nsommetsCyl_, nsommetsBout_ );
|
|||
|
glDrawArrays( GL_TRIANGLE_FAN, nsommetsCyl_+nsommetsBout_, nsommetsBout_ );
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
private:
|
|||
|
GLint nsommetsCyl_, nsommetsBout_;
|
|||
|
GLuint vbo[3];
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
class FormeDisque : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeDisque( GLdouble inner, GLdouble outer, GLint slices, GLint loops,
|
|||
|
bool plein = true )
|
|||
|
: FormeBase2705( plein )
|
|||
|
{
|
|||
|
if ( obtenirAttributs( ) )
|
|||
|
{
|
|||
|
// initialisation
|
|||
|
const int TAILLEMAX = 2*(slices+1)*(loops);
|
|||
|
GLfloat sommets[3*TAILLEMAX], normales[3*TAILLEMAX], texcoord[2*TAILLEMAX];
|
|||
|
int nsommets = 0;
|
|||
|
|
|||
|
// variables locales
|
|||
|
const GLfloat da = 2.0 * M_PI / slices;
|
|||
|
const GLfloat dr = (outer - inner) / (GLfloat) loops;
|
|||
|
|
|||
|
/* texture of a shapesDisk is a cut out of the texture unit square
|
|||
|
* x, y in [-outer, +outer]; s, t in [0, 1] * (linear mapping) */
|
|||
|
GLfloat r1 = inner;
|
|||
|
for ( int l = 0; l < loops; l++ )
|
|||
|
{
|
|||
|
GLfloat r2 = r1 + dr;
|
|||
|
for ( int i = slices; i >= 0; i-- )
|
|||
|
{
|
|||
|
GLfloat a = ( i == slices ) ? 0.0 : i * da;
|
|||
|
GLfloat x = sin( a );
|
|||
|
GLfloat y = cos( a );
|
|||
|
AJOUTE( r2*x, r2*y, 0.0, 0.0, 0.0, +1.0, 0.5*( 1.0 - x*r2/outer ), 0.5*( 1.0 + y*r2/outer ) );
|
|||
|
AJOUTE( r1*x, r1*y, 0.0, 0.0, 0.0, +1.0, 0.5*( 1.0 - x*r1/outer ), 0.5*( 1.0 + y*r1/outer ) );
|
|||
|
}
|
|||
|
r1 = r2;
|
|||
|
}
|
|||
|
nsommets_ = nsommets;
|
|||
|
|
|||
|
// remplir VBOs
|
|||
|
glBindVertexArray( vao );
|
|||
|
glGenBuffers( 3, vbo );
|
|||
|
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[0] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), sommets );
|
|||
|
glVertexAttribPointer( locVertex, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locVertex);
|
|||
|
|
|||
|
if ( locNormal >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[1] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 3*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 3*nsommets*sizeof(GLfloat), normales );
|
|||
|
glVertexAttribPointer( locNormal, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locNormal);
|
|||
|
}
|
|||
|
|
|||
|
if ( locTexCoord >= 0 )
|
|||
|
{
|
|||
|
glBindBuffer( GL_ARRAY_BUFFER, vbo[2] );
|
|||
|
glBufferData( GL_ARRAY_BUFFER, 2*nsommets*sizeof(GLfloat), NULL, GL_STATIC_DRAW );
|
|||
|
glBufferSubData( GL_ARRAY_BUFFER, 0, 2*nsommets*sizeof(GLfloat), texcoord );
|
|||
|
glVertexAttribPointer( locTexCoord, 2, GL_FLOAT, GL_FALSE, 0, 0 );
|
|||
|
glEnableVertexAttribArray(locTexCoord);
|
|||
|
}
|
|||
|
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
}
|
|||
|
~FormeDisque()
|
|||
|
{
|
|||
|
glDeleteBuffers( 3, vbo );
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
glBindVertexArray( vao );
|
|||
|
glDrawArrays( GL_TRIANGLE_STRIP, 0, nsommets_ );
|
|||
|
glBindVertexArray( 0 );
|
|||
|
}
|
|||
|
private:
|
|||
|
GLint nsommets_;
|
|||
|
GLuint vbo[3];
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
class FormeIcosaedre : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeIcosaedre( bool plein = true )
|
|||
|
: FormeBase2705( plein )
|
|||
|
{
|
|||
|
}
|
|||
|
~FormeIcosaedre()
|
|||
|
{
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
#if !defined( __APPLE__ )
|
|||
|
shapesSolidIcosahedron( );
|
|||
|
#endif
|
|||
|
}
|
|||
|
private:
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
class FormeDodecaedre : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeDodecaedre( bool plein = true )
|
|||
|
: FormeBase2705( plein )
|
|||
|
{
|
|||
|
}
|
|||
|
~FormeDodecaedre()
|
|||
|
{
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
#if !defined( __APPLE__ )
|
|||
|
shapesSolidDodecahedron( );
|
|||
|
#endif
|
|||
|
}
|
|||
|
private:
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
// teapot(14, true);
|
|||
|
// teapot(10, false);
|
|||
|
class FormeTheiere : public FormeBase2705
|
|||
|
{
|
|||
|
public:
|
|||
|
FormeTheiere( GLint npts = 14,
|
|||
|
bool plein = true )
|
|||
|
: FormeBase2705( plein ) //, npts_(npts)
|
|||
|
{
|
|||
|
#if 0
|
|||
|
if ( obtenirAttributs( ) )
|
|||
|
{
|
|||
|
// initialisation
|
|||
|
const int TAILLEMAX = 10*(npts_+1)*(npts_);
|
|||
|
GLfloat sommets[3*TAILLEMAX], normales[3*TAILLEMAX], texcoord[2*TAILLEMAX];
|
|||
|
int nsommets = 0;
|
|||
|
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
~FormeTheiere()
|
|||
|
{
|
|||
|
#if 0
|
|||
|
glDeleteBuffers( 3, vbo );
|
|||
|
#endif
|
|||
|
}
|
|||
|
void afficher()
|
|||
|
{
|
|||
|
#if 1
|
|||
|
#if !defined( __APPLE__ )
|
|||
|
shapesSolidTeapot();
|
|||
|
#endif
|
|||
|
#else
|
|||
|
glBindVertexArray( vao );
|
|||
|
//glDrawArrays( GL_TRIANGLE_STRIP, 0, nsommets_ );
|
|||
|
/* Rim, body, lid, and bottom data must be reflected in x and
|
|||
|
y; handle and spout data across the y axis only. */
|
|||
|
int patchdata[][16] =
|
|||
|
{
|
|||
|
/* rim */
|
|||
|
{102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
|||
|
/* body */
|
|||
|
{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27},
|
|||
|
{24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40},
|
|||
|
/* lid */
|
|||
|
{96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3,},
|
|||
|
{0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117},
|
|||
|
/* bottom */
|
|||
|
{118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37},
|
|||
|
/* handle */
|
|||
|
{41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56},
|
|||
|
{53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67},
|
|||
|
/* spout */
|
|||
|
{68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83},
|
|||
|
{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}
|
|||
|
};
|
|||
|
float cpdata[][3] =
|
|||
|
{
|
|||
|
{0.2,0,2.7}, {0.2,-0.112,2.7}, {0.112,-0.2,2.7}, {0,-0.2,2.7},
|
|||
|
{1.3375,0,2.53125}, {1.3375,-0.749,2.53125}, {0.749,-1.3375,2.53125},
|
|||
|
{0,-1.3375,2.53125}, {1.4375,0,2.53125}, {1.4375,-0.805, 2.53125},
|
|||
|
{0.805,-1.4375,2.53125}, {0,-1.4375,2.53125}, {1.5,0,2.4}, {1.5,-0.84,2.4},
|
|||
|
{0.84,-1.5,2.4}, {0,-1.5,2.4}, {1.75,0, 1.875}, {1.75,-0.98,1.875},
|
|||
|
{0.98,-1.75,1.875}, {0,-1.75,1.875}, {2,0,1.35}, {2,-1.12,1.35},
|
|||
|
{1.12,-2,1.35}, {0,-2,1.35}, {2,0,0.9}, {2,-1.12,0.9}, {1.12,-2,0.9},
|
|||
|
{0,-2,0.9}, {-2,0,0.9}, {2, 0,0.45}, {2,-1.12,0.45}, {1.12,-2,0.45},
|
|||
|
{0,-2,0.45}, {1.5,0,0.225}, {1.5,-0.84,0.225}, {0.84,-1.5,0.225},
|
|||
|
{0,-1.5,0.225}, {1.5, 0,0.15}, {1.5,-0.84,0.15}, {0.84,-1.5,0.15},
|
|||
|
{0,-1.5,0.15}, {-1.6,0,2.025}, {-1.6,-0.3,2.025}, {-1.5,-0.3,2.25},
|
|||
|
{-1.5,0,2.25}, {-2.3,0,2.025}, {-2.3,-0.3,2.025}, {-2.5,-0.3,2.25},
|
|||
|
{-2.5,0,2.25}, {-2.7,0,2.025}, {-2.7,-0.3,2.025}, {-3,-0.3,2.25},
|
|||
|
{-3,0,2.25}, {-2.7,0,1.8}, {-2.7,-0.3,1.8}, {-3,-0.3,1.8}, {-3,0,1.8},
|
|||
|
{-2.7,0,1.575}, {-2.7,-0.3,1.575}, {-3,-0.3,1.35}, {-3,0,1.35},
|
|||
|
{-2.5,0,1.125}, {-2.5,-0.3,1.125}, {-2.65,-0.3,0.9375}, {-2.65,0, 0.9375},
|
|||
|
{-2,-0.3,0.9}, {-1.9,-0.3,0.6}, {-1.9,0,0.6}, {1.7,0, 1.425},
|
|||
|
{1.7,-0.66,1.425}, {1.7,-0.66,0.6}, {1.7,0,0.6}, {2.6,0, 1.425},
|
|||
|
{2.6,-0.66,1.425}, {3.1,-0.66,0.825}, {3.1,0,0.825}, {2.3, 0,2.1},
|
|||
|
{2.3,-0.25,2.1}, {2.4,-0.25,2.025}, {2.4,0,2.025}, {2.7, 0,2.4},
|
|||
|
{2.7,-0.25,2.4}, {3.3,-0.25,2.4}, {3.3,0,2.4}, {2.8,0, 2.475},
|
|||
|
{2.8,-0.25,2.475}, {3.525,-0.25,2.49375}, {3.525,0, 2.49375}, {2.9,0,2.475},
|
|||
|
{2.9,-0.15,2.475}, {3.45,-0.15,2.5125}, {3.45,0,2.5125}, {2.8,0,2.4},
|
|||
|
{2.8,-0.15,2.4}, {3.2,-0.15,2.4}, {3.2,0,2.4}, {0,0,3.15}, {0.8,0,3.15},
|
|||
|
{0.8,-0.45,3.15}, {0.45, -0.8,3.15}, {0,-0.8,3.15}, {0,0,2.85}, {1.4,0,2.4},
|
|||
|
{1.4,-0.784, 2.4}, {0.784,-1.4,2.4}, {0,-1.4,2.4}, {0.4,0,2.55},
|
|||
|
{0.4,-0.224, 2.55}, {0.224,-0.4,2.55}, {0,-0.4,2.55}, {1.3,0,2.55},
|
|||
|
{1.3,-0.728,2.55}, {0.728,-1.3,2.55}, {0,-1.3,2.55}, {1.3,0,2.4},
|
|||
|
{1.3,-0.728,2.4}, {0.728,-1.3,2.4}, {0,-1.3,2.4}, {0,0,0}, {1.425,-0.798,0},
|
|||
|
{1.5,0,0.075}, {1.425,0,0}, {0.798,-1.425,0}, {0,-1.5, 0.075}, {0,-1.425,0},
|
|||
|
{1.5,-0.84,0.075}, {0.84,-1.5,0.075}
|
|||
|
};
|
|||
|
float tex[2][2][2] =
|
|||
|
{
|
|||
|
{ {0, 0},
|
|||
|
{1, 0}},
|
|||
|
{ {0, 1},
|
|||
|
{1, 1}}
|
|||
|
};
|
|||
|
float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3];
|
|||
|
for ( int i = 0; i < 10; i++ )
|
|||
|
{
|
|||
|
for ( int j = 0; j < 4; j++ )
|
|||
|
{
|
|||
|
for ( int k = 0; k < 4; k++ )
|
|||
|
{
|
|||
|
for ( int l = 0; l < 3; l++ )
|
|||
|
{
|
|||
|
p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
|||
|
q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
|||
|
if (l == 1) q[j][k][l] *= -1.0;
|
|||
|
if (i < 6)
|
|||
|
{
|
|||
|
r[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
|||
|
if (l == 0) r[j][k][l] *= -1.0;
|
|||
|
s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
|||
|
if (l == 0) s[j][k][l] *= -1.0;
|
|||
|
if (l == 1) s[j][k][l] *= -1.0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
glEnable( GL_AUTO_NORMAL );
|
|||
|
glEnable( GL_MAP2_TEXTURE_COORD_2 );
|
|||
|
glEnable( GL_MAP2_VERTEX_3 );
|
|||
|
glMap2f( GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &tex[0][0][0] );
|
|||
|
glMap2f( GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &p[0][0][0] );
|
|||
|
glMapGrid2f( npts_, 0.0, 1.0, npts_, 0.0, 1.0 );
|
|||
|
glEvalMesh2( GL_FILL, 0, npts_, 0, npts_ );
|
|||
|
glMap2f( GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &q[0][0][0] );
|
|||
|
glEvalMesh2( GL_FILL, 0, npts_, 0, npts_ );
|
|||
|
if ( i < 6 )
|
|||
|
{
|
|||
|
glMap2f( GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &r[0][0][0] );
|
|||
|
glEvalMesh2( GL_FILL, 0, npts_, 0, npts_ );
|
|||
|
glMap2f( GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &s[0][0][0] );
|
|||
|
glEvalMesh2( GL_FILL, 0, npts_, 0, npts_ );
|
|||
|
}
|
|||
|
}
|
|||
|
glBindVertexArray( 0 );
|
|||
|
#endif
|
|||
|
}
|
|||
|
private:
|
|||
|
#if 0
|
|||
|
void Map2f( GLenum target,
|
|||
|
GLfloat u1, GLfloat u2, GLint ustride, GLint uorder,
|
|||
|
GLfloat v1, GLfloat v2, GLint vstride, GLint vorder,
|
|||
|
const GLfloat *points )
|
|||
|
{
|
|||
|
}
|
|||
|
GLint un; GLfloat u1, u2, du;
|
|||
|
GLint vn; GLfloat v1, v2, dv;
|
|||
|
void MapGrid2f( GLint unArg, GLfloat u1Arg, GLfloat u2Arg,
|
|||
|
GLint vnArg, GLfloat v1Arg, GLfloat v2Arg )
|
|||
|
{
|
|||
|
un = unArg; u1 = u1Arg; u2 = u2Arg; du = u2 - u1;
|
|||
|
vn = vnArg; v1 = v1Arg; v2 = v2Arg; dv = v2 - v1;
|
|||
|
}
|
|||
|
void EvalMesh2( GLint i1, GLint i2, GLint j1, GLint j2 )
|
|||
|
{
|
|||
|
if ( plein_ )
|
|||
|
{
|
|||
|
for ( int j = j1; j < j2; j += 1 )
|
|||
|
{
|
|||
|
glBegin( GL_QUAD_STRIP );
|
|||
|
for ( int i = i1; i <= i2; i += 1 )
|
|||
|
{
|
|||
|
glEvalCoord2f( i * du + u1, j * dv + v1 );
|
|||
|
glEvalCoord2f( i * du + u1, j + 1 * dv + v1 );
|
|||
|
} glEnd();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for ( int j = j1; j <= j2; j += 1 )
|
|||
|
{
|
|||
|
glBegin( GL_LINE_STRIP );
|
|||
|
for ( int i = i1; i <= i2; i += 1 )
|
|||
|
glEvalCoord2f( i * du + u1, j * dv + v1 );
|
|||
|
glEnd();
|
|||
|
}
|
|||
|
for ( int i = i1; i <= i2; i += 1 )
|
|||
|
{
|
|||
|
glBegin( GL_LINE_STRIP );
|
|||
|
for ( int j = j1; j <= j1; j += 1 )
|
|||
|
glEvalCoord2f( i * du + u1, j * dv + v1 );
|
|||
|
glEnd();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#if 0
|
|||
|
GLint npts_;
|
|||
|
GLint nsommets_;
|
|||
|
GLuint vbo[3];
|
|||
|
#endif
|
|||
|
};
|
|||
|
|
|||
|
//////////
|
|||
|
|
|||
|
#endif
|
|||
|
|