From 2cb3823e440116f331c0287b29667f7c448e3ed0 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 24 Mar 2009 08:58:57 +1000 Subject: Import shader implementation from before the history cut. --- demos/boxes/boxes.pro | 2 - demos/boxes/glextensions.cpp | 37 - demos/boxes/glextensions.h | 85 - demos/boxes/glshaders.cpp | 266 --- demos/boxes/glshaders.h | 108 -- demos/boxes/scene.cpp | 102 +- demos/boxes/scene.h | 11 +- examples/opengl/hellogl_es2/glwidget.cpp | 391 ++-- examples/opengl/hellogl_es2/glwidget.h | 31 +- src/opengl/gl2paintengineex/qglshader_p.h | 3 +- src/opengl/opengl.pro | 6 +- src/opengl/qglextensions.cpp | 214 ++- src/opengl/qglextensions_p.h | 126 ++ src/opengl/qglpixmapfilter.cpp | 165 +- src/opengl/qglpixmapfilter_p.h | 29 - src/opengl/qglshaderprogram.cpp | 2828 +++++++++++++++++++++++++++++ src/opengl/qglshaderprogram.h | 285 +++ 17 files changed, 3619 insertions(+), 1070 deletions(-) delete mode 100644 demos/boxes/glshaders.cpp delete mode 100644 demos/boxes/glshaders.h create mode 100644 src/opengl/qglshaderprogram.cpp create mode 100644 src/opengl/qglshaderprogram.h diff --git a/demos/boxes/boxes.pro b/demos/boxes/boxes.pro index 6c1a331..a7b19a3 100644 --- a/demos/boxes/boxes.pro +++ b/demos/boxes/boxes.pro @@ -11,7 +11,6 @@ INCLUDEPATH += . HEADERS += 3rdparty/fbm.h \ glbuffers.h \ glextensions.h \ - glshaders.h \ gltrianglemesh.h \ qtbox.h \ roundedbox.h \ @@ -21,7 +20,6 @@ HEADERS += 3rdparty/fbm.h \ SOURCES += 3rdparty/fbm.c \ glbuffers.cpp \ glextensions.cpp \ - glshaders.cpp \ main.cpp \ qtbox.cpp \ roundedbox.cpp \ diff --git a/demos/boxes/glextensions.cpp b/demos/boxes/glextensions.cpp index 59256a8..5f168b6 100644 --- a/demos/boxes/glextensions.cpp +++ b/demos/boxes/glextensions.cpp @@ -47,23 +47,6 @@ bool GLExtensionFunctions::resolve(const QGLContext *context) { bool ok = true; - RESOLVE_GL_FUNC(CreateShaderObjectARB) - RESOLVE_GL_FUNC(ShaderSourceARB) - RESOLVE_GL_FUNC(CompileShaderARB) - RESOLVE_GL_FUNC(GetObjectParameterivARB) - RESOLVE_GL_FUNC(DeleteObjectARB) - RESOLVE_GL_FUNC(GetInfoLogARB) - RESOLVE_GL_FUNC(CreateProgramObjectARB) - RESOLVE_GL_FUNC(AttachObjectARB) - RESOLVE_GL_FUNC(DetachObjectARB) - RESOLVE_GL_FUNC(LinkProgramARB) - RESOLVE_GL_FUNC(UseProgramObjectARB) - RESOLVE_GL_FUNC(GetUniformLocationARB) - RESOLVE_GL_FUNC(Uniform1iARB) - RESOLVE_GL_FUNC(Uniform1fARB) - RESOLVE_GL_FUNC(Uniform4fARB) - RESOLVE_GL_FUNC(UniformMatrix4fvARB) - RESOLVE_GL_FUNC(GenFramebuffersEXT) RESOLVE_GL_FUNC(GenRenderbuffersEXT) RESOLVE_GL_FUNC(BindRenderbufferEXT) @@ -88,26 +71,6 @@ bool GLExtensionFunctions::resolve(const QGLContext *context) return ok; } -bool GLExtensionFunctions::glslSupported() { - return CreateShaderObjectARB - && CreateShaderObjectARB - && ShaderSourceARB - && CompileShaderARB - && GetObjectParameterivARB - && DeleteObjectARB - && GetInfoLogARB - && CreateProgramObjectARB - && AttachObjectARB - && DetachObjectARB - && LinkProgramARB - && UseProgramObjectARB - && GetUniformLocationARB - && Uniform1iARB - && Uniform1fARB - && Uniform4fARB - && UniformMatrix4fvARB; -} - bool GLExtensionFunctions::fboSupported() { return GenFramebuffersEXT && GenRenderbuffersEXT diff --git a/demos/boxes/glextensions.h b/demos/boxes/glextensions.h index 74617d6..4755532 100644 --- a/demos/boxes/glextensions.h +++ b/demos/boxes/glextensions.h @@ -47,23 +47,6 @@ /* Functions resolved: -glCreateShaderObjectARB -glShaderSourceARB -glCompileShaderARB -glGetObjectParameterivARB -glDeleteObjectARB -glGetInfoLogARB -glCreateProgramObjectARB -glAttachObjectARB -glDetachObjectARB -glLinkProgramARB -glUseProgramObjectARB -glGetUniformLocationARB -glUniform1iARB -glUniform1fARB -glUniform4fARB -glUniformMatrix4fvARB - glGenFramebuffersEXT glGenRenderbuffersEXT glBindRenderbufferEXT @@ -136,39 +119,6 @@ typedef ptrdiff_t GLsizeiptr; #define GL_DEPTH_ATTACHMENT_EXT 0x8D00 #endif -#ifndef GL_ARB_vertex_shader -#define GL_VERTEX_SHADER_ARB 0x8B31 -#endif - -#ifndef GL_ARB_fragment_shader -#define GL_FRAGMENT_SHADER_ARB 0x8B30 -#endif - -#ifndef GL_ARB_shader_objects -typedef char GLcharARB; -typedef unsigned int GLhandleARB; -#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 -#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 -#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 -#endif - -typedef GLhandleARB (APIENTRY *_glCreateShaderObjectARB) (GLenum); -typedef void (APIENTRY *_glShaderSourceARB) (GLhandleARB, GLuint, const GLcharARB**, GLint *); -typedef void (APIENTRY *_glCompileShaderARB) (GLhandleARB); -typedef void (APIENTRY *_glGetObjectParameterivARB) (GLhandleARB, GLenum, int *); -typedef void (APIENTRY *_glDeleteObjectARB) (GLhandleARB); -typedef void (APIENTRY *_glGetInfoLogARB) (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); -typedef GLhandleARB (APIENTRY *_glCreateProgramObjectARB) (); -typedef void (APIENTRY *_glAttachObjectARB) (GLhandleARB, GLhandleARB); -typedef void (APIENTRY *_glDetachObjectARB) (GLhandleARB, GLhandleARB); -typedef void (APIENTRY *_glLinkProgramARB) (GLhandleARB); -typedef void (APIENTRY *_glUseProgramObjectARB) (GLhandleARB); -typedef GLint (APIENTRY *_glGetUniformLocationARB) (GLhandleARB, const GLcharARB *); -typedef void (APIENTRY *_glUniform1iARB) (GLint, GLint); -typedef void (APIENTRY *_glUniform1fARB) (GLint, GLfloat); -typedef void (APIENTRY *_glUniform4fARB) (GLint, GLfloat, GLfloat, GLfloat, GLfloat); -typedef void (APIENTRY *_glUniformMatrix4fvARB) (GLint, GLuint, GLboolean, const GLfloat *); - typedef void (APIENTRY *_glGenFramebuffersEXT) (GLsizei, GLuint *); typedef void (APIENTRY *_glGenRenderbuffersEXT) (GLsizei, GLuint *); typedef void (APIENTRY *_glBindRenderbufferEXT) (GLenum, GLuint); @@ -194,27 +144,9 @@ struct GLExtensionFunctions { bool resolve(const QGLContext *context); - bool glslSupported(); bool fboSupported(); bool openGL15Supported(); // the rest: multi-texture, 3D-texture, vertex buffer objects - _glCreateShaderObjectARB CreateShaderObjectARB; - _glShaderSourceARB ShaderSourceARB; - _glCompileShaderARB CompileShaderARB; - _glGetObjectParameterivARB GetObjectParameterivARB; - _glDeleteObjectARB DeleteObjectARB; - _glGetInfoLogARB GetInfoLogARB; - _glCreateProgramObjectARB CreateProgramObjectARB; - _glAttachObjectARB AttachObjectARB; - _glDetachObjectARB DetachObjectARB; - _glLinkProgramARB LinkProgramARB; - _glUseProgramObjectARB UseProgramObjectARB; - _glGetUniformLocationARB GetUniformLocationARB; - _glUniform1iARB Uniform1iARB; - _glUniform1fARB Uniform1fARB; - _glUniform4fARB Uniform4fARB; - _glUniformMatrix4fvARB UniformMatrix4fvARB; - _glGenFramebuffersEXT GenFramebuffersEXT; _glGenRenderbuffersEXT GenRenderbuffersEXT; _glBindRenderbufferEXT BindRenderbufferEXT; @@ -243,23 +175,6 @@ inline GLExtensionFunctions &getGLExtensionFunctions() return funcs; } -#define glCreateShaderObjectARB getGLExtensionFunctions().CreateShaderObjectARB -#define glShaderSourceARB getGLExtensionFunctions().ShaderSourceARB -#define glCompileShaderARB getGLExtensionFunctions().CompileShaderARB -#define glGetObjectParameterivARB getGLExtensionFunctions().GetObjectParameterivARB -#define glDeleteObjectARB getGLExtensionFunctions().DeleteObjectARB -#define glGetInfoLogARB getGLExtensionFunctions().GetInfoLogARB -#define glCreateProgramObjectARB getGLExtensionFunctions().CreateProgramObjectARB -#define glAttachObjectARB getGLExtensionFunctions().AttachObjectARB -#define glDetachObjectARB getGLExtensionFunctions().DetachObjectARB -#define glLinkProgramARB getGLExtensionFunctions().LinkProgramARB -#define glUseProgramObjectARB getGLExtensionFunctions().UseProgramObjectARB -#define glGetUniformLocationARB getGLExtensionFunctions().GetUniformLocationARB -#define glUniform1iARB getGLExtensionFunctions().Uniform1iARB -#define glUniform1fARB getGLExtensionFunctions().Uniform1fARB -#define glUniform4fARB getGLExtensionFunctions().Uniform4fARB -#define glUniformMatrix4fvARB getGLExtensionFunctions().UniformMatrix4fvARB - #define glGenFramebuffersEXT getGLExtensionFunctions().GenFramebuffersEXT #define glGenRenderbuffersEXT getGLExtensionFunctions().GenRenderbuffersEXT #define glBindRenderbufferEXT getGLExtensionFunctions().BindRenderbufferEXT diff --git a/demos/boxes/glshaders.cpp b/demos/boxes/glshaders.cpp deleted file mode 100644 index b6999a8..0000000 --- a/demos/boxes/glshaders.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "glshaders.h" - -#define GLSHADERS_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; \ -} - - -GLShader::GLShader(const char *data, int size, GLenum shaderType) -: m_compileError(false), m_failed(false) -{ - GLSHADERS_ASSERT_OPENGL("GLShader::GLShader", - glCreateShaderObjectARB && glShaderSourceARB && glCompileShaderARB && glGetObjectParameterivARB, return) - - m_shader = glCreateShaderObjectARB(shaderType); - - GLint glSize = size; - glShaderSourceARB(m_shader, 1, &data, &glSize); - glCompileShaderARB(m_shader); - int status; - glGetObjectParameterivARB(m_shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); - m_compileError = (status != 1); -} - -GLShader::GLShader(const QString& fileName, GLenum shaderType) - : m_compileError(false), m_failed(false) -{ - GLSHADERS_ASSERT_OPENGL("GLShader::GLShader", - glCreateShaderObjectARB && glShaderSourceARB && glCompileShaderARB && glGetObjectParameterivARB, return) - - m_shader = glCreateShaderObjectARB(shaderType); - - QFile file(fileName); - if (file.open(QIODevice::ReadOnly)) { - QByteArray bytes = file.readAll(); - GLint size = file.size(); - const char *p = bytes.data(); - file.close(); - glShaderSourceARB(m_shader, 1, &p, &size); - glCompileShaderARB(m_shader); - int status; - glGetObjectParameterivARB(m_shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); - m_compileError = (status != 1); - } else { - m_compileError = true; - } -} - -GLShader::~GLShader() -{ - GLSHADERS_ASSERT_OPENGL("GLShader::~GLShader", glDeleteObjectARB, return) - - glDeleteObjectARB(m_shader); -} - -QString GLShader::log() -{ - GLSHADERS_ASSERT_OPENGL("GLShader::log", glGetObjectParameterivARB - && glGetInfoLogARB, return QLatin1String("GLSL not supported.")) - - int length; - glGetObjectParameterivARB(m_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); - char *log = new char[length + 1]; - GLsizei glLength = length; - glGetInfoLogARB(m_shader, glLength, &glLength, log); - log[glLength] = '\0'; - QString result(log); - delete log; - return result; -} - -GLVertexShader::GLVertexShader(const char *data, int size) : GLShader(data, size, GL_VERTEX_SHADER_ARB) -{ -} - -GLVertexShader::GLVertexShader(const QString& fileName) : GLShader(fileName, GL_VERTEX_SHADER_ARB) -{ -} - -GLFragmentShader::GLFragmentShader(const char *data, int size) : GLShader(data, size, GL_FRAGMENT_SHADER_ARB) -{ -} - -GLFragmentShader::GLFragmentShader(const QString& fileName) : GLShader(fileName, GL_FRAGMENT_SHADER_ARB) -{ -} - -GLProgram::GLProgram() : m_linked(false), m_linkError(false), m_failed(false) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::GLProgram", glCreateProgramObjectARB, return) - - m_program = glCreateProgramObjectARB(); -} - -GLProgram::~GLProgram() -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::~GLProgram", glDeleteObjectARB, return) - - glDeleteObjectARB(m_program); -} - -void GLProgram::attach(const GLShader &shader) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::attach", glAttachObjectARB, return) - - glAttachObjectARB(m_program, shader.m_shader); - m_linked = m_linkError = false; -} - -void GLProgram::detach(const GLShader &shader) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::detach", glDetachObjectARB, return) - - glDetachObjectARB(m_program, shader.m_shader); - m_linked = m_linkError = false; -} - -bool GLProgram::failed() -{ - if (m_failed || m_linkError) - return true; - - if (m_linked) - return false; - - GLSHADERS_ASSERT_OPENGL("GLProgram::failed", glLinkProgramARB && glGetObjectParameterivARB, return true) - - glLinkProgramARB(m_program); - int status; - glGetObjectParameterivARB(m_program, GL_OBJECT_LINK_STATUS_ARB, &status); - m_linkError = !(m_linked = (status == 1)); - return m_linkError; -} - -QString GLProgram::log() -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::log", glGetObjectParameterivARB && glGetInfoLogARB, - return QLatin1String("Failed.")) - - int length; - glGetObjectParameterivARB(m_program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); - char *log = new char[length + 1]; - GLsizei glLength = length; - glGetInfoLogARB(m_program, glLength, &glLength, log); - log[glLength] = '\0'; - QString result(log); - delete log; - return result; -} - -void GLProgram::bind() -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::bind", glUseProgramObjectARB, return) - - if (!failed()) - glUseProgramObjectARB(m_program); -} - -void GLProgram::unbind() -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::bind", glUseProgramObjectARB, return) - - glUseProgramObjectARB(0); -} - -bool GLProgram::hasParameter(const QString& name) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::hasParameter", glGetUniformLocationARB, return false) - - if (!failed()) { - QByteArray asciiName = name.toAscii(); - return -1 != glGetUniformLocationARB(m_program, asciiName.data()); - } - return false; -} - -void GLProgram::setInt(const QString& name, int value) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::setInt", glGetUniformLocationARB && glUniform1iARB, return) - - if (!failed()) { - QByteArray asciiName = name.toAscii(); - int loc = glGetUniformLocationARB(m_program, asciiName.data()); - glUniform1iARB(loc, value); - } -} - -void GLProgram::setFloat(const QString& name, float value) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::setFloat", glGetUniformLocationARB && glUniform1fARB, return) - - if (!failed()) { - QByteArray asciiName = name.toAscii(); - int loc = glGetUniformLocationARB(m_program, asciiName.data()); - glUniform1fARB(loc, value); - } -} - -void GLProgram::setColor(const QString& name, QRgb value) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::setColor", glGetUniformLocationARB && glUniform4fARB, return) - - //qDebug() << "Setting color" << name; - if (!failed()) { - QByteArray asciiName = name.toAscii(); - int loc = glGetUniformLocationARB(m_program, asciiName.data()); - //qDebug() << "Location of" << name << "is" << loc; - QColor color(value); - glUniform4fARB(loc, color.redF(), color.greenF(), color.blueF(), color.alphaF()); - } -} - -void GLProgram::setMatrix(const QString& name, const gfx::Matrix4x4f &mat) -{ - GLSHADERS_ASSERT_OPENGL("GLProgram::setMatrix", glGetUniformLocationARB && glUniformMatrix4fvARB, return) - - if (!failed()) { - QByteArray asciiName = name.toAscii(); - int loc = glGetUniformLocationARB(m_program, asciiName.data()); - //qDebug() << "Location of" << name << "is" << loc; - glUniformMatrix4fvARB(loc, 1, GL_FALSE, mat.bits()); - } -} \ No newline at end of file diff --git a/demos/boxes/glshaders.h b/demos/boxes/glshaders.h deleted file mode 100644 index 2b6209a..0000000 --- a/demos/boxes/glshaders.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef GLSHADERS_H -#define GLSHADERS_H - -//#include -#include "glextensions.h" - -#include -#include - -#include "vector.h" - -class GLShader -{ -public: - friend class GLProgram; - virtual ~GLShader(); - bool failed() const {return m_failed;} - QString log(); -protected: - GLShader(const char *data, int size, GLenum shaderType); - GLShader(const QString& fileName, GLenum shaderType); - - GLhandleARB m_shader; - bool m_compileError; - bool m_failed; -}; - -class GLVertexShader : public GLShader -{ -public: - GLVertexShader(const char *data, int size); - GLVertexShader(const QString& fileName); -}; - -class GLFragmentShader : public GLShader -{ -public: - GLFragmentShader(const char *data, int size); - GLFragmentShader(const QString& fileName); -}; - -class GLProgram -{ -public: - GLProgram(); - ~GLProgram(); - void attach(const GLShader &shader); - void detach(const GLShader &shader); - void bind(); - void unbind(); - bool failed(); - QString log(); - bool hasParameter(const QString& name); - // use program before setting values - void setInt(const QString& name, int value); - void setFloat(const QString& name, float value); - void setColor(const QString& name, QRgb value); - void setMatrix(const QString& name, const gfx::Matrix4x4f &mat); - // TODO: add a bunch of set-functions for different types. -private: - GLhandleARB m_program; - bool m_linked; - bool m_linkError; - bool m_failed; -}; - -#endif diff --git a/demos/boxes/scene.cpp b/demos/boxes/scene.cpp index 1040e17..e5aab75 100644 --- a/demos/boxes/scene.cpp +++ b/demos/boxes/scene.cpp @@ -531,11 +531,11 @@ Scene::~Scene() if (texture) delete texture; if (m_mainCubemap) delete m_mainCubemap; - foreach (GLProgram *program, m_programs) + foreach (QGLShaderProgram *program, m_programs) if (program) delete program; if (m_vertexShader) delete m_vertexShader; - foreach (GLFragmentShader *shader, m_fragmentShaders) + foreach (QGLShader *shader, m_fragmentShaders) if (shader) delete shader; foreach (GLRenderTargetCube *rt, m_cubemaps) if (rt) delete rt; @@ -549,16 +549,18 @@ void Scene::initGL() { m_box = new GLRoundedBox(0.25f, 1.0f, 10); - m_vertexShader = new GLVertexShader(":/res/boxes/basic.vsh"); + m_vertexShader = new QGLShader(":/res/boxes/basic.vsh", QGLShader::VertexShader); QStringList list; list << ":/res/boxes/cubemap_posx.jpg" << ":/res/boxes/cubemap_negx.jpg" << ":/res/boxes/cubemap_posy.jpg" << ":/res/boxes/cubemap_negy.jpg" << ":/res/boxes/cubemap_posz.jpg" << ":/res/boxes/cubemap_negz.jpg"; m_environment = new GLTextureCube(list, qMin(1024, m_maxTextureSize)); - m_environmentShader = new GLFragmentShader(environmentShaderText, strlen(environmentShaderText)); - m_environmentProgram = new GLProgram; - m_environmentProgram->attach(*m_vertexShader); - m_environmentProgram->attach(*m_environmentShader); + m_environmentShader = new QGLShader(QGLShader::FragmentShader); + m_environmentShader->setSourceCode(environmentShaderText); + m_environmentProgram = new QGLShaderProgram; + m_environmentProgram->addShader(m_vertexShader); + m_environmentProgram->addShader(m_environmentShader); + m_environmentProgram->link(); const int NOISE_SIZE = 128; // for a different size, B and BM in fbm.c must also be changed m_noise = new GLTexture3D(NOISE_SIZE, NOISE_SIZE, NOISE_SIZE); @@ -610,19 +612,19 @@ void Scene::initGL() filter = QStringList("*.fsh"); files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable); foreach (QFileInfo file, files) { - GLProgram *program = new GLProgram; - GLFragmentShader* shader = new GLFragmentShader(file.absoluteFilePath()); + QGLShaderProgram *program = new QGLShaderProgram; + QGLShader* shader = new QGLShader(file.absoluteFilePath(), QGLShader::FragmentShader); // The program does not take ownership over the shaders, so store them in a vector so they can be deleted afterwards. - program->attach(*m_vertexShader); - program->attach(*shader); - if (program->failed()) { + program->addShader(m_vertexShader); + program->addShader(shader); + if (!program->link()) { qWarning("Failed to compile and link shader program"); qWarning("Vertex shader log:"); - qWarning() << m_vertexShader->log(); + qWarning() << m_vertexShader->errors(); qWarning() << "Fragment shader log ( file =" << file.absoluteFilePath() << "):"; - qWarning() << shader->log(); + qWarning() << shader->errors(); qWarning("Shader program log:"); - qWarning() << program->log(); + qWarning() << program->errors(); delete shader; delete program; @@ -633,13 +635,13 @@ void Scene::initGL() m_programs << program; m_renderOptions->addShader(file.baseName()); - program->bind(); - m_cubemaps << (program->hasParameter("env") ? new GLRenderTargetCube(qMin(256, m_maxTextureSize)) : 0); - program->unbind(); + program->enable(); + m_cubemaps << ((program->uniformLocation("env") != -1) ? new GLRenderTargetCube(qMin(256, m_maxTextureSize)) : 0); + program->disable(); } if (m_programs.size() == 0) - m_programs << new GLProgram; + m_programs << new QGLShaderProgram; m_renderOptions->emitParameterChanged(); } @@ -674,12 +676,12 @@ void Scene::renderBoxes(const gfx::Matrix4x4f &view, int excludeBox) // Don't render the environment if the environment texture can't be set for the correct sampler. if (glActiveTexture) { m_environment->bind(); - m_environmentProgram->bind(); - m_environmentProgram->setInt("tex", 0); - m_environmentProgram->setInt("env", 1); - m_environmentProgram->setInt("noise", 2); + m_environmentProgram->enable(); + m_environmentProgram->setUniformValue("tex", 0); + m_environmentProgram->setUniformValue("env", 1); + m_environmentProgram->setUniformValue("noise", 2); m_box->draw(); - m_environmentProgram->unbind(); + m_environmentProgram->disable(); m_environment->unbind(); } @@ -707,14 +709,18 @@ void Scene::renderBoxes(const gfx::Matrix4x4f &view, int excludeBox) else m_environment->bind(); } - m_programs[i]->bind(); - m_programs[i]->setInt("tex", 0); - m_programs[i]->setInt("env", 1); - m_programs[i]->setInt("noise", 2); - m_programs[i]->setMatrix("view", view); - m_programs[i]->setMatrix("invView", invView); + m_programs[i]->enable(); + m_programs[i]->setUniformValue("tex", 0); + m_programs[i]->setUniformValue("env", 1); + m_programs[i]->setUniformValue("noise", 2); + QMatrix4x4 mview; + QMatrix4x4 minvview; + memcpy(mview.data(), view.bits(), sizeof(float) * 16); + memcpy(minvview.data(), invView.bits(), sizeof(float) * 16); + m_programs[i]->setUniformValue("view", mview); + m_programs[i]->setUniformValue("invView", minvview); m_box->draw(); - m_programs[i]->unbind(); + m_programs[i]->disable(); if (glActiveTexture) { if (m_dynamicCubemap && m_cubemaps[i]) @@ -737,14 +743,18 @@ void Scene::renderBoxes(const gfx::Matrix4x4f &view, int excludeBox) m_environment->bind(); } - m_programs[m_currentShader]->bind(); - m_programs[m_currentShader]->setInt("tex", 0); - m_programs[m_currentShader]->setInt("env", 1); - m_programs[m_currentShader]->setInt("noise", 2); - m_programs[m_currentShader]->setMatrix("view", view); - m_programs[m_currentShader]->setMatrix("invView", invView); + m_programs[m_currentShader]->enable(); + m_programs[m_currentShader]->setUniformValue("tex", 0); + m_programs[m_currentShader]->setUniformValue("env", 1); + m_programs[m_currentShader]->setUniformValue("noise", 2); + QMatrix4x4 mview; + QMatrix4x4 minvview; + memcpy(mview.data(), view.bits(), sizeof(float) * 16); + memcpy(minvview.data(), invView.bits(), sizeof(float) * 16); + m_programs[m_currentShader]->setUniformValue("view", mview); + m_programs[m_currentShader]->setUniformValue("invView", minvview); m_box->draw(); - m_programs[m_currentShader]->unbind(); + m_programs[m_currentShader]->disable(); if (glActiveTexture) { if (m_dynamicCubemap) @@ -1021,20 +1031,20 @@ void Scene::toggleDynamicCubemap(int state) void Scene::setColorParameter(const QString &name, QRgb color) { // set the color in all programs - foreach (GLProgram *program, m_programs) { - program->bind(); - program->setColor(name, color); - program->unbind(); + foreach (QGLShaderProgram *program, m_programs) { + program->enable(); + program->setUniformValue(program->uniformLocation(name), QColor(color)); + program->disable(); } } void Scene::setFloatParameter(const QString &name, float value) { // set the color in all programs - foreach (GLProgram *program, m_programs) { - program->bind(); - program->setFloat(name, value); - program->unbind(); + foreach (QGLShaderProgram *program, m_programs) { + program->enable(); + program->setUniformValue(program->uniformLocation(name), value); + program->disable(); } } diff --git a/demos/boxes/scene.h b/demos/boxes/scene.h index 2db9317..c056739 100644 --- a/demos/boxes/scene.h +++ b/demos/boxes/scene.h @@ -53,7 +53,6 @@ #include "vector.h" #include "trackball.h" #include "glbuffers.h" -#include "glshaders.h" #include "qtbox.h" #define PI 3.14159265358979 @@ -231,11 +230,11 @@ private: GLTexture3D *m_noise; GLRenderTargetCube *m_mainCubemap; QVector m_cubemaps; - QVector m_programs; - GLVertexShader *m_vertexShader; - QVector m_fragmentShaders; - GLFragmentShader *m_environmentShader; - GLProgram *m_environmentProgram; + QVector m_programs; + QGLShader *m_vertexShader; + QVector m_fragmentShaders; + QGLShader *m_environmentShader; + QGLShaderProgram *m_environmentProgram; }; diff --git a/examples/opengl/hellogl_es2/glwidget.cpp b/examples/opengl/hellogl_es2/glwidget.cpp index 213c5b2..ee50670 100644 --- a/examples/opengl/hellogl_es2/glwidget.cpp +++ b/examples/opengl/hellogl_es2/glwidget.cpp @@ -48,124 +48,10 @@ const int bubbleNum = 8; -inline void CrossProduct(qreal &xOut, qreal &yOut, qreal &zOut, qreal x1, qreal y1, qreal z1, qreal x2, qreal y2, qreal z2) -{ - xOut = y1 * z2 - z1 * y2; - yOut = z1 * x2 - x1 * z2; - zOut = x1 * y2 - y1 * x2; -} - -inline void Normalize(qreal &x, qreal &y, qreal &z) -{ - qreal l = sqrt(x*x + y*y + z*z); - x = x / l; - y = y / l; - z = z / l; -} - -inline void IdentityMatrix(GLfloat *m) -{ - m[0 * 4 + 0] = 1.0f; - m[1 * 4 + 0] = 0.0f; - m[2 * 4 + 0] = 0.0f; - m[3 * 4 + 0] = 0.0f; - m[0 * 4 + 1] = 0.0f; - m[1 * 4 + 1] = 1.0f; - m[2 * 4 + 1] = 0.0f; - m[3 * 4 + 1] = 0.0f; - m[0 * 4 + 2] = 0.0f; - m[1 * 4 + 2] = 0.0f; - m[2 * 4 + 2] = 1.0f; - m[3 * 4 + 2] = 0.0f; - m[0 * 4 + 3] = 0.0f; - m[1 * 4 + 3] = 0.0f; - m[2 * 4 + 3] = 0.0f; - m[3 * 4 + 3] = 1.0f; -} - -// Adjust a 4x4 matrix to apply a scale. -inline void ScaleMatrix(GLfloat *m, GLfloat scalex, GLfloat scaley, GLfloat scalez) -{ - m[0 * 4 + 0] *= scalex; - m[0 * 4 + 1] *= scalex; - m[0 * 4 + 2] *= scalex; - m[0 * 4 + 3] *= scalex; - m[1 * 4 + 0] *= scaley; - m[1 * 4 + 1] *= scaley; - m[1 * 4 + 2] *= scaley; - m[1 * 4 + 3] *= scaley; - m[2 * 4 + 0] *= scalez; - m[2 * 4 + 1] *= scalez; - m[2 * 4 + 2] *= scalez; - m[2 * 4 + 3] *= scalez; -} - -// Adjust a 4x4 matrix to apply a translation. -inline void TranslateMatrix(GLfloat *m, GLfloat translatex, GLfloat translatey, GLfloat translatez) -{ - m[3 * 4 + 0] += m[0 * 4 + 0] * translatex + m[1 * 4 + 0] * translatey + m[2 * 4 + 0] * translatez; - m[3 * 4 + 1] += m[0 * 4 + 1] * translatex + m[1 * 4 + 1] * translatey + m[2 * 4 + 1] * translatez; - m[3 * 4 + 2] += m[0 * 4 + 2] * translatex + m[1 * 4 + 2] * translatey + m[2 * 4 + 2] * translatez; - m[3 * 4 + 3] += m[0 * 4 + 3] * translatex + m[1 * 4 + 3] * translatey + m[2 * 4 + 3] * translatez; -} - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -// Adjust a 4x4 matrix to apply a rotation. -inline void RotateMatrix(GLfloat *m, GLfloat angle, GLfloat vx, GLfloat vy, GLfloat vz) -{ - GLfloat len = sqrt(vx * vx + vy * vy + vz * vz); - if (len != 0) { - vx /= len; - vy /= len; - vz /= len; - } - - GLfloat c, s, ic; - c = cos(angle * M_PI / 180.0); - s = sin(angle * M_PI / 180.0); - ic = 1.0f - c; - - GLfloat rot[16]; - rot[0 * 4 + 0] = vx * vx * ic + c; - rot[1 * 4 + 0] = vx * vy * ic - vz * s; - rot[2 * 4 + 0] = vx * vz * ic + vy * s; - rot[3 * 4 + 0] = 0.0f; - rot[0 * 4 + 1] = vy * vx * ic + vz * s; - rot[1 * 4 + 1] = vy * vy * ic + c; - rot[2 * 4 + 1] = vy * vz * ic - vx * s; - rot[3 * 4 + 1] = 0.0f; - rot[0 * 4 + 2] = vx * vz * ic - vy * s; - rot[1 * 4 + 2] = vy * vz * ic + vx * s; - rot[2 * 4 + 2] = vz * vz * ic + c; - rot[3 * 4 + 2] = 0.0f; - rot[0 * 4 + 3] = 0.0f; - rot[1 * 4 + 3] = 0.0f; - rot[2 * 4 + 3] = 0.0f; - rot[3 * 4 + 3] = 1.0f; - - GLfloat temp[16]; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - temp[j * 4 + i] = 0.0f; - for (int k = 0; k < 4; ++k) { - temp[j * 4 + i] += m[k * 4 + i] * rot[j * 4 + k]; - } - } - } - - qMemCopy(m, temp, sizeof(temp)); -} - GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent) { qtLogo = true; - createdVertices = 0; - createdNormals = 0; - m_vertexNumber = 0; frames = 0; setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_NoSystemBackground); @@ -178,10 +64,6 @@ GLWidget::GLWidget(QWidget *parent) GLWidget::~GLWidget() { - if (createdVertices) - delete[] createdVertices; - if (createdNormals) - delete[] createdNormals; } void GLWidget::setScaling(int scale) { @@ -210,13 +92,11 @@ void GLWidget::showBubbles(bool bubbles) void GLWidget::paintQtLogo() { glDisable(GL_TEXTURE_2D); - glVertexAttribPointer(vertexAttr1, 3, GL_FLOAT, GL_FALSE, 0, createdVertices); - glEnableVertexAttribArray(vertexAttr1); - glVertexAttribPointer(normalAttr1, 3, GL_FLOAT, GL_FALSE, 0, createdNormals); - glEnableVertexAttribArray(normalAttr1); - glDrawArrays(GL_TRIANGLES, 0, m_vertexNumber / 3); - glDisableVertexAttribArray(normalAttr1); - glDisableVertexAttribArray(vertexAttr1); + program1.setAttributeArray(vertexAttr1, vertices.constData()); + program1.setAttributeArray(normalAttr1, normals.constData()); + glDrawArrays(GL_TRIANGLES, 0, vertices.size()); + program1.disableAttributeArray(normalAttr1); + program1.disableAttributeArray(vertexAttr1); } void GLWidget::paintTexturedCube() @@ -239,8 +119,7 @@ void GLWidget::paintTexturedCube() -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5 }; - glVertexAttribPointer(vertexAttr2, 3, GL_FLOAT, GL_FALSE, 0, afVertices); - glEnableVertexAttribArray(vertexAttr2); + program2.setAttributeArray(vertexAttr2, afVertices, 3); GLfloat afTexCoord[] = { 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f, @@ -258,8 +137,7 @@ void GLWidget::paintTexturedCube() 1.0f,0.0f, 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f }; - glVertexAttribPointer(texCoordAttr2, 2, GL_FLOAT, GL_FALSE, 0, afTexCoord); - glEnableVertexAttribArray(texCoordAttr2); + program2.setAttributeArray(texCoordAttr2, afTexCoord, 2); GLfloat afNormals[] = { @@ -278,50 +156,15 @@ void GLWidget::paintTexturedCube() 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0 }; - glVertexAttribPointer(normalAttr2, 3, GL_FLOAT, GL_FALSE, 0, afNormals); - glEnableVertexAttribArray(normalAttr2); + program2.setAttributeArray(normalAttr2, afNormals, 3); - glUniform1i(textureUniform2, 0); // use texture unit 0 + program2.setUniformValue(textureUniform2, 0); // use texture unit 0 glDrawArrays(GL_TRIANGLES, 0, 36); - glDisableVertexAttribArray(vertexAttr2); - glDisableVertexAttribArray(normalAttr2); - glDisableVertexAttribArray(texCoordAttr2); -} - -static void reportCompileErrors(GLuint shader, const char *src) -{ - GLint value = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &value); - bool compiled = (value != 0); - value = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &value); - if (!compiled && value > 1) { - char *log = new char [value]; - GLint len; - glGetShaderInfoLog(shader, value, &len, log); - qWarning("%s\n", log); - qWarning("when compiling:\n%s\n", src); - delete [] log; - } -} - -static void reportLinkErrors(GLuint program, const char *vsrc, const char *fsrc) -{ - GLint value = 0; - glGetProgramiv(program, GL_LINK_STATUS, &value); - bool linked = (value != 0); - value = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value); - if (!linked && value > 1) { - char *log = new char [value]; - GLint len; - glGetProgramInfoLog(program, value, &len, log); - qWarning("%s\n", log); - qWarning("when linking:\n%s\nwith:\n%s\n", vsrc, fsrc); - delete [] log; - } + program2.disableAttributeArray(vertexAttr2); + program2.disableAttributeArray(normalAttr2); + program2.disableAttributeArray(texCoordAttr2); } void GLWidget::initializeGL () @@ -332,8 +175,8 @@ void GLWidget::initializeGL () glGenTextures(1, &m_uiTexture); m_uiTexture = bindTexture(QImage(":/qt.png")); - GLuint vshader1 = glCreateShader(GL_VERTEX_SHADER); - const char *vsrc1[1] = { + QGLShader *vshader1 = new QGLShader(QGLShader::VertexShader, this); + const char *vsrc1 = "attribute highp vec4 vertex;\n" "attribute mediump vec3 normal;\n" "uniform mediump mat4 matrix;\n" @@ -346,36 +189,28 @@ void GLWidget::initializeGL () " color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n" " color = clamp(color, 0.0, 1.0);\n" " gl_Position = matrix * vertex;\n" - "}\n" - }; - glShaderSource(vshader1, 1, vsrc1, 0); - glCompileShader(vshader1); - reportCompileErrors(vshader1, vsrc1[0]); + "}\n"; + vshader1->setSourceCode(vsrc1); - GLuint fshader1 = glCreateShader(GL_FRAGMENT_SHADER); - const char *fsrc1[1] = { + QGLShader *fshader1 = new QGLShader(QGLShader::FragmentShader, this); + const char *fsrc1 = "varying mediump vec4 color;\n" "void main(void)\n" "{\n" " gl_FragColor = color;\n" - "}\n" - }; - glShaderSource(fshader1, 1, fsrc1, 0); - glCompileShader(fshader1); - reportCompileErrors(fshader1, fsrc1[0]); - - program1 = glCreateProgram(); - glAttachShader(program1, vshader1); - glAttachShader(program1, fshader1); - glLinkProgram(program1); - reportLinkErrors(program1, vsrc1[0], fsrc1[0]); - - vertexAttr1 = glGetAttribLocation(program1, "vertex"); - normalAttr1 = glGetAttribLocation(program1, "normal"); - matrixUniform1 = glGetUniformLocation(program1, "matrix"); - - GLuint vshader2 = glCreateShader(GL_VERTEX_SHADER); - const char *vsrc2[1] = { + "}\n"; + fshader1->setSourceCode(fsrc1); + + program1.addShader(vshader1); + program1.addShader(fshader1); + program1.link(); + + vertexAttr1 = program1.attributeLocation("vertex"); + normalAttr1 = program1.attributeLocation("normal"); + matrixUniform1 = program1.uniformLocation("matrix"); + + QGLShader *vshader2 = new QGLShader(QGLShader::VertexShader); + const char *vsrc2 = "attribute highp vec4 vertex;\n" "attribute highp vec4 texCoord;\n" "attribute mediump vec3 normal;\n" @@ -388,14 +223,11 @@ void GLWidget::initializeGL () " angle = max(dot(normal, toLight), 0.0);\n" " gl_Position = matrix * vertex;\n" " texc = texCoord;\n" - "}\n" - }; - glShaderSource(vshader2, 1, vsrc2, 0); - glCompileShader(vshader2); - reportCompileErrors(vshader2, vsrc2[0]); + "}\n"; + vshader2->setSourceCode(vsrc2); - GLuint fshader2 = glCreateShader(GL_FRAGMENT_SHADER); - const char *fsrc2[1] = { + QGLShader *fshader2 = new QGLShader(QGLShader::FragmentShader); + const char *fsrc2 = "varying highp vec4 texc;\n" "uniform sampler2D tex;\n" "varying mediump float angle;\n" @@ -404,23 +236,18 @@ void GLWidget::initializeGL () " highp vec3 color = texture2D(tex, texc.st).rgb;\n" " color = color * 0.2 + color * 0.8 * angle;\n" " gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);\n" - "}\n" - }; - glShaderSource(fshader2, 1, fsrc2, 0); - glCompileShader(fshader2); - reportCompileErrors(fshader2, fsrc2[0]); - - program2 = glCreateProgram(); - glAttachShader(program2, vshader2); - glAttachShader(program2, fshader2); - glLinkProgram(program2); - reportLinkErrors(program2, vsrc2[0], fsrc2[0]); - - vertexAttr2 = glGetAttribLocation(program2, "vertex"); - normalAttr2 = glGetAttribLocation(program2, "normal"); - texCoordAttr2 = glGetAttribLocation(program2, "texCoord"); - matrixUniform2 = glGetUniformLocation(program2, "matrix"); - textureUniform2 = glGetUniformLocation(program2, "tex"); + "}\n"; + fshader2->setSourceCode(fsrc2); + + program2.addShader(vshader2); + program2.addShader(fshader2); + program2.link(); + + vertexAttr2 = program2.attributeLocation("vertex"); + normalAttr2 = program2.attributeLocation("normal"); + texCoordAttr2 = program2.attributeLocation("texCoord"); + matrixUniform2 = program2.uniformLocation("matrix"); + textureUniform2 = program2.uniformLocation("tex"); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); @@ -450,24 +277,23 @@ void GLWidget::paintGL() glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); - GLfloat modelview[16]; - IdentityMatrix(modelview); - RotateMatrix(modelview, m_fAngle, 0.0, 1.0, 0.0); - RotateMatrix(modelview, m_fAngle, 1.0, 0.0, 0.0); - RotateMatrix(modelview, m_fAngle, 0.0, 0.0, 1.0); - ScaleMatrix(modelview, m_fScale, m_fScale, m_fScale); - TranslateMatrix(modelview, 0, -0.2, 0); + QMatrix4x4 modelview; + modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f); + modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f); + modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f); + modelview.scale(m_fScale); + modelview.translate(0.0f, -0.2f, 0.0f); if (qtLogo) { - glUseProgram(program1); - glUniformMatrix4fv(matrixUniform1, 1, GL_FALSE, modelview); + program1.enable(); + program1.setUniformValue(matrixUniform1, modelview); paintQtLogo(); - glUseProgram(0); + program1.disable(); } else { - glUseProgram(program2); - glUniformMatrix4fv(matrixUniform2, 1, GL_FALSE, modelview); + program2.enable(); + program1.setUniformValue(matrixUniform2, modelview); paintTexturedCube(); - glUseProgram(0); + program2.disable(); } glDisable(GL_DEPTH_TEST); @@ -563,80 +389,69 @@ void GLWidget::createGeometry() extrude(x8, y8, x5, y5); } - m_vertexNumber = vertices.size(); - createdVertices = new GLfloat[m_vertexNumber]; - createdNormals = new GLfloat[m_vertexNumber]; - for (int i = 0;i < m_vertexNumber;i++) { - createdVertices[i] = vertices.at(i) * 2; - createdNormals[i] = normals.at(i); - } - vertices.clear(); - normals.clear(); + for (int i = 0;i < vertices.size();i++) + vertices[i] *= 2.0f; } void GLWidget::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4) { - qreal nx, ny, nz; + vertices << QVector3D(x1, y1, -0.05f); + vertices << QVector3D(x2, y2, -0.05f); + vertices << QVector3D(x4, y4, -0.05f); - vertices << x1 << y1 << -0.05f; - vertices << x2 << y2 << -0.05f; - vertices << x4 << y4 << -0.05f; + vertices << QVector3D(x3, y3, -0.05f); + vertices << QVector3D(x4, y4, -0.05f); + vertices << QVector3D(x2, y2, -0.05f); - vertices << x3 << y3 << -0.05f; - vertices << x4 << y4 << -0.05f; - vertices << x2 << y2 << -0.05f; + QVector3D n = QVector3D::normal + (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f)); - CrossProduct(nx, ny, nz, x2 - x1, y2 - y1, 0, x4 - x1, y4 - y1, 0); - Normalize(nx, ny, nz); + normals << n; + normals << n; + normals << n; - normals << nx << ny << nz; - normals << nx << ny << nz; - normals << nx << ny << nz; + normals << n; + normals << n; + normals << n; - normals << nx << ny << nz; - normals << nx << ny << nz; - normals << nx << ny << nz; + vertices << QVector3D(x4, y4, 0.05f); + vertices << QVector3D(x2, y2, 0.05f); + vertices << QVector3D(x1, y1, 0.05f); - vertices << x4 << y4 << 0.05f; - vertices << x2 << y2 << 0.05f; - vertices << x1 << y1 << 0.05f; + vertices << QVector3D(x2, y2, 0.05f); + vertices << QVector3D(x4, y4, 0.05f); + vertices << QVector3D(x3, y3, 0.05f); - vertices << x2 << y2 << 0.05f; - vertices << x4 << y4 << 0.05f; - vertices << x3 << y3 << 0.05f; + n = QVector3D::normal + (QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f)); - CrossProduct(nx, ny, nz, x2 - x4, y2 - y4, 0, x1 - x4, y1 - y4, 0); - Normalize(nx, ny, nz); + normals << n; + normals << n; + normals << n; - normals << nx << ny << nz; - normals << nx << ny << nz; - normals << nx << ny << nz; - - normals << nx << ny << nz; - normals << nx << ny << nz; - normals << nx << ny << nz; + normals << n; + normals << n; + normals << n; } void GLWidget::extrude(qreal x1, qreal y1, qreal x2, qreal y2) { - qreal nx, ny, nz; - - vertices << x1 << y1 << +0.05f; - vertices << x2 << y2 << +0.05f; - vertices << x1 << y1 << -0.05f; + vertices << QVector3D(x1, y1, +0.05f); + vertices << QVector3D(x2, y2, +0.05f); + vertices << QVector3D(x1, y1, -0.05f); - vertices << x2 << y2 << -0.05f; - vertices << x1 << y1 << -0.05f; - vertices << x2 << y2 << +0.05f; + vertices << QVector3D(x2, y2, -0.05f); + vertices << QVector3D(x1, y1, -0.05f); + vertices << QVector3D(x2, y2, +0.05f); - CrossProduct(nx, ny, nz, x2 - x1, y2 - y1, 0.0f, 0.0f, 0.0f, -0.1f); - Normalize(nx, ny, nz); + QVector3D n = QVector3D::normal + (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f)); - normals << nx << ny << nz; - normals << nx << ny << nz; - normals << nx << ny << nz; + normals << n; + normals << n; + normals << n; - normals << nx << ny << nz; - normals << nx << ny << nz; - normals << nx << ny << nz; + normals << n; + normals << n; + normals << n; } diff --git a/examples/opengl/hellogl_es2/glwidget.h b/examples/opengl/hellogl_es2/glwidget.h index 9a7823a..596e1cc 100644 --- a/examples/opengl/hellogl_es2/glwidget.h +++ b/examples/opengl/hellogl_es2/glwidget.h @@ -43,7 +43,11 @@ #define GLWIDGET_H #include +#include +#include +#include #include +#include class Bubble; class GLWidget : public QGLWidget { @@ -71,24 +75,21 @@ private: void createBubbles(int number); void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4); void extrude(qreal x1, qreal y1, qreal x2, qreal y2); - QList vertices; - QList normals; - GLfloat *createdVertices; - GLfloat *createdNormals; - int m_vertexNumber; + QVector vertices; + QVector normals; bool qtLogo; QList bubbles; int frames; QTime time; - GLuint program1; - GLuint program2; - GLuint vertexAttr1; - GLuint normalAttr1; - GLuint matrixUniform1; - GLuint vertexAttr2; - GLuint normalAttr2; - GLuint texCoordAttr2; - GLuint matrixUniform2; - GLuint textureUniform2; + QGLShaderProgram program1; + QGLShaderProgram program2; + int vertexAttr1; + int normalAttr1; + int matrixUniform1; + int vertexAttr2; + int normalAttr2; + int texCoordAttr2; + int matrixUniform2; + int textureUniform2; }; #endif diff --git a/src/opengl/gl2paintengineex/qglshader_p.h b/src/opengl/gl2paintengineex/qglshader_p.h index 4cbf3f6..64c9a42 100644 --- a/src/opengl/gl2paintengineex/qglshader_p.h +++ b/src/opengl/gl2paintengineex/qglshader_p.h @@ -81,7 +81,8 @@ SAMPLER_2D_SHADOW. #include -#include +#define QGLShader QGLEngineShader +#define QGLShaderProgram QGLEngineShaderProgram typedef struct { GLfloat a; diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index af16312..3b8bfa1 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -25,14 +25,16 @@ HEADERS += qgl.h \ qglcolormap.h \ qglpixelbuffer.h \ qglframebufferobject.h \ - qglpixmapfilter_p.h + qglpixmapfilter_p.h \ + qglshaderprogram.h SOURCES += qgl.cpp \ qglcolormap.cpp \ qglpixelbuffer.cpp \ qglframebufferobject.cpp \ qglextensions.cpp \ - qglpixmapfilter.cpp + qglpixmapfilter.cpp \ + qglshaderprogram.cpp #!contains(QT_CONFIG, opengles2) { # HEADERS += qpaintengine_opengl_p.h diff --git a/src/opengl/qglextensions.cpp b/src/opengl/qglextensions.cpp index e6ac043..5fda346 100644 --- a/src/opengl/qglextensions.cpp +++ b/src/opengl/qglextensions.cpp @@ -153,55 +153,179 @@ bool qt_resolve_buffer_extensions(QGLContext *ctx) bool qt_resolve_glsl_extensions(QGLContext *ctx) { +#if defined(QT_OPENGL_ES_2) + // The GLSL shader functions are always present in OpenGL/ES 2.0. + // The only exceptions are glGetProgramBinaryOES and glProgramBinaryOES. + if (!QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glslResolved) { + glGetProgramBinaryOES = (_glGetProgramBinaryOES) ctx->getProcAddress(QLatin1String("glGetProgramBinaryOES")); + glProgramBinaryOES = (_glProgramBinaryOES) ctx->getProcAddress(QLatin1String("glProgramBinaryOES")); + QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glslResolved = true; + } + return true; +#else if (glCreateShader) return true; glCreateShader = (_glCreateShader) ctx->getProcAddress(QLatin1String("glCreateShader")); - glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSource")); - glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShader")); - glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteShader")); - - glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgram")); - glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachShader")); - glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachShader")); - glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgram")); - glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgram")); - glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteProgram")); - - glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetShaderInfoLog")); - glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetShaderiv")); - glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetProgramiv")); - - glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocation")); - glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fv")); - glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fv")); - glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fv")); - glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fv")); - glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1i")); - - glGetActiveAttrib = (_glGetActiveAttrib) ctx->getProcAddress(QLatin1String("glGetActiveAttrib")); - glGetAttribLocation = (_glGetAttribLocation) ctx->getProcAddress(QLatin1String("glGetAttribLocation")); - glGetActiveUniform = (_glGetActiveUniform) ctx->getProcAddress(QLatin1String("glGetActiveUniform")); - glGetProgramInfoLog = (_glGetProgramInfoLog) ctx->getProcAddress(QLatin1String("glGetProgramInfoLog")); - glUniform1f = (_glUniform1f) ctx->getProcAddress(QLatin1String("glUniform1f")); - glUniform2f = (_glUniform2f) ctx->getProcAddress(QLatin1String("glUniform2f")); - glUniform4f = (_glUniform4f) ctx->getProcAddress(QLatin1String("glUniform4f")); - glUniformMatrix2fv = (_glUniformMatrix2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2fv")); - glUniformMatrix3fv = (_glUniformMatrix3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3fv")); - glUniformMatrix4fv = (_glUniformMatrix4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4fv")); - glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArray")); - glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArray")); - glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointer")); - glStencilOpSeparate = (_glStencilOpSeparate) ctx->getProcAddress(QLatin1String("glStencilOpSeparate")); - - return glCreateShader && glShaderSource && glCompileShader && glDeleteProgram && - glCreateProgram && glAttachShader && glDetachShader && glLinkProgram && glUseProgram && - glDeleteProgram && glGetShaderInfoLog && glGetShaderiv && glGetProgramiv && glGetUniformLocation && - glUniform1i && glUniform1fv && glUniform2fv && glUniform3fv && glUniform4fv && - glGetActiveAttrib && glGetAttribLocation && glGetActiveUniform && glGetProgramInfoLog && - glUniform1f && glUniform2f && glUniform4f && - glUniformMatrix2fv && glUniformMatrix3fv && glUniformMatrix4fv && - glEnableVertexAttribArray && glDisableVertexAttribArray && glVertexAttribPointer && glStencilOpSeparate; + if (glCreateShader) { + glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSource")); + glShaderBinary = (_glShaderBinary) ctx->getProcAddress(QLatin1String("glShaderBinary")); + glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShader")); + glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteShader")); + glIsShader = (_glIsShader) ctx->getProcAddress(QLatin1String("glIsShader")); + + glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgram")); + glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachShader")); + glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachShader")); + glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgram")); + glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgram")); + glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteProgram")); + glIsProgram = (_glIsProgram) ctx->getProcAddress(QLatin1String("glIsProgram")); + + glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetShaderInfoLog")); + glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetShaderiv")); + glGetShaderSource = (_glGetShaderSource) ctx->getProcAddress(QLatin1String("glGetShaderSource")); + glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetProgramiv")); + glGetProgramInfoLog = (_glGetProgramInfoLog) ctx->getProcAddress(QLatin1String("glGetProgramInfoLog")); + + glGetActiveUniform = (_glGetActiveUniform) ctx->getProcAddress(QLatin1String("glGetActiveUniform"));//### REMOVE + glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocation")); + glUniform4f = (_glUniform4f) ctx->getProcAddress(QLatin1String("glUniform4f")); //### REMOVE + glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fv")); + glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fv")); + glUniform2f = (_glUniform2f) ctx->getProcAddress(QLatin1String("glUniform2f")); //### REMOVE + glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fv")); + glUniform1f = (_glUniform1f) ctx->getProcAddress(QLatin1String("glUniform1f")); //### REMOVE + glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fv")); + glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1i")); + glUniform1iv = (_glUniform1iv) ctx->getProcAddress(QLatin1String("glUniform1iv")); + glUniformMatrix2fv = (_glUniformMatrix2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2fv")); + glUniformMatrix3fv = (_glUniformMatrix3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3fv")); + glUniformMatrix4fv = (_glUniformMatrix4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4fv")); + glUniformMatrix2x3fv = (_glUniformMatrix2x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x3fv")); + glUniformMatrix2x4fv = (_glUniformMatrix2x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x4fv")); + glUniformMatrix3x2fv = (_glUniformMatrix3x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x2fv")); + glUniformMatrix3x4fv = (_glUniformMatrix3x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x4fv")); + glUniformMatrix4x2fv = (_glUniformMatrix4x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x2fv")); + glUniformMatrix4x3fv = (_glUniformMatrix4x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x3fv")); + + glGetActiveAttrib = (_glGetActiveAttrib) ctx->getProcAddress(QLatin1String("glGetActiveAttrib")); //### REMOVE + glBindAttribLocation = (_glBindAttribLocation) ctx->getProcAddress(QLatin1String("glBindAttribLocation")); + glGetAttribLocation = (_glGetAttribLocation) ctx->getProcAddress(QLatin1String("glGetAttribLocation")); + glVertexAttrib1fv = (_glVertexAttrib1fv) ctx->getProcAddress(QLatin1String("glVertexAttrib1fv")); + glVertexAttrib2fv = (_glVertexAttrib2fv) ctx->getProcAddress(QLatin1String("glVertexAttrib2fv")); + glVertexAttrib3fv = (_glVertexAttrib3fv) ctx->getProcAddress(QLatin1String("glVertexAttrib3fv")); + glVertexAttrib4fv = (_glVertexAttrib4fv) ctx->getProcAddress(QLatin1String("glVertexAttrib4fv")); + glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointer")); + glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArray")); + glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArray")); + + glStencilOpSeparate = (_glStencilOpSeparate) ctx->getProcAddress(QLatin1String("glStencilOpSeparate")); //### Not really a glsl extension, but needed for gl2 + + } else { + // We may not have the standard shader functions, but we might + // have the older ARB functions instead. + glCreateShader = (_glCreateShader) ctx->getProcAddress(QLatin1String("glCreateShaderObjectARB")); + glShaderSource = (_glShaderSource) ctx->getProcAddress(QLatin1String("glShaderSourceARB")); + glShaderBinary = (_glShaderBinary) ctx->getProcAddress(QLatin1String("glShaderBinaryARB")); + glCompileShader = (_glCompileShader) ctx->getProcAddress(QLatin1String("glCompileShaderARB")); + glDeleteShader = (_glDeleteShader) ctx->getProcAddress(QLatin1String("glDeleteObjectARB")); + glIsShader = 0; + + glCreateProgram = (_glCreateProgram) ctx->getProcAddress(QLatin1String("glCreateProgramObjectARB")); + glAttachShader = (_glAttachShader) ctx->getProcAddress(QLatin1String("glAttachObjectARB")); + glDetachShader = (_glDetachShader) ctx->getProcAddress(QLatin1String("glDetachObjectARB")); + glLinkProgram = (_glLinkProgram) ctx->getProcAddress(QLatin1String("glLinkProgramARB")); + glUseProgram = (_glUseProgram) ctx->getProcAddress(QLatin1String("glUseProgramObjectARB")); + glDeleteProgram = (_glDeleteProgram) ctx->getProcAddress(QLatin1String("glDeleteObjectARB")); + glIsProgram = 0; + + glGetShaderInfoLog = (_glGetShaderInfoLog) ctx->getProcAddress(QLatin1String("glGetInfoLogARB")); + glGetShaderiv = (_glGetShaderiv) ctx->getProcAddress(QLatin1String("glGetObjectParameterivARB")); + glGetShaderSource = (_glGetShaderSource) ctx->getProcAddress(QLatin1String("glGetShaderSourceARB")); + glGetProgramiv = (_glGetProgramiv) ctx->getProcAddress(QLatin1String("glGetObjectParameterivARB")); + glGetProgramInfoLog = (_glGetProgramInfoLog) ctx->getProcAddress(QLatin1String("glGetInfoLogARB")); + + glGetActiveUniform = (_glGetActiveUniform) ctx->getProcAddress(QLatin1String("glGetActiveUniformARB"));//### REMOVE + glGetUniformLocation = (_glGetUniformLocation) ctx->getProcAddress(QLatin1String("glGetUniformLocationARB")); + glUniform4f = (_glUniform4f) ctx->getProcAddress(QLatin1String("glUniform4fARB")); //### REMOVE + glUniform4fv = (_glUniform4fv) ctx->getProcAddress(QLatin1String("glUniform4fvARB")); + glUniform3fv = (_glUniform3fv) ctx->getProcAddress(QLatin1String("glUniform3fvARB")); + glUniform2f = (_glUniform2f) ctx->getProcAddress(QLatin1String("glUniform2fARB")); //### REMOVE + glUniform2fv = (_glUniform2fv) ctx->getProcAddress(QLatin1String("glUniform2fvARB")); + glUniform1f = (_glUniform1f) ctx->getProcAddress(QLatin1String("glUniform1fARB")); //### REMOVE + glUniform1fv = (_glUniform1fv) ctx->getProcAddress(QLatin1String("glUniform1fvARB")); + glUniform1i = (_glUniform1i) ctx->getProcAddress(QLatin1String("glUniform1iARB")); + glUniform1iv = (_glUniform1iv) ctx->getProcAddress(QLatin1String("glUniform1ivARB")); + glUniformMatrix2fv = (_glUniformMatrix2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2fvARB")); + glUniformMatrix3fv = (_glUniformMatrix3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3fvARB")); + glUniformMatrix4fv = (_glUniformMatrix4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4fvARB")); + glUniformMatrix2x3fv = (_glUniformMatrix2x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x3fvARB")); + glUniformMatrix2x4fv = (_glUniformMatrix2x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix2x4fvARB")); + glUniformMatrix3x2fv = (_glUniformMatrix3x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x2fvARB")); + glUniformMatrix3x4fv = (_glUniformMatrix3x4fv) ctx->getProcAddress(QLatin1String("glUniformMatrix3x4fvARB")); + glUniformMatrix4x2fv = (_glUniformMatrix4x2fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x2fvARB")); + glUniformMatrix4x3fv = (_glUniformMatrix4x3fv) ctx->getProcAddress(QLatin1String("glUniformMatrix4x3fvARB")); + + glGetActiveAttrib = (_glGetActiveAttrib) ctx->getProcAddress(QLatin1String("glGetActiveAttribARB")); //### REMOVE + glBindAttribLocation = (_glBindAttribLocation) ctx->getProcAddress(QLatin1String("glBindAttribLocationARB")); + glGetAttribLocation = (_glGetAttribLocation) ctx->getProcAddress(QLatin1String("glGetAttribLocationARB")); + glVertexAttrib1fv = (_glVertexAttrib1fv) ctx->getProcAddress(QLatin1String("glVertexAttrib1fvARB")); + glVertexAttrib2fv = (_glVertexAttrib2fv) ctx->getProcAddress(QLatin1String("glVertexAttrib2fvARB")); + glVertexAttrib3fv = (_glVertexAttrib3fv) ctx->getProcAddress(QLatin1String("glVertexAttrib3fvARB")); + glVertexAttrib4fv = (_glVertexAttrib4fv) ctx->getProcAddress(QLatin1String("glVertexAttrib4fvARB")); + glVertexAttribPointer = (_glVertexAttribPointer) ctx->getProcAddress(QLatin1String("glVertexAttribPointerARB")); + glDisableVertexAttribArray = (_glDisableVertexAttribArray) ctx->getProcAddress(QLatin1String("glDisableVertexAttribArrayARB")); + glEnableVertexAttribArray = (_glEnableVertexAttribArray) ctx->getProcAddress(QLatin1String("glEnableVertexAttribArrayARB")); + + glStencilOpSeparate = 0; //### Was never an ARB extension but went strait into OpenGL 2.0 + } + + // Note: glShaderBinary(), glIsShader(), glIsProgram(), and + // glUniformMatrixNxMfv() are optional, but all other functions + // are required. + + return glCreateShader && + glShaderSource && + glCompileShader && + glDeleteProgram && + glCreateProgram && + glAttachShader && + glDetachShader && + glLinkProgram && + glUseProgram && + glDeleteProgram && + glGetShaderInfoLog && + glGetShaderiv && + glGetShaderSource && + glGetProgramiv && + glGetProgramInfoLog && + glGetActiveUniform && //### REMOVE + glGetUniformLocation && + glUniform1f && //### REMOVE + glUniform1fv && + glUniform2f && //### REMOVE + glUniform2fv && + glUniform3fv && + glUniform4f && //### REMOVE + glUniform4fv && + glUniform1i && + glUniform1iv && + glUniformMatrix2fv && + glUniformMatrix3fv && + glUniformMatrix4fv && + glGetActiveAttrib && //### REMOVE + glBindAttribLocation && + glGetAttribLocation && + glVertexAttrib1fv && + glVertexAttrib2fv && + glVertexAttrib3fv && + glVertexAttrib4fv && + glVertexAttribPointer && + glDisableVertexAttribArray && + glEnableVertexAttribArray && + glStencilOpSeparate; +#endif } QT_END_NAMESPACE diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index cd35eb0..69632e7 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -96,8 +96,10 @@ typedef void (APIENTRY *_glProgramLocalParameter4fvARB) (GLenum, GLuint, const G // GLSL typedef GLuint (APIENTRY *_glCreateShader) (GLenum); typedef void (APIENTRY *_glShaderSource) (GLuint, GLsizei, const char **, const GLint *); +typedef void (APIENTRY *_glShaderBinary) (GLint, const GLuint*, GLenum, const void*, GLint); typedef void (APIENTRY *_glCompileShader) (GLuint); typedef void (APIENTRY *_glDeleteShader) (GLuint); +typedef GLboolean (APIENTRY *_glIsShader) (GLuint); typedef GLuint (APIENTRY *_glCreateProgram) (); typedef void (APIENTRY *_glAttachShader) (GLuint, GLuint); @@ -105,10 +107,13 @@ typedef void (APIENTRY *_glDetachShader) (GLuint, GLuint); typedef void (APIENTRY *_glLinkProgram) (GLuint); typedef void (APIENTRY *_glUseProgram) (GLuint); typedef void (APIENTRY *_glDeleteProgram) (GLuint); +typedef GLboolean (APIENTRY *_glIsProgram) (GLuint); typedef void (APIENTRY *_glGetShaderInfoLog) (GLuint, GLsizei, GLsizei *, char *); typedef void (APIENTRY *_glGetShaderiv) (GLuint, GLenum, GLint *); +typedef void (APIENTRY *_glGetShaderSource) (GLuint, GLsizei, GLsizei *, char *); typedef void (APIENTRY *_glGetProgramiv) (GLuint, GLenum, GLint *); +typedef void (APIENTRY *_glGetProgramInfoLog) (GLuint, GLsizei, GLsizei *, char *); typedef GLuint (APIENTRY *_glGetUniformLocation) (GLuint, const char*); typedef void (APIENTRY *_glUniform4fv) (GLint, GLsizei, const GLfloat *); @@ -116,6 +121,29 @@ typedef void (APIENTRY *_glUniform3fv) (GLint, GLsizei, const GLfloat *); typedef void (APIENTRY *_glUniform2fv) (GLint, GLsizei, const GLfloat *); typedef void (APIENTRY *_glUniform1fv) (GLint, GLsizei, const GLfloat *); typedef void (APIENTRY *_glUniform1i) (GLint, GLint); +typedef void (APIENTRY *_glUniform1iv) (GLint, GLsizei, const GLint *); +typedef void (APIENTRY *_glUniformMatrix2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix2x3fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix2x4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3x2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix3x4fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4x2fv) (GLint, GLsizei, GLboolean, const GLfloat *); +typedef void (APIENTRY *_glUniformMatrix4x3fv) (GLint, GLsizei, GLboolean, const GLfloat *); + +typedef void (APIENTRY *_glBindAttribLocation) (GLuint, GLuint, const char *); +typedef GLint (APIENTRY *_glGetAttribLocation) (GLuint, const char *); +typedef void (APIENTRY *_glVertexAttrib1fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib2fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib3fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttrib4fv) (GLuint, const GLfloat *); +typedef void (APIENTRY *_glVertexAttribPointer) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *); +typedef void (APIENTRY *_glDisableVertexAttribArray) (GLuint); +typedef void (APIENTRY *_glEnableVertexAttribArray) (GLuint); + +typedef void (APIENTRY *_glGetProgramBinaryOES) (GLuint, GLsizei, GLsizei *, GLenum *, void *); +typedef void (APIENTRY *_glProgramBinaryOES) (GLuint, GLenum, const void *, GLint); typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum ); @@ -182,10 +210,13 @@ struct QGLExtensionFuncs qt_glGenProgramsARB = 0; qt_glProgramLocalParameter4fvARB = 0; +#if !defined(QT_OPENGL_ES_2) qt_glCreateShader = 0; qt_glShaderSource = 0; + qt_glShaderBinary = 0; qt_glCompileShader = 0; qt_glDeleteShader = 0; + qt_glIsShader = 0; qt_glCreateProgram = 0; qt_glAttachShader = 0; @@ -193,10 +224,13 @@ struct QGLExtensionFuncs qt_glLinkProgram = 0; qt_glUseProgram = 0; qt_glDeleteProgram = 0; + qt_glIsProgram = 0; qt_glGetShaderInfoLog = 0; qt_glGetShaderiv = 0; + qt_glGetShaderSource = 0; qt_glGetProgramiv = 0; + qt_glGetProgramInfoLog = 0; qt_glGetUniformLocation = 0; qt_glUniform4fv = 0; @@ -204,6 +238,32 @@ struct QGLExtensionFuncs qt_glUniform2fv = 0; qt_glUniform1fv = 0; qt_glUniform1i = 0; + qt_glUniform1iv = 0; + qt_glUniformMatrix2fv = 0; + qt_glUniformMatrix3fv = 0; + qt_glUniformMatrix4fv = 0; + qt_glUniformMatrix2x3fv = 0; + qt_glUniformMatrix2x4fv = 0; + qt_glUniformMatrix3x2fv = 0; + qt_glUniformMatrix3x4fv = 0; + qt_glUniformMatrix4x2fv = 0; + qt_glUniformMatrix4x3fv = 0; + + qt_glBindAttribLocation = 0; + qt_glGetAttribLocation = 0; + qt_glVertexAttrib1fv = 0; + qt_glVertexAttrib2fv = 0; + qt_glVertexAttrib3fv = 0; + qt_glVertexAttrib4fv = 0; + qt_glVertexAttribPointer = 0; + qt_glDisableVertexAttribArray = 0; + qt_glEnableVertexAttribArray = 0; +#else + qt_glslResolved = false; + + qt_glGetProgramBinaryOES = 0; + qt_glProgramBinaryOES = 0; +#endif qt_glActiveStencilFaceEXT = 0; @@ -261,11 +321,14 @@ struct QGLExtensionFuncs _glGenProgramsARB qt_glGenProgramsARB; _glProgramLocalParameter4fvARB qt_glProgramLocalParameter4fvARB; +#if !defined(QT_OPENGL_ES_2) // GLSL definitions _glCreateShader qt_glCreateShader; _glShaderSource qt_glShaderSource; + _glShaderBinary qt_glShaderBinary; _glCompileShader qt_glCompileShader; _glDeleteShader qt_glDeleteShader; + _glIsShader qt_glIsShader; _glCreateProgram qt_glCreateProgram; _glAttachShader qt_glAttachShader; @@ -273,10 +336,13 @@ struct QGLExtensionFuncs _glLinkProgram qt_glLinkProgram; _glUseProgram qt_glUseProgram; _glDeleteProgram qt_glDeleteProgram; + _glIsProgram qt_glIsProgram; _glGetShaderInfoLog qt_glGetShaderInfoLog; _glGetShaderiv qt_glGetShaderiv; + _glGetShaderSource qt_glGetShaderSource; _glGetProgramiv qt_glGetProgramiv; + _glGetProgramInfoLog qt_glGetProgramInfoLog; _glGetUniformLocation qt_glGetUniformLocation; _glUniform4fv qt_glUniform4fv; @@ -284,6 +350,32 @@ struct QGLExtensionFuncs _glUniform2fv qt_glUniform2fv; _glUniform1fv qt_glUniform1fv; _glUniform1i qt_glUniform1i; + _glUniform1iv qt_glUniform1iv; + _glUniformMatrix2fv qt_glUniformMatrix2fv; + _glUniformMatrix3fv qt_glUniformMatrix3fv; + _glUniformMatrix4fv qt_glUniformMatrix4fv; + _glUniformMatrix2x3fv qt_glUniformMatrix2x3fv; + _glUniformMatrix2x4fv qt_glUniformMatrix2x4fv; + _glUniformMatrix3x2fv qt_glUniformMatrix3x2fv; + _glUniformMatrix3x4fv qt_glUniformMatrix3x4fv; + _glUniformMatrix4x2fv qt_glUniformMatrix4x2fv; + _glUniformMatrix4x3fv qt_glUniformMatrix4x3fv; + + _glBindAttribLocation qt_glBindAttribLocation; + _glGetAttribLocation qt_glGetAttribLocation; + _glVertexAttrib1fv qt_glVertexAttrib1fv; + _glVertexAttrib2fv qt_glVertexAttrib2fv; + _glVertexAttrib3fv qt_glVertexAttrib3fv; + _glVertexAttrib4fv qt_glVertexAttrib4fv; + _glVertexAttribPointer qt_glVertexAttribPointer; + _glDisableVertexAttribArray qt_glDisableVertexAttribArray; + _glEnableVertexAttribArray qt_glEnableVertexAttribArray; +#else + bool qt_glslResolved; + + _glGetProgramBinaryOES qt_glGetProgramBinaryOES; + _glProgramBinaryOES qt_glProgramBinaryOES; +#endif _glActiveStencilFaceEXT qt_glActiveStencilFaceEXT; @@ -600,10 +692,14 @@ struct QGLExtensionFuncs #define glMapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glMapBufferARB #define glUnmapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUnmapBufferARB +#if !defined(QT_OPENGL_ES_2) + #define glCreateShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateShader #define glShaderSource QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glShaderSource +#define glShaderBinary QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glShaderBinary #define glCompileShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCompileShader #define glDeleteShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteShader +#define glIsShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsShader #define glCreateProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateProgram #define glAttachShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glAttachShader @@ -611,10 +707,13 @@ struct QGLExtensionFuncs #define glLinkProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glLinkProgram #define glUseProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUseProgram #define glDeleteProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteProgram +#define glIsProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsProgram #define glGetShaderInfoLog QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderInfoLog #define glGetShaderiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderiv +#define glGetShaderSource QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderSource #define glGetProgramiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramiv +#define glGetProgramInfoLog QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramInfoLog #define glGetUniformLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetUniformLocation #define glUniform4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform4fv @@ -622,6 +721,33 @@ struct QGLExtensionFuncs #define glUniform2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform2fv #define glUniform1fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1fv #define glUniform1i QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1i +#define glUniform1iv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1iv +#define glUniformMatrix2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2fv +#define glUniformMatrix3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3fv +#define glUniformMatrix4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4fv +#define glUniformMatrix2x3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2x3fv +#define glUniformMatrix2x4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2x4fv +#define glUniformMatrix3x2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3x2fv +#define glUniformMatrix3x4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3x4fv +#define glUniformMatrix4x2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4x2fv +#define glUniformMatrix4x3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4x3fv + +#define glBindAttribLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindAttribLocation +#define glGetAttribLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetAttribLocation +#define glVertexAttrib1fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib1fv +#define glVertexAttrib2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib2fv +#define glVertexAttrib3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib3fv +#define glVertexAttrib4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib4fv +#define glVertexAttribPointer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttribPointer +#define glDisableVertexAttribArray QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDisableVertexAttribArray +#define glEnableVertexAttribArray QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glEnableVertexAttribArray + +#else // QT_OPENGL_ES_2 + +#define glGetProgramBinaryOES QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramBinaryOES +#define glProgramBinaryOES QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramBinaryOES + +#endif // QT_OPENGL_ES_2 #define glGetActiveAttrib QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetActiveAttrib #define glGetAttribLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetAttribLocation diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 8a64515..87abf60 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -45,27 +45,12 @@ #include "qpaintengine_opengl_p.h" #include "qglpixelbuffer.h" -#include "qglextensions_p.h" +#include "qglshaderprogram.h" #include "qgl_p.h" #include "private/qapplication_p.h" -#ifndef GL_FRAGMENT_SHADER -#define GL_FRAGMENT_SHADER 0x8B30 -#endif - -#ifndef GL_COMPILE_STATUS -#define GL_COMPILE_STATUS 0x8B81 -#endif - -#ifndef GL_LINK_STATUS -#define GL_LINK_STATUS 0x8B82 -#endif - - - - QT_BEGIN_NAMESPACE @@ -79,110 +64,6 @@ void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const processGL(painter, pos, src, source); } -QGLSLProgram::QGLSLProgram(const QString &src) - : ctx(QGLContext::currentContext()) -{ - if (!qt_resolve_glsl_extensions(const_cast(ctx))) { - qWarning("Failed to resolve GLSL functions"); - m_valid = false; - return; - } - - m_shader = glCreateShader(GL_FRAGMENT_SHADER); - - const QByteArray src_ba = src.toAscii(); - const char *src_cstr = src_ba.constData(); - - glShaderSource(m_shader, 1, &src_cstr, 0); - glCompileShader(m_shader); - glGetShaderiv(m_shader, GL_COMPILE_STATUS, &m_valid); - if (!m_valid) { - char data[4096]; - GLsizei len; - glGetShaderInfoLog(m_shader, 4096, &len, data); - qWarning("Failed to compile GLSL shader:\n%s\nCODE:\n%s\n", data, src_cstr); - return; - } - - m_program = glCreateProgram(); - glAttachShader(m_program, m_shader); - glLinkProgram(m_program); - glGetProgramiv(m_program, GL_LINK_STATUS, &m_valid); - if (!m_valid) { - char data[4096]; - GLsizei len; - glGetShaderInfoLog(m_shader, 4096, &len, data); - qWarning("Failed to link GLSL program:\n%s\nCODE:\n%s\n", data, src_cstr); - return; - } -} - -QGLSLProgram::~QGLSLProgram() -{ - glDeleteProgram(m_program); - glDeleteShader(m_shader); -} - -bool QGLSLProgram::success() const -{ - return m_valid; -} - -void QGLSLProgram::enable() -{ - glUseProgram(m_program); -} - -void QGLSLProgram::disable() -{ - glUseProgram(0); -} - -int QGLSLProgram::getUniformLocation(const QString &name) -{ - return glGetUniformLocation(m_program, name.toAscii().constData()); -} - -void QGLSLProgram::setUniform(int uniform, int value) -{ - enable(); - glUniform1i(uniform, value); -} - -void QGLSLProgram::setUniform(int uniform, qreal value) -{ - enable(); - GLfloat v[] = { value }; - glUniform1fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2) -{ - enable(); - GLfloat v[] = { v1, v2 }; - glUniform2fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2, qreal v3) -{ - enable(); - GLfloat v[] = { v1, v2, v3 }; - glUniform3fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, qreal v1, qreal v2, qreal v3, qreal v4) -{ - enable(); - GLfloat v[] = { v1, v2, v3, v4 }; - glUniform4fv(uniform, 1, v); -} - -void QGLSLProgram::setUniform(int uniform, int count, float *v) -{ - enable(); - glUniform1fv(uniform, count, v); -} - class QGLPixmapColorizeFilter: public QGLPixmapFilter { public: @@ -192,8 +73,8 @@ protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &pixmap, const QRectF &srcRect) const; private: - mutable QGLSLProgram m_program; - uint m_colorUniform; + mutable QGLShaderProgram m_program; + int m_colorUniform; }; class QGLPixmapConvolutionFilter: public QGLPixmapFilter @@ -206,11 +87,11 @@ protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; private: - QString generateConvolutionShader() const; + QByteArray generateConvolutionShader() const; - mutable QGLSLProgram *m_program; - mutable uint m_scaleUniform; - mutable uint m_matrixUniform; + mutable QGLShaderProgram *m_program; + mutable int m_scaleUniform; + mutable int m_matrixUniform; mutable int m_kernelWidth; mutable int m_kernelHeight; @@ -298,10 +179,12 @@ static const char *qt_gl_colorize_filter = "}"; QGLPixmapColorizeFilter::QGLPixmapColorizeFilter() - : m_program(QLatin1String(qt_gl_colorize_filter)) { - m_program.setUniform(m_program.getUniformLocation(QLatin1String("texture")), 0); // GL_TEXTURE_0 - m_colorUniform = m_program.getUniformLocation(QLatin1String("color")); + m_program.addShader(QGLShader::FragmentShader, qt_gl_colorize_filter); + m_program.link(); + m_program.enable(); + m_program.setUniformValue(m_program.uniformLocation("texture"), 0); // GL_TEXTURE_0 + m_colorUniform = m_program.uniformLocation("color"); } bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const @@ -309,10 +192,10 @@ bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QP bindTexture(src); QColor col = color(); - m_program.setUniform(m_colorUniform, col.redF(), col.greenF(), col.blueF()); + m_program.enable(); + m_program.setUniformValue(m_colorUniform, col.redF(), col.greenF(), col.blueF()); QRectF target = (srcRect.isNull() ? QRectF(src.rect()) : srcRect).translated(pos); - m_program.enable(); qgl_drawTexture(target, src.width(), src.height(), srcRect); m_program.disable(); @@ -320,7 +203,7 @@ bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QP } // generates convolution filter code for arbitrary sized kernel -QString QGLPixmapConvolutionFilter::generateConvolutionShader() const { +QByteArray QGLPixmapConvolutionFilter::generateConvolutionShader() const { QByteArray code; code.append("uniform sampler2D texture;\n"); code.append("uniform vec2 inv_texture_size;\n"); @@ -356,7 +239,7 @@ QString QGLPixmapConvolutionFilter::generateConvolutionShader() const { code.append(" }\n"); code.append(" gl_FragColor = sum;\n"); code.append("}"); - return QLatin1String(code); + return code; } QGLPixmapConvolutionFilter::QGLPixmapConvolutionFilter() @@ -388,10 +271,12 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const m_kernelWidth = columns(); m_kernelHeight = rows(); - QString code = generateConvolutionShader(); - m_program = new QGLSLProgram(code); - m_scaleUniform = m_program->getUniformLocation(QLatin1String("inv_texture_size")); - m_matrixUniform = m_program->getUniformLocation(QLatin1String("matrix")); + QByteArray code = generateConvolutionShader(); + m_program = new QGLShaderProgram(); + m_program->addShader(QGLShader::FragmentShader, code); + m_program->link(); + m_scaleUniform = m_program->uniformLocation("inv_texture_size"); + m_matrixUniform = m_program->uniformLocation("matrix"); } const qreal *kernel = convolutionKernel(); @@ -401,10 +286,10 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const const qreal iw = 1.0 / src.width(); const qreal ih = 1.0 / src.height(); - m_program->setUniform(m_scaleUniform, iw, ih); - m_program->setUniform(m_matrixUniform, m_kernelWidth * m_kernelHeight, conv); - m_program->enable(); + m_program->setUniformValue(m_scaleUniform, iw, ih); + m_program->setUniformValueArray(m_matrixUniform, conv, m_kernelWidth * m_kernelHeight, 1); + qgl_drawTexture(target, src.width(), src.height(), boundingRectFor(srcRect)); m_program->disable(); return true; diff --git a/src/opengl/qglpixmapfilter_p.h b/src/opengl/qglpixmapfilter_p.h index dc2eea6..d6742fc 100644 --- a/src/opengl/qglpixmapfilter_p.h +++ b/src/opengl/qglpixmapfilter_p.h @@ -87,35 +87,6 @@ public: } }; -class Q_OPENGL_EXPORT QGLSLProgram -{ -public: - QGLSLProgram(const QString &src); - ~QGLSLProgram(); - - bool success() const; - - void enable(); - void disable(); - - int getUniformLocation(const QString &name); - - void setUniform(int uniform, int value); - void setUniform(int uniform, qreal value); - void setUniform(int uniform, qreal v1, qreal v2); - void setUniform(int uniform, qreal v1, qreal v2, qreal v3); - void setUniform(int uniform, qreal v1, qreal v2, qreal v3, qreal v4); - void setUniform(int uniform, int count, float *v); - -private: - GLuint m_shader; - GLuint m_program; - - GLint m_valid; - - const QGLContext *ctx; -}; - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp new file mode 100644 index 0000000..934b5a5 --- /dev/null +++ b/src/opengl/qglshaderprogram.cpp @@ -0,0 +1,2828 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglshaderprogram.h" +#include "qglextensions_p.h" +#include "qgl_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_OPENGL_ES_1_CL) + +/*! + \class QGLShaderProgram + \brief The QGLShaderProgram class allows OpenGL shader programs to be linked and used. + \since 4.6 + + \section1 Introduction + + This class supports shader programs written in the OpenGL Shading + Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES). + + QGLShader and QGLShaderProgram shelter the programmer from the details of + compiling and linking vertex and fragment shaders. + + The following example creates a vertex shader program using the + supplied source \c{code}. Once compiled and linked, the shader + program is activated in the current QGLContext by calling + QGLShaderProgram::enable(): + + \code + QGLShader shader(QGLShader::VertexShader); + shader.setSourceCode(code); + + QGLShaderProgram program(context); + program.addShader(shader); + program.link(); + + program.enable(); + \endcode + + \section1 Writing portable shaders + + Shader programs can be difficult to reuse across OpenGL implementations + because of varying levels of support for standard vertex attributes and + uniform variables. In particular, GLSL/ES lacks all of the + standard variables that are present on desktop OpenGL systems: + \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL + lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}. + + The QGLShaderProgram class makes the process of writing portable shaders + easier by prefixing all shader programs with the following lines on + desktop OpenGL: + + \code + #define highp + #define mediump + #define lowp + \endcode + + This makes it possible to run most GLSL/ES shader programs + on desktop systems. The programmer should restrict themselves + to just features that are present in GLSL/ES, and avoid + standard variable names that only work on the desktop. + + \section1 Simple shader example + + \code + program.addShader(QGLShader::VertexShader, + "attribute highp vec4 vertex;\n" + "attribute mediump mat4 matrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = matrix * vertex;\n" + "}"); + program.addShader(QGLShader::FragmentShader, + "uniform mediump vec4 color;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = color;\n" + "}"); + program.link(); + program.enable(); + + int vertexLocation = program.attributeLocation("vertex"); + int matrixLocation = program.attributeLocation("matrix"); + int colorLocation = program.uniformLocation("color"); + \endcode + + With the above shader program active, we can draw a green triangle + as follows: + + \code + static GLfloat const triangleVertices[] = { + 60.0f, 10.0f, 0.0f, + 110.0f, 110.0f, 0.0f, + 10.0f, 110.0f, 0.0f + }; + + QColor color(0, 255, 0, 255); + + QMatrix4x4 pmvMatrix; + pmvMatrix.ortho(rect()); + + program.setAttributeArray(vertexLocation, triangleVertices, 3); + program.setUniformValue(matrixLocation, pmvMatrix); + program.setUniformValue(colorLocation, color); + + glDrawArrays(GL_TRIANGLES, 0, 3); + \endcode + + \section1 Partial shaders + + Desktop GLSL can attach an arbitrary number of vertex and fragment + shaders to a shader program. Embedded GLSL/ES on the other hand + supports only a single shader of each type on a shader program. + + Multiple shaders of the same type can be useful when large libraries + of shaders are needed. Common functions can be factored out into + library shaders that can be reused in multiple shader programs. + + To support this use of shaders, the application programmer can + create shaders with the QGLShader::PartialVertexShader and + QGLShader::PartialFragmentShader types. These types direct + QGLShader and QGLShaderProgram to delay shader compilation until + link time. + + When link() is called, the sources for the partial shaders are + concatenated, and a single vertex or fragment shader is compiled + and linked into the shader program. + + It is more efficient to use the QGLShader::VertexShader and + QGLShader::FragmentShader when there is only one shader of that + type in the program. + + \sa QGLShader +*/ + +/*! + \class QGLShader + \brief The QGLShader class allows OpenGL shaders to be compiled. + \since 4.6 + + This class supports shaders written in the OpenGL Shading Language (GLSL) + and in the OpenGL/ES Shading Language (GLSL/ES). + + QGLShader and QGLShaderProgram shelter the programmer from the details of + compiling and linking vertex and fragment shaders. + + \sa QGLShaderProgram +*/ + +/*! + \enum QGLShader::ShaderType + This enum specifies the type of QGLShader that is being created. + + \value VertexShader Vertex shader written in the OpenGL Shading Language (GLSL). + \value FragmentShader Fragment shader written in the OpenGL Shading Language (GLSL). + \value PartialVertexShader Partial vertex shader that will be concatenated with all other partial vertex shaders at link time. + \value PartialFragmentShader Partial fragment shader that will be concatenated with all other partial fragment shaders at link time. +*/ + +#ifndef GL_FRAGMENT_SHADER +#define GL_FRAGMENT_SHADER 0x8B30 +#endif +#ifndef GL_VERTEX_SHADER +#define GL_VERTEX_SHADER 0x8B31 +#endif +#ifndef GL_COMPILE_STATUS +#define GL_COMPILE_STATUS 0x8B81 +#endif +#ifndef GL_LINK_STATUS +#define GL_LINK_STATUS 0x8B82 +#endif +#ifndef GL_INFO_LOG_LENGTH +#define GL_INFO_LOG_LENGTH 0x8B84 +#endif +#ifndef GL_ACTIVE_UNIFORMS +#define GL_ACTIVE_UNIFORMS 0x8B86 +#endif +#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#endif +#ifndef GL_ACTIVE_ATTRIBUTES +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#endif +#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#endif +#ifndef GL_CURRENT_VERTEX_ATTRIB +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#endif +#ifndef GL_SHADER_SOURCE_LENGTH +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#endif +#ifndef GL_SHADER_BINARY_FORMATS +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#endif +#ifndef GL_NUM_SHADER_BINARY_FORMATS +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#endif + +class QGLShaderPrivate +{ +public: + QGLShaderPrivate(QGLShader::ShaderType type, const QGLContext *ctx) + { + context = ctx; + shader = 0; + shaderType = type; + compiled = false; + isPartial = (type == QGLShader::PartialVertexShader || + type == QGLShader::PartialFragmentShader); + hasPartialSource = false; + } + + const QGLContext *context; + GLuint shader; + QGLShader::ShaderType shaderType; + bool compiled; + bool isPartial; + bool hasPartialSource; + QString errors; + QByteArray partialSource; + + bool create(); + bool compile(); +}; + +#define ctx context + +bool QGLShaderPrivate::create() +{ + if (isPartial) + return true; + if (!context) + context = QGLContext::currentContext(); + if (!context) + return false; + if (qt_resolve_glsl_extensions(const_cast(context))) { + if (shaderType == QGLShader::VertexShader) + shader = glCreateShader(GL_VERTEX_SHADER); + else + shader = glCreateShader(GL_FRAGMENT_SHADER); + if (!shader) { + qWarning() << "QGLShader: could not create shader"; + return false; + } + return true; + } else { + return false; + } +} + +bool QGLShaderPrivate::compile() +{ + // Partial shaders are compiled during QGLShaderProgram::link(). + if (isPartial && hasPartialSource) { + compiled = true; + return true; + } + if (!shader) + return false; + glCompileShader(shader); + GLint value = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &value); + compiled = (value != 0); + value = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &value); + if (!compiled && value > 1) { + char *log = new char [value]; + GLint len; + glGetShaderInfoLog(shader, value, &len, log); + errors = QString::fromLatin1(log); + qWarning() << "QGLShader::compile:" << errors; + delete [] log; + } + return compiled; +} + +#undef ctx +#define ctx d->context + +/*! + Constructs a new QGLShader object of the specified \a type + and attaches it to \a parent. If shader programs are not supported, + then isValid() will return false. + + This constructor is normally followed by a call to setSourceCode() + or setSourceCodeFile(). + + The shader will be associated with the current QGLContext. + + \sa setSourceCode(), setSourceCodeFile(), isValid() +*/ +QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, QGLContext::currentContext()); + d->create(); +} + +/*! + Constructs a new QGLShader object from the source code in \a fileName + and attaches it to \a parent. If the filename ends in \c{.fsh}, + it is assumed to be a fragment shader, otherwise it is assumed to + be a vertex shader (normally the extension is \c{.vsh} for vertex shaders). + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with the current QGLContext. + + \sa isValid() +*/ +QGLShader::QGLShader(const QString& fileName, QObject *parent) + : QObject(parent) +{ + if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive)) + d = new QGLShaderPrivate(QGLShader::FragmentShader, QGLContext::currentContext()); + else + d = new QGLShaderPrivate(QGLShader::VertexShader, QGLContext::currentContext()); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Constructs a new QGLShader object of the specified \a type from the + source code in \a fileName and attaches it to \a parent. + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with the current QGLContext. + + \sa isValid() +*/ +QGLShader::QGLShader + (const QString& fileName, QGLShader::ShaderType type, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, QGLContext::currentContext()); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Constructs a new QGLShader object of the specified \a type + and attaches it to \a parent. If shader programs are not supported, + then isValid() will return false. + + This constructor is normally followed by a call to setSourceCode() + or setSourceCodeFile(). + + The shader will be associated with \a context. + + \sa setSourceCode(), setSourceCodeFile(), isValid() +*/ +QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, context); + d->create(); +} + +/*! + Constructs a new QGLShader object from the source code in \a fileName + and attaches it to \a parent. If the filename ends in \c{.fsh}, + it is assumed to be a fragment shader, otherwise it is assumed to + be a vertex shader (normally the extension is \c{.vsh} for vertex shaders). + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with \a context. + + \sa isValid() +*/ +QGLShader::QGLShader(const QString& fileName, const QGLContext *context, QObject *parent) + : QObject(parent) +{ + if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive)) + d = new QGLShaderPrivate(QGLShader::FragmentShader, context); + else + d = new QGLShaderPrivate(QGLShader::VertexShader, context); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Constructs a new QGLShader object of the specified \a type from the + source code in \a fileName and attaches it to \a parent. + If the shader could not be loaded, then isValid() will return false. + + The shader will be associated with \a context. + + \sa isValid() +*/ +QGLShader::QGLShader + (const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderPrivate(type, context); + if (d->create() && !setSourceCodeFile(fileName)) { + if (d->shader) + glDeleteShader(d->shader); + d->shader = 0; + } +} + +/*! + Deletes this shader. If the shader has been attached to a + QGLShaderProgram object, then the actual shader will stay around + until the QGLShaderProgram is destroyed. +*/ +QGLShader::~QGLShader() +{ + if (d->shader) + glDeleteShader(d->shader); + delete d; +} + +/*! + Returns true if this shader is valid. Shaders become invalid + when they are destroyed and no longer attached to a QGLShaderProgram. +*/ +bool QGLShader::isValid() const +{ + if (d->isPartial && d->hasPartialSource) + return true; + if (!d->shader) + return false; +#if defined(QT_OPENGL_ES_2) + return glIsShader(d->shader); +#else + // glIsShader() may not exist on some systems. + return (!glIsShader || glIsShader(d->shader)); +#endif +} + +/*! + Returns the type of this shader. +*/ +QGLShader::ShaderType QGLShader::shaderType() const +{ + return d->shaderType; +} + +// The precision qualifiers are useful on OpenGL/ES systems, +// but usually not present on desktop systems. Define the +// keywords to empty strings on desktop systems. +#ifndef QT_OPENGL_ES +#define QGL_DEFINE_QUALIFIERS 1 +static const char qualifierDefines[] = + "#define lowp\n" + "#define mediump\n" + "#define highp\n"; +#endif + +/*! + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCode(const char *source) +{ + if (d->isPartial) { + d->partialSource = QByteArray(source); + d->hasPartialSource = true; + return d->compile(); + } else if (d->shader) { + QVarLengthArray src; +#ifdef QGL_DEFINE_QUALIFIERS + src.append(qualifierDefines); +#endif + src.append(source); + glShaderSource(d->shader, src.size(), src.data(), 0); + return d->compile(); + } else { + return false; + } +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCode(const QByteArray& source) +{ + return setSourceCode(source.constData()); +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCode(const QString& source) +{ + return setSourceCode(source.toLatin1().constData()); +} + +/*! + Sets the source code for this shader to the contents of \a fileName + and compiles it. Returns true if the file could be opened and the + source compiled, false otherwise. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + then this function will always return true, even if the source code + is invalid. Partial shaders are compiled when QGLShaderProgram::link() + is called. +*/ +bool QGLShader::setSourceCodeFile(const QString& fileName) +{ + if (!d->shader) + return false; + + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + qWarning() << "QGLShader: Unable to open file" << fileName; + return false; + } + + QByteArray contents = file.readAll(); + return setSourceCode(contents.constData()); +} + +/*! + Sets the binary code for this shader to the \a length bytes from + the array \a binary. The \a format specifies how the binary data + should be interpreted by the OpenGL engine. Returns true if the + binary was set on the shader; false otherwise. + + This function cannot be used with PartialVertexShader or + PartialFragmentShader. + + \sa shaderBinaryFormats() +*/ +bool QGLShader::setBinaryCode(GLenum format, const void *binary, int length) +{ +#if !defined(QT_OPENGL_ES_2) + if (!glShaderBinary) + return false; +#endif + if (d->isPartial || !d->shader) + return false; + glGetError(); // Clear error state. + glShaderBinary(1, &(d->shader), format, binary, length); + return (glGetError() == GL_NO_ERROR); +} + +/*! + Sets the binary code for this shader to the \a length bytes from + the array \a binary. The \a format specifies how the binary data + should be interpreted by the OpenGL engine. Returns true if the + binary was set on the shader; false otherwise. + + The \a otherShader will also have binary code set on it. This is + for the case where \a binary contains both vertex and fragment + shader code. + + This function cannot be used with PartialVertexShader or + PartialFragmentShader. + + \sa shaderBinaryFormats() +*/ +bool QGLShader::setBinaryCode + (QGLShader& otherShader, GLenum format, const void *binary, int length) +{ +#if !defined(QT_OPENGL_ES_2) + if (!glShaderBinary) + return false; +#endif + if (d->isPartial || !d->shader) + return false; + if (otherShader.d->isPartial || !otherShader.d->shader) + return false; + glGetError(); // Clear error state. + GLuint shaders[2]; + shaders[0] = d->shader; + shaders[1] = otherShader.d->shader; + glShaderBinary(2, shaders, format, binary, length); + return (glGetError() == GL_NO_ERROR); +} + +/*! + Returns a list of all binary formats that are supported by + setBinaryCode() on this system. + + \sa setBinaryCode() +*/ +QList QGLShader::shaderBinaryFormats() +{ + GLint num; + QList list; + glGetError(); // Clear error state. + glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &num); + if (glGetError() != GL_NO_ERROR || num <= 0) + return list; + QVarLengthArray formats(num); + glGetIntegerv(GL_SHADER_BINARY_FORMATS, formats.data()); + for (GLint i = 0; i < num; ++i) + list += (GLenum)(formats[i]); + return list; +} + +/*! + Returns the source code for this shader. + + \sa setSourceCode() +*/ +QByteArray QGLShader::sourceCode() const +{ + if (d->isPartial) + return d->partialSource; + if (!d->shader) + return QByteArray(); + GLint size = 0; + glGetShaderiv(d->shader, GL_SHADER_SOURCE_LENGTH, &size); + if (size <= 0) + return QByteArray(); + GLint len = 0; + char *source = new char [size]; + glGetShaderSource(d->shader, size, &len, source); + QByteArray src(source); + delete [] source; + return src; +} + +/*! + Returns true if this shader has been compiled; false otherwise. + + \sa setSourceCode() +*/ +bool QGLShader::isCompiled() const +{ + return d->compiled; +} + +/*! + Returns the errors that occurred during the last compile. + + \sa setSourceCode() +*/ +QString QGLShader::errors() const +{ + return d->errors; +} + +/*! + Returns the OpenGL identifier associated with this shader. + + If shaderType() is PartialVertexShader or PartialFragmentShader, + this function will always return zero. Partial shaders are + created and compiled when QGLShaderProgram::link() is called. + + \sa QGLShaderProgram::programId() +*/ +GLuint QGLShader::shaderId() const +{ + return d->shader; +} + +#undef ctx +#define ctx context + +class QGLShaderProgramPrivate +{ +public: + QGLShaderProgramPrivate(const QGLContext *ctx) + { + context = ctx; + program = 0; + linked = false; + inited = false; + hasPartialShaders = false; + vertexShader = 0; + fragmentShader = 0; + } + ~QGLShaderProgramPrivate() + { + if (program) + glDeleteProgram(program); + } + + const QGLContext *context; + GLuint program; + bool linked; + bool inited; + bool hasPartialShaders; + QString errors; + QList shaders; + QList anonShaders; + QGLShader *vertexShader; + QGLShader *fragmentShader; +}; + +#undef ctx +#define ctx d->context + +/*! + Constructs a new shader program and attaches it to \a parent. + The program will be invalid until addShader() is called. + + The shader program will be associated with the current QGLContext. + + \sa isValid(), addShader() +*/ +QGLShaderProgram::QGLShaderProgram(QObject *parent) + : QObject(parent) +{ + d = new QGLShaderProgramPrivate(QGLContext::currentContext()); +} + +/*! + Constructs a new shader program and attaches it to \a parent. + The program will be invalid until addShader() is called. + + The shader program will be associated with \a context. + + \sa isValid(), addShader() +*/ +QGLShaderProgram::QGLShaderProgram(const QGLContext *context, QObject *parent) + : QObject(parent) +{ + d = new QGLShaderProgramPrivate(context); +} + +/*! + Deletes this shader program. +*/ +QGLShaderProgram::~QGLShaderProgram() +{ + delete d; +} + +bool QGLShaderProgram::init() +{ + if (d->program || d->inited) + return true; + d->inited = true; + if (!d->context) + d->context = QGLContext::currentContext(); + if (!d->context) + return false; + if (qt_resolve_glsl_extensions(const_cast(d->context))) { + d->program = glCreateProgram(); + if (!(d->program)) { + qWarning() << "QGLShaderProgram: could not create shader program"; + return false; + } + return true; + } else { + qWarning() << "QGLShaderProgram: shader programs are not supported"; + return false; + } +} + +/*! + Returns true if this shader program object is valid, false otherwise. +*/ +bool QGLShaderProgram::isValid() const +{ + if (!d->program) + return false; +#if defined(QT_OPENGL_ES_2) + return glIsProgram(d->program); +#else + // glIsProgram() may not exist on some systems. + return (!glIsProgram || glIsProgram(d->program)); +#endif +} + +/*! + Adds a compiled \a shader to this shader program. Returns true + if the shader could be added, or false otherwise. + + Ownership of the \a shader object remains with the caller. + It will not be deleted when this QGLShaderProgram instance + is deleted. This allows the caller to add the same shader + to multiple shader programs. + + \sa removeShader(), link(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader *shader) +{ + if (!init()) + return false; + if (d->shaders.contains(shader)) + return true; // Already added to this shader program. + if (d->program && shader && shader->d->shader) { + if (!shader->d->compiled) + return false; + if (!shader->d->isPartial) + glAttachShader(d->program, shader->d->shader); + else + d->hasPartialShaders = true; + d->linked = false; // Program needs to be relinked. + d->shaders.append(shader); + return true; + } else { + return false; + } +} + +/*! + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + will be made available via errors(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QGLShader first. + + \sa removeShader(), link(), errors(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const char *source) +{ + if (!init()) + return false; + QGLShader *shader = new QGLShader(type, this); + if (!shader->setSourceCode(source)) { + d->errors = shader->errors(); + delete shader; + return false; + } + d->anonShaders.append(shader); + return addShader(shader); +} + +/*! + \overload + + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + will be made available via errors(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QGLShader first. + + \sa removeShader(), link(), errors(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QByteArray& source) +{ + return addShader(type, source.constData()); +} + +/*! + \overload + + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + will be made available via errors(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QGLShader first. + + \sa removeShader(), link(), errors(), removeAllShaders() +*/ +bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QString& source) +{ + return addShader(type, source.toLatin1().constData()); +} + +/*! + Removes \a shader from this shader program. The object is not deleted. + + \sa addShader(), link(), removeAllShaders() +*/ +void QGLShaderProgram::removeShader(QGLShader *shader) +{ + if (d->program && shader && shader->d->shader) { + glDetachShader(d->program, shader->d->shader); + d->linked = false; // Program needs to be relinked. + } + d->shaders.removeAll(shader); + d->anonShaders.removeAll(shader); +} + +/*! + Returns a list of all shaders that have been added to this shader + program using addShader(). + + \sa addShader(), removeShader() +*/ +QList QGLShaderProgram::shaders() const +{ + return d->shaders; +} + +/*! + Removes all of the shaders that were added to this program previously. + The QGLShader objects for the shaders will not be deleted if they + were constructed externally. QGLShader objects that are constructed + internally by QGLShaderProgram will be deleted. + + \sa addShader(), removeShader() +*/ +void QGLShaderProgram::removeAllShaders() +{ + foreach (QGLShader *shader, d->shaders) { + if (d->program && shader && shader->d->shader) + glDetachShader(d->program, shader->d->shader); + } + foreach (QGLShader *shader, d->anonShaders) { + // Delete shader objects that were created anonymously. + delete shader; + } + d->shaders.clear(); + d->anonShaders.clear(); + d->linked = false; // Program needs to be relinked. +} + +#if defined(QT_OPENGL_ES_2) + +#ifndef GL_PROGRAM_BINARY_LENGTH_OES +#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#endif +#ifndef GL_NUM_PROGRAM_BINARY_FORMATS_OES +#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE +#endif +#ifndef GL_PROGRAM_BINARY_FORMATS_OES +#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF +#endif + +#endif + +/*! + Returns the program binary associated with this shader program. + The numeric identifier of the program binary format is returned + in \a format. The \c OES_get_program_binary extension will need + to be supported by the system for binary retrieval to succeed. + + Returns an empty QByteArray if the program binary cannot be + retrieved on this system, or the shader program has not yet + been linked. + + The returned binary can be supplied to setProgramBinary() on the + same machine at some future point to reload the program. It contains + the compiled code of all of the shaders that were attached to the + program at the time programBinary() is called. + + \sa setProgramBinary(), programBinaryFormats() +*/ +QByteArray QGLShaderProgram::programBinary(int *format) const +{ +#if defined(QT_OPENGL_ES_2) + if (!isLinked()) + return QByteArray(); + + // Get the length of the binary data, bailing out if there is none. + GLint length = 0; + glGetProgramiv(d->program, GL_PROGRAM_BINARY_LENGTH_OES, &length); + if (length <= 0) + return QByteArray(); + + // Retrieve the binary data. + QByteArray binary(length, 0); + GLenum binaryFormat; + glGetProgramBinaryOES(d->program, length, 0, &binaryFormat, binary.data()); + if (format) + *format = (int)binaryFormat; + return binary; +#else + Q_UNUSED(format); + return QByteArray(); +#endif +} + +/*! + Sets the \a binary for this shader program according to \a format. + Returns true if the binary was set, or false if the binary format + is not supported or this system does not support program binaries. + The program will be linked if the load succeeds. + + \sa programBinary(), programBinaryFormats(), isLinked() +*/ +bool QGLShaderProgram::setProgramBinary(int format, const QByteArray& binary) +{ +#if defined(QT_OPENGL_ES_2) + // Load the binary and check that it was linked correctly. + glProgramBinaryOES(d->program, (GLenum)format, + binary.constData(), binary.size()); + GLint value = 0; + glGetProgramiv(d->program, GL_LINK_STATUS, &value); + d->linked = (value != 0); + value = 0; + glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value); + d->errors = QString(); + if (value > 1) { + char *log = new char [value]; + GLint len; + glGetProgramInfoLog(d->program, value, &len, log); + d->errors = QString::fromLatin1(log); + qWarning() << "QGLShaderProgram::setProgramBinary:" << d->errors; + delete [] log; + } + return d->linked; +#else + Q_UNUSED(format); + Q_UNUSED(binary); + return false; +#endif +} + +/*! + Returns the list of program binary formats that are accepted by + this system for use with setProgramBinary(). + + \sa programBinary, setProgramBinary() +*/ +QList QGLShaderProgram::programBinaryFormats() +{ +#if defined(QT_OPENGL_ES_2) + GLint count = 0; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &count); + if (count <= 0) + return QList(); + QVector list; + list.resize(count); + glGetIntegerv(GL_PROGRAM_BINARY_FORMATS_OES, list.data()); + return list.toList(); +#else + return QList(); +#endif +} + +/*! + Links together the shaders that were added to this program with + addShader(). Returns true if the link was successful or + false otherwise. If the link failed, the error messages can + be retrieved with errors(). + + Subclasses can override this function to initialize attributes + and uniform variables for use in specific shader programs. + + If the shader program was already linked, calling this + function again will force it to be re-linked. + + \sa addShader(), errors() +*/ +bool QGLShaderProgram::link() +{ + if (!d->program) + return false; + if (d->hasPartialShaders) { + // Compile the partial vertex and fragment shaders. + QByteArray vertexSource; + QByteArray fragmentSource; + foreach (QGLShader *shader, d->shaders) { + if (shader->shaderType() == QGLShader::PartialVertexShader) + vertexSource += shader->sourceCode(); + else if (shader->shaderType() == QGLShader::PartialFragmentShader) + fragmentSource += shader->sourceCode(); + } + if (vertexSource.isEmpty()) { + if (d->vertexShader) { + glDetachShader(d->program, d->vertexShader->d->shader); + delete d->vertexShader; + d->vertexShader = 0; + } + } else { + if (!d->vertexShader) { + d->vertexShader = + new QGLShader(QGLShader::VertexShader, this); + } + if (!d->vertexShader->setSourceCode(vertexSource)) { + d->errors = d->vertexShader->errors(); + return false; + } + glAttachShader(d->program, d->vertexShader->d->shader); + } + if (fragmentSource.isEmpty()) { + if (d->fragmentShader) { + glDetachShader(d->program, d->fragmentShader->d->shader); + delete d->fragmentShader; + d->fragmentShader = 0; + } + } else { + if (!d->fragmentShader) { + d->fragmentShader = + new QGLShader(QGLShader::FragmentShader, this); + } + if (!d->fragmentShader->setSourceCode(fragmentSource)) { + d->errors = d->fragmentShader->errors(); + return false; + } + glAttachShader(d->program, d->fragmentShader->d->shader); + } + } + glLinkProgram(d->program); + GLint value = 0; + glGetProgramiv(d->program, GL_LINK_STATUS, &value); + d->linked = (value != 0); + value = 0; + glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value); + d->errors = QString(); + if (value > 1) { + char *log = new char [value]; + GLint len; + glGetProgramInfoLog(d->program, value, &len, log); + d->errors = QString::fromLatin1(log); + qWarning() << "QGLShaderProgram::link:" << d->errors; + delete [] log; + } + return d->linked; +} + +/*! + Returns true if this shader program has been linked; false otherwise. + + \sa link() +*/ +bool QGLShaderProgram::isLinked() const +{ + return d->linked; +} + +/*! + Returns the errors that occurred during the last link() + or addShader() with explicitly specified source code. + + \sa link() +*/ +QString QGLShaderProgram::errors() const +{ + return d->errors; +} + +/*! + Enable use of this shader program in the currently active QGLContext. + Returns true if the program was successfully enabled; false + otherwise. If the shader program has not yet been linked, + or it needs to be re-linked, this function will call link(). + + \sa link(), disable() +*/ +bool QGLShaderProgram::enable() +{ + if (!d->program) + return false; + if (!d->linked && !link()) + return false; + glUseProgram(d->program); + return true; +} + +/*! + Disables this shader program in the currently active QGLContext. + This is equivalent to calling \c{glUseProgram(0)}. + + \sa enable() +*/ +void QGLShaderProgram::disable() +{ +#if defined(QT_OPENGL_ES_2) + glUseProgram(0); +#else + if (glUseProgram) + glUseProgram(0); +#endif +} + +/*! + Returns the OpenGL identifier associated with this shader program. + + \sa QGLShader::shaderId() +*/ +GLuint QGLShaderProgram::programId() const +{ + return d->program; +} + +/*! + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + \sa attributeLocation() +*/ +void QGLShaderProgram::bindAttributeLocation(const char *name, int location) +{ + glBindAttribLocation(d->program, location, name); +} + +/*! + \overload + + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + \sa attributeLocation() +*/ +void QGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location) +{ + glBindAttribLocation(d->program, location, name.constData()); +} + +/*! + \overload + + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + \sa attributeLocation() +*/ +void QGLShaderProgram::bindAttributeLocation(const QString& name, int location) +{ + glBindAttribLocation(d->program, location, name.toLatin1().constData()); +} + +/*! + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QGLShaderProgram::attributeLocation(const char *name) const +{ + if (d->linked) { + return glGetAttribLocation(d->program, name); + } else { + qWarning() << "QGLShaderProgram::attributeLocation(" << name + << "): shader program is not linked"; + return -1; + } +} + +/*! + \overload + + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QGLShaderProgram::attributeLocation(const QByteArray& name) const +{ + return attributeLocation(name.constData()); +} + +/*! + \overload + + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QGLShaderProgram::attributeLocation(const QString& name) const +{ + return attributeLocation(name.toLatin1().constData()); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, GLfloat value) +{ + if (location != -1) + glVertexAttrib1fv(location, &value); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, GLfloat value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to + the 2D vector (\a x, \a y). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y) +{ + if (location != -1) { + GLfloat values[2] = {x, y}; + glVertexAttrib2fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 2D vector (\a x, \a y). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y) +{ + setAttributeValue(attributeLocation(name), x, y); +} + +/*! + Sets the attribute at \a location in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (int location, GLfloat x, GLfloat y, GLfloat z) +{ + if (location != -1) { + GLfloat values[3] = {x, y, z}; + glVertexAttrib3fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (const char *name, GLfloat x, GLfloat y, GLfloat z) +{ + setAttributeValue(attributeLocation(name), x, y, z); +} + +/*! + Sets the attribute at \a location in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + if (location != -1) { + GLfloat values[4] = {x, y, z, w}; + glVertexAttrib4fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + setAttributeValue(attributeLocation(name), x, y, z, w); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QVector2D& value) +{ + if (location != -1) + glVertexAttrib2fv(location, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QVector2D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QVector3D& value) +{ + if (location != -1) + glVertexAttrib3fv(location, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QVector3D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QVector4D& value) +{ + if (location != -1) + glVertexAttrib4fv(location, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QVector4D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(int location, const QColor& value) +{ + if (location != -1) { + GLfloat values[4] = {value.redF(), value.greenF(), value.blueF(), value.alphaF()}; + glVertexAttrib4fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue(const char *name, const QColor& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to the + contents of \a values, which contains \a columns elements, each + consisting of \a rows elements. The \a rows value should be + 1, 2, 3, or 4. This function is typically used to set matrix + values and column vectors. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (int location, const GLfloat *values, int columns, int rows) +{ + if (rows < 1 || rows > 4) { + qWarning() << "QGLShaderProgram::setAttributeValue: rows" << rows << "not supported"; + return; + } + if (location != -1) { + while (columns-- > 0) { + if (rows == 1) + glVertexAttrib1fv(location, values); + else if (rows == 2) + glVertexAttrib2fv(location, values); + else if (rows == 3) + glVertexAttrib3fv(location, values); + else + glVertexAttrib4fv(location, values); + values += rows; + ++location; + } + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to the + contents of \a values, which contains \a columns elements, each + consisting of \a rows elements. The \a rows value should be + 1, 2, 3, or 4. This function is typically used to set matrix + values and column vectors. + + \sa setUniformValue() +*/ +void QGLShaderProgram::setAttributeValue + (const char *name, const GLfloat *values, int columns, int rows) +{ + setAttributeValue(attributeLocation(name), values, columns, rows); +} + +/*! + Sets an array of vertex \a values on the attribute at \a location + in this shader program. The \a size indicates the number of + components per vertex (1, 2, 3, or 4), and the \a stride indicates + the number of bytes between vertices. A default \a stride value + of zero indicates that the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const GLfloat *values, int size, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + Sets an array of 2D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const QVector2D *values, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + Sets an array of 3D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const QVector3D *values, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + Sets an array of 4D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (int location, const QVector4D *values, int stride) +{ + if (location != -1) { + glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, + stride, values); + glEnableVertexAttribArray(location); + } +} + +/*! + \overload + + Sets an array of vertex \a values on the attribute called \a name + in this shader program. The \a size indicates the number of + components per vertex (1, 2, 3, or 4), and the \a stride indicates + the number of bytes between vertices. A default \a stride value + of zero indicates that the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const GLfloat *values, int size, int stride) +{ + setAttributeArray(attributeLocation(name), values, size, stride); +} + +/*! + \overload + + Sets an array of 2D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const QVector2D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + \overload + + Sets an array of 3D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const QVector3D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + \overload + + Sets an array of 4D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + \sa setAttributeValue(), setUniformValue(), disableAttributeArray() +*/ +void QGLShaderProgram::setAttributeArray + (const char *name, const QVector4D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + Disables the vertex array at \a location in this shader program + that was enabled by a previous call to setAttributeArray(). + + \sa setAttributeArray(), setAttributeValue(), setUniformValue() +*/ +void QGLShaderProgram::disableAttributeArray(int location) +{ + if (location != -1) + glDisableVertexAttribArray(location); +} + +/*! + \overload + + Disables the vertex array called \a name in this shader program + that was enabled by a previous call to setAttributeArray(). + + \sa setAttributeArray(), setAttributeValue(), setUniformValue() +*/ +void QGLShaderProgram::disableAttributeArray(const char *name) +{ + disableAttributeArray(attributeLocation(name)); +} + +/*! + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QGLShaderProgram::uniformLocation(const char *name) const +{ + if (d->linked) { + return glGetUniformLocation(d->program, name); + } else { + qWarning() << "QGLShaderProgram::uniformLocation(" << name + << "): shader program is not linked"; + return -1; + } +} + +/*! + \overload + + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QGLShaderProgram::uniformLocation(const QByteArray& name) const +{ + return uniformLocation(name.constData()); +} + +/*! + \overload + + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QGLShaderProgram::uniformLocation(const QString& name) const +{ + return uniformLocation(name.toLatin1().constData()); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, GLfloat value) +{ + if (location != -1) + glUniform1fv(location, 1, &value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, GLfloat value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + This function must be used when setting sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, GLint value) +{ + if (location != -1) + glUniform1i(location, value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. This function must be used when setting sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, GLint value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 2D vector (\a x, \a y). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y) +{ + if (location != -1) { + GLfloat values[2] = {x, y}; + glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 2D vector (\a x, \a y). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y) +{ + setUniformValue(uniformLocation(name), x, y); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (int location, GLfloat x, GLfloat y, GLfloat z) +{ + if (location != -1) { + GLfloat values[3] = {x, y, z}; + glUniform3fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (const char *name, GLfloat x, GLfloat y, GLfloat z) +{ + setUniformValue(uniformLocation(name), x, y, z); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + if (location != -1) { + GLfloat values[4] = {x, y, z, w}; + glUniform4fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue + (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + setUniformValue(uniformLocation(name), x, y, z, w); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QVector2D& value) +{ + if (location != -1) + glUniform2fv(location, 1, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QVector2D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QVector3D& value) +{ + if (location != -1) + glUniform3fv(location, 1, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QVector3D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QVector4D& value) +{ + if (location != -1) + glUniform4fv(location, 1, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QVector4D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to + the red, green, blue, and alpha components of \a color. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QColor& color) +{ + if (location != -1) { + GLfloat values[4] = {color.redF(), color.greenF(), color.blueF(), color.alphaF()}; + glUniform4fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the red, green, blue, and alpha components of \a color. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QColor& color) +{ + setUniformValue(uniformLocation(name), color); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value) +{ + if (location != -1) + glUniformMatrix2fv(location, 1, GL_FALSE, value.data()); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix2x3fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix2x3fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform3fv(location, 2, value.data()); + } + } +#else + if (location != -1) + glUniform3fv(location, 2, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix2x4fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix2x4fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform4fv(location, 2, value.data()); + } + } +#else + if (location != -1) + glUniform4fv(location, 2, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix3x2fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix3x2fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform2fv(location, 3, value.data()); + } + } +#else + if (location != -1) + glUniform2fv(location, 3, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value) +{ + if (location != -1) + glUniformMatrix3fv(location, 1, GL_FALSE, value.data()); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix3x4fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix3x4fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform4fv(location, 3, value.data()); + } + } +#else + if (location != -1) + glUniform4fv(location, 3, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix4x2fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix4x2fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform2fv(location, 4, value.data()); + } + } +#else + if (location != -1) + glUniform2fv(location, 4, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value) +{ +#if !defined(QT_OPENGL_ES_2) + if (location != -1) { + if (glUniformMatrix4x3fv) { + // OpenGL 2.1+: pass the matrix directly. + glUniformMatrix4x3fv(location, 1, GL_FALSE, value.data()); + } else { + // OpenGL 2.0: pass the matrix columns as a vector. + glUniform3fv(location, 4, value.data()); + } + } +#else + if (location != -1) + glUniform3fv(location, 4, value.data()); +#endif +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value) +{ + if (location != -1) + glUniformMatrix4fv(location, 1, GL_FALSE, value.data()); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + \overload + + Sets the uniform variable at \a location in the current context + to a 4x4 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4]) +{ + if (location != -1) + glUniformMatrix4fv(location, 1, GL_FALSE, value[0]); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x4 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][4]) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to a + 3x3 transformation matrix \a value that is specified as a QTransform value. + + To set a QTransform value as a 4x4 matrix in a shader, use + \c{setUniformValue(location, QMatrix4x4(value))}. +*/ +void QGLShaderProgram::setUniformValue(int location, const QTransform& value) +{ + if (location != -1) { + GLfloat mat[3][3] = { + {value.m11(), value.m12(), value.m13()}, + {value.m21(), value.m22(), value.m23()}, + {value.m31(), value.m32(), value.m33()} + }; + glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to a + 3x3 transformation matrix \a value that is specified as a QTransform value. + + To set a QTransform value as a 4x4 matrix in a shader, use + \c{setUniformValue(name, QMatrix4x4(value))}. +*/ +void QGLShaderProgram::setUniformValue + (const char *name, const QTransform& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. This overload + must be used when setting an array of sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count) +{ + if (location != -1) + glUniform1iv(location, count, values); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. This overload + must be used when setting an array of sampler values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray + (const char *name, const GLint *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. Each element + has \a size components. The \a size must be 1, 2, 3, or 4. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int size) +{ + if (location != -1) { + if (size == 1) + glUniform1fv(location, count, values); + else if (size == 2) + glUniform2fv(location, count, values); + else if (size == 3) + glUniform3fv(location, count, values); + else if (size == 4) + glUniform4fv(location, count, values); + else + qWarning() << "QGLShaderProgram::setUniformValue: size" << size << "not supported"; + } +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. Each element + has \a size components. The \a size must be 1, 2, 3, or 4. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray + (const char *name, const GLfloat *values, int count, int size) +{ + setUniformValueArray(uniformLocation(name), values, count, size); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count) +{ + if (location != -1) + glUniform2fv(location, count, reinterpret_cast(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count) +{ + if (location != -1) + glUniform3fv(location, count, reinterpret_cast(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count) +{ + if (location != -1) + glUniform4fv(location, count, reinterpret_cast(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +// We may have to repack matrix arrays if the matrix types +// contain additional flag bits. Especially QMatrix4x4. +#define setUniformMatrixArray(func,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \ + func(location, count, GL_FALSE, values->constData()); \ + } else { \ + QVarLengthArray temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + qMemCopy(temp.data() + cols * rows * index, \ + values[index].constData(), cols * rows * sizeof(GLfloat)); \ + } \ + func(location, count, GL_FALSE, temp.constData()); \ + } +#if !defined(QT_OPENGL_ES_2) +#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \ + if (func) \ + func(location, count, GL_FALSE, values->constData()); \ + else \ + colfunc(location, cols * count, values->constData()); \ + } else { \ + QVarLengthArray temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + qMemCopy(temp.data() + cols * rows * index, \ + values[index].constData(), cols * rows * sizeof(GLfloat)); \ + } \ + if (func) \ + func(location, count, GL_FALSE, temp.constData()); \ + else \ + colfunc(location, count * cols, temp.constData()); \ + } +#else +#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \ + colfunc(location, cols * count, values->constData()); \ + } else { \ + QVarLengthArray temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + qMemCopy(temp.data() + cols * rows * index, \ + values[index].constData(), cols * rows * sizeof(GLfloat)); \ + } \ + colfunc(location, count * cols, temp.constData()); \ + } +#endif + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count) +{ + setUniformMatrixArray + (glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix2x3fv, glUniform3fv, location, values, count, + QMatrix2x3, 2, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix2x4fv, glUniform4fv, location, values, count, + QMatrix2x4, 2, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix3x2fv, glUniform2fv, location, values, count, + QMatrix3x2, 3, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count) +{ + setUniformMatrixArray + (glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix3x4fv, glUniform4fv, location, values, count, + QMatrix3x4, 3, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix4x2fv, glUniform2fv, location, values, count, + QMatrix4x2, 4, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count) +{ + setUniformGenericMatrixArray + (glUniformMatrix4x3fv, glUniform3fv, location, values, count, + QMatrix4x3, 4, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count) +{ + setUniformMatrixArray + (glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Returns true if shader programs written in the OpenGL Shading + Language (GLSL) are supported on this system; false otherwise. + + The \a context is used to resolve the GLSL extensions. + If \a context is null, then QGLContext::currentContext() is used. +*/ +bool QGLShaderProgram::hasShaderPrograms(const QGLContext *context) +{ +#if !defined(QT_OPENGL_ES_2) + if (!context) + context = QGLContext::currentContext(); + if (!context) + return false; + return qt_resolve_glsl_extensions(const_cast(context)); +#else + Q_UNUSED(context); + return true; +#endif +} + +#endif + +QT_END_NAMESPACE diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h new file mode 100644 index 0000000..ec6faaf --- /dev/null +++ b/src/opengl/qglshaderprogram.h @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGLSHADERPROGRAM_H +#define QGLSHADERPROGRAM_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + +#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_GL_FIXED_PREFERRED) + +class QGLShaderProgram; +class QGLShaderPrivate; + +class Q_OPENGL_EXPORT QGLShader : public QObject +{ + Q_OBJECT +public: + enum ShaderType + { + VertexShader, + FragmentShader, + PartialVertexShader, + PartialFragmentShader + }; + + explicit QGLShader(QGLShader::ShaderType type, QObject *parent = 0); + explicit QGLShader(const QString& fileName, QObject *parent = 0); + QGLShader(const QString& fileName, QGLShader::ShaderType type, QObject *parent = 0); + QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); + QGLShader(const QString& fileName, const QGLContext *context, QObject *parent = 0); + QGLShader(const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); + virtual ~QGLShader(); + + bool isValid() const; + + QGLShader::ShaderType shaderType() const; + + bool setSourceCode(const char *source); + bool setSourceCode(const QByteArray& source); + bool setSourceCode(const QString& source); + bool setSourceCodeFile(const QString& fileName); + + bool setBinaryCode(GLenum format, const void *binary, int length); + bool setBinaryCode(QGLShader& otherShader, GLenum format, const void *binary, int length); + + static QList shaderBinaryFormats(); + + QByteArray sourceCode() const; + + bool isCompiled() const; + QString errors() const; + + GLuint shaderId() const; + +private: + QGLShaderPrivate *d; + + friend class QGLShaderProgram; + + Q_DISABLE_COPY(QGLShader); +}; + +class QGLShaderProgramPrivate; + +class Q_OPENGL_EXPORT QGLShaderProgram : public QObject +{ + Q_OBJECT +public: + explicit QGLShaderProgram(QObject *parent = 0); + explicit QGLShaderProgram(const QGLContext *context, QObject *parent = 0); + virtual ~QGLShaderProgram(); + + bool isValid() const; + + bool addShader(QGLShader *shader); + void removeShader(QGLShader *shader); + QList shaders() const; + + bool addShader(QGLShader::ShaderType type, const char *source); + bool addShader(QGLShader::ShaderType type, const QByteArray& source); + bool addShader(QGLShader::ShaderType type, const QString& source); + + void removeAllShaders(); + + QByteArray programBinary(int *format) const; + bool setProgramBinary(int format, const QByteArray& binary); + static QList programBinaryFormats(); + + virtual bool link(); + bool isLinked() const; + QString errors() const; + + bool enable(); + void disable(); + + GLuint programId() const; + + void bindAttributeLocation(const char *name, int location); + void bindAttributeLocation(const QByteArray& name, int location); + void bindAttributeLocation(const QString& name, int location); + + int attributeLocation(const char *name) const; + int attributeLocation(const QByteArray& name) const; + int attributeLocation(const QString& name) const; + + void setAttributeValue(int location, GLfloat value); + void setAttributeValue(int location, GLfloat x, GLfloat y); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(int location, const QVector2D& value); + void setAttributeValue(int location, const QVector3D& value); + void setAttributeValue(int location, const QVector4D& value); + void setAttributeValue(int location, const QColor& value); + void setAttributeValue(int location, const GLfloat *values, int columns, int rows); + + void setAttributeValue(const char *name, GLfloat value); + void setAttributeValue(const char *name, GLfloat x, GLfloat y); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(const char *name, const QVector2D& value); + void setAttributeValue(const char *name, const QVector3D& value); + void setAttributeValue(const char *name, const QVector4D& value); + void setAttributeValue(const char *name, const QColor& value); + void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows); + + void setAttributeArray + (int location, const GLfloat *values, int size, int stride = 0); + void setAttributeArray + (int location, const QVector2D *values, int stride = 0); + void setAttributeArray + (int location, const QVector3D *values, int stride = 0); + void setAttributeArray + (int location, const QVector4D *values, int stride = 0); + void setAttributeArray + (const char *name, const GLfloat *values, int size, int stride = 0); + void setAttributeArray + (const char *name, const QVector2D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector3D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector4D *values, int stride = 0); + void disableAttributeArray(int location); + void disableAttributeArray(const char *name); + + int uniformLocation(const char *name) const; + int uniformLocation(const QByteArray& name) const; + int uniformLocation(const QString& name) const; + + void setUniformValue(int location, GLfloat value); + void setUniformValue(int location, GLint value); + void setUniformValue(int location, GLfloat x, GLfloat y); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(int location, const QVector2D& value); + void setUniformValue(int location, const QVector3D& value); + void setUniformValue(int location, const QVector4D& value); + void setUniformValue(int location, const QColor& color); + void setUniformValue(int location, const QMatrix2x2& value); + void setUniformValue(int location, const QMatrix2x3& value); + void setUniformValue(int location, const QMatrix2x4& value); + void setUniformValue(int location, const QMatrix3x2& value); + void setUniformValue(int location, const QMatrix3x3& value); + void setUniformValue(int location, const QMatrix3x4& value); + void setUniformValue(int location, const QMatrix4x2& value); + void setUniformValue(int location, const QMatrix4x3& value); + void setUniformValue(int location, const QMatrix4x4& value); + void setUniformValue(int location, const GLfloat value[4][4]); + void setUniformValue(int location, const QTransform& value); + + void setUniformValue(const char *name, GLfloat value); + void setUniformValue(const char *name, GLint value); + void setUniformValue(const char *name, GLfloat x, GLfloat y); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(const char *name, const QVector2D& value); + void setUniformValue(const char *name, const QVector3D& value); + void setUniformValue(const char *name, const QVector4D& value); + void setUniformValue(const char *name, const QColor& color); + void setUniformValue(const char *name, const QMatrix2x2& value); + void setUniformValue(const char *name, const QMatrix2x3& value); + void setUniformValue(const char *name, const QMatrix2x4& value); + void setUniformValue(const char *name, const QMatrix3x2& value); + void setUniformValue(const char *name, const QMatrix3x3& value); + void setUniformValue(const char *name, const QMatrix3x4& value); + void setUniformValue(const char *name, const QMatrix4x2& value); + void setUniformValue(const char *name, const QMatrix4x3& value); + void setUniformValue(const char *name, const QMatrix4x4& value); + void setUniformValue(const char *name, const GLfloat value[4][4]); + void setUniformValue(const char *name, const QTransform& value); + + void setUniformValueArray(int location, const GLfloat *values, int count, int size); + void setUniformValueArray(int location, const GLint *values, int count); + void setUniformValueArray(int location, const QVector2D *values, int count); + void setUniformValueArray(int location, const QVector3D *values, int count); + void setUniformValueArray(int location, const QVector4D *values, int count); + void setUniformValueArray(int location, const QMatrix2x2 *values, int count); + void setUniformValueArray(int location, const QMatrix2x3 *values, int count); + void setUniformValueArray(int location, const QMatrix2x4 *values, int count); + void setUniformValueArray(int location, const QMatrix3x2 *values, int count); + void setUniformValueArray(int location, const QMatrix3x3 *values, int count); + void setUniformValueArray(int location, const QMatrix3x4 *values, int count); + void setUniformValueArray(int location, const QMatrix4x2 *values, int count); + void setUniformValueArray(int location, const QMatrix4x3 *values, int count); + void setUniformValueArray(int location, const QMatrix4x4 *values, int count); + + void setUniformValueArray(const char *name, const GLfloat *values, int count, int size); + void setUniformValueArray(const char *name, const GLint *values, int count); + void setUniformValueArray(const char *name, const QVector2D *values, int count); + void setUniformValueArray(const char *name, const QVector3D *values, int count); + void setUniformValueArray(const char *name, const QVector4D *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count); + + static bool hasShaderPrograms(const QGLContext *context = 0); + +private: + QGLShaderProgramPrivate *d; + + Q_DISABLE_COPY(QGLShaderProgram); + + bool init(); +}; + +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif -- cgit v0.12