|
|
|
|
#ifndef Magnum_TransformFeedback_h
|
|
|
|
|
#define Magnum_TransformFeedback_h
|
|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015
|
|
|
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
to deal in the Software without restriction, including without limitation
|
|
|
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <Corrade/Containers/Array.h>
|
|
|
|
|
|
|
|
|
|
#include "Magnum/AbstractObject.h"
|
|
|
|
|
|
|
|
|
|
#ifndef MAGNUM_TARGET_GLES2
|
|
|
|
|
/** @file
|
|
|
|
|
* @brief Class @ref Magnum::TransformFeedback
|
|
|
|
|
*/
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef MAGNUM_TARGET_GLES2
|
|
|
|
|
namespace Magnum {
|
|
|
|
|
|
|
|
|
|
namespace Implementation { struct TransformFeedbackState; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@brief Transform feedback
|
|
|
|
|
|
|
|
|
|
## Performance optimizations
|
|
|
|
|
|
|
|
|
|
The engine tracks currently bound transform feedback to avoid unnecessary calls
|
|
|
|
|
to @fn_gl{BindTransformFeedback}. Transform feedback limits and
|
|
|
|
|
implementation-defined values (such as @ref maxSeparateComponents()) are
|
|
|
|
|
cached, so repeated queries don't result in repeated @fn_gl{Get} calls.
|
|
|
|
|
|
|
|
|
|
If extension @extension{ARB,direct_state_access} (part of OpenGL 4.5) is
|
|
|
|
|
available, functions @ref attachBuffer() and @ref attachBuffers() use DSA to
|
|
|
|
|
avoid unnecessary call to @fn_gl{BindTransformFeedback}. See their respective
|
|
|
|
|
documentation for more information.
|
|
|
|
|
|
|
|
|
|
@see @ref PrimitiveQuery
|
|
|
|
|
@requires_gl40 Extension @extension{ARB,transform_feedback2}
|
|
|
|
|
@requires_gles30 Transform feedback is not available in OpenGL ES 2.0
|
|
|
|
|
@todo @extension{AMD,transform_feedback3_lines_triangles}?
|
|
|
|
|
*/
|
|
|
|
|
class MAGNUM_EXPORT TransformFeedback: public AbstractObject {
|
|
|
|
|
friend Implementation::TransformFeedbackState;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Transform feedback primitive mode
|
|
|
|
|
*
|
|
|
|
|
* @see @ref begin()
|
|
|
|
|
*/
|
|
|
|
|
enum class PrimitiveMode: GLenum {
|
|
|
|
|
/**
|
|
|
|
|
* Points. If no geometry shader is present, allowed only in
|
|
|
|
|
* combination with @ref MeshPrimitive::Points mesh primitive type.
|
|
|
|
|
* If geometry shader is present, allowed only in combination with
|
|
|
|
|
* `points` output primitive type.
|
|
|
|
|
*/
|
|
|
|
|
Points = GL_POINTS,
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Lines. If no geometry shader is present, allowed only in
|
|
|
|
|
* combination with @ref MeshPrimitive::LineStrip,
|
|
|
|
|
* @ref MeshPrimitive::LineLoop, @ref MeshPrimitive::Lines,
|
|
|
|
|
* @ref MeshPrimitive::LineStripAdjacency and
|
|
|
|
|
* @ref MeshPrimitive::LinesAdjacency mesh primitive type. If
|
|
|
|
|
* geometry shader is present, allowed only in combination with
|
|
|
|
|
* `line_strip` output primitive type.
|
|
|
|
|
*/
|
|
|
|
|
Lines = GL_LINES,
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Triangles. If no geometry shader is present, allowed only in
|
|
|
|
|
* combination with @ref MeshPrimitive::TriangleStrip,
|
|
|
|
|
* @ref MeshPrimitive::TriangleFan, @ref MeshPrimitive::Triangles,
|
|
|
|
|
* @ref MeshPrimitive::TriangleStripAdjacency and
|
|
|
|
|
* @ref MeshPrimitive::TrianglesAdjacency mesh primitive type. If
|
|
|
|
|
* geometry shader is present, allowed only in commbination with
|
|
|
|
|
* `triangle_strip` output primitive type.
|
|
|
|
|
*/
|
|
|
|
|
Triangles = GL_TRIANGLES
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Max supported interleaved component count
|
|
|
|
|
*
|
|
|
|
|
* The result is cached, repeated queries don't result in repeated
|
|
|
|
|
* OpenGL calls. If extension @extension{EXT,transform_feedback}
|
|
|
|
|
* (part of OpenGL 3.0) is not available, returns `0`.
|
|
|
|
|
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS}
|
|
|
|
|
*/
|
|
|
|
|
static Int maxInterleavedComponents();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Max supported separate attribute count
|
|
|
|
|
*
|
|
|
|
|
* The result is cached, repeated queries don't result in repeated
|
|
|
|
|
* OpenGL calls. If extension @extension{EXT,transform_feedback}
|
|
|
|
|
* (part of OpenGL 3.0) is not available, returns `0`.
|
|
|
|
|
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS}
|
|
|
|
|
*/
|
|
|
|
|
static Int maxSeparateAttributes();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Max supported separate component count
|
|
|
|
|
*
|
|
|
|
|
* The result is cached, repeated queries don't result in repeated
|
|
|
|
|
* OpenGL calls. If extension @extension{EXT,transform_feedback}
|
|
|
|
|
* (part of OpenGL 3.0) is not available, returns `0`.
|
|
|
|
|
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS}
|
|
|
|
|
*/
|
|
|
|
|
static Int maxSeparateComponents();
|
|
|
|
|
|
|
|
|
|
#ifndef MAGNUM_TARGET_GLES
|
|
|
|
|
/**
|
|
|
|
|
* @brief Max supported buffer count
|
|
|
|
|
*
|
|
|
|
|
* The result is cached, repeated queries don't result in repeated
|
|
|
|
|
* OpenGL calls. If extension @extension{ARB,transform_feedback3}
|
|
|
|
|
* (part of OpenGL 4.0) is not available, returns the same value as
|
|
|
|
|
* @ref maxSeparateAttributes().
|
|
|
|
|
* @see @fn_gl{Get} with @def_gl{MAX_TRANSFORM_FEEDBACK_BUFFERS}
|
|
|
|
|
* @requires_gl Use @ref maxSeparateAttributes() in OpenGL ES.
|
|
|
|
|
*/
|
|
|
|
|
static Int maxBuffers();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Constructor
|
|
|
|
|
*
|
|
|
|
|
* Creates new OpenGL transform feedback object. If
|
|
|
|
|
* @extension{ARB,direct_state_access} (part of OpenGL 4.5) is not
|
|
|
|
|
* supported, the transform feedback object is created on first use.
|
|
|
|
|
* @see @fn_gl{CreateTransformFeedbacks}, eventually
|
|
|
|
|
* @fn_gl{GenTransformFeedbacks}
|
|
|
|
|
*/
|
|
|
|
|
explicit TransformFeedback();
|
|
|
|
|
|
|
|
|
|
/** @brief Copying is not allowed */
|
|
|
|
|
TransformFeedback(const TransformFeedback&) = delete;
|
|
|
|
|
|
|
|
|
|
/** @brief Move constructor */
|
|
|
|
|
TransformFeedback(TransformFeedback&& other) noexcept;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Destructor
|
|
|
|
|
*
|
|
|
|
|
* Deletes associated OpenGL transform feedback object.
|
|
|
|
|
* @see @fn_gl{DeleteTransformFeedbacks}
|
|
|
|
|
*/
|
|
|
|
|
~TransformFeedback();
|
|
|
|
|
|
|
|
|
|
/** @brief Copying is not allowed */
|
|
|
|
|
TransformFeedback& operator=(const TransformFeedback&) = delete;
|
|
|
|
|
|
|
|
|
|
/** @brief Move assignment */
|
|
|
|
|
TransformFeedback& operator=(TransformFeedback&& other) noexcept;
|
|
|
|
|
|
|
|
|
|
/** @brief OpenGL transform feedback ID */
|
|
|
|
|
GLuint id() const { return _id; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Buffer label
|
|
|
|
|
*
|
|
|
|
|
* The result is *not* cached, repeated queries will result in repeated
|
|
|
|
|
* OpenGL calls. If OpenGL 4.3 is not supported and neither
|
|
|
|
|
* @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES
|
|
|
|
|
* extension is available, this function returns empty string.
|
|
|
|
|
* @see @fn_gl{GetObjectLabel} or @fn_gl_extension2{GetObjectLabel,EXT,debug_label}
|
|
|
|
|
* with @def_gl{TRANSFORM_FEEDBACK}
|
|
|
|
|
*/
|
|
|
|
|
std::string label();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Set buffer label
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* Default is empty string. If OpenGL 4.3 is not supported and neither
|
|
|
|
|
* @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES
|
|
|
|
|
* extension is available, this function does nothing.
|
|
|
|
|
* @see @ref maxLabelLength(), @fn_gl{ObjectLabel} or
|
|
|
|
|
* @fn_gl_extension2{LabelObject,EXT,debug_label} with
|
|
|
|
|
* @def_gl{TRANSFORM_FEEDBACK}
|
|
|
|
|
*/
|
|
|
|
|
TransformFeedback& setLabel(const std::string& label) {
|
|
|
|
|
return setLabelInternal({label.data(), label.size()});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @overload */
|
|
|
|
|
template<std::size_t size> TransformFeedback& setLabel(const char(&label)[size]) {
|
|
|
|
|
return setLabelInternal(label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Attach range of buffer
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* The @p offset parameter must be aligned to 4 bytes. If on OpenGL ES
|
|
|
|
|
* or @extension{ARB,direct_state_access} (part of OpenGL 4.5) is not
|
|
|
|
|
* available, the transform feedback object is bound (if not already)
|
|
|
|
|
* and the operation is then done equivalently to
|
|
|
|
|
* @ref Buffer::bind(Buffer::Target, UnsignedInt, GLintptr, GLsizeiptr).
|
|
|
|
|
* @note This function is meant to be used only internally from
|
|
|
|
|
* @ref AbstractShaderProgram subclasses. See its documentation
|
|
|
|
|
* for more information.
|
|
|
|
|
* @see @ref attachBuffers(), @ref maxBuffers()/@ref maxSeparateAttributes(),
|
|
|
|
|
* @fn_gl{TransformFeedbackBufferRange}, eventually
|
|
|
|
|
* @fn_gl{BindTransformFeedback} and @fn_gl{BindBuffersRange} or
|
|
|
|
|
* @fn_gl{BindBufferRange}
|
|
|
|
|
*/
|
|
|
|
|
TransformFeedback& attachBuffer(UnsignedInt index, Buffer& buffer, GLintptr offset, GLsizeiptr size);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Attach buffer
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* If on OpenGL ES or @extension{ARB,direct_state_access} (part of
|
|
|
|
|
* OpenGL 4.5) is not available, the transform feedback object is bound
|
|
|
|
|
* (if not already) and the operation is then done equivalently to
|
|
|
|
|
* @ref Buffer::bind(Buffer::Target, UnsignedInt).
|
|
|
|
|
* @note This function is meant to be used only internally from
|
|
|
|
|
* @ref AbstractShaderProgram subclasses. See its documentation
|
|
|
|
|
* for more information.
|
|
|
|
|
* @see @ref attachBuffers(), @ref maxBuffers()/@ref maxSeparateAttributes(),
|
|
|
|
|
* @fn_gl{TransformFeedbackBufferRange}, eventually
|
|
|
|
|
* @fn_gl{BindTransformFeedback} and @fn_gl{BindBuffersRange} or
|
|
|
|
|
* @fn_gl{BindBufferRange}
|
|
|
|
|
*/
|
|
|
|
|
TransformFeedback& attachBuffer(UnsignedInt index, Buffer& buffer);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Attach ranges of buffers
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* Attches first buffer in the list to @p firstIndex, second to
|
|
|
|
|
* `firstIndex + 1` etc. Second parameter is offset, third is size. If
|
|
|
|
|
* any buffer is `nullptr`, given attachment point is detached. The
|
|
|
|
|
* range of indices must respect @ref maxBuffers() (@ref maxSeparateComponents()
|
|
|
|
|
* in OpenGL ES or if @extension{ARB,transform_feedback3} (part of
|
|
|
|
|
* OpenGL 4.0) is not available). The offsets must be aligned to 4
|
|
|
|
|
* bytes. All the buffers must have allocated data store. If on OpenGL
|
|
|
|
|
* ES or @extension{ARB,direct_state_access} (part of OpenGL 4.5) is
|
|
|
|
|
* not available, the transform feedback object is bound (if not
|
|
|
|
|
* already) and the operation is then done equivalently to
|
|
|
|
|
* @ref Buffer::bind(Buffer::Target, UnsignedInt, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>>).
|
|
|
|
|
* @note This function is meant to be used only internally from
|
|
|
|
|
* @ref AbstractShaderProgram subclasses. See its documentation
|
|
|
|
|
* for more information.
|
|
|
|
|
* @see @ref attachBuffer(), @fn_gl{TransformFeedbackBufferRange},
|
|
|
|
|
* eventually @fn_gl{BindTransformFeedback} and
|
|
|
|
|
* @fn_gl{BindBuffersRange} or @fn_gl{BindBufferRange}
|
|
|
|
|
*/
|
|
|
|
|
TransformFeedback& attachBuffers(UnsignedInt firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Attach buffers
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* Attches first buffer in the list to @p firstIndex, second to
|
|
|
|
|
* `firstIndex + 1` etc. If any buffer is `nullptr`, given index is
|
|
|
|
|
* detached. The range of indices must respect @ref maxBuffers()
|
|
|
|
|
* (@ref maxSeparateComponents() in OpenGL ES or if
|
|
|
|
|
* @extension{ARB,transform_feedback3} (part of OpenGL 4.0) is not
|
|
|
|
|
* available). All the buffers must have allocated data store. If on
|
|
|
|
|
* OpenGL ES or @extension{ARB,direct_state_access} (part of OpenGL
|
|
|
|
|
* 4.5) is not available, the transform feedback object is bound (if
|
|
|
|
|
* not already) and the operation then is done equivalently to
|
|
|
|
|
* @ref Buffer::bind(Buffer::Target, UnsignedInt, std::initializer_list<Buffer*>).
|
|
|
|
|
* @note This function is meant to be used only internally from
|
|
|
|
|
* @ref AbstractShaderProgram subclasses. See its documentation
|
|
|
|
|
* for more information.
|
|
|
|
|
* @see @ref attachBuffer(), @fn_gl{TransformFeedbackBufferBase},
|
|
|
|
|
* eventually @fn_gl{BindTransformFeedback} and
|
|
|
|
|
* @fn_gl{BindBuffersBase} or @fn_gl{BindBufferBase}
|
|
|
|
|
*/
|
|
|
|
|
TransformFeedback& attachBuffers(UnsignedInt firstIndex, std::initializer_list<Buffer*> buffers);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Begin transform feedback
|
|
|
|
|
* @param shader Shader from which to capture data
|
|
|
|
|
* @param mode Primitive mode
|
|
|
|
|
*
|
|
|
|
|
* When transform feedback is active, only shader given in @p shader
|
|
|
|
|
* and meshes with primitive type (or geometry shaders with output
|
|
|
|
|
* primitive type) compatible with @p mode can be used. Only one
|
|
|
|
|
* transform feedback object can be active at a time.
|
|
|
|
|
* @see @ref pause(), @ref end(), @fn_gl{BindTransformFeedback} and
|
|
|
|
|
* @fn_gl{BeginTransformFeedback}
|
|
|
|
|
*/
|
|
|
|
|
void begin(AbstractShaderProgram& shader, PrimitiveMode mode);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Pause transform feedback
|
|
|
|
|
*
|
|
|
|
|
* Pausing transform feedback makes it inactive, allowing to use
|
|
|
|
|
* different shader, or starting another transform feedback.
|
|
|
|
|
* @see @ref resume(), @ref end(), @fn_gl{BindTransformFeedback} and
|
|
|
|
|
* @fn_gl{PauseTransformFeedback}
|
|
|
|
|
*/
|
|
|
|
|
void pause();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Resume transform feedback
|
|
|
|
|
*
|
|
|
|
|
* Resumes transform feedback so the next captured data are appended to
|
|
|
|
|
* already captured ones. The restrictions specified for @ref begin()
|
|
|
|
|
* still apply after resuming. Only one transform feedback object can
|
|
|
|
|
* be active at a time.
|
|
|
|
|
* @see @ref pause(), @ref end(), @fn_gl{BindTransformFeedback} and
|
|
|
|
|
* @fn_gl{ResumeTransformFeedback}
|
|
|
|
|
*/
|
|
|
|
|
void resume();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief End transform feedback
|
|
|
|
|
*
|
|
|
|
|
* Ends transform feedback so the captured data can be used.
|
|
|
|
|
* @see @ref begin(), @fn_gl{BindTransformFeedback} and
|
|
|
|
|
* @fn_gl{EndTransformFeedback}
|
|
|
|
|
*/
|
|
|
|
|
void end();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void bindInternal();
|
|
|
|
|
|
|
|
|
|
void MAGNUM_LOCAL createIfNotAlready();
|
|
|
|
|
|
|
|
|
|
void MAGNUM_LOCAL createImplementationDefault();
|
|
|
|
|
#ifndef MAGNUM_TARGET_GLES
|
|
|
|
|
void MAGNUM_LOCAL createImplementationDSA();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationFallback(GLuint index, Buffer& buffer, GLintptr offset, GLsizeiptr size);
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationFallback(GLuint index, Buffer& buffer);
|
|
|
|
|
#ifndef MAGNUM_TARGET_GLES
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationDSA(GLuint index, Buffer& buffer, GLintptr offset, GLsizeiptr size);
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationDSA(GLuint index, Buffer& buffer);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationFallback(GLuint firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers);
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationFallback(GLuint firstIndex, std::initializer_list<Buffer*> buffers);
|
|
|
|
|
#ifndef MAGNUM_TARGET_GLES
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationDSA(GLuint firstIndex, std::initializer_list<std::tuple<Buffer*, GLintptr, GLsizeiptr>> buffers);
|
|
|
|
|
void MAGNUM_LOCAL attachImplementationDSA(GLuint firstIndex, std::initializer_list<Buffer*> buffers);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TransformFeedback& setLabelInternal(Containers::ArrayReference<const char> label);
|
|
|
|
|
|
|
|
|
|
GLuint _id;
|
|
|
|
|
bool _created; /* see createIfNotAlready() for details */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline TransformFeedback::TransformFeedback(TransformFeedback&& other) noexcept: _id{other._id}, _created{other._created} {
|
|
|
|
|
other._id = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline TransformFeedback& TransformFeedback::operator=(TransformFeedback&& other) noexcept {
|
|
|
|
|
using std::swap;
|
|
|
|
|
swap(_id, other._id);
|
|
|
|
|
swap(_created, other._created);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
#error This header is not available in OpenGL ES 2.0 build.
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif
|