#ifndef Magnum_Mesh_h #define Magnum_Mesh_h /* Copyright © 2010, 2011, 2012 Vladimír Vondruš 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 #include #include #include "Magnum.h" #include "TypeTraits.h" namespace Magnum { class Buffer; /** @ingroup rendering mesh @brief Base class for managing non-indexed meshes VAOs are used for desktop OpenGL (not in OpenGL ES). @requires_gl30 Extension @extension{APPLE,vertex_array_object} @requires_gl30 Extension @extension{EXT,gpu_shader4} (for unsigned integer attributes) @todo Support for normalized values (e.g. for color as char[4] passed to shader as floating-point vec4) @todo Support for provoking vertex (OpenGL 3.2, @extension{ARB,provoking_vertex}) @todo Support for packed unsigned integer types for attributes (OpenGL 3.3, @extension{ARB,vertex_type_2_10_10_10_rev}) @todo Support for fixed precision type for attributes (OpenGL 4.1, @extension{ARB,ES2_compatibility}) @todo Support for double type for attributes (OpenGL 4.1, @extension{ARB,vertex_attrib_64bit}) @todo Support for indirect draw buffer (OpenGL 4.0, @extension{ARB,draw_indirect}) @todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc. */ class MAGNUM_EXPORT Mesh { Mesh(const Mesh& other) = delete; Mesh(Mesh&& other) = delete; Mesh& operator=(const Mesh& other) = delete; Mesh& operator=(Mesh&& other) = delete; public: #ifndef MAGNUM_TARGET_GLES /** * @brief Polygon mode * * @see setPolygonMode() * @requires_gl */ enum class PolygonMode: GLenum { /** * Interior of the polygon is filled. */ Fill = GL_FILL, /** * Boundary edges are filled. See also setLineWidth(). */ Line = GL_LINE, /** * Starts of boundary edges are drawn as points. See also * setPointSize(). */ Point = GL_POINT }; #endif /** * @brief Primitive type * * @see primitive(), setPrimitive() */ enum class Primitive: GLenum { /** * 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 Buffer type * * 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. * @see addBuffer() */ enum class BufferType: bool { Interleaved, /**< Interleaved buffer */ NonInterleaved /**< Non-interleaved buffer */ }; #ifndef MAGNUM_TARGET_GLES /** * @brief Set polygon drawing mode * * Initial value is PolygonMode::Fill. * @requires_gl */ inline static void setPolygonMode(PolygonMode mode) { glPolygonMode(GL_FRONT_AND_BACK, static_cast(mode)); } #endif /** * @brief Set line width * * Initial value is 1. */ inline static void setLineWidth(GLfloat width) { glLineWidth(width); } #ifndef MAGNUM_TARGET_GLES /** * @brief Set point size * * @see setProgramPointSize() * @requires_gl */ inline static void setPointSize(GLfloat size) { glPointSize(size); } /** * @brief Enable/disable programmable point size * * If enabled, the point size is taken from vertex/geometry shader * builtin `gl_PointSize`. * @see setPointSize() * @requires_gl */ inline static void setProgramPointSize(bool enabled) { enabled ? glEnable(GL_PROGRAM_POINT_SIZE) : glDisable(GL_PROGRAM_POINT_SIZE); } #endif /** * @brief Implicit constructor * @param primitive Primitive type * * Allows creating the object without knowing anything about mesh * data. Note that you have to call setVertexCount() manually for mesh * to draw properly. */ inline Mesh(Primitive primitive = Primitive::Triangles): _primitive(primitive), _vertexCount(0), finalized(false) { #ifndef MAGNUM_TARGET_GLES glGenVertexArrays(1, &vao); #endif } /** * @brief Constructor * @param primitive Primitive type * @param vertexCount Vertex count */ inline Mesh(Primitive primitive, GLsizei vertexCount): _primitive(primitive), _vertexCount(vertexCount), finalized(false) { #ifndef MAGNUM_TARGET_GLES glGenVertexArrays(1, &vao); #endif } /** * @brief Destructor * * Deletes all associated buffers. */ virtual ~Mesh(); /** * @brief Whether the mesh is finalized * * When the mesh is finalized, no new attributes can be bound. */ inline bool isFinalized() const { return finalized; } /** @brief Primitive type */ inline Primitive primitive() const { return _primitive; } /** @brief Set primitive type */ inline void setPrimitive(Primitive primitive) { _primitive = primitive; } /** @brief Vertex count */ inline GLsizei vertexCount() const { return _vertexCount; } /** * @brief Set vertex count * * This forces recalculation of attribute positions upon next drawing. */ inline void setVertexCount(GLsizei vertexCount) { _vertexCount = vertexCount; finalized = false; } /** * @brief Add buffer * @param interleaved Whether the buffer is interleaved * * Adds new buffer to the mesh. The buffer can be then filled with * Buffer::setData(). See also isInterleaved(). * * @todo Move interleaveability to Buffer itself? */ Buffer* addBuffer(BufferType interleaved); /** * @brief Whether given buffer is interleaved * @return True if the buffer belongs to the mesh and the buffer is * interleaved, false otherwise. * * See also addBuffer(). */ inline bool isInterleaved(Buffer* buffer) const { auto found = _buffers.find(buffer); return found != _buffers.end() && found->second.first == BufferType::Interleaved; } /** * @brief Bind attribute * @tparam attribute Attribute, defined in the shader * @param buffer Buffer where bind the attribute to (pointer * returned by addBuffer()) * * 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 inline void bindAttribute(Buffer* buffer) { bindAttribute(buffer, Attribute::Location, TypeTraits::count(), TypeTraits::type()); } /** * @brief Draw the mesh * * Expects an active shader with all uniforms set. */ virtual void draw(); protected: #ifndef DOXYGEN_GENERATING_OUTPUT /** @brief Bind all buffers */ void bindBuffers(); /** @brief Bind vertex array or all buffers */ void bind(); /** @brief Unbind vertex array or all buffers */ void unbind(); /** * @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. */ MAGNUM_LOCAL void finalize(); #endif private: /** @brief Vertex attribute */ struct MAGNUM_LOCAL Attribute { GLuint attribute; /**< @brief %Attribute ID */ GLint size; /**< @brief How many items of `type` are in the attribute */ Type type; /**< @brief %Attribute item type */ GLsizei stride; /**< @brief Distance of two adjacent attributes of this type in interleaved buffer */ const GLvoid* pointer; /**< @brief Pointer to first attribute of this type in the buffer */ }; #ifndef MAGNUM_TARGET_GLES GLuint vao; #endif Primitive _primitive; GLsizei _vertexCount; bool finalized; /** * @brief Buffers with their attributes * * Map of associated buffers, evey buffer has: * - boolean value which signalizes whether the buffer is interleaved * - list of bound attributes */ std::map > > _buffers; /** * @brief List of all bound attributes * * List of all bound attributes bound with bindAttribute(). */ std::set _attributes; MAGNUM_EXPORT void bindAttribute(Buffer* buffer, GLuint attribute, GLint size, Type type); }; } #endif