diff --git a/src/imports/qtcanvas3d/context3d.cpp b/src/imports/qtcanvas3d/context3d.cpp index adc18595dd8c6d85bed94d32ec9c75ad255e64d1..cc95dba4cf012453c3f141d51e53a444e76b8970 100644 --- a/src/imports/qtcanvas3d/context3d.cpp +++ b/src/imports/qtcanvas3d/context3d.cpp @@ -574,6 +574,153 @@ bool CanvasContext::checkParent(QObject *obj, const char *function) return true; } +/*! + * \internal + * + * Transposes matrices. \a dim is the dimensions of the square matrices in \a src. + * A newly allocated array containing transposed matrices is returned. \a count specifies how many + * matrices are handled. + * Required for uniformMatrix*fv functions in ES2. + */ +float *CanvasContext::transposeMatrix(int dim, int count, float *src) +{ + float *dest = new float[dim * dim * count]; + + for (int k = 0; k < count; k++) { + const int offset = k * dim * dim; + for (int i = 0; i < dim; i++) { + for (int j = 0; j < dim; j++) + dest[offset + (i * dim) + j] = src[offset + (j * dim) + i]; + } + } + + return dest; +} + +/*! + * \internal + * + * Set matrix uniform values. + */ +void CanvasContext::uniformMatrixNfv(int dim, const QJSValue &location3D, bool transpose, + const QJSValue &array) +{ + qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ + << "(dim:" << dim + << ", uniformLocation:" << location3D.toString() + << ", transpose:" << transpose + << ", array:" << array.toString() + <<")"; + + if (!isOfType(location3D, "QtCanvas3D::CanvasUniformLocation")) + return; + + CanvasUniformLocation *locationObj = + static_cast<CanvasUniformLocation *>(location3D.toQObject()); + + if (!checkParent(locationObj, __FUNCTION__)) + return; + + // Check if we have a JavaScript array + if (array.isArray()) { + uniformMatrixNfva(dim, locationObj, transpose, array.toVariant().toList()); + return; + } + + int arrayLen = 0; + float *uniformData = reinterpret_cast<float * >( + getTypedArrayAsRawDataPtr(array, arrayLen, QV4::Heap::TypedArray::Float32Array)); + + if (!m_currentProgram || !uniformData || !locationObj) + return; + + int uniformLocation = locationObj->id(); + int numMatrices = arrayLen / (dim * dim * 4); + + qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ + << "numMatrices:" << numMatrices; + + float *transposedMatrix = 0; + if (m_isOpenGLES2 && transpose) { + transpose = false; + transposedMatrix = transposeMatrix(dim, numMatrices, uniformData); + uniformData = transposedMatrix; + } + + switch (dim) { + case 2: + glUniformMatrix2fv(uniformLocation, numMatrices, transpose, uniformData); + break; + case 3: + glUniformMatrix3fv(uniformLocation, numMatrices, transpose, uniformData); + break; + case 4: + glUniformMatrix4fv(uniformLocation, numMatrices, transpose, uniformData); + break; + default: + qWarning() << "Warning: Unsupported dim specified in" << __FUNCTION__; + break; + } + + logAllGLErrors(__FUNCTION__); + + delete[] transposedMatrix; +} + +/*! + * \internal + * + * Set matrix uniform values from JS array. + */ +void CanvasContext::uniformMatrixNfva(int dim, CanvasUniformLocation *uniformLocation, + bool transpose, const QVariantList &array) +{ + qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ + << "(dim:" << dim + << ", location3D:" << uniformLocation + << ", transpose:" << transpose + << ", array:" << array + << ")"; + + if (!m_currentProgram || !uniformLocation) + return; + + int location3D = uniformLocation->id(); + int size = array.count(); + float *dataArray = new float[size]; + float *arrayPtr = dataArray; + int numMatrices = size / (dim * dim); + + ArrayUtils::fillFloatArrayFromVariantList(array, arrayPtr); + + float *transposedMatrix = 0; + if (m_isOpenGLES2 && transpose) { + transpose = false; + transposedMatrix = transposeMatrix(dim, numMatrices, arrayPtr); + arrayPtr = transposedMatrix; + } + + switch (dim) { + case 2: + glUniformMatrix2fv(location3D, numMatrices, transpose, arrayPtr); + break; + case 3: + glUniformMatrix3fv(location3D, numMatrices, transpose, arrayPtr); + break; + case 4: + glUniformMatrix4fv(location3D, numMatrices, transpose, arrayPtr); + break; + default: + qWarning() << "Warning: Unsupported dim specified in" << __FUNCTION__; + break; + } + + logAllGLErrors(__FUNCTION__); + + delete[] dataArray; + delete[] transposedMatrix; +} + /*! * \qmlmethod void Context3D::generateMipmap(glEnums target) * Generates a complete set of mipmaps for a texture object of the currently active texture unit. @@ -3801,42 +3948,7 @@ void CanvasContext::disableVertexAttribArray(int index) */ void CanvasContext::uniformMatrix2fv(QJSValue location3D, bool transpose, QJSValue array) { - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "(uniformLocation:" << location3D.toString() - << ", transpose:" << transpose - << ", array:" << array.toString() - <<")"; - - if (!isOfType(location3D, "QtCanvas3D::CanvasUniformLocation")) - return; - - CanvasUniformLocation *locationObj = - static_cast<CanvasUniformLocation *>(location3D.toQObject()); - - if (!checkParent(locationObj, __FUNCTION__)) - return; - - // Check if we have a JavaScript array - if (array.isArray()) { - uniformMatrix2fva(locationObj, transpose, array.toVariant().toList()); - return; - } - - int arrayLen = 0; - uchar *uniformData = getTypedArrayAsRawDataPtr(array, arrayLen, - QV4::Heap::TypedArray::Float32Array); - - if (!m_currentProgram || !uniformData || !locationObj) - return; - - int uniformLocation = locationObj->id(); - int numMatrices = arrayLen / (4 * 4); - - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "numMatrices:" << numMatrices; - - glUniformMatrix2fv(uniformLocation, numMatrices, transpose, (float *)uniformData); - logAllGLErrors(__FUNCTION__); + uniformMatrixNfv(2, location3D, transpose, array); } /*! @@ -3849,41 +3961,7 @@ void CanvasContext::uniformMatrix2fv(QJSValue location3D, bool transpose, QJSVal */ void CanvasContext::uniformMatrix3fv(QJSValue location3D, bool transpose, QJSValue array) { - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "(location3D:" << location3D.toString() - << ", transpose:" << transpose - << ", array:" << array.toString() - <<")"; - - if (!isOfType(location3D, "QtCanvas3D::CanvasUniformLocation")) - return; - CanvasUniformLocation *locationObj = - static_cast<CanvasUniformLocation *>(location3D.toQObject()); - - if (!checkParent(locationObj, __FUNCTION__)) - return; - - // Check if we have a JavaScript array - if (array.isArray()) { - uniformMatrix3fva(locationObj, transpose, array.toVariant().toList()); - return; - } - - int arrayLen = 0; - uchar *uniformData = getTypedArrayAsRawDataPtr(array, arrayLen, - QV4::Heap::TypedArray::Float32Array); - - if (!m_currentProgram || !uniformData || !locationObj) - return; - - int uniformLocation = locationObj->id(); - int numMatrices = arrayLen / (4 * 9); - - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "numMatrices:" << numMatrices; - - glUniformMatrix3fv(uniformLocation, numMatrices, transpose, (float *)uniformData); - logAllGLErrors(__FUNCTION__); + uniformMatrixNfv(3, location3D, transpose, array); } /*! @@ -3896,124 +3974,7 @@ void CanvasContext::uniformMatrix3fv(QJSValue location3D, bool transpose, QJSVal */ void CanvasContext::uniformMatrix4fv(QJSValue location3D, bool transpose, QJSValue array) { - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "(location3D:" << location3D.toString() - << ", transpose:" << transpose - << ", array:" << array.toString() - << ")"; - - if (!isOfType(location3D, "QtCanvas3D::CanvasUniformLocation")) - return; - CanvasUniformLocation *locationObj = - static_cast<CanvasUniformLocation *>(location3D.toQObject()); - - if (!checkParent(locationObj, __FUNCTION__)) - return; - - // Check if we have a JavaScript array - if (array.isArray()) { - uniformMatrix4fva(locationObj, transpose,array.toVariant().toList()); - return; - } - - int arrayLen = 0; - uchar *uniformData = getTypedArrayAsRawDataPtr(array, arrayLen, - QV4::Heap::TypedArray::Float32Array); - - if (!m_currentProgram || !uniformData || !locationObj) - return; - - int uniformLocation = locationObj->id(); - int numMatrices = arrayLen / (4 * 16); - - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "numMatrices:" << numMatrices; - - glUniformMatrix4fv(uniformLocation, numMatrices, transpose, (float *)uniformData); - logAllGLErrors(__FUNCTION__); -} - -/*! - * \internal - */ -void CanvasContext::uniformMatrix4fva(CanvasUniformLocation *uniformLocation, bool transpose, - QVariantList array) -{ - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "(location3D:" << uniformLocation - << ", transpose:" << transpose - << ", array:" << array - << ")"; - if (!m_currentProgram || !uniformLocation) - return; - - int location3D = uniformLocation->id(); - int size = array.count(); - float *arrayData = new float[size]; - int numMatrices = size / 16; - - ArrayUtils::fillFloatArrayFromVariantList(array, arrayData); - - glUniformMatrix4fv(location3D, numMatrices, transpose, arrayData); - logAllGLErrors(__FUNCTION__); - - delete [] arrayData; -} - - -/*! - * \internal - */ -void CanvasContext::uniformMatrix3fva(CanvasUniformLocation *uniformLocation, bool transpose, - QVariantList array) -{ - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "(location3D:" << uniformLocation - << ", transpose:" << transpose - << ", array:" << array - << ")"; - if (!m_currentProgram || !uniformLocation) - return; - - int location3D = uniformLocation->id(); - int size = array.count(); - float *arrayData = new float[size]; - int numMatrices = size / 9; - - ArrayUtils::fillFloatArrayFromVariantList(array, arrayData); - - glUniformMatrix3fv(location3D, numMatrices, transpose, arrayData); - logAllGLErrors(__FUNCTION__); - - delete [] arrayData; -} - -/*! - * \internal - */ -void CanvasContext::uniformMatrix2fva(CanvasUniformLocation *uniformLocation, bool transpose, - QVariantList array) -{ - qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ - << "(location3D:" << uniformLocation - << ", transpose:" << transpose - << ", array:" << array - << ")"; - - if (!m_currentProgram || !uniformLocation) - return; - - int location3D = uniformLocation->id(); - int size = array.count(); - float *arrayData = new float[size]; - int numMatrices = size / 4; - - ArrayUtils::fillFloatArrayFromVariantList(array, arrayData); - - glUniformMatrix2fv(location3D, numMatrices, transpose, arrayData); - logAllGLErrors(__FUNCTION__); - - delete [] arrayData; + uniformMatrixNfv(4, location3D, transpose, array); } /*! @@ -6015,123 +5976,171 @@ QJSValue CanvasContext::getUniform(QJSValue program3D, QJSValue location3D) uint programId = program->id(); uint locationId = location->id(); - CanvasActiveInfo *info = getActiveUniform(program3D, locationId); + int type = location->type(); + + if (type < 0) { + // Resolve location type. + // There is no easy way to determine this, as the active uniform + // indices do not usually match the uniform locations. We must query + // active uniforms until we hit the one we want. This is obviously + // extremely inefficient, but luckily getUniform is not something most + // users typically need or use. + + const int maxCharCount = 512; + GLsizei length; + GLint size; + GLenum glType; + char nameBuf[maxCharCount]; + GLint uniformCount = 0; + glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &uniformCount); + // Strip any [] from the uniform name, unless part of struct + QByteArray strippedName = location->name().toLatin1(); + int idx = strippedName.indexOf('['); + if (idx >= 0) { + // Don't truncate if part of struct + if (strippedName.indexOf('.') == -1) + strippedName.truncate(idx); + } + for (int i = 0; i < uniformCount; i++) { + nameBuf[0] = '\0'; + glGetActiveUniform(programId, i, maxCharCount, &length, &size, &glType, nameBuf); + QByteArray activeName(nameBuf, length); + idx = activeName.indexOf('['); + if (idx >= 0) { + // Don't truncate if part of struct + if (activeName.indexOf('.') == -1) + activeName.truncate(idx); + } - int numValues = 4; - switch (info->type()) { - case SAMPLER_2D: - // Intentional flow through - case SAMPLER_CUBE: - // Intentional flow through - case INT: { - GLint value = 0; - glGetUniformiv(programId, locationId, &value); - logAllGLErrors(__FUNCTION__); - return QJSValue(value); - } - case FLOAT: { - GLfloat value = 0; - glGetUniformfv(programId, locationId, &value); - logAllGLErrors(__FUNCTION__); - return QJSValue(value); - } - case BOOL: { - GLint value = 0; - glGetUniformiv(programId, locationId, &value); - logAllGLErrors(__FUNCTION__); - return QJSValue(bool(value)); + if (activeName == strippedName) { + type = glType; + location->setType(type); + break; + } + } } - case INT_VEC2: - numValues--; - // Intentional flow through - case INT_VEC3: - numValues--; - // Intentional flow through - case INT_VEC4: { - QV4::Scope scope(m_v4engine); - QV4::Scoped<QV4::ArrayBuffer> buffer(scope, - m_v4engine->memoryManager->alloc<QV4::ArrayBuffer>( - m_v4engine, - sizeof(int) * numValues)); - glGetUniformiv(programId, locationId, (int *) buffer->data()); - logAllGLErrors(__FUNCTION__); - QV4::ScopedFunctionObject constructor(scope, - m_v4engine->typedArrayCtors[ - QV4::Heap::TypedArray::Int32Array]); - QV4::ScopedCallData callData(scope, 1); - callData->args[0] = buffer; - return QJSValue(m_v4engine, constructor->construct(callData)); - } - case FLOAT_VEC2: - numValues--; - // Intentional flow through - case FLOAT_VEC3: - numValues--; - // Intentional flow through - case FLOAT_VEC4: { - QV4::Scope scope(m_v4engine); - QV4::Scoped<QV4::ArrayBuffer> buffer(scope, - m_v4engine->memoryManager->alloc<QV4::ArrayBuffer>( - m_v4engine, - sizeof(float) * numValues)); - glGetUniformfv(programId, locationId, (float *) buffer->data()); - logAllGLErrors(__FUNCTION__); + if (type < 0) { + qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__ + << ":INVALID_OPERATION:Uniform type could not be determined"; + m_error |= CANVAS_INVALID_OPERATION; + return QJSValue(QJSValue::UndefinedValue); + } else { + int numValues = 4; + switch (type) { + case SAMPLER_2D: + // Intentional flow through + case SAMPLER_CUBE: + // Intentional flow through + case INT: { + GLint value = 0; + glGetUniformiv(programId, locationId, &value); + logAllGLErrors(__FUNCTION__); + return QJSValue(value); + } + case FLOAT: { + GLfloat value = 0; + glGetUniformfv(programId, locationId, &value); + logAllGLErrors(__FUNCTION__); + return QJSValue(value); + } + case BOOL: { + GLint value = 0; + glGetUniformiv(programId, locationId, &value); + logAllGLErrors(__FUNCTION__); + return QJSValue(bool(value)); + } + case INT_VEC2: + numValues--; + // Intentional flow through + case INT_VEC3: + numValues--; + // Intentional flow through + case INT_VEC4: { + QV4::Scope scope(m_v4engine); + QV4::Scoped<QV4::ArrayBuffer> buffer(scope, + m_v4engine->memoryManager->alloc<QV4::ArrayBuffer>( + m_v4engine, + sizeof(int) * numValues)); + glGetUniformiv(programId, locationId, (int *) buffer->data()); + logAllGLErrors(__FUNCTION__); - QV4::ScopedFunctionObject constructor(scope, - m_v4engine->typedArrayCtors[ - QV4::Heap::TypedArray::Float32Array]); - QV4::ScopedCallData callData(scope, 1); - callData->args[0] = buffer; - return QJSValue(m_v4engine, constructor->construct(callData)); - } - case BOOL_VEC2: - numValues--; - // Intentional flow through - case BOOL_VEC3: - numValues--; - // Intentional flow through - case BOOL_VEC4: { - GLint *value = new GLint[numValues]; - QJSValue array = m_engine->newArray(numValues); + QV4::ScopedFunctionObject constructor(scope, + m_v4engine->typedArrayCtors[ + QV4::Heap::TypedArray::Int32Array]); + QV4::ScopedCallData callData(scope, 1); + callData->args[0] = buffer; + return QJSValue(m_v4engine, constructor->construct(callData)); + } + case FLOAT_VEC2: + numValues--; + // Intentional flow through + case FLOAT_VEC3: + numValues--; + // Intentional flow through + case FLOAT_VEC4: { + QV4::Scope scope(m_v4engine); + QV4::Scoped<QV4::ArrayBuffer> buffer(scope, + m_v4engine->memoryManager->alloc<QV4::ArrayBuffer>( + m_v4engine, + sizeof(float) * numValues)); + glGetUniformfv(programId, locationId, (float *) buffer->data()); + logAllGLErrors(__FUNCTION__); - glGetUniformiv(programId, locationId, value); - logAllGLErrors(__FUNCTION__); + QV4::ScopedFunctionObject constructor(scope, + m_v4engine->typedArrayCtors[ + QV4::Heap::TypedArray::Float32Array]); + QV4::ScopedCallData callData(scope, 1); + callData->args[0] = buffer; + return QJSValue(m_v4engine, constructor->construct(callData)); + } + case BOOL_VEC2: + numValues--; + // Intentional flow through + case BOOL_VEC3: + numValues--; + // Intentional flow through + case BOOL_VEC4: { + GLint *value = new GLint[numValues]; + QJSValue array = m_engine->newArray(numValues); + + glGetUniformiv(programId, locationId, value); + logAllGLErrors(__FUNCTION__); - for (int i = 0; i < numValues; i++) - array.setProperty(i, bool(value[i])); + for (int i = 0; i < numValues; i++) + array.setProperty(i, bool(value[i])); - return array; - } - case FLOAT_MAT2: - numValues--; - // Intentional flow through - case FLOAT_MAT3: - numValues--; - // Intentional flow through - case FLOAT_MAT4: { - numValues = numValues * numValues; + return array; + } + case FLOAT_MAT2: + numValues--; + // Intentional flow through + case FLOAT_MAT3: + numValues--; + // Intentional flow through + case FLOAT_MAT4: { + numValues = numValues * numValues; - QV4::Scope scope(m_v4engine); - QV4::Scoped<QV4::ArrayBuffer> buffer(scope, - m_v4engine->memoryManager->alloc<QV4::ArrayBuffer>( - m_v4engine, - sizeof(float) * numValues)); - glGetUniformfv(programId, locationId, (float *) buffer->data()); - logAllGLErrors(__FUNCTION__); + QV4::Scope scope(m_v4engine); + QV4::Scoped<QV4::ArrayBuffer> buffer(scope, + m_v4engine->memoryManager->alloc<QV4::ArrayBuffer>( + m_v4engine, + sizeof(float) * numValues)); + glGetUniformfv(programId, locationId, (float *) buffer->data()); + logAllGLErrors(__FUNCTION__); - QV4::ScopedFunctionObject constructor(scope, - m_v4engine->typedArrayCtors[ - QV4::Heap::TypedArray::Float32Array]); - QV4::ScopedCallData callData(scope, 1); - callData->args[0] = buffer; - return QJSValue(m_v4engine, constructor->construct(callData)); - } - default: - break; + QV4::ScopedFunctionObject constructor(scope, + m_v4engine->typedArrayCtors[ + QV4::Heap::TypedArray::Float32Array]); + QV4::ScopedCallData callData(scope, 1); + callData->args[0] = buffer; + return QJSValue(m_v4engine, constructor->construct(callData)); + } + default: + break; + } } - return QJSValue(QJSValue::UndefinedValue); } diff --git a/src/imports/qtcanvas3d/context3d_p.h b/src/imports/qtcanvas3d/context3d_p.h index 6faddaec29f62d0f52ab73d5ffb949ede8198215..280bf9809af9ece63b1d4d125b2d483b121106d7 100644 --- a/src/imports/qtcanvas3d/context3d_p.h +++ b/src/imports/qtcanvas3d/context3d_p.h @@ -1210,10 +1210,6 @@ private: void uniform3iva(CanvasUniformLocation *location, QVariantList array); void uniform4iva(CanvasUniformLocation *location, QVariantList array); - void uniformMatrix2fva(CanvasUniformLocation *location, bool transpose, QVariantList value); - void uniformMatrix3fva(CanvasUniformLocation *location, bool transpose, QVariantList value); - void uniformMatrix4fva(CanvasUniformLocation *location, bool transpose, QVariantList value); - void vertexAttrib1fva(uint indx, QVariantList values); void vertexAttrib2fva(uint indx, QVariantList values); void vertexAttrib3fva(uint indx, QVariantList values); @@ -1236,6 +1232,12 @@ private: bool isValidTextureBound(glEnums target, const QString &funcName); bool checkParent(QObject *jsObj, const char *function); + float *transposeMatrix(int dim, int count, float *src); + void uniformMatrixNfv(int dim, const QJSValue &location3D, bool transpose, + const QJSValue &array); + void uniformMatrixNfva(int dim, CanvasUniformLocation *uniformLocation, bool transpose, + const QVariantList &array); + typedef enum { CANVAS_NO_ERRORS = 0, CANVAS_INVALID_ENUM = 1 << 0, diff --git a/src/imports/qtcanvas3d/uniformlocation.cpp b/src/imports/qtcanvas3d/uniformlocation.cpp index f1f50c8ce18b6dcc5a62e3ea894eff0801885542..31c228f214d80bf4b802a96436a76fca6020812d 100644 --- a/src/imports/qtcanvas3d/uniformlocation.cpp +++ b/src/imports/qtcanvas3d/uniformlocation.cpp @@ -54,7 +54,8 @@ QT_CANVAS3D_BEGIN_NAMESPACE */ CanvasUniformLocation::CanvasUniformLocation(int location, QObject *parent) : CanvasAbstractObject(parent), - m_location(location) + m_location(location), + m_type(-1) { } @@ -73,6 +74,22 @@ int CanvasUniformLocation::id() return m_location; } +/*! + * \internal + */ +int CanvasUniformLocation::type() +{ + return m_type; +} + +/*! + * \internal + */ +void CanvasUniformLocation::setType(int type) +{ + m_type = type; +} + /*! * \internal */ diff --git a/src/imports/qtcanvas3d/uniformlocation_p.h b/src/imports/qtcanvas3d/uniformlocation_p.h index fb1548ba50f5f5027c94ea2ab6cb41e60b77f5d3..cb99ca1e736a220192023c468fdb06d5a9720aea 100644 --- a/src/imports/qtcanvas3d/uniformlocation_p.h +++ b/src/imports/qtcanvas3d/uniformlocation_p.h @@ -63,11 +63,14 @@ public: virtual ~CanvasUniformLocation(); int id(); + int type(); + void setType(int type); friend QDebug operator<< (QDebug d, const CanvasUniformLocation *uLoc); private: int m_location; + int m_type; }; QT_CANVAS3D_END_NAMESPACE diff --git a/tests/auto/qmltest/canvas3d/tst_uniforms.js b/tests/auto/qmltest/canvas3d/tst_uniforms.js new file mode 100644 index 0000000000000000000000000000000000000000..d6227bccd47b0f9de5f0c59f02b0c96317010976 --- /dev/null +++ b/tests/auto/qmltest/canvas3d/tst_uniforms.js @@ -0,0 +1,922 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCanvas3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +var gl; +var positionLocation; +var inactiveUniformLocation; +var testUniformLocation; +var shaderProgram; +var buffer; +var vertexShader; +var fragmentShader; + +var uniform1i; +var uniform2i; +var uniform3i; +var uniform4i; +var uniform1f; +var uniform2f; +var uniform3f; +var uniform4f; +var uniform1b; +var uniform2b; +var uniform3b; +var uniform4b; +var uniform1iv; +var uniform2iv; +var uniform3iv; +var uniform4iv; +var uniform1fv; +var uniform2fv; +var uniform3fv; +var uniform4fv; +var uniform1bv; +var uniform2bv; +var uniform3bv; +var uniform4bv; +var uniformMatrix2fv; +var uniformMatrix3fv; +var uniformMatrix4fv; +var uniformSampler; + +var fillValue; +var testArray; + +function constructTestArrayJS(count) { + testArray = []; + for (var i = 0; i < count; i++) { + testArray[i] = fillValue++; + } + return testArray; +} + +function constructTestArrayBooleanJS(count) { + testArray = []; + for (var i = 0; i < count; i++) { + testArray[i] = Boolean(fillValue++ % 2); + } + return testArray; +} + +function constructTestArrayInt(count) { + testArray = new Int32Array(count); + for (var i = 0; i < count; i++) { + testArray[i] = fillValue++; + } + return testArray; +} + +function constructTestArrayFloat(count) { + testArray = new Float32Array(count); + for (var i = 0; i < count; i++) { + testArray[i] = fillValue++; + } + return testArray; +} + +function compareUniformValues(a, b) { + if (a !== b) { + console.log("initializeGL(): FAILURE: returned uniform doesn't have expected contents.", + "Expected:", a, "Actual:", b); + return false; + } + + return true; +} + +function compareUniformArrays(a, b) { + if (a.length !== b.length) { + console.log("initializeGL(): FAILURE: returned uniform array not the expected length. Expected:", + a.length, "Actual:", b.length); + return false; + } + + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + console.log("initializeGL(): FAILURE: returned uniform array doesn't have expected contents.", + "Expected:", a[i], "Actual:", b[i], "Index:", i); + return false; + } + } + + return true; +} + +function compareUniformSubArrays(index, len, a, b) { + var newArray = []; + + if (len !== b.length) { + console.log("initializeGL(): FAILURE: returned uniform arrays not the expected length. Expected:", + a.length - index, "Actual:", b.length); + return false; + } + + for (var i = 0; i < len; i++) { + newArray[i] = a[i + index]; + } + + return compareUniformArrays(newArray, b); +} +function compareUniformSubArraysTransposed(index, len, a, b) { + var newArray = []; + + if (len !== b.length) { + console.log("initializeGL(): FAILURE: returned uniform arrays not the expected length. Expected:", + a.length - index, "Actual:", b.length); + return false; + } + + var dim = Math.sqrt(len); + + // Transpose the original array + var newIndex = 0; + for (var i = 0; i < dim; i++) { + for (var j = 0; j < dim; j++) { + newArray[newIndex++] = a[index + (j * dim) + i]; + } + } + + return compareUniformArrays(newArray, b); +} + +function debugPrintArray(title, a) { + var len = a.length; + console.log(title); + for (var i = 0; i < len; i++) { + console.log(i, ":", a[i]); + } +} + +function getUniformValue(uniformName) { + var uniformLocation = gl.getUniformLocation(shaderProgram, uniformName); + var uniformValue = gl.getUniform(shaderProgram, uniformLocation); + + return uniformValue; +} + +function initializeGL(canvas) { + var initStatus = 0 + try { + gl = canvas.getContext("3d"); + buffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData( + gl.ARRAY_BUFFER, new Float32Array( + [-1.0, -1.0, + 1.0, -1.0, + -1.0, 1.0 + ]), + gl.STATIC_DRAW); + + if (!initShaders()) { + initStatus = 1; + } else { + gl.useProgram(shaderProgram); + + positionLocation = gl.getAttribLocation(shaderProgram, "a_position"); + gl.enableVertexAttribArray(positionLocation); + gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); + + inactiveUniformLocation = gl.getUniformLocation(shaderProgram, "inactiveUniform"); + testUniformLocation = gl.getUniformLocation(shaderProgram, "testUniform"); + + uniform1i = gl.getUniformLocation(shaderProgram, "i1"); + uniform2i = gl.getUniformLocation(shaderProgram, "i2"); + uniform3i = gl.getUniformLocation(shaderProgram, "i3"); + uniform4i = gl.getUniformLocation(shaderProgram, "i4"); + uniform1f = gl.getUniformLocation(shaderProgram, "f1"); + uniform2f = gl.getUniformLocation(shaderProgram, "f2"); + uniform3f = gl.getUniformLocation(shaderProgram, "f3"); + uniform4f = gl.getUniformLocation(shaderProgram, "f4"); + uniform1b = gl.getUniformLocation(shaderProgram, "b1"); + uniform2b = gl.getUniformLocation(shaderProgram, "b2"); + uniform3b = gl.getUniformLocation(shaderProgram, "b3"); + uniform4b = gl.getUniformLocation(shaderProgram, "b4"); + uniform1iv = gl.getUniformLocation(shaderProgram, "i1v"); + uniform2iv = gl.getUniformLocation(shaderProgram, "i2v"); + uniform3iv = gl.getUniformLocation(shaderProgram, "i3v"); + uniform4iv = gl.getUniformLocation(shaderProgram, "i4v"); + uniform1fv = gl.getUniformLocation(shaderProgram, "f1v"); + uniform2fv = gl.getUniformLocation(shaderProgram, "f2v"); + uniform3fv = gl.getUniformLocation(shaderProgram, "f3v"); + uniform4fv = gl.getUniformLocation(shaderProgram, "f4v"); + uniform1bv = gl.getUniformLocation(shaderProgram, "b1v"); + uniform2bv = gl.getUniformLocation(shaderProgram, "b2v"); + uniform3bv = gl.getUniformLocation(shaderProgram, "b3v"); + uniform4bv = gl.getUniformLocation(shaderProgram, "b4v"); + uniformMatrix2fv = gl.getUniformLocation(shaderProgram, "matrix2"); + uniformMatrix3fv = gl.getUniformLocation(shaderProgram, "matrix3"); + uniformMatrix4fv = gl.getUniformLocation(shaderProgram, "matrix4"); + uniformSampler = gl.getUniformLocation(shaderProgram, "uSampler") + + gl.activeTexture(gl.TEXTURE0); + gl.uniform1i(uniformSampler, 0); + + gl.clearColor(0.0, 0.0, 0.0, 1.0); + + gl.viewport(0, 0, + canvas.width * canvas.devicePixelRatio, + canvas.height * canvas.devicePixelRatio); + + // Test getActiveUniform + var uniformCount = 0; + var expectedUniformCount = 37; + var actualUniformCount = gl.getProgramParameter(shaderProgram, gl.ACTIVE_UNIFORMS); + + for (var i = 0; i < actualUniformCount; i++) { + var activeInfo = gl.getActiveUniform(shaderProgram, i); + if (activeInfo.name !== "") + uniformCount++; + if (activeInfo.name === "testUniform") { + if (activeInfo.size !== 1) { + console.log("initializeGL(): FAILURE: testUniform size wrong"); + return 2; + } + + if (activeInfo.type !== Context3D.FLOAT) { + console.log("initializeGL(): FAILURE: testUniform type wrong"); + return 3; + } + } + } + + if (uniformCount !== expectedUniformCount) { + console.log("initializeGL(): FAILURE: active uniform count wrong, expected:", + expectedUniformCount, "actual:", uniformCount); + return 4; + } + + // Test uniform setters and getters + var uniformValue = 0; + var checkValue = false; + fillValue = 1; + + gl.uniform1i(uniform1i, fillValue); + uniformValue = gl.getUniform(shaderProgram, uniform1i); + if (!compareUniformValues(fillValue, uniformValue)) + return 5; + fillValue++; + + constructTestArrayJS(2); + gl.uniform2i(uniform2i, testArray[0], testArray[1]); + uniformValue = gl.getUniform(shaderProgram, uniform2i); + if (!compareUniformArrays(testArray, uniformValue)) + return 6; + + constructTestArrayJS(3); + gl.uniform3i(uniform3i, testArray[0], testArray[1], testArray[2]); + uniformValue = gl.getUniform(shaderProgram, uniform3i); + if (!compareUniformArrays(testArray, uniformValue)) + return 7; + + constructTestArrayJS(4); + gl.uniform4i(uniform4i, testArray[0], testArray[1], testArray[2], testArray[3]); + uniformValue = gl.getUniform(shaderProgram, uniform4i); + if (!compareUniformArrays(testArray, uniformValue)) + return 8; + + gl.uniform1f(uniform1f, fillValue); + uniformValue = gl.getUniform(shaderProgram, uniform1f); + if (!compareUniformValues(fillValue, uniformValue)) + return 9; + fillValue++; + + constructTestArrayJS(2); + gl.uniform2f(uniform2f, testArray[0], testArray[1]); + uniformValue = gl.getUniform(shaderProgram, uniform2f); + if (!compareUniformArrays(testArray, uniformValue)) + return 10; + + constructTestArrayJS(3); + gl.uniform3f(uniform3f, testArray[0], testArray[1], testArray[2]); + uniformValue = gl.getUniform(shaderProgram, uniform3f); + if (!compareUniformArrays(testArray, uniformValue)) + return 11; + + constructTestArrayJS(4); + gl.uniform4f(uniform4f, testArray[0], testArray[1], testArray[2], testArray[3]); + uniformValue = gl.getUniform(shaderProgram, uniform4f); + if (!compareUniformArrays(testArray, uniformValue)) + return 12; + + gl.uniform1i(uniform1b, true); + uniformValue = gl.getUniform(shaderProgram, uniform1b); + if (!compareUniformValues(true, uniformValue)) + return 13; + fillValue++; + + constructTestArrayBooleanJS(2); + gl.uniform2i(uniform2b, testArray[0], testArray[1]); + uniformValue = gl.getUniform(shaderProgram, uniform2b); + if (!compareUniformArrays(testArray, uniformValue)) + return 14; + + constructTestArrayBooleanJS(3); + gl.uniform3i(uniform3b, testArray[0], testArray[1], testArray[2]); + uniformValue = gl.getUniform(shaderProgram, uniform3b); + if (!compareUniformArrays(testArray, uniformValue)) + return 15; + + constructTestArrayBooleanJS(4); + gl.uniform4i(uniform4b, testArray[0], testArray[1], testArray[2], testArray[3]); + uniformValue = gl.getUniform(shaderProgram, uniform4b); + if (!compareUniformArrays(testArray, uniformValue)) + return 16; + + // Test both javascript arrays and typed arrays for functions that take arrays + var arrayElements = 3; + var elementLen = 1; + gl.uniform1iv(uniform1iv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("i1v[0]"); + if (!compareUniformValues(testArray[0], uniformValue)) + return 17; + uniformValue = getUniformValue("i1v[1]"); + if (!compareUniformValues(testArray[1], uniformValue)) + return 18; + uniformValue = getUniformValue("i1v[2]"); + if (!compareUniformValues(testArray[2], uniformValue)) + return 19; + + elementLen = 2; + gl.uniform2iv(uniform2iv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("i2v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 20; + uniformValue = getUniformValue("i2v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 21; + uniformValue = getUniformValue("i2v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 22; + + elementLen = 3; + gl.uniform3iv(uniform3iv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("i3v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 23; + uniformValue = getUniformValue("i3v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 24; + uniformValue = getUniformValue("i3v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 25; + + elementLen = 4; + gl.uniform4iv(uniform4iv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("i4v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 26; + uniformValue = getUniformValue("i4v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 27; + uniformValue = getUniformValue("i4v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 28; + + elementLen = 1; + gl.uniform1fv(uniform1fv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("f1v[0]"); + if (!compareUniformValues(testArray[0], uniformValue)) + return 29; + uniformValue = getUniformValue("f1v[1]"); + if (!compareUniformValues(testArray[1], uniformValue)) + return 30; + uniformValue = getUniformValue("f1v[2]"); + if (!compareUniformValues(testArray[2], uniformValue)) + return 31; + + elementLen = 2; + gl.uniform2fv(uniform2fv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("f2v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 32; + uniformValue = getUniformValue("f2v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 33; + uniformValue = getUniformValue("f2v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 34; + + elementLen = 3; + gl.uniform3fv(uniform3fv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("f3v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 35; + uniformValue = getUniformValue("f3v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 36; + uniformValue = getUniformValue("f3v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 37; + + elementLen = 4; + gl.uniform4fv(uniform4fv, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("f4v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 38; + uniformValue = getUniformValue("f4v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 39; + uniformValue = getUniformValue("f4v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 40; + + elementLen = 1 + gl.uniform1iv(uniform1bv, constructTestArrayBooleanJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("b1v[0]"); + if (!compareUniformValues(testArray[0], uniformValue)) + return 41; + uniformValue = getUniformValue("b1v[1]"); + if (!compareUniformValues(testArray[1], uniformValue)) + return 42; + uniformValue = getUniformValue("b1v[2]"); + if (!compareUniformValues(testArray[2], uniformValue)) + return 43; + + elementLen = 2; + gl.uniform2iv(uniform2bv, constructTestArrayBooleanJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("b2v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 44; + uniformValue = getUniformValue("b2v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 45; + uniformValue = getUniformValue("b2v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 46; + + elementLen = 3; + gl.uniform3iv(uniform3bv, constructTestArrayBooleanJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("b3v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 47; + uniformValue = getUniformValue("b3v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 48; + uniformValue = getUniformValue("b3v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 49; + + elementLen = 4; + gl.uniform4iv(uniform4bv, constructTestArrayBooleanJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("b4v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 50; + uniformValue = getUniformValue("b4v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 51; + uniformValue = getUniformValue("b4v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 52; + + elementLen = 2 * 2; + gl.uniformMatrix2fv(uniformMatrix2fv, false, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix2[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 53; + uniformValue = getUniformValue("matrix2[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 54; + uniformValue = getUniformValue("matrix2[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 55; + + gl.uniformMatrix2fv(uniformMatrix2fv, true, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix2[0]"); + if (!compareUniformSubArraysTransposed(0 * elementLen, elementLen, testArray, uniformValue)) + return 56; + uniformValue = getUniformValue("matrix2[1]"); + if (!compareUniformSubArraysTransposed(1 * elementLen, elementLen, testArray, uniformValue)) + return 57; + uniformValue = getUniformValue("matrix2[2]"); + if (!compareUniformSubArraysTransposed(2 * elementLen, elementLen, testArray, uniformValue)) + return 58; + + elementLen = 3 * 3; + gl.uniformMatrix3fv(uniformMatrix3fv, false, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix3[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 59; + uniformValue = getUniformValue("matrix3[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 60; + uniformValue = getUniformValue("matrix3[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 61; + + gl.uniformMatrix3fv(uniformMatrix3fv, true, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix3[0]"); + if (!compareUniformSubArraysTransposed(0 * elementLen, elementLen, testArray, uniformValue)) + return 62; + uniformValue = getUniformValue("matrix3[1]"); + if (!compareUniformSubArraysTransposed(1 * elementLen, elementLen, testArray, uniformValue)) + return 63; + uniformValue = getUniformValue("matrix3[2]"); + if (!compareUniformSubArraysTransposed(2 * elementLen, elementLen, testArray, uniformValue)) + return 64; + + elementLen = 4 * 4; + gl.uniformMatrix4fv(uniformMatrix4fv, false, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix4[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 65; + uniformValue = getUniformValue("matrix4[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 66; + uniformValue = getUniformValue("matrix4[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 67; + + gl.uniformMatrix4fv(uniformMatrix4fv, true, constructTestArrayJS(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix4[0]"); + if (!compareUniformSubArraysTransposed(0 * elementLen, elementLen, testArray, uniformValue)) + return 68; + uniformValue = getUniformValue("matrix4[1]"); + if (!compareUniformSubArraysTransposed(1 * elementLen, elementLen, testArray, uniformValue)) + return 69; + uniformValue = getUniformValue("matrix4[2]"); + if (!compareUniformSubArraysTransposed(2 * elementLen, elementLen, testArray, uniformValue)) + return 70; + + elementLen = 1; + gl.uniform1iv(uniform1iv, constructTestArrayInt(arrayElements * elementLen)); + + uniformValue = getUniformValue("i1v[0]"); + if (!compareUniformValues(testArray[0], uniformValue)) + return 71; + uniformValue = getUniformValue("i1v[1]"); + if (!compareUniformValues(testArray[1], uniformValue)) + return 72; + uniformValue = getUniformValue("i1v[2]"); + if (!compareUniformValues(testArray[2], uniformValue)) + return 73; + + elementLen = 2; + gl.uniform2iv(uniform2iv, constructTestArrayInt(arrayElements * elementLen)); + + uniformValue = getUniformValue("i2v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 74; + uniformValue = getUniformValue("i2v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 75; + uniformValue = getUniformValue("i2v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 76; + + elementLen = 3; + gl.uniform3iv(uniform3iv, constructTestArrayInt(arrayElements * elementLen)); + + uniformValue = getUniformValue("i3v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 77; + uniformValue = getUniformValue("i3v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 78; + uniformValue = getUniformValue("i3v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 79; + + elementLen = 4; + gl.uniform4iv(uniform4iv, constructTestArrayInt(arrayElements * elementLen)); + + uniformValue = getUniformValue("i4v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 80; + uniformValue = getUniformValue("i4v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 81; + uniformValue = getUniformValue("i4v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 82; + + elementLen = 1; + gl.uniform1fv(uniform1fv, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("f1v[0]"); + if (!compareUniformValues(testArray[0], uniformValue)) + return 83; + uniformValue = getUniformValue("f1v[1]"); + if (!compareUniformValues(testArray[1], uniformValue)) + return 84; + uniformValue = getUniformValue("f1v[2]"); + if (!compareUniformValues(testArray[2], uniformValue)) + return 85; + + elementLen = 2; + gl.uniform2fv(uniform2fv, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("f2v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 86; + uniformValue = getUniformValue("f2v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 87; + uniformValue = getUniformValue("f2v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 88; + + elementLen = 3; + gl.uniform3fv(uniform3fv, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("f3v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 89; + uniformValue = getUniformValue("f3v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 90; + uniformValue = getUniformValue("f3v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 91; + + elementLen = 4; + gl.uniform4fv(uniform4fv, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("f4v[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 92; + uniformValue = getUniformValue("f4v[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 93; + uniformValue = getUniformValue("f4v[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 94; + + elementLen = 2 * 2; + gl.uniformMatrix2fv(uniformMatrix2fv, false, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix2[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 95; + uniformValue = getUniformValue("matrix2[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 96; + uniformValue = getUniformValue("matrix2[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 97; + + gl.uniformMatrix2fv(uniformMatrix2fv, true, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix2[0]"); + if (!compareUniformSubArraysTransposed(0 * elementLen, elementLen, testArray, uniformValue)) + return 98; + uniformValue = getUniformValue("matrix2[1]"); + if (!compareUniformSubArraysTransposed(1 * elementLen, elementLen, testArray, uniformValue)) + return 99; + uniformValue = getUniformValue("matrix2[2]"); + if (!compareUniformSubArraysTransposed(2 * elementLen, elementLen, testArray, uniformValue)) + return 100; + + elementLen = 3 * 3; + gl.uniformMatrix3fv(uniformMatrix3fv, false, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix3[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 101; + uniformValue = getUniformValue("matrix3[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 102; + uniformValue = getUniformValue("matrix3[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 103; + + gl.uniformMatrix3fv(uniformMatrix3fv, true, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix3[0]"); + if (!compareUniformSubArraysTransposed(0 * elementLen, elementLen, testArray, uniformValue)) + return 104; + uniformValue = getUniformValue("matrix3[1]"); + if (!compareUniformSubArraysTransposed(1 * elementLen, elementLen, testArray, uniformValue)) + return 105; + uniformValue = getUniformValue("matrix3[2]"); + if (!compareUniformSubArraysTransposed(2 * elementLen, elementLen, testArray, uniformValue)) + return 106; + + elementLen = 4 * 4; + gl.uniformMatrix4fv(uniformMatrix4fv, false, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix4[0]"); + if (!compareUniformSubArrays(0 * elementLen, elementLen, testArray, uniformValue)) + return 107; + uniformValue = getUniformValue("matrix4[1]"); + if (!compareUniformSubArrays(1 * elementLen, elementLen, testArray, uniformValue)) + return 108; + uniformValue = getUniformValue("matrix4[2]"); + if (!compareUniformSubArrays(2 * elementLen, elementLen, testArray, uniformValue)) + return 109; + + gl.uniformMatrix4fv(uniformMatrix4fv, true, constructTestArrayFloat(arrayElements * elementLen)); + + uniformValue = getUniformValue("matrix4[0]"); + if (!compareUniformSubArraysTransposed(0 * elementLen, elementLen, testArray, uniformValue)) + return 110; + uniformValue = getUniformValue("matrix4[1]"); + if (!compareUniformSubArraysTransposed(1 * elementLen, elementLen, testArray, uniformValue)) + return 111; + uniformValue = getUniformValue("matrix4[2]"); + if (!compareUniformSubArraysTransposed(2 * elementLen, elementLen, testArray, uniformValue)) + return 112; + + gl.uniform1i(uniformSampler, 1); + uniformValue = gl.getUniform(shaderProgram, uniformSampler); + if (!compareUniformValues(1, uniformValue)) + return 113; + + constructTestArrayJS(3); + var uniformLocation = gl.getUniformLocation(shaderProgram, "uStruct.first"); + gl.uniform3f(uniformLocation, testArray[0], testArray[1], testArray[2]); + uniformValue = gl.getUniform(shaderProgram, uniformLocation); + if (!compareUniformArrays(testArray, uniformValue)) + return 114; + + uniformLocation = gl.getUniformLocation(shaderProgram, "uStruct.second"); + gl.uniform1i(uniformLocation, fillValue); + uniformValue = gl.getUniform(shaderProgram, uniformLocation); + if (!compareUniformValues(fillValue, uniformValue)) + return 115; + fillValue++; + + constructTestArrayJS(3); + uniformLocation = gl.getUniformLocation(shaderProgram, "uStructv[0].first"); + gl.uniform3f(uniformLocation, testArray[0], testArray[1], testArray[2]); + uniformValue = gl.getUniform(shaderProgram, uniformLocation); + if (!compareUniformArrays(testArray, uniformValue)) + return 116; + + uniformLocation = gl.getUniformLocation(shaderProgram, "uStructv[0].second"); + gl.uniform1i(uniformLocation, fillValue); + uniformValue = gl.getUniform(shaderProgram, uniformLocation); + if (!compareUniformValues(fillValue, uniformValue)) + return 117; + fillValue++; + } + } catch(e) { + console.log("initializeGL(): FAILURE!"); + console.log(""+e); + console.log(""+e.message); + initStatus = -1; + } + return initStatus; +} + +function paintGL(canvas) { + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + return 0; +} + +function initShaders() +{ + vertexShader = compileShader("attribute vec2 a_position; \ + void main() { \ + gl_Position = vec4(a_position, 0.0, 1.0); \ + }", gl.VERTEX_SHADER); + fragmentShader = compileShader("struct TestStruct \ + { \ + highp vec3 first; \ + int second; \ + }; \ + uniform highp float inactiveUniform; \ + uniform highp float testUniform; \ + uniform int i1; \ + uniform ivec2 i2; \ + uniform ivec3 i3; \ + uniform ivec4 i4; \ + uniform highp float f1; \ + uniform highp vec2 f2; \ + uniform highp vec3 f3; \ + uniform highp vec4 f4; \ + uniform bool b1; \ + uniform bvec2 b2; \ + uniform bvec3 b3; \ + uniform bvec4 b4; \ + uniform int i1v[3]; \ + uniform ivec2 i2v[3]; \ + uniform ivec3 i3v[3]; \ + uniform ivec4 i4v[3]; \ + uniform highp float f1v[3]; \ + uniform highp vec2 f2v[3]; \ + uniform highp vec3 f3v[3]; \ + uniform highp vec4 f4v[3]; \ + uniform bool b1v[3]; \ + uniform bvec2 b2v[3]; \ + uniform bvec3 b3v[3]; \ + uniform bvec4 b4v[3]; \ + uniform highp mat2 matrix2[3]; \ + uniform highp mat3 matrix3[3]; \ + uniform highp mat4 matrix4[3]; \ + uniform sampler2D uSampler; \ + uniform TestStruct uStruct; \ + uniform TestStruct uStructv[3]; \ + void main() { \ + int iValue = i1 + i2.x + i3.y + i4.z; \ + highp float fValue = f1 + f2.x + f3.y + f4.z; \ + if (b1 || b2.x || b3.y || b4.z) \ + iValue++; \ + fValue += uStruct.first.x; \ + iValue += uStruct.second; \ + for (int i = 0; i < 3; i++) { \ + iValue += i1v[i]; \ + iValue += i2v[i].x; \ + iValue += i3v[i].y; \ + iValue += i4v[i].z; \ + fValue += f1v[i]; \ + fValue += f2v[i].x; \ + fValue += f3v[i].y; \ + fValue += f4v[i].z; \ + fValue += matrix2[i][0][0]; \ + fValue += matrix3[i][1][1]; \ + fValue += matrix4[i][2][2]; \ + if (b1v[i] || b2v[i].x || b3v[i].y || b4v[i].z) \ + iValue++; \ + fValue += uStructv[i].first.x; \ + iValue += uStructv[i].second; \ + } \ + highp vec4 texelColor = texture2D(uSampler, vec2(fValue, fValue)); \ + if (iValue > 30) { \ + gl_FragColor = vec4(fValue, testUniform, texelColor.b, 1.0); \ + } else { \ + gl_FragColor = texelColor; \ + } \ + }", gl.FRAGMENT_SHADER); + + shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + // Check linking status + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + console.log("Could not initialize shaders"); + console.log(gl.getProgramInfoLog(shaderProgram)); + return false; + } + + return true; +} + +function compileShader(str, type) { + var shader = gl.createShader(type); + gl.shaderSource(shader, str); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.log("JS:Shader compile failed"); + console.log(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +} diff --git a/tests/auto/qmltest/canvas3d/tst_uniforms.qml b/tests/auto/qmltest/canvas3d/tst_uniforms.qml new file mode 100644 index 0000000000000000000000000000000000000000..a42d89ce1e6cf873af69b598073f726289ca6a9f --- /dev/null +++ b/tests/auto/qmltest/canvas3d/tst_uniforms.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCanvas3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtCanvas3D 1.0 +import QtTest 1.0 + +import "tst_uniforms.js" as Content + +Item { + id: top + height: 300 + width: 300 + + Canvas3D { + id: uniforms_test + property bool heightChanged: false + property bool widthChanged: false + property int initStatus: -1 + property int renderStatus: -1 + + anchors.fill: parent + onInitializeGL: initStatus = Content.initializeGL(uniforms_test) + onPaintGL: { + renderStatus = Content.paintGL(uniforms_test) + } + onHeightChanged: heightChanged = true + onWidthChanged: widthChanged = true + } + + TestCase { + name: "Canvas3D_test_uniforms" + when: windowShown + + function test_uniforms() { + waitForRendering(uniforms_test) + tryCompare(uniforms_test, "initStatus", 0) + tryCompare(uniforms_test, "renderStatus", 0) + } + } +}