mirror of https://github.com/mosra/magnum.git
3 changed files with 357 additions and 0 deletions
@ -0,0 +1,156 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2010 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Magnum is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU Lesser General Public License version 3 |
||||||
|
only, as published by the Free Software Foundation. |
||||||
|
|
||||||
|
Magnum is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU Lesser General Public License version 3 for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "Mesh.h" |
||||||
|
#include "Buffer.h" |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
|
||||||
|
namespace Magnum { |
||||||
|
|
||||||
|
Mesh::~Mesh() { |
||||||
|
for(map<Buffer*, pair<bool, vector<Attribute> > >::iterator it = buffers.begin(); it != buffers.end(); ++it) |
||||||
|
delete it->first; |
||||||
|
} |
||||||
|
|
||||||
|
Buffer* Mesh::addBuffer(bool interleaved) { |
||||||
|
Buffer* buffer = new Buffer(Buffer::ArrayBuffer); |
||||||
|
buffers.insert(pair<Buffer*, pair<bool, vector<Attribute> > >( |
||||||
|
buffer, |
||||||
|
pair<bool, vector<Attribute> >(interleaved, vector<Attribute>()) |
||||||
|
)); |
||||||
|
|
||||||
|
return buffer; |
||||||
|
} |
||||||
|
|
||||||
|
void Mesh::draw() { |
||||||
|
/* Finalize the mesh, if it is not already */ |
||||||
|
finalize(); |
||||||
|
|
||||||
|
/* Enable vertex arrays for all attributes */ |
||||||
|
for(set<GLuint>::const_iterator it = attributes.begin(); it != attributes.end(); ++it) |
||||||
|
glEnableVertexAttribArray(*it); |
||||||
|
|
||||||
|
/* Bind attributes to vertex buffers */ |
||||||
|
for(map<Buffer*, pair<bool, vector<Attribute> > >::iterator it = buffers.begin(); it != buffers.end(); ++it) { |
||||||
|
/* Bind buffer */ |
||||||
|
it->first->bind(); |
||||||
|
|
||||||
|
/* Bind all attributes to this buffer */ |
||||||
|
for(vector<Attribute>::const_iterator ait = it->second.second.begin(); ait != it->second.second.end(); ++ait) |
||||||
|
switch(ait->type) { |
||||||
|
case GL_BYTE: |
||||||
|
case GL_UNSIGNED_BYTE: |
||||||
|
case GL_SHORT: |
||||||
|
case GL_UNSIGNED_SHORT: |
||||||
|
case GL_INT: |
||||||
|
case GL_UNSIGNED_INT: |
||||||
|
glVertexAttribIPointer(ait->location, ait->size, ait->type, ait->stride, ait->pointer); |
||||||
|
break; |
||||||
|
default: |
||||||
|
glVertexAttribPointer(ait->location, ait->size, ait->type, GL_FALSE, ait->stride, ait->pointer); |
||||||
|
} |
||||||
|
|
||||||
|
/* Unbind buffer */ |
||||||
|
it->first->unbind(); |
||||||
|
} |
||||||
|
|
||||||
|
glDrawArrays(primitive, 0, count); |
||||||
|
|
||||||
|
/* Disable vertex arrays for all attributes */ |
||||||
|
for(set<GLuint>::const_iterator it = attributes.begin(); it != attributes.end(); ++it) |
||||||
|
glDisableVertexAttribArray(*it); |
||||||
|
} |
||||||
|
|
||||||
|
void Mesh::finalize() { |
||||||
|
/* Already finalized */ |
||||||
|
if(finalized) return; |
||||||
|
|
||||||
|
/* Finalize attribute positions for every buffer */ |
||||||
|
for(map<Buffer*, pair<bool, vector<Attribute> > >::iterator it = buffers.begin(); it != buffers.end(); ++it) { |
||||||
|
/* Avoid confustion */ |
||||||
|
bool interleaved = it->second.first; |
||||||
|
vector<Attribute>& attributes = it->second.second; |
||||||
|
|
||||||
|
/* Interleaved buffer, set stride and position of first attribute */ |
||||||
|
if(interleaved) { |
||||||
|
/* Set attribute position and compute stride */ |
||||||
|
GLsizei stride = 0; |
||||||
|
for(vector<Attribute>::iterator ait = attributes.begin(); ait != attributes.end(); ++ait) { |
||||||
|
/* The attribute is positioned at the end of previous */ |
||||||
|
ait->pointer = reinterpret_cast<const GLvoid*>(stride); |
||||||
|
|
||||||
|
/* Add attribute size (per vertex) to stride */ |
||||||
|
stride += ait->size*sizeOf(ait->type); |
||||||
|
} |
||||||
|
|
||||||
|
/* Set computed stride for all attributes */ |
||||||
|
for(vector<Attribute>::iterator ait = attributes.begin(); ait != attributes.end(); ++ait) |
||||||
|
ait->stride = stride; |
||||||
|
|
||||||
|
/* Non-interleaved buffer, set position of every attribute */ |
||||||
|
} else { |
||||||
|
/* Set attribute position */ |
||||||
|
GLsizei position = 0; |
||||||
|
for(vector<Attribute>::iterator ait = attributes.begin(); ait != attributes.end(); ++ait) { |
||||||
|
/* The attribute is positioned at the end of previous attribute array */ |
||||||
|
ait->pointer = reinterpret_cast<const GLvoid*>(position); |
||||||
|
|
||||||
|
/* Add attribute size (for all vertices) to position */ |
||||||
|
position += ait->size*sizeOf(ait->type)*count; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Mesh is now finalized, attribute binding is not allowed */ |
||||||
|
finalized = true; |
||||||
|
} |
||||||
|
|
||||||
|
void Mesh::bindAttribute(Buffer* buffer, GLuint attribute, GLint size, GLenum type) { |
||||||
|
/* The mesh is finalized or attribute is already bound, nothing to do */ |
||||||
|
if(finalized || attributes.find(attribute) != attributes.end()) return; |
||||||
|
|
||||||
|
/* If buffer is not managed by this mesh, nothing to do */ |
||||||
|
map<Buffer*, pair<bool, vector<Attribute> > >::iterator found = buffers.find(buffer); |
||||||
|
if(found == buffers.end()) return; |
||||||
|
|
||||||
|
Attribute a; |
||||||
|
a.location = attribute; |
||||||
|
a.size = size; |
||||||
|
a.type = type; |
||||||
|
a.stride = 0; |
||||||
|
a.pointer = 0; |
||||||
|
|
||||||
|
found->second.second.push_back(a); |
||||||
|
attributes.insert(attribute); |
||||||
|
} |
||||||
|
|
||||||
|
GLsizei Mesh::sizeOf(GLenum type) { |
||||||
|
switch(type) { |
||||||
|
case GL_BYTE: return sizeof(GLbyte); |
||||||
|
case GL_UNSIGNED_BYTE: return sizeof(GLubyte); |
||||||
|
case GL_SHORT: return sizeof(GLshort); |
||||||
|
case GL_UNSIGNED_SHORT: return sizeof(GLushort); |
||||||
|
case GL_INT: return sizeof(GLint); |
||||||
|
case GL_UNSIGNED_INT: return sizeof(GLuint); |
||||||
|
case GL_FLOAT: return sizeof(GLfloat); |
||||||
|
case GL_DOUBLE: return sizeof(GLdouble); |
||||||
|
default: return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,200 @@ |
|||||||
|
#ifndef Magnum_Mesh_h |
||||||
|
#define Magnum_Mesh_h |
||||||
|
/*
|
||||||
|
Copyright © 2010 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Magnum is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU Lesser General Public License version 3 |
||||||
|
only, as published by the Free Software Foundation. |
||||||
|
|
||||||
|
Magnum is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU Lesser General Public License version 3 for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @brief Class Magnum::Mesh |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <map> |
||||||
|
#include <vector> |
||||||
|
#include <set> |
||||||
|
|
||||||
|
#include "Magnum.h" |
||||||
|
|
||||||
|
namespace Magnum { |
||||||
|
|
||||||
|
class Buffer; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base class for managing non-indexed meshes |
||||||
|
* |
||||||
|
* @todo Support for normalized values (e.g. for color as char[4] passed to |
||||||
|
* shader as floating-point vec4) |
||||||
|
*/ |
||||||
|
class Mesh { |
||||||
|
public: |
||||||
|
/** @brief Primitive type */ |
||||||
|
enum Primitive { |
||||||
|
/**
|
||||||
|
* Single points |
||||||
|
*/ |
||||||
|
Points = GL_POINTS, |
||||||
|
|
||||||
|
/**
|
||||||
|
* Each pair of vertices defines a single line, lines aren't |
||||||
|
* connected together. |
||||||
|
*/ |
||||||
|
Lines = GL_LINES, |
||||||
|
|
||||||
|
/**
|
||||||
|
* Polyline |
||||||
|
*/ |
||||||
|
LineStrip = GL_LINE_STRIP, |
||||||
|
|
||||||
|
/**
|
||||||
|
* Polyline, last vertex is connected to first. |
||||||
|
*/ |
||||||
|
LineLoop = GL_LINE_LOOP, |
||||||
|
|
||||||
|
/**
|
||||||
|
* Each three vertices define one triangle. |
||||||
|
*/ |
||||||
|
Triangles = GL_TRIANGLES, |
||||||
|
|
||||||
|
/**
|
||||||
|
* First three vertices define first triangle, each following |
||||||
|
* vertex defines another triangle. |
||||||
|
*/ |
||||||
|
TriangleStrip = GL_TRIANGLE_STRIP, |
||||||
|
|
||||||
|
/**
|
||||||
|
* First vertex is center, each following vertex is connected to |
||||||
|
* previous and center vertex. |
||||||
|
*/ |
||||||
|
TriangleFan = GL_TRIANGLE_FAN |
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor |
||||||
|
* @param _primitive Primitive type |
||||||
|
* @param _count Vertex count |
||||||
|
*/ |
||||||
|
inline Mesh(Primitive _primitive, GLsizei _count): primitive(_primitive), count(_count), finalized(false) {} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor |
||||||
|
* |
||||||
|
* Deletes all associated buffers. |
||||||
|
*/ |
||||||
|
~Mesh(); |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add buffer |
||||||
|
* @param interleaved If storing more than one attribute data in the |
||||||
|
* buffer, the data of one attribute can be either kept together |
||||||
|
* or interleaved with data for another attributes, so data for |
||||||
|
* every vertex will be in one continuous place. |
||||||
|
* |
||||||
|
* Adds new buffer to the mesh. The buffer can be then filled with |
||||||
|
* Buffer::setData(). |
||||||
|
*/ |
||||||
|
Buffer* addBuffer(bool interleaved); |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Bind attribute |
||||||
|
* @param buffer Buffer where bind the attribute to (pointer |
||||||
|
* returned by addBuffer()) |
||||||
|
* @param attribute Attribute |
||||||
|
* |
||||||
|
* Binds attribute of given type with given buffer. If the attribute is |
||||||
|
* already bound, given buffer isn't managed with this mesh (wasn't |
||||||
|
* initialized with addBuffer) or the mesh was already drawn, the |
||||||
|
* function does nothing. |
||||||
|
*/ |
||||||
|
template<class T> void bindAttribute(Buffer* buffer, GLuint attribute); |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Draw a mesh |
||||||
|
* |
||||||
|
* Binds attributes to buffers and draws the mesh. Expects an active |
||||||
|
* shader with all uniforms set. |
||||||
|
*/ |
||||||
|
void draw(); |
||||||
|
|
||||||
|
protected: |
||||||
|
/**
|
||||||
|
* @brief Finalize the mesh |
||||||
|
* |
||||||
|
* Computes location and stride of each attribute in its buffer. After |
||||||
|
* this function is called, no new attribute can be bound. |
||||||
|
*/ |
||||||
|
void finalize(); |
||||||
|
|
||||||
|
private: |
||||||
|
struct Attribute { |
||||||
|
GLuint location; |
||||||
|
GLint size; |
||||||
|
GLenum type; |
||||||
|
GLsizei stride; |
||||||
|
const GLvoid* pointer; |
||||||
|
}; |
||||||
|
|
||||||
|
std::map<Buffer*, std::pair<bool, std::vector<Attribute> > > buffers; |
||||||
|
std::set<GLuint> attributes; |
||||||
|
|
||||||
|
GLenum primitive; |
||||||
|
GLsizei count; |
||||||
|
bool finalized; |
||||||
|
|
||||||
|
void bindAttribute(Buffer* buffer, GLuint attribute, GLint size, GLenum type); |
||||||
|
|
||||||
|
GLsizei sizeOf(GLenum type); |
||||||
|
}; |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLbyte>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_BYTE); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLubyte>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_UNSIGNED_BYTE); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLshort>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_SHORT); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLushort>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_UNSIGNED_SHORT); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLint>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_INT); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLuint>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_UNSIGNED_INT); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLfloat>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_FLOAT); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<GLdouble>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 1, GL_DOUBLE); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<Vector3>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 3, GL_FLOAT); |
||||||
|
} |
||||||
|
|
||||||
|
template<> inline void Mesh::bindAttribute<Vector4>(Buffer* buffer, GLuint attribute) { |
||||||
|
bindAttribute(buffer, attribute, 4, GL_FLOAT); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
#endif |
||||||
Loading…
Reference in new issue