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