/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the demonstration applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef GLBUFFERS_H #define GLBUFFERS_H //#include #include "glextensions.h" #include #include #define BUFFER_OFFSET(i) ((char*)0 + (i)) #define SIZE_OF_MEMBER(cls, member) sizeof(static_cast(nullptr)->member) #define GLBUFFERS_ASSERT_OPENGL(prefix, assertion, returnStatement) \ if (m_failed || !(assertion)) { \ if (!m_failed) qCritical(prefix ": The necessary OpenGL functions are not available."); \ m_failed = true; \ returnStatement; \ } void qgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); QT_BEGIN_NAMESPACE class QMatrix4x4; QT_END_NAMESPACE class GLTexture { public: GLTexture(); virtual ~GLTexture(); virtual void bind() = 0; virtual void unbind() = 0; virtual bool failed() const {return m_failed;} protected: GLuint m_texture = 0; bool m_failed = false; }; class GLFrameBufferObject { public: friend class GLRenderTargetCube; // friend class GLRenderTarget2D; GLFrameBufferObject(int width, int height); virtual ~GLFrameBufferObject(); bool isComplete(); virtual bool failed() const {return m_failed;} protected: void setAsRenderTarget(bool state = true); GLuint m_fbo = 0; GLuint m_depthBuffer = 0; int m_width, m_height; bool m_failed = false; }; class GLTexture2D : public GLTexture { public: GLTexture2D(int width, int height); explicit GLTexture2D(const QString &fileName, int width = 0, int height = 0); void load(int width, int height, QRgb *data); void bind() override; void unbind() override; }; class GLTexture3D : public GLTexture { public: GLTexture3D(int width, int height, int depth); // TODO: Implement function below //GLTexture3D(const QString& fileName, int width = 0, int height = 0); void load(int width, int height, int depth, QRgb *data); void bind() override; void unbind() override; }; class GLTextureCube : public GLTexture { public: GLTextureCube(int size); explicit GLTextureCube(const QStringList &fileNames, int size = 0); void load(int size, int face, QRgb *data); void bind() override; void unbind() override; }; // TODO: Define and implement class below //class GLRenderTarget2D : public GLTexture2D class GLRenderTargetCube : public GLTextureCube { public: GLRenderTargetCube(int size); // begin rendering to one of the cube's faces. 0 <= face < 6 void begin(int face); // end rendering void end(); bool failed() const override { return m_failed || m_fbo.failed(); } static void getViewMatrix(QMatrix4x4& mat, int face); static void getProjectionMatrix(QMatrix4x4& mat, float nearZ, float farZ); private: GLFrameBufferObject m_fbo; }; struct VertexDescription { enum { Null = 0, // Terminates a VertexDescription array Position, TexCoord, Normal, Color, }; int field; // Position, TexCoord, Normal, Color int type; // GL_FLOAT, GL_UNSIGNED_BYTE int count; // number of elements int offset; // field's offset into vertex struct int index; // 0 (unused at the moment) }; // Implementation of interleaved buffers. // 'T' is a struct which must include a null-terminated static array // 'VertexDescription* description'. // Example: /* struct Vertex { GLfloat position[3]; GLfloat texCoord[2]; GLfloat normal[3]; GLbyte color[4]; static VertexDescription description[]; }; VertexDescription Vertex::description[] = { {VertexDescription::Position, GL_FLOAT, SIZE_OF_MEMBER(Vertex, position) / sizeof(GLfloat), offsetof(Vertex, position), 0}, {VertexDescription::TexCoord, GL_FLOAT, SIZE_OF_MEMBER(Vertex, texCoord) / sizeof(GLfloat), offsetof(Vertex, texCoord), 0}, {VertexDescription::Normal, GL_FLOAT, SIZE_OF_MEMBER(Vertex, normal) / sizeof(GLfloat), offsetof(Vertex, normal), 0}, {VertexDescription::Color, GL_BYTE, SIZE_OF_MEMBER(Vertex, color) / sizeof(GLbyte), offsetof(Vertex, color), 0}, {VertexDescription::Null, 0, 0, 0, 0}, }; */ template class GLVertexBuffer { public: GLVertexBuffer(int length, const T *data = nullptr, int mode = GL_STATIC_DRAW) { GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::GLVertexBuffer", glGenBuffers && glBindBuffer && glBufferData, return) glGenBuffers(1, &m_buffer); glBindBuffer(GL_ARRAY_BUFFER, m_buffer); glBufferData(GL_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode); } ~GLVertexBuffer() { GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::~GLVertexBuffer", glDeleteBuffers, return) glDeleteBuffers(1, &m_buffer); } void bind() { GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::bind", glBindBuffer, return) glBindBuffer(GL_ARRAY_BUFFER, m_buffer); for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) { switch (desc->field) { case VertexDescription::Position: glVertexPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); glEnableClientState(GL_VERTEX_ARRAY); break; case VertexDescription::TexCoord: glTexCoordPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); break; case VertexDescription::Normal: glNormalPointer(desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); glEnableClientState(GL_NORMAL_ARRAY); break; case VertexDescription::Color: glColorPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); glEnableClientState(GL_COLOR_ARRAY); break; default: break; } } } void unbind() { GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unbind", glBindBuffer, return) glBindBuffer(GL_ARRAY_BUFFER, 0); for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) { switch (desc->field) { case VertexDescription::Position: glDisableClientState(GL_VERTEX_ARRAY); break; case VertexDescription::TexCoord: glDisableClientState(GL_TEXTURE_COORD_ARRAY); break; case VertexDescription::Normal: glDisableClientState(GL_NORMAL_ARRAY); break; case VertexDescription::Color: glDisableClientState(GL_COLOR_ARRAY); break; default: break; } } } int length() const {return m_length;} T *lock() { GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::lock", glBindBuffer && glMapBuffer, return nullptr) glBindBuffer(GL_ARRAY_BUFFER, m_buffer); //glBufferData(GL_ARRAY_BUFFER, m_length, NULL, m_mode); GLvoid* buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); m_failed = (buffer == nullptr); return reinterpret_cast(buffer); } void unlock() { GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unlock", glBindBuffer && glUnmapBuffer, return) glBindBuffer(GL_ARRAY_BUFFER, m_buffer); glUnmapBuffer(GL_ARRAY_BUFFER); } bool failed() { return m_failed; } private: int m_length = 0; int m_mode = 0; GLuint m_buffer = 0; bool m_failed = false; }; template class GLIndexBuffer { public: GLIndexBuffer(int length, const T *data = nullptr, int mode = GL_STATIC_DRAW) : m_length(0) , m_mode(mode) , m_buffer(0) , m_failed(false) { GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::GLIndexBuffer", glGenBuffers && glBindBuffer && glBufferData, return) glGenBuffers(1, &m_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode); } ~GLIndexBuffer() { GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::~GLIndexBuffer", glDeleteBuffers, return) glDeleteBuffers(1, &m_buffer); } void bind() { GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::bind", glBindBuffer, return) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); } void unbind() { GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unbind", glBindBuffer, return) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } int length() const {return m_length;} T *lock() { GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::lock", glBindBuffer && glMapBuffer, return nullptr) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); GLvoid* buffer = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE); m_failed = (buffer == nullptr); return reinterpret_cast(buffer); } void unlock() { GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unlock", glBindBuffer && glUnmapBuffer, return) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); } bool failed() { return m_failed; } private: int m_length, m_mode; GLuint m_buffer; bool m_failed; }; #endif