src/opengl/qglshaderprogram.cpp
changeset 30 5dc02b23752f
parent 22 79de32ba3296
child 33 3e2da88830cd
--- a/src/opengl/qglshaderprogram.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/opengl/qglshaderprogram.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -50,7 +50,7 @@
 
 QT_BEGIN_NAMESPACE
 
-#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+#if !defined(QT_OPENGL_ES_1)
 
 /*!
     \class QGLShaderProgram
@@ -143,6 +143,8 @@
 
     \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL).
     \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL).
+    \value Geometry Geometry shaders written in the OpenGL Shading
+           Language (GLSL), based on the GL_EXT_geometry_shader4 extension.
 */
 
 #ifndef GL_FRAGMENT_SHADER
@@ -226,6 +228,8 @@
         GLuint shader;
         if (shaderType == QGLShader::Vertex)
             shader = glCreateShader(GL_VERTEX_SHADER);
+        else if (shaderType == QGLShader::Geometry)
+            shader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
         else
             shader = glCreateShader(GL_FRAGMENT_SHADER);
         if (!shader) {
@@ -509,6 +513,10 @@
     return d->shaderGuard.id();
 }
 
+
+
+
+
 #undef ctx
 #define ctx programGuard.context()
 
@@ -521,8 +529,9 @@
         , linked(false)
         , inited(false)
         , removingShaders(false)
-        , vertexShader(0)
-        , fragmentShader(0)
+        , geometryVertexCount(64)
+        , geometryInputType(0)
+        , geometryOutputType(0)
     {
     }
     ~QGLShaderProgramPrivate();
@@ -531,11 +540,14 @@
     bool linked;
     bool inited;
     bool removingShaders;
+
+    int geometryVertexCount;
+    GLenum geometryInputType;
+    GLenum geometryOutputType;
+
     QString log;
     QList<QGLShader *> shaders;
     QList<QGLShader *> anonShaders;
-    QGLShader *vertexShader;
-    QGLShader *fragmentShader;
 
     bool hasShader(QGLShader::ShaderType type) const;
 };
@@ -604,6 +616,7 @@
         context = QGLContext::currentContext();
         d->programGuard.setContext(context);
     }
+
     if (!context)
         return false;
     if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
@@ -831,6 +844,7 @@
     GLuint program = d->programGuard.id();
     if (!program)
         return false;
+
     GLint value;
     if (d->shaders.isEmpty()) {
         // If there are no explicit shaders, then it is possible that the
@@ -843,6 +857,22 @@
         if (d->linked)
             return true;
     }
+
+    // Set up the geometry shader parameters
+    if (glProgramParameteriEXT) {
+        foreach (QGLShader *shader, d->shaders) {
+            if (shader->shaderType() & QGLShader::Geometry) {
+                glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT,
+                                       d->geometryInputType);
+                glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT,
+                                       d->geometryOutputType);
+                glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT,
+                                       d->geometryVertexCount);
+                break;
+            }
+        }
+    }
+
     glLinkProgram(program);
     value = 0;
     glGetProgramiv(program, GL_LINK_STATUS, &value);
@@ -1267,7 +1297,8 @@
     Q_D(QGLShaderProgram);
     Q_UNUSED(d);
     if (location != -1) {
-        GLfloat values[4] = {value.redF(), value.greenF(), value.blueF(), value.alphaF()};
+        GLfloat values[4] = {GLfloat(value.redF()), GLfloat(value.greenF()),
+                             GLfloat(value.blueF()), GLfloat(value.alphaF())};
         glVertexAttrib4fv(location, values);
     }
 }
@@ -1433,6 +1464,38 @@
 }
 
 /*!
+    Sets an array of 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.
+
+    The \a type indicates the type of elements in the \a values array,
+    usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc.  The \a tupleSize
+    indicates the number of components per vertex: 1, 2, 3, or 4.
+
+    The array will become active when enableAttributeArray() is called
+    on the \a location.  Otherwise the value specified with
+    setAttributeValue() for \a location will be used.
+
+    The setAttributeBuffer() function can be used to set the attribute
+    array to an offset within a vertex buffer.
+
+    \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+    \sa disableAttributeArray(), setAttributeBuffer()
+    \since 4.7
+*/
+void QGLShaderProgram::setAttributeArray
+    (int location, GLenum type, const void *values, int tupleSize, int stride)
+{
+    Q_D(QGLShaderProgram);
+    Q_UNUSED(d);
+    if (location != -1) {
+        glVertexAttribPointer(location, tupleSize, type, GL_FALSE,
+                              stride, values);
+    }
+}
+
+/*!
     \overload
 
     Sets an array of vertex \a values on the attribute called \a name
@@ -1518,6 +1581,92 @@
 }
 
 /*!
+    \overload
+
+    Sets an array of 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.
+
+    The \a type indicates the type of elements in the \a values array,
+    usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc.  The \a tupleSize
+    indicates the number of components per vertex: 1, 2, 3, or 4.
+
+    The array will become active when enableAttributeArray() is called
+    on the \a name.  Otherwise the value specified with
+    setAttributeValue() for \a name will be used.
+
+    The setAttributeBuffer() function can be used to set the attribute
+    array to an offset within a vertex buffer.
+
+    \sa setAttributeValue(), setUniformValue(), enableAttributeArray()
+    \sa disableAttributeArray(), setAttributeBuffer()
+    \since 4.7
+*/
+void QGLShaderProgram::setAttributeArray
+    (const char *name, GLenum type, const void *values, int tupleSize, int stride)
+{
+    setAttributeArray(attributeLocation(name), type, values, tupleSize, stride);
+}
+
+/*!
+    Sets an array of vertex values on the attribute at \a location in
+    this shader program, starting at a specific \a offset in the
+    currently bound vertex buffer.  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 the value array.
+
+    The \a type indicates the type of elements in the vertex value
+    array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc.  The \a
+    tupleSize indicates the number of components per vertex: 1, 2, 3,
+    or 4.
+
+    The array will become active when enableAttributeArray() is called
+    on the \a location.  Otherwise the value specified with
+    setAttributeValue() for \a location will be used.
+
+    \sa setAttributeArray()
+    \since 4.7
+*/
+void QGLShaderProgram::setAttributeBuffer
+    (int location, GLenum type, int offset, int tupleSize, int stride)
+{
+    Q_D(QGLShaderProgram);
+    Q_UNUSED(d);
+    if (location != -1) {
+        glVertexAttribPointer(location, tupleSize, type, GL_FALSE, stride,
+                              reinterpret_cast<const void *>(offset));
+    }
+}
+
+/*!
+    \overload
+
+    Sets an array of vertex values on the attribute called \a name
+    in this shader program, starting at a specific \a offset in the
+    currently bound vertex buffer.  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 the value array.
+
+    The \a type indicates the type of elements in the vertex value
+    array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc.  The \a
+    tupleSize indicates the number of components per vertex: 1, 2, 3,
+    or 4.
+
+    The array will become active when enableAttributeArray() is called
+    on the \a name.  Otherwise the value specified with
+    setAttributeValue() for \a name will be used.
+
+    \sa setAttributeArray()
+    \since 4.7
+*/
+void QGLShaderProgram::setAttributeBuffer
+    (const char *name, GLenum type, int offset, int tupleSize, int stride)
+{
+    setAttributeBuffer(attributeLocation(name), type, offset, tupleSize, stride);
+}
+
+/*!
     Enables the vertex array at \a location in this shader program
     so that the value set by setAttributeArray() on \a location
     will be used by the shader program.
@@ -1884,7 +2033,8 @@
     Q_D(QGLShaderProgram);
     Q_UNUSED(d);
     if (location != -1) {
-        GLfloat values[4] = {color.redF(), color.greenF(), color.blueF(), color.alphaF()};
+        GLfloat values[4] = {GLfloat(color.redF()), GLfloat(color.greenF()),
+                             GLfloat(color.blueF()), GLfloat(color.alphaF())};
         glUniform4fv(location, 1, values);
     }
 }
@@ -1913,7 +2063,7 @@
     Q_D(QGLShaderProgram);
     Q_UNUSED(d);
     if (location != -1) {
-        GLfloat values[4] = {point.x(), point.y()};
+        GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())};
         glUniform2fv(location, 1, values);
     }
 }
@@ -1942,7 +2092,7 @@
     Q_D(QGLShaderProgram);
     Q_UNUSED(d);
     if (location != -1) {
-        GLfloat values[4] = {point.x(), point.y()};
+        GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())};
         glUniform2fv(location, 1, values);
     }
 }
@@ -1971,7 +2121,7 @@
     Q_D(QGLShaderProgram);
     Q_UNUSED(d);
     if (location != -1) {
-        GLfloat values[4] = {size.width(), size.width()};
+        GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.width())};
         glUniform2fv(location, 1, values);
     }
 }
@@ -2000,7 +2150,7 @@
     Q_D(QGLShaderProgram);
     Q_UNUSED(d);
     if (location != -1) {
-        GLfloat values[4] = {size.width(), size.height()};
+        GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())};
         glUniform2fv(location, 1, values);
     }
 }
@@ -2314,6 +2464,42 @@
     \overload
 
     Sets the uniform variable at \a location in the current context
+    to a 2x2 matrix \a value.  The matrix elements must be specified
+    in column-major order.
+
+    \sa setAttributeValue()
+    \since 4.7
+*/
+void QGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2])
+{
+    Q_D(QGLShaderProgram);
+    Q_UNUSED(d);
+    if (location != -1)
+        glUniformMatrix2fv(location, 1, GL_FALSE, value[0]);
+}
+
+/*!
+    \overload
+
+    Sets the uniform variable at \a location in the current context
+    to a 3x3 matrix \a value.  The matrix elements must be specified
+    in column-major order.
+
+    \sa setAttributeValue()
+    \since 4.7
+*/
+void QGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3])
+{
+    Q_D(QGLShaderProgram);
+    Q_UNUSED(d);
+    if (location != -1)
+        glUniformMatrix3fv(location, 1, GL_FALSE, value[0]);
+}
+
+/*!
+    \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.
 
@@ -2327,6 +2513,37 @@
         glUniformMatrix4fv(location, 1, GL_FALSE, value[0]);
 }
 
+
+/*!
+    \overload
+
+    Sets the uniform variable called \a name in the current context
+    to a 2x2 matrix \a value.  The matrix elements must be specified
+    in column-major order.
+
+    \sa setAttributeValue()
+    \since 4.7
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2])
+{
+    setUniformValue(uniformLocation(name), value);
+}
+
+/*!
+    \overload
+
+    Sets the uniform variable called \a name in the current context
+    to a 3x3 matrix \a value.  The matrix elements must be specified
+    in column-major order.
+
+    \sa setAttributeValue()
+    \since 4.7
+*/
+void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3])
+{
+    setUniformValue(uniformLocation(name), value);
+}
+
 /*!
     \overload
 
@@ -2354,9 +2571,9 @@
     Q_UNUSED(d);
     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()}
+            {GLfloat(value.m11()), GLfloat(value.m12()), GLfloat(value.m13())},
+            {GLfloat(value.m21()), GLfloat(value.m22()), GLfloat(value.m23())},
+            {GLfloat(value.m31()), GLfloat(value.m32()), GLfloat(value.m33())}
         };
         glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]);
     }
@@ -2869,6 +3086,108 @@
 #undef ctx
 
 /*!
+    Returns the hardware limit for how many vertices a geometry shader
+    can output.
+
+    \since 4.7
+
+    \sa setGeometryOutputVertexCount()
+*/
+int QGLShaderProgram::maxGeometryOutputVertices() const
+{
+    GLint n;
+    glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &n);
+    return n;
+}
+
+/*!
+    Sets the maximum number of vertices the current geometry shader
+    program will produce, if active, to \a count.
+
+    \since 4.7
+
+    This parameter takes effect the next time the program is linked.
+*/
+void QGLShaderProgram::setGeometryOutputVertexCount(int count)
+{
+#ifndef QT_NO_DEBUG
+    int max = maxGeometryOutputVertices();
+    if (count > max) {
+        qWarning("QGLShaderProgram::setGeometryOutputVertexCount: count: %d higher than maximum: %d",
+                 count, max);
+    }
+#endif
+    d_func()->geometryVertexCount = count;
+}
+
+
+/*!
+    Returns the maximum number of vertices the current geometry shader
+    program will produce, if active.
+
+    \since 4.7
+
+    This parameter takes effect the ntext time the program is linked.
+*/
+int QGLShaderProgram::geometryOutputVertexCount() const
+{
+    return d_func()->geometryVertexCount;
+}
+
+
+/*!
+    Sets the input type from \a inputType.
+
+    This parameter takes effect the next time the program is linked.
+*/
+void QGLShaderProgram::setGeometryInputType(GLenum inputType)
+{
+    d_func()->geometryInputType = inputType;
+}
+
+
+/*!
+    Returns the geometry shader input type, if active.
+
+    This parameter takes effect the next time the program is linked.
+
+    \since 4.7
+ */
+
+GLenum QGLShaderProgram::geometryInputType() const
+{
+    return d_func()->geometryInputType;
+}
+
+
+/*!
+    Sets the output type from the geometry shader, if active, to
+    \a outputType.
+
+    This parameter takes effect the next time the program is linked.
+
+    \since 4.7
+*/
+void QGLShaderProgram::setGeometryOutputType(GLenum outputType)
+{
+    d_func()->geometryOutputType = outputType;
+}
+
+
+/*!
+    Returns the geometry shader output type, if active.
+
+    This parameter takes effect the next time the program is linked.
+
+    \since 4.7
+ */
+GLenum QGLShaderProgram::geometryOutputType() const
+{
+    return d_func()->geometryOutputType;
+}
+
+
+/*!
     Returns true if shader programs written in the OpenGL Shading
     Language (GLSL) are supported on this system; false otherwise.
 
@@ -2900,8 +3219,71 @@
         removeShader(shader);
 }
 
+
+#undef ctx
+#undef context
+
+/*!
+    Returns true if shader programs of type \a type 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.
+
+    \since 4.7
+*/
+bool QGLShader::hasOpenGLShaders(ShaderType type, const QGLContext *context)
+{
+    if (!context)
+        context = QGLContext::currentContext();
+    if (!context)
+        return false;
+
+    if ((type & ~(Geometry | Vertex | Fragment)) || type == 0)
+        return false;
+
+    bool resolved = qt_resolve_glsl_extensions(const_cast<QGLContext *>(context));
+    if (!resolved)
+        return false;
+
+    if ((type & Geometry) && !QByteArray((const char *) glGetString(GL_EXTENSIONS)).contains("GL_EXT_geometry_shader4"))
+        return false;
+
+    return true;
+}
+
+
+
 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
 /*! \internal */
+void QGLShaderProgram::setAttributeArray
+    (int location, QMacCompatGLenum type, const void *values, int tupleSize, int stride)
+{
+    setAttributeArray(location, GLenum(type), values, tupleSize, stride);
+}
+
+/*! \internal */
+void QGLShaderProgram::setAttributeArray
+    (const char *name, QMacCompatGLenum type, const void *values, int tupleSize, int stride)
+{
+    setAttributeArray(name, GLenum(type), values, tupleSize, stride);
+}
+
+/*! \internal */
+void QGLShaderProgram::setAttributeBuffer
+    (int location, QMacCompatGLenum type, int offset, int tupleSize, int stride)
+{
+    setAttributeBuffer(location, GLenum(type), offset, tupleSize, stride);
+}
+
+/*! \internal */
+void QGLShaderProgram::setAttributeBuffer
+    (const char *name, QMacCompatGLenum type, int offset, int tupleSize, int stride)
+{
+    setAttributeBuffer(name, GLenum(type), offset, tupleSize, stride);
+}
+
+/*! \internal */
 void QGLShaderProgram::setUniformValue(int location, QMacCompatGLint value)
 {
     setUniformValue(location, GLint(value));
@@ -2950,6 +3332,6 @@
 }
 #endif
 
-#endif // !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+#endif // !defined(QT_OPENGL_ES_1)
 
 QT_END_NAMESPACE