Newer
Older
/****************************************************************************
**
** 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.
**
** 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$
**
****************************************************************************/
#include "canvasglstatedump_p.h"
#include "activeinfo3d_p.h"
#include "canvas3d_p.h"
#include "context3d_p.h"
#include "texture3d_p.h"
#include "shader3d_p.h"
#include "program3d_p.h"
#include "buffer3d_p.h"
#include "framebuffer3d_p.h"
#include "renderbuffer3d_p.h"
#include "uniformlocation_p.h"
#include "teximage3d_p.h"
#include "arrayutils_p.h"
#include "shaderprecisionformat_p.h"
#include "enumtostringmap_p.h"
#include "canvas3dcommon_p.h"
#include "contextextensions_p.h"
#include <QtGui/QOpenGLShader>
#include <QtQml/private/qv4typedarray_p.h>
#include <QtQml/private/qv4arraybuffer_p.h>
#include <QtQml/private/qjsvalue_p.h>
#include <QtCore/private/qbytedata_p.h>
/*!
* \qmltype Context3D
* \since QtCanvas3D 1.0
* \ingroup qtcanvas3d-qml-types
* \brief Provides the 3D rendering API and context.
*
* An uncreatable QML type that provides a WebGL-like API that can be used to draw 3D graphics to
* the Canvas3D element. You can get it by calling \l{Canvas3D::getContext}{Canvas3D.getContext}
* method.
*
* \sa Canvas3D
*/
CanvasContext::CanvasContext(QOpenGLContext *context, QSurface *surface, QQmlEngine *engine,
int width, int height, bool isES2, QObject *parent) :
CanvasAbstractObject(parent),
m_v4engine(QQmlEnginePrivate::getV4Engine(engine)),
m_unpackFlipYEnabled(false),
m_unpackPremultiplyAlphaEnabled(false),
m_glViewportRect(0, 0, width, height),
m_devicePixelRatio(1.0),
m_currentProgram(0),
m_currentArrayBuffer(0),
m_currentElementArrayBuffer(0),
m_context(context),
m_surface(surface),
m_error(NO_ERROR),
m_currentFramebuffer(0),
m_map(EnumToStringMap::newInstance()),
m_stateDumpExt(0),
m_standardDerivatives(0)
m_extensions = m_context->extensions();
int value = 0;
glGetIntegerv(MAX_VERTEX_ATTRIBS, &value);
m_maxVertexAttribs = uint(value);
#ifndef QT_NO_DEBUG
const GLubyte *version = glGetString(GL_VERSION);
qCDebug(canvas3dinfo) << "Context3D::" << __FUNCTION__
<< "OpenGL version:" << (const char *)version;
qCDebug(canvas3dinfo) << "Context3D::" << __FUNCTION__
<< "GLSL version:" << (const char *)version;
qCDebug(canvas3dinfo) << "Context3D::" << __FUNCTION__
<< "EXTENSIONS: " << m_extensions;
#endif
}
/*!
* \internal
*/
CanvasContext::~CanvasContext()
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__;
EnumToStringMap::deleteInstance();
}
/*!
* \internal
*/
void CanvasContext::setCanvas(Canvas *canvas)
{
if (m_canvas != canvas) {
if (m_canvas) {
disconnect(m_canvas, &QQuickItem::widthChanged, this, 0);
disconnect(m_canvas, &QQuickItem::heightChanged, this, 0);
}
connect(m_canvas, &QQuickItem::widthChanged,
this, &CanvasContext::drawingBufferWidthChanged);
connect(m_canvas, &QQuickItem::heightChanged,
this, &CanvasContext::drawingBufferHeightChanged);
/*!
* \qmlproperty Canvas3D Context3D::canvas
* Holds the read only reference to the Canvas3D for this Context3D.
*/
Canvas *CanvasContext::canvas()
{
return m_canvas;
}
* \qmlproperty int Context3D::drawingBufferWidth
* Holds the current read-only logical pixel width of the drawing buffer. To get width in physical pixels
* you need to multiply this with the \c devicePixelRatio.
*/
uint CanvasContext::drawingBufferWidth()
{
uint width = 0;
if (m_canvas)
width = m_canvas->width();
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(): " << width;
return width;
}
/*!
* \qmlproperty int Context3D::drawingBufferHeight
* Holds the current read-only logical pixel height of the drawing buffer. To get height in physical pixels
* you need to multiply this with the \c devicePixelRatio.
*/
uint CanvasContext::drawingBufferHeight()
{
uint height = 0;
if (m_canvas)
height = m_canvas->height();
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(): " << height;
return height;
}
/*!
* \internal
*/
QString CanvasContext::glEnumToString(glEnums value) const
{
return m_map->lookUp(value);
}
/*!
* \internal
*/
void CanvasContext::logAllGLErrors(const QString &funcName)
if (!((QLoggingCategory &) canvas3dglerrors()).isDebugEnabled())
return;
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) {
qCWarning(canvas3dglerrors) << "Context3D::" << funcName
<< ": OpenGL ERROR: "
<< glEnumToString(CanvasContext::glEnums(err));
}
/*!
* \internal
*/
void CanvasContext::setContextAttributes(const CanvasContextAttributes &attribs)
{
m_contextAttributes.setFrom(attribs);
}
/*!
* \internal
*/
float CanvasContext::devicePixelRatio()
{
return m_devicePixelRatio;
}
/*!
* \internal
*/
void CanvasContext::setDevicePixelRatio(float ratio)
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__ << "(" << ratio << ")";
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
m_devicePixelRatio = ratio;
}
/*!
* \internal
*/
QRect CanvasContext::glViewportRect() const
{
return m_glViewportRect;
}
/*!
* \internal
*/
GLuint CanvasContext::currentFramebuffer()
{
if (!m_currentFramebuffer)
return 0;
return m_currentFramebuffer->id();
}
/*!
* \qmlmethod ShaderPrecisionFormat Context3D::getShaderPrecisionFormat(glEnums shadertype, glEnums precisiontype)
* Return a new ShaderPrecisionFormat describing the range and precision for the specified shader
* numeric format.
* \a shadertype Type of the shader, either \c Context3D.FRAGMENT_SHADER or
* \c{Context3D.VERTEX_SHADER}.
* \a precisiontype Can be \c{Context3D.LOW_FLOAT}, \c{Context3D.MEDIUM_FLOAT},
* \c{Context3D.HIGH_FLOAT}, \c{Context3D.LOW_INT}, \c{Context3D.MEDIUM_INT} or
* \c{Context3D.HIGH_INT}.
*
* \sa ShaderPrecisionFormat
*/
/*!
* \internal
*/
QJSValue CanvasContext::getShaderPrecisionFormat(glEnums shadertype,
glEnums precisiontype)
QString str = QString(__FUNCTION__);
str += QStringLiteral("(shaderType:")
+ glEnumToString(shadertype)
+ QStringLiteral(", precisionType:")
+ glEnumToString(precisiontype)
+ QStringLiteral(")");
qCDebug(canvas3drendering) << "Context3D::" << str;
GLint range[2];
range[0] = 1;
range[1] = 1;
GLint precision = 1;
glGetShaderPrecisionFormat((GLenum)(shadertype), (GLenum)(precisiontype), range, &precision);
CanvasShaderPrecisionFormat *format = new CanvasShaderPrecisionFormat();
format->setPrecision(int(precision));
format->setRangeMin(int(range[0]));
format->setRangeMax(int(range[1]));
}
/*!
* \qmlmethod bool Context3D::isContextLost()
* Always returns false.
*/
/*!
* \internal
*/
bool CanvasContext::isContextLost()
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(): false";
return false;
}
/*!
* \qmlmethod ContextAttributes Context3D::getContextAttributes()
* Returns a copy of the actual context parameters that are used in the current context.
*/
/*!
* \internal
*/
QJSValue CanvasContext::getContextAttributes()
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__ << "()";
CanvasContextAttributes *attributes = new CanvasContextAttributes();
attributes->setAlpha(m_contextAttributes.alpha());
attributes->setDepth(m_contextAttributes.depth());
attributes->setStencil(m_contextAttributes.stencil());
attributes->setAntialias(m_contextAttributes.antialias());
attributes->setPremultipliedAlpha(m_contextAttributes.premultipliedAlpha());
attributes->setPreserveDrawingBuffer(m_contextAttributes.preserveDrawingBuffer());
attributes->setPreferLowPowerToHighPerformance(
m_contextAttributes.preferLowPowerToHighPerformance());
attributes->setFailIfMajorPerformanceCaveat(
m_contextAttributes.failIfMajorPerformanceCaveat());
return m_engine->newQObject(attributes);
}
/*!
* \qmlmethod void Context3D::flush()
* Indicates to graphics driver that previously sent commands must complete within finite time.
*/
/*!
* \internal
*/
void CanvasContext::flush()
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "()";
}
/*!
* \qmlmethod void Context3D::finish()
* Forces all previous 3D rendering commands to complete.
*/
/*!
* \internal
*/
void CanvasContext::finish()
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "()";
}
/*!
* \qmlmethod Texture3D Context3D::createTexture()
* Create a Texture3D object and initialize a name for it as by calling \c{glGenTextures()}.
*/
/*!
* \internal
*/
QJSValue value = m_engine->newQObject(texture);
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "():" << value.toString();
* \qmlmethod void Context3D::deleteTexture(Texture3D texture3D)
* Deletes the given texture as if by calling \c{glDeleteTextures()}.
* Calling this method repeatedly on the same object has no side effects.
* \a texture3D is the Texture3D to be deleted.
void CanvasContext::deleteTexture(QJSValue texture3D)
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(texture:" << texture3D.toString()
<< ")";
CanvasTexture *texture = getAsTexture3D(texture3D);
if (!texture) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID texture handle:" << texture3D.toString();
}
}
/*!
* \qmlmethod void Context3D::scissor(int x, int y, int width, int height)
* Defines a rectangle that constrains the drawing.
* \a x is theleft edge of the rectangle.
* \a y is the bottom edge of the rectangle.
* \a width is the width of the rectangle.
* \a height is the height of the rectangle.
*/
/*!
* \internal
*/
void CanvasContext::scissor(int x, int y, int width, int height)
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(x:" << x
<< ", y:" << y
<< ", width:" << width
<< ", height:" << height
<< ")";
}
/*!
* \qmlmethod void Context3D::activeTexture(glEnums texture)
* Sets the given texture unit as active. Number of texture units is implementation dependent,
* but must be at least 8. Initially \c Context3D.TEXTURE0 is active.
* \a texture must be one of \c Context3D.TEXTUREi values where \c i ranges from \c 0 to
* \c{(Context3D.MAX_COMBINED_TEXTURE_IMAGE_UNITS-1)}.
*/
/*!
* \internal
*/
void CanvasContext::activeTexture(glEnums texture)
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(texture:" << glEnumToString(texture)
<< ")";
* \qmlmethod void Context3D::bindTexture(glEnums target, Texture3D texture3D)
* Bind a Texture3D to a texturing target.
* \a target is the target of the active texture unit to which the Texture3D will be bound.
* Must be either \c{Context3D.TEXTURE_2D} or \c{Context3D.TEXTURE_CUBE_MAP}.
* \a texture3D is the Texture3D to be bound.
void CanvasContext::bindTexture(glEnums target, QJSValue texture3D)
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(target:" << glEnumToString(target)
<< ", texture:" << texture3D.toString()
<< ")";
CanvasTexture *texture = getAsTexture3D(texture3D);
if (target == TEXTURE_2D)
m_currentTexture2D = texture;
else if (target == TEXTURE_CUBE_MAP)
m_currentTextureCubeMap = texture;
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ": Trying to bind deleted texture object";
if (target == TEXTURE_2D)
m_currentTexture2D->bind(target);
else if (target == TEXTURE_CUBE_MAP)
m_currentTextureCubeMap->bind(target);
}
/*!
* \qmlmethod void Context3D::generateMipmap(glEnums target)
* Generates a complete set of mipmaps for a texture object of the currently active texture unit.
* \a target defines the texture target to which the texture object is bound whose mipmaps will be
* generated. Must be either \c{Context3D.TEXTURE_2D} or \c{Context3D.TEXTURE_CUBE_MAP}.
*/
/*!
* \internal
*/
void CanvasContext::generateMipmap(glEnums target)
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(target:" << glEnumToString(target)
<< ")";
if (target == TEXTURE_2D) {
if (!m_currentTexture2D) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current TEXTURE_2D bound";
m_error = INVALID_OPERATION;
} else if (!m_currentTexture2D->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound TEXTURE_2D is deleted";
m_error = INVALID_OPERATION;
} else {
glGenerateMipmap(target);
logAllGLErrors(__FUNCTION__);
}
} else if (target == TEXTURE_CUBE_MAP) {
if (!m_currentTextureCubeMap) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current TEXTURE_CUBE_MAP bound";
m_error = INVALID_OPERATION;
} else if (!m_currentTextureCubeMap->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound TEXTURE_CUBE_MAP is deleted";
m_error = INVALID_OPERATION;
} else {
glGenerateMipmap(target);
logAllGLErrors(__FUNCTION__);
}
}
}
/*!
* \qmlmethod bool Context3D::isTexture(Object anyObject)
* Returns true if the given object is a valid Texture3D object.
* \a anyObject is the object that is to be verified as a valid texture.
*/
/*!
* \internal
*/
bool CanvasContext::isTexture(QJSValue anyObject)
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(anyObject:" << anyObject.toString()
<< ")";
CanvasTexture *texture = getAsTexture3D(anyObject);
if (!texture)
return glIsTexture(texture->textureId());
}
/*!
* \internal
*/
CanvasTexture *CanvasContext::getAsTexture3D(QJSValue anyObject)
{
if (!anyObject.isQObject())
return 0;
if (!isOfType(anyObject, "QtCanvas3D::CanvasTexture"))
return 0;
CanvasTexture *texture = static_cast<CanvasTexture *>(anyObject.toQObject());
}
/*!
* \qmlmethod void Context3D::compressedTexImage2D(glEnums target, int level, glEnums internalformat, int width, int height, int border, TypedArray pixels)
* Not supported, \c{Context3D.INVALID_OPERATION} is generated when called.
* \a target, \a level, \a internalformat, \a width, \a height, \a border and \a pixels are ignored.
*/
/*!
* \internal
*/
void CanvasContext::compressedTexImage2D(glEnums target, int level, glEnums internalformat,
int width, int height, int border,
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(target:" << glEnumToString(target)
<< ", level:" << level
<< ", internalformat:" << glEnumToString(internalformat)
<< ", width:" << width
<< ", height:" << height
<< ", border:" << border
<< ", pixels:" << pixels.toString()
<< ")";
if (target == TEXTURE_2D) {
if (!m_currentTexture2D) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current TEXTURE_2D bound";
m_error = INVALID_OPERATION;
return;
} else if (!m_currentTexture2D->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound TEXTURE_2D is deleted";
m_error = INVALID_OPERATION;
return;
}
} else if (target == TEXTURE_CUBE_MAP) {
if (!m_currentTextureCubeMap) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current TEXTURE_CUBE_MAP bound";
m_error = INVALID_OPERATION;
return;
} else if (!m_currentTextureCubeMap->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound TEXTURE_CUBE_MAP is deleted";
m_error = INVALID_OPERATION;
return;
}
}
QV4::Scope scope(m_v4engine);
QV4::Scoped<QV4::TypedArray> typedArray(scope,
QJSValuePrivate::convertedToValue(m_v4engine, pixels));
if (typedArray) {
glCompressedTexImage2D(target,
level,
internalformat,
width, height, border,
typedArray->byteLength(),
(GLvoid *) typedArray->arrayData()->data());
logAllGLErrors(__FUNCTION__);
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_VALUE pixels must be TypedArray";
m_error = INVALID_VALUE;
return;
}
}
/*!
* \qmlmethod void Context3D::compressedTexSubImage2D(glEnums target, int level, int xoffset, int yoffset, int width, int height, glEnums format, TypedArray pixels)
* Not supported, \c{Context3D.INVALID_OPERATION} is generated when called.
* \a target, \a level, \a xoffset, \a yoffset, \a width, \a height, \a format and \a pixels are
* ignored.
*/
/*!
* \internal
*/
void CanvasContext::compressedTexSubImage2D(glEnums target, int level,
int xoffset, int yoffset,
int width, int height,
glEnums format,
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(target:" << glEnumToString(target)
<< ", level:" << level
<< ", xoffset:" << xoffset
<< ", yoffset:" << yoffset
<< ", width:" << width
<< ", height:" << height
<< ", format:" << glEnumToString(format)
<< ", pixels:" << pixels.toString()
<< ")";
if (target == TEXTURE_2D) {
if (!m_currentTexture2D) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current TEXTURE_2D bound";
m_error = INVALID_OPERATION;
return;
} else if (!m_currentTexture2D->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound TEXTURE_2D is deleted";
m_error = INVALID_OPERATION;
return;
}
} else if (target == TEXTURE_CUBE_MAP) {
if (!m_currentTextureCubeMap) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current TEXTURE_CUBE_MAP bound";
m_error = INVALID_OPERATION;
return;
} else if (!m_currentTextureCubeMap->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound TEXTURE_CUBE_MAP is deleted";
m_error = INVALID_OPERATION;
return;
}
}
QV4::Scope scope(m_v4engine);
QV4::Scoped<QV4::TypedArray> typedArray(scope,
QJSValuePrivate::convertedToValue(m_v4engine, pixels));
if (typedArray) {
glCompressedTexSubImage2D(target,
level,
xoffset, yoffset,
width, height,
format,
typedArray->byteLength(),
(GLvoid *) typedArray->arrayData()->data());
logAllGLErrors(__FUNCTION__);
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_VALUE pixels must be TypedArray";
m_error = INVALID_VALUE;
return;
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
}
}
/*!
* \qmlmethod void Context3D::copyTexImage2D(glEnums target, int level, glEnums internalformat, int x, int y, int width, int height, int border)
* Copies pixels into currently bound 2D texture.
* \a target specifies the target texture of the active texture unit. Must be \c{Context3D.TEXTURE_2D},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_X},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Y},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Z}.
* \a level specifies the level of detail number. Level \c 0 is the base image level. Level \c n is
* the \c{n}th mipmap reduction image.
* \a internalformat specifies the internal format of the texture. Must be \c{Context3D.ALPHA},
* \c{Context3D.LUMINANCE}, \c{Context3D.LUMINANCE_ALPHA}, \c{Context3D.RGB} or \c{Context3D.RGBA}.
* \a x specifies the window coordinate of the left edge of the rectangular region of pixels to be
* copied.
* \a y specifies the window coordinate of the lower edge of the rectangular region of pixels to be
* copied.
* \a width specifies the width of the texture image. All implementations will support 2D texture
* images that are at least 64 texels wide and cube-mapped texture images that are at least 16
* texels wide.
* \a height specifies the height of the texture image. All implementations will support 2D texture
* images that are at least 64 texels high and cube-mapped texture images that are at least 16
* texels high.
* \a border must be \c{0}.
*/
/*!
* \internal
*/
void CanvasContext::copyTexImage2D(glEnums target, int level, glEnums internalformat,
int x, int y, int width, int height,
int border)
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(target:" << glEnumToString(target)
<< ", level:" << level
<< ", internalformat:" << glEnumToString(internalformat)
<< ", x:" << x
<< ", y:" << y
<< ", width:" << width
<< ", height:" << height
<< ", border:" << border
<< ")";
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current texture bound";
} else if (!m_currentTexture2D->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound texture is deleted";
m_error = INVALID_OPERATION;
} else {
glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
}
}
/*!
* \qmlmethod void Context3D::copyTexSubImage2D(glEnums target, int level, int xoffset, int yoffset, int x, int y, int width, int height)
* Copies to into a currently bound 2D texture subimage.
* \a target specifies the target texture of the active texture unit. Must be
* \c{Context3D.TEXTURE_2D},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_X},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Y},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Z}.
* \a level specifies the level of detail number. Level \c 0 is the base image level. Level \c n is
* the \c{n}th mipmap reduction image.
* \a xoffset specifies the texel offset in the x direction within the texture array.
* \a yoffset specifies the texel offset in the y direction within the texture array.
* \a x specifies the window coordinate of the left edge of the rectangular region of pixels to be
* copied.
* \a y specifies the window coordinate of the lower edge of the rectangular region of pixels to be
* copied.
* \a width specifies the width of the texture subimage.
* \a height specifies the height of the texture subimage.
*/
/*!
* \internal
*/
void CanvasContext::copyTexSubImage2D(glEnums target, int level,
int xoffset, int yoffset,
int x, int y,
int width, int height)
{
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(target:" << glEnumToString(target)
<< ", level:" << level
<< ", xoffset:" << xoffset
<< ", yoffset:" << yoffset
<< ", x:" << x
<< ", y:" << y
<< ", width:" << width
<< ", height:" << height
<< ")";
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION No current texture bound";
} else if (!m_currentTexture2D->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound texture is deleted";
m_error = INVALID_OPERATION;
} else {
copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
}
}
/*!
* \qmlmethod void Context3D::texImage2D(glEnums target, int level, glEnums internalformat, int width, int height, int border, glEnums format, glEnums type, TypedArray pixels)
* Specify a 2D texture image.
* \a target specifies the target texture of the active texture unit. Must be one of:
* \c{Context3D.TEXTURE_2D},
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_X},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Y},
* \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Z}.
* \a level specifies the level of detail number. Level \c 0 is the base image level. Level \c n is
* the \c{n}th mipmap reduction image.
* \a internalformat specifies the internal format of the texture. Must be \c{Context3D.ALPHA},
* \c{Context3D.LUMINANCE}, \c{Context3D.LUMINANCE_ALPHA}, \c{Context3D.RGB} or \c{Context3D.RGBA}.
* \a width specifies the width of the texture image. All implementations will support 2D texture
* images that are at least 64 texels wide and cube-mapped texture images that are at least 16
* texels wide.
* \a height specifies the height of the texture image. All implementations will support 2D texture
* images that are at least 64 texels high and cube-mapped texture images that are at least 16
* texels high.
* \a border must be \c{0}.
* \a format specifies the format of the texel data given in \a pixels, must match the value
* of \a internalFormat.
* \a type specifies the data type of the data given in \a pixels, must match the TypedArray type
* of \a pixels. Must be \c{Context3D.UNSIGNED_BYTE}, \c{Context3D.UNSIGNED_SHORT_5_6_5},
* \c{Context3D.UNSIGNED_SHORT_4_4_4_4} or \c{Context3D.UNSIGNED_SHORT_5_5_5_1}.
* \a pixels specifies the TypedArray containing the image data. If pixels is \c{null}, a buffer
* of sufficient size initialized to 0 is passed.
*/
/*!
* \internal
*/
void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat,
int width, int height, int border,
glEnums format, glEnums type,
qCDebug(canvas3drendering) << "Context3D::" << __FUNCTION__
<< "(target:" << glEnumToString(target)
<< ", level:" << level
<< ", internalformat:" << glEnumToString(internalformat)
<< ", width:" << width
<< ", height:" << height
<< ", border:" << border
<< ", format:" << glEnumToString(format)
<< ", type:" << glEnumToString(type)
<< ", pixels:" << pixels.toString()
<< ")";
qCWarning(canvas3drendering) << "Context3D::"
<< __FUNCTION__
<< ":INVALID_OPERATION No current texture bound";
} else if (!m_currentTexture2D->isAlive()) {
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_OPERATION Currently bound texture is deleted";
int bytesPerPixel = 0;
uchar *srcData = 0;
uchar *unpackedData = 0;
int size = getSufficientSize(type, width, height);
srcData = new uchar[size];
memset(srcData, 0, size);
case UNSIGNED_BYTE: {
switch (format) {
case ALPHA:
bytesPerPixel = 1;
break;
case RGB:
bytesPerPixel = 3;
break;
case RGBA:
bytesPerPixel = 4;
break;
case LUMINANCE:
bytesPerPixel = 1;
break;
case LUMINANCE_ALPHA:
bytesPerPixel = 2;
break;
default:
break;
}
if (bytesPerPixel == 0) {
m_error = INVALID_ENUM;
qCWarning(canvas3drendering) << "Context3D::" << __FUNCTION__
<< ":INVALID_ENUM Invalid format supplied "
<< glEnumToString(format);
return;
}
if (!srcData)
srcData = getAsUint8ArrayRawPtr(pixels);
if (!srcData) {
qCWarning(canvas3drendering) << "Context3D::"
<< __FUNCTION__
<< ":INVALID_OPERATION Expected Uint8Array, received "
<< pixels.toString();
m_error = INVALID_OPERATION;
return;
}
unpackedData = unpackPixels(srcData, false, bytesPerPixel, width, height);
glTexImage2D(target, level, internalformat, width, height,
border, format, type, unpackedData);
break;
case UNSIGNED_SHORT_4_4_4_4:
case UNSIGNED_SHORT_5_6_5:
case UNSIGNED_SHORT_5_5_5_1: {
if (!srcData)
srcData = getAsUint16ArrayRawPtr(pixels);
if (!srcData) {
qCWarning(canvas3drendering) << "Context3D::"
<< __FUNCTION__
<< ":INVALID_OPERATION Expected Uint16Array, received "
unpackedData = unpackPixels(srcData, false, 2, width, height);
glTexImage2D(target, level, internalformat, width, height,
border, format, type, unpackedData);
qCWarning(canvas3drendering) << "Context3D::"
<< __FUNCTION__
<< ":INVALID_ENUM Invalid type enum";
// Delete temp data
if (unpackedData != srcData)
delete unpackedData;
uchar *CanvasContext::getAsUint8ArrayRawPtr(QJSValue jsValue)
QV4::Scope scope(m_v4engine);
QV4::Scoped<QV4::TypedArray> typedArray(scope,
QJSValuePrivate::convertedToValue(m_v4engine, jsValue));
if (!typedArray)
if (typedArray->arrayType() != QV4::Heap::TypedArray::UInt8Array)
return 0;