2016-06-30 15:26:55 +02:00

279 lines
9.3 KiB
C++

#ifndef MESH_H
#define MESH_H
#include "opengl.h"
#include <vector>
#include <string>
#include <glm/vec3.hpp>
#include <glm/vec2.hpp>
class Buffer;
class Material;
class Shader;
struct Mesh
{
public:
/*************************************************************/
/* MESH AND MATERIAL FLAGS */
/*************************************************************/
// Mesh properties
enum {
// Geometric properties
MESH_INDEXED,
MESH_TEXTURABLE,
MESH_INSTANCED,
// Mesh type
MESH_3D,
MESH_2D,
// 3D Geometric properties
MESH_TANGENT_SPACE,
MESH_DOUBLE_SIDED,
MESH_BILLBOARD,
MESH_SHADOWED,
// simple material (no lighting)
MATERIAL_COLOR_TEXTURE,
MATERIAL_ALPHA_MASK,
// 3D phong material
MATERIAL_PHONG,
MATERIAL_PHONG_DIFFUSE_TEXTURE,
MATERIAL_PHONG_EMISSION_TEXTURE,
MATERIAL_PHONG_SPECULAR_TEXTURE,
MATERIAL_PHONG_NORMAL_MAP,
// 3D Beckman-like materials
MATERIAL_BACKMANN_BUMP_MAP,
NB_FLAGS
};
// shader "#define" strings associated to the properties
static const char* const flagStr[NB_FLAGS];
/*************************************************************/
/* GEOMETRY DATA */
/*************************************************************/
// 3D public data
std::vector<glm::vec3> positions3D;
std::vector<glm::vec3> normals;
typedef struct
{
glm::vec3 tangent;
glm::vec3 binormal;
} Tangents;
std::vector<Tangents> tangents;
// 2D public data
std::vector<glm::vec2> positions2D;
// public data common to 2D and 3D
std::vector<glm::vec2> texCoords;
std::vector<glm::vec3> instances_offsets;
std::vector<GLuint> indices;
/*************************************************************/
/* MAIN METHODS */
/*************************************************************/
/**
* @brief Mesh builds an empty mesh, to be renderable, a mesh must have vertices and a material.
*/
Mesh(const std::string &name = "mesh");
~Mesh();
void setName(const std::string &name) { m_name = name; }
std::string getName() { return m_name; }
/**
* OpenGL methods :
* - initGL allocates the GPU buffers and sends the mesh data to the GPU
* - draw binds the material attributes and draws the mesh geometry
* - destroyGL releases the allocated GPU memory, destroyGL is called automatically in Mesh's destructor and at the beginning of initGL
*/
void initGL();
void draw(Shader* shader, bool drawNormals = true, bool drawTexCoord = true, bool drawTangents = true);
void destroyGL();
/**
* @brief clearData clears all data vectors, but keeps GPU data allocated.
*/
void clearData();
/**
* @brief getFlags returns the flags that defines the specificities of the mesh and his material
*/
unsigned int getFlags();
/*************************************************************/
/* MESH BUILDING METHODS */
/*************************************************************/
// add vertex
void addVertex(float x, float y, float z) {addVertex(glm::vec3(x, y, z));}
void addVertex(const glm::vec3 &position) {positions3D.push_back(position);}
void addVertex(float x, float y) {addVertex(glm::vec2(x, y));}
void addVertex(const glm::vec2 &position) {positions2D.push_back(position);}
void addVertex(const glm::vec3 &position, const glm::vec2 &texCoord) {addVertex(position); addTexCoord(texCoord);}
void addVertex(const glm::vec2 &position, const glm::vec2 &texCoord) {addVertex(position); addTexCoord(texCoord);}
void addVertex(const glm::vec3 &position, const glm::vec3 &normal) {addVertex(position); addNormal(normal);}
void addVertex(const glm::vec3 &position, const glm::vec3 &normal, const glm::vec2 &texCoord) {addVertex(position, normal); addTexCoord(texCoord);}
void addRectangle2D(const glm::vec2 &pos, const glm::vec2 &dim, const glm::vec2 &texCoord, const glm::vec2 &texRange, bool indexed = false);
void addRectangle2D(const glm::vec2 &pos, const glm::vec2 &dim, bool indexed = false) {addRectangle2D(pos, dim, glm::vec2(0), glm::vec2(1), indexed);}
void addRectangle2D(float x, float y, float width, float height, bool indexed = false) {addRectangle2D(glm::vec2(x, y), glm::vec2(width, height), indexed);}
// add indices
void addTriangle(int i1, int i2, int i3) {indices.push_back(i1), indices.push_back(i2), indices.push_back(i3);}
void addLine(int i1, int i2) {indices.push_back(i1), indices.push_back(i2);}
// Material accessers
void setMaterial(Material* mat) {material = mat;}
Material *getMaterial() {return material;}
// other accessers
void addNormal(float x, float y, float z) {addNormal(glm::vec3(x, y, z));}
void addNormal(const glm::vec3 &normal) {normals.push_back(normal);}
void addTexCoord(float u, float v) {addTexCoord(glm::vec2(u, v));}
void addTexCoord(const glm::vec2 &texCoord) {texCoords.push_back(texCoord);}
/*************************************************************/
/* 2D MESH PROPERTIES */
/*************************************************************/
/**
* @brief setDepth allows to set the depth of a 2D mesh, the depth must be between -1 and 1, -1 being the closest to the camera
*/
void setDepth(float d) { depth = d; }
float getDepth() { return depth; }
/*************************************************************/
/* 3D MESH PROPERTIES */
/*************************************************************/
/**
* @brief setIsDoubleSided allows to enable or disable face culling for this Mesh
*/
void setIsDoubleSided(bool val) {isDoubleSided = val;}
/**
* @brief setIsBillboard allows to enable or disable billboarding,
* a billboard mesh will always follow the camera orientation
*/
void setIsBillboard(bool val) {isBillboard = val;}
/**
* @brief setIsShadowCaster allows to enable or disable,
* rendering of this mesh in the shadowmaps
*/
void setIsShadowCaster(bool val) {isShadowCaster = val;}
/*************************************************************/
/* 3D MESH TOOLS */
/*************************************************************/
/**
* @brief mergeVertices simplifies an indexed mesh by merging all vertices that
* have exactly the same position, texcoord, and normals, the tangents will be averaged.
*/
void mergeVertices();
/**
* @brief computeNormals computes adjacency for a triangle mesh, the mesh type changes to GL_TRIANGLES_ADJACENCY
*/
void computeNeighbors();
/**
* compute normals from an indexed mesh (positions + indices)
*/
void computeNormals();
/**
* compute tangent space from a textured indexed mesh (positions + normals + texcoords + indices)
*/
void computeTangents();
/**
* compute the bounding box of the mesh based on the 3D positions
*/
void computeBoundingBox(glm::vec3 &min, glm::vec3 &max);
/*************************************************************/
/* SERIALISATION */
/*************************************************************/
/**
* @brief serializeMesh can be used to save a mesh
* @return true if the mesh has succesfully been saved
*/
static bool serialize(Mesh* mesh, FILE *file);
bool serialize(FILE *file) { return serialize(this, file); }
/**
* @brief deserializeMesh can be used to load a mesh
* @return the loaded mesh of NULL if a reading error has occured
*/
static Mesh* deserialize(FILE *file);
/*************************************************************/
/* ADVANCED CUSTOMISATION */
/*************************************************************/
/**
* Specifies what kind of primitives to render. Symbolic constants GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY,
* GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY and GL_PATCHES are accepted.
*
* default is GL_TRIANGLES
*/
void setPrimitiveType(GLenum type) {primitive_type = type;}
protected:
std::string m_name;
Material* material;
bool isDoubleSided;
bool isBillboard;
bool isShadowCaster;
float depth;
GLenum primitive_type;
std::vector<Buffer*> buffers;
enum {
// required buffer
POSITION2D_BUFFER,
POSITION3D_BUFFER,
// indices buffers
INDICES_BUFFER,
// optionnal buffers :
NORMAL_BUFFER,
TEXCOORD_BUFFER,
TANGENT_BUFFER,
// instanciation buffer
INSTANCE_BUFFER,
NB_BUFFERS
};
int buffersId[NB_BUFFERS];
void addBuffer(Buffer *b, int bufferType);
void clearBuffers();
GLuint vao;
};
#endif // MESH_H