ripple/ripple.cpp
2017-11-28 12:35:49 -05:00

1150 lines
39 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdlib.h>
#include <iostream>
#include "inf2705.h"
#include "constants.h"
#include "FBO.h"
#include "Packets.h"
#include "util.h"
#define SOL 1
enum {LocAttrib, LocUniform}; /* Shader location type */
enum {
RWMP_SHADER,
APD_SHADER,
DPO_SHADER,
DMM_SHADER,
DT_SHADER,
RAA_SHADER,
NB_SHADERS
}; /* Shaders stages */
// variables pour l'utilisation des nuanceurs
GLuint prog; // votre programme de nuanceurs
GLuint progRasterizeWaveMeshPosition;
GLuint progAddPacketDisplacement;
GLuint progDisplayPacketOutlined;
GLuint progDisplayMicroMesh;
GLuint progDisplayTerrain;
GLuint progRenderAA;
GLint locVertex = -1;
GLint locNormal = -1;
GLint locTexCoord = -1;
GLint locmatrModel = -1;
GLint locmatrVisu = -1;
GLint locmatrProj = -1;
GLint locmatrNormale = -1;
GLint loclaTexture = -1;
// Locations for RasterizeWaveMeshPosition shader
GLint locVertexRWMP = -1;
GLint locTexCoordRWMP = -1;
GLint locmatrModelRWMP = -1;
GLint locmatrVisuRWMP = -1;
GLint locmatrProjRWMP = -1;
GLint locmatrNormaleRWMP = -1;
// Locations for AddPacketDisplacement shader
GLuint locPosAPD = -1;
GLuint locAtt1APD = -1;
GLuint locAtt2APD = -1;
GLuint locmatrModelAPD = -1;
GLuint locmatrVisuAPD = -1;
GLuint locmatrProjAPD = -1;
GLuint locTexAPD = -1;
// Locations for DisplayPacketOutlined shader
GLuint locPosDPO = -1;
GLuint locAtt1DPO = -1;
GLuint locAtt2DPO = -1;
GLuint locmatrModelDPO = -1;
GLuint locmatrVisuDPO = -1;
GLuint locmatrProjDPO = -1;
GLuint locTexDPO = -1;
// Locations for DisplayMicroMesh shader
GLuint locVertexDMM = -1;
GLuint locTexCoordDMM = -1;
GLuint locmatrModelDMM = -1;
GLuint locmatrVisuDMM = -1;
GLuint locmatrProjDMM = -1;
GLuint locTerrainTexDMM = -1;
GLuint locWaterPosTexDMM = -1;
GLuint locWaterHeightTexDMM = -1;
// Locationss for DisplayTerrain shader
GLuint locVertexDT = -1;
GLuint locmatrModelDT = -1;
GLuint locmatrVisuDT = -1;
GLuint locmatrProjDT = -1;
GLuint locTerrainTexDT = -1;
// Locations for RenderAA shader
GLuint locVertexRAA = -1;
GLuint locTexCoordRAA = -1;
GLuint locmatrModelRAA = -1;
GLuint locmatrVisuRAA = -1;
GLuint locmatrProjRAA = -1;
GLuint locTexRAA = -1;
GLuint indLightSource;
GLuint indFrontMaterial;
GLuint indLightModel;
GLuint indvarsUnif;
GLuint progBase; // le programme de nuanceurs de base
GLint locVertexBase = -1;
GLint locColorBase = -1;
GLint locmatrModelBase = -1;
GLint locmatrVisuBase = -1;
GLint locmatrProjBase = -1;
GLuint vao[NB_SHADERS];
GLuint vbo[5];
GLuint ubo[4];
GLuint vbosQuad[2]; /* Vertex & Tex Coord */
GLuint vboPacket;
GLuint vboHeightField;
GLuint vboDMM[2]; /* Vertex & Index */
// matrices de du pipeline graphique
MatricePipeline matrModel;
MatricePipeline matrVisu;
MatricePipeline matrProj;
MatricePipeline matrProjWide;
// les formes
FormeSphere *sphere = NULL, *sphereLumi = NULL;
FormeTheiere *theiere = NULL;
FormeTore *tore = NULL;
FormeCylindre *cylindre = NULL;
FormeCylindre *cone = NULL;
// variables pour définir le point de vue
double thetaCam = 0.0; // angle de rotation de la caméra (coord. sphériques)
double phiCam = 0.0; // angle de rotation de la caméra (coord. sphériques)
double distCam = 0.0; // distance (coord. sphériques)
// variables d'état
bool enPerspective = false; // indique si on est en mode Perspective (true) ou Ortho (false)
bool enmouvement = false; // le modèle est en mouvement/rotation automatique ou non
bool afficheAxes = true; // indique si on affiche les axes
GLenum modePolygone = GL_FILL; // comment afficher les polygones
// FBOs
FBO *posFBO;
FBO *heightFBO;
FBO *aaFBO;
// Terrain mesh size
const int terrainW = 1024;
const int terrainH = 1024;
// Wave Packets
Packets *packets;
int packetBudget = 10000;
/* Wave packets:
* vec4: xy = position, zw = direction
* vec4: x = amplitude, y = wavelength, z = phase offset, w = enveloppe size
* vec4: for rendering x = center of wave bending circle*/
GLfloat packetData[PACKET_GPU_BUFFER_SIZE * 3 * 4];
int nIndexDMM = 0;
////////////////////////////////////////
// déclaration des variables globales //
////////////////////////////////////////
// partie 1: illumination
int modele = 1; // le modèle à afficher
// partie 3: texture
GLuint texTerrain = 0;
GLuint textureECHIQUIER = 0;
// définition des lumières
struct LightSourceParameters
{
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
glm::vec4 position;
glm::vec3 spotDirection;
float spotExposant;
float spotAngle; // ([0.0,90.0] ou 180.0)
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
} LightSource[1] = { { glm::vec4( 1.0, 1.0, 1.0, 1.0 ),
glm::vec4( 1.0, 1.0, 1.0, 1.0 ),
glm::vec4( 1.0, 1.0, 1.0, 1.0 ),
glm::vec4( 4, 1, 15, 1.0 ),
glm::vec3( -5.0, -2.0, -10.0 ),
1.0, // l'exposant du cône
15.0, // l'angle du cône du spot
1., 0., 0. } };
// définition du matériau
struct MaterialParameters
{
glm::vec4 emission;
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
float shininess;
} FrontMaterial = { glm::vec4( 0.0, 0.0, 0.0, 1.0 ),
glm::vec4( 0.1, 0.1, 0.1, 1.0 ),
glm::vec4( 1.0, 0.1, 1.0, 1.0 ),
glm::vec4( 1.0, 1.0, 1.0, 1.0 ),
100.0 };
struct LightModelParameters
{
glm::vec4 ambient; // couleur ambiante
int localViewer; // doit-on prendre en compte la position de l'observateur? (local ou à l'infini)
int twoSide; // éclairage sur les deux côtés ou un seul?
} LightModel = { glm::vec4(0,0,0,1), false, false };
struct
{
// partie 1: illumination
int typeIllumination; // 0:Lambert, 1:Gouraud, 2:Phong
int utiliseBlinn; // indique si on veut utiliser modèle spéculaire de Blinn ou Phong
int utiliseDirect; // indique si on utilise un spot style Direct3D ou OpenGL
int afficheNormales; // indique si on utilise les normales comme couleurs (utile pour le débogage)
// partie 3: texture
int texnumero; // numéro de la texture appliquée
int utiliseCouleur; // doit-on utiliser la couleur de base de l'objet en plus de celle de la texture?
int afficheTexelNoir; // un texel noir doit-il être affiché 0:noir, 1:mi-coloré, 2:transparent?
} varsUnif = { 2, false, false, false,
0, true, 0 };
// ( En glsl, les types 'bool' et 'int' sont de la même taille, ce qui n'est pas le cas en C++.
// Ci-dessus, on triche donc un peu en déclarant les 'bool' comme des 'int', mais ça facilite la
// copie directe vers le nuanceur où les variables seront bien de type 'bool'. )
/* Forward declarations */
void displayPacketOutlined(int count);
void addPacketDisplacement(int count);
void displayTerrain();
void displayMicroMesh();
void verifierAngles()
{
if ( thetaCam > 360.0 )
thetaCam -= 360.0;
else if ( thetaCam < 0.0 )
thetaCam += 360.0;
const GLdouble MINPHI = -90.0, MAXPHI = 90.0;
if ( phiCam > MAXPHI )
phiCam = MAXPHI;
else if ( phiCam < MINPHI )
phiCam = MINPHI;
}
void calculerPhysique( )
{
if ( enmouvement )
{
static int sensTheta = 1;
static int sensPhi = 1;
thetaCam += 0.3 * sensTheta;
phiCam += 0.5 * sensPhi;
//if ( thetaCam <= 0. || thetaCam >= 360.0 ) sensTheta = -sensTheta;
if ( phiCam < -90.0 || phiCam > 90.0 ) sensPhi = -sensPhi;
static int sensAngle = 1;
LightSource[0].spotAngle += sensAngle * 0.3;
if ( LightSource[0].spotAngle < 5.0 ) sensAngle = -sensAngle;
if ( LightSource[0].spotAngle > 60.0 ) sensAngle = -sensAngle;
// De temps à autre, alterner entre le modèle d'illumination: Lambert, Gouraud, Phong
static float type = 0;
type += 0.005;
varsUnif.typeIllumination = fmod(type,3);
}
verifierAngles();
}
void updatePackets()
{
// Compute wave packets
packets->AdvectWavePackets(INIT_WAVE_SPEED);
// TODO Setup wide projection for InitiateWaveField (RasterizeWaveMeshPosition)
heightFBO->CommencerCapture();
int displayedPackets = 0;
int packetChunk =0;
/* Standard wave packets */
for (int i = 0; i < packets->m_usedPackets; ++i) {
int pk = packets->m_usedPacket[i];
/* Test for 3rd vertex (sliding point) */
if (!packets->m_packet[pk].use3rd) {
/* Position */
packetData[packetChunk++] = packets->m_packet[pk].midPos.x();
packetData[packetChunk++] = packets->m_packet[pk].midPos.y();
/* Direction */
packetData[packetChunk++] = packets->m_packet[pk].travelDir.x();
packetData[packetChunk++] = packets->m_packet[pk].travelDir.y();
/* Att1 */
packetData[packetChunk++] = packets->m_packet[pk].ampOld;
packetData[packetChunk++] = 2.0f * M_PI / packets->m_packet[pk].k;
packetData[packetChunk++] = packets->m_packet[pk].phase;
packetData[packetChunk++] = packets->m_packet[pk].envelope;
/* Att2 */
packetData[packetChunk++] = packets->m_packet[pk].bending;
packetData[packetChunk++] = 0.0;
packetData[packetChunk++] = 0.0;
packetData[packetChunk++] = 0.0;
displayedPackets++;
if (packetChunk >= PACKET_GPU_BUFFER_SIZE * 3 * 4) {
glBindBuffer(GL_ARRAY_BUFFER, vboPacket);
/* TODO Use Buffer mapping for better performance */
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(packetData), packetData);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//displayPacketOutlined(packetChunk / 12);
/* TODO EvaluatePackets(packetChunk) */
addPacketDisplacement(packetChunk / 12);
packetChunk = 0;
}
}
}
// printf("PacketData[0] = %f , %f\n", packetData[0], packetData[1]);
/* Ghost packets */
for (int i = 0; i < packets->m_usedGhosts; ++i) {
int pk = packets->m_usedGhost[i];
/* Position */
packetData[packetChunk++] = packets->m_ghostPacket[pk].pos.x();
packetData[packetChunk++] = packets->m_ghostPacket[pk].pos.y();
/* Direction */
packetData[packetChunk++] = packets->m_ghostPacket[pk].dir.x();
packetData[packetChunk++] = packets->m_ghostPacket[pk].dir.y();
/* Att1 */
packetData[packetChunk++] = packets->m_ghostPacket[pk].ampOld;
packetData[packetChunk++] = 2.0f * M_PI / packets->m_ghostPacket[pk].k;
packetData[packetChunk++] = packets->m_ghostPacket[pk].phase;
packetData[packetChunk++] = packets->m_ghostPacket[pk].envelope;
/* Att2 */
packetData[packetChunk++] = packets->m_ghostPacket[pk].bending;
packetData[packetChunk++] = 0.0;
packetData[packetChunk++] = 0.0;
packetData[packetChunk++] = 0.0;
displayedPackets++;
if (packetChunk >= PACKET_GPU_BUFFER_SIZE * 3 * 4) {
glBindBuffer(GL_ARRAY_BUFFER, vboPacket);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(packetData), packetData);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//displayPacketOutlined();
/* TODO EvaluatePackets(packetChunk) */
addPacketDisplacement(packetChunk / 12);
packetChunk = 0;
}
}
glBindBuffer(GL_ARRAY_BUFFER, vboPacket);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(packetData), packetData);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//displayPacketOutlined(packetChunk / 12);
/* TODO EvaluatePackets(packetChunk) */
addPacketDisplacement(packetChunk / 12);
heightFBO->TerminerCapture();
/* TODO DisplayScene */
/* TODO Get camera center */
}
void chargerTextures()
{
unsigned char *pixels;
GLsizei largeur, hauteur;
if ( ( pixels = ChargerImage( WATER_TERRAIN_FILE, largeur, hauteur ) ) != NULL )
{
glGenTextures( 1, &texTerrain );
glBindTexture( GL_TEXTURE_2D, texTerrain );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, largeur, hauteur, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glBindTexture( GL_TEXTURE_2D, 0 );
delete[] pixels;
}
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
}
/* Create program and link it
* Input : filenames for vertex, geometry and fragment shader, or NULL*/
GLuint createShader(const GLchar *shaders[3])
{
GLuint prog;
GLenum shaderType[3] = {
GL_VERTEX_SHADER,
GL_GEOMETRY_SHADER,
GL_FRAGMENT_SHADER
};
prog = glCreateProgram();
for (int i = 0; i < 3; ++i) {
if (shaders[i] != NULL) {
printf("Compiling %s ...\n", shaders[i]);
const GLchar *shaderStr = ProgNuanceur::lireNuanceur(shaders[i]);
if (shaderStr == NULL)
break;
GLuint s = glCreateShader(shaderType[i]);
glShaderSource( s, 1, &shaderStr, NULL );
glCompileShader( s );
glAttachShader( prog, s );
ProgNuanceur::afficherLogCompile( s );
delete [] shaderStr;
}
}
glLinkProgram(prog);
ProgNuanceur::afficherLogLink(prog);
return prog;
}
GLuint
getloc(GLuint prog, const GLchar *name, const int type)
{
GLuint loc;
switch (type) {
case LocAttrib:
loc = glGetAttribLocation(prog, name);
break;
case LocUniform:
loc = glGetUniformLocation(prog, name);
break;
}
if (loc == -1)
fprintf(stderr, "Cannot find location for %s\n", name);
return loc;
}
void chargerNuanceurs()
{
// charger le nuanceur de base
{
// créer le programme
progBase = glCreateProgram();
// attacher le nuanceur de sommets
{
GLuint nuanceurObj = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( nuanceurObj, 1, &ProgNuanceur::chainesSommetsMinimal, NULL );
glCompileShader( nuanceurObj );
glAttachShader( progBase, nuanceurObj );
ProgNuanceur::afficherLogCompile( nuanceurObj );
}
// attacher le nuanceur de fragments
{
GLuint nuanceurObj = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( nuanceurObj, 1, &ProgNuanceur::chainesFragmentsMinimal, NULL );
glCompileShader( nuanceurObj );
glAttachShader( progBase, nuanceurObj );
ProgNuanceur::afficherLogCompile( nuanceurObj );
}
// faire l'édition des liens du programme
glLinkProgram( progBase );
ProgNuanceur::afficherLogLink( progBase );
// demander la "Location" des variables
locVertexBase = getloc( progBase, "Vertex", LocAttrib );
locColorBase = getloc( progBase, "Color", LocAttrib );
locmatrModelBase = getloc( progBase, "matrModel", LocUniform );
locmatrVisuBase = getloc( progBase, "matrVisu", LocUniform );
locmatrProjBase = getloc( progBase, "matrProj", LocUniform );
}
// Load RasterizeWaveMeshPosition shader
{
// créer le programme
const GLchar *shaders[3] = {"rasterizeWaveMeshPosition.vert", NULL, "rasterizeWaveMeshPosition.frag"};
progRasterizeWaveMeshPosition = createShader(shaders);
// demander la "Location" des variables
locVertexRWMP = getloc( progRasterizeWaveMeshPosition, "Vertex" , LocAttrib);
locTexCoordRWMP = getloc( progRasterizeWaveMeshPosition, "TexCoord" , LocAttrib);
locmatrModelRWMP = getloc( progRasterizeWaveMeshPosition, "matrModel" , LocUniform);
locmatrVisuRWMP = getloc( progRasterizeWaveMeshPosition, "matrVisu" , LocUniform);
locmatrProjRWMP = getloc( progRasterizeWaveMeshPosition, "matrProj" , LocUniform);
}
// Load AddPacketDisplacement shader
{
// créer le programme
const GLchar *shaders[3] = {"addPacketDisplacement.vert", "addPacketDisplacement.geom", "addPacketDisplacement.frag"};
progAddPacketDisplacement = createShader(shaders);
// demander la "Location" des variables
locPosAPD = getloc( progAddPacketDisplacement, "Pos" , LocAttrib);
locAtt1APD = getloc( progAddPacketDisplacement, "Att1" , LocAttrib);
locAtt2APD = getloc( progAddPacketDisplacement, "Att2" , LocAttrib);
locmatrModelAPD = getloc( progAddPacketDisplacement, "matrModel" , LocUniform);
locmatrVisuAPD = getloc( progAddPacketDisplacement, "matrVisu" , LocUniform);
locmatrProjAPD = getloc( progAddPacketDisplacement, "matrProj" , LocUniform);
locTexAPD = getloc( progAddPacketDisplacement, "tex" , LocUniform);
}
// Load DisplayPacketOutlined shader
{
const GLchar *shaders[3] = {"displayPacketOutlined.vert", "displayPacketOutlined.geom", "displayPacketOutlined.frag"};
progDisplayPacketOutlined = createShader(shaders);
locPosDPO = getloc( progDisplayPacketOutlined, "Pos" , LocAttrib);
locAtt1DPO = getloc( progDisplayPacketOutlined, "Att1" , LocAttrib);
locAtt2DPO = getloc( progDisplayPacketOutlined, "Att2" , LocAttrib);
locmatrModelDPO = getloc( progDisplayPacketOutlined, "matrModel" , LocUniform);
locmatrVisuDPO = getloc( progDisplayPacketOutlined, "matrVisu" , LocUniform);
locmatrProjDPO = getloc( progDisplayPacketOutlined, "matrProj" , LocUniform);
locTexDPO = getloc( progDisplayPacketOutlined, "tex" , LocUniform);
}
// Load DisplayMicroMesh shader
{
const GLchar *shaders[3] = {"displayMicroMesh.vert", "displayMicroMesh.geom", "displayMicroMesh.frag"};
progDisplayMicroMesh = createShader(shaders);
locVertexDMM = getloc( progDisplayMicroMesh, "Vertex" , LocAttrib);
locTexCoordDMM = getloc( progDisplayMicroMesh, "TexCoord" , LocAttrib);
locmatrModelDMM = getloc( progDisplayMicroMesh, "matrModel" , LocUniform);
locmatrVisuDMM = getloc( progDisplayMicroMesh, "matrVisu" , LocUniform);
locmatrProjDMM = getloc( progDisplayMicroMesh, "matrProj" , LocUniform);
locTerrainTexDMM = getloc( progDisplayMicroMesh, "terrain" , LocUniform);
locWaterPosTexDMM = getloc( progDisplayMicroMesh, "waterPos" , LocUniform);
locWaterHeightTexDMM = getloc( progDisplayMicroMesh, "waterHeight" , LocUniform);
}
// Load DisplayTerrain shader
{
const GLchar *shaders[3] = {"displayTerrain.vert", NULL, "displayTerrain.frag"};
progDisplayTerrain = createShader(shaders);
locVertexDT = getloc( progDisplayTerrain, "Vertex" , LocAttrib);
locmatrModelDT = getloc( progDisplayTerrain, "matrModel" , LocUniform);
locmatrVisuDT = getloc( progDisplayTerrain, "matrVisu" , LocUniform);
locmatrProjDT = getloc( progDisplayTerrain, "matrProj" , LocUniform);
locTerrainTexDT = getloc( progDisplayTerrain, "terrain" , LocUniform);
}
// Load RenderAA shader
{
const GLchar *shaders[3] = {"renderAA.vert", NULL, "RenderAA.frag"};
progRenderAA = createShader(shaders);
locVertexRAA = getloc( progRenderAA, "Vertex" , LocAttrib);
locTexCoordRAA = getloc( progRenderAA, "TexCoord" , LocAttrib);
locmatrModelRAA = getloc( progRenderAA, "matrModel" , LocUniform);
locmatrVisuRAA = getloc( progRenderAA, "matrVisu" , LocUniform);
locmatrProjRAA = getloc( progRenderAA, "matrProj" , LocUniform);
locTexRAA = getloc( progRenderAA, "tex" , LocUniform);
}
}
// Create a screen space quad
void initQuad()
{
GLfloat vertices[3*2*2] = {
-1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
1.0, -1.0, 1.0, 1.0, -1.0, 1.0
};
GLfloat texcoords[3*2*2] = {
0.0, 1.0, 1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 0.0, 0.0, 0.0
};
// allouer les objets OpenGL
/* TODO Add support for RenderAA shader */
glGenBuffers( 2, vbosQuad );
/* Prepare VAO for RasterizeWaveMeshPosition shader */
glBindVertexArray(vao[RWMP_SHADER]);
// Bind vertices VBO
glBindBuffer( GL_ARRAY_BUFFER, vbosQuad[0] );
glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW );
glVertexAttribPointer( locVertexRWMP, 2, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray(locVertexRWMP);
// Bind texture coord VBO
glBindBuffer( GL_ARRAY_BUFFER, vbosQuad[1] );
glBufferData( GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW );
glVertexAttribPointer( locTexCoordRWMP, 2, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray(locTexCoordRWMP);
/* Prepare VAO for RenderAA shader */
glBindVertexArray(vao[RAA_SHADER]);
// Bind vertices VBO
glBindBuffer( GL_ARRAY_BUFFER, vbosQuad[0] );
glVertexAttribPointer( locVertexRAA, 2, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray(locVertexRAA);
// Bind texture coord VBO
glBindBuffer( GL_ARRAY_BUFFER, vbosQuad[1] );
glVertexAttribPointer( locTexCoordRAA, 2, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray(locTexCoordRAA);
}
// Create the buffer to store wave packets
void initPacketMesh()
{
glGenBuffers(1, &vboPacket);
glBindVertexArray(vao[APD_SHADER]);
glBindBuffer(GL_ARRAY_BUFFER, vboPacket);
glBufferData(GL_ARRAY_BUFFER, sizeof(packetData), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(locPosAPD, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (void*)0);
glVertexAttribPointer(locAtt1APD, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (void*)4);
glVertexAttribPointer(locAtt2APD, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (void*)8);
glEnableVertexAttribArray(locPosAPD);
glEnableVertexAttribArray(locAtt1APD);
glEnableVertexAttribArray(locAtt2APD);
glBindVertexArray(vao[DPO_SHADER]);
glBindBuffer(GL_ARRAY_BUFFER, vboPacket);
/* No need to initialize the buffer a second time */
glVertexAttribPointer(locPosDPO, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (void*)0);
glVertexAttribPointer(locAtt1DPO, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (void*)4);
glVertexAttribPointer(locAtt2DPO, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 12, (void*)8);
glEnableVertexAttribArray(locPosDPO);
glEnableVertexAttribArray(locAtt1DPO);
glEnableVertexAttribArray(locAtt2DPO);
glBindVertexArray(0);
}
void initHeightFieldMesh()
{
GLfloat *data = new GLfloat[terrainW * terrainH * 6 * 2];
/* TODO Benchmark usefullness of parallel for */
#pragma omp parallel for
for (int y=0; y<terrainH; ++y) {
for (int x=0; x<terrainW; ++x) {
data[(y*terrainW + x) * 12 + 0] = 2.0 * (float)(x) / terrainW - 1.0;
data[(y*terrainW + x) * 12 + 1] = 2.0 * (float)(y) / terrainH - 1.0;
data[(y*terrainW + x) * 12 + 2] = 2.0 * (float)(x) / terrainW - 1.0;
data[(y*terrainW + x) * 12 + 3] = 2.0 * (float)(y+1) / terrainH - 1.0;
data[(y*terrainW + x) * 12 + 4] = 2.0 * (float)(x+1) / terrainW - 1.0;
data[(y*terrainW + x) * 12 + 5] = 2.0 * (float)(y) / terrainH - 1.0;
data[(y*terrainW + x) * 12 + 6] = 2.0 * (float)(x) / terrainW - 1.0;
data[(y*terrainW + x) * 12 + 7] = 2.0 * (float)(y+1) / terrainH - 1.0;
data[(y*terrainW + x) * 12 + 8] = 2.0 * (float)(x+1) / terrainW - 1.0;
data[(y*terrainW + x) * 12 + 9] = 2.0 * (float)(y+1) / terrainH - 1.0;
data[(y*terrainW + x) * 12 + 10] = 2.0 * (float)(x+1) / terrainW - 1.0;
data[(y*terrainW + x) * 12 + 11] = 2.0 * (float)(y) / terrainH - 1.0;
}
}
glGenBuffers(1, &vboHeightField);
glBindVertexArray(vao[DT_SHADER]);
glBindBuffer(GL_ARRAY_BUFFER, vboHeightField);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * terrainW * terrainH * 12, data, GL_STATIC_DRAW);
glVertexAttribPointer(locVertexDT, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(locVertexDT);
glBindVertexArray(0);
delete [] data;
}
// initialisation d'openGL
void initialiser()
{
// donner l'orientation du modèle
thetaCam = 0.0;
phiCam = 0.0;
distCam = 90.0;
// Create FBOs
posFBO = new FBO();
heightFBO = new FBO();
aaFBO = new FBO();
// Create Packets
packets = new Packets(packetBudget);
// couleur de l'arrière-plan
glClearColor( 0.5, 0.6, 0.8, 0.0 );
// activer les etats openGL
glEnable( GL_DEPTH_TEST );
// charger les textures
chargerTextures();
// allouer les UBO pour les variables uniformes
glGenBuffers( 4, ubo );
glGenVertexArrays(NB_SHADERS, vao);
// charger les nuanceurs
chargerNuanceurs();
// Initialize VBOs
initQuad();
initPacketMesh();
initHeightFieldMesh();
}
void conclure()
{
glUseProgram( 0 );
glDeleteVertexArrays( NB_SHADERS, vao );
glDeleteBuffers( 4, vbo );
glDeleteBuffers( 4, ubo );
delete sphere;
delete sphereLumi;
delete theiere;
delete tore;
delete cylindre;
delete cone;
delete posFBO;
delete heightFBO;
delete aaFBO;
delete packets;
}
/* TODO rename according to convention */
void rasterizeWaveMeshPosition()
{
glUseProgram(progRasterizeWaveMeshPosition);
glUniformMatrix4fv( locmatrProjRWMP, 1, GL_FALSE, matrProjWide );
glUniformMatrix4fv( locmatrVisuRWMP, 1, GL_FALSE, matrVisu );
glUniformMatrix4fv( locmatrModelRWMP, 1, GL_FALSE, matrModel );
glBindVertexArray(vao[RWMP_SHADER]);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glUseProgram(0);
}
void displayPacketOutlined(int count)
{
glUseProgram(progDisplayPacketOutlined);
glBindVertexArray(vao[DPO_SHADER]);
glUniformMatrix4fv(locmatrModelDPO, 1, GL_FALSE, matrModel);
glUniformMatrix4fv(locmatrVisuDPO, 1, GL_FALSE, matrVisu);
glUniformMatrix4fv(locmatrProjDPO, 1, GL_FALSE, matrProj);
glDrawArrays(GL_POINTS, 0, count);
glBindVertexArray(0);
glUseProgram(0);
}
void addPacketDisplacement(int count)
{
glUseProgram(progAddPacketDisplacement);
glBindVertexArray(vao[APD_SHADER]);
glUniformMatrix4fv(locmatrModelAPD, 1, GL_FALSE, matrModel);
glUniformMatrix4fv(locmatrVisuAPD, 1, GL_FALSE, matrVisu);
glUniformMatrix4fv(locmatrProjAPD, 1, GL_FALSE, matrProj);
glDrawArrays(GL_POINTS, 0, count);
glBindVertexArray(0);
glUseProgram(0);
}
void displayTerrain()
{
glUseProgram(progDisplayTerrain);
glBindVertexArray(vao[DT_SHADER]);
glUniformMatrix4fv(locmatrModelDT, 1, GL_FALSE, matrModel);
glUniformMatrix4fv(locmatrVisuDT, 1, GL_FALSE, matrVisu);
glUniformMatrix4fv(locmatrProjDT, 1, GL_FALSE, matrProj);
glActiveTexture(GL_TEXTURE0); /* Default value, can be omitted */
glBindTexture(GL_TEXTURE_2D, texTerrain);
glUniform1i(locTerrainTexDT, 0);
glDrawArrays(GL_TRIANGLES, 0, terrainW * terrainH * 12);
glBindVertexArray(0);
glUseProgram(0);
}
void displayMicroMesh()
{
glUseProgram(progDisplayMicroMesh);
glBindVertexArray(vao[DMM_SHADER]);
glUniformMatrix4fv(locmatrModelDMM, 1, GL_FALSE, matrModel);
glUniformMatrix4fv(locmatrVisuDMM, 1, GL_FALSE, matrVisu);
glUniformMatrix4fv(locmatrProjDMM, 1, GL_FALSE, matrProj);
/* Setup textures */
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texTerrain);
glUniform1i(locTerrainTexDMM, 0);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, posFBO->GetRGBTex());
glUniform1i(locWaterPosTexDMM, 1);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, heightFBO->GetRGBTex());
glUniform1i(locWaterHeightTexDMM, 2);
glDrawElements(GL_TRIANGLES, nIndexDMM, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glUseProgram(0);
}
void afficherModele()
{
// Dessiner le modèle
matrModel.PushMatrix(); {
// appliquer les rotations
matrModel.Rotate( phiCam, -1.0, 0.0, 0.0 );
matrModel.Rotate( thetaCam, 0.0, -1.0, 0.0 );
// mise à l'échelle
matrModel.Scale( 5.0, 5.0, 5.0 );
posFBO->CommencerCapture();
rasterizeWaveMeshPosition();
posFBO->TerminerCapture();
updatePackets();
displayTerrain();
displayMicroMesh();
// displayTerrain();
} matrModel.PopMatrix();
}
// fonction d'affichage
void FenetreTP::afficherScene()
{
// effacer l'ecran et le tampon de profondeur
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram( progBase );
// définir le pipeline graphique
matrProj.Perspective( 45.0, (GLdouble)largeur_ / (GLdouble)hauteur_, 0.5, 4000.0 );
matrProjWide.Perspective( 60.0, (GLdouble)largeur_ / (GLdouble)hauteur_, 0.1, 15000.0 );
glUniformMatrix4fv( locmatrProjBase, 1, GL_FALSE, matrProj );
//matrVisu.LookAt( 0.0, 3.0, distCam, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );
matrVisu.LookAt( 10.17, 22.13, 59.49, 10.17, 21.66, 58.61, 0.0, 1.0, 0.0 );
glUniformMatrix4fv( locmatrVisuBase, 1, GL_FALSE, matrVisu );
matrModel.LoadIdentity();
glUniformMatrix4fv( locmatrModelBase, 1, GL_FALSE, matrModel );
// afficher les axes
if ( afficheAxes ) FenetreTP::afficherAxes( 1.0 );
afficherModele();
}
// fonction de redimensionnement de la fenêtre graphique
void FenetreTP::redimensionner( GLsizei w, GLsizei h )
{
std::cout << "Resizing to " << w << "×" << h << std::endl;
/* FIXME Is this function called on program start ? */
glViewport( 0, 0, w, h );
posFBO->Liberer();
posFBO->Init(WAVETEX_WIDTH_FACTOR * w, WAVETEX_HEIGHT_FACTOR * h);
heightFBO->Liberer();
heightFBO->Init(WAVETEX_WIDTH_FACTOR * w, WAVETEX_HEIGHT_FACTOR * h);
aaFBO->Liberer();
aaFBO->Init(AA_OVERSAMPLE_FACTOR * w, AA_OVERSAMPLE_FACTOR * h);
/* Create/resize display mesh */
int meshW = WAVEMESH_WIDTH_FACTOR * w; /*Ça fait un gros mouton */
int meshH = WAVEMESH_HEIGHT_FACTOR * h;
GLfloat *mesh = new GLfloat[meshW * meshH * 2];
nIndexDMM = 3 * 2 * (meshW - 1) * (meshH -1);
GLuint *index = new GLuint[nIndexDMM];
#pragma omp parallel for
for (int y = 0; y < meshH; ++y) {
for (int x = 0; x < meshW; ++x) {
mesh[(y * meshW + x) * 2 + 0] = (x + 0.5) / meshW;
mesh[(y * meshW + x) * 2 + 1] = (y + 0.5) / meshH;
}
}
#pragma omp parallel for
for (int y = 0; y < meshH - 1; ++y) {
for (int x = 0; x < meshW - 1; ++x) {
index[(y * (meshW - 1) + x) * 6 + 0] = y * meshW + x;
index[(y * (meshW - 1) + x) * 6 + 1] = y * meshW + x + 1;
index[(y * (meshW - 1) + x) * 6 + 2] = (y + 1) * meshW + x;
index[(y * (meshW - 1) + x) * 6 + 3] = y * meshW + x + 1;
index[(y * (meshW - 1) + x) * 6 + 4] = (y + 1) * meshW + x + 1;
index[(y * (meshW - 1) + x) * 6 + 5] = (y + 1) * meshW + x;
}
}
glGenBuffers(2, vboDMM);
glBindVertexArray(vao[DMM_SHADER]);
glBindBuffer(GL_ARRAY_BUFFER, vboDMM[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * meshW * meshH * 2, mesh, GL_STATIC_DRAW);
glVertexAttribPointer(locVertexDMM, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(locVertexDMM);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboDMM[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * nIndexDMM, index, GL_STATIC_DRAW);
glBindVertexArray(0);
delete [] mesh;
delete [] index;
}
static void echoEtats( )
{
static std::string illuminationStr[] = { "0:Lambert", "1:Gouraud", "2:Phong" };
static std::string reflexionStr[] = { "0:Phong", "1:Blinn" };
static std::string spotStr[] = { "0:OpenGL", "1:Direct3D" };
std::cout << " modèle d'illumination= " << illuminationStr[varsUnif.typeIllumination]
<< ", refléxion spéculaire= " << reflexionStr[varsUnif.utiliseBlinn]
<< ", spot= " << spotStr[varsUnif.utiliseDirect]
<< std::endl;
}
// fonction de gestion du clavier
void FenetreTP::clavier( TP_touche touche )
{
// traitement des touches q et echap
switch ( touche )
{
case TP_ECHAP:
case TP_q: // Quitter l'application
quit();
break;
case TP_x: // Activer/désactiver l'affichage des axes
afficheAxes = !afficheAxes;
std::cout << "// Affichage des axes ? " << ( afficheAxes ? "OUI" : "NON" ) << std::endl;
break;
case TP_v: // Recharger les fichiers des nuanceurs et recréer le programme
chargerNuanceurs();
std::cout << "// Recharger nuanceurs" << std::endl;
break;
case TP_p: // Permuter la projection: perspective ou orthogonale
enPerspective = !enPerspective;
break;
case TP_i: // Alterner entre le modèle d'illumination: Lambert, Gouraud, Phong
if ( ++varsUnif.typeIllumination > 2 ) varsUnif.typeIllumination = 0;
echoEtats( );
break;
case TP_r: // Alterner entre le modèle de réflexion spéculaire: Phong, Blinn
// Send one wave front
packets->CreateCircularWavefront(0.0, 0.0, 2.0, 0.2, 1.0, 10000);
printf("Sending a circular wavefront...\n");
break;
case TP_s: // Alterner entre le modèle de spot: OpenGL, Direct3D
varsUnif.utiliseDirect = !varsUnif.utiliseDirect;
echoEtats( );
break;
//case TP_l: // Alterner entre une caméra locale à la scène ou distante (localViewer)
// LightModel.localViewer = !LightModel.localViewer;
// std::cout << " localViewer=" << LightModel.localViewer << std::endl;
// break;
case TP_a: // Incrémenter l'angle du cône du spot
case TP_EGAL:
case TP_PLUS:
LightSource[0].spotAngle += 2.0;
if ( LightSource[0].spotAngle > 90.0 ) LightSource[0].spotAngle = 90.0;
std::cout << " spotAngle=" << LightSource[0].spotAngle << std::endl;
break;
case TP_z: // Décrémenter l'angle du cône du spot
case TP_MOINS:
case TP_SOULIGNE:
LightSource[0].spotAngle -= 2.0;
if ( LightSource[0].spotAngle < 0.0 ) LightSource[0].spotAngle = 0.0;
std::cout << " spotAngle=" << LightSource[0].spotAngle << std::endl;
break;
case TP_d: // Incrémenter l'exposant du spot
case TP_BARREOBLIQUE:
LightSource[0].spotExposant += 0.3;
if ( LightSource[0].spotExposant > 89.0 ) LightSource[0].spotExposant = 89.0;
std::cout << " spotExposant=" << LightSource[0].spotExposant << std::endl;
break;
case TP_e: // Décrémenter l'exposant du spot
case TP_POINT:
LightSource[0].spotExposant -= 0.3;
if ( LightSource[0].spotExposant < 0.0 ) LightSource[0].spotExposant = 0.0;
std::cout << " spotExposant=" << LightSource[0].spotExposant << std::endl;
break;
case TP_j: // Incrémenter le coefficient de brillance
case TP_CROCHETDROIT:
FrontMaterial.shininess *= 1.1;
std::cout << " FrontMaterial.shininess=" << FrontMaterial.shininess << std::endl;
break;
case TP_u: // Décrémenter le coefficient de brillance
case TP_CROCHETGAUCHE:
FrontMaterial.shininess /= 1.1; if ( FrontMaterial.shininess < 0.0 ) FrontMaterial.shininess = 0.0;
std::cout << " FrontMaterial.shininess=" << FrontMaterial.shininess << std::endl;
break;
case TP_DROITE:
LightSource[0].position.x += 0.3;
break;
case TP_GAUCHE:
LightSource[0].position.x -= 0.3;
break;
case TP_BAS:
LightSource[0].position.y += 0.3;
break;
case TP_HAUT:
LightSource[0].position.y -= 0.3;
break;
case TP_FIN:
LightSource[0].spotDirection.x += 0.6;
break;
case TP_DEBUT:
LightSource[0].spotDirection.x -= 0.6;
break;
case TP_PAGEPREC:
LightSource[0].spotDirection.y += 0.6;
break;
case TP_PAGESUIV:
LightSource[0].spotDirection.y -= 0.6;
break;
case TP_m: // Choisir le modèle affiché: cube, tore, sphère, théière, cylindre, cône
if ( ++modele > 6 ) modele = 1;
std::cout << " modele=" << modele << std::endl;
break;
case TP_0:
thetaCam = 0.0; phiCam = 0.0; distCam = 30.0; // placer les choses afin d'avoir une belle vue
break;
case TP_t: // Choisir la texture utilisée: aucune, dé, échiquier
varsUnif.texnumero++;
if ( varsUnif.texnumero > 2 ) varsUnif.texnumero = 0;
std::cout << " varsUnif.texnumero=" << varsUnif.texnumero << std::endl;
break;
// case TP_c: // Changer l'affichage de l'objet texturé avec couleurs ou sans couleur
// varsUnif.utiliseCouleur = !varsUnif.utiliseCouleur;
// std::cout << " utiliseCouleur=" << varsUnif.utiliseCouleur << std::endl;
// break;
case TP_o: // Changer l'affichage des texels noirs (noir, mi-coloré, transparent)
varsUnif.afficheTexelNoir++;
if ( varsUnif.afficheTexelNoir > 2 ) varsUnif.afficheTexelNoir = 0;
std::cout << " afficheTexelNoir=" << varsUnif.afficheTexelNoir << std::endl;
break;
case TP_g: // Permuter l'affichage en fil de fer ou plein
modePolygone = ( modePolygone == GL_FILL ) ? GL_LINE : GL_FILL;
glPolygonMode( GL_FRONT_AND_BACK, modePolygone );
break;
case TP_n: // Utiliser ou non les normales calculées comme couleur (pour le débogage)
varsUnif.afficheNormales = !varsUnif.afficheNormales;
break;
case TP_ESPACE: // Permuter la rotation automatique du modèle
enmouvement = !enmouvement;
break;
default:
std::cout << " touche inconnue : " << (char) touche << std::endl;
imprimerTouches();
break;
}
}
// fonction callback pour un clic de souris
int dernierX = 0; // la dernière valeur en X de position de la souris
int dernierY = 0; // la derniere valeur en Y de position de la souris
static enum { deplaceCam, deplaceSpotDirection, deplaceSpotPosition } deplace = deplaceCam;
static bool pressed = false;
void FenetreTP::sourisClic( int button, int state, int x, int y )
{
pressed = ( state == TP_PRESSE );
if ( pressed )
{
// on vient de presser la souris
dernierX = x;
dernierY = y;
switch ( button )
{
case TP_BOUTON_GAUCHE: // Tourner l'objet
deplace = deplaceCam;
break;
case TP_BOUTON_MILIEU: // Modifier l'orientation du spot
deplace = deplaceSpotDirection;
break;
case TP_BOUTON_DROIT: // Déplacer la lumière
deplace = deplaceSpotPosition;
break;
}
}
else
{
// on vient de relâcher la souris
}
}
void FenetreTP::sourisWheel( int x, int y ) // Changer la taille du spot
{
const int sens = +1;
LightSource[0].spotAngle += sens*y;
if ( LightSource[0].spotAngle > 90.0 ) LightSource[0].spotAngle = 90.0;
if ( LightSource[0].spotAngle < 0.0 ) LightSource[0].spotAngle = 0.0;
std::cout << " spotAngle=" << LightSource[0].spotAngle << std::endl;
}
// fonction de mouvement de la souris
void FenetreTP::sourisMouvement( int x, int y )
{
if ( pressed )
{
int dx = x - dernierX;
int dy = y - dernierY;
switch ( deplace )
{
case deplaceCam:
thetaCam -= dx / 3.0;
phiCam -= dy / 3.0;
break;
case deplaceSpotDirection:
LightSource[0].spotDirection.x += 0.06 * dx;
LightSource[0].spotDirection.y -= 0.06 * dy;
// std::cout << " LightSource[0].spotDirection=" << glm::to_string(LightSource[0].spotDirection) << std::endl;
break;
case deplaceSpotPosition:
LightSource[0].position.x += 0.03 * dx;
LightSource[0].position.y -= 0.03 * dy;
// std::cout << " LightSource[0].position=" << glm::to_string(LightSource[0].position) << std::endl;
//glm::vec3 ecranPos( x, hauteur_-y, ecranLumi[2] );
//LightSource[0].position = glm::vec4(glm::unProject( ecranPos, VM, P, cloture ), 1.0);
break;
}
dernierX = x;
dernierY = y;
verifierAngles();
}
}
int main( int argc, char *argv[] )
{
// créer une fenêtre
FenetreTP fenetre( "INF2705 TP" );
// allouer des ressources et définir le contexte OpenGL
initialiser();
bool boucler = true;
while ( boucler )
{
// mettre à jour la physique
calculerPhysique( );
// affichage
fenetre.afficherScene();
fenetre.swap();
// récupérer les événements et appeler la fonction de rappel
boucler = fenetre.gererEvenement();
}
// détruire les ressources OpenGL allouées
conclure();
return 0;
}