//////////////////////////////////////////////////////////////////////////////
/// \file CooneyMesh.h
///
/// Declares:
/// Mesh - Geometric data structure organized for rendering with OpenGL.
///
/// Stephen Timothy Cooney, 2009
//////////////////////////////////////////////////////////////////////////////
#ifndef COONEYMESH_H
#define COONEYMESH_H
#include <vector>
#include "CooneyMath.h"
namespace Cooney
{
// prototypes
struct MeshVertex;
struct MeshVertFace;
struct MeshIndexFace;
struct MeshVertQuad;
struct MeshIndexQuad;
class Mesh;
/// Describes a geometric mesh with OpenGL capabilities.
/// Data is kept in seperate streams and can be pushed-popped
/// from OpenGL without affecting the other data.
///
/// Supports:
/// Triangles (Called faces here)
/// Quads
/// -
/// Positions
/// Normals
/// Tangents (necessary for normal maps)
/// Colors
/// Texture Coordinates (1 right now but easily extendable)
class Mesh
{
std::vector<MeshIndexFace> faces; // Tris
std::vector<MeshIndexQuad> quads; // Quads
std::vector<Cooney::Math::Vec3> positions;
std::vector<Cooney::Math::Vec3> normals;
std::vector<Cooney::Math::Vec3> tangents;
std::vector<Cooney::Math::Vec3> colors;
std::vector<Cooney::Math::Vec2> texCoords;
// OpenGL mapping
#define VBO_POSITION 0
#define VBO_NORMAL 1
#define VBO_TANGENT 2
#define VBO_COLOR 3
#define VBO_TEXCOORD 4
#define VBO_FACEINDEX 5
#define VBO_QUADINDEX 6
#define VBO_NUM 7
bool initiatedvbo[VBO_NUM];
unsigned int vertexbufferobject[VBO_NUM];
#define VBO_STATIC 0 // if this, will load the vertex data ONCE!!! if you change the data, it won't update it unless you tell it to! PushGLData(); default...
#define VBO_STREAM 1 // if this, will load the vertex data every FRAME! (streaming, hint hint) use for animated meshes
unsigned int vboStyle[VBO_NUM];
public:
Mesh();
~Mesh();
// VERTEX
/// Add a vertex into the buffer.
/// Returns an int that directly maps to the vertex's
/// index. If an equivalent vertex already exists, the
/// vertex will not be added, but that equal vert's
/// index will be returned. Returns -1 on failure.
int AddVertex(const MeshVertex &vertex);
/// Overwrites a vertex at a specific index.
/// Returns true on success, false on failure.
bool SetVertex(const MeshVertex &vertex, const unsigned int vertIndex);
/// Does a vertex compare(== see class) to determine if
/// the vertex exists in the mesh. Returns it's index
/// if it exists. Returns -1 if it is not found.
int FindVertex(const MeshVertex &vertex);
/// Returns a copy of the vertex at a specific index.
/// Will return a default/empty vertex if one is not
/// found so it's best to know you're using the right
/// index.
MeshVertex GetVertex(const unsigned int vertIndex);
/// Gets the vertex at a specific index and fills an out vertex
/// with it's data. Returns true on success, false on failure.
bool GetVertex(const unsigned int vertIndex, MeshVertex& outVert);
// TRIANGLES
/// Add a triangle face to the mesh.
/// First adds the face's vertexes and then pushes
/// an index face onto the list.
/// Returns the new face's index. Returns -1 on failure.
int AddFace(const MeshVertFace &face);
/// Add a triangle face based on indexes.
/// Checks for bad indexes, otherwise adds the index
/// face to the list. It is assumed that the indexes
/// map towards indended vertices in the mesh.
/// Returns the faces index, otherwise returns -1.
int AddFace(const MeshIndexFace &face);
/// Adds a triangle A-B-C(-A) from three vertexes.
/// Adds the vertexes to the vertex stack and adds
/// their index face to a list for rendering.
int AddFace(const MeshVertex &vertA, const MeshVertex &vertB, const MeshVertex &vertC);
/// Adds a triangle built directly from indexes that map to
/// a triangle A-B-C(-A).
/// Returns the new index triangle's own index
/// or -1 on failure.
int AddFace(const unsigned int indexA, const unsigned int indexB, const unsigned int indexC);
/// Overwrites a triangle face at a specific index.
/// Returns true on success, false on failure.
bool SetFace(const MeshVertFace &face, const unsigned int indexFace);
/// Overwrites a triangle index face at a
/// specific index.
/// Returns true on success, false on failure.
bool SetFace(const MeshIndexFace &face, const unsigned int indexFace);
/// Overwrites a face's vertices at a specific index.
/// Returns true on success, returns -1 on failure.
bool SetFace(const MeshVertex &vertA, const MeshVertex &vertB, const MeshVertex &vertC, const unsigned int indexFace);
/// Overwrites an index face at a specific index.
/// Returns true on success, returns -1 on failure.
bool SetFace(const unsigned int indexA, const unsigned int indexB, const unsigned int indexC, const unsigned int indexFace);
/// Returns a face consisting the actual vertexes at
/// a specific face index. If the index is bad, returns
/// an empty MeshVertFace.
MeshVertFace GetVertFace(const unsigned int index);
/// Returns a face consisting of the vertex indexes
/// at a face index. If the index is bad, returns
/// a default MeshIndexFace.
MeshIndexFace GetIndexFace(const unsigned int index);
/// QUADS
/// Add a quad face to the mesh.
/// First adds the quads's vertexes and then pushes
/// an index face onto the list.
/// Returns the new quad's index. Returns -1 on failure.
int AddQuad(const MeshVertQuad &quad);
/// Add a quad face based on indexes.
/// Checks for bad indexes, otherwise adds the index
/// quad to the list. It is assumed that the indexes
/// map towards indended vertices in the mesh.
/// Returns the qaud's index, otherwise returns -1.
int AddQuad(const MeshIndexQuad &quad);
/// Adds a quad A-B-C-D(-A) from four vertexes.
/// Adds the vertexes to the vertex stack and adds
/// their index quad to a list for rendering.
int AddQuad(const MeshVertex &vertA, const MeshVertex &vertB, const MeshVertex &vertC, const MeshVertex &vertD);
/// Adds a quad built directly from indexes that map to
/// a quad A-B-C-D(-A).
/// Returns the new index quad's own index or
/// -1 on failure.
int AddQuad(const unsigned int indexA, const unsigned int indexB, const unsigned int indexC, const unsigned int indexD);
/// Overwrites a quad face at a specific index.
/// Returns true on success, false on failure.
bool SetQuad(const MeshVertQuad &quad, const unsigned int indexQuad);
/// Overwrites a quad index face at a
/// specific index.
/// Returns true on success, false on failure.
bool SetQuad(const MeshIndexQuad &quad, const unsigned int indexQuad);
/// Overwrites a quad's vertices at a specific index.
/// Returns true on success, returns -1 on failure.
bool SetQuad(const MeshVertex &vertA, const MeshVertex &vertB, const MeshVertex &vertC, const MeshVertex &vertD, const unsigned int indexQuad);
/// Overwrites a quad face at a specific index.
/// Returns true on success, returns -1 on failure.
bool SetQuad(const unsigned int indexA, const unsigned int indexB, const unsigned int indexC, const unsigned int indexD, const unsigned int indexQuad);
/// Returns a quad consisting the actual vertexes at
/// a specific quad index. If the index is bad, returns
/// an empty MeshVertQuad.
MeshVertQuad GetVertQuad(const unsigned int index);
/// Returns a quad consisting of the vertex indexes
/// at a quad index. If the index is bad, returns
/// a default MeshIndexQuad.
MeshIndexQuad GetIndexQuad(const unsigned int index);
// Utility functions for autogenerating
// normals and tangents.
/// Automatically generates the normals based on the
/// face's winding and size. The first pass sums each
/// vertex's faces cross product normals. Last (and only
/// last) these summed normals are normalized which
/// allows larger faces to have more 'weight' on the
/// vertex's lighting normal.
void CalculateNormals();
/// Automatically generate tangents based on the UV
/// coordinates of the faces connected to a vertex.
void CalculateTangents();
/// Empty the mesh.
void Clear();
/// Resize the number of verts in the mesh.
void Resize(unsigned int numVertexes, unsigned int numFaces, unsigned int numQuads);
/// Reserve memory for a potential amount of vertexes in the mesh.
void Reserve(unsigned int numVertexes, unsigned int numFaces, unsigned int numQuads);
/// Makes a deep copy of an input mesh.
/// This method is a little more explicit than using
/// a copy constructor.
void Copy(Cooney::Mesh ©);
/// DATA ACCESSORS
/// Return the number of triangle faces in the mesh.
inline unsigned int NumFaces() const { return (unsigned int)faces.size(); }
/// Return a pointer to the beginning of the index
/// faces array.
inline MeshIndexFace * Faces() { return &*faces.begin(); }
/// Return the number of quad faces in the mesh.
inline unsigned int NumQuads() const { return (unsigned int)quads.size(); }
/// Returns a pointer to the beginning of the index
/// quads array.
inline MeshIndexQuad * Quads() { return &*quads.begin(); }
/// Returns the number of vertexes in the mesh.
/// This number is equivalent for positions, normals,
/// tangents, colors and texcoords.
inline const unsigned int NumVertexes() const { return (unsigned int)positions.size(); }
/// Returns a pointer to the beginning of the vertex positions array.
inline Cooney::Math::Vec3 * VertPositions() { return &*positions.begin(); }
/// Returns a pointer to the beginning of the normals array.
inline Cooney::Math::Vec3 * VertNormals() { return &*normals.begin(); }
/// Returns a pointer to the beginning of the tangents array.
inline Cooney::Math::Vec3 * VertTangents() { return &*tangents.begin(); }
/// Returns a pointer to the beginning of the colors array.
inline Cooney::Math::Vec3 * VertColors() { return &*colors.begin(); }
/// Returns a pointer to the beginning of the texture coordinates array.
inline Cooney::Math::Vec2 * VertTexCoords() { return &*texCoords.begin(); }
// OPENGL
/// For each of the vertex data channels, set whether or not that
/// data should be expected to be streamed or static. Static data
/// is processed faster, however streamed data has a better
/// connection to the buffer between the host and GPU (This is what
/// OpenGL says, implementation may vary).
void SetGLStreaming(bool bPositions=false, bool bNormals=false, bool bTangents=false, bool bColors=false, bool bTexCoords=false, bool bFaceIndexes=false, bool bQuadIndexes=false);
/// Push the vertex data onto OpenGL's registers and draw.
/// If the data is not already on the card, this call will
/// automatically upload the data first. This may also
/// automatically push the data onto the card if a certain
/// buffer was set to streaming with SetGLStreaming().
void PushGL(bool bPositions=true, bool bNormals=false, bool bTangents=false, bool bColors=false, bool bTexCoords=false);
/// Upload/Push new data to the OpenGL enabled device.
void PushGLData(bool bPositions=true, bool bNormals=false, bool bTangents=false, bool bColors=false, bool bTexCoords=false, bool bFaceIndexes=false, bool bQuadIndexes=false);
/// Remove the OpenGL data from device and delete their
/// buffer references.
void PopGLData(bool bPositions=true, bool bNormals=true, bool bTangents=true, bool bColors=true, bool bTexCoords=true, bool bFaceIndexes=true, bool bQuadIndexes=true); // kills all connection to OPENGL
// FILE UTILITIES
/// Load into this mesh from a prorietary format (defined here).
bool Load(const char *filePath);
/// Save out to a file in a proprietary format (defined here).
bool Save(const char *filePath);
/// Used in parallel with Load, this abstracts the
/// loading procedure to a stream so that it can be
/// used with different forms of data input.
void StreamInMesh(std::istream& inStream);
/// Used in parallel with Save, this abstracts the
/// saving procedure to a stream so that it can be
/// used with different forms of data output.
void StreamOutMesh(std::ostream& outStream);
};
/// Describes a geometric point on a mesh.
struct MeshVertex
{
Cooney::Math::Vec3 position;
Cooney::Math::Vec3 normal;
Cooney::Math::Vec3 tangent;
Cooney::Math::Vec3 color;
Cooney::Math::Vec2 texCoord;
bool operator ==(const MeshVertex &other)
{
if( position == other.position )
// TODO: FatSim: Create a more dynamic compare,
// in this application we only need this
// sort but for other applications, vertex
// individuality may have different meanings.
//&&
//normal == other.normal &&
//tangent == other.tangent &&
//color == other.color &&
//texCoord == other.texCoord )
{
return true;
}
return false;
}
bool operator !=(const MeshVertex &other)
{
if( position == other.position )
// TODO: FatSim: Create a more dynamic compare,
// in this application we only need this
// sort but for other applications, vertex
// individuality may have different meanings.
//&&
//normal == other.normal &&
//tangent == other.tangent &&
//color == other.color &&
//texCoord == other.texCoord )
{
return false;
}
return true;
}
};
/// A triangle face is not much more here than
/// a collection of three vertices.
struct MeshVertFace
{
MeshVertex vertA, vertB, vertC;
};
/// A index triangle face describes mappings to
/// indexes in mesh that contains many, some shared,
/// vertexes.
struct MeshIndexFace
{
unsigned int indexA, indexB, indexC;
MeshIndexFace(){indexA=indexB=indexC=0;}
};
/// A quad face is not much more here than a
/// collection of four vertexes.
struct MeshVertQuad
{
MeshVertex vertA, vertB, vertC, vertD;
};
/// A index quad face describes mappings to
/// vertexes in a mesh that contains many,
/// some shared, vertexes.
struct MeshIndexQuad
{
unsigned int indexA, indexB, indexC, indexD;
MeshIndexQuad(){indexA=indexB=indexC=indexD=0;}
};
};
#endif //#ifndef COONEYMESH_H