summaryrefslogtreecommitdiffstats
path: root/src/threed
diff options
context:
space:
mode:
Diffstat (limited to 'src/threed')
-rw-r--r--src/threed/api/api.pri4
-rw-r--r--src/threed/api/gl-funcs.txt858
-rwxr-xr-xsrc/threed/api/gl-gen-funcs.pl483
-rw-r--r--src/threed/api/qopenglfunctions.cpp3690
-rw-r--r--src/threed/api/qopenglfunctions.h2292
-rw-r--r--src/threed/arrays/arrays.pri28
-rw-r--r--src/threed/arrays/qarray.cpp1022
-rw-r--r--src/threed/arrays/qarray.h1209
-rw-r--r--src/threed/arrays/qcolor4ub.cpp319
-rw-r--r--src/threed/arrays/qcolor4ub.h216
-rw-r--r--src/threed/arrays/qcustomdataarray.cpp909
-rw-r--r--src/threed/arrays/qcustomdataarray.h421
-rw-r--r--src/threed/arrays/qglattributedescription.cpp188
-rw-r--r--src/threed/arrays/qglattributedescription.h149
-rw-r--r--src/threed/arrays/qglattributeset.cpp207
-rw-r--r--src/threed/arrays/qglattributeset.h130
-rw-r--r--src/threed/arrays/qglattributevalue.cpp276
-rw-r--r--src/threed/arrays/qglattributevalue.h207
-rw-r--r--src/threed/arrays/qglindexbuffer.cpp777
-rw-r--r--src/threed/arrays/qglindexbuffer.h108
-rw-r--r--src/threed/arrays/qglvertexbundle.cpp495
-rw-r--r--src/threed/arrays/qglvertexbundle.h111
-rw-r--r--src/threed/arrays/qglvertexbundle_p.h216
-rw-r--r--src/threed/arrays/qvector2darray.cpp275
-rw-r--r--src/threed/arrays/qvector2darray.h124
-rw-r--r--src/threed/arrays/qvector3darray.cpp257
-rw-r--r--src/threed/arrays/qvector3darray.h116
-rw-r--r--src/threed/arrays/qvector4darray.cpp257
-rw-r--r--src/threed/arrays/qvector4darray.h118
-rw-r--r--src/threed/effects/effects.pri26
-rw-r--r--src/threed/effects/qglcolladafxeffect.cpp406
-rw-r--r--src/threed/effects/qglcolladafxeffect.h94
-rw-r--r--src/threed/effects/qglcolladafxeffect_p.h107
-rw-r--r--src/threed/effects/qglcolladafxeffectfactory.cpp1688
-rw-r--r--src/threed/effects/qglcolladafxeffectfactory.h214
-rw-r--r--src/threed/effects/qglcolladafxeffectloader.cpp186
-rw-r--r--src/threed/effects/qglcolladafxeffectloader.h69
-rw-r--r--src/threed/effects/qglflatcoloreffect.cpp350
-rw-r--r--src/threed/effects/qglflatcoloreffect_p.h99
-rw-r--r--src/threed/effects/qglflattextureeffect.cpp373
-rw-r--r--src/threed/effects/qglflattextureeffect_p.h98
-rw-r--r--src/threed/effects/qgllitmaterialeffect.cpp571
-rw-r--r--src/threed/effects/qgllitmaterialeffect_p.h85
-rw-r--r--src/threed/effects/qgllittextureeffect.cpp215
-rw-r--r--src/threed/effects/qgllittextureeffect_p.h86
-rw-r--r--src/threed/effects/qglshaderprogrameffect.cpp1027
-rw-r--r--src/threed/effects/qglshaderprogrameffect.h91
-rw-r--r--src/threed/geometry/geometry.pri28
-rw-r--r--src/threed/geometry/qgeometrydata.cpp2025
-rw-r--r--src/threed/geometry/qgeometrydata.h213
-rw-r--r--src/threed/geometry/qglbezierpatches.cpp815
-rw-r--r--src/threed/geometry/qglbezierpatches.h97
-rw-r--r--src/threed/geometry/qglbuilder.cpp1378
-rw-r--r--src/threed/geometry/qglbuilder.h140
-rw-r--r--src/threed/geometry/qglbuilder_p.h89
-rw-r--r--src/threed/geometry/qglcube.cpp168
-rw-r--r--src/threed/geometry/qglcube.h76
-rw-r--r--src/threed/geometry/qglcylinder.cpp384
-rw-r--r--src/threed/geometry/qglcylinder.h105
-rw-r--r--src/threed/geometry/qgldome.cpp256
-rw-r--r--src/threed/geometry/qgldome.h83
-rw-r--r--src/threed/geometry/qglmaterialcollection.cpp415
-rw-r--r--src/threed/geometry/qglmaterialcollection.h101
-rw-r--r--src/threed/geometry/qglsection.cpp696
-rw-r--r--src/threed/geometry/qglsection_p.h131
-rw-r--r--src/threed/geometry/qglsphere.cpp243
-rw-r--r--src/threed/geometry/qglsphere.h79
-rw-r--r--src/threed/geometry/qglteapot.cpp104
-rw-r--r--src/threed/geometry/qglteapot.h64
-rw-r--r--src/threed/geometry/qglteapot_data_p.h408
-rw-r--r--src/threed/geometry/qlogicalvertex.cpp416
-rw-r--r--src/threed/geometry/qlogicalvertex.h328
-rw-r--r--src/threed/geometry/qvector_utils_p.h110
-rw-r--r--src/threed/global/global.pri7
-rw-r--r--src/threed/global/qglnamespace.cpp290
-rw-r--r--src/threed/global/qglnamespace.h163
-rw-r--r--src/threed/global/qt3dglobal.h74
-rw-r--r--src/threed/graphicsview/graphicsview.pri21
-rw-r--r--src/threed/graphicsview/qglgraphicsviewportitem.cpp365
-rw-r--r--src/threed/graphicsview/qglgraphicsviewportitem.h100
-rw-r--r--src/threed/graphicsview/qgraphicsbillboardtransform.cpp260
-rw-r--r--src/threed/graphicsview/qgraphicsbillboardtransform.h82
-rw-r--r--src/threed/graphicsview/qgraphicsembedscene.cpp469
-rw-r--r--src/threed/graphicsview/qgraphicsembedscene.h88
-rw-r--r--src/threed/graphicsview/qgraphicsrotation3d.cpp274
-rw-r--r--src/threed/graphicsview/qgraphicsrotation3d.h91
-rw-r--r--src/threed/graphicsview/qgraphicsscale3d.cpp259
-rw-r--r--src/threed/graphicsview/qgraphicsscale3d.h88
-rw-r--r--src/threed/graphicsview/qgraphicstransform3d.cpp112
-rw-r--r--src/threed/graphicsview/qgraphicstransform3d.h71
-rw-r--r--src/threed/graphicsview/qgraphicstranslation3d.cpp233
-rw-r--r--src/threed/graphicsview/qgraphicstranslation3d.h87
-rw-r--r--src/threed/materials/materials.pri18
-rw-r--r--src/threed/materials/qglabstractmaterial.cpp239
-rw-r--r--src/threed/materials/qglabstractmaterial.h82
-rw-r--r--src/threed/materials/qglcolormaterial.cpp162
-rw-r--r--src/threed/materials/qglcolormaterial.h85
-rw-r--r--src/threed/materials/qglmaterial.cpp586
-rw-r--r--src/threed/materials/qglmaterial.h149
-rw-r--r--src/threed/materials/qglmaterial_p.h85
-rw-r--r--src/threed/materials/qgltwosidedmaterial.cpp259
-rw-r--r--src/threed/materials/qgltwosidedmaterial.h89
-rw-r--r--src/threed/math3d/math3d.pri12
-rw-r--r--src/threed/math3d/qbox3d.cpp690
-rw-r--r--src/threed/math3d/qbox3d.h218
-rw-r--r--src/threed/math3d/qplane3d.cpp302
-rw-r--r--src/threed/math3d/qplane3d.h161
-rw-r--r--src/threed/math3d/qray3d.cpp301
-rw-r--r--src/threed/math3d/qray3d.h164
-rw-r--r--src/threed/math3d/qsphere3d.cpp385
-rw-r--r--src/threed/math3d/qsphere3d.h164
-rw-r--r--src/threed/math3d/qtriangle3d.cpp379
-rw-r--r--src/threed/math3d/qtriangle3d.h182
-rw-r--r--src/threed/painting/painting.pri29
-rw-r--r--src/threed/painting/qglabstracteffect.cpp151
-rw-r--r--src/threed/painting/qglabstracteffect.h68
-rw-r--r--src/threed/painting/qglabstracteffect_p.h70
-rw-r--r--src/threed/painting/qglext.cpp98
-rw-r--r--src/threed/painting/qglext_p.h220
-rw-r--r--src/threed/painting/qgllightmodel.cpp291
-rw-r--r--src/threed/painting/qgllightmodel.h119
-rw-r--r--src/threed/painting/qgllightparameters.cpp828
-rw-r--r--src/threed/painting/qgllightparameters.h150
-rw-r--r--src/threed/painting/qglpainter.cpp2305
-rw-r--r--src/threed/painting/qglpainter.h225
-rw-r--r--src/threed/painting/qglpainter_p.h155
-rw-r--r--src/threed/painting/qglpickcolors.cpp1125
-rw-r--r--src/threed/painting/qglpickcolors_p.h64
-rw-r--r--src/threed/painting/qmatrix4x4stack.cpp380
-rw-r--r--src/threed/painting/qmatrix4x4stack.h105
-rw-r--r--src/threed/painting/qmatrix4x4stack_p.h77
-rw-r--r--src/threed/scene/qglabstractscene.cpp527
-rw-r--r--src/threed/scene/qglabstractscene.h107
-rw-r--r--src/threed/scene/qglpicknode.cpp215
-rw-r--r--src/threed/scene/qglpicknode.h78
-rw-r--r--src/threed/scene/qglrenderorder.cpp318
-rw-r--r--src/threed/scene/qglrenderorder.h203
-rw-r--r--src/threed/scene/qglrenderordercomparator.cpp164
-rw-r--r--src/threed/scene/qglrenderordercomparator.h69
-rw-r--r--src/threed/scene/qglrendersequencer.cpp365
-rw-r--r--src/threed/scene/qglrendersequencer.h87
-rw-r--r--src/threed/scene/qglrenderstate.cpp316
-rw-r--r--src/threed/scene/qglrenderstate.h101
-rw-r--r--src/threed/scene/qglsceneformatplugin.cpp228
-rw-r--r--src/threed/scene/qglsceneformatplugin.h107
-rw-r--r--src/threed/scene/qglscenenode.cpp1794
-rw-r--r--src/threed/scene/qglscenenode.h197
-rw-r--r--src/threed/scene/qglscenenode_p.h138
-rw-r--r--src/threed/scene/scene.pri19
-rw-r--r--src/threed/surfaces/qglabstractsurface.cpp318
-rw-r--r--src/threed/surfaces/qglabstractsurface.h95
-rw-r--r--src/threed/surfaces/qglcontextsurface.cpp70
-rw-r--r--src/threed/surfaces/qglcontextsurface_p.h85
-rw-r--r--src/threed/surfaces/qgldrawbuffersurface.cpp71
-rw-r--r--src/threed/surfaces/qgldrawbuffersurface_p.h86
-rw-r--r--src/threed/surfaces/qglframebufferobjectsurface.cpp209
-rw-r--r--src/threed/surfaces/qglframebufferobjectsurface.h86
-rw-r--r--src/threed/surfaces/qglmaskedsurface.cpp214
-rw-r--r--src/threed/surfaces/qglmaskedsurface_p.h105
-rw-r--r--src/threed/surfaces/qglpaintersurface.cpp72
-rw-r--r--src/threed/surfaces/qglpaintersurface_p.h86
-rw-r--r--src/threed/surfaces/qglpixelbuffersurface.cpp142
-rw-r--r--src/threed/surfaces/qglpixelbuffersurface.h79
-rw-r--r--src/threed/surfaces/qglsubsurface.cpp199
-rw-r--r--src/threed/surfaces/qglsubsurface.h84
-rw-r--r--src/threed/surfaces/qglwidgetsurface.cpp146
-rw-r--r--src/threed/surfaces/qglwidgetsurface.h80
-rw-r--r--src/threed/surfaces/surfaces.pri23
-rw-r--r--src/threed/textures/qareaallocator.cpp877
-rw-r--r--src/threed/textures/qareaallocator.h169
-rw-r--r--src/threed/textures/qglsharedresource.cpp236
-rw-r--r--src/threed/textures/qglsharedresource_p.h96
-rw-r--r--src/threed/textures/qgltexture2d.cpp697
-rw-r--r--src/threed/textures/qgltexture2d.h110
-rw-r--r--src/threed/textures/qgltexture2d_p.h116
-rw-r--r--src/threed/textures/qgltexturecube.cpp549
-rw-r--r--src/threed/textures/qgltexturecube.h112
-rw-r--r--src/threed/textures/qgltextureutils.cpp785
-rw-r--r--src/threed/textures/qgltextureutils_p.h164
-rw-r--r--src/threed/textures/textures.pri15
-rw-r--r--src/threed/threed.pri13
-rw-r--r--src/threed/threed.pro67
-rw-r--r--src/threed/viewing/qglcamera.cpp1310
-rw-r--r--src/threed/viewing/qglcamera.h179
-rw-r--r--src/threed/viewing/qglcameraanimation.cpp543
-rw-r--r--src/threed/viewing/qglcameraanimation.h116
-rw-r--r--src/threed/viewing/qglview.cpp1475
-rw-r--r--src/threed/viewing/qglview.h145
-rw-r--r--src/threed/viewing/viewing.pri12
189 files changed, 59574 insertions, 0 deletions
diff --git a/src/threed/api/api.pri b/src/threed/api/api.pri
new file mode 100644
index 000000000..0499f0dc7
--- /dev/null
+++ b/src/threed/api/api.pri
@@ -0,0 +1,4 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += qopenglfunctions.h
+SOURCES += qopenglfunctions.cpp
diff --git a/src/threed/api/gl-funcs.txt b/src/threed/api/gl-funcs.txt
new file mode 100644
index 000000000..6bef6ce4e
--- /dev/null
+++ b/src/threed/api/gl-funcs.txt
@@ -0,0 +1,858 @@
+void glActiveTexture(GLenum texture);
+ inline es1, es2
+ alt_name glActiveTextureARB
+
+void glAttachShader(GLuint program, GLuint shader);
+ shader_only yes
+ inline es2
+ alt_name glAttachObjectARB
+
+void glBindAttribLocation(GLuint program, GLuint index, const char* name);
+ shader_only yes
+ inline es2
+ alt_name glBindAttribLocationARB
+
+void glBindBuffer(GLenum target, GLuint buffer);
+ inline es1, es2
+
+void glBindFramebuffer(GLenum target, GLuint framebuffer);
+ inline es2
+
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer);
+ inline es2
+
+void glBindTexture(GLenum target, GLuint texture);
+ inline all
+
+void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+ inline es2
+
+void glBlendEquation( GLenum mode );
+ inline es2
+
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
+ inline es2
+
+void glBlendFunc(GLenum sfactor, GLenum dfactor);
+ inline all
+
+void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+ inline es2
+
+void glBufferData(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage);
+ inline es1, es2
+
+void glBufferSubData(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data);
+ inline es1, es2
+
+GLenum glCheckFramebufferStatus(GLenum target);
+ inline es2
+
+void glClear(GLbitfield mask);
+ inline all
+
+void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+ inline all
+
+void glClearDepth(GLclampf depth);
+ inline all_diff
+ es_name glClearDepthf
+
+void glClearStencil(GLint s);
+ inline all
+
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+ inline all
+
+void glCompileShader(GLuint shader);
+ shader_only yes
+ inline es2
+ alt_name glCompileShader
+
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+ inline es1, es2
+
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+ inline es1, es2
+
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+ inline all
+
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+ inline all
+
+GLuint glCreateProgram(void);
+ shader_only yes
+ inline es2
+ alt_name glCreateProgramObjectARB
+
+GLuint glCreateShader(GLenum type);
+ shader_only yes
+ inline es2
+ alt_name glCreateShaderObjectARB
+
+void glCullFace(GLenum mode);
+ inline all
+
+void glDeleteBuffers(GLsizei n, const GLuint* buffers);
+ inline es1, es2
+
+void glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
+ inline es2
+
+void glDeleteProgram(GLuint program);
+ shader_only yes
+ inline es2
+ alt_name glDeleteObjectARB
+
+void glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
+ inline es2
+
+void glDeleteShader(GLuint shader);
+ shader_only yes
+ inline es2
+ alt_name glDeleteObjectARB
+
+void glDeleteTextures(GLsizei n, const GLuint* textures);
+ inline all
+
+void glDepthFunc(GLenum func);
+ inline all
+
+void glDepthMask(GLboolean flag);
+ inline all
+
+void glDepthRange(GLclampf zNear, GLclampf zFar);
+ inline all_diff
+ es_name glDepthRangef
+
+void glDetachShader(GLuint program, GLuint shader);
+ shader_only yes
+ inline es2
+ alt_name glDetachObjectARB
+
+void glDisable(GLenum cap);
+ inline all
+
+void glDisableVertexAttribArray(GLuint index);
+ shader_only yes
+ inline es2
+ alt_name glDisableVertexAttribArrayARB
+
+void glDrawArrays(GLenum mode, GLint first, GLsizei count);
+ inline all
+
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
+ inline all
+
+void glEnable(GLenum cap);
+ inline all
+
+void glEnableVertexAttribArray(GLuint index);
+ shader_only yes
+ inline es2
+ alt_name glEnableVertexAttribArrayARB
+
+void glFinish(void);
+ inline all
+
+void glFlush(void);
+ inline all
+
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+ inline es2
+
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+ inline es2
+
+void glFrontFace(GLenum mode);
+ inline all
+
+void glGenBuffers(GLsizei n, GLuint* buffers);
+ inline es1, es2
+
+void glGenerateMipmap(GLenum target);
+ inline es2
+
+void glGenFramebuffers(GLsizei n, GLuint* framebuffers);
+ inline es2
+
+void glGenRenderbuffers(GLsizei n, GLuint* renderbuffers);
+ inline es2
+
+void glGenTextures(GLsizei n, GLuint* textures);
+ inline all
+
+void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+ shader_only yes
+ inline es2
+ alt_name glGetActiveAttribARB
+
+void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+ shader_only yes
+ inline es2
+ alt_name glGetActiveUniformARB
+
+void glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+ shader_only yes
+ inline es2
+ alt_name glGetAttachedObjectsARB
+
+int glGetAttribLocation(GLuint program, const char* name);
+ shader_only yes
+ inline es2
+ alt_name glGetAttribLocationARB
+
+void glGetBooleanv(GLenum pname, GLboolean* params);
+ inline all
+
+void glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
+ inline es2
+
+GLenum glGetError(void);
+ inline all
+
+void glGetFloatv(GLenum pname, GLfloat* params);
+ inline all
+
+void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+ inline es2
+
+void glGetIntegerv(GLenum pname, GLint* params);
+ inline all
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint* params);
+ shader_only yes
+ inline es2
+ alt_name glGetObjectParameterivARB
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+ shader_only yes
+ inline es2
+ alt_name glGetInfoLogARB
+
+void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
+ inline es2
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint* params);
+ shader_only yes
+ inline es2
+ alt_name glGetObjectParameterivARB
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+ shader_only yes
+ inline es2
+ alt_name glGetInfoLogARB
+
+void glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+ shader_only yes
+ inline es2
+ special_handling yes
+
+void glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+ shader_only yes
+ inline es2
+ alt_name glGetShaderSourceARB
+
+const GLubyte* glGetString(GLenum name);
+ inline all
+
+void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
+ inline all
+
+void glGetTexParameteriv(GLenum target, GLenum pname, GLint* params);
+ inline all
+
+void glGetUniformfv(GLuint program, GLint location, GLfloat* params);
+ shader_only yes
+ inline es2
+ alt_name glGetUniformfvARB
+
+void glGetUniformiv(GLuint program, GLint location, GLint* params);
+ shader_only yes
+ inline es2
+ alt_name glGetUniformivARB
+
+int glGetUniformLocation(GLuint program, const char* name);
+ shader_only yes
+ inline es2
+ alt_name glGetUniformLocationARB
+
+void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
+ shader_only yes
+ inline es2
+ alt_name glGetVertexAttribfvARB
+
+void glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
+ shader_only yes
+ inline es2
+ alt_name glGetVertexAttribivARB
+
+void glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer);
+ shader_only yes
+ inline es2
+ alt_name glGetVertexAttribPointervARB
+
+void glHint(GLenum target, GLenum mode);
+ inline all
+
+GLboolean glIsBuffer(GLuint buffer);
+ inline es1, es2
+
+GLboolean glIsEnabled(GLenum cap);
+ inline all
+
+GLboolean glIsFramebuffer(GLuint framebuffer);
+ inline es2
+
+GLboolean glIsProgram(GLuint program);
+ shader_only yes
+ inline es2
+ alt_name glIsProgramARB
+ special_handling yes
+
+GLboolean glIsRenderbuffer(GLuint renderbuffer);
+ inline es2
+
+GLboolean glIsShader(GLuint shader);
+ shader_only yes
+ inline es2
+ alt_name glIsShaderARB
+ special_handling yes
+
+GLboolean glIsTexture(GLuint texture);
+ inline all
+
+void glLineWidth(GLfloat width);
+ inline all
+
+void glLinkProgram(GLuint program);
+ shader_only yes
+ inline es2
+ alt_name glLinkProgramARB
+
+void glPixelStorei(GLenum pname, GLint param);
+ inline all
+
+void glPolygonOffset(GLfloat factor, GLfloat units);
+ inline all
+
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
+ inline all
+
+void glReleaseShaderCompiler(void);
+ shader_only yes
+ inline es2
+ alt_name glReleaseShaderCompilerARB
+ special_handling yes
+
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+ inline es2
+
+void glSampleCoverage(GLclampf value, GLboolean invert);
+ inline es1, es2
+
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+ inline all
+
+void glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length);
+ shader_only yes
+ inline es2
+ alt_name glShaderBinaryARB
+
+void glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length);
+ shader_only yes
+ inline es2
+ alt_name glShaderSourceARB
+
+void glStencilFunc(GLenum func, GLint ref, GLuint mask);
+ inline all
+
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
+ inline es2
+
+void glStencilMask(GLuint mask);
+ inline all
+
+void glStencilMaskSeparate(GLenum face, GLuint mask);
+ inline es2
+
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
+ inline all
+
+void glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+ inline es2
+
+void glTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
+ inline all
+
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param);
+ inline all
+
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
+ inline all
+
+void glTexParameteri(GLenum target, GLenum pname, GLint param);
+ inline all
+
+void glTexParameteriv(GLenum target, GLenum pname, const GLint* params);
+ inline all
+
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
+ inline all
+
+void glUniform1f(GLint location, GLfloat x);
+ shader_only yes
+ inline es2
+ alt_name glUniform1fARB
+
+void glUniform1fv(GLint location, GLsizei count, const GLfloat* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform1fvARB
+
+void glUniform1i(GLint location, GLint x);
+ shader_only yes
+ inline es2
+ alt_name glUniform1iARB
+
+void glUniform1iv(GLint location, GLsizei count, const GLint* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform1ivARB
+
+void glUniform2f(GLint location, GLfloat x, GLfloat y);
+ shader_only yes
+ inline es2
+ alt_name glUniform2fARB
+
+void glUniform2fv(GLint location, GLsizei count, const GLfloat* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform2fvARB
+
+void glUniform2i(GLint location, GLint x, GLint y);
+ shader_only yes
+ inline es2
+ alt_name glUniform2iARB
+
+void glUniform2iv(GLint location, GLsizei count, const GLint* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform2ivARB
+
+void glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z);
+ shader_only yes
+ inline es2
+ alt_name glUniform3fARB
+
+void glUniform3fv(GLint location, GLsizei count, const GLfloat* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform3fvARB
+
+void glUniform3i(GLint location, GLint x, GLint y, GLint z);
+ shader_only yes
+ inline es2
+ alt_name glUniform3iARB
+
+void glUniform3iv(GLint location, GLsizei count, const GLint* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform3ivARB
+
+void glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ shader_only yes
+ inline es2
+ alt_name glUniform4fARB
+
+void glUniform4fv(GLint location, GLsizei count, const GLfloat* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform4fvARB
+
+void glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w);
+ shader_only yes
+ inline es2
+ alt_name glUniform4iARB
+
+void glUniform4iv(GLint location, GLsizei count, const GLint* v);
+ shader_only yes
+ inline es2
+ alt_name glUniform4ivARB
+
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ shader_only yes
+ inline es2
+ alt_name glUniformMatrix2fvARB
+
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ shader_only yes
+ inline es2
+ alt_name glUniformMatrix3fvARB
+
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ shader_only yes
+ inline es2
+ alt_name glUniformMatrix4fvARB
+
+void glUseProgram(GLuint program);
+ shader_only yes
+ inline es2
+ alt_name glUseProgramObjectARB
+
+void glValidateProgram(GLuint program);
+ shader_only yes
+ inline es2
+ alt_name glValidateProgramARB
+
+void glVertexAttrib1f(GLuint indx, GLfloat x);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib1fARB
+
+void glVertexAttrib1fv(GLuint indx, const GLfloat* values);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib1fvARB
+
+void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib2fARB
+
+void glVertexAttrib2fv(GLuint indx, const GLfloat* values);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib2fvARB
+
+void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib3fARB
+
+void glVertexAttrib3fv(GLuint indx, const GLfloat* values);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib3fvARB
+
+void glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib4fARB
+
+void glVertexAttrib4fv(GLuint indx, const GLfloat* values);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttrib4fvARB
+
+void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+ shader_only yes
+ inline es2
+ alt_name glVertexAttribPointerARB
+
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
+ inline all
+
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALPHA 0x1906
+#define GL_ALPHA_BITS 0x0D55
+#define GL_ALWAYS 0x0207
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_BACK 0x0405
+#define GL_BLEND 0x0BE2
+#define GL_BLEND_COLOR 0x8005
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_BLEND_EQUATION_RGB 0x8009
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLUE_BITS 0x0D54
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+#define GL_BYTE 0x1400
+#define GL_CCW 0x0901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_CULL_FACE 0x0B44
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#define GL_CW 0x0900
+#define GL_DECR 0x1E03
+#define GL_DECR_WRAP 0x8508
+#define GL_DELETE_STATUS 0x8B80
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_DEPTH_BITS 0x0D56
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_TEST 0x0B71
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DITHER 0x0BD0
+#define GL_DONT_CARE 0x1100
+#define GL_DST_ALPHA 0x0304
+#define GL_DST_COLOR 0x0306
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_EQUAL 0x0202
+#define GL_EXTENSIONS 0x1F03
+#define GL_FALSE 0
+#define GL_FASTEST 0x1101
+#define GL_FIXED 0x140C
+#define GL_FLOAT 0x1406
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+#define GL_FRONT 0x0404
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_FRONT_FACE 0x0B46
+#define GL_FUNC_ADD 0x8006
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+#define GL_GEQUAL 0x0206
+#define GL_GREATER 0x0204
+#define GL_GREEN_BITS 0x0D53
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_HIGH_INT 0x8DF5
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_INCR 0x1E02
+#define GL_INCR_WRAP 0x8507
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_INT 0x1404
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+#define GL_INVALID_OPERATION 0x0502
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVERT 0x150A
+#define GL_KEEP 0x1E00
+#define GL_LEQUAL 0x0203
+#define GL_LESS 0x0201
+#define GL_LINEAR 0x2601
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_LINE_LOOP 0x0002
+#define GL_LINES 0x0001
+#define GL_LINE_STRIP 0x0003
+#define GL_LINE_WIDTH 0x0B21
+#define GL_LINK_STATUS 0x8B82
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_LOW_INT 0x8DF3
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_MIRRORED_REPEAT 0x8370
+#define GL_NEAREST 0x2600
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_NEVER 0x0200
+#define GL_NICEST 0x1102
+#define GL_NO_ERROR 0
+#define GL_NONE 0
+#define GL_NOTEQUAL 0x0205
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+#define GL_ONE 1
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_OUT_OF_MEMORY 0x0505
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_POINTS 0x0000
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_RED_BITS 0x0D52
+#define GL_RENDERBUFFER 0x8D41
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERER 0x1F01
+#define GL_REPEAT 0x2901
+#define GL_REPLACE 0x1E01
+#define GL_RGB 0x1907
+#define GL_RGB565 0x8D62
+#define GL_RGB5_A1 0x8057
+#define GL_RGBA 0x1908
+#define GL_RGBA4 0x8056
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_SAMPLES 0x80A9
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_SHADER_COMPILER 0x8DFA
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_SHORT 0x1402
+#define GL_SRC_ALPHA 0x0302
+#define GL_SRC_ALPHA_SATURATE 0x0308
+#define GL_SRC_COLOR 0x0300
+#define GL_STATIC_DRAW 0x88E4
+#define GL_STENCIL_ATTACHMENT 0x8D20
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_STENCIL_BITS 0x0D57
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX8 0x8D48
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_TEST 0x0B90
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STREAM_DRAW 0x88E0
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE 0x1702
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE31 0x84DF
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TRIANGLE_FAN 0x0006
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRUE 1
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_UNSIGNED_INT 0x1405
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_VENDOR 0x1F00
+#define GL_VERSION 0x1F02
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_VIEWPORT 0x0BA2
+#define GL_ZERO 0
diff --git a/src/threed/api/gl-gen-funcs.pl b/src/threed/api/gl-gen-funcs.pl
new file mode 100755
index 000000000..b42551e2d
--- /dev/null
+++ b/src/threed/api/gl-gen-funcs.pl
@@ -0,0 +1,483 @@
+#!/usr/bin/perl
+#############################################################################
+##
+## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+## All rights reserved.
+## Contact: Nokia Corporation (qt-info@nokia.com)
+##
+## This file is part of the Qt3D module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## No Commercial Usage
+## This file contains pre-release code and may not be distributed.
+## You may use this file in accordance with the terms and conditions
+## contained in the Technology Preview License Agreement accompanying
+## this package.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## In addition, as a special exception, Nokia gives you certain additional
+## rights. These rights are described in the Nokia Qt LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## If you have questions regarding the use of this file, please contact
+## Nokia at qt-info@nokia.com.
+##
+##
+##
+##
+##
+##
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+#
+# USAGE:
+#
+# perl gl-gen-funcs.pl < gl-functs.txt > output.txt
+#
+# This will automatically generate the qopenglfunctions.h/.cpp files for Qt3D
+# based on the platform and available functions/capabilities.
+#
+# The file output.txt will contain the text for the header and implementation
+# files - it is left to the user to manually cut and paste this content into
+# their own qopenglfunctions.h and qopenglfunctions.cpp files.
+#
+# Note: this script is intended for perl version 5.10.1 or better, and has not
+# been tested on previous versions of perl.
+#
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+
+# Read the function definitions from the input.
+my @functions = ();
+my @macros = ();
+my %func_info = ();
+while (<>)
+{
+ my ($returnType, $name, $argstr) =
+ m/^(\w+|const GLubyte\*)\s+(\w+)\s*\(([^)]*)\)/;
+
+ if (!$returnType) {
+ my ($macroname, $macrovalue) = m/^#define\s+(\w+)\s+(.*)$/;
+ if ($macroname) {
+ my %macro_info = ();
+ $macro_info{'name'} = $macroname;
+ $macro_info{'value'} = $macrovalue;
+ push @macros, { %macro_info };
+ next;
+ }
+ my ($tag, $value) = m/^\s+(\w+)\s+(.*)$/;
+ next unless $tag;
+ $func_info{$tag} = $value;
+ $func_info{'funcname'} = $value if ($tag eq "es_name");
+ next;
+ }
+
+ if ($func_info{'name'}) {
+ push @functions, { %func_info };
+ %func_info = ();
+ }
+
+ $argstr =~ s/^\s+//;
+ $argstr =~ s/\s+$//;
+ my @args = split /,\s*/,$argstr;
+
+ my @argNames = ();
+ if ($argstr ne 'void') {
+ foreach (@args) {
+ my ($argType, $argName) = m/^(\w+|\w+.*\*)\s+(\w+)$/;
+ push @argNames, $argName;
+ }
+ } else {
+ $argstr = "";
+ }
+ my $argnamestr = join(', ', @argNames);
+
+ $func_info{'name'} = $name;
+ $func_info{'funcname'} = $name;
+ $name =~ s/^gl//;
+ $func_info{'varname'} = lcfirst($name);
+ $func_info{'returnType'} = $returnType;
+ $func_info{'argstr'} = $argstr;
+ $func_info{'argnamestr'} = $argnamestr;
+}
+if ($func_info{'name'}) {
+ push @functions, { %func_info };
+}
+
+# Generate the declarations for qopenglfunctions.h.
+print "// qopenglfunctions.h\n\n";
+print "#ifdef Q_WS_WIN\n";
+print "# define QT3D_GLF_APIENTRY APIENTRY\n";
+print "#endif\n";
+print "\n";
+print "#ifndef Q_WS_MAC\n";
+print "# ifndef QT3D_GLF_APIENTRYP\n";
+print "# ifdef QT3D_GLF_APIENTRY\n";
+print "# define QT3D_GLF_APIENTRYP QT3D_GLF_APIENTRY *\n";
+print "# else\n";
+print "# define QT3D_GLF_APIENTRY\n";
+print "# define QT3D_GLF_APIENTRYP *\n";
+print "# endif\n";
+print "# endif\n";
+print "#else\n";
+print "# define QT3D_GLF_APIENTRY\n";
+print "# define QT3D_GLF_APIENTRYP *\n";
+print "#endif\n";
+print "\n";
+print "struct QOpenGLFunctionsPrivate;\n";
+print "\n";
+
+print "// Undefine any macros from GLEW, qglextensions_p.h, etc that\n";
+print "// may interfere with the definition of QOpenGLFunctions.\n";
+foreach ( @functions ) {
+ my $inline = $_->{'inline'};
+ next if ($inline && $inline eq 'all');
+ my $name = $_->{'funcname'};
+ print "#undef $name\n";
+}
+print "\n";
+
+# Output the prototypes into the QOpenGLFunctions class.
+print "class Q_QT3D_EXPORT QOpenGLFunctions\n";
+print "{\n";
+print "public:\n";
+print " QOpenGLFunctions();\n";
+print " explicit QOpenGLFunctions(const QGLContext *context);\n";
+print " ~QOpenGLFunctions() {}\n";
+print "\n";
+print " enum OpenGLFeature\n";
+print " {\n";
+print " Multitexture = 0x0001,\n";
+print " Shaders = 0x0002,\n";
+print " Buffers = 0x0004,\n";
+print " Framebuffers = 0x0008,\n";
+print " BlendColor = 0x0010,\n";
+print " BlendEquation = 0x0020,\n";
+print " BlendEquationSeparate = 0x0040,\n";
+print " BlendFuncSeparate = 0x0080,\n";
+print " BlendSubtract = 0x0100,\n";
+print " CompressedTextures = 0x0200,\n";
+print " Multisample = 0x0400,\n";
+print " StencilSeparate = 0x0800,\n";
+print " NPOTTextures = 0x1000\n";
+print " };\n";
+print " Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature)\n";
+print "\n";
+print " QOpenGLFunctions::OpenGLFeatures openGLFeatures() const;\n";
+print " bool hasOpenGLFeature(QOpenGLFunctions::OpenGLFeature feature) const;\n";
+print "\n";
+print " void initializeGLFunctions(const QGLContext *context = 0);\n";
+print "\n";
+my $last_shader_only = 0;
+foreach ( @functions ) {
+ my $inline = $_->{'inline'};
+ next if ($inline && $inline eq 'all');
+ my $shader_only = ($_->{'shader_only'} && $_->{'shader_only'} eq 'yes');
+ my $name = $_->{'funcname'};
+ #print "#ifndef QT_OPENGL_ES_1\n" if ($shader_only && !$last_shader_only);
+ #print "#endif\n" if (!$shader_only && $last_shader_only);
+ print " $_->{'returnType'} $name($_->{'argstr'});\n";
+ $last_shader_only = $shader_only;
+}
+#print "#endif\n" if $last_shader_only;
+
+print "\n";
+print "private:\n";
+print " QOpenGLFunctionsPrivate *d_ptr;\n";
+print " static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; }\n";
+print "};\n";
+print "\n";
+print "Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLFunctions::OpenGLFeatures)\n";
+print "\n";
+print "struct QOpenGLFunctionsPrivate\n";
+print "{\n";
+print " QOpenGLFunctionsPrivate(const QGLContext *context = 0);\n";
+print "\n";
+print "#ifndef QT_OPENGL_ES_2";
+print "\n";
+
+# Output the function pointers into the QOpenGLFunctionsPrivate class.
+$last_shader_only = 0;
+foreach ( @functions ) {
+ my $shader_only = ($_->{'shader_only'} && $_->{'shader_only'} eq 'yes');
+ my $inline = $_->{'inline'};
+ next if ($inline && $inline eq 'all');
+ next if $inline && $inline eq 'all_diff';
+ my $name = $_->{'varname'};
+ #print "#ifndef QT_OPENGL_ES_1\n" if ($shader_only && !$last_shader_only);
+ #print "#endif\n" if (!$shader_only && $last_shader_only);
+ print " $_->{'returnType'} (QT3D_GLF_APIENTRYP $name)($_->{'argstr'});\n";
+ $last_shader_only = $shader_only;
+}
+#print "#endif\n" if $last_shader_only;
+
+print "#endif\n";
+print "};\n";
+print "\n";
+
+my %platform_defines = ();
+$platform_defines{'es1'} = "defined(QT_OPENGL_ES_1)";
+$platform_defines{'es2'} = "defined(QT_OPENGL_ES_2)";
+$platform_defines{'es'} = "defined(QT_OPENGL_ES)";
+$platform_defines{'desktop'} = "!defined(QT_OPENGL_ES)";
+
+# Output the inline functions that call either the raw GL function
+# or resolve via the function pointer.
+$last_shader_only = 0;
+foreach ( @functions ) {
+ my $shader_only = ($_->{'shader_only'} && $_->{'shader_only'} eq 'yes');
+ my $funcname = $_->{'funcname'};
+ my $varname = $_->{'varname'};
+ my $is_void = ($_->{'returnType'} eq 'void');
+ my $inline = $_->{'inline'};
+ next if ($inline && $inline eq 'all');
+ #print "#ifndef QT_OPENGL_ES_1\n\n" if ($shader_only && !$last_shader_only);
+ #print "#endif\n\n" if (!$shader_only && $last_shader_only);
+ print "inline $_->{'returnType'} QOpenGLFunctions::$funcname($_->{'argstr'})\n";
+ print "{\n";
+ if ($_->{'es_name'}) {
+ # Functions like glClearDepth() that are inline, but named differently.
+ print "#ifndef QT_OPENGL_ES\n";
+ print " ::$_->{'name'}($_->{'argnamestr'});\n";
+ print "#else\n";
+ print " ::$_->{'es_name'}($_->{'argnamestr'});\n";
+ print "#endif\n";
+ } elsif ($inline && $inline eq 'all') {
+ # Inlined on all platforms.
+ if ($is_void) {
+ print (" ");
+ } else {
+ print (" return ");
+ }
+ print "::$_->{'name'}($_->{'argnamestr'});\n";
+ } elsif ($inline) {
+ # Inlined only on certain platforms.
+ my @platforms = split /,\s*/,$inline;
+ my @defines = ();
+ foreach (@platforms) {
+ push @defines, $platform_defines{$_};
+ }
+ print "#if ";
+ print join(' || ', @defines);
+ print "\n";
+ if ($is_void) {
+ print (" ");
+ } else {
+ print (" return ");
+ }
+ print "::$_->{'name'}($_->{'argnamestr'});\n";
+ print "#else\n";
+ print " Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));\n";
+ if ($is_void) {
+ print (" ");
+ } else {
+ print (" return ");
+ }
+ print "d_ptr->$varname($_->{'argnamestr'});\n";
+ print "#endif\n";
+ } else {
+ # Resolve on all platforms.
+ print " Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));\n";
+ if ($is_void) {
+ print (" ");
+ } else {
+ print (" return ");
+ }
+ print "d_ptr->$varname($_->{'argnamestr'});\n";
+ }
+ print "}\n\n";
+ $last_shader_only = $shader_only;
+}
+#print "#endif\n" if $last_shader_only;
+
+# Output the macro definitions.
+foreach ( @macros ) {
+ my $name = $_->{'name'};
+ my $value = $_->{'value'};
+ print "#ifndef $name\n";
+ print "#define $name $value\n";
+ print "#endif\n";
+}
+print "\n";
+
+print "// qopenglfunctions.cpp\n\n";
+
+# Generate qdoc documentation for all of the functions.
+foreach ( @functions ) {
+ my $inline = $_->{'inline'};
+ next if $inline && $inline eq 'all';
+
+ my $shader_only = ($_->{'shader_only'} && $_->{'shader_only'} eq 'yes');
+
+ my $name = $_->{'funcname'};
+
+ my $docargs = $_->{'argnamestr'};
+ if (length($docargs) > 0) {
+ $docargs =~ s/,/, \\a/g;
+ $docargs =~ s/^/\\a /;
+ }
+
+ my $khronos_name = $_->{'es_name'};
+ if (!$khronos_name) {
+ $khronos_name = $_->{'name'};
+ }
+
+ print "/*!\n";
+ print " \\fn $_->{'returnType'} QOpenGLFunctions::$name($_->{'argstr'})\n";
+ print "\n";
+ if ($khronos_name eq $_->{'name'}) {
+ print " Convenience function that calls $khronos_name($docargs).\n";
+ } else {
+ print " Convenience function that calls $_->{'name'}($docargs) on\n";
+ print " desktop OpenGL systems and $khronos_name($docargs) on\n";
+ print " embedded OpenGL/ES systems.\n";
+ }
+ print "\n";
+ print " For more information, see the OpenGL/ES 2.0 documentation for\n";
+ print " \\l{http://www.khronos.org/opengles/sdk/docs/man/$khronos_name.xml}{$khronos_name()}.\n";
+ if ($shader_only) {
+ print "\n";
+ print " This convenience function will do nothing on OpenGL/ES 1.x systems.\n";
+ }
+ print "*/\n\n";
+}
+
+# Generate the resolver functions.
+print "#ifndef QT_OPENGL_ES_2\n\n";
+$last_shader_only = 0;
+foreach ( @functions ) {
+ my $inline = $_->{'inline'};
+ next if $inline && $inline eq 'all';
+ next if $inline && $inline eq 'all_diff';
+ my $shader_only = ($_->{'shader_only'} && $_->{'shader_only'} eq 'yes');
+ my $name = $_->{'varname'};
+ my $resolver_name = $_->{'name'};
+ $resolver_name =~ s/^gl/qglfResolve/;
+ my $special_name = $_->{'name'};
+ $special_name =~ s/^gl/qglfSpecial/;
+ my @platforms = split /,\s*/,$inline;
+ $shader_only = 1 if @platforms ~~ 'es1';
+ my $is_void = ($_->{'returnType'} eq 'void');
+ my $special_handling = ($_->{'special_handling'} && $_->{'special_handling'} eq 'yes');
+ #print "#ifndef QT_OPENGL_ES_1\n\n" if ($shader_only && !$last_shader_only);
+ #print "#endif\n\n" if (!$shader_only && $last_shader_only);
+
+ if ($special_handling) {
+ # Output special fallback implementations for certain functions.
+ if ($name eq "getShaderPrecisionFormat") {
+ print "static $_->{'returnType'} QT3D_GLF_APIENTRY $special_name($_->{'argstr'})\n";
+ print "{\n";
+ print " Q_UNUSED(shadertype);\n";
+ print " Q_UNUSED(precisiontype);\n";
+ print " range[0] = range[1] = precision[0] = 0;\n";
+ print "}\n\n";
+ } elsif ($name eq "isProgram" || $name eq "isShader") {
+ print "static $_->{'returnType'} QT3D_GLF_APIENTRY $special_name($_->{'argstr'})\n";
+ print "{\n";
+ print " return $_->{'argnamestr'} != 0;\n";
+ print "}\n\n";
+ } elsif ($name eq "releaseShaderCompiler") {
+ print "static $_->{'returnType'} QT3D_GLF_APIENTRY $special_name($_->{'argstr'})\n";
+ print "{\n";
+ print "}\n\n";
+ }
+ }
+
+ print "static $_->{'returnType'} QT3D_GLF_APIENTRY $resolver_name($_->{'argstr'})\n";
+ print "{\n";
+ my $type_name = "type_$_->{'name'}";
+ print " typedef $_->{'returnType'} (QT3D_GLF_APIENTRYP $type_name)($_->{'argstr'});\n\n";
+ print " const QGLContext *context = QGLContext::currentContext();\n";
+ print " QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);\n";
+ print "\n";
+ print " funcs->$name = ($type_name)\n";
+ print " context->getProcAddress(QLatin1String(\"$_->{'name'}\"));\n";
+ my @alt_names = ();
+ if ($_->{'alt_name'}) {
+ push @alt_names, $_->{'alt_name'};
+ } else {
+ push @alt_names, "$_->{'name'}OES";
+ push @alt_names, "$_->{'name'}EXT";
+ push @alt_names, "$_->{'name'}ARB";
+ }
+ foreach (@alt_names) {
+ print "#ifdef QT_OPENGL_ES\n" if /OES/;
+ print " if (!funcs->$name) {\n";
+ print " funcs->$name = ($type_name)\n";
+ print " context->getProcAddress(QLatin1String(\"$_\"));\n";
+ print " }\n";
+ print "#endif\n" if /OES/;
+ }
+ if ($special_handling) {
+ print "\n";
+ print " if (!funcs->$name)\n";
+ print " funcs->$name = $special_name;\n\n";
+ if ($is_void) {
+ print (" ");
+ } else {
+ print (" return ");
+ }
+ print "funcs->$name($_->{'argnamestr'});\n";
+ } else {
+ print "\n";
+ print " if (funcs->$name)\n";
+ if ($is_void) {
+ print (" ");
+ } else {
+ print (" return ");
+ }
+ print "funcs->$name($_->{'argnamestr'});\n";
+ if ($is_void) {
+ print " else\n";
+ print " funcs->$name = $resolver_name;\n";
+ } else {
+ print " funcs->$name = $resolver_name;\n";
+ print " return $_->{'returnType'}(0);\n";
+ }
+ }
+ print "}\n\n";
+
+ $last_shader_only = $shader_only;
+}
+#print "#endif\n" if $last_shader_only;
+print "#endif // !QT_OPENGL_ES_2\n\n";
+
+# Generate the initialization code for QOpenGLFunctionsPrivate.
+print "QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(const QGLContext *)\n";
+print "{\n";
+print "#ifndef QT_OPENGL_ES_2\n";
+$last_shader_only = 0;
+foreach ( @functions ) {
+ my $inline = $_->{'inline'};
+ next if $inline && $inline eq 'all';
+ next if $inline && $inline eq 'all_diff';
+ my $shader_only = ($_->{'shader_only'} && $_->{'shader_only'} eq 'yes');
+ my $name = $_->{'varname'};
+ my $resolver_name = $_->{'name'};
+ $resolver_name =~ s/^gl/qglfResolve/;
+ my @platforms = split /,\s*/,$inline;
+ $shader_only = 1 if @platforms ~~ 'es1';
+ #print "#ifndef QT_OPENGL_ES_1\n" if ($shader_only && !$last_shader_only);
+ #print "#endif\n" if (!$shader_only && $last_shader_only);
+ print " $name = $resolver_name;\n";
+ $last_shader_only = $shader_only;
+}
+#print "#endif\n" if $last_shader_only;
+print "#endif // !QT_OPENGL_ES_2\n";
+print "}\n\n";
+
+#print Dumper(\@functions);
diff --git a/src/threed/api/qopenglfunctions.cpp b/src/threed/api/qopenglfunctions.cpp
new file mode 100644
index 000000000..fd5e1f072
--- /dev/null
+++ b/src/threed/api/qopenglfunctions.cpp
@@ -0,0 +1,3690 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopenglfunctions.h"
+#include "qglext_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpenGLFunctions
+ \brief The QOpenGLFunctions class provides cross-platform access to the OpenGL/ES 2.0 API.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::enablers
+
+ OpenGL/ES 2.0 defines a subset of the OpenGL specification that is
+ common across many desktop and embedded OpenGL implementations.
+ However, it can be difficult to use the functions from that subset
+ because they need to be resolved manually on desktop systems.
+
+ QOpenGLFunctions provides a guaranteed API that is available on all
+ OpenGL systems and takes care of function resolution on systems
+ that need it. The recommended way to use QOpenGLFunctions is by
+ direct inheritance:
+
+ \code
+ class MyGLWidget : public QGLWidget, protected QOpenGLFunctions
+ {
+ Q_OBJECT
+ public:
+ MyGLWidget(QWidget *parent = 0) : QGLWidget(parent) {}
+
+ protected:
+ void initializeGL();
+ void paintGL();
+ };
+
+ void MyGLWidget::initializeGL()
+ {
+ initializeGLFunctions();
+ }
+ \endcode
+
+ The \c{paintGL()} function can then use any of the OpenGL/ES 2.0
+ functions without explicit resolution, such as glActiveTexture()
+ in the following example:
+
+ \code
+ void MyGLWidget::paintGL()
+ {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ ...
+ }
+ \endcode
+
+ QOpenGLFunctions can also be used directly for ad-hoc invocation
+ of OpenGL/ES 2.0 functions on all platforms:
+
+ \code
+ QOpenGLFunctions glFuncs(QGLContext::currentContext());
+ glFuncs.glActiveTexture(GL_TEXTURE1);
+ \endcode
+
+ QOpenGLFunctions provides wrappers for all OpenGL/ES 2.0 functions,
+ except those like \c{glDrawArrays()}, \c{glViewport()}, and
+ \c{glBindTexture()} that don't have portability issues.
+
+ Including the header for QOpenGLFunctions will also define all of
+ the OpenGL/ES 2.0 macro constants that are not already defined by
+ the system's OpenGL headers, such as \c{GL_TEXTURE1} above.
+
+ The hasOpenGLFeature() and openGLFeatures() functions can be used
+ to determine if the OpenGL implementation has a major OpenGL/ES 2.0
+ feature. For example, the following checks if non power of two
+ textures are available:
+
+ \code
+ QOpenGLFunctions funcs(QGLContext::currentContext());
+ bool npot = funcs.hasOpenGLFeature(QOpenGLFunctions::NPOTTextures);
+ \endcode
+*/
+
+/*!
+ \enum QOpenGLFunctions::OpenGLFeature
+ This enum defines OpenGL/ES 2.0 features that may be optional
+ on other platforms.
+
+ \value Multitexture glActiveTexture() function is available.
+ \value Shaders Shader functions are available.
+ \value Buffers Vertex and index buffer functions are available.
+ \value Framebuffers Framebuffer object functions are available.
+ \value BlendColor glBlendColor() is available.
+ \value BlendEquation glBlendEquation() is available.
+ \value BlendEquationSeparate glBlendEquationSeparate() is available.
+ \value BlendFuncSeparate glBlendFuncSeparate() is available.
+ \value BlendSubtract Blend subtract mode is available.
+ \value CompressedTextures Compressed texture functions are available.
+ \value Multisample glSampleCoverage() function is available.
+ \value StencilSeparate Separate stencil functions are available.
+ \value NPOTTextures Non power of two textures are available.
+*/
+
+// Hidden private fields for additional extension data.
+// Hidden private fields for additional extension data.
+struct QOpenGLFunctionsPrivateEx : public QOpenGLFunctionsPrivate
+{
+ QOpenGLFunctionsPrivateEx(const QGLContext *context = 0)
+ : QOpenGLFunctionsPrivate(context)
+ , m_features(-1) {}
+
+ int m_features;
+};
+
+Q_GLOBAL_STATIC(QGLResource<QOpenGLFunctionsPrivateEx>, qt_gl_functions_resource)
+
+static QOpenGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0)
+{
+ if (!context)
+ context = QGLContext::currentContext();
+ Q_ASSERT(context);
+ return qt_gl_functions_resource()->value(context);
+}
+
+/*!
+ Constructs a default function resolver. The resolver cannot
+ be used until initializeGLFunctions() is called to specify
+ the context.
+
+ \sa initializeGLFunctions()
+*/
+QOpenGLFunctions::QOpenGLFunctions()
+ : d_ptr(0)
+{
+}
+
+/*!
+ Constructs a function resolver for \a context. If \a context
+ is null, then the resolver will be created for the current QGLContext.
+
+ An object constructed in this way can only be used with \a context
+ and other contexts that share with it. Use initializeGLFunctions()
+ to change the object's context association.
+
+ \sa initializeGLFunctions()
+*/
+QOpenGLFunctions::QOpenGLFunctions(const QGLContext *context)
+ : d_ptr(qt_gl_functions(context))
+{
+}
+
+/*!
+ \fn QOpenGLFunctions::~QOpenGLFunctions()
+
+ Destroys this function resolver.
+*/
+
+static int qt_gl_resolve_features()
+{
+#if defined(QT_OPENGL_ES_2)
+ return QOpenGLFunctions::Multitexture |
+ QOpenGLFunctions::Shaders |
+ QOpenGLFunctions::Buffers |
+ QOpenGLFunctions::Framebuffers |
+ QOpenGLFunctions::BlendColor |
+ QOpenGLFunctions::BlendEquation |
+ QOpenGLFunctions::BlendEquationSeparate |
+ QOpenGLFunctions::BlendFuncSeparate |
+ QOpenGLFunctions::BlendSubtract |
+ QOpenGLFunctions::CompressedTextures |
+ QOpenGLFunctions::Multisample |
+ QOpenGLFunctions::StencilSeparate |
+ QOpenGLFunctions::NPOTTextures;
+#elif defined(QT_OPENGL_ES)
+ int features = QOpenGLFunctions::Multitexture |
+ QOpenGLFunctions::Buffers |
+ QOpenGLFunctions::CompressedTextures |
+ QOpenGLFunctions::Multisample;
+ QGLExtensionChecker extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
+ if (extensions.match("GL_OES_framebuffer_object"))
+ features |= QOpenGLFunctions::Framebuffers;
+ if (extensions.match("GL_OES_blend_equation_separate"))
+ features |= QOpenGLFunctions::BlendEquationSeparate;
+ if (extensions.match("GL_OES_blend_func_separate"))
+ features |= QOpenGLFunctions::BlendFuncSeparate;
+ if (extensions.match("GL_OES_blend_subtract"))
+ features |= QOpenGLFunctions::BlendSubtract;
+ if (extensions.match("GL_OES_texture_npot"))
+ features |= QOpenGLFunctions::NPOTTextures;
+ return features;
+#else
+ int features = 0;
+ QGLFormat::OpenGLVersionFlags versions = QGLFormat::openGLVersionFlags();
+ QGLExtensionChecker extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
+
+ // Recognize features by extension name.
+ if (extensions.match("GL_ARB_multitexture"))
+ features |= QOpenGLFunctions::Multitexture;
+ if (extensions.match("GL_ARB_shader_objects"))
+ features |= QOpenGLFunctions::Shaders;
+ if (extensions.match("GL_EXT_framebuffer_object") ||
+ extensions.match("GL_ARB_framebuffer_object"))
+ features |= QOpenGLFunctions::Framebuffers;
+ if (extensions.match("GL_EXT_blend_color"))
+ features |= QOpenGLFunctions::BlendColor;
+ if (extensions.match("GL_EXT_blend_equation_separate"))
+ features |= QOpenGLFunctions::BlendEquationSeparate;
+ if (extensions.match("GL_EXT_blend_func_separate"))
+ features |= QOpenGLFunctions::BlendFuncSeparate;
+ if (extensions.match("GL_EXT_blend_subtract"))
+ features |= QOpenGLFunctions::BlendSubtract;
+ if (extensions.match("GL_ARB_texture_compression"))
+ features |= QOpenGLFunctions::CompressedTextures;
+ if (extensions.match("GL_ARB_multisample"))
+ features |= QOpenGLFunctions::Multisample;
+ if (extensions.match("GL_ARB_texture_non_power_of_two"))
+ features |= QOpenGLFunctions::NPOTTextures;
+
+ // Recognize features by minimum OpenGL version.
+ if (versions & QGLFormat::OpenGL_Version_1_2) {
+ features |= QOpenGLFunctions::BlendColor |
+ QOpenGLFunctions::BlendEquation;
+ }
+ if (versions & QGLFormat::OpenGL_Version_1_3) {
+ features |= QOpenGLFunctions::Multitexture |
+ QOpenGLFunctions::CompressedTextures |
+ QOpenGLFunctions::Multisample;
+ }
+ if (versions & QGLFormat::OpenGL_Version_1_4)
+ features |= QOpenGLFunctions::BlendFuncSeparate;
+ if (versions & QGLFormat::OpenGL_Version_1_5)
+ features |= QOpenGLFunctions::Buffers;
+ if (versions & QGLFormat::OpenGL_Version_2_0) {
+ features |= QOpenGLFunctions::Shaders |
+ QOpenGLFunctions::StencilSeparate |
+ QOpenGLFunctions::BlendEquationSeparate |
+ QOpenGLFunctions::NPOTTextures;
+ }
+ return features;
+#endif
+}
+
+/*!
+ Returns the set of features that are present on this system's
+ OpenGL implementation.
+
+ It is assumed that the QGLContext associated with this function
+ resolver is current.
+
+ \sa hasOpenGLFeature()
+*/
+QOpenGLFunctions::OpenGLFeatures QOpenGLFunctions::openGLFeatures() const
+{
+ QOpenGLFunctionsPrivateEx *d = static_cast<QOpenGLFunctionsPrivateEx *>(d_ptr);
+ if (!d)
+ return 0;
+ if (d->m_features == -1)
+ d->m_features = qt_gl_resolve_features();
+ return QOpenGLFunctions::OpenGLFeatures(d->m_features);
+}
+
+/*!
+ Returns true if \a feature is present on this system's OpenGL
+ implementation; false otherwise.
+
+ It is assumed that the QGLContext associated with this function
+ resolver is current.
+
+ \sa openGLFeatures()
+*/
+bool QOpenGLFunctions::hasOpenGLFeature(QOpenGLFunctions::OpenGLFeature feature) const
+{
+ QOpenGLFunctionsPrivateEx *d = static_cast<QOpenGLFunctionsPrivateEx *>(d_ptr);
+ if (!d)
+ return false;
+ if (d->m_features == -1)
+ d->m_features = qt_gl_resolve_features();
+ return (d->m_features & int(feature)) != 0;
+}
+
+/*!
+ Initializes GL function resolution for \a context. If \a context
+ is null, then the current QGLContext will be used.
+
+ After calling this function, the QOpenGLFunctions object can only be
+ used with \a context and other contexts that share with it.
+ Call initializeGLFunctions() again to change the object's context
+ association.
+*/
+void QOpenGLFunctions::initializeGLFunctions(const QGLContext *context)
+{
+ d_ptr = qt_gl_functions(context);
+}
+
+
+/*!
+ \fn void QOpenGLFunctions::glActiveTexture(GLenum texture)
+
+ Convenience function that calls glActiveTexture(\a texture).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glActiveTexture.xml}{glActiveTexture()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glAttachShader(GLuint program, GLuint shader)
+
+ Convenience function that calls glAttachShader(\a program, \a shader).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glAttachShader.xml}{glAttachShader()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBindAttribLocation(GLuint program, GLuint index, const char* name)
+
+ Convenience function that calls glBindAttribLocation(\a program, \a index, \a name).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBindAttribLocation.xml}{glBindAttribLocation()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBindBuffer(GLenum target, GLuint buffer)
+
+ Convenience function that calls glBindBuffer(\a target, \a buffer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBindBuffer.xml}{glBindBuffer()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffer)
+
+ Convenience function that calls glBindFramebuffer(\a target, \a framebuffer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBindFramebuffer.xml}{glBindFramebuffer()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+
+ Convenience function that calls glBindRenderbuffer(\a target, \a renderbuffer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBindRenderbuffer.xml}{glBindRenderbuffer()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+
+ Convenience function that calls glBlendColor(\a red, \a green, \a blue, \a alpha).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendColor.xml}{glBlendColor()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBlendEquation(GLenum mode)
+
+ Convenience function that calls glBlendEquation(\a mode).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendEquation.xml}{glBlendEquation()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+
+ Convenience function that calls glBlendEquationSeparate(\a modeRGB, \a modeAlpha).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendEquationSeparate.xml}{glBlendEquationSeparate()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+
+ Convenience function that calls glBlendFuncSeparate(\a srcRGB, \a dstRGB, \a srcAlpha, \a dstAlpha).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendFuncSeparate.xml}{glBlendFuncSeparate()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBufferData(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage)
+
+ Convenience function that calls glBufferData(\a target, \a size, \a data, \a usage).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBufferData.xml}{glBufferData()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glBufferSubData(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data)
+
+ Convenience function that calls glBufferSubData(\a target, \a offset, \a size, \a data).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glBufferSubData.xml}{glBufferSubData()}.
+*/
+
+/*!
+ \fn GLenum QOpenGLFunctions::glCheckFramebufferStatus(GLenum target)
+
+ Convenience function that calls glCheckFramebufferStatus(\a target).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glCheckFramebufferStatus.xml}{glCheckFramebufferStatus()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glClearDepthf(GLclampf depth)
+
+ Convenience function that calls glClearDepth(\a depth) on
+ desktop OpenGL systems and glClearDepthf(\a depth) on
+ embedded OpenGL/ES systems.
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glClearDepthf.xml}{glClearDepthf()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glCompileShader(GLuint shader)
+
+ Convenience function that calls glCompileShader(\a shader).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glCompileShader.xml}{glCompileShader()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+
+ Convenience function that calls glCompressedTexImage2D(\a target, \a level, \a internalformat, \a width, \a height, \a border, \a imageSize, \a data).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glCompressedTexImage2D.xml}{glCompressedTexImage2D()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+
+ Convenience function that calls glCompressedTexSubImage2D(\a target, \a level, \a xoffset, \a yoffset, \a width, \a height, \a format, \a imageSize, \a data).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glCompressedTexSubImage2D.xml}{glCompressedTexSubImage2D()}.
+*/
+
+/*!
+ \fn GLuint QOpenGLFunctions::glCreateProgram()
+
+ Convenience function that calls glCreateProgram().
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glCreateProgram.xml}{glCreateProgram()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn GLuint QOpenGLFunctions::glCreateShader(GLenum type)
+
+ Convenience function that calls glCreateShader(\a type).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glCreateShader.xml}{glCreateShader()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDeleteBuffers(GLsizei n, const GLuint* buffers)
+
+ Convenience function that calls glDeleteBuffers(\a n, \a buffers).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteBuffers.xml}{glDeleteBuffers()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+
+ Convenience function that calls glDeleteFramebuffers(\a n, \a framebuffers).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteFramebuffers.xml}{glDeleteFramebuffers()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDeleteProgram(GLuint program)
+
+ Convenience function that calls glDeleteProgram(\a program).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteProgram.xml}{glDeleteProgram()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+
+ Convenience function that calls glDeleteRenderbuffers(\a n, \a renderbuffers).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteRenderbuffers.xml}{glDeleteRenderbuffers()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDeleteShader(GLuint shader)
+
+ Convenience function that calls glDeleteShader(\a shader).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteShader.xml}{glDeleteShader()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar)
+
+ Convenience function that calls glDepthRange(\a zNear, \a zFar) on
+ desktop OpenGL systems and glDepthRangef(\a zNear, \a zFar) on
+ embedded OpenGL/ES systems.
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDepthRangef.xml}{glDepthRangef()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDetachShader(GLuint program, GLuint shader)
+
+ Convenience function that calls glDetachShader(\a program, \a shader).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDetachShader.xml}{glDetachShader()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glDisableVertexAttribArray(GLuint index)
+
+ Convenience function that calls glDisableVertexAttribArray(\a index).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glDisableVertexAttribArray.xml}{glDisableVertexAttribArray()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glEnableVertexAttribArray(GLuint index)
+
+ Convenience function that calls glEnableVertexAttribArray(\a index).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glEnableVertexAttribArray.xml}{glEnableVertexAttribArray()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+
+ Convenience function that calls glFramebufferRenderbuffer(\a target, \a attachment, \a renderbuffertarget, \a renderbuffer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glFramebufferRenderbuffer.xml}{glFramebufferRenderbuffer()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+
+ Convenience function that calls glFramebufferTexture2D(\a target, \a attachment, \a textarget, \a texture, \a level).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glFramebufferTexture2D.xml}{glFramebufferTexture2D()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGenBuffers(GLsizei n, GLuint* buffers)
+
+ Convenience function that calls glGenBuffers(\a n, \a buffers).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGenBuffers.xml}{glGenBuffers()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGenerateMipmap(GLenum target)
+
+ Convenience function that calls glGenerateMipmap(\a target).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGenerateMipmap.xml}{glGenerateMipmap()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGenFramebuffers(GLsizei n, GLuint* framebuffers)
+
+ Convenience function that calls glGenFramebuffers(\a n, \a framebuffers).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGenFramebuffers.xml}{glGenFramebuffers()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+
+ Convenience function that calls glGenRenderbuffers(\a n, \a renderbuffers).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGenRenderbuffers.xml}{glGenRenderbuffers()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+
+ Convenience function that calls glGetActiveAttrib(\a program, \a index, \a bufsize, \a length, \a size, \a type, \a name).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetActiveAttrib.xml}{glGetActiveAttrib()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+
+ Convenience function that calls glGetActiveUniform(\a program, \a index, \a bufsize, \a length, \a size, \a type, \a name).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetActiveUniform.xml}{glGetActiveUniform()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+
+ Convenience function that calls glGetAttachedShaders(\a program, \a maxcount, \a count, \a shaders).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetAttachedShaders.xml}{glGetAttachedShaders()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn int QOpenGLFunctions::glGetAttribLocation(GLuint program, const char* name)
+
+ Convenience function that calls glGetAttribLocation(\a program, \a name).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetAttribLocation.xml}{glGetAttribLocation()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetBufferParameteriv(\a target, \a pname, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetBufferParameteriv.xml}{glGetBufferParameteriv()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetFramebufferAttachmentParameteriv(\a target, \a attachment, \a pname, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetFramebufferAttachmentParameteriv.xml}{glGetFramebufferAttachmentParameteriv()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetProgramiv(\a program, \a pname, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetProgramiv.xml}{glGetProgramiv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+
+ Convenience function that calls glGetProgramInfoLog(\a program, \a bufsize, \a length, \a infolog).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetProgramInfoLog.xml}{glGetProgramInfoLog()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetRenderbufferParameteriv(\a target, \a pname, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetRenderbufferParameteriv.xml}{glGetRenderbufferParameteriv()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetShaderiv(\a shader, \a pname, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderiv.xml}{glGetShaderiv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+
+ Convenience function that calls glGetShaderInfoLog(\a shader, \a bufsize, \a length, \a infolog).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderInfoLog.xml}{glGetShaderInfoLog()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+
+ Convenience function that calls glGetShaderPrecisionFormat(\a shadertype, \a precisiontype, \a range, \a precision).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderPrecisionFormat.xml}{glGetShaderPrecisionFormat()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+
+ Convenience function that calls glGetShaderSource(\a shader, \a bufsize, \a length, \a source).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderSource.xml}{glGetShaderSource()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+
+ Convenience function that calls glGetUniformfv(\a program, \a location, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetUniformfv.xml}{glGetUniformfv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetUniformiv(GLuint program, GLint location, GLint* params)
+
+ Convenience function that calls glGetUniformiv(\a program, \a location, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetUniformiv.xml}{glGetUniformiv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn int QOpenGLFunctions::glGetUniformLocation(GLuint program, const char* name)
+
+ Convenience function that calls glGetUniformLocation(\a program, \a name).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetUniformLocation.xml}{glGetUniformLocation()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+
+ Convenience function that calls glGetVertexAttribfv(\a index, \a pname, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetVertexAttribfv.xml}{glGetVertexAttribfv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetVertexAttribiv(\a index, \a pname, \a params).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetVertexAttribiv.xml}{glGetVertexAttribiv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer)
+
+ Convenience function that calls glGetVertexAttribPointerv(\a index, \a pname, \a pointer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glGetVertexAttribPointerv.xml}{glGetVertexAttribPointerv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn GLboolean QOpenGLFunctions::glIsBuffer(GLuint buffer)
+
+ Convenience function that calls glIsBuffer(\a buffer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glIsBuffer.xml}{glIsBuffer()}.
+*/
+
+/*!
+ \fn GLboolean QOpenGLFunctions::glIsFramebuffer(GLuint framebuffer)
+
+ Convenience function that calls glIsFramebuffer(\a framebuffer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glIsFramebuffer.xml}{glIsFramebuffer()}.
+*/
+
+/*!
+ \fn GLboolean QOpenGLFunctions::glIsProgram(GLuint program)
+
+ Convenience function that calls glIsProgram(\a program).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glIsProgram.xml}{glIsProgram()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn GLboolean QOpenGLFunctions::glIsRenderbuffer(GLuint renderbuffer)
+
+ Convenience function that calls glIsRenderbuffer(\a renderbuffer).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glIsRenderbuffer.xml}{glIsRenderbuffer()}.
+*/
+
+/*!
+ \fn GLboolean QOpenGLFunctions::glIsShader(GLuint shader)
+
+ Convenience function that calls glIsShader(\a shader).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glIsShader.xml}{glIsShader()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glLinkProgram(GLuint program)
+
+ Convenience function that calls glLinkProgram(\a program).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glLinkProgram.xml}{glLinkProgram()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glReleaseShaderCompiler()
+
+ Convenience function that calls glReleaseShaderCompiler().
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glReleaseShaderCompiler.xml}{glReleaseShaderCompiler()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+
+ Convenience function that calls glRenderbufferStorage(\a target, \a internalformat, \a width, \a height).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glRenderbufferStorage.xml}{glRenderbufferStorage()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glSampleCoverage(GLclampf value, GLboolean invert)
+
+ Convenience function that calls glSampleCoverage(\a value, \a invert).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glSampleCoverage.xml}{glSampleCoverage()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length)
+
+ Convenience function that calls glShaderBinary(\a n, \a shaders, \a binaryformat, \a binary, \a length).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glShaderBinary.xml}{glShaderBinary()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
+
+ Convenience function that calls glShaderSource(\a shader, \a count, \a string, \a length).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glShaderSource.xml}{glShaderSource()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+
+ Convenience function that calls glStencilFuncSeparate(\a face, \a func, \a ref, \a mask).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glStencilFuncSeparate.xml}{glStencilFuncSeparate()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glStencilMaskSeparate(GLenum face, GLuint mask)
+
+ Convenience function that calls glStencilMaskSeparate(\a face, \a mask).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glStencilMaskSeparate.xml}{glStencilMaskSeparate()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+
+ Convenience function that calls glStencilOpSeparate(\a face, \a fail, \a zfail, \a zpass).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glStencilOpSeparate.xml}{glStencilOpSeparate()}.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform1f(GLint location, GLfloat x)
+
+ Convenience function that calls glUniform1f(\a location, \a x).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1f.xml}{glUniform1f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+
+ Convenience function that calls glUniform1fv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1fv.xml}{glUniform1fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform1i(GLint location, GLint x)
+
+ Convenience function that calls glUniform1i(\a location, \a x).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1i.xml}{glUniform1i()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform1iv(GLint location, GLsizei count, const GLint* v)
+
+ Convenience function that calls glUniform1iv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1iv.xml}{glUniform1iv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform2f(GLint location, GLfloat x, GLfloat y)
+
+ Convenience function that calls glUniform2f(\a location, \a x, \a y).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2f.xml}{glUniform2f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+
+ Convenience function that calls glUniform2fv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2fv.xml}{glUniform2fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform2i(GLint location, GLint x, GLint y)
+
+ Convenience function that calls glUniform2i(\a location, \a x, \a y).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2i.xml}{glUniform2i()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform2iv(GLint location, GLsizei count, const GLint* v)
+
+ Convenience function that calls glUniform2iv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2iv.xml}{glUniform2iv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+
+ Convenience function that calls glUniform3f(\a location, \a x, \a y, \a z).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3f.xml}{glUniform3f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+
+ Convenience function that calls glUniform3fv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3fv.xml}{glUniform3fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform3i(GLint location, GLint x, GLint y, GLint z)
+
+ Convenience function that calls glUniform3i(\a location, \a x, \a y, \a z).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3i.xml}{glUniform3i()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform3iv(GLint location, GLsizei count, const GLint* v)
+
+ Convenience function that calls glUniform3iv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3iv.xml}{glUniform3iv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+
+ Convenience function that calls glUniform4f(\a location, \a x, \a y, \a z, \a w).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4f.xml}{glUniform4f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+
+ Convenience function that calls glUniform4fv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4fv.xml}{glUniform4fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+
+ Convenience function that calls glUniform4i(\a location, \a x, \a y, \a z, \a w).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4i.xml}{glUniform4i()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniform4iv(GLint location, GLsizei count, const GLint* v)
+
+ Convenience function that calls glUniform4iv(\a location, \a count, \a v).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4iv.xml}{glUniform4iv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+
+ Convenience function that calls glUniformMatrix2fv(\a location, \a count, \a transpose, \a value).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniformMatrix2fv.xml}{glUniformMatrix2fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+
+ Convenience function that calls glUniformMatrix3fv(\a location, \a count, \a transpose, \a value).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniformMatrix3fv.xml}{glUniformMatrix3fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+
+ Convenience function that calls glUniformMatrix4fv(\a location, \a count, \a transpose, \a value).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUniformMatrix4fv.xml}{glUniformMatrix4fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glUseProgram(GLuint program)
+
+ Convenience function that calls glUseProgram(\a program).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glUseProgram.xml}{glUseProgram()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glValidateProgram(GLuint program)
+
+ Convenience function that calls glValidateProgram(\a program).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glValidateProgram.xml}{glValidateProgram()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib1f(GLuint indx, GLfloat x)
+
+ Convenience function that calls glVertexAttrib1f(\a indx, \a x).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib1f.xml}{glVertexAttrib1f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib1fv(GLuint indx, const GLfloat* values)
+
+ Convenience function that calls glVertexAttrib1fv(\a indx, \a values).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib1fv.xml}{glVertexAttrib1fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+
+ Convenience function that calls glVertexAttrib2f(\a indx, \a x, \a y).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib2f.xml}{glVertexAttrib2f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib2fv(GLuint indx, const GLfloat* values)
+
+ Convenience function that calls glVertexAttrib2fv(\a indx, \a values).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib2fv.xml}{glVertexAttrib2fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+
+ Convenience function that calls glVertexAttrib3f(\a indx, \a x, \a y, \a z).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib3f.xml}{glVertexAttrib3f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib3fv(GLuint indx, const GLfloat* values)
+
+ Convenience function that calls glVertexAttrib3fv(\a indx, \a values).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib3fv.xml}{glVertexAttrib3fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+
+ Convenience function that calls glVertexAttrib4f(\a indx, \a x, \a y, \a z, \a w).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib4f.xml}{glVertexAttrib4f()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttrib4fv(GLuint indx, const GLfloat* values)
+
+ Convenience function that calls glVertexAttrib4fv(\a indx, \a values).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib4fv.xml}{glVertexAttrib4fv()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+/*!
+ \fn void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+
+ Convenience function that calls glVertexAttribPointer(\a indx, \a size, \a type, \a normalized, \a stride, \a ptr).
+
+ For more information, see the OpenGL/ES 2.0 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttribPointer.xml}{glVertexAttribPointer()}.
+
+ This convenience function will do nothing on OpenGL/ES 1.x systems.
+*/
+
+#ifndef QT_OPENGL_ES_2
+
+static void QT3D_GLF_APIENTRY qglfResolveActiveTexture(GLenum texture)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glActiveTexture)(GLenum texture);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->activeTexture = (type_glActiveTexture)
+ context->getProcAddress(QLatin1String("glActiveTexture"));
+ if (!funcs->activeTexture) {
+ funcs->activeTexture = (type_glActiveTexture)
+ context->getProcAddress(QLatin1String("glActiveTextureARB"));
+ }
+
+ if (funcs->activeTexture)
+ funcs->activeTexture(texture);
+ else
+ funcs->activeTexture = qglfResolveActiveTexture;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveAttachShader(GLuint program, GLuint shader)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glAttachShader)(GLuint program, GLuint shader);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->attachShader = (type_glAttachShader)
+ context->getProcAddress(QLatin1String("glAttachShader"));
+ if (!funcs->attachShader) {
+ funcs->attachShader = (type_glAttachShader)
+ context->getProcAddress(QLatin1String("glAttachObjectARB"));
+ }
+
+ if (funcs->attachShader)
+ funcs->attachShader(program, shader);
+ else
+ funcs->attachShader = qglfResolveAttachShader;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBindAttribLocation(GLuint program, GLuint index, const char* name)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBindAttribLocation)(GLuint program, GLuint index, const char* name);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->bindAttribLocation = (type_glBindAttribLocation)
+ context->getProcAddress(QLatin1String("glBindAttribLocation"));
+ if (!funcs->bindAttribLocation) {
+ funcs->bindAttribLocation = (type_glBindAttribLocation)
+ context->getProcAddress(QLatin1String("glBindAttribLocationARB"));
+ }
+
+ if (funcs->bindAttribLocation)
+ funcs->bindAttribLocation(program, index, name);
+ else
+ funcs->bindAttribLocation = qglfResolveBindAttribLocation;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBindBuffer(GLenum target, GLuint buffer)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBindBuffer)(GLenum target, GLuint buffer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->bindBuffer = (type_glBindBuffer)
+ context->getProcAddress(QLatin1String("glBindBuffer"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->bindBuffer) {
+ funcs->bindBuffer = (type_glBindBuffer)
+ context->getProcAddress(QLatin1String("glBindBufferOES"));
+ }
+#endif
+ if (!funcs->bindBuffer) {
+ funcs->bindBuffer = (type_glBindBuffer)
+ context->getProcAddress(QLatin1String("glBindBufferEXT"));
+ }
+ if (!funcs->bindBuffer) {
+ funcs->bindBuffer = (type_glBindBuffer)
+ context->getProcAddress(QLatin1String("glBindBufferARB"));
+ }
+
+ if (funcs->bindBuffer)
+ funcs->bindBuffer(target, buffer);
+ else
+ funcs->bindBuffer = qglfResolveBindBuffer;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBindFramebuffer)(GLenum target, GLuint framebuffer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->bindFramebuffer = (type_glBindFramebuffer)
+ context->getProcAddress(QLatin1String("glBindFramebuffer"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->bindFramebuffer) {
+ funcs->bindFramebuffer = (type_glBindFramebuffer)
+ context->getProcAddress(QLatin1String("glBindFramebufferOES"));
+ }
+#endif
+ if (!funcs->bindFramebuffer) {
+ funcs->bindFramebuffer = (type_glBindFramebuffer)
+ context->getProcAddress(QLatin1String("glBindFramebufferEXT"));
+ }
+ if (!funcs->bindFramebuffer) {
+ funcs->bindFramebuffer = (type_glBindFramebuffer)
+ context->getProcAddress(QLatin1String("glBindFramebufferARB"));
+ }
+
+ if (funcs->bindFramebuffer)
+ funcs->bindFramebuffer(target, framebuffer);
+ else
+ funcs->bindFramebuffer = qglfResolveBindFramebuffer;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBindRenderbuffer)(GLenum target, GLuint renderbuffer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->bindRenderbuffer = (type_glBindRenderbuffer)
+ context->getProcAddress(QLatin1String("glBindRenderbuffer"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->bindRenderbuffer) {
+ funcs->bindRenderbuffer = (type_glBindRenderbuffer)
+ context->getProcAddress(QLatin1String("glBindRenderbufferOES"));
+ }
+#endif
+ if (!funcs->bindRenderbuffer) {
+ funcs->bindRenderbuffer = (type_glBindRenderbuffer)
+ context->getProcAddress(QLatin1String("glBindRenderbufferEXT"));
+ }
+ if (!funcs->bindRenderbuffer) {
+ funcs->bindRenderbuffer = (type_glBindRenderbuffer)
+ context->getProcAddress(QLatin1String("glBindRenderbufferARB"));
+ }
+
+ if (funcs->bindRenderbuffer)
+ funcs->bindRenderbuffer(target, renderbuffer);
+ else
+ funcs->bindRenderbuffer = qglfResolveBindRenderbuffer;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->blendColor = (type_glBlendColor)
+ context->getProcAddress(QLatin1String("glBlendColor"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->blendColor) {
+ funcs->blendColor = (type_glBlendColor)
+ context->getProcAddress(QLatin1String("glBlendColorOES"));
+ }
+#endif
+ if (!funcs->blendColor) {
+ funcs->blendColor = (type_glBlendColor)
+ context->getProcAddress(QLatin1String("glBlendColorEXT"));
+ }
+ if (!funcs->blendColor) {
+ funcs->blendColor = (type_glBlendColor)
+ context->getProcAddress(QLatin1String("glBlendColorARB"));
+ }
+
+ if (funcs->blendColor)
+ funcs->blendColor(red, green, blue, alpha);
+ else
+ funcs->blendColor = qglfResolveBlendColor;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBlendEquation(GLenum mode)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBlendEquation)(GLenum mode);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->blendEquation = (type_glBlendEquation)
+ context->getProcAddress(QLatin1String("glBlendEquation"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->blendEquation) {
+ funcs->blendEquation = (type_glBlendEquation)
+ context->getProcAddress(QLatin1String("glBlendEquationOES"));
+ }
+#endif
+ if (!funcs->blendEquation) {
+ funcs->blendEquation = (type_glBlendEquation)
+ context->getProcAddress(QLatin1String("glBlendEquationEXT"));
+ }
+ if (!funcs->blendEquation) {
+ funcs->blendEquation = (type_glBlendEquation)
+ context->getProcAddress(QLatin1String("glBlendEquationARB"));
+ }
+
+ if (funcs->blendEquation)
+ funcs->blendEquation(mode);
+ else
+ funcs->blendEquation = qglfResolveBlendEquation;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->blendEquationSeparate = (type_glBlendEquationSeparate)
+ context->getProcAddress(QLatin1String("glBlendEquationSeparate"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->blendEquationSeparate) {
+ funcs->blendEquationSeparate = (type_glBlendEquationSeparate)
+ context->getProcAddress(QLatin1String("glBlendEquationSeparateOES"));
+ }
+#endif
+ if (!funcs->blendEquationSeparate) {
+ funcs->blendEquationSeparate = (type_glBlendEquationSeparate)
+ context->getProcAddress(QLatin1String("glBlendEquationSeparateEXT"));
+ }
+ if (!funcs->blendEquationSeparate) {
+ funcs->blendEquationSeparate = (type_glBlendEquationSeparate)
+ context->getProcAddress(QLatin1String("glBlendEquationSeparateARB"));
+ }
+
+ if (funcs->blendEquationSeparate)
+ funcs->blendEquationSeparate(modeRGB, modeAlpha);
+ else
+ funcs->blendEquationSeparate = qglfResolveBlendEquationSeparate;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->blendFuncSeparate = (type_glBlendFuncSeparate)
+ context->getProcAddress(QLatin1String("glBlendFuncSeparate"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->blendFuncSeparate) {
+ funcs->blendFuncSeparate = (type_glBlendFuncSeparate)
+ context->getProcAddress(QLatin1String("glBlendFuncSeparateOES"));
+ }
+#endif
+ if (!funcs->blendFuncSeparate) {
+ funcs->blendFuncSeparate = (type_glBlendFuncSeparate)
+ context->getProcAddress(QLatin1String("glBlendFuncSeparateEXT"));
+ }
+ if (!funcs->blendFuncSeparate) {
+ funcs->blendFuncSeparate = (type_glBlendFuncSeparate)
+ context->getProcAddress(QLatin1String("glBlendFuncSeparateARB"));
+ }
+
+ if (funcs->blendFuncSeparate)
+ funcs->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ else
+ funcs->blendFuncSeparate = qglfResolveBlendFuncSeparate;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBufferData(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBufferData)(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->bufferData = (type_glBufferData)
+ context->getProcAddress(QLatin1String("glBufferData"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->bufferData) {
+ funcs->bufferData = (type_glBufferData)
+ context->getProcAddress(QLatin1String("glBufferDataOES"));
+ }
+#endif
+ if (!funcs->bufferData) {
+ funcs->bufferData = (type_glBufferData)
+ context->getProcAddress(QLatin1String("glBufferDataEXT"));
+ }
+ if (!funcs->bufferData) {
+ funcs->bufferData = (type_glBufferData)
+ context->getProcAddress(QLatin1String("glBufferDataARB"));
+ }
+
+ if (funcs->bufferData)
+ funcs->bufferData(target, size, data, usage);
+ else
+ funcs->bufferData = qglfResolveBufferData;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveBufferSubData(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glBufferSubData)(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->bufferSubData = (type_glBufferSubData)
+ context->getProcAddress(QLatin1String("glBufferSubData"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->bufferSubData) {
+ funcs->bufferSubData = (type_glBufferSubData)
+ context->getProcAddress(QLatin1String("glBufferSubDataOES"));
+ }
+#endif
+ if (!funcs->bufferSubData) {
+ funcs->bufferSubData = (type_glBufferSubData)
+ context->getProcAddress(QLatin1String("glBufferSubDataEXT"));
+ }
+ if (!funcs->bufferSubData) {
+ funcs->bufferSubData = (type_glBufferSubData)
+ context->getProcAddress(QLatin1String("glBufferSubDataARB"));
+ }
+
+ if (funcs->bufferSubData)
+ funcs->bufferSubData(target, offset, size, data);
+ else
+ funcs->bufferSubData = qglfResolveBufferSubData;
+}
+
+static GLenum QT3D_GLF_APIENTRY qglfResolveCheckFramebufferStatus(GLenum target)
+{
+ typedef GLenum (QT3D_GLF_APIENTRYP type_glCheckFramebufferStatus)(GLenum target);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->checkFramebufferStatus = (type_glCheckFramebufferStatus)
+ context->getProcAddress(QLatin1String("glCheckFramebufferStatus"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->checkFramebufferStatus) {
+ funcs->checkFramebufferStatus = (type_glCheckFramebufferStatus)
+ context->getProcAddress(QLatin1String("glCheckFramebufferStatusOES"));
+ }
+#endif
+ if (!funcs->checkFramebufferStatus) {
+ funcs->checkFramebufferStatus = (type_glCheckFramebufferStatus)
+ context->getProcAddress(QLatin1String("glCheckFramebufferStatusEXT"));
+ }
+ if (!funcs->checkFramebufferStatus) {
+ funcs->checkFramebufferStatus = (type_glCheckFramebufferStatus)
+ context->getProcAddress(QLatin1String("glCheckFramebufferStatusARB"));
+ }
+
+ if (funcs->checkFramebufferStatus)
+ return funcs->checkFramebufferStatus(target);
+ funcs->checkFramebufferStatus = qglfResolveCheckFramebufferStatus;
+ return GLenum(0);
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveCompileShader(GLuint shader)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glCompileShader)(GLuint shader);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->compileShader = (type_glCompileShader)
+ context->getProcAddress(QLatin1String("glCompileShader"));
+ if (!funcs->compileShader) {
+ funcs->compileShader = (type_glCompileShader)
+ context->getProcAddress(QLatin1String("glCompileShader"));
+ }
+
+ if (funcs->compileShader)
+ funcs->compileShader(shader);
+ else
+ funcs->compileShader = qglfResolveCompileShader;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->compressedTexImage2D = (type_glCompressedTexImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexImage2D"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->compressedTexImage2D) {
+ funcs->compressedTexImage2D = (type_glCompressedTexImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexImage2DOES"));
+ }
+#endif
+ if (!funcs->compressedTexImage2D) {
+ funcs->compressedTexImage2D = (type_glCompressedTexImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexImage2DEXT"));
+ }
+ if (!funcs->compressedTexImage2D) {
+ funcs->compressedTexImage2D = (type_glCompressedTexImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
+ }
+
+ if (funcs->compressedTexImage2D)
+ funcs->compressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
+ else
+ funcs->compressedTexImage2D = qglfResolveCompressedTexImage2D;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->compressedTexSubImage2D = (type_glCompressedTexSubImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexSubImage2D"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->compressedTexSubImage2D) {
+ funcs->compressedTexSubImage2D = (type_glCompressedTexSubImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexSubImage2DOES"));
+ }
+#endif
+ if (!funcs->compressedTexSubImage2D) {
+ funcs->compressedTexSubImage2D = (type_glCompressedTexSubImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexSubImage2DEXT"));
+ }
+ if (!funcs->compressedTexSubImage2D) {
+ funcs->compressedTexSubImage2D = (type_glCompressedTexSubImage2D)
+ context->getProcAddress(QLatin1String("glCompressedTexSubImage2DARB"));
+ }
+
+ if (funcs->compressedTexSubImage2D)
+ funcs->compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+ else
+ funcs->compressedTexSubImage2D = qglfResolveCompressedTexSubImage2D;
+}
+
+static GLuint QT3D_GLF_APIENTRY qglfResolveCreateProgram()
+{
+ typedef GLuint (QT3D_GLF_APIENTRYP type_glCreateProgram)();
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->createProgram = (type_glCreateProgram)
+ context->getProcAddress(QLatin1String("glCreateProgram"));
+ if (!funcs->createProgram) {
+ funcs->createProgram = (type_glCreateProgram)
+ context->getProcAddress(QLatin1String("glCreateProgramObjectARB"));
+ }
+
+ if (funcs->createProgram)
+ return funcs->createProgram();
+ funcs->createProgram = qglfResolveCreateProgram;
+ return GLuint(0);
+}
+
+static GLuint QT3D_GLF_APIENTRY qglfResolveCreateShader(GLenum type)
+{
+ typedef GLuint (QT3D_GLF_APIENTRYP type_glCreateShader)(GLenum type);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->createShader = (type_glCreateShader)
+ context->getProcAddress(QLatin1String("glCreateShader"));
+ if (!funcs->createShader) {
+ funcs->createShader = (type_glCreateShader)
+ context->getProcAddress(QLatin1String("glCreateShaderObjectARB"));
+ }
+
+ if (funcs->createShader)
+ return funcs->createShader(type);
+ funcs->createShader = qglfResolveCreateShader;
+ return GLuint(0);
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glDeleteBuffers)(GLsizei n, const GLuint* buffers);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->deleteBuffers = (type_glDeleteBuffers)
+ context->getProcAddress(QLatin1String("glDeleteBuffers"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->deleteBuffers) {
+ funcs->deleteBuffers = (type_glDeleteBuffers)
+ context->getProcAddress(QLatin1String("glDeleteBuffersOES"));
+ }
+#endif
+ if (!funcs->deleteBuffers) {
+ funcs->deleteBuffers = (type_glDeleteBuffers)
+ context->getProcAddress(QLatin1String("glDeleteBuffersEXT"));
+ }
+ if (!funcs->deleteBuffers) {
+ funcs->deleteBuffers = (type_glDeleteBuffers)
+ context->getProcAddress(QLatin1String("glDeleteBuffersARB"));
+ }
+
+ if (funcs->deleteBuffers)
+ funcs->deleteBuffers(n, buffers);
+ else
+ funcs->deleteBuffers = qglfResolveDeleteBuffers;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->deleteFramebuffers = (type_glDeleteFramebuffers)
+ context->getProcAddress(QLatin1String("glDeleteFramebuffers"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->deleteFramebuffers) {
+ funcs->deleteFramebuffers = (type_glDeleteFramebuffers)
+ context->getProcAddress(QLatin1String("glDeleteFramebuffersOES"));
+ }
+#endif
+ if (!funcs->deleteFramebuffers) {
+ funcs->deleteFramebuffers = (type_glDeleteFramebuffers)
+ context->getProcAddress(QLatin1String("glDeleteFramebuffersEXT"));
+ }
+ if (!funcs->deleteFramebuffers) {
+ funcs->deleteFramebuffers = (type_glDeleteFramebuffers)
+ context->getProcAddress(QLatin1String("glDeleteFramebuffersARB"));
+ }
+
+ if (funcs->deleteFramebuffers)
+ funcs->deleteFramebuffers(n, framebuffers);
+ else
+ funcs->deleteFramebuffers = qglfResolveDeleteFramebuffers;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveDeleteProgram(GLuint program)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glDeleteProgram)(GLuint program);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->deleteProgram = (type_glDeleteProgram)
+ context->getProcAddress(QLatin1String("glDeleteProgram"));
+ if (!funcs->deleteProgram) {
+ funcs->deleteProgram = (type_glDeleteProgram)
+ context->getProcAddress(QLatin1String("glDeleteObjectARB"));
+ }
+
+ if (funcs->deleteProgram)
+ funcs->deleteProgram(program);
+ else
+ funcs->deleteProgram = qglfResolveDeleteProgram;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->deleteRenderbuffers = (type_glDeleteRenderbuffers)
+ context->getProcAddress(QLatin1String("glDeleteRenderbuffers"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->deleteRenderbuffers) {
+ funcs->deleteRenderbuffers = (type_glDeleteRenderbuffers)
+ context->getProcAddress(QLatin1String("glDeleteRenderbuffersOES"));
+ }
+#endif
+ if (!funcs->deleteRenderbuffers) {
+ funcs->deleteRenderbuffers = (type_glDeleteRenderbuffers)
+ context->getProcAddress(QLatin1String("glDeleteRenderbuffersEXT"));
+ }
+ if (!funcs->deleteRenderbuffers) {
+ funcs->deleteRenderbuffers = (type_glDeleteRenderbuffers)
+ context->getProcAddress(QLatin1String("glDeleteRenderbuffersARB"));
+ }
+
+ if (funcs->deleteRenderbuffers)
+ funcs->deleteRenderbuffers(n, renderbuffers);
+ else
+ funcs->deleteRenderbuffers = qglfResolveDeleteRenderbuffers;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveDeleteShader(GLuint shader)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glDeleteShader)(GLuint shader);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->deleteShader = (type_glDeleteShader)
+ context->getProcAddress(QLatin1String("glDeleteShader"));
+ if (!funcs->deleteShader) {
+ funcs->deleteShader = (type_glDeleteShader)
+ context->getProcAddress(QLatin1String("glDeleteObjectARB"));
+ }
+
+ if (funcs->deleteShader)
+ funcs->deleteShader(shader);
+ else
+ funcs->deleteShader = qglfResolveDeleteShader;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveDetachShader(GLuint program, GLuint shader)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glDetachShader)(GLuint program, GLuint shader);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->detachShader = (type_glDetachShader)
+ context->getProcAddress(QLatin1String("glDetachShader"));
+ if (!funcs->detachShader) {
+ funcs->detachShader = (type_glDetachShader)
+ context->getProcAddress(QLatin1String("glDetachObjectARB"));
+ }
+
+ if (funcs->detachShader)
+ funcs->detachShader(program, shader);
+ else
+ funcs->detachShader = qglfResolveDetachShader;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveDisableVertexAttribArray(GLuint index)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glDisableVertexAttribArray)(GLuint index);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->disableVertexAttribArray = (type_glDisableVertexAttribArray)
+ context->getProcAddress(QLatin1String("glDisableVertexAttribArray"));
+ if (!funcs->disableVertexAttribArray) {
+ funcs->disableVertexAttribArray = (type_glDisableVertexAttribArray)
+ context->getProcAddress(QLatin1String("glDisableVertexAttribArrayARB"));
+ }
+
+ if (funcs->disableVertexAttribArray)
+ funcs->disableVertexAttribArray(index);
+ else
+ funcs->disableVertexAttribArray = qglfResolveDisableVertexAttribArray;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveEnableVertexAttribArray(GLuint index)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glEnableVertexAttribArray)(GLuint index);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->enableVertexAttribArray = (type_glEnableVertexAttribArray)
+ context->getProcAddress(QLatin1String("glEnableVertexAttribArray"));
+ if (!funcs->enableVertexAttribArray) {
+ funcs->enableVertexAttribArray = (type_glEnableVertexAttribArray)
+ context->getProcAddress(QLatin1String("glEnableVertexAttribArrayARB"));
+ }
+
+ if (funcs->enableVertexAttribArray)
+ funcs->enableVertexAttribArray(index);
+ else
+ funcs->enableVertexAttribArray = qglfResolveEnableVertexAttribArray;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->framebufferRenderbuffer = (type_glFramebufferRenderbuffer)
+ context->getProcAddress(QLatin1String("glFramebufferRenderbuffer"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->framebufferRenderbuffer) {
+ funcs->framebufferRenderbuffer = (type_glFramebufferRenderbuffer)
+ context->getProcAddress(QLatin1String("glFramebufferRenderbufferOES"));
+ }
+#endif
+ if (!funcs->framebufferRenderbuffer) {
+ funcs->framebufferRenderbuffer = (type_glFramebufferRenderbuffer)
+ context->getProcAddress(QLatin1String("glFramebufferRenderbufferEXT"));
+ }
+ if (!funcs->framebufferRenderbuffer) {
+ funcs->framebufferRenderbuffer = (type_glFramebufferRenderbuffer)
+ context->getProcAddress(QLatin1String("glFramebufferRenderbufferARB"));
+ }
+
+ if (funcs->framebufferRenderbuffer)
+ funcs->framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+ else
+ funcs->framebufferRenderbuffer = qglfResolveFramebufferRenderbuffer;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->framebufferTexture2D = (type_glFramebufferTexture2D)
+ context->getProcAddress(QLatin1String("glFramebufferTexture2D"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->framebufferTexture2D) {
+ funcs->framebufferTexture2D = (type_glFramebufferTexture2D)
+ context->getProcAddress(QLatin1String("glFramebufferTexture2DOES"));
+ }
+#endif
+ if (!funcs->framebufferTexture2D) {
+ funcs->framebufferTexture2D = (type_glFramebufferTexture2D)
+ context->getProcAddress(QLatin1String("glFramebufferTexture2DEXT"));
+ }
+ if (!funcs->framebufferTexture2D) {
+ funcs->framebufferTexture2D = (type_glFramebufferTexture2D)
+ context->getProcAddress(QLatin1String("glFramebufferTexture2DARB"));
+ }
+
+ if (funcs->framebufferTexture2D)
+ funcs->framebufferTexture2D(target, attachment, textarget, texture, level);
+ else
+ funcs->framebufferTexture2D = qglfResolveFramebufferTexture2D;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGenBuffers(GLsizei n, GLuint* buffers)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGenBuffers)(GLsizei n, GLuint* buffers);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->genBuffers = (type_glGenBuffers)
+ context->getProcAddress(QLatin1String("glGenBuffers"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->genBuffers) {
+ funcs->genBuffers = (type_glGenBuffers)
+ context->getProcAddress(QLatin1String("glGenBuffersOES"));
+ }
+#endif
+ if (!funcs->genBuffers) {
+ funcs->genBuffers = (type_glGenBuffers)
+ context->getProcAddress(QLatin1String("glGenBuffersEXT"));
+ }
+ if (!funcs->genBuffers) {
+ funcs->genBuffers = (type_glGenBuffers)
+ context->getProcAddress(QLatin1String("glGenBuffersARB"));
+ }
+
+ if (funcs->genBuffers)
+ funcs->genBuffers(n, buffers);
+ else
+ funcs->genBuffers = qglfResolveGenBuffers;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGenerateMipmap(GLenum target)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGenerateMipmap)(GLenum target);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->generateMipmap = (type_glGenerateMipmap)
+ context->getProcAddress(QLatin1String("glGenerateMipmap"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->generateMipmap) {
+ funcs->generateMipmap = (type_glGenerateMipmap)
+ context->getProcAddress(QLatin1String("glGenerateMipmapOES"));
+ }
+#endif
+ if (!funcs->generateMipmap) {
+ funcs->generateMipmap = (type_glGenerateMipmap)
+ context->getProcAddress(QLatin1String("glGenerateMipmapEXT"));
+ }
+ if (!funcs->generateMipmap) {
+ funcs->generateMipmap = (type_glGenerateMipmap)
+ context->getProcAddress(QLatin1String("glGenerateMipmapARB"));
+ }
+
+ if (funcs->generateMipmap)
+ funcs->generateMipmap(target);
+ else
+ funcs->generateMipmap = qglfResolveGenerateMipmap;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGenFramebuffers(GLsizei n, GLuint* framebuffers)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGenFramebuffers)(GLsizei n, GLuint* framebuffers);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->genFramebuffers = (type_glGenFramebuffers)
+ context->getProcAddress(QLatin1String("glGenFramebuffers"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->genFramebuffers) {
+ funcs->genFramebuffers = (type_glGenFramebuffers)
+ context->getProcAddress(QLatin1String("glGenFramebuffersOES"));
+ }
+#endif
+ if (!funcs->genFramebuffers) {
+ funcs->genFramebuffers = (type_glGenFramebuffers)
+ context->getProcAddress(QLatin1String("glGenFramebuffersEXT"));
+ }
+ if (!funcs->genFramebuffers) {
+ funcs->genFramebuffers = (type_glGenFramebuffers)
+ context->getProcAddress(QLatin1String("glGenFramebuffersARB"));
+ }
+
+ if (funcs->genFramebuffers)
+ funcs->genFramebuffers(n, framebuffers);
+ else
+ funcs->genFramebuffers = qglfResolveGenFramebuffers;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->genRenderbuffers = (type_glGenRenderbuffers)
+ context->getProcAddress(QLatin1String("glGenRenderbuffers"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->genRenderbuffers) {
+ funcs->genRenderbuffers = (type_glGenRenderbuffers)
+ context->getProcAddress(QLatin1String("glGenRenderbuffersOES"));
+ }
+#endif
+ if (!funcs->genRenderbuffers) {
+ funcs->genRenderbuffers = (type_glGenRenderbuffers)
+ context->getProcAddress(QLatin1String("glGenRenderbuffersEXT"));
+ }
+ if (!funcs->genRenderbuffers) {
+ funcs->genRenderbuffers = (type_glGenRenderbuffers)
+ context->getProcAddress(QLatin1String("glGenRenderbuffersARB"));
+ }
+
+ if (funcs->genRenderbuffers)
+ funcs->genRenderbuffers(n, renderbuffers);
+ else
+ funcs->genRenderbuffers = qglfResolveGenRenderbuffers;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getActiveAttrib = (type_glGetActiveAttrib)
+ context->getProcAddress(QLatin1String("glGetActiveAttrib"));
+ if (!funcs->getActiveAttrib) {
+ funcs->getActiveAttrib = (type_glGetActiveAttrib)
+ context->getProcAddress(QLatin1String("glGetActiveAttribARB"));
+ }
+
+ if (funcs->getActiveAttrib)
+ funcs->getActiveAttrib(program, index, bufsize, length, size, type, name);
+ else
+ funcs->getActiveAttrib = qglfResolveGetActiveAttrib;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getActiveUniform = (type_glGetActiveUniform)
+ context->getProcAddress(QLatin1String("glGetActiveUniform"));
+ if (!funcs->getActiveUniform) {
+ funcs->getActiveUniform = (type_glGetActiveUniform)
+ context->getProcAddress(QLatin1String("glGetActiveUniformARB"));
+ }
+
+ if (funcs->getActiveUniform)
+ funcs->getActiveUniform(program, index, bufsize, length, size, type, name);
+ else
+ funcs->getActiveUniform = qglfResolveGetActiveUniform;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getAttachedShaders = (type_glGetAttachedShaders)
+ context->getProcAddress(QLatin1String("glGetAttachedShaders"));
+ if (!funcs->getAttachedShaders) {
+ funcs->getAttachedShaders = (type_glGetAttachedShaders)
+ context->getProcAddress(QLatin1String("glGetAttachedObjectsARB"));
+ }
+
+ if (funcs->getAttachedShaders)
+ funcs->getAttachedShaders(program, maxcount, count, shaders);
+ else
+ funcs->getAttachedShaders = qglfResolveGetAttachedShaders;
+}
+
+static int QT3D_GLF_APIENTRY qglfResolveGetAttribLocation(GLuint program, const char* name)
+{
+ typedef int (QT3D_GLF_APIENTRYP type_glGetAttribLocation)(GLuint program, const char* name);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getAttribLocation = (type_glGetAttribLocation)
+ context->getProcAddress(QLatin1String("glGetAttribLocation"));
+ if (!funcs->getAttribLocation) {
+ funcs->getAttribLocation = (type_glGetAttribLocation)
+ context->getProcAddress(QLatin1String("glGetAttribLocationARB"));
+ }
+
+ if (funcs->getAttribLocation)
+ return funcs->getAttribLocation(program, name);
+ funcs->getAttribLocation = qglfResolveGetAttribLocation;
+ return int(0);
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getBufferParameteriv = (type_glGetBufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetBufferParameteriv"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->getBufferParameteriv) {
+ funcs->getBufferParameteriv = (type_glGetBufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetBufferParameterivOES"));
+ }
+#endif
+ if (!funcs->getBufferParameteriv) {
+ funcs->getBufferParameteriv = (type_glGetBufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetBufferParameterivEXT"));
+ }
+ if (!funcs->getBufferParameteriv) {
+ funcs->getBufferParameteriv = (type_glGetBufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetBufferParameterivARB"));
+ }
+
+ if (funcs->getBufferParameteriv)
+ funcs->getBufferParameteriv(target, pname, params);
+ else
+ funcs->getBufferParameteriv = qglfResolveGetBufferParameteriv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getFramebufferAttachmentParameteriv = (type_glGetFramebufferAttachmentParameteriv)
+ context->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameteriv"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->getFramebufferAttachmentParameteriv) {
+ funcs->getFramebufferAttachmentParameteriv = (type_glGetFramebufferAttachmentParameteriv)
+ context->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivOES"));
+ }
+#endif
+ if (!funcs->getFramebufferAttachmentParameteriv) {
+ funcs->getFramebufferAttachmentParameteriv = (type_glGetFramebufferAttachmentParameteriv)
+ context->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivEXT"));
+ }
+ if (!funcs->getFramebufferAttachmentParameteriv) {
+ funcs->getFramebufferAttachmentParameteriv = (type_glGetFramebufferAttachmentParameteriv)
+ context->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivARB"));
+ }
+
+ if (funcs->getFramebufferAttachmentParameteriv)
+ funcs->getFramebufferAttachmentParameteriv(target, attachment, pname, params);
+ else
+ funcs->getFramebufferAttachmentParameteriv = qglfResolveGetFramebufferAttachmentParameteriv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetProgramiv)(GLuint program, GLenum pname, GLint* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getProgramiv = (type_glGetProgramiv)
+ context->getProcAddress(QLatin1String("glGetProgramiv"));
+ if (!funcs->getProgramiv) {
+ funcs->getProgramiv = (type_glGetProgramiv)
+ context->getProcAddress(QLatin1String("glGetObjectParameterivARB"));
+ }
+
+ if (funcs->getProgramiv)
+ funcs->getProgramiv(program, pname, params);
+ else
+ funcs->getProgramiv = qglfResolveGetProgramiv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getProgramInfoLog = (type_glGetProgramInfoLog)
+ context->getProcAddress(QLatin1String("glGetProgramInfoLog"));
+ if (!funcs->getProgramInfoLog) {
+ funcs->getProgramInfoLog = (type_glGetProgramInfoLog)
+ context->getProcAddress(QLatin1String("glGetInfoLogARB"));
+ }
+
+ if (funcs->getProgramInfoLog)
+ funcs->getProgramInfoLog(program, bufsize, length, infolog);
+ else
+ funcs->getProgramInfoLog = qglfResolveGetProgramInfoLog;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getRenderbufferParameteriv = (type_glGetRenderbufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetRenderbufferParameteriv"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->getRenderbufferParameteriv) {
+ funcs->getRenderbufferParameteriv = (type_glGetRenderbufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetRenderbufferParameterivOES"));
+ }
+#endif
+ if (!funcs->getRenderbufferParameteriv) {
+ funcs->getRenderbufferParameteriv = (type_glGetRenderbufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetRenderbufferParameterivEXT"));
+ }
+ if (!funcs->getRenderbufferParameteriv) {
+ funcs->getRenderbufferParameteriv = (type_glGetRenderbufferParameteriv)
+ context->getProcAddress(QLatin1String("glGetRenderbufferParameterivARB"));
+ }
+
+ if (funcs->getRenderbufferParameteriv)
+ funcs->getRenderbufferParameteriv(target, pname, params);
+ else
+ funcs->getRenderbufferParameteriv = qglfResolveGetRenderbufferParameteriv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetShaderiv)(GLuint shader, GLenum pname, GLint* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getShaderiv = (type_glGetShaderiv)
+ context->getProcAddress(QLatin1String("glGetShaderiv"));
+ if (!funcs->getShaderiv) {
+ funcs->getShaderiv = (type_glGetShaderiv)
+ context->getProcAddress(QLatin1String("glGetObjectParameterivARB"));
+ }
+
+ if (funcs->getShaderiv)
+ funcs->getShaderiv(shader, pname, params);
+ else
+ funcs->getShaderiv = qglfResolveGetShaderiv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getShaderInfoLog = (type_glGetShaderInfoLog)
+ context->getProcAddress(QLatin1String("glGetShaderInfoLog"));
+ if (!funcs->getShaderInfoLog) {
+ funcs->getShaderInfoLog = (type_glGetShaderInfoLog)
+ context->getProcAddress(QLatin1String("glGetInfoLogARB"));
+ }
+
+ if (funcs->getShaderInfoLog)
+ funcs->getShaderInfoLog(shader, bufsize, length, infolog);
+ else
+ funcs->getShaderInfoLog = qglfResolveGetShaderInfoLog;
+}
+
+static void QT3D_GLF_APIENTRY qglfSpecialGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+ Q_UNUSED(shadertype);
+ Q_UNUSED(precisiontype);
+ range[0] = range[1] = precision[0] = 0;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getShaderPrecisionFormat = (type_glGetShaderPrecisionFormat)
+ context->getProcAddress(QLatin1String("glGetShaderPrecisionFormat"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->getShaderPrecisionFormat) {
+ funcs->getShaderPrecisionFormat = (type_glGetShaderPrecisionFormat)
+ context->getProcAddress(QLatin1String("glGetShaderPrecisionFormatOES"));
+ }
+#endif
+ if (!funcs->getShaderPrecisionFormat) {
+ funcs->getShaderPrecisionFormat = (type_glGetShaderPrecisionFormat)
+ context->getProcAddress(QLatin1String("glGetShaderPrecisionFormatEXT"));
+ }
+ if (!funcs->getShaderPrecisionFormat) {
+ funcs->getShaderPrecisionFormat = (type_glGetShaderPrecisionFormat)
+ context->getProcAddress(QLatin1String("glGetShaderPrecisionFormatARB"));
+ }
+
+ if (!funcs->getShaderPrecisionFormat)
+ funcs->getShaderPrecisionFormat = qglfSpecialGetShaderPrecisionFormat;
+
+ funcs->getShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getShaderSource = (type_glGetShaderSource)
+ context->getProcAddress(QLatin1String("glGetShaderSource"));
+ if (!funcs->getShaderSource) {
+ funcs->getShaderSource = (type_glGetShaderSource)
+ context->getProcAddress(QLatin1String("glGetShaderSourceARB"));
+ }
+
+ if (funcs->getShaderSource)
+ funcs->getShaderSource(shader, bufsize, length, source);
+ else
+ funcs->getShaderSource = qglfResolveGetShaderSource;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetUniformfv)(GLuint program, GLint location, GLfloat* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getUniformfv = (type_glGetUniformfv)
+ context->getProcAddress(QLatin1String("glGetUniformfv"));
+ if (!funcs->getUniformfv) {
+ funcs->getUniformfv = (type_glGetUniformfv)
+ context->getProcAddress(QLatin1String("glGetUniformfvARB"));
+ }
+
+ if (funcs->getUniformfv)
+ funcs->getUniformfv(program, location, params);
+ else
+ funcs->getUniformfv = qglfResolveGetUniformfv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetUniformiv)(GLuint program, GLint location, GLint* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getUniformiv = (type_glGetUniformiv)
+ context->getProcAddress(QLatin1String("glGetUniformiv"));
+ if (!funcs->getUniformiv) {
+ funcs->getUniformiv = (type_glGetUniformiv)
+ context->getProcAddress(QLatin1String("glGetUniformivARB"));
+ }
+
+ if (funcs->getUniformiv)
+ funcs->getUniformiv(program, location, params);
+ else
+ funcs->getUniformiv = qglfResolveGetUniformiv;
+}
+
+static int QT3D_GLF_APIENTRY qglfResolveGetUniformLocation(GLuint program, const char* name)
+{
+ typedef int (QT3D_GLF_APIENTRYP type_glGetUniformLocation)(GLuint program, const char* name);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getUniformLocation = (type_glGetUniformLocation)
+ context->getProcAddress(QLatin1String("glGetUniformLocation"));
+ if (!funcs->getUniformLocation) {
+ funcs->getUniformLocation = (type_glGetUniformLocation)
+ context->getProcAddress(QLatin1String("glGetUniformLocationARB"));
+ }
+
+ if (funcs->getUniformLocation)
+ return funcs->getUniformLocation(program, name);
+ funcs->getUniformLocation = qglfResolveGetUniformLocation;
+ return int(0);
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getVertexAttribfv = (type_glGetVertexAttribfv)
+ context->getProcAddress(QLatin1String("glGetVertexAttribfv"));
+ if (!funcs->getVertexAttribfv) {
+ funcs->getVertexAttribfv = (type_glGetVertexAttribfv)
+ context->getProcAddress(QLatin1String("glGetVertexAttribfvARB"));
+ }
+
+ if (funcs->getVertexAttribfv)
+ funcs->getVertexAttribfv(index, pname, params);
+ else
+ funcs->getVertexAttribfv = qglfResolveGetVertexAttribfv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getVertexAttribiv = (type_glGetVertexAttribiv)
+ context->getProcAddress(QLatin1String("glGetVertexAttribiv"));
+ if (!funcs->getVertexAttribiv) {
+ funcs->getVertexAttribiv = (type_glGetVertexAttribiv)
+ context->getProcAddress(QLatin1String("glGetVertexAttribivARB"));
+ }
+
+ if (funcs->getVertexAttribiv)
+ funcs->getVertexAttribiv(index, pname, params);
+ else
+ funcs->getVertexAttribiv = qglfResolveGetVertexAttribiv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->getVertexAttribPointerv = (type_glGetVertexAttribPointerv)
+ context->getProcAddress(QLatin1String("glGetVertexAttribPointerv"));
+ if (!funcs->getVertexAttribPointerv) {
+ funcs->getVertexAttribPointerv = (type_glGetVertexAttribPointerv)
+ context->getProcAddress(QLatin1String("glGetVertexAttribPointervARB"));
+ }
+
+ if (funcs->getVertexAttribPointerv)
+ funcs->getVertexAttribPointerv(index, pname, pointer);
+ else
+ funcs->getVertexAttribPointerv = qglfResolveGetVertexAttribPointerv;
+}
+
+static GLboolean QT3D_GLF_APIENTRY qglfResolveIsBuffer(GLuint buffer)
+{
+ typedef GLboolean (QT3D_GLF_APIENTRYP type_glIsBuffer)(GLuint buffer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->isBuffer = (type_glIsBuffer)
+ context->getProcAddress(QLatin1String("glIsBuffer"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->isBuffer) {
+ funcs->isBuffer = (type_glIsBuffer)
+ context->getProcAddress(QLatin1String("glIsBufferOES"));
+ }
+#endif
+ if (!funcs->isBuffer) {
+ funcs->isBuffer = (type_glIsBuffer)
+ context->getProcAddress(QLatin1String("glIsBufferEXT"));
+ }
+ if (!funcs->isBuffer) {
+ funcs->isBuffer = (type_glIsBuffer)
+ context->getProcAddress(QLatin1String("glIsBufferARB"));
+ }
+
+ if (funcs->isBuffer)
+ return funcs->isBuffer(buffer);
+ funcs->isBuffer = qglfResolveIsBuffer;
+ return GLboolean(0);
+}
+
+static GLboolean QT3D_GLF_APIENTRY qglfResolveIsFramebuffer(GLuint framebuffer)
+{
+ typedef GLboolean (QT3D_GLF_APIENTRYP type_glIsFramebuffer)(GLuint framebuffer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->isFramebuffer = (type_glIsFramebuffer)
+ context->getProcAddress(QLatin1String("glIsFramebuffer"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->isFramebuffer) {
+ funcs->isFramebuffer = (type_glIsFramebuffer)
+ context->getProcAddress(QLatin1String("glIsFramebufferOES"));
+ }
+#endif
+ if (!funcs->isFramebuffer) {
+ funcs->isFramebuffer = (type_glIsFramebuffer)
+ context->getProcAddress(QLatin1String("glIsFramebufferEXT"));
+ }
+ if (!funcs->isFramebuffer) {
+ funcs->isFramebuffer = (type_glIsFramebuffer)
+ context->getProcAddress(QLatin1String("glIsFramebufferARB"));
+ }
+
+ if (funcs->isFramebuffer)
+ return funcs->isFramebuffer(framebuffer);
+ funcs->isFramebuffer = qglfResolveIsFramebuffer;
+ return GLboolean(0);
+}
+
+static GLboolean QT3D_GLF_APIENTRY qglfSpecialIsProgram(GLuint program)
+{
+ return program != 0;
+}
+
+static GLboolean QT3D_GLF_APIENTRY qglfResolveIsProgram(GLuint program)
+{
+ typedef GLboolean (QT3D_GLF_APIENTRYP type_glIsProgram)(GLuint program);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->isProgram = (type_glIsProgram)
+ context->getProcAddress(QLatin1String("glIsProgram"));
+ if (!funcs->isProgram) {
+ funcs->isProgram = (type_glIsProgram)
+ context->getProcAddress(QLatin1String("glIsProgramARB"));
+ }
+
+ if (!funcs->isProgram)
+ funcs->isProgram = qglfSpecialIsProgram;
+
+ return funcs->isProgram(program);
+}
+
+static GLboolean QT3D_GLF_APIENTRY qglfResolveIsRenderbuffer(GLuint renderbuffer)
+{
+ typedef GLboolean (QT3D_GLF_APIENTRYP type_glIsRenderbuffer)(GLuint renderbuffer);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->isRenderbuffer = (type_glIsRenderbuffer)
+ context->getProcAddress(QLatin1String("glIsRenderbuffer"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->isRenderbuffer) {
+ funcs->isRenderbuffer = (type_glIsRenderbuffer)
+ context->getProcAddress(QLatin1String("glIsRenderbufferOES"));
+ }
+#endif
+ if (!funcs->isRenderbuffer) {
+ funcs->isRenderbuffer = (type_glIsRenderbuffer)
+ context->getProcAddress(QLatin1String("glIsRenderbufferEXT"));
+ }
+ if (!funcs->isRenderbuffer) {
+ funcs->isRenderbuffer = (type_glIsRenderbuffer)
+ context->getProcAddress(QLatin1String("glIsRenderbufferARB"));
+ }
+
+ if (funcs->isRenderbuffer)
+ return funcs->isRenderbuffer(renderbuffer);
+ funcs->isRenderbuffer = qglfResolveIsRenderbuffer;
+ return GLboolean(0);
+}
+
+static GLboolean QT3D_GLF_APIENTRY qglfSpecialIsShader(GLuint shader)
+{
+ return shader != 0;
+}
+
+static GLboolean QT3D_GLF_APIENTRY qglfResolveIsShader(GLuint shader)
+{
+ typedef GLboolean (QT3D_GLF_APIENTRYP type_glIsShader)(GLuint shader);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->isShader = (type_glIsShader)
+ context->getProcAddress(QLatin1String("glIsShader"));
+ if (!funcs->isShader) {
+ funcs->isShader = (type_glIsShader)
+ context->getProcAddress(QLatin1String("glIsShaderARB"));
+ }
+
+ if (!funcs->isShader)
+ funcs->isShader = qglfSpecialIsShader;
+
+ return funcs->isShader(shader);
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveLinkProgram(GLuint program)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glLinkProgram)(GLuint program);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->linkProgram = (type_glLinkProgram)
+ context->getProcAddress(QLatin1String("glLinkProgram"));
+ if (!funcs->linkProgram) {
+ funcs->linkProgram = (type_glLinkProgram)
+ context->getProcAddress(QLatin1String("glLinkProgramARB"));
+ }
+
+ if (funcs->linkProgram)
+ funcs->linkProgram(program);
+ else
+ funcs->linkProgram = qglfResolveLinkProgram;
+}
+
+static void QT3D_GLF_APIENTRY qglfSpecialReleaseShaderCompiler()
+{
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveReleaseShaderCompiler()
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glReleaseShaderCompiler)();
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->releaseShaderCompiler = (type_glReleaseShaderCompiler)
+ context->getProcAddress(QLatin1String("glReleaseShaderCompiler"));
+ if (!funcs->releaseShaderCompiler) {
+ funcs->releaseShaderCompiler = (type_glReleaseShaderCompiler)
+ context->getProcAddress(QLatin1String("glReleaseShaderCompilerARB"));
+ }
+
+ if (!funcs->releaseShaderCompiler)
+ funcs->releaseShaderCompiler = qglfSpecialReleaseShaderCompiler;
+
+ funcs->releaseShaderCompiler();
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->renderbufferStorage = (type_glRenderbufferStorage)
+ context->getProcAddress(QLatin1String("glRenderbufferStorage"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->renderbufferStorage) {
+ funcs->renderbufferStorage = (type_glRenderbufferStorage)
+ context->getProcAddress(QLatin1String("glRenderbufferStorageOES"));
+ }
+#endif
+ if (!funcs->renderbufferStorage) {
+ funcs->renderbufferStorage = (type_glRenderbufferStorage)
+ context->getProcAddress(QLatin1String("glRenderbufferStorageEXT"));
+ }
+ if (!funcs->renderbufferStorage) {
+ funcs->renderbufferStorage = (type_glRenderbufferStorage)
+ context->getProcAddress(QLatin1String("glRenderbufferStorageARB"));
+ }
+
+ if (funcs->renderbufferStorage)
+ funcs->renderbufferStorage(target, internalformat, width, height);
+ else
+ funcs->renderbufferStorage = qglfResolveRenderbufferStorage;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveSampleCoverage(GLclampf value, GLboolean invert)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glSampleCoverage)(GLclampf value, GLboolean invert);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->sampleCoverage = (type_glSampleCoverage)
+ context->getProcAddress(QLatin1String("glSampleCoverage"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->sampleCoverage) {
+ funcs->sampleCoverage = (type_glSampleCoverage)
+ context->getProcAddress(QLatin1String("glSampleCoverageOES"));
+ }
+#endif
+ if (!funcs->sampleCoverage) {
+ funcs->sampleCoverage = (type_glSampleCoverage)
+ context->getProcAddress(QLatin1String("glSampleCoverageEXT"));
+ }
+ if (!funcs->sampleCoverage) {
+ funcs->sampleCoverage = (type_glSampleCoverage)
+ context->getProcAddress(QLatin1String("glSampleCoverageARB"));
+ }
+
+ if (funcs->sampleCoverage)
+ funcs->sampleCoverage(value, invert);
+ else
+ funcs->sampleCoverage = qglfResolveSampleCoverage;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glShaderBinary)(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->shaderBinary = (type_glShaderBinary)
+ context->getProcAddress(QLatin1String("glShaderBinary"));
+ if (!funcs->shaderBinary) {
+ funcs->shaderBinary = (type_glShaderBinary)
+ context->getProcAddress(QLatin1String("glShaderBinaryARB"));
+ }
+
+ if (funcs->shaderBinary)
+ funcs->shaderBinary(n, shaders, binaryformat, binary, length);
+ else
+ funcs->shaderBinary = qglfResolveShaderBinary;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->shaderSource = (type_glShaderSource)
+ context->getProcAddress(QLatin1String("glShaderSource"));
+ if (!funcs->shaderSource) {
+ funcs->shaderSource = (type_glShaderSource)
+ context->getProcAddress(QLatin1String("glShaderSourceARB"));
+ }
+
+ if (funcs->shaderSource)
+ funcs->shaderSource(shader, count, string, length);
+ else
+ funcs->shaderSource = qglfResolveShaderSource;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->stencilFuncSeparate = (type_glStencilFuncSeparate)
+ context->getProcAddress(QLatin1String("glStencilFuncSeparate"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->stencilFuncSeparate) {
+ funcs->stencilFuncSeparate = (type_glStencilFuncSeparate)
+ context->getProcAddress(QLatin1String("glStencilFuncSeparateOES"));
+ }
+#endif
+ if (!funcs->stencilFuncSeparate) {
+ funcs->stencilFuncSeparate = (type_glStencilFuncSeparate)
+ context->getProcAddress(QLatin1String("glStencilFuncSeparateEXT"));
+ }
+ if (!funcs->stencilFuncSeparate) {
+ funcs->stencilFuncSeparate = (type_glStencilFuncSeparate)
+ context->getProcAddress(QLatin1String("glStencilFuncSeparateARB"));
+ }
+
+ if (funcs->stencilFuncSeparate)
+ funcs->stencilFuncSeparate(face, func, ref, mask);
+ else
+ funcs->stencilFuncSeparate = qglfResolveStencilFuncSeparate;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveStencilMaskSeparate(GLenum face, GLuint mask)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glStencilMaskSeparate)(GLenum face, GLuint mask);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->stencilMaskSeparate = (type_glStencilMaskSeparate)
+ context->getProcAddress(QLatin1String("glStencilMaskSeparate"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->stencilMaskSeparate) {
+ funcs->stencilMaskSeparate = (type_glStencilMaskSeparate)
+ context->getProcAddress(QLatin1String("glStencilMaskSeparateOES"));
+ }
+#endif
+ if (!funcs->stencilMaskSeparate) {
+ funcs->stencilMaskSeparate = (type_glStencilMaskSeparate)
+ context->getProcAddress(QLatin1String("glStencilMaskSeparateEXT"));
+ }
+ if (!funcs->stencilMaskSeparate) {
+ funcs->stencilMaskSeparate = (type_glStencilMaskSeparate)
+ context->getProcAddress(QLatin1String("glStencilMaskSeparateARB"));
+ }
+
+ if (funcs->stencilMaskSeparate)
+ funcs->stencilMaskSeparate(face, mask);
+ else
+ funcs->stencilMaskSeparate = qglfResolveStencilMaskSeparate;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->stencilOpSeparate = (type_glStencilOpSeparate)
+ context->getProcAddress(QLatin1String("glStencilOpSeparate"));
+#ifdef QT_OPENGL_ES
+ if (!funcs->stencilOpSeparate) {
+ funcs->stencilOpSeparate = (type_glStencilOpSeparate)
+ context->getProcAddress(QLatin1String("glStencilOpSeparateOES"));
+ }
+#endif
+ if (!funcs->stencilOpSeparate) {
+ funcs->stencilOpSeparate = (type_glStencilOpSeparate)
+ context->getProcAddress(QLatin1String("glStencilOpSeparateEXT"));
+ }
+ if (!funcs->stencilOpSeparate) {
+ funcs->stencilOpSeparate = (type_glStencilOpSeparate)
+ context->getProcAddress(QLatin1String("glStencilOpSeparateARB"));
+ }
+
+ if (funcs->stencilOpSeparate)
+ funcs->stencilOpSeparate(face, fail, zfail, zpass);
+ else
+ funcs->stencilOpSeparate = qglfResolveStencilOpSeparate;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform1f(GLint location, GLfloat x)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform1f)(GLint location, GLfloat x);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform1f = (type_glUniform1f)
+ context->getProcAddress(QLatin1String("glUniform1f"));
+ if (!funcs->uniform1f) {
+ funcs->uniform1f = (type_glUniform1f)
+ context->getProcAddress(QLatin1String("glUniform1fARB"));
+ }
+
+ if (funcs->uniform1f)
+ funcs->uniform1f(location, x);
+ else
+ funcs->uniform1f = qglfResolveUniform1f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform1fv)(GLint location, GLsizei count, const GLfloat* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform1fv = (type_glUniform1fv)
+ context->getProcAddress(QLatin1String("glUniform1fv"));
+ if (!funcs->uniform1fv) {
+ funcs->uniform1fv = (type_glUniform1fv)
+ context->getProcAddress(QLatin1String("glUniform1fvARB"));
+ }
+
+ if (funcs->uniform1fv)
+ funcs->uniform1fv(location, count, v);
+ else
+ funcs->uniform1fv = qglfResolveUniform1fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform1i(GLint location, GLint x)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform1i)(GLint location, GLint x);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform1i = (type_glUniform1i)
+ context->getProcAddress(QLatin1String("glUniform1i"));
+ if (!funcs->uniform1i) {
+ funcs->uniform1i = (type_glUniform1i)
+ context->getProcAddress(QLatin1String("glUniform1iARB"));
+ }
+
+ if (funcs->uniform1i)
+ funcs->uniform1i(location, x);
+ else
+ funcs->uniform1i = qglfResolveUniform1i;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform1iv)(GLint location, GLsizei count, const GLint* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform1iv = (type_glUniform1iv)
+ context->getProcAddress(QLatin1String("glUniform1iv"));
+ if (!funcs->uniform1iv) {
+ funcs->uniform1iv = (type_glUniform1iv)
+ context->getProcAddress(QLatin1String("glUniform1ivARB"));
+ }
+
+ if (funcs->uniform1iv)
+ funcs->uniform1iv(location, count, v);
+ else
+ funcs->uniform1iv = qglfResolveUniform1iv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform2f)(GLint location, GLfloat x, GLfloat y);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform2f = (type_glUniform2f)
+ context->getProcAddress(QLatin1String("glUniform2f"));
+ if (!funcs->uniform2f) {
+ funcs->uniform2f = (type_glUniform2f)
+ context->getProcAddress(QLatin1String("glUniform2fARB"));
+ }
+
+ if (funcs->uniform2f)
+ funcs->uniform2f(location, x, y);
+ else
+ funcs->uniform2f = qglfResolveUniform2f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform2fv)(GLint location, GLsizei count, const GLfloat* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform2fv = (type_glUniform2fv)
+ context->getProcAddress(QLatin1String("glUniform2fv"));
+ if (!funcs->uniform2fv) {
+ funcs->uniform2fv = (type_glUniform2fv)
+ context->getProcAddress(QLatin1String("glUniform2fvARB"));
+ }
+
+ if (funcs->uniform2fv)
+ funcs->uniform2fv(location, count, v);
+ else
+ funcs->uniform2fv = qglfResolveUniform2fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform2i(GLint location, GLint x, GLint y)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform2i)(GLint location, GLint x, GLint y);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform2i = (type_glUniform2i)
+ context->getProcAddress(QLatin1String("glUniform2i"));
+ if (!funcs->uniform2i) {
+ funcs->uniform2i = (type_glUniform2i)
+ context->getProcAddress(QLatin1String("glUniform2iARB"));
+ }
+
+ if (funcs->uniform2i)
+ funcs->uniform2i(location, x, y);
+ else
+ funcs->uniform2i = qglfResolveUniform2i;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform2iv)(GLint location, GLsizei count, const GLint* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform2iv = (type_glUniform2iv)
+ context->getProcAddress(QLatin1String("glUniform2iv"));
+ if (!funcs->uniform2iv) {
+ funcs->uniform2iv = (type_glUniform2iv)
+ context->getProcAddress(QLatin1String("glUniform2ivARB"));
+ }
+
+ if (funcs->uniform2iv)
+ funcs->uniform2iv(location, count, v);
+ else
+ funcs->uniform2iv = qglfResolveUniform2iv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform3f = (type_glUniform3f)
+ context->getProcAddress(QLatin1String("glUniform3f"));
+ if (!funcs->uniform3f) {
+ funcs->uniform3f = (type_glUniform3f)
+ context->getProcAddress(QLatin1String("glUniform3fARB"));
+ }
+
+ if (funcs->uniform3f)
+ funcs->uniform3f(location, x, y, z);
+ else
+ funcs->uniform3f = qglfResolveUniform3f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform3fv)(GLint location, GLsizei count, const GLfloat* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform3fv = (type_glUniform3fv)
+ context->getProcAddress(QLatin1String("glUniform3fv"));
+ if (!funcs->uniform3fv) {
+ funcs->uniform3fv = (type_glUniform3fv)
+ context->getProcAddress(QLatin1String("glUniform3fvARB"));
+ }
+
+ if (funcs->uniform3fv)
+ funcs->uniform3fv(location, count, v);
+ else
+ funcs->uniform3fv = qglfResolveUniform3fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform3i)(GLint location, GLint x, GLint y, GLint z);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform3i = (type_glUniform3i)
+ context->getProcAddress(QLatin1String("glUniform3i"));
+ if (!funcs->uniform3i) {
+ funcs->uniform3i = (type_glUniform3i)
+ context->getProcAddress(QLatin1String("glUniform3iARB"));
+ }
+
+ if (funcs->uniform3i)
+ funcs->uniform3i(location, x, y, z);
+ else
+ funcs->uniform3i = qglfResolveUniform3i;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform3iv)(GLint location, GLsizei count, const GLint* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform3iv = (type_glUniform3iv)
+ context->getProcAddress(QLatin1String("glUniform3iv"));
+ if (!funcs->uniform3iv) {
+ funcs->uniform3iv = (type_glUniform3iv)
+ context->getProcAddress(QLatin1String("glUniform3ivARB"));
+ }
+
+ if (funcs->uniform3iv)
+ funcs->uniform3iv(location, count, v);
+ else
+ funcs->uniform3iv = qglfResolveUniform3iv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform4f = (type_glUniform4f)
+ context->getProcAddress(QLatin1String("glUniform4f"));
+ if (!funcs->uniform4f) {
+ funcs->uniform4f = (type_glUniform4f)
+ context->getProcAddress(QLatin1String("glUniform4fARB"));
+ }
+
+ if (funcs->uniform4f)
+ funcs->uniform4f(location, x, y, z, w);
+ else
+ funcs->uniform4f = qglfResolveUniform4f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform4fv)(GLint location, GLsizei count, const GLfloat* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform4fv = (type_glUniform4fv)
+ context->getProcAddress(QLatin1String("glUniform4fv"));
+ if (!funcs->uniform4fv) {
+ funcs->uniform4fv = (type_glUniform4fv)
+ context->getProcAddress(QLatin1String("glUniform4fvARB"));
+ }
+
+ if (funcs->uniform4fv)
+ funcs->uniform4fv(location, count, v);
+ else
+ funcs->uniform4fv = qglfResolveUniform4fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform4i = (type_glUniform4i)
+ context->getProcAddress(QLatin1String("glUniform4i"));
+ if (!funcs->uniform4i) {
+ funcs->uniform4i = (type_glUniform4i)
+ context->getProcAddress(QLatin1String("glUniform4iARB"));
+ }
+
+ if (funcs->uniform4i)
+ funcs->uniform4i(location, x, y, z, w);
+ else
+ funcs->uniform4i = qglfResolveUniform4i;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniform4iv)(GLint location, GLsizei count, const GLint* v);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniform4iv = (type_glUniform4iv)
+ context->getProcAddress(QLatin1String("glUniform4iv"));
+ if (!funcs->uniform4iv) {
+ funcs->uniform4iv = (type_glUniform4iv)
+ context->getProcAddress(QLatin1String("glUniform4ivARB"));
+ }
+
+ if (funcs->uniform4iv)
+ funcs->uniform4iv(location, count, v);
+ else
+ funcs->uniform4iv = qglfResolveUniform4iv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniformMatrix2fv = (type_glUniformMatrix2fv)
+ context->getProcAddress(QLatin1String("glUniformMatrix2fv"));
+ if (!funcs->uniformMatrix2fv) {
+ funcs->uniformMatrix2fv = (type_glUniformMatrix2fv)
+ context->getProcAddress(QLatin1String("glUniformMatrix2fvARB"));
+ }
+
+ if (funcs->uniformMatrix2fv)
+ funcs->uniformMatrix2fv(location, count, transpose, value);
+ else
+ funcs->uniformMatrix2fv = qglfResolveUniformMatrix2fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniformMatrix3fv = (type_glUniformMatrix3fv)
+ context->getProcAddress(QLatin1String("glUniformMatrix3fv"));
+ if (!funcs->uniformMatrix3fv) {
+ funcs->uniformMatrix3fv = (type_glUniformMatrix3fv)
+ context->getProcAddress(QLatin1String("glUniformMatrix3fvARB"));
+ }
+
+ if (funcs->uniformMatrix3fv)
+ funcs->uniformMatrix3fv(location, count, transpose, value);
+ else
+ funcs->uniformMatrix3fv = qglfResolveUniformMatrix3fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->uniformMatrix4fv = (type_glUniformMatrix4fv)
+ context->getProcAddress(QLatin1String("glUniformMatrix4fv"));
+ if (!funcs->uniformMatrix4fv) {
+ funcs->uniformMatrix4fv = (type_glUniformMatrix4fv)
+ context->getProcAddress(QLatin1String("glUniformMatrix4fvARB"));
+ }
+
+ if (funcs->uniformMatrix4fv)
+ funcs->uniformMatrix4fv(location, count, transpose, value);
+ else
+ funcs->uniformMatrix4fv = qglfResolveUniformMatrix4fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveUseProgram(GLuint program)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glUseProgram)(GLuint program);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->useProgram = (type_glUseProgram)
+ context->getProcAddress(QLatin1String("glUseProgram"));
+ if (!funcs->useProgram) {
+ funcs->useProgram = (type_glUseProgram)
+ context->getProcAddress(QLatin1String("glUseProgramObjectARB"));
+ }
+
+ if (funcs->useProgram)
+ funcs->useProgram(program);
+ else
+ funcs->useProgram = qglfResolveUseProgram;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveValidateProgram(GLuint program)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glValidateProgram)(GLuint program);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->validateProgram = (type_glValidateProgram)
+ context->getProcAddress(QLatin1String("glValidateProgram"));
+ if (!funcs->validateProgram) {
+ funcs->validateProgram = (type_glValidateProgram)
+ context->getProcAddress(QLatin1String("glValidateProgramARB"));
+ }
+
+ if (funcs->validateProgram)
+ funcs->validateProgram(program);
+ else
+ funcs->validateProgram = qglfResolveValidateProgram;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib1f(GLuint indx, GLfloat x)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib1f)(GLuint indx, GLfloat x);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib1f = (type_glVertexAttrib1f)
+ context->getProcAddress(QLatin1String("glVertexAttrib1f"));
+ if (!funcs->vertexAttrib1f) {
+ funcs->vertexAttrib1f = (type_glVertexAttrib1f)
+ context->getProcAddress(QLatin1String("glVertexAttrib1fARB"));
+ }
+
+ if (funcs->vertexAttrib1f)
+ funcs->vertexAttrib1f(indx, x);
+ else
+ funcs->vertexAttrib1f = qglfResolveVertexAttrib1f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib1fv(GLuint indx, const GLfloat* values)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib1fv)(GLuint indx, const GLfloat* values);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib1fv = (type_glVertexAttrib1fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib1fv"));
+ if (!funcs->vertexAttrib1fv) {
+ funcs->vertexAttrib1fv = (type_glVertexAttrib1fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib1fvARB"));
+ }
+
+ if (funcs->vertexAttrib1fv)
+ funcs->vertexAttrib1fv(indx, values);
+ else
+ funcs->vertexAttrib1fv = qglfResolveVertexAttrib1fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib2f = (type_glVertexAttrib2f)
+ context->getProcAddress(QLatin1String("glVertexAttrib2f"));
+ if (!funcs->vertexAttrib2f) {
+ funcs->vertexAttrib2f = (type_glVertexAttrib2f)
+ context->getProcAddress(QLatin1String("glVertexAttrib2fARB"));
+ }
+
+ if (funcs->vertexAttrib2f)
+ funcs->vertexAttrib2f(indx, x, y);
+ else
+ funcs->vertexAttrib2f = qglfResolveVertexAttrib2f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib2fv(GLuint indx, const GLfloat* values)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib2fv)(GLuint indx, const GLfloat* values);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib2fv = (type_glVertexAttrib2fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib2fv"));
+ if (!funcs->vertexAttrib2fv) {
+ funcs->vertexAttrib2fv = (type_glVertexAttrib2fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib2fvARB"));
+ }
+
+ if (funcs->vertexAttrib2fv)
+ funcs->vertexAttrib2fv(indx, values);
+ else
+ funcs->vertexAttrib2fv = qglfResolveVertexAttrib2fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib3f = (type_glVertexAttrib3f)
+ context->getProcAddress(QLatin1String("glVertexAttrib3f"));
+ if (!funcs->vertexAttrib3f) {
+ funcs->vertexAttrib3f = (type_glVertexAttrib3f)
+ context->getProcAddress(QLatin1String("glVertexAttrib3fARB"));
+ }
+
+ if (funcs->vertexAttrib3f)
+ funcs->vertexAttrib3f(indx, x, y, z);
+ else
+ funcs->vertexAttrib3f = qglfResolveVertexAttrib3f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib3fv(GLuint indx, const GLfloat* values)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib3fv)(GLuint indx, const GLfloat* values);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib3fv = (type_glVertexAttrib3fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib3fv"));
+ if (!funcs->vertexAttrib3fv) {
+ funcs->vertexAttrib3fv = (type_glVertexAttrib3fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib3fvARB"));
+ }
+
+ if (funcs->vertexAttrib3fv)
+ funcs->vertexAttrib3fv(indx, values);
+ else
+ funcs->vertexAttrib3fv = qglfResolveVertexAttrib3fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib4f = (type_glVertexAttrib4f)
+ context->getProcAddress(QLatin1String("glVertexAttrib4f"));
+ if (!funcs->vertexAttrib4f) {
+ funcs->vertexAttrib4f = (type_glVertexAttrib4f)
+ context->getProcAddress(QLatin1String("glVertexAttrib4fARB"));
+ }
+
+ if (funcs->vertexAttrib4f)
+ funcs->vertexAttrib4f(indx, x, y, z, w);
+ else
+ funcs->vertexAttrib4f = qglfResolveVertexAttrib4f;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttrib4fv(GLuint indx, const GLfloat* values)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttrib4fv)(GLuint indx, const GLfloat* values);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttrib4fv = (type_glVertexAttrib4fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib4fv"));
+ if (!funcs->vertexAttrib4fv) {
+ funcs->vertexAttrib4fv = (type_glVertexAttrib4fv)
+ context->getProcAddress(QLatin1String("glVertexAttrib4fvARB"));
+ }
+
+ if (funcs->vertexAttrib4fv)
+ funcs->vertexAttrib4fv(indx, values);
+ else
+ funcs->vertexAttrib4fv = qglfResolveVertexAttrib4fv;
+}
+
+static void QT3D_GLF_APIENTRY qglfResolveVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+{
+ typedef void (QT3D_GLF_APIENTRYP type_glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+
+ const QGLContext *context = QGLContext::currentContext();
+ QOpenGLFunctionsPrivate *funcs = qt_gl_functions(context);
+
+ funcs->vertexAttribPointer = (type_glVertexAttribPointer)
+ context->getProcAddress(QLatin1String("glVertexAttribPointer"));
+ if (!funcs->vertexAttribPointer) {
+ funcs->vertexAttribPointer = (type_glVertexAttribPointer)
+ context->getProcAddress(QLatin1String("glVertexAttribPointerARB"));
+ }
+
+ if (funcs->vertexAttribPointer)
+ funcs->vertexAttribPointer(indx, size, type, normalized, stride, ptr);
+ else
+ funcs->vertexAttribPointer = qglfResolveVertexAttribPointer;
+}
+
+#endif // !QT_OPENGL_ES_2
+
+QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(const QGLContext *)
+{
+#ifndef QT_OPENGL_ES_2
+ activeTexture = qglfResolveActiveTexture;
+ attachShader = qglfResolveAttachShader;
+ bindAttribLocation = qglfResolveBindAttribLocation;
+ bindBuffer = qglfResolveBindBuffer;
+ bindFramebuffer = qglfResolveBindFramebuffer;
+ bindRenderbuffer = qglfResolveBindRenderbuffer;
+ blendColor = qglfResolveBlendColor;
+ blendEquation = qglfResolveBlendEquation;
+ blendEquationSeparate = qglfResolveBlendEquationSeparate;
+ blendFuncSeparate = qglfResolveBlendFuncSeparate;
+ bufferData = qglfResolveBufferData;
+ bufferSubData = qglfResolveBufferSubData;
+ checkFramebufferStatus = qglfResolveCheckFramebufferStatus;
+ compileShader = qglfResolveCompileShader;
+ compressedTexImage2D = qglfResolveCompressedTexImage2D;
+ compressedTexSubImage2D = qglfResolveCompressedTexSubImage2D;
+ createProgram = qglfResolveCreateProgram;
+ createShader = qglfResolveCreateShader;
+ deleteBuffers = qglfResolveDeleteBuffers;
+ deleteFramebuffers = qglfResolveDeleteFramebuffers;
+ deleteProgram = qglfResolveDeleteProgram;
+ deleteRenderbuffers = qglfResolveDeleteRenderbuffers;
+ deleteShader = qglfResolveDeleteShader;
+ detachShader = qglfResolveDetachShader;
+ disableVertexAttribArray = qglfResolveDisableVertexAttribArray;
+ enableVertexAttribArray = qglfResolveEnableVertexAttribArray;
+ framebufferRenderbuffer = qglfResolveFramebufferRenderbuffer;
+ framebufferTexture2D = qglfResolveFramebufferTexture2D;
+ genBuffers = qglfResolveGenBuffers;
+ generateMipmap = qglfResolveGenerateMipmap;
+ genFramebuffers = qglfResolveGenFramebuffers;
+ genRenderbuffers = qglfResolveGenRenderbuffers;
+ getActiveAttrib = qglfResolveGetActiveAttrib;
+ getActiveUniform = qglfResolveGetActiveUniform;
+ getAttachedShaders = qglfResolveGetAttachedShaders;
+ getAttribLocation = qglfResolveGetAttribLocation;
+ getBufferParameteriv = qglfResolveGetBufferParameteriv;
+ getFramebufferAttachmentParameteriv = qglfResolveGetFramebufferAttachmentParameteriv;
+ getProgramiv = qglfResolveGetProgramiv;
+ getProgramInfoLog = qglfResolveGetProgramInfoLog;
+ getRenderbufferParameteriv = qglfResolveGetRenderbufferParameteriv;
+ getShaderiv = qglfResolveGetShaderiv;
+ getShaderInfoLog = qglfResolveGetShaderInfoLog;
+ getShaderPrecisionFormat = qglfResolveGetShaderPrecisionFormat;
+ getShaderSource = qglfResolveGetShaderSource;
+ getUniformfv = qglfResolveGetUniformfv;
+ getUniformiv = qglfResolveGetUniformiv;
+ getUniformLocation = qglfResolveGetUniformLocation;
+ getVertexAttribfv = qglfResolveGetVertexAttribfv;
+ getVertexAttribiv = qglfResolveGetVertexAttribiv;
+ getVertexAttribPointerv = qglfResolveGetVertexAttribPointerv;
+ isBuffer = qglfResolveIsBuffer;
+ isFramebuffer = qglfResolveIsFramebuffer;
+ isProgram = qglfResolveIsProgram;
+ isRenderbuffer = qglfResolveIsRenderbuffer;
+ isShader = qglfResolveIsShader;
+ linkProgram = qglfResolveLinkProgram;
+ releaseShaderCompiler = qglfResolveReleaseShaderCompiler;
+ renderbufferStorage = qglfResolveRenderbufferStorage;
+ sampleCoverage = qglfResolveSampleCoverage;
+ shaderBinary = qglfResolveShaderBinary;
+ shaderSource = qglfResolveShaderSource;
+ stencilFuncSeparate = qglfResolveStencilFuncSeparate;
+ stencilMaskSeparate = qglfResolveStencilMaskSeparate;
+ stencilOpSeparate = qglfResolveStencilOpSeparate;
+ uniform1f = qglfResolveUniform1f;
+ uniform1fv = qglfResolveUniform1fv;
+ uniform1i = qglfResolveUniform1i;
+ uniform1iv = qglfResolveUniform1iv;
+ uniform2f = qglfResolveUniform2f;
+ uniform2fv = qglfResolveUniform2fv;
+ uniform2i = qglfResolveUniform2i;
+ uniform2iv = qglfResolveUniform2iv;
+ uniform3f = qglfResolveUniform3f;
+ uniform3fv = qglfResolveUniform3fv;
+ uniform3i = qglfResolveUniform3i;
+ uniform3iv = qglfResolveUniform3iv;
+ uniform4f = qglfResolveUniform4f;
+ uniform4fv = qglfResolveUniform4fv;
+ uniform4i = qglfResolveUniform4i;
+ uniform4iv = qglfResolveUniform4iv;
+ uniformMatrix2fv = qglfResolveUniformMatrix2fv;
+ uniformMatrix3fv = qglfResolveUniformMatrix3fv;
+ uniformMatrix4fv = qglfResolveUniformMatrix4fv;
+ useProgram = qglfResolveUseProgram;
+ validateProgram = qglfResolveValidateProgram;
+ vertexAttrib1f = qglfResolveVertexAttrib1f;
+ vertexAttrib1fv = qglfResolveVertexAttrib1fv;
+ vertexAttrib2f = qglfResolveVertexAttrib2f;
+ vertexAttrib2fv = qglfResolveVertexAttrib2fv;
+ vertexAttrib3f = qglfResolveVertexAttrib3f;
+ vertexAttrib3fv = qglfResolveVertexAttrib3fv;
+ vertexAttrib4f = qglfResolveVertexAttrib4f;
+ vertexAttrib4fv = qglfResolveVertexAttrib4fv;
+ vertexAttribPointer = qglfResolveVertexAttribPointer;
+#endif // !QT_OPENGL_ES_2
+}
+
diff --git a/src/threed/api/qopenglfunctions.h b/src/threed/api/qopenglfunctions.h
new file mode 100644
index 000000000..0081e907c
--- /dev/null
+++ b/src/threed/api/qopenglfunctions.h
@@ -0,0 +1,2292 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENGLFUNCTIONS_H
+#define QOPENGLFUNCTIONS_H
+
+#include <QtOpenGL/qgl.h>
+#include "qt3dglobal.h"
+#include <QDebug>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+// Types that aren't defined in all system's gl.h files.
+typedef ptrdiff_t qgl_GLintptr;
+typedef ptrdiff_t qgl_GLsizeiptr;
+
+#ifdef Q_WS_WIN
+# define QT3D_GLF_APIENTRY APIENTRY
+#endif
+
+#ifndef Q_WS_MAC
+# ifndef QT3D_GLF_APIENTRYP
+# ifdef QT3D_GLF_APIENTRY
+# define QT3D_GLF_APIENTRYP QT3D_GLF_APIENTRY *
+# else
+# define QT3D_GLF_APIENTRY
+# define QT3D_GLF_APIENTRYP *
+# endif
+# endif
+#else
+# define QT3D_GLF_APIENTRY
+# define QT3D_GLF_APIENTRYP *
+#endif
+
+struct QOpenGLFunctionsPrivate;
+
+// Undefine any macros from GLEW, qglextensions_p.h, etc that
+// may interfere with the definition of QOpenGLFunctions.
+#undef glActiveTexture
+#undef glAttachShader
+#undef glBindAttribLocation
+#undef glBindBuffer
+#undef glBindFramebuffer
+#undef glBindRenderbuffer
+#undef glBlendColor
+#undef glBlendEquation
+#undef glBlendEquationSeparate
+#undef glBlendFuncSeparate
+#undef glBufferData
+#undef glBufferSubData
+#undef glCheckFramebufferStatus
+#undef glClearDepthf
+#undef glCompileShader
+#undef glCompressedTexImage2D
+#undef glCompressedTexSubImage2D
+#undef glCreateProgram
+#undef glCreateShader
+#undef glDeleteBuffers
+#undef glDeleteFramebuffers
+#undef glDeleteProgram
+#undef glDeleteRenderbuffers
+#undef glDeleteShader
+#undef glDepthRangef
+#undef glDetachShader
+#undef glDisableVertexAttribArray
+#undef glEnableVertexAttribArray
+#undef glFramebufferRenderbuffer
+#undef glFramebufferTexture2D
+#undef glGenBuffers
+#undef glGenerateMipmap
+#undef glGenFramebuffers
+#undef glGenRenderbuffers
+#undef glGetActiveAttrib
+#undef glGetActiveUniform
+#undef glGetAttachedShaders
+#undef glGetAttribLocation
+#undef glGetBufferParameteriv
+#undef glGetFramebufferAttachmentParameteriv
+#undef glGetProgramiv
+#undef glGetProgramInfoLog
+#undef glGetRenderbufferParameteriv
+#undef glGetShaderiv
+#undef glGetShaderInfoLog
+#undef glGetShaderPrecisionFormat
+#undef glGetShaderSource
+#undef glGetUniformfv
+#undef glGetUniformiv
+#undef glGetUniformLocation
+#undef glGetVertexAttribfv
+#undef glGetVertexAttribiv
+#undef glGetVertexAttribPointerv
+#undef glIsBuffer
+#undef glIsFramebuffer
+#undef glIsProgram
+#undef glIsRenderbuffer
+#undef glIsShader
+#undef glLinkProgram
+#undef glReleaseShaderCompiler
+#undef glRenderbufferStorage
+#undef glSampleCoverage
+#undef glShaderBinary
+#undef glShaderSource
+#undef glStencilFuncSeparate
+#undef glStencilMaskSeparate
+#undef glStencilOpSeparate
+#undef glUniform1f
+#undef glUniform1fv
+#undef glUniform1i
+#undef glUniform1iv
+#undef glUniform2f
+#undef glUniform2fv
+#undef glUniform2i
+#undef glUniform2iv
+#undef glUniform3f
+#undef glUniform3fv
+#undef glUniform3i
+#undef glUniform3iv
+#undef glUniform4f
+#undef glUniform4fv
+#undef glUniform4i
+#undef glUniform4iv
+#undef glUniformMatrix2fv
+#undef glUniformMatrix3fv
+#undef glUniformMatrix4fv
+#undef glUseProgram
+#undef glValidateProgram
+#undef glVertexAttrib1f
+#undef glVertexAttrib1fv
+#undef glVertexAttrib2f
+#undef glVertexAttrib2fv
+#undef glVertexAttrib3f
+#undef glVertexAttrib3fv
+#undef glVertexAttrib4f
+#undef glVertexAttrib4fv
+#undef glVertexAttribPointer
+
+class Q_QT3D_EXPORT QOpenGLFunctions
+{
+public:
+ QOpenGLFunctions();
+ explicit QOpenGLFunctions(const QGLContext *context);
+ ~QOpenGLFunctions() {}
+
+ enum OpenGLFeature
+ {
+ Multitexture = 0x0001,
+ Shaders = 0x0002,
+ Buffers = 0x0004,
+ Framebuffers = 0x0008,
+ BlendColor = 0x0010,
+ BlendEquation = 0x0020,
+ BlendEquationSeparate = 0x0040,
+ BlendFuncSeparate = 0x0080,
+ BlendSubtract = 0x0100,
+ CompressedTextures = 0x0200,
+ Multisample = 0x0400,
+ StencilSeparate = 0x0800,
+ NPOTTextures = 0x1000
+ };
+ Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature)
+
+ QOpenGLFunctions::OpenGLFeatures openGLFeatures() const;
+ bool hasOpenGLFeature(QOpenGLFunctions::OpenGLFeature feature) const;
+
+ void initializeGLFunctions(const QGLContext *context = 0);
+
+ void glActiveTexture(GLenum texture);
+ void glAttachShader(GLuint program, GLuint shader);
+ void glBindAttribLocation(GLuint program, GLuint index, const char* name);
+ void glBindBuffer(GLenum target, GLuint buffer);
+ void glBindFramebuffer(GLenum target, GLuint framebuffer);
+ void glBindRenderbuffer(GLenum target, GLuint renderbuffer);
+ void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+ void glBlendEquation(GLenum mode);
+ void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
+ void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+ void glBufferData(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage);
+ void glBufferSubData(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data);
+ GLenum glCheckFramebufferStatus(GLenum target);
+ void glClearDepthf(GLclampf depth);
+ void glCompileShader(GLuint shader);
+ void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+ void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+ GLuint glCreateProgram();
+ GLuint glCreateShader(GLenum type);
+ void glDeleteBuffers(GLsizei n, const GLuint* buffers);
+ void glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
+ void glDeleteProgram(GLuint program);
+ void glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
+ void glDeleteShader(GLuint shader);
+ void glDepthRangef(GLclampf zNear, GLclampf zFar);
+ void glDetachShader(GLuint program, GLuint shader);
+ void glDisableVertexAttribArray(GLuint index);
+ void glEnableVertexAttribArray(GLuint index);
+ void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+ void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+ void glGenBuffers(GLsizei n, GLuint* buffers);
+ void glGenerateMipmap(GLenum target);
+ void glGenFramebuffers(GLsizei n, GLuint* framebuffers);
+ void glGenRenderbuffers(GLsizei n, GLuint* renderbuffers);
+ void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+ void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+ void glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+ int glGetAttribLocation(GLuint program, const char* name);
+ void glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
+ void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+ void glGetProgramiv(GLuint program, GLenum pname, GLint* params);
+ void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+ void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
+ void glGetShaderiv(GLuint shader, GLenum pname, GLint* params);
+ void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+ void glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+ void glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+ void glGetUniformfv(GLuint program, GLint location, GLfloat* params);
+ void glGetUniformiv(GLuint program, GLint location, GLint* params);
+ int glGetUniformLocation(GLuint program, const char* name);
+ void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
+ void glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
+ void glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer);
+ GLboolean glIsBuffer(GLuint buffer);
+ GLboolean glIsFramebuffer(GLuint framebuffer);
+ GLboolean glIsProgram(GLuint program);
+ GLboolean glIsRenderbuffer(GLuint renderbuffer);
+ GLboolean glIsShader(GLuint shader);
+ void glLinkProgram(GLuint program);
+ void glReleaseShaderCompiler();
+ void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+ void glSampleCoverage(GLclampf value, GLboolean invert);
+ void glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length);
+ void glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length);
+ void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
+ void glStencilMaskSeparate(GLenum face, GLuint mask);
+ void glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+ void glUniform1f(GLint location, GLfloat x);
+ void glUniform1fv(GLint location, GLsizei count, const GLfloat* v);
+ void glUniform1i(GLint location, GLint x);
+ void glUniform1iv(GLint location, GLsizei count, const GLint* v);
+ void glUniform2f(GLint location, GLfloat x, GLfloat y);
+ void glUniform2fv(GLint location, GLsizei count, const GLfloat* v);
+ void glUniform2i(GLint location, GLint x, GLint y);
+ void glUniform2iv(GLint location, GLsizei count, const GLint* v);
+ void glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z);
+ void glUniform3fv(GLint location, GLsizei count, const GLfloat* v);
+ void glUniform3i(GLint location, GLint x, GLint y, GLint z);
+ void glUniform3iv(GLint location, GLsizei count, const GLint* v);
+ void glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void glUniform4fv(GLint location, GLsizei count, const GLfloat* v);
+ void glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w);
+ void glUniform4iv(GLint location, GLsizei count, const GLint* v);
+ void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ void glUseProgram(GLuint program);
+ void glValidateProgram(GLuint program);
+ void glVertexAttrib1f(GLuint indx, GLfloat x);
+ void glVertexAttrib1fv(GLuint indx, const GLfloat* values);
+ void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y);
+ void glVertexAttrib2fv(GLuint indx, const GLfloat* values);
+ void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+ void glVertexAttrib3fv(GLuint indx, const GLfloat* values);
+ void glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void glVertexAttrib4fv(GLuint indx, const GLfloat* values);
+ void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+
+private:
+ QOpenGLFunctionsPrivate *d_ptr;
+ static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; }
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLFunctions::OpenGLFeatures)
+
+struct QOpenGLFunctionsPrivate
+{
+ QOpenGLFunctionsPrivate(const QGLContext *context = 0);
+
+#ifndef QT_OPENGL_ES_2
+ void (QT3D_GLF_APIENTRYP activeTexture)(GLenum texture);
+ void (QT3D_GLF_APIENTRYP attachShader)(GLuint program, GLuint shader);
+ void (QT3D_GLF_APIENTRYP bindAttribLocation)(GLuint program, GLuint index, const char* name);
+ void (QT3D_GLF_APIENTRYP bindBuffer)(GLenum target, GLuint buffer);
+ void (QT3D_GLF_APIENTRYP bindFramebuffer)(GLenum target, GLuint framebuffer);
+ void (QT3D_GLF_APIENTRYP bindRenderbuffer)(GLenum target, GLuint renderbuffer);
+ void (QT3D_GLF_APIENTRYP blendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+ void (QT3D_GLF_APIENTRYP blendEquation)(GLenum mode);
+ void (QT3D_GLF_APIENTRYP blendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha);
+ void (QT3D_GLF_APIENTRYP blendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+ void (QT3D_GLF_APIENTRYP bufferData)(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage);
+ void (QT3D_GLF_APIENTRYP bufferSubData)(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data);
+ GLenum (QT3D_GLF_APIENTRYP checkFramebufferStatus)(GLenum target);
+ void (QT3D_GLF_APIENTRYP compileShader)(GLuint shader);
+ void (QT3D_GLF_APIENTRYP compressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+ void (QT3D_GLF_APIENTRYP compressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+ GLuint (QT3D_GLF_APIENTRYP createProgram)();
+ GLuint (QT3D_GLF_APIENTRYP createShader)(GLenum type);
+ void (QT3D_GLF_APIENTRYP deleteBuffers)(GLsizei n, const GLuint* buffers);
+ void (QT3D_GLF_APIENTRYP deleteFramebuffers)(GLsizei n, const GLuint* framebuffers);
+ void (QT3D_GLF_APIENTRYP deleteProgram)(GLuint program);
+ void (QT3D_GLF_APIENTRYP deleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers);
+ void (QT3D_GLF_APIENTRYP deleteShader)(GLuint shader);
+ void (QT3D_GLF_APIENTRYP detachShader)(GLuint program, GLuint shader);
+ void (QT3D_GLF_APIENTRYP disableVertexAttribArray)(GLuint index);
+ void (QT3D_GLF_APIENTRYP enableVertexAttribArray)(GLuint index);
+ void (QT3D_GLF_APIENTRYP framebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+ void (QT3D_GLF_APIENTRYP framebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+ void (QT3D_GLF_APIENTRYP genBuffers)(GLsizei n, GLuint* buffers);
+ void (QT3D_GLF_APIENTRYP generateMipmap)(GLenum target);
+ void (QT3D_GLF_APIENTRYP genFramebuffers)(GLsizei n, GLuint* framebuffers);
+ void (QT3D_GLF_APIENTRYP genRenderbuffers)(GLsizei n, GLuint* renderbuffers);
+ void (QT3D_GLF_APIENTRYP getActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+ void (QT3D_GLF_APIENTRYP getActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+ void (QT3D_GLF_APIENTRYP getAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+ int (QT3D_GLF_APIENTRYP getAttribLocation)(GLuint program, const char* name);
+ void (QT3D_GLF_APIENTRYP getBufferParameteriv)(GLenum target, GLenum pname, GLint* params);
+ void (QT3D_GLF_APIENTRYP getFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params);
+ void (QT3D_GLF_APIENTRYP getProgramiv)(GLuint program, GLenum pname, GLint* params);
+ void (QT3D_GLF_APIENTRYP getProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+ void (QT3D_GLF_APIENTRYP getRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params);
+ void (QT3D_GLF_APIENTRYP getShaderiv)(GLuint shader, GLenum pname, GLint* params);
+ void (QT3D_GLF_APIENTRYP getShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+ void (QT3D_GLF_APIENTRYP getShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+ void (QT3D_GLF_APIENTRYP getShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+ void (QT3D_GLF_APIENTRYP getUniformfv)(GLuint program, GLint location, GLfloat* params);
+ void (QT3D_GLF_APIENTRYP getUniformiv)(GLuint program, GLint location, GLint* params);
+ int (QT3D_GLF_APIENTRYP getUniformLocation)(GLuint program, const char* name);
+ void (QT3D_GLF_APIENTRYP getVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params);
+ void (QT3D_GLF_APIENTRYP getVertexAttribiv)(GLuint index, GLenum pname, GLint* params);
+ void (QT3D_GLF_APIENTRYP getVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer);
+ GLboolean (QT3D_GLF_APIENTRYP isBuffer)(GLuint buffer);
+ GLboolean (QT3D_GLF_APIENTRYP isFramebuffer)(GLuint framebuffer);
+ GLboolean (QT3D_GLF_APIENTRYP isProgram)(GLuint program);
+ GLboolean (QT3D_GLF_APIENTRYP isRenderbuffer)(GLuint renderbuffer);
+ GLboolean (QT3D_GLF_APIENTRYP isShader)(GLuint shader);
+ void (QT3D_GLF_APIENTRYP linkProgram)(GLuint program);
+ void (QT3D_GLF_APIENTRYP releaseShaderCompiler)();
+ void (QT3D_GLF_APIENTRYP renderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+ void (QT3D_GLF_APIENTRYP sampleCoverage)(GLclampf value, GLboolean invert);
+ void (QT3D_GLF_APIENTRYP shaderBinary)(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length);
+ void (QT3D_GLF_APIENTRYP shaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length);
+ void (QT3D_GLF_APIENTRYP stencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask);
+ void (QT3D_GLF_APIENTRYP stencilMaskSeparate)(GLenum face, GLuint mask);
+ void (QT3D_GLF_APIENTRYP stencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+ void (QT3D_GLF_APIENTRYP uniform1f)(GLint location, GLfloat x);
+ void (QT3D_GLF_APIENTRYP uniform1fv)(GLint location, GLsizei count, const GLfloat* v);
+ void (QT3D_GLF_APIENTRYP uniform1i)(GLint location, GLint x);
+ void (QT3D_GLF_APIENTRYP uniform1iv)(GLint location, GLsizei count, const GLint* v);
+ void (QT3D_GLF_APIENTRYP uniform2f)(GLint location, GLfloat x, GLfloat y);
+ void (QT3D_GLF_APIENTRYP uniform2fv)(GLint location, GLsizei count, const GLfloat* v);
+ void (QT3D_GLF_APIENTRYP uniform2i)(GLint location, GLint x, GLint y);
+ void (QT3D_GLF_APIENTRYP uniform2iv)(GLint location, GLsizei count, const GLint* v);
+ void (QT3D_GLF_APIENTRYP uniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z);
+ void (QT3D_GLF_APIENTRYP uniform3fv)(GLint location, GLsizei count, const GLfloat* v);
+ void (QT3D_GLF_APIENTRYP uniform3i)(GLint location, GLint x, GLint y, GLint z);
+ void (QT3D_GLF_APIENTRYP uniform3iv)(GLint location, GLsizei count, const GLint* v);
+ void (QT3D_GLF_APIENTRYP uniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void (QT3D_GLF_APIENTRYP uniform4fv)(GLint location, GLsizei count, const GLfloat* v);
+ void (QT3D_GLF_APIENTRYP uniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w);
+ void (QT3D_GLF_APIENTRYP uniform4iv)(GLint location, GLsizei count, const GLint* v);
+ void (QT3D_GLF_APIENTRYP uniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ void (QT3D_GLF_APIENTRYP uniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ void (QT3D_GLF_APIENTRYP uniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+ void (QT3D_GLF_APIENTRYP useProgram)(GLuint program);
+ void (QT3D_GLF_APIENTRYP validateProgram)(GLuint program);
+ void (QT3D_GLF_APIENTRYP vertexAttrib1f)(GLuint indx, GLfloat x);
+ void (QT3D_GLF_APIENTRYP vertexAttrib1fv)(GLuint indx, const GLfloat* values);
+ void (QT3D_GLF_APIENTRYP vertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y);
+ void (QT3D_GLF_APIENTRYP vertexAttrib2fv)(GLuint indx, const GLfloat* values);
+ void (QT3D_GLF_APIENTRYP vertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+ void (QT3D_GLF_APIENTRYP vertexAttrib3fv)(GLuint indx, const GLfloat* values);
+ void (QT3D_GLF_APIENTRYP vertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+ void (QT3D_GLF_APIENTRYP vertexAttrib4fv)(GLuint indx, const GLfloat* values);
+ void (QT3D_GLF_APIENTRYP vertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+#endif
+};
+
+inline void QOpenGLFunctions::glActiveTexture(GLenum texture)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glActiveTexture(texture);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->activeTexture(texture);
+#endif
+}
+
+inline void QOpenGLFunctions::glAttachShader(GLuint program, GLuint shader)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glAttachShader(program, shader);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->attachShader(program, shader);
+#endif
+}
+
+inline void QOpenGLFunctions::glBindAttribLocation(GLuint program, GLuint index, const char* name)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBindAttribLocation(program, index, name);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->bindAttribLocation(program, index, name);
+#endif
+}
+
+inline void QOpenGLFunctions::glBindBuffer(GLenum target, GLuint buffer)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBindBuffer(target, buffer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->bindBuffer(target, buffer);
+#endif
+}
+
+inline void QOpenGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBindFramebuffer(target, framebuffer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->bindFramebuffer(target, framebuffer);
+#endif
+}
+
+inline void QOpenGLFunctions::glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBindRenderbuffer(target, renderbuffer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->bindRenderbuffer(target, renderbuffer);
+#endif
+}
+
+inline void QOpenGLFunctions::glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBlendColor(red, green, blue, alpha);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->blendColor(red, green, blue, alpha);
+#endif
+}
+
+inline void QOpenGLFunctions::glBlendEquation(GLenum mode)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBlendEquation(mode);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->blendEquation(mode);
+#endif
+}
+
+inline void QOpenGLFunctions::glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBlendEquationSeparate(modeRGB, modeAlpha);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->blendEquationSeparate(modeRGB, modeAlpha);
+#endif
+}
+
+inline void QOpenGLFunctions::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+#endif
+}
+
+inline void QOpenGLFunctions::glBufferData(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBufferData(target, size, data, usage);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->bufferData(target, size, data, usage);
+#endif
+}
+
+inline void QOpenGLFunctions::glBufferSubData(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glBufferSubData(target, offset, size, data);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->bufferSubData(target, offset, size, data);
+#endif
+}
+
+inline GLenum QOpenGLFunctions::glCheckFramebufferStatus(GLenum target)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glCheckFramebufferStatus(target);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->checkFramebufferStatus(target);
+#endif
+}
+
+inline void QOpenGLFunctions::glClearDepthf(GLclampf depth)
+{
+#ifndef QT_OPENGL_ES
+ ::glClearDepth(depth);
+#else
+ ::glClearDepthf(depth);
+#endif
+}
+
+inline void QOpenGLFunctions::glCompileShader(GLuint shader)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glCompileShader(shader);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->compileShader(shader);
+#endif
+}
+
+inline void QOpenGLFunctions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->compressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
+#endif
+}
+
+inline void QOpenGLFunctions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+#endif
+}
+
+inline GLuint QOpenGLFunctions::glCreateProgram()
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glCreateProgram();
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->createProgram();
+#endif
+}
+
+inline GLuint QOpenGLFunctions::glCreateShader(GLenum type)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glCreateShader(type);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->createShader(type);
+#endif
+}
+
+inline void QOpenGLFunctions::glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glDeleteBuffers(n, buffers);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->deleteBuffers(n, buffers);
+#endif
+}
+
+inline void QOpenGLFunctions::glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glDeleteFramebuffers(n, framebuffers);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->deleteFramebuffers(n, framebuffers);
+#endif
+}
+
+inline void QOpenGLFunctions::glDeleteProgram(GLuint program)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glDeleteProgram(program);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->deleteProgram(program);
+#endif
+}
+
+inline void QOpenGLFunctions::glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glDeleteRenderbuffers(n, renderbuffers);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->deleteRenderbuffers(n, renderbuffers);
+#endif
+}
+
+inline void QOpenGLFunctions::glDeleteShader(GLuint shader)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glDeleteShader(shader);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->deleteShader(shader);
+#endif
+}
+
+inline void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+#ifndef QT_OPENGL_ES
+ ::glDepthRange(zNear, zFar);
+#else
+ ::glDepthRangef(zNear, zFar);
+#endif
+}
+
+inline void QOpenGLFunctions::glDetachShader(GLuint program, GLuint shader)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glDetachShader(program, shader);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->detachShader(program, shader);
+#endif
+}
+
+inline void QOpenGLFunctions::glDisableVertexAttribArray(GLuint index)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glDisableVertexAttribArray(index);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->disableVertexAttribArray(index);
+#endif
+}
+
+inline void QOpenGLFunctions::glEnableVertexAttribArray(GLuint index)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glEnableVertexAttribArray(index);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->enableVertexAttribArray(index);
+#endif
+}
+
+inline void QOpenGLFunctions::glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+#endif
+}
+
+inline void QOpenGLFunctions::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glFramebufferTexture2D(target, attachment, textarget, texture, level);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->framebufferTexture2D(target, attachment, textarget, texture, level);
+#endif
+}
+
+inline void QOpenGLFunctions::glGenBuffers(GLsizei n, GLuint* buffers)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGenBuffers(n, buffers);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->genBuffers(n, buffers);
+#endif
+}
+
+inline void QOpenGLFunctions::glGenerateMipmap(GLenum target)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGenerateMipmap(target);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->generateMipmap(target);
+#endif
+}
+
+inline void QOpenGLFunctions::glGenFramebuffers(GLsizei n, GLuint* framebuffers)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGenFramebuffers(n, framebuffers);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->genFramebuffers(n, framebuffers);
+#endif
+}
+
+inline void QOpenGLFunctions::glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGenRenderbuffers(n, renderbuffers);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->genRenderbuffers(n, renderbuffers);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetActiveAttrib(program, index, bufsize, length, size, type, name);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getActiveAttrib(program, index, bufsize, length, size, type, name);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetActiveUniform(program, index, bufsize, length, size, type, name);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getActiveUniform(program, index, bufsize, length, size, type, name);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetAttachedShaders(program, maxcount, count, shaders);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getAttachedShaders(program, maxcount, count, shaders);
+#endif
+}
+
+inline int QOpenGLFunctions::glGetAttribLocation(GLuint program, const char* name)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glGetAttribLocation(program, name);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->getAttribLocation(program, name);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetBufferParameteriv(target, pname, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getBufferParameteriv(target, pname, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getFramebufferAttachmentParameteriv(target, attachment, pname, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetProgramiv(program, pname, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getProgramiv(program, pname, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetProgramInfoLog(program, bufsize, length, infolog);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getProgramInfoLog(program, bufsize, length, infolog);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetRenderbufferParameteriv(target, pname, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getRenderbufferParameteriv(target, pname, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetShaderiv(shader, pname, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getShaderiv(shader, pname, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetShaderInfoLog(shader, bufsize, length, infolog);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getShaderInfoLog(shader, bufsize, length, infolog);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetShaderSource(shader, bufsize, length, source);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getShaderSource(shader, bufsize, length, source);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetUniformfv(program, location, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getUniformfv(program, location, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetUniformiv(program, location, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getUniformiv(program, location, params);
+#endif
+}
+
+inline int QOpenGLFunctions::glGetUniformLocation(GLuint program, const char* name)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glGetUniformLocation(program, name);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->getUniformLocation(program, name);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetVertexAttribfv(index, pname, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getVertexAttribfv(index, pname, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetVertexAttribiv(index, pname, params);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getVertexAttribiv(index, pname, params);
+#endif
+}
+
+inline void QOpenGLFunctions::glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glGetVertexAttribPointerv(index, pname, pointer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->getVertexAttribPointerv(index, pname, pointer);
+#endif
+}
+
+inline GLboolean QOpenGLFunctions::glIsBuffer(GLuint buffer)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glIsBuffer(buffer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->isBuffer(buffer);
+#endif
+}
+
+inline GLboolean QOpenGLFunctions::glIsFramebuffer(GLuint framebuffer)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glIsFramebuffer(framebuffer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->isFramebuffer(framebuffer);
+#endif
+}
+
+inline GLboolean QOpenGLFunctions::glIsProgram(GLuint program)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glIsProgram(program);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->isProgram(program);
+#endif
+}
+
+inline GLboolean QOpenGLFunctions::glIsRenderbuffer(GLuint renderbuffer)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glIsRenderbuffer(renderbuffer);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->isRenderbuffer(renderbuffer);
+#endif
+}
+
+inline GLboolean QOpenGLFunctions::glIsShader(GLuint shader)
+{
+#if defined(QT_OPENGL_ES_2)
+ return ::glIsShader(shader);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ return d_ptr->isShader(shader);
+#endif
+}
+
+inline void QOpenGLFunctions::glLinkProgram(GLuint program)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glLinkProgram(program);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->linkProgram(program);
+#endif
+}
+
+inline void QOpenGLFunctions::glReleaseShaderCompiler()
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glReleaseShaderCompiler();
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->releaseShaderCompiler();
+#endif
+}
+
+inline void QOpenGLFunctions::glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glRenderbufferStorage(target, internalformat, width, height);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->renderbufferStorage(target, internalformat, width, height);
+#endif
+}
+
+inline void QOpenGLFunctions::glSampleCoverage(GLclampf value, GLboolean invert)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glSampleCoverage(value, invert);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->sampleCoverage(value, invert);
+#endif
+}
+
+inline void QOpenGLFunctions::glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glShaderBinary(n, shaders, binaryformat, binary, length);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->shaderBinary(n, shaders, binaryformat, binary, length);
+#endif
+}
+
+inline void QOpenGLFunctions::glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glShaderSource(shader, count, string, length);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->shaderSource(shader, count, string, length);
+#endif
+}
+
+inline void QOpenGLFunctions::glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glStencilFuncSeparate(face, func, ref, mask);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->stencilFuncSeparate(face, func, ref, mask);
+#endif
+}
+
+inline void QOpenGLFunctions::glStencilMaskSeparate(GLenum face, GLuint mask)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glStencilMaskSeparate(face, mask);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->stencilMaskSeparate(face, mask);
+#endif
+}
+
+inline void QOpenGLFunctions::glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glStencilOpSeparate(face, fail, zfail, zpass);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->stencilOpSeparate(face, fail, zfail, zpass);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform1f(GLint location, GLfloat x)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform1f(location, x);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform1f(location, x);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform1fv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform1fv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform1i(GLint location, GLint x)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform1i(location, x);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform1i(location, x);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform1iv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform1iv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform2f(location, x, y);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform2f(location, x, y);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform2fv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform2fv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform2i(GLint location, GLint x, GLint y)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform2i(location, x, y);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform2i(location, x, y);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform2iv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform2iv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform3f(location, x, y, z);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform3f(location, x, y, z);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform3fv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform3fv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform3i(location, x, y, z);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform3i(location, x, y, z);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform3iv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform3iv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform4f(location, x, y, z, w);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform4f(location, x, y, z, w);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform4fv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform4fv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform4i(location, x, y, z, w);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform4i(location, x, y, z, w);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniform4iv(location, count, v);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniform4iv(location, count, v);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniformMatrix2fv(location, count, transpose, value);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniformMatrix2fv(location, count, transpose, value);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniformMatrix3fv(location, count, transpose, value);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniformMatrix3fv(location, count, transpose, value);
+#endif
+}
+
+inline void QOpenGLFunctions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUniformMatrix4fv(location, count, transpose, value);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->uniformMatrix4fv(location, count, transpose, value);
+#endif
+}
+
+inline void QOpenGLFunctions::glUseProgram(GLuint program)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glUseProgram(program);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->useProgram(program);
+#endif
+}
+
+inline void QOpenGLFunctions::glValidateProgram(GLuint program)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glValidateProgram(program);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->validateProgram(program);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib1f(GLuint indx, GLfloat x)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib1f(indx, x);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib1f(indx, x);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib1fv(GLuint indx, const GLfloat* values)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib1fv(indx, values);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib1fv(indx, values);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib2f(indx, x, y);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib2f(indx, x, y);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib2fv(GLuint indx, const GLfloat* values)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib2fv(indx, values);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib2fv(indx, values);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib3f(indx, x, y, z);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib3f(indx, x, y, z);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib3fv(GLuint indx, const GLfloat* values)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib3fv(indx, values);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib3fv(indx, values);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib4f(indx, x, y, z, w);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib4f(indx, x, y, z, w);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttrib4fv(GLuint indx, const GLfloat* values)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttrib4fv(indx, values);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttrib4fv(indx, values);
+#endif
+}
+
+inline void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+{
+#if defined(QT_OPENGL_ES_2)
+ ::glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
+#else
+ Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
+ d_ptr->vertexAttribPointer(indx, size, type, normalized, stride, ptr);
+#endif
+}
+
+#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#endif
+#ifndef GL_ACTIVE_ATTRIBUTES
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#endif
+#ifndef GL_ACTIVE_TEXTURE
+#define GL_ACTIVE_TEXTURE 0x84E0
+#endif
+#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#endif
+#ifndef GL_ACTIVE_UNIFORMS
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#endif
+#ifndef GL_ALIASED_LINE_WIDTH_RANGE
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#endif
+#ifndef GL_ALIASED_POINT_SIZE_RANGE
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#endif
+#ifndef GL_ALPHA
+#define GL_ALPHA 0x1906
+#endif
+#ifndef GL_ALPHA_BITS
+#define GL_ALPHA_BITS 0x0D55
+#endif
+#ifndef GL_ALWAYS
+#define GL_ALWAYS 0x0207
+#endif
+#ifndef GL_ARRAY_BUFFER
+#define GL_ARRAY_BUFFER 0x8892
+#endif
+#ifndef GL_ARRAY_BUFFER_BINDING
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#endif
+#ifndef GL_ATTACHED_SHADERS
+#define GL_ATTACHED_SHADERS 0x8B85
+#endif
+#ifndef GL_BACK
+#define GL_BACK 0x0405
+#endif
+#ifndef GL_BLEND
+#define GL_BLEND 0x0BE2
+#endif
+#ifndef GL_BLEND_COLOR
+#define GL_BLEND_COLOR 0x8005
+#endif
+#ifndef GL_BLEND_DST_ALPHA
+#define GL_BLEND_DST_ALPHA 0x80CA
+#endif
+#ifndef GL_BLEND_DST_RGB
+#define GL_BLEND_DST_RGB 0x80C8
+#endif
+#ifndef GL_BLEND_EQUATION
+#define GL_BLEND_EQUATION 0x8009
+#endif
+#ifndef GL_BLEND_EQUATION_ALPHA
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#endif
+#ifndef GL_BLEND_EQUATION_RGB
+#define GL_BLEND_EQUATION_RGB 0x8009
+#endif
+#ifndef GL_BLEND_SRC_ALPHA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#endif
+#ifndef GL_BLEND_SRC_RGB
+#define GL_BLEND_SRC_RGB 0x80C9
+#endif
+#ifndef GL_BLUE_BITS
+#define GL_BLUE_BITS 0x0D54
+#endif
+#ifndef GL_BOOL
+#define GL_BOOL 0x8B56
+#endif
+#ifndef GL_BOOL_VEC2
+#define GL_BOOL_VEC2 0x8B57
+#endif
+#ifndef GL_BOOL_VEC3
+#define GL_BOOL_VEC3 0x8B58
+#endif
+#ifndef GL_BOOL_VEC4
+#define GL_BOOL_VEC4 0x8B59
+#endif
+#ifndef GL_BUFFER_SIZE
+#define GL_BUFFER_SIZE 0x8764
+#endif
+#ifndef GL_BUFFER_USAGE
+#define GL_BUFFER_USAGE 0x8765
+#endif
+#ifndef GL_BYTE
+#define GL_BYTE 0x1400
+#endif
+#ifndef GL_CCW
+#define GL_CCW 0x0901
+#endif
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+#ifndef GL_COLOR_ATTACHMENT0
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#endif
+#ifndef GL_COLOR_BUFFER_BIT
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#endif
+#ifndef GL_COLOR_CLEAR_VALUE
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#endif
+#ifndef GL_COLOR_WRITEMASK
+#define GL_COLOR_WRITEMASK 0x0C23
+#endif
+#ifndef GL_COMPILE_STATUS
+#define GL_COMPILE_STATUS 0x8B81
+#endif
+#ifndef GL_COMPRESSED_TEXTURE_FORMATS
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#endif
+#ifndef GL_CONSTANT_ALPHA
+#define GL_CONSTANT_ALPHA 0x8003
+#endif
+#ifndef GL_CONSTANT_COLOR
+#define GL_CONSTANT_COLOR 0x8001
+#endif
+#ifndef GL_CULL_FACE
+#define GL_CULL_FACE 0x0B44
+#endif
+#ifndef GL_CULL_FACE_MODE
+#define GL_CULL_FACE_MODE 0x0B45
+#endif
+#ifndef GL_CURRENT_PROGRAM
+#define GL_CURRENT_PROGRAM 0x8B8D
+#endif
+#ifndef GL_CURRENT_VERTEX_ATTRIB
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#endif
+#ifndef GL_CW
+#define GL_CW 0x0900
+#endif
+#ifndef GL_DECR
+#define GL_DECR 0x1E03
+#endif
+#ifndef GL_DECR_WRAP
+#define GL_DECR_WRAP 0x8508
+#endif
+#ifndef GL_DELETE_STATUS
+#define GL_DELETE_STATUS 0x8B80
+#endif
+#ifndef GL_DEPTH_ATTACHMENT
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#endif
+#ifndef GL_DEPTH_BITS
+#define GL_DEPTH_BITS 0x0D56
+#endif
+#ifndef GL_DEPTH_BUFFER_BIT
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#endif
+#ifndef GL_DEPTH_CLEAR_VALUE
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#endif
+#ifndef GL_DEPTH_COMPONENT
+#define GL_DEPTH_COMPONENT 0x1902
+#endif
+#ifndef GL_DEPTH_COMPONENT16
+#define GL_DEPTH_COMPONENT16 0x81A5
+#endif
+#ifndef GL_DEPTH_FUNC
+#define GL_DEPTH_FUNC 0x0B74
+#endif
+#ifndef GL_DEPTH_RANGE
+#define GL_DEPTH_RANGE 0x0B70
+#endif
+#ifndef GL_DEPTH_TEST
+#define GL_DEPTH_TEST 0x0B71
+#endif
+#ifndef GL_DEPTH_WRITEMASK
+#define GL_DEPTH_WRITEMASK 0x0B72
+#endif
+#ifndef GL_DITHER
+#define GL_DITHER 0x0BD0
+#endif
+#ifndef GL_DONT_CARE
+#define GL_DONT_CARE 0x1100
+#endif
+#ifndef GL_DST_ALPHA
+#define GL_DST_ALPHA 0x0304
+#endif
+#ifndef GL_DST_COLOR
+#define GL_DST_COLOR 0x0306
+#endif
+#ifndef GL_DYNAMIC_DRAW
+#define GL_DYNAMIC_DRAW 0x88E8
+#endif
+#ifndef GL_ELEMENT_ARRAY_BUFFER
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#endif
+#ifndef GL_ELEMENT_ARRAY_BUFFER_BINDING
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#endif
+#ifndef GL_EQUAL
+#define GL_EQUAL 0x0202
+#endif
+#ifndef GL_EXTENSIONS
+#define GL_EXTENSIONS 0x1F03
+#endif
+#ifndef GL_FALSE
+#define GL_FALSE 0
+#endif
+#ifndef GL_FASTEST
+#define GL_FASTEST 0x1101
+#endif
+#ifndef GL_FIXED
+#define GL_FIXED 0x140C
+#endif
+#ifndef GL_FLOAT
+#define GL_FLOAT 0x1406
+#endif
+#ifndef GL_FLOAT_MAT2
+#define GL_FLOAT_MAT2 0x8B5A
+#endif
+#ifndef GL_FLOAT_MAT3
+#define GL_FLOAT_MAT3 0x8B5B
+#endif
+#ifndef GL_FLOAT_MAT4
+#define GL_FLOAT_MAT4 0x8B5C
+#endif
+#ifndef GL_FLOAT_VEC2
+#define GL_FLOAT_VEC2 0x8B50
+#endif
+#ifndef GL_FLOAT_VEC3
+#define GL_FLOAT_VEC3 0x8B51
+#endif
+#ifndef GL_FLOAT_VEC4
+#define GL_FLOAT_VEC4 0x8B52
+#endif
+#ifndef GL_FRAGMENT_SHADER
+#define GL_FRAGMENT_SHADER 0x8B30
+#endif
+#ifndef GL_FRAMEBUFFER
+#define GL_FRAMEBUFFER 0x8D40
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#endif
+#ifndef GL_FRAMEBUFFER_BINDING
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#endif
+#ifndef GL_FRAMEBUFFER_COMPLETE
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#endif
+#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#endif
+#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#endif
+#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#endif
+#ifndef GL_FRAMEBUFFER_UNSUPPORTED
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+#endif
+#ifndef GL_FRONT
+#define GL_FRONT 0x0404
+#endif
+#ifndef GL_FRONT_AND_BACK
+#define GL_FRONT_AND_BACK 0x0408
+#endif
+#ifndef GL_FRONT_FACE
+#define GL_FRONT_FACE 0x0B46
+#endif
+#ifndef GL_FUNC_ADD
+#define GL_FUNC_ADD 0x8006
+#endif
+#ifndef GL_FUNC_REVERSE_SUBTRACT
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#endif
+#ifndef GL_FUNC_SUBTRACT
+#define GL_FUNC_SUBTRACT 0x800A
+#endif
+#ifndef GL_GENERATE_MIPMAP_HINT
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+#endif
+#ifndef GL_GEQUAL
+#define GL_GEQUAL 0x0206
+#endif
+#ifndef GL_GREATER
+#define GL_GREATER 0x0204
+#endif
+#ifndef GL_GREEN_BITS
+#define GL_GREEN_BITS 0x0D53
+#endif
+#ifndef GL_HIGH_FLOAT
+#define GL_HIGH_FLOAT 0x8DF2
+#endif
+#ifndef GL_HIGH_INT
+#define GL_HIGH_INT 0x8DF5
+#endif
+#ifndef GL_IMPLEMENTATION_COLOR_READ_FORMAT
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+#endif
+#ifndef GL_IMPLEMENTATION_COLOR_READ_TYPE
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#endif
+#ifndef GL_INCR
+#define GL_INCR 0x1E02
+#endif
+#ifndef GL_INCR_WRAP
+#define GL_INCR_WRAP 0x8507
+#endif
+#ifndef GL_INFO_LOG_LENGTH
+#define GL_INFO_LOG_LENGTH 0x8B84
+#endif
+#ifndef GL_INT
+#define GL_INT 0x1404
+#endif
+#ifndef GL_INT_VEC2
+#define GL_INT_VEC2 0x8B53
+#endif
+#ifndef GL_INT_VEC3
+#define GL_INT_VEC3 0x8B54
+#endif
+#ifndef GL_INT_VEC4
+#define GL_INT_VEC4 0x8B55
+#endif
+#ifndef GL_INVALID_ENUM
+#define GL_INVALID_ENUM 0x0500
+#endif
+#ifndef GL_INVALID_FRAMEBUFFER_OPERATION
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+#endif
+#ifndef GL_INVALID_OPERATION
+#define GL_INVALID_OPERATION 0x0502
+#endif
+#ifndef GL_INVALID_VALUE
+#define GL_INVALID_VALUE 0x0501
+#endif
+#ifndef GL_INVERT
+#define GL_INVERT 0x150A
+#endif
+#ifndef GL_KEEP
+#define GL_KEEP 0x1E00
+#endif
+#ifndef GL_LEQUAL
+#define GL_LEQUAL 0x0203
+#endif
+#ifndef GL_LESS
+#define GL_LESS 0x0201
+#endif
+#ifndef GL_LINEAR
+#define GL_LINEAR 0x2601
+#endif
+#ifndef GL_LINEAR_MIPMAP_LINEAR
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#endif
+#ifndef GL_LINEAR_MIPMAP_NEAREST
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#endif
+#ifndef GL_LINE_LOOP
+#define GL_LINE_LOOP 0x0002
+#endif
+#ifndef GL_LINES
+#define GL_LINES 0x0001
+#endif
+#ifndef GL_LINE_STRIP
+#define GL_LINE_STRIP 0x0003
+#endif
+#ifndef GL_LINE_WIDTH
+#define GL_LINE_WIDTH 0x0B21
+#endif
+#ifndef GL_LINK_STATUS
+#define GL_LINK_STATUS 0x8B82
+#endif
+#ifndef GL_LOW_FLOAT
+#define GL_LOW_FLOAT 0x8DF0
+#endif
+#ifndef GL_LOW_INT
+#define GL_LOW_INT 0x8DF3
+#endif
+#ifndef GL_LUMINANCE
+#define GL_LUMINANCE 0x1909
+#endif
+#ifndef GL_LUMINANCE_ALPHA
+#define GL_LUMINANCE_ALPHA 0x190A
+#endif
+#ifndef GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#endif
+#ifndef GL_MAX_CUBE_MAP_TEXTURE_SIZE
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#endif
+#ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#endif
+#ifndef GL_MAX_RENDERBUFFER_SIZE
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+#endif
+#ifndef GL_MAX_TEXTURE_IMAGE_UNITS
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#endif
+#ifndef GL_MAX_TEXTURE_SIZE
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#endif
+#ifndef GL_MAX_VARYING_VECTORS
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#endif
+#ifndef GL_MAX_VERTEX_ATTRIBS
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#endif
+#ifndef GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#endif
+#ifndef GL_MAX_VERTEX_UNIFORM_VECTORS
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#endif
+#ifndef GL_MAX_VIEWPORT_DIMS
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#endif
+#ifndef GL_MEDIUM_FLOAT
+#define GL_MEDIUM_FLOAT 0x8DF1
+#endif
+#ifndef GL_MEDIUM_INT
+#define GL_MEDIUM_INT 0x8DF4
+#endif
+#ifndef GL_MIRRORED_REPEAT
+#define GL_MIRRORED_REPEAT 0x8370
+#endif
+#ifndef GL_NEAREST
+#define GL_NEAREST 0x2600
+#endif
+#ifndef GL_NEAREST_MIPMAP_LINEAR
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#endif
+#ifndef GL_NEAREST_MIPMAP_NEAREST
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#endif
+#ifndef GL_NEVER
+#define GL_NEVER 0x0200
+#endif
+#ifndef GL_NICEST
+#define GL_NICEST 0x1102
+#endif
+#ifndef GL_NO_ERROR
+#define GL_NO_ERROR 0
+#endif
+#ifndef GL_NONE
+#define GL_NONE 0
+#endif
+#ifndef GL_NOTEQUAL
+#define GL_NOTEQUAL 0x0205
+#endif
+#ifndef GL_NUM_COMPRESSED_TEXTURE_FORMATS
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#endif
+#ifndef GL_NUM_SHADER_BINARY_FORMATS
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+#endif
+#ifndef GL_ONE
+#define GL_ONE 1
+#endif
+#ifndef GL_ONE_MINUS_CONSTANT_ALPHA
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#endif
+#ifndef GL_ONE_MINUS_CONSTANT_COLOR
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#endif
+#ifndef GL_ONE_MINUS_DST_ALPHA
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#endif
+#ifndef GL_ONE_MINUS_DST_COLOR
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#endif
+#ifndef GL_ONE_MINUS_SRC_ALPHA
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#endif
+#ifndef GL_ONE_MINUS_SRC_COLOR
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#endif
+#ifndef GL_OUT_OF_MEMORY
+#define GL_OUT_OF_MEMORY 0x0505
+#endif
+#ifndef GL_PACK_ALIGNMENT
+#define GL_PACK_ALIGNMENT 0x0D05
+#endif
+#ifndef GL_POINTS
+#define GL_POINTS 0x0000
+#endif
+#ifndef GL_POLYGON_OFFSET_FACTOR
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#endif
+#ifndef GL_POLYGON_OFFSET_FILL
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#endif
+#ifndef GL_POLYGON_OFFSET_UNITS
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#endif
+#ifndef GL_RED_BITS
+#define GL_RED_BITS 0x0D52
+#endif
+#ifndef GL_RENDERBUFFER
+#define GL_RENDERBUFFER 0x8D41
+#endif
+#ifndef GL_RENDERBUFFER_ALPHA_SIZE
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#endif
+#ifndef GL_RENDERBUFFER_BINDING
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#endif
+#ifndef GL_RENDERBUFFER_BLUE_SIZE
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#endif
+#ifndef GL_RENDERBUFFER_DEPTH_SIZE
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#endif
+#ifndef GL_RENDERBUFFER_GREEN_SIZE
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#endif
+#ifndef GL_RENDERBUFFER_HEIGHT
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#endif
+#ifndef GL_RENDERBUFFER_INTERNAL_FORMAT
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#endif
+#ifndef GL_RENDERBUFFER_RED_SIZE
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#endif
+#ifndef GL_RENDERBUFFER_STENCIL_SIZE
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+#endif
+#ifndef GL_RENDERBUFFER_WIDTH
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#endif
+#ifndef GL_RENDERER
+#define GL_RENDERER 0x1F01
+#endif
+#ifndef GL_REPEAT
+#define GL_REPEAT 0x2901
+#endif
+#ifndef GL_REPLACE
+#define GL_REPLACE 0x1E01
+#endif
+#ifndef GL_RGB
+#define GL_RGB 0x1907
+#endif
+#ifndef GL_RGB565
+#define GL_RGB565 0x8D62
+#endif
+#ifndef GL_RGB5_A1
+#define GL_RGB5_A1 0x8057
+#endif
+#ifndef GL_RGBA
+#define GL_RGBA 0x1908
+#endif
+#ifndef GL_RGBA4
+#define GL_RGBA4 0x8056
+#endif
+#ifndef GL_SAMPLE_ALPHA_TO_COVERAGE
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#endif
+#ifndef GL_SAMPLE_BUFFERS
+#define GL_SAMPLE_BUFFERS 0x80A8
+#endif
+#ifndef GL_SAMPLE_COVERAGE
+#define GL_SAMPLE_COVERAGE 0x80A0
+#endif
+#ifndef GL_SAMPLE_COVERAGE_INVERT
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#endif
+#ifndef GL_SAMPLE_COVERAGE_VALUE
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#endif
+#ifndef GL_SAMPLER_2D
+#define GL_SAMPLER_2D 0x8B5E
+#endif
+#ifndef GL_SAMPLER_CUBE
+#define GL_SAMPLER_CUBE 0x8B60
+#endif
+#ifndef GL_SAMPLES
+#define GL_SAMPLES 0x80A9
+#endif
+#ifndef GL_SCISSOR_BOX
+#define GL_SCISSOR_BOX 0x0C10
+#endif
+#ifndef GL_SCISSOR_TEST
+#define GL_SCISSOR_TEST 0x0C11
+#endif
+#ifndef GL_SHADER_BINARY_FORMATS
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#endif
+#ifndef GL_SHADER_COMPILER
+#define GL_SHADER_COMPILER 0x8DFA
+#endif
+#ifndef GL_SHADER_SOURCE_LENGTH
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#endif
+#ifndef GL_SHADER_TYPE
+#define GL_SHADER_TYPE 0x8B4F
+#endif
+#ifndef GL_SHADING_LANGUAGE_VERSION
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#endif
+#ifndef GL_SHORT
+#define GL_SHORT 0x1402
+#endif
+#ifndef GL_SRC_ALPHA
+#define GL_SRC_ALPHA 0x0302
+#endif
+#ifndef GL_SRC_ALPHA_SATURATE
+#define GL_SRC_ALPHA_SATURATE 0x0308
+#endif
+#ifndef GL_SRC_COLOR
+#define GL_SRC_COLOR 0x0300
+#endif
+#ifndef GL_STATIC_DRAW
+#define GL_STATIC_DRAW 0x88E4
+#endif
+#ifndef GL_STENCIL_ATTACHMENT
+#define GL_STENCIL_ATTACHMENT 0x8D20
+#endif
+#ifndef GL_STENCIL_BACK_FAIL
+#define GL_STENCIL_BACK_FAIL 0x8801
+#endif
+#ifndef GL_STENCIL_BACK_FUNC
+#define GL_STENCIL_BACK_FUNC 0x8800
+#endif
+#ifndef GL_STENCIL_BACK_PASS_DEPTH_FAIL
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#endif
+#ifndef GL_STENCIL_BACK_PASS_DEPTH_PASS
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#endif
+#ifndef GL_STENCIL_BACK_REF
+#define GL_STENCIL_BACK_REF 0x8CA3
+#endif
+#ifndef GL_STENCIL_BACK_VALUE_MASK
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#endif
+#ifndef GL_STENCIL_BACK_WRITEMASK
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#endif
+#ifndef GL_STENCIL_BITS
+#define GL_STENCIL_BITS 0x0D57
+#endif
+#ifndef GL_STENCIL_BUFFER_BIT
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#endif
+#ifndef GL_STENCIL_CLEAR_VALUE
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#endif
+#ifndef GL_STENCIL_FAIL
+#define GL_STENCIL_FAIL 0x0B94
+#endif
+#ifndef GL_STENCIL_FUNC
+#define GL_STENCIL_FUNC 0x0B92
+#endif
+#ifndef GL_STENCIL_INDEX
+#define GL_STENCIL_INDEX 0x1901
+#endif
+#ifndef GL_STENCIL_INDEX8
+#define GL_STENCIL_INDEX8 0x8D48
+#endif
+#ifndef GL_STENCIL_PASS_DEPTH_FAIL
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#endif
+#ifndef GL_STENCIL_PASS_DEPTH_PASS
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#endif
+#ifndef GL_STENCIL_REF
+#define GL_STENCIL_REF 0x0B97
+#endif
+#ifndef GL_STENCIL_TEST
+#define GL_STENCIL_TEST 0x0B90
+#endif
+#ifndef GL_STENCIL_VALUE_MASK
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#endif
+#ifndef GL_STENCIL_WRITEMASK
+#define GL_STENCIL_WRITEMASK 0x0B98
+#endif
+#ifndef GL_STREAM_DRAW
+#define GL_STREAM_DRAW 0x88E0
+#endif
+#ifndef GL_SUBPIXEL_BITS
+#define GL_SUBPIXEL_BITS 0x0D50
+#endif
+#ifndef GL_TEXTURE0
+#define GL_TEXTURE0 0x84C0
+#endif
+#ifndef GL_TEXTURE
+#define GL_TEXTURE 0x1702
+#endif
+#ifndef GL_TEXTURE10
+#define GL_TEXTURE10 0x84CA
+#endif
+#ifndef GL_TEXTURE1
+#define GL_TEXTURE1 0x84C1
+#endif
+#ifndef GL_TEXTURE11
+#define GL_TEXTURE11 0x84CB
+#endif
+#ifndef GL_TEXTURE12
+#define GL_TEXTURE12 0x84CC
+#endif
+#ifndef GL_TEXTURE13
+#define GL_TEXTURE13 0x84CD
+#endif
+#ifndef GL_TEXTURE14
+#define GL_TEXTURE14 0x84CE
+#endif
+#ifndef GL_TEXTURE15
+#define GL_TEXTURE15 0x84CF
+#endif
+#ifndef GL_TEXTURE16
+#define GL_TEXTURE16 0x84D0
+#endif
+#ifndef GL_TEXTURE17
+#define GL_TEXTURE17 0x84D1
+#endif
+#ifndef GL_TEXTURE18
+#define GL_TEXTURE18 0x84D2
+#endif
+#ifndef GL_TEXTURE19
+#define GL_TEXTURE19 0x84D3
+#endif
+#ifndef GL_TEXTURE20
+#define GL_TEXTURE20 0x84D4
+#endif
+#ifndef GL_TEXTURE2
+#define GL_TEXTURE2 0x84C2
+#endif
+#ifndef GL_TEXTURE21
+#define GL_TEXTURE21 0x84D5
+#endif
+#ifndef GL_TEXTURE22
+#define GL_TEXTURE22 0x84D6
+#endif
+#ifndef GL_TEXTURE23
+#define GL_TEXTURE23 0x84D7
+#endif
+#ifndef GL_TEXTURE24
+#define GL_TEXTURE24 0x84D8
+#endif
+#ifndef GL_TEXTURE25
+#define GL_TEXTURE25 0x84D9
+#endif
+#ifndef GL_TEXTURE26
+#define GL_TEXTURE26 0x84DA
+#endif
+#ifndef GL_TEXTURE27
+#define GL_TEXTURE27 0x84DB
+#endif
+#ifndef GL_TEXTURE28
+#define GL_TEXTURE28 0x84DC
+#endif
+#ifndef GL_TEXTURE29
+#define GL_TEXTURE29 0x84DD
+#endif
+#ifndef GL_TEXTURE_2D
+#define GL_TEXTURE_2D 0x0DE1
+#endif
+#ifndef GL_TEXTURE30
+#define GL_TEXTURE30 0x84DE
+#endif
+#ifndef GL_TEXTURE3
+#define GL_TEXTURE3 0x84C3
+#endif
+#ifndef GL_TEXTURE31
+#define GL_TEXTURE31 0x84DF
+#endif
+#ifndef GL_TEXTURE4
+#define GL_TEXTURE4 0x84C4
+#endif
+#ifndef GL_TEXTURE5
+#define GL_TEXTURE5 0x84C5
+#endif
+#ifndef GL_TEXTURE6
+#define GL_TEXTURE6 0x84C6
+#endif
+#ifndef GL_TEXTURE7
+#define GL_TEXTURE7 0x84C7
+#endif
+#ifndef GL_TEXTURE8
+#define GL_TEXTURE8 0x84C8
+#endif
+#ifndef GL_TEXTURE9
+#define GL_TEXTURE9 0x84C9
+#endif
+#ifndef GL_TEXTURE_BINDING_2D
+#define GL_TEXTURE_BINDING_2D 0x8069
+#endif
+#ifndef GL_TEXTURE_BINDING_CUBE_MAP
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_X
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_Y
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_Z
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#endif
+#ifndef GL_TEXTURE_MAG_FILTER
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#endif
+#ifndef GL_TEXTURE_MIN_FILTER
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#endif
+#ifndef GL_TEXTURE_WRAP_S
+#define GL_TEXTURE_WRAP_S 0x2802
+#endif
+#ifndef GL_TEXTURE_WRAP_T
+#define GL_TEXTURE_WRAP_T 0x2803
+#endif
+#ifndef GL_TRIANGLE_FAN
+#define GL_TRIANGLE_FAN 0x0006
+#endif
+#ifndef GL_TRIANGLES
+#define GL_TRIANGLES 0x0004
+#endif
+#ifndef GL_TRIANGLE_STRIP
+#define GL_TRIANGLE_STRIP 0x0005
+#endif
+#ifndef GL_TRUE
+#define GL_TRUE 1
+#endif
+#ifndef GL_UNPACK_ALIGNMENT
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#endif
+#ifndef GL_UNSIGNED_BYTE
+#define GL_UNSIGNED_BYTE 0x1401
+#endif
+#ifndef GL_UNSIGNED_INT
+#define GL_UNSIGNED_INT 0x1405
+#endif
+#ifndef GL_UNSIGNED_SHORT
+#define GL_UNSIGNED_SHORT 0x1403
+#endif
+#ifndef GL_UNSIGNED_SHORT_4_4_4_4
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#endif
+#ifndef GL_UNSIGNED_SHORT_5_5_5_1
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#endif
+#ifndef GL_UNSIGNED_SHORT_5_6_5
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#endif
+#ifndef GL_VALIDATE_STATUS
+#define GL_VALIDATE_STATUS 0x8B83
+#endif
+#ifndef GL_VENDOR
+#define GL_VENDOR 0x1F00
+#endif
+#ifndef GL_VERSION
+#define GL_VERSION 0x1F02
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_ENABLED
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_POINTER
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_SIZE
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_STRIDE
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_TYPE
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#endif
+#ifndef GL_VERTEX_SHADER
+#define GL_VERTEX_SHADER 0x8B31
+#endif
+#ifndef GL_VIEWPORT
+#define GL_VIEWPORT 0x0BA2
+#endif
+#ifndef GL_ZERO
+#define GL_ZERO 0
+#endif
+
+#endif
diff --git a/src/threed/arrays/arrays.pri b/src/threed/arrays/arrays.pri
new file mode 100644
index 000000000..f9eb72d94
--- /dev/null
+++ b/src/threed/arrays/arrays.pri
@@ -0,0 +1,28 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += \
+ qglattributedescription.h \
+ qglattributeset.h \
+ qglattributevalue.h \
+ qglindexbuffer.h \
+ qglvertexbundle.h \
+ qarray.h \
+ qcolor4ub.h \
+ qcustomdataarray.h \
+ qvector2darray.h \
+ qvector3darray.h \
+ qvector4darray.h
+SOURCES += \
+ qglattributedescription.cpp \
+ qglattributeset.cpp \
+ qglattributevalue.cpp \
+ qglindexbuffer.cpp \
+ qglvertexbundle.cpp \
+ qarray.cpp \
+ qcolor4ub.cpp \
+ qcustomdataarray.cpp \
+ qvector2darray.cpp \
+ qvector3darray.cpp \
+ qvector4darray.cpp
+PRIVATE_HEADERS += \
+ qglvertexbundle_p.h
diff --git a/src/threed/arrays/qarray.cpp b/src/threed/arrays/qarray.cpp
new file mode 100644
index 000000000..52bb1eb2a
--- /dev/null
+++ b/src/threed/arrays/qarray.cpp
@@ -0,0 +1,1022 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qarray.h"
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QArray
+ \brief The QArray class is a template class that provides a dynamic array of simple types.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ QArray is similar to QVector except that it has much less overhead
+ when constructing large arrays by appending individual elements
+ one by one.
+
+ QArray instances have a preallocated data area for quickly
+ building small arrays on the stack without malloc overhead.
+ Once the array grows beyond the preallocated size, it is copied
+ to the heap. The size of the preallocated area, which defaults to 8,
+ can be specified with the second template parameter:
+
+ \code
+ QArray<QVector3D, 32> array;
+ \endcode
+
+ QArray uses implicit sharing and copy-on-write semantics to support
+ passing large arrays around an application with little overhead.
+
+ QArray is heavily optimized for copy-on-write and the case of
+ constructing an array by calling append(). It has a slight
+ performance penalty for random access using the non-const
+ version of operator[]().
+*/
+
+/*!
+ \fn QArray::QArray()
+
+ Constructs an empty array.
+
+ \sa reserve()
+*/
+
+/*!
+ \fn QArray::QArray(int size, const T &value)
+
+ Constructs an array of \a size elements, all initialized
+ to \a value.
+
+ \sa fill()
+*/
+
+/*!
+ \fn QArray::QArray(int size)
+
+ Constructs an array of \a size elements, all initialized
+ to their default-constructed values.
+*/
+
+/*!
+ \fn QArray::QArray(const T *values, int size)
+
+ Constructs an array of \a size elements, initialized
+ from \a values.
+*/
+
+/*!
+ \fn QArray::QArray(const QArray<T, PreallocSize> &other)
+
+ Constructs a copy of \a other.
+
+ \sa operator=()
+*/
+
+/*!
+ \fn QArray::~QArray()
+
+ Destroys the array.
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> &QArray::operator=(const QArray<T, PreallocSize> &other)
+
+ Assigns \a other to this array and returns a reference
+ to this array.
+*/
+
+/*!
+ \fn int QArray::size() const
+
+ Returns the number of elements in this array.
+
+ \sa resize(), capacity(), isEmpty()
+*/
+
+/*!
+ \fn int QArray::count() const
+ \overload
+
+ Same as size(), provided for convenience.
+*/
+
+/*!
+ \fn int QArray::capacity() const
+
+ Returns the number of elements that can be stored in this
+ array before reallocation.
+
+ \sa reserve(), size()
+*/
+
+/*!
+ \fn bool QArray::isEmpty() const
+
+ Returns true if this array is empty; false otherwise.
+
+ \sa size(), clear()
+*/
+
+/*!
+ \fn bool QArray::isDetached() const
+ \internal
+
+ Returns true if this array has definitely been detached from all
+ other shared copies of the data; false otherwise.
+
+ It is possible for this function to return false if the
+ array was previously shared but no longer is. It is thus
+ an indication that a detach() will probably be required.
+
+ This function can be used to determine if functions that
+ write to this array such as append(), replace(),
+ and data(), will need to make a copy.
+
+ Raw data arrays that are created with fromRawData() are
+ never detached.
+
+ \sa detach()
+*/
+
+/*!
+ \fn void QArray::detach()
+ \internal
+
+ Detaches this array from all other shared copies of the data.
+
+ \sa isDetached()
+*/
+
+/*!
+ \fn void QArray::clear()
+
+ Clears all elements from this array and sets the size to zero.
+
+ This function will deallocate any memory that is used on the heap
+ to store the array's elements. To reuse the same memory
+ as before, call resize() with an argument of zero.
+
+ \sa resize(), isEmpty()
+*/
+
+/*!
+ \fn const T &QArray::at(int index) const
+
+ Returns the item at position \a index in the array.
+
+ \a index must be a valid index position in the array (i.e., 0 <= \a
+ index < size()).
+
+ \sa operator[](), constData(), value()
+*/
+
+/*!
+ \fn T &QArray::operator[](int index)
+
+ Returns the item at position \a index as a modifiable reference.
+
+ \a index must be a valid index position in the vector (i.e., 0 <= \a index
+ < size()).
+
+ Note that using non-const operators can cause QArray
+ to do a deep copy.
+
+ \sa at(), value()
+*/
+
+/*!
+ \fn const T &QArray::operator[](int index) const
+
+ \overload
+
+ Same as at(\a index).
+*/
+
+/*!
+ \fn T QArray::value(int index) const
+
+ Returns the value at position \a index in the vector.
+
+ If the \a index is out of bounds, the function returns
+ a default-constructed value. If you are certain that
+ \a index is within bounds, you can use at() instead,
+ which is slightly faster.
+
+ \sa at(), operator[]()
+*/
+
+/*!
+ \fn T QArray::value(int index, const T &defaultValue) const
+ \overload
+
+ If the \a index is out of bounds, the function returns
+ \a defaultValue.
+*/
+
+/*!
+ \fn T *QArray::extend(int size)
+
+ Extends this array by \a size elements and returns a pointer
+ to the storage, which is not initialized. The pointer is only
+ valid until the array is reallocated or destroyed.
+
+ The append() or resize() functions are recommended if T is a
+ complex type, with extend() only used for simple types.
+ Because the storage is not initialized, the caller should use
+ the in-place new operator to set elements:
+
+ \code
+ QArray<QRegExp> array;
+ QRegExp *space = array.extend(1);
+ new (space) QRegExp(QLatin1String("exp"));
+ \endcode
+
+ \sa append(), resize()
+*/
+
+/*!
+ \fn void QArray::append(const T &value)
+
+ Appends \a value to this array.
+
+ \sa prepend(), insert()
+*/
+
+/*!
+ \fn void QArray::append(const T &value1, const T &value2)
+
+ \overload
+
+ Appends \a value1 and \a value2 to this array.
+*/
+
+/*!
+ \fn void QArray::append(const T &value1, const T &value2, const T &value3)
+
+ \overload
+
+ Appends \a value1, \a value2, and \a value3 to this array.
+*/
+
+/*!
+ \fn void QArray::append(const T &value1, const T &value2, const T &value3, const T &value4)
+
+ \overload
+
+ Appends \a value1, \a value2, \a value3, and \a value4 to this array.
+*/
+
+/*!
+ \fn void QArray::append(const T *values, int count)
+
+ Appends the \a count elements of \a values to this array.
+*/
+
+/*!
+ \fn void QArray::append(const QArray<T, PreallocSize> &other)
+
+ Appends the elements of \a other to this array.
+*/
+
+/*!
+ \fn void QArray::prepend(const T &value)
+
+ Prepends \a value to this array.
+
+ \sa append(), insert()
+*/
+
+/*!
+ \fn void QArray::insert(int index, const T &value)
+
+ Inserts \a value at position \a index in this array.
+ If \a index is 0, then \a value is prepended to the array.
+ If \a index is size(), then \a value is appended to the array.
+
+ \sa append(), prepend()
+*/
+
+/*!
+ \fn void QArray::insert(int index, int count, const T &value)
+ \overload
+
+ Inserts \a count copies of \a value at position \a index
+ in this array.
+*/
+
+/*!
+ \fn QArray::iterator QArray::insert(iterator before, int count, const T &value)
+
+ Inserts \a count copies of \a value in front of the item
+ pointed to by the iterator \a before. Returns an iterator
+ pointing at the first of the inserted items.
+*/
+
+/*!
+ \fn QArray::iterator QArray::insert(iterator before, const T &value)
+ \overload
+
+ Inserts \a value in front of the item pointed to by the
+ iterator \a before. Returns an iterator pointing at the
+ inserted item.
+*/
+
+/*!
+ \fn void QArray::replace(int index, const T &value)
+
+ Replaces the element at \a index with \a value.
+
+ \sa operator[](), remove()
+*/
+
+/*!
+ \fn void QArray::replace(int index, const T *values, int count)
+ \overload
+
+ Replaces the \a count elements of this array with the
+ contents of \a values, starting at \a index.
+
+ If (\a index + \a count) is larger than the current size of this
+ array, the array will be extended to that size.
+
+ \sa append()
+*/
+
+/*!
+ \fn void QArray::remove(int index)
+
+ \overload
+
+ Removes the element at position \a index in this array.
+*/
+
+/*!
+ \fn void QArray::remove(int index, int count)
+
+ Removes the \a count elements starting at position \a index
+ in this array. If \a index or \a count is out of range,
+ the set of removed elements will be truncated to those that
+ are in range.
+*/
+
+/*!
+ \fn QArray::iterator QArray::erase(iterator begin, iterator end)
+ \overload
+
+ Removes all the items from \a begin up to (but not including) \a
+ end. Returns an iterator to the same item that \a end referred to
+ before the call.
+*/
+
+/*!
+ \fn QArray::iterator QArray::erase(iterator pos)
+
+ Removes the item pointed to by the iterator \a pos from the
+ vector, and returns an iterator to the next item in the vector
+ (which may be end()).
+
+ \sa insert(), remove()
+*/
+
+/*!
+ \fn void QArray::removeFirst()
+
+ Removes the first element from this array. Does nothing if
+ the array is empty.
+
+ \sa remove(), removeLast()
+*/
+
+/*!
+ \fn void QArray::removeLast()
+
+ Removes the last element from this array. Does nothing if
+ the array is empty.
+
+ \sa remove(), removeFirst()
+*/
+
+/*!
+ \fn int QArray::indexOf(const T &value, int from) const
+
+ Returns the index position of the first occurrence of
+ \a value in the array, searching forward from index
+ position \a from. Returns -1 if no item matched.
+
+ If \a from is negative, then it indicates an index position
+ relative to the end of the array, -1 being the last index
+ position.
+
+ This function requires the value type T to have an implementation
+ of \c operator==().
+
+ \sa lastIndexOf(), contains()
+*/
+
+/*!
+ \fn int QArray::lastIndexOf(const T &value, int from) const
+
+ Returns the index position of the last occurrence of
+ \a value in the array, searching backward from index
+ position \a from. Returns -1 if no item matched.
+
+ If \a from is negative, then it indicates an index position
+ relative to the end of the array, -1 being the last index
+ position. The default for \a from is -1.
+
+ This function requires the value type T to have an implementation
+ of \c operator==().
+
+ \sa indexOf(), contains()
+*/
+
+/*!
+ \fn bool QArray::contains(const T &value) const
+
+ Returns true if the array contains an occurrence of \a value;
+ false otherwise.
+
+ This function requires the value type T to have an implementation
+ of \c operator==().
+
+ \sa indexOf(), count()
+*/
+
+/*!
+ \fn int QArray::count(const T &value) const
+
+ Returns the number of occurrences of \a value in the array.
+
+ This function requires the value type T to have an implementation
+ of \c operator==().
+
+ \sa contains(), indexOf()
+*/
+
+/*!
+ \fn void QArray::resize(int size)
+
+ Sets the size of the array to \a size. If \a size is greater
+ than the current size, elements are added to the end and are
+ initialized to a default-constructed value. If \a size is less
+ than the current size, elements are removed from the end.
+
+ \sa size(), reserve(), squeeze()
+*/
+
+/*!
+ \fn void QArray::reserve(int size)
+
+ Increases the capacity of this array to reserve space for
+ at least \a size elements. If the capacity is already larger
+ than \a size, this function does nothing; in particular, it does
+ not remove elements from the array like resize() does.
+
+ This function can be useful when you know how roughly many elements
+ will be appended ahead of time. Reserving the space once can avoid
+ unnecessary realloc operations later.
+
+ \sa capacity(), resize(), squeeze()
+*/
+
+/*!
+ \fn void QArray::squeeze()
+
+ Releases any memory not required to store the array's elements
+ by reducing its capacity() to size().
+
+ This function is intended for reclaiming memory in an
+ array that is being used over and over with different contents.
+ As elements are added to an array, it will be constantly
+ expanded in size. This function can realloc the array
+ to a smaller size to reclaim unused memory.
+
+ \sa reserve(), capacity()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> &QArray::fill(const T &value, int size)
+
+ Assigns \a value to all items in the array. If \a size is
+ different from -1 (the default), the array is resized to
+ \a size beforehand. Returns a reference to the array.
+
+ \sa resize()
+*/
+
+/*!
+ \fn void QArray::reverse()
+
+ Reverses the order of this array in place.
+
+ \sa reversed()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> QArray::reversed() const
+
+ Returns a copy of this array with elements in the reverse order.
+
+ \sa reverse()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> QArray::mid(int index, int length) const
+
+ Returns an array containing the \a length elements of
+ this array, starting at \a index. If \a length is less
+ than zero, or extends further than the end of the array, then all
+ elements extending from \a index to the end of the array will be
+ included in the return value.
+
+ \sa left(), right()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> QArray::left(int length) const;
+
+ Returns an array containing the first \a length
+ elements of this array. If \a length is less than zero,
+ or greater than size(), then all elements in this array will
+ be included in the return value.
+
+ \sa mid(), right()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> QArray::right(int length) const;
+
+ Returns an array containing the last \a length
+ elements of this array. If \a length is less than zero,
+ or greater than size(), then all elements in this array
+ will be included in the return value.
+
+ \sa mid(), left()
+*/
+
+/*!
+ \fn T *QArray::data()
+
+ Returns a pointer to the data stored in the array. The pointer
+ can be used to access and modify the items in the array.
+
+ The pointer remains valid as long as the array isn't
+ reallocated.
+
+ This function is mostly useful to pass an array to a function
+ that accepts a plain C++ array. It may make a deep copy of the
+ array's elements if the array is implicitly shared.
+
+ \sa constData(), operator[]()
+*/
+
+/*!
+ \fn const T *QArray::data() const
+
+ \overload
+*/
+
+/*!
+ \fn const T *QArray::constData() const
+
+ Returns a const pointer to the data stored in the array.
+ The pointer can be used to access the items in the array.
+ The pointer remains valid as long as the array isn't
+ reallocated.
+
+ This function is mostly useful to pass an array to a function
+ that accepts a plain C++ array.
+
+ \sa data(), operator[]()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> QArray::fromRawData(const T *data, int size)
+
+ Returns an array consisting of the \a size elements from \a data.
+
+ This function takes a reference to \a data, but does not copy
+ the elements until the array is modified. The memory at \a data
+ must remain valid until the returned array is destroyed
+ or modified.
+
+ Use append() instead of fromRawData() to force a copy to be made
+ of the elements at \a data when the array is created:
+
+ \code
+ // Makes a copy of the data immediately.
+ QArray<float> array;
+ array.append(data, size);
+
+ // Does not make a copy of the data until the array is modified.
+ QArray<float> array;
+ array = QArray<float>::fromRawData(data, size);
+ \endcode
+
+ \sa fromWritableRawData(), append()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> QArray::fromWritableRawData(T *data, int size)
+
+ Returns an array consisting of the \a size elements from \a data.
+
+ This function takes a reference to \a data, but does not copy
+ the elements until the array is reallocated to a larger size.
+ The memory at \a data must remain valid until the returned
+ array is destroyed or reallocated.
+
+ The elements of \a data will be modified in-place. This differs
+ from fromRawData() which will make a copy of the elements
+ of \a data when the array is modified.
+
+ If the returned array is resized to less than \a size,
+ then a copy will not be made, and append() can be used to
+ append new items up to \a size. Further calls to append()
+ after \a size will force the array to be reallocated.
+
+ If the returned array is resized to more than \a size,
+ then a copy of the data will be made and further modifications
+ will not affect the elements at \a data.
+
+ \sa fromRawData()
+*/
+
+/*!
+ \fn bool QArray::operator==(const QArray<T, PreallocSize> &other) const
+
+ Returns true if \a other is equal to this array; otherwise
+ returns false.
+
+ Two arrays are considered equal if they contain the same values
+ in the same order.
+
+ This function requires the value type to have an implementation
+ of \c operator==().
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QArray::operator!=(const QArray<T, PreallocSize> &other) const
+
+ Returns true if \a other is not equal to this array; otherwise
+ returns false.
+
+ Two arrays are considered equal if they contain the same values
+ in the same order.
+
+ This function requires the value type to have an implementation
+ of \c operator==().
+
+ \sa operator==()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> &QArray::operator+=(const T &value)
+
+ \overload
+
+ Appends \a value to this array and returns a reference to
+ this array.
+
+ \sa operator<<(), append()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> &QArray::operator+=(const QArray<T, PreallocSize> &other)
+
+ Appends the elements of the \a other array to this array
+ and returns a reference to this array.
+
+ \sa operator<<(), append()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> &QArray::operator<<(const T &value)
+
+ \overload
+
+ Appends \a value to this array and returns a reference to
+ this array.
+
+ \sa operator+=(), append()
+*/
+
+/*!
+ \fn QArray<T, PreallocSize> &QArray::operator<<(const QArray<T, PreallocSize> &other)
+
+ Appends the elements of the \a other array to this array
+ and returns a reference to this array.
+
+ \sa operator+=(), append()
+*/
+
+/*!
+ \typedef QArray::iterator
+
+ The QArray::iterator typedef provides an STL-style non-const
+ iterator for QArray. The iterator is simply a typedef
+ for "T *" (pointer to T).
+
+ \sa QArray::begin(), QArray::const_iterator
+*/
+
+/*!
+ \typedef QArray::const_iterator
+
+ The QArray::iterator typedef provides an STL-style const
+ iterator for QArray. The iterator is simply a typedef
+ for "const T *" (pointer to const T).
+
+ \sa QArray::constBegin(), QArray::iterator
+*/
+
+/*!
+ \typedef QArray::Iterator
+
+ Qt-style synonym for QArray::iterator.
+*/
+
+/*!
+ \typedef QArray::ConstIterator
+
+ Qt-style synonym for QArray::const_iterator.
+*/
+
+/*!
+ \typedef QArray::const_pointer
+
+ Typedef for const T *. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QArray::const_reference
+
+ Typedef for T &. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QArray::difference_type
+
+ Typedef for ptrdiff_t. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QArray::pointer
+
+ Typedef for T *. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QArray::reference
+
+ Typedef for T &. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QArray::size_type
+
+ Typedef for int. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QArray::value_type
+
+ Typedef for T. Provided for STL compatibility.
+*/
+
+/*!
+ \fn QArray::iterator QArray::begin()
+
+ Returns an STL-style iterator pointing to the first item
+ in the array.
+
+ \sa end(), constBegin(), QArray::iterator
+*/
+
+/*!
+ \fn QArray::const_iterator QArray::begin() const
+ \overload
+*/
+
+/*!
+ \fn QArray::const_iterator QArray::constBegin() const
+
+ Returns a const STL-style iterator pointing to the first item
+ in the array.
+
+ \sa constEnd(), begin(), QArray::const_iterator
+*/
+
+/*!
+ \fn QArray::iterator QArray::end()
+
+ Returns an STL-style iterator pointing to the imaginary item
+ after the last item in the array.
+
+ \sa begin(), constEnd(), QArray::iterator
+*/
+
+/*!
+ \fn QArray::const_iterator QArray::end() const
+ \overload
+*/
+
+/*!
+ \fn QArray::const_iterator QArray::constEnd() const
+
+ Returns a const STL-style iterator pointing to the imaginary item
+ after the last item in the array.
+
+ \sa constBegin(), end(), QArray::const_iterator
+*/
+
+/*!
+ \fn T &QArray::first()
+
+ Returns a reference to the first item in the array. This
+ function assumes that the array isn't empty.
+
+ \sa last(), isEmpty()
+*/
+
+/*!
+ \fn const T &QArray::first() const
+ \overload
+*/
+
+/*!
+ \fn T &QArray::last()
+
+ Returns a reference to the last item in the array. This function
+ assumes that the array isn't empty.
+
+ \sa first(), isEmpty()
+*/
+
+/*!
+ \fn const T &QArray::last() const
+ \overload
+*/
+
+/*!
+ \fn bool QArray::startsWith(const T &value) const
+
+ Returns true if this array is not empty and its first
+ item is equal to \a value; otherwise returns false.
+
+ \sa isEmpty(), first()
+*/
+
+/*!
+ \fn bool QArray::endsWith(const T &value) const
+
+ Returns true if this array is not empty and its last
+ item is equal to \a value; otherwise returns false.
+
+ \sa isEmpty(), last()
+*/
+
+/*!
+ \fn void QArray::push_back(const T &value)
+
+ This function is provided for STL compatibility. It is equivalent
+ to append(\a value).
+*/
+
+/*!
+ \fn void QArray::push_front(const T &value)
+
+ This function is provided for STL compatibility. It is equivalent
+ to prepend(\a value).
+*/
+
+/*!
+ \fn void QArray::pop_front()
+
+ This function is provided for STL compatibility. It is equivalent
+ to removeFirst().
+*/
+
+/*!
+ \fn void QArray::pop_back()
+
+ This function is provided for STL compatibility. It is equivalent
+ to removeLast().
+*/
+
+/*!
+ \fn QArray::reference QArray::front()
+
+ This function is provided for STL compatibility. It is equivalent
+ to first().
+*/
+
+/*!
+ \fn QArray::const_reference QArray::front() const
+ \overload
+*/
+
+/*!
+ \fn QArray::reference QArray::back()
+
+ This function is provided for STL compatibility. It is equivalent
+ to last().
+*/
+
+/*!
+ \fn QArray::const_reference QArray::back() const
+ \overload
+*/
+
+/*!
+ \fn bool QArray::empty() const
+
+ This function is provided for STL compatibility. It is equivalent
+ to isEmpty(), returning true if the array is empty; otherwise
+ returns false.
+*/
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream& operator<<(QDataStream& stream, const QArray<T, PreallocSize>& array)
+ \relates QArray
+
+ Writes \a array to the given \a stream and returns a reference
+ to the \a stream.
+*/
+
+/*!
+ \fn QDataStream& operator>>(QDataStream& stream, QArray<T, PreallocSize>& array)
+ \relates QArray
+
+ Reads \a array from the given \a stream and returns a reference
+ to the \a stream.
+*/
+
+#endif
+
+int qArrayAllocMore(int alloc, int extra, int sizeOfT)
+{
+ if (alloc == 0 && extra == 0)
+ return 0;
+ const int page = 1 << 12;
+ int nalloc;
+ alloc += extra;
+ alloc *= sizeOfT;
+ // don't do anything if the loop will overflow signed int.
+ if (alloc >= INT_MAX/2)
+ return INT_MAX / sizeOfT;
+ nalloc = (alloc < page) ? 64 : page;
+ while (nalloc < alloc) {
+ if (nalloc <= 0)
+ return INT_MAX / sizeOfT;
+ nalloc *= 2;
+ }
+ return nalloc / sizeOfT;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qarray.h b/src/threed/arrays/qarray.h
new file mode 100644
index 000000000..c00ec20e5
--- /dev/null
+++ b/src/threed/arrays/qarray.h
@@ -0,0 +1,1209 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QARRAY_H
+#define QARRAY_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qatomic.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdebug.h>
+#include <string.h>
+#include <new>
+
+#include "qt3dglobal.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+#if defined(Q_DECL_ALIGN) && defined(Q_ALIGNOF)
+
+#if defined(Q_CC_GNU) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
+ typedef char __attribute__((__may_alias__)) QArrayAlignedChar;
+#else
+ typedef char QArrayAlignedChar;
+#endif
+
+template <typename T, int PreallocSize, size_t AlignT>
+struct QArrayAlignedPrealloc;
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 1>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(1) data[sizeof(T) * PreallocSize];
+};
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 2>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(2) data[sizeof(T) * PreallocSize];
+};
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 4>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(4) data[sizeof(T) * PreallocSize];
+};
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 8>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(8) data[sizeof(T) * PreallocSize];
+};
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 16>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(16) data[sizeof(T) * PreallocSize];
+};
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 32>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(32) data[sizeof(T) * PreallocSize];
+};
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 64>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(64) data[sizeof(T) * PreallocSize];
+};
+template <typename T, int PreallocSize>
+struct QArrayAlignedPrealloc<T, PreallocSize, 128>
+{
+ QArrayAlignedChar Q_DECL_ALIGN(128) data[sizeof(T) * PreallocSize];
+};
+
+#else
+
+template <typename T, int PreallocSize, size_t AlignT>
+union QArrayAlignedPrealloc
+{
+ char data[sizeof(T) * PreallocSize];
+ qint64 q_for_alignment_1;
+ double q_for_alignment_2;
+};
+
+#endif
+
+template <typename T, int PreallocSize>
+class QArrayData
+{
+public:
+#if defined(Q_ALIGNOF)
+ QArrayAlignedPrealloc<T, PreallocSize, Q_ALIGNOF(T)> m_prealloc;
+#else
+ QArrayAlignedPrealloc<T, PreallocSize, sizeof(T)> m_prealloc;
+#endif
+
+ inline T *prealloc()
+ {
+ return reinterpret_cast<T *>(m_prealloc.data);
+ }
+
+ inline bool isPrealloc(const T *start) const
+ {
+ return start == reinterpret_cast<const T *>(m_prealloc.data);
+ }
+};
+
+template <typename T>
+class QArrayData<T, 0>
+{
+public:
+
+ inline T *prealloc() { return 0; }
+
+ inline bool isPrealloc(const T *start) const
+ {
+ Q_UNUSED(start);
+ return false;
+ }
+};
+
+template <typename T, int PreallocSize = 8>
+class QArray : private QArrayData<T, PreallocSize>
+{
+public:
+ QArray();
+ explicit QArray(int size);
+ QArray(int size, const T &value);
+ QArray(const T *values, int size);
+ QArray(const QArray<T, PreallocSize> &other);
+ ~QArray();
+
+ typedef T *iterator;
+ typedef const T *const_iterator;
+
+ QArray<T, PreallocSize> &operator=
+ (const QArray<T, PreallocSize> &other);
+
+ int size() const;
+ int count() const;
+ int capacity() const;
+
+ bool isEmpty() const;
+
+ bool isDetached() const;
+ void detach();
+
+ void clear();
+
+ const T &at(int index) const;
+ const T &operator[](int index) const;
+ T &operator[](int index);
+
+ T value(int index) const;
+ T value(int index, const T &defaultValue) const;
+
+ T *extend(int size);
+
+ void append(const T &value);
+ void append(const T &value1, const T &value2);
+ void append(const T &value1, const T &value2, const T &value3);
+ void append(const T &value1, const T &value2, const T &value3, const T &value4);
+ void append(const T *values, int count);
+ void append(const QArray<T, PreallocSize> &other);
+
+ void prepend(const T &value);
+
+ void insert(int index, const T &value);
+ void insert(int index, int count, const T &value);
+ iterator insert(iterator before, int count, const T &value);
+ iterator insert(iterator before, const T &value);
+
+ void replace(int index, const T &value);
+ void replace(int index, const T *values, int count);
+
+ void remove(int index);
+ void remove(int index, int count);
+ void removeFirst() { remove(0); }
+ void removeLast() { remove(size() - 1); }
+
+ iterator erase(iterator begin, iterator end);
+ iterator erase(iterator pos);
+
+ int indexOf(const T &value, int from = 0) const;
+ int lastIndexOf(const T &value, int from = -1) const;
+ bool contains(const T &value) const;
+ int count(const T &value) const;
+
+ void resize(int size);
+ void reserve(int size);
+ void squeeze();
+
+ QArray<T, PreallocSize> &fill(const T &value, int size = -1);
+
+ void reverse();
+ QArray<T, PreallocSize> reversed() const;
+
+ QArray<T, PreallocSize> mid(int index, int length = -1) const;
+ QArray<T, PreallocSize> left(int length) const;
+ QArray<T, PreallocSize> right(int length) const;
+
+ T *data();
+ const T *data() const;
+ const T *constData() const;
+
+ static QArray<T, PreallocSize> fromRawData(const T *data, int size);
+ static QArray<T, PreallocSize> fromWritableRawData(T *data, int size);
+
+ bool operator==(const QArray<T, PreallocSize> &other) const;
+ bool operator!=(const QArray<T, PreallocSize> &other) const;
+
+ QArray<T, PreallocSize> &operator+=(const T &value);
+ QArray<T, PreallocSize> &operator+=(const QArray<T, PreallocSize> &other);
+ QArray<T, PreallocSize> &operator<<(const T &value);
+ QArray<T, PreallocSize> &operator<<(const QArray<T, PreallocSize> &other);
+
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
+ typedef T value_type;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef value_type &reference;
+ typedef const value_type &const_reference;
+ typedef ptrdiff_t difference_type;
+ typedef int size_type;
+
+ inline iterator begin() { return data(); }
+ inline const_iterator begin() const { return constData(); }
+ inline const_iterator constBegin() const { return constData(); }
+ inline iterator end() { return data() + size(); }
+ inline const_iterator end() const { return constData() + size(); }
+ inline const_iterator constEnd() const { return constData() + size(); }
+
+ inline T &first() { Q_ASSERT(!isEmpty()); return *begin(); }
+ inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); }
+ inline T &last() { Q_ASSERT(!isEmpty()); return *(end()-1); }
+ inline const T &last() const { Q_ASSERT(!isEmpty()); return *(end()-1); }
+ inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; }
+ inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; }
+
+ inline void push_back(const T &value) { append(value); }
+ inline void push_front(const T &value) { prepend(value); }
+ inline void pop_back() { Q_ASSERT(!isEmpty()); removeLast(); }
+ inline void pop_front() { Q_ASSERT(!isEmpty()); removeFirst(); }
+ inline bool empty() const { return isEmpty(); }
+ inline reference front() { return first(); }
+ inline const_reference front() const { return first(); }
+ inline reference back() { return last(); }
+ inline const_reference back() const { return last(); }
+
+private:
+ struct Data
+ {
+ QBasicAtomicInt ref;
+ int capacity;
+ T array[1];
+ };
+
+ // Invariants:
+ // 1. If the data is not shared, then the usual condition is
+ // for m_limit >= m_end.
+ // 2. If the data is shared, then m_limit == m_start.
+ // This triggers the range check in append() to call grow(),
+ // which will copy-on-write. It also triggers the detach
+ // check in data() and operator[] to cause a copy-on-write.
+ // 3. If the data is not shared, but previously was, then
+ // m_limit == m_start. This will trigger grow() or
+ // detach(), which may then notice that it doesn't have to
+ // copy-on-write. In that case, m_limit is set back
+ // to m_start + m_data->capacity.
+ // 4. If m_data is null, then m_start is either the same as
+ // m_prealloc, or it points at raw data (const or non-const).
+ // 5. If the array contains const raw data, then m_limit will
+ // be set to m_start to force copy-on-write.
+ T *m_start;
+ T *m_end;
+ mutable T *m_limit;
+ Data *m_data;
+
+ inline void initPrealloc()
+ {
+ m_end = m_start = QArrayData<T, PreallocSize>::prealloc();
+ m_limit = m_start + PreallocSize;
+ }
+
+ QArray(const T *data, int size, bool isWritable);
+
+ void free(T *data, int count);
+ void release();
+ void copyReplace(T *dst, const T *src, int count);
+ Data *copyData(const T *src, int size, int capacity);
+ void reallocate(int capacity);
+ void detach_helper();
+ void assign(const QArray<T, PreallocSize> &other);
+ void grow(int needed);
+ void setSize(int size);
+};
+
+int Q_QT3D_EXPORT qArrayAllocMore(int alloc, int extra, int sizeOfT);
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::free(T *data, int count)
+{
+ while (count-- > 0) {
+ data->~T();
+ ++data;
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::release()
+{
+ if (m_data) {
+ if (!m_data->ref.deref()) {
+ if (QTypeInfo<T>::isComplex)
+ free(m_start, m_end - m_start);
+ qFree(m_data);
+ }
+ } else if (this->isPrealloc(m_start)) {
+ if (QTypeInfo<T>::isComplex)
+ free(m_start, m_end - m_start);
+ }
+}
+
+// Copy values to initialized memory, replacing previous values.
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::copyReplace(T *dst, const T *src, int count)
+{
+ if (!QTypeInfo<T>::isStatic) {
+ ::memmove(dst, src, count * sizeof(T));
+ } else {
+ while (count-- > 0)
+ *dst++ = *src++;
+ }
+}
+
+// Make a copy of m_data, while remaining exception-safe.
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE Q_TYPENAME QArray<T, PreallocSize>::Data *QArray<T, PreallocSize>::copyData(const T *src, int size, int capacity)
+{
+ Data *data = reinterpret_cast<Data *>
+ (qMalloc(sizeof(Data) + sizeof(T) * (capacity - 1)));
+ Q_CHECK_PTR(data);
+ data->ref = 1;
+ data->capacity = capacity;
+ T *dst = data->array;
+ int copied = 0;
+ QT_TRY {
+ while (copied < size) {
+ new (dst) T(*src++);
+ ++dst;
+ ++copied;
+ }
+ } QT_CATCH(...) {
+ while (copied-- > 0)
+ (--dst)->~T();
+ qFree(data);
+ QT_RETHROW;
+ }
+ return data;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::reallocate(int capacity)
+{
+ int size = m_end - m_start;
+ if (!QTypeInfo<T>::isStatic) {
+ Data *data = reinterpret_cast<Data *>
+ (qRealloc(m_data, sizeof(Data) + sizeof(T) * (capacity - 1)));
+ Q_CHECK_PTR(data);
+ data->capacity = capacity;
+ m_data = data;
+ } else {
+ Data *data = copyData(m_data->array, size, capacity);
+ free(m_data->array, size);
+ qFree(m_data);
+ m_data = data;
+ }
+ m_start = m_data->array;
+ m_end = m_start + size;
+ m_limit = m_start + capacity;
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::detach_helper()
+{
+ // If the reference count is 1, then the array may have been
+ // copied and then the copy released. So just reset the limit.
+ if (m_data && m_data->ref == 1) {
+ m_limit = m_start + m_data->capacity;
+ return;
+ }
+
+ // Allocate a new block on the heap and copy the data across.
+ int size = m_end - m_start;
+ int capacity = qArrayAllocMore(size, 0, sizeof(T));
+ m_data = copyData(m_start, size, capacity);
+
+ // Update the start/end/append pointers for faster updates.
+ m_start = m_data->array;
+ m_end = m_start + size;
+ m_limit = m_start + capacity;
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::assign(const QArray<T, PreallocSize> &other)
+{
+ if (other.m_data) {
+ m_start = other.m_start;
+ m_end = other.m_end;
+ m_data = other.m_data;
+ m_data->ref.ref();
+
+ // We set the append limit of both objects to m_start, which forces
+ // the next append() or data() in either object to copy-on-write.
+ other.m_limit = m_limit = m_start;
+ } else if (other.isPrealloc(other.m_start)) {
+ // Make a deep copy of preallocated data.
+ initPrealloc();
+ m_data = 0;
+ append(other.constData(), other.size());
+ } else {
+ // Shallow copy of raw data.
+ m_start = other.m_start;
+ m_end = other.m_end;
+ m_limit = other.m_limit;
+ m_data = 0;
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::grow(int needed)
+{
+ int size = m_end - m_start;
+ int capacity = qArrayAllocMore(size, needed, sizeof(T));
+ if (!m_data || m_data->ref != 1) {
+ // Copy preallocated, raw, or shared data and expand the capacity.
+ Data *data = copyData(m_start, size, capacity);
+ if (this->isPrealloc(m_start))
+ free(m_start, size);
+ if (m_data)
+ m_data->ref.deref();
+ m_data = data;
+ m_start = data->array;
+ m_end = m_start + size;
+ m_limit = m_start + capacity;
+ } else if ((size + needed) > m_data->capacity) {
+ // Reallocate to create more capacity.
+ reallocate(capacity);
+ } else {
+ // We have enough capacity - just fix the append limit.
+ // This can happen when an array is copied and then the
+ // copy is removed.
+ m_limit = m_start + m_data->capacity;
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::setSize(int size)
+{
+ if (size <= PreallocSize) {
+ initPrealloc();
+ m_data = 0;
+ } else {
+ int capacity = qArrayAllocMore(size, 0, sizeof(T));
+ Data *data = reinterpret_cast<Data *>
+ (qMalloc(sizeof(Data) + sizeof(T) * (capacity - 1)));
+ Q_CHECK_PTR(data);
+ m_data = data;
+ m_data->ref = 1;
+ m_data->capacity = capacity;
+ m_start = m_data->array;
+ m_end = m_start;
+ m_limit = m_start + capacity;
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize>::QArray()
+{
+ initPrealloc();
+ m_data = 0;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize>::QArray(int size)
+{
+ setSize(size);
+ while (size-- > 0)
+ new (m_end++) T();
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize>::QArray(int size, const T &value)
+{
+ setSize(size);
+ while (size-- > 0)
+ new (m_end++) T(value);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize>::QArray(const T *values, int size)
+{
+ setSize(size);
+ while (size-- > 0)
+ new (m_end++) T(*values++);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize>::QArray(const QArray<T, PreallocSize> &other)
+{
+ assign(other);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize>::QArray(const T *data, int size, bool isWritable)
+{
+ // Constructing a raw data array.
+ m_start = const_cast<T *>(data);
+ m_end = m_start + size;
+ if (isWritable)
+ m_limit = m_end;
+ else
+ m_limit = m_start;
+ m_data = 0;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize>::~QArray()
+{
+ release();
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> &QArray<T, PreallocSize>::operator=(const QArray<T, PreallocSize> &other)
+{
+ if (this == &other)
+ return *this;
+ if (other.m_data && m_data == other.m_data)
+ return *this;
+ release();
+ assign(other);
+ return *this;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE int QArray<T, PreallocSize>::size() const
+{
+ return m_end - m_start;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE int QArray<T, PreallocSize>::count() const
+{
+ return m_end - m_start;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE int QArray<T, PreallocSize>::capacity() const
+{
+ if (m_data)
+ return m_data->capacity;
+ else if (this->isPrealloc(m_start))
+ return PreallocSize;
+ else
+ return m_end - m_start; // raw data, m_limit == m_start
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE bool QArray<T, PreallocSize>::isEmpty() const
+{
+ return m_start == m_end;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE bool QArray<T, PreallocSize>::isDetached() const
+{
+ // If m_limit is the same as m_start, then the array
+ // is either shared or contains raw data.
+ return m_limit != m_start;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::detach()
+{
+ if (m_limit == m_start)
+ detach_helper();
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::clear()
+{
+ release();
+ initPrealloc();
+ m_data = 0;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE const T &QArray<T, PreallocSize>::operator[](int index) const
+{
+ Q_ASSERT_X(index >= 0 && index < size(),
+ "QArray<T>::at", "index out of range");
+ return m_start[index];
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE const T &QArray<T, PreallocSize>::at(int index) const
+{
+ Q_ASSERT_X(index >= 0 && index < size(),
+ "QArray<T>::operator[]", "index out of range");
+ return m_start[index];
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE T &QArray<T, PreallocSize>::operator[](int index)
+{
+ Q_ASSERT_X(index >= 0 && index < size(),
+ "QArray<T>::operator[]", "index out of range");
+ return data()[index];
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE T QArray<T, PreallocSize>::value(int index) const
+{
+ if (index >= 0 && index < size())
+ return m_start[index];
+ else
+ return T();
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE T QArray<T, PreallocSize>::value(int index, const T &defaultValue) const
+{
+ if (index >= 0 && index < size())
+ return m_start[index];
+ else
+ return defaultValue;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE T *QArray<T, PreallocSize>::extend(int size)
+{
+ Q_ASSERT(size > 0);
+ if ((m_end + size) >= m_limit)
+ grow(size);
+ T *end = m_end;
+ m_end += size; // Note: new elements are not initialized.
+ return end;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::append(const T &value)
+{
+ if (m_end >= m_limit)
+ grow(1);
+ new (m_end) T(value);
+ ++m_end;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::append(const T &value1, const T &value2)
+{
+ if ((m_end + 1) >= m_limit)
+ grow(2);
+ new (m_end) T(value1);
+ ++m_end; // Increment one at a time in case an exception is thrown.
+ new (m_end) T(value2);
+ ++m_end;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::append(const T &value1, const T &value2, const T &value3)
+{
+ if ((m_end + 2) >= m_limit)
+ grow(3);
+ new (m_end) T(value1);
+ ++m_end;
+ new (m_end) T(value2);
+ ++m_end;
+ new (m_end) T(value3);
+ ++m_end;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::append(const T &value1, const T &value2, const T &value3, const T &value4)
+{
+ if ((m_end + 3) >= m_limit)
+ grow(4);
+ new (m_end) T(value1);
+ ++m_end;
+ new (m_end) T(value2);
+ ++m_end;
+ new (m_end) T(value3);
+ ++m_end;
+ new (m_end) T(value4);
+ ++m_end;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::append(const T *values, int count)
+{
+ if (count <= 0)
+ return;
+ if (!m_start || (m_end + count) > m_limit)
+ grow(count);
+ while (count-- > 0) {
+ new (m_end) T(*values++);
+ ++m_end;
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::append(const QArray<T, PreallocSize> &other)
+{
+ if (isEmpty()) {
+ *this = other;
+ } else {
+ if (&other == this || (m_data && other.m_data == m_data))
+ grow(size()); // Appending to ourselves: make some room.
+ append(other.constData(), other.size());
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::prepend(const T &value)
+{
+ insert(begin(), 1, value);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::insert(int index, const T &value)
+{
+ Q_ASSERT_X(index >= 0 && index <= size(),
+ "QArray<T>::insert", "index out of range");
+ insert(begin() + index, 1, value);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::insert(int index, int count, const T &value)
+{
+ Q_ASSERT_X(index >= 0 && index <= size(),
+ "QArray<T>::insert", "index out of range");
+ insert(begin() + index, count, value);
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE Q_TYPENAME QArray<T, PreallocSize>::iterator QArray<T, PreallocSize>::insert(iterator before, int count, const T &value)
+{
+ // Check the parameters.
+ int size = this->size();
+ int offset = int(before - m_start);
+ Q_ASSERT_X(offset >= 0 && offset <= size,
+ "QArray<T>::insert", "iterator offset is out of range");
+ Q_ASSERT(count >= 0);
+ if (count <= 0)
+ return m_start + offset;
+
+ // Reserve extra space and then copy-on-write.
+ reserve(size + count);
+ detach();
+
+ // Move items up to make room, and replace at the insert point.
+ if (QTypeInfo<T>::isStatic) {
+ int newcount = count;
+ while (newcount > 0) {
+ new (m_end++) T();
+ --newcount;
+ }
+ int posn = size;
+ while (posn > offset) {
+ --posn;
+ m_start[posn + count] = m_start[posn];
+ }
+ while (count > 0) {
+ --count;
+ m_start[offset + count] = value;
+ }
+ } else {
+ ::memmove(m_start + offset + count, m_start + offset,
+ (size - offset) * sizeof(T));
+ m_end += count;
+ while (count > 0) {
+ --count;
+ new (m_start + offset + count) T(value);
+ }
+ }
+
+ // Return the new iterator at the insert position.
+ return m_start + offset;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE Q_TYPENAME QArray<T, PreallocSize>::iterator QArray<T, PreallocSize>::insert(iterator before, const T &value)
+{
+ return insert(before, 1, value);
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::replace(int index, const T &value)
+{
+ Q_ASSERT_X(index >= 0 && index < size(),
+ "QArray<T>::replace", "index out of range");
+ data()[index] = value;
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::replace(int index, const T *values, int count)
+{
+ if (index < 0 || count <= 0)
+ return;
+ int replaceSize = index + count;
+ if (replaceSize > size())
+ resize(replaceSize);
+ copyReplace(data() + index, values, count);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::remove(int index)
+{
+ remove(index, 1);
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::remove(int index, int count)
+{
+ // Truncate the range to be removed.
+ int currentSize = size();
+ if (index < 0) {
+ count += index;
+ index = 0;
+ }
+ if (count > 0 && (index + count) > currentSize)
+ count = currentSize - index;
+ if (count <= 0)
+ return;
+
+ // Perform the removal.
+ if (index == 0 && count >= currentSize) {
+ clear();
+ return;
+ }
+ T *start = data();
+ copyReplace(start + index, start + index + count,
+ (currentSize - (index + count)));
+ resize(currentSize - count);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE Q_TYPENAME QArray<T, PreallocSize>::iterator QArray<T, PreallocSize>::erase(iterator begin, iterator end)
+{
+ int index = begin - m_start;
+ remove(index, end - begin);
+ return m_start + index;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE Q_TYPENAME QArray<T, PreallocSize>::iterator QArray<T, PreallocSize>::erase(iterator pos)
+{
+ int index = pos - m_start;
+ remove(index, 1);
+ return m_start + index;
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE int QArray<T, PreallocSize>::indexOf(const T &value, int from) const
+{
+ if (from < 0)
+ from = qMax(from + size(), 0);
+ const T *ptr = m_start + from;
+ while (ptr < m_end) {
+ if (*ptr == value)
+ return ptr - m_start;
+ ++ptr;
+ }
+ return -1;
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE int QArray<T, PreallocSize>::lastIndexOf(const T &value, int from) const
+{
+ int size = count();
+ if (from < 0)
+ from += size;
+ else if (from >= size)
+ from = size - 1;
+ if (from >= 0) {
+ const T *ptr = m_start + from;
+ while (ptr >= m_start) {
+ if (*ptr == value)
+ return ptr - m_start;
+ --ptr;
+ }
+ }
+ return -1;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE bool QArray<T, PreallocSize>::contains(const T &value) const
+{
+ const T *ptr = m_start;
+ while (ptr < m_end) {
+ if (*ptr == value)
+ return true;
+ ++ptr;
+ }
+ return false;
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE int QArray<T, PreallocSize>::count(const T &value) const
+{
+ const T *ptr = m_start;
+ int count = 0;
+ while (ptr < m_end) {
+ if (*ptr == value)
+ ++count;
+ ++ptr;
+ }
+ return count;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::resize(int size)
+{
+ if (size < 0)
+ return;
+ int currentSize = count();
+ if (size < currentSize) {
+ T *start = data(); // Force copy on write if necessary.
+ if (QTypeInfo<T>::isComplex)
+ free(start + size, currentSize - size);
+ m_end = start + size;
+ } else if (size > currentSize) {
+ grow(size - currentSize);
+ while (currentSize++ < size) {
+ new (m_end) T();
+ ++m_end;
+ }
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE void QArray<T, PreallocSize>::reserve(int size)
+{
+ int cap = capacity();
+ if (size > cap)
+ grow(size - this->size());
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE QArray<T, PreallocSize> &QArray<T, PreallocSize>::fill(const T &value, int size)
+{
+ if (size >= 0)
+ resize(size);
+ T *ptr = m_start;
+ while (ptr < m_end)
+ *ptr++ = value;
+ return *this;
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::squeeze()
+{
+ int size = count();
+ if (size <= 0) {
+ clear();
+ } else if (size < capacity() && m_data) {
+ reallocate(size);
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE void QArray<T, PreallocSize>::reverse()
+{
+ if (count() > 0) {
+ T *src = m_start;
+ T *dst = m_end - 1;
+ while (src < dst)
+ qSwap(*(dst--), *(src++));
+ }
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE QArray<T, PreallocSize> QArray<T, PreallocSize>::reversed() const
+{
+ QArray<T, PreallocSize> result;
+ int count = size();
+ if (count > 0) {
+ result.extend(count);
+ const T *src = m_start;
+ T *dst = result.m_end - 1;
+ if (!QTypeInfo<T>::isComplex) {
+ while (src != m_end)
+ *(dst--) = *(src++);
+ } else {
+ while (src != m_end)
+ new (dst--) T(*src++);
+ }
+ }
+ return result;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> QArray<T, PreallocSize>::mid(int index, int length) const
+{
+ int count = size();
+ Q_ASSERT(index >= 0 && index <= count);
+ if (length < 0 || (index + length) > count)
+ length = count - index;
+ if (index == 0 && length == count)
+ return *this;
+ QArray<T, PreallocSize> result;
+ result.append(constData() + index, length);
+ return result;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> QArray<T, PreallocSize>::left(int length) const
+{
+ return mid(0, length);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> QArray<T, PreallocSize>::right(int length) const
+{
+ int size = count();
+ if (length < 0 || length >= size)
+ length = size;
+ return mid(size - length, length);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE T *QArray<T, PreallocSize>::data()
+{
+ detach();
+ return m_start;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE const T *QArray<T, PreallocSize>::data() const
+{
+ return m_start;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE const T *QArray<T, PreallocSize>::constData() const
+{
+ return m_start;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> QArray<T, PreallocSize>::fromRawData(const T *data, int size)
+{
+ Q_ASSERT(size >= 0);
+ return QArray<T, PreallocSize>(data, size, false);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> QArray<T, PreallocSize>::fromWritableRawData(T *data, int size)
+{
+ Q_ASSERT(size >= 0);
+ return QArray<T, PreallocSize>(data, size, true);
+}
+
+template <typename T, int PreallocSize>
+Q_OUTOFLINE_TEMPLATE bool QArray<T, PreallocSize>::operator==
+ (const QArray<T, PreallocSize> &other) const
+{
+ if (this == &other)
+ return true;
+ const T *thisData = constData();
+ const T *otherData = other.constData();
+ if (thisData == otherData)
+ return true;
+ int thisCount = count();
+ int otherCount = other.count();
+ if (thisCount == 0 && otherCount == 0)
+ return true;
+ if (thisCount != otherCount)
+ return false;
+ for (int index = 0; index < thisCount; ++index, ++thisData, ++otherData)
+ if (*thisData != *otherData)
+ return false;
+ return true;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE bool QArray<T, PreallocSize>::operator!=
+ (const QArray<T, PreallocSize> &other) const
+{
+ return !(*this == other);
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> &QArray<T, PreallocSize>::operator+=(const T &value)
+{
+ append(value);
+ return *this;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> &QArray<T, PreallocSize>::operator+=(const QArray<T, PreallocSize> &other)
+{
+ append(other);
+ return *this;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> &QArray<T, PreallocSize>::operator<<(const T &value)
+{
+ append(value);
+ return *this;
+}
+
+template <typename T, int PreallocSize>
+Q_INLINE_TEMPLATE QArray<T, PreallocSize> &QArray<T, PreallocSize>::operator<<(const QArray<T, PreallocSize> &other)
+{
+ append(other);
+ return *this;
+}
+
+#ifndef QT_NO_DATASTREAM
+
+template <typename T, int PreallocSize>
+QDataStream& operator<<(QDataStream& stream, const QArray<T, PreallocSize>& array)
+{
+ int size = array.size();
+ stream << quint32(size);
+ for (int index = 0; index < size; ++index)
+ stream << array.at(index);
+ return stream;
+}
+
+template <typename T, int PreallocSize>
+QDataStream& operator>>(QDataStream& stream, QArray<T, PreallocSize>& array)
+{
+ array.clear();
+ quint32 size;
+ stream >> size;
+ array.reserve(size);
+ for (int index = 0; index < int(size); ++index) {
+ T t;
+ stream >> t;
+ array.append(t);
+ if (stream.atEnd())
+ break;
+ }
+ return stream;
+}
+
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+
+template <typename T, int PreallocSize>
+QDebug operator<<(QDebug dbg, const QArray<T, PreallocSize>& array)
+{
+ dbg.nospace() << "QArray(\n";
+ int size = array.size();
+ for (int index = 0; index < size; ++index) {
+ dbg << " " << index << ": " << array.at(index) << "\n";
+ }
+ dbg << ")\n";
+ return dbg.space();
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qcolor4ub.cpp b/src/threed/arrays/qcolor4ub.cpp
new file mode 100644
index 000000000..9a26e6ed4
--- /dev/null
+++ b/src/threed/arrays/qcolor4ub.cpp
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcolor4ub.h"
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QColor4ub
+ \brief The QColor4ub class represents a color by four unsigned byte components.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ OpenGL applications commonly use four unsigned byte values to compactly
+ represent a color value. QColor4ub provides a convenience
+ class for manipulating such compact color values.
+
+ An alternative is to represent a color value as four floating-point
+ values between 0.0 and 1.0. The QVector4D class can be used for
+ that purpose if required.
+*/
+
+/*!
+ \fn QColor4ub::QColor4ub()
+
+ Constructs a four-byte default color value of (0, 0, 0, 255).
+*/
+
+/*!
+ \fn QColor4ub::QColor4ub(int red, int green, int blue, int alpha)
+
+ Constructs a four-byte color value with the components \a red,
+ \a green, \a blue, and \a alpha.
+*/
+
+/*!
+ \fn QColor4ub::QColor4ub(const QColor& color)
+
+ Constructs a four-byte color value from \a color.
+*/
+
+/*!
+ \fn QColor4ub::QColor4ub(Qt::GlobalColor color)
+
+ Constructs a four-byte color value from \a color.
+*/
+
+/*!
+ \fn QColor4ub::QColor4ub(QRgb rgba)
+
+ Constructs a four-byte color value from the red, green, blue, and
+ alpha components of \a rgba.
+*/
+
+/*!
+ \fn QColor4ub& QColor4ub::operator=(const QColor& color)
+
+ Copies the red, green, blue, and alpha components of \a color
+ into this object.
+*/
+
+/*!
+ \fn QColor4ub& QColor4ub::operator=(Qt::GlobalColor color)
+
+ Copies the red, green, blue, and alpha components of the
+ specified global \a color name into this object.
+*/
+
+/*!
+ \fn int QColor4ub::red() const
+
+ Returns the red component of this color, between 0 and 255.
+
+ \sa green(), blue(), alpha(), setRed(), redF()
+*/
+
+/*!
+ \fn int QColor4ub::green() const
+
+ Returns the green component of this color, between 0 and 255.
+
+ \sa red(), blue(), alpha(), setGreen(), greenF()
+*/
+
+/*!
+ \fn int QColor4ub::blue() const
+
+ Returns the blue component of this color, between 0 and 255.
+
+ \sa red(), green(), alpha(), setBlue(), blueF()
+*/
+
+/*!
+ \fn int QColor4ub::alpha() const
+
+ Returns the alpha component of this color, between 0 and 255.
+
+ \sa red(), green(), blue(), setAlpha(), alphaF()
+*/
+
+/*!
+ \fn void QColor4ub::setRed(int value)
+
+ Sets the red component of this color to \a value, between 0 and 255.
+
+ \sa setGreen(), setBlue(), setAlpha(), red(), setRedF()
+*/
+
+/*!
+ \fn void QColor4ub::setGreen(int value)
+
+ Sets the green component of this color to \a value, between 0 and 255.
+
+ \sa setRed(), setBlue(), setAlpha(), green(), setGreenF()
+*/
+
+/*!
+ \fn void QColor4ub::setBlue(int value)
+
+ Sets the blue component of this color to \a value, between 0 and 255.
+
+ \sa setRed(), setGreen(), setAlpha(), blue(), setBlueF()
+*/
+
+/*!
+ \fn void QColor4ub::setAlpha(int value)
+
+ Sets the alpha component of this color to \a value, between 0 and 255.
+
+ \sa setRed(), setGreen(), setBlue(), alpha(), setAlphaF()
+*/
+
+/*!
+ \fn qreal QColor4ub::redF() const { return m_red / 255.0f; }
+
+ Returns the red component of this color as a floating-point
+ value between 0 and 1.
+
+ \sa greenF(), blueF(), alphaF(), setRedF(), red()
+*/
+
+/*!
+ \fn qreal QColor4ub::greenF() const { return m_green / 255.0f; }
+
+ Returns the green component of this color as a floating-point
+ value between 0 and 1.
+
+ \sa redF(), blueF(), alphaF(), setGreenF(), green()
+*/
+
+/*!
+ \fn qreal QColor4ub::blueF() const { return m_blue / 255.0f; }
+
+ Returns the blue component of this color as a floating-point
+ value between 0 and 1.
+
+ \sa redF(), greenF(), alphaF(), setBlueF(), blue()
+*/
+
+/*!
+ \fn qreal QColor4ub::alphaF() const { return m_alpha / 255.0f; }
+
+ Returns the alpha component of this color as a floating-point
+ value between 0 and 1.
+
+ \sa redF(), greenF(), blueF(), setAlphaF(), alpha()
+*/
+
+/*!
+ \fn void QColor4ub::setRedF(qreal value)
+
+ Sets the red component of this color to a floating-point \a value,
+ between 0 and 1.
+
+ \sa setGreenF(), setBlueF(), setAlphaF(), redF(), setRed()
+*/
+
+/*!
+ \fn void QColor4ub::setGreenF(qreal value)
+
+ Sets the green component of this color to a floating-point \a value,
+ between 0 and 1.
+
+ \sa setRedF(), setBlueF(), setAlphaF(), greenF(), setGreen()
+*/
+
+/*!
+ \fn void QColor4ub::setBlueF(qreal value)
+
+ Sets the blue component of this color to a floating-point \a value,
+ between 0 and 1.
+
+ \sa setRedF(), setGreenF(), setAlphaF(), blueF(), setBlue()
+*/
+
+/*!
+ \fn void QColor4ub::setAlphaF(qreal value)
+
+ Sets the alpha component of this color to a floating-point \a value,
+ between 0 and 1.
+
+ \sa setRedF(), setGreenF(), setBlueF(), alphaF(), setAlpha()
+*/
+
+/*!
+ \fn void QColor4ub::setRgb(int red, int green, int blue, int alpha)
+
+ Sets the components of this color to \a red, \a green, \a blue,
+ and \a alpha. Each component is between 0 and 255.
+
+ \sa setRgbF(), fromRgb()
+*/
+
+/*!
+ \fn void QColor4ub::setRgbF(qreal red, qreal green, qreal blue, qreal alpha)
+
+ Sets the components of this color to \a red, \a green, \a blue,
+ and \a alpha. Each component is a floating-point value between 0 and 1.
+
+ \sa setRgb(), fromRgbF()
+*/
+
+/*!
+ \fn QColor4ub QColor4ub::fromRgb(int red, int green, int blue, int alpha)
+
+ Returns a QColor4ub with the components \a red, \a green, \a blue,
+ and \a alpha. Each component is between 0 and 255.
+
+ \sa fromRgbF(), setRgb()
+*/
+
+/*!
+ \fn QColor4ub QColor4ub::fromRgbF(qreal red, qreal green, qreal blue, qreal alpha)
+
+ Returns a QColor4ub with the components \a red, \a green, \a blue,
+ and \a alpha. Each component is a floating-point value between 0 and 1.
+
+ \sa fromRgb(), setRgbF()
+*/
+
+/*!
+ \fn QColor4ub QColor4ub::fromRaw(const uchar *data)
+
+ Returns a QColor4ub with components from the first four elements
+ in \a data. The \a data parameter must contain at least four
+ elements and not be null.
+*/
+
+/*!
+ \fn QColor QColor4ub::toColor() const
+
+ Returns this color as a QColor.
+*/
+
+/*!
+ \fn bool QColor4ub::operator==(const QColor4ub& other) const
+
+ Returns true if this color is the same as \a other; false otherwise.
+*/
+
+/*!
+ \fn bool QColor4ub::operator!=(const QColor4ub& other) const
+
+ Returns true if this color is not the same as \a other; false otherwise.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QColor4ub &color)
+{
+ dbg.nospace() << "QColor4ub("
+ << color.redF() << ", " << color.greenF() << ", "
+ << color.blueF() << ", " << color.alphaF() << ')';
+ return dbg.space();
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qcolor4ub.h b/src/threed/arrays/qcolor4ub.h
new file mode 100644
index 000000000..3ec27ba20
--- /dev/null
+++ b/src/threed/arrays/qcolor4ub.h
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOLOR4UB_H
+#define QCOLOR4UB_H
+
+#include "qt3dglobal.h"
+#include <QtGui/qcolor.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QColor4ub
+{
+public:
+ QColor4ub();
+ QColor4ub(int red, int green, int blue, int alpha = 255);
+ QColor4ub(const QColor& color);
+ QColor4ub(Qt::GlobalColor color);
+ QColor4ub(QRgb rgba);
+
+ QColor4ub& operator=(const QColor& color);
+ QColor4ub& operator=(Qt::GlobalColor color);
+
+ int red() const { return m_red; }
+ int green() const { return m_green; }
+ int blue() const { return m_blue; }
+ int alpha() const { return m_alpha; }
+
+ void setRed(int value) { m_red = uchar(value); }
+ void setGreen(int value) { m_green = uchar(value); }
+ void setBlue(int value) { m_blue = uchar(value); }
+ void setAlpha(int value) { m_alpha = uchar(value); }
+
+ qreal redF() const { return m_red / 255.0f; }
+ qreal greenF() const { return m_green / 255.0f; }
+ qreal blueF() const { return m_blue / 255.0f; }
+ qreal alphaF() const { return m_alpha / 255.0f; }
+
+ void setRedF(qreal value) { m_red = uchar(qRound(value * 255.0f)); }
+ void setGreenF(qreal value) { m_green = uchar(qRound(value * 255.0f)); }
+ void setBlueF(qreal value) { m_blue = uchar(qRound(value * 255.0f)); }
+ void setAlphaF(qreal value) { m_alpha = uchar(qRound(value * 255.0f)); }
+
+ void setRgb(int red, int green, int blue, int alpha = 255);
+ void setRgbF(qreal red, qreal green, qreal blue, qreal alpha = 1.0f);
+
+ static QColor4ub fromRgb(int red, int green, int blue, int alpha = 255);
+ static QColor4ub fromRgbF
+ (qreal red, qreal green, qreal blue, qreal alpha = 1.0f);
+ static QColor4ub fromRaw(const uchar *data);
+
+ QColor toColor() const;
+
+ bool operator==(const QColor4ub& other) const;
+ bool operator!=(const QColor4ub& other) const;
+
+private:
+ QColor4ub(const uchar *data);
+
+ uchar m_red;
+ uchar m_green;
+ uchar m_blue;
+ uchar m_alpha;
+};
+
+inline QColor4ub::QColor4ub() : m_red(0), m_green(0), m_blue(0), m_alpha(255) {}
+
+inline QColor4ub::QColor4ub(int red, int green, int blue, int alpha)
+ : m_red(uchar(red)), m_green(uchar(green)),
+ m_blue(uchar(blue)), m_alpha(uchar(alpha)) {}
+
+inline QColor4ub::QColor4ub(const QColor& color)
+ : m_red(uchar(color.red())), m_green(uchar(color.green())),
+ m_blue(uchar(color.blue())), m_alpha(uchar(color.alpha())) {}
+
+inline QColor4ub::QColor4ub(Qt::GlobalColor color)
+{
+ QColor c(color);
+ m_red = uchar(c.red());
+ m_green = uchar(c.green());
+ m_blue = uchar(c.blue());
+ m_alpha = uchar(c.alpha());
+}
+
+inline QColor4ub::QColor4ub(QRgb rgba)
+ : m_red(uchar(qRed(rgba))), m_green(uchar(qGreen(rgba))),
+ m_blue(uchar(qBlue(rgba))), m_alpha(uchar(qAlpha(rgba))) {}
+
+inline QColor4ub::QColor4ub(const uchar *data)
+ : m_red(data[0]), m_green(data[1]), m_blue(data[2]), m_alpha(data[3]) {}
+
+inline QColor4ub& QColor4ub::operator=(const QColor& color)
+{
+ m_red = uchar(color.red());
+ m_green = uchar(color.green());
+ m_blue = uchar(color.blue());
+ m_alpha = uchar(color.alpha());
+ return *this;
+}
+
+inline QColor4ub& QColor4ub::operator=(Qt::GlobalColor color)
+{
+ QColor c(color);
+ m_red = uchar(c.red());
+ m_green = uchar(c.green());
+ m_blue = uchar(c.blue());
+ m_alpha = uchar(c.alpha());
+ return *this;
+}
+
+inline void QColor4ub::setRgb(int red, int green, int blue, int alpha)
+{
+ m_red = uchar(red);
+ m_green = uchar(green);
+ m_blue = uchar(blue);
+ m_alpha = uchar(alpha);
+}
+
+inline void QColor4ub::setRgbF(qreal red, qreal green, qreal blue, qreal alpha)
+{
+ m_red = uchar(qRound(red * 255.0f));
+ m_green = uchar(qRound(green * 255.0f));
+ m_blue = uchar(qRound(blue * 255.0f));
+ m_alpha = uchar(qRound(alpha * 255.0f));
+}
+
+inline QColor4ub QColor4ub::fromRgb(int red, int green, int blue, int alpha)
+{
+ return QColor4ub(red, green, blue, alpha);
+}
+
+inline QColor4ub QColor4ub::fromRgbF
+ (qreal red, qreal green, qreal blue, qreal alpha)
+{
+ return QColor4ub(qRound(red * 255.0f), qRound(green * 255.0f),
+ qRound(blue * 255.0f), qRound(alpha * 255.0f));
+}
+
+inline QColor4ub QColor4ub::fromRaw(const uchar *data)
+{
+ return QColor4ub(data);
+}
+
+inline QColor QColor4ub::toColor() const
+{
+ return QColor(m_red, m_green, m_blue, m_alpha);
+}
+
+inline bool QColor4ub::operator==(const QColor4ub& other) const
+{
+ return m_red == other.m_red && m_green == other.m_green &&
+ m_blue == other.m_blue && m_alpha == other.m_alpha;
+}
+
+inline bool QColor4ub::operator!=(const QColor4ub& other) const
+{
+ return m_red != other.m_red || m_green != other.m_green ||
+ m_blue != other.m_blue || m_alpha != other.m_alpha;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QColor4ub &color);
+#endif
+
+Q_DECLARE_TYPEINFO(QColor4ub, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QColor4ub)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qcustomdataarray.cpp b/src/threed/arrays/qcustomdataarray.cpp
new file mode 100644
index 000000000..f34793af7
--- /dev/null
+++ b/src/threed/arrays/qcustomdataarray.cpp
@@ -0,0 +1,909 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcustomdataarray.h"
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QCustomDataArray
+ \brief The QCustomDataArray class is a polymorphic array of data values suitable for use in 3D applications.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ QArray is an efficient storage mechanism for vertex attributes.
+ However, there are some situations where the element type of a custom
+ vertex attribute is not known until runtime. QCustomDataArray is
+ intended for use in those situations. It has a small performance
+ penalty compared to QArray to achieve polymorphism.
+
+ The elements that may be stored in a QCustomDataArray are limited
+ to a few types: float, QVector2D, QVector3D, QVector4D, and
+ QColor4ub. This provides a reasonable range of efficient use
+ cases without overloading the API. QArray can be used on
+ any type, but is restricted to types that are known at compile time.
+
+ Like QArray, QCustomDataArray uses implicit sharing and
+ copy-on-write semantics to support passing large arrays around
+ an application with little overhead.
+
+ \sa QArray
+*/
+
+/*!
+ \enum QCustomDataArray::ElementType
+ This enum defines the element type within a QCustomDataArray.
+
+ \value Float The elements are of type float.
+ \value Vector2D The elements are of type QVector2D.
+ \value Vector3D The elements are of type QVector3D.
+ \value Vector4D The elements are of type QVector4D.
+ \value Color The elements are of type QColor4ub, which consists of
+ four unsigned bytes. To represent colors as four floating-point
+ values, use Vector4D as the element type.
+*/
+
+/*!
+ \fn QCustomDataArray::QCustomDataArray()
+
+ Constructs an empty custom data array. The elementType() will
+ initially be QCustomDataArray::Float, which can be changed with a
+ call to setElementType() before the elements are appended.
+
+ \sa setElementType(), append()
+*/
+
+/*!
+ Constructs an empty custom data array with elements represented
+ by the specified \a type.
+
+ \sa setElementType()
+*/
+QCustomDataArray::QCustomDataArray(QCustomDataArray::ElementType type)
+{
+ setElementType(type);
+}
+
+/*!
+ Constructs an empty custom data array with elements represented
+ by the specified \a type. The array is initially resized to \a size;
+ filling all elements with zeroes.
+
+ \sa setElementType(), resize()
+*/
+QCustomDataArray::QCustomDataArray(QCustomDataArray::ElementType type, int size)
+{
+ setElementType(type);
+ resize(size);
+}
+
+/*!
+ \fn QCustomDataArray::QCustomDataArray(const QCustomDataArray& other)
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ Constructs a copy of the floating-point QArray \a other.
+
+ The elementType() will be set to QCustomDataArray::Float.
+
+ \sa toFloatArray()
+*/
+QCustomDataArray::QCustomDataArray(const QArray<float>& other)
+ : m_array(other),
+ m_elementType(QCustomDataArray::Float),
+ m_elementComponents(1)
+{
+}
+
+/*!
+ Constructs a copy of the 2D vector QArray \a other.
+
+ The elementType() will be set to QCustomDataArray::Vector2D.
+
+ This constructor needs to make a complete copy of the data
+ in \a other so it may be expensive performance-wise.
+
+ \sa toVector2DArray()
+*/
+QCustomDataArray::QCustomDataArray(const QArray<QVector2D>& other)
+ : m_elementType(QCustomDataArray::Vector2D),
+ m_elementComponents(2)
+{
+ int size = other.size();
+ if (size > 0) {
+ const QVector2D *src = other.constData();
+ float *dst = m_array.extend(size * 2);
+ qMemCopy(dst, src, size * sizeof(QVector2D));
+ }
+}
+
+/*!
+ Constructs a copy of the 3D vector QArray \a other.
+
+ The elementType() will be set to QCustomDataArray::Vector3D.
+
+ This constructor needs to make a complete copy of the data
+ in \a other so it may be expensive performance-wise.
+
+ \sa toVector3DArray()
+*/
+QCustomDataArray::QCustomDataArray(const QArray<QVector3D>& other)
+ : m_elementType(QCustomDataArray::Vector3D),
+ m_elementComponents(3)
+{
+ int size = other.size();
+ if (size > 0) {
+ const QVector3D *src = other.constData();
+ float *dst = m_array.extend(size * 3);
+ qMemCopy(dst, src, size * sizeof(QVector3D));
+ }
+}
+
+/*!
+ Constructs a copy of the 4D vector QArray \a other.
+
+ The elementType() will be set to QCustomDataArray::Vector4D.
+
+ This constructor needs to make a complete copy of the data
+ in \a other so it may be expensive performance-wise.
+
+ \sa toVector3DArray()
+*/
+QCustomDataArray::QCustomDataArray(const QArray<QVector4D>& other)
+ : m_elementType(QCustomDataArray::Vector4D),
+ m_elementComponents(4)
+{
+ int size = other.size();
+ if (size > 0) {
+ const QVector4D *src = other.constData();
+ float *dst = m_array.extend(size * 4);
+ qMemCopy(dst, src, size * sizeof(QVector4D));
+ }
+}
+
+/*!
+ Constructs a copy of the color QArray \a other.
+
+ The elementType() will be set to QCustomDataArray::Color.
+
+ This constructor needs to make a complete copy of the data
+ in \a other so it may be expensive performance-wise.
+
+ \sa toColorArray()
+*/
+QCustomDataArray::QCustomDataArray(const QArray<QColor4ub>& other)
+ : m_elementType(QCustomDataArray::Color),
+ m_elementComponents(1)
+{
+ int size = other.size();
+ qMemCopy(m_array.extend(size), other.constData(), sizeof(QColor4ub) * size);
+}
+
+/*!
+ \fn QCustomDataArray::~QCustomDataArray()
+
+ Destroys this custom data array.
+*/
+
+/*!
+ \fn QCustomDataArray& QCustomDataArray::operator=(const QCustomDataArray& other)
+
+ Assigns \a other to this custom data array and returns a reference
+ to this custom data array.
+
+ The previous elementType() for this custom data array will be
+ replaced with the type from \a other. The element data is assigned
+ directly without conversion.
+*/
+
+/*!
+ \fn QCustomDataArray::ElementType QCustomDataArray::elementType() const
+
+ Returns the representation type of elements in this custom data array.
+
+ \sa setElementType()
+*/
+
+/*!
+ Sets the representation \a type of elements in this custom data array.
+ The array must be empty to change the element type.
+
+ \sa elementType(), append()
+*/
+void QCustomDataArray::setElementType(QCustomDataArray::ElementType type)
+{
+ Q_ASSERT(m_array.isEmpty());
+ m_elementType = type;
+ switch (type) {
+ case QCustomDataArray::Float:
+ m_elementComponents = 1;
+ break;
+ case QCustomDataArray::Vector2D:
+ m_elementComponents = 2;
+ break;
+ case QCustomDataArray::Vector3D:
+ m_elementComponents = 3;
+ break;
+ case QCustomDataArray::Vector4D:
+ m_elementComponents = 4;
+ break;
+ case QCustomDataArray::Color:
+ m_elementComponents = 1; // 4 bytes packed into a float.
+ break;
+ default:
+ Q_ASSERT_X(false, "QCustomDataArray::setElementType",
+ "unknown element type");
+ m_elementComponents = 1;
+ break;
+ }
+}
+
+/*!
+ \fn int QCustomDataArray::size() const
+
+ Returns the number of elements in this custom data array.
+
+ \sa resize(), capacity(), isEmpty()
+*/
+
+/*!
+ \fn int QCustomDataArray::count() const
+
+ Same as size(); provided for convenience.
+*/
+
+/*!
+ \fn int QCustomDataArray::capacity() const
+
+ Returns the number of elements that can be stored in this
+ custom data array before reallocation.
+
+ \sa reserve(), size()
+*/
+
+/*!
+ \fn bool QCustomDataArray::isEmpty() const
+
+ Returns true if this data array is empty; false otherwise.
+
+ \sa size(), clear()
+*/
+
+/*!
+ \fn int QCustomDataArray::elementSize() const
+
+ Returns the size of individual elements in this custom data
+ array, in bytes. For example, the element size of an array
+ containing QVector3D values will be 3 * sizeof(float),
+ normally 12.
+
+ \sa setElementType()
+*/
+
+/*!
+ \fn void QCustomDataArray::clear()
+
+ Clears all elements from this custom data array and sets the size to zero.
+
+ This function will deallocate any memory that is used on the heap
+ to store the custom data array's elements. To reuse the same memory
+ as before, call resize() with an argument of zero.
+
+ \sa resize(), isEmpty()
+*/
+
+/*!
+ \fn void QCustomDataArray::resize(int size)
+
+ Sets the size of the custom data array to \a size. If \a size is greater
+ than the current size, elements are added to the end; the new elements
+ are initialized with all-zeroes. If \a size is less than the current
+ size, elements are removed from the end.
+
+ \sa size(), reserve(), squeeze()
+*/
+
+/*!
+ \fn void QCustomDataArray::reserve(int size)
+
+ Increases the capacity of this custom data array to reserve space for
+ at least \a size elements. If the capacity is already larger
+ than \a size, this function does nothing; in particular, it does
+ not remove elements from the array like resize() does.
+
+ This function can be useful when you know how roughly many elements
+ will be appended ahead of time. Reserving the space once can avoid
+ unnecessary realloc operations later.
+
+ \sa capacity(), resize(), squeeze()
+*/
+
+/*!
+ \fn void QCustomDataArray::squeeze()
+
+ Releases any memory not required to store the custom data array's
+ elements by reducing its capacity() to size().
+
+ This function is intended for reclaiming memory in a custom data
+ array that is being used over and over with different contents.
+ As elements are added to a custom data array, it will be constantly
+ expanded in size. This function can realloc the custom data array
+ to a smaller size to reclaim unused memory.
+
+ \sa reserve(), capacity()
+*/
+
+/*!
+ Returns the value of the element at \a index in this custom
+ data array as a QVariant.
+
+ Color elements are returned as a QVariant containing a
+ QColor4ub, not a QColor.
+
+ \sa setAt(), append(), floatAt(), vector2DAt(), vector3DAt()
+ \sa vector4DAt(), colorAt()
+*/
+QVariant QCustomDataArray::at(int index) const
+{
+ Q_ASSERT(index >= 0 && index < size());
+
+ const float *data;
+ switch (m_elementType) {
+
+ case QCustomDataArray::Float:
+ return QVariant(m_array.at(index));
+
+ case QCustomDataArray::Vector2D:
+ data = m_array.constData() + index * 2;
+ return qVariantFromValue(QVector2D(data[0], data[1]));
+
+ case QCustomDataArray::Vector3D:
+ data = m_array.constData() + index * 3;
+ return qVariantFromValue(QVector3D(data[0], data[1], data[2]));
+
+ case QCustomDataArray::Vector4D:
+ data = m_array.constData() + index * 4;
+ return qVariantFromValue
+ (QVector4D(data[0], data[1], data[2], data[3]));
+
+ case QCustomDataArray::Color:
+ data = m_array.constData() + index;
+ return qVariantFromValue
+ (QColor4ub::fromRaw(reinterpret_cast<const uchar *>(data)));
+
+ default: break;
+ }
+ return QVariant();
+}
+
+/*!
+ Sets the element at \a index in this custom data array to \a value.
+
+ The type of \a value must be consistent with elementType().
+ The two exceptions to this are that a Float value can be
+ specified by either a float or double QVariant, and a Color
+ value can be specified as either a QColor4ub or QColor QVariant.
+
+ \sa at(), elementType()
+*/
+void QCustomDataArray::setAt(int index, const QVariant& value)
+{
+ Q_ASSERT(index >= 0 && index < size());
+
+ switch (value.type()) {
+
+ case (QVariant::Type)QMetaType::Float:
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ m_array[index] = value.toFloat();
+ break;
+
+ case QVariant::Double:
+ // Convert Double into Float.
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ m_array[index] = float(value.toDouble());
+ break;
+
+ case QVariant::Vector2D:
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector2D);
+ *(reinterpret_cast<QVector2D *>(m_array.data() + index * 2))
+ = qVariantValue<QVector2D>(value);
+ break;
+
+ case QVariant::Vector3D:
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector3D);
+ *(reinterpret_cast<QVector3D *>(m_array.data() + index * 3))
+ = qVariantValue<QVector3D>(value);
+ break;
+
+ case QVariant::Vector4D:
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector4D);
+ *(reinterpret_cast<QVector4D *>(m_array.data() + index * 4))
+ = qVariantValue<QVector4D>(value);
+ break;
+
+ case QVariant::Color:
+ // Convert QColor into QColor4ub.
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ *(reinterpret_cast<QColor4ub *>(m_array.data() + index))
+ = QColor4ub(qVariantValue<QColor>(value));
+ break;
+
+ case QVariant::UserType:
+ if (value.userType() == qMetaTypeId<QColor4ub>()) {
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ *(reinterpret_cast<QColor4ub *>(m_array.data() + index))
+ = qVariantValue<QColor4ub>(value);
+ break;
+ }
+ // Fall through.
+
+ default:
+ Q_ASSERT_X(false, "QCustomDataArray::setAt",
+ "QVariant type not supported for elements");
+ break;
+ }
+}
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, qreal x)
+ \overload
+
+ Sets the floating-point element at \a index in this custom data
+ array to \a x. The elementType() must be QCustomDataArray::Float.
+
+ \sa at(), elementType(), floatAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, qreal x, qreal y)
+ \overload
+
+ Sets the 2D vector element at \a index in this custom
+ data array to (\a x, \a y). The elementType() must be
+ QCustomDataArray::Vector2D.
+
+ \sa at(), elementType(), vector2DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, qreal x, qreal y, qreal z)
+ \overload
+
+ Sets the 3D vector element at \a index in this custom
+ data array to (\a x, \a y, \a z). The elementType() must be
+ QCustomDataArray::Vector3D.
+
+ \sa at(), elementType(), vector3DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, qreal x, qreal y, qreal z, qreal w)
+ \overload
+
+ Sets the 4D vector element at \a index in this custom
+ data array to (\a x, \a y, \a z, \a w). The elementType() must be
+ QCustomDataArray::Vector4D.
+
+ \sa at(), elementType(), vector4DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, const QVector2D& value)
+ \overload
+
+ Sets the 2D vector element at \a index in this custom
+ data array to \a value. The elementType() must be
+ QCustomDataArray::Vector2D.
+
+ \sa at(), elementType(), vector2DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, const QVector3D& value)
+ \overload
+
+ Sets the 3D vector element at \a index in this custom
+ data array to \a value. The elementType() must be
+ QCustomDataArray::Vector3D.
+
+ \sa at(), elementType(), vector3DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, const QVector4D& value)
+ \overload
+
+ Sets the 4D vector element at \a index in this custom
+ data array to \a value. The elementType() must be
+ QCustomDataArray::Vector4D.
+
+ \sa at(), elementType(), vector4DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, const QColor4ub& value)
+ \overload
+
+ Sets the color element at \a index in this custom data array to \a value.
+ The elementType() must be QCustomDataArray::Color.
+
+ \sa at(), elementType(), colorAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::setAt(int index, Qt::GlobalColor value)
+ \overload
+
+ Sets the color element at \a index in this custom data array to \a value.
+ The elementType() must be QCustomDataArray::Color.
+
+ \sa at(), elementType(), colorAt()
+*/
+
+/*!
+ \fn qreal QCustomDataArray::floatAt(int index) const
+
+ Returns the floating-point element at \a index in this custom data array.
+ The elementType() must be QCustomDataArray::Float.
+
+ \sa at(), setAt(), elementType()
+*/
+
+/*!
+ \fn QVector2D QCustomDataArray::vector2DAt(int index) const
+
+ Returns the 2D vector element at \a index in this custom data array.
+ The elementType() must be QCustomDataArray::Vector2D.
+
+ \sa at(), setAt(), elementType()
+*/
+
+/*!
+ \fn QVector3D QCustomDataArray::vector3DAt(int index) const
+
+ Returns the 3D vector element at \a index in this custom data array.
+ The elementType() must be QCustomDataArray::Vector3D.
+
+ \sa at(), setAt(), elementType()
+*/
+
+/*!
+ \fn QVector4D QCustomDataArray::vector4DAt(int index) const
+
+ Returns the 4D vector element at \a index in this custom data array.
+ The elementType() must be QCustomDataArray::Vector4D.
+
+ \sa at(), setAt(), elementType()
+*/
+
+/*!
+ \fn QColor4ub QCustomDataArray::colorAt(int index) const
+
+ Returns the color element at \a index in this custom data array.
+ The elementType() must be QCustomDataArray::Color.
+
+ \sa at(), setAt(), elementType()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(qreal x)
+ \overload
+
+ Appends the floating-point value \a x to this custom data array.
+ The elementType() must be QCustomDataArray::Float.
+
+ \sa setAt(), floatAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(qreal x, qreal y)
+ \overload
+
+ Appends the 2D vector value (\a x, \a y) to this custom data array.
+ The elementType() must be QCustomDataArray::Vector2D.
+
+ \sa setAt(), vector2DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(qreal x, qreal y, qreal z)
+ \overload
+
+ Appends the 3D vector value (\a x, \a y, \a z) to this custom
+ data array. The elementType() must be QCustomDataArray::Vector3D.
+
+ \sa setAt(), vector3DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(qreal x, qreal y, qreal z, qreal w)
+ \overload
+
+ Appends the 4D vector value (\a x, \a y, \a z, \a w) to this custom
+ data array. The elementType() must be QCustomDataArray::Vector4D.
+
+ \sa setAt(), vector4DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(const QVector2D& value)
+ \overload
+
+ Appends the 2D vector \a value to this custom data array.
+ The elementType() must be QCustomDataArray::Vector2D.
+
+ \sa setAt(), vector2DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(const QVector3D& value)
+ \overload
+
+ Appends the 3D vector \a value to this custom data array.
+ The elementType() must be QCustomDataArray::Vector3D.
+
+ \sa setAt(), vector3DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(const QVector4D& value)
+ \overload
+
+ Appends the 4D vector \a value to this custom data array.
+ The elementType() must be QCustomDataArray::Vector4D.
+
+ \sa setAt(), vector4DAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(const QColor4ub& value)
+ \overload
+
+ Appends the color \a value to this custom data array.
+ The elementType() must be QCustomDataArray::Color.
+
+ \sa setAt(), colorAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(Qt::GlobalColor value)
+ \overload
+
+ Appends the color \a value to this custom data array.
+ The elementType() must be QCustomDataArray::Color.
+
+ \sa setAt(), colorAt()
+*/
+
+/*!
+ \fn void QCustomDataArray::append(const QCustomDataArray &array)
+ \overload
+
+ Appends the values in \a array to this custom data array. This
+ custom data array must have the same element type as \a array,
+ unless this custom data array is empty - in which case the
+ element type and data of \a array will be assigned to this.
+*/
+
+/*!
+ Appends \a value to this custom data array.
+
+ The type of \a value must be consistent with elementType().
+ The two exceptions to this are that a Float value can be
+ specified by either a float or double QVariant, and a Color
+ value can be specified as either a QColor4ub or QColor QVariant.
+
+ \sa at(), setAt(), elementType()
+*/
+void QCustomDataArray::append(const QVariant& value)
+{
+ switch (value.type()) {
+
+ case (QVariant::Type)QMetaType::Float:
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ m_array.append(value.toFloat());
+ break;
+
+ case QVariant::Double:
+ // Convert Double into Float.
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ m_array.append(float(value.toDouble()));
+ break;
+
+ case QVariant::Vector2D:
+ append(qVariantValue<QVector2D>(value));
+ break;
+
+ case QVariant::Vector3D:
+ append(qVariantValue<QVector3D>(value));
+ break;
+
+ case QVariant::Vector4D:
+ append(qVariantValue<QVector4D>(value));
+ break;
+
+ case QVariant::Color:
+ // Convert QColor into QColor4ub.
+ append(QColor4ub(qVariantValue<QColor>(value)));
+ break;
+
+ case QVariant::UserType:
+ if (value.userType() == qMetaTypeId<QColor4ub>()) {
+ append(qVariantValue<QColor4ub>(value));
+ break;
+ }
+ // Fall through.
+
+ default:
+ Q_ASSERT_X(false, "QCustomDataArray::append",
+ "QVariant type not supported for elements");
+ break;
+ }
+}
+
+/*!
+ Returns the contents of this custom data array as a QArray
+ of float values.
+
+ The elementType() must be QCustomDataArray::Float.
+*/
+QArray<float> QCustomDataArray::toFloatArray() const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ return m_array;
+}
+
+/*!
+ Returns the contents of this custom data array as a QArray
+ of QVector2D values.
+
+ The elementType() must be QCustomDataArray::Vector2D.
+
+ This function needs to make a complete copy of the data
+ in this array so it may be expensive performance-wise.
+*/
+QArray<QVector2D> QCustomDataArray::toVector2DArray() const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector2D);
+ int size = m_array.size() / 2;
+ QArray<QVector2D> result;
+ if (size > 0) {
+ QVector2D *dst = result.extend(size);
+ const float *src = m_array.constData();
+ qMemCopy(dst, src, size * sizeof(QVector2D));
+ }
+ return result;
+}
+
+/*!
+ Returns the contents of this custom data array as a QArray
+ of QVector3D values.
+
+ The elementType() must be QCustomDataArray::Vector3D.
+
+ This function needs to make a complete copy of the data
+ in this array so it may be expensive performance-wise.
+*/
+QArray<QVector3D> QCustomDataArray::toVector3DArray() const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector3D);
+ int size = m_array.size() / 3;
+ QArray<QVector3D> result;
+ if (size > 0) {
+ QVector3D *dst = result.extend(size);
+ const float *src = m_array.constData();
+ qMemCopy(dst, src, size * sizeof(QVector3D));
+ }
+ return result;
+}
+
+/*!
+ Returns the contents of this custom data array as a QArray
+ of QVector4D values.
+
+ The elementType() must be QCustomDataArray::Vector4D.
+
+ This function needs to make a complete copy of the data
+ in this array so it may be expensive performance-wise.
+*/
+QArray<QVector4D> QCustomDataArray::toVector4DArray() const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector4D);
+ int size = m_array.size() / 4;
+ QArray<QVector4D> result;
+ if (size > 0) {
+ QVector4D *dst = result.extend(size);
+ const float *src = m_array.constData();
+ qMemCopy(dst, src, size * sizeof(QVector4D));
+ }
+ return result;
+}
+
+/*!
+ Returns the contents of this custom data array as a QArray
+ of QColor4ub values.
+
+ The elementType() must be QCustomDataArray::Color.
+
+ This function needs to make a complete copy of the data
+ in this array so it may be expensive performance-wise.
+*/
+QArray<QColor4ub> QCustomDataArray::toColorArray() const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ int size = m_array.size();
+ QArray<QColor4ub> result;
+ result.reserve(size);
+ const QColor4ub *data =
+ reinterpret_cast<const QColor4ub *>(m_array.constData());
+ for (int index = 0; index < size; ++index)
+ result.append(*data++);
+ return result;
+}
+
+/*!
+ \fn const void *QCustomDataArray::data() const
+
+ Returns a const pointer to the data stored in the custom data array.
+ The pointer can be used to access the items in the custom data array.
+ The pointer remains valid as long as the custom data array isn't
+ reallocated.
+
+ This function is mostly useful to pass a custom data array to a function
+ that accepts a plain C++ array.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QCustomDataArray &array)
+{
+ dbg << "QCustomDataArray" << &array << " -- count:" << array.count();
+ for (int i = 0; i < array.count(); ++i)
+ dbg << array.at(i);
+ return dbg;
+}
+#endif
+
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qcustomdataarray.h b/src/threed/arrays/qcustomdataarray.h
new file mode 100644
index 000000000..c4064a982
--- /dev/null
+++ b/src/threed/arrays/qcustomdataarray.h
@@ -0,0 +1,421 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCUSTOMDATAARRAY_H
+#define QCUSTOMDATAARRAY_H
+
+#include "qarray.h"
+#include "qcolor4ub.h"
+#include <QtCore/qvariant.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLVertexBundleCustomAttribute;
+class QGeometryData;
+
+class Q_QT3D_EXPORT QCustomDataArray
+{
+public:
+ enum ElementType
+ {
+ Float,
+ Vector2D,
+ Vector3D,
+ Vector4D,
+ Color
+ };
+
+ QCustomDataArray();
+ explicit QCustomDataArray(QCustomDataArray::ElementType type);
+ QCustomDataArray(QCustomDataArray::ElementType type, int size);
+ QCustomDataArray(const QCustomDataArray& other);
+ QCustomDataArray(const QArray<float>& other);
+ QCustomDataArray(const QArray<QVector2D>& other);
+ QCustomDataArray(const QArray<QVector3D>& other);
+ QCustomDataArray(const QArray<QVector4D>& other);
+ QCustomDataArray(const QArray<QColor4ub>& other);
+ ~QCustomDataArray();
+
+ QCustomDataArray& operator=(const QCustomDataArray& other);
+
+ QCustomDataArray::ElementType elementType() const;
+ void setElementType(QCustomDataArray::ElementType type);
+
+ int size() const;
+ int count() const;
+
+ int capacity() const;
+ bool isEmpty() const;
+
+ int elementSize() const;
+
+ void clear();
+ void reserve(int size);
+ void resize(int size);
+ void squeeze();
+
+ QVariant at(int index) const;
+ void setAt(int index, const QVariant& value);
+
+ void setAt(int index, qreal x);
+ void setAt(int index, qreal x, qreal y);
+ void setAt(int index, qreal x, qreal y, qreal z);
+ void setAt(int index, qreal x, qreal y, qreal z, qreal w);
+ void setAt(int index, const QVector2D& value);
+ void setAt(int index, const QVector3D& value);
+ void setAt(int index, const QVector4D& value);
+ void setAt(int index, const QColor4ub& value);
+ void setAt(int index, Qt::GlobalColor value);
+
+ qreal floatAt(int index) const;
+ QVector2D vector2DAt(int index) const;
+ QVector3D vector3DAt(int index) const;
+ QVector4D vector4DAt(int index) const;
+ QColor4ub colorAt(int index) const;
+
+ void append(qreal x);
+ void append(qreal x, qreal y);
+ void append(qreal x, qreal y, qreal z);
+ void append(qreal x, qreal y, qreal z, qreal w);
+ void append(const QVector2D& value);
+ void append(const QVector3D& value);
+ void append(const QVector4D& value);
+ void append(const QColor4ub& value);
+ void append(const QVariant& value);
+ void append(Qt::GlobalColor value);
+ void append(const QCustomDataArray &array);
+
+ QArray<float> toFloatArray() const;
+ QArray<QVector2D> toVector2DArray() const;
+ QArray<QVector3D> toVector3DArray() const;
+ QArray<QVector4D> toVector4DArray() const;
+ QArray<QColor4ub> toColorArray() const;
+
+ const void *data() const;
+
+private:
+ QArray<float> m_array;
+ QCustomDataArray::ElementType m_elementType;
+ int m_elementComponents;
+
+ friend class QGLVertexBundleCustomAttribute;
+ friend class QGeometryData;
+};
+
+inline QCustomDataArray::QCustomDataArray()
+ : m_elementType(QCustomDataArray::Float),
+ m_elementComponents(1)
+{
+}
+
+inline QCustomDataArray::QCustomDataArray(const QCustomDataArray& other)
+ : m_array(other.m_array),
+ m_elementType(other.m_elementType),
+ m_elementComponents(other.m_elementComponents)
+{
+}
+
+inline QCustomDataArray::~QCustomDataArray() {}
+
+inline QCustomDataArray& QCustomDataArray::operator=(const QCustomDataArray& other)
+{
+ if (this != &other) {
+ m_array = other.m_array;
+ m_elementType = other.m_elementType;
+ m_elementComponents = other.m_elementComponents;
+ }
+ return *this;
+}
+
+inline QCustomDataArray::ElementType QCustomDataArray::elementType() const
+{
+ return m_elementType;
+}
+
+inline int QCustomDataArray::size() const
+{
+ return m_array.size() / m_elementComponents;
+}
+
+inline int QCustomDataArray::count() const
+{
+ return m_array.size() / m_elementComponents;
+}
+
+inline int QCustomDataArray::capacity() const
+{
+ return m_array.capacity() / m_elementComponents;
+}
+
+inline bool QCustomDataArray::isEmpty() const
+{
+ return m_array.isEmpty();
+}
+
+inline int QCustomDataArray::elementSize() const
+{
+ return m_elementComponents * sizeof(float);
+}
+
+inline void QCustomDataArray::clear()
+{
+ m_array.clear();
+}
+
+inline void QCustomDataArray::reserve(int size)
+{
+ m_array.reserve(size * m_elementComponents);
+}
+
+inline void QCustomDataArray::resize(int size)
+{
+ m_array.resize(size * m_elementComponents);
+}
+
+inline void QCustomDataArray::squeeze()
+{
+ m_array.squeeze();
+}
+
+inline void QCustomDataArray::setAt(int index, qreal x)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ Q_ASSERT(index >= 0 && index < size());
+ m_array[index] = float(x);
+}
+
+inline void QCustomDataArray::setAt(int index, qreal x, qreal y)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector2D);
+ Q_ASSERT(index >= 0 && index < size());
+ float *data = m_array.data() + index * 2;
+ data[0] = float(x);
+ data[1] = float(y);
+}
+
+inline void QCustomDataArray::setAt(int index, qreal x, qreal y, qreal z)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector3D);
+ Q_ASSERT(index >= 0 && index < size());
+ float *data = m_array.data() + index * 3;
+ data[0] = float(x);
+ data[1] = float(y);
+ data[2] = float(z);
+}
+
+inline void QCustomDataArray::setAt(int index, qreal x, qreal y, qreal z, qreal w)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector4D);
+ Q_ASSERT(index >= 0 && index < size());
+ float *data = m_array.data() + index * 4;
+ data[0] = float(x);
+ data[1] = float(y);
+ data[2] = float(z);
+ data[3] = float(w);
+}
+
+inline void QCustomDataArray::setAt(int index, const QVector2D& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector2D);
+ Q_ASSERT(index >= 0 && index < size());
+ float *data = m_array.data() + index * 2;
+ data[0] = float(value.x());
+ data[1] = float(value.y());
+}
+
+inline void QCustomDataArray::setAt(int index, const QVector3D& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector3D);
+ Q_ASSERT(index >= 0 && index < size());
+ float *data = m_array.data() + index * 3;
+ data[0] = float(value.x());
+ data[1] = float(value.y());
+ data[2] = float(value.z());
+}
+
+inline void QCustomDataArray::setAt(int index, const QVector4D& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector4D);
+ Q_ASSERT(index >= 0 && index < size());
+ float *data = m_array.data() + index * 4;
+ data[0] = float(value.x());
+ data[1] = float(value.y());
+ data[2] = float(value.z());
+ data[3] = float(value.w());
+}
+
+inline void QCustomDataArray::setAt(int index, const QColor4ub& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ Q_ASSERT(index >= 0 && index < size());
+ *(reinterpret_cast<QColor4ub *>(m_array.data() + index)) = value;
+}
+
+inline void QCustomDataArray::setAt(int index, Qt::GlobalColor value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ Q_ASSERT(index >= 0 && index < size());
+ *(reinterpret_cast<QColor4ub *>(m_array.data() + index)) = QColor4ub(value);
+}
+
+inline qreal QCustomDataArray::floatAt(int index) const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ Q_ASSERT(index >= 0 && index < size());
+ return m_array.at(index);
+}
+
+inline QVector2D QCustomDataArray::vector2DAt(int index) const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector2D);
+ Q_ASSERT(index >= 0 && index < size());
+ const float *data = m_array.constData() + index * 2;
+ return QVector2D(data[0], data[1]);
+}
+
+inline QVector3D QCustomDataArray::vector3DAt(int index) const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector3D);
+ Q_ASSERT(index >= 0 && index < size());
+ const float *data = m_array.constData() + index * 3;
+ return QVector3D(data[0], data[1], data[2]);
+}
+
+inline QVector4D QCustomDataArray::vector4DAt(int index) const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector4D);
+ Q_ASSERT(index >= 0 && index < size());
+ const float *data = m_array.constData() + index * 4;
+ return QVector4D(data[0], data[1], data[2], data[3]);
+}
+
+inline QColor4ub QCustomDataArray::colorAt(int index) const
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ Q_ASSERT(index >= 0 && index < size());
+ return *(reinterpret_cast<const QColor4ub *>(m_array.constData() + index));
+}
+
+inline void QCustomDataArray::append(qreal x)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Float);
+ m_array.append(float(x));
+}
+
+inline void QCustomDataArray::append(qreal x, qreal y)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector2D);
+ m_array.append(float(x), float(y));
+}
+
+inline void QCustomDataArray::append(qreal x, qreal y, qreal z)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector3D);
+ m_array.append(float(x), float(y), float(z));
+}
+
+inline void QCustomDataArray::append(qreal x, qreal y, qreal z, qreal w)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector4D);
+ m_array.append(float(x), float(y), float(z), float(w));
+}
+
+inline void QCustomDataArray::append(const QVector2D& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector2D);
+ m_array.append(float(value.x()), float(value.y()));
+}
+
+inline void QCustomDataArray::append(const QVector3D& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector3D);
+ m_array.append(float(value.x()), float(value.y()), float(value.z()));
+}
+
+inline void QCustomDataArray::append(const QVector4D& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Vector4D);
+ m_array.append(float(value.x()), float(value.y()),
+ float(value.z()), float(value.w()));
+}
+
+inline void QCustomDataArray::append(const QColor4ub& value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ *(reinterpret_cast<QColor4ub *>(m_array.extend(1))) = value;
+}
+
+inline void QCustomDataArray::append(Qt::GlobalColor value)
+{
+ Q_ASSERT(m_elementType == QCustomDataArray::Color);
+ *(reinterpret_cast<QColor4ub *>(m_array.extend(1))) = QColor4ub(value);
+}
+
+inline void QCustomDataArray::append(const QCustomDataArray &array)
+{
+ Q_ASSERT(isEmpty() || (array.elementType() == elementType()));
+ if (isEmpty())
+ *this = array;
+ else
+ m_array.append(array.m_array);
+}
+
+inline const void *QCustomDataArray::data() const
+{
+ return m_array.constData();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QCustomDataArray &array);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qglattributedescription.cpp b/src/threed/arrays/qglattributedescription.cpp
new file mode 100644
index 000000000..572c04f87
--- /dev/null
+++ b/src/threed/arrays/qglattributedescription.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglattributedescription.h"
+#include "qopenglfunctions.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLAttributeDescription
+ \brief The QGLAttributeDescription class encapsulates information about an OpenGL attribute value's layout and type.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ OpenGL has many functions that take a pointer to vertex attribute
+ values: \c{glVertexPointer()}, \c{glNormalPointer()},
+ \c{glVertexAttribPointer()}, etc. These functions typically
+ take four arguments: tuple size (1, 2, 3, or 4), component type
+ (e.g. GL_FLOAT), stride, and data pointer (\c{glNormalPointer()}
+ does not use tuple size, assuming that it is 3). When used with
+ vertex buffers, the data pointer may be an offset into the vertex
+ buffer instead.
+
+ QGLAttributeDescription encapsulates the vertex attribute() kind
+ (QGL::Position, QGL::Normal, etc) with the type(), tupleSize(),
+ and stride() information of an attribute. The companion
+ QGLAttributeValue class adds the data pointer.
+
+ \sa QGLAttributeValue
+*/
+
+/*!
+ \fn QGLAttributeDescription::QGLAttributeDescription()
+
+ Constructs a null attribute description with default parameters of
+ tupleSize() and stride() set to zero, type() set to GL_FLOAT,
+ and attribute() set to QGL::Position.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn QGLAttributeDescription::QGLAttributeDescription(QGL::VertexAttribute attribute, int tupleSize, GLenum type, int stride)
+
+ Constructs an attribute description with the fields \a attribute,
+ \a tupleSize, \a type, and \a stride.
+*/
+
+/*!
+ \fn bool QGLAttributeDescription::isNull() const
+
+ Returns true if tupleSize() is zero, which indicates an unset
+ attribute description; false otherwise.
+*/
+
+/*!
+ \fn QGL::VertexAttribute QGLAttributeDescription::attribute() const
+
+ Returns the vertex attribute that this description applies to.
+ The default value is QGL::Position.
+
+ \sa setAttribute(), type()
+*/
+
+/*!
+ \fn void QGLAttributeDescription::setAttribute(QGL::VertexAttribute attribute)
+
+ Sets the vertex \a attribute that this description applies to.
+
+ \sa attribute()
+*/
+
+/*!
+ \fn GLenum QGLAttributeDescription::type() const
+
+ Returns the component type for this attribute description. The default
+ value is GL_FLOAT.
+
+ \sa setType(), sizeOfType(), attribute()
+*/
+
+/*!
+ \fn void QGLAttributeDescription::setType(GLenum type)
+
+ Sets the component \a type for this attribute description.
+
+ \sa type(), sizeOfType()
+*/
+
+/*!
+ Returns the size in bytes of type().
+
+ \sa type(), tupleSize()
+*/
+int QGLAttributeDescription::sizeOfType() const
+{
+ switch (m_type) {
+ case GL_BYTE: return int(sizeof(GLbyte));
+ case GL_UNSIGNED_BYTE: return int(sizeof(GLubyte));
+ case GL_SHORT: return int(sizeof(GLshort));
+ case GL_UNSIGNED_SHORT: return int(sizeof(GLushort));
+ case GL_INT: return int(sizeof(GLint));
+ case GL_UNSIGNED_INT: return int(sizeof(GLuint));
+ case GL_FLOAT: return int(sizeof(GLfloat));
+#if defined(GL_DOUBLE) && !defined(QT_OPENGL_ES)
+ case GL_DOUBLE: return int(sizeof(GLdouble));
+#endif
+ default: return 0;
+ }
+}
+
+/*!
+ \fn int QGLAttributeDescription::tupleSize() const
+
+ Returns the tuple size of this attribute in components. For example,
+ a return value of 3 indicates a vector of 3-dimensional values.
+ If tupleSize() is zero, then this attribute description is null.
+
+ \sa setTupleSize(), isNull(), sizeOfType()
+*/
+
+/*!
+ \fn void QGLAttributeDescription::setTupleSize(int tupleSize)
+
+ Sets the tuple size of this attribute in components to \a tupleSize.
+
+ \sa tupleSize()
+*/
+
+/*!
+ \fn int QGLAttributeDescription::stride() const
+
+ Returns the stride in bytes from one vertex element to the
+ next for this attribute description. The default value of 0 indicates
+ that the elements are tightly packed within the data array.
+
+ \sa setStride()
+*/
+
+/*!
+ \fn void QGLAttributeDescription::setStride(int stride)
+
+ Sets the \a stride in bytes from one vertex element to the next
+ for this attribute description.
+
+ \sa stride()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qglattributedescription.h b/src/threed/arrays/qglattributedescription.h
new file mode 100644
index 000000000..533ff68d1
--- /dev/null
+++ b/src/threed/arrays/qglattributedescription.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLATTRIBUTEDESCRIPTION_H
+#define QGLATTRIBUTEDESCRIPTION_H
+
+#include <QtOpenGL/qgl.h>
+#include "qt3dglobal.h"
+#include "qglnamespace.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QGLAttributeDescription
+{
+public:
+ QGLAttributeDescription();
+ QGLAttributeDescription(QGL::VertexAttribute attribute,
+ int tupleSize, GLenum type, int stride);
+
+ bool isNull() const;
+
+ QGL::VertexAttribute attribute() const;
+ void setAttribute(QGL::VertexAttribute attribute);
+
+ GLenum type() const;
+ void setType(GLenum type);
+
+ int sizeOfType() const;
+
+ int tupleSize() const;
+ void setTupleSize(int tupleSize);
+
+ int stride() const;
+ void setStride(int stride);
+
+private:
+ QGL::VertexAttribute m_attribute;
+ GLenum m_type;
+ int m_tupleSize;
+ int m_stride;
+};
+
+inline QGLAttributeDescription::QGLAttributeDescription()
+ : m_attribute(QGL::Position), m_type(GL_FLOAT),
+ m_tupleSize(0), m_stride(0)
+{
+}
+
+inline QGLAttributeDescription::QGLAttributeDescription
+ (QGL::VertexAttribute attribute, int tupleSize, GLenum type, int stride)
+ : m_attribute(attribute), m_type(type),
+ m_tupleSize(tupleSize), m_stride(stride)
+{
+ Q_ASSERT(tupleSize >= 1 && tupleSize <= 4);
+}
+
+inline bool QGLAttributeDescription::isNull() const
+{
+ return m_tupleSize == 0;
+}
+
+inline QGL::VertexAttribute QGLAttributeDescription::attribute() const
+{
+ return m_attribute;
+}
+
+inline void QGLAttributeDescription::setAttribute(QGL::VertexAttribute attribute)
+{
+ m_attribute = attribute;
+}
+
+inline GLenum QGLAttributeDescription::type() const
+{
+ return m_type;
+}
+
+inline void QGLAttributeDescription::setType(GLenum type)
+{
+ m_type = type;
+}
+
+inline int QGLAttributeDescription::tupleSize() const
+{
+ return m_tupleSize;
+}
+
+inline void QGLAttributeDescription::setTupleSize(int tupleSize)
+{
+ Q_ASSERT(tupleSize >= 1 && tupleSize <= 4);
+ m_tupleSize = tupleSize;
+}
+
+inline int QGLAttributeDescription::stride() const
+{
+ return m_stride;
+}
+
+inline void QGLAttributeDescription::setStride(int stride)
+{
+ m_stride = stride;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qglattributeset.cpp b/src/threed/arrays/qglattributeset.cpp
new file mode 100644
index 000000000..6f6ae0e84
--- /dev/null
+++ b/src/threed/arrays/qglattributeset.cpp
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglattributeset.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLAttributeSet
+ \brief The QGLAttributeSet class provides a set of QGL::VertexAttribute indexes.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ QGLAttributeSet is intended for checking if a specific vertex
+ attribute is present in a piece of geometry, or has been set on a
+ QGLPainter during rendering operations. The members of the set
+ are instances of QGL::VertexAttribute, with the restriction that
+ the index must be between 0 and 31.
+
+ The most common use for this class is to determine if specific
+ attributes have been supplied on a QGLPainter so as to adjust the
+ current drawing effect accordingly. The following example will
+ use a lit texture effect if texture co-ordinates were provided
+ in the vertex bundle, or a simple lit material effect if
+ texture co-ordinates were not provided:
+
+ \code
+ painter.clearAttributes();
+ painter.setVertexBundle(bundle);
+ if (painter.attributes().contains(QGL::TextureCoord0))
+ painter.setStandardEffect(QGL::LitModulateTexture2D);
+ else
+ painter.setStandardEffect(QGL::LitMaterial);
+ \endcode
+
+ It is important to clear the attributes before setting the vertex
+ bundle, so that attributes from a previous bundle will not leak
+ through. Multiple vertex bundles may be supplied if they contain
+ different parts of the same logical piece of geometry.
+
+ \sa QGLVertexBundle::attributes(), QGLPainter::attributes()
+*/
+
+/*!
+ \fn QGLAttributeSet::QGLAttributeSet()
+
+ Constructs an empty attribute set.
+
+ \sa isEmpty()
+*/
+
+/*!
+ \fn bool QGLAttributeSet::isEmpty() const
+
+ Returns true if this attribute set is empty; false otherwise.
+*/
+
+/*!
+ \fn void QGLAttributeSet::clear()
+
+ Clears this attribute set to empty.
+*/
+
+/*!
+ \fn bool QGLAttributeSet::contains(QGL::VertexAttribute attr) const
+
+ Returns true if this attribute set contains \a attr; false otherwise.
+
+ \sa insert(), remove()
+*/
+
+/*!
+ \fn void QGLAttributeSet::insert(QGL::VertexAttribute attr)
+
+ Inserts \a attr into this attribute set. Note: \a attr must be
+ within the range 0 to 31. Attribute indexes outside this range
+ are ignored and not added to the set.
+
+ \sa remove(), contains()
+*/
+
+/*!
+ \fn void QGLAttributeSet::remove(QGL::VertexAttribute attr)
+
+ Removes \a attr from this attribute set.
+
+ \sa insert(), contains()
+*/
+
+/*!
+ Returns the members of this attribute set as a list.
+
+ \sa fromList()
+*/
+QList<QGL::VertexAttribute> QGLAttributeSet::toList() const
+{
+ QList<QGL::VertexAttribute> list;
+ quint32 attrs = m_attrs;
+ int index = 0;
+ while (attrs != 0) {
+ if ((attrs & 1) != 0)
+ list.append(QGL::VertexAttribute(index));
+ ++index;
+ attrs >>= 1;
+ }
+ return list;
+}
+
+/*!
+ Returns a new attribute set that is initialized with the members
+ of \a list.
+
+ \sa toList(), insert()
+*/
+QGLAttributeSet QGLAttributeSet::fromList(const QList<QGL::VertexAttribute> &list)
+{
+ QGLAttributeSet set;
+ for (int index = 0; index < list.size(); ++index)
+ set.insert(list.at(index));
+ return set;
+}
+
+/*!
+ \fn void QGLAttributeSet::unite(const QGLAttributeSet &other)
+
+ Unites the contents of \a other with this attribute set
+ and modifies this set accordingly.
+
+ \sa intersect(), subtract(), insert()
+*/
+
+/*!
+ \fn void QGLAttributeSet::intersect(const QGLAttributeSet &other)
+
+ Intersects the contents of \a other with this attribute set
+ and modifies this set accordingly.
+
+ \sa unite(), subtract()
+*/
+
+/*!
+ \fn void QGLAttributeSet::subtract(const QGLAttributeSet &other)
+
+ Subtracts the contents of \a other from this attribute set
+ and modifies this set accordingly.
+
+ \sa unite(), intersect(), remove()
+*/
+
+/*!
+ \fn bool QGLAttributeSet::operator==(const QGLAttributeSet &other) const
+
+ Returns true if this attribute set has the same elements as \a other;
+ false otherwise.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QGLAttributeSet::operator!=(const QGLAttributeSet &other) const
+
+ Returns true if this attribute set does not have the same elements as
+ \a other; false otherwise.
+
+ \sa operator==()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qglattributeset.h b/src/threed/arrays/qglattributeset.h
new file mode 100644
index 000000000..39aed5bae
--- /dev/null
+++ b/src/threed/arrays/qglattributeset.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLATTRIBUTESET_H
+#define QGLATTRIBUTESET_H
+
+#include "qt3dglobal.h"
+#include "qglnamespace.h"
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QGLAttributeSet
+{
+public:
+ QGLAttributeSet() : m_attrs(0) {}
+
+ bool isEmpty() const { return !m_attrs; }
+ void clear() { m_attrs = 0; }
+
+ bool contains(QGL::VertexAttribute attr) const;
+ void insert(QGL::VertexAttribute attr);
+ void remove(QGL::VertexAttribute attr);
+
+ QList<QGL::VertexAttribute> toList() const;
+ static QGLAttributeSet fromList(const QList<QGL::VertexAttribute> &list);
+
+ void unite(const QGLAttributeSet &other);
+ void intersect(const QGLAttributeSet &other);
+ void subtract(const QGLAttributeSet &other);
+
+ bool operator==(const QGLAttributeSet &other) const;
+ bool operator!=(const QGLAttributeSet &other) const;
+
+private:
+ quint32 m_attrs;
+};
+
+inline bool QGLAttributeSet::contains(QGL::VertexAttribute attr) const
+{
+ quint32 flag = quint32(attr);
+ return flag < 32 ? ((m_attrs & (((quint32)1) << flag)) != 0) : false;
+}
+
+inline void QGLAttributeSet::insert(QGL::VertexAttribute attr)
+{
+ quint32 flag = quint32(attr);
+ if (flag < 32)
+ m_attrs |= (((quint32)1) << flag);
+}
+
+inline void QGLAttributeSet::remove(QGL::VertexAttribute attr)
+{
+ quint32 flag = quint32(attr);
+ if (flag < 32)
+ m_attrs &= ~(((quint32)1) << flag);
+}
+
+inline void QGLAttributeSet::unite(const QGLAttributeSet &other)
+{
+ m_attrs |= other.m_attrs;
+}
+
+inline void QGLAttributeSet::intersect(const QGLAttributeSet &other)
+{
+ m_attrs &= other.m_attrs;
+}
+
+inline void QGLAttributeSet::subtract(const QGLAttributeSet &other)
+{
+ m_attrs &= ~(other.m_attrs);
+}
+
+inline bool QGLAttributeSet::operator==(const QGLAttributeSet &other) const
+{
+ return m_attrs == other.m_attrs;
+}
+
+inline bool QGLAttributeSet::operator!=(const QGLAttributeSet &other) const
+{
+ return m_attrs != other.m_attrs;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qglattributevalue.cpp b/src/threed/arrays/qglattributevalue.cpp
new file mode 100644
index 000000000..104aa39ff
--- /dev/null
+++ b/src/threed/arrays/qglattributevalue.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglattributevalue.h"
+#include "qopenglfunctions.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLAttributeValue
+ \brief The QGLAttributeValue class encapsulates information about an OpenGL attribute value.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ OpenGL has many functions that take a pointer to vertex attribute
+ values: \c{glVertexPointer()}, \c{glNormalPointer()},
+ \c{glVertexAttribPointer()}, etc. These functions typically
+ take four arguments: tuple size (1, 2, 3, or 4), component type
+ (e.g. GL_FLOAT), stride, and data pointer (\c{glNormalPointer()}
+ does not use tuple size, assuming that it is 3). When used with
+ vertex buffers, the data pointer may be an offset into the vertex
+ buffer instead.
+
+ QGLAttributeValue encapsulates these four values so that they can
+ be easily manipulated as a set during OpenGL painting operations.
+ Constructors are provided for converting QArray and
+ QCustomDataArray objects into an attribute value.
+
+ Because the data() value is a raw pointer to arbitrary memory,
+ care should be taken that the memory remains valid until the
+ QGLAttributeValue is no longer required.
+
+ \sa QGLAttributeDescription, QArray, QCustomDataArray
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue()
+
+ Constructs a null attribute value with default parameters of
+ tupleSize(), and stride() set to zero, type() set to GL_FLOAT,
+ and data() set to null.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(const QArray<float>& array)
+
+ Constructs an attribute value that refers to the contents of \a array,
+ setting tupleSize() to 1, type() to GL_FLOAT, and stride() to zero.
+
+ The \a array must not be destroyed or modified until the attribute
+ value is no longer required.
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(const QArray<QVector2D>& array)
+
+ Constructs an attribute value that refers to the contents of \a array,
+ setting tupleSize() to 2, type() to GL_FLOAT, and stride() to zero.
+
+ The \a array must not be destroyed or modified until the attribute
+ value is no longer required.
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(const QArray<QVector3D>& array)
+
+ Constructs an attribute value that refers to the contents of \a array,
+ setting tupleSize() to 3, type() to GL_FLOAT, and stride() to zero.
+
+ The \a array must not be destroyed or modified until the attribute
+ value is no longer required.
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(const QArray<QVector4D>& array)
+
+ Constructs an attribute value that refers to the contents of \a array,
+ setting tupleSize() to 4, type() to GL_FLOAT, and stride() to zero.
+
+ The \a array must not be destroyed or modified until the attribute
+ value is no longer required.
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(const QArray<QColor4ub>& array)
+
+ Constructs an attribute value that refers to the contents of \a array,
+ setting tupleSize() to 4, type() to GL_UNSIGNED_BYTE, and stride() to zero.
+
+ The \a array must not be destroyed or modified until the attribute
+ value is no longer required.
+*/
+
+/*!
+ Constructs an attribute value that refers to the contents of \a array.
+ The tupleSize() and type() of the attribute value will be set according
+ to the QCustomDataArray::elementType() of \a array.
+
+ The \a array must not be destroyed or modified until the attribute
+ value is no longer required.
+*/
+QGLAttributeValue::QGLAttributeValue(const QCustomDataArray& array)
+ : m_tupleSize(0), m_type(GL_FLOAT), m_stride(0)
+ , m_data(array.data()), m_count(array.count())
+{
+ switch (array.elementType()) {
+ case QCustomDataArray::Float:
+ m_tupleSize = 1;
+ break;
+ case QCustomDataArray::Vector2D:
+ m_tupleSize = 2;
+ break;
+ case QCustomDataArray::Vector3D:
+ m_tupleSize = 3;
+ break;
+ case QCustomDataArray::Vector4D:
+ m_tupleSize = 4;
+ break;
+ case QCustomDataArray::Color:
+ m_tupleSize = 4;
+ m_type = GL_UNSIGNED_BYTE;
+ break;
+ }
+}
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(int tupleSize, GLenum type, int stride, const void *data, int count)
+
+ Constructs an attribute value with the fields \a tupleSize, \a type,
+ \a stride, \a data, and \a count.
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(int tupleSize, GLenum type, int stride, int offset, int count)
+
+ Constructs an attribute value with the fields \a tupleSize, \a type,
+ \a stride, \a offset, and \a count.
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(const QGLAttributeDescription& description, const void *data, int count)
+
+ Constructs an attribute value with the supplied \a description,
+ \a data, and \a count.
+*/
+
+/*!
+ \fn QGLAttributeValue::QGLAttributeValue(const QGLAttributeDescription& description, int offset, int count)
+
+ Constructs an attribute value with the supplied \a description,
+ \a offset, and \a count.
+*/
+
+/*!
+ \fn bool QGLAttributeValue::isNull() const
+
+ Returns true if tupleSize() is zero, which indicates an unset
+ attribute value; false otherwise.
+
+ Note: it is possible for data() to be null, but isNull() returns true.
+ This can happen when data() is actually a zero offset into a
+ vertex buffer.
+*/
+
+/*!
+ \fn QGLAttributeDescription QGLAttributeValue::description(QGL::VertexAttribute attribute) const
+
+ Returns the description of this value, tagged with \a attribute.
+
+ \sa type()
+*/
+
+/*!
+ \fn GLenum QGLAttributeValue::type() const
+
+ Returns the component type for this attribute value. The default
+ value is GL_FLOAT.
+
+ \sa sizeOfType(), description()
+*/
+
+/*!
+ Returns the size in bytes of type().
+
+ \sa type(), tupleSize()
+*/
+int QGLAttributeValue::sizeOfType() const
+{
+ switch (m_type) {
+ case GL_BYTE: return int(sizeof(GLbyte));
+ case GL_UNSIGNED_BYTE: return int(sizeof(GLubyte));
+ case GL_SHORT: return int(sizeof(GLshort));
+ case GL_UNSIGNED_SHORT: return int(sizeof(GLushort));
+ case GL_INT: return int(sizeof(GLint));
+ case GL_UNSIGNED_INT: return int(sizeof(GLuint));
+ case GL_FLOAT: return int(sizeof(GLfloat));
+#if defined(GL_DOUBLE) && !defined(QT_OPENGL_ES)
+ case GL_DOUBLE: return int(sizeof(GLdouble));
+#endif
+ default: return 0;
+ }
+}
+
+/*!
+ \fn int QGLAttributeValue::tupleSize() const
+
+ Returns the tuple size of this attribute in components. For example,
+ a return value of 3 indicates a vector of 3-dimensional values.
+ If tupleSize() is zero, then this attribute value is null.
+
+ \sa isNull(), sizeOfType()
+*/
+
+/*!
+ \fn int QGLAttributeValue::stride() const
+
+ Returns the stride in bytes from one vertex element to the
+ next for this attribute value. The default value of 0 indicates
+ that the elements are tightly packed within the data() array.
+*/
+
+/*!
+ \fn const void *QGLAttributeValue::data() const
+
+ Returns the data pointer for the elements in this attribute value.
+*/
+
+/*!
+ \fn int QGLAttributeValue::count() const
+
+ Returns the count of vertex elements in this attribute value;
+ zero if the count is unknown.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qglattributevalue.h b/src/threed/arrays/qglattributevalue.h
new file mode 100644
index 000000000..cf4c9319b
--- /dev/null
+++ b/src/threed/arrays/qglattributevalue.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLATTRIBUTEVALUE_H
+#define QGLATTRIBUTEVALUE_H
+
+#include "qglattributedescription.h"
+#include "qcustomdataarray.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLVertexBundle;
+
+class Q_QT3D_EXPORT QGLAttributeValue
+{
+public:
+ QGLAttributeValue();
+ QGLAttributeValue(const QArray<float>& array);
+ QGLAttributeValue(const QArray<QVector2D>& array);
+ QGLAttributeValue(const QArray<QVector3D>& array);
+ QGLAttributeValue(const QArray<QVector4D>& array);
+ QGLAttributeValue(const QArray<QColor4ub>& array);
+ QGLAttributeValue(const QCustomDataArray& array);
+ QGLAttributeValue(int tupleSize, GLenum type, int stride, const void *data, int count = 0);
+ QGLAttributeValue(int tupleSize, GLenum type, int stride, int offset, int count = 0);
+ QGLAttributeValue(const QGLAttributeDescription& description, const void *data, int count = 0);
+ QGLAttributeValue(const QGLAttributeDescription& description, int offset, int count = 0);
+
+ bool isNull() const;
+
+ QGLAttributeDescription description(QGL::VertexAttribute attribute) const;
+ GLenum type() const;
+ int sizeOfType() const;
+ int tupleSize() const;
+ int stride() const;
+ const void *data() const;
+ int count() const;
+
+private:
+ int m_tupleSize;
+ GLenum m_type;
+ int m_stride;
+ const void *m_data;
+ int m_count;
+
+ void setStride(int stride) { m_stride = stride; }
+ void setOffset(int offset)
+ { m_data = reinterpret_cast<const void *>(offset); }
+
+ friend class QGLVertexBundle;
+};
+
+inline QGLAttributeValue::QGLAttributeValue()
+ : m_tupleSize(0), m_type(GL_FLOAT), m_stride(0), m_data(0), m_count(0)
+{
+}
+
+inline QGLAttributeValue::QGLAttributeValue(const QArray<float>& array)
+ : m_tupleSize(1), m_type(GL_FLOAT), m_stride(0)
+ , m_data(array.constData()), m_count(array.count())
+{
+}
+
+inline QGLAttributeValue::QGLAttributeValue(const QArray<QVector2D>& array)
+ : m_tupleSize(2), m_type(GL_FLOAT), m_stride(0)
+ , m_data(array.constData()), m_count(array.count())
+{
+}
+
+inline QGLAttributeValue::QGLAttributeValue(const QArray<QVector3D>& array)
+ : m_tupleSize(3), m_type(GL_FLOAT), m_stride(0)
+ , m_data(array.constData()), m_count(array.count())
+{
+}
+
+inline QGLAttributeValue::QGLAttributeValue(const QArray<QVector4D>& array)
+ : m_tupleSize(4), m_type(GL_FLOAT), m_stride(0)
+ , m_data(array.constData()), m_count(array.count())
+{
+}
+
+inline QGLAttributeValue::QGLAttributeValue(const QArray<QColor4ub>& array)
+ : m_tupleSize(4), m_type(GL_UNSIGNED_BYTE), m_stride(0)
+ , m_data(array.constData()), m_count(array.count())
+{
+}
+
+inline QGLAttributeValue::QGLAttributeValue
+ (int tupleSize, GLenum type, int stride, const void *data, int count)
+ : m_tupleSize(tupleSize), m_type(type), m_stride(stride)
+ , m_data(data), m_count(count)
+{
+ Q_ASSERT(tupleSize >= 1 && tupleSize <= 4);
+}
+
+inline QGLAttributeValue::QGLAttributeValue
+ (int tupleSize, GLenum type, int stride, int offset, int count)
+ : m_tupleSize(tupleSize), m_type(type), m_stride(stride)
+ , m_data(reinterpret_cast<const void *>(offset)), m_count(count)
+{
+ Q_ASSERT(tupleSize >= 1 && tupleSize <= 4);
+}
+
+inline QGLAttributeValue::QGLAttributeValue
+ (const QGLAttributeDescription& description, const void *data, int count)
+ : m_tupleSize(description.tupleSize()), m_type(description.type())
+ , m_stride(description.stride()), m_data(data), m_count(count)
+{
+}
+
+inline QGLAttributeValue::QGLAttributeValue
+ (const QGLAttributeDescription& description, int offset, int count)
+ : m_tupleSize(description.tupleSize()), m_type(description.type())
+ , m_stride(description.stride())
+ , m_data(reinterpret_cast<const void *>(offset))
+ , m_count(count)
+{
+}
+
+inline bool QGLAttributeValue::isNull() const
+{
+ return m_tupleSize == 0;
+}
+
+inline QGLAttributeDescription QGLAttributeValue::description(QGL::VertexAttribute attribute) const
+{
+ if (!isNull()) {
+ return QGLAttributeDescription(attribute, m_tupleSize, m_type, m_stride);
+ } else {
+ QGLAttributeDescription desc;
+ desc.setAttribute(attribute);
+ return desc;
+ }
+}
+
+inline GLenum QGLAttributeValue::type() const
+{
+ return m_type;
+}
+
+inline int QGLAttributeValue::tupleSize() const
+{
+ return m_tupleSize;
+}
+
+inline int QGLAttributeValue::stride() const
+{
+ return m_stride;
+}
+
+inline const void *QGLAttributeValue::data() const
+{
+ return m_data;
+}
+
+inline int QGLAttributeValue::count() const
+{
+ return m_count;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qglindexbuffer.cpp b/src/threed/arrays/qglindexbuffer.cpp
new file mode 100644
index 000000000..b50b19257
--- /dev/null
+++ b/src/threed/arrays/qglindexbuffer.cpp
@@ -0,0 +1,777 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglindexbuffer.h"
+#include "qglpainter.h"
+#include "qglpainter_p.h"
+#include "qglext_p.h"
+#include <QtOpenGL/qgl.h>
+#include <QtCore/qatomic.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLIndexBuffer
+ \brief The QGLIndexBuffer class manages uploading of index arrays into a GL server.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+*/
+
+#ifdef QT_OPENGL_ES
+
+static bool qt_has_uint_buffers()
+{
+ static bool done = false;
+ static bool answer = false;
+ if (!done) {
+ QGLExtensionChecker extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
+ answer = extensions.match("GL_OES_element_index_uint");
+ done = true;
+ }
+ return answer;
+}
+
+#endif
+
+class QGLIndexBufferPrivate
+{
+public:
+ QGLIndexBufferPrivate()
+ : indexCount(0)
+ , elementType(GL_UNSIGNED_SHORT)
+ , buffer(QGLBuffer::IndexBuffer)
+#ifdef QT_OPENGL_ES
+ , hasIntBuffers(qt_has_uint_buffers())
+#else
+ , hasIntBuffers(true)
+#endif
+ {
+ ref = 1;
+ }
+
+ QBasicAtomicInt ref;
+ int indexCount;
+ QArray<ushort> indexesShort;
+ QArray<uint> indexesInt;
+ GLenum elementType;
+ QGLBuffer buffer;
+ bool hasIntBuffers;
+
+ void append(const QGLIndexBufferPrivate *other, uint offset, int start);
+ uint headIndex(int posn) const;
+ uint tailIndex(int posn) const;
+};
+
+/*!
+ Creates a new index buffer.
+*/
+QGLIndexBuffer::QGLIndexBuffer()
+ : d_ptr(new QGLIndexBufferPrivate)
+{
+}
+
+/*!
+ Creates a copy of \a other. Note that this just copies a reference
+ to the index buffer. Any modifications to the copy will also
+ affect the original object.
+*/
+QGLIndexBuffer::QGLIndexBuffer(const QGLIndexBuffer& other)
+ : d_ptr(other.d_ptr)
+{
+ d_ptr->ref.ref();
+}
+
+/*!
+ Destroys this index buffer if this object is the last reference to it.
+*/
+QGLIndexBuffer::~QGLIndexBuffer()
+{
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+}
+
+/*!
+ Assigns \a other to this object. Note that this just assigns a
+ reference to the \a other index buffer. Any modifications to this
+ object will also affect \a other.
+*/
+QGLIndexBuffer& QGLIndexBuffer::operator=(const QGLIndexBuffer& other)
+{
+ if (d_ptr != other.d_ptr) {
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+ d_ptr = other.d_ptr;
+ d_ptr->ref.ref();
+ }
+ return *this;
+}
+
+/*!
+ Returns the indexes in this buffer as an array of ushort values.
+
+ Returns an empty array if type() is not \c GL_UNSIGNED_SHORT or the
+ buffer has already been uploaded.
+*/
+QArray<ushort> QGLIndexBuffer::indexesUShort() const
+{
+ Q_D(const QGLIndexBuffer);
+ return d->indexesShort;
+}
+
+/*!
+ Returns the indexes in this buffer as an array of uint values.
+
+ Returns an empty array if type() is not \c GL_UNSIGNED_INT or the
+ buffer has already been uploaded.
+*/
+QArray<uint> QGLIndexBuffer::indexesUInt() const
+{
+ Q_D(const QGLIndexBuffer);
+ return d->indexesInt;
+}
+
+/*!
+ Returns the usage pattern for this index buffer.
+ The default value is QGLBuffer::StaticDraw.
+
+ \sa setUsagePattern()
+*/
+QGLBuffer::UsagePattern QGLIndexBuffer::usagePattern() const
+{
+ Q_D(const QGLIndexBuffer);
+ return d->buffer.usagePattern();
+}
+
+/*!
+ Sets the usage pattern for this index buffer to \a value.
+ This function must be called before upload() for the \a value
+ to take effect.
+
+ \sa usagePattern(), upload()
+*/
+void QGLIndexBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
+{
+ Q_D(QGLIndexBuffer);
+ d->buffer.setUsagePattern(value);
+}
+
+static QArray<ushort> qt_qarray_uint_to_ushort(const QArray<uint> &array)
+{
+ QArray<ushort> result;
+ const uint *values = array.constData();
+ int size = array.size();
+ bool largeValue = false;
+ result.reserve(size);
+ while (size-- > 0) {
+ uint value = *values++;
+ if (ushort(value) != value)
+ largeValue = true;
+ result.append(ushort(value));
+ }
+ if (largeValue)
+ qWarning("QGLIndexBuffer::setIndexes: large 32-bit value provided to a 16-bit only buffer");
+ return result;
+}
+
+/*!
+ Sets the index \a values in this index buffer, replacing the
+ entire current contents.
+
+ If the index buffer has been uploaded to the GL server, then this
+ function must be called with a current GL context that is compatible
+ with the uploaded buffer.
+
+ \sa replaceIndexes()
+*/
+void QGLIndexBuffer::setIndexes(const QArray<ushort>& values)
+{
+ Q_D(QGLIndexBuffer);
+ if (d->buffer.isCreated()) {
+ d->buffer.bind();
+ d->buffer.allocate(values.constData(), values.size() * sizeof(ushort));
+ d->buffer.release();
+ // The element type may have changed from int to ushort.
+ d->elementType = GL_UNSIGNED_SHORT;
+ } else {
+ d->indexesShort = values;
+ d->elementType = GL_UNSIGNED_SHORT;
+ d->indexesInt = QArray<uint>();
+ }
+ d->indexCount = values.size();
+}
+
+/*!
+ Sets the index \a values in this index buffer, replacing the
+ entire current contents.
+
+ If the index buffer has been uploaded to the GL server, then this
+ function must be called with a current GL context that is compatible
+ with the uploaded buffer.
+
+ OpenGL/ES systems usually do not support 32-bit index values unless
+ they have a special extension for that purpose. On systems without
+ 32-bit index values, this function will need to convert all values
+ to 16-bit which may incur a performance penalty and lose information.
+
+ \sa replaceIndexes()
+*/
+void QGLIndexBuffer::setIndexes(const QArray<uint>& values)
+{
+ Q_D(QGLIndexBuffer);
+ if (d->buffer.isCreated()) {
+ if (d->hasIntBuffers) {
+ d->buffer.bind();
+ d->buffer.allocate(values.constData(), values.size() * sizeof(int));
+ d->buffer.release();
+ // The element type may have changed from ushort to int.
+ d->elementType = GL_UNSIGNED_INT;
+ } else {
+ QArray<ushort> svalues = qt_qarray_uint_to_ushort(values);
+ d->buffer.bind();
+ d->buffer.allocate(svalues.constData(), svalues.size() * sizeof(ushort));
+ d->buffer.release();
+ }
+ } else if (d->hasIntBuffers) {
+ d->indexesInt = values;
+ d->elementType = GL_UNSIGNED_INT;
+ d->indexesShort = QArray<ushort>();
+ } else {
+ d->indexesShort = qt_qarray_uint_to_ushort(values);
+ d->elementType = GL_UNSIGNED_SHORT;
+ d->indexesInt = QArray<uint>();
+ }
+ d->indexCount = values.size();
+}
+
+/*!
+ Replaces the elements of this index buffer, starting at \a index,
+ with the contents of \a values. All other elements keep their
+ current values.
+
+ If the index buffer has been uploaded to the GL server, then this
+ function must be called with a current GL context that is compatible
+ with the uploaded buffer.
+
+ The index buffer must have been originally created with the
+ ushort element type.
+
+ \sa setIndexes()
+*/
+void QGLIndexBuffer::replaceIndexes(int index, const QArray<ushort>& values)
+{
+ Q_D(QGLIndexBuffer);
+ Q_ASSERT_X(d->elementType == GL_UNSIGNED_SHORT,
+ "QGLIndexBuffer::replaceIndexes()",
+ "buffer created with int element type, replacing with ushort");
+ if (d->elementType != GL_UNSIGNED_SHORT)
+ return;
+ if (d->buffer.isCreated()) {
+ d->buffer.bind();
+ d->buffer.write(index * sizeof(ushort),
+ values.constData(), values.size() * sizeof(ushort));
+ d->buffer.release();
+ } else {
+ d->indexesShort.replace(index, values.constData(), values.size());
+ d->indexCount = d->indexesShort.size();
+ }
+}
+
+/*!
+ Replaces the elements of this index buffer, starting at \a index,
+ with the contents of \a values. All other elements keep their
+ current values.
+
+ If the index buffer has been uploaded to the GL server, then this
+ function must be called with a current GL context that is compatible
+ with the uploaded buffer.
+
+ The index buffer must have been originally created with the
+ int element type.
+
+ OpenGL/ES systems usually do not support 32-bit index values unless
+ they have a special extension for that purpose. On systems without
+ 32-bit index values, this function will need to convert all values
+ to 16-bit which may incur a performance penalty and lose information.
+
+ \sa setIndexes()
+*/
+void QGLIndexBuffer::replaceIndexes(int index, const QArray<uint>& values)
+{
+ Q_D(QGLIndexBuffer);
+ Q_ASSERT_X(d->elementType == GL_UNSIGNED_INT || !d->hasIntBuffers,
+ "QGLIndexBuffer::replaceIndexes()",
+ "buffer created with ushort element type, replacing with int");
+ if (d->elementType != GL_UNSIGNED_INT && d->hasIntBuffers)
+ return;
+ if (d->buffer.isCreated()) {
+ if (d->hasIntBuffers) {
+ d->buffer.bind();
+ d->buffer.write(index * sizeof(int),
+ values.constData(), values.size() * sizeof(int));
+ d->buffer.release();
+ } else {
+ QArray<ushort> svalues = qt_qarray_uint_to_ushort(values);
+ d->buffer.bind();
+ d->buffer.write(index * sizeof(ushort),
+ svalues.constData(),
+ svalues.size() * sizeof(ushort));
+ d->buffer.release();
+ }
+ } else if (d->elementType == GL_UNSIGNED_INT) {
+ d->indexesInt.replace(index, values.constData(), values.size());
+ d->indexCount = d->indexesInt.size();
+ } else {
+ QArray<ushort> svalues = qt_qarray_uint_to_ushort(values);
+ d->indexesShort.replace(index, svalues.constData(), svalues.size());
+ d->indexCount = d->indexesShort.size();
+ }
+}
+
+/*!
+ Returns the element type for this index buffer, \c{GL_UNSIGNED_SHORT}
+ or \c{GL_UNSIGNED_INT}.
+*/
+GLenum QGLIndexBuffer::elementType() const
+{
+ Q_D(const QGLIndexBuffer);
+ return d->elementType;
+}
+
+/*!
+ Returns the number of indexes in this index buffer.
+*/
+int QGLIndexBuffer::indexCount() const
+{
+ Q_D(const QGLIndexBuffer);
+ return d->indexCount;
+}
+
+/*!
+ \fn bool QGLIndexBuffer::isEmpty() const
+
+ Returns true if indexCount() is zero; false otherwise.
+*/
+
+/*!
+ Uploads the index data specified by a previous setIndexes()
+ call into the GL server as an index buffer object.
+
+ Returns true if the data could be uploaded; false if index buffer
+ objects are not supported or there is insufficient memory to complete
+ the request. Returns true if the data was already uploaded.
+
+ Once the index data has been uploaded, the client-side copies of
+ the data arrays will be released. If the index data could not be
+ uploaded, then it is retained client-side. This way, regardless of
+ whether the data could be uploaded or not, QGLPainter::draw() can
+ be used to support drawing of primitives using this object.
+
+ \sa isUploaded(), setIndexes(), QGLPainter::draw()
+*/
+bool QGLIndexBuffer::upload()
+{
+ Q_D(QGLIndexBuffer);
+ if (d->buffer.isCreated())
+ return true;
+ if (!d->buffer.create())
+ return false;
+ d->buffer.bind();
+ if (d->elementType == GL_UNSIGNED_SHORT) {
+ d->buffer.allocate(d->indexesShort.constData(),
+ d->indexesShort.size() * sizeof(ushort));
+ d->indexesShort = QArray<ushort>();
+ } else {
+ d->buffer.allocate(d->indexesInt.constData(),
+ d->indexesInt.size() * sizeof(int));
+ d->indexesInt = QArray<uint>();
+ }
+ d->buffer.release();
+ return true;
+}
+
+/*!
+ Returns true if the index data specified by previous a setIndexes()
+ call has been uploaded into the GL server; false otherwise.
+
+ \sa upload(), setIndexes()
+*/
+bool QGLIndexBuffer::isUploaded() const
+{
+ Q_D(const QGLIndexBuffer);
+ return d->buffer.isCreated();
+}
+
+/*!
+ Returns the QGLBuffer in use by this index buffer object,
+ so that its properties or contents can be modified directly.
+
+ \sa isUploaded()
+*/
+QGLBuffer QGLIndexBuffer::buffer() const
+{
+ Q_D(const QGLIndexBuffer);
+ return d->buffer;
+}
+
+/*!
+ Binds this index buffer to the current GL context. Returns false if
+ binding was not possible, usually because upload() has not been called.
+
+ The buffer must be bound to the same QGLContext current when upload()
+ was called, or to another QGLContext that is sharing with it.
+ Otherwise, false will be returned from this function.
+
+ \sa release(), upload()
+*/
+bool QGLIndexBuffer::bind()
+{
+ Q_D(QGLIndexBuffer);
+ return d->buffer.bind();
+}
+
+/*!
+ Releases this index buffer from the current GL context.
+
+ This function must be called with the same QGLContext current
+ as when bind() was called on the index buffer.
+
+ \sa bind()
+*/
+void QGLIndexBuffer::release()
+{
+ Q_D(QGLIndexBuffer);
+ d->buffer.release();
+}
+
+void QGLIndexBufferPrivate::append
+ (const QGLIndexBufferPrivate *other, uint offset, int start)
+{
+ if (elementType == GL_UNSIGNED_SHORT &&
+ other->elementType == GL_UNSIGNED_SHORT) {
+ // Both buffers are ushort.
+ const ushort *data = other->indexesShort.constData() + start;
+ int count = other->indexesShort.count() - start;
+ indexesShort.reserve(indexesShort.count() + count);
+ indexCount += count;
+ while (count-- > 0)
+ indexesShort.append(ushort(*data++ + offset));
+ } else if (elementType == GL_UNSIGNED_SHORT) {
+ // Only first buffer is ushort: convert it to int first.
+ const ushort *indexes = indexesShort.constData();
+ int count = indexesShort.count();
+ indexesInt.reserve(count + other->indexesInt.count());
+ while (count-- > 0)
+ indexesInt.append(*indexes++);
+ indexesShort = QArray<ushort>();
+ elementType = GL_UNSIGNED_INT;
+ const uint *data = other->indexesInt.constData() + start;
+ count = other->indexesInt.count() - start;
+ indexCount += count;
+ while (count-- > 0)
+ indexesInt.append(*data++ + offset);
+ } else if (other->elementType == GL_UNSIGNED_SHORT) {
+ // Only second buffer is ushort.
+ const ushort *data = other->indexesShort.constData() + start;
+ int count = other->indexesShort.count() - start;
+ indexesInt.reserve(indexesInt.count() + count);
+ indexCount += count;
+ while (count-- > 0)
+ indexesInt.append(*data++ + offset);
+ } else {
+ // Neither buffer is ushort.
+ const uint *data = other->indexesInt.constData() + start;
+ int count = other->indexesInt.count() - start;
+ indexesInt.reserve(indexesInt.count() + count);
+ indexCount += count;
+ while (count-- > 0)
+ indexesInt.append(*data++ + offset);
+ }
+}
+
+uint QGLIndexBufferPrivate::headIndex(int posn) const
+{
+ if (indexCount <= posn)
+ return uint(-1);
+ if (elementType == GL_UNSIGNED_SHORT)
+ return indexesShort[posn];
+ else
+ return indexesInt[posn];
+}
+
+uint QGLIndexBufferPrivate::tailIndex(int posn) const
+{
+ if (indexCount <= posn)
+ return uint(-1);
+ if (elementType == GL_UNSIGNED_SHORT)
+ return indexesShort[indexCount - posn - 1];
+ else
+ return indexesInt[indexCount - posn - 1];
+}
+
+/*!
+ Appends the contents of \a buffer to this index buffer and adds
+ \a offset to all of the entries in \a buffer.
+
+ This function is typically used to combine multiple geometry meshes
+ into a single mesh that can be bound as a single buffer.
+
+ The request is ignored if this index buffer or \a buffer have already
+ been uploaded, or \a buffer is this index buffer.
+
+ \sa isUploaded(), setIndexes()
+*/
+void QGLIndexBuffer::append(const QGLIndexBuffer &buffer, uint offset)
+{
+ Q_D(QGLIndexBuffer);
+ const QGLIndexBufferPrivate *dbuf = buffer.d_ptr;
+
+ // Bail out if the buffers are uploaded or identical.
+ if (d->buffer.isCreated() || dbuf->buffer.isCreated())
+ return;
+ if (d == dbuf)
+ return;
+
+ // Append the two index arrays.
+ d->append(dbuf, offset, 0);
+}
+
+/*!
+ Appends the contents of \a buffer to this index buffer and adds
+ \a offset to all of the entries in \a buffer.
+
+ The two buffers will be merged at the join point according to
+ \a combineMode. For example, if \a combineMode is QGL::TriangleStrip,
+ then the result will be a single triangle strip. Indexes are
+ dropped from the front of \a buffer as necessary to correctly
+ merge the buffers.
+
+ This function is typically used to combine multiple geometry meshes
+ into a single mesh that can be bound as a single buffer.
+
+ The request is ignored if this index buffer or \a buffer have already
+ been uploaded, or \a buffer is this index buffer.
+
+ \sa isUploaded(), setIndexes()
+*/
+void QGLIndexBuffer::append
+ (const QGLIndexBuffer &buffer, uint offset, QGL::DrawingMode combineMode)
+{
+ Q_D(QGLIndexBuffer);
+ const QGLIndexBufferPrivate *dbuf = buffer.d_ptr;
+
+ // Bail out if the buffers are uploaded or identical.
+ if (d->buffer.isCreated() || dbuf->buffer.isCreated())
+ return;
+ if (d == dbuf)
+ return;
+
+ // Determine how to combine the buffers.
+ switch (int(combineMode)) {
+ case QGL::Points:
+ case QGL::Lines:
+ case QGL::Triangles:
+ case QGL::LinesAdjacency:
+ case QGL::TrianglesAdjacency:
+ case 0x0007: // GL_QUADS
+ // These can be done by just appending the raw data with no changes.
+ d->append(dbuf, offset, 0);
+ break;
+
+ case QGL::LineLoop:
+ case QGL::LineStrip:
+ case 0x0009: // GL_POLYGON
+ // Join the last index of the first buffer to the first
+ // index of the second buffer to continue the loop or strip.
+ if (d->tailIndex(0) == (dbuf->headIndex(0) + offset))
+ d->append(dbuf, offset, 1);
+ else
+ d->append(dbuf, offset, 0);
+ break;
+
+ case QGL::TriangleStrip:
+ // Join the last two indexes of the first buffer to the first
+ // two indexes of the second buffer to continue the strip.
+ // It is possible that the first two indexes of the second
+ // buffer may be reversed for strip continuation depending
+ // upon whether the first strip is odd or even in length.
+ if (d->tailIndex(1) == (dbuf->headIndex(0) + offset) &&
+ d->tailIndex(0) == (dbuf->headIndex(1) + offset))
+ d->append(dbuf, offset, 2);
+ else if (d->tailIndex(1) == (dbuf->headIndex(1) + offset) &&
+ d->tailIndex(0) == (dbuf->headIndex(0) + offset))
+ d->append(dbuf, offset, 2);
+ else
+ d->append(dbuf, offset, 0);
+ break;
+
+ case 0x0008: // GL_QUAD_STRIP
+ // Join the last two indexes of the first buffer to the first
+ // two indexes of the second buffer to continue the strip.
+ if (d->tailIndex(1) == (dbuf->headIndex(0) + offset) &&
+ d->tailIndex(0) == (dbuf->headIndex(1) + offset))
+ d->append(dbuf, offset, 2);
+ else
+ d->append(dbuf, offset, 0);
+ break;
+
+ case QGL::TriangleFan:
+ // The first index of both buffers should be the same, and the
+ // last index of the first buffer should be the same as the second
+ // index of the second buffer.
+ if (d->headIndex(0) == (dbuf->headIndex(0) + offset) &&
+ d->tailIndex(0) == (dbuf->headIndex(1) + offset))
+ d->append(dbuf, offset, 2);
+ else
+ d->append(dbuf, offset, 0);
+ break;
+
+ case QGL::LineStripAdjacency:
+ // Join the last three indexes of the first buffer to the first
+ // three indexes of the second buffer to continue the strip.
+ if (d->tailIndex(2) == (dbuf->headIndex(0) + offset) &&
+ d->tailIndex(1) == (dbuf->headIndex(1) + offset) &&
+ d->tailIndex(0) == (dbuf->headIndex(2) + offset))
+ d->append(dbuf, offset, 3);
+ else
+ d->append(dbuf, offset, 0);
+ break;
+
+ case QGL::TriangleStripAdjacency:
+ // Fourth last and second last of first buffer need to be the
+ // same as the first and third of the second buffer.
+ if (d->tailIndex(3) == (dbuf->headIndex(0) + offset) &&
+ d->tailIndex(1) == (dbuf->headIndex(2) + offset))
+ d->append(dbuf, offset, 4);
+ else
+ d->append(dbuf, offset, 0);
+ break;
+
+ default:
+ qWarning("QGLIndexBuffer::append: unknown drawing mode 0x%04x",
+ int(combineMode));
+ break;
+ }
+}
+
+/*!
+ \overload
+
+ Draws primitives using vertices from the arrays specified by
+ setVertexAttribute(). The type of primitive to draw is
+ specified by \a mode.
+
+ This operation will consume all of the elements of \a indexes,
+ which are used to index into the enabled arrays.
+
+ If \a indexes has not been uploaded to the GL server as an index
+ buffer, then this function will draw using a client-side array.
+
+ \sa update(), QGLIndexBuffer::upload()
+*/
+void QGLPainter::draw(QGL::DrawingMode mode, const QGLIndexBuffer& indexes)
+{
+ QGLIndexBufferPrivate *d = const_cast<QGLIndexBufferPrivate *>(indexes.d_func());
+ update();
+ GLuint id = d->buffer.bufferId();
+ if (id != d_ptr->boundIndexBuffer) {
+ if (id)
+ d->buffer.bind();
+ else
+ QGLBuffer::release(QGLBuffer::IndexBuffer);
+ d_ptr->boundIndexBuffer = id;
+ }
+ if (id) {
+ glDrawElements(GLenum(mode), d->indexCount, d->elementType, 0);
+ } else if (d->elementType == GL_UNSIGNED_SHORT) {
+ glDrawElements(GLenum(mode), d->indexCount, GL_UNSIGNED_SHORT,
+ d->indexesShort.constData());
+ } else {
+ glDrawElements(GLenum(mode), d->indexCount, GL_UNSIGNED_INT,
+ d->indexesInt.constData());
+ }
+}
+
+/*!
+ \overload
+
+ Draws primitives using vertices from the arrays specified by
+ setVertexAttribute(). The type of primitive to draw is
+ specified by \a mode.
+
+ This operation will consume \a count elements of \a indexes,
+ starting at \a offset, which are used to index into the enabled arrays.
+
+ If \a indexes has not been uploaded to the GL server as an index
+ buffer, then this function will draw using a client-side array.
+
+ \sa update(), QGLIndexBuffer::upload()
+*/
+void QGLPainter::draw(QGL::DrawingMode mode, const QGLIndexBuffer& indexes, int offset, int count)
+{
+ QGLIndexBufferPrivate *d = const_cast<QGLIndexBufferPrivate *>(indexes.d_func());
+ update();
+ GLuint id = d->buffer.bufferId();
+ if (id != d_ptr->boundIndexBuffer) {
+ if (id)
+ d->buffer.bind();
+ else
+ QGLBuffer::release(QGLBuffer::IndexBuffer);
+ d_ptr->boundIndexBuffer = id;
+ }
+ if (id) {
+ if (d->elementType == GL_UNSIGNED_SHORT) {
+ glDrawElements(GLenum(mode), count, GL_UNSIGNED_SHORT,
+ reinterpret_cast<const void *>(offset * sizeof(ushort)));
+ } else {
+ glDrawElements(GLenum(mode), count, GL_UNSIGNED_INT,
+ reinterpret_cast<const void *>(offset * sizeof(int)));
+ }
+ } else if (d->elementType == GL_UNSIGNED_SHORT) {
+ glDrawElements(GLenum(mode), count, GL_UNSIGNED_SHORT,
+ d->indexesShort.constData() + offset);
+ } else {
+ glDrawElements(GLenum(mode), count, GL_UNSIGNED_INT,
+ d->indexesInt.constData() + offset);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qglindexbuffer.h b/src/threed/arrays/qglindexbuffer.h
new file mode 100644
index 000000000..c3e92e4f8
--- /dev/null
+++ b/src/threed/arrays/qglindexbuffer.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLINDEXBUFFER_H
+#define QGLINDEXBUFFER_H
+
+#include <QtOpenGL/qgl.h>
+#include <QtOpenGL/qglbuffer.h>
+#include "qglnamespace.h"
+#include "qarray.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLIndexBufferPrivate;
+class QGLPainter;
+
+class Q_QT3D_EXPORT QGLIndexBuffer
+{
+public:
+ QGLIndexBuffer();
+ QGLIndexBuffer(const QGLIndexBuffer& other);
+ ~QGLIndexBuffer();
+
+ QGLIndexBuffer& operator=(const QGLIndexBuffer& other);
+
+ QGLBuffer::UsagePattern usagePattern() const;
+ void setUsagePattern(QGLBuffer::UsagePattern value);
+
+ QArray<ushort> indexesUShort() const;
+ QArray<uint> indexesUInt() const;
+
+ void setIndexes(const QArray<ushort>& values);
+ void setIndexes(const QArray<uint>& values);
+
+ void replaceIndexes(int index, const QArray<ushort>& values);
+ void replaceIndexes(int index, const QArray<uint>& values);
+
+ GLenum elementType() const;
+
+ int indexCount() const;
+ bool isEmpty() const { return indexCount() == 0; }
+
+ bool upload();
+ bool isUploaded() const;
+
+ QGLBuffer buffer() const;
+
+ bool bind();
+ void release();
+
+ void append(const QGLIndexBuffer &buffer, uint offset);
+ void append(const QGLIndexBuffer &buffer, uint offset, QGL::DrawingMode combineMode);
+
+private:
+ QGLIndexBufferPrivate *d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLIndexBuffer)
+
+ friend class QGLPainter;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qglvertexbundle.cpp b/src/threed/arrays/qglvertexbundle.cpp
new file mode 100644
index 000000000..000c93c84
--- /dev/null
+++ b/src/threed/arrays/qglvertexbundle.cpp
@@ -0,0 +1,495 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglvertexbundle.h"
+#include "qglvertexbundle_p.h"
+#include "qglabstracteffect.h"
+#include <QtCore/qlist.h>
+#include <QtCore/qatomic.h>
+#include <QtOpenGL/qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLVertexBundle
+ \brief The QGLVertexBundle class bundles vertex attribute arrays for efficient uploading into a GL server.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ QGLVertexBundle provides an implementation of a static vertex
+ buffer, where the vertex attributes are supplied once at construction
+ time and then never modified until the bundle is destroyed.
+ When the vertex attributes are sent ot the GL server by upload(),
+ they may be repacked for greater drawing efficiency.
+
+ For general-purpose vertex buffers that can be allocated and modified
+ in-place, use QGLBuffer instead.
+*/
+
+/*!
+ Constructs a new vertex bundle.
+*/
+QGLVertexBundle::QGLVertexBundle()
+ : d_ptr(new QGLVertexBundlePrivate())
+{
+}
+
+/*!
+ Creates a copy of \a other. Note that this just copies a reference
+ to the vertex bundle. Any modifications to the copy will also
+ affect the original object.
+*/
+QGLVertexBundle::QGLVertexBundle(const QGLVertexBundle& other)
+ : d_ptr(other.d_ptr)
+{
+ d_ptr->ref.ref();
+}
+
+/*!
+ Destroys this vertex bundle if this object is the last reference to it.
+*/
+QGLVertexBundle::~QGLVertexBundle()
+{
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+}
+
+/*!
+ Assigns \a other to this object. Note that this just assigns a
+ reference to the \a other vertex bundle. Any modifications to this
+ object will also affect \a other.
+*/
+QGLVertexBundle& QGLVertexBundle::operator=(const QGLVertexBundle& other)
+{
+ if (d_ptr != other.d_ptr) {
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+ d_ptr = other.d_ptr;
+ d_ptr->ref.ref();
+ }
+ return *this;
+}
+
+/*!
+ Adds the floating-point array \a value to this vertex bundle as the
+ data for \a attribute.
+
+ \sa upload()
+*/
+void QGLVertexBundle::addAttribute
+ (QGL::VertexAttribute attribute, const QArray<float>& value)
+{
+ Q_D(QGLVertexBundle);
+ if (!d->buffer.isCreated()) {
+ d->attributeSet.insert(attribute);
+ d->attributes +=
+ new QGLVertexBundleFloatAttribute(attribute, value);
+ d->vertexCount = qMax(d->vertexCount, value.count());
+ }
+}
+
+/*!
+ Adds the 2D vector array \a value to this vertex bundle as the
+ data for \a attribute.
+
+ \sa upload()
+*/
+void QGLVertexBundle::addAttribute
+ (QGL::VertexAttribute attribute, const QArray<QVector2D>& value)
+{
+ Q_D(QGLVertexBundle);
+ if (!d->buffer.isCreated()) {
+ d->attributeSet.insert(attribute);
+ d->attributes +=
+ new QGLVertexBundleVector2DAttribute(attribute, value);
+ d->vertexCount = qMax(d->vertexCount, value.count());
+ }
+}
+
+/*!
+ Adds the 3D vector array \a value to this vertex bundle as the
+ data for \a attribute.
+
+ \sa upload()
+*/
+void QGLVertexBundle::addAttribute
+ (QGL::VertexAttribute attribute, const QArray<QVector3D>& value)
+{
+ Q_D(QGLVertexBundle);
+ if (!d->buffer.isCreated()) {
+ d->attributeSet.insert(attribute);
+ d->attributes +=
+ new QGLVertexBundleVector3DAttribute(attribute, value);
+ d->vertexCount = qMax(d->vertexCount, value.count());
+ }
+}
+
+/*!
+ Adds the 4D vector array \a value to this vertex bundle as the
+ data for \a attribute.
+
+ \sa upload()
+*/
+void QGLVertexBundle::addAttribute
+ (QGL::VertexAttribute attribute, const QArray<QVector4D>& value)
+{
+ Q_D(QGLVertexBundle);
+ if (!d->buffer.isCreated()) {
+ d->attributeSet.insert(attribute);
+ d->attributes +=
+ new QGLVertexBundleVector4DAttribute(attribute, value);
+ d->vertexCount = qMax(d->vertexCount, value.count());
+ }
+}
+
+/*!
+ Adds the color array \a value to this vertex bundle as the
+ data for \a attribute.
+
+ \sa upload()
+*/
+void QGLVertexBundle::addAttribute
+ (QGL::VertexAttribute attribute, const QArray<QColor4ub>& value)
+{
+ Q_D(QGLVertexBundle);
+ if (!d->buffer.isCreated()) {
+ d->attributeSet.insert(attribute);
+ d->attributes +=
+ new QGLVertexBundleColorAttribute(attribute, value);
+ d->vertexCount = qMax(d->vertexCount, value.count());
+ }
+}
+
+/*!
+ Adds the custom data array \a value to this vertex bundle as the
+ data for \a attribute.
+
+ \sa upload()
+*/
+void QGLVertexBundle::addAttribute
+ (QGL::VertexAttribute attribute, const QCustomDataArray& value)
+{
+ Q_D(QGLVertexBundle);
+ if (!d->buffer.isCreated()) {
+ d->attributeSet.insert(attribute);
+ d->attributes +=
+ new QGLVertexBundleCustomAttribute(attribute, value);
+ d->vertexCount = qMax(d->vertexCount, value.count());
+ }
+}
+
+// Interleave a source array into a destination array.
+static void vertexBufferInterleave
+ (float *dst, int dstStride, const float *src, int srcStride, int count)
+{
+ switch (srcStride) {
+ case 1:
+ while (count-- > 0) {
+ dst[0] = src[0];
+ ++src;
+ dst += dstStride;
+ }
+ break;
+ case 2:
+ while (count-- > 0) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 2;
+ dst += dstStride;
+ }
+ break;
+ case 3:
+ while (count-- > 0) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ src += 3;
+ dst += dstStride;
+ }
+ break;
+ case 4:
+ while (count-- > 0) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ src += 4;
+ dst += dstStride;
+ }
+ break;
+ default:
+ while (count-- > 0) {
+ for (int component = 0; component < srcStride; ++component)
+ dst[component] = src[component];
+ src += srcStride;
+ dst += dstStride;
+ }
+ break;
+ }
+}
+
+/*!
+ Returns the set of attributes that are present in this vertex bundle.
+*/
+QGLAttributeSet QGLVertexBundle::attributes() const
+{
+ Q_D(const QGLVertexBundle);
+ return d->attributeSet;
+}
+
+/*!
+ Returns the raw attribute value associated with \a attribute in
+ this vertex bundle; null if \a attribute does not exist in the
+ vertex bundle.
+
+ If isUploaded() is true, then the returned value will contain a
+ buffer offset to the attribute. If isUploaded() is false,
+ then the returned value will contain a client-side data pointer
+ to the attribute.
+
+ \sa addAttribute()
+*/
+QGLAttributeValue QGLVertexBundle::attributeValue(QGL::VertexAttribute attribute) const
+{
+ Q_D(const QGLVertexBundle);
+ QGLVertexBundleAttribute *attr = 0;
+ int attrIndex;
+ for (attrIndex = 0; attrIndex < d->attributes.size(); ++attrIndex) {
+ attr = d->attributes[attrIndex];
+ if (attr->attribute == attribute)
+ return attr->value;
+ }
+ return QGLAttributeValue();
+}
+
+/*!
+ Returns the number of vertices that were defined by previous
+ called to addAttribute().
+
+ \sa addAttribute()
+*/
+int QGLVertexBundle::vertexCount() const
+{
+ Q_D(const QGLVertexBundle);
+ return d->vertexCount;
+}
+
+/*!
+ \fn bool QGLVertexBundle::isEmpty() const
+
+ Returns true if vertexCount() is zero; false otherwise.
+*/
+
+/*!
+ Uploads the vertex data specified by previous addAttribute()
+ calls into the GL server as a vertex buffer object.
+
+ Returns true if the data could be uploaded; false if vertex buffer
+ objects are not supported or there is insufficient memory to complete
+ the request. Returns true if the data was already uploaded.
+
+ Once the vertex data has been uploaded, the client-side copies of
+ the data arrays will be released. If the vertex data could not be
+ uploaded, then it is retained client-side. This way, regardless of
+ whether the data could be uploaded or not, QGLPainter::setVertexBundle()
+ can be used to support drawing of primitives using this object.
+
+ \sa isUploaded(), addAttribute(), QGLPainter::setVertexBundle()
+*/
+bool QGLVertexBundle::upload()
+{
+ Q_D(QGLVertexBundle);
+ QGLVertexBundleAttribute *attr;
+
+ // Nothing to do if already uploaded or there are no attributes.
+ if (d->buffer.isCreated())
+ return true;
+ if (d->attributes.isEmpty())
+ return false;
+
+ // Create the VBO in the GL server and bind it.
+ if (!d->buffer.create())
+ return false;
+ d->buffer.bind();
+
+ // If there is only one attribute, then realloc and write in one step.
+ if (d->attributes.size() == 1) {
+ attr = d->attributes[0];
+ d->buffer.allocate(attr->value.data(),
+ attr->count() * attr->elementSize());
+ attr->value.setOffset(0);
+ attr->clear();
+ d->buffer.release();
+ return true;
+ }
+
+ // Calculate the total size of the VBO that we will need,
+ // the maximum number of interleaved vertices, and the
+ // interleaved stride.
+ int size = 0;
+ int stride = 0;
+ int maxCount = 0;
+ for (int index = 0; index < d->attributes.size(); ++index) {
+ attr = d->attributes[index];
+ int count = attr->count();
+ if (count > maxCount)
+ maxCount = count;
+ int elemSize = attr->elementSize();
+ size += count * elemSize;
+ stride += elemSize;
+ }
+ int bufferSize = size;
+ d->buffer.allocate(bufferSize);
+ stride /= sizeof(float);
+
+ // Determine how to upload the data, using a map if possible.
+ // Interleave the data into the final buffer. We do it in
+ // sections so as to keep locality problems to a minimum.
+ void *mapped = d->buffer.map(QGLBuffer::WriteOnly);
+ int offset = 0;
+ QArray<float> temp;
+ float *dst;
+ if (mapped)
+ dst = reinterpret_cast<float *>(mapped);
+ else
+ dst = temp.extend(1024);
+ int sectionSize = 1024 / stride;
+ for (int vertex = 0; vertex < maxCount; vertex += sectionSize) {
+ int attrPosn = 0;
+ for (int index = 0; index < d->attributes.size(); ++index) {
+ attr = d->attributes[index];
+ int count = attr->count() - vertex;
+ if (count <= 0)
+ continue;
+ count = qMin(count, sectionSize);
+ int components = attr->elementSize() / sizeof(float);
+ vertexBufferInterleave
+ (dst + attrPosn, stride,
+ reinterpret_cast<const float *>(attr->value.data()) +
+ vertex * components,
+ components, count);
+ attrPosn += attr->elementSize() / sizeof(float);
+ }
+ size = sectionSize * stride;
+ if (mapped) {
+ dst += size;
+ } else {
+ size *= sizeof(float);
+ if ((offset + size) > bufferSize) // buffer overflow check
+ size = bufferSize-offset;
+ d->buffer.write(offset, dst, size);
+ offset += size;
+ }
+ }
+ offset = 0;
+ for (int index = 0; index < d->attributes.size(); ++index) {
+ attr = d->attributes[index];
+ attr->value.setOffset(offset);
+ attr->value.setStride(stride * sizeof(float));
+ offset += attr->elementSize();
+ attr->clear();
+ }
+ if (mapped)
+ d->buffer.unmap();
+
+ // Buffer is uploaded and ready to go.
+ d->buffer.release();
+ return true;
+}
+
+/*!
+ Returns true if the vertex data specified by previous addAttribute()
+ calls has been uploaded into the GL server; false otherwise.
+
+ \sa upload(), addAttribute()
+*/
+bool QGLVertexBundle::isUploaded() const
+{
+ Q_D(const QGLVertexBundle);
+ return d->buffer.isCreated();
+}
+
+/*!
+ Returns the QGLBuffer in use by this vertex bundle object,
+ so that its properties or contents can be modified directly.
+
+ \sa isUploaded()
+*/
+QGLBuffer QGLVertexBundle::buffer() const
+{
+ Q_D(const QGLVertexBundle);
+ return d->buffer;
+}
+
+/*!
+ Binds the vertex buffer associated with this bundle to the current GL
+ context. Returns false if binding was not possible, usually because
+ upload() has not been called.
+
+ The buffer must be bound to the same QGLContext current when upload()
+ was called, or to another QGLContext that is sharing with it.
+ Otherwise, false will be returned from this function.
+
+ \sa release(), upload()
+*/
+bool QGLVertexBundle::bind()
+{
+ Q_D(QGLVertexBundle);
+ return d->buffer.bind();
+}
+
+/*!
+ Releases the vertex buffer associated with this bundle from the
+ current GL context.
+
+ This function must be called with the same QGLContext current
+ as when bind() was called on the vertex buffer.
+
+ \sa bind()
+*/
+void QGLVertexBundle::release()
+{
+ Q_D(QGLVertexBundle);
+ d->buffer.release();
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qglvertexbundle.h b/src/threed/arrays/qglvertexbundle.h
new file mode 100644
index 000000000..8776782e8
--- /dev/null
+++ b/src/threed/arrays/qglvertexbundle.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLVERTEXBUNDLE_H
+#define QGLVERTEXBUNDLE_H
+
+#include <QtOpenGL/qglbuffer.h>
+#include "qcustomdataarray.h"
+#include "qglattributevalue.h"
+#include "qglattributeset.h"
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLVertexBundlePrivate;
+class QGLPainter;
+class QGLAbstractEffect;
+class QGLShaderProgram;
+
+class Q_QT3D_EXPORT QGLVertexBundle
+{
+public:
+ QGLVertexBundle();
+ QGLVertexBundle(const QGLVertexBundle& other);
+ ~QGLVertexBundle();
+
+ QGLVertexBundle& operator=(const QGLVertexBundle& other);
+
+ void addAttribute(QGL::VertexAttribute attribute,
+ const QArray<float>& value);
+ void addAttribute(QGL::VertexAttribute attribute,
+ const QArray<QVector2D>& value);
+ void addAttribute(QGL::VertexAttribute attribute,
+ const QArray<QVector3D>& value);
+ void addAttribute(QGL::VertexAttribute attribute,
+ const QArray<QVector4D>& value);
+ void addAttribute(QGL::VertexAttribute attribute,
+ const QArray<QColor4ub>& value);
+ void addAttribute(QGL::VertexAttribute attribute,
+ const QCustomDataArray& value);
+
+ QGLAttributeSet attributes() const;
+
+ QGLAttributeValue attributeValue(QGL::VertexAttribute attribute) const;
+
+ int vertexCount() const;
+ bool isEmpty() const { return vertexCount() == 0; }
+
+ bool upload();
+ bool isUploaded() const;
+
+ QGLBuffer buffer() const;
+
+ bool bind();
+ void release();
+
+private:
+ QGLVertexBundlePrivate *d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLVertexBundle)
+
+ friend class QGLPainter;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qglvertexbundle_p.h b/src/threed/arrays/qglvertexbundle_p.h
new file mode 100644
index 000000000..ae2866be5
--- /dev/null
+++ b/src/threed/arrays/qglvertexbundle_p.h
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLVERTEXBUNDLE_P_H
+#define QGLVERTEXBUNDLE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglvertexbundle.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLVertexBundleAttribute
+{
+public:
+ QGLVertexBundleAttribute(QGL::VertexAttribute attr) : attribute(attr) {}
+ virtual ~QGLVertexBundleAttribute() {}
+
+ virtual void clear() = 0;
+ virtual QGLAttributeValue uploadValue() = 0;
+ virtual int count() = 0;
+ virtual int elementSize() = 0;
+
+ QGL::VertexAttribute attribute;
+ QGLAttributeValue value;
+};
+
+class QGLVertexBundleFloatAttribute : public QGLVertexBundleAttribute
+{
+public:
+ QGLVertexBundleFloatAttribute
+ (QGL::VertexAttribute attr, const QArray<float>& array)
+ : QGLVertexBundleAttribute(attr), floatArray(array)
+ {
+ value = QGLAttributeValue(floatArray);
+ }
+
+ void clear() { floatArray.clear(); }
+ QGLAttributeValue uploadValue()
+ { return QGLAttributeValue(floatArray); }
+ int count() { return floatArray.count(); }
+ int elementSize() { return sizeof(float); }
+
+ QArray<float> floatArray;
+};
+
+class QGLVertexBundleVector2DAttribute : public QGLVertexBundleAttribute
+{
+public:
+ QGLVertexBundleVector2DAttribute
+ (QGL::VertexAttribute attr, const QArray<QVector2D>& array)
+ : QGLVertexBundleAttribute(attr), vector2DArray(array)
+ {
+ value = QGLAttributeValue(vector2DArray);
+ }
+
+ void clear() { vector2DArray.clear(); }
+ QGLAttributeValue uploadValue()
+ { return QGLAttributeValue(vector2DArray); }
+ int count() { return vector2DArray.count(); }
+ int elementSize() { return sizeof(QVector2D); }
+
+ QArray<QVector2D> vector2DArray;
+};
+
+class QGLVertexBundleVector3DAttribute : public QGLVertexBundleAttribute
+{
+public:
+ QGLVertexBundleVector3DAttribute
+ (QGL::VertexAttribute attr, const QArray<QVector3D>& array)
+ : QGLVertexBundleAttribute(attr), vector3DArray(array)
+ {
+ value = QGLAttributeValue(vector3DArray);
+ }
+
+ void clear() { vector3DArray.clear(); }
+ QGLAttributeValue uploadValue()
+ { return QGLAttributeValue(vector3DArray); }
+ int count() { return vector3DArray.count(); }
+ int elementSize() { return sizeof(QVector3D); }
+
+ QArray<QVector3D> vector3DArray;
+};
+
+class QGLVertexBundleVector4DAttribute : public QGLVertexBundleAttribute
+{
+public:
+ QGLVertexBundleVector4DAttribute
+ (QGL::VertexAttribute attr, const QArray<QVector4D>& array)
+ : QGLVertexBundleAttribute(attr), vector4DArray(array)
+ {
+ value = QGLAttributeValue(vector4DArray);
+ }
+
+ void clear() { vector4DArray.clear(); }
+ QGLAttributeValue uploadValue()
+ { return QGLAttributeValue(vector4DArray); }
+ int count() { return vector4DArray.count(); }
+ int elementSize() { return sizeof(QVector4D); }
+
+ QArray<QVector4D> vector4DArray;
+};
+
+class QGLVertexBundleColorAttribute : public QGLVertexBundleAttribute
+{
+public:
+ QGLVertexBundleColorAttribute
+ (QGL::VertexAttribute attr, const QArray<QColor4ub>& array)
+ : QGLVertexBundleAttribute(attr), colorArray(array)
+ {
+ value = QGLAttributeValue(colorArray);
+ }
+
+ void clear() { colorArray.clear(); }
+ QGLAttributeValue uploadValue()
+ { return QGLAttributeValue(colorArray); }
+ int count() { return colorArray.count(); }
+ int elementSize() { return sizeof(QColor4ub); }
+
+ QArray<QColor4ub> colorArray;
+};
+
+class QGLVertexBundleCustomAttribute : public QGLVertexBundleAttribute
+{
+public:
+ QGLVertexBundleCustomAttribute
+ (QGL::VertexAttribute attr, const QCustomDataArray& array)
+ : QGLVertexBundleAttribute(attr), customArray(array)
+ {
+ value = QGLAttributeValue(customArray);
+ }
+
+ void clear() { customArray.clear(); }
+ QGLAttributeValue uploadValue()
+ { return QGLAttributeValue(customArray); }
+ int count() { return customArray.count(); }
+ int elementSize() { return customArray.elementSize(); }
+
+ QCustomDataArray customArray;
+};
+
+class QGLVertexBundlePrivate
+{
+public:
+ QGLVertexBundlePrivate()
+ : buffer(QGLBuffer::VertexBuffer),
+ vertexCount(0)
+ {
+ ref = 1;
+ }
+ ~QGLVertexBundlePrivate()
+ {
+ qDeleteAll(attributes);
+ }
+
+ QBasicAtomicInt ref;
+ QGLBuffer buffer;
+ QList<QGLVertexBundleAttribute *> attributes;
+ int vertexCount;
+ QGLAttributeSet attributeSet;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qvector2darray.cpp b/src/threed/arrays/qvector2darray.cpp
new file mode 100644
index 000000000..368417f4d
--- /dev/null
+++ b/src/threed/arrays/qvector2darray.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvector2darray.h"
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QVector2DArray
+ \brief The QVector2DArray class is a convenience for wrapping a QArray of QVector2D values.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ QVector2DArray is used to build an array of 2D vector values
+ based on floating-point x and y arguments:
+
+ \code
+ QVector2DArray array;
+ array.append(1.0f, 2.0f);
+ array.append(-1.0f, 2.0f);
+ array.append(1.0f, -2.0f);
+ \endcode
+
+ This is more convenient and readable than the equivalent with
+ QArray:
+
+ \code
+ QArray<QVector2D> array;
+ array.append(QVector2D(1.0f, 2.0f));
+ array.append(QVector2D(-1.0f, 2.0f));
+ array.append(QVector2D(1.0f, -2.0f));
+ \endcode
+
+ QVector2DArray also has convenience functions for transforming
+ the contents of the array with translate(), translated(),
+ transform(), and transformed().
+
+ \sa QArray, QVector3DArray, QVector4DArray
+*/
+
+/*!
+ \fn QVector2DArray::QVector2DArray()
+
+ Constructs an empty array of QVector2D values.
+*/
+
+/*!
+ \fn QVector2DArray::QVector2DArray(int size, const QVector2D& value)
+
+ Constructs an array of QVector2D values with an initial \a size.
+ All elements in the array are initialized to \a value.
+*/
+
+/*!
+ \fn QVector2DArray::QVector2DArray(const QArray<QVector2D>& other)
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ \fn void QVector2DArray::append(qreal x, qreal y)
+ \overload
+
+ Appends (\a x, \a y) to this array of QVector2D values.
+*/
+
+/*!
+ \fn void QVector2DArray::append(const QPointF& point)
+ \overload
+
+ Appends \a point to this array of QVector2D values.
+*/
+
+/*!
+ \fn void QVector2DArray::append(const QPoint& point);
+ \overload
+
+ Appends \a point to this array of QVector2D values.
+*/
+
+/*!
+ Multiplies the elements in this array of QVector2D values by
+ the \a scale.
+
+ \sa scaled()
+*/
+void QVector2DArray::scale(qreal scale)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector2D *dst = data();
+ for (int index = 0; index < size; ++index)
+ *dst++ *= scale;
+ } else {
+ // Create a new array, translate the values, and assign.
+ QArray<QVector2D> result;
+ int size = count();
+ const QVector2D *src = constData();
+ QVector2D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ * scale;
+ *this = result;
+ }
+}
+
+/*!
+ Returns a copy of this array of QVector2D values, multiplied
+ by the \a scale.
+
+ \sa scale()
+*/
+QVector2DArray QVector2DArray::scaled(qreal scale) const
+{
+ const qreal identity = 1.0;
+ if (qFuzzyCompare(scale, identity))
+ return *this;
+ QArray<QVector2D> result;
+ int size = count();
+ const QVector2D *src = constData();
+ QVector2D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ * scale;
+ return result;
+}
+
+/*!
+ Translates the elements in this array of QVector2D values
+ by the components of \a value.
+
+ \sa translated()
+*/
+void QVector2DArray::translate(const QVector2D& value)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector2D *dst = data();
+ for (int index = 0; index < size; ++index)
+ *dst++ += value;
+ } else {
+ // Create a new array, translate the values, and assign.
+ QArray<QVector2D> result;
+ int size = count();
+ const QVector2D *src = constData();
+ QVector2D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ + value;
+ *this = result;
+ }
+}
+
+/*!
+ \fn void QVector2DArray::translate(qreal x, qreal y)
+ \overload
+
+ Translates the elements in this array of QVector2D values
+ by (\a x, \a y).
+
+ \sa translated()
+*/
+
+/*!
+ Returns a copy of this array of QVector2D values, translated
+ by the components of \a value.
+
+ \sa translate()
+*/
+QArray<QVector2D> QVector2DArray::translated(const QVector2D& value) const
+{
+ QArray<QVector2D> result;
+ int size = count();
+ QVector2D *dst = result.extend(size);
+ const QVector2D *src = constData();
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ + value;
+ return result;
+}
+
+/*!
+ \fn QArray<QVector2D> QVector2DArray::translated(qreal x, qreal y) const
+ \overload
+
+ Returns a copy of this array of QVector2D values, translated
+ by (\a x, \a y).
+
+ \sa translate()
+*/
+
+/*!
+ Transforms the elements in this array of QVector2D values
+ by \a matrix.
+
+ \sa transformed()
+*/
+void QVector2DArray::transform(const QMatrix4x4& matrix)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector2D *dst = data();
+ for (int index = 0; index < size; ++index) {
+ *dst = (matrix * QVector3D(*dst, 0.0f)).toVector2D();
+ ++dst;
+ }
+ } else {
+ // Create a new array, transform the values, and assign.
+ QArray<QVector2D> result;
+ int size = count();
+ const QVector2D *src = constData();
+ QVector2D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = (matrix * QVector3D(*src++, 0.0f)).toVector2D();
+ *this = result;
+ }
+}
+
+/*!
+ Returns a copy of this array of QVector2D values,
+ transformed by \a matrix.
+
+ \sa transform()
+*/
+QArray<QVector2D> QVector2DArray::transformed(const QMatrix4x4& matrix) const
+{
+ QArray<QVector2D> result;
+ int size = count();
+ const QVector2D *src = constData();
+ QVector2D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = (matrix * QVector3D(*src++, 0.0f)).toVector2D();
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qvector2darray.h b/src/threed/arrays/qvector2darray.h
new file mode 100644
index 000000000..f72eef63b
--- /dev/null
+++ b/src/threed/arrays/qvector2darray.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVECTOR2DARRAY_H
+#define QVECTOR2DARRAY_H
+
+#include "qarray.h"
+#include <QtGui/qvector2d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QMatrix4x4;
+
+class Q_QT3D_EXPORT QVector2DArray : public QArray<QVector2D>
+{
+public:
+ QVector2DArray();
+ QVector2DArray(int size, const QVector2D& value = QVector2D());
+ QVector2DArray(const QArray<QVector2D>& other);
+
+ void append(qreal x, qreal y);
+ void append(const QPointF& point);
+ void append(const QPoint& point);
+
+ void scale(qreal scale);
+ QVector2DArray scaled(qreal scale) const;
+
+ void translate(const QVector2D& value);
+ void translate(qreal x, qreal y);
+
+ QArray<QVector2D> translated(const QVector2D& value) const;
+ QArray<QVector2D> translated(qreal x, qreal y) const;
+
+ void transform(const QMatrix4x4& matrix);
+ QArray<QVector2D> transformed(const QMatrix4x4& matrix) const;
+
+#if !defined(Q_NO_USING_KEYWORD) || defined(Q_QDOC)
+ using QArray<QVector2D>::append;
+#else
+ inline void append(const QVector2D& value)
+ { QArray<QVector2D>::append(value); }
+ inline void append(const QVector2D& value1, const QVector2D& value2)
+ { QArray<QVector2D>::append(value1, value2); }
+ inline void append(const QVector2D& value1, const QVector2D& value2, const QVector2D& value3)
+ { QArray<QVector2D>::append(value1, value2, value3); }
+ inline void append(const QVector2D& value1, const QVector2D& value2, const QVector2D& value3, const QVector2D& value4)
+ { QArray<QVector2D>::append(value1, value2, value3, value4); }
+ inline void append(const QVector2D *values, int count)
+ { QArray<QVector2D>::append(values, count); }
+ inline void append(const QArray<QVector2D>& other)
+ { QArray<QVector2D>::append(other); }
+#endif
+};
+
+inline QVector2DArray::QVector2DArray() {}
+
+inline QVector2DArray::QVector2DArray(int size, const QVector2D& value)
+ : QArray<QVector2D>(size, value) {}
+
+inline QVector2DArray::QVector2DArray(const QArray<QVector2D>& other)
+ : QArray<QVector2D>(other) {}
+
+inline void QVector2DArray::append(qreal x, qreal y)
+ { QArray<QVector2D>::append(QVector2D(x, y)); }
+
+inline void QVector2DArray::append(const QPointF& point)
+ { QArray<QVector2D>::append(QVector2D(point)); }
+
+inline void QVector2DArray::append(const QPoint& point)
+ { QArray<QVector2D>::append(QVector2D(point)); }
+
+inline void QVector2DArray::translate(qreal x, qreal y)
+ { translate(QVector2D(x, y)); }
+
+inline QArray<QVector2D> QVector2DArray::translated(qreal x, qreal y) const
+ { return translated(QVector2D(x, y)); }
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qvector3darray.cpp b/src/threed/arrays/qvector3darray.cpp
new file mode 100644
index 000000000..460ccf6c0
--- /dev/null
+++ b/src/threed/arrays/qvector3darray.cpp
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvector3darray.h"
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QVector3DArray
+ \brief The QVector3DArray class is a convenience for wrapping a QArray of QVector3D values.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ QVector3DArray is used to build an array of 3D vector values
+ based on floating-point x, y, and z arguments:
+
+ \code
+ QVector3DArray array;
+ array.append(1.0f, 2.0f, 3.0f);
+ array.append(-1.0f, 2.0f, 3.0f);
+ array.append(1.0f, -2.0f, 3.0f);
+ \endcode
+
+ This is more convenient and readable than the equivalent with
+ QArray:
+
+ \code
+ QArray<QVector3D> array;
+ array.append(QVector3D(1.0f, 2.0f, 3.0f));
+ array.append(QVector3D(-1.0f, 2.0f, 3.0f));
+ array.append(QVector3D(1.0f, -2.0f, 3.0f));
+ \endcode
+
+ QVector3DArray also has convenience functions for transforming
+ the contents of the array with translate(), translated(),
+ transform(), and transformed().
+
+ \sa QArray, QVector2DArray, QVector4DArray
+*/
+
+/*!
+ \fn QVector3DArray::QVector3DArray()
+
+ Constructs an empty array of QVector3D values.
+*/
+
+/*!
+ \fn QVector3DArray::QVector3DArray(int size, const QVector3D& value)
+
+ Constructs an array of QVector3D values with an initial \a size.
+ All elements in the array are initialized to \a value.
+*/
+
+/*!
+ \fn QVector3DArray::QVector3DArray(const QArray<QVector3D>& other)
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ \fn void QVector3DArray::append(qreal x, qreal y, qreal z)
+
+ Appends (\a x, \a y, \a z) to this array of QVector3D values.
+*/
+
+/*!
+ Multiplies the elements in this array of QVector3D values by
+ the \a scale.
+
+ \sa scaled()
+*/
+void QVector3DArray::scale(qreal scale)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector3D *dst = data();
+ for (int index = 0; index < size; ++index)
+ *dst++ *= scale;
+ } else {
+ // Create a new array, translate the values, and assign.
+ QArray<QVector3D> result;
+ int size = count();
+ const QVector3D *src = constData();
+ QVector3D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ * scale;
+ *this = result;
+ }
+}
+
+/*!
+ Returns a copy of this array of QVector3D values, multiplied
+ by the \a scale.
+
+ \sa scale()
+*/
+QVector3DArray QVector3DArray::scaled(qreal scale) const
+{
+ QArray<QVector3D> result;
+ int size = count();
+ const QVector3D *src = constData();
+ QVector3D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ * scale;
+ return result;
+}
+
+/*!
+ Translates the elements in this array of QVector3D values
+ by the components of \a value.
+
+ \sa translated()
+*/
+void QVector3DArray::translate(const QVector3D& value)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector3D *dst = data();
+ for (int index = 0; index < size; ++index)
+ *dst++ += value;
+ } else {
+ // Create a new array, translate the values, and assign.
+ QArray<QVector3D> result;
+ int size = count();
+ const QVector3D *src = constData();
+ QVector3D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ + value;
+ *this = result;
+ }
+}
+
+/*!
+ \fn void QVector3DArray::translate(qreal x, qreal y, qreal z)
+ \overload
+
+ Translates the elements in this array of QVector3D values
+ by (\a x, \a y, \a z).
+
+ \sa translated()
+*/
+
+/*!
+ Returns a copy of this array of QVector3D values, translated
+ by the components of \a value.
+
+ \sa translate()
+*/
+QArray<QVector3D> QVector3DArray::translated(const QVector3D& value) const
+{
+ QArray<QVector3D> result;
+ int size = count();
+ const QVector3D *src = constData();
+ QVector3D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ + value;
+ return result;
+}
+
+/*!
+ \fn QArray<QVector3D> QVector3DArray::translated(qreal x, qreal y, qreal z) const
+ \overload
+
+ Returns a copy of this array of QVector3D values, translated
+ by (\a x, \a y, \a z).
+
+ \sa translate()
+*/
+
+/*!
+ Transforms the elements in this array of QVector3D values
+ by \a matrix.
+
+ \sa transformed()
+*/
+void QVector3DArray::transform(const QMatrix4x4& matrix)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector3D *dst = data();
+ for (int index = 0; index < size; ++index) {
+ *dst = matrix * *dst;
+ ++dst;
+ }
+ } else {
+ // Create a new array, transform the values, and assign.
+ QArray<QVector3D> result;
+ int size = count();
+ const QVector3D *src = constData();
+ QVector3D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = matrix * *src++;
+ *this = result;
+ }
+}
+
+/*!
+ Returns a copy of this array of QVector3D values, transformed
+ by \a matrix.
+
+ \sa transform()
+*/
+QArray<QVector3D> QVector3DArray::transformed(const QMatrix4x4& matrix) const
+{
+ QArray<QVector3D> result;
+ int size = count();
+ const QVector3D *src = constData();
+ QVector3D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = matrix * *src++;
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qvector3darray.h b/src/threed/arrays/qvector3darray.h
new file mode 100644
index 000000000..f04742e5f
--- /dev/null
+++ b/src/threed/arrays/qvector3darray.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVECTOR3DARRAY_H
+#define QVECTOR3DARRAY_H
+
+#include "qarray.h"
+#include <QtGui/qvector3d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QMatrix4x4;
+
+class Q_QT3D_EXPORT QVector3DArray : public QArray<QVector3D>
+{
+public:
+ QVector3DArray();
+ QVector3DArray(int size, const QVector3D& value = QVector3D());
+ QVector3DArray(const QArray<QVector3D>& other);
+
+ void append(qreal x, qreal y, qreal z);
+
+ void scale(qreal scale);
+ QVector3DArray scaled(qreal scale) const;
+
+ void translate(const QVector3D& value);
+ void translate(qreal x, qreal y, qreal z);
+
+ QArray<QVector3D> translated(const QVector3D& value) const;
+ QArray<QVector3D> translated(qreal x, qreal y, qreal z) const;
+
+ void transform(const QMatrix4x4& matrix);
+ QArray<QVector3D> transformed(const QMatrix4x4& matrix) const;
+
+#if !defined(Q_NO_USING_KEYWORD) || defined(Q_QDOC)
+ using QArray<QVector3D>::append;
+#else
+ inline void append(const QVector3D& value)
+ { QArray<QVector3D>::append(value); }
+ inline void append(const QVector3D& value1, const QVector3D& value2)
+ { QArray<QVector3D>::append(value1, value2); }
+ inline void append(const QVector3D& value1, const QVector3D& value2, const QVector3D& value3)
+ { QArray<QVector3D>::append(value1, value2, value3); }
+ inline void append(const QVector3D& value1, const QVector3D& value2, const QVector3D& value3, const QVector3D& value4)
+ { QArray<QVector3D>::append(value1, value2, value3, value4); }
+ inline void append(const QVector3D *values, int count)
+ { QArray<QVector3D>::append(values, count); }
+ inline void append(const QArray<QVector3D>& other)
+ { QArray<QVector3D>::append(other); }
+#endif
+};
+
+inline QVector3DArray::QVector3DArray() {}
+
+inline QVector3DArray::QVector3DArray(int size, const QVector3D& value)
+ : QArray<QVector3D>(size, value) {}
+
+inline QVector3DArray::QVector3DArray(const QArray<QVector3D>& other)
+ : QArray<QVector3D>(other) {}
+
+inline void QVector3DArray::append(qreal x, qreal y, qreal z)
+ { QArray<QVector3D>::append(QVector3D(x, y, z)); }
+
+inline void QVector3DArray::translate(qreal x, qreal y, qreal z)
+ { translate(QVector3D(x, y, z)); }
+
+inline QArray<QVector3D> QVector3DArray::translated(qreal x, qreal y, qreal z) const
+ { return translated(QVector3D(x, y, z)); }
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/arrays/qvector4darray.cpp b/src/threed/arrays/qvector4darray.cpp
new file mode 100644
index 000000000..0c7056695
--- /dev/null
+++ b/src/threed/arrays/qvector4darray.cpp
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvector4darray.h"
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QVector4DArray
+ \brief The QVector4DArray class is a convenience for wrapping a QArray of QVector4D values.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::arrays
+
+ QVector4DArray is used to build an array of 4D vector values
+ based on floating-point x, y, and z arguments:
+
+ \code
+ QVector4DArray array;
+ array.append(1.0f, 2.0f, 3.0f, -4.0f);
+ array.append(-1.0f, 2.0f, 3.0f, -4.0f);
+ array.append(1.0f, -2.0f, 3.0f, -4.0f);
+ \endcode
+
+ This is more convenient and readable than the equivalent with
+ QArray:
+
+ \code
+ QArray<QVector4D> array;
+ array.append(QVector4D(1.0f, 2.0f, 3.0f, -4.0f));
+ array.append(QVector4D(-1.0f, 2.0f, 3.0f, -4.0f));
+ array.append(QVector4D(1.0f, -2.0f, 3.0f, -4.0f));
+ \endcode
+
+ QVector4DArray also has convenience functions for transforming
+ the contents of the array with translate(), translated(),
+ transform(), and transformed().
+
+ \sa QArray, QVector2DArray, QVector3DArray
+*/
+
+/*!
+ \fn QVector4DArray::QVector4DArray()
+
+ Constructs an empty array of QVector4D values.
+*/
+
+/*!
+ \fn QVector4DArray::QVector4DArray(int size, const QVector4D& value)
+
+ Constructs an array of QVector4D values with an initial \a size.
+ All elements in the array are initialized to \a value.
+*/
+
+/*!
+ \fn QVector4DArray::QVector4DArray(const QArray<QVector4D>& other)
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ \fn void QVector4DArray::append(qreal x, qreal y, qreal z, qreal w)
+
+ Appends (\a x, \a y, \a z, \a w) to this array of QVector4D values.
+*/
+
+/*!
+ Multiplies the elements in this array of QVector4D values by
+ the \a scale.
+
+ \sa scaled()
+*/
+void QVector4DArray::scale(qreal scale)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector4D *dst = data();
+ for (int index = 0; index < size; ++index)
+ *dst++ *= scale;
+ } else {
+ // Create a new array, translate the values, and assign.
+ QArray<QVector4D> result;
+ int size = count();
+ const QVector4D *src = constData();
+ QVector4D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ * scale;
+ *this = result;
+ }
+}
+
+/*!
+ Returns a copy of this array of QVector4D values, multiplied
+ by the \a scale.
+
+ \sa scale()
+*/
+QVector4DArray QVector4DArray::scaled(qreal scale) const
+{
+ QArray<QVector4D> result;
+ int size = count();
+ const QVector4D *src = constData();
+ QVector4D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ * scale;
+ return result;
+}
+
+/*!
+ Translates the elements in this array of QVector4D values
+ by the components of \a value.
+
+ \sa translated()
+*/
+void QVector4DArray::translate(const QVector4D& value)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector4D *dst = data();
+ for (int index = 0; index < size; ++index)
+ *dst++ += value;
+ } else {
+ // Create a new array, translate the values, and assign.
+ QArray<QVector4D> result;
+ int size = count();
+ const QVector4D *src = constData();
+ QVector4D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ + value;
+ *this = result;
+ }
+}
+
+/*!
+ \fn void QVector4DArray::translate(qreal x, qreal y, qreal z, qreal w);
+ \overload
+
+ Translates the elements in this array of QVector4D values
+ by (\a x, \a y, \a z, \a w).
+
+ \sa translated()
+*/
+
+/*!
+ Returns a copy of this array of QVector4D values, translated
+ by the components of \a value.
+
+ \sa translate()
+*/
+QArray<QVector4D> QVector4DArray::translated(const QVector4D& value) const
+{
+ QArray<QVector4D> result;
+ int size = count();
+ const QVector4D *src = constData();
+ QVector4D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = *src++ + value;
+ return result;
+}
+
+/*!
+ \fn QArray<QVector4D> QVector4DArray::translated(qreal x, qreal y, qreal z, qreal w) const
+ \overload
+
+ Returns a copy of this array of QVector4D values, translated
+ by (\a x, \a y, \a z, \a w).
+
+ \sa translate()
+*/
+
+/*!
+ Transforms the elements in this array of QVector4D values
+ by \a matrix.
+
+ \sa transformed()
+*/
+void QVector4DArray::transform(const QMatrix4x4& matrix)
+{
+ if (isDetached()) {
+ // Modify the array in-place.
+ int size = count();
+ QVector4D *dst = data();
+ for (int index = 0; index < size; ++index) {
+ *dst = matrix * *dst;
+ ++dst;
+ }
+ } else {
+ // Create a new array, transform the values, and assign.
+ QArray<QVector4D> result;
+ int size = count();
+ const QVector4D *src = constData();
+ QVector4D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = matrix * *src++;
+ *this = result;
+ }
+}
+
+/*!
+ Returns a copy of this array of QVector3D values, transformed
+ by \a matrix.
+
+ \sa transform()
+*/
+QArray<QVector4D> QVector4DArray::transformed(const QMatrix4x4& matrix) const
+{
+ QArray<QVector4D> result;
+ int size = count();
+ const QVector4D *src = constData();
+ QVector4D *dst = result.extend(size);
+ for (int index = 0; index < size; ++index)
+ *dst++ = matrix * *src++;
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/arrays/qvector4darray.h b/src/threed/arrays/qvector4darray.h
new file mode 100644
index 000000000..c9770a023
--- /dev/null
+++ b/src/threed/arrays/qvector4darray.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVECTOR4DARRAY_H
+#define QVECTOR4DARRAY_H
+
+#include "qarray.h"
+#include <QtGui/qvector4d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QMatrix4x4;
+
+class Q_QT3D_EXPORT QVector4DArray : public QArray<QVector4D>
+{
+public:
+ QVector4DArray();
+ QVector4DArray(int size, const QVector4D& value = QVector4D());
+ QVector4DArray(const QArray<QVector4D>& other);
+
+ void append(qreal x, qreal y, qreal z, qreal w);
+
+ void scale(qreal scale);
+ QVector4DArray scaled(qreal scale) const;
+
+ void translate(const QVector4D& value);
+ void translate(qreal x, qreal y, qreal z, qreal w);
+
+ QArray<QVector4D> translated(const QVector4D& value) const;
+ QArray<QVector4D> translated
+ (qreal x, qreal y, qreal z, qreal w) const;
+
+ void transform(const QMatrix4x4& matrix);
+ QArray<QVector4D> transformed(const QMatrix4x4& matrix) const;
+
+#if !defined(Q_NO_USING_KEYWORD) || defined(Q_QDOC)
+ using QArray<QVector4D>::append;
+#else
+ inline void append(const QVector4D& value)
+ { QArray<QVector4D>::append(value); }
+ inline void append(const QVector4D& value1, const QVector4D& value2)
+ { QArray<QVector4D>::append(value1, value2); }
+ inline void append(const QVector4D& value1, const QVector4D& value2, const QVector4D& value3)
+ { QArray<QVector4D>::append(value1, value2, value3); }
+ inline void append(const QVector4D& value1, const QVector4D& value2, const QVector4D& value3, const QVector4D& value4)
+ { QArray<QVector4D>::append(value1, value2, value3, value4); }
+ inline void append(const QVector4D *values, int count)
+ { QArray<QVector4D>::append(values, count); }
+ inline void append(const QArray<QVector4D>& other)
+ { QArray<QVector4D>::append(other); }
+#endif
+};
+
+inline QVector4DArray::QVector4DArray() {}
+
+inline QVector4DArray::QVector4DArray(int size, const QVector4D& value)
+ : QArray<QVector4D>(size, value) {}
+
+inline QVector4DArray::QVector4DArray(const QArray<QVector4D>& other)
+ : QArray<QVector4D>(other) {}
+
+inline void QVector4DArray::append(qreal x, qreal y, qreal z, qreal w)
+ { QArray<QVector4D>::append(QVector4D(x, y, z, w)); }
+
+inline void QVector4DArray::translate(qreal x, qreal y, qreal z, qreal w)
+ { translate(QVector4D(x, y, z, w)); }
+
+inline QArray<QVector4D> QVector4DArray::translated
+ (qreal x, qreal y, qreal z, qreal w) const
+ { return translated(QVector4D(x, y, z, w)); }
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/effects/effects.pri b/src/threed/effects/effects.pri
new file mode 100644
index 000000000..19b0cae37
--- /dev/null
+++ b/src/threed/effects/effects.pri
@@ -0,0 +1,26 @@
+
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+
+HEADERS += \
+ qglshaderprogrameffect.h \
+ qglcolladafxeffectfactory.h \
+ qglcolladafxeffect.h \
+ qglcolladafxeffectloader.h
+
+SOURCES += \
+ qglflatcoloreffect.cpp \
+ qglflattextureeffect.cpp \
+ qgllitmaterialeffect.cpp \
+ qgllittextureeffect.cpp \
+ qglshaderprogrameffect.cpp \
+ qglcolladafxeffect.cpp \
+ qglcolladafxeffectfactory.cpp \
+ qglcolladafxeffectloader.cpp
+
+PRIVATE_HEADERS += \
+ qglflatcoloreffect_p.h \
+ qglflattextureeffect_p.h \
+ qgllitmaterialeffect_p.h \
+ qgllittextureeffect_p.h \
+ qglcolladafxeffect_p.h
diff --git a/src/threed/effects/qglcolladafxeffect.cpp b/src/threed/effects/qglcolladafxeffect.cpp
new file mode 100644
index 000000000..35940d3e8
--- /dev/null
+++ b/src/threed/effects/qglcolladafxeffect.cpp
@@ -0,0 +1,406 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QXmlStreamReader>
+#include <QFile>
+#include <QDebug>
+#include <QImage>
+#include "qgl.h"
+#include "qgltexture2d.h"
+#include "qglcolladafxeffect.h"
+#include "qglcolladafxeffect_p.h"
+
+QGLColladaFxEffect::QGLColladaFxEffect() : QGLShaderProgramEffect()
+ , d( new QGLColladaFxEffectPrivate )
+{
+}
+
+QGLColladaFxEffect::QGLColladaFxEffect(const QGLColladaFxEffect&) : QGLShaderProgramEffect()
+{
+ Q_ASSERT(false);
+};
+
+
+QGLColladaFxEffect::~QGLColladaFxEffect()
+{
+ delete d;
+}
+
+
+
+QGLColladaFxEffectPrivate::QGLColladaFxEffectPrivate() : id()
+ , sid()
+ , name()
+ , emissiveTexture(0)
+ , ambientTexture(0)
+ , diffuseTexture(0)
+ , specularTexture(0)
+ , lighting(QGLColladaFxEffect::NoLighting)
+ , material(0)
+{
+ resetGlueSnippets();
+}
+
+
+
+QGLColladaFxEffectPrivate::~QGLColladaFxEffectPrivate()
+{
+ delete emissiveTexture;
+ emissiveTexture = 0;
+ delete ambientTexture;
+ ambientTexture = 0;
+ delete diffuseTexture;
+ diffuseTexture = 0;
+ delete specularTexture;
+ specularTexture = 0;
+ delete material;
+ material = 0;
+
+}
+
+
+
+inline void QGLColladaFxEffectPrivate::updateMaterialChannelSnippets(QString channelName, QGLTexture2D* texture, int* textureUnit, QColor fallbackColor)
+{
+ QString qVariableName = QLatin1String("q") + channelName;
+ if (texture != 0)
+ {
+ QString sourceVariableName = QLatin1String("texture") + channelName;
+ QString texVariableName = QString(QLatin1String("texCoord%1")).arg(*textureUnit);
+ // Take care of texture coordinates
+ QString varyingSnippet = QString(QLatin1String("varying vec4 %1;")).arg(texVariableName);
+ vertexShaderDeclarationSnippets.append(varyingSnippet);
+ vertexShaderVariableNames.append(texVariableName);
+ fragmentShaderDeclarationSnippets.append(varyingSnippet);
+ fragmentShaderVariableNames.append(texVariableName);
+
+ vertexShaderCodeSnippets.append(QString(QLatin1String("%1 = texCoords; // TODO: dynamically add tex attributes\n")).arg(texVariableName));
+ vertexShaderVariableNames.append(texVariableName);
+
+ // Declare the color variable in the fragment shader
+ fragmentShaderDeclarationSnippets.append(QString(QLatin1String("lowp vec4 %1;")).arg(qVariableName));
+ fragmentShaderVariableNames.append(qVariableName);
+ fragmentShaderDeclarationSnippets.append(QString(QLatin1String("uniform sampler2D %1;")).arg(sourceVariableName));
+ fragmentShaderVariableNames.append(sourceVariableName);
+
+ // Assign a colour to the variable out of the appropriate sampler
+ fragmentShaderCodeSnippets.append(QLatin1String(" mediump vec4 ") + qVariableName + QLatin1String(" = texture2D(") + sourceVariableName + QLatin1String(", ") + texVariableName + QLatin1String(".st);"));
+ fragmentShaderVariableNames.append(qVariableName);
+ // mediump? lowp?
+
+ *textureUnit++;
+ } else {
+ fragmentShaderDeclarationSnippets.append(QString (QLatin1String("const vec4 %1 = vec4(%2, %3, %4, %5);")).arg( qVariableName).arg(fallbackColor.redF(), 0, 'f', 6).arg(fallbackColor.greenF(), 0, 'f', 6).arg(fallbackColor.blueF(), 0, 'f', 6).arg(fallbackColor.alphaF(), 0, 'f', 6 ));
+ fragmentShaderVariableNames.append(qVariableName);
+ }
+}
+
+
+
+inline void QGLColladaFxEffectPrivate::setTextureUniform(QGLShaderProgram *program, QGLPainter* painter, QString channelName, QGLTexture2D* texture, int* textureUnit, QColor fallbackColor)
+{
+ QString qVariableName = QLatin1String("q") + channelName;
+
+ if (texture != 0)
+ {
+ QString sourceVariableName = QLatin1String("texture") + channelName;
+ QString texVariableName = QString(QLatin1String("texCoord%1")).arg(*textureUnit);
+ painter->glActiveTexture(GL_TEXTURE0 + *textureUnit);
+ texture->bind();
+ program->setUniformValue(sourceVariableName.toAscii().data(), *textureUnit);
+ }
+ else
+ {
+ // It's just a const value, so set it that way in the fragment shader.
+ program->setUniformValue(qVariableName.toAscii().data(), fallbackColor);
+ }
+}
+
+
+
+void QGLColladaFxEffect::update(QGLPainter *painter, QGLPainter::Updates updates)
+{
+ QGLShaderProgramEffect::update(painter, updates);
+
+ if (updates && QGLPainter::UpdateMaterials)
+ {
+
+ if (program() == 0)
+ {
+ qWarning() << "no program in QGLColladaFxEffect::update()";
+ return;
+ }
+
+ // Start from texture unit 1 so as not to stomp a texture set on the
+ // painter.
+ int textureUnit = 1;
+ d->setTextureUniform(
+ program(), painter, QLatin1String("Emissive"), d->emissiveTexture,
+ &textureUnit,
+ material() ? material()->emittedLight() : QColor());
+
+ d->setTextureUniform(
+ program(), painter, QLatin1String("Ambient"), d->ambientTexture, &textureUnit,
+ material() ? material()->ambientColor() : QColor());
+
+ d->setTextureUniform(
+ program(), painter, QLatin1String("Diffuse"), d->diffuseTexture, &textureUnit,
+ material() ? material()->diffuseColor() : QColor());
+
+ d->setTextureUniform(
+ program(), painter, QLatin1String("Specular"), d->specularTexture,
+ &textureUnit,
+ material() ? material()->specularColor() : QColor());
+ }
+}
+
+
+
+void QGLColladaFxEffect::setId(QString id)
+{
+ d->id = id;
+}
+
+
+
+QString QGLColladaFxEffect::id()
+{
+ return d->id;
+}
+
+
+
+void QGLColladaFxEffect::setSid(QString sid)
+{
+ d->sid = sid;
+}
+
+
+
+void QGLColladaFxEffectPrivate::addMaterialChannelsToShaderSnippets(const QGLMaterial *material)
+{
+ int textureUnit = 1;
+
+ updateMaterialChannelSnippets(QLatin1String("Emissive"), emissiveTexture, &textureUnit, material->emittedLight());
+ updateMaterialChannelSnippets(QLatin1String("Ambient"), ambientTexture, &textureUnit, material->ambientColor());
+ updateMaterialChannelSnippets(QLatin1String("Diffuse"), diffuseTexture, &textureUnit, material->diffuseColor());
+ updateMaterialChannelSnippets(QLatin1String("Specular"), specularTexture, &textureUnit, material->specularColor());
+}
+
+
+
+void QGLColladaFxEffect::addBlinnPhongLighting()
+{
+ d->addMaterialChannelsToShaderSnippets(material());
+
+ // Fragment shader declarations:
+ d->fragmentShaderDeclarationSnippets.append(QLatin1String("uniform mediump sampler2D texture0;"));
+ d->fragmentShaderVariableNames.append(QLatin1String("texture0"));
+ d->fragmentShaderDeclarationSnippets.append(QLatin1String("varying highp vec4 qt_TexCoord0;"));
+ d->fragmentShaderVariableNames.append(QLatin1String("qt_TexCoord0"));
+
+ // Fragment Shader code
+ d->fragmentShaderCodeSnippets.append(QLatin1String(
+ " vec4 specularComponent = vec4( 0.0, 0.0, 0.0, 0.0 );\n"\
+ " if (intensity > 0.0)\n"\
+ " {\n"\
+ " float specularIntensity = max( dot(perPixelNormal, qHalfVector), 0.0 );\n"\
+ " if (specularIntensity > 0.0)\n"\
+ " specularComponent = qSpecular * pow(specularIntensity, shininess);\n"\
+ " }\n"));
+ d->fragmentShaderVariableNames.append(QLatin1String("lighting"));
+
+
+ // Replace the "end glue" to set colour from lighting
+ d->fragmentShaderEndGlueSnippet = QLatin1String(
+ " vec4 texture0Color = texture2D(texture0, qt_TexCoord0.st);\n"\
+ " vec4 diffuseColor = qDiffuse;\n"\
+ " vec4 lightingColor = qAmbient + diffuseColor * intensity + specularComponent;\n"\
+ " vec4 texturedColor = vec4(lightingColor.xyz * (1.0 - texture0Color.a)\n"\
+ "+ (texture0Color.xyz + specularComponent.rgb) * texture0Color.a, lightingColor.a);\n"\
+ " gl_FragColor = texturedColor;\n"\
+ "}");
+ generateShaders();
+}
+
+
+
+void QGLColladaFxEffect::generateShaders()
+{
+ if (vertexShader().isEmpty())
+ {
+ QString shader =
+ d->vertexShaderDeclarationSnippets.join(QLatin1String("\n"))
+ + QLatin1String("\n") + d->vertexShaderMainGlueSnippet
+ + d->vertexShaderCodeSnippets.join(QLatin1String("\n"))
+ + QLatin1String("\n") + d->vertexShaderEndGlueSnippet;
+ setVertexShader(shader.toLatin1());
+ }
+
+ if (fragmentShader().isEmpty())
+ {
+ QString shader =
+ d->fragmentShaderDeclarationSnippets.join(QLatin1String("\n"))
+ + QLatin1String("\n") + d->fragmentShaderMainGlueSnippet
+ + d->fragmentShaderCodeSnippets.join(QLatin1String("\n"))
+ + QLatin1String("\n") + d->fragmentShaderEndGlueSnippet;
+ setFragmentShader(shader.toLatin1());
+ }
+}
+
+
+
+void QGLColladaFxEffectPrivate::resetGlueSnippets()
+{
+ vertexShaderMainGlueSnippet = QLatin1String(
+ "attribute highp vec4 vertex;\n"\
+ "attribute highp vec4 normal;\n"\
+ "attribute highp vec4 texCoords;\n"\
+ "uniform highp mat4 matrix;\n"\
+ "uniform highp mat3 qt_NormalMatrix;\n"\
+ "varying mediump vec3 qNormal;\n"\
+ "varying mediump vec3 qLightDirection;\n"\
+ "varying mediump vec3 qHalfVector;\n"\
+ "uniform mediump vec3 pli; // Position of the light\n"\
+ "varying highp vec4 qt_TexCoord0; // TEMP\n" /* Got to get rid of this*/\
+ "\n"\
+ "void qLightVertex(vec4 vertex, vec3 normal)\n"\
+ "{\n"\
+ " vec3 toEye;\n"\
+ " qLightDirection = normalize(pli);\n"\
+ " toEye = vec3(0, 0, 1); // assume viewer at infinity\n"\
+ " qHalfVector = normalize(qLightDirection + toEye);\n"\
+ "}\n"\
+ "\n"\
+ "void main(void)\n"\
+ "{\n"\
+ " qNormal = normalize(qt_NormalMatrix * vec3(normal));\n"\
+ " qLightVertex(vertex, qNormal);\n"\
+ " qt_TexCoord0 = texCoords;\n"\
+ );
+
+ vertexShaderEndGlueSnippet = QLatin1String (
+ " gl_Position = matrix * vertex;\n"\
+ "}\n");
+
+
+ fragmentShaderEndGlueSnippet = QLatin1String(
+ " gl_FragColor = color;\n"\
+ "}\n"
+ );
+
+ fragmentShaderMainGlueSnippet = QLatin1String(
+ "varying mediump vec3 qNormal;\n"\
+ "varying mediump vec3 qLightDirection;\n"\
+ "varying mediump vec3 qHalfVector;\n"\
+ "uniform float shininess;\n"\
+ "uniform vec4 color;\n"\
+ "vec3 perPixelNormal;"
+ "\n"\
+ "void main()\n"\
+ "{\n"\
+ " perPixelNormal = normalize(qNormal);\n"\
+ " float intensity = max(dot(perPixelNormal, qLightDirection), 0.0);\n"
+ );
+}
+
+
+
+QString QGLColladaFxEffect::sid()
+{
+ return d->sid;
+}
+
+
+
+QGLTexture2D* QGLColladaFxEffect::diffuseTexture()
+{
+ return d->diffuseTexture;
+}
+
+
+void QGLColladaFxEffect::setLighting(int lighting)
+{
+ d->lighting = lighting;
+}
+
+int QGLColladaFxEffect::lighting()
+{
+ return d->lighting;
+}
+
+/*!
+ Sets this effect to use \a newMaterial. If \a newMaterial is 0, sets this
+ effect to have no material, and instead use whatever material is set
+ on the QGLPainter.
+
+ \sa QGLPainter, material()
+*/
+void QGLColladaFxEffect::setMaterial(QGLMaterial* newMaterial)
+{
+ d->material = newMaterial;
+}
+
+/*!
+ Returns a pointer to the material of this effect. If the effect has no material,
+ this function returns 0;
+*/
+QGLMaterial* QGLColladaFxEffect::material()
+{
+ return d->material;
+}
+
+/*!
+ Returns true if the effect is currently active (applied to a QGLPainter)
+ and false if it is not.
+ */
+bool QGLColladaFxEffect::isActive()
+{
+ return d->currentlyActive;
+}
+
+void QGLColladaFxEffect::setActive(QGLPainter *painter, bool flag)
+{
+ d->currentlyActive = flag && !vertexShader().isEmpty() &&
+ !fragmentShader().isEmpty();
+ QGLShaderProgramEffect::setActive(painter, d->currentlyActive);
+}
diff --git a/src/threed/effects/qglcolladafxeffect.h b/src/threed/effects/qglcolladafxeffect.h
new file mode 100644
index 000000000..fc224a87f
--- /dev/null
+++ b/src/threed/effects/qglcolladafxeffect.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCOLLADAEFFECT_H
+#define QGLCOLLADAEFFECT_H
+
+#include <QStack>
+#include <QList>
+#include <QGLShaderProgram>
+#include "qglshaderprogrameffect.h"
+
+class QXmlStreamReader;
+class QGLColladaParam;
+class QGLColladaFxEffectPrivate;
+
+class Q_QT3D_EXPORT QGLColladaFxEffect : public QGLShaderProgramEffect
+{
+ friend class QGLColladaFxEffectFactory;
+
+public:
+ enum Lighting
+ {
+ NoLighting,
+ BlinnLighting,
+ PhongLighting,
+ ConstantLighting,
+ LambertLighting,
+ CustomLighting
+ };
+
+ QGLColladaFxEffect();
+ ~QGLColladaFxEffect();
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+ void generateShaders();
+ void addBlinnPhongLighting();
+
+ void setId(QString);
+ void setSid(QString);
+ QString id();
+ QString sid();
+
+ void setLighting(int lighting);
+ int lighting();
+ void setMaterial(QGLMaterial* newMaterial);
+ QGLMaterial* material();
+
+ QGLTexture2D* diffuseTexture();
+
+ bool isActive();
+ void setActive(QGLPainter *painter, bool flag);
+private:
+ QGLColladaFxEffect(const QGLColladaFxEffect&);
+ QGLColladaFxEffectPrivate* d;
+};
+
+#endif // QGLCOLLADAEFFECT_H
diff --git a/src/threed/effects/qglcolladafxeffect_p.h b/src/threed/effects/qglcolladafxeffect_p.h
new file mode 100644
index 000000000..ac47898d5
--- /dev/null
+++ b/src/threed/effects/qglcolladafxeffect_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCOLLADAFXEFFECT_P_H
+#define QGLCOLLADAFXEFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QString>
+#include <QMap>
+#include <QColor>
+#include "qgltexture2d.h"
+#include "qglcolladafxeffect.h"
+
+class QGLPainter;
+class QGLShaderProgram;
+class QGLMaterial;
+
+class QGLColladaFxEffectPrivate
+{
+ friend class QGLColladaFxEffectFactory;
+public:
+ QGLColladaFxEffectPrivate();
+ ~QGLColladaFxEffectPrivate();
+
+ void addMaterialChannelsToShaderSnippets(const QGLMaterial *material);
+ void resetGlueSnippets();
+ void setTextureUniform(QGLShaderProgram *program, QGLPainter* painter, QString channelName, QGLTexture2D* texture, int* textureUnit, QColor fallbackColor);
+ void updateMaterialChannelSnippets(QString channelName, QGLTexture2D* texture, int* textureUnit, QColor fallbackColor);
+
+ QString id;
+ QString sid;
+ QString name;
+
+ // The spec allows for 3D textures as well, but for now only 2D is
+ // supported
+ QGLTexture2D* emissiveTexture;
+ QGLTexture2D* ambientTexture;
+ QGLTexture2D* diffuseTexture;
+ QGLTexture2D* specularTexture;
+ int lighting;
+ QGLMaterial* material;
+
+ QStringList vertexShaderCodeSnippets;
+ QStringList vertexShaderDeclarationSnippets;
+ QStringList vertexShaderVariableNames;
+
+ QStringList fragmentShaderCodeSnippets;
+ QStringList fragmentShaderDeclarationSnippets;
+ QStringList fragmentShaderVariableNames;
+
+ QString vertexShaderEndGlueSnippet;
+ QString vertexShaderMainGlueSnippet;
+ QString fragmentShaderEndGlueSnippet;
+ QString fragmentShaderMainGlueSnippet;
+
+ bool currentlyActive;
+};
+
+#endif // QGLCOLLADAFXEFFECT_P_H
diff --git a/src/threed/effects/qglcolladafxeffectfactory.cpp b/src/threed/effects/qglcolladafxeffectfactory.cpp
new file mode 100644
index 000000000..3728b00b5
--- /dev/null
+++ b/src/threed/effects/qglcolladafxeffectfactory.cpp
@@ -0,0 +1,1688 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QVector>
+#include <QFile>
+#include <QFileInfo>
+#include <QTime>
+#include <QDir>
+#include "qgltexture2d.h"
+#include "qgl.h"
+
+#include "qglcolladafxeffect.h"
+#include "qglcolladafxeffectfactory.h"
+//#include "qglcolladafxeffectfactory_p.h"
+#include "qglcolladafxeffect_p.h"
+
+// The QGLColladaFxFactory class creates a list of QGLColladaFx objects from
+// COLLADA FX information according to the 1.4.1 March 2008 Release from
+// http://www.khronos.org/collada/
+
+//#define DEBUG_QGL_COLLADA_PARSING
+//#define DEBUG_MATERIALS
+
+#define INDENT_SIZE 4
+
+static int QGLColladaIndentLevel = 0;
+
+// This is a simple RAII helper class to conveniently indent across
+// various functions when building up the collada elements.
+// Instantiate an indent to increment the indent level with that scope.
+// add an indent object to the beginning of a string to indent it
+// the correct amount.
+class Indent
+{
+public:
+ static int currentIndent() { return QGLColladaIndentLevel; };
+ Indent()
+ {
+ ++QGLColladaIndentLevel;
+ };
+ ~Indent()
+ {
+ --QGLColladaIndentLevel;
+ }
+};
+
+QString operator +(Indent&, QString string)
+{
+ return QString(QGLColladaIndentLevel * INDENT_SIZE, QLatin1Char(' ')) + string;
+}
+
+QString operator +(char c, Indent&)
+{
+ return QLatin1Char(c) + QString(QGLColladaIndentLevel * INDENT_SIZE, QLatin1Char(' '));
+}
+
+// xml convenience function - find the first end tag with the given tagname
+// Note that this is not as smart as xml.skipCurrentElement(), and does
+// not handle the case where (grand)children node share tagName
+// With this caveat, can be called from within any (grand)child node.
+static inline void findEndTag( QXmlStreamReader& xml, QString tagName )
+{
+ while ( !xml.atEnd() && !( xml.tokenType() == xml.EndElement && xml.name() == tagName))
+ {
+ xml.readNext();
+ }
+}
+
+
+
+/*!
+ \internal
+ Convenience function to find parameters in \a resultState that have an id,
+ sid, or name that is equal to \a stringToMatch
+ Note that this using this is not in line with the Collada specification,
+ and that non-unique sids will always return the last parameter parsed.
+ */
+static inline QVariant findParameterVariant(ResultState* resultState, QString stringToMatch)
+{
+ QVariant result = resultState->paramSids.value(stringToMatch);
+
+ if ( result.isNull() )
+ result = resultState->paramIds.value(stringToMatch);
+
+ if ( result.isNull() )
+ result = resultState->paramNames.value(stringToMatch);
+
+ return result;
+}
+
+/*!
+ Parse a collada 1.4 or 1.5 .dae file \a fileName, find the effects in the
+ library_effects element, and convert these into a list of QGLColladaFxEffect objects
+ suitable for use with Qt3D. Specific effects can be identified out of
+ this list using their sid.
+
+ This is the only function intended to be called from outside this class, e.g.:
+
+ QList<QGLColladaFxEffect*> colladaEffects = QGLColladaFxEffectFactory::loadEffectsFromFile("myColladaFile.dae");
+
+ \sa QGLColladaFxEffect
+*/
+QList<QGLColladaFxEffect*> QGLColladaFxEffectFactory::loadEffectsFromFile( const QString& fileName )
+{
+ QFile file( fileName );
+ if ( !file.open( QIODevice::ReadOnly ))
+ {
+ qWarning() << "Warning: QGLColladaFxEffect failed to open file" << fileName;
+ return QList<QGLColladaFxEffect*>();
+ }
+
+
+ QXmlStreamReader xml;
+ xml.setDevice( &file );
+ if (xml.tokenType() == QXmlStreamReader::Invalid)
+ file.readLine();
+ xml.setDevice( &file );
+
+ QFileInfo fileInfo(file);
+
+ return loadEffectsFromXml( xml, fileInfo.dir() );
+}
+
+
+
+QString QGLColladaFxEffectFactory::exportEffect(QGLColladaFxEffect *effect, QString effectId, QString techniqueSid)
+{
+ QStringList result;
+
+ result += QLatin1String("<?xml version=\"1.0\"?>");
+
+ result += QLatin1String("<COLLADA "\
+ "xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.5.0\" >");
+
+ {
+ Indent indent;
+ result += indent + QLatin1String("<asset>");
+ {
+ Indent indent;
+ QDateTime time = QDateTime::currentDateTime();
+ result += indent + QLatin1String("<created>") + time.toString(Qt::ISODate) + QLatin1String("</created>");
+ result += indent + QLatin1String("<modified>") + time.toString(Qt::ISODate) + QLatin1String("</modified>");
+ }
+ result += indent + QLatin1String("</asset>");
+
+ result += indent + QLatin1String("<library_effects>");
+ {
+ Indent indent;
+ result += indent + QLatin1String("<effect id=\"") + effectId + QLatin1String("\">");
+ result += glslProfileFromEffect(effect, techniqueSid);
+ result += indent + QLatin1String("</effect>");
+ }
+ result += indent + QLatin1String("</library_effects>");
+ result += QLatin1String("</COLLADA>");
+ return result.join(QLatin1String("\n"));
+ }
+}
+
+
+/*!
+ \internal
+ parse the top level \a xml from a .dae file and process the library_effects elements therein.
+*/
+QList<QGLColladaFxEffect*> QGLColladaFxEffectFactory::loadEffectsFromXml( QXmlStreamReader& xml, QDir homeDirectory )
+{
+ ResultState resultState;
+ resultState.sourceDir = homeDirectory;
+ QList<QGLColladaFxEffect*> result;
+
+ while ( !xml.atEnd() ) {
+ xml.readNextStartElement();
+ if ( xml.name() == "library_effects" ) {
+ result += processLibraryEffectsElement( xml , &resultState );
+ } else if (xml.name() == "library_images")
+ {
+ processLibraryImagesElement( xml, &resultState );
+ }
+ }
+
+ // Try and resolve outstanding textures
+ QList<QGLTexture2D*> unresolvedTexturePointers = resultState.unresolvedTexture2Ds.keys();
+ for (int i = 0; i < unresolvedTexturePointers.count(); i++)
+ {
+ QGLTexture2D* texture = unresolvedTexturePointers[i];
+ QString parameterName = resultState.unresolvedTexture2Ds.value(texture);
+ resolveTexture2DImage(texture, &resultState, parameterName);
+ }
+ return result;
+}
+
+
+
+QGLColladaParam::~QGLColladaParam()
+{
+
+}
+
+
+
+/*!
+ \internal
+*/
+int QGLColladaParam::type()
+{
+ return mType;
+}
+
+
+
+/*!
+ \internal
+*/
+QString QGLColladaParam::sid()
+{
+ return mSid;
+}
+
+
+
+/*!
+ \internal
+*/
+QVector<float> QGLColladaParam::value() {
+ return mValue;
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaParam::QGLColladaParam(QString sid, int type) : mSid(sid)
+ , mType(type)
+{
+}
+
+
+
+/*!
+ \internal
+*/
+QString QGLColladaParam::id()
+{
+ return mId;
+}
+
+
+
+/*!
+ \internal
+*/
+QString QGLColladaParam::typeString(int type)
+{
+ const char* typeStringArray[] = {
+ "UnkownType",
+ "Sampler2DType",
+ "Texture2DType",
+ "SurfaceType",
+ "ImageType"};
+
+ if (type >= UserDefinedType)
+ return QLatin1String("UserDefinedType");
+ else if ( type < 0 || type > ImageType)
+ return QLatin1String("Unrecognized Type");
+ else
+ return QLatin1String(typeStringArray[type]);
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaTextureParam::QGLColladaTextureParam(QString sid, QGLTexture2D* texture) : QGLColladaParam(sid, Texture2DType)
+{
+ mTexture = texture;
+}
+
+
+
+/*!
+ \internal
+*/
+QGLTexture2D* QGLColladaTextureParam::texture()
+{
+ Q_ASSERT( mType == Sampler2DType || mType == Texture2DType);
+ return mTexture;
+}
+
+
+
+/*!
+ \internal
+*/
+QString QGLColladaTextureParam::samplerSid()
+{
+ return sampler2DSid;
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaFxEffectFactory::QGLColladaFxEffectFactory()
+{
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaSampler2DParam::QGLColladaSampler2DParam(QString sid, QGLTexture2D* texture)
+ : QGLColladaParam(sid, QGLColladaParam::Sampler2DType)
+ , mTexture(texture)
+{
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaSampler2DParam::QGLColladaSampler2DParam(QString sid, QString sourceSid)
+ : QGLColladaParam(sid, QGLColladaParam::Sampler2DType)
+ , mTexture(0)
+ , mSourceSid(sourceSid)
+{
+}
+
+
+
+/*!
+ \internal
+*/
+QString QGLColladaSampler2DParam::sourceSid()
+{
+ return mSourceSid;
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaSurfaceParam::QGLColladaSurfaceParam(QString sid) : QGLColladaParam(sid, QGLColladaParam::SurfaceType)
+ , mInitFrom()
+ , mFormat()
+ , mFormatHint()
+ , mSize()
+ , mSizeVector( 3, 0 )
+ , mViewportRatio( 1.0, 1.0 )
+ , mMipLevels( 0 )
+ , mMipMapGenerate( false )
+ , mExtra()
+ , mGenerator()
+{
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaImageParam::QGLColladaImageParam(QString sid, QImage image)
+ : QGLColladaParam(sid, QGLColladaParam::ImageType)
+ , mImage(image)
+{
+}
+
+
+
+/*!
+ \internal
+*/
+QImage QGLColladaImageParam::image()
+{
+ return mImage;
+}
+
+
+
+/*!
+ \internal
+*/
+QString QGLColladaImageParam::name()
+{
+ return mName;
+}
+
+
+
+/*!
+ \internal
+*/
+QGLColladaSurfaceParam* QGLColladaFxEffectFactory::processSurfaceElement( QXmlStreamReader& xml , ResultState* resultState, QString passedInSid)
+{
+ Q_UNUSED(resultState);
+ QXmlStreamAttributes attributes = xml.attributes();
+ QString surfaceSid = attributes.value(QLatin1String("sid")).toString();
+ // Surfaces are the only children of a newparam, but don't have their own
+ // sids. For simplicity, use the parent's sid.
+
+ if (surfaceSid.isEmpty() && !passedInSid.isEmpty())
+ surfaceSid = passedInSid;
+ QGLColladaSurfaceParam* result = new QGLColladaSurfaceParam( surfaceSid );
+ xml.readNextStartElement();
+ if ( xml.name().toString().left(4) == QLatin1String("init") )
+ {
+ if (xml.name().toString() != QLatin1String("init_from"))
+ qWarning() << "Warning: only ""init_from"" supported in surface element ( line:" << xml.lineNumber() << ")";
+ QString init_from = xml.readElementText();
+ result->mInitFrom = init_from;
+ resultState->paramSids[surfaceSid] = init_from;
+ }
+ return result;
+}
+
+
+
+/*!
+ \internal
+ Processes a list of floating point numbers. If the list contains only 1
+ element, a QVariant<float> is returned. If the list containst 2, 3 or 4
+ elements, they are converted into a QVariant containing a QVector2D,
+ QVector3D, or QVector4D respectively.
+ If the list containst more elements than that, they are returned as a
+ QArray<float>.
+
+*/
+QVariant QGLColladaFxEffectFactory::processFloatList( QXmlStreamReader& xml )
+{
+ QArray<float> floats;
+ QString elementString = xml.readElementText();
+ QStringList list = elementString.split( QRegExp( QLatin1String("\\s+") ), QString::SkipEmptyParts );
+ bool ok;
+ float f;
+ foreach ( QString string, list )
+ {
+ f = string.toFloat( &ok );
+ if ( ok )
+ floats.append(string.toFloat());
+ else
+ {
+ qWarning() << "Warning: malformed float ( line" << xml.lineNumber() << ")";
+ }
+ }
+
+ switch(floats.count())
+ {
+ case 0:
+ return QVariant();
+ // no break necessary
+ case 1:
+ return QVariant(floats[0]);
+ // no break necessary
+ case 2:
+ return QVariant(QVector2D(floats[0], floats[1]));
+ // no break necessary
+ case 3:
+ return QVariant(QVector3D(floats[0], floats[1], floats[2]));
+ // no break necessary
+ case 4:
+ return QVariant(QVector4D(floats[0], floats[1], floats[2], floats[3]));
+ // no break necessary
+ default:
+ {
+ QVariant result;
+ result.setValue(floats);
+ return result;
+ }
+ }
+ // Function should always return out of switch statement
+}
+
+
+
+/*!
+ \internal
+*/
+void QGLColladaFxEffectFactory::processSampler2DElement( QXmlStreamReader& xml, ResultState* resultState, QString passedInSid )
+{
+ Q_UNUSED(resultState);
+ QXmlStreamAttributes attributes = xml.attributes();
+ QString sid = attributes.value(QLatin1String("sid")).toString();
+ if (sid.isEmpty() && !passedInSid.isEmpty())
+ {
+ sid = passedInSid;
+ }
+
+ xml.readNextStartElement();
+ if ( xml.name() == QLatin1String("source"))
+ {
+ // Collada 1.4 Spec
+ QString sourceSurfaceSid = xml.readElementText().trimmed();
+ resultState->paramSids[sid] = sourceSurfaceSid;
+ }
+
+ if ( xml.name() == QLatin1String("instance_image") )
+ {
+ // Collada 1.5 Spec
+ qWarning() << "collada 1.5 sampler elements not supported ( line:" << xml.lineNumber() << ")";
+ }
+ // exit cleanly, just in case.
+ findEndTag( xml, QLatin1String("sampler2D"));
+ return;
+}
+
+
+
+/*!
+ \internal
+ Parses and consumes a color collada element from \a xml.
+*/
+QColor QGLColladaFxEffectFactory::processColorElement( QXmlStreamReader& xml )
+{
+ QVariant floatList = processFloatList( xml );
+
+ QColor result( 0, 0, 0, 255 );
+ if (floatList.type() == QVariant::Vector3D)
+ {
+ QVector3D vector3D = floatList.value<QVector3D>();
+ if ( !vector3D.isNull())
+ {
+ result.setRgbF( vector3D.x()
+ , vector3D.y()
+ , vector3D.z()
+ , 1.0 );
+ return result;
+ }
+ }
+ else if (floatList.type() == QVariant::Vector4D)
+ {
+ QVector4D vector4D = floatList.value<QVector4D>();
+ if (!vector4D.isNull())
+ {
+ result.setRgbF( vector4D.x()
+ , vector4D.y()
+ , vector4D.z()
+ , vector4D.w() );
+ return result;
+ }
+ }
+ qWarning() << "Warning: Malformed color element ( line" << xml.lineNumber() << ")";
+ return result;
+}
+
+
+
+/*!
+ \internal
+ Parses and consumes an fx_common_color_or_texture_type collada element from \a xml.
+*/
+QVariant QGLColladaFxEffectFactory::processColorOrTextureElement( QXmlStreamReader& xml )
+{
+ if ( xml.name() == QLatin1String("color"))
+ {
+ return processColorElement( xml );
+ } else if ( xml.name() == QLatin1String("texture") )
+ {
+ qWarning() << "Warning: texture element not supported ( line" << xml.lineNumber()<<")";
+ } else
+ {
+ qWarning() << "Color or Texture expected ( line" << xml.lineNumber() << ")";
+ }
+ xml.skipCurrentElement();
+ return( QColor( 0, 0, 0,255 ));
+}
+
+
+
+/*!
+ \internal
+ Parses an fx_common_float_or_param_type collada element from \a xml.
+ Always consumes the element.
+*/
+float QGLColladaFxEffectFactory::processParamOrFloatElement( QXmlStreamReader& xml )
+{
+ if ( xml.name() == QLatin1String("param") )
+ {
+ qWarning() << "Warning: params not supported ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ return 0.0;
+ } else
+ {
+ return xml.readElementText().toFloat();
+ }
+}
+
+
+
+/*!
+ Parses and consumes a library_images collada element pointed to by \a xml,
+ and pushes any images found onto the \a resultState for use in resolving
+ elements later.
+*/
+void QGLColladaFxEffectFactory::processLibraryImagesElement( QXmlStreamReader& xml, ResultState* resultState )
+{
+ xml.readNextStartElement();
+
+ if ( xml.name() == QLatin1String("asset") )
+ {
+ qWarning() << "Warning: effect asset handling not supported in library_images element ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("image") && xml.tokenType() == QXmlStreamReader::StartElement )
+ {
+ processImageElement( xml , resultState );
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+}
+
+
+/*!
+ \internal
+*/
+QList<QGLColladaFxEffect*> QGLColladaFxEffectFactory::processLibraryEffectsElement( QXmlStreamReader& xml, ResultState* resultState )
+{
+ QList<QGLColladaFxEffect*> result;
+ // A collada library_effects is
+ // 0 or 1 <asset>
+ // 1 or more <effect>,
+ // 0 or more <extra>;
+ xml.readNextStartElement();
+
+ if ( xml.name() == QLatin1String("asset") )
+ {
+ qWarning() << "Warning: effect asset handling not supported in effects library ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("effect") && xml.tokenType() == QXmlStreamReader::StartElement )
+ {
+ result += processEffectElement( xml , resultState );
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("extra") )
+ {
+ qWarning() << "Warning: extra element not handled in effects library ( line" << xml.lineNumber() << ")";
+ xml.readNextStartElement();
+ }
+
+ // be sure to exit cleanly
+ findEndTag(xml, QLatin1String("library_effects"));
+ return result;
+}
+
+
+
+/*!
+ \internal
+ Parses and consumes an effect element from \a xml.
+*/
+QList<QGLColladaFxEffect*> QGLColladaFxEffectFactory::processEffectElement( QXmlStreamReader& xml, ResultState* resultState )
+{
+ // An effect element is:
+ // 0 or 1 <annotate>
+ // 0 or more newparam
+ // 1 or more profile ( either <profile_BRIDGE>, <profile_CG>, <profile_GLES>, <profile_GLES2>, <profile_GLSL>, or <profile_COMMON>
+ // 0 or more <extra>
+
+ QList<QGLColladaFxEffect*> result;
+ xml.readNextStartElement();
+
+ if ( xml.name() == QLatin1String("annotate") )
+ {
+ qWarning() << "effect annotation not supported ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("newparam") && xml.tokenType() == QXmlStreamReader::StartElement )
+ {
+ processNewparamElement( xml , resultState );
+ xml.readNextStartElement();
+ }
+
+ // find any of the profile_* elements defined in the spec
+ QRegExp profileRegExp( QLatin1String("profile_(BRIDGE|CG|GLES2?|GLSL|COMMON)") );
+ while ( profileRegExp.indexIn( xml.name().toString() ) == 0 && xml.tokenType() == QXmlStreamReader::StartElement )
+ {
+ result += processProfileElement( xml, resultState );
+ xml.readNextStartElement();
+ }
+
+ findEndTag(xml, QLatin1String("effect"));
+ return result;
+}
+
+
+
+/*!
+ \internal
+*/
+QList<QGLColladaFxEffect*> QGLColladaFxEffectFactory::processProfileElement( QXmlStreamReader& xml, ResultState* resultState )
+{
+ // A profile_GLES2 element is:
+ // 0 or 1 <asset>
+ // 0 or more <code> or <include>
+ // 0 or more <newparam>
+ // 1 or more <technique>
+
+ // A profile_GLSL element is:
+ // 0 or 1 <asset>
+ // 0 or more <code>
+ // 0 or more <include>
+ // 0 or more <newparam>
+ // 1 or more <technique>
+ // 0 or more <extra>
+
+ // A profile_COMMON element is
+ // an optional id element
+ // 0 or 1 <asset>
+ // 0 or more <newparam>
+ // 1 <technique>
+ // 0 or more <extra>
+
+ // Note: techniques need to be handled differently for different profiles
+
+ QString rootNodeString = xml.name().toString();
+ QList<QGLColladaFxEffect*> result;
+
+ xml.readNextStartElement();
+ if ( xml.name() == QLatin1String("asset") )
+ {
+ qWarning() << "Warning: asset element not supported in " << rootNodeString << "elements ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if (rootNodeString == QLatin1String("profile_GLSL"))
+ {
+ while ( xml.name() == QLatin1String("code") )
+ {
+ QString codeSid = xml.attributes().value(QLatin1String("sid")).toString();
+ QString codeText = xml.readElementText();
+ resultState->paramSids[codeSid] = codeText;
+
+ findEndTag(xml, QLatin1String("code"));
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("include") )
+ {
+ QString includeSid = xml.attributes().value(QLatin1String("sid")).toString();
+ QString includeUrl = xml.attributes().value(QLatin1String("url")).toString();
+
+ // create an include param?
+ qWarning() << "Warning: include element not supported in " << rootNodeString << "elements ( line" << xml.lineNumber() << ")";
+
+ findEndTag(xml, QLatin1String("include"));
+ xml.readNextStartElement();
+ }
+
+ }
+
+ while ( xml.tokenType() == QXmlStreamReader::StartElement &&
+ ( xml.name() == QLatin1String("newparam") || xml.name() == QLatin1String("image") ))
+ {
+ if ( xml.name() == QLatin1String("newparam") )
+ processNewparamElement( xml , resultState );
+ else if ( xml.name() == QLatin1String("image") )
+ processImageElement( xml , resultState );
+
+ xml.readNextStartElement();
+ }
+
+
+ while ( xml.name() == QLatin1String("technique") )
+ {
+ result.append(
+ processTechniqueElement( xml, resultState, rootNodeString ));
+ xml.readNextStartElement();
+ // only 1 technique in profile_COMMON
+ if ( rootNodeString == QLatin1String("profile_COMMON"))
+ {
+ break;
+ }
+ };
+
+ while ( xml.name() == QLatin1String("extra") )
+ {
+ qWarning() << "extra elements currently not supported in " << rootNodeString << "elements ( line" << xml.lineNumber() << ")";
+ findEndTag( xml, QLatin1String("extra") );
+ xml.readNextStartElement();
+ };
+
+ findEndTag( xml, rootNodeString );
+ return result;
+}
+
+
+QGLColladaParam* QGLColladaFxEffectFactory::processPassElement( QXmlStreamReader& xml, ResultState* resultState, QGLColladaFxEffect* effect )
+{
+ QGLColladaParam* result = 0;
+ // a profile_GLSL pass is:
+ // 0 or 1 <annotate>
+ // 0 or 1 <states>
+ // 0 or 1 <program> (CG, GLES2 or GLSL only)
+ // 0 or 1 <evaluate>
+ // 0 or 1 <extra>
+
+ xml.readNextStartElement();
+
+ if ( xml.name() == QLatin1String("annotate") )
+ {
+ qWarning() << "Warning: annotate element not supported ( line" << xml.lineNumber() << ")";
+ findEndTag( xml, QLatin1String("annotate") );
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("states") )
+ {
+ qWarning() << "Warning: states element not supported ( line" << xml.lineNumber() << ")";
+ findEndTag( xml, QLatin1String("states") );
+ xml.readNextStartElement();
+ }
+
+ // 0 or 1 <program> (CG, GLES2 or GLSL only)
+ if ( xml.name() == QLatin1String("program") )
+ {
+ processProgramElement( xml, resultState, effect );
+ findEndTag( xml, QLatin1String("program") );
+ xml.readNextStartElement();
+ }
+
+ // 0 or 1 <evaluate>
+ if ( xml.name() == QLatin1String("evaluate") )
+ {
+ qWarning() << "Warning: evaluate element not supported ( line" << xml.lineNumber() << ")";
+ findEndTag( xml, QLatin1String("evaluate") );
+ xml.readNextStartElement();
+ }
+
+ // 0 or more <extra>
+ while ( xml.name() == QLatin1String("extra") )
+ {
+ qWarning() << "Warning: extra element not supported ( line" << xml.lineNumber() << ")";
+ findEndTag( xml, QLatin1String("extra") );
+ xml.readNextStartElement();
+ }
+
+ findEndTag( xml, QLatin1String("pass"));
+ return result;
+}
+
+QGLColladaFxEffect* QGLColladaFxEffectFactory::processTechniqueElement( QXmlStreamReader& xml, ResultState* resultState, QString &profileName )
+{
+ // A 1.4 technique is:
+ // 0 or 1 <asset>
+ // 0 or more <newparam> or <image> (in any order)
+ // 0 or more of <constant>, <lambert>, <phong>, <blinn>
+ // 0 or more <extra>
+
+ // A 1.5 profile_COMMON technique is:
+ // 0 or 1 <asset>
+ // exactly 1 of <blinn>, <constant>, <lambert>, or <phong>
+ // 0 or more <extra>
+
+ // a profile_GLSL technique is:
+ // 0 or 1 <asset>
+ // 0 or more <annotate>
+ // 1 or more <pass>
+ // 0 or more <extra>
+
+ QGLColladaFxEffect* effect = new QGLColladaFxEffect();
+
+ QXmlStreamAttributes attributes = xml.attributes();
+ effect->setSid( attributes.value( QLatin1String("sid") ).toString() );
+ QStringRef id = attributes.value( QLatin1String("id") );
+ Q_UNUSED( id );
+
+ xml.readNextStartElement();
+
+ if ( xml.name() == QLatin1String("asset") )
+ {
+ qWarning() << "Warning: asset element not supported ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("annotate") && xml.tokenType() == QXmlStreamReader::StartElement )
+ {
+ qWarning() << "Warning: annotate element not supported ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ // Collada specifies exactly one of blinn, lambert, constant or phong
+ // If the effect is malformed, default QGLMaterial will be used.
+ QGLMaterial* material = new QGLMaterial;
+
+ if ( profileName == QLatin1String("profile_COMMON") &&
+ (xml.name() == QLatin1String("blinn") || xml.name() == QLatin1String("phong") ||
+ xml.name() == QLatin1String("constant") || xml.name() == QLatin1String("lambert")) )
+ {
+ if ( xml.name() == QLatin1String("blinn") )
+ {
+ effect->setLighting( QGLColladaFxEffect::BlinnLighting );
+ } else if ( xml.name() == QLatin1String("phong") ) {
+ effect->setLighting( QGLColladaFxEffect::PhongLighting );
+ } else if ( xml.name() == QLatin1String("constant") ) {
+ effect->setLighting( QGLColladaFxEffect::ConstantLighting );
+ } else if ( xml.name() == QLatin1String("lambert") ) {
+ effect->setLighting( QGLColladaFxEffect::LambertLighting );
+ }
+
+ // TODO: get appropriate shader fragments for the specified lighting models
+ if ( xml.readNextStartElement() )
+ {
+ // a blinn element is 0 or 1 of each of:
+ // <emission>
+ // <diffuse>
+ // <specular>
+ // <shininess>
+ // <reflectivity>
+ // <transparent>
+ // <transparency>
+ // <index_of_refraction>
+
+ if ( xml.name() == QLatin1String("emission") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ // handle color or texture element:
+ if (xml.name() == QLatin1String("color"))
+ {
+ material->setEmittedLight( processColorElement( xml ));
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set emitted light to " << material->emittedLight();
+#endif
+ }
+ else if ( xml.name() == QLatin1String("texture"))
+ {
+ effect->d->emissiveTexture = processTextureElement( xml, resultState );
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set emissive texture to " << effect->d->emissiveTexture;
+#endif
+ } else if ( xml.name() == QLatin1String("param"))
+ {
+ qWarning() << "params not supported in lighting elements ( line" << xml.lineNumber() << ")";
+ }
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("ambient") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ // handle color or texture element:
+ if (xml.name() == QLatin1String("color"))
+ {
+ material->setAmbientColor( processColorElement( xml ));
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set ambient color to " << material->ambientColor();
+#endif
+ }
+ else if ( xml.name() == QLatin1String("texture"))
+ {
+ effect->d->ambientTexture = processTextureElement( xml, resultState );
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set ambient texture to " << effect->d->ambientTexture;
+#endif
+ } else if ( xml.name() == QLatin1String("param"))
+ {
+ qWarning() << "params not supported in lighting elements ( line" << xml.lineNumber() << ")";
+ }
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("diffuse") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ // handle color or texture element:
+ if (xml.name() == QLatin1String("color"))
+ {
+ material->setDiffuseColor( processColorElement( xml ));
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set diffuse color to " << material->diffuseColor();
+#endif
+ }
+ else if ( xml.name() == QLatin1String("texture"))
+ {
+ effect->d->diffuseTexture = processTextureElement( xml, resultState );
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set diffuse texture to " << effect->d->diffuseTexture;
+#endif
+ } else if ( xml.name() == QLatin1String("param"))
+ {
+ qWarning() << "params not supported in lighting elements ( line" << xml.lineNumber() << ")";
+ }
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("specular") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ // handle color or texture element:
+ if (xml.name() == QLatin1String("color"))
+ {
+ material->setSpecularColor( processColorElement( xml ));
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set specular color to " << material->specularColor();
+#endif
+ }
+ else if ( xml.name() == QLatin1String("texture"))
+ {
+ effect->d->specularTexture = processTextureElement( xml, resultState );
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set specular texture to " << effect->d->specularTexture;
+#endif
+ } else if ( xml.name() == QLatin1String("param"))
+ {
+ qWarning() << "params not supported in lighting elements ( line" << xml.lineNumber() << ")";
+ }
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("shininess") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ float shininess = processParamOrFloatElement( xml );
+ if ( 0.0 < shininess && shininess < 1.0 )
+ {
+ qWarning() << "Warning: Blinn-Torrance-Sparrow specular lighting not suported ( line" << xml.lineNumber()
+ << "), converting to Blinn-Phong specular model";
+ material->setShininess( int( shininess * 128.0 ));
+ }
+ else
+ material->setShininess( int( shininess ) );
+#ifdef DEBUG_MATERIALS
+ qDebug() << "set shininess to " << material->shininess();
+#endif
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("reflective") )
+ {
+ qWarning() << "Warning reflective not supported ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("reflectivity") )
+ {
+ qWarning() << "Warning: reflectivity not supported ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("transparent") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ if (xml.name() == QLatin1String("texture"))
+ {
+ QGLTexture2D* transparentTexture = processTextureElement( xml , resultState );
+ Q_UNUSED(transparentTexture);
+ qWarning() << "Warning: transparent not supported ( line" << xml.lineNumber() << ")";
+#ifdef DEBUG_MATERIALS
+ qDebug() << "unused transparent texture" << transparentTexture;
+#endif
+ }
+ else if (xml.name() == QLatin1String("color"))
+ {
+ QColor transparent = processColorElement( xml );
+ Q_UNUSED( transparent );
+ qWarning() << "Warning: transparent not supported ( line" << xml.lineNumber() << ")";
+#ifdef DEBUG_MATERIALS
+ qDebug() << "unused transparent color of " << transparent;
+#endif
+ }
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if ( xml.name() == QLatin1String("transparency") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ float transparency = processParamOrFloatElement( xml );
+ if ( transparency < 1.0 )
+ {
+ qWarning() << "Warning: transparency not supported";
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+ }
+
+ if ( xml.name() == QLatin1String("index_of_refraction") )
+ {
+ if ( xml.readNextStartElement() )
+ {
+ float indexOfRefraction = processParamOrFloatElement( xml );
+ Q_UNUSED( indexOfRefraction );
+ qWarning() << "Warning: index_of_refraction not supported ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ }
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+ }
+ // end of lighting scope
+
+ effect->setMaterial( material );
+
+ switch(effect->lighting())
+ {
+ case QGLColladaFxEffect::PhongLighting:
+ case QGLColladaFxEffect::LambertLighting:
+ qWarning() << "Warning: requested lighting not supported, using Blinn-Phong instead";
+ case QGLColladaFxEffect::BlinnLighting:
+ effect->addBlinnPhongLighting();
+ case QGLColladaFxEffect::ConstantLighting:
+ case QGLColladaFxEffect::NoLighting:
+ default:
+ break;
+ }
+ };
+
+ while ( xml.name() == QLatin1String("pass") && xml.tokenType() == QXmlStreamReader::StartElement )
+ {
+ processPassElement( xml, resultState, effect);
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ // Make sure to exit cleanly
+ findEndTag( xml, QLatin1String("technique") );
+
+ return effect;
+}
+
+
+
+QGLColladaParam* QGLColladaFxEffectFactory::processNewparamElement( QXmlStreamReader& xml, ResultState* resultState)
+{
+ QXmlStreamAttributes attributes = xml.attributes();
+ QString sidString = attributes.value(QLatin1String("sid")).toString();
+ QGLColladaParam* result = 0;
+ if (xml.readNextStartElement())
+ {
+ if (xml.name().toString().left(5) == QLatin1String("float"))
+ {
+
+ QVariant floatValues = processFloatList( xml );
+ resultState->paramSids[sidString] = floatValues;
+
+ if ( xml.name() == QLatin1String("float")
+ && ( floatValues.type() !=
+ static_cast<QVariant::Type>(QMetaType::Float )))
+ {
+ qWarning() << "Warning: parsed type incorrectly, expected float ( line" << xml.lineNumber() << ")";
+ resultState->paramSids[sidString] = floatValues.value<float>();
+ }
+ else if ( xml.name() == QLatin1String("float2")
+ && floatValues.type() != QVariant::Vector2D )
+ {
+ qWarning() << "Warning: parsed type incorrectly, expected float2 ( line" << xml.lineNumber() << ")";
+ }
+ else if ( xml.name() == QLatin1String("float3")
+ && floatValues.type() != QVariant::Vector3D )
+ {
+ qWarning() << "Warning: parsed type incorrectly, expected float3 ( line" << xml.lineNumber() << ")";
+ }
+ else if ( xml.name() == QLatin1String("float4")
+ && floatValues.type() != QVariant::Vector4D)
+ {
+ qWarning() << "Warning: parsed type incorrectly, expected float4 ( line" << xml.lineNumber() << ")";
+ }
+ } else if ( xml.name() == QLatin1String("sampler2D") )
+ {
+ processSampler2DElement( xml , resultState, sidString );
+ } else if ( xml.name() == QLatin1String("surface") )
+ {
+ result = processSurfaceElement( xml, resultState, sidString);
+ } else {
+ qWarning() << "unrecognized parameter type ( line:" << xml.lineNumber() << ")";
+ findEndTag( xml, QLatin1String("newparam") );
+ return 0;
+ }
+ }
+ findEndTag(xml, QLatin1String("newparam"));
+ return result;
+}
+
+
+/*!
+ \internal
+ the library_images can come after the library_effects, so textures referenced
+ in effects might not have been defined when the effect was created. Try and
+ resolve those images now. (Other properties - wrap, mipmap and filters etc
+ should have been resolved when the texture was originally parsed).
+ */
+bool QGLColladaFxEffectFactory::resolveTexture2DImage(QGLTexture2D *texture, ResultState *resultState, QString paramName)
+{
+ if (texture == 0)
+ {
+ qWarning() << "Warning: Cannot resolve images for null QGLTexture2D";
+ return false;
+ }
+ QVariant samplerParam = findParameterVariant(resultState, paramName);
+ QString surfaceName = samplerParam.value<QString>();
+ QImage image;
+
+ if (!surfaceName.isEmpty())
+ {
+ QVariant surfaceParam = findParameterVariant(resultState, surfaceName);
+ QString initFrom = surfaceParam.value<QString>();
+ if (!initFrom.isEmpty())
+ {
+ image = resolveImageURI(resultState, initFrom);
+ }
+ }
+
+ // If that's failed, try again with the passed in paramName
+ if (image.isNull())
+ {
+ image = resolveImageURI(resultState, paramName);
+ }
+
+ texture->setImage(image);
+ return !image.isNull();
+}
+
+
+
+
+Q_DECLARE_METATYPE(QGLTexture2D*);
+/*!
+ \internal
+ Parses and consumes a texture collada element from \a xml.
+*/
+QGLTexture2D* QGLColladaFxEffectFactory::processTextureElement( QXmlStreamReader& xml , ResultState* resultState )
+{
+ QGLTexture2D* result = new QGLTexture2D();
+ QXmlStreamAttributes attributes = xml.attributes();
+
+ foreach (QXmlStreamAttribute attribute, attributes)
+ {
+ if ( attribute.name() == QLatin1String("texture") )
+ {
+ QString paramName = attribute.value().toString();
+
+ // in Collada Fx Textures must reference a previously defined
+ // sampler2D param.
+ // However, this sampler may refer to images in the library_images,
+ // which is parsed after the library_effects, so try and resolve
+ // now, but save failures to try again later.
+
+ if (!resolveTexture2DImage(result, resultState, paramName))
+ {
+ resultState->unresolvedTexture2Ds[result] = paramName;
+ }
+ } else if ( attribute.name() == QLatin1String("texcoord") )
+ {
+ // TODO: Create a repository for this sort of data, to be used in creating the shader progams later
+ // I'm pretty sure the effect is going to need to be passed in.
+ qWarning() << "texcoord not supported yet: " << attribute.name() << attribute.value() << " ( line" << xml.lineNumber() << ")";
+ } else if (attribute.name() == QLatin1String("extra"))
+ {
+ qWarning() << "extra elements in texture elements not supported ( line" << xml.lineNumber() << ")";
+ }
+ }
+ xml.skipCurrentElement();
+
+ return result;
+}
+
+/*!
+ \internal
+ Try and get an image to attach to a texture. The URI could be a reference to
+ a param in the collada document (which may in turn be a reference), or
+ file referenced either absolutely or relative to the original dae file.
+ (It could concievably be a web URL, but that is not handled here.)
+ */
+QImage QGLColladaFxEffectFactory::resolveImageURI(ResultState *resultState, QString URI)
+{
+ QImage result;
+ QString imageFileName;
+ QString workingURI = URI;
+ if (workingURI.length() > 0 && workingURI.at(0) == QLatin1Char('#'))
+ {
+ workingURI = workingURI.right(workingURI.length() - 1);
+ }
+
+ QVariant potentialParameter = findParameterVariant(resultState, workingURI);
+ // Might be parameter itself:
+ if ( !potentialParameter.value<QImage>().isNull() )
+ return potentialParameter.value<QImage>();
+ // or might be another URI
+ if (!potentialParameter.value<QString>().isNull())
+ {
+ imageFileName = potentialParameter.value<QString>();
+ } else {
+ imageFileName = workingURI;
+ }
+
+ // First try as a relative path.
+ QString filePath = resultState->sourceDir.path() + QLatin1Char('/') + imageFileName;
+ result.load(filePath);
+ if (result.isNull())
+ {
+ // No relative file found, so try as an absolute path
+ result.load(imageFileName);
+ }
+ return result;
+}
+
+/*!
+ \internal
+ Parses and consumes an image element from \a xml.
+*/
+void QGLColladaFxEffectFactory::processImageElement( QXmlStreamReader& xml, ResultState* resultState )
+{
+ // 1.4 has a bunch of optional values in the attributes:
+ QString sid = xml.attributes().value(QLatin1String("sid")).toString();
+ QString id = xml.attributes().value(QLatin1String("id")).toString();
+ QString name = xml.attributes().value(QLatin1String("name")).toString();
+
+ QString height = xml.attributes().value(QLatin1String("height")).toString();
+ QString width = xml.attributes().value(QLatin1String("width")).toString();
+ QString depth = xml.attributes().value(QLatin1String("depth")).toString();
+
+ Q_UNUSED(height);
+ Q_UNUSED(width);
+ Q_UNUSED(depth);
+
+ QImage result;
+
+ xml.readNextStartElement();
+ if (xml.name() == QLatin1String("asset"))
+ {
+ qWarning() << "asset element not supported in image elements ( line" << xml.lineNumber() << ")";
+ xml.skipCurrentElement();
+ xml.readNextStartElement();
+ }
+
+ if (xml.name() == QLatin1String("init_from"))
+ {
+ QString imageFileName = xml.readElementText().trimmed();
+ QDir sourceDir = resultState->sourceDir;
+ // ignore path information for resources
+ QString filePath = sourceDir.path() + QLatin1Char('/') + imageFileName;
+ result.load(filePath);
+ if (result.isNull())
+ {
+ // Catch resources or files with absolute paths
+ result.load(imageFileName);
+ }
+ if (!sid.isEmpty())
+ resultState->paramSids[sid] = result;
+ if (!id.isEmpty())
+ resultState->paramIds[id] = result;
+ if (!name.isEmpty())
+ resultState->paramNames[name] = result;
+ }
+
+ // exit cleanly
+ findEndTag( xml, QLatin1String("image"));
+}
+
+QStringList QGLColladaFxEffectFactory::glslProfileFromEffect(QGLColladaFxEffect* effect, QString sid)
+{
+ Q_UNUSED(effect)
+ Indent indent;
+ QStringList result;
+ result += indent + QLatin1String("<profile_GLSL>");
+ {
+ result += generateCodeElements(effect, sid);
+ result += indent + QLatin1String("<technique sid=\"") + sid + QLatin1String("\">");
+ {
+ Indent indent;
+ result += indent + QLatin1String("<pass>");
+ result += generateProgramElement(effect, sid);
+ result += indent + QLatin1String("</pass>");
+ }
+ result += indent + QLatin1String("</technique>");
+ }
+ result += indent + QLatin1String("</profile_GLSL>");
+
+ return result;
+}
+
+QStringList QGLColladaFxEffectFactory::generateProgramElement(QGLColladaFxEffect* effect, QString techniqueSid)
+{
+ QStringList result;
+ QString vertexShaderRefSid = QLatin1String("VertexShaderRefSidRefsCodeOrIncludeAtProfileOrEffectLevel");
+ QString fragmentShaderRefSid = QLatin1String("FragmentShaderRefSidRefsCodeOrIncludeAtProfileOrEffectLevel");
+ Indent indent;
+ result += indent + QLatin1String("<program>");
+ result += generateShaderElement(effect, techniqueSid + QLatin1String("VertexShader"), techniqueSid + QLatin1String("FragmentShader"));
+ // 0 or more
+ result += generateBindAttributeElement( effect );
+ // 0 or more
+ result += generateBindUniformElements( effect );
+ result += indent + QLatin1String("</program>");
+ return result;
+}
+
+QStringList QGLColladaFxEffectFactory::generateShaderElement( QGLColladaFxEffect* effect, QString vertexShaderRefSid, QString fragmentShaderRefSid )
+{
+ Q_UNUSED(effect);
+ QStringList result;
+ Indent indent;
+ result += indent + QLatin1String("<shader stage=\"VERTEX\">");
+ {
+ Indent indent;
+ result += indent + QLatin1String("<sources>");
+ {
+ // 0 or more <import> elements
+ Indent indent;
+ result += indent + QLatin1String("<import ref=\"") + vertexShaderRefSid + QLatin1String("\"/>");
+ }
+ result += indent + QLatin1String("</sources>");
+ // 0 or <extra> elements;
+ }
+ result += indent + QLatin1String("</shader>");
+
+ result += indent + QLatin1String("<shader stage=\"FRAGMENT\">");
+ {
+ Indent indent;
+ result += indent + QLatin1String("<sources>");
+ {
+ Indent indent;
+ result += indent + QLatin1String("<import ref=\"") + fragmentShaderRefSid + QLatin1String("\"/>");
+ }
+ result += indent + QLatin1String("</sources>");
+ // <extra> element(s) here if necessary;
+ }
+ result += indent + QLatin1String("</shader>");
+ return result;
+}
+
+QStringList QGLColladaFxEffectFactory::generateBindAttributeElement( QGLColladaFxEffect* effect )
+{
+ // Currently no need for bind_attribute elements.
+ Q_UNUSED(effect);
+ QStringList result;
+ // Indent indent;
+ // result += indent + "<bind_attribute>";
+ // result += indent + "</bind_attribute>";
+ return result;
+}
+
+QStringList generateBindUniformParamElement( QString symbol, QString ref)
+{
+ QStringList result;
+ // 0 or more <bind_uniform> elements
+ Indent indent;
+ result += indent + QLatin1String("<bind_uniform symbol=\"") + symbol + QLatin1String("\">");
+ {
+ Indent indent;
+ result += indent + QLatin1String("<param ref=\"") + ref + QLatin1String("\">");
+ }
+ result += indent + QLatin1String("</bind_uniform>");
+ return result;
+}
+
+QStringList generateBindUniformParamElement( QString symbol, const QVector3D& value)
+{
+ QStringList result;
+ // 0 or more <bind_uniform> elements
+ Indent indent;
+ result += indent + QLatin1String("<bind_uniform symbol=\"") + symbol + QLatin1String("\">");
+ {
+ Indent indent;
+ result += indent + QString(QLatin1String("<float3> %1 %2 %3 </float3>")).arg(value.x()).arg(value.y()).arg(value.z());
+ }
+ result += indent + QLatin1String("</bind_uniform>");
+ return result;
+}
+
+QStringList generateBindUniformParamElement( QString symbol, const QColor& value)
+{
+ QStringList result;
+ // 0 or more <bind_uniform> elements
+ Indent indent;
+ result += indent + QLatin1String("<bind_uniform symbol=\"") + symbol + QLatin1String("\">");
+ {
+ Indent indent;
+ result += indent + QString(QLatin1String("<float3> %1 %2 %3 </float3>")).arg(value.redF()).arg(value.greenF()).arg(value.blueF());
+ }
+ result += indent + QLatin1String("</bind_uniform>");
+ return result;
+}
+
+
+QStringList QGLColladaFxEffectFactory::generateBindUniformElements( QGLColladaFxEffect* effect )
+{
+ QStringList result;
+ if (effect == 0)
+ return result;
+ // // 0 or more <bind_uniform> elements
+ // Example uniforms
+ // result += generateBindUniformParamElement( "exampleRefSymbol", QString("exampleRef"));
+ // result += generateBindUniformParamElement( "exampleFloat3Symbol", QVector3D(0.1, 0.2, 0.3) );
+
+ if (effect->material() != 0)
+ {
+ QGLMaterial* material = effect->material();
+
+ // Actual uniforms:
+ result += generateBindUniformParamElement( QLatin1String("ambientColor"), material->ambientColor());
+ result += generateBindUniformParamElement( QLatin1String("diffuseColor"), material->diffuseColor());
+ result += generateBindUniformParamElement( QLatin1String("emittedLight"), material->emittedLight());
+ result += generateBindUniformParamElement( QLatin1String("objectName"), material->objectName());
+ result += generateBindUniformParamElement( QLatin1String("shininess"), material->shininess());
+ result += generateBindUniformParamElement( QLatin1String("specularColor"), material->specularColor());
+
+ effect->supportsPicking();
+
+ // TODO: Find and store effect uniforms
+ // effect->bindProgramUniforms();
+ }
+ return result;
+}
+
+QStringList QGLColladaFxEffectFactory::generateCodeElements( QGLColladaFxEffect* effect, QString baseSid )
+{
+ QStringList result;
+ // 0 or more <bind_uniform> elements
+ Indent indent;
+
+ // put all this on one line to avoid adding carriage returns to the
+ // shader programs
+ result += indent + QLatin1String("<code sid=\"") + baseSid + QLatin1String("VertexShader\">")
+ + effect->vertexShader() + QLatin1String("</code>");
+
+ result += indent + QLatin1String("<code sid=\"") + baseSid + QLatin1String("FragmentShader\">")
+ + effect->fragmentShader() + QLatin1String("</code>");
+
+ return result;
+}
+
+void QGLColladaFxEffectFactory::processProgramElement( QXmlStreamReader& xml, ResultState* resultState, QGLColladaFxEffect* effect )
+{
+ // A profile_GLSL shader element is
+ // 0 or more <shader>
+ // 0 or more <bind_attribute>
+ // 0 or more <bind_uniform>
+
+ xml.readNextStartElement();
+
+ while ( xml.name() == QLatin1String("shader") )
+ {
+ // in profile_GLSL a shader is
+ // exactly 1 <source>
+ // 0 or more <extra>
+
+ QString stage = xml.attributes().value(QLatin1String("stage")).toString();
+ xml.readNextStartElement();
+ if ( xml.name() == QLatin1String("sources") )
+ {
+ // a <sources> element is
+ // 1 or more <inline> elements
+ // 0 or more <import> elements
+ // Note: child elements can appear in any order
+
+ xml.readNextStartElement();
+ while ( (xml.name() == QLatin1String("inline") || xml.name() == QLatin1String("import")) && xml.tokenType() == QXmlStreamReader::StartElement)
+ {
+ if ( xml.name() == QLatin1String("import"))
+ {
+ QString ref = xml.attributes().value(QLatin1String("ref")).toString();
+
+ QXmlStreamAttribute attr;
+ if (xml.attributes().count())
+ {
+ attr = xml.attributes().first();
+ }
+
+ QVariant param = findParameterVariant(resultState, ref);
+ if (param.isNull() || param.type() != QVariant::String)
+ {
+ qWarning() << "null or unexpected parameter found in import element ( line"
+ << xml.lineNumber()<<")";
+ }
+ else
+ {
+ if (stage == QLatin1String("VERTEX"))
+ {
+ effect->setVertexShader( param.value<QString>().toLatin1() );
+ }
+ else if (stage == QLatin1String("FRAGMENT"))
+ {
+ effect->setFragmentShader( param.value<QString>().toLatin1() );
+ } else
+ {
+ qWarning() << "unrecognized shader stage: "
+ << stage << " ( line" << xml.lineNumber()<<")";
+ }
+ }
+
+ } else if ( xml.name() == QLatin1String("inline"))
+ {
+
+ }
+ xml.readNextStartElement();
+ }
+ } else {
+ qWarning() << "collada parsing error. expected <sources> element ( line"
+ << xml.lineNumber()<<")";
+ }
+
+ if (xml.name() == QLatin1String("extra"))
+ qWarning() << "Warning: extra element not supported in profile_GLSL <shader> element ( line" << xml.lineNumber()<<")";
+
+ findEndTag ( xml, QLatin1String("shader"));
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("bind_attribute") )
+ {
+ qWarning() << "Warning: bind_attribute element not supported ( line" << xml.lineNumber()<<")";
+ findEndTag ( xml, QLatin1String("bind_attribute"));
+ xml.readNextStartElement();
+ }
+
+ while ( xml.name() == QLatin1String("bind_uniform") )
+ {
+ qWarning() << "Warning: bind_uniform element not supported ( line" << xml.lineNumber()<<")";
+ findEndTag ( xml, QLatin1String("bind_uniform"));
+ xml.readNextStartElement();
+ }
+
+ findEndTag(xml, QLatin1String("program"));
+ return;
+}
diff --git a/src/threed/effects/qglcolladafxeffectfactory.h b/src/threed/effects/qglcolladafxeffectfactory.h
new file mode 100644
index 000000000..e1e31ddb5
--- /dev/null
+++ b/src/threed/effects/qglcolladafxeffectfactory.h
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCOLLADAFXEFFECTFACTORY_H
+#define QGLCOLLADAFXEFFECTFACTORY_H
+
+#include <QVector>
+#include <QXmlStreamReader>
+#include <QDir>
+#include "qgl.h"
+#include "qgltexture2d.h"
+
+#include "qglcolladafxeffect.h"
+
+class QGLColladaFxEffect;
+class QGLColladaImageParam;
+class QGLColladaSurfaceParam;
+class QGLColladaSampler2DParam;
+
+Q_DECLARE_METATYPE(QArray<float>)
+
+typedef struct _ResultState
+{
+ QMap<QString, QVariant> paramSids;
+ QMap<QString, QVariant> paramIds;
+ QMap<QString, QVariant> paramNames;
+ QDir sourceDir;
+ QMap<QGLTexture2D*, QString> unresolvedTexture2Ds;
+} ResultState;
+
+
+
+
+class Q_QT3D_EXPORT QGLColladaFxEffectFactory
+{
+public:
+ // Collada parsing functions
+ static QList<QGLColladaFxEffect*> loadEffectsFromFile(const QString& fileName );
+
+protected:
+ static QList<QGLColladaFxEffect*> loadEffectsFromXml( QXmlStreamReader& xml, QDir homeDirectory = QDir());
+ static void processLibraryImagesElement( QXmlStreamReader& xml, ResultState* stateStack );
+ static QList<QGLColladaFxEffect*> processLibraryEffectsElement( QXmlStreamReader& xml, ResultState* stateStack );
+ static QList<QGLColladaFxEffect*> processEffectElement( QXmlStreamReader& xml, ResultState* stateStack );
+ static QList<QGLColladaFxEffect*> processProfileElement( QXmlStreamReader& xml, ResultState* stateStack );
+
+ static QGLColladaParam* processPassElement( QXmlStreamReader& xml, ResultState* stateStack, QGLColladaFxEffect* effect );
+ static QGLColladaFxEffect* processTechniqueElement( QXmlStreamReader& xml, ResultState* stateStack, QString &profileName );
+ static QGLColladaParam* processNewparamElement( QXmlStreamReader& xml, ResultState* stateStack );
+ static void processImageElement( QXmlStreamReader& xml, ResultState* stateStack );
+ static QGLColladaSurfaceParam* processSurfaceElement( QXmlStreamReader& xml, ResultState* stateStack, QString passedInSid = "");
+ static void processSampler2DElement( QXmlStreamReader& xml, ResultState* stateStack, QString passedInSid );
+ static QGLTexture2D* processTextureElement( QXmlStreamReader& xml , ResultState* stateStack );
+ static QVariant processFloatList( QXmlStreamReader& xml );
+ static QColor processColorElement( QXmlStreamReader& xml );
+ static float processParamOrFloatElement( QXmlStreamReader& xml );
+ static QVariant processColorOrTextureElement( QXmlStreamReader& xml );
+ QGLColladaFxEffectFactory();
+ static void processProgramElement( QXmlStreamReader& xml, ResultState* stateStack, QGLColladaFxEffect* effect );
+
+ // Collada generation functions
+public:
+ static QString exportEffect(QGLColladaFxEffect *effect, QString effectId, QString techniqueSid);
+
+protected:
+ static QStringList glslProfileFromEffect(QGLColladaFxEffect* effect, QString techniqueSid);
+ static QStringList generateProgramElement(QGLColladaFxEffect* effect, QString techniqueSid);
+ static QStringList generateShaderElement( QGLColladaFxEffect* effect, QString vertexShaderRefSid, QString fragmentShaderRefSid );
+ static QStringList generateBindUniformElement( QGLColladaFxEffect* effect );
+ static QStringList generateBindAttributeElement( QGLColladaFxEffect* effect );
+ static QStringList generateBindUniformElements( QGLColladaFxEffect* effect );
+ static QStringList generateCodeElements( QGLColladaFxEffect* effect, QString baseSid );
+
+ static QImage resolveImageURI(ResultState *resultState, QString imageFileName);
+ static bool resolveTexture2DImage(QGLTexture2D *result, ResultState *resultState, QString paramName);
+};
+
+
+
+class QGLColladaParam
+{
+ friend class QGLColladaFxEffectFactory;
+public:
+ enum {
+ UnknownType = 0,
+ Sampler2DType,
+ Texture2DType,
+ SurfaceType,
+ ImageType,
+ UserDefinedType = 100
+ };
+
+ virtual ~QGLColladaParam();
+
+ int type();
+ QVector<float> value();
+ QString sid();
+ QString id();
+
+ static QString typeString(int);
+
+protected:
+ QGLColladaParam(QString sid, int type);
+ QString mSid;
+ QString mId;
+ int mType;
+ QVector<float> mValue;
+};
+
+
+
+class QGLColladaTextureParam : public QGLColladaParam
+{
+ friend class QGLColladaFxEffectFactory;
+public:
+ QGLColladaTextureParam(QString sid, QGLTexture2D* texture);
+ QGLTexture2D* texture();
+ QString samplerSid();
+protected:
+ QGLTexture2D* mTexture;
+ QString sampler2DSid;
+ QString texCoordSid;
+};
+
+
+
+class QGLColladaSurfaceParam : public QGLColladaParam
+{
+ friend class QGLColladaFxEffectFactory;
+public:
+ QGLColladaSurfaceParam(QString sid);
+protected:
+ QString mInitFrom;
+ QString mFormat;
+ QString mFormatHint;
+ QString mSize;
+ QVector<int> mSizeVector;
+ QPointF mViewportRatio;
+ int mMipLevels;
+ bool mMipMapGenerate;
+ QString mExtra;
+ QString mGenerator;
+};
+
+
+
+class QGLColladaSampler2DParam : public QGLColladaParam
+{
+ friend class QGLColladaFxEffectFactory;
+public:
+ QGLColladaSampler2DParam(QString sid, QGLTexture2D* sampler);
+ QGLColladaSampler2DParam(QString sid, QString sourceSid);
+ QGLTexture2D sampler();
+ QString sourceSid();
+protected:
+ QGLTexture2D* mTexture;
+ QString mSourceSid;
+};
+
+
+
+// "image" isn't really a param, but it shares enough that it seems sensible
+// to re-use the QGLColladaParam base.
+class QGLColladaImageParam : public QGLColladaParam
+{
+ friend class QGLColladaFxEffectFactory;
+public:
+ QGLColladaImageParam(QString sid, QImage image);
+ QImage image();
+ QString name();
+protected:
+ QImage mImage;
+ QString mName;
+};
+
+#endif // QGLCOLLADAFXEFFECTFACTORY_H
diff --git a/src/threed/effects/qglcolladafxeffectloader.cpp b/src/threed/effects/qglcolladafxeffectloader.cpp
new file mode 100644
index 000000000..1eff70399
--- /dev/null
+++ b/src/threed/effects/qglcolladafxeffectloader.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcolladafxeffectloader.h"
+
+#include <QList>
+#include "qglcolladafxeffectfactory.h"
+#include "qglcolladafxeffect.h"
+
+#include <QStringList>
+
+//Q_DECLARE_METATYPE(QGLColladaFxEffect)
+
+/*!
+ \class QGLColladaFxEffectLoader
+ \brief The QGLColladaFxEffectLoader class is a convenient way to load
+ effects from collada files for use with Qt3D.
+ \since 4.8
+ \ingroup qt3d
+
+ QGLColladaFxEffectLoader provides a simple class to create and store
+ QGLColladaEffect objects from Collada Fx files. It currently supports
+ a simple subset of the Collada 1.5 Fx specification.
+
+ The QGLColladaEffect effects are destroyed automatically when the loader
+ is destroyed. If finer control over effect lifetime is required, use
+ QGLColladaFxEffectFactory::loadEffectsFromFile() directly.
+*/
+
+class QGLColladaFxEffectLoaderPrivate
+{
+public:
+ QList<QGLColladaFxEffect*> effects;
+ ~QGLColladaFxEffectLoaderPrivate()
+ {
+ deleteAndClearEffects();
+ }
+
+ void deleteAndClearEffects()
+ {
+ while (effects.count())
+ {
+ delete effects.back();
+ effects.pop_back();
+ }
+ }
+
+};
+
+
+/*!
+ Constructs an empty QGLColladaFxEffectLoader object.
+*/
+QGLColladaFxEffectLoader::QGLColladaFxEffectLoader() :
+ d_ptr(new QGLColladaFxEffectLoaderPrivate())
+{
+}
+
+/*!
+ Destroys the QGLColladaFxEffectLoader and any generated QGLColladaFxEffect
+ objects.
+*/
+QGLColladaFxEffectLoader::~QGLColladaFxEffectLoader()
+{
+}
+
+/*!
+ Reads the collada file indicated by \a filename and generates
+ QGLColladaFxEffect objects from it.
+
+ The QGLColladaFxEffectFactory owns all the effects it generates, and destroys
+ them when it is destroyed, or when a new file is loaded.
+
+ If effects are needed from multiple files, use one QGLColladaFxEffectLoader
+ per file.
+
+ Returns true if at least one effect was generated.
+
+ \sa effectNames(), effect(), operator[](), QGLColladaFxEffectFactory::loadEffectsFromFile()
+ */
+bool QGLColladaFxEffectLoader::load(QString filename)
+{
+ Q_D(QGLColladaFxEffectLoader);
+ d->deleteAndClearEffects();
+ d->effects = QGLColladaFxEffectFactory::loadEffectsFromFile(filename);
+ return d->effects.count() > 0;
+}
+
+/*!
+ Returns a list of the sid attributes of effects that have been generated
+ \sa effect()
+ */
+QStringList QGLColladaFxEffectLoader::effectNames()
+{
+ Q_D(QGLColladaFxEffectLoader);
+ QStringList result;
+ QGLColladaFxEffect *effect;
+ foreach (effect, d->effects)
+ {
+ result.append(effect->sid());
+ }
+ return result;
+}
+
+/*!
+ Returns a pointer to the effect with an sid matching \a effectName, or
+ 0 if no such effect exists.
+
+ \sa load()
+ */
+QGLColladaFxEffect* QGLColladaFxEffectLoader::effect(QString effectName)
+{
+ Q_D(QGLColladaFxEffectLoader);
+ QGLColladaFxEffect* effect;
+
+ foreach (effect, d->effects)
+ {
+ if (effect && effect->sid() == effectName)
+ {
+ return effect;
+ }
+ }
+ return 0;
+}
+
+/*!
+ Returns the number of effects the loader has generated and stored.
+ */
+int QGLColladaFxEffectLoader::count()
+{
+ Q_D(QGLColladaFxEffectLoader);
+ return d->effects.count();
+}
+
+/*!
+ Returns a pointer to the effect in position \a i. QGLColladaFxEffectLoader
+ makes no guarantee about the ordering of effects relative to their position
+ in a collada document, but does not reorder effects once they have been read.
+
+ \sa load()
+ */
+QGLColladaFxEffect *QGLColladaFxEffectLoader::operator[](int i)
+{
+ Q_D(QGLColladaFxEffectLoader);
+ Q_ASSERT(i < d->effects.count());
+
+ return d->effects.at(i);
+}
diff --git a/src/threed/effects/qglcolladafxeffectloader.h b/src/threed/effects/qglcolladafxeffectloader.h
new file mode 100644
index 000000000..675e0cee4
--- /dev/null
+++ b/src/threed/effects/qglcolladafxeffectloader.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCOLLADAFXEFFECTLOADER_H
+#define QGLCOLLADAFXEFFECTLOADER_H
+
+#include <qglobal.h>
+#include <QString>
+#include <QStringList>
+#include <QtCore/qscopedpointer.h>
+#include "qt3dglobal.h"
+
+class QGLColladaFxEffect;
+class QGLColladaFxEffectLoaderPrivate;
+
+class Q_QT3D_EXPORT QGLColladaFxEffectLoader
+{
+public:
+ QGLColladaFxEffectLoader();
+ ~QGLColladaFxEffectLoader();
+ bool load(QString filename);
+ QStringList effectNames();
+ QGLColladaFxEffect *effect(QString effectName);
+ int count();
+ QGLColladaFxEffect* operator[](int);
+private:
+ Q_DECLARE_PRIVATE(QGLColladaFxEffectLoader);
+ QScopedPointer<QGLColladaFxEffectLoaderPrivate> d_ptr;
+};
+
+#endif // QGLCOLLADAFXEFFECTLOADER_H
diff --git a/src/threed/effects/qglflatcoloreffect.cpp b/src/threed/effects/qglflatcoloreffect.cpp
new file mode 100644
index 000000000..5aa167db6
--- /dev/null
+++ b/src/threed/effects/qglflatcoloreffect.cpp
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglflatcoloreffect_p.h"
+#include "qglabstracteffect_p.h"
+#include <QtOpenGL/qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLFlatColorEffect
+ \since 4.8
+ \brief The QGLFlatColorEffect class provides a standard effect that draws fragments with a flat unlit color.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+*/
+
+/*!
+ \class QGLPerVertexColorEffect
+ \since 4.8
+ \brief The QGLPerVertexColorEffect class provides a standard effect that draws fragments with a per-vertex unlit color.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+*/
+
+class QGLFlatColorEffectPrivate
+{
+public:
+ QGLFlatColorEffectPrivate()
+ : program(0)
+ , matrixUniform(-1)
+ , colorUniform(-1)
+ , isFixedFunction(false)
+ {
+ }
+
+ QGLShaderProgram *program;
+ int matrixUniform;
+ int colorUniform;
+ bool isFixedFunction;
+};
+
+/*!
+ Constructs a new flat color effect.
+*/
+QGLFlatColorEffect::QGLFlatColorEffect()
+ : d_ptr(new QGLFlatColorEffectPrivate)
+{
+}
+
+/*!
+ Destroys this flat color effect.
+*/
+QGLFlatColorEffect::~QGLFlatColorEffect()
+{
+}
+
+/*!
+ \reimp
+*/
+bool QGLFlatColorEffect::supportsPicking() const
+{
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QGLFlatColorEffect::setActive(QGLPainter *painter, bool flag)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ Q_UNUSED(painter);
+ if (flag)
+ glEnableClientState(GL_VERTEX_ARRAY);
+ else
+ glDisableClientState(GL_VERTEX_ARRAY);
+#else
+ Q_UNUSED(painter);
+ Q_D(QGLFlatColorEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (painter->isFixedFunction()) {
+ d->isFixedFunction = true;
+ if (flag)
+ glEnableClientState(GL_VERTEX_ARRAY);
+ else
+ glDisableClientState(GL_VERTEX_ARRAY);
+ return;
+ }
+#endif
+ static char const flatColorVertexShader[] =
+ "attribute highp vec4 vertex;\n"
+ "uniform highp mat4 matrix;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_Position = matrix * vertex;\n"
+ "}\n";
+
+ static char const flatColorFragmentShader[] =
+ "uniform mediump vec4 color;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+
+ QGLShaderProgram *program =
+ painter->cachedProgram(QLatin1String("qt.color.flat"));
+ d->program = program;
+ if (!program) {
+ if (!flag)
+ return;
+ program = new QGLShaderProgram();
+ program->addShaderFromSourceCode(QGLShader::Vertex, flatColorVertexShader);
+ program->addShaderFromSourceCode(QGLShader::Fragment, flatColorFragmentShader);
+ program->bindAttributeLocation("vertex", QGL::Position);
+ if (!program->link()) {
+ qWarning("QGLFlatColorEffect::setActive(): could not link shader program");
+ delete program;
+ return;
+ }
+ painter->setCachedProgram(QLatin1String("qt.color.flat"), program);
+ d->program = program;
+ d->colorUniform = program->uniformLocation("color");
+ d->matrixUniform = program->uniformLocation("matrix");
+ program->bind();
+ program->enableAttributeArray(QGL::Position);
+ } else if (flag) {
+ d->colorUniform = program->uniformLocation("color");
+ d->matrixUniform = program->uniformLocation("matrix");
+ program->bind();
+ program->enableAttributeArray(QGL::Position);
+ } else {
+ program->disableAttributeArray(QGL::Position);
+ program->release();
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGLFlatColorEffect::update
+ (QGLPainter *painter, QGLPainter::Updates updates)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ painter->updateFixedFunction
+ (updates & (QGLPainter::UpdateColor |
+ QGLPainter::UpdateMatrices));
+#else
+ Q_D(QGLFlatColorEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (d->isFixedFunction) {
+ painter->updateFixedFunction
+ (updates & (QGLPainter::UpdateColor |
+ QGLPainter::UpdateMatrices));
+ return;
+ }
+#endif
+ if ((updates & QGLPainter::UpdateColor) != 0) {
+ if (painter->isPicking())
+ d->program->setUniformValue(d->colorUniform, painter->pickColor());
+ else
+ d->program->setUniformValue(d->colorUniform, painter->color());
+ }
+ if ((updates & QGLPainter::UpdateMatrices) != 0) {
+ QMatrix4x4 proj = painter->projectionMatrix();
+ QMatrix4x4 mv = painter->modelViewMatrix();
+ d->program->setUniformValue(d->matrixUniform, proj * mv);
+ }
+#endif
+}
+
+class QGLPerVertexColorEffectPrivate
+{
+public:
+ QGLPerVertexColorEffectPrivate()
+ : program(0)
+ , matrixUniform(-1)
+ , isFixedFunction(false)
+ {
+ }
+
+ QGLShaderProgram *program;
+ int matrixUniform;
+ bool isFixedFunction;
+};
+
+/*!
+ Constructs a new per-vertex color effect.
+*/
+QGLPerVertexColorEffect::QGLPerVertexColorEffect()
+ : d_ptr(new QGLPerVertexColorEffectPrivate)
+{
+}
+
+/*!
+ Destroys this per-vertex color effect.
+*/
+QGLPerVertexColorEffect::~QGLPerVertexColorEffect()
+{
+}
+
+/*!
+ \reimp
+*/
+void QGLPerVertexColorEffect::setActive(QGLPainter *painter, bool flag)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ Q_UNUSED(painter);
+ if (flag) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ } else {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ }
+#else
+ Q_UNUSED(painter);
+ Q_D(QGLPerVertexColorEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (painter->isFixedFunction()) {
+ d->isFixedFunction = true;
+ if (flag) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ } else {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ }
+ return;
+ }
+#endif
+ static char const pvColorVertexShader[] =
+ "attribute highp vec4 vertex;\n"
+ "attribute mediump vec4 color;\n"
+ "uniform highp mat4 matrix;\n"
+ "varying mediump vec4 qColor;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_Position = matrix * vertex;\n"
+ " qColor = color;\n"
+ "}\n";
+
+ static char const pvColorFragmentShader[] =
+ "varying mediump vec4 qColor;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_FragColor = qColor;\n"
+ "}\n";
+
+ QGLShaderProgram *program =
+ painter->cachedProgram(QLatin1String("qt.color.pervertex"));
+ d->program = program;
+ if (!program) {
+ if (!flag)
+ return;
+ program = new QGLShaderProgram();
+ program->addShaderFromSourceCode(QGLShader::Vertex, pvColorVertexShader);
+ program->addShaderFromSourceCode(QGLShader::Fragment, pvColorFragmentShader);
+ program->bindAttributeLocation("vertex", QGL::Position);
+ program->bindAttributeLocation("color", QGL::Color);
+ if (!program->link()) {
+ qWarning("QGLPerVertexColorEffect::setActive(): could not link shader program");
+ delete program;
+ program = 0;
+ return;
+ }
+ painter->setCachedProgram(QLatin1String("qt.color.pervertex"), program);
+ d->program = program;
+ d->matrixUniform = program->uniformLocation("matrix");
+ program->bind();
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::Color);
+ } else if (flag) {
+ d->matrixUniform = program->uniformLocation("matrix");
+ program->bind();
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::Color);
+ } else {
+ program->disableAttributeArray(QGL::Position);
+ program->disableAttributeArray(QGL::Color);
+ program->release();
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGLPerVertexColorEffect::update
+ (QGLPainter *painter, QGLPainter::Updates updates)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ painter->updateFixedFunction(updates & QGLPainter::UpdateMatrices);
+#else
+ Q_UNUSED(painter);
+ Q_D(QGLPerVertexColorEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (d->isFixedFunction) {
+ painter->updateFixedFunction(updates & QGLPainter::UpdateMatrices);
+ return;
+ }
+#endif
+ if ((updates & QGLPainter::UpdateMatrices) != 0) {
+ d->program->setUniformValue
+ (d->matrixUniform, painter->combinedMatrix());
+ }
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/effects/qglflatcoloreffect_p.h b/src/threed/effects/qglflatcoloreffect_p.h
new file mode 100644
index 000000000..c43bcca0d
--- /dev/null
+++ b/src/threed/effects/qglflatcoloreffect_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLFLATCOLOREFFECT_P_H
+#define QGLFLATCOLOREFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstracteffect.h"
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLFlatColorEffectPrivate;
+class QGLPerVertexColorEffectPrivate;
+
+class QGLFlatColorEffect : public QGLAbstractEffect
+{
+public:
+ QGLFlatColorEffect();
+ virtual ~QGLFlatColorEffect();
+
+ bool supportsPicking() const;
+ void setActive(QGLPainter *painter, bool flag);
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+
+private:
+ QScopedPointer<QGLFlatColorEffectPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLFlatColorEffect)
+ Q_DISABLE_COPY(QGLFlatColorEffect)
+};
+
+class QGLPerVertexColorEffect : public QGLAbstractEffect
+{
+public:
+ QGLPerVertexColorEffect();
+ virtual ~QGLPerVertexColorEffect();
+
+ void setActive(QGLPainter *painter, bool flag);
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+
+private:
+ QScopedPointer<QGLPerVertexColorEffectPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLPerVertexColorEffect)
+ Q_DISABLE_COPY(QGLPerVertexColorEffect)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/threed/effects/qglflattextureeffect.cpp b/src/threed/effects/qglflattextureeffect.cpp
new file mode 100644
index 000000000..307549784
--- /dev/null
+++ b/src/threed/effects/qglflattextureeffect.cpp
@@ -0,0 +1,373 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglflattextureeffect_p.h"
+#include "qglabstracteffect_p.h"
+#include "qglext_p.h"
+#include <QtOpenGL/qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLFlatTextureEffect
+ \since 4.8
+ \brief The QGLFlatTextureEffect class provides a standard effect that draws fragments with a flat unlit texture.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+*/
+
+/*!
+ \class QGLFlatDecalTextureEffect
+ \since 4.8
+ \brief The QGLFlatDecalTextureEffect class provides a standard effect that decals fragments with a flat unlit texture.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+*/
+
+class QGLFlatTextureEffectPrivate
+{
+public:
+ QGLFlatTextureEffectPrivate()
+ : program(0)
+ , matrixUniform(-1)
+ , isFixedFunction(false)
+ {
+ }
+
+ QGLShaderProgram *program;
+ int matrixUniform;
+ bool isFixedFunction;
+};
+
+/*!
+ Constructs a new flat texture effect.
+*/
+QGLFlatTextureEffect::QGLFlatTextureEffect()
+ : d_ptr(new QGLFlatTextureEffectPrivate)
+{
+}
+
+/*!
+ Destroys this flat texture effect.
+*/
+QGLFlatTextureEffect::~QGLFlatTextureEffect()
+{
+}
+
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+
+static char const flatTexVertexShader[] =
+ "attribute highp vec4 vertex;\n"
+ "attribute highp vec4 texcoord;\n"
+ "uniform highp mat4 matrix;\n"
+ "varying highp vec4 qt_TexCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_Position = matrix * vertex;\n"
+ " qt_TexCoord0 = texcoord;\n"
+ "}\n";
+
+static char const flatTexFragmentShader[] =
+ "uniform sampler2D tex;\n"
+ "varying highp vec4 qt_TexCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_FragColor = texture2D(tex, qt_TexCoord0.st);\n"
+ "}\n";
+
+static char const flatDecalFragmentShader[] =
+ "uniform sampler2D tex;\n"
+ "uniform mediump vec4 color;\n"
+ "varying highp vec4 qt_TexCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " mediump vec4 col = texture2D(tex, qt_TexCoord0.st);\n"
+ " gl_FragColor = vec4(clamp(color.rgb * (1.0 - col.a) + col.rgb, 0.0, 1.0), color.a);\n"
+ "}\n";
+
+#endif
+
+/*!
+ \reimp
+*/
+void QGLFlatTextureEffect::setActive(QGLPainter *painter, bool flag)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ Q_UNUSED(painter);
+ if (flag) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ } else {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+#else
+ Q_UNUSED(painter);
+ Q_D(QGLFlatTextureEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (painter->isFixedFunction()) {
+ d->isFixedFunction = true;
+ if (flag) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ } else {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+ return;
+ }
+#endif
+ QGLShaderProgram *program =
+ painter->cachedProgram(QLatin1String("qt.texture.flat.replace"));
+ d->program = program;
+ if (!program) {
+ if (!flag)
+ return;
+ program = new QGLShaderProgram();
+ program->addShaderFromSourceCode(QGLShader::Vertex, flatTexVertexShader);
+ program->addShaderFromSourceCode(QGLShader::Fragment, flatTexFragmentShader);
+ program->bindAttributeLocation("vertex", QGL::Position);
+ program->bindAttributeLocation("texcoord", QGL::TextureCoord0);
+ if (!program->link()) {
+ qWarning("QGLFlatTextureEffect::setActive(): could not link shader program");
+ delete program;
+ program = 0;
+ return;
+ }
+ painter->setCachedProgram
+ (QLatin1String("qt.texture.flat.replace"), program);
+ d->program = program;
+ d->matrixUniform = program->uniformLocation("matrix");
+ program->bind();
+ program->setUniformValue("tex", 0);
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::TextureCoord0);
+ } else if (flag) {
+ d->matrixUniform = program->uniformLocation("matrix");
+ program->bind();
+ program->setUniformValue("tex", 0);
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::TextureCoord0);
+ } else {
+ program->disableAttributeArray(QGL::Position);
+ program->disableAttributeArray(QGL::TextureCoord0);
+ program->release();
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGLFlatTextureEffect::update
+ (QGLPainter *painter, QGLPainter::Updates updates)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ painter->updateFixedFunction(updates & QGLPainter::UpdateMatrices);
+#else
+ Q_D(QGLFlatTextureEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (d->isFixedFunction) {
+ painter->updateFixedFunction(updates & QGLPainter::UpdateMatrices);
+ return;
+ }
+#endif
+ if ((updates & QGLPainter::UpdateMatrices) != 0) {
+ d->program->setUniformValue
+ (d->matrixUniform, painter->combinedMatrix());
+ }
+#endif
+}
+
+class QGLFlatDecalTextureEffectPrivate
+{
+public:
+ QGLFlatDecalTextureEffectPrivate()
+ : program(0)
+ , matrixUniform(-1)
+ , colorUniform(-1)
+ , isFixedFunction(false)
+ {
+ }
+
+ QGLShaderProgram *program;
+ int matrixUniform;
+ int colorUniform;
+ bool isFixedFunction;
+};
+
+/*!
+ Constructs a new flat decal texture effect.
+*/
+QGLFlatDecalTextureEffect::QGLFlatDecalTextureEffect()
+ : d_ptr(new QGLFlatDecalTextureEffectPrivate)
+{
+}
+
+/*!
+ Destroys this flat decal texture effect.
+*/
+QGLFlatDecalTextureEffect::~QGLFlatDecalTextureEffect()
+{
+}
+
+/*!
+ \reimp
+*/
+void QGLFlatDecalTextureEffect::setActive(QGLPainter *painter, bool flag)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ Q_UNUSED(painter);
+ if (flag) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ glEnable(GL_TEXTURE_2D);
+ } else {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+#else
+ Q_UNUSED(painter);
+ Q_D(QGLFlatDecalTextureEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (painter->isFixedFunction()) {
+ d->isFixedFunction = true;
+ if (flag) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ glEnable(GL_TEXTURE_2D);
+ } else {
+ glDisableClientState(GL_VERTEX_ARRAY);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+ }
+#endif
+ QGLShaderProgram *program =
+ painter->cachedProgram(QLatin1String("qt.texture.flat.decal"));
+ d->program = program;
+ if (!program) {
+ if (!flag)
+ return;
+ program = new QGLShaderProgram();
+ program->addShaderFromSourceCode(QGLShader::Vertex, flatTexVertexShader);
+ program->addShaderFromSourceCode(QGLShader::Fragment, flatDecalFragmentShader);
+ program->bindAttributeLocation("vertex", QGL::Position);
+ program->bindAttributeLocation("texcoord", QGL::TextureCoord0);
+ if (!program->link()) {
+ qWarning("QGLFlatDecalTextureEffect::setActive(): could not link shader program");
+ delete program;
+ program = 0;
+ return;
+ }
+ painter->setCachedProgram
+ (QLatin1String("qt.texture.flat.decal"), program);
+ d->program = program;
+ d->matrixUniform = program->uniformLocation("matrix");
+ d->colorUniform = program->uniformLocation("color");
+ program->bind();
+ program->setUniformValue("tex", 0);
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::TextureCoord0);
+ } else if (flag) {
+ d->matrixUniform = program->uniformLocation("matrix");
+ d->colorUniform = program->uniformLocation("color");
+ program->bind();
+ program->setUniformValue("tex", 0);
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::TextureCoord0);
+ } else {
+ program->disableAttributeArray(QGL::Position);
+ program->disableAttributeArray(QGL::TextureCoord0);
+ program->release();
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGLFlatDecalTextureEffect::update
+ (QGLPainter *painter, QGLPainter::Updates updates)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ painter->updateFixedFunction
+ (updates & (QGLPainter::UpdateColor |
+ QGLPainter::UpdateMatrices));
+#else
+ Q_D(QGLFlatDecalTextureEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (d->isFixedFunction) {
+ painter->updateFixedFunction
+ (updates & (QGLPainter::UpdateColor |
+ QGLPainter::UpdateMatrices));
+ return;
+ }
+#endif
+ if ((updates & QGLPainter::UpdateColor) != 0)
+ d->program->setUniformValue(d->colorUniform, painter->color());
+ if ((updates & QGLPainter::UpdateMatrices) != 0) {
+ d->program->setUniformValue
+ (d->matrixUniform, painter->combinedMatrix());
+ }
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/effects/qglflattextureeffect_p.h b/src/threed/effects/qglflattextureeffect_p.h
new file mode 100644
index 000000000..9672a94f9
--- /dev/null
+++ b/src/threed/effects/qglflattextureeffect_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLFLATTEXTUREEFFECT_P_H
+#define QGLFLATTEXTUREEFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstracteffect.h"
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLFlatTextureEffectPrivate;
+class QGLFlatDecalTextureEffectPrivate;
+
+class QGLFlatTextureEffect : public QGLAbstractEffect
+{
+public:
+ QGLFlatTextureEffect();
+ virtual ~QGLFlatTextureEffect();
+
+ void setActive(QGLPainter *painter, bool flag);
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+
+private:
+ QScopedPointer<QGLFlatTextureEffectPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLFlatTextureEffect)
+ Q_DISABLE_COPY(QGLFlatTextureEffect)
+};
+
+class QGLFlatDecalTextureEffect : public QGLAbstractEffect
+{
+public:
+ QGLFlatDecalTextureEffect();
+ virtual ~QGLFlatDecalTextureEffect();
+
+ void setActive(QGLPainter *painter, bool flag);
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+
+private:
+ QScopedPointer<QGLFlatDecalTextureEffectPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLFlatDecalTextureEffect)
+ Q_DISABLE_COPY(QGLFlatDecalTextureEffect)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/threed/effects/qgllitmaterialeffect.cpp b/src/threed/effects/qgllitmaterialeffect.cpp
new file mode 100644
index 000000000..6461e86b5
--- /dev/null
+++ b/src/threed/effects/qgllitmaterialeffect.cpp
@@ -0,0 +1,571 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgllitmaterialeffect_p.h"
+#include "qglabstracteffect_p.h"
+#include "qglext_p.h"
+#include <QtOpenGL/qglshaderprogram.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLLitMaterialEffect
+ \since 4.8
+ \brief The QGLLitMaterialEffect class provides a standard effect that draws fragments with a lit material.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+*/
+
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+
+static char const litMaterialVertexShader[] =
+ "attribute highp vec4 vertex;\n"
+ "attribute highp vec3 normal;\n"
+ "uniform highp mat4 matrix;\n"
+ "uniform highp mat4 modelView;\n"
+ "uniform highp mat3 normalMatrix;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_Position = matrix * vertex;\n"
+ " highp vec4 tvertex = modelView * vertex;\n"
+ " highp vec3 norm = normalize(normalMatrix * normal);\n"
+ " qLightVertex(tvertex, norm);\n"
+ "}\n";
+
+static char const litMaterialFragmentShader[] =
+#if !defined(QT_OPENGL_ES)
+ "varying mediump vec4 qColor;\n"
+ "varying mediump vec4 qSecondaryColor;\n"
+ "\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_FragColor = clamp(qColor + vec4(qSecondaryColor.xyz, 0.0), 0.0, 1.0);\n"
+ "}\n";
+#else
+ "varying mediump vec4 qCombinedColor;\n"
+ "\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_FragColor = qCombinedColor;\n"
+ "}\n";
+#endif
+
+// Algorithm from section 2.14.1 of OpenGL 2.1 specification.
+static char const litMaterialLightingShader[] =
+#if !defined(QT_OPENGL_ES)
+"uniform mediump vec3 sdli;\n" // Direction of the light (must be normalized).
+"uniform mediump vec3 pli;\n" // Position of the light
+"uniform mediump float pliw;\n" // 0 for directional, 1 for positional.
+"uniform mediump float srli;\n" // Spotlight exponent for the light
+"uniform mediump float crli;\n" // Spotlight cutoff for the light
+"uniform mediump float ccrli;\n" // Cosine of spotlight cutoff for the light
+"uniform mediump float k0;\n" // Constant attentuation factor for the light
+"uniform mediump float k1;\n" // Linear attentuation factor for the light
+"uniform mediump float k2;\n" // Quadratic attentuation factor for the light
+"uniform mediump vec4 acm[2];\n" // Ambient color of the material and light
+"uniform mediump vec4 dcm[2];\n" // Diffuse color of the material and light
+"uniform mediump vec4 scm[2];\n" // Specular color of the material and light
+"uniform mediump vec4 ecm[2];\n" // Emissive color and ambient scene color
+"uniform mediump float srm[2];\n"// Specular exponent of the material
+"uniform bool viewerAtInfinity;\n" // Light model indicates viewer at infinity
+"uniform bool twoSided;\n" // Light model indicates two-sided lighting
+
+"varying mediump vec4 qColor;\n"
+"varying mediump vec4 qSecondaryColor;\n"
+
+"void qLightVertex(vec4 vertex, vec3 normal)\n"
+"{\n"
+" int i, material;\n"
+" vec3 toEye, toLight, h;\n"
+" float angle, spot, attenuation;\n"
+" vec4 color, scolor;\n"
+" vec4 adcomponent, scomponent;\n"
+
+ // Determine which material to use.
+" if (!twoSided || normal.z >= 0.0) {\n"
+" material = 0;\n"
+" } else {\n"
+" material = 1;\n"
+" normal = -normal;\n"
+" }\n"
+
+ // Start with the material's emissive color and the ambient scene color,
+ // which have been combined into the ecm parameter by the C++ code.
+" color = ecm[material];\n"
+" scolor = vec4(0, 0, 0, 0);\n"
+
+ // Vector from the vertex to the eye position (i.e. the origin).
+" if (viewerAtInfinity)\n"
+" toEye = vec3(0, 0, 1);\n"
+" else\n"
+" toEye = normalize(-vertex.xyz);\n"
+
+ // Determine the cosine of the angle between the normal and the
+ // vector from the vertex to the light.
+" if (pliw == 0.0)\n"
+" toLight = normalize(pli);\n"
+" else\n"
+" toLight = normalize(pli - vertex.xyz);\n"
+" angle = max(dot(normal, toLight), 0.0);\n"
+
+ // Calculate the ambient and diffuse light components.
+" adcomponent = acm[material] + angle * dcm[material];\n"
+
+ // Calculate the specular light components.
+" if (angle != 0.0) {\n"
+" h = normalize(toLight + toEye);\n"
+" angle = max(dot(normal, h), 0.0);\n"
+" if (srm[material] != 0.0)\n"
+" scomponent = pow(angle, srm[material]) * scm[material];\n"
+" else\n"
+" scomponent = scm[material];\n"
+" } else {\n"
+" scomponent = vec4(0, 0, 0, 0);\n"
+" }\n"
+
+ // Apply the spotlight angle and exponent.
+" if (crli != 180.0) {\n"
+" spot = max(dot(normalize(vertex.xyz - pli), sdli), 0.0);\n"
+" if (spot < ccrli) {\n"
+" adcomponent = vec4(0, 0, 0, 0);\n"
+" scomponent = vec4(0, 0, 0, 0);\n"
+" } else {\n"
+" spot = pow(spot, srli);\n"
+" adcomponent *= spot;\n"
+" scomponent *= spot;\n"
+" }\n"
+" }\n"
+
+ // Apply attenuation to the colors.
+" if (pliw != 0.0) {\n"
+" attenuation = k0;\n"
+" if (k1 != 0.0 || k2 != 0.0) {\n"
+" float len = length(pli - vertex.xyz);\n"
+" attenuation += k1 * len + k2 * len * len;\n"
+" }\n"
+" color += adcomponent / attenuation;\n"
+" scolor += scomponent / attenuation;\n"
+" } else {\n"
+" color += adcomponent;\n"
+" scolor += scomponent;\n"
+" }\n"
+
+ // Generate the final output colors.
+" float alpha = dcm[material].a;\n"
+" qColor = vec4(clamp(color.rgb, 0.0, 1.0), alpha);\n"
+" qSecondaryColor = clamp(scolor, 0.0, 1.0);\n"
+"}\n";
+#else
+"uniform mediump vec3 sdli;\n" // Direction of the light (must be normalized).
+"uniform mediump vec3 pli;\n" // Position of the light
+"uniform mediump float pliw;\n" // 0 for directional, 1 for positional.
+"uniform mediump float srli;\n" // Spotlight exponent for the light
+"uniform mediump float crli;\n" // Spotlight cutoff for the light
+"uniform mediump float ccrli;\n" // Cosine of spotlight cutoff for the light
+"uniform mediump vec4 acm;\n" // Ambient color of the material and light
+"uniform mediump vec4 dcm;\n" // Diffuse color of the material and light
+"uniform mediump vec4 scm;\n" // Specular color of the material and light
+"uniform mediump vec4 ecm;\n" // Emissive color and ambient scene color
+"uniform mediump float srm;\n" // Specular exponent of the material
+"uniform bool viewerAtInfinity;\n" // Light model indicates viewer at infinity
+
+"varying mediump vec4 qColor;\n"
+"varying mediump vec4 qSecondaryColor;\n"
+"varying mediump vec4 qCombinedColor;\n"
+
+"void qLightVertex(vec4 vertex, vec3 normal)\n"
+"{\n"
+" vec3 toEye, toLight, h;\n"
+" float angle, spot;\n"
+" vec4 color, scolor;\n"
+
+ // Vector from the vertex to the eye position (i.e. the origin).
+" if (viewerAtInfinity)\n"
+" toEye = vec3(0, 0, 1);\n"
+" else\n"
+" toEye = normalize(-vertex.xyz);\n"
+
+ // Determine the cosine of the angle between the normal and the
+ // vector from the vertex to the light.
+" if (pliw == 0.0)\n"
+" toLight = normalize(pli);\n"
+" else\n"
+" toLight = normalize(pli - vertex.xyz);\n"
+" angle = max(dot(normal, toLight), 0.0);\n"
+
+ // Calculate the ambient and diffuse light components.
+" color = acm + angle * dcm;\n"
+
+ // Calculate the specular light components.
+" if (angle != 0.0) {\n"
+" h = normalize(toLight + toEye);\n"
+" angle = max(dot(normal, h), 0.0);\n"
+" if (srm != 0.0)\n"
+" scolor = pow(angle, srm) * scm;\n"
+" else\n"
+" scolor = scm;\n"
+" } else {\n"
+" scolor = vec4(0, 0, 0, 0);\n"
+" }\n"
+
+ // Apply the spotlight angle and exponent.
+" if (crli != 180.0) {\n"
+" spot = max(dot(normalize(vertex.xyz - pli), sdli), 0.0);\n"
+" if (spot < ccrli) {\n"
+" color = vec4(0, 0, 0, 0);\n"
+" scolor = vec4(0, 0, 0, 0);\n"
+" } else {\n"
+" spot = pow(spot, srli);\n"
+" color *= spot;\n"
+" scolor *= spot;\n"
+" }\n"
+" }\n"
+
+ // Generate the final output colors.
+" color += ecm;\n"
+" float alpha = dcm.a;\n"
+ // Note: Normally, the qCombinedColor is ignored, and per-pixel
+ // value is calculated.
+ // If OPENGL_ES is defined, qColor and qSecondaryColor are ignored,
+ // and qCombinedColor is calculated here to speed up the fragment shader.
+" qColor = vec4(clamp(color.rgb, 0.0, 1.0), alpha);\n"
+" qSecondaryColor = clamp(scolor, 0.0, 1.0);\n"
+" qCombinedColor = clamp(qColor + vec4(qSecondaryColor.xyz, 0.0), 0.0, 1.0);\n"
+"}\n";
+#endif
+
+static QByteArray createVertexSource(const char *lighting, const char *extra)
+{
+ QByteArray contents(lighting);
+ return contents + extra;
+}
+
+static inline QVector4D colorToVector4(const QColor& color)
+{
+ return QVector4D(color.redF(), color.greenF(),
+ color.blueF(), color.alphaF());
+}
+
+// Combine a material and light color into a single color.
+static inline QVector4D colorToVector4
+ (const QColor &color, const QColor &lightColor)
+{
+ return QVector4D(color.redF() * lightColor.redF(),
+ color.greenF() * lightColor.greenF(),
+ color.blueF() * lightColor.blueF(),
+ color.alphaF() * lightColor.alphaF());
+}
+
+#endif
+
+class QGLLitMaterialEffectPrivate
+{
+public:
+ QGLLitMaterialEffectPrivate()
+ : program(0)
+ , matrixUniform(-1)
+ , modelViewUniform(-1)
+ , normalMatrixUniform(-1)
+ , textureMode(0)
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+ , vertexShader(litMaterialVertexShader)
+ , fragmentShader(litMaterialFragmentShader)
+#else
+ , vertexShader(0)
+ , fragmentShader(0)
+#endif
+ , programName(QLatin1String("qt.color.material"))
+ , isFixedFunction(false)
+ {
+ }
+
+ QGLShaderProgram *program;
+ int matrixUniform;
+ int modelViewUniform;
+ int normalMatrixUniform;
+ GLenum textureMode;
+ const char *vertexShader;
+ const char *fragmentShader;
+ QString programName;
+ bool isFixedFunction;
+};
+
+/*!
+ Constructs a new lit material effect.
+*/
+QGLLitMaterialEffect::QGLLitMaterialEffect()
+ : d_ptr(new QGLLitMaterialEffectPrivate)
+{
+}
+
+/*!
+ \internal
+*/
+QGLLitMaterialEffect::QGLLitMaterialEffect
+ (GLenum mode, const char *vshader, const char *fshader,
+ const QString& programName)
+ : d_ptr(new QGLLitMaterialEffectPrivate)
+{
+ Q_D(QGLLitMaterialEffect);
+ d->textureMode = mode;
+ d->vertexShader = vshader;
+ d->fragmentShader = fshader;
+ d->programName = programName;
+}
+
+/*!
+ Destroys this lit material effect.
+*/
+QGLLitMaterialEffect::~QGLLitMaterialEffect()
+{
+}
+
+/*!
+ \reimp
+*/
+void QGLLitMaterialEffect::setActive(QGLPainter *painter, bool flag)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ Q_UNUSED(painter);
+ Q_D(QGLLitMaterialEffect);
+ if (flag) {
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ if (d->textureMode) {
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, d->textureMode);
+ glEnable(GL_TEXTURE_2D);
+ }
+ } else {
+ glDisable(GL_LIGHTING);
+ glDisable(GL_LIGHT0);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ if (d->textureMode) {
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+ }
+#else
+ Q_UNUSED(painter);
+ Q_D(QGLLitMaterialEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (painter->isFixedFunction()) {
+ d->isFixedFunction = true;
+ if (flag) {
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ if (d->textureMode) {
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, d->textureMode);
+ glEnable(GL_TEXTURE_2D);
+ }
+ } else {
+ glDisable(GL_LIGHTING);
+ glDisable(GL_LIGHT0);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ if (d->textureMode) {
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+ }
+ return;
+ }
+#endif
+ QGLShaderProgram *program = painter->cachedProgram(d->programName);
+ d->program = program;
+ if (!program) {
+ if (!flag)
+ return;
+ program = new QGLShaderProgram();
+ program->addShaderFromSourceCode(QGLShader::Vertex, createVertexSource(litMaterialLightingShader, d->vertexShader));
+ program->addShaderFromSourceCode(QGLShader::Fragment, d->fragmentShader);
+ program->bindAttributeLocation("vertex", QGL::Position);
+ program->bindAttributeLocation("normal", QGL::Normal);
+ if (d->textureMode != 0)
+ program->bindAttributeLocation("texcoord", QGL::TextureCoord0);
+ if (!program->link()) {
+ qWarning("QGLLitMaterialEffect::setActive(): could not link shader program");
+ delete program;
+ program = 0;
+ return;
+ }
+ painter->setCachedProgram(d->programName, program);
+ d->program = program;
+ d->matrixUniform = program->uniformLocation("matrix");
+ d->modelViewUniform = program->uniformLocation("modelView");
+ d->normalMatrixUniform = program->uniformLocation("normalMatrix");
+ program->bind();
+ if (d->textureMode != 0) {
+ program->setUniformValue("tex", 0);
+ program->enableAttributeArray(QGL::TextureCoord0);
+ }
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::Normal);
+ } else if (flag) {
+ d->matrixUniform = program->uniformLocation("matrix");
+ d->modelViewUniform = program->uniformLocation("modelView");
+ d->normalMatrixUniform = program->uniformLocation("normalMatrix");
+ program->bind();
+ if (d->textureMode != 0) {
+ program->setUniformValue("tex", 0);
+ program->enableAttributeArray(QGL::TextureCoord0);
+ }
+ program->enableAttributeArray(QGL::Position);
+ program->enableAttributeArray(QGL::Normal);
+ } else {
+ program->disableAttributeArray(QGL::Position);
+ program->disableAttributeArray(QGL::Normal);
+ if (d->textureMode != 0)
+ program->disableAttributeArray(QGL::TextureCoord0);
+ program->release();
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGLLitMaterialEffect::update
+ (QGLPainter *painter, QGLPainter::Updates updates)
+{
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ painter->updateFixedFunction
+ (updates & (QGLPainter::UpdateMatrices |
+ QGLPainter::UpdateLights |
+ QGLPainter::UpdateMaterials));
+#else
+ Q_D(QGLLitMaterialEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (d->isFixedFunction) {
+ painter->updateFixedFunction
+ (updates & (QGLPainter::UpdateMatrices |
+ QGLPainter::UpdateLights |
+ QGLPainter::UpdateMaterials));
+ return;
+ }
+#endif
+ QGLShaderProgram *program = d->program;
+ if ((updates & QGLPainter::UpdateMatrices) != 0) {
+ program->setUniformValue(d->matrixUniform, painter->combinedMatrix());
+ program->setUniformValue(d->modelViewUniform, painter->modelViewMatrix());
+ program->setUniformValue(d->normalMatrixUniform, painter->normalMatrix());
+ }
+ const QGLLightParameters *lparams = painter->mainLight();
+ QMatrix4x4 ltransform = painter->mainLightTransform();
+ const QGLLightModel *model = painter->lightModel();
+ if ((updates & (QGLPainter::UpdateLights | QGLPainter::UpdateMaterials)) != 0) {
+ // Set the uniform variables for the light.
+ program->setUniformValue
+ ("sdli", lparams->eyeSpotDirection(ltransform).normalized());
+ QVector4D pli = lparams->eyePosition(ltransform);
+ program->setUniformValue("pli", QVector3D(pli.x(), pli.y(), pli.z()));
+ program->setUniformValue("pliw", GLfloat(pli.w()));
+ program->setUniformValue("srli", GLfloat(lparams->spotExponent()));
+ program->setUniformValue("crli", GLfloat(lparams->spotAngle()));
+ program->setUniformValue("ccrli", GLfloat(lparams->spotCosAngle()));
+#if !defined(QT_OPENGL_ES)
+ // Attenuation is not supported under ES, for performance.
+ program->setUniformValue("k0", GLfloat(lparams->constantAttenuation()));
+ program->setUniformValue("k1", GLfloat(lparams->linearAttenuation()));
+ program->setUniformValue("k2", GLfloat(lparams->quadraticAttenuation()));
+#endif
+
+ // Set the uniform variables for the light model.
+#if !defined(QT_OPENGL_ES)
+ program->setUniformValue("twoSided", (int)(model->model() == QGLLightModel::TwoSided));
+#endif
+ program->setUniformValue("viewerAtInfinity", (int)(model->viewerPosition() == QGLLightModel::ViewerAtInfinity));
+#if !defined(QT_OPENGL_ES)
+ if (d->textureMode != 0)
+ program->setUniformValue("separateSpecular", (int)(model->colorControl() == QGLLightModel::SeparateSpecularColor));
+#endif
+
+ // Set the uniform variables for the front and back materials.
+#if defined(QT_OPENGL_ES)
+ static const int MaxMaterials = 1;
+#else
+ static const int MaxMaterials = 2;
+#endif
+ QVector4D acm[MaxMaterials];
+ QVector4D dcm[MaxMaterials];
+ QVector4D scm[MaxMaterials];
+ QVector4D ecm[MaxMaterials];
+ float srm[MaxMaterials];
+ const QGLMaterial *mparams = painter->faceMaterial(QGL::FrontFaces);
+ acm[0] = colorToVector4(mparams->ambientColor(), lparams->ambientColor());
+ dcm[0] = colorToVector4(mparams->diffuseColor(), lparams->diffuseColor());
+ scm[0] = colorToVector4(mparams->specularColor(), lparams->specularColor());
+ ecm[0] = colorToVector4(mparams->emittedLight()) +
+ colorToVector4(mparams->ambientColor(),
+ model->ambientSceneColor());
+ srm[0] = (float)(mparams->shininess());
+#if !defined(QT_OPENGL_ES)
+ mparams = painter->faceMaterial(QGL::BackFaces);
+ acm[1] = colorToVector4(mparams->ambientColor(), lparams->ambientColor());
+ dcm[1] = colorToVector4(mparams->diffuseColor(), lparams->diffuseColor());
+ scm[1] = colorToVector4(mparams->specularColor(), lparams->specularColor());
+ ecm[1] = colorToVector4(mparams->emittedLight()) +
+ colorToVector4(mparams->ambientColor(),
+ model->ambientSceneColor());
+ srm[1] = (float)(mparams->shininess());
+#endif
+ program->setUniformValueArray("acm", (const GLfloat *)acm, MaxMaterials, 4);
+ program->setUniformValueArray("dcm", (const GLfloat *)dcm, MaxMaterials, 4);
+ program->setUniformValueArray("scm", (const GLfloat *)scm, MaxMaterials, 4);
+ program->setUniformValueArray("ecm", (const GLfloat *)ecm, MaxMaterials, 4);
+ program->setUniformValueArray("srm", srm, MaxMaterials, 1);
+ }
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/effects/qgllitmaterialeffect_p.h b/src/threed/effects/qgllitmaterialeffect_p.h
new file mode 100644
index 000000000..bca37096e
--- /dev/null
+++ b/src/threed/effects/qgllitmaterialeffect_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLLITMATERIALEFFECT_P_H
+#define QGLLITMATERIALEFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstracteffect.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGLLitMaterialEffectPrivate;
+
+class QGLLitMaterialEffect : public QGLAbstractEffect
+{
+public:
+ QGLLitMaterialEffect();
+ virtual ~QGLLitMaterialEffect();
+
+ void setActive(QGLPainter *painter, bool flag);
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+
+protected:
+ QGLLitMaterialEffect
+ (GLenum mode, const char *vshader, const char *fshader,
+ const QString& programName);
+
+private:
+ QScopedPointer<QGLLitMaterialEffectPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLLitMaterialEffect)
+ Q_DISABLE_COPY(QGLLitMaterialEffect)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/threed/effects/qgllittextureeffect.cpp b/src/threed/effects/qgllittextureeffect.cpp
new file mode 100644
index 000000000..457576f5a
--- /dev/null
+++ b/src/threed/effects/qgllittextureeffect.cpp
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgllittextureeffect_p.h"
+#include "qglabstracteffect_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLLitTextureEffect
+ \since 4.8
+ \brief The QGLLitTextureEffect class provides a standard effect base class for drawing fragments with a lit texture.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+
+ \sa QGLLitDecalTextureEffect, QGLLitModulateTextureEffect
+*/
+
+/*!
+ \class QGLLitDecalTextureEffect
+ \since 4.8
+ \brief The QGLLitDecalTextureEffect class provides a standard effect for drawing fragments with a texture decaled over a lit material.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+*/
+
+/*!
+ \class QGLLitModulateTextureEffect
+ \since 4.8
+ \brief The QGLLitModulateTextureEffect class provides a standard effect for drawing fragments with a texture modulated with a lit material.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+*/
+
+/*!
+ \internal
+*/
+QGLLitTextureEffect::QGLLitTextureEffect
+ (GLenum mode, const char *vshader, const char *fshader,
+ const QString& programName)
+ : QGLLitMaterialEffect(mode, vshader, fshader, programName)
+{
+}
+
+/*!
+ Destroys this lit texture effect.
+*/
+QGLLitTextureEffect::~QGLLitTextureEffect()
+{
+}
+
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+
+static char const litTextureVertexShader[] =
+ "attribute highp vec4 vertex;\n"
+ "attribute highp vec3 normal;\n"
+ "attribute highp vec4 texcoord;\n"
+ "uniform highp mat4 matrix;\n"
+ "uniform highp mat4 modelView;\n"
+ "uniform highp mat3 normalMatrix;\n"
+ "varying highp vec4 qt_TexCoord0;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_Position = matrix * vertex;\n"
+ " highp vec4 tvertex = modelView * vertex;\n"
+ " highp vec3 norm = normalize(normalMatrix * normal);\n"
+ " qLightVertex(tvertex, norm);\n"
+ " qt_TexCoord0 = texcoord;\n"
+ "}\n";
+
+static char const litDecalFragmentShader[] =
+ "uniform sampler2D tex;\n"
+#if defined(QT_OPENGL_ES)
+ "varying mediump vec4 qCombinedColor;\n"
+#else
+ "uniform bool separateSpecular;\n"
+ "varying mediump vec4 qColor;\n"
+ "varying mediump vec4 qSecondaryColor;\n"
+#endif
+ "varying highp vec4 qt_TexCoord0;\n"
+ "\n"
+ "void main(void)\n"
+ "{\n"
+ " mediump vec4 col = texture2D(tex, qt_TexCoord0.st);\n"
+#if defined(QT_OPENGL_ES)
+ " gl_FragColor = vec4(clamp(qCombinedColor.rgb * (1.0 - col.a) + col.rgb * col.a, 0.0, 1.0), qCombinedColor.a);\n"
+#else
+ " if (separateSpecular) {\n"
+ " gl_FragColor = vec4(clamp(qColor.rgb * (1.0 - col.a) + col.rgb * col.a + qSecondaryColor.xyz, 0.0, 1.0), qColor.a);\n"
+ " } else {\n"
+ " mediump vec4 lcolor = clamp(qColor + vec4(qSecondaryColor.xyz, 0.0), 0.0, 1.0);\n"
+ " gl_FragColor = vec4(clamp(lcolor.rgb * (1.0 - col.a) + col.rgb * col.a, 0.0, 1.0), lcolor.a);\n"
+ " }\n"
+#endif
+ "}\n";
+
+static char const litModulateFragmentShader[] =
+ "uniform sampler2D tex;\n"
+#if defined(QT_OPENGL_ES)
+ "varying mediump vec4 qCombinedColor;\n"
+#else
+ "uniform bool separateSpecular;\n"
+ "varying mediump vec4 qColor;\n"
+ "varying mediump vec4 qSecondaryColor;\n"
+#endif
+ "varying highp vec4 qt_TexCoord0;\n"
+ "\n"
+ "void main(void)\n"
+ "{\n"
+ " mediump vec4 col = texture2D(tex, qt_TexCoord0.st);\n"
+#if defined(QT_OPENGL_ES)
+ " gl_FragColor = col * qCombinedColor;\n"
+#else
+ " if (separateSpecular) {\n"
+ " gl_FragColor = clamp(col * qColor + vec4(qSecondaryColor.xyz, 0.0), 0.0, 1.0);\n"
+ " } else {\n"
+ " mediump vec4 lcolor = clamp(qColor + vec4(qSecondaryColor.xyz, 0.0), 0.0, 1.0);\n"
+ " gl_FragColor = col * lcolor;\n"
+ " }\n"
+#endif
+ "}\n";
+
+#endif
+
+#ifndef GL_MODULATE
+#define GL_MODULATE 0x2100
+#endif
+#ifndef GL_DECAL
+#define GL_DECAL 0x2101
+#endif
+
+/*!
+ Constructs a new lit decal texture effect.
+*/
+QGLLitDecalTextureEffect::QGLLitDecalTextureEffect()
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ : QGLLitTextureEffect(GL_DECAL, 0, 0, QString())
+#else
+ : QGLLitTextureEffect(GL_DECAL,
+ litTextureVertexShader, litDecalFragmentShader,
+ QLatin1String("qt.texture.litdecal"))
+#endif
+{
+}
+
+/*!
+ Destroys this lit decal texture effect.
+*/
+QGLLitDecalTextureEffect::~QGLLitDecalTextureEffect()
+{
+}
+
+/*!
+ Constructs a new lit modulate texture effect.
+*/
+QGLLitModulateTextureEffect::QGLLitModulateTextureEffect()
+#if defined(QGL_FIXED_FUNCTION_ONLY)
+ : QGLLitTextureEffect(GL_MODULATE, 0, 0, QString())
+#else
+ : QGLLitTextureEffect(GL_MODULATE,
+ litTextureVertexShader, litModulateFragmentShader,
+ QLatin1String("qt.texture.litmodulate"))
+#endif
+{
+}
+
+/*!
+ Destroys this lit modulate texture effect.
+*/
+QGLLitModulateTextureEffect::~QGLLitModulateTextureEffect()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/effects/qgllittextureeffect_p.h b/src/threed/effects/qgllittextureeffect_p.h
new file mode 100644
index 000000000..82dbb977b
--- /dev/null
+++ b/src/threed/effects/qgllittextureeffect_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLLITTEXTUREEFFECT_P_H
+#define QGLLITTEXTUREEFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgllitmaterialeffect_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGLLitTextureEffect : public QGLLitMaterialEffect
+{
+public:
+ virtual ~QGLLitTextureEffect();
+
+protected:
+ QGLLitTextureEffect(GLenum mode, const char *vshader, const char *fshader,
+ const QString& programName);
+};
+
+class QGLLitDecalTextureEffect : public QGLLitTextureEffect
+{
+public:
+ QGLLitDecalTextureEffect();
+ virtual ~QGLLitDecalTextureEffect();
+};
+
+class QGLLitModulateTextureEffect : public QGLLitTextureEffect
+{
+public:
+ QGLLitModulateTextureEffect();
+ virtual ~QGLLitModulateTextureEffect();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/threed/effects/qglshaderprogrameffect.cpp b/src/threed/effects/qglshaderprogrameffect.cpp
new file mode 100644
index 000000000..17883df49
--- /dev/null
+++ b/src/threed/effects/qglshaderprogrameffect.cpp
@@ -0,0 +1,1027 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglshaderprogrameffect.h"
+#include "qglabstracteffect_p.h"
+#include <QtOpenGL/qglshaderprogram.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLShaderProgramEffect
+ \since 4.8
+ \brief The QGLShaderProgramEffect class provides applications with the ability to use shader programs written in GLSL as effects for 3D rendering.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+
+ \section1 Writing portable shaders
+
+ Shader programs can be difficult to reuse across OpenGL implementations
+ because of varying levels of support for standard vertex attributes and
+ uniform variables. In particular, GLSL/ES lacks all of the
+ standard variables that are present on desktop OpenGL systems:
+ \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL
+ lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}.
+
+ QGLShaderProgramEffect is built on top of
+ \l{http://doc.qt.nokia.com/4.7/qglshaderprogram.html}{QGLShaderProgram},
+ which makes the process of writing portable shaders easier by
+ prefixing all shader programs with the following lines on desktop OpenGL:
+
+ \code
+ #define highp
+ #define mediump
+ #define lowp
+ \endcode
+
+ This makes it possible to run most GLSL/ES shader programs
+ on desktop systems. The programmer should also restrict themselves
+ to just features that are present in GLSL/ES, and avoid
+ standard variable names that only work on the desktop.
+
+ QGLShaderProgramEffect also defines some standard attribute and uniform
+ variable names that all shaders are expected to use. The following
+ sections define these standard names.
+
+ \section1 Attributes
+
+ QGLShaderProgramEffect provides a standard set of 8 named vertex
+ attributes that can be provided via QGLPainter::setVertexBundle():
+
+ \table
+ \header \o Shader Variable \o Mesh Attribute \o Purpose
+ \row \o \c qt_Vertex \o QGL::Position
+ \o The primary position of the vertex.
+ \row \o \c qt_Normal \o QGL::Normal
+ \o The normal at each vertex, for lit material effects.
+ \row \o \c qt_Color \o QGL::Color
+ \o The color at each vertex, for per-vertex color effects.
+ \row \o \c qt_MultiTexCoord0 \o QGL::TextureCoord0
+ \o The texture co-ordinate at each vertex for texture unit 0.
+ \row \o \c qt_MultiTexCoord1 \o QGL::TextureCoord1
+ \o Secondary texture co-ordinate at each vertex.
+ \row \o \c qt_MultiTexCoord2 \o QGL::TextureCoord2
+ \o Tertiary texture co-ordinate at each vertex.
+ \row \o \c qt_Custom0 \o QGL::CustomVertex0
+ \o First custom vertex attribute that can be used for any
+ user-defined purpose.
+ \row \o \c qt_Custom1 \o QGL::CustomVertex1
+ \o Second custom vertex attribute that can be used for any
+ user-defined purpose.
+ \endtable
+
+ These attributes may be used in the vertexShader(), as in the following
+ example of a simple texture shader:
+
+ \code
+ attribute highp vec4 qt_Vertex;
+ attribute highp vec4 qt_MultiTexCoord0;
+ uniform mediump mat4 qt_ModelViewProjectionMatrix;
+ varying highp vec4 qt_TexCoord0;
+
+ void main(void)
+ {
+ gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex;
+ qt_TexCoord0 = qt_MultiTexCoord0;
+ }
+ \endcode
+
+ \section1 Uniform variables
+
+ QGLShaderProgramEffect provides a standard set of uniform variables for
+ common values from the QGLPainter environment:
+
+ \table
+ \header \o Shader Variable \o Purpose
+ \row \o \c qt_ModelViewProjectionMatrix
+ \o Combination of the modelview and projection matrices into a
+ single 4x4 matrix.
+ \row \o \c qt_ModelViewMatrix
+ \o Modelview matrix without the projection. This is typically
+ used for performing calculations in eye co-ordinates.
+ \row \o \c qt_ProjectionMatrix
+ \o Projection matrix without the modelview.
+ \row \o \c qt_NormalMatrix
+ \o Normal matrix, which is the transpose of the inverse of the
+ top-left 3x3 part of the modelview matrix. This is typically
+ used in lighting calcuations to transform \c qt_Normal.
+ \row \o \c qt_WorldMatrix
+ \o Modelview matrix without the eye position and orientation
+ component. See QGLPainter::worldMatrix() for further
+ information.
+ \row \o \c qt_Texture0
+ \o Sampler corresponding to the texture on unit 0.
+ \row \o \c qt_Texture1
+ \o Sampler corresponding to the texture on unit 1.
+ \row \o \c qt_Texture2
+ \o Sampler corresponding to the texture on unit 2.
+ \row \o \c qt_Color
+ \o Set to the value of the QGLPainter::color() property.
+ This is typically used for flat-color shaders that do
+ not involve lighting. Note that this is different from
+ the \c qt_Color attribute, which provides per-vertex colors.
+ \endtable
+
+ The above variables are usually declared in the shaders as follows
+ (where \c highp may be replaced with \c mediump or \c lowp depending
+ upon the shader's precision requirements):
+
+ \code
+ uniform highp mat4 qt_ModelViewProjectionMatrix;
+ uniform highp mat4 qt_ModelViewMatrix;
+ uniform highp mat4 qt_ProjectionMatrix;
+ uniform highp mat3 qt_NormalMatrix;
+ uniform sampler2D qt_Texture0;
+ uniform sampler2D qt_Texture1;
+ uniform sampler2D qt_Texture2;
+ uniform highp vec4 qt_Color;
+ \endcode
+
+ \section1 Material parameters
+
+ QGLShaderProgramEffect will provide information about the front and
+ back materials from QGLPainter::faceMaterial() if the
+ \c qt_Materials array is present in the shader code.
+ The array should be declared as follows:
+
+ \code
+ struct qt_MaterialParameters {
+ mediump vec4 emission;
+ mediump vec4 ambient;
+ mediump vec4 diffuse;
+ mediump vec4 specular;
+ mediump float shininess;
+ };
+ uniform qt_MaterialParameters qt_Materials[2];
+ \endcode
+
+ The front material will be provided as index 0 and the back
+ material will be provided as index 1. If the shader only
+ needs a single material, then the \c qt_Material variable
+ can be declared instead:
+
+ \code
+ uniform qt_MaterialParameters qt_Material;
+ \endcode
+
+ The front material will be provided as the value of \c qt_Material
+ and the back material will be ignored.
+
+ Note: the \c emission parameter is actually QGLMaterial::emittedLight()
+ combined with the QGLLightModel::ambientSceneColor() and
+ QGLMaterial::ambientColor(). This helps simplify lighting shaders.
+
+ \section1 Lighting parameters
+
+ QGLShaderProgramEffect will provide information about the current lights
+ specified on the QGLPainter if the \c qt_Lights array is present
+ in the shader code. The array should be declared as follows:
+
+ \code
+ struct qt_LightParameters {
+ mediump vec4 ambient;
+ mediump vec4 diffuse;
+ mediump vec4 specular;
+ mediump vec4 position;
+ mediump vec3 spotDirection;
+ mediump float spotExponent;
+ mediump float spotCutoff;
+ mediump float spotCosCutoff;
+ mediump float constantAttenuation;
+ mediump float linearAttenuation;
+ mediump float quadraticAttenuation;
+ };
+ const int qt_MaxLights = 8;
+ uniform qt_LightParameters qt_Lights[qt_MaxLights];
+ uniform int qt_NumLights;
+ \endcode
+
+ As shown, up to 8 lights can be supported at once. Usually this is
+ more lights than most shaders need, and so the user can change the
+ \c qt_MaxLights constant to a smaller value if they wish. Be sure
+ to also call setMaximumLights() to tell QGLShaderProgramEffect about
+ the new light count limit.
+
+ The \c qt_NumLights uniform variable will be set to the actual number
+ of lights that are active on the QGLPainter when update() is called.
+
+ Because most shaders will only need a single light, the shader can
+ declare the \c qt_Light variable instead of the \c qt_Lights array:
+
+ \code
+ struct qt_SingleLightParameters {
+ mediump vec4 position;
+ mediump vec3 spotDirection;
+ mediump float spotExponent;
+ mediump float spotCutoff;
+ mediump float spotCosCutoff;
+ mediump float constantAttenuation;
+ mediump float linearAttenuation;
+ mediump float quadraticAttenuation;
+ };
+ uniform qt_SingleLightParameters qt_Light;
+ \endcode
+
+ Note that we have omitted the \c ambient, \c diffuse, and \c specular
+ colors for the single light. QGLShaderProgramEffect will combine the material
+ and light colors ahead of time into \c qt_Material or \c qt_Materials.
+ This makes lighting shaders more efficient because they do not have
+ to compute \c material_color * \c light_color; just \c material_color
+ is sufficient.
+
+ \section1 Varying variables
+
+ The name and purpose of the varying variables is up to the
+ author of the vertex and fragment shaders, but the following names
+ are recommended for texture co-ordinates:
+
+ \table
+ \header \o Varying Variable \o Purpose
+ \row \o \c qt_TexCoord0
+ \o Texture coordinate for unit 0, copied from the \c qt_MultiTexCoord0
+ attribute.
+ \row \o \c qt_TexCoord1
+ \o Texture coordinate for unit 1, copied from the \c qt_MultiTexCoord1
+ attribute.
+ \row \o \c qt_TexCoord2
+ \o Texture coordinate for unit 2, copied from the \c qt_MultiTexCoord2
+ attribute.
+ \endtable
+
+ \section1 Lighting shader example
+
+ The following example demonstrates what a lighting shader that
+ uses a single light, a single material, and a texture might look like.
+ The shader is quite complex but demonstrates most of the features that
+ can be found in the lighting implementation of a fixed-function
+ OpenGL pipeline:
+
+ \code
+ attribute highp vec4 qt_Vertex;
+ uniform highp mat4 qt_ModelViewProjectionMatrix;
+ attribute highp vec3 qt_Normal;
+ uniform highp mat4 qt_ModelViewMatrix;
+ uniform highp mat3 qt_NormalMatrix;
+ attribute highp vec4 qt_MultiTexCoord0;
+ varying highp vec4 qt_TexCoord0;
+
+ struct qt_MaterialParameters {
+ mediump vec4 emission;
+ mediump vec4 ambient;
+ mediump vec4 diffuse;
+ mediump vec4 specular;
+ mediump float shininess;
+ };
+ uniform qt_MaterialParameters qt_Material;
+
+ struct qt_SingleLightParameters {
+ mediump vec4 position;
+ mediump vec3 spotDirection;
+ mediump float spotExponent;
+ mediump float spotCutoff;
+ mediump float spotCosCutoff;
+ mediump float constantAttenuation;
+ mediump float linearAttenuation;
+ mediump float quadraticAttenuation;
+ };
+ uniform qt_SingleLightParameters qt_Light;
+
+ varying mediump vec4 litColor;
+ varying mediump vec4 litSecondaryColor;
+
+ void main(void)
+ {
+ gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex;
+ gTexCoord0 = qt_MultiTexCoord0;
+
+ // Calculate the vertex and normal to use for lighting calculations.
+ highp vec4 vertex = qt_ModelViewMatrix * qt_Vertex;
+ highp vec3 normal = normalize(qt_NormalMatrix * qt_Normal);
+
+ // Start with the material's emissive color and the ambient scene color,
+ // which have been combined into the emission parameter.
+ vec4 color = ggl_Material.emission;
+
+ // Viewer is at infinity.
+ vec3 toEye = vec3(0, 0, 1);
+
+ // Determine the angle between the normal and the light direction.
+ vec4 pli = qt_Light.position;
+ vec3 toLight;
+ if (pli.w == 0.0)
+ toLight = normalize(pli.xyz);
+ else
+ toLight = normalize(pli.xyz - vertex.xyz);
+ float angle = max(dot(normal, toLight), 0.0);
+
+ // Calculate the ambient and diffuse light components.
+ vec4 adcomponent = qt_Material.ambient + angle * qt_Material.diffuse;
+
+ // Calculate the specular light components.
+ vec4 scomponent;
+ if (angle != 0.0) {
+ vec3 h = normalize(toLight + toEye);
+ angle = max(dot(normal, h), 0.0);
+ float srm = qt_Material.shininess;
+ vec4 scm = qt_Material.specular;
+ if (srm != 0.0)
+ scomponent = pow(angle, srm) * scm;
+ else
+ scomponent = scm;
+ } else {
+ scomponent = vec4(0, 0, 0, 0);
+ }
+
+ // Apply the spotlight angle and exponent.
+ if (qt_Light.spotCutoff != 180.0) {
+ float spot = max(dot(normalize(vertex.xyz - pli.xyz),
+ qt_Light.spotDirection), 0.0);
+ if (spot < qt_Light.spotCosCutoff) {
+ adcomponent = vec4(0, 0, 0, 0);
+ scomponent = vec4(0, 0, 0, 0);
+ } else {
+ spot = pow(spot, qt_Light.spotExponent);
+ adcomponent *= spot;
+ scomponent *= spot;
+ }
+ }
+
+ // Apply attenuation to the colors.
+ if (pli.w != 0.0) {
+ float attenuation = qt_Light.constantAttenuation;
+ float k1 = qt_Light.linearAttenuation;
+ float k2 = qt_Light.quadraticAttenuation;
+ if (k1 != 0.0 || k2 != 0.0) {
+ float len = length(pli.xyz - vertex.xyz);
+ attenuation += k1 * len + k2 * len * len;
+ }
+ color += adcomponent / attenuation;
+ scolor += scomponent / attenuation;
+ } else {
+ color += adcomponent;
+ scolor += scomponent;
+ }
+
+ // Generate the final output colors to pass to the fragment shader.
+ float alpha = qt_Material.diffuse.a;
+ litColor = vec4(clamp(color.rgb, 0.0, 1.0), alpha);
+ litSecondaryColor = vec4(clamp(scolor.rgb, 0.0, 1.0), 0.0);
+ }
+ \endcode
+
+ The corresponding fragment shader is as follows:
+
+ \code
+ varying mediump vec4 litColor;
+ varying mediump vec4 litSecondaryColor;
+ varying highp vec4 qt_TexCoord0;
+
+ void main(void)
+ {
+ vec4 color = litColor * texture2D(qt_Texture0, qt_TexCoord0.st);
+ gl_FragColor = clamp(color + litSecondaryColor, 0.0, 1.0);
+ }
+ \endcode
+
+ \section1 Fixed function operation
+
+ If the OpenGL implementation does not support shaders, then
+ QGLShaderProgramEffect will fall back to a flat color effect based
+ on QGLPainter::color(). It is recommended that the application
+ consult QGLPainter::isFixedFunction() to determine if some
+ other effect should be used instead.
+*/
+
+class QGLShaderProgramEffectPrivate
+{
+public:
+ QGLShaderProgramEffectPrivate()
+ : maximumLights(8)
+ , attributes(0)
+ , regenerate(true)
+ , fixedFunction(false)
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+ , program(0)
+ , matrix(-1)
+ , mvMatrix(-1)
+ , projMatrix(-1)
+ , normalMatrix(-1)
+ , worldMatrix(-1)
+ , texture0(-1)
+ , texture1(-1)
+ , texture2(-1)
+ , color(-1)
+ , numLights(-1)
+ , haveLight(0)
+ , haveLights(0)
+ , haveMaterial(0)
+ , haveMaterials(0)
+#endif
+ {
+ }
+ ~QGLShaderProgramEffectPrivate()
+ {
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+ delete program;
+#endif
+ }
+
+ QByteArray vertexShader;
+ QByteArray fragmentShader;
+ int maximumLights;
+ int attributes;
+ bool regenerate;
+ bool fixedFunction;
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+ QGLShaderProgram *program;
+ int matrix;
+ int mvMatrix;
+ int projMatrix;
+ int normalMatrix;
+ int worldMatrix;
+ int texture0;
+ int texture1;
+ int texture2;
+ int color;
+ int numLights;
+ int haveLight : 1;
+ int haveLights : 1;
+ int haveMaterial : 1;
+ int haveMaterials : 1;
+
+ void setUniformValue
+ (const char *array, int index, const char *field, GLfloat v);
+ void setUniformValue
+ (const char *array, int index, const char *field, const QVector3D &v);
+ void setUniformValue
+ (const char *array, int index, const char *field, const QVector4D &v);
+ void setUniformValue
+ (const char *array, int index, const char *field, const QColor &v);
+
+ void setLight
+ (const QGLLightParameters *lparams, const QMatrix4x4 &ltransform,
+ const char *array, int index);
+ void setMaterial
+ (const QGLMaterial *mparams, const QGLLightModel *model,
+ const QGLLightParameters *lparams, const char *array, int index);
+#endif
+};
+
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+
+void QGLShaderProgramEffectPrivate::setUniformValue
+ (const char *array, int index, const char *field, GLfloat v)
+{
+ char name[128];
+ if (index >= 0)
+ qsnprintf(name, sizeof(name), "%s[%d].%s", array, index, field);
+ else
+ qsnprintf(name, sizeof(name), "%s.%s", array, field);
+ program->setUniformValue(name, v);
+}
+
+void QGLShaderProgramEffectPrivate::setUniformValue
+ (const char *array, int index, const char *field, const QVector3D &v)
+{
+ char name[128];
+ if (index >= 0)
+ qsnprintf(name, sizeof(name), "%s[%d].%s", array, index, field);
+ else
+ qsnprintf(name, sizeof(name), "%s.%s", array, field);
+ program->setUniformValue(name, v);
+}
+
+void QGLShaderProgramEffectPrivate::setUniformValue
+ (const char *array, int index, const char *field, const QVector4D &v)
+{
+ char name[128];
+ if (index >= 0)
+ qsnprintf(name, sizeof(name), "%s[%d].%s", array, index, field);
+ else
+ qsnprintf(name, sizeof(name), "%s.%s", array, field);
+ program->setUniformValue(name, v);
+}
+
+void QGLShaderProgramEffectPrivate::setUniformValue
+ (const char *array, int index, const char *field, const QColor &v)
+{
+ char name[128];
+ if (index >= 0)
+ qsnprintf(name, sizeof(name), "%s[%d].%s", array, index, field);
+ else
+ qsnprintf(name, sizeof(name), "%s.%s", array, field);
+ program->setUniformValue(name, v);
+}
+
+void QGLShaderProgramEffectPrivate::setLight
+ (const QGLLightParameters *lparams, const QMatrix4x4 &ltransform,
+ const char *array, int index)
+{
+ if (index >= 0) {
+ // Single lights embed the color values into the material.
+ setUniformValue(array, index, "ambient", lparams->ambientColor());
+ setUniformValue(array, index, "diffuse", lparams->diffuseColor());
+ setUniformValue(array, index, "specular", lparams->specularColor());
+ }
+ setUniformValue
+ (array, index, "position", lparams->eyePosition(ltransform));
+ setUniformValue
+ (array, index, "spotDirection",
+ lparams->eyeSpotDirection(ltransform).normalized());
+ setUniformValue
+ (array, index, "spotExponent", GLfloat(lparams->spotExponent()));
+ setUniformValue
+ (array, index, "spotCutoff", GLfloat(lparams->spotAngle()));
+ setUniformValue
+ (array, index, "spotCosCutoff", GLfloat(lparams->spotCosAngle()));
+ setUniformValue
+ (array, index, "constantAttenuation",
+ GLfloat(lparams->constantAttenuation()));
+ setUniformValue
+ (array, index, "linearAttenuation",
+ GLfloat(lparams->linearAttenuation()));
+ setUniformValue
+ (array, index, "quadraticAttenuation",
+ GLfloat(lparams->quadraticAttenuation()));
+}
+
+static inline QVector4D colorToVector4(const QColor& color)
+{
+ return QVector4D(color.redF(), color.greenF(),
+ color.blueF(), color.alphaF());
+}
+
+// Combine a material and light color into a single color.
+static inline QVector4D colorToVector4
+ (const QColor &color, const QColor &lightColor)
+{
+ return QVector4D(color.redF() * lightColor.redF(),
+ color.greenF() * lightColor.greenF(),
+ color.blueF() * lightColor.blueF(),
+ color.alphaF() * lightColor.alphaF());
+}
+
+void QGLShaderProgramEffectPrivate::setMaterial
+ (const QGLMaterial *mparams, const QGLLightModel *model,
+ const QGLLightParameters *lparams, const char *array, int index)
+{
+ if (lparams) {
+ setUniformValue
+ (array, index, "ambient",
+ colorToVector4(mparams->ambientColor(), lparams->ambientColor()));
+ setUniformValue
+ (array, index, "diffuse",
+ colorToVector4(mparams->diffuseColor(), lparams->diffuseColor()));
+ setUniformValue
+ (array, index, "specular",
+ colorToVector4(mparams->specularColor(), lparams->specularColor()));
+ } else {
+ setUniformValue
+ (array, index, "ambient", mparams->ambientColor());
+ setUniformValue
+ (array, index, "diffuse", mparams->diffuseColor());
+ setUniformValue
+ (array, index, "specular", mparams->specularColor());
+ }
+ setUniformValue
+ (array, index, "emission",
+ colorToVector4(mparams->emittedLight()) +
+ colorToVector4(mparams->ambientColor(), model->ambientSceneColor()));
+ setUniformValue
+ (array, index, "shininess", GLfloat(mparams->shininess()));
+}
+
+#endif // !QGL_FIXED_FUNCTION_ONLY
+
+/*!
+ Constructs a new shader program effect. This constructor is typically
+ followed by calls to setVertexShader() and setFragmentShader().
+
+ Note that a shader program effect will be bound to the QGLContext that
+ is current when setActive() is called for the first time. After that,
+ the effect can only be used with that context or any other QGLContext
+ that shares with it.
+*/
+QGLShaderProgramEffect::QGLShaderProgramEffect()
+ : d_ptr(new QGLShaderProgramEffectPrivate)
+{
+}
+
+/*!
+ Destroys this shader program effect.
+*/
+QGLShaderProgramEffect::~QGLShaderProgramEffect()
+{
+}
+
+/*!
+ \reimp
+*/
+void QGLShaderProgramEffect::setActive(QGLPainter *painter, bool flag)
+{
+ Q_D(QGLShaderProgramEffect);
+
+#if !defined(QGL_SHADERS_ONLY)
+ d->fixedFunction = painter->isFixedFunction();
+ if (d->fixedFunction) {
+ // Fixed function emulation is flat color only.
+ if (flag)
+ glEnableClientState(GL_VERTEX_ARRAY);
+ else
+ glDisableClientState(GL_VERTEX_ARRAY);
+ return;
+ }
+#endif
+
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+ static const char *const attributes[] = {
+ "qt_Vertex",
+ "qt_Normal",
+ "qt_Color",
+ "qt_MultiTexCoord0",
+ "qt_MultiTexCoord1",
+ "qt_MultiTexCoord2",
+ "qt_Custom0",
+ "qt_Custom1"
+ };
+ const int numAttributes = 8;
+ Q_UNUSED(painter);
+ int attr;
+ if (d->regenerate) {
+ // The shader source has changed since the last call to setActive().
+ delete d->program;
+ d->program = 0;
+ d->regenerate = false;
+ }
+ if (!d->program) {
+ if (!flag)
+ return;
+ Q_ASSERT(!d->vertexShader.isEmpty());
+ Q_ASSERT(!d->fragmentShader.isEmpty());
+ d->program = new QGLShaderProgram();
+ d->program->addShaderFromSourceCode
+ (QGLShader::Vertex, d->vertexShader);
+ d->program->addShaderFromSourceCode
+ (QGLShader::Fragment, d->fragmentShader);
+ if (beforeLink()) {
+ for (attr = 0; attr < numAttributes; ++attr)
+ d->program->bindAttributeLocation(attributes[attr], attr);
+ }
+ if (!d->program->link()) {
+ qWarning("QGLShaderProgramEffect::setActive(): could not link shader program");
+ delete d->program;
+ d->program = 0;
+ return;
+ }
+ afterLink();
+ d->attributes = 0;
+ for (attr = 0; attr < numAttributes; ++attr) {
+ // Determine which attributes were actually present in the program.
+ if (d->program->attributeLocation(attributes[attr]) != -1)
+ d->attributes |= (1 << attr);
+ }
+ if (d->program->attributeLocation("qgl_Vertex") != -1)
+ qWarning("QGLShaderProgramEffect: qgl_Vertex no longer supported; use qt_Vertex instead");
+ d->matrix = d->program->uniformLocation("qt_ModelViewProjectionMatrix");
+ d->mvMatrix = d->program->uniformLocation("qt_ModelViewMatrix");
+ d->projMatrix = d->program->uniformLocation("qt_ProjectionMatrix");
+ d->normalMatrix = d->program->uniformLocation("qt_NormalMatrix");
+ d->worldMatrix = d->program->uniformLocation("qt_WorldMatrix");
+ d->texture0 = d->program->uniformLocation("qt_Texture0");
+ d->texture1 = d->program->uniformLocation("qt_Texture1");
+ d->texture2 = d->program->uniformLocation("qt_Texture2");
+ d->color = d->program->uniformLocation("qt_Color");
+ d->numLights = d->program->uniformLocation("qt_NumLights");
+ d->haveLight =
+ (d->program->uniformLocation("qt_Light.position") != -1);
+ d->haveLights =
+ (d->program->uniformLocation("qt_Lights[0].position") != -1);
+ d->haveMaterial =
+ (d->program->uniformLocation("qt_Material.diffuse") != -1);
+ d->haveMaterials =
+ (d->program->uniformLocation("qt_Materials[0].diffuse") != -1);
+ }
+ if (flag) {
+ d->program->bind();
+ for (attr = 0; attr < numAttributes; ++attr) {
+ if ((d->attributes & (1 << attr)) == 0)
+ continue;
+ d->program->enableAttributeArray(attr);
+ }
+ if (d->texture0 != -1)
+ d->program->setUniformValue(d->texture0, 0);
+ if (d->texture1 != -1)
+ d->program->setUniformValue(d->texture1, 1);
+ if (d->texture2 != -1)
+ d->program->setUniformValue(d->texture2, 2);
+ } else {
+ for (attr = 0; attr < int(QGL::UserVertex); ++attr) {
+ if ((d->attributes & (1 << attr)) != 0)
+ d->program->disableAttributeArray(attr);
+ }
+ d->program->release();
+ }
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QGLShaderProgramEffect::update(QGLPainter *painter, QGLPainter::Updates updates)
+{
+ Q_D(QGLShaderProgramEffect);
+#if !defined(QGL_SHADERS_ONLY)
+ if (d->fixedFunction) {
+ // Fixed function emulation is flat color only.
+ painter->updateFixedFunction
+ (updates & (QGLPainter::UpdateColor | QGLPainter::UpdateMatrices));
+ return;
+ }
+#endif
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+ if ((updates & QGLPainter::UpdateColor) != 0 && d->color != -1)
+ d->program->setUniformValue(d->color, painter->color());
+ if ((updates & QGLPainter::UpdateMatrices) != 0) {
+ if (d->matrix != -1)
+ d->program->setUniformValue(d->matrix, painter->combinedMatrix());
+ }
+ if ((updates & QGLPainter::UpdateModelViewMatrix) != 0) {
+ if (d->mvMatrix != -1)
+ d->program->setUniformValue(d->mvMatrix, painter->modelViewMatrix());
+ if (d->normalMatrix != -1)
+ d->program->setUniformValue(d->normalMatrix, painter->normalMatrix());
+ if (d->worldMatrix != -1)
+ d->program->setUniformValue(d->worldMatrix, painter->worldMatrix());
+ }
+ if ((updates & QGLPainter::UpdateProjectionMatrix) != 0) {
+ if (d->projMatrix != -1)
+ d->program->setUniformValue(d->projMatrix, painter->projectionMatrix());
+ }
+ if ((updates & QGLPainter::UpdateLights) != 0) {
+ if (d->haveLight) {
+ // Only one light needed so make it the main light.
+ d->setLight(painter->mainLight(), painter->mainLightTransform(),
+ "qt_Light", -1);
+ } else if (d->haveLights) {
+ // Shader supports multiple light sources.
+ int numLights = 0;
+ int maxLightId = painter->maximumLightId();
+ if (maxLightId < 0) {
+ // No lights - re-enable the main light so we have something.
+ painter->mainLight();
+ maxLightId = 0;
+ }
+ for (int lightId = 0; lightId <= maxLightId; ++lightId) {
+ // Is this light currently enabled?
+ const QGLLightParameters *lparams = painter->light(lightId);
+ if (!lparams)
+ continue;
+
+ // Set the parameters for the next shader light number.
+ d->setLight(lparams, painter->lightTransform(lightId),
+ "qt_Lights", numLights);
+
+ // Bail out if we've hit the maximum shader light limit.
+ ++numLights;
+ if (numLights >= d->maximumLights)
+ break;
+ }
+ if (d->numLights != -1)
+ d->program->setUniformValue(d->numLights, numLights);
+ }
+ }
+ if ((updates & QGLPainter::UpdateMaterials) != 0 ||
+ ((updates & QGLPainter::UpdateLights) != 0 && d->haveLight)) {
+ if (d->haveLight) {
+ // For a single light source, combine the light colors
+ // into the material colors.
+ if (d->haveMaterial) {
+ d->setMaterial(painter->faceMaterial(QGL::FrontFaces),
+ painter->lightModel(), painter->mainLight(),
+ "qt_Material", -1);
+ } else if (d->haveMaterials) {
+ d->setMaterial(painter->faceMaterial(QGL::FrontFaces),
+ painter->lightModel(), painter->mainLight(),
+ "qt_Materials", 0);
+ d->setMaterial(painter->faceMaterial(QGL::BackFaces),
+ painter->lightModel(), painter->mainLight(),
+ "qt_Materials", 1);
+ }
+ } else {
+ // Multiple light sources, so light colors are separate.
+ if (d->haveMaterial) {
+ d->setMaterial(painter->faceMaterial(QGL::FrontFaces),
+ painter->lightModel(), 0, "qt_Material", -1);
+ } else if (d->haveMaterials) {
+ d->setMaterial(painter->faceMaterial(QGL::FrontFaces),
+ painter->lightModel(), 0, "qt_Materials", 0);
+ d->setMaterial(painter->faceMaterial(QGL::BackFaces),
+ painter->lightModel(), 0, "qt_Materials", 1);
+ }
+ }
+ }
+#endif
+}
+
+/*!
+ Returns the source code for the vertex shader.
+
+ \sa setVertexShader(), fragmentShader(), setVertexShaderFromFile()
+*/
+QByteArray QGLShaderProgramEffect::vertexShader() const
+{
+ Q_D(const QGLShaderProgramEffect);
+ return d->vertexShader;
+}
+
+/*!
+ Sets the \a source code for the vertex shader.
+
+ \sa vertexShader(), setFragmentShader(), setVertexShaderFromFile()
+*/
+void QGLShaderProgramEffect::setVertexShader(const QByteArray &source)
+{
+ Q_D(QGLShaderProgramEffect);
+ d->vertexShader = source;
+ d->regenerate = true;
+}
+
+/*!
+ Sets the source code for the vertex shader to the contents
+ of \a fileName.
+
+ \sa setVertexShader(), setFragmentShaderFromFile()
+*/
+void QGLShaderProgramEffect::setVertexShaderFromFile(const QString &fileName)
+{
+ Q_D(QGLShaderProgramEffect);
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ d->vertexShader = file.readAll();
+ d->regenerate = true;
+ } else {
+ qWarning() << "QGLShaderProgramEffect::setVertexShaderFromFile: could not open " << fileName;
+ }
+}
+
+/*!
+ Returns the source code for the fragment shader.
+
+ \sa setFragmentShader(), vertexShader()
+*/
+QByteArray QGLShaderProgramEffect::fragmentShader() const
+{
+ Q_D(const QGLShaderProgramEffect);
+ return d->fragmentShader;
+}
+
+/*!
+ Sets the source code for the fragment shader to the contents
+ of \a fileName.
+
+ \sa setFragmentShader(), setVertexShaderFromFile()
+*/
+void QGLShaderProgramEffect::setFragmentShaderFromFile(const QString &fileName)
+{
+ Q_D(QGLShaderProgramEffect);
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ d->fragmentShader = file.readAll();
+ d->regenerate = true;
+ } else {
+ qWarning() << "QGLShaderProgramEffect::setFragmentShaderFromFile: could not open " << fileName;
+ }
+}
+
+/*!
+ Sets the \a source code for the fragment shader.
+
+ \sa fragmentShader(), setVertexShader()
+*/
+void QGLShaderProgramEffect::setFragmentShader(const QByteArray &source)
+{
+ Q_D(QGLShaderProgramEffect);
+ d->fragmentShader = source;
+ d->regenerate = true;
+}
+
+/*!
+ Returns the maximum number of lights that are supported by this
+ shader program effect. The default value is 8.
+
+ The actual number of lights will be provided to the vertexShader()
+ as the \c{qt_NumLights} uniform variable, which will always be
+ less than or equal to maximumLights().
+
+ \sa setMaximumLights()
+*/
+int QGLShaderProgramEffect::maximumLights() const
+{
+ Q_D(const QGLShaderProgramEffect);
+ return d->maximumLights;
+}
+
+/*!
+ Sets the maximum number of lights that are supported by this
+ shader program effect to \a value.
+
+ \sa maximumLights()
+*/
+void QGLShaderProgramEffect::setMaximumLights(int value)
+{
+ Q_D(QGLShaderProgramEffect);
+ d->maximumLights = value;
+}
+
+/*!
+ Returns the shader program object that was created for this effect;
+ null if setActive() has not been called yet.
+
+ This function can be used by the application to adjust custom
+ uniform variables after the effect is activated on a QGLPainter:
+
+ \code
+ painter.setUserEffect(effect);
+ effect->program()->setUniformValue("springiness", GLfloat(0.5f));
+ \endcode
+*/
+QGLShaderProgram *QGLShaderProgramEffect::program() const
+{
+#if !defined(QGL_FIXED_FUNCTION_ONLY)
+ Q_D(const QGLShaderProgramEffect);
+ return d->program;
+#else
+ return 0;
+#endif
+}
+
+/*!
+ Called by setActive() just before the program() is linked.
+ Returns true if the standard vertex attributes should be bound
+ by calls to QGLShaderProgram::bindAttributeLocation(). Returns
+ false if the subclass has already bound the attributes.
+
+ This function can be overridden by subclasses to alter the
+ vertex attribute bindings, or to add additional shader stages
+ to program().
+
+ \sa afterLink()
+*/
+bool QGLShaderProgramEffect::beforeLink()
+{
+ return true;
+}
+
+/*!
+ Called by setActive() just after the program() is linked.
+ The default implementation does nothing.
+
+ This function can be overridden by subclasses to resolve uniform
+ variable locations and cache them for later use in update().
+
+ \sa beforeLink()
+*/
+void QGLShaderProgramEffect::afterLink()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/effects/qglshaderprogrameffect.h b/src/threed/effects/qglshaderprogrameffect.h
new file mode 100644
index 000000000..c77392184
--- /dev/null
+++ b/src/threed/effects/qglshaderprogrameffect.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSHADERPROGRAMEFFECT_H
+#define QGLSHADERPROGRAMEFFECT_H
+
+#include "qglabstracteffect.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLShaderProgramEffectPrivate;
+class QGLShaderProgram;
+
+class Q_QT3D_EXPORT QGLShaderProgramEffect : public QGLAbstractEffect
+{
+public:
+ QGLShaderProgramEffect();
+ virtual ~QGLShaderProgramEffect();
+
+ void setActive(QGLPainter *painter, bool flag);
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+
+ QByteArray vertexShader() const;
+ void setVertexShader(const QByteArray &source);
+ void setVertexShaderFromFile(const QString &fileName);
+
+ QByteArray fragmentShader() const;
+ void setFragmentShader(const QByteArray &source);
+ void setFragmentShaderFromFile(const QString &fileName);
+
+ int maximumLights() const;
+ void setMaximumLights(int value);
+
+ QGLShaderProgram *program() const;
+
+protected:
+ virtual bool beforeLink();
+ virtual void afterLink();
+
+private:
+ QScopedPointer<QGLShaderProgramEffectPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGLShaderProgramEffect)
+ Q_DECLARE_PRIVATE(QGLShaderProgramEffect)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/geometry/geometry.pri b/src/threed/geometry/geometry.pri
new file mode 100644
index 000000000..5623ac054
--- /dev/null
+++ b/src/threed/geometry/geometry.pri
@@ -0,0 +1,28 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += qglcube.h \
+ qglsphere.h \
+ qgeometrydata.h \
+ qlogicalvertex.h \
+ qglbuilder.h \
+ qglbezierpatches.h \
+ qglmaterialcollection.h \
+ qglteapot.h \
+ qglcylinder.h \
+ qgldome.h
+SOURCES += qglcube.cpp \
+ qglsphere.cpp \
+ qgeometrydata.cpp \
+ qglbuilder.cpp \
+ qglsection.cpp \
+ qglbezierpatches.cpp \
+ qglmaterialcollection.cpp \
+ qglteapot.cpp \
+ qlogicalvertex.cpp \
+ qglcylinder.cpp \
+ qgldome.cpp
+PRIVATE_HEADERS += qglteapot_data_p.h \
+ qglbuilder_p.h \
+ qglsection_p.h \
+ qglteapot_data_p.h \
+ qvector_utils_p.h
diff --git a/src/threed/geometry/qgeometrydata.cpp b/src/threed/geometry/qgeometrydata.cpp
new file mode 100644
index 000000000..f5cedc960
--- /dev/null
+++ b/src/threed/geometry/qgeometrydata.cpp
@@ -0,0 +1,2025 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeometrydata.h"
+#include "qlogicalvertex.h"
+#include "qglpainter.h"
+
+#include <QtOpenGL/qgl.h>
+#include <QtCore/qdebug.h>
+
+/*!
+ \class QGeometryData
+ \brief The QGeometryData class encapsulates sets of geometry data.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ The QGeometryData class encloses a number of data arrays
+ that model most typical vertex data needs. The class provides a
+ store for all of the data types in the QGL::VertexAttribute enumeration.
+
+ \table
+ \header
+ \o QGL::VertexAttribute
+ \o QGeometryData functions
+ \row
+ \o QGL::Position
+ \o appendVertex(), vertex(), vertices()
+ \row
+ \o QGL::Normal
+ \o appendNormal(), normal(), normals()
+ \row
+ \o QGL::Color
+ \o appendColor(), colorRef(), colors()
+ \row
+ \o QGL::TextureCoord0 - QGL::TextureCoord3
+ \o appendTexCoord(), texCoordRef(), texCoords()
+ \row
+ \o QGL::CustomVertex0 - QGL::CustomVertex1, QGL::UserVertex
+ \o appendAttribute(), vector3DAttribute(), attributes()
+ \endtable
+
+ Additionally the class provides the following features:
+ \list
+ \o appendVertex() for adding a QLogicalVertex()
+ \o logicalVertexAt() for return the data at an index as a QLogicalVertex()
+ \o hasField() to find if a particular data type is present
+ \o normalizeNormals() to reduce all normal vectors to unit length
+ \o boundingBox() to find the bounds of the geometry
+ \endlist
+
+ It is up to the user of a QGeometryData instance to ensure that the
+ data has an equal number of items in each field. For example, if five
+ vertices are added and only two normals are added, the logical vertex at
+ position 3 will be corrupt, since it does not have a normal.
+
+ While data is being accumulated the counts of different fields will vary,
+ since it may be convenient to add several vertices, then several normals,
+ colors or attributes at a time. However when a logical vertex is
+ constructed or when the data is sent to the GPU, counts of all fields
+ must be equal.
+
+ QGeometryData uses explicit sharing with lazy creation of internal
+ data so that code like:
+ \code
+ QGeometryData myData;
+ if (processed)
+ myData = processedData();
+ \endcode
+ is very inexpensive, since the first declaration and initialization
+ does not cause internal data to be created (only to be overwritten by the
+ assignment operation).
+
+ Since QGeometryData is explicitly shared, variables of type
+ QGeometryData behave like references, and the underlying data is modified
+ by calling a non-const function on any variable which shares that data.
+
+ To force an explicit copy call the detach() function.
+*/
+
+/*!
+ \typedef QGL::IndexArray
+
+ This is a convenience for either QArray<ushort> (OpenGL/ES) or
+ QArray<int> (desktop OpenGL).
+*/
+
+class QGeometryDataPrivate
+{
+public:
+ QGeometryDataPrivate();
+ ~QGeometryDataPrivate();
+ QGeometryDataPrivate *clone() const;
+
+ QBasicAtomicInt ref;
+
+ QVector3DArray vertices;
+ QVector3DArray normals;
+ QArray<QColor4ub> colors;
+ QList<QCustomDataArray> attributes;
+ QList<QVector2DArray> textures;
+ QGL::IndexArray indices;
+ QGLVertexBundle vertexBundle;
+ QGLIndexBuffer indexBuffer;
+ bool uploadsViable;
+ bool modified;
+ QBox3D bb;
+ static const int ATTR_CNT = 32;
+ quint32 fields;
+ qint8 key[ATTR_CNT];
+ quint8 size[ATTR_CNT];
+ int count;
+ int reserved;
+ bool boxValid;
+ QGeometryData::BufferStrategy bufferStrategy;
+};
+
+QGeometryDataPrivate::QGeometryDataPrivate()
+ : uploadsViable(true)
+ , modified(false)
+ , fields(0)
+ , count(0)
+ , reserved(-1)
+ , boxValid(true)
+ , bufferStrategy(QGeometryData::BufferIfPossible | QGeometryData::KeepClientData)
+{
+ ref = 0;
+ qMemSet(key, -1, ATTR_CNT);
+ qMemSet(size, 0, ATTR_CNT);
+}
+
+QGeometryDataPrivate::~QGeometryDataPrivate()
+{
+}
+
+QGeometryDataPrivate *QGeometryDataPrivate::clone() const
+{
+ QGeometryDataPrivate *temp = new QGeometryDataPrivate;
+ temp->vertices = vertices;
+ temp->normals = normals;
+ temp->colors = colors;
+ temp->attributes = attributes;
+ temp->textures = textures;
+ temp->indices = indices;
+ temp->vertexBundle = vertexBundle;
+ temp->indexBuffer = indexBuffer;
+ temp->uploadsViable = uploadsViable;
+ temp->modified = modified;
+ temp->bb = bb;
+ temp->fields = fields;
+ qMemCopy(temp->key, key, ATTR_CNT);
+ qMemCopy(temp->size, size, ATTR_CNT);
+ temp->count = count;
+ temp->reserved = reserved;
+ temp->boxValid = boxValid;
+ temp->bufferStrategy = bufferStrategy;
+ return temp;
+}
+
+/*!
+ \fn quint32 QGL::fieldMask(QGL::VertexAttribute attribute)
+ \relates QGeometryData
+ Returns an unsigned integer mask from the \a attribute.
+
+ \sa QGeometryData::fields()
+*/
+
+/*!
+ \enum QGeometryData::BufferStrategyFlags
+
+ This enum serves to describe how management of the data is handled
+ with respect to vertex buffer objects. The strategies are essentially a
+ combination of whether the client data is kept around after it has been
+ successfully uploaded to the GPU; and whether an upload is attempted at
+ all.
+
+ If the data set is very small it may be pointless to use up a VBO, hence
+ in this case KeepClientData may be used resulting in no attempt to upload
+ the data and client side arrays used instead.
+
+ \value InvalidStrategy No valid strategy has been specified.
+ \value KeepClientData Keep the client data, even after successful upload to the GPU.
+ \value BufferIfPossible Try to upload the data to the GPU.
+*/
+
+/*!
+ Construct an empty QGeometryData
+*/
+QGeometryData::QGeometryData()
+ : d(0)
+{
+}
+
+/*!
+ Construct QGeometryData as a copy of \a other
+*/
+QGeometryData::QGeometryData(const QGeometryData &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Construct an empty QGeometryData with the \a fields enabled.
+*/
+QGeometryData::QGeometryData(quint32 fields)
+ : d(new QGeometryDataPrivate)
+{
+ d->ref.ref();
+ const quint32 mask = 0x01;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (!(mask & fields)) continue;
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ enableField(attr);
+ }
+}
+
+/*!
+ Destroys this QGeometryData recovering any resources.
+*/
+QGeometryData::~QGeometryData()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Assigns this QGeometryData to be a copy of \a other.
+*/
+QGeometryData &QGeometryData::operator=(const QGeometryData &other)
+{
+ if (d != other.d)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = other.d;
+ if (d)
+ d->ref.ref();
+ }
+ return *this;
+}
+
+/*!
+ Appends the geometry in \a data to this. If this is empty, then all
+ fields of \a data are appended; otherwise (when this has existing fields)
+ only those fields that exist in both are appended.
+
+ This does not change the indices - to reference the new geometry add
+ indices via the appendIndices() functions.
+*/
+void QGeometryData::appendGeometry(const QGeometryData &data)
+{
+ if (data.d && data.count())
+ {
+ detach();
+ d->modified = true;
+ d->boxValid = false;
+ int cnt = data.d->count;
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields | data.fields();
+ d->fields = fields;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ enableField(attr); // might not be enabled if we had NO fields
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ d->vertices.append(data.d->vertices);
+ else if (attr == QGL::Normal)
+ d->normals.append(data.d->normals);
+ else // colors
+ d->colors.append(data.d->colors);
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ d->textures[d->key[attr]].append(data.texCoords(attr));
+ }
+ else
+ {
+ d->attributes[d->key[attr]].append(data.attributes(attr));
+ }
+ }
+ }
+ d->count += cnt;
+ }
+}
+
+/*!
+ Appends all the data fields in QLogicalVertex \a v to this
+ QGeometryData object.
+*/
+int QGeometryData::appendVertex(const QLogicalVertex &v)
+{
+ create();
+ d->modified = true;
+ if (d->boxValid)
+ d->bb.unite(v.vertex());
+ quint32 fields = v.fields();
+ const quint32 mask = 0x01;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ appendVertex(v.vertex());
+ else if (attr == QGL::Normal)
+ appendNormal(v.normal());
+ else
+ appendColor(v.color());
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ appendTexCoord(v.texCoord(attr), attr);
+ }
+ else
+ {
+ appendAttribute(v.attribute(attr), attr);
+ }
+ }
+ }
+ return d->count - 1;
+}
+
+/*!
+ Returns a QLogicalVertex that references the \a{i}'th logical vertex
+ of this geometry.
+*/
+QLogicalVertex QGeometryData::logicalVertexAt(int i) const
+{
+ return QLogicalVertex(*this, i);
+}
+
+/*!
+ Normalize all the normal vectors in this geometry to unit length.
+*/
+void QGeometryData::normalizeNormals()
+{
+ check();
+ if (d) // nothng to do if its null
+ {
+ create();
+ d->modified = true;
+ if (hasField(QGL::Normal))
+ {
+ for (int i = 0; i < d->normals.count(); ++i)
+ d->normals[i].normalize();
+ }
+ }
+}
+
+/*!
+ Calculate and return a bounding box for the vertex data in this geometry.
+*/
+QBox3D QGeometryData::boundingBox() const
+{
+ QBox3D box;
+ if (d)
+ {
+ if (d->boxValid)
+ {
+ box = d->bb;
+ }
+ else
+ {
+ for (int i = 0; i < d->count; ++i)
+ box.unite(d->vertices.at(i));
+ d->bb = box;
+ }
+ }
+ return box;
+}
+
+/*!
+ Returns the coordinates of the center of the geometry.
+
+ The center is calculated as the centroid or geometric barycenter
+ of the vertices (the average of the vertices). For a convex hull this
+ is guaranteed to be inside the figure.
+*/
+QVector3D QGeometryData::center() const
+{
+ QVector3D center;
+ for (int i = 0; i < d->vertices.count(); ++i)
+ center += d->vertices.at(i);
+ return center / (float)d->vertices.count();
+}
+
+/*!
+ Returns a copy of this geometry data with elements in reverse order.
+*/
+QGeometryData QGeometryData::reversed() const
+{
+ QGeometryData r;
+ for (int i = count() - 1; i >= 0; --i)
+ r.appendVertex(logicalVertexAt(i));
+ return r;
+}
+
+/*!
+ Returns a copy of this geometry data with QGL::Position data translated by
+ the vector \a t. The other fields are unchanged.
+*/
+QGeometryData QGeometryData::translated(const QVector3D &t) const
+{
+ QGeometryData r(*this);
+ r.detach();
+ for (int i = 0; i < count(); ++i)
+ {
+ r.vertex(i) = r.vertexAt(i) + t;
+ }
+ return r;
+}
+
+/*!
+ Modifies this geometry data by generating texture data based on QGL::Position
+ values. If \a orientation is Qt::Horizontal (the default) then x-coordinate
+ values are generated, and y-coordinate values are set to 0.0; otherwise
+ y-coordinate values are generated and x-coordinate values are set to 0.0.
+ The values are appended to the texture coordinate \a field.
+
+ The method of calculation is based on the assumption that the vertex data
+ is a list of extents which span across the texture space horizontally, from
+ x = 0.0 to x = 1.0, in the case of Qt::Horizontal; or vertically in the
+ case of Qt::Vertical. The texture space of 1.0 is divided up proportionately
+ by the length of each extent.
+
+ \image texture-coords-gen.png
+
+ In this diagram the large blue numbers are the lengths of each extent, and
+ the texture coordinates generated are shown as \c{t(7/16, 1)} and so on.
+
+ Thus the texture coordinate t0 for vertex v0, is 0.0; t1 for vertex v1 is
+ \c{(v1 - v0).length() / totalLength} and so on.
+
+ The code to produce the texture coordinates for the quads in the image is:
+ \code
+ QGeometryData top;
+
+ // add data to the primitive
+ top.appendVertex(QVector3D(0.0, 0.0, 0.0));
+ top.appendVertex(QVector3D(6.0, 3.6, 0.0)); // (v1 - v0).length() = 7.0
+ top.appendVertex(QVector3D(10.0, 0.6, 0.0)); // (v2 - v1).length() = 5.0
+ top.appendVertex(QVector3D(13.0, 3.24, 0.0)); // (v3 - v2).length() = 4.0
+
+ // generate x (Qt::Horizontal) texture coordinates over the primitive
+ top.generateTextureCoordinates(); // spread over 7 + 5 + 4 = 16
+
+ // make a copy translated down, the copy has y texture coordinates all 0
+ QGeometryData bottom = top.translated(QVector3D(0, 0, -1));
+
+ // now modify the top so its y texture coordinates are all 1
+ for (int i = 0; i < top.count(); ++i)
+ top.texCoordRef(QGL::TextureCoord0).setY(1.0);
+
+ displayList->addQuadsZipped(top, bottom);
+ \endcode
+*/
+void QGeometryData::generateTextureCoordinates(Qt::Orientation orientation, QGL::VertexAttribute field)
+{
+ QArray<qreal> extents;
+ extents.append(0.0);
+ qreal totalExtents = 0.0;
+ QArray<QVector3D> v = vertices();
+ for (int i = 0; i < v.count() - 1; ++i)
+ {
+ int n = (i + 1) % v.count();
+ QVector3D e = v[n] - v[i];
+ qreal extent = e.length();
+ totalExtents += extent;
+ extents.append(totalExtents);
+ }
+ if (hasField(field))
+ clear(field);
+ if (orientation == Qt::Horizontal)
+ {
+ for (int i = 0; i < v.count(); ++i)
+ appendTexCoord(QVector2D(extents[i] / totalExtents, 0.0), field);
+ }
+ else
+ {
+ for (int i = 0; i < v.count(); ++i)
+ appendTexCoord(QVector2D(0.0, extents[i] / totalExtents), field);
+ }
+}
+
+/*!
+ Returns a QGeometryData instance containing alternating vertices from
+ this geometry and \a other. The resulting geometry contains N vertices
+ where \c{N == qMin(count(), other.count())}, and has only the fields
+ that are in both geometries.
+*/
+QGeometryData QGeometryData::interleavedWith(const QGeometryData &other) const
+{
+ QGeometryData res;
+ check();
+ other.check();
+ if (d && other.d)
+ {
+ int cnt = qMax(d->count, other.d->count);
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields & other.d->fields;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ res.enableField(attr);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ {
+ QArray<QVector3D> tmp;
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(d->vertices.at(i));
+ tmp.append(other.d->vertices.at(i));
+ }
+ res.d->vertices = tmp;
+ }
+ else if (attr == QGL::Normal)
+ {
+ QArray<QVector3D> tmp;
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(d->normals.at(i));
+ tmp.append(other.d->normals.at(i));
+ }
+ res.d->normals = tmp;
+ }
+ else // colors
+ {
+ QArray<QColor4ub> tmp;
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(d->colors.at(i));
+ tmp.append(other.d->colors.at(i));
+ }
+ res.d->colors = tmp;
+ }
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ QArray<QVector2D> tmp;
+ const QArray<QVector2D> txa = d->textures.at(d->key[attr]);
+ const QArray<QVector2D> txb = other.d->textures.at(other.d->key[attr]);
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(txa.at(i));
+ tmp.append(txb.at(i));
+ }
+ res.d->textures[d->key[attr]] = tmp;
+ }
+ else
+ {
+ QCustomDataArray tmp;
+ const QCustomDataArray ata = d->attributes.at(d->key[attr]);
+ const QCustomDataArray atb = other.d->attributes.at(other.d->key[attr]);
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(ata.at(i));
+ tmp.append(atb.at(i));
+ }
+ res.d->attributes[d->key[attr]] = tmp;
+ }
+ }
+ }
+ res.d->count = cnt * 2;
+ }
+ return res;
+}
+
+/*!
+ Sets this QGeometryData to contain alternating vertices from
+ this geometry and \a other. The resulting geometry contains \c{N * 2} vertices
+ where \c{N == qMin(count(), other.count())}, and has only the fields
+ that are in both geometries.
+*/
+void QGeometryData::interleaveWith(const QGeometryData &other)
+{
+ check();
+ other.check();
+ if (d && other.d)
+ {
+ create();
+ d->modified = true;
+ d->boxValid = false;
+ int cnt = qMin(d->count, other.d->count);
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields & other.d->fields;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ {
+ QArray<QVector3D> tmp;
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(d->vertices.at(i));
+ tmp.append(other.d->vertices.at(i));
+ }
+ d->vertices = tmp;
+ }
+ else if (attr == QGL::Normal)
+ {
+ QArray<QVector3D> tmp;
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(d->normals.at(i));
+ tmp.append(other.d->normals.at(i));
+ }
+ d->normals = tmp;
+ }
+ else // colors
+ {
+ QArray<QColor4ub> tmp;
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(d->colors.at(i));
+ tmp.append(other.d->colors.at(i));
+ }
+ d->colors = tmp;
+ }
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ QArray<QVector2D> tmp;
+ const QArray<QVector2D> txa = d->textures.at(d->key[attr]);
+ const QArray<QVector2D> txb = other.d->textures.at(other.d->key[attr]);
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(txa.at(i));
+ tmp.append(txb.at(i));
+ }
+ d->textures[d->key[attr]] = tmp;
+ }
+ else
+ {
+ QCustomDataArray tmp;
+ const QCustomDataArray ata = d->attributes.at(d->key[attr]);
+ const QCustomDataArray atb = other.d->attributes.at(other.d->key[attr]);
+ for (int i = 0; i < cnt; ++i)
+ {
+ tmp.append(ata.at(i));
+ tmp.append(atb.at(i));
+ }
+ d->attributes[d->key[attr]] = tmp;
+ }
+ }
+ }
+ d->count = cnt * 2;
+ }
+}
+
+/*!
+ Clear all data structures. The actual fields are retained, but they
+ have no contents.
+ \code
+ QGeometryData data;
+ data.appendVertex(a);
+ data.appendTexCoord(t);
+
+ // prints "1"
+ qDebug() << data.count();
+
+ // x == a
+ QVector3D x = data.vertexAt(0);
+
+ quint32 flds = QGL::fieldMask(QGL::Position) | QGL::fieldMask(QGL::TextureCoord0);
+ qDebug() << (flds == data.fields()); // prints "true"
+
+ data.clear();
+ qDebug() << data.count(); // prints "0"
+ QVector3D x = data.vertexAt(0); // asserts - no data in vertices
+ qDebug() << (flds == data.fields()); // still prints "true"
+ \endcode
+
+ To clear a specific field and its data use \c{data.clear(field)} below.
+
+ To clear all fields and data, simply set this to an empty geometry:
+ \code
+ data = QGeometryData();
+ \endcode
+ */
+void QGeometryData::clear()
+{
+ if (d)
+ {
+ create();
+ d->modified = true;
+ d->bb = QBox3D();
+ d->boxValid = true;
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ d->vertices.clear();
+ else if (attr == QGL::Normal)
+ d->normals.clear();
+ else
+ d->colors.clear();
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ d->textures[d->key[field]].clear();
+ }
+ else
+ {
+ d->attributes[d->key[field]].clear();
+ }
+ }
+ }
+ d->count = 0;
+ }
+}
+
+/*!
+ Clears the data from \a field, and removes the field. After this call
+ hasField() will return false for this field.
+*/
+void QGeometryData::clear(QGL::VertexAttribute field)
+{
+ if (d && (QGL::fieldMask(field) & d->fields))
+ {
+ create();
+ d->modified = true;
+ if (field == QGL::Position)
+ {
+ d->bb = QBox3D();
+ d->boxValid = true;
+ }
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ d->vertices.clear();
+ else if (attr == QGL::Normal)
+ d->normals.clear();
+ else
+ d->colors.clear();
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ d->textures[d->key[field]].clear();
+ }
+ else
+ {
+ d->attributes[d->key[field]].clear();
+ }
+ d->key[field] = -1;
+ d->fields = d->fields & ~QGL::fieldMask(field);
+ }
+}
+
+/*!
+ Sets the geometry data to handle an \a amount of data. This is generally
+ not required unless its anticipated that a large amount of data will be
+ appended and realloc overhead is desired to be avoided. If \a amount is
+ less than the amount already reserved, or if this object has
+ more than the \a amount of data items, then this function exits without
+ doing anything. This function will never delete data.
+*/
+void QGeometryData::reserve(int amount)
+{
+ if (d && (d->reserved > amount || d->reserved < d->count))
+ return;
+ create();
+ d->reserved = amount;
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ d->vertices.reserve(amount);
+ else if (attr == QGL::Normal)
+ d->normals.reserve(amount);
+ else
+ d->colors.reserve(amount);
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ d->textures[d->key[field]].reserve(amount);
+ }
+ else
+ {
+ d->attributes[d->key[field]].reserve(amount);
+ }
+ }
+ }
+}
+
+/*!
+ Draws this geometry on the \a painter, from \a start for \a count elements
+ in \a mode. The drawing \a mode is by default QGL::Triangles. This function
+ Also calls the upload() method to ensure that the geometry is resident on
+ the graphics hardware if appropriate.
+
+ If the geometry is a point or line, then the \a drawWidth value specified the
+ width/size of the line/point.
+*/
+void QGeometryData::draw(QGLPainter *painter, int start, int count, GLenum mode, qreal drawWidth)
+{
+ if (d && d->indices.size() && d->count)
+ {
+ upload();
+ painter->clearAttributes();
+ if (mode==QGL::Points) {
+#if !defined(QT_OPENGL_ES_2)
+ ::glPointSize(drawWidth);
+#endif
+ } else if (mode==QGL::LineStrip || mode == QGL::Lines) {
+ ::glLineWidth(drawWidth);
+ }
+ painter->setVertexBundle(d->vertexBundle);
+ if (count == 0)
+ count = d->indexBuffer.indexCount();
+ painter->draw(QGL::DrawingMode(mode), d->indexBuffer, start, count);
+ }
+}
+
+/*!
+ Uploads this geometry data to the graphics hardware if appropriate. If the
+ data is already uploaded and has not been modified since it was last
+ uploaded, then this function does nothing.
+
+ If the bufferStrategy() does not specify QGL::BufferIfPossible then this
+ function does nothing.
+
+ If the data was successfully uploaded, and the bufferStrategy() does not
+ specify QGL::KeepClientData then the data will be removed with a call to
+ the clear() function.
+
+ If the data was successfully uploaded, on this call or previously, then this
+ function will return true. Otherwise it returns false.
+*/
+bool QGeometryData::upload()
+{
+ bool vboUploaded = false;
+ bool iboUploaded = false;
+
+ if (!d)
+ return false;
+ if (!d->modified)
+ return d->vertexBundle.isUploaded() && d->indexBuffer.isUploaded();
+
+ check();
+
+ // Need to recreate the buffers from the modified data.
+ d->vertexBundle = QGLVertexBundle();
+ d->indexBuffer = QGLIndexBuffer();
+
+ // Copy the geometry data to the vertex buffer.
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (!(mask & fields))
+ continue;
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr == QGL::Position)
+ d->vertexBundle.addAttribute(attr, d->vertices);
+ else if (attr == QGL::Normal)
+ d->vertexBundle.addAttribute(attr, d->normals);
+ else if (attr == QGL::Color)
+ d->vertexBundle.addAttribute(attr, d->colors);
+ else if (attr < QGL::CustomVertex0)
+ d->vertexBundle.addAttribute(attr, d->textures.at(d->key[field]));
+ else
+ d->vertexBundle.addAttribute(attr, d->attributes.at(d->key[field]));
+ }
+
+ // Upload the buffer if requested, otherwise keep it client-side.
+ // Note: QGLVertexBundle will act as a client-side buffer if not uploaded.
+ if ((d->bufferStrategy & BufferIfPossible) != 0)
+ {
+ if (d->vertexBundle.upload())
+ vboUploaded = true;
+ }
+
+ // Copy the geometry data to the index buffer and upload if requested.
+ d->indexBuffer.setIndexes(d->indices);
+ if ((d->bufferStrategy & BufferIfPossible) != 0)
+ {
+ if (d->indexBuffer.upload())
+ iboUploaded = true;
+ }
+
+ d->modified = false;
+
+ if (!(d->bufferStrategy & KeepClientData) && vboUploaded && iboUploaded)
+ clear();
+
+ return vboUploaded && iboUploaded;
+}
+
+/*!
+ Sets the buffer \a strategy for this geometry.
+
+ \sa bufferStrategy()
+*/
+void QGeometryData::setBufferStrategy(QGeometryData::BufferStrategy strategy)
+{
+ if (!d || d->bufferStrategy != strategy)
+ {
+ create();
+ d->modified = true;
+ d->bufferStrategy = strategy;
+ }
+}
+
+/*!
+ Returns the buffer strategy for this geometry. The default is
+ \c{QGL::BufferIfPossible | QGL::KeepClientData}.
+
+ \sa setBufferStrategy()
+*/
+QGeometryData::BufferStrategy QGeometryData::bufferStrategy() const
+{
+ if (d)
+ return d->bufferStrategy;
+ return InvalidStrategy;
+}
+
+/*!
+ Returns a reference to the vertex buffer for this geometry.
+
+ \sa indexBuffer()
+*/
+QGLVertexBundle QGeometryData::vertexBundle() const
+{
+ return d->vertexBundle;
+}
+
+/*!
+ Returns a reference to the index buffer for this geometry.
+
+ \sa vertexBundle()
+*/
+QGLIndexBuffer QGeometryData::indexBuffer() const
+{
+ return d->indexBuffer;
+}
+
+/*!
+ Appends \a index to the vertex index array.
+
+ \sa appendIndices(), indices()
+*/
+void QGeometryData::appendIndex(int index)
+{
+ create();
+ d->modified = true;
+ d->indices.append(index);
+}
+
+/*!
+ Appends \a index1, \a index2, and \a index3 to the geometry's
+ index array.
+
+ \sa appendIndex(), indices()
+*/
+void QGeometryData::appendIndices(int index1, int index2, int index3)
+{
+ create();
+ d->modified = true;
+ d->indices.append(index1, index2, index3);
+}
+
+/*!
+ Returns the index array that was created by appendIndex().
+
+ \sa appendIndex(), appendIndices()
+*/
+QGL::IndexArray QGeometryData::indices() const
+{
+ if (d)
+ return d->indices;
+ else
+ return QGL::IndexArray();
+}
+
+/*!
+ Appends the \a indices to the geometry's index array.
+*/
+void QGeometryData::appendIndices(const QGL::IndexArray &indices)
+{
+ create();
+ d->modified = true;
+ d->indices.append(indices);
+}
+
+/*!
+ Append the point \a v0 to this geometry data as a position field.
+*/
+void QGeometryData::appendVertex(const QVector3D &v0)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Position);
+ d->vertices.append(v0);
+ if (d->boxValid)
+ d->bb.unite(v0);
+ d->count = qMax(d->count, d->vertices.count());
+}
+
+/*!
+ Append the points \a v0 and \a v1 to this geometry data as position fields.
+*/
+void QGeometryData::appendVertex(const QVector3D &v0, const QVector3D &v1)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Position);
+ d->vertices.append(v0, v1);
+ if (d->boxValid)
+ {
+ d->bb.unite(v0);
+ d->bb.unite(v1);
+ }
+ d->count = qMax(d->count, d->vertices.count());
+}
+
+/*!
+ Append the points \a v0, \a v1 and \a v2 to this geometry data as position fields.
+*/
+void QGeometryData::appendVertex(const QVector3D &v0, const QVector3D &v1, const QVector3D &v2)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Position);
+ d->vertices.append(v0, v1, v2);
+ if (d->boxValid)
+ {
+ d->bb.unite(v0);
+ d->bb.unite(v1);
+ d->bb.unite(v2);
+ }
+ d->count = qMax(d->count, d->vertices.count());
+}
+
+/*!
+ Append the points \a v0, \a v1, \a v2 and \a v3 to this geometry data as position fields.
+*/
+void QGeometryData::appendVertex(const QVector3D &v0, const QVector3D &v1, const QVector3D &v2, const QVector3D &v3)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Position);
+ d->vertices.append(v0, v1, v2, v3);
+ if (d->boxValid)
+ {
+ d->bb.unite(v0);
+ d->bb.unite(v1);
+ d->bb.unite(v2);
+ d->bb.unite(v3);
+ }
+ d->count = qMax(d->count, d->vertices.count());
+}
+
+/*!
+ Append the float \a a0 to this geometry data, as an attribute \a field.
+*/
+void QGeometryData::appendAttribute(float a0, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->attributes[d->key[field]].append(a0);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+}
+
+/*!
+ Append the float \a a0 and \a a1 to this geometry data, as an attribute \a field.
+*/
+void QGeometryData::appendAttribute(float a0, float a1, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->attributes[d->key[field]].append(a0, a1);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+}
+
+/*!
+ Append the floats \a a0, \a a1 and \a a2 to this geometry data, as attribute \a field.
+*/
+void QGeometryData::appendAttribute(float a0, float a1, float a2, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->attributes[d->key[field]].append(a0, a1, a2);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+}
+
+/*!
+ Append the floats \a a0, \a a1, \a a2 and \a a3 to this geometry data, as attribute \a field.
+*/
+void QGeometryData::appendAttribute(float a0, float a1, float a2, float a3, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->attributes[d->key[field]].append(a0, a1, a2, a3);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+}
+
+/*!
+ Append the 2D point \a a to this geometry data, as an attribute \a field.
+*/
+void QGeometryData::appendAttribute(const QVector2D &a, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ if (d->attributes.at(d->key[field]).isEmpty())
+ d->attributes[d->key[field]].setElementType(QCustomDataArray::Vector2D);
+ d->attributes[d->key[field]].append(a);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+}
+
+/*!
+ Append the 3D point \a v to this geometry data, as an attribute \a field.
+*/
+void QGeometryData::appendAttribute(const QVector3D &v, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ if (d->attributes.at(d->key[field]).isEmpty())
+ d->attributes[d->key[field]].setElementType(QCustomDataArray::Vector3D);
+ d->attributes[d->key[field]].append(v);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+}
+
+/*!
+ Append the variant value \a a to this geometry data, as an attribute \a field.
+*/
+void QGeometryData::appendAttribute(const QVariant &a, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ if (d->attributes.at(d->key[field]).isEmpty())
+ {
+ // floats and doubles get handled "automatically" - float is default
+ if (a.type() == QVariant::Vector2D)
+ d->attributes[d->key[field]].setElementType(QCustomDataArray::Vector2D);
+ else if (a.type() == QVariant::Vector3D)
+ d->attributes[d->key[field]].setElementType(QCustomDataArray::Vector3D);
+ else if (a.type() == QVariant::Vector4D)
+ d->attributes[d->key[field]].setElementType(QCustomDataArray::Vector4D);
+ else if (a.type() == QVariant::Color)
+ d->attributes[d->key[field]].setElementType(QCustomDataArray::Color);
+ else
+ Q_ASSERT_X(false, "QGeometryData::appendAttribute", "bad type");
+ }
+ d->attributes[d->key[field]].append(a);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+}
+
+/*!
+ Append the vector \a n0 to this geometry data, as a lighting normal.
+*/
+void QGeometryData::appendNormal(const QVector3D &n0)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Normal);
+ d->normals.append(n0);
+ d->count = qMax(d->count, d->normals.count());
+}
+
+/*!
+ Append the vectors \a n0 and \a n1 to this geometry data, as lighting normals.
+*/
+void QGeometryData::appendNormal(const QVector3D &n0, const QVector3D &n1)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Normal);
+ d->normals.append(n0, n1);
+ d->count = qMax(d->count, d->normals.count());
+}
+
+/*!
+ Append the vectors \a n0, \a n1 and \a n2 to this geometry data, as lighting normals.
+*/
+void QGeometryData::appendNormal(const QVector3D &n0, const QVector3D &n1, const QVector3D &n2)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Normal);
+ d->normals.append(n0, n1, n2);
+ d->count = qMax(d->count, d->normals.count());
+}
+
+/*!
+ Append the vectors \a n0, \a n1, \a n2 and \a n3 to this geometry data, as lighting normals.
+*/
+void QGeometryData::appendNormal(const QVector3D &n0, const QVector3D &n1, const QVector3D &n2, const QVector3D &n3)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Normal);
+ d->normals.append(n0, n1, n2, n3);
+ d->count = qMax(d->count, d->normals.count());
+}
+
+/*!
+ Append the point \a t0 to this geometry data, as an texture \a field.
+*/
+void QGeometryData::appendTexCoord(const QVector2D &t0, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->textures[d->key[field]].append(t0);
+ d->count = qMax(d->count, d->textures[d->key[field]].count());
+}
+
+/*!
+ Append the points \a t0 and \a t1 to this geometry data, as texture \a{field}s.
+*/
+void QGeometryData::appendTexCoord(const QVector2D &t0, const QVector2D &t1, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->textures[d->key[field]].append(t0, t1);
+ d->count = qMax(d->count, d->textures[d->key[field]].count());
+}
+
+/*!
+ Append the points \a t0, \a t1 and \a t2 to this geometry data, as texture \a{field}s.
+*/
+void QGeometryData::appendTexCoord(const QVector2D &t0, const QVector2D &t1, const QVector2D &t2, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->textures[d->key[field]].append(t0, t1, t2);
+ d->count = qMax(d->count, d->textures[d->key[field]].count());
+}
+
+/*!
+ Append the points \a t0, \a t1, \a t2 and \a t3 to this geometry data, as texture \a{field}s.
+*/
+void QGeometryData::appendTexCoord(const QVector2D &t0, const QVector2D &t1, const QVector2D &t2, const QVector2D &t3, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ enableField(field);
+ d->textures[d->key[field]].append(t0, t1, t2, t3);
+ d->count = qMax(d->count, d->textures[d->key[field]].count());
+}
+
+/*!
+ Append the color \a c0 to this geometry data, as an color field.
+*/
+void QGeometryData::appendColor(const QColor4ub &c0)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Color);
+ d->colors.append(c0);
+ d->count = qMax(d->count, d->colors.count());
+}
+
+/*!
+ Append the color \a c0 and \a c1 to this geometry data, as color fields.
+*/
+void QGeometryData::appendColor(const QColor4ub &c0, const QColor4ub &c1)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Color);
+ d->colors.append(c0, c1);
+ d->count = qMax(d->count, d->colors.count());
+}
+
+/*!
+ Append the color \a c0, \a c1 and \a c2 to this geometry data, as color fields.
+*/
+void QGeometryData::appendColor(const QColor4ub &c0, const QColor4ub &c1, const QColor4ub &c2)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Color);
+ d->colors.append(c0, c1, c2);
+ d->count = qMax(d->count, d->colors.count());
+}
+
+/*!
+ Append the color \a c0, \a c1, \a c2 and \a c3 to this geometry data, as color fields.
+*/
+void QGeometryData::appendColor(const QColor4ub &c0, const QColor4ub &c1, const QColor4ub &c2, const QColor4ub &c3)
+{
+ create();
+ d->modified = true;
+ enableField(QGL::Color);
+ d->colors.append(c0, c1, c2, c3);
+ d->count = qMax(d->count, d->colors.count());
+}
+
+/*!
+ Append the points in \a ary to this geometry data as position fields.
+*/
+void QGeometryData::appendVertexArray(const QVector3DArray &ary)
+{
+ if (ary.count())
+ {
+ create();
+ d->modified = true;
+ d->boxValid = false;
+ enableField(QGL::Position);
+ d->vertices.append(ary);
+ d->count = qMax(d->count, d->vertices.count());
+ }
+}
+
+/*!
+ Append the points in \a ary to this geometry data, as an attribute \a field entries.
+*/
+void QGeometryData::appendAttributeArray(const QCustomDataArray &ary, QGL::VertexAttribute field)
+{
+ if (ary.count())
+ {
+ create();
+ d->modified = true;
+ enableField(field);
+ d->attributes[d->key[field]].append(ary);
+ d->count = qMax(d->count, d->attributes[d->key[field]].count());
+ }
+}
+
+/*!
+ Append the vectors in \a ary to this geometry data, as lighting normals.
+*/
+void QGeometryData::appendNormalArray(const QVector3DArray &ary)
+{
+ if (ary.count())
+ {
+ create();
+ d->modified = true;
+ enableField(QGL::Normal);
+ d->normals.append(ary);
+ d->count = qMax(d->count, d->normals.count());
+ }
+}
+
+/*!
+ Append the 2D points in \a ary to this geometry data, as texture \a field entries.
+*/
+void QGeometryData::appendTexCoordArray(const QVector2DArray &ary, QGL::VertexAttribute field)
+{
+ if (ary.count())
+ {
+ create();
+ d->modified = true;
+ enableField(field);
+ d->textures[d->key[field]].append(ary);
+ d->count = qMax(d->count, d->textures[d->key[field]].count());
+ }
+}
+
+/*!
+ Append the colors in \a ary to this geometry data, as color fields.
+*/
+void QGeometryData::appendColorArray(const QArray<QColor4ub> &ary)
+{
+ if (ary.count())
+ {
+ create();
+ d->modified = true;
+ enableField(QGL::Color);
+ d->colors.append(ary);
+ d->count = qMax(d->count, d->colors.count());
+ }
+}
+
+/*!
+ Returns a modifiable reference to the vertex data at index \a i.
+*/
+QVector3D &QGeometryData::vertex(int i)
+{
+ create();
+ d->modified = true;
+ d->boxValid = false;
+ return d->vertices[i];
+}
+
+/*!
+ Returns a copy of the vertex position data.
+*/
+QVector3DArray QGeometryData::vertices() const
+{
+ if (d)
+ return d->vertices;
+ return QArray<QVector3D>();
+}
+
+/*!
+ \internal
+ Returns a pointer to the vertex data.
+*/
+const QVector3DArray *QGeometryData::vertexData() const
+{
+ if (d)
+ return &d->vertices;
+ return 0;
+}
+
+
+/*!
+ Returns a non-modifiable reference to the vertex position data at index \a i.
+*/
+const QVector3D &QGeometryData::vertexAt(int i) const
+{
+ Q_ASSERT(hasField(QGL::Position));
+ return d->vertices.at(i);
+}
+
+/*!
+ Returns a modifiable reference to the normal data at index \a i.
+*/
+QVector3D &QGeometryData::normal(int i)
+{
+ create();
+ d->modified = true;
+ return d->normals[i];
+}
+
+/*!
+ Returns a non-modifiable reference to the normal data at index \a i.
+*/
+const QVector3D &QGeometryData::normalAt(int i) const
+{
+ Q_ASSERT(hasField(QGL::Normal));
+ return d->normals.at(i);
+}
+
+/*!
+ Returns a copy of the lighting normal data.
+*/
+QVector3DArray QGeometryData::normals() const
+{
+ if (d)
+ return d->normals;
+ return QArray<QVector3D>();
+}
+
+/*!
+ Returns a modifiable reference to the color data at index \a i.
+*/
+QColor4ub &QGeometryData::color(int i)
+{
+ create();
+ d->modified = true;
+ return d->colors[i];
+}
+
+/*!
+ Returns a non-modifiable reference to the color data at index \a i.
+*/
+const QColor4ub &QGeometryData::colorAt(int i) const
+{
+ Q_ASSERT(hasField(QGL::Color));
+ return d->colors.at(i);
+}
+
+/*!
+ Returns a copy of the color data.
+*/
+QArray<QColor4ub> QGeometryData::colors() const
+{
+ if (d)
+ return d->colors;
+ return QArray<QColor4ub>();
+}
+
+/*!
+ Returns a modifiable reference to the \a field texture coordinate data at index \a i.
+*/
+QVector2D &QGeometryData::texCoord(int i, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ return d->textures[d->key[field]][i];
+}
+
+/*!
+ Returns a copy of the \a field texture coordinate data.
+*/
+QVector2DArray QGeometryData::texCoords(QGL::VertexAttribute field) const
+{
+ return hasField(field) ? d->textures.at(d->key[field]) : QVector2DArray();
+}
+
+/*!
+ Returns a non-modifiable reference to the texture coordinate data at index \a i for \a field.
+*/
+const QVector2D &QGeometryData::texCoordAt(int i, QGL::VertexAttribute field) const
+{
+ Q_ASSERT(hasField(field));
+ return d->textures.at(d->key[field]).at(i);
+}
+
+/*!
+ Returns a modifiable reference to the float \a field attribute data at index \a i.
+*/
+float &QGeometryData::floatAttribute(int i, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ QCustomDataArray &ary = d->attributes[d->key[field]];
+ Q_ASSERT(ary.elementType() == QCustomDataArray::Float);
+ return ary.m_array[i];
+}
+
+/*!
+ Returns a modifiable reference to the 2D vector \a field attribute data at index \a i.
+*/
+QVector2D &QGeometryData::vector2DAttribute(int i, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ QCustomDataArray &ary = d->attributes[d->key[field]];
+ Q_ASSERT(ary.elementType() == QCustomDataArray::Vector2D);
+ float *data = ary.m_array.data();
+ QVector2D *v = reinterpret_cast<QVector2D*>(data + i*2);
+ return *v;
+}
+
+/*!
+ Returns a modifiable reference to the 3D vector \a field attribute data at index \a i.
+*/
+QVector3D &QGeometryData::vector3DAttribute(int i, QGL::VertexAttribute field)
+{
+ create();
+ d->modified = true;
+ QCustomDataArray &ary = d->attributes[d->key[field]];
+ Q_ASSERT(ary.elementType() == QCustomDataArray::Vector3D);
+ float *data = ary.m_array.data();
+ QVector3D *v = reinterpret_cast<QVector3D*>(data + i*2);
+ return *v;
+}
+
+/*!
+ Returns a copy of the \a field attribute data.
+*/
+QCustomDataArray QGeometryData::attributes(QGL::VertexAttribute field) const
+{
+ return hasField(field) ? d->attributes.at(d->key[field]) : QCustomDataArray();
+}
+
+/*!
+ Returns a copy of the float \a field attribute data at index \a i.
+*/
+float QGeometryData::floatAttributeAt(int i, QGL::VertexAttribute field) const
+{
+ Q_ASSERT(hasField(field));
+ return d->attributes.at(d->key[field]).floatAt(i);
+}
+
+/*!
+ Returns a copy of the 2D vector \a field attribute data at index \a i.
+*/
+QVector2D QGeometryData::vector2DAttributeAt(int i, QGL::VertexAttribute field) const
+{
+ Q_ASSERT(hasField(field));
+ return d->attributes.at(d->key[field]).vector2DAt(i);
+}
+
+/*!
+ Returns a copy of the 3D vector \a field attribute data at index \a i.
+*/
+QVector3D QGeometryData::vector3DAttributeAt(int i, QGL::VertexAttribute field) const
+{
+ Q_ASSERT(hasField(field));
+ return d->attributes.at(d->key[field]).vector3DAt(i);
+}
+
+/*!
+ Returns the attribute value for the \a field, suitable for passing
+ to QGLPainter.
+
+ \sa QGLPainter::setVertexAttribute()
+*/
+QGLAttributeValue QGeometryData::attributeValue(QGL::VertexAttribute field) const
+{
+ if (hasField(field))
+ {
+ if (field < QGL::TextureCoord0)
+ {
+ if (field == QGL::Position)
+ return QGLAttributeValue(d->vertices);
+ else if (field == QGL::Normal)
+ return QGLAttributeValue(d->normals);
+ else if (field == QGL::Color)
+ return QGLAttributeValue(d->colors);
+ }
+ else
+ {
+ if (field < QGL::CustomVertex0)
+ return QGLAttributeValue(d->textures.at(d->key[field]));
+ else
+ return QGLAttributeValue(d->attributes.at(d->key[field]));
+ }
+ }
+ return QGLAttributeValue();
+}
+
+/*!
+ Returns true if this geometry has the field corresponding to \a attr. Note
+ that it is still possible for no data to have been added for that field.
+*/
+bool QGeometryData::hasField(QGL::VertexAttribute attr) const
+{
+ if (d)
+ return d->key[attr] != -1;
+ return false;
+}
+
+/*!
+ Enables this geometry to contain data of type \a field. Generally it is
+ not necessary to call this function since it is called by all the append
+ functions.
+*/
+void QGeometryData::enableField(QGL::VertexAttribute field)
+{
+ if (d && d->key[field] != -1)
+ return;
+ create();
+ d->modified = true;
+ Q_ASSERT(field < d->ATTR_CNT); // don't expand that enum too much
+ d->fields |= (1 << field);
+ switch (field)
+ {
+ case QGL::Position:
+ d->key[QGL::Position] = 0;
+ d->size[QGL::Position] = 3;
+ if (d->reserved > 0)
+ d->vertices.reserve(d->reserved);
+ break;
+ case QGL::Normal:
+ d->key[QGL::Normal] = 1;
+ d->size[QGL::Normal] = 3;
+ if (d->reserved > 0)
+ d->normals.reserve(d->reserved);
+ break;
+ case QGL::Color:
+ d->key[QGL::Color] = 2;
+ d->size[QGL::Color] = 1;
+ if (d->reserved > 0)
+ d->colors.reserve(d->reserved);
+ break;
+ case QGL::TextureCoord0:
+ case QGL::TextureCoord1:
+ case QGL::TextureCoord2:
+ d->textures.append(QVector2DArray());
+ d->key[field] = d->textures.count() - 1;
+ d->size[field] = 2;
+ if (d->reserved > 0)
+ d->textures[d->key[field]].reserve(d->reserved);
+ break;
+ default:
+ // Custom and User vertex attributes.
+ d->attributes.append(QCustomDataArray());
+ d->key[field] = d->attributes.count() - 1;
+ d->size[field] = d->attributes.at(d->key[field]).elementSize();
+ if (d->reserved > 0)
+ d->attributes[d->key[field]].reserve(d->reserved);
+ break;
+ }
+}
+
+/*!
+ Return a bit-mask of the supported fields in this geometry. The
+ QGL::VertexAttribute enum can be recovered from this bit-mask by
+ \code
+ quint32 fields = fields();
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(fields);
+ \endcode
+*/
+quint32 QGeometryData::fields() const
+{
+ if (d)
+ return d->fields;
+ return 0;
+}
+
+/*!
+ Returns the count of logical vertices stored. This is effectively
+ the max() of QArray::count() over all of the enabled data types.
+*/
+int QGeometryData::count() const
+{
+ if (d)
+ return d->count;
+ return 0;
+}
+
+/*!
+ Returns the count of data stored in \a field. This will always be at
+ most count(), but could be less.
+*/
+int QGeometryData::count(QGL::VertexAttribute field) const
+{
+ int result = 0;
+ if (d && (QGL::fieldMask(field) & d->fields))
+ {
+ if (field < QGL::TextureCoord0)
+ {
+ if (field == QGL::Position)
+ result = d->vertices.count();
+ else if (field == QGL::Normal)
+ result = d->normals.count();
+ else
+ result = d->colors.count();
+ }
+ else if (field < QGL::CustomVertex0)
+ {
+ result = d->textures[d->key[field]].count();
+ }
+ else
+ {
+ result = d->attributes[d->key[field]].count();
+ }
+ }
+ return result;
+}
+
+/*!
+ Returns true if this geometry is identical to the \a other; and false otherwise.
+*/
+bool QGeometryData::operator==(const QGeometryData &other) const
+{
+ bool isEqual = false;
+ if (d)
+ {
+ if (d == other.d)
+ {
+ isEqual = true;
+ }
+ else
+ {
+ if (other.d && d->fields == other.d->fields && d->count == other.d->count)
+ {
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields;
+ isEqual = true;
+ for (int field = 0; fields && isEqual; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ isEqual = (d->vertices == other.d->vertices);
+ else if (attr == QGL::Normal)
+ isEqual = (d->normals == other.d->normals);
+ else // colors
+ isEqual = (d->colors == other.d->colors);
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ isEqual = (d->textures.at(d->key[attr]) == other.d->textures.at(d->key[attr]));
+ }
+ else
+ {
+ QArray<float> me = d->attributes.at(d->key[attr]).toFloatArray();
+ QArray<float> him = other.d->attributes.at(d->key[attr]).toFloatArray();
+ isEqual = (me == him);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ isEqual = other.isNull();
+ }
+ return isEqual;
+}
+
+/*!
+ Returns true if this geometry is empty - that is it contains no vertices
+ or other data - and returns false otherwise. If an existing geometry has
+ been made empty by a call to clear() then this will be true (but isNull()
+ will be false).
+
+ \sa isNull()
+*/
+bool QGeometryData::isEmpty() const
+{
+ bool empty = true;
+ if (d)
+ empty = d->count == 0;
+ return empty;
+}
+
+/*!
+ Returns true if this geometry is uninitialized - that is it contains no
+ internal data structures. A newly constructed QGeometryData object is
+ null until some data is added or changed.
+
+ \sa isEmpty()
+*/
+bool QGeometryData::isNull() const
+{
+ return d == NULL;
+}
+
+/*!
+ Returns the number of index values stored in this geometry data.
+
+ This value is exactly the same as indices().size() (but does not
+ incur the copy).
+*/
+int QGeometryData::indexCount() const
+{
+ if (d)
+ return d->indices.size();
+ return 0;
+}
+
+void QGeometryData::create()
+{
+ if (!d) // lazy creation of data block
+ {
+ d = new QGeometryDataPrivate;
+ d->ref.ref();
+ }
+}
+
+/*!
+ Force this geometry to ensure it has its own unshared internal data
+ block, making a copy in the case that it is currently shared.
+*/
+void QGeometryData::detach()
+{
+ create();
+ if (d->ref > 1) // being shared, must detach
+ {
+ QGeometryDataPrivate *temp = d->clone();
+ d->ref.deref();
+ d = temp;
+ d->ref.ref();
+ }
+}
+
+/*!
+ \fn quint64 QGeometryData::id() const
+ Return an opaque value that can be used to identify which data block is
+ being used by this QGeometryData instance. See the class documentation
+ relating to explicit sharing.
+*/
+
+#ifndef QT_NO_DEBUG
+void QGeometryData::check() const
+{
+ if (!d)
+ return;
+ const quint32 mask = 0x01;
+ quint32 fields = d->fields;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ {
+ if (d->vertices.count() < d->count)
+ qWarning("QGeometryData - expected %d vertices, only %d found!",
+ d->count, d->vertices.count());
+ }
+ else if (attr == QGL::Normal)
+ {
+ if (d->normals.count() < d->count)
+ qWarning("QGeometryData - expected %d normals, only %d found!",
+ d->count, d->normals.count());
+ }
+ else
+ {
+ if (d->colors.count() < d->count)
+ qWarning("QGeometryData - expected %d colors, only %d found!",
+ d->count, d->colors.count());
+ }
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ if (d->textures.at(d->key[field]).count() < d->count)
+ qWarning("QGeometryData - expected %d texture coordinates for"
+ "QGL::TextureCoord%d, only %d found!",
+ d->count, field - QGL::TextureCoord0, d->textures.at(d->key[field]).count());
+ }
+ else
+ {
+ if (d->attributes.at(d->key[field]).count() < d->count)
+ qWarning("QGeometryData - expected %d attributes for"
+ "QGL::CustomVertex%d, only %d found!",
+ d->count, field - QGL::CustomVertex0, d->attributes.at(d->key[field]).count());
+ }
+ }
+ }
+}
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QGeometryData &vertices)
+{
+ dbg << "QGeometryData" << &vertices << " size:" << vertices.count()
+#ifndef QT_NO_DEBUG
+ << "data block id:" << vertices.id()
+#endif
+ ;
+ quint32 fields = vertices.fields();
+ const quint32 mask = 0x01;
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ {
+ dbg << " vertices:" << vertices.count(attr);
+ dbg << vertices.vertices();
+ }
+ else if (attr == QGL::Normal)
+ {
+ dbg << " normals:" << vertices.count(attr);
+ dbg << vertices.normals();
+ }
+ else
+ {
+ dbg << " colors:" << vertices.count(attr);
+ dbg << vertices.colors();
+ }
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ dbg << " textures:" << (attr - QGL::TextureCoord0) << vertices.count(attr);
+ dbg << vertices.texCoords(attr);
+ }
+ else
+ {
+ dbg << " custom:" << (attr - QGL::CustomVertex0) << vertices.count(attr);
+ dbg << vertices.texCoords(attr);
+ }
+ }
+ }
+ if (vertices.indexCount() > 0)
+ {
+ dbg << " indices:" << vertices.indices();
+ }
+ return dbg;
+}
+#endif
diff --git a/src/threed/geometry/qgeometrydata.h b/src/threed/geometry/qgeometrydata.h
new file mode 100644
index 000000000..051915e32
--- /dev/null
+++ b/src/threed/geometry/qgeometrydata.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGEOMETRYDATA_H
+#define QGEOMETRYDATA_H
+
+#include "qcolor4ub.h"
+#include "qglnamespace.h"
+#include "qglindexbuffer.h"
+#include "qglvertexbundle.h"
+#include "qglattributevalue.h"
+#include "qcustomdataarray.h"
+#include "qbox3d.h"
+#include "qarray.h"
+#include "qvector2darray.h"
+#include "qvector3darray.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGeometryDataPrivate;
+class QLogicalVertex;
+class QGLPainter;
+
+namespace QGL
+{
+ inline quint32 fieldMask(QGL::VertexAttribute f) { return (quint32)0x01 << f; }
+
+#if defined(QT_OPENGL_ES)
+ typedef QArray<ushort> IndexArray;
+#else
+ typedef QArray<uint> IndexArray;
+#endif
+};
+
+class Q_QT3D_EXPORT QGeometryData
+{
+public:
+ QGeometryData();
+ QGeometryData(const QGeometryData &);
+ QGeometryData(quint32 fields);
+ ~QGeometryData();
+
+ QGeometryData &operator=(const QGeometryData &);
+
+ void appendGeometry(const QGeometryData &data);
+ int appendVertex(const QLogicalVertex &v);
+ void normalizeNormals();
+ QBox3D boundingBox() const;
+ QVector3D center() const;
+
+ QGeometryData reversed() const;
+ QGeometryData translated(const QVector3D &) const;
+ void generateTextureCoordinates(Qt::Orientation orientation = Qt::Horizontal,
+ QGL::VertexAttribute attribute = QGL::TextureCoord0);
+ QGeometryData interleavedWith(const QGeometryData &other) const;
+ void interleaveWith(const QGeometryData &other);
+ void clear();
+ void clear(QGL::VertexAttribute);
+ void reserve(int amount);
+ void draw(QGLPainter *painter, int start, int count, GLenum mode = QGL::Triangles, qreal drawWidth=1.0);
+ bool upload();
+ enum BufferStrategyFlags
+ {
+ InvalidStrategy = 0x00,
+ KeepClientData = 0x01,
+ BufferIfPossible = 0x02,
+ };
+ Q_DECLARE_FLAGS(BufferStrategy, BufferStrategyFlags)
+ void setBufferStrategy(BufferStrategy strategy);
+ BufferStrategy bufferStrategy() const;
+ QGLVertexBundle vertexBundle() const;
+ QGLIndexBuffer indexBuffer() const;
+
+ void appendIndex(int index);
+ void appendIndices(int index1, int index2, int index3);
+ void appendIndices(const QGL::IndexArray &indices);
+ QGL::IndexArray indices() const;
+
+ void appendVertex(const QVector3D &v0);
+ void appendVertex(const QVector3D &v0, const QVector3D &v1);
+ void appendVertex(const QVector3D &v0, const QVector3D &v1, const QVector3D &v2);
+ void appendVertex(const QVector3D &v0, const QVector3D &v1, const QVector3D &v2, const QVector3D &v3);
+
+ void appendAttribute(float a, QGL::VertexAttribute field = QGL::CustomVertex0);
+ void appendAttribute(float a, float b, QGL::VertexAttribute field = QGL::CustomVertex0);
+ void appendAttribute(float a, float b, float c, QGL::VertexAttribute field = QGL::CustomVertex0);
+ void appendAttribute(float a, float b, float c, float d, QGL::VertexAttribute field = QGL::CustomVertex0);
+ void appendAttribute(const QVector2D &a, QGL::VertexAttribute field = QGL::CustomVertex0);
+ void appendAttribute(const QVector3D &a, QGL::VertexAttribute field = QGL::CustomVertex0);
+ void appendAttribute(const QVariant &a, QGL::VertexAttribute field = QGL::CustomVertex0);
+
+ void appendNormal(const QVector3D &n0);
+ void appendNormal(const QVector3D &n0, const QVector3D &n1);
+ void appendNormal(const QVector3D &n0, const QVector3D &n1, const QVector3D &n2);
+ void appendNormal(const QVector3D &n0, const QVector3D &n1, const QVector3D &n2, const QVector3D &n3);
+
+ void appendTexCoord(const QVector2D &t0, QGL::VertexAttribute field = QGL::TextureCoord0);
+ void appendTexCoord(const QVector2D &t0, const QVector2D &t1, QGL::VertexAttribute field = QGL::TextureCoord0);
+ void appendTexCoord(const QVector2D &t0, const QVector2D &t1, const QVector2D &t2, QGL::VertexAttribute field = QGL::TextureCoord0);
+ void appendTexCoord(const QVector2D &t0, const QVector2D &t1, const QVector2D &t2, const QVector2D &t3, QGL::VertexAttribute field = QGL::TextureCoord0);
+
+ void appendColor(const QColor4ub &c0);
+ void appendColor(const QColor4ub &c0, const QColor4ub &c1);
+ void appendColor(const QColor4ub &c0, const QColor4ub &c1, const QColor4ub &c2);
+ void appendColor(const QColor4ub &c0, const QColor4ub &c1, const QColor4ub &c2, const QColor4ub &c3);
+
+ void appendVertexArray(const QVector3DArray &ary);
+ void appendAttributeArray(const QCustomDataArray &ary, QGL::VertexAttribute field = QGL::CustomVertex0);
+ void appendNormalArray(const QVector3DArray &ary);
+ void appendTexCoordArray(const QVector2DArray &ary, QGL::VertexAttribute field = QGL::TextureCoord0);
+ void appendColorArray(const QArray<QColor4ub> &ary);
+
+ QLogicalVertex logicalVertexAt(int i) const;
+
+ QVector3DArray vertices() const;
+ QVector3D &vertex(int i);
+ const QVector3D &vertexAt(int i) const;
+
+ QVector3DArray normals() const;
+ QVector3D &normal(int i);
+ const QVector3D &normalAt(int i) const;
+
+ QArray<QColor4ub> colors() const;
+ QColor4ub &color(int i);
+ const QColor4ub &colorAt(int i) const;
+
+ QVector2DArray texCoords(QGL::VertexAttribute field = QGL::TextureCoord0) const;
+ QVector2D &texCoord(int i, QGL::VertexAttribute field = QGL::TextureCoord0);
+ const QVector2D &texCoordAt(int i, QGL::VertexAttribute field = QGL::TextureCoord0) const;
+
+ float &floatAttribute(int i, QGL::VertexAttribute field = QGL::CustomVertex0);
+ QVector2D &vector2DAttribute(int i, QGL::VertexAttribute field = QGL::CustomVertex0);
+ QVector3D &vector3DAttribute(int i, QGL::VertexAttribute field = QGL::CustomVertex0);
+ QCustomDataArray attributes(QGL::VertexAttribute field = QGL::CustomVertex0) const;
+ float floatAttributeAt(int i, QGL::VertexAttribute field = QGL::CustomVertex0) const;
+ QVector2D vector2DAttributeAt(int i, QGL::VertexAttribute field = QGL::CustomVertex0) const;
+ QVector3D vector3DAttributeAt(int i, QGL::VertexAttribute field = QGL::CustomVertex0) const;
+
+ QGLAttributeValue attributeValue(QGL::VertexAttribute field) const;
+ bool hasField(QGL::VertexAttribute field) const;
+ void enableField(QGL::VertexAttribute field);
+ quint32 fields() const;
+ int count() const;
+ int count(QGL::VertexAttribute field) const;
+ int indexCount() const;
+ bool operator==(const QGeometryData &other) const;
+ bool isEmpty() const;
+ bool isNull() const;
+ void detach();
+#ifndef QT_NO_DEBUG
+ quint64 id() const { return (quint64)d; }
+#endif
+protected:
+ const QVector3DArray *vertexData() const;
+private:
+ void create();
+#ifndef QT_NO_DEBUG
+ void check() const;
+#else
+ void check() const {}
+#endif
+ friend class QLogicalVertex;
+
+ QGeometryDataPrivate *d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGeometryData::BufferStrategy);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QGeometryData &vertices);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QGEOMETRYDATA_H
diff --git a/src/threed/geometry/qglbezierpatches.cpp b/src/threed/geometry/qglbezierpatches.cpp
new file mode 100644
index 000000000..49842c653
--- /dev/null
+++ b/src/threed/geometry/qglbezierpatches.cpp
@@ -0,0 +1,815 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglbezierpatches.h"
+#include "qglbuilder.h"
+#include "qray3d.h"
+#include "qtriangle3d.h"
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLBezierPatches
+ \brief The QGLBezierPatches class represents 3D geometry as a set of Bezier bicubic patches.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ Bezier bicubic patches represent a curved 3D surface by four fixed
+ control points at indices 0, 3, 12, and 15, together with twelve
+ additional floating control points that define the surface
+ curvature. Bezier geometry objects are made up of one or more
+ such patches to define the surface of an object.
+
+ The application specifies the vertex position data to the
+ constructor, and can optionally provide an index array.
+ The class interprets groups of 16 vertices as the control
+ points for successive patches.
+
+ A mesh defined by QGLBezierPatches is subdivided into flat
+ triangles for rendering when the \c{<<} operator is used
+ to add the patches to a QGLBuilder.
+
+ Many curved 3D objects can be defined as being made up of Bezier
+ bicubic patches, stitched together into a mesh. The most famous
+ Bezier bicubic object is probably the classic 3D "Utah Teapot",
+ first rendered in 1975. The QGLTeapot class provides a built-in
+ implementation of this object for testing purposes.
+
+ If texture co-ordinates are supplied via setTextureCoords(),
+ then patch texture co-ordinates will be derived from the
+ specified values as the patches are subdivided. Otherwise,
+ QGLBezierPatches will generate texture co-ordinates for each
+ patch based on the default square from (0, 0) to (1, 1).
+ The first vertex in the patch corresponds to (0, 0),
+ and the opposite vertex in the patch corresponds to (1, 1).
+
+ \sa QGLBuilder, QGLTeapot
+*/
+
+class QGLBezierPatchesPrivate
+{
+public:
+ QGLBezierPatchesPrivate()
+ : subdivisionDepth(4) {}
+ QGLBezierPatchesPrivate(const QGLBezierPatchesPrivate *other)
+ : positions(other->positions)
+ , textureCoords(other->textureCoords)
+ , subdivisionDepth(other->subdivisionDepth) {}
+
+ void copy(const QGLBezierPatchesPrivate *other)
+ {
+ positions = other->positions;
+ textureCoords = other->textureCoords;
+ subdivisionDepth = other->subdivisionDepth;
+ }
+
+ void subdivide(QGLBuilder *list) const;
+ qreal intersection
+ (const QRay3D &ray, bool anyIntersection, QVector2D *texCoord, int *patch) const;
+
+ QVector3DArray positions;
+ QVector2DArray textureCoords;
+ int subdivisionDepth;
+};
+
+// Temporary patch data for performing sub-divisions.
+class QGLBezierPatch
+{
+public:
+ // Control points for this mesh.
+ QVector3D points[16];
+
+ // Triangle mesh indices of the control points at each corner.
+ int indices[4];
+
+ QVector3D normal(qreal s, qreal t) const;
+ void convertToTriangles
+ (QGeometryData *prim,
+ qreal xtex, qreal ytex, qreal wtex, qreal htex);
+ void subDivide(QGLBezierPatch &patch1, QGLBezierPatch &patch2,
+ QGLBezierPatch &patch3, QGLBezierPatch &patch4);
+ void createNewCorners(QGLBezierPatch &patch1, QGLBezierPatch &patch2,
+ QGLBezierPatch &patch3, QGLBezierPatch &patch4,
+ QGeometryData *prim,
+ qreal xtex, qreal ytex, qreal wtex, qreal htex);
+ void recursiveSubDivide
+ (QGeometryData *prim,
+ int depth, qreal xtex, qreal ytex, qreal wtex, qreal htex);
+ qreal intersection
+ (qreal result, int depth, const QRay3D &ray, bool anyIntersection,
+ qreal xtex, qreal ytex, qreal wtex, qreal htex, QVector2D *tc);
+};
+
+static int const cornerOffsets[] = {0, 3, 12, 15};
+static qreal const cornerS[] = {0.0f, 1.0f, 0.0f, 1.0f};
+static qreal const cornerT[] = {0.0f, 0.0f, 1.0f, 1.0f};
+
+// Helper functions for calculating the components of the Bernstein
+// polynomial and its derivative that make up the surface.
+static inline qreal b0(qreal v)
+{
+ return (1.0f - v) * (1.0f - v) * (1.0f - v);
+}
+static inline qreal b1(qreal v)
+{
+ return 3.0f * v * (1.0f - v) * (1.0f - v);
+}
+static inline qreal b2(qreal v)
+{
+ return 2.0f * v * v * (1.0f - v);
+}
+static inline qreal b3(qreal v)
+{
+ return v * v * v;
+}
+static inline qreal db0(qreal v)
+{
+ return -3.0f * (1.0f - v) * (1.0f - v);
+}
+static inline qreal db1(qreal v)
+{
+ return -6.0f * v * (1.0f - v) + 3.0f * (1.0f - v) * (1.0f - v);
+}
+static inline qreal db2(qreal v)
+{
+ return -3.0f * v * v + 6.0f * v * (1.0f - v);
+}
+static inline qreal db3(qreal v)
+{
+ return 3.0f * v * v;
+}
+
+// Compute the normal at a specific point in the patch.
+// The s and t values vary between 0 and 1.
+QVector3D QGLBezierPatch::normal(qreal s, qreal t) const
+{
+ qreal a[4];
+ qreal b[4];
+ qreal tx, ty, tz;
+ qreal sx, sy, sz;
+
+ // Compute the derivative of the surface in t.
+ a[0] = b0(s);
+ a[1] = b1(s);
+ a[2] = b2(s);
+ a[3] = b3(s);
+ b[0] = db0(t);
+ b[1] = db1(t);
+ b[2] = db2(t);
+ b[3] = db3(t);
+ tx = 0.0f;
+ ty = 0.0f;
+ tz = 0.0f;
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ tx += a[i] * points[j * 4 + i].x() * b[j];
+ ty += a[i] * points[j * 4 + i].y() * b[j];
+ tz += a[i] * points[j * 4 + i].z() * b[j];
+ }
+ }
+
+ // Compute the derivative of the surface in s.
+ a[0] = db0(s);
+ a[1] = db1(s);
+ a[2] = db2(s);
+ a[3] = db3(s);
+ b[0] = b0(t);
+ b[1] = b1(t);
+ b[2] = b2(t);
+ b[3] = b3(t);
+ sx = 0.0f;
+ sy = 0.0f;
+ sz = 0.0f;
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ sx += a[i] * points[j * 4 + i].x() * b[j];
+ sy += a[i] * points[j * 4 + i].y() * b[j];
+ sz += a[i] * points[j * 4 + i].z() * b[j];
+ }
+ }
+
+ // The normal is the cross-product of the two derivatives,
+ // normalized to a unit vector.
+ QVector3D n = QVector3D::normal(QVector3D(sx, sy, sz), QVector3D(tx, ty, tz));
+ if (n.isNull()) {
+ // A zero normal may occur if one of the patch edges is zero-length.
+ // We correct for this by substituting an overall patch normal that
+ // we compute from two of the sides that are not zero in length.
+ QVector3D sides[4];
+ QVector3D vectors[2];
+ sides[0] = points[3] - points[0];
+ sides[1] = points[15] - points[3];
+ sides[2] = points[12] - points[15];
+ sides[3] = points[0] - points[12];
+ int i = 0;
+ int j = 0;
+ vectors[0] = QVector3D(1.0f, 0.0f, 0.0f);
+ vectors[1] = QVector3D(0.0f, 1.0f, 0.0f);
+ while (i < 2 && j < 4) {
+ if (sides[j].isNull())
+ ++j;
+ else
+ vectors[i++] = sides[j++];
+ }
+ n = QVector3D::normal(vectors[0], vectors[1]);
+ }
+ return n;
+}
+
+// Convert this patch into flat triangles.
+void QGLBezierPatch::convertToTriangles
+ (QGeometryData *prim,
+ qreal xtex, qreal ytex, qreal wtex, qreal htex)
+{
+ // The edges are considered ok if they have a non-zero length.
+ // Zero-length edges can occur in triangular-shaped patches.
+ // There is no point generating triangles along such edges.
+ bool edge1ok = (points[0] != points[3]);
+ bool edge2ok = (points[0] != points[12]);
+ bool edge3ok = (points[12] != points[15]);
+ bool edge4ok = (points[15] != points[3]);
+
+ // Find the mid-point on the patch by averaging the corners.
+ QVector3D mid = (points[0] + points[3] + points[12] + points[15]) / 4.0f;
+
+ // Allocate a triangle mesh vertex for the mid-point.
+ int midIndex = prim->count();
+ prim->appendVertex(mid);
+ prim->appendNormal(normal(0.5f, 0.5f));
+ prim->appendTexCoord
+ (QVector2D(xtex + wtex / 2.0f, ytex + htex / 2.0f));
+
+ // Divide the patch into 4 triangles pointing at the center.
+ if (edge1ok)
+ prim->appendIndices(indices[0], indices[1], midIndex);
+ if (edge2ok)
+ prim->appendIndices(indices[2], indices[0], midIndex);
+ if (edge3ok)
+ prim->appendIndices(indices[3], indices[2], midIndex);
+ if (edge4ok)
+ prim->appendIndices(indices[1], indices[3], midIndex);
+}
+
+// Sub-divide a Bezier curve (p1, p2, p3, p4) into two new
+// Bezier curves (l1, l2, l3, l4) and (r1, r2, r3, r4).
+static void subDivideBezierCurve
+ (const QVector3D &p1, const QVector3D &p2,
+ const QVector3D &p3, const QVector3D &p4,
+ QVector3D &l1, QVector3D &l2, QVector3D &l3, QVector3D &l4,
+ QVector3D &r1, QVector3D &r2, QVector3D &r3, QVector3D &r4)
+{
+ l1 = p1;
+ l2 = (p1 + p2) / 2.0f;
+ QVector3D h = (p2 + p3) / 2.0f;
+ l3 = (l2 + h) / 2.0f;
+ r3 = (p3 + p4) / 2.0f;
+ r2 = (h + r3) / 2.0f;
+ l4 = r1 = (l3 + r2) / 2.0f;
+ r4 = p4;
+}
+
+// Sub-divide this patch into four new patches. The triangle mesh
+// is used to allocate vertices for the corners of the new patches.
+void QGLBezierPatch::subDivide
+ (QGLBezierPatch &patch1, QGLBezierPatch &patch2,
+ QGLBezierPatch &patch3, QGLBezierPatch &patch4)
+{
+ // Sub-divide the Bezier curves for the control rows to create
+ // four rows of 8 control points. These define the left and
+ // right halves of the patch.
+ QVector3D row1[8];
+ QVector3D row2[8];
+ QVector3D row3[8];
+ QVector3D row4[8];
+ subDivideBezierCurve
+ (points[0], points[1], points[2], points[3],
+ row1[0], row1[1], row1[2], row1[3], row1[4], row1[5], row1[6], row1[7]);
+ subDivideBezierCurve
+ (points[4], points[5], points[6], points[7],
+ row2[0], row2[1], row2[2], row2[3], row2[4], row2[5], row2[6], row2[7]);
+ subDivideBezierCurve
+ (points[8], points[9], points[10], points[11],
+ row3[0], row3[1], row3[2], row3[3], row3[4], row3[5], row3[6], row3[7]);
+ subDivideBezierCurve
+ (points[12], points[13], points[14], points[15],
+ row4[0], row4[1], row4[2], row4[3], row4[4], row4[5], row4[6], row4[7]);
+
+ // Now sub-divide the 8 columns to create the four new patches.
+ subDivideBezierCurve
+ (row1[0], row2[0], row3[0], row4[0],
+ patch1.points[0], patch1.points[4], patch1.points[8], patch1.points[12],
+ patch3.points[0], patch3.points[4], patch3.points[8], patch3.points[12]);
+ subDivideBezierCurve
+ (row1[1], row2[1], row3[1], row4[1],
+ patch1.points[1], patch1.points[5], patch1.points[9], patch1.points[13],
+ patch3.points[1], patch3.points[5], patch3.points[9], patch3.points[13]);
+ subDivideBezierCurve
+ (row1[2], row2[2], row3[2], row4[2],
+ patch1.points[2], patch1.points[6], patch1.points[10], patch1.points[14],
+ patch3.points[2], patch3.points[6], patch3.points[10], patch3.points[14]);
+ subDivideBezierCurve
+ (row1[3], row2[3], row3[3], row4[3],
+ patch1.points[3], patch1.points[7], patch1.points[11], patch1.points[15],
+ patch3.points[3], patch3.points[7], patch3.points[11], patch3.points[15]);
+ subDivideBezierCurve
+ (row1[4], row2[4], row3[4], row4[4],
+ patch2.points[0], patch2.points[4], patch2.points[8], patch2.points[12],
+ patch4.points[0], patch4.points[4], patch4.points[8], patch4.points[12]);
+ subDivideBezierCurve
+ (row1[5], row2[5], row3[5], row4[5],
+ patch2.points[1], patch2.points[5], patch2.points[9], patch2.points[13],
+ patch4.points[1], patch4.points[5], patch4.points[9], patch4.points[13]);
+ subDivideBezierCurve
+ (row1[6], row2[6], row3[6], row4[6],
+ patch2.points[2], patch2.points[6], patch2.points[10], patch2.points[14],
+ patch4.points[2], patch4.points[6], patch4.points[10], patch4.points[14]);
+ subDivideBezierCurve
+ (row1[7], row2[7], row3[7], row4[7],
+ patch2.points[3], patch2.points[7], patch2.points[11], patch2.points[15],
+ patch4.points[3], patch4.points[7], patch4.points[11], patch4.points[15]);
+}
+
+void QGLBezierPatch::createNewCorners
+ (QGLBezierPatch &patch1, QGLBezierPatch &patch2,
+ QGLBezierPatch &patch3, QGLBezierPatch &patch4,
+ QGeometryData *prim,
+ qreal xtex, qreal ytex, qreal wtex, qreal htex)
+{
+ // Add vertices for the new patch corners we have created.
+ qreal hwtex = wtex / 2.0f;
+ qreal hhtex = htex / 2.0f;
+ int topPointIndex = prim->count();
+ int leftPointIndex = topPointIndex + 1;
+ int midPointIndex = topPointIndex + 2;
+ int rightPointIndex = topPointIndex + 3;
+ int bottomPointIndex = topPointIndex + 4;
+
+ prim->appendVertex(patch1.points[3]);
+ prim->appendNormal(normal(0.5f, 0.0f));
+ prim->appendTexCoord(QVector2D(xtex + hwtex, ytex));
+
+ prim->appendVertex(patch1.points[12]);
+ prim->appendNormal(normal(0.0f, 0.5f));
+ prim->appendTexCoord(QVector2D(xtex, ytex + hhtex));
+
+ prim->appendVertex(patch1.points[15]);
+ prim->appendNormal(normal(0.5f, 0.5f));
+ prim->appendTexCoord(QVector2D(xtex + hwtex, ytex + hhtex));
+
+ prim->appendVertex(patch2.points[15]);
+ prim->appendNormal(normal(1.0f, 0.5f));
+ prim->appendTexCoord(QVector2D(xtex + wtex, ytex + hhtex));
+
+ prim->appendVertex(patch3.points[15]);
+ prim->appendNormal(normal(0.5f, 1.0f));
+ prim->appendTexCoord(QVector2D(xtex + hwtex, ytex + htex));
+
+ // Copy the indices for the corners of the new patches.
+ patch1.indices[0] = indices[0];
+ patch1.indices[1] = topPointIndex;
+ patch1.indices[2] = leftPointIndex;
+ patch1.indices[3] = midPointIndex;
+ patch2.indices[0] = topPointIndex;
+ patch2.indices[1] = indices[1];
+ patch2.indices[2] = midPointIndex;
+ patch2.indices[3] = rightPointIndex;
+ patch3.indices[0] = leftPointIndex;
+ patch3.indices[1] = midPointIndex;
+ patch3.indices[2] = indices[2];
+ patch3.indices[3] = bottomPointIndex;
+ patch4.indices[0] = midPointIndex;
+ patch4.indices[1] = rightPointIndex;
+ patch4.indices[2] = bottomPointIndex;
+ patch4.indices[3] = indices[3];
+}
+
+// Recursively sub-divide a patch into triangles.
+void QGLBezierPatch::recursiveSubDivide
+ (QGeometryData *prim,
+ int depth, qreal xtex, qreal ytex, qreal wtex, qreal htex)
+{
+ if (depth <= 1) {
+ convertToTriangles(prim, xtex, ytex, wtex, htex);
+ } else {
+ QGLBezierPatch patch1, patch2, patch3, patch4;
+ subDivide(patch1, patch2, patch3, patch4);
+ createNewCorners(patch1, patch2, patch3, patch4, prim, xtex, ytex, wtex, htex);
+ --depth;
+ qreal hwtex = wtex / 2.0f;
+ qreal hhtex = htex / 2.0f;
+ patch1.recursiveSubDivide(prim, depth, xtex, ytex, hwtex, hhtex);
+ patch2.recursiveSubDivide(prim, depth, xtex + hwtex, ytex, hwtex, hhtex);
+ patch3.recursiveSubDivide(prim, depth, xtex, ytex + hhtex, hwtex, hhtex);
+ patch4.recursiveSubDivide(prim, depth, xtex + hwtex, ytex + hhtex, hwtex, hhtex);
+ }
+}
+
+void QGLBezierPatchesPrivate::subdivide(QGLBuilder *list) const
+{
+ QGeometryData prim;
+ int count = positions.size();
+ for (int posn = 0; (posn + 15) < count; posn += 16) {
+ // Construct a QGLBezierPatch object from the next high-level patch.
+ QGLBezierPatch patch;
+ int vertex;
+ for (int vertex = 0; vertex < 16; ++vertex)
+ patch.points[vertex] = positions[posn + vertex];
+ QVector2D tex1, tex2;
+ if (!textureCoords.isEmpty()) {
+ tex1 = textureCoords[(posn / 16) * 2];
+ tex2 = textureCoords[(posn / 16) * 2 + 1];
+ } else {
+ tex1 = QVector2D(0.0f, 0.0f);
+ tex2 = QVector2D(1.0f, 1.0f);
+ }
+ qreal xtex = tex1.x();
+ qreal ytex = tex1.y();
+ qreal wtex = tex2.x() - xtex;
+ qreal htex = tex2.y() - ytex;
+ for (int corner = 0; corner < 4; ++corner) {
+ vertex = posn + cornerOffsets[corner];
+ QVector3D n = patch.normal(cornerS[corner], cornerT[corner]);
+ patch.indices[corner] = prim.count();
+ prim.appendVertex(patch.points[cornerOffsets[corner]]);
+ prim.appendNormal(n);
+ prim.appendTexCoord
+ (QVector2D(xtex + wtex * cornerS[corner],
+ ytex + htex * cornerT[corner]));
+ }
+
+ // Subdivide the patch and generate the final triangles.
+ patch.recursiveSubDivide(&prim, subdivisionDepth,
+ xtex, ytex, wtex, htex);
+ }
+ list->addTriangles(prim);
+}
+
+static inline qreal combineResults(qreal result, qreal t)
+{
+ if (qIsNaN(result))
+ return t;
+ if (t >= 0.0f)
+ return result < 0.0f ? t : qMin(result, t);
+ else
+ return result >= 0.0f ? result : qMax(result, t);
+}
+
+qreal QGLBezierPatch::intersection
+ (qreal result, int depth, const QRay3D& ray, bool anyIntersection,
+ qreal xtex, qreal ytex, qreal wtex, qreal htex, QVector2D *tc)
+{
+ // Check the convex hull of the patch for an intersection.
+ // If no intersection with the convex hull, then there is
+ // no point subdividing this patch further.
+ QBox3D box;
+ for (int point = 0; point < 16; ++point)
+ box.unite(points[point]);
+ if (!box.intersects(ray))
+ return result;
+
+ // Are we at the lowest point of subdivision yet?
+ if (depth <= 1) {
+ // Divide the patch into two triangles and intersect with those.
+ QTriangle3D triangle1(points[0], points[3], points[12]);
+ qreal t = triangle1.intersection(ray);
+ if (!qIsNaN(t)) {
+ result = combineResults(result, t);
+ if (result == t) {
+ QVector2D uv = triangle1.uv(ray.point(t));
+ QVector2D tp(xtex, ytex);
+ QVector2D tq(xtex + wtex, ytex);
+ QVector2D tr(xtex, ytex + htex);
+ *tc = uv.x() * tp + uv.y() * tq + (1 - uv.x() - uv.y()) * tr;
+ }
+ } else {
+ QTriangle3D triangle2(points[3], points[15], points[12]);
+ qreal t = triangle2.intersection(ray);
+ if (!qIsNaN(t)) {
+ result = combineResults(result, t);
+ if (result == t) {
+ QVector2D uv = triangle2.uv(ray.point(t));
+ QVector2D tp(xtex + wtex, ytex);
+ QVector2D tq(xtex + wtex, ytex + htex);
+ QVector2D tr(xtex, ytex + htex);
+ *tc = uv.x() * tp + uv.y() * tq + (1 - uv.x() - uv.y()) * tr;
+ }
+ }
+ }
+ } else {
+ // Subdivide the patch to find the point of intersection.
+ QGLBezierPatch patch1, patch2, patch3, patch4;
+ subDivide(patch1, patch2, patch3, patch4);
+ --depth;
+ qreal hwtex = wtex / 2.0f;
+ qreal hhtex = htex / 2.0f;
+ result = patch1.intersection
+ (result, depth, ray, anyIntersection,
+ xtex, ytex, hwtex, hhtex, tc);
+ if (anyIntersection && !qIsNaN(result))
+ return result;
+ result = patch2.intersection
+ (result, depth, ray, anyIntersection,
+ xtex + hwtex, ytex, hwtex, hhtex, tc);
+ if (anyIntersection && !qIsNaN(result))
+ return result;
+ result = patch3.intersection
+ (result, depth, ray, anyIntersection,
+ xtex, ytex + hhtex, hwtex, hhtex, tc);
+ if (anyIntersection && !qIsNaN(result))
+ return result;
+ result = patch4.intersection
+ (result, depth, ray, anyIntersection,
+ xtex + hwtex, ytex + hhtex, hwtex, hhtex, tc);
+ }
+ return result;
+}
+
+qreal QGLBezierPatchesPrivate::intersection
+ (const QRay3D &ray, bool anyIntersection, QVector2D *texCoord, int *bestPatch) const
+{
+ int count = positions.size();
+ qreal result = qSNaN();
+ QVector2D tc;
+ if (bestPatch)
+ *bestPatch = -1;
+ for (int posn = 0; (posn + 15) < count; posn += 16) {
+ QGLBezierPatch patch;
+ for (int vertex = 0; vertex < 16; ++vertex)
+ patch.points[vertex] = positions[posn + vertex];
+ QVector2D tex1, tex2;
+ if (!textureCoords.isEmpty()) {
+ tex1 = textureCoords[(posn / 16) * 2];
+ tex2 = textureCoords[(posn / 16) * 2 + 1];
+ } else {
+ tex1 = QVector2D(0.0f, 0.0f);
+ tex2 = QVector2D(1.0f, 1.0f);
+ }
+ qreal xtex = tex1.x();
+ qreal ytex = tex1.y();
+ qreal wtex = tex2.x() - xtex;
+ qreal htex = tex2.y() - ytex;
+ qreal prev = result;
+ result = patch.intersection
+ (result, subdivisionDepth, ray, anyIntersection,
+ xtex, ytex, wtex, htex, &tc);
+ if (bestPatch && result != prev)
+ *bestPatch = posn / 16;
+ if (anyIntersection && !qIsNaN(result))
+ break;
+ }
+ if (texCoord && !qIsNaN(result))
+ *texCoord = tc;
+ return result;
+}
+
+/*!
+ Constructs an empty Bezier patch list.
+
+ \sa setPositions()
+*/
+QGLBezierPatches::QGLBezierPatches()
+ : d_ptr(new QGLBezierPatchesPrivate())
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+
+ \sa operator=()
+*/
+QGLBezierPatches::QGLBezierPatches(const QGLBezierPatches &other)
+ : d_ptr(new QGLBezierPatchesPrivate(other.d_ptr.data()))
+{
+}
+
+/*!
+ Destroys this Bezier patch list.
+*/
+QGLBezierPatches::~QGLBezierPatches()
+{
+}
+
+/*!
+ Assigns \a other to this Bezier patch list.
+*/
+QGLBezierPatches &QGLBezierPatches::operator=
+ (const QGLBezierPatches &other)
+{
+ if (this != &other)
+ d_ptr->copy(other.d_ptr.data());
+ return *this;
+}
+
+/*!
+ Returns the positions of the vertices in the Bezier patches.
+
+ \sa setPositions(), textureCoords()
+*/
+QVector3DArray QGLBezierPatches::positions() const
+{
+ Q_D(const QGLBezierPatches);
+ return d->positions;
+}
+
+/*!
+ Sets the \a positions of the vertices in the Bezier patches.
+
+ \sa positions(), setTextureCoords()
+*/
+void QGLBezierPatches::setPositions(const QVector3DArray &positions)
+{
+ Q_D(QGLBezierPatches);
+ d->positions = positions;
+}
+
+/*!
+ Returns the texture co-ordinates for the Bezier patches.
+ Each patch consumes two elements from the texture
+ co-ordinate array, defining the opposite corners.
+
+ The default is an empty array, which indicates that each
+ patch will generate texture co-ordinates in the range
+ (0, 0) to (1, 1).
+
+ \sa setTextureCoords(), positions()
+*/
+QVector2DArray QGLBezierPatches::textureCoords() const
+{
+ Q_D(const QGLBezierPatches);
+ return d->textureCoords;
+}
+
+/*!
+ Sets the texture co-ordinates for the Bezier patches to
+ the elements of \a textureCoords. Each patch consumes
+ two elements from \a textureCoords, defining the opposite
+ corners.
+
+ If \a textureCoords is empty, then each patch will generate
+ texture co-ordinates in the range (0, 0) to (1, 1).
+
+ \sa textureCoords(), setPositions()
+*/
+void QGLBezierPatches::setTextureCoords(const QVector2DArray &textureCoords)
+{
+ Q_D(QGLBezierPatches);
+ d->textureCoords = textureCoords;
+}
+
+/*!
+ Returns the depth of subdivision to use when converting the
+ Bezier geometry into triangles. The default value is 4.
+
+ \sa setSubdivisionDepth()
+*/
+int QGLBezierPatches::subdivisionDepth() const
+{
+ Q_D(const QGLBezierPatches);
+ return d->subdivisionDepth;
+}
+
+/*!
+ Sets the depth of subdivision to use when converting the
+ Bezier geometry into triangles to \a value.
+
+ \sa subdivisionDepth()
+*/
+void QGLBezierPatches::setSubdivisionDepth(int value)
+{
+ Q_D(QGLBezierPatches);
+ d->subdivisionDepth = value;
+}
+
+/*!
+ Transforms the positions() in this Bezier geometry object
+ according to \a matrix.
+
+ \sa transformed()
+*/
+void QGLBezierPatches::transform(const QMatrix4x4 &matrix)
+{
+ Q_D(QGLBezierPatches);
+ d->positions.transform(matrix);
+}
+
+/*!
+ Returns a new Bezier geometry object that results from transforming
+ this object's positions() according to \a matrix.
+
+ \sa transform()
+*/
+QGLBezierPatches QGLBezierPatches::transformed(const QMatrix4x4 &matrix) const
+{
+ QGLBezierPatches result(*this);
+ result.d_ptr->positions.transform(matrix);
+ return result;
+}
+
+/*!
+ Returns true if \a ray intersects this Bezier geometry object;
+ false otherwise.
+
+ \sa intersection()
+*/
+bool QGLBezierPatches::intersects(const QRay3D &ray) const
+{
+ Q_D(const QGLBezierPatches);
+ return !qIsNaN(d->intersection(ray, true, 0, 0));
+}
+
+/*!
+ Returns the t value at which \a ray intersects this Bezier
+ geometry object, or not-a-number if there is no intersection.
+
+ When the \a ray intersects this object, the return value is a
+ parametric value that can be passed to QRay3D::point() to determine
+ the actual intersection point, as shown in the following example:
+
+ \code
+ qreal t = patches.intersection(ray);
+ QVector3D pt;
+ if (qIsNaN(t)) {
+ qWarning("no intersection occurred");
+ else
+ pt = ray.point(t);
+ \endcode
+
+ If \a ray intersects the object multiple times, the returned
+ t will be the smallest t value, corresponding to the first
+ intersection of the \a ray with the object. The t value may
+ be negative if the first intersection occurs in the reverse
+ direction of \a ray.
+
+ The intersection is determined by subdividing the patches into
+ triangles and intersecting with those triangles. A pruning
+ algorithm is used to discard patches whose convex hull do not
+ intersect with \a ray.
+
+ If \a texCoord is not null, then it will return the texture
+ co-ordinate of the intersection point.
+
+ If \a patch is not null, then it will return the index of the
+ patch that contains the intersection, or -1 if there is no
+ intersection.
+
+ \sa intersects()
+*/
+qreal QGLBezierPatches::intersection(const QRay3D &ray, QVector2D *texCoord, int *patch) const
+{
+ Q_D(const QGLBezierPatches);
+ return d->intersection(ray, false, texCoord, patch);
+}
+
+/*!
+ \relates QGLBezierPatches
+
+ Subdivides the Bezier patch data in \a patches into triangles
+ and adds them to the specified display \a list.
+*/
+QGLBuilder &operator<<(QGLBuilder &list, const QGLBezierPatches &patches)
+{
+ patches.d_ptr->subdivide(&list);
+ return list;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/geometry/qglbezierpatches.h b/src/threed/geometry/qglbezierpatches.h
new file mode 100644
index 000000000..3bab8f5ff
--- /dev/null
+++ b/src/threed/geometry/qglbezierpatches.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLBEZIERPATCHES_H
+#define QGLBEZIERPATCHES_H
+
+#include "qvector2darray.h"
+#include "qvector3darray.h"
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLBezierPatchesPrivate;
+class QGLBuilder;
+class QRay3D;
+
+class Q_QT3D_EXPORT QGLBezierPatches
+{
+public:
+ QGLBezierPatches();
+ QGLBezierPatches(const QGLBezierPatches &other);
+ virtual ~QGLBezierPatches();
+
+ QGLBezierPatches &operator=(const QGLBezierPatches &other);
+
+ QVector3DArray positions() const;
+ void setPositions(const QVector3DArray &positions);
+
+ QVector2DArray textureCoords() const;
+ void setTextureCoords(const QVector2DArray &textureCoords);
+
+ int subdivisionDepth() const;
+ void setSubdivisionDepth(int value);
+
+ void transform(const QMatrix4x4 &matrix);
+ QGLBezierPatches transformed(const QMatrix4x4 &matrix) const;
+
+ bool intersects(const QRay3D &ray) const;
+ qreal intersection(const QRay3D &ray, QVector2D *texCoord = 0, int *patch = 0) const;
+
+private:
+ QScopedPointer<QGLBezierPatchesPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLBezierPatches)
+
+ friend Q_QT3D_EXPORT QGLBuilder &operator<<(QGLBuilder &list, const QGLBezierPatches &patches);
+};
+
+Q_QT3D_EXPORT QGLBuilder &operator<<(QGLBuilder &list, const QGLBezierPatches &patches);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/geometry/qglbuilder.cpp b/src/threed/geometry/qglbuilder.cpp
new file mode 100644
index 000000000..d3be13899
--- /dev/null
+++ b/src/threed/geometry/qglbuilder.cpp
@@ -0,0 +1,1378 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglbuilder.h"
+#include "qglbuilder_p.h"
+#include "qglsection_p.h"
+#include "qglmaterialcollection.h"
+#include "qglpainter.h"
+#include "qgeometrydata.h"
+#include "qvector_utils_p.h"
+
+#include <QtGui/qvector2d.h>
+
+#include <QtCore/qdebug.h>
+
+/*!
+ \class QGLBuilder
+ \brief The QGLBuilder class constructs geometry for efficient display.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ \tableofcontents
+
+ Use a QGLBuilder to build up vertex, index, texture and other data
+ during application initialization. The finalizedSceneNode() function
+ returns an optimized scene which can be efficiently and flexibly
+ displayed during frames of rendering. It is suited to writing loaders
+ for 3D models, and for programatically creating geometry.
+
+ \section1 Geometry Building
+
+ QGLBuilder makes the job of getting triangles on the GPU simple. It
+ calculates indices and normals for you, then uploads the data. While
+ it has addQuads() and other functions to deal with quads, all data is
+ represented as triangles for portability.
+
+ The simplest way to use QGLBuilder is to send a set of geometry
+ values to it using QGeometryData in the constructor:
+
+ \code
+ MyView::MyView() : QGLView()
+ {
+ // in the constructor construct a builder on the stack
+ QGLBuilder builder;
+ QGeometryData triangle;
+ QVector3D a(2, 2, 0);
+ QVector3D b(-2, 2, 0);
+ QVector3D c(0, -2, 0);
+ triangle.appendVertex(a, b, c);
+
+ // When adding geometry, QGLBuilder automatically creates lighting normals
+ builder << triangle;
+
+ // obtain the scene from the builder
+ m_scene = builder.finalizedSceneNode();
+
+ // apply effects at app initialization time
+ QGLMaterial *mat = new QGLMaterial;
+ mat->setDiffuseColor(Qt::red);
+ m_scene->setMaterial(mat);
+ }
+ \endcode
+
+ Then during rendering the scene is used to display the results:
+ \code
+ MyView::paintGL(QGLPainter *painter)
+ {
+ m_scene->draw(painter);
+ }
+ \endcode
+
+ QGLBuilder automatically generates index values and normals
+ on-the-fly during geometry building. During building, simply send
+ primitives to the builder as a sequence of vertices, and
+ vertices that are the same will be referenced by a single index
+ automatically.
+
+ Primitives will have standard normals generated automatically
+ based on vertex winding.
+
+ Consider the following code for OpenGL to draw a quad with corner
+ points A, B, C and D :
+
+ \code
+ float vertices[12] =
+ {
+ -1.0, -1.0, -1.0, // A
+ 1.0, -1.0, -1.0, // B
+ 1.0, 1.0, 1.0, // C
+ -1.0, 1.0, 1.0 // D
+ };
+ float normals[12] = { 0.0f };
+ for (int i = 0; i < 12; i += 3)
+ {
+ normals[i] = 0.0;
+ normals[i+1] = -sqrt(2.0);
+ normals[i+2] = sqrt(2.0);
+ }
+ GLuint indices[6] = {
+ 0, 1, 2, // triangle A-B-C
+ 0, 2, 3 // triangle A-C-D
+ };
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vertices);
+ glNormalPointer(3, GL_FLOAT, 0, normals);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, indices);
+ \endcode
+
+ With QGLBuilder this code becomes:
+
+ \code
+ float vertices[12] =
+ {
+ -1.0, -1.0, -1.0, // A
+ 1.0, -1.0, -1.0, // B
+ 1.0, 1.0, 1.0, // C
+ -1.0, 1.0, 1.0 // D
+ };
+ QGLBuilder quad;
+ QGeometryData data;
+ data.appendVertexArray(QArray<QVector3D>::fromRawData(
+ reinterpret_cast<const QVector3D*>(vertices), 4));
+ quad.addQuads(data);
+ \endcode
+
+ The data primitive is added to the list, as two triangles, indexed to
+ removed the redundant double storage of B & C - just the same as the
+ OpenGL code.
+
+ QGLBuilder will also calculate a normal for the quad and apply it
+ to the vertices.
+
+ In this trivial example the indices are easily calculated, however
+ in more complex geometry it is easy to introduce bugs by trying
+ to manually control indices. Extra work is required to generate,
+ track and store the index values correctly.
+
+ Bugs such as trying to index two vertices with different data -
+ one with texture data and one without - into one triangle can
+ easily result. The picture becomes more difficult when smoothing
+ groups are introduced - see below.
+
+ Using indices is always preferred since it saves space on the GPU,
+ and makes the geometry perform faster during application run time.
+
+ \section2 Removing Epsilon Errors
+
+ Where vertices are generated by modelling packages or tools, or
+ during computation in code, very frequently rounding errors will
+ result in several vertices being generated that are actually
+ the same vertex but are separated by tiny amounts. At best these
+ duplications waste space on the GPU but at worst can introduce
+ visual artifacts that mar the image displayed.
+
+ Closing paths, generating solids of rotation, or moving model
+ sections out and back can all introduce these types of epsilon
+ errors, resulting in "cracks" or artifacts on display.
+
+ QGLBuilder's index generation process uses a fuzzy match that
+ coalesces all vertex values at a point - even if they are out by
+ a tiny amount - and references them with a single index.
+
+ \section2 Lighting Normals and Null Triangles
+
+ QGLBuilder functions calculate lighting normals, when building
+ geometry. This saves the application programmer from having to write
+ code to calculate them. Normals for each triangle (a, b, c) are
+ calculated as the QVector3D::normal(a, b, c).
+
+ If lighting normals are explicitly supplied when using QGLBuilder,
+ then this calculation is not done. This may save on build time.
+
+ As an optimization, QGLBuilder skips null triangles, that is ones
+ with zero area, where it can. Such triangles generate no fragments on
+ the GPU, and thus do not display but nonetheless can take up space
+ and processing power.
+
+ Null triangles can easily occur when calculating vertices results
+ in two vertices coinciding, or three vertices lying on the same line.
+
+ This skipping is done using the lighting normals cross-product. If the
+ cross-product is a null vector then the triangle is null.
+
+ When lighting normals are specified explicitly the skipping
+ optimization is suppressed, so if for some reason null triangles are
+ required to be retained, then specify normals for each logical vertex.
+
+ See the documentation below of the individual addTriangle() and other
+ functions for more details.
+
+ \section2 Raw Triangle Mode
+
+ Where generation of indices and normals is not needed - for example if
+ porting an existing application, it is possible to do a raw import of
+ triangle data, without using any of QGLBuilder's processing.
+
+ To do this ensure that indices are placed in the QGeometryData passed to
+ the addTriangles() function, and this will trigger \bold{raw triangle} mode.
+
+ When adding triangles in this way ensure that all appropriate values
+ have been correctly set, and that the normals, indices and other data
+ are correctly calculated, since no checking is done.
+
+ When writing new applications, simply leave construction of normals and
+ indices to the QGLBuilder
+
+ \section1 Rendering and QGLSceneNode items.
+
+ QGLSceneNodes are used to manage application of local transformations,
+ materials and effects.
+
+ QGLBuilder generates a root level QGLSceneNode, which can be accessed
+ with the sceneNode() function. Under this a new node is created for
+ each section of geometry, and also by using pushNode() and popNode().
+
+ To organize geometry for painting with different materials and effects
+ call the newNode() function:
+
+ \code
+ QGLSceneNode *box = builder.newNode();
+ box->setMaterial(wood);
+ \endcode
+
+ Many nodes may be created this way, but they will be optimized into
+ a small number of buffers under the one scene when the
+ finalizedSceneNode() function is called.
+
+ \image soup.png
+
+ Here the front can is a set of built geometry and the other two are
+ scene nodes that reference it, without copying any geometry.
+
+ \snippet builder/builder.cpp 0
+
+ QGLSceneNodes can be used after the builder is created to cheaply
+ copy and redisplay the whole scene. Or to reference parts of the geometry
+ use the functions newNode() or pushNode() and popNode() to manage
+ QGLSceneNode generation while building geometry.
+
+ To draw the resulting built geometry simply call the draw method of the
+ build geometry.
+
+ \snippet builder/builder.cpp 1
+
+ Call the \l{QGLSceneNode::palette()}{palette()} function on the sceneNode()
+ to get the QGLMaterialCollection for the node, and place textures
+ and materials into it.
+
+ Built geometry will typically share the one palette. Either create a
+ palette, and pass it to the \l{QGLBuilder::QGLBuilder()}{constructor};
+ or pass no arguments to the constructor and the QGLBuilder
+ will create a palette:
+
+ \snippet builder/builder.cpp 2
+
+ These may then be applied as needed throughout the building of the
+ geometry using the integer reference, \c{canMat} in the above code.
+
+ See the QGLSceneNode documentation for more.
+
+ \section1 Using Sections
+
+ During initialization of the QGLBuilder, while accumulating
+ geometry, the geometry data in a QGLBuilder is placed into
+ sections - there must be at least one section.
+
+ Call the newSection() function to create a new section:
+
+ \snippet builder/builder.cpp 3
+
+ Here separate sections for the rounded outside cylinder and flat top and
+ bottom of the soup can model makes for the appearance of a sharp edge
+ between them. If the sides and top and bottom were in the same section
+ QGLBuilder would attempt to average the normals around the edge resulting
+ in an unrealistic effect.
+
+ In 3D applications this concept is referred to as
+ \l{http://www.google.com/search?smoothing+groups}{smoothing groups}. Within
+ a section (smoothing group) all normals are averaged making it appear
+ as one smoothly shaded surface.
+
+ The can has 3 smoothing groups - bottom, top and sides.
+
+ This mesh of a Q is a faceted model - it has 0 smoothing groups:
+
+ \image faceted-q.png
+
+ To create geometry with a faceted appearance call newSection() with
+ an argument of QGL::Faceted thus \c{newSection(QGL::Faceted)}.
+
+ Faceted geometry is suitable for small models, where hard edges are
+ desired between every face - a dice, gem or geometric solid for example.
+
+ If no section has been created when geometry is added a new section is
+ created automatically. This section will have its smoothing set
+ to QGL::Smooth.
+
+ To create a faceted appearance rather than accepting the automatically
+ created section the << operator can also be used:
+
+ \code
+ QGLBuilder builder;
+ QGeometryData triangles;
+ triangles.appendVertices(a, b, c);
+ builder << QGL::Faceted << triangles;
+ \endcode
+
+ \section2 Geometry Data in a Section
+
+ Management of normals and vertices for smoothing, and other data is
+ handled automatically by the QGLBuilder instance.
+
+ Within a section, incoming geometry data will be coalesced and
+ indices created to reference the fewest possible copies of the vertex
+ data. For example, in smooth geometry all copies of a vertex are
+ coalesced into one, and referenced by indices.
+
+ One of the few exceptions to this is the case where texture data forms
+ a \i seam and a copy of a vertex must be created to carry the two
+ texture coordinates either side of the seam.
+
+ \image texture-seam.png
+
+ Coalescing has the effect of packing geometry data into the
+ smallest space possible thus improving cache coherence and performance.
+
+ Again all this is managed automatically by QGLBuilder and all
+ that is required is to create smooth or faceted sections, and add
+ geometry to them.
+
+ Each QGLSection references a contiguous range of vertices in a
+ QGLBuilder.
+
+ \section1 Finalizing and Retrieving the Scene
+
+ Once the geometry has been accumulated in the QGLBuilder instance, the
+ finalizedSceneNode() method must be called to retrieve the optimized
+ scene. This function serves to normalize the geometry and optimize
+ it for display.
+
+ While it may be convenient to get pointers to sub nodes in the scene
+ during construction, it is important to retrieve the root of the scene
+ so that the memory consumed by the scene can be recovered. The builder
+ will create a QGLMaterialCollection; and there may be geometry, materials
+ and other resources: these are all parented onto the root scene node.
+ These can easily be recovered by deleting the root scene node:
+
+ \code
+ MyView::MyView() : QGLView()
+ {
+ // in the constructor construct a builder on the stack
+ QGLBuilder builder;
+
+ // add geometry as shown above
+ builder << triangles;
+
+ // obtain the scene from the builder & take ownership
+ m_scene = builder.finalizedSceneNode();
+ }
+
+ MyView::~MyView()
+ {
+ // recover all scene resources
+ delete m_scene;
+ }
+ \endcode
+
+ Alternatively set the scene's parent to ensure resource recovery
+ \c{m_scene->setParent(this)}.
+
+
+*/
+
+QGLBuilderPrivate::QGLBuilderPrivate(QGLBuilder *parent)
+ : currentSection(0)
+ , currentNode(0)
+ , rootNode(0)
+ , defThreshold(5)
+ , q(parent)
+{
+}
+
+QGLBuilderPrivate::~QGLBuilderPrivate()
+{
+ qDeleteAll(sections);
+ if (rootNode)
+ {
+ qWarning("Destroying QGLBuilder but finalizedSceneNode() not called");
+ delete rootNode;
+ }
+}
+
+/*!
+ Construct a new QGLBuilder using \a materials for the palette. If the
+ \a materials argument is null, then a new palette is created.
+*/
+QGLBuilder::QGLBuilder(QGLMaterialCollection *materials)
+ : dptr(new QGLBuilderPrivate(this))
+{
+ dptr->rootNode = new QGLSceneNode;
+ if (!materials)
+ materials = new QGLMaterialCollection(dptr->rootNode);
+ dptr->rootNode->setPalette(materials);
+}
+
+/*!
+ Destroys this QGLBuilder recovering any resources.
+*/
+QGLBuilder::~QGLBuilder()
+{
+ delete dptr;
+}
+
+/*!
+ Helper function to calculate the normal for and set it on vertices
+ in \a i, \a j and \a k in triangle data \a p. If the triangle in
+ data \a p is a null triangle (area == 0) then the function returns
+ false, otherwise it returns true.
+*/
+static inline void setNormals(int i, int j, int k, QGeometryData &p, const QVector3D &n)
+{
+ p.normal(i) = n;
+ p.normal(j) = n;
+ p.normal(k) = n;
+}
+
+static bool qCalculateNormal(int i, int j, int k, QGeometryData &p, QVector3D *vec = 0)
+{
+ QVector3D norm;
+ QVector3D *n = &norm;
+ if (vec)
+ n = vec;
+ bool nullTriangle = false;
+ *n = QVector3D::crossProduct(p.vertexAt(j) - p.vertexAt(i),
+ p.vertexAt(k) - p.vertexAt(j));
+ if (qFskIsNull(n->x()))
+ n->setX(0.0f);
+ if (qFskIsNull(n->y()))
+ n->setY(0.0f);
+ if (qFskIsNull(n->z()))
+ n->setZ(0.0f);
+ if (n->isNull())
+ {
+ nullTriangle = true;
+ }
+ else
+ {
+ setNormals(i, j, k, p, *n);
+ }
+ return nullTriangle;
+}
+
+/*!
+ \internal
+ Helper function to actually add the vertices to geometry.
+*/
+void QGLBuilderPrivate::addTriangle(int i, int j, int k,
+ const QGeometryData &p, int &count)
+{
+ if (currentSection == 0)
+ q->newSection();
+ QLogicalVertex a(p, i);
+ QLogicalVertex b(p, j);
+ QLogicalVertex c(p, k);
+ currentSection->append(a, b, c);
+ count += 3;
+}
+
+/*!
+ Add \a triangles - a series of one or more triangles - to this builder.
+
+ The data is broken into groups of 3 vertices, each processed as a triangle.
+
+ If \a triangles has less than 3 vertices this function exits without
+ doing anything. Any vertices at the end of the list under a multiple
+ of 3 are ignored.
+
+ If no normals are supplied in \a triangles, a normal is calculated; as
+ the cross-product \c{(b - a) x (c - a)}, for each group of 3
+ logical vertices \c{a(triangle, i), b(triangle, i+1), c(triangle, i+2)}.
+
+ In the case of a degenerate triangle, where the cross-product is null,
+ that triangle is skipped. Supplying normals suppresses this behaviour
+ (and means any degenerate triangles will be added to the geometry).
+
+ \bold{Raw Triangle Mode}
+
+ If \a triangles has indices specified then no processing of any kind is
+ done and all the geometry is simply dumped in to the builder.
+
+ This \bold{raw triangle} mode is for advanced use, and it is assumed that
+ the user knows what they are doing, in particular that the indices
+ supplied are correct, and normals are supplied and correct.
+
+ Normals are not calculated in raw triangle mode, and skipping of null
+ triangles is likewise not performed. See the section on
+ \l{raw-triangle-mode}{raw triangle mode}
+ in the class documentation above.
+
+ \sa addQuads(), operator>>()
+*/
+void QGLBuilder::addTriangles(const QGeometryData &triangles)
+{
+ if (triangles.count() < 3)
+ return;
+ if (triangles.indexCount() > 0)
+ {
+ // raw triangle mode
+ if (dptr->currentSection == 0)
+ newSection();
+ dptr->currentSection->appendGeometry(triangles);
+ dptr->currentSection->appendIndices(triangles.indices());
+ dptr->currentNode->setCount(dptr->currentNode->count() + triangles.indexCount());
+ }
+ else
+ {
+ QGeometryData t = triangles;
+ bool calcNormal = !t.hasField(QGL::Normal);
+ if (calcNormal)
+ {
+ QVector3DArray nm(t.count());
+ t.appendNormalArray(nm);
+ }
+ bool skip = false;
+ int k = 0;
+ for (int i = 0; i < t.count() - 2; i += 3)
+ {
+ if (calcNormal)
+ skip = qCalculateNormal(i, i+1, i+2, t);
+ if (!skip)
+ dptr->addTriangle(i, i+1, i+2, t, k);
+ }
+ dptr->currentNode->setCount(dptr->currentNode->count() + k);
+ }
+}
+
+/*!
+ Add \a quads - a series of one or more quads - to this builder.
+
+ If \a quads has less than four vertices this function exits without
+ doing anything.
+
+ One normal per quad is calculated if \a quads does not have normals.
+ For this reason quads should have all four vertices in the same plane.
+ If the vertices do not lie in the same plane, use addTriangleStrip()
+ to add two adjacent triangles instead.
+
+ Since internally \l{geometry-building}{quads are stored as two triangles},
+ each quad is actually divided in half into two triangles.
+
+ Degenerate triangles are skipped in the same way as addTriangles().
+
+ \sa addTriangles(), addTriangleStrip()
+*/
+void QGLBuilder::addQuads(const QGeometryData &quads)
+{
+ if (quads.count() < 4)
+ return;
+ QGeometryData q = quads;
+ bool calcNormal = !q.hasField(QGL::Normal);
+ if (calcNormal)
+ {
+ QVector3DArray nm(q.count());
+ q.appendNormalArray(nm);
+ }
+ bool skip = false;
+ int k = 0;
+ QVector3D norm;
+ for (int i = 0; i < q.count(); i += 4)
+ {
+ if (calcNormal)
+ skip = qCalculateNormal(i, i+1, i+2, q, &norm);
+ if (!skip)
+ dptr->addTriangle(i, i+1, i+2, q, k);
+ if (skip)
+ skip = qCalculateNormal(i, i+2, i+3, q, &norm);
+ if (!skip)
+ {
+ if (calcNormal)
+ setNormals(i, i+2, i+3, q, norm);
+ dptr->addTriangle(i, i+2, i+3, q, k);
+ }
+ }
+ dptr->currentNode->setCount(dptr->currentNode->count() + k);
+}
+
+/*!
+ Adds to this section a set of connected triangles defined by \a fan.
+
+ N triangular faces are generated, where \c{N == fan.count() - 2}. Each
+ face contains the 0th vertex in \a fan, followed by the i'th and i+1'th
+ vertex - where i takes on the values from 1 to \c{fan.count() - 1}.
+
+ If \a fan has less than three vertices this function exits without
+ doing anything.
+
+ This function is similar to the OpenGL mode GL_TRIANGLE_FAN. It
+ generates a number of triangles all sharing one common vertex, which
+ is the 0'th vertex of the \a fan.
+
+ Normals are calculated as for addTriangle(), given the above ordering.
+ There is no requirement or assumption that all triangles lie in the
+ same plane. Degenerate triangles are skipped in the same way as
+ addTriangles().
+
+ \sa addTriangulatedFace()
+*/
+void QGLBuilder::addTriangleFan(const QGeometryData &fan)
+{
+ if (fan.count() < 3)
+ return;
+ QGeometryData f = fan;
+ bool calcNormal = !f.hasField(QGL::Normal);
+ if (calcNormal)
+ {
+ QVector3DArray nm(f.count());
+ f.appendNormalArray(nm);
+ }
+ int k = 0;
+ bool skip = false;
+ for (int i = 1; i < f.count() - 1; ++i)
+ {
+ if (calcNormal)
+ skip = qCalculateNormal(0, i, i+1, f);
+ if (!skip)
+ dptr->addTriangle(0, i, i+1, f, k);
+ }
+ dptr->currentNode->setCount(dptr->currentNode->count() + k);
+}
+
+/*!
+ Adds to this section a set of connected triangles defined by \a strip.
+
+ N triangular faces are generated, where \c{N == strip.count() - 2}.
+ The triangles are generated from vertices 0, 1, & 2, then 2, 1 & 3,
+ then 2, 3 & 4, and so on. In other words every second triangle has
+ the first and second vertices switched, as a new triangle is generated
+ from each successive set of three vertices.
+
+ If \a strip has less than three vertices this function exits without
+ doing anything.
+
+ Normals are calculated as for addTriangle(), given the above ordering.
+
+ This function is very similar to the OpenGL mode GL_TRIANGLE_STRIP. It
+ generates triangles along a strip whose two sides are the even and odd
+ vertices.
+
+ \sa addTriangulatedFace()
+*/
+void QGLBuilder::addTriangleStrip(const QGeometryData &strip)
+{
+ if (strip.count() < 3)
+ return;
+ QGeometryData s = strip;
+ bool calcNormal = !s.hasField(QGL::Normal);
+ if (calcNormal)
+ {
+ QVector3DArray nm(s.count());
+ s.appendNormalArray(nm);
+ }
+ bool skip = false;
+ int k = 0;
+ for (int i = 0; i < s.count() - 2; ++i)
+ {
+ if (i % 2)
+ {
+ if (calcNormal)
+ skip = qCalculateNormal(i+1, i, i+2, s);
+ if (!skip)
+ dptr->addTriangle(i+1, i, i+2, s, k);
+ }
+ else
+ {
+ if (calcNormal)
+ skip = qCalculateNormal(i, i+1, i+2, s);
+ if (!skip)
+ dptr->addTriangle(i, i+1, i+2, s, k);
+ }
+ }
+ dptr->currentNode->setCount(dptr->currentNode->count() + k);
+}
+
+/*!
+ Adds to this section a set of quads defined by \a strip.
+
+ If \a strip has less than four vertices this function exits without
+ doing anything.
+
+ The first quad is formed from the 0'th, 2'nd, 3'rd and 1'st vertices.
+ The second quad is formed from the 2'nd, 4'th, 5'th and 3'rd vertices,
+ and so on, as shown in this diagram:
+
+ \image quads.png
+
+ One normal per quad is calculated if \a strip does not have normals.
+ For this reason quads should have all four vertices in the same plane.
+ If the vertices do not lie in the same plane, use addTriangles() instead.
+
+ Since internally \l{geometry-building}{quads are stored as two triangles},
+ each quad is actually divided in half into two triangles.
+
+ Degenerate triangles are skipped in the same way as addTriangles().
+
+ \sa addQuads(), addTriangleStrip()
+*/
+void QGLBuilder::addQuadStrip(const QGeometryData &strip)
+{
+ if (strip.count() < 4)
+ return;
+ QGeometryData s = strip;
+ bool calcNormal = !s.hasField(QGL::Normal);
+ if (calcNormal)
+ {
+ QVector3DArray nm(s.count());
+ s.appendNormalArray(nm);
+ }
+ bool skip = false;
+ QVector3D norm;
+ int k = 0;
+ for (int i = 0; i < s.count() - 3; i += 2)
+ {
+ if (calcNormal)
+ skip = qCalculateNormal(i, i+2, i+3, s, &norm);
+ if (!skip)
+ dptr->addTriangle(i, i+2, i+3, s, k);
+ if (skip)
+ skip = qCalculateNormal(i, i+3, i+1, s, &norm);
+ if (!skip)
+ {
+ if (calcNormal)
+ setNormals(i, i+3, i+1, s, norm);
+ dptr->addTriangle(i, i+3, i+1, s, k);
+ }
+ }
+ dptr->currentNode->setCount(dptr->currentNode->count() + k);
+}
+
+/*!
+ Adds to this section a polygonal face made of triangular sub-faces,
+ defined by \a face. The 0'th vertex is used for the center, while
+ the subsequent vertices form the perimeter of the face, which must
+ at minimum be a triangle.
+
+ If \a face has less than four vertices this function exits without
+ doing anything.
+
+ This function provides functionality similar to the OpenGL mode GL_POLYGON,
+ except it divides the face into sub-faces around a \bold{central point}.
+ The center and perimeter vertices must lie in the same plane (unlike
+ triangle fan). If they do not normals will be incorrectly calculated.
+
+ \image triangulated-face.png
+
+ Here the sub-faces are shown divided by green lines. Note how this
+ function handles some re-entrant (non-convex) polygons, whereas
+ addTriangleFan will not support such polygons.
+
+ If required, the center point can be calculated using the center() function
+ of QGeometryData:
+
+ \code
+ QGeometryData face;
+ face.appendVertex(perimeter.center()); // perimeter is a QGeometryData
+ face.appendVertices(perimeter);
+ builder.addTriangulatedFace(face);
+ \endcode
+
+ N sub-faces are generated where \c{N == face.count() - 2}.
+
+ Each triangular sub-face consists of the center; followed by the \c{i'th}
+ and \c{((i + 1) % N)'th} vertex. The last face generated then is
+ \c{(center, face[N - 1], face[0]}, the closing face. Note that the closing
+ face is automatically created, unlike addTriangleFan().
+
+ If no normals are supplied in the vertices of \a face, normals are
+ calculated as per addTriangle(). One normal is calculated, since a
+ faces vertices lie in the same plane.
+
+ Degenerate triangles are skipped in the same way as addTriangles().
+
+ \sa addTriangleFan(), addTriangles()
+*/
+void QGLBuilder::addTriangulatedFace(const QGeometryData &face)
+{
+ if (face.count() < 4)
+ return;
+ QGeometryData f;
+ f.appendGeometry(face);
+ int cnt = f.count();
+ bool calcNormal = !f.hasField(QGL::Normal);
+ if (calcNormal)
+ {
+ QVector3DArray nm(cnt);
+ f.appendNormalArray(nm);
+ }
+ bool skip = false;
+ QVector3D norm;
+ int k = 0;
+ for (int i = 1; i < cnt; ++i)
+ {
+ int n = i + 1;
+ if (n == cnt)
+ n = 1;
+ if (calcNormal)
+ {
+ skip = qCalculateNormal(0, i, n, f);
+ if (norm.isNull() && !skip)
+ {
+ norm = f.normalAt(0);
+ for (int i = 0; i < cnt; ++i)
+ f.normal(i) = norm;
+ }
+ }
+ if (!skip)
+ dptr->addTriangle(0, i, n, f, k);
+ }
+ dptr->currentNode->setCount(dptr->currentNode->count() + k);
+}
+
+/*!
+ Add a series of quads by 'interleaving' \a top and \a bottom.
+
+ This function behaves like quadStrip(), where the odd-numbered vertices in
+ the input primitive are from \a top and the even-numbered vertices from
+ \a bottom.
+
+ It is trivial to do extrusions using this function:
+
+ \code
+ // create a series of quads for an extruded edge along -Y
+ addQuadsInterleaved(topEdge, topEdge.translated(QVector3D(0, -1, 0));
+ \endcode
+
+ N quad faces are generated where \c{N == min(top.count(), bottom.count() - 1}.
+ If \a top or \a bottom has less than 2 elements, this functions does
+ nothing.
+
+ Each face is formed by the \c{i'th} and \c{(i + 1)'th}
+ vertices of \a bottom, followed by the \c{(i + 1)'th} and \c{i'th}
+ vertices of \a top.
+
+ If the vertices in \a top and \a bottom are the perimeter vertices of
+ two polygons then this function can be used to generate quads which form
+ the sides of a \l{http://en.wikipedia.org/wiki/Prism_(geometry)}{prism}
+ with the polygons as the prisms top and bottom end-faces.
+
+ \image quad-extrude.png
+
+ In the diagram above, the \a top is shown in orange, and the \a bottom in
+ dark yellow. The first generated quad, (a, b, c, d) is generated in
+ the order shown by the blue arrow.
+
+ To create such a extruded prismatic solid, complete with top and bottom cap
+ polygons, given just the top edge do this:
+ \code
+ QGeometryData top = buildTopEdge();
+ QGeometryData bottom = top.translated(QVector3D(0, 0, -1));
+ builder.addQuadsInterleaved(top, bottom);
+ builder.addTriangulatedFace(top);
+ builder.addTriangulatedFace(bottom.reversed());
+ \endcode
+ The \a bottom QGeometryData must be \bold{reversed} so that the correct
+ winding for an outward facing polygon is obtained.
+*/
+void QGLBuilder::addQuadsInterleaved(const QGeometryData &top,
+ const QGeometryData &bottom)
+{
+ if (top.count() < 2 || bottom.count() < 2)
+ return;
+ QGeometryData zipped = bottom.interleavedWith(top);
+ bool calcNormal = !zipped.hasField(QGL::Normal);
+ if (calcNormal)
+ {
+ QVector3DArray nm(zipped.count());
+ zipped.appendNormalArray(nm);
+ }
+ bool skip = false;
+ QVector3D norm;
+ int k = 0;
+ for (int i = 0; i < zipped.count() - 2; i += 2)
+ {
+ if (calcNormal)
+ skip = qCalculateNormal(i, i+2, i+3, zipped, &norm);
+ if (!skip)
+ dptr->addTriangle(i, i+2, i+3, zipped, k);
+ if (skip)
+ skip = qCalculateNormal(i, i+3, i+1, zipped, &norm);
+ if (!skip)
+ {
+ if (calcNormal)
+ setNormals(i, i+3, i+1, zipped, norm);
+ dptr->addTriangle(i, i+3, i+1, zipped, k);
+ }
+ }
+ dptr->currentNode->setCount(dptr->currentNode->count() + k);
+}
+
+/*!
+ \fn void QGLBuilder::addPane(QSizeF size)
+ Convenience function to create a quad centered on the origin,
+ lying in the Z=0 plane, with width (x dimension) and height
+ (y dimension) specified by \a size.
+*/
+
+/*!
+ \fn void QGLBuilder::addPane(qreal size)
+ Convenience method to add a single quad of dimensions \a size wide by
+ \a size high in the z = 0 plane, centered on the origin. The quad has
+ texture coordinates of (0, 0) at the bottom left and (1, 1) at the top
+ right. The default value for \a size is 1.0, resulting in a quad
+ from QVector3D(-0.5, -0.5, 0.0) to QVector3D(0.5, 0.5, 0.0).
+*/
+
+/*!
+ \internal
+*/
+void QGLBuilderPrivate::adjustSectionNodes(QGLSection *sec,
+ int offset, const QGeometryData &geom)
+{
+ QList<QGLSceneNode*> children = sec->nodes();
+ QList<QGLSceneNode*>::iterator it = children.begin();
+ QList<QGLSceneNode*> deleted;
+ for ( ; it != children.end(); ++it)
+ adjustNodeTree(*it, offset, geom, deleted);
+}
+
+/*!
+ \internal
+ Adjust \a top by incrementing its start by \a offset, and setting its
+ geometry to \a geom. Find the cumulative total of indexes -
+ QGLSceneNode::count() - for \a top and all its children. If this total is
+ equal to zero, then delete that node.
+*/
+int QGLBuilderPrivate::adjustNodeTree(QGLSceneNode *top,
+ int offset, const QGeometryData &geom,
+ QList<QGLSceneNode*> &deleted)
+{
+ int totalItems = 0;
+ if (top && !deleted.contains(top))
+ {
+ top->setStart(top->start() + offset);
+ top->setGeometry(geom);
+ totalItems = top->count();
+ QList<QGLSceneNode*> children = top->children();
+ QList<QGLSceneNode*>::iterator it = children.begin();
+ for ( ; it != children.end(); ++it)
+ {
+ totalItems += adjustNodeTree(*it, offset, geom, deleted);
+ }
+ if (totalItems == 0 && top->objectName().isEmpty())
+ {
+ delete top;
+ deleted.append(top);
+ }
+ }
+ return totalItems;
+}
+
+/*!
+ \internal
+ Returns a count of all the items referenced by this node
+ and all its children.
+*/
+static int recursiveCount(QGLSceneNode *top)
+{
+ int totalItems = 0;
+ if (top)
+ {
+ totalItems = top->count();
+ QList<QGLSceneNode*> children = top->children();
+ QList<QGLSceneNode*>::const_iterator it = children.constBegin();
+ for ( ; it != children.constEnd(); ++it)
+ totalItems += recursiveCount(*it);
+ }
+ return totalItems;
+}
+
+static int nodeCount(const QList<QGLSceneNode*> &list)
+{
+ int total = 0;
+ QList<QGLSceneNode*>::const_iterator it = list.constBegin();
+ for ( ; it != list.constEnd(); ++it)
+ total += recursiveCount(*it);
+ return total;
+}
+
+static inline void warnIgnore(int secCount, QGLSection *s, int vertCount, int nodeCount,
+ const char *msg)
+{
+ qWarning("Ignoring section %d (%p) with %d vertices and"
+ " %d indexes - %s", secCount, s, vertCount, nodeCount, msg);
+}
+
+/*!
+ Finish the building of this geometry, optimize it for rendering, and return a
+ pointer to the detached top-level scene node (root node).
+
+ Since the scene is detached from the builder object, the builder itself
+ may be deleted or go out of scope while the scene lives on:
+
+ \code
+ void MyView::MyView()
+ {
+ QGLBuilder builder;
+ // construct geometry
+ m_thing = builder.finalizedSceneNode();
+ }
+
+ void MyView::~MyView()
+ {
+ delete m_thing;
+ }
+
+ void MyView::paintGL()
+ {
+ m_thing->draw(painter);
+ }
+ \endcode
+
+ The root node will have a child node for each section that was created
+ during geometry building.
+
+ This method must be called exactly once after building the scene.
+
+ \bold{Calling code takes ownership of the scene.} In particular take care
+ to either explicitly destroy the scene when it is no longer needed - as shown
+ above.
+
+ For more complex applications parent each finalized scene node onto a QObject
+ so it will be implictly cleaned up by Qt. If you use QGLSceneNode::setParent()
+ to do this, you can save an explicit call to addNode() since if setParent()
+ detects that the new parent is a QGLSceneNode it will call addNode() for you:
+
+ \code
+ // here a top level node for the app is created, and parented to the view
+ QGLSceneNode *topNode = new QGLSceneNode(this);
+
+ QGLBuilder b1;
+ // build geometry
+
+ QGLSceneNode *thing = b1.finalizedSceneNode();
+
+ // does a QObject::setParent() to manage memory, and also adds to the scene
+ // graph, so no need to call topNode->addNode(thing)
+ thing->setParent(topNode);
+
+ QGLBuilder b2;
+ // build more geometry
+ QGLSceneNode *anotherThing = b2.finalizedSceneNode();
+
+ // again parent on get addNode for free
+ anotherThing->setParent(topNode);
+ \endcode
+
+ If this builder is destroyed without calling this method to take
+ ownership of the scene, a warning will be printed on the console and the
+ scene will be deleted. If this method is called more than once, on the
+ second and subsequent calls a warning is printed and NULL is returned.
+
+ This function does the following:
+ \list
+ \o packs all geometry data from sections into QGLSceneNode instances
+ \o recalculates QGLSceneNode start() and count() for the scene
+ \o deletes all QGLBuilder's internal data structures
+ \o returns the top level scene node that references the geometry
+ \o sets the internal pointer to the top level scene node to NULL
+ \endlist
+
+ \sa sceneNode()
+*/
+QGLSceneNode *QGLBuilder::finalizedSceneNode()
+{
+ if (dptr->rootNode == 0)
+ {
+ qWarning("QGLBuilder::finalizedSceneNode() called twice");
+ return 0;
+ }
+ QGeometryData g;
+ QMap<quint32, QGeometryData> geos;
+ QMap<QGLSection*, int> offsets;
+ for (int i = 0; i < dptr->sections.count(); ++i)
+ {
+ // pack sections that have the same fields into one geometry
+ QGLSection *s = dptr->sections.at(i);
+ QGL::IndexArray indices = s->indices();
+ int icnt = indices.size();
+ int ncnt = nodeCount(s->nodes());
+ int scnt = s->count();
+ if (scnt == 0 || icnt == 0 || ncnt == 0)
+ {
+ if (!qgetenv("Q_WARN_EMPTY_MESH").isEmpty())
+ {
+ if (ncnt == 0)
+ warnIgnore(scnt, s, icnt, ncnt, "nodes empty");
+ else if (scnt == 0)
+ warnIgnore(scnt, s, icnt, ncnt, "geometry count zero");
+ else
+ warnIgnore(scnt, s, icnt, ncnt, "index count zero");
+ }
+ continue;
+ }
+ s->normalizeNormals();
+ int sectionOffset = 0;
+ int sectionIndexOffset = 0;
+ if (geos.contains(s->fields()))
+ {
+ QGeometryData &gd = geos[s->fields()];
+ sectionOffset = gd.count();
+ sectionIndexOffset = gd.indexCount();
+ offsets.insert(s, sectionIndexOffset);
+ gd.appendGeometry(*s);
+ for (int i = 0; i < icnt; ++i)
+ indices[i] += sectionOffset;
+ gd.appendIndices(indices);
+ }
+ else
+ {
+ g = QGeometryData(*s);
+ geos.insert(s->fields(), g);
+ }
+ }
+ while (dptr->sections.count() > 0)
+ {
+ QGLSection *s = dptr->sections.takeFirst();
+ dptr->adjustSectionNodes(s, offsets[s], geos[s->fields()]);
+ delete s;
+ }
+ QGLSceneNode *tmp = dptr->rootNode;
+ dptr->rootNode = 0; // indicates root node detached
+ return tmp;
+}
+
+/*!
+ Creates a new section with smoothing mode set to \a smooth. By default
+ \a smooth is QGL::Smooth.
+
+ A section must be created before any geometry or new nodes can be added
+ to the builder. However one is created automatically by addTriangle()
+ and the other add functions; and also by newNode(), pushNode() or popNode()
+ if needed.
+
+ The internal node stack - see pushNode() and popNode() - is cleared,
+ and a new top-level QGLSceneNode is created for this section by calling
+ newNode().
+
+ \sa newNode(), pushNode()
+*/
+void QGLBuilder::newSection(QGL::Smoothing smooth)
+{
+ new QGLSection(this, smooth); // calls addSection
+}
+
+void QGLBuilder::addSection(QGLSection *sec)
+{
+ dptr->currentSection = sec;
+ sec->setMapThreshold(dptr->defThreshold);
+ dptr->sections.append(sec);
+ dptr->nodeStack.clear();
+ newNode();
+}
+
+/*!
+ \internal
+ Returns the current section, in which new geometry is being added.
+*/
+QGLSection *QGLBuilder::currentSection() const
+{
+ return dptr->currentSection;
+}
+
+/*!
+ \internal
+ Returns a list of the sections of the geometry in this builder.
+*/
+QList<QGLSection*> QGLBuilder::sections() const
+{
+ return dptr->sections;
+}
+
+/*!
+ \internal
+ Test function only.
+*/
+void QGLBuilder::setDefaultThreshold(int t)
+{
+ dptr->defThreshold = t;
+}
+
+/*!
+ Returns the root scene node of the geometry created by this builder.
+
+ \sa newNode(), newSection()
+*/
+QGLSceneNode *QGLBuilder::sceneNode()
+{
+ return dptr->rootNode;
+}
+
+/*!
+ Creates a new QGLSceneNode and makes it current. A pointer to the new
+ node is returned. The node is added into the scene at the same level
+ as the currentNode().
+
+ The node is set to reference the geometry starting from the next
+ vertex created, such that currentNode()->start() will return the
+ index of this next vertex.
+
+ \sa newSection()
+*/
+QGLSceneNode *QGLBuilder::newNode()
+{
+ if (dptr->currentSection == 0)
+ {
+ newSection(); // calls newNode()
+ return dptr->currentNode;
+ }
+ QGLSceneNode *parentNode = dptr->rootNode;
+ if (dptr->nodeStack.count() > 0)
+ parentNode = dptr->nodeStack.last();
+ dptr->currentNode = new QGLSceneNode(parentNode);
+ dptr->currentNode->setPalette(parentNode->palette());
+ dptr->currentNode->setStart(dptr->currentSection->indexCount());
+ if (dptr->nodeStack.count() == 0)
+ dptr->currentSection->addNode(dptr->currentNode);
+ return dptr->currentNode;
+}
+
+/*!
+ Returns a pointer to the current scene node, within the current section.
+
+ If there is no current section then newSection() will be called to
+ create one.
+
+ \sa newNode(), newSection()
+*/
+QGLSceneNode *QGLBuilder::currentNode()
+{
+ if (dptr->currentSection == 0)
+ newSection(); // calls newNode()
+ return dptr->currentNode;
+}
+
+/*!
+ Creates a new scene node that is a child of the current node and,
+ makes it the current node. A pointer to the new node is returned.
+ The previous current node is saved on a stack and it may
+ be made current again by calling popNode().
+
+ \sa popNode(), newNode()
+*/
+QGLSceneNode *QGLBuilder::pushNode()
+{
+ if (dptr->currentSection == 0)
+ newSection(); // calls newNode()
+ QGLSceneNode *parentNode = dptr->currentNode;
+ dptr->nodeStack.append(parentNode);
+ dptr->currentNode = new QGLSceneNode(parentNode);
+ dptr->currentNode->setStart(dptr->currentSection->indexCount());
+ dptr->currentNode->setPalette(parentNode->palette());
+ return dptr->currentNode;
+}
+
+/*!
+ Removes the node from the top of the stack, makes a copy of it, and
+ makes the copy current.
+
+ If the stack is empty, behaviour is undefined. In debug mode, calling
+ this function when the stack is empty will cause an assert.
+
+ A pointer to the new current node is returned.
+
+ The node is set to reference the geometry starting from the next
+ vertex created, such that QGLSceneNode::start() will return the
+ index of this next vertex.
+
+ \sa pushNode(), newNode()
+*/
+QGLSceneNode *QGLBuilder::popNode()
+{
+ if (dptr->currentSection == 0)
+ newSection(); // calls newNode()
+ int cnt = dptr->currentSection->indexCount();
+ QGLSceneNode *s = dptr->nodeStack.takeLast(); // assert here
+ QGLSceneNode *parentNode = dptr->rootNode;
+ if (dptr->nodeStack.count() > 0)
+ parentNode = dptr->nodeStack.last();
+ dptr->currentNode = s->cloneNoChildren(parentNode);
+ dptr->currentNode->setStart(cnt);
+ dptr->currentNode->setCount(0);
+ dptr->currentNode->setPalette(parentNode->palette());
+ if (dptr->nodeStack.count() == 0)
+ dptr->currentSection->addNode(dptr->currentNode);
+ return dptr->currentNode;
+}
+
+/*!
+ Returns the palette for this builder. This is the QGLMaterialCollection
+ pointer that was passed to the constructor; or if that was null a new
+ QGLMaterialCollection. This function returns the same result as
+ \c{sceneNode()->palette()}.
+
+ \sa sceneNode()
+*/
+QGLMaterialCollection *QGLBuilder::palette()
+{
+ return dptr->rootNode->palette();
+}
+
+/*!
+ \relates QGLBuilder
+ Convenience operator for creating a new section in \a builder with \a smoothing.
+
+ \code
+ // equivalent to builder.newSection(QGL::Faceted)
+ builder << QGL::Faceted;
+ \endcode
+*/
+QGLBuilder& operator<<(QGLBuilder& builder, const QGL::Smoothing& smoothing)
+{
+ builder.newSection(smoothing);
+ return builder;
+}
+
+/*!
+ \relates QGLBuilder
+ Convenience operator for adding \a triangles to the \a builder.
+
+ \code
+ // equivalent to builder.addTriangles(triangles);
+ builder << triangles;
+ \endcode
+*/
+QGLBuilder& operator<<(QGLBuilder& builder, const QGeometryData& triangles)
+{
+ builder.addTriangles(triangles);
+ return builder;
+}
diff --git a/src/threed/geometry/qglbuilder.h b/src/threed/geometry/qglbuilder.h
new file mode 100644
index 000000000..8c278e192
--- /dev/null
+++ b/src/threed/geometry/qglbuilder.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLBuilder_H
+#define QGLBuilder_H
+
+#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
+#include <QtGui/qvector3d.h>
+#include <QtOpenGL/qgl.h>
+
+#include "qglnamespace.h"
+#include "qglscenenode.h"
+#include "qglattributevalue.h"
+#include "qgeometrydata.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLSection;
+class QGLMaterialCollection;
+class QGLBuilderPrivate;
+class QGLPainter;
+
+class Q_QT3D_EXPORT QGLBuilder
+{
+public:
+ explicit QGLBuilder(QGLMaterialCollection *materials = 0);
+ virtual ~QGLBuilder();
+
+ // section management
+ void newSection(QGL::Smoothing sm = QGL::Smooth);
+
+ // scene management
+ QGLSceneNode *sceneNode();
+ QGLSceneNode *currentNode();
+ QGLSceneNode *newNode();
+ QGLSceneNode *pushNode();
+ QGLSceneNode *popNode();
+ QGLMaterialCollection *palette();
+ QGLSceneNode *finalizedSceneNode();
+
+ // geometry building by primitive
+ void addTriangles(const QGeometryData &triangle);
+ void addQuads(const QGeometryData &quad);
+ void addTriangleFan(const QGeometryData &fan);
+ void addTriangleStrip(const QGeometryData &strip);
+ void addTriangulatedFace(const QGeometryData &face);
+ void addQuadStrip(const QGeometryData &strip);
+ void addQuadsInterleaved(const QGeometryData &top,
+ const QGeometryData &bottom);
+ inline void addPane(qreal size = 1.0f);
+ inline void addPane(QSizeF size);
+
+protected:
+ // internal and test functions
+ QGLSection *currentSection() const;
+ QList<QGLSection*> sections() const;
+ void setDefaultThreshold(int);
+
+private:
+ Q_DISABLE_COPY(QGLBuilder);
+ void addSection(QGLSection *section);
+
+ friend class QGLSection;
+
+ QGLBuilderPrivate *dptr;
+};
+
+inline void QGLBuilder::addPane(qreal size)
+{
+ addPane(QSizeF(size, size));
+}
+
+inline void QGLBuilder::addPane(QSizeF size)
+{
+ QSizeF f = size / 2.0f;
+ QVector2D a(-f.width(), -f.height());
+ QVector2D b(f.width(), -f.height());
+ QVector2D c(f.width(), f.height());
+ QVector2D d(-f.width(), f.height());
+ QVector2D ta(0.0f, 0.0f);
+ QVector2D tb(1.0f, 0.0f);
+ QVector2D tc(1.0f, 1.0f);
+ QVector2D td(0.0f, 1.0f);
+ QGeometryData quad;
+ quad.appendVertex(a, b, c, d);
+ quad.appendTexCoord(ta, tb, tc, td);
+ addQuads(quad);
+}
+
+Q_QT3D_EXPORT QGLBuilder& operator<<(QGLBuilder& builder, const QGL::Smoothing& smoothing);
+Q_QT3D_EXPORT QGLBuilder& operator<<(QGLBuilder& builder, const QGeometryData& triangles);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGLBuilder_H
diff --git a/src/threed/geometry/qglbuilder_p.h b/src/threed/geometry/qglbuilder_p.h
new file mode 100644
index 000000000..bcbd16883
--- /dev/null
+++ b/src/threed/geometry/qglbuilder_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLBuilder_P_H
+#define QGLBuilder_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglbuilder.h"
+
+#include <QtCore/qmap.h>
+#include <QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QGLBuilder;
+class QGLSection;
+class QGeometryData;
+
+class QGLBuilderPrivate
+{
+public:
+ QGLBuilderPrivate(QGLBuilder *parent);
+ ~QGLBuilderPrivate();
+ inline void setDirty(bool dirty = true);
+ void addTriangle(int a, int b, int c, const QGeometryData &p, int &count);
+ void adjustSectionNodes(QGLSection *sec, int offset, const QGeometryData &geom);
+ int adjustNodeTree(QGLSceneNode *top, int offset, const QGeometryData &geom,
+ QList<QGLSceneNode*> &deleted);
+
+ QList<QGLSection*> sections;
+ QGLSection *currentSection;
+ QList<QGLSceneNode*> nodeStack;
+ QGLSceneNode *currentNode;
+ QGLSceneNode *rootNode;
+ int defThreshold;
+ QGLBuilder *q;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGLBuilder_P_H
diff --git a/src/threed/geometry/qglcube.cpp b/src/threed/geometry/qglcube.cpp
new file mode 100644
index 000000000..5f5bda118
--- /dev/null
+++ b/src/threed/geometry/qglcube.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcube.h"
+#include "qglbuilder.h"
+#include "qvector3darray.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLCube
+ \brief The QGLCube class represents the geometry of simple six-sided cube in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ The following example adds a cube of 2 units on a side to a
+ geometry builder, and draws it at (10, 25, 0) in a QGLPainter:
+
+ \code
+ QGLBuilder list;
+ list.newSection(QGL::Faceted);
+ list << QGLCube(2);
+ painter->translate(10, 25, 0);
+ list.draw(painter);
+ \endcode
+
+ QGLCube will create a default set of texture coordinates that shows
+ the same texture of all six faces.
+*/
+
+/*!
+ \fn QGLCube::QGLCube(qreal size)
+
+ Constructs the geometry for a regular cube of \a size
+ units on a side.
+*/
+
+/*!
+ \fn qreal QGLCube::size() const
+
+ Returns the size of this cube.
+
+ \sa setSize()
+*/
+
+/*!
+ \fn void QGLCube::setSize(qreal size)
+
+ Sets the \a size of this cube.
+
+ \sa size()
+*/
+
+static const int vertexDataLen = 6 * 4 * 3;
+
+static const float vertexData[vertexDataLen] = {
+ -0.5f, -0.5f, -0.5f,
+ -0.5f, -0.5f, 0.5f,
+ -0.5f, 0.5f, 0.5f,
+ -0.5f, 0.5f, -0.5f,
+
+ -0.5f, 0.5f, -0.5f,
+ -0.5f, 0.5f, 0.5f,
+ 0.5f, 0.5f, 0.5f,
+ 0.5f, 0.5f, -0.5f,
+
+ 0.5f, 0.5f, -0.5f,
+ 0.5f, 0.5f, 0.5f,
+ 0.5f, -0.5f, 0.5f,
+ 0.5f, -0.5f, -0.5f,
+
+ 0.5f, -0.5f, -0.5f,
+ 0.5f, -0.5f, 0.5f,
+ -0.5f, -0.5f, 0.5f,
+ -0.5f, -0.5f, -0.5f,
+
+ 0.5f, -0.5f, 0.5f,
+ 0.5f, 0.5f, 0.5f,
+ -0.5f, 0.5f, 0.5f,
+ -0.5f, -0.5f, 0.5f,
+
+ 0.5f, 0.5f, -0.5f,
+ 0.5f, -0.5f, -0.5f,
+ -0.5f, -0.5f, -0.5f,
+ -0.5f, 0.5f, -0.5f
+};
+
+static const int texCoordDataLen = 4 * 2;
+
+static const float texCoordData[texCoordDataLen] = {
+ 1.0f, 0.0f,
+ 1.0f, 1.0f,
+ 0.0f, 1.0f,
+ 0.0f, 0.0f
+};
+
+/*!
+ \relates QGLCube
+
+ Builds the geometry for \a cube within the specified
+ geometry \a builder.
+
+ This operator specifies the positions, and 2D texture
+ co-ordinates for all of the vertices that make up the cube.
+ Normals will be calculated by the \a builder, depending on its
+ current section's smoothing setting.
+*/
+QGLBuilder& operator<<(QGLBuilder& builder, const QGLCube& cube)
+{
+ QGeometryData op;
+
+ QVector3DArray vrts = QVector3DArray::fromRawData(
+ reinterpret_cast<const QVector3D *>(vertexData), vertexDataLen / 3);
+ if (cube.size() != 1.0f)
+ vrts.scale(cube.size());
+
+ op.appendVertexArray(vrts);
+
+ QVector2DArray texx = QVector2DArray::fromRawData(
+ reinterpret_cast<const QVector2D *>(texCoordData), texCoordDataLen / 2);
+
+ for (int i = 0; i < 6; ++i)
+ op.appendTexCoordArray(texx);
+
+ builder.addQuads(op);
+ return builder;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/geometry/qglcube.h b/src/threed/geometry/qglcube.h
new file mode 100644
index 000000000..19eebc26c
--- /dev/null
+++ b/src/threed/geometry/qglcube.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCUBE_H
+#define QGLCUBE_H
+
+#include "qt3dglobal.h"
+
+#include <QtGui/qvector2d.h>
+#include "qvector2darray.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLBuilder;
+
+class Q_QT3D_EXPORT QGLCube
+{
+public:
+ explicit QGLCube(qreal size = 1.0f) : m_size(size) {}
+
+ qreal size() const { return m_size; }
+ void setSize(qreal size) { m_size = size; }
+
+private:
+ qreal m_size;
+};
+
+Q_QT3D_EXPORT QGLBuilder& operator<<(QGLBuilder& builder, const QGLCube& cube);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/geometry/qglcylinder.cpp b/src/threed/geometry/qglcylinder.cpp
new file mode 100644
index 000000000..30b4f34cc
--- /dev/null
+++ b/src/threed/geometry/qglcylinder.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcylinder.h"
+#include "qglbuilder.h"
+#include "qvector2darray.h"
+#include "qvector3darray.h"
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLCylinder
+ \brief The QGLCylinder class represents the geometry of a simple cylinder/cone in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ The following example creates a cone with a top diameter of 1 unit,
+ a bottom diameter of of 2 units in diameter and height of 3 units.
+
+ It then draws it at (10, 25, 0) in a QGLPainter:
+
+ \code
+ QGLBuilder builder;
+ builder << QGLCylinder(1.0,2.0,3.0);
+ QGLSceneNode *node = builder.finalizedSceneNode();
+
+ painter.translate(10, 25, 0);
+ node->draw(&painter);
+ \endcode
+
+ Note that the bottom circle of the cylinder will always be centred at (0,0,0)
+ unless otherwise transformed after cylinder creation.
+
+ The QGLCylinder class specifies positions, normals and 2D texture
+ co-ordinates for all of the vertices that make up the cylinder.
+
+ The texture co-ordinates are fixed at construction time. This
+ is because constructing the cylinder can involve generating additional
+ vertices which need to interpolate the texture co-ordinates of their
+ neighboring vertices.
+
+ The QGLCylinder is divided into slices and layers. The slices value
+ indicate number of triangular sections into which the top and bottom
+ circles of the cylinder are broken into. Consequently it also sets the
+ number of facets which run the length of the cylinder. More slices
+ results in a smoother circumference.
+
+ The layers value indicates the number of longitudinal sections the
+ cylinder is broken into. Fewer layers means that the side facets of the
+ cylinder will be made up of fewer, very long, triangles, while a higher
+ number of layers will produce many and smaller triangles. Often it is
+ desirable to avoid large triangles as they may cause inefficiencies in
+ texturing/lighting on certain platforms.
+
+ The end-caps and sides of the cylinder are independent sections of the
+ scene-graph, and so may be textured separately.
+
+ Textures are wrapped around the sides of thecylinder in such a way that
+ the texture may distort across the x axis if the top and bottom diameters
+ of the cylinder differ (ie. the cylinder forms a truncated cone). Textures
+ begin and end at the centre points of the top and bottom end-caps of the
+ cylinder. This wrapping means that textures on either end-cap may be
+ distorted.
+
+ Texture coordinates are assigned as shown below.
+
+ \image cylinder-texture-coords.png
+
+ It is worth noting that the cylinder class can, in fact, be used to generate
+ any regular solid polygonal prism. A rectangular prism can be created, for
+ example, by creating a 4 sided cylinder. Likewise a hexagonal prism is
+ simply a 6 sided cylinder.
+
+ With this knowledge, and an understanding of the texture coordinate mapping,
+ it is possible to make custom textures which will be usable with these
+ three dimensional objects.
+
+ \sa QGLBuilder
+*/
+
+
+/*!
+ \fn QGLCylinder::QGLCylinder(qreal diameterTop, qreal diameterBase , qreal height, int slices, int layers, bool top, bool base)
+
+ Constructs the geometry for a cylinder with top of diameter \a diameterTop,
+ a base of diameter \a diameterBase, and a height of \a height.
+
+ The resultant mesh will be divided around the vertical axis of the cylinder
+ into \a slices individual wedges, and shall be formed of \a layers stacked
+ to form the cylinder.
+
+ If the values for \a top or \a base are true, then the cylinder will be
+ created with solid endcaps. Otherwise, it shall form a hollow pipe.
+
+ units on a side.
+*/
+
+
+/*!
+ \fn qreal QGLCylinder::diameterTop() const
+
+ Returns the diameter of the top of the cylinder.
+
+ The default value is 1.
+
+ \sa setDiameterTop()
+*/
+
+/*!
+ \fn void QGLCylinder::setDiameterTop(qreal diameter)
+
+ Sets the diameter of the top of this cylinder to \a diameter.
+
+ \sa diameterTop()
+*/
+
+/*!
+ \fn qreal QGLCylinder::diameterBottom() const
+
+ Returns the diameter of the bottom of the cylinder.
+
+ The default value is 1.
+
+ \sa setDiameterBottom()
+*/
+
+/*!
+ \fn void QGLCylinder::setDiameterBottom(qreal diameter)
+
+ Sets the diameter of the bottom of this cylinder to \a diameter.
+
+ \sa diameterBottom()
+*/
+
+/*!
+ \fn qreal QGLCylinder::height() const
+
+ Returns the height of the cylinder.
+
+ The default value is 1.0
+
+ \sa setDiameterBottom()
+*/
+
+/*!
+ \fn void QGLCylinder::setHeight(qreal height)
+
+ Sets the height of this cylinder to \a height.
+
+ \sa diameterBottom()
+*/
+
+
+/*!
+ \fn int QGLCylinder::slices() const
+
+ Returns the number of triangular slices the cylinder is divided into
+ around its polar axis.
+
+ The default is 6.
+
+ \sa setSlices()
+*/
+
+/*!
+ \fn int QGLCylinder::setSlices(int slices)
+
+ Sets the number of triangular \a slices the cylinder is divided into
+ around its polar axis.
+
+ \sa slices()
+*/
+
+/*!
+ \fn int QGLCylinder::layers() const
+
+ Returns the number of cylindrical layers the cylinder is divided into
+ along its height.
+
+ The default is 3.
+
+ \sa setLayers()
+*/
+
+/*!
+ \fn int QGLCylinder::setLayers(int layers)
+
+ Sets the number of stacked \a layers the cylinder is divided into
+ along its height.
+
+ \sa layers()
+*/
+
+/*!
+ \fn bool QGLCylinder::topEnabled() const
+
+ Returns true if the top of the cyclinder will be created when
+ building the mesh.
+
+ The default is true.
+
+ \sa setTopEnabled()
+*/
+
+/*!
+ \fn void QGLCylinder::setTopEnabled(bool top)
+
+ Set whether the top end-cap of the cylinder will be created when
+ building the mesh. If \a top is true, the end-cap will be created.
+
+ \sa topEnabled()
+*/
+
+/*!
+ \fn bool QGLCylinder::baseEnabled() const
+
+ Returns true if the base of the cyclinder will be created when
+ building the mesh.
+
+ The default is true.
+
+ \sa setBaseEnabled()
+*/
+
+/*!
+ \fn void QGLCylinder::setBaseEnabled(bool base)
+
+ Set whether the base end-cap of the cylinder will be created when
+ building the mesh. If \a base is true, the end-cap will be created.
+
+ \sa baseEnabled()
+*/
+
+/*!
+ \relates QGLCylinder
+
+ Builds the geometry for \a cylinder within the specified
+ geometry \a builder.
+*/
+
+QGLBuilder& operator<<(QGLBuilder& builder, const QGLCylinder& cylinder)
+{
+ /* ASSERT(cylinder.diameterBottom()>=0 &&
+ cylinder.diameterTop()>=0 &&
+ cylinder.height()>0);*/
+
+ qreal numSlices = qreal(cylinder.slices());
+ qreal numLayers = qreal(cylinder.layers());
+ qreal topRadius = cylinder.diameterTop()/2.0;
+ qreal bottomRadius = cylinder.diameterBottom()/2.0;
+
+ qreal angle = 0;
+ qreal angleIncrement = (2.0 * M_PI) / numSlices;
+ qreal radius = topRadius;
+ qreal radiusIncrement = qreal(bottomRadius-topRadius)/ numLayers;
+ qreal height = qreal(cylinder.height());
+ qreal heightDecrement = height/numLayers;
+
+ qreal textureHeight = 1.0;
+ qreal textureDecrement = 1.0/numLayers;
+
+ QGeometryData oldLayer;
+
+ //Generate vertices for the next layer of cylinder
+ for (int layerCount=0; layerCount<=cylinder.layers(); layerCount++) {
+ QGeometryData newLayer;
+
+ //Generate a circle of vertices for this layer.
+ for (int i=0; i<cylinder.slices(); i++)
+ {
+ newLayer.appendVertex(QVector3D(radius * qCos(angle),
+ radius * qSin(angle),
+ height));
+ angle+=angleIncrement;
+ }
+ angle = 0;
+ // Generate texture coordinates (including an extra seam vertex for textures).
+ newLayer.appendVertex(newLayer.vertex(0));
+ newLayer.generateTextureCoordinates();
+ for (int i = 0; i < newLayer.count(); i++) newLayer.texCoord(i).setY(textureHeight);
+
+ //Special cases for top end-cap
+ if (layerCount==0 && cylinder.topEnabled()) {
+ //Draw end-cap at top
+ QGeometryData top;
+ builder.newSection();
+ builder.currentNode()->setObjectName("Cylinder Top");
+ top.appendVertex(newLayer.center());
+ top.appendVertexArray(newLayer.vertices());
+ //Generate a circle of texture vertices for this layer.
+ top.appendTexCoord(QVector2D(0.5,0.5));
+
+ for (int i=1; i<top.count(); i++)
+ {
+ top.appendTexCoord(QVector2D(0.5*qCos(angle)+0.5, 0.5*qSin(angle)+0.5));
+ angle+=angleIncrement;
+ }
+ angle = 0;
+ builder.addTriangulatedFace(top);
+ }
+
+
+ //Add a new cylinder layer to the mesh
+ if (layerCount>0)
+ {
+ //If it's the first section, create a cylinder sides section
+ if (layerCount==1) {
+ builder.newSection();
+ builder.currentNode()->setObjectName("Cylinder Sides");
+ }
+ builder.addQuadsInterleaved(oldLayer, newLayer);
+ }
+
+ //Special cases for bottom end-cap
+ if (layerCount==cylinder.layers() && cylinder.baseEnabled()) {
+ //Draw end-cap at bottom
+ QGeometryData base;
+ builder.newSection();
+ builder.currentNode()->setObjectName("Cylinder Base");
+ base.appendVertexArray(newLayer.vertices());
+ base.appendVertex(newLayer.center());
+ //Generate a circle of texture vertices for this layer.
+ for (int i=1; i<base.count(); i++)
+ {
+ base.appendTexCoord(QVector2D(0.5*qCos(angle)+0.5, 0.5*qSin(angle)+0.5));
+ angle+=angleIncrement;
+ }
+ base.appendTexCoord(QVector2D(0.5,0.5));
+ angle = 0;
+
+ //we need to reverse the above to draw it properly - windings!
+ builder.addTriangulatedFace(base.reversed());
+ }
+
+ //Keep the current layer for drawing the next segment of the cylinder
+ oldLayer.clear();
+ oldLayer.appendGeometry(newLayer);
+ radius+=radiusIncrement;
+ height-=heightDecrement;
+ textureHeight-=textureDecrement;
+ }
+
+ return builder;
+}
diff --git a/src/threed/geometry/qglcylinder.h b/src/threed/geometry/qglcylinder.h
new file mode 100644
index 000000000..51d2cfba6
--- /dev/null
+++ b/src/threed/geometry/qglcylinder.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCYLINDER_H
+#define QGLCYLINDER_H
+
+#include "qt3dglobal.h"
+#include "qglmaterialcollection.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLBuilder;
+class QVector2D;
+
+class Q_QT3D_EXPORT QGLCylinder
+{
+public:
+ explicit QGLCylinder(qreal diameterTop = 1.0f, qreal diameterBase = 1.0f, qreal height = 1.0f, int slices = 6, int layers = 3, bool top = true, bool base = true)
+ : m_diameterTop(diameterTop), m_diameterBottom(diameterBase), m_height(height), m_slices(slices), m_layers(layers), m_top(top), m_base(base) {}
+
+ //Cylinder dimensions
+ qreal diameterTop() const {return m_diameterTop;}
+ void setDiameterTop(qreal diameter) {m_diameterTop=diameter;}
+
+ qreal diameterBottom() const {return m_diameterBottom;}
+ void setDiameterBottom(qreal diameter) {m_diameterBottom=diameter;}
+
+ qreal height() const {return m_height;}
+ void setHeight(qreal height) {m_height = height;}
+
+ //Cylinder geometrical subdivisions
+ int slices() const {return m_slices;}
+ void setSlices(int slices) {m_slices = slices;}
+
+ int layers() const {return m_layers;}
+ void setLayers(int layers) {m_layers = layers;}
+
+ //End-caps attached?
+ bool topEnabled() const {return m_top;}
+ void setTopEnabled(bool top) {m_top = top;}
+
+ bool baseEnabled() const {return m_base;}
+ void setBaseEnabled(bool base) {m_base = base;}
+
+protected:
+ qreal m_diameterTop;
+ qreal m_diameterBottom;
+ qreal m_height;
+
+ int m_slices;
+ int m_layers;
+
+ bool m_top;
+ bool m_base;
+};
+
+Q_QT3D_EXPORT QGLBuilder& operator<<(QGLBuilder& builder, const QGLCylinder& cylinder);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGLCYLINDER_H
diff --git a/src/threed/geometry/qgldome.cpp b/src/threed/geometry/qgldome.cpp
new file mode 100644
index 000000000..5cd18da01
--- /dev/null
+++ b/src/threed/geometry/qgldome.cpp
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgldome.h"
+#include "qglbuilder.h"
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLDome
+ \brief The QGLDome class represents the geometry of a simple hemisphere in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ The following example creates a dome of 2 units in diameter and
+ draws it at (10, 25, 0) in a QGLPainter:
+
+ \code
+ QGLBuilder builder;
+ builder << QGLDome(2);
+ QGLSceneNode *node = builder.finalizedSceneNode();
+
+ painter.translate(10, 25, 0);
+ node->draw(&painter);
+ \endcode
+
+ The QGLDome class specifies positions, normals and 2D texture
+ co-ordinates for all of the vertices that make up the sphere.
+
+ The texture co-ordinates are fixed at construction time. This
+ is because constructing the sphere can involve generating additional
+ vertices which need to interpolate the texture co-ordinates of their
+ neighboring vertices.
+
+ The default mode of QGLDome is half of a "UV sphere", which divides
+ the object up into longitudinal and latitudinal sections. The longitudinal
+ slices meet at the pole, which in a single unit dome is defined to
+ be at (0, 0, +0.5) and (0, 0, -0.5). This choice is the simplest to
+ texture map as the texture will only distort along the x-axis of the
+ 2D texture. However the density of vertices is significantly higher at
+ the poles than it is elsewhere on the sphere and is a poor choice if a
+ uniform density of pixels from the texture map is required.
+
+ \sa QGLBuilder
+*/
+
+/*!
+ \fn QGLDome::QGLDome(qreal diameter, int depth, bool base)
+
+ Creates a dome of \a diameter across (default is 1). When the dome
+ is recursively subdivided into triangles, it will be subdivided no more
+ than \a depth times (between 1 and 5, default is 3).
+
+ If \a base is true, the dome will be drawn with a bottom circle, creating
+ an enclosed solid.
+*/
+
+/*!
+ Destroys this dome object.
+*/
+QGLDome::~QGLDome()
+{
+}
+
+/*!
+ \fn qreal QGLDome::diameter() const
+
+ Returns the diameter of this dome. The default is 1.
+
+ \sa setDiameter()
+*/
+
+/*!
+ \fn void QGLDome::setDiameter(qreal diameter)
+
+ Sets the diameter of this dome to \a diameter.
+
+ \sa diameter()
+*/
+
+/*!
+ \fn int QGLDome::subdivisionDepth() const
+
+ Returns the maximum depth when this hemisphere is subdivided into
+ triangles. The default is 3. The following picture shows the effect
+ of depth values between 1 and 5 for a UV sphere (hemisphere subdivision
+ depth shares this scheme).
+
+ \image sphere-detail.png
+
+ \sa setSubdivisionDepth(), QGLSphere::subdivisionDepth()
+*/
+
+/*!
+ \fn void QGLDome::setSubdivisionDepth(int depth)
+
+ Sets the maximum \a depth when this hemisphere is subdivided into triangles.
+
+ \sa subdivisionDepth()
+*/
+
+/*!
+ \fn bool QGLDome::baseEnabled() const
+
+ Returns true if the base of the dome will be created when
+ building the mesh.
+
+ The default is true.
+
+ \sa setBaseEnabled()
+*/
+
+/*!
+ \fn void QGLDome::setBaseEnabled(bool base)
+
+ Set whether the bottom of the dome will be created when
+ building the mesh. If \a base is true, the end-cap will be
+ created.
+
+ \sa baseEnabled()
+*/
+
+/*!
+ \relates QGLDome
+
+ Builds the geometry for \a dome within the specified
+ geometry \a builder.
+*/
+QGLBuilder& operator<<(QGLBuilder& builder, const QGLDome& dome)
+{
+ qreal radius = dome.diameter() / 2.0f;
+
+ // Determine the number of slices and stacks to generate.
+ int divisions = dome.subdivisionDepth();
+ if (divisions < 1)
+ divisions = 1;
+ else if (divisions > 5)
+ divisions = 5;
+ int stacks = 2 * (1 << divisions);
+ int slices = 2 * stacks;
+ stacks = stacks>>1;
+
+ // Precompute sin/cos values for the slices and stacks.
+ const int maxSlices = 4 * (1 << 5) + 1;
+ const int maxStacks = 2 * (1 << 5) + 1;
+ qreal sliceSin[maxSlices];
+ qreal sliceCos[maxSlices];
+ qreal stackSin[maxStacks];
+ qreal stackCos[maxStacks];
+ for (int slice = 0; slice < slices; ++slice) {
+ qreal angle = 2 * M_PI * slice / slices;
+ sliceSin[slice] = qFastSin(angle);
+ sliceCos[slice] = qFastCos(angle);
+ }
+ sliceSin[slices] = sliceSin[0]; // Join first and last slice.
+ sliceCos[slices] = sliceCos[0];
+
+ const qreal halfPi=M_PI/2.0;
+
+ for (int stack = 0; stack <= stacks; ++stack) {
+ qreal angle = halfPi * stack / stacks;
+ stackSin[stack] = qFastSin(angle);
+ stackCos[stack] = qFastCos(angle);
+ }
+ stackSin[0] = 0.0f; // Come to a point at the poles.
+ stackSin[stacks] = 1.0f;
+
+ builder.newSection();
+ builder.currentNode()->setObjectName("Dome");
+ // Create the stacks for the dome part of the dome
+ for (int stack = 0; stack < stacks; ++stack) {
+ QGeometryData prim;
+ qreal z = radius * stackCos[stack];
+ qreal nextz = radius * stackCos[stack + 1];
+ qreal s = stackSin[stack];
+ qreal nexts = stackSin[stack + 1];
+ qreal c = stackCos[stack];
+ qreal nextc = stackCos[stack + 1];
+ qreal r = radius * s;
+ qreal nextr = radius * nexts;
+ for (int slice = 0; slice <= slices; ++slice) {
+ prim.appendVertex(QVector3D(nextr * sliceSin[slice], nextr * sliceCos[slice], nextz));
+ prim.appendNormal(QVector3D(sliceSin[slice] * nexts, sliceCos[slice] * nexts, nextc));
+ prim.appendTexCoord(QVector2D(1.0f - qreal(slice) / slices, 1.0f - qreal(stack + 1) / stacks));
+
+ prim.appendVertex(QVector3D(r * sliceSin[slice], r * sliceCos[slice], z));
+ prim.appendNormal(QVector3D(sliceSin[slice] * s, sliceCos[slice] * s, c));
+ prim.appendTexCoord(QVector2D(1.0f - qreal(slice) / slices, 1.0f - qreal(stack) / stacks));
+ }
+ builder.addQuadStrip(prim);
+ }
+
+ if (dome.baseEnabled()) {
+ //Draw end-cap at bottom
+ builder.newSection();
+ builder.currentNode()->setObjectName("Base");
+
+ //Generate a circle of vertices for this layer.
+ QGeometryData tempBase;
+
+ tempBase.appendVertex(QVector3D(0,0,0));
+ tempBase.appendTexCoord(QVector2D(0.5,0.5));
+ for (int slice=0; slice<=slices+1; slice++)
+ {
+ tempBase.appendVertex(QVector3D(radius * sliceCos[slice], radius * sliceSin[slice], 0));
+ tempBase.appendTexCoord(QVector2D(0.5*sliceCos[slice]+0.5, 0.5*sliceSin[slice]+0.5));
+ }
+
+ //we need to reverse the above to draw it properly - windings!
+ builder.addTriangulatedFace(tempBase.reversed());
+ }
+ return builder;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/threed/geometry/qgldome.h b/src/threed/geometry/qgldome.h
new file mode 100644
index 000000000..23d86f508
--- /dev/null
+++ b/src/threed/geometry/qgldome.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLDOME_H
+#define QGLDOME_H
+
+#include "qt3dglobal.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLBuilder;
+
+class Q_QT3D_EXPORT QGLDome
+{
+public:
+ explicit QGLDome(qreal diameter = 1.0f, int depth = 3, bool baseEnabled = true)
+ : m_diameter(diameter), m_subdivisionDepth(depth), m_baseEnabled(baseEnabled) {}
+ virtual ~QGLDome();
+
+ qreal diameter() const { return m_diameter; }
+ void setDiameter(qreal diameter) { m_diameter = diameter; }
+
+ int subdivisionDepth() const { return m_subdivisionDepth; }
+ void setSubdivisionDepth(int depth) { m_subdivisionDepth = depth; }
+
+ bool baseEnabled() const {return m_baseEnabled; }
+ void setBaseEnabled(bool baseEnabled) {m_baseEnabled = baseEnabled;}
+
+private:
+ qreal m_diameter;
+ int m_subdivisionDepth;
+ bool m_baseEnabled;
+};
+
+Q_QT3D_EXPORT QGLBuilder& operator<<(QGLBuilder& builder, const QGLDome& dome);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/geometry/qglmaterialcollection.cpp b/src/threed/geometry/qglmaterialcollection.cpp
new file mode 100644
index 000000000..674dac70f
--- /dev/null
+++ b/src/threed/geometry/qglmaterialcollection.cpp
@@ -0,0 +1,415 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglmaterialcollection.h"
+#include "qglmaterial_p.h"
+#include <QtCore/qlist.h>
+#include <QtCore/qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLMaterialCollection
+ \brief The QGLMaterialCollection class manages groups of materials.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::enablers
+
+ Managing more complex 3d graphics with several materials is easier when the
+ materials can be referred to as a collection. This is the role of the
+ QGLMaterialCollection class.
+
+ Plug-ins implementing 3D formats may make the materials defined in
+ the format available to the application via a QGLMaterialCollection.
+
+ The collection is also optimised for the case where many small objects
+ must refer to materials - such as faces in a mesh, or particles. In
+ this case the materials can be specified as a short data type using an
+ offset into the collection, rather than the material name.
+
+ When building up a collection, meshes that refer to the various materials
+ can check off which ones are used by calling markMaterialAsUsed(), and then
+ remove spurious unused materials by calling removeUnusedMaterials(). This
+ technique is suitable for models loaded from a model file where a large
+ number of materials may be specified but only a few of those materials
+ are used by the particular mesh selected from the scene.
+
+ To make a material available from a collection, call addMaterial(). To
+ retrieve a material from the collection call removeMaterial().
+
+ The collection takes ownership of the QGLMaterial
+ objects passed to it by the addMaterial() function. These
+ objects will be destroyed when the collection is destroyed.
+*/
+
+class QGLMaterialCollectionPrivate
+{
+public:
+ QGLMaterialCollectionPrivate()
+ {
+ }
+
+ QList<QGLMaterial *> materials;
+ QHash<QString, int> materialNames;
+};
+
+/*!
+ Construct a new empty QGLMaterialCollection object. The \a parent
+ is set as the parent of this object.
+*/
+QGLMaterialCollection::QGLMaterialCollection(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new QGLMaterialCollectionPrivate)
+{
+}
+
+/*!
+ Destroy this collection. All material objects referred to by this
+ collection will be destroyed.
+*/
+QGLMaterialCollection::~QGLMaterialCollection()
+{
+ // The QGLMaterial QObject's are reparented to the collection
+ // when addMaterial() is called, so the QObject destructor
+ // will take care of cleaning them up for us.
+}
+
+/*!
+ Returns a pointer to the material corresponding to \a index; or null
+ if \a index is out of range or the material has been removed.
+
+ Here's an example of searching for a material with a given ambient
+ \c{color} in the collection \c{materials}:
+
+ \code
+ for (int colorIndex; colorIndex < materials->size(); ++colorIndex) {
+ if (material(colorIndex) &&
+ material(colorIndex)->ambientColor() == color)
+ break;
+ }
+ if (colorIndex < materials->size())
+ myObject->setMaterial(colorIndex);
+ \endcode
+*/
+QGLMaterial *QGLMaterialCollection::material(int index) const
+{
+ Q_D(const QGLMaterialCollection);
+ return d->materials.value(index, 0);
+}
+
+/*!
+ \overload
+
+ Returns the material associated with \a name in this collection;
+ null if \a name is not present or the material has been removed.
+*/
+QGLMaterial *QGLMaterialCollection::material(const QString &name) const
+{
+ Q_D(const QGLMaterialCollection);
+ int index = d->materialNames.value(name, -1);
+ if (index >= 0)
+ return d->materials[index];
+ else
+ return 0;
+}
+
+/*!
+ Returns true if this collection contains \a material; false otherwise.
+
+ \sa indexOf()
+*/
+bool QGLMaterialCollection::contains(QGLMaterial *material) const
+{
+ return material && material->d_func()->collection == this;
+}
+
+/*!
+ \overload
+
+ Returns true if this collection contains a material called \a name;
+ false otherwise.
+
+ \sa indexOf()
+*/
+bool QGLMaterialCollection::contains(const QString &name) const
+{
+ Q_D(const QGLMaterialCollection);
+ return d->materialNames.contains(name);
+}
+
+/*!
+ Returns the index of \a material in this collection; -1 if
+ \a material is not present in this collection.
+
+ \sa contains()
+*/
+int QGLMaterialCollection::indexOf(QGLMaterial *material) const
+{
+ if (material && material->d_func()->collection == this)
+ return material->d_func()->index;
+ else
+ return -1;
+}
+
+/*!
+ \overload
+
+ Returns the index of the material called \a name in this collection;
+ -1 if \a name is not present in this collection.
+
+ \sa contains()
+*/
+int QGLMaterialCollection::indexOf(const QString &name) const
+{
+ Q_D(const QGLMaterialCollection);
+ return d->materialNames.value(name, -1);
+}
+
+/*!
+ Returns the name of the material at \a index in this material collection;
+ a null QString if \a index is out of range.
+*/
+QString QGLMaterialCollection::materialName(int index) const
+{
+ Q_D(const QGLMaterialCollection);
+ if (index >= 0 && index < d->materials.count()) {
+ QGLMaterial *material = d->materials[index];
+ if (material) {
+ // Use the name in the private data block just in case the
+ // application has modified objectName() since adding.
+ return material->d_func()->name;
+ }
+ }
+ return QString();
+}
+
+/*!
+ Returns true if the material at \a index in this collection has been
+ marked as used by markMaterialAsUsed().
+
+ \sa markMaterialAsUsed()
+*/
+bool QGLMaterialCollection::isMaterialUsed(int index) const
+{
+ QGLMaterial *mat = material(index);
+ if (mat)
+ return mat->d_func()->used;
+ else
+ return false;
+}
+
+/*!
+ Flags the material corresponding to the \a index as used. Some model files
+ may contain a range of materials, applying to various objects in the scene.
+
+ When a particular object is loaded from the file, many of those
+ materials may not be used in that object. This wastes space,
+ with many spurious materials being stored.
+
+ Use this method during model loading or construction to mark off
+ materials that have been used. Materials so marked will not
+ be removed by removeUnusedMaterials().
+
+ \sa removeUnusedMaterials(), isMaterialUsed()
+*/
+void QGLMaterialCollection::markMaterialAsUsed(int index)
+{
+ QGLMaterial *mat = material(index);
+ if (mat)
+ mat->d_func()->used = true;
+}
+
+/*!
+ Removes and deletes materials which have not been marked as used.
+
+ \sa markMaterialAsUsed(), isMaterialUsed()
+*/
+void QGLMaterialCollection::removeUnusedMaterials()
+{
+ Q_D(QGLMaterialCollection);
+ for (int index = 0; index < d->materials.size(); ++index) {
+ QGLMaterial *material = d->materials[index];
+ if (material && !material->d_func()->used)
+ delete removeMaterial(index);
+ }
+}
+
+/*!
+ Adds \a material to this collection and returns its new index. The
+ collection takes ownership of the material and will delete it when the
+ collection is destroyed. Initially the \a material is marked as unused.
+
+ The QObject::objectName() of \a material at the time addMaterial()
+ is called will be used as the material's name within this collection.
+ Changes to the object name after the material is added are ignored.
+
+ If \a material is already present in this collection, then this
+ function will return the index that was previously assigned.
+
+ Returns -1 if \a material has been added to another collection.
+
+ \sa removeMaterial(), markMaterialAsUsed()
+*/
+int QGLMaterialCollection::addMaterial(QGLMaterial *material)
+{
+ Q_D(QGLMaterialCollection);
+ Q_ASSERT(material);
+
+ // Allocate a new index for the material.
+ int index = d->materials.count();
+
+ // Record the index in the private data attached to the material.
+ // This allows us to find the material's index quickly later.
+ QGLMaterialPrivate *dm = material->d_func();
+ if (dm->collection) {
+ if (dm->collection == this)
+ return dm->index;
+ return -1;
+ }
+ dm->collection = this;
+ dm->index = index;
+ dm->name = material->objectName();
+ dm->used = false;
+
+ // Add the material to this collection.
+ material->setParent(this);
+ d->materials.append(material);
+ if (!dm->name.isEmpty())
+ d->materialNames[dm->name] = index;
+ connect(material, SIGNAL(destroyed()), this, SLOT(materialDeleted()));
+ return index;
+}
+
+/*!
+ Removes all instances of \a material from this collection.
+ The \a material object is not deleted and can be reused.
+
+ Does nothing if \a material is null or not a member of
+ this collection.
+
+ \sa addMaterial()
+*/
+void QGLMaterialCollection::removeMaterial(QGLMaterial *material)
+{
+ Q_D(QGLMaterialCollection);
+ if (!material)
+ return;
+
+ // Check the material's owning collection.
+ QGLMaterialPrivate *dm = material->d_func();
+ if (dm->collection != this)
+ return;
+
+ // Remove the material from the collection.
+ d->materials[dm->index] = 0;
+ if (!dm->name.isEmpty())
+ d->materialNames.remove(dm->name);
+ material->setParent(0);
+
+ // Detach from the owning collection.
+ dm->collection = 0;
+ dm->index = -1;
+}
+
+/*!
+ Removes the material at \a index from this collection, and returns
+ a pointer to the material.
+
+ Since the collection is designed for fast lookup by index, the
+ the stored material pointer is set to null but the \a index
+ otherwise remains valid.
+*/
+QGLMaterial *QGLMaterialCollection::removeMaterial(int index)
+{
+ Q_D(QGLMaterialCollection);
+
+ // Bail out if the material is invalid.
+ if (index < 0 || index >= d->materials.count())
+ return 0;
+ QGLMaterial *material = d->materials[index];
+ if (!material)
+ return 0;
+
+ // Remove the material from the collection.
+ QGLMaterialPrivate *dm = material->d_func();
+ d->materials[index] = 0;
+ if (!dm->name.isEmpty())
+ d->materialNames.remove(dm->name);
+ material->setParent(0);
+
+ // Detach from the owning collection.
+ dm->collection = 0;
+ dm->index = -1;
+ return material;
+}
+
+/*!
+ Returns true if this collection is empty, false otherwise.
+
+ \sa size()
+*/
+bool QGLMaterialCollection::isEmpty() const
+{
+ Q_D(const QGLMaterialCollection);
+ return d->materials.isEmpty();
+}
+
+/*!
+ Returns the number of (possibly null) materials in this collection.
+ Null materials result from calling removeMaterial().
+
+ \sa isEmpty()
+*/
+int QGLMaterialCollection::size() const
+{
+ Q_D(const QGLMaterialCollection);
+ return d->materials.size();
+}
+
+/*!
+ \internal
+ Responds to the destroyed() signal by calling removeMaterial() on the
+ material about to be deleted;
+*/
+void QGLMaterialCollection::materialDeleted()
+{
+ removeMaterial(qobject_cast<QGLMaterial *>(sender()));
+}
diff --git a/src/threed/geometry/qglmaterialcollection.h b/src/threed/geometry/qglmaterialcollection.h
new file mode 100644
index 000000000..52ec79bec
--- /dev/null
+++ b/src/threed/geometry/qglmaterialcollection.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLMATERIALCOLLECTION_H
+#define QGLMATERIALCOLLECTION_H
+
+#include <QtCore/qobject.h>
+
+#include "qt3dglobal.h"
+#include "qglmaterial.h"
+#include "qgltexture2d.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLMaterialCollectionPrivate;
+
+class Q_QT3D_EXPORT QGLMaterialCollection : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGLMaterialCollection)
+ Q_DISABLE_COPY(QGLMaterialCollection)
+public:
+ QGLMaterialCollection(QObject *parent = 0);
+ virtual ~QGLMaterialCollection();
+
+ QGLMaterial *material(int index) const;
+ QGLMaterial *material(const QString &name) const;
+
+ bool contains(QGLMaterial *material) const;
+ bool contains(const QString &name) const;
+
+ int indexOf(QGLMaterial *material) const;
+ int indexOf(const QString &name) const;
+
+ QString materialName(int index) const;
+
+ bool isMaterialUsed(int index) const;
+ void markMaterialAsUsed(int index);
+ void removeUnusedMaterials();
+
+ int addMaterial(QGLMaterial *material);
+ void removeMaterial(QGLMaterial *material);
+ QGLMaterial *removeMaterial(int index);
+
+ bool isEmpty() const;
+ int size() const;
+
+private Q_SLOTS:
+ void materialDeleted();
+
+private:
+ QScopedPointer<QGLMaterialCollectionPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGLMATERIALCOLLECTION_H
diff --git a/src/threed/geometry/qglsection.cpp b/src/threed/geometry/qglsection.cpp
new file mode 100644
index 000000000..3775af4ee
--- /dev/null
+++ b/src/threed/geometry/qglsection.cpp
@@ -0,0 +1,696 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglsection_p.h"
+#include "qglbuilder_p.h"
+#include "qarray.h"
+#include "qvector_utils_p.h"
+
+#include <QtGui/qvector3d.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qbitarray.h>
+
+#include <limits.h>
+
+/*!
+ \internal
+ \class QGLSection
+ \brief The QGLSection class clusters like geometry in a QGLBuilder.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ QGLSection instances partition a QGLBuilder into related sections,
+ while the builder is being initialized with geometry data.
+
+ Once the builder is initialized, and geometry building is complete
+ the QGLSection instances are destroyed and the data is uploaded to the
+ graphics hardware.
+
+ The QGLSection class is a work horse for the QGLBuilder, and it
+ takes care of automatically managing vertex data. As such
+ for usual use cases, its functionality will not need to be referenced
+ directly. For low-level access to geometry, QGLSection provides a
+ range of accessors to reference geometry data during scene building.
+
+ Within a section, incoming geometry data will be coalesced and
+ indexes created to reference the fewest possible copies of the vertex
+ data. For example, in smooth geometry all copies of a vertex are
+ coalesced into one, and referenced by indices - except in the case
+ where texture data forms a \i seam and a copy must be created to carry
+ the two texture coordinates of the seam.
+
+ This is handled automatically by QGLSection, to pack data into the
+ smallest space possible thus improving cache coherence and performance.
+
+ All the vertices in a QGLSection are treated with the same
+ \l{QGL::Smoothing}{smoothing}, and have the same
+ \l{QLogicalVertex::Type}{data types}.
+
+ Each QGLSection references a contiguous range of vertices in a
+ QGLBuilder.
+
+ A QGLBuilder instance has the \l{QGLBuilder::newSection()}{newSection()}
+ function which creates a new QGLSection to reference its data. Use this
+ to construct new QGLSection instances, or alternatively construct
+ a new QGLSection() and pass a non-null QGLBuilder pointer.
+
+ These functions all return QVector values. QVector instances are
+ implicitly shared, thus the copies are inexpensive unless a
+ non-const function is called on them, triggering a copy-on-write.
+
+ Generally for adding geometry, use append(). This function simply
+ calls virtual protected functions appendSmooth() (for smoothed vertices)
+ and appendFaceted() (for faceted vertices). See QGLBuilder for a
+ discussion of smoothing.
+*/
+
+// allow QVector3D's to be stored in a QMap
+inline bool operator<(const QVector3D &a, const QVector3D &b)
+{
+ if (qFskCompare(a.x(), b.x()))
+ {
+ if (qFskCompare(a.y(), b.y()))
+ {
+ if (qFskCompare(a.z(), b.z()))
+ {
+ return false; // equal so not less-than
+ }
+ else
+ {
+ return a.z() < b.z();
+ }
+ }
+ else
+ {
+ return a.y() < b.y();
+ }
+ }
+ else
+ {
+ return a.x() < b.x();
+ }
+}
+
+static inline bool qSameDirection(const QVector3D &a , const QVector3D &b)
+{
+ bool res = false;
+ if (!a.isNull() && !b.isNull())
+ {
+ float dot = QVector3D::dotProduct(a, b);
+ res = qFskCompare((qreal)dot, a.length() * b.length());
+ }
+ return res;
+}
+
+class QGLSectionPrivate
+{
+public:
+ QGLSectionPrivate(const QVector3DArray *ary)
+ : vec_data(ary)
+ , it(vec_map.end())
+ , map_threshold(5)
+ , number_mapped(0)
+ , start_ptr(-1)
+ , end_ptr(-1)
+ {
+ normIndices.fill(-1, 32);
+ }
+
+ ~QGLSectionPrivate() {}
+
+ bool normalAccumulated(int index, const QVector3D &norm) const
+ {
+ if (index >= normIndices.size())
+ return false;
+ int ptr = normIndices.at(index);
+ while (ptr != -1)
+ {
+ int val_ptr = normPtrs.at(ptr);
+ //if (normValues.at(val_ptr) == norm)
+ if (qSameDirection(normValues.at(val_ptr), norm))
+ return true;
+ ptr = normPtrs.at(ptr+1);
+ }
+ return false;
+ }
+
+ void accumulateNormal(int index, const QVector3D &norm)
+ {
+ int new_norm_index = normValues.size();
+ normValues.append(norm);
+ if (normIndices.size() <= index)
+ {
+ int old_size = normIndices.size();
+ normIndices.extend(32);
+ for (int i = old_size; i < normIndices.size(); ++i)
+ normIndices[i] = -1;
+ }
+ int new_norm_ptr = normPtrs.size();
+ normPtrs.append(new_norm_index); // even ptrs point to vector value
+ normPtrs.append(-1); // odd ptrs point to next in normPtr linked list
+ if (normIndices.at(index) == -1)
+ {
+ normIndices[index] = new_norm_ptr;
+ }
+ else
+ {
+ int norm_ptr = normIndices.at(index);
+ while (normPtrs.at(norm_ptr + 1) != -1)
+ {
+ norm_ptr = normPtrs.at(norm_ptr + 1);
+ }
+ normPtrs[norm_ptr+1] = new_norm_ptr;
+ }
+ }
+
+ void mapVertex(const QVector3D &v, int ix)
+ {
+ Q_UNUSED(ix);
+ Q_UNUSED(v);
+ static bool seeded = false;
+ if (!seeded)
+ qsrand(31415);
+ Q_ASSERT(vec_data->at(ix) == v);
+ if ((vec_data->size() - number_mapped) > map_threshold)
+ {
+ int to_map = vec_data->size() - number_mapped;
+ QArray<int, 100> shuffle(to_map, -1);
+ for (int i = number_mapped, k = 0; i < vec_data->size(); ++i, ++k)
+ shuffle[k] = i;
+ for (int n = to_map; n > 1; --n)
+ {
+ int k = qrand() % n;
+ int tmp = shuffle[k];
+ shuffle[k] = shuffle[n - 1];
+ shuffle[n - 1] = tmp;
+ }
+ for (int i = 0; i < to_map; ++i)
+ vec_map.insertMulti(vec_data->at(shuffle.at(i)), shuffle.at(i));
+ number_mapped += to_map;
+ }
+ }
+
+ int nextIndex()
+ {
+ int result = -1;
+ if (end_ptr != -1)
+ {
+ // first look through the unmapped items
+ while (start_ptr <= end_ptr && result == -1)
+ {
+ // search from the end and beginning, favouring the end - most often
+ // its in the last few we added, sometimes in the first ones
+ if (qFskCompare(vec_data->at(end_ptr--), target))
+ result = end_ptr+1;
+ else if (start_ptr <= end_ptr && qFskCompare(vec_data->at(end_ptr--), target))
+ result = end_ptr+1;
+ else if (start_ptr <= end_ptr && qFskCompare(vec_data->at(start_ptr++), target))
+ result = start_ptr-1;
+ }
+ // if that found nothing, have a look at the map
+ if (result == -1)
+ {
+ start_ptr = -1;
+ end_ptr = -1;
+ it = vec_map.constEnd();
+ if (vec_map.size() > 0)
+ it = vec_map.find(target);
+ }
+ }
+ if (it != vec_map.constEnd())
+ {
+ // if there was something in the map see if its still on target
+ if (qFskCompare(it.key(), target))
+ {
+ result = it.value();
+ ++it; // increment to find more insertMulti instances
+ }
+ else
+ {
+ // not on target - flag that we're done here
+ it = vec_map.constEnd();
+ }
+ }
+ return result;
+ }
+
+ int findVertex(const QVector3D &v)
+ {
+ end_ptr = vec_data->size() - 1; // last one not in QMap
+ start_ptr = number_mapped; // first one not in QMap
+ target = v;
+ return nextIndex();
+ }
+
+ // mapper
+ int index;
+ QVector3D target;
+ const QVector3DArray *vec_data;
+ QMap<QVector3D, int> vec_map;
+ QMap<int, int> index_map;
+ QMap<QVector3D,int>::const_iterator it;
+ int map_threshold; // if more than this is unmapped, do a mapping run
+ int number_mapped; // how many vertices have been mapped
+ int start_ptr;
+ int end_ptr;
+
+ QArray<int, 32> normIndices;
+ QArray<int, 32> normPtrs;
+ QArray<QVector3D, 32> normValues;
+
+ QList<QGLSceneNode*> nodes;
+};
+
+/*!
+ \internal
+ Construct a new QGLSection on \a builder, and with smoothing \a s.
+ By default the smoothing is QGL::Smooth.
+
+ See QGLBuilder for a discussion of smoothing.
+
+ The pointer \a list must be non-null, and in debug mode, unless QT_NO_DEBUG is
+ defined, this function will assert if \a list is null.
+
+ The following lines of code have identical effect:
+ \code
+ QGLSection *s = myDisplayList->newSection(QGL::Faceted);
+ QGLSection *s2 = new QGLSection(myDisplayList, QGL::Faceted);
+ \endcode
+*/
+QGLSection::QGLSection(QGLBuilder *builder, QGL::Smoothing s)
+ : m_smoothing(s)
+ , d(0)
+{
+ Q_ASSERT(builder);
+ enableField(QGL::Position);
+ Q_ASSERT(vertexData());
+ d = new QGLSectionPrivate(vertexData());
+ builder->addSection(this);
+}
+
+/*!
+ \internal
+ Destroy this QGLSection, recovering any resources.
+*/
+QGLSection::~QGLSection()
+{
+ delete d;
+}
+
+/*!
+ \internal
+ Reserve capacity for \a amount items. This may avoid realloc
+ overhead when a large number of items will be appended.
+*/
+void QGLSection::reserve(int amount)
+{
+ QGeometryData::reserve(amount);
+ d->normIndices.reserve(amount);
+ d->normPtrs.reserve(amount * 2);
+ d->normValues.reserve(amount);
+}
+
+/*!
+ \internal
+ Adds the logical vertices \a a, \a b and \c to this section. All
+ should have the same fields. This function is exactly equivalent to
+ \code
+ append(a); append(b); append(c);
+ \endcode
+
+ \sa appendSmooth(), appendFaceted()
+*/
+void QGLSection::append(const QLogicalVertex &a, const QLogicalVertex &b, const QLogicalVertex &c)
+{
+ Q_ASSERT(a.fields() == b.fields() && b.fields() == c.fields());
+ if (!a.hasField(QGL::Normal))
+ {
+ appendFaceted(a, b, c);
+ }
+ else
+ {
+ if (m_smoothing == QGL::Smooth)
+ appendSmooth(a, b, c);
+ else
+ appendFaceted(a, b, c);
+ }
+}
+
+/*!
+ \internal
+ Adds the logical vertex \a lv to this section.
+
+ Otherwise, if the \a lv does have a lighting normal; then the
+ vertex processing depends on the smoothing property of this section.
+ If this section has smoothing QGL::Smooth, then the append will be done
+ by calling appendSmooth(); or if this section has smoothing QGL::Faceted,
+ then the append will be done by calling appendFaceted().
+
+ \sa appendSmooth(), appendFaceted()
+*/
+void QGLSection::append(const QLogicalVertex &lv)
+{
+ if (!lv.hasField(QGL::Normal))
+ {
+ appendFaceted(lv);
+ }
+ else
+ {
+ if (m_smoothing == QGL::Smooth)
+ appendSmooth(lv);
+ else
+ appendFaceted(lv);
+ }
+}
+
+static bool qCompareByAttributes(const QLogicalVertex &a, const QLogicalVertex &b)
+{
+ static const quint32 ATTRS_AND_TEXTURES = (0xFFFFFFFF << QGL::TextureCoord0);
+ quint32 af = a.fields() & ATTRS_AND_TEXTURES;
+ quint32 bf = b.fields() & ATTRS_AND_TEXTURES;
+ if (af != bf)
+ return false;
+ quint32 flds = af | bf;
+ const quint32 mask = 0x01;
+ flds >>= QGL::TextureCoord0;
+ for (int i = QGL::TextureCoord0; flds; ++i, flds >>= 1)
+ {
+ if (flds & mask)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(i);
+ if (attr < QGL::CustomVertex0)
+ {
+ if (!qFskCompare(a.texCoord(attr), b.texCoord(attr)))
+ return false;
+ }
+ else
+ {
+ QVariant v1 = a.attribute(attr);
+ QVariant v2 = b.attribute(attr);
+ if (v1.type() == (QVariant::Type)QMetaType::Float)
+ return qFskCompare(v1.toFloat(), v2.toFloat());
+ else if (v1.type() == QVariant::Vector2D)
+ return qFskCompare(qVariantValue<QVector2D>(v1), qVariantValue<QVector2D>(v2));
+ else if (v1.type() == QVariant::Vector3D)
+ return qFskCompare(qVariantValue<QVector3D>(v1), qVariantValue<QVector3D>(v2));
+ else
+ return v1 == v2;
+ }
+ }
+ }
+ return true;
+}
+
+int QGLSection::appendOne(const QLogicalVertex &lv)
+{
+#ifndef QT_NO_DEBUG_STREAM
+ if (count() && lv.fields() != fields())
+ {
+ qDebug() << "Warning: adding" << lv << "fields:" << lv.fields()
+ << "fields do not match existing:" << fields()
+ << "create new section first?";
+ }
+#endif
+ int index = appendVertex(lv);
+ d->mapVertex(lv.vertex(), index);
+ appendIndex(index);
+ return index;
+}
+
+/*!
+ \internal
+ Adds the logical vertex \a lv to this section of a builder.
+
+ Two QLogicalVertex instances a and b are treated as being duplicates for
+ the purpose of smoothing, if \c{qFuzzyCompare(a.vertex(), b.vertex())} is
+ true
+
+ All duplicate occurrences of a vertex are coalesced, that is replaced
+ by a GL index referencing the one copy.
+
+ In order to draw \a lv as part of a smooth continuous surface, with
+ no distinct edge, duplicates of vertex \a lv are coalesced into one
+ (within this section) and the normal for that one set to the average of
+ the incoming unique normals.
+
+ The incoming vertex \a lv is not treated as a duplicate if \a lv has
+ different texture coordinates or attributes. This occurs for example
+ in the case of a texture seam, where two different texture coordinates
+ are required at the same point on the geometry.
+
+ In that case a new duplicate vertex is added to carry the unique
+ texture coordinates or attributes. When new vertex copies are added in
+ this way all copies receive the averaged normals.
+
+ Call this function to add the vertices of a smooth face to the section
+ of a builder, or use:
+
+ \code
+ myDisplayList->newSection(QGLBuilder::Smooth);
+ myDisplayList->addTriangle(a, b, c);
+ \endcode
+
+ In smooth surfaces, the vertex and its normal is only sent to the
+ graphics hardware once (not once per face), thus smooth geometry may
+ consume fewer resources.
+
+ \sa appendFaceted(), updateTexCoord(), QGLBuilder::newSection()
+*/
+void QGLSection::appendSmooth(const QLogicalVertex &lv)
+{
+ Q_ASSERT(lv.hasField(QGL::Position));
+ Q_ASSERT(lv.hasField(QGL::Normal));
+
+ int found_index = d->findVertex(lv.vertex());
+ bool coalesce = false;
+ if (found_index == -1)
+ {
+ int newIndex = appendOne(lv);
+ d->accumulateNormal(newIndex, lv.normal());
+ }
+ else
+ {
+ while (!coalesce && found_index != -1)
+ {
+ if (qCompareByAttributes(lv, logicalVertexAt(found_index)))
+ coalesce = true;
+ else
+ found_index = d->nextIndex();
+ }
+ if (!coalesce) // texture or attributes prevented coalesce
+ {
+ // new vert to carry tex/attrib data
+ d->accumulateNormal(appendOne(lv), lv.normal());
+ }
+ else
+ {
+ appendIndex(found_index);
+ while (found_index != -1)
+ {
+ if (!d->normalAccumulated(found_index, lv.normal()))
+ {
+ normal(found_index) += lv.normal();
+ d->accumulateNormal(found_index, lv.normal());
+ }
+ found_index = d->nextIndex();
+ }
+ }
+ }
+}
+
+
+void QGLSection::appendSmooth(const QLogicalVertex &lv, int index)
+{
+ Q_ASSERT(lv.hasField(QGL::Position));
+ Q_ASSERT(lv.hasField(QGL::Normal));
+
+ int found_index = -1;
+ QMap<int, int>::const_iterator it = d->index_map.constFind(index);
+ if (it != d->index_map.constEnd())
+ found_index = it.value();
+ if (found_index == -1)
+ {
+ int newIndex = appendVertex(lv);
+ d->index_map.insert(index, newIndex);
+ appendIndex(newIndex);
+ d->accumulateNormal(newIndex, lv.normal());
+ }
+ else
+ {
+ appendIndex(found_index);
+ if (!d->normalAccumulated(found_index, lv.normal()))
+ {
+ normal(found_index) += lv.normal();
+ d->accumulateNormal(found_index, lv.normal());
+ }
+ }
+}
+
+/*!
+ \internal
+ Add the logical vertex \a lv to this section of a builder.
+
+ The vertex will be drawn as a distinct edge, instead of just part of a
+ continuous smooth surface. To acheive this the vertex value of \a lv
+ is duplicated for each unique normal in the current section.
+
+ Note that duplication is only for unique normals: if a vertex is already
+ present with a given normal it is coalesced and simply referenced by index.
+ As for appendSmooth() vertices are not coalesced in this way if \a lv
+ has a different texture coordinate or attribute than its duplicate.
+
+ In faceted surfaces, the vertex is sent to the graphics hardware once for
+ each normal it has, and thus may consume more resources.
+
+ \sa appendSmooth(), updateTexCoord(), QGLBuilder::newSection()
+*/
+void QGLSection::appendFaceted(const QLogicalVertex &lv)
+{
+ Q_ASSERT(lv.hasField(QGL::Position));
+ int found_index = d->findVertex(lv.vertex());
+ bool coalesce = false;
+ while (!coalesce && found_index != -1)
+ {
+ if (logicalVertexAt(found_index) == lv)
+ coalesce = true;
+ else
+ found_index = d->nextIndex();
+ }
+ if (coalesce) // found
+ {
+ appendIndex(found_index);
+ }
+ else
+ {
+ appendOne(lv);
+ }
+}
+
+/*!
+ \internal
+ Returns the current map threshold for this section. The threshold is the
+ point at which the section switches from using a plain QArray - with
+ linear performance ie O(n) - to using a QMap - with approx O(log n). These
+ structures are used for looking up vertices during the index generation and
+ normals calculation.
+
+ The default value is 50.
+
+ \sa setMapThreshold()
+*/
+int QGLSection::mapThreshold() const
+{
+ return d->map_threshold;
+}
+
+/*!
+ \internal
+ Sets the current map threshold to \a t for this section.
+
+ \sa mapThreshold()
+*/
+void QGLSection::setMapThreshold(int t)
+{
+ d->map_threshold = t;
+}
+
+/*!
+ \internal
+ Returns a list of the QGLSceneNode instances associated with this section.
+*/
+QList<QGLSceneNode*> QGLSection::nodes() const
+{
+ return d->nodes;
+}
+
+/*!
+ \internal
+ Adds the \a node to the list of QGLSceneNode instances associated with
+ this section.
+*/
+void QGLSection::addNode(QGLSceneNode *node)
+{
+ d->nodes.append(node);
+}
+
+/*!
+ \internal
+ Deletes the \a node from the list of QGLSceneNode instances associated
+ with this section. Returns true if the \a node was found, false
+ otherwise.
+*/
+bool QGLSection::deleteNode(QGLSceneNode *node)
+{
+ int ix = d->nodes.indexOf(node);
+ if (ix != -1)
+ {
+ d->nodes.removeAt(ix);
+ return true;
+ }
+ return false;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \internal
+ Output a string representation of \a section to a debug stream \a dbg.
+ \relates QGLSection
+*/
+QDebug operator<<(QDebug dbg, const QGLSection &section)
+{
+ dbg.space()
+ << "QGLSection(" << &section
+ << "- count:" << section.count()
+ << "- smoothing mode:" << (section.smoothing() == QGL::Smooth ?
+ "QGL::Smooth" : "QGL::Faceted") << "\n";
+ QGL::IndexArray indices = section.indices();
+ for (int i = 0; i < section.count(); ++i)
+ {
+ int ix = indices[i];
+ dbg << section.logicalVertexAt(ix) << "\n";
+ }
+ dbg << ")\n";
+ return dbg.space();
+}
+#endif
diff --git a/src/threed/geometry/qglsection_p.h b/src/threed/geometry/qglsection_p.h
new file mode 100644
index 000000000..ea48ff1b1
--- /dev/null
+++ b/src/threed/geometry/qglsection_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSECTION_H
+#define QGLSECTION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglpainter.h"
+#include "qlogicalvertex.h"
+#include "qbox3d.h"
+#include "qglnamespace.h"
+
+#include <QtOpenGL/qgl.h>
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLPainter;
+class QGLBuilder;
+class QGLSectionPrivate;
+class QGeometryData;
+class QGLSceneNode;
+
+class Q_QT3D_EXPORT QGLSection : public QGeometryData
+{
+public:
+ QGLSection(QGLBuilder *d, QGL::Smoothing sm = QGL::Smooth);
+ ~QGLSection();
+
+ void reserve(int amount);
+
+ void append(const QLogicalVertex &lv);
+ void append(const QLogicalVertex &a, const QLogicalVertex &b, const QLogicalVertex &c);
+ void appendSmooth(const QLogicalVertex &lv);
+ void appendSmooth(const QLogicalVertex &lv, int index);
+ void appendSmooth(const QLogicalVertex &a, const QLogicalVertex &b, const QLogicalVertex &c)
+ {
+ appendSmooth(a);
+ appendSmooth(b);
+ appendSmooth(c);
+ }
+ void appendFaceted(const QLogicalVertex &lv);
+ void appendFaceted(const QLogicalVertex &a, const QLogicalVertex &b, const QLogicalVertex &c)
+ {
+ appendFaceted(a);
+ appendFaceted(b);
+ appendFaceted(c);
+ }
+
+ inline QGL::Smoothing smoothing() const;
+ inline void setSmoothing(QGL::Smoothing s);
+ int mapThreshold() const;
+ void setMapThreshold(int);
+ QList<QGLSceneNode*> nodes() const;
+ void addNode(QGLSceneNode *node);
+ bool deleteNode(QGLSceneNode *node);
+private:
+ Q_DISABLE_COPY(QGLSection);
+ friend class QGLBuilder;
+
+ int appendOne(const QLogicalVertex &vertex);
+
+ QGL::Smoothing m_smoothing;
+ QGLSectionPrivate *d;
+};
+
+inline QGL::Smoothing QGLSection::smoothing() const
+{
+ return m_smoothing;
+}
+
+inline void QGLSection::setSmoothing(QGL::Smoothing s)
+{
+ m_smoothing = s;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QGLSection &section);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QGLSECTION_H
diff --git a/src/threed/geometry/qglsphere.cpp b/src/threed/geometry/qglsphere.cpp
new file mode 100644
index 000000000..9a8976ac3
--- /dev/null
+++ b/src/threed/geometry/qglsphere.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglsphere.h"
+#include "qglbuilder.h"
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLSphere
+ \brief The QGLSphere class represents the geometry of a simple sphere in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ The following example creates a sphere of 2 units in diameter and
+ draws it at (10, 25, 0) in a QGLPainter:
+
+ \code
+ QGLBuilder builder;
+ builder << QGLSphere(2);
+ QGLSceneNode *node = builder.finalizedSceneNode();
+
+ painter.translate(10, 25, 0);
+ node->draw(&painter);
+ \endcode
+
+ The QGLSphere class specifies positions, normals and 2D texture
+ co-ordinates for all of the vertices that make up the sphere.
+
+ The texture co-ordinates are fixed at construction time. This
+ is because constructing the sphere can involve generating additional
+ vertices which need to interpolate the texture co-ordinates of their
+ neighboring vertices.
+
+ The default mode of QGLSphere is a "UV sphere", which divides the
+ sphere up into longitudinal and latitudinal sections. The longitudinal
+ slices meet at the poles, which in a single unit sphere are defined to
+ be at (0, 0, +0.5) and (0, 0, -0.5). This choice is the simplest to
+ texture map as the texture will only distort along the x-axis of the
+ 2D texture. However the density of vertices is significantly higher at
+ the poles than it is elsewhere on the sphere and is a poor choice if a
+ uniform density of pixels from the texture map is required.
+
+ \sa QGLBuilder
+*/
+
+/*!
+ \fn QGLSphere::QGLSphere(qreal diameter, int depth)
+
+ Creates a sphere of \a diameter across (default is 1). When the sphere
+ is recursively subdivided into triangles, it will be subdivided no more
+ than \a depth times (between 1 and 10, default is 5).
+*/
+
+/*!
+ Destroys this sphere object.
+*/
+QGLSphere::~QGLSphere()
+{
+}
+
+/*!
+ \fn qreal QGLSphere::diameter() const
+
+ Returns the diameter of this sphere. The default is 1.
+
+ \sa setDiameter()
+*/
+
+/*!
+ \fn void QGLSphere::setDiameter(qreal diameter)
+
+ Sets the diameter of this sphere to \a diameter.
+
+ \sa diameter()
+*/
+
+/*!
+ \fn int QGLSphere::subdivisionDepth() const
+
+ Returns the maximum depth when this sphere is subdivided into triangles.
+ The default is 5. The following picture shows the effect of depth
+ values between 1 and 10 for a UV sphere:
+
+ \image sphere-detail.png
+
+ \table
+ \header \o Level of Detail \o Number of Triangles
+ \row \o 1 \o 64
+ \row \o 2 \o 128
+ \row \o 3 \o 256
+ \row \o 4 \o 512
+ \row \o 5 \o 1024
+ \row \o 6 \o 2048
+ \row \o 7 \o 4096
+ \row \o 8 \o 8192
+ \row \o 9 \o 16384
+ \row \o 10 \o 32768
+ \endtable
+
+ \sa setSubdivisionDepth()
+*/
+
+/*!
+ \fn void QGLSphere::setSubdivisionDepth(int depth)
+
+ Sets the maximum \a depth when this sphere is subdivided into triangles.
+
+ \sa subdivisionDepth()
+*/
+
+/*!
+ \relates QGLSphere
+
+ Builds the geometry for \a sphere within the specified
+ geometry \a builder.
+*/
+QGLBuilder& operator<<(QGLBuilder& builder, const QGLSphere& sphere)
+{
+ qreal radius = sphere.diameter() / 2.0f;
+
+ // Determine the number of slices and stacks to generate.
+ static int const slicesAndStacks[] = {
+ 8, 4,
+ 8, 8,
+ 16, 8,
+ 16, 16,
+ 32, 16,
+ 32, 32,
+ 64, 32,
+ 64, 64,
+ 128, 64,
+ 128, 128
+ };
+ int divisions = sphere.subdivisionDepth();
+ if (divisions < 1)
+ divisions = 1;
+ else if (divisions > 10)
+ divisions = 10;
+ int stacks = slicesAndStacks[divisions * 2 - 1];
+ int slices = slicesAndStacks[divisions * 2 - 2];
+
+ // Precompute sin/cos values for the slices and stacks.
+ const int maxSlices = 128 + 1;
+ const int maxStacks = 128 + 1;
+ qreal sliceSin[maxSlices];
+ qreal sliceCos[maxSlices];
+ qreal stackSin[maxStacks];
+ qreal stackCos[maxStacks];
+ for (int slice = 0; slice < slices; ++slice) {
+ qreal angle = 2 * M_PI * slice / slices;
+ sliceSin[slice] = qFastSin(angle);
+ sliceCos[slice] = qFastCos(angle);
+ }
+ sliceSin[slices] = sliceSin[0]; // Join first and last slice.
+ sliceCos[slices] = sliceCos[0];
+ for (int stack = 0; stack <= stacks; ++stack) {
+ qreal angle = M_PI * stack / stacks;
+ stackSin[stack] = qFastSin(angle);
+ stackCos[stack] = qFastCos(angle);
+ }
+ stackSin[0] = 0.0f; // Come to a point at the poles.
+ stackSin[stacks] = 0.0f;
+
+ // Create the stacks.
+ for (int stack = 0; stack < stacks; ++stack) {
+ QGeometryData prim;
+ qreal z = radius * stackCos[stack];
+ qreal nextz = radius * stackCos[stack + 1];
+ qreal s = stackSin[stack];
+ qreal nexts = stackSin[stack + 1];
+ qreal c = stackCos[stack];
+ qreal nextc = stackCos[stack + 1];
+ qreal r = radius * s;
+ qreal nextr = radius * nexts;
+ for (int slice = 0; slice <= slices; ++slice) {
+ prim.appendVertex
+ (QVector3D(nextr * sliceSin[slice],
+ nextr * sliceCos[slice], nextz));
+ prim.appendNormal
+ (QVector3D(sliceSin[slice] * nexts,
+ sliceCos[slice] * nexts, nextc));
+ prim.appendTexCoord
+ (QVector2D(1.0f - qreal(slice) / slices,
+ 1.0f - qreal(stack + 1) / stacks));
+
+ prim.appendVertex
+ (QVector3D(r * sliceSin[slice],
+ r * sliceCos[slice], z));
+ prim.appendNormal
+ (QVector3D(sliceSin[slice] * s,
+ sliceCos[slice] * s, c));
+ prim.appendTexCoord
+ (QVector2D(1.0f - qreal(slice) / slices,
+ 1.0f - qreal(stack) / stacks));
+ }
+ builder.addQuadStrip(prim);
+ }
+
+ return builder;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/geometry/qglsphere.h b/src/threed/geometry/qglsphere.h
new file mode 100644
index 000000000..784f9db4c
--- /dev/null
+++ b/src/threed/geometry/qglsphere.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSPHERE_H
+#define QGLSPHERE_H
+
+#include "qt3dglobal.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLBuilder;
+
+class Q_QT3D_EXPORT QGLSphere
+{
+public:
+ explicit QGLSphere(qreal diameter = 1.0f, int depth = 5)
+ : m_diameter(diameter), m_subdivisionDepth(depth) {}
+ virtual ~QGLSphere();
+
+ qreal diameter() const { return m_diameter; }
+ void setDiameter(qreal diameter) { m_diameter = diameter; }
+
+ int subdivisionDepth() const { return m_subdivisionDepth; }
+ void setSubdivisionDepth(int depth) { m_subdivisionDepth = depth; }
+
+private:
+ qreal m_diameter;
+ int m_subdivisionDepth;
+};
+
+Q_QT3D_EXPORT QGLBuilder& operator<<(QGLBuilder& builder, const QGLSphere& sphere);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/geometry/qglteapot.cpp b/src/threed/geometry/qglteapot.cpp
new file mode 100644
index 000000000..fb2419dce
--- /dev/null
+++ b/src/threed/geometry/qglteapot.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglteapot.h"
+#include "qglteapot_data_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLTeapot
+ \brief The QGLTeapot class represents a 3D teapot object.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ The classic 3D "Utah Teapot" was originally drawn by Martin Newell
+ in 1975. The vertex data was made publicly available by him and
+ it has been a standard 3D test object ever since.
+
+ For more information on the history of the "Utah Teapot", see
+ Wikipedia, http://en.wikipedia.org/wiki/Utah_teapot.
+
+ The following example code uses QGLTeapot to draw a teapot of size
+ 0.5 at the origin:
+
+ \code
+ QGLBuilder builder;
+ builder << QGLTeapot();
+ teapot = builder.finalizedSceneNode();
+
+ painter.modelViewMatrix().scale(0.5f);
+ teapot->draw(painter);
+ \endcode
+
+ The QGLTeapot object contains a lot of vertex data once it has
+ been subdivided into triangles. It is recommended that instances
+ of this class be created at startup, added to a QGLBuilder,
+ and then the finalized scene node can be reused over and over.
+
+ \sa QGLBezierPatches
+*/
+
+/*!
+ Constructs a new 3D teapot geometry object.
+*/
+QGLTeapot::QGLTeapot()
+{
+ QVector3DArray positions;
+ for (int pindex = 0; pindex < teapotPatchCount * 16; ++pindex) {
+ int vindex = teapotPatchData[pindex];
+ positions.append(teapotBezierVertexData[vindex * 3],
+ teapotBezierVertexData[vindex * 3 + 1],
+ teapotBezierVertexData[vindex * 3 + 2]);
+ }
+ setPositions(positions);
+ setSubdivisionDepth(teapotDepth);
+}
+
+/*!
+ Destroys this teapot geometry object.
+*/
+QGLTeapot::~QGLTeapot()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/geometry/qglteapot.h b/src/threed/geometry/qglteapot.h
new file mode 100644
index 000000000..290ff23d9
--- /dev/null
+++ b/src/threed/geometry/qglteapot.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTEAPOT_H
+#define QGLTEAPOT_H
+
+#include "qglbezierpatches.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QGLTeapot : public QGLBezierPatches
+{
+public:
+ QGLTeapot();
+ ~QGLTeapot();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/geometry/qglteapot_data_p.h b/src/threed/geometry/qglteapot_data_p.h
new file mode 100644
index 000000000..28dbfa7ac
--- /dev/null
+++ b/src/threed/geometry/qglteapot_data_p.h
@@ -0,0 +1,408 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTEAPOT_DATA_P_H
+#define QGLTEAPOT_DATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglbezierpatches.h"
+
+// Generated from teapot.txt by meshcvt, depth = 4
+
+#define teapotBezierVertexCount 306
+#define teapotBezierVertexStride 3
+#define teapotPatchCount 32
+#define teapotDepth 4
+static float const teapotBezierVertexData[] = {
+ 0.700000f, 0.450000f, -0.000000f,
+ 0.700000f, 0.450000f, 0.392000f,
+ 0.392000f, 0.450000f, 0.700000f,
+ 0.000000f, 0.450000f, 0.700000f,
+ 0.668750f, 0.515625f, -0.000000f,
+ 0.668750f, 0.515625f, 0.374500f,
+ 0.374500f, 0.515625f, 0.668750f,
+ 0.000000f, 0.515625f, 0.668750f,
+ 0.718750f, 0.515625f, -0.000000f,
+ 0.718750f, 0.515625f, 0.402500f,
+ 0.402500f, 0.515625f, 0.718750f,
+ 0.000000f, 0.515625f, 0.718750f,
+ 0.750000f, 0.450000f, -0.000000f,
+ 0.750000f, 0.450000f, 0.420000f,
+ 0.420000f, 0.450000f, 0.750000f,
+ 0.000000f, 0.450000f, 0.750000f,
+ -0.392000f, 0.450000f, 0.700000f,
+ -0.700000f, 0.450000f, 0.392000f,
+ -0.700000f, 0.450000f, -0.000000f,
+ -0.374500f, 0.515625f, 0.668750f,
+ -0.668750f, 0.515625f, 0.374500f,
+ -0.668750f, 0.515625f, -0.000000f,
+ -0.402500f, 0.515625f, 0.718750f,
+ -0.718750f, 0.515625f, 0.402500f,
+ -0.718750f, 0.515625f, -0.000000f,
+ -0.420000f, 0.450000f, 0.750000f,
+ -0.750000f, 0.450000f, 0.420000f,
+ -0.750000f, 0.450000f, -0.000000f,
+ -0.700000f, 0.450000f, -0.392000f,
+ -0.392000f, 0.450000f, -0.700000f,
+ 0.000000f, 0.450000f, -0.700000f,
+ -0.668750f, 0.515625f, -0.374500f,
+ -0.374500f, 0.515625f, -0.668750f,
+ 0.000000f, 0.515625f, -0.668750f,
+ -0.718750f, 0.515625f, -0.402500f,
+ -0.402500f, 0.515625f, -0.718750f,
+ 0.000000f, 0.515625f, -0.718750f,
+ -0.750000f, 0.450000f, -0.420000f,
+ -0.420000f, 0.450000f, -0.750000f,
+ 0.000000f, 0.450000f, -0.750000f,
+ 0.392000f, 0.450000f, -0.700000f,
+ 0.700000f, 0.450000f, -0.392000f,
+ 0.374500f, 0.515625f, -0.668750f,
+ 0.668750f, 0.515625f, -0.374500f,
+ 0.402500f, 0.515625f, -0.718750f,
+ 0.718750f, 0.515625f, -0.402500f,
+ 0.420000f, 0.450000f, -0.750000f,
+ 0.750000f, 0.450000f, -0.420000f,
+ 0.875000f, 0.187500f, -0.000000f,
+ 0.875000f, 0.187500f, 0.490000f,
+ 0.490000f, 0.187500f, 0.875000f,
+ 0.000000f, 0.187500f, 0.875000f,
+ 1.000000f, -0.075000f, -0.000000f,
+ 1.000000f, -0.075000f, 0.560000f,
+ 0.560000f, -0.075000f, 1.000000f,
+ 0.000000f, -0.075000f, 1.000000f,
+ 1.000000f, -0.300000f, -0.000000f,
+ 1.000000f, -0.300000f, 0.560000f,
+ 0.560000f, -0.300000f, 1.000000f,
+ 0.000000f, -0.300000f, 1.000000f,
+ -0.490000f, 0.187500f, 0.875000f,
+ -0.875000f, 0.187500f, 0.490000f,
+ -0.875000f, 0.187500f, -0.000000f,
+ -0.560000f, -0.075000f, 1.000000f,
+ -1.000000f, -0.075000f, 0.560000f,
+ -1.000000f, -0.075000f, -0.000000f,
+ -0.560000f, -0.300000f, 1.000000f,
+ -1.000000f, -0.300000f, 0.560000f,
+ -1.000000f, -0.300000f, -0.000000f,
+ -0.875000f, 0.187500f, -0.490000f,
+ -0.490000f, 0.187500f, -0.875000f,
+ 0.000000f, 0.187500f, -0.875000f,
+ -1.000000f, -0.075000f, -0.560000f,
+ -0.560000f, -0.075000f, -1.000000f,
+ 0.000000f, -0.075000f, -1.000000f,
+ -1.000000f, -0.300000f, -0.560000f,
+ -0.560000f, -0.300000f, -1.000000f,
+ 0.000000f, -0.300000f, -1.000000f,
+ 0.490000f, 0.187500f, -0.875000f,
+ 0.875000f, 0.187500f, -0.490000f,
+ 0.560000f, -0.075000f, -1.000000f,
+ 1.000000f, -0.075000f, -0.560000f,
+ 0.560000f, -0.300000f, -1.000000f,
+ 1.000000f, -0.300000f, -0.560000f,
+ 1.000000f, -0.525000f, -0.000000f,
+ 1.000000f, -0.525000f, 0.560000f,
+ 0.560000f, -0.525000f, 1.000000f,
+ 0.000000f, -0.525000f, 1.000000f,
+ 0.750000f, -0.637500f, -0.000000f,
+ 0.750000f, -0.637500f, 0.420000f,
+ 0.420000f, -0.637500f, 0.750000f,
+ 0.000000f, -0.637500f, 0.750000f,
+ 0.750000f, -0.675000f, -0.000000f,
+ 0.750000f, -0.675000f, 0.420000f,
+ 0.420000f, -0.675000f, 0.750000f,
+ 0.000000f, -0.675000f, 0.750000f,
+ -0.560000f, -0.525000f, 1.000000f,
+ -1.000000f, -0.525000f, 0.560000f,
+ -1.000000f, -0.525000f, -0.000000f,
+ -0.420000f, -0.637500f, 0.750000f,
+ -0.750000f, -0.637500f, 0.420000f,
+ -0.750000f, -0.637500f, -0.000000f,
+ -0.420000f, -0.675000f, 0.750000f,
+ -0.750000f, -0.675000f, 0.420000f,
+ -0.750000f, -0.675000f, -0.000000f,
+ -1.000000f, -0.525000f, -0.560000f,
+ -0.560000f, -0.525000f, -1.000000f,
+ 0.000000f, -0.525000f, -1.000000f,
+ -0.750000f, -0.637500f, -0.420000f,
+ -0.420000f, -0.637500f, -0.750000f,
+ 0.000000f, -0.637500f, -0.750000f,
+ -0.750000f, -0.675000f, -0.420000f,
+ -0.420000f, -0.675000f, -0.750000f,
+ 0.000000f, -0.675000f, -0.750000f,
+ 0.560000f, -0.525000f, -1.000000f,
+ 1.000000f, -0.525000f, -0.560000f,
+ 0.420000f, -0.637500f, -0.750000f,
+ 0.750000f, -0.637500f, -0.420000f,
+ 0.420000f, -0.675000f, -0.750000f,
+ 0.750000f, -0.675000f, -0.420000f,
+ -0.800000f, 0.262500f, -0.000000f,
+ -0.800000f, 0.262500f, 0.150000f,
+ -0.750000f, 0.375000f, 0.150000f,
+ -0.750000f, 0.375000f, -0.000000f,
+ -1.150000f, 0.262500f, -0.000000f,
+ -1.150000f, 0.262500f, 0.150000f,
+ -1.250000f, 0.375000f, 0.150000f,
+ -1.250000f, 0.375000f, -0.000000f,
+ -1.350000f, 0.262500f, -0.000000f,
+ -1.350000f, 0.262500f, 0.150000f,
+ -1.500000f, 0.375000f, 0.150000f,
+ -1.500000f, 0.375000f, -0.000000f,
+ -1.350000f, 0.150000f, -0.000000f,
+ -1.350000f, 0.150000f, 0.150000f,
+ -1.500000f, 0.150000f, 0.150000f,
+ -1.500000f, 0.150000f, -0.000000f,
+ -0.750000f, 0.375000f, -0.150000f,
+ -0.800000f, 0.262500f, -0.150000f,
+ -1.250000f, 0.375000f, -0.150000f,
+ -1.150000f, 0.262500f, -0.150000f,
+ -1.500000f, 0.375000f, -0.150000f,
+ -1.350000f, 0.262500f, -0.150000f,
+ -1.500000f, 0.150000f, -0.150000f,
+ -1.350000f, 0.150000f, -0.150000f,
+ -1.350000f, 0.037500f, -0.000000f,
+ -1.350000f, 0.037500f, 0.150000f,
+ -1.500000f, -0.075000f, 0.150000f,
+ -1.500000f, -0.075000f, -0.000000f,
+ -1.250000f, -0.187500f, -0.000000f,
+ -1.250000f, -0.187500f, 0.150000f,
+ -1.325000f, -0.281250f, 0.150000f,
+ -1.325000f, -0.281250f, -0.000000f,
+ -1.000000f, -0.300000f, 0.150000f,
+ -0.950000f, -0.450000f, 0.150000f,
+ -0.950000f, -0.450000f, -0.000000f,
+ -1.500000f, -0.075000f, -0.150000f,
+ -1.350000f, 0.037500f, -0.150000f,
+ -1.325000f, -0.281250f, -0.150000f,
+ -1.250000f, -0.187500f, -0.150000f,
+ -0.950000f, -0.450000f, -0.150000f,
+ -1.000000f, -0.300000f, -0.150000f,
+ 0.850000f, -0.037500f, -0.000000f,
+ 0.850000f, -0.037500f, 0.330000f,
+ 0.850000f, -0.450000f, 0.330000f,
+ 0.850000f, -0.450000f, -0.000000f,
+ 1.300000f, -0.037500f, -0.000000f,
+ 1.300000f, -0.037500f, 0.330000f,
+ 1.550000f, -0.337500f, 0.330000f,
+ 1.550000f, -0.337500f, -0.000000f,
+ 1.150000f, 0.300000f, -0.000000f,
+ 1.150000f, 0.300000f, 0.125000f,
+ 1.200000f, 0.262500f, 0.125000f,
+ 1.200000f, 0.262500f, -0.000000f,
+ 1.350000f, 0.450000f, -0.000000f,
+ 1.350000f, 0.450000f, 0.125000f,
+ 1.650000f, 0.450000f, 0.125000f,
+ 1.650000f, 0.450000f, -0.000000f,
+ 0.850000f, -0.450000f, -0.330000f,
+ 0.850000f, -0.037500f, -0.330000f,
+ 1.550000f, -0.337500f, -0.330000f,
+ 1.300000f, -0.037500f, -0.330000f,
+ 1.200000f, 0.262500f, -0.125000f,
+ 1.150000f, 0.300000f, -0.125000f,
+ 1.650000f, 0.450000f, -0.125000f,
+ 1.350000f, 0.450000f, -0.125000f,
+ 1.400000f, 0.487500f, -0.000000f,
+ 1.400000f, 0.487500f, 0.125000f,
+ 1.762500f, 0.496875f, 0.125000f,
+ 1.762500f, 0.496875f, -0.000000f,
+ 1.450000f, 0.487500f, -0.000000f,
+ 1.450000f, 0.487500f, 0.075000f,
+ 1.725000f, 0.506250f, 0.075000f,
+ 1.725000f, 0.506250f, -0.000000f,
+ 1.400000f, 0.450000f, -0.000000f,
+ 1.400000f, 0.450000f, 0.075000f,
+ 1.600000f, 0.450000f, 0.075000f,
+ 1.600000f, 0.450000f, -0.000000f,
+ 1.762500f, 0.496875f, -0.125000f,
+ 1.400000f, 0.487500f, -0.125000f,
+ 1.725000f, 0.506250f, -0.075000f,
+ 1.450000f, 0.487500f, -0.075000f,
+ 1.600000f, 0.450000f, -0.075000f,
+ 1.400000f, 0.450000f, -0.075000f,
+ 0.000000f, 0.825000f, -0.000000f,
+ 0.000000f, 0.825000f, 0.001000f,
+ 0.001000f, 0.825000f, -0.000000f,
+ 0.400000f, 0.825000f, -0.000000f,
+ 0.400000f, 0.825000f, 0.225000f,
+ 0.225000f, 0.825000f, 0.400000f,
+ 0.000000f, 0.825000f, 0.400000f,
+ 0.000000f, 0.675000f, -0.000000f,
+ 0.100000f, 0.600000f, -0.000000f,
+ 0.100000f, 0.600000f, 0.056000f,
+ 0.056000f, 0.600000f, 0.100000f,
+ 0.000000f, 0.600000f, 0.100000f,
+ -0.001000f, 0.825000f, -0.000000f,
+ -0.225000f, 0.825000f, 0.400000f,
+ -0.400000f, 0.825000f, 0.225000f,
+ -0.400000f, 0.825000f, -0.000000f,
+ -0.056000f, 0.600000f, 0.100000f,
+ -0.100000f, 0.600000f, 0.056000f,
+ -0.100000f, 0.600000f, -0.000000f,
+ 0.000000f, 0.825000f, -0.001000f,
+ -0.400000f, 0.825000f, -0.225000f,
+ -0.225000f, 0.825000f, -0.400000f,
+ 0.000000f, 0.825000f, -0.400000f,
+ -0.100000f, 0.600000f, -0.056000f,
+ -0.056000f, 0.600000f, -0.100000f,
+ 0.000000f, 0.600000f, -0.100000f,
+ 0.225000f, 0.825000f, -0.400000f,
+ 0.400000f, 0.825000f, -0.225000f,
+ 0.056000f, 0.600000f, -0.100000f,
+ 0.100000f, 0.600000f, -0.056000f,
+ 0.200000f, 0.525000f, -0.000000f,
+ 0.200000f, 0.525000f, 0.112000f,
+ 0.112000f, 0.525000f, 0.200000f,
+ 0.000000f, 0.525000f, 0.200000f,
+ 0.650000f, 0.525000f, -0.000000f,
+ 0.650000f, 0.525000f, 0.364000f,
+ 0.364000f, 0.525000f, 0.650000f,
+ 0.000000f, 0.525000f, 0.650000f,
+ 0.650000f, 0.450000f, -0.000000f,
+ 0.650000f, 0.450000f, 0.364000f,
+ 0.364000f, 0.450000f, 0.650000f,
+ 0.000000f, 0.450000f, 0.650000f,
+ -0.112000f, 0.525000f, 0.200000f,
+ -0.200000f, 0.525000f, 0.112000f,
+ -0.200000f, 0.525000f, -0.000000f,
+ -0.364000f, 0.525000f, 0.650000f,
+ -0.650000f, 0.525000f, 0.364000f,
+ -0.650000f, 0.525000f, -0.000000f,
+ -0.364000f, 0.450000f, 0.650000f,
+ -0.650000f, 0.450000f, 0.364000f,
+ -0.650000f, 0.450000f, -0.000000f,
+ -0.200000f, 0.525000f, -0.112000f,
+ -0.112000f, 0.525000f, -0.200000f,
+ 0.000000f, 0.525000f, -0.200000f,
+ -0.650000f, 0.525000f, -0.364000f,
+ -0.364000f, 0.525000f, -0.650000f,
+ 0.000000f, 0.525000f, -0.650000f,
+ -0.650000f, 0.450000f, -0.364000f,
+ -0.364000f, 0.450000f, -0.650000f,
+ 0.000000f, 0.450000f, -0.650000f,
+ 0.112000f, 0.525000f, -0.200000f,
+ 0.200000f, 0.525000f, -0.112000f,
+ 0.364000f, 0.525000f, -0.650000f,
+ 0.650000f, 0.525000f, -0.364000f,
+ 0.364000f, 0.450000f, -0.650000f,
+ 0.650000f, 0.450000f, -0.364000f,
+ 0.000000f, -0.750000f, -0.000000f,
+ 0.750000f, -0.675000f, -0.000000f,
+ 0.750000f, -0.675000f, -0.420000f,
+ 0.420000f, -0.675000f, -0.750000f,
+ 0.000000f, -0.675000f, -0.750000f,
+ 0.750000f, -0.712500f, -0.000000f,
+ 0.750000f, -0.712500f, -0.420000f,
+ 0.420000f, -0.712500f, -0.750000f,
+ 0.000000f, -0.712500f, -0.750000f,
+ 0.712500f, -0.750000f, -0.000000f,
+ 0.712500f, -0.750000f, -0.399000f,
+ 0.399000f, -0.750000f, -0.712500f,
+ 0.000000f, -0.750000f, -0.712500f,
+ -0.420000f, -0.675000f, -0.750000f,
+ -0.750000f, -0.675000f, -0.420000f,
+ -0.750000f, -0.675000f, -0.000000f,
+ -0.420000f, -0.712500f, -0.750000f,
+ -0.750000f, -0.712500f, -0.420000f,
+ -0.750000f, -0.712500f, -0.000000f,
+ -0.399000f, -0.750000f, -0.712500f,
+ -0.712500f, -0.750000f, -0.399000f,
+ -0.712500f, -0.750000f, -0.000000f,
+ -0.750000f, -0.675000f, 0.420000f,
+ -0.420000f, -0.675000f, 0.750000f,
+ 0.000000f, -0.675000f, 0.750000f,
+ -0.750000f, -0.712500f, 0.420000f,
+ -0.420000f, -0.712500f, 0.750000f,
+ 0.000000f, -0.712500f, 0.750000f,
+ -0.712500f, -0.750000f, 0.399000f,
+ -0.399000f, -0.750000f, 0.712500f,
+ 0.000000f, -0.750000f, 0.712500f,
+ 0.420000f, -0.675000f, 0.750000f,
+ 0.750000f, -0.675000f, 0.420000f,
+ 0.420000f, -0.712500f, 0.750000f,
+ 0.750000f, -0.712500f, 0.420000f,
+ 0.399000f, -0.750000f, 0.712500f,
+ 0.712500f, -0.750000f, 0.399000f
+};
+
+static ushort const teapotPatchData[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 3, 16, 17, 18, 7, 19, 20, 21, 11, 22, 23, 24, 15, 25, 26, 27,
+ 18, 28, 29, 30, 21, 31, 32, 33, 24, 34, 35, 36, 27, 37, 38, 39,
+ 30, 40, 41, 0, 33, 42, 43, 4, 36, 44, 45, 8, 39, 46, 47, 12,
+ 12, 13, 14, 15, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 15, 25, 26, 27, 51, 60, 61, 62, 55, 63, 64, 65, 59, 66, 67, 68,
+ 27, 37, 38, 39, 62, 69, 70, 71, 65, 72, 73, 74, 68, 75, 76, 77,
+ 39, 46, 47, 12, 71, 78, 79, 48, 74, 80, 81, 52, 77, 82, 83, 56,
+ 56, 57, 58, 59, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 59, 66, 67, 68, 87, 96, 97, 98, 91, 99, 100, 101, 95, 102, 103, 104,
+ 68, 75, 76, 77, 98, 105, 106, 107, 101, 108, 109, 110, 104, 111, 112, 113,
+ 77, 82, 83, 56, 107, 114, 115, 84, 110, 116, 117, 88, 113, 118, 119, 92,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
+ 123, 136, 137, 120, 127, 138, 139, 124, 131, 140, 141, 128, 135, 142, 143, 132,
+ 132, 133, 134, 135, 144, 145, 146, 147, 148, 149, 150, 151, 68, 152, 153, 154,
+ 135, 142, 143, 132, 147, 155, 156, 144, 151, 157, 158, 148, 154, 159, 160, 68,
+ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
+ 164, 177, 178, 161, 168, 179, 180, 165, 172, 181, 182, 169, 176, 183, 184, 173,
+ 173, 174, 175, 176, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
+ 176, 183, 184, 173, 188, 197, 198, 185, 192, 199, 200, 189, 196, 201, 202, 193,
+ 203, 203, 203, 203, 206, 207, 208, 209, 210, 210, 210, 210, 211, 212, 213, 214,
+ 203, 203, 203, 203, 209, 216, 217, 218, 210, 210, 210, 210, 214, 219, 220, 221,
+ 203, 203, 203, 203, 218, 223, 224, 225, 210, 210, 210, 210, 221, 226, 227, 228,
+ 203, 203, 203, 203, 225, 229, 230, 206, 210, 210, 210, 210, 228, 231, 232, 211,
+ 211, 212, 213, 214, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
+ 214, 219, 220, 221, 236, 245, 246, 247, 240, 248, 249, 250, 244, 251, 252, 253,
+ 221, 226, 227, 228, 247, 254, 255, 256, 250, 257, 258, 259, 253, 260, 261, 262,
+ 228, 231, 232, 211, 256, 263, 264, 233, 259, 265, 266, 237, 262, 267, 268, 241,
+ 269, 269, 269, 269, 278, 279, 280, 281, 274, 275, 276, 277, 270, 271, 272, 273,
+ 269, 269, 269, 269, 281, 288, 289, 290, 277, 285, 286, 287, 273, 282, 283, 284,
+ 269, 269, 269, 269, 290, 297, 298, 299, 287, 294, 295, 296, 284, 291, 292, 293,
+ 269, 269, 269, 269, 299, 304, 305, 278, 296, 302, 303, 274, 293, 300, 301, 270
+};
+
+#endif
diff --git a/src/threed/geometry/qlogicalvertex.cpp b/src/threed/geometry/qlogicalvertex.cpp
new file mode 100644
index 000000000..e1f892c3d
--- /dev/null
+++ b/src/threed/geometry/qlogicalvertex.cpp
@@ -0,0 +1,416 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlogicalvertex.h"
+#include "qvector_utils_p.h"
+
+#include <QtCore/qdebug.h>
+
+/*!
+ \class QLogicalVertex
+ \brief The QLogicalVertex class references QGeometryData at a single vertex.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::geometry
+
+ QLogicalVertex instances are a convenience class for use with
+ QGeometryData. A QLogicalVertex simply references through to the data
+ in a QGeometryData for a particular vertex, providing accessors to fetch
+ position, texture coordinates, and other values.
+
+ Create a QLogicalVertex referring to a particular QGeometryData instance:
+ \code
+ QGeometryData data;
+ data.appendVertex(QVector3D(1, 2, 3));
+
+ // construct a QLogicalVertex referring to the first vertex in data
+ // the QGeometryData is implicitly shared with lv
+ QLogicalVertex lv(data, 0);
+ // lv.vertex() == QVector3D(1, 2, 3)
+ \endcode
+ This is inexpensive and no new storage is allocated for the actual data,
+ just the reference and index.
+
+ With logical vertices instances referencing large QGeometryData instances,
+ avoid modifying the instance:
+ \code
+ // careful - assigning to a QLogicalVertex which refers to an external
+ // QGeometryData will result in a possibly expensive copy-on-write
+ lv.setVertex(3, 2, 1);
+ \endcode
+
+ Create a QLogicalVertex with its own QGeometryData internally:
+ \code
+ QLogicalVertex lv;
+ // no copy on write here - internal QGeometryData is not shared
+ lv.setVertex(1, 2, 3);
+ \endcode
+
+ Assign an instance of QLogicalVertex:
+ \code
+ QLogicalVertex lv2;
+ lv2 = data.logicalVertexAt(0);
+ \endcode
+ Although lv2 gets its own internal QGeometryData which is then immediately
+ thrown away by the assignment, because of lazy initialization in
+ QGeometryData the cost is negligible.
+
+ Use the fields() and hasField() functions to determine if a particular
+ field is present in the vertex. Accessing non-existent data will cause
+ an assert in debug mode (from the underlying QArray), and give
+ undefined behaviour in release mode.
+
+ \sa QGeometryData, QGLBuilder
+*/
+
+/*!
+ \fn QLogicalVertex::QLogicalVertex()
+ Constructs a new invalid QLogicalVertex which has no data.
+*/
+
+/*!
+ \fn QLogicalVertex::QLogicalVertex(QGeometryData data, int index)
+ Constructs a new QLogicalVertex referencing the \a data at \a index.
+ Note that if this QLogicalVertex is modified, by calling vertex() or
+ setNormal() for example, then a copy-on-write for \a data will be
+ triggered.
+*/
+
+/*!
+ \fn QLogicalVertex::QLogicalVertex(const QVector3D &a)
+ Constructs a new QLogicalVertex with a vertex set to \a a.
+*/
+
+/*!
+ \fn QLogicalVertex::QLogicalVertex(const QVector3D &a, const QVector3D &n);
+ Constructs a new QLogicalVertex with a vertex set to \a a, and normal set to \a n.
+*/
+
+/*!
+ \fn QLogicalVertex::QLogicalVertex(const QVector3D &a, const QVector3D &n, const QVector2D &t)
+ Constructs a new QLogicalVertex with its vertex value set to \a a, normal set
+ to \a n, and texture set to \a t. By default \a n is the null QVector3D,
+ and \a t is the InvalidTexCoord. If \a n is null then hasType(QLogicalVertex::Normal)
+ will return false. Likewise if \a t is the InvalidTexCoord then
+ hasType(QLogicalVertex::Texture) will return false.
+*/
+
+/*!
+ \fn QLogicalVertex::QLogicalVertex(const QVector3D &a, QColor4ub color)
+ Constructs a new QLogicalVertex with its vertex value set to \a a,
+ color value set to \a color.
+*/
+
+/*!
+ \fn QLogicalVertex::~QLogicalVertex()
+ Destroys this QLogicalVertex reclaiming any resources.
+*/
+
+/*!
+ \fn const QVector3D &QLogicalVertex::vertex() const
+ Returns a const reference to the vertex value for this vertex.
+*/
+
+/*!
+ \fn void QLogicalVertex::setVertex(const QVector3D &v)
+ Sets the vertex value for this vertex to \a v.
+*/
+
+/*!
+ \fn QVector3D &QLogicalVertex::vertex()
+ Returns a modifiable reference to the vertex value.
+*/
+
+/*!
+ \fn QLogicalVertex::operator QVector3D ()
+ Returns a copy of the vertex value, by casting as a QVector3D. This
+ allows passing of a QLogicalVertex to functions that expect a QVector3D.
+*/
+
+/*!
+ \fn QVariant QLogicalVertex::attribute(QGL::VertexAttribute field) const
+ Returns the attribute value for \a field. The \a field defaults
+ to QGL::CustomVertex0.
+*/
+
+/*!
+ \fn void QLogicalVertex::setAttribute(float value, QGL::VertexAttribute field)
+ Sets the float attribute \a value at \a field. The \a field
+ defaults to QGL::CustomVertex0.
+*/
+
+/*!
+ \fn void QLogicalVertex::setAttribute(const QVector2D &v, QGL::VertexAttribute field)
+ Sets the QVector2D attribute \a v at \a field. The \a field
+ defaults to QGL::CustomVertex0.
+*/
+
+/*!
+ \fn void QLogicalVertex::setAttribute(const QVector3D &v, QGL::VertexAttribute field)
+ Sets the QVector3D attribute \a v at \a field. The \a field
+ defaults to QGL::CustomVertex0.
+*/
+
+/*!
+ \fn float &QLogicalVertex::floatAttribute(QGL::VertexAttribute field)
+ Returns a modifiable reference to the attribute at \a field, which
+ must be a float. The \a field defaults to QGL::CustomVertex0.
+*/
+
+/*!
+ \fn QVector2D &QLogicalVertex::vector2DAttribute(QGL::VertexAttribute field)
+ Returns a modifiable reference to the attribute at \a field, which
+ must be a QVector2D. The \a field defaults to QGL::CustomVertex0.
+*/
+
+/*!
+ \fn QVector3D &QLogicalVertex::vector3DAttribute(QGL::VertexAttribute field = QGL::CustomVertex0);
+ Returns a modifiable reference to the attribute at \a field, which
+ must be a QVector3D. The \a field defaults to QGL::CustomVertex0.
+*/
+
+/*!
+ \fn float QLogicalVertex::floatAttribute(QGL::VertexAttribute field) const
+ Returns the attribute at \a field. The \a field defaults to QGL::CustomVertex0.
+ The attribute must be a float value.
+*/
+
+/*!
+ \fn QVector2D QLogicalVertex::vector2DAttribute(QGL::VertexAttribute field) const
+ Returns the attribute at \a field. The \a field defaults to QGL::CustomVertex0.
+ The attribute must be a QVector2D value.
+*/
+
+/*!
+ \fn QVector3D QLogicalVertex::vector3DAttribute(QGL::VertexAttribute field) const
+ Returns the attribute at \a field. The \a field defaults to QGL::CustomVertex0.
+ The attribute must be a QVector3D value.
+*/
+
+/*!
+ \fn QCustomDataArray::ElementType QLogicalVertex::attributeType(QGL::VertexAttribute field)
+ Returns the element type for the attribute \a field.
+*/
+
+/*!
+ \fn const QVector3D &QLogicalVertex::normal() const
+ Returns a const reference to the normal value for this vertex.
+*/
+
+/*!
+ \fn void QLogicalVertex::setNormal(const QVector3D &n)
+ Sets the normal value for this vertex to \a n.
+*/
+
+/*!
+ \fn QVector3D &QLogicalVertex::normal()
+ Returns a modifiable reference to the normal value for this vertex.
+*/
+
+/*!
+ \fn QVector2D QLogicalVertex::texCoord(QGL::VertexAttribute field) const
+ Returns a copy of the texture coordinate value at \a field for this vertex.
+ The \a field defaults to QGL::TextureCoord0.
+*/
+
+/*!
+ \fn void QLogicalVertex::setTexCoord(const QVector2D &t, QGL::VertexAttribute field)
+ Sets the texture coordinate at \a field for this vertex to \a t.
+ The \a field defaults to QGL::TextureCoord0.
+*/
+
+/*!
+ \fn QVector2D &QLogicalVertex::texCoordRef(QGL::VertexAttribute field)
+ Returns a modifiable reference to the texture coordinate for this vertex.
+ The \a field defaults to QGL::TextureCoord0.
+*/
+
+/*!
+ \fn QColor4ub QLogicalVertex::color() const
+ Returns a const reference to the color value for this vertex.
+*/
+
+/*!
+ \fn void QLogicalVertex::setColor(const QColor4ub &c)
+ Sets the color value for this vertex to \a c.
+*/
+
+/*!
+ \fn QColor4ub &QLogicalVertex::colorRef()
+ Returns a modifiable reference to the color value for this vertex.
+*/
+
+/*!
+ \fn bool QLogicalVertex::hasField(QGL::VertexAttribute type) const
+ Returns true if this vertex has data field \a type, and false otherwise.
+
+ In general check to see if a logical vertex has a particular field
+ type before attempting to access it. In debug mode accessing a
+ non-existent field will cause an assert; but in release mode the
+ behaviour is undefined.
+*/
+
+/*!
+ \fn quint32 QLogicalVertex::fields() const
+ Returns a bit-mask of the fields in this logical vertex. Test the
+ fields like this:
+ \code
+ if (vertex.fields() & QGL::fieldMask(QGL::TextureCoord0))
+ tex = vertex.texCoord();
+ \endcode
+
+ \sa QGeometryData::fields()
+*/
+
+/*!
+ \fn int QLogicalVertex::index() const
+ Returns the index at which this logical vertex's data is located in
+ its associated QGeometryData; or -1 if this vertex is null.
+*/
+
+/*!
+ \fn QGeometryData QLogicalVertex::data() const
+ Returns a copy of the QGeometryData underlying this vertex. Note that
+ the copy is not expensive in terms of performance due to implicit sharing
+ unless the copy is modified (causing a copy-on-write).
+
+ \sa QLogicalVertex::index()
+*/
+
+/*!
+ \fn QGeometryData data() const
+ Returns a copy of the QGeometryData associated with this vertex. Note
+ that as long as the copy is not modified, this method is not expensive.
+*/
+
+/*!
+ \fn bool QLogicalVertex::isNull() const
+ Returns true if this vertex is null.
+
+ \sa QLogicalVertex()
+*/
+
+/*!
+ Returns true if \a rhs has exactly the same fields as this logical
+ vertex, and each of those are equal to the corresponding field of the \a rhs.
+
+ If either are null, then false is returned.
+*/
+bool QLogicalVertex::operator==(const QLogicalVertex &rhs) const
+{
+ if (isNull() || rhs.isNull())
+ return false;
+ if (this == &rhs)
+ return true;
+ if (m_data.fields() != rhs.fields())
+ return false;
+ const quint32 mask = 0x01;
+ quint32 fields = m_data.fields();
+ for (int field = 0; fields; ++field, fields >>= 1)
+ {
+ if (mask & fields)
+ {
+ QGL::VertexAttribute attr = static_cast<QGL::VertexAttribute>(field);
+ if (attr < QGL::TextureCoord0)
+ {
+ if (attr == QGL::Position)
+ {
+ if (!qFskCompare(vertex(), rhs.vertex()))
+ return false;
+ }
+ else if (attr == QGL::Normal)
+ {
+ if (!qFskCompare(normal(), rhs.normal()))
+ return false;
+ }
+ else
+ {
+ if (color() != rhs.color())
+ return false;
+ }
+ }
+ else if (attr < QGL::CustomVertex0)
+ {
+ if (!qFskCompare(texCoord(attr), rhs.texCoord(attr)))
+ return false;
+ }
+ else
+ {
+ if (attribute(attr) != rhs.attribute(attr))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QLogicalVertex &lv)
+{
+ dbg.nospace();
+ dbg << "QLogicalVertex(";
+ if (lv.isNull())
+ {
+ dbg << " NULL";
+ }
+ else
+ {
+ if (lv.hasField(QGL::Position))
+ dbg << "V:" << QVector3D(lv.vertex());
+ else
+ dbg << " (No Vertex)";
+ if (lv.hasField(QGL::Normal))
+ dbg << "N:" << QVector3D(lv.normal());
+ else
+ dbg << " (No Normal)";
+ if (lv.hasField(QGL::TextureCoord0))
+ dbg << "T:" << QVector2D(lv.texCoord());
+ else
+ dbg << " (No Texture)";
+ if (lv.hasField(QGL::Color))
+ dbg << "C:" << QColor4ub(lv.color());
+ else
+ dbg << " (No Color)";
+ }
+ dbg << " )";
+ return dbg.space();
+}
+#endif
diff --git a/src/threed/geometry/qlogicalvertex.h b/src/threed/geometry/qlogicalvertex.h
new file mode 100644
index 000000000..304aa9b05
--- /dev/null
+++ b/src/threed/geometry/qlogicalvertex.h
@@ -0,0 +1,328 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLOGICALVERTEX_H
+#define QLOGICALVERTEX_H
+
+#include "qgeometrydata.h"
+#include "qcustomdataarray.h"
+
+QT_BEGIN_NAMESPACE
+
+// uncomment this to perform heavy checking of QLogicalVertex
+// #define QT3D_DEBUG_QLOGICALVERTEX 1
+
+class QLogicalVertex
+{
+public:
+ inline QLogicalVertex();
+ inline QLogicalVertex(QGeometryData data, int index);
+ inline QLogicalVertex(const QVector3D &a);
+ inline QLogicalVertex(const QVector3D &a, const QVector3D &n);
+ inline QLogicalVertex(const QVector3D &a, const QVector3D &n, const QVector2D &t);
+ inline QLogicalVertex(const QVector3D &a, QColor4ub color);
+ ~QLogicalVertex() {}
+
+ inline const QVector3D &vertex() const;
+ inline void setVertex(const QVector3D &v);
+ inline QVector3D &vertex();
+
+ operator QVector3D () { return vertex(); }
+
+ inline QVariant attribute(QGL::VertexAttribute field = QGL::CustomVertex0) const;
+ inline void setAttribute(float value, QGL::VertexAttribute attr);
+ inline void setAttribute(const QVector2D &v, QGL::VertexAttribute field = QGL::CustomVertex0);
+ inline void setAttribute(const QVector3D &v, QGL::VertexAttribute field = QGL::CustomVertex0);
+ inline float &floatAttribute(QGL::VertexAttribute field = QGL::CustomVertex0);
+ inline QVector2D &vector2DAttribute(QGL::VertexAttribute field = QGL::CustomVertex0);
+ inline QVector3D &vector3DAttribute(QGL::VertexAttribute field = QGL::CustomVertex0);
+ inline float floatAttribute(QGL::VertexAttribute field = QGL::CustomVertex0) const;
+ inline QVector2D vector2DAttribute(QGL::VertexAttribute field = QGL::CustomVertex0) const;
+ inline QVector3D vector3DAttribute(QGL::VertexAttribute field = QGL::CustomVertex0) const;
+ inline QCustomDataArray::ElementType attributeType(QGL::VertexAttribute field = QGL::CustomVertex0);
+
+ inline const QVector3D &normal() const;
+ inline void setNormal(const QVector3D &n);
+ inline QVector3D &normal();
+
+ inline const QColor4ub &color() const;
+ inline void setColor(const QColor4ub &c);
+ inline QColor4ub &colorRef();
+
+ inline const QVector2D &texCoord(QGL::VertexAttribute attr = QGL::TextureCoord0) const;
+ inline void setTexCoord(const QVector2D &t, QGL::VertexAttribute attr = QGL::TextureCoord0);
+ inline QVector2D &texCoordRef(QGL::VertexAttribute attr = QGL::TextureCoord0);
+
+ inline bool hasField(QGL::VertexAttribute type) const;
+ inline quint32 fields() const;
+ inline int index() const;
+ inline QGeometryData data() const;
+ inline bool isNull() const;
+
+ bool operator==(const QLogicalVertex &rhs) const;
+
+private:
+ QGeometryData m_data;
+ int m_index;
+};
+
+inline QLogicalVertex::QLogicalVertex()
+ : m_index(-1)
+{
+}
+
+inline QLogicalVertex::QLogicalVertex(QGeometryData data, int index)
+ : m_data(data)
+ , m_index(index)
+{
+ Q_ASSERT(index < data.count());
+#ifdef QT3D_DEBUG_QLOGICALVERTEX
+ data.check();
+#endif
+}
+
+inline QLogicalVertex::QLogicalVertex(const QVector3D &a)
+ : m_index(0)
+{
+ m_data.appendVertex(a);
+}
+
+inline QLogicalVertex::QLogicalVertex(const QVector3D &a, const QVector3D &n)
+ : m_index(0)
+{
+ m_data.appendVertex(a);
+ m_data.appendNormal(n);
+}
+
+inline QLogicalVertex::QLogicalVertex(const QVector3D &a, const QVector3D &n, const QVector2D &t)
+ : m_index(0)
+{
+ m_data.appendVertex(a);
+ m_data.appendNormal(n);
+ m_data.appendTexCoord(t);
+}
+
+inline QLogicalVertex::QLogicalVertex(const QVector3D &a, QColor4ub color)
+ : m_index(0)
+{
+ m_data.appendVertex(a);
+ m_data.appendColor(color);
+}
+
+inline const QVector3D &QLogicalVertex::vertex() const
+{
+ return m_data.vertexAt(m_index);
+}
+
+inline void QLogicalVertex::setVertex(const QVector3D &v)
+{
+ if (m_index == -1)
+ m_index = 0;
+ if (m_index == m_data.count(QGL::Position))
+ m_data.appendVertex(v);
+ else
+ m_data.vertex(m_index) = v;
+}
+
+inline QVector3D &QLogicalVertex::vertex()
+{
+ return m_data.vertex(m_index);
+}
+
+inline QVariant QLogicalVertex::attribute(QGL::VertexAttribute attr) const
+{
+ return m_data.attributes(attr).at(m_index);
+}
+
+inline void QLogicalVertex::setAttribute(float v, QGL::VertexAttribute attr)
+{
+ if (m_index == -1)
+ m_index = 0;
+ if (m_index == m_data.count(attr))
+ m_data.appendAttribute(v, attr);
+ else
+ m_data.floatAttribute(m_index, attr) = v;
+}
+
+inline void QLogicalVertex::setAttribute(const QVector2D &v, QGL::VertexAttribute attr)
+{
+ if (m_index == -1)
+ m_index = 0;
+ if (m_index == m_data.count(attr))
+ m_data.appendAttribute(v, attr);
+ else
+ m_data.vector2DAttribute(m_index, attr) = v;
+}
+
+inline void QLogicalVertex::setAttribute(const QVector3D &v, QGL::VertexAttribute attr)
+{
+ if (m_index == -1)
+ m_index = 0;
+ if (m_index == m_data.count(attr))
+ m_data.appendAttribute(v, attr);
+ else
+ m_data.vector3DAttribute(m_index, attr) = v;
+}
+
+inline float &QLogicalVertex::floatAttribute(QGL::VertexAttribute field)
+{
+ return m_data.floatAttribute(m_index, field);
+}
+
+inline QVector2D &QLogicalVertex::vector2DAttribute(QGL::VertexAttribute field)
+{
+ return m_data.vector2DAttribute(m_index, field);
+}
+
+inline QVector3D &QLogicalVertex::vector3DAttribute(QGL::VertexAttribute field)
+{
+
+ return m_data.vector3DAttribute(m_index, field);
+}
+
+inline float QLogicalVertex::floatAttribute(QGL::VertexAttribute field) const
+{
+ return m_data.floatAttributeAt(m_index, field);
+}
+
+inline QVector2D QLogicalVertex::vector2DAttribute(QGL::VertexAttribute field) const
+{
+ return m_data.vector2DAttributeAt(m_index, field);
+}
+
+inline QVector3D QLogicalVertex::vector3DAttribute(QGL::VertexAttribute field) const
+{
+ return m_data.vector3DAttributeAt(m_index, field);
+}
+
+inline QCustomDataArray::ElementType QLogicalVertex::attributeType(QGL::VertexAttribute field)
+{
+ return m_data.attributes(field).elementType();
+}
+
+inline const QVector3D &QLogicalVertex::normal() const
+{
+ return m_data.normalAt(m_index);
+}
+
+inline void QLogicalVertex::setNormal(const QVector3D &n)
+{
+ if (m_index == -1)
+ m_index = 0;
+ if (m_index == m_data.count(QGL::Normal))
+ m_data.appendNormal(n);
+ else
+ m_data.normal(m_index) = n;
+}
+
+inline QVector3D &QLogicalVertex::normal()
+{
+ return m_data.normal(m_index);
+}
+
+inline const QVector2D &QLogicalVertex::texCoord(QGL::VertexAttribute attr) const
+{
+ return m_data.texCoordAt(m_index, attr);
+}
+
+inline void QLogicalVertex::setTexCoord(const QVector2D &t, QGL::VertexAttribute attr)
+{
+ Q_ASSERT(attr >= QGL::TextureCoord0 && attr <= QGL::TextureCoord2);
+ if (m_index == -1)
+ m_index = 0;
+ if (m_index == m_data.count(attr))
+ m_data.appendTexCoord(t, attr);
+ else
+ m_data.texCoord(m_index, attr) = t;
+}
+
+inline QVector2D &QLogicalVertex::texCoordRef(QGL::VertexAttribute attr)
+{
+ return m_data.texCoord(m_index, attr);
+}
+
+inline const QColor4ub &QLogicalVertex::color() const
+{
+ return m_data.colorAt(m_index);
+}
+
+inline void QLogicalVertex::setColor(const QColor4ub &c)
+{
+ if (m_index == -1)
+ m_index = 0;
+ if (m_index == m_data.count(QGL::Color))
+ m_data.appendColor(c);
+ else
+ m_data.color(m_index) = c;
+}
+
+inline QColor4ub &QLogicalVertex::colorRef()
+{
+ return m_data.color(m_index);
+}
+
+inline bool QLogicalVertex::hasField(QGL::VertexAttribute attr) const
+{
+ return m_data.hasField(attr);
+}
+
+inline quint32 QLogicalVertex::fields() const
+{
+ return m_data.fields();
+}
+
+inline int QLogicalVertex::index() const
+{
+ return m_index;
+}
+
+inline bool QLogicalVertex::isNull() const
+{
+ return (m_index == -1);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QLogicalVertex &section);
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QLOGICALVERTEX_H
diff --git a/src/threed/geometry/qvector_utils_p.h b/src/threed/geometry/qvector_utils_p.h
new file mode 100644
index 000000000..64b436226
--- /dev/null
+++ b/src/threed/geometry/qvector_utils_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVECTOR_UTILS_P_H
+#define QVECTOR_UTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector2d.h>
+
+// Replacement for qFuzzyCompare(QVector3D, QVector3D) and friends,
+// for a specific case where the results are going to be rendered
+// by the GPU onto a display.
+//
+// The accuracy of this comparison should not change. Especially it
+// should not change when you go from doubles to floats or when
+// you get close to zero. If two verts or lighting normals are
+// the same to within 5 places of floating point accuracy then they
+// will dislay as being on top of each other.
+//
+// Also this avoids doing 3 floating point multiplications every time
+// since the normal qFuzzyIsNull does a mul to scale the epsilon when
+// close to zero.
+
+inline bool qFskIsNull(double d)
+{
+ return qAbs(d) <= 0.00001;
+}
+
+inline bool qFskIsNull(float f)
+{
+ return qAbs(f) <= 0.00001f;
+}
+
+inline bool qFskCompare(float a, float b)
+{
+ return qFskIsNull(a - b);
+}
+
+inline bool qFskCompare(double a, double b)
+{
+ return qFskIsNull(a - b);
+}
+
+inline bool qFskCompare(const QVector3D &a, const QVector3D &b)
+{
+ return (
+ qFskIsNull(a.x() - b.x()) &&
+ qFskIsNull(a.y() - b.y()) &&
+ qFskIsNull(a.z() - b.z())
+ );
+}
+
+inline bool qFskCompare(const QVector2D &a, const QVector2D &b)
+{
+ return (
+ qFskIsNull(a.x() - b.x()) &&
+ qFskIsNull(a.y() - b.y())
+ );
+}
+
+#endif // QVECTOR_UTILS_P_H
diff --git a/src/threed/global/global.pri b/src/threed/global/global.pri
new file mode 100644
index 000000000..d911c784a
--- /dev/null
+++ b/src/threed/global/global.pri
@@ -0,0 +1,7 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += \
+ qt3dglobal.h \
+ qglnamespace.h
+SOURCES += \
+ qglnamespace.cpp
diff --git a/src/threed/global/qglnamespace.cpp b/src/threed/global/qglnamespace.cpp
new file mode 100644
index 000000000..f62cb6479
--- /dev/null
+++ b/src/threed/global/qglnamespace.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglnamespace.h"
+#include <QtCore/qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \namespace QGL
+
+ \brief The QGL namespace contains miscellaneous identifiers
+ used throughout the Qt3D module.
+*/
+
+/*!
+ \enum QGL::VertexAttribute
+ \since 4.8
+ This enum defines the type of vertex attribute to set on an effect with QGLPainter::setVertexAttribute()
+
+ \value Position The primary position of the vertex.
+ \value Normal The normal at each vertex.
+ \value Color The color at each vertex.
+ \value TextureCoord0 The texture co-ordinate at each vertex for texture unit 0.
+ \value TextureCoord1 The texture co-ordinate at each vertex for texture unit 1.
+ \value TextureCoord2 The texture co-ordinate at each vertex for texture unit 2.
+ \value CustomVertex0 First custom vertex attribute. Custom attributes
+ can be used for any purpose: texture co-ordinates, colors,
+ or other values of interest to shader programs.
+ \value CustomVertex1 Second custom vertex attribute.
+ \value UserVertex First user-assigned vertex attribute. Additional
+ attributes can be assigned as UserVertex, UserVertex + 1, etc.
+ Note that on OpenGL/ES 2.0 systems, usually the maximum
+ number of vertex attributes is 8, which means that user-assigned
+ vertex attributes will be out of range.
+*/
+
+/*!
+ \enum QGL::Face
+ \since 4.8
+ This enum defines the faces to apply an operation to.
+
+ \value FrontFaces Apply the operation to front faces only.
+ \value BackFaces Apply the operation to back faces only.
+ \value AllFaces Apply the operation to both front and back faces.
+*/
+
+/*!
+ \enum QGL::DrawingMode
+ \since 4.8
+ This enum defines the type of OpenGL primitive to render with QGLPainter::draw().
+
+ \value Points Draws a point at each of the specified vertices.
+ \value Lines Draws a series of unconnected line segments, using two
+ vertices for each line.
+ \value LineLoop series of connected line segments, from the
+ first to the last vertex, and then connecting the last
+ vertex back to the first vertex.
+ \value LineStrip Draws a series of connected line segments, from the
+ first to the last vertex.
+ \value Triangles Draws a series of triangles using three vertices from
+ the enabled vertex arrays for each triangle.
+ \value TriangleStrip Draws a series of triangles in a strip, starting
+ with the first three vertices and then one extra vertex for each
+ additional triangle.
+ \value TriangleFan Draws a series of triangles that fan out around the
+ first vertex in the enabled vertex arrays, starting with the
+ first three vertices and then one extra vertex for each additional
+ triangle.
+ \value LinesAdjacency Draws a series of unconnected lines, using
+ two vertices for each line to define the positions, and an
+ additional vertices per line to define adjacent points.
+ This drawing mode is only supported on OpenGL systems that
+ have geometry shaders.
+ \value LineStripAdjacency Draws a series of connected line segments,
+ from the second to the second last vertex. The first and last
+ vertices define adjacent points. This drawing mode is only
+ supported on OpenGL systems that have geometry shaders.
+ \value TrianglesAdjacency Draws a series of triangles using three
+ vertices from the enabled vertex arrays for each triangle.
+ An additional three vertices per triangle are supplied to
+ define adjacent points. This drawing mode is only supported
+ on OpenGL systems that have geometry shaders.
+ \value TriangleStripAdjacency Draws a series of triangles in a strip,
+ with additional vertices for points adjacent to the strip.
+ This drawing mode is only supported on OpenGL systems that
+ have geometry shaders.
+*/
+
+/*!
+ \enum QGL::StandardEffect
+ \since 4.8
+ This enum defines a standard drawing effect for use with QGLPainter.
+
+ \value FlatColor Single flat color specified by QGLPainter::setColor()
+ with no lighting.
+ \value FlatPerVertexColor Per-vertex flat colors specified by a
+ QGL::Color vertex array with no lighting.
+ \value FlatReplaceTexture2D Map a texture across the fragments with
+ no lighting. The final fragment color is replaced directly
+ with the texture. The texture is sourced from texture unit 0.
+ \value FlatDecalTexture2D Map a texture across the fragments, combined
+ with QGLPainter::color(), and no lighting. The texture is sourced
+ from texture unit 0.
+ \value LitMaterial Material colors specified by
+ QGLPainter::setFaceMaterial() with lighting enabled. It is
+ assumed that per-vertex normals are provided. Under OpenGL/ES 2.0
+ only one light is supported, with single-sided materials,
+ and no attenuation.
+ \value LitDecalTexture2D Map a texture across the fragments, combined
+ with the material color specified by QGLPainter::setFaceMaterial(),
+ and lighting using the GL_DECAL combination rule. The texture is
+ sourced from texture unit 0. It is assumed that per-vertex
+ normals are provided. Under OpenGL/ES 2.0 only one light is
+ supported, with single-sided materials, and no attenuation.
+ \value LitModulateTexture2D Map a texture across the fragments, combined
+ with the material color specified by QGLPainter::setFaceMaterial(),
+ and lighting using the GL_MODULATE combination rule. The texture
+ is sourced from texture unit 0. It is assumed that per-vertex
+ normals are provided. Under OpenGL/ES 2.0 only one light is
+ supported, with single-sided materials, and no attenuation.
+*/
+
+/*!
+ \enum QGL::TextureWrap
+ \since 4.8
+ This enum defines the wrapping mode for texture co-ordinates.
+
+ \value Repeat Ignore the integer part of the texture co-ordinate and
+ create a repeating pattern using the texture.
+ \value Clamp Clamps the texture co-ordinate to the range 0 to 1.
+ This value is not supported in OpenGL/ES, where it will be
+ treated the same as ClampToEdge.
+ \value ClampToBorder Clamps the texture co-ordinate to the range
+ (-1 / 2N) to (1 + 1 / 2N) where N is the size of the texture in
+ the direction of clamping. This value is supported in OpenGL 1.3
+ and higher. In OpenGL versions less than 1.3, this value will
+ be treated the same as Clamp. In OpenGL/ES, this value will be
+ treated the same as ClampToEdge.
+ \value ClampToEdge Clamps the texture co-ordinate to the range
+ (1 / 2N) to (1 - 1 / 2N) where N is the size of the texture in
+ the direction of clamping. This value is supported in OpenGL 1.2
+ and higher, and in all versions of OpenGL/ES. In OpenGL versions
+ less than 1.2, this value will be treated the same as Clamp.
+ \value MirroredRepeat If the integer part of the texture co-ordinate
+ is even, then use the fractional part. If the integer part of
+ the texture co-ordinate is odd, then use 1 - the fractional part.
+ This creates an alternating repeating pattern from the texture.
+ This value is only supported in OpenGL 1.4 and higher, or
+ OpenGL/ES 2.0 and higher. On other versions, MirroredRepeat
+ will be treated the same as Repeat.
+*/
+
+/*!
+ \enum QGL::Eye
+ \since 4.8
+ This enum defines the eye that is being rendered by a QGLPainter
+ when stereo rendering is in effect.
+
+ \value NoEye Do not perform an eye adjustment on the camera because
+ stereo rendering is not in effect.
+ \value LeftEye Render the scene from the perspective of the left eye.
+ \value RightEye Render the scene from the perspective of the right eye.
+*/
+
+/*!
+ \enum QGL::Smoothing
+ \since 4.8
+ \relates QGLBuilder
+
+ This enum defines vertex smoothing treatments.
+ \value NoSmoothing No smoothing processing is performed.
+ \value Smooth Lighting normals averaged for each face for a smooth appearance.
+ \value Faceted Lighting normals separate for each face for a faceted appearance.
+*/
+
+/*!
+ \enum QGL::Mouse3DKeys
+ \since 4.8
+ This enum defines extra key codes for QKeyEvent related to 3D mice
+ devices. See QMouse3DEventProvider for further details.
+
+ \value Key_Fit Reset the transform so the model is centered to
+ fit within the view.
+ \value Key_TopView Switch to the top view.
+ \value Key_LeftView Switch to the left view.
+ \value Key_RightView Switch to the right view.
+ \value Key_FrontView Switch to the front view.
+ \value Key_BottomView Switch to the bottom view.
+ \value Key_BackView Switch to the back view.
+ \value Key_RotateCW90 Rotate clockwise by 90 degrees.
+ \value Key_RotateCCW90 Rotate counter-clockwise by 90 degrees.
+ \value Key_ISO1 Show an isometric view of the model with top, front,
+ and right sides.
+ \value Key_ISO2 Show an isometric view of the model with top, back
+ and left sides.
+ \value Key_Button1 Special function button 1.
+ \value Key_Button2 Special function button 2.
+ \value Key_Button3 Special function button 3.
+ \value Key_Button4 Special function button 4.
+ \value Key_Button5 Special function button 5.
+ \value Key_Button6 Special function button 6.
+ \value Key_Button7 Special function button 7.
+ \value Key_Button8 Special function button 8.
+ \value Key_Button9 Special function button 9.
+ \value Key_Button10 Special function button 10.
+ \value Key_Rotations Toggles whether or not the rotation axes on a
+ 3D mouse will be filtered.
+ \value Key_Translations Toggles whether or not the translation axes
+ on a 3D mouse will be filtered.
+ \value Key_DominantAxis Toggles whether or not 3D mouse movements
+ should be constrained to the dominant axis.
+ \value Key_IncreaseSensitivity Increase the sensitivity of the mouse
+ to wrist movements.
+ \value Key_DecreaseSensitivity Decrease the sensitivity of the mouse
+ to wrist movements.
+*/
+
+/*!
+ Returns the next power of two that is greater than or
+ equal to \a value. The \a value must be positive or the
+ result is undefined.
+
+ This is a convenience function for use with GL texture
+ handling code.
+*/
+int QGL::nextPowerOfTwo(int value)
+{
+ value--;
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ ++value;
+ return value;
+}
+
+/*!
+ Returns the next power of two that is greater than or
+ equal to the width and height components of \a value.
+
+ This is a convenience function for use with GL texture
+ handling code.
+*/
+QSize QGL::nextPowerOfTwo(const QSize& value)
+{
+ return QSize(nextPowerOfTwo(value.width()),
+ nextPowerOfTwo(value.height()));
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/global/qglnamespace.h b/src/threed/global/qglnamespace.h
new file mode 100644
index 000000000..7b97c84ab
--- /dev/null
+++ b/src/threed/global/qglnamespace.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLNAMESPACE_H
+#define QGLNAMESPACE_H
+
+#include "qt3dglobal.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QSize;
+
+namespace QGL
+{
+ enum VertexAttribute {
+ Position,
+ Normal,
+ Color,
+ TextureCoord0,
+ TextureCoord1,
+ TextureCoord2,
+ CustomVertex0,
+ CustomVertex1,
+ UserVertex
+ };
+
+ enum Face
+ {
+ FrontFaces = 0x0404, // GL_FRONT
+ BackFaces = 0x0405, // GL_BACK
+ AllFaces = 0x0408 // GL_FRONT_AND_BACK
+ };
+
+ enum DrawingMode
+ {
+ Points = 0x0000, // GL_POINTS
+ Lines = 0x0001, // GL_LINES
+ LineLoop = 0x0002, // GL_LINE_LOOP
+ LineStrip = 0x0003, // GL_LINE_STRIP
+ Triangles = 0x0004, // GL_TRIANGLES
+ TriangleStrip = 0x0005, // GL_TRIANGLE_STRIP
+ TriangleFan = 0x0006, // GL_TRIANGLE_FAN
+ LinesAdjacency = 0x000A, // GL_LINES_ADJACENCY
+ LineStripAdjacency = 0x000B, // GL_LINE_STRIP_ADJACENCY
+ TrianglesAdjacency = 0x000C, // GL_TRIANGLES_ADJACENCY
+ TriangleStripAdjacency = 0x000D // GL_TRIANGLE_STRIP_ADJACENCY
+ };
+
+ enum StandardEffect
+ {
+ FlatColor,
+ FlatPerVertexColor,
+ FlatReplaceTexture2D,
+ FlatDecalTexture2D,
+ LitMaterial,
+ LitDecalTexture2D,
+ LitModulateTexture2D
+ };
+
+ enum TextureWrap
+ {
+ Repeat = 0x2901, // GL_REPEAT
+ Clamp = 0x2900, // GL_CLAMP
+ ClampToBorder = 0x812D, // GL_CLAMP_TO_BORDER
+ ClampToEdge = 0x812F, // GL_CLAMP_TO_EDGE
+ MirroredRepeat = 0x8370 // GL_MIRRORED_REPEAT
+ };
+
+ enum Eye
+ {
+ NoEye,
+ LeftEye,
+ RightEye
+ };
+
+ enum Smoothing
+ {
+ NoSmoothing,
+ Smooth,
+ Faceted
+ };
+
+ enum Mouse3DKeys
+ {
+ Key_Fit = 0x01200002,
+ Key_TopView = 0x01200003,
+ Key_LeftView = 0x01200004,
+ Key_RightView = 0x01200005,
+ Key_FrontView = 0x01200006,
+ Key_BottomView = 0x01200007,
+ Key_BackView = 0x01200008,
+ Key_RotateCW90 = 0x01200009,
+ Key_RotateCCW90 = 0x0120000a,
+ Key_ISO1 = 0x0120000b,
+ Key_ISO2 = 0x0120000c,
+ Key_Button1 = 0x0120000d,
+ Key_Button2 = 0x0120000e,
+ Key_Button3 = 0x0120000f,
+ Key_Button4 = 0x01200010,
+ Key_Button5 = 0x01200011,
+ Key_Button6 = 0x01200012,
+ Key_Button7 = 0x01200013,
+ Key_Button8 = 0x01200014,
+ Key_Button9 = 0x01200015,
+ Key_Button10 = 0x01200016,
+ Key_Rotations = 0x0120001b,
+ Key_Translations = 0x0120001c,
+ Key_DominantAxis = 0x0120001d,
+ Key_IncreaseSensitivity = 0x0120001e,
+ Key_DecreaseSensitivity = 0x0120001f
+ };
+
+ Q_QT3D_EXPORT int nextPowerOfTwo(int value);
+ Q_QT3D_EXPORT QSize nextPowerOfTwo(const QSize& value);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/global/qt3dglobal.h b/src/threed/global/qt3dglobal.h
new file mode 100644
index 000000000..1e3b3d793
--- /dev/null
+++ b/src/threed/global/qt3dglobal.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DGLOBAL_H
+#define QT3DGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+// XXX: Move to qglobal.h eventually.
+QT_LICENSED_MODULE(Qt3D)
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+# if defined(QT_NODLL)
+# undef QT_MAKEDLL
+# undef QT_DLL
+# elif defined(QT_MAKEDLL) /* create a Qt DLL library */
+# if defined(QT_DLL)
+# undef QT_DLL
+# endif
+# if defined(QT_BUILD_QT3D_LIB)
+# define Q_QT3D_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QT3D_EXPORT Q_DECL_IMPORT
+# endif
+# elif defined(QT_DLL) /* use a Qt DLL library */
+# define Q_QT3D_EXPORT Q_DECL_IMPORT
+# endif
+#endif
+#if !defined(Q_QT3D_EXPORT)
+# if defined(QT_SHARED)
+# define Q_QT3D_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QT3D_EXPORT
+# endif
+#endif
+
+#endif
diff --git a/src/threed/graphicsview/graphicsview.pri b/src/threed/graphicsview/graphicsview.pri
new file mode 100644
index 000000000..2c853f02a
--- /dev/null
+++ b/src/threed/graphicsview/graphicsview.pri
@@ -0,0 +1,21 @@
+
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+
+HEADERS += \
+ qglgraphicsviewportitem.h \
+ qgraphicsbillboardtransform.h \
+ qgraphicsembedscene.h \
+ qgraphicsrotation3d.h \
+ qgraphicsscale3d.h \
+ qgraphicstransform3d.h \
+ qgraphicstranslation3d.h
+
+SOURCES += \
+ qglgraphicsviewportitem.cpp \
+ qgraphicsbillboardtransform.cpp \
+ qgraphicsembedscene.cpp \
+ qgraphicsrotation3d.cpp \
+ qgraphicsscale3d.cpp \
+ qgraphicstransform3d.cpp \
+ qgraphicstranslation3d.cpp
diff --git a/src/threed/graphicsview/qglgraphicsviewportitem.cpp b/src/threed/graphicsview/qglgraphicsviewportitem.cpp
new file mode 100644
index 000000000..27acec610
--- /dev/null
+++ b/src/threed/graphicsview/qglgraphicsviewportitem.cpp
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglgraphicsviewportitem.h"
+#include "qglpainter.h"
+#include "qglsubsurface.h"
+#include <QtGui/qpainter.h>
+#include <QtGui/qgraphicsscene.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLGraphicsViewportItem
+ \brief The QGLGraphicsViewportItem class provides a rectangular viewport for arbitrary OpenGL painting.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::graphicsview
+*/
+
+class QGLGraphicsViewportItemPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QGLGraphicsViewportItemPrivate(QGLGraphicsViewportItem *item)
+ : q(item)
+ {
+ defaultCamera = camera = new QGLCamera(this);
+ connect(camera, SIGNAL(projectionChanged()),
+ this, SLOT(cameraChanged()));
+ connect(camera, SIGNAL(viewChanged()),
+ this, SLOT(cameraChanged()));
+ }
+
+ void changeCamera(QGLCamera *c);
+ void setDefaults(QGLPainter *painter);
+
+ QGLGraphicsViewportItem *q;
+ QRectF rect;
+ QGLCamera *camera;
+ QGLCamera *defaultCamera;
+ QColor backgroundColor;
+
+private Q_SLOTS:
+ void cameraChanged();
+};
+
+void QGLGraphicsViewportItemPrivate::changeCamera(QGLCamera *c)
+{
+ disconnect(camera, SIGNAL(projectionChanged()),
+ this, SLOT(cameraChanged()));
+ disconnect(camera, SIGNAL(viewChanged()),
+ this, SLOT(cameraChanged()));
+ camera = c;
+ connect(camera, SIGNAL(projectionChanged()),
+ this, SLOT(cameraChanged()));
+ connect(camera, SIGNAL(viewChanged()),
+ this, SLOT(cameraChanged()));
+}
+
+void QGLGraphicsViewportItemPrivate::cameraChanged()
+{
+ q->update();
+}
+
+void QGLGraphicsViewportItemPrivate::setDefaults(QGLPainter *painter)
+{
+ // Set the default depth buffer options.
+ glDepthFunc(GL_LESS);
+ glDepthMask(GL_TRUE);
+#if defined(QT_OPENGL_ES)
+ glDepthRangef(0.0f, 1.0f);
+#else
+ glDepthRange(0.0f, 1.0f);
+#endif
+
+ // Set the default blend options.
+ glDisable(GL_BLEND);
+ if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendColor))
+ painter->glBlendColor(0, 0, 0, 0);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendEquation))
+ painter->glBlendEquation(GL_FUNC_ADD);
+ else if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendEquationSeparate))
+ painter->glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
+}
+
+/*!
+ Constructs a new GL graphics viewport and attaches it to \a parent.
+*/
+QGLGraphicsViewportItem::QGLGraphicsViewportItem(QGraphicsItem *parent)
+ : QGraphicsItem(parent), d_ptr(new QGLGraphicsViewportItemPrivate(this))
+{
+}
+
+/*!
+ Constructs a new GL graphics viewport and attaches it to \a parent.
+ The boundingRect() is initially set to \a rect.
+*/
+QGLGraphicsViewportItem::QGLGraphicsViewportItem(const QRectF& rect, QGraphicsItem *parent)
+ : QGraphicsItem(parent), d_ptr(new QGLGraphicsViewportItemPrivate(this))
+{
+ d_ptr->rect = rect;
+}
+
+/*!
+ Constructs a new GL graphics viewport and attaches it to \a parent.
+ The boundingRect() is initially set to (\a x, \a y, \a w, \a h).
+*/
+QGLGraphicsViewportItem::QGLGraphicsViewportItem
+ (qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent)
+ : QGraphicsItem(parent), d_ptr(new QGLGraphicsViewportItemPrivate(this))
+{
+ d_ptr->rect = QRectF(x, y, w, h);
+}
+
+/*!
+ Destroys this GL graphics viewport.
+*/
+QGLGraphicsViewportItem::~QGLGraphicsViewportItem()
+{
+}
+
+/*!
+ Returns the rectangular area of the view that is occupied by
+ this GL graphics viewport.
+
+ \sa setRect(), boundingRect()
+*/
+QRectF QGLGraphicsViewportItem::rect() const
+{
+ Q_D(const QGLGraphicsViewportItem);
+ return d->rect;
+}
+
+/*!
+ Sets the rectangular area of the view that is occupied by
+ this GL graphics viewport to \a rect.
+
+ \sa rect(), boundingRect()
+*/
+void QGLGraphicsViewportItem::setRect(const QRectF &rect)
+{
+ Q_D(QGLGraphicsViewportItem);
+ if (d->rect == rect)
+ return;
+ prepareGeometryChange();
+ d->rect = rect;
+ update();
+}
+
+/*!
+ \fn void QGLGraphicsViewportItem::setRect(qreal x, qreal y, qreal w, qreal h)
+ \overload
+
+ Sets the rectangular area of the view that is occupied by
+ this GL graphics viewport to (\a x, \a y, \a w, \a h).
+
+ \sa rect(), boundingRect()
+*/
+
+/*!
+ Returns the bounding rectangle for this GL graphics viewport,
+ which is the same as rect().
+
+ \sa rect()
+*/
+QRectF QGLGraphicsViewportItem::boundingRect() const
+{
+ Q_D(const QGLGraphicsViewportItem);
+ return d->rect;
+}
+
+/*!
+ Returns the camera parameters. The camera defines the projection
+ to apply to convert eye co-ordinates into window co-ordinates,
+ and the position and orientation of the viewer's eye.
+
+ This item will be updated whenever the camera's parameters change.
+
+ \sa setCamera()
+*/
+QGLCamera *QGLGraphicsViewportItem::camera() const
+{
+ Q_D(const QGLGraphicsViewportItem);
+ return d->camera;
+}
+
+/*!
+ Sets the camera parameters to \a camera. The camera defines the
+ projection to apply to convert eye co-ordinates into window
+ co-ordinates, and the position and orientation of the viewer's eye.
+
+ If \a camera is null, then the default camera object will be used.
+
+ This function will call update() to force the viewport to update
+ with the new camera parameters upon the next event loop. Afterwards,
+ this item will be updated whenever the camera's parameters change.
+
+ \sa camera()
+*/
+void QGLGraphicsViewportItem::setCamera(QGLCamera *camera)
+{
+ Q_D(QGLGraphicsViewportItem);
+ if (!camera)
+ camera = d->defaultCamera;
+ if (d->camera != camera) {
+ d->changeCamera(camera);
+ update();
+ }
+}
+
+/*!
+ Returns the background color, which is used to clear the viewport
+ before calling paintGL(). The default value is an invalid QColor,
+ which indicates that the viewport should not be cleared.
+
+ \sa setBackgroundColor()
+*/
+QColor QGLGraphicsViewportItem::backgroundColor() const
+{
+ Q_D(const QGLGraphicsViewportItem);
+ return d->backgroundColor;
+}
+
+/*!
+ Sets the background \a color, which is used to clear the viewport
+ before calling paintGL().
+
+ \sa backgroundColor()
+*/
+void QGLGraphicsViewportItem::setBackgroundColor(const QColor& color)
+{
+ Q_D(QGLGraphicsViewportItem);
+ d->backgroundColor = color;
+}
+
+/*!
+ Paints this GL graphics viewport onto \a painter, with the specified
+ \a option and \a widget parameters.
+
+ This override creates a QGLPainter for \a painter and passes
+ it to paintGL().
+
+ \sa paintGL()
+*/
+void QGLGraphicsViewportItem::paint
+ (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_D(QGLGraphicsViewportItem);
+
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ if (d->rect.isEmpty())
+ return;
+
+ // Initialize a QGLPainter for the surface and bail out if not active.
+ QGLPainter glpainter;
+ if (!glpainter.begin(painter)) {
+ qWarning("GL graphics system is not active; cannot use 3D items");
+ return;
+ }
+
+ // Set up the GL viewport to limit drawing to the bounds of this item.
+ QRect viewport = painter->deviceTransform().mapRect(rect()).toRect();
+ QGLSubsurface surface(glpainter.currentSurface(), viewport);
+ glpainter.pushSurface(&surface);
+
+ // Set up the desired drawing options.
+ glDisable(GL_CULL_FACE);
+ d->setDefaults(&glpainter);
+ if (d->backgroundColor.isValid()) {
+ // We clear the background by drawing a triangle fan so
+ // that the background color will blend with the underlying
+ // screen content if it has an alpha component.
+ glDisable(GL_DEPTH_TEST);
+ if (d->backgroundColor.alpha() != 255)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+ QVector2DArray array;
+ array.append(-1, -1);
+ array.append(1, -1);
+ array.append(1, 1);
+ array.append(-1, 1);
+ glpainter.projectionMatrix().setToIdentity();
+ glpainter.modelViewMatrix().setToIdentity();
+ glpainter.setStandardEffect(QGL::FlatColor);
+ glpainter.setColor(d->backgroundColor);
+ glpainter.setVertexAttribute(QGL::Position, array);
+ glpainter.draw(QGL::TriangleFan, 4);
+ }
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+
+ // Apply the camera.
+ glpainter.setEye(QGL::NoEye);
+ glpainter.setCamera(d->camera);
+
+ // Paint the GL contents.
+ paintGL(&glpainter);
+
+ // Disable the current drawing effect so that QGLPainter will
+ // forcibly update the GL context the next time QGLPainter is used.
+ glpainter.disableEffect();
+
+ // Try to restore the GL state to something paint-engine compatible.
+ glDisable(GL_CULL_FACE);
+ d->setDefaults(&glpainter);
+ glDisable(GL_DEPTH_TEST);
+
+ glpainter.popSurface();
+}
+
+/*!
+ \fn void QGLGraphicsViewportItem::paintGL(QGLPainter *painter)
+
+ Paints this GL graphics viewport onto \a painter. This function is called
+ from paint().
+
+ \sa paint()
+*/
+
+QT_END_NAMESPACE
+
+#include "qglgraphicsviewportitem.moc"
diff --git a/src/threed/graphicsview/qglgraphicsviewportitem.h b/src/threed/graphicsview/qglgraphicsviewportitem.h
new file mode 100644
index 000000000..c9e12506b
--- /dev/null
+++ b/src/threed/graphicsview/qglgraphicsviewportitem.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLGRAPHICSVIEWPORTITEM_H
+#define QGLGRAPHICSVIEWPORTITEM_H
+
+#include "qglnamespace.h"
+#include <QtGui/qgraphicsitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLGraphicsViewportItemPrivate;
+class QGLPainter;
+class QGLCamera;
+
+class Q_QT3D_EXPORT QGLGraphicsViewportItem : public QGraphicsItem
+{
+public:
+ QGLGraphicsViewportItem(QGraphicsItem *parent = 0);
+ QGLGraphicsViewportItem(const QRectF& rect, QGraphicsItem *parent = 0);
+ QGLGraphicsViewportItem(qreal x, qreal y, qreal w, qreal h,
+ QGraphicsItem *parent = 0);
+ ~QGLGraphicsViewportItem();
+
+ QRectF rect() const;
+ void setRect(const QRectF &rect);
+ inline void setRect(qreal x, qreal y, qreal w, qreal h);
+
+ QRectF boundingRect() const;
+
+ QGLCamera *camera() const;
+ void setCamera(QGLCamera *camera);
+
+ QColor backgroundColor() const;
+ void setBackgroundColor(const QColor& color);
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+
+protected:
+ virtual void paintGL(QGLPainter *painter) = 0;
+
+private:
+ QScopedPointer<QGLGraphicsViewportItemPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLGraphicsViewportItem)
+ Q_DISABLE_COPY(QGLGraphicsViewportItem)
+};
+
+void QGLGraphicsViewportItem::setRect(qreal x, qreal y, qreal w, qreal h)
+{
+ setRect(QRectF(x, y, w, h));
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/graphicsview/qgraphicsbillboardtransform.cpp b/src/threed/graphicsview/qgraphicsbillboardtransform.cpp
new file mode 100644
index 000000000..7072e526f
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsbillboardtransform.cpp
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsbillboardtransform.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsBillboardTransform
+ \brief The QGraphicsBillboardTransform class implements a transformation that causes objects to face the camera.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::graphicsview
+
+ Sometimes it can be useful to make an object face towards the camera
+ no matter what orientation the scene is in. The common name for
+ this technique is "billboarding".
+
+ When applied as a transformation, this class will replace the top-left
+ 3x3 part of the transformation matrix with the identity. This has the
+ effect of removing the rotation and scale components from the current
+ world co-ordinate orientation.
+*/
+
+/*!
+ \qmlclass BillboardTransform QGraphicsBillboardTransform
+ \brief The BillboardTransform item implements a transformation that causes objects to face the camera.
+ \since 4.8
+ \ingroup qt3d::qml3d
+
+ Sometimes it can be useful to make an object face towards the camera
+ no matter what orientation the scene is in. The common name for
+ this technique is "billboarding".
+
+ When applied as a transformation, this class will replace the top-left
+ 3x3 part of the transformation matrix with the identity. This has the
+ effect of removing the rotation and scale components from the current
+ world co-ordinate orientation. In QML, this can be used as follows
+ to orient a pane to point towards the viewer:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "pane.obj" }
+ position: Qt.vector3d(2, 0, -20)
+ transform: BillboardTransform {}
+ effect: Effect { texture: "picture.jpg" }
+ }
+ \endcode
+
+ Because the billboard transformation will strip any further
+ alterations to the matrix, it will usually be the last element
+ in the \c transform list (transformations are applied to the matrix in
+ reverse order of their appearance in \c transform):
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "pane.obj" }
+ position: Qt.vector3d(2, 0, -20)
+ transform: [
+ Scale3D { scale: 0.5 },
+ Rotation3D { angle: 30 },
+ BillboardTransform {}
+ ]
+ effect: Effect { texture: "picture.jpg" }
+ }
+ \endcode
+
+ The \c scale property is applied to the matrix after \c transform has
+ performed the billboard transformation, so the above can also be written
+ as follows:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "pane.obj" }
+ position: Qt.vector3d(2, 0, -20)
+ scale: 0.5
+ transform: [
+ Rotation3D { angle: 30 },
+ BillboardTransform {}
+ ]
+ effect: Effect { texture: "picture.jpg" }
+ }
+ \endcode
+
+ By default the billboard transform will cause the object to
+ face directly at the camera no matter how the world co-ordinate
+ system is rotated. Sometimes the billboard needs to stay at right
+ angles to the "ground plane" even if the user's viewpoint is
+ elevated. This behavior can be enabled using the preserveUpVector
+ property:
+
+ \code
+ Pane {
+ position: Qt.vector3d(2, 0, -20)
+ transform: BillboardTransform { preserveUpVector: true }
+ effect: Effect { texture: "picture.jpg" }
+ }
+ \endcode
+
+ \sa {Forest Example}
+*/
+
+class QGraphicsBillboardTransformPrivate
+{
+public:
+ QGraphicsBillboardTransformPrivate() : preserveUpVector(false) {}
+
+ bool preserveUpVector;
+};
+
+/*!
+ Construct a billboard transform and attach it to \a parent.
+*/
+QGraphicsBillboardTransform::QGraphicsBillboardTransform(QObject *parent)
+ : QGraphicsTransform3D(parent), d_ptr(new QGraphicsBillboardTransformPrivate)
+{
+}
+
+/*!
+ Destroy this billboard transform.
+*/
+QGraphicsBillboardTransform::~QGraphicsBillboardTransform()
+{
+}
+
+/*!
+ \property QGraphicsBillboardTransform::preserveUpVector
+ \brief true to preserve the up orientation.
+
+ The default value for this property is false, which indicates that
+ the object being transformed should always face directly to the camera
+ This is also known as a "spherical billboard".
+
+ If the value for this property is true, then the object will have
+ its up orientation preserved. This is also known as a "cylindrical
+ billboard".
+*/
+
+/*!
+ \qmlproperty bool BillboardTransform::preserveUpVector
+
+ This property specifies whether the billboard transform should
+ preserve the "up vector" so that objects stay at right angles
+ to the ground plane in the scene.
+
+ The default value for this property is false, which indicates that
+ the object being transformed should always face directly to the camera
+ This is also known as a "spherical billboard".
+
+ If the value for this property is true, then the object will have
+ its up orientation preserved. This is also known as a "cylindrical
+ billboard".
+*/
+
+bool QGraphicsBillboardTransform::preserveUpVector() const
+{
+ Q_D(const QGraphicsBillboardTransform);
+ return d->preserveUpVector;
+}
+
+void QGraphicsBillboardTransform::setPreserveUpVector(bool value)
+{
+ Q_D(QGraphicsBillboardTransform);
+ if (d->preserveUpVector != value) {
+ d->preserveUpVector = value;
+ emit transformChanged();
+ emit preserveUpVectorChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsBillboardTransform::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QGraphicsBillboardTransform);
+ if (!d->preserveUpVector) {
+ // Replace the top-left 3x3 of the matrix with the identity.
+ // The technique is "Cheating Spherical Billboards", described here:
+ // http://www.lighthouse3d.com/opengl/billboarding/index.php?billCheat
+ (*matrix)(0, 0) = 1.0f;
+ (*matrix)(0, 1) = 0.0f;
+ (*matrix)(0, 2) = 0.0f;
+ (*matrix)(1, 0) = 0.0f;
+ (*matrix)(1, 1) = 1.0f;
+ (*matrix)(1, 2) = 0.0f;
+ (*matrix)(2, 0) = 0.0f;
+ (*matrix)(2, 1) = 0.0f;
+ (*matrix)(2, 2) = 1.0f;
+ } else {
+ // Replace some of the top-left 3x3 of the matrix with the identity,
+ // but leave the up vector component in the second column as-is.
+ // The technique is "Cheating Cylindrical Billboards", described here:
+ // http://www.lighthouse3d.com/opengl/billboarding/index.php?billCheat1
+ (*matrix)(0, 0) = 1.0f;
+ (*matrix)(0, 2) = 0.0f;
+ (*matrix)(1, 0) = 0.0f;
+ (*matrix)(1, 2) = 0.0f;
+ (*matrix)(2, 0) = 0.0f;
+ (*matrix)(2, 2) = 1.0f;
+ }
+ matrix->optimize();
+}
+
+/*!
+ \internal
+*/
+QGraphicsTransform3D *QGraphicsBillboardTransform::clone(QObject *parent) const
+{
+ Q_D(const QGraphicsBillboardTransform);
+ QGraphicsBillboardTransform *copy = new QGraphicsBillboardTransform(parent);
+ copy->setPreserveUpVector(d->preserveUpVector);
+ return copy;
+}
+
+/*!
+ \fn void QGraphicsBillboardTransform::preserveUpVectorChanged()
+
+ Signal that is emitted when preserveUpVector() changes.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/graphicsview/qgraphicsbillboardtransform.h b/src/threed/graphicsview/qgraphicsbillboardtransform.h
new file mode 100644
index 000000000..00b589997
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsbillboardtransform.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSBILLBOARDTRANSFORM_H
+#define QGRAPHICSBILLBOARDTRANSFORM_H
+
+#include "qgraphicstransform3d.h"
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsBillboardTransformPrivate;
+
+class Q_QT3D_EXPORT QGraphicsBillboardTransform : public QGraphicsTransform3D
+{
+ Q_OBJECT
+ Q_PROPERTY(bool preserveUpVector READ preserveUpVector WRITE setPreserveUpVector NOTIFY preserveUpVectorChanged)
+public:
+ QGraphicsBillboardTransform(QObject *parent = 0);
+ ~QGraphicsBillboardTransform();
+
+ bool preserveUpVector() const;
+ void setPreserveUpVector(bool value);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+ QGraphicsTransform3D *clone(QObject *parent) const;
+
+Q_SIGNALS:
+ void preserveUpVectorChanged();
+
+private:
+ QScopedPointer<QGraphicsBillboardTransformPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGraphicsBillboardTransform)
+ Q_DECLARE_PRIVATE(QGraphicsBillboardTransform)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/graphicsview/qgraphicsembedscene.cpp b/src/threed/graphicsview/qgraphicsembedscene.cpp
new file mode 100644
index 000000000..cc059e737
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsembedscene.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsembedscene.h"
+#include "qglnamespace.h"
+#include <QtOpenGL/qglframebufferobject.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsEmbedScene
+ \brief The QGraphicsEmbedScene class provides a method to render a QGraphicsScene into a texture.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::graphicsview
+
+ \section1 Rendering the scene into a texture
+
+ Embedded scenes are rendered into textures with renderToTexture()
+ before the main 3D scene painting with QGLPainter starts. The following
+ example shows the sequence of operations for a QGLWidget:
+
+ \code
+ void MyGLWidget::paintGL()
+ {
+ GLuint textureId = scene.renderToTexture();
+
+ QGLPainter painter(this);
+ painter.glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ ... // draw the 3D object
+ painter.glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ \endcode
+
+ When using QGLView, override the QGLWidget::paintGL() function
+ explicitly to render scenes into textures before QGLView::paintGL()
+ is called:
+
+ \code
+ void MyGLView::paintGL()
+ {
+ textureId = scene.renderToTexture();
+ QGLView::paintGL();
+ }
+
+ void MyGLView::paintGL(QGLPainter *painter)
+ {
+ painter->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ ... // draw the 3D object
+ painter->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ \endcode
+
+ The texture is oriented so that (0, 0) corresponds to the bottom-left
+ of the scene, and (1, 1) corresponds to the top-right of the scene.
+ The texture may be scaled up to a power of two in size for better
+ performance.
+
+ \section1 Delivering mouse and keyboard events
+
+ Mouse and keyboard events originate with the widget that is
+ displaying the 3D scene. The application needs to intercept
+ these events and decide which 3D object in the scene should
+ get the event.
+
+ The application then performs an intersection between the 3D
+ object and a line in 3D space (usually a QRay3D) to determine
+ the texture co-ordinate of where the user clicked on the object.
+ How the intersection is determined is application-specific; different
+ algorithms are needed based on the type of object (cube, sphere,
+ parameterized mesh, etc).
+
+ Once the texture co-ordinate has been determined, the application
+ passes the widget event and the texture co-ordinate to deliverEvent().
+ QGraphicsEmbedScene will then route the event to the appropriate
+ graphics item in the embedded scene.
+
+ Keyboard, focus in/out, and other non-mouse events do not need a
+ texture co-ordinate. Pass (0, 0) as the texture co-ordinate for
+ those event types.
+
+ \section1 Updating the 3D scene
+
+ The application will probably want to perform an update() whenever
+ something changes in the embedded scene. The application should
+ listen for the QGraphicsScene::changed() and
+ QGraphicsScene::sceneRectChanged() signals.
+
+ \section1 Performance notes
+
+ QGraphicsEmbedScene renders the scene into a framebuffer object,
+ which will involve GL state switching. The scene will be
+ effectively triple-buffered: render into the fbo, then render
+ the fbo into the GL window's back buffer, and finally copy to the
+ GL window's front buffer.
+
+ If the scene is showing a video item or something else that is
+ highly animated, then it may be better to render the source into a
+ texture some other way.
+
+ If the embedded scene is itself a 3D scene drawn with GL, then use
+ QGLPainter::pushSurface() and a QGLFramebufferObjectSurface instead
+ of QGraphicsEmbedScene.
+
+ \section1 Limitations
+
+ When rendered into a texture, the scene does not have a QGraphicsView
+ or a viewport QWidget associated with it. Graphics items that require a
+ widget rendering surface will not work correctly.
+*/
+
+class QGraphicsEmbedScenePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QGraphicsEmbedScenePrivate(QGraphicsScene *scene, QObject *parent = 0)
+ : QObject(parent)
+ , dirty(true)
+ , fbo(0)
+ {
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+ connect(scene, SIGNAL(changed(QList<QRectF>)), this, SLOT(update()));
+ connect(scene, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(update()));
+ }
+ ~QGraphicsEmbedScenePrivate()
+ {
+ delete fbo;
+ }
+
+ bool dirty;
+ QGLFramebufferObject *fbo;
+ QGLFramebufferObjectFormat format;
+ QPoint pressedPos;
+
+public Q_SLOTS:
+ void update() { dirty = true; }
+};
+
+/*!
+ Constructs an embedded graphics scene and attaches it to \a parent.
+*/
+QGraphicsEmbedScene::QGraphicsEmbedScene(QObject *parent)
+ : QGraphicsScene(parent)
+ , d_ptr(new QGraphicsEmbedScenePrivate(this))
+{
+}
+
+/*!
+ Constructs an embedded graphics scene, using \a sceneRect for its
+ scene rectangle, and attaches it to \a parent.
+*/
+QGraphicsEmbedScene::QGraphicsEmbedScene(const QRectF &sceneRect, QObject *parent)
+ : QGraphicsScene(sceneRect, parent)
+ , d_ptr(new QGraphicsEmbedScenePrivate(this))
+{
+}
+
+/*!
+ Constructs an embedded graphics scene, using (\a x, \a y, \a width,
+ \a height) for its scene rectangle, and attaches it to \a parent.
+*/
+QGraphicsEmbedScene::QGraphicsEmbedScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
+ : QGraphicsScene(x, y, width, height, parent)
+ , d_ptr(new QGraphicsEmbedScenePrivate(this))
+{
+}
+
+/*!
+ Destroys this embedded graphics scene.
+*/
+QGraphicsEmbedScene::~QGraphicsEmbedScene()
+{
+}
+
+/*!
+ Returns the framebuffer object format to use when renderToTexture()
+ is called. The default is a framebuffer format with depth and
+ stencil buffers, RGBA format, and no multisampling.
+
+ \sa setFormat()
+*/
+QGLFramebufferObjectFormat QGraphicsEmbedScene::format() const
+{
+ Q_D(const QGraphicsEmbedScene);
+ return d->format;
+}
+
+/*!
+ Sets the framebuffer object \a format to use when renderToTexture()
+ is called.
+
+ \sa format()
+*/
+void QGraphicsEmbedScene::setFormat(const QGLFramebufferObjectFormat &format)
+{
+ Q_D(QGraphicsEmbedScene);
+ d->format = format;
+}
+
+/*!
+ Renders this scene to a GL texture and returns the texture identifier.
+ If the scene has not changed since the last call, then the same
+ texture identifier will be returned without repainting the scene.
+
+ The \a levelOfDetail is a hint that allows some control over the
+ texture size. The default value of 1 indicates that the texture size
+ should be the same or similar to the size of the scene. A value of 2
+ would indicate that the texture size should have twice the width and
+ height. A value of 0.5 would indicate half the size.
+
+ The primary use for \a levelOfDetail is to render the scene with a
+ greater level of detail when the 3D object showing the texture is
+ larger on-screen than the scene's natural size. The parameter can
+ also be used to reduce the level of detail in the texture when the
+ 3D object is very small.
+
+ It is assumed that a QGLContext is bound when this function is
+ called. Usually this is the QGLContext that is bound by a QPainter
+ for 2D painting into a GL surface. Note however that a QGLPainter must
+ not be active on the QGLContext when this function is called.
+
+ \sa format()
+*/
+GLuint QGraphicsEmbedScene::renderToTexture(qreal levelOfDetail)
+{
+ Q_D(QGraphicsEmbedScene);
+
+ // Determine the fbo size we will need.
+ QSize size = (sceneRect().size() * levelOfDetail).toSize();
+ QSize fboSize = QGL::nextPowerOfTwo(size);
+ if (fboSize.isEmpty())
+ fboSize = QSize(16, 16);
+
+ // Create or re-create the fbo.
+ if (!d->fbo || d->fbo->size() != fboSize) {
+ delete d->fbo;
+ d->fbo = new QGLFramebufferObject(fboSize, d->format);
+ if (!d->fbo->isValid()) {
+ delete d->fbo;
+ d->fbo = 0;
+ return 0;
+ }
+ d->dirty = true;
+ }
+
+ // Return the previous texture contents if the scene hasn't changed.
+ if (!d->dirty && d->fbo)
+ return d->fbo->texture();
+
+ // Render the scene into the fbo, scaling the QPainter's view
+ // transform up to the power-of-two fbo size.
+ QPainter painter(d->fbo);
+ painter.setWindow(0, 0, size.width(), size.height());
+ painter.setViewport(0, 0, fboSize.width(), fboSize.height());
+ render(&painter);
+ painter.end();
+ d->dirty = false;
+ return d->fbo->texture();
+}
+
+/*!
+ Delivers \a event to this scene. If \a event is a mouse event, then
+ \a texCoord indicates the texture co-ordinate on the side of the
+ 3D object where the user clicked. This \a texCoord is used to determine
+ the actual scene co-ordinate to deliver: (0, 0) corresponds to the
+ bottom-left corner of the scene and (1, 1) corresponds to the
+ top-right corner of the scene.
+
+ The \a event normally originates from a QWidget or QGraphicsItem that
+ contains the 3D object. The caller performs a ray intersection in
+ 3D space on the position within \a event to determine the \a texCoord
+ and then passes \a event on to deliverEvent() for further processing.
+*/
+void QGraphicsEmbedScene::deliverEvent(QEvent *event, const QPointF &texCoord)
+{
+ Q_D(QGraphicsEmbedScene);
+
+ // Map the texture co-ordinate into "screen" co-ordinates.
+ // Mouse move and release events can extend beyond the boundaries
+ // of the scene, for "click and drag off-screen" operations.
+ // Mouse press and double-click events need to be constrained.
+ QRectF bounds = sceneRect();
+ int screenX = qRound(texCoord.x() * bounds.width());
+ int screenY = qRound((1.0f - texCoord.y()) * bounds.height());
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseDoubleClick:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ if (screenX < 0)
+ screenX = 0;
+ else if (screenX >= bounds.width())
+ screenX = qRound(bounds.width() - 1);
+ if (screenY < 0)
+ screenY = 0;
+ else if (screenY >= bounds.height())
+ screenY = qRound(bounds.height() - 1);
+ d->pressedPos = QPoint(screenX, screenY);
+ break;
+ default: break;
+ }
+
+ // Convert the event and deliver it to the scene.
+ switch (event->type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::GraphicsSceneMouseDoubleClick: {
+ QGraphicsSceneMouseEvent *ev =
+ static_cast<QGraphicsSceneMouseEvent *>(event);
+ QGraphicsSceneMouseEvent e(ev->type());
+ e.setPos(QPointF(screenX, screenY));
+ e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
+ e.setScreenPos(QPoint(screenX, screenY));
+ e.setButtonDownScreenPos(ev->button(), d->pressedPos);
+ e.setButtonDownScenePos
+ (ev->button(), QPointF(d->pressedPos.x() + bounds.x(),
+ d->pressedPos.y() + bounds.y()));
+ e.setButtons(ev->buttons());
+ e.setButton(ev->button());
+ e.setModifiers(ev->modifiers());
+ e.setAccepted(false);
+ QApplication::sendEvent(this, &e);
+ }
+ break;
+
+#ifndef QT_NO_WHEELEVENT
+ case QEvent::GraphicsSceneWheel: {
+ QGraphicsSceneWheelEvent *ev =
+ static_cast<QGraphicsSceneWheelEvent *>(event);
+ QGraphicsSceneWheelEvent e(QEvent::GraphicsSceneWheel);
+ e.setPos(QPointF(screenX, screenY));
+ e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
+ e.setScreenPos(QPoint(screenX, screenY));
+ e.setButtons(ev->buttons());
+ e.setModifiers(ev->modifiers());
+ e.setDelta(ev->delta());
+ e.setOrientation(ev->orientation());
+ e.setAccepted(false);
+ QApplication::sendEvent(this, &e);
+ }
+ break;
+#endif
+
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove: {
+ QMouseEvent *ev = static_cast<QMouseEvent *>(event);
+ QEvent::Type type;
+ if (ev->type() == QEvent::MouseButtonPress)
+ type = QEvent::GraphicsSceneMousePress;
+ else if (ev->type() == QEvent::MouseButtonRelease)
+ type = QEvent::GraphicsSceneMouseRelease;
+ else if (ev->type() == QEvent::MouseButtonDblClick)
+ type = QEvent::GraphicsSceneMouseDoubleClick;
+ else
+ type = QEvent::GraphicsSceneMouseMove;
+ QGraphicsSceneMouseEvent e(type);
+ e.setPos(QPointF(screenX, screenY));
+ e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
+ e.setScreenPos(QPoint(screenX, screenY));
+ e.setButtonDownScreenPos(ev->button(), d->pressedPos);
+ e.setButtonDownScenePos
+ (ev->button(), QPointF(d->pressedPos.x() + bounds.x(),
+ d->pressedPos.y() + bounds.y()));
+ e.setButtons(ev->buttons());
+ e.setButton(ev->button());
+ e.setModifiers(ev->modifiers());
+ e.setAccepted(false);
+ QApplication::sendEvent(this, &e);
+ }
+ break;
+
+#ifndef QT_NO_WHEELEVENT
+ case QEvent::Wheel: {
+ QWheelEvent *ev = static_cast<QWheelEvent *>(event);
+ QGraphicsSceneWheelEvent e(QEvent::GraphicsSceneWheel);
+ e.setPos(QPointF(screenX, screenY));
+ e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
+ e.setScreenPos(QPoint(screenX, screenY));
+ e.setButtons(ev->buttons());
+ e.setModifiers(ev->modifiers());
+ e.setDelta(ev->delta());
+ e.setOrientation(ev->orientation());
+ e.setAccepted(false);
+ QApplication::sendEvent(this, &e);
+ }
+ break;
+#endif
+
+ default: {
+ // Send the event directly without any conversion.
+ // Typically used for keyboard, focus, and enter/leave events.
+ QApplication::sendEvent(this, event);
+ }
+ break;
+
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsEmbedScene::drawBackground(QPainter *painter, const QRectF &rect)
+{
+ if (backgroundBrush().style() == Qt::NoBrush) {
+ // Fill the fbo with the transparent color as there won't
+ // be a window or graphics item drawing a previous background.
+ painter->save();
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+ painter->fillRect(rect, Qt::transparent);
+ painter->restore();
+ } else {
+ QGraphicsScene::drawBackground(painter, rect);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qgraphicsembedscene.moc"
diff --git a/src/threed/graphicsview/qgraphicsembedscene.h b/src/threed/graphicsview/qgraphicsembedscene.h
new file mode 100644
index 000000000..44a24d1a9
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsembedscene.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSEMBEDSCENE_H
+#define QGRAPHICSEMBEDSCENE_H
+
+#include "qglnamespace.h"
+#include <QtGui/qgraphicsscene.h>
+#include <QtOpenGL/qgl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGraphicsEmbedScenePrivate;
+class QGLFramebufferObjectFormat;
+
+class Q_QT3D_EXPORT QGraphicsEmbedScene : public QGraphicsScene
+{
+ Q_OBJECT
+public:
+ QGraphicsEmbedScene(QObject *parent = 0);
+ QGraphicsEmbedScene(const QRectF &sceneRect, QObject *parent = 0);
+ QGraphicsEmbedScene(qreal x, qreal y, qreal width, qreal height, QObject *parent = 0);
+ virtual ~QGraphicsEmbedScene();
+
+ QGLFramebufferObjectFormat format() const;
+ void setFormat(const QGLFramebufferObjectFormat &format);
+
+ GLuint renderToTexture(qreal levelOfDetail = 1.0f);
+
+ void deliverEvent(QEvent *event, const QPointF &texCoord);
+
+protected:
+ void drawBackground(QPainter *painter, const QRectF &rect);
+
+private:
+ QScopedPointer<QGraphicsEmbedScenePrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGraphicsEmbedScene)
+ Q_DISABLE_COPY(QGraphicsEmbedScene)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/graphicsview/qgraphicsrotation3d.cpp b/src/threed/graphicsview/qgraphicsrotation3d.cpp
new file mode 100644
index 000000000..533de4f75
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsrotation3d.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsrotation3d.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsRotation3D
+ \brief The QGraphicsRotation3D class supports arbitrary rotation around an axis in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::graphicsview
+
+ \sa QGraphicsTranslation3D, QGraphicsScale3D
+*/
+
+/*!
+ \qmlclass Rotation3D QGraphicsRotation3D
+ \brief The Rotation3D item supports arbitrary rotation around an axis in 3D space.
+ \since 4.8
+ \ingroup qt3d::qml3d
+
+ Frequently a user will create and item in the 3d world and immediately
+ wish to apply a rotation to that item before it is displayed, or,
+ optionally, perform an animation on that rotation parameter based on
+ user inputs, or other events. Such an rotation can easily be defined
+ in QML using the following code:
+
+ \code
+ Item3D {
+ id: helicoptor
+ mesh: {source: "bellUH1.3ds"}
+ effect: Effect {}
+ cullFaces: "CullBackFaces"
+
+ transform: [
+ Rotation3D {
+ id: rotate1
+ angle: 5
+ axis: Qt.vector3d(1, 0, 0)
+ },
+ Rotation3D {
+ id: rotate2
+ angle: 5
+ axis: Qt.vector3d(0, 1, 0)
+ },
+ Rotation3D {
+ id: rotate3
+ angle: 45
+ axis: Qt.vector3d(0, 0, 1)
+ }
+ ]
+
+ SequentialAnimation {
+ NumberAnimation {target: rotate1; property: "angle"; to : 360.0; duration: 3000; easing:"easeOutQuad" }
+ }
+ }
+ \endcode
+
+ Notice here that we create a list of rotations for the \c transform
+ property of the container item. By doing this we allow rotations
+ around each of the axes individually in a manner which is conducive
+ to animation and interaction.
+
+ Each of the rotations has an \c axis property which is a QVector3D.
+ This vector contains a value for each of the three components
+ corresponding to x, y, and z. In the above example, we first
+ rotate by 5 degrees about the x axis, then 5 degrees about the y
+ axis, and finally by 45 degrees about the z axis.
+
+ By giving each rotation a unique \c id users can then refer to these
+ rotations in the QML source in order to perform rotational animations.
+
+ \sa Translation3D, Scale3D
+*/
+
+class QGraphicsRotation3DPrivate
+{
+public:
+ QGraphicsRotation3DPrivate() : axis(0, 0, 1), angle(0) {}
+
+ QVector3D origin;
+ QVector3D axis;
+ qreal angle;
+};
+
+/*!
+ Create a 3D rotation transformation and attach it to \a parent.
+*/
+QGraphicsRotation3D::QGraphicsRotation3D(QObject *parent)
+ : QGraphicsTransform3D(parent)
+ , d_ptr(new QGraphicsRotation3DPrivate)
+{
+}
+
+/*!
+ Destroy this 3D rotation transformation.
+*/
+QGraphicsRotation3D::~QGraphicsRotation3D()
+{
+}
+
+/*!
+ \property QGraphicsRotation3D::origin
+ \brief the origin about which to rotate.
+
+ The default value for this property is (0, 0, 0).
+*/
+
+/*!
+ \qmlproperty vector3D Rotation3D::origin
+
+ The origin about which to rotate. The default value for this
+ property is (0, 0, 0).
+*/
+
+QVector3D QGraphicsRotation3D::origin() const
+{
+ Q_D(const QGraphicsRotation3D);
+ return d->origin;
+}
+
+void QGraphicsRotation3D::setOrigin(const QVector3D &value)
+{
+ Q_D(QGraphicsRotation3D);
+ if (d->origin != value) {
+ d->origin = value;
+ emit transformChanged();
+ emit originChanged();
+ }
+}
+
+/*!
+ \property QGraphicsRotation3D::angle
+ \brief the angle to rotate around the axis, in degrees anti-clockwise.
+
+ The default value for this property is 0.
+*/
+
+/*!
+ \qmlproperty real Rotation3D::angle
+
+ The angle to rotate around the axis, in degrees anti-clockwise.
+ The default value for this property is 0.
+*/
+
+qreal QGraphicsRotation3D::angle() const
+{
+ Q_D(const QGraphicsRotation3D);
+ return d->angle;
+}
+
+void QGraphicsRotation3D::setAngle(qreal value)
+{
+ Q_D(QGraphicsRotation3D);
+ if (d->angle != value) {
+ d->angle = value;
+ emit transformChanged();
+ emit angleChanged();
+ }
+}
+
+/*!
+ \property QGraphicsRotation3D::axis
+ \brief the axis to rotate around.
+
+ The default value for this property is (0, 0, 1); i.e. the z-axis.
+*/
+
+/*!
+ \qmlproperty vector3D Rotation3D::axis
+
+ The axis to rotate around. The default value for this property
+ is (0, 0, 1); i.e. the z-axis.
+*/
+
+QVector3D QGraphicsRotation3D::axis() const
+{
+ Q_D(const QGraphicsRotation3D);
+ return d->axis;
+}
+
+void QGraphicsRotation3D::setAxis(const QVector3D &value)
+{
+ Q_D(QGraphicsRotation3D);
+ if (d->axis != value) {
+ d->axis = value;
+ emit transformChanged();
+ emit axisChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsRotation3D::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QGraphicsRotation3D);
+ matrix->translate(d->origin);
+ matrix->rotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z());
+ matrix->translate(-d->origin);
+}
+
+/*!
+ \internal
+*/
+QGraphicsTransform3D *QGraphicsRotation3D::clone(QObject *parent) const
+{
+ Q_D(const QGraphicsRotation3D);
+ QGraphicsRotation3D *copy = new QGraphicsRotation3D(parent);
+ copy->setOrigin(d->origin);
+ copy->setAxis(d->axis);
+ copy->setAngle(d->angle);
+ return copy;
+}
+
+/*!
+ \fn void QGraphicsRotation3D::originChanged()
+
+ Signal that is emitted when origin() changes.
+*/
+
+/*!
+ \fn void QGraphicsRotation3D::angleChanged()
+
+ Signal that is emitted when angle() changes.
+*/
+
+/*!
+ \fn void QGraphicsRotation3D::axisChanged()
+
+ Signal that is emitted when axis() changes.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/graphicsview/qgraphicsrotation3d.h b/src/threed/graphicsview/qgraphicsrotation3d.h
new file mode 100644
index 000000000..cf1690a0a
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsrotation3d.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSROTATION3D_H
+#define QGRAPHICSROTATION3D_H
+
+#include "qgraphicstransform3d.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsRotation3DPrivate;
+
+class Q_QT3D_EXPORT QGraphicsRotation3D : public QGraphicsTransform3D
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged)
+public:
+ QGraphicsRotation3D(QObject *parent = 0);
+ ~QGraphicsRotation3D();
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &value);
+
+ qreal angle() const;
+ void setAngle(qreal value);
+
+ QVector3D axis() const;
+ void setAxis(const QVector3D &value);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+ QGraphicsTransform3D *clone(QObject *parent) const;
+
+Q_SIGNALS:
+ void originChanged();
+ void angleChanged();
+ void axisChanged();
+
+private:
+ QScopedPointer<QGraphicsRotation3DPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGraphicsRotation3D)
+ Q_DECLARE_PRIVATE(QGraphicsRotation3D)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/graphicsview/qgraphicsscale3d.cpp b/src/threed/graphicsview/qgraphicsscale3d.cpp
new file mode 100644
index 000000000..48803b6bf
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsscale3d.cpp
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsscale3d.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsScale3D
+ \brief The QGraphicsScale3D class supports scaling of items in 3D.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::graphicsview
+
+ \sa QGraphicsRotation3D, QGraphicsTranslation3D
+*/
+
+/*!
+ \qmlclass Scale3D QGraphicsScale3D
+ \brief The Scale3D item supports scaling of items in 3D.
+ \since 4.8
+ \ingroup qt3d::qml3d
+
+ 3D items in QML can have a simple scale applied directly as follows:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "chair.3ds" }
+ scale: 0.5
+ }
+ \endcode
+
+ An alternative is to use Scale3D to apply a transform directly
+ to an item as part of a sequence of transformations:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "chair.3ds" }
+ transform: [
+ Translation3D { translate: Qt.vector3d(5, 0, 0) },
+ Scale3D { scale: 0.5 }
+ ]
+ }
+ \endcode
+
+ This allows the application writer to control exactly when the
+ scale occurs relative to other transformations. In the example
+ above, the item is first translated by 5 units along the x-axis,
+ and then the co-ordinates are scaled by half. This is distinct
+ from the following example which scales the object to half its
+ original size and then translates it by 5 units along the x-axis:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "chair.3ds" }
+ transform: [
+ Scale3D { scale: 0.5 },
+ Translation3D { translate: Qt.vector3d(5, 0, 0) }
+ ]
+ }
+ \endcode
+
+ The scale property on the item itself is applied before
+ any of the transforms. So the previous example is equivalent to:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "chair.3ds" }
+ scale: 0.5
+ transform: [
+ Translation3D { translate: Qt.vector3d(5, 0, 0) }
+ ]
+ }
+ \endcode
+
+ Scale values can also affect the x, y, and z axes by different amounts
+ by using a \c{vector3D} value:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "chair.3ds" }
+ transform: [
+ Scale3D { scale: Qt.vector3d(0.5, 0.2, 1.0) },
+ Translation3D { translate: Qt.vector3d(5, 0, 0) }
+ ]
+ }
+ \endcode
+
+ \sa Rotation3D, Translation3D
+*/
+
+class QGraphicsScale3DPrivate
+{
+public:
+ QGraphicsScale3DPrivate() : scale(1, 1, 1) {}
+
+ QVector3D origin;
+ QVector3D scale;
+};
+
+/*!
+ Construct a 3D scale transform and attach it to \a parent.
+*/
+QGraphicsScale3D::QGraphicsScale3D(QObject *parent)
+ : QGraphicsTransform3D(parent), d_ptr(new QGraphicsScale3DPrivate)
+{
+}
+
+/*!
+ Destroy this 3D scale transform.
+*/
+QGraphicsScale3D::~QGraphicsScale3D()
+{
+}
+
+/*!
+ \property QGraphicsScale3D::origin
+ \brief the origin about which to scale.
+
+ The default value for this property is (0, 0, 0).
+*/
+
+/*!
+ \qmlproperty vector3D Scale3D::origin
+
+ The origin about which to scale. The default value for this
+ property is (0, 0, 0).
+*/
+
+QVector3D QGraphicsScale3D::origin() const
+{
+ Q_D(const QGraphicsScale3D);
+ return d->origin;
+}
+
+void QGraphicsScale3D::setOrigin(const QVector3D &value)
+{
+ Q_D(QGraphicsScale3D);
+ if (d->origin != value) {
+ d->origin = value;
+ emit transformChanged();
+ emit originChanged();
+ }
+}
+
+/*!
+ \property QGraphicsScale3D::scale
+ \brief the amount with which to scale each component.
+
+ The default value for this property is QVector3D(1, 1, 1).
+*/
+
+/*!
+ \qmlproperty vector3D Scale3D::scale
+
+ The amount with which to scale each component. The default value for
+ this property is (1, 1, 1).
+
+ This property can be specified as either a vector3D or a single
+ floating-point value. A single floating-point value will set
+ the x, y, and z scale components to the same value. In other words,
+ the following two transformations are equivalent:
+
+ \code
+ Scale3D { scale: 2 }
+ Scale3D { scale: Qt.vector3d(2, 2, 2) }
+ \endcode
+*/
+
+QVector3D QGraphicsScale3D::scale() const
+{
+ Q_D(const QGraphicsScale3D);
+ return d->scale;
+}
+
+void QGraphicsScale3D::setScale(const QVector3D &value)
+{
+ Q_D(QGraphicsScale3D);
+ if (d->scale != value) {
+ d->scale = value;
+ emit transformChanged();
+ emit scaleChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsScale3D::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QGraphicsScale3D);
+ matrix->translate(d->origin);
+ matrix->scale(d->scale);
+ matrix->translate(-d->origin);
+}
+
+/*!
+ \internal
+*/
+QGraphicsTransform3D *QGraphicsScale3D::clone(QObject *parent) const
+{
+ Q_D(const QGraphicsScale3D);
+ QGraphicsScale3D *copy = new QGraphicsScale3D(parent);
+ copy->setOrigin(d->origin);
+ copy->setScale(d->scale);
+ return copy;
+}
+
+/*!
+ \fn void QGraphicsScale3D::originChanged()
+
+ Signal that is emitted when origin() changes.
+*/
+
+/*!
+ \fn void QGraphicsScale3D::scaleChanged()
+
+ Signal that is emitted when scale() changes.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/graphicsview/qgraphicsscale3d.h b/src/threed/graphicsview/qgraphicsscale3d.h
new file mode 100644
index 000000000..2c648e285
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicsscale3d.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSCALE3D_H
+#define QGRAPHICSSCALE3D_H
+
+#include "qgraphicstransform3d.h"
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsScale3DPrivate;
+
+class Q_QT3D_EXPORT QGraphicsScale3D : public QGraphicsTransform3D
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
+ Q_PROPERTY(QVector3D scale READ scale WRITE setScale NOTIFY scaleChanged)
+public:
+ QGraphicsScale3D(QObject *parent = 0);
+ ~QGraphicsScale3D();
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &value);
+
+ QVector3D scale() const;
+ void setScale(const QVector3D &value);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+ QGraphicsTransform3D *clone(QObject *parent) const;
+
+Q_SIGNALS:
+ void originChanged();
+ void scaleChanged();
+
+private:
+ QScopedPointer<QGraphicsScale3DPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGraphicsScale3D)
+ Q_DECLARE_PRIVATE(QGraphicsScale3D)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/graphicsview/qgraphicstransform3d.cpp b/src/threed/graphicsview/qgraphicstransform3d.cpp
new file mode 100644
index 000000000..8e72d2a62
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicstransform3d.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicstransform3d.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsTransform3D
+ \brief The QGraphicsTransform3D class is an abstract base class for building 3D transformations.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::graphicsview
+
+ QGraphicsTransform3D lets you create and control advanced transformations
+ that can be configured independently using specialized properties.
+ Scene nodes have an associated list of transforms, which are applied
+ in order, one at a time, to the modelview matrix. Transformations are
+ computed in true 3D space using QMatrix4x4.
+
+ QGraphicsTransform3D is particularly useful for animations. Whereas
+ QGLPainter::modelViewMatrix() lets you assign any transform directly,
+ there is no direct way to interpolate between two different
+ transformations (e.g., when transitioning between two states, each for
+ which the item has a different arbitrary transform assigned). Using
+ QGraphicsTransform3D you can interpolate the property values of each
+ independent transformation. The resulting operation is then combined into a
+ single transform which is applied to the modelview matrix during drawing.
+
+ If you want to create your own configurable transformation, you can create
+ a subclass of QGraphicsTransform3D (or any or the existing subclasses), and
+ reimplement the pure virtual applyTo() function, which takes a pointer to a
+ QMatrix4x4. Each operation you would like to apply should be exposed as
+ properties (e.g., customTransform->setVerticalShear(2.5)). Inside you
+ reimplementation of applyTo(), you can modify the provided transform
+ respectively.
+
+ \sa QGraphicsScale3D, QGraphicsRotation3D, QGraphicsTranslation3D
+ \sa QGraphicsBillboardTransform
+*/
+
+/*!
+ \fn QGraphicsTransform3D::QGraphicsTransform3D(QObject *parent)
+
+ Constructs a 3D transformation and attaches it to \a parent.
+*/
+
+/*!
+ \fn QGraphicsTransform3D::~QGraphicsTransform3D()
+
+ Destroys this 3D transformation.
+*/
+
+/*!
+ \fn void QGraphicsTransform3D::applyTo(QMatrix4x4 *matrix) const
+
+ Applies the effect of this transformation to the specified
+ modelview \a matrix.
+*/
+
+/*!
+ \fn QGraphicsTransform3D *QGraphicsTransform3D::clone(QObject *parent) const
+
+ Clones a copy of this transformation and attaches the clone to \a parent.
+*/
+
+/*!
+ \fn void QGraphicsTransform3D::transformChanged()
+
+ Signal that is emitted whenever any of the transformation's
+ parameters are changed.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/graphicsview/qgraphicstransform3d.h b/src/threed/graphicsview/qgraphicstransform3d.h
new file mode 100644
index 000000000..84a544932
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicstransform3d.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSTRANSFORM3D_H
+#define QGRAPHICSTRANSFORM3D_H
+
+#include <QtCore/qobject.h>
+#include <QtGui/qmatrix4x4.h>
+#include "qt3dglobal.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class Q_QT3D_EXPORT QGraphicsTransform3D : public QObject
+{
+ Q_OBJECT
+public:
+ QGraphicsTransform3D(QObject *parent = 0) : QObject(parent) {}
+ ~QGraphicsTransform3D() {}
+
+ virtual void applyTo(QMatrix4x4 *matrix) const = 0;
+ virtual QGraphicsTransform3D *clone(QObject *parent = 0) const = 0;
+
+Q_SIGNALS:
+ void transformChanged();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/graphicsview/qgraphicstranslation3d.cpp b/src/threed/graphicsview/qgraphicstranslation3d.cpp
new file mode 100644
index 000000000..446b61380
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicstranslation3d.cpp
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicstranslation3d.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGraphicsTranslation3D
+ \brief The QGraphicsTranslation3D class supports translation of 3D items.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::graphicsview
+
+ QGraphicsTranslation3D is derived directly from QGraphicsTransform, and
+ provides a \l translate property to specify the 3D vector to
+ apply to incoming co-ordinates.
+
+ The \l progress property can be used to perform animation along a
+ translation vector by varying the progress value between 0 and 1.
+ Overshoot animations are also possible by setting the progress
+ value to something outside this range. The default progress
+ value is 1.
+
+ \sa QGraphicsRotation3D, QGraphicsScale3D
+*/
+
+/*!
+ \qmlclass Translation3D QGraphicsTranslation3D
+ \brief The Translation3D item supports translation of items in 3D.
+ \since 4.8
+ \ingroup qt3d::qml3d
+
+ 3D items in QML are typically positioned directly as follows:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "chair.3ds" }
+ position: Qt.vector3d(0, 5, 10)
+ }
+ \endcode
+
+ However, it can sometimes be useful to translate an object along a
+ vector under the control of an animation. The Translate3D
+ element can be used for this purpose. The following example
+ translates the object along a straight-line path 5 units to
+ the right of its original position, and then back again:
+
+ \code
+ Item3D {
+ mesh: Mesh { source: "chair.3ds" }
+ position: Qt.vector3d(0, 5, 10)
+ transform: [
+ Translation3D {
+ translate: Qt.vector3d(5, 0, 0)
+ SequentialAnimation on progress {
+ running: true
+ loops: Animation.Infinite
+ NumberAnimation { to : 1.0; duration: 300 }
+ NumberAnimation { to : 0.0; duration: 300 }
+ }
+ }
+ ]
+ }
+ \endcode
+
+ \sa Rotation3D, Scale3D
+*/
+
+class QGraphicsTranslation3DPrivate
+{
+public:
+ QGraphicsTranslation3DPrivate() : progress(1.0f) {}
+
+ QVector3D translate;
+ qreal progress;
+};
+
+/*!
+ Constructs a new translation and attaches it to \a parent.
+*/
+QGraphicsTranslation3D::QGraphicsTranslation3D(QObject *parent)
+ : QGraphicsTransform3D(parent), d_ptr(new QGraphicsTranslation3DPrivate)
+{
+}
+
+/*!
+ Destroys this translation.
+*/
+QGraphicsTranslation3D::~QGraphicsTranslation3D()
+{
+}
+
+/*!
+ \property QGraphicsTranslation3D::translate
+ \brief the translation to apply to incoming co-ordinates.
+
+ The default value for this property is (0, 0, 0).
+*/
+
+/*!
+ \qmlproperty vector3D Translation3D::translate
+
+ The translation to apply to incoming co-ordinates. The default value
+ for this property is (0, 0, 0).
+*/
+
+QVector3D QGraphicsTranslation3D::translate() const
+{
+ Q_D(const QGraphicsTranslation3D);
+ return d->translate;
+}
+
+void QGraphicsTranslation3D::setTranslate(const QVector3D &value)
+{
+ Q_D(QGraphicsTranslation3D);
+ if (d->translate != value) {
+ d->translate = value;
+ emit transformChanged();
+ emit translateChanged();
+ }
+}
+
+/*!
+ \property QGraphicsTranslation3D::progress
+ \brief the progress along the translation vector, from 0 to 1.
+
+ The default value for this property is 1.
+
+ This property can be used to perform animation along a translation
+ vector by varying the progress between 0 and 1. Overshoot animations
+ are also possible by setting the value to something outside this range.
+*/
+
+/*!
+ \qmlproperty real Translation3D::progress
+
+ The progress along the translation vector, from 0 to 1. The default
+ value for this property is 1.
+
+ This property can be used to perform animation along a translation
+ vector by varying the progress between 0 and 1. Overshoot animations
+ are also possible by setting the value to something outside this range.
+*/
+
+qreal QGraphicsTranslation3D::progress() const
+{
+ Q_D(const QGraphicsTranslation3D);
+ return d->progress;
+}
+
+void QGraphicsTranslation3D::setProgress(qreal value)
+{
+ Q_D(QGraphicsTranslation3D);
+ if (d->progress != value) {
+ d->progress = value;
+ emit transformChanged();
+ emit progressChanged();
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsTranslation3D::applyTo(QMatrix4x4 *matrix) const
+{
+ Q_D(const QGraphicsTranslation3D);
+ matrix->translate(d->translate * d->progress);
+}
+
+/*!
+ \internal
+*/
+QGraphicsTransform3D *QGraphicsTranslation3D::clone(QObject *parent) const
+{
+ Q_D(const QGraphicsTranslation3D);
+ QGraphicsTranslation3D *copy = new QGraphicsTranslation3D(parent);
+ copy->setTranslate(d->translate);
+ copy->setProgress(d->progress);
+ return copy;
+}
+
+/*!
+ \fn void QGraphicsTranslation3D::translateChanged()
+
+ Signal that is emitted when translate() changes.
+*/
+
+/*!
+ \fn void QGraphicsTranslation3D::progressChanged()
+
+ Signal that is emitted when progress() changes.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/graphicsview/qgraphicstranslation3d.h b/src/threed/graphicsview/qgraphicstranslation3d.h
new file mode 100644
index 000000000..c2a3e1633
--- /dev/null
+++ b/src/threed/graphicsview/qgraphicstranslation3d.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSTRANSLATION3D_H
+#define QGRAPHICSTRANSLATION3D_H
+
+#include "qgraphicstransform3d.h"
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsTranslation3DPrivate;
+
+class Q_QT3D_EXPORT QGraphicsTranslation3D : public QGraphicsTransform3D
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector3D translate READ translate WRITE setTranslate NOTIFY translateChanged)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
+public:
+ QGraphicsTranslation3D(QObject *parent = 0);
+ ~QGraphicsTranslation3D();
+
+ QVector3D translate() const;
+ void setTranslate(const QVector3D &value);
+
+ qreal progress() const;
+ void setProgress(qreal value);
+
+ void applyTo(QMatrix4x4 *matrix) const;
+ QGraphicsTransform3D *clone(QObject *parent) const;
+
+Q_SIGNALS:
+ void translateChanged();
+ void progressChanged();
+
+private:
+ QScopedPointer<QGraphicsTranslation3DPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGraphicsTranslation3D)
+ Q_DECLARE_PRIVATE(QGraphicsTranslation3D)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/materials/materials.pri b/src/threed/materials/materials.pri
new file mode 100644
index 000000000..3eb8e0173
--- /dev/null
+++ b/src/threed/materials/materials.pri
@@ -0,0 +1,18 @@
+
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+
+HEADERS += \
+ qglabstractmaterial.h \
+ qglcolormaterial.h \
+ qglmaterial.h \
+ qgltwosidedmaterial.h
+
+SOURCES += \
+ qglabstractmaterial.cpp \
+ qglcolormaterial.cpp \
+ qglmaterial.cpp \
+ qgltwosidedmaterial.cpp
+
+PRIVATE_HEADERS += \
+ qglmaterial_p.h
diff --git a/src/threed/materials/qglabstractmaterial.cpp b/src/threed/materials/qglabstractmaterial.cpp
new file mode 100644
index 000000000..c0b37dc37
--- /dev/null
+++ b/src/threed/materials/qglabstractmaterial.cpp
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglabstractmaterial.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLAbstractMaterial
+ \since 4.8
+ \brief The QGLAbstractMaterial class provides a standard interface for rendering surface materials with GL.
+ \ingroup qt3d
+ \ingroup qt3d::materials
+
+ Materials are the primary method to specify the surface appearance of an
+ object, as distinct from the geometry for the object. Materials have an
+ almost endless variety of parameters:
+
+ \list
+ \o Properties of the material under various lighting conditions;
+ i.e., the traditional parameters for ambient, diffuse, specular, etc.
+ \o Textures in multiple layers, with different combination modes;
+ decal, modulate, replace, etc.
+ \o Environmental conditions such as fogging.
+ \o Alpha values for opacity and blending.
+ \o Interpolation factors for animated surface effects.
+ \o etc
+ \endlist
+
+ QGLAbstractMaterial is the base class for all such materials.
+ It provides a very simple API to bind() a material to a QGLPainter
+ when the material needs to be rendered, to release() a material
+ from a QGLPainter when the material is no longer needed, and to
+ prepareToDraw().
+
+ Subclasses of QGLAbstractMaterial implement specific materials.
+ QGLMaterial provides the traditional ambient, diffuse, specular, etc
+ parameters for lighting properties.
+
+ Materials are distinct from \i effects, which have the base class
+ QGLAbstractEffect. Effects are typically shader programs that are
+ used to render a specific type of material. The material's bind()
+ function will use QGLPainter::setStandardEffect() or
+ QGLPainter::setUserEffect() to select the exact effect that is
+ needed to render the material.
+
+ It is possible that the same material may be rendered with different
+ effects depending upon the material parameters. For example, a lit
+ material may select a simpler and more efficient shader program effect
+ if the material has the default spotlight properties, or if the
+ QGLPainter only has a single light source specified.
+
+ \sa QGLMaterial, QGLAbstractEffect
+*/
+
+/*!
+ Constructs a new material and attaches it to \a parent.
+*/
+QGLAbstractMaterial::QGLAbstractMaterial(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys this material.
+*/
+QGLAbstractMaterial::~QGLAbstractMaterial()
+{
+}
+
+/*!
+ Returns the material lighting parameters for rendering the front
+ faces of fragments with this abstract material. The default
+ implementation returns null.
+
+ This function is provided as a convenience for applications that
+ wish to alter the lighting parameters or textures of a material,
+ without regard to any wrapping that has been performed to add
+ blending or other options.
+
+ \sa back(), QGLMaterial
+*/
+QGLMaterial *QGLAbstractMaterial::front() const
+{
+ return 0;
+}
+
+/*!
+ Returns the material lighting parameters for rendering the back
+ faces of fragments with this abstract material. The default
+ implementation returns null, which indicates that front()
+ is also used to render back faces.
+
+ \sa front(), QGLMaterial
+*/
+QGLMaterial *QGLAbstractMaterial::back() const
+{
+ return 0;
+}
+
+/*!
+ \fn bool QGLAbstractMaterial::isTransparent() const
+
+ Returns true if this material is transparent and will therefore
+ require the \c{GL_BLEND} mode to be enabled to render the material.
+ Returns false if the material is fully opaque.
+*/
+
+/*!
+ \fn void QGLAbstractMaterial::bind(QGLPainter *painter)
+
+ Binds resources to \a painter that are needed to render this
+ material; textures, shader programs, blending modes, etc.
+
+ In the following example, lit material parameters and a texture
+ are bound to the \a painter, for rendering with the standard
+ QGL::LitModulateTexture2D effect:
+
+ \code
+ void TexturedLitMaterial::bind(QGLPainter *painter)
+ {
+ painter->setStandardEffect(QGL::LitModulateTexture2D);
+ painter->setFaceMaterial(QGL::AllFaces, material);
+ painter->glActiveTexture(GL_TEXTURE0);
+ texture->bind();
+ }
+ \endcode
+
+ Normally the effect is bound to \a painter during the bind()
+ function. However, some materials may need to use different
+ effects depending upon which attributes are present in the
+ geometry. For example, a per-vertex color effect instead of a
+ uniform color effect if the geometry has the QGL::Color attribute.
+ The prepareToDraw() function can be overridden to alter the
+ effect once the specific set of geometry attributes are known.
+
+ \sa release(), prepareToDraw()
+*/
+
+/*!
+ \fn void QGLAbstractMaterial::release(QGLPainter *painter, QGLAbstractMaterial *next)
+
+ Releases resources from \a painter that were used to render this
+ material. The QGLPainter::effect() can be left bound to \a painter,
+ but other resources such as textures and blending modes
+ should be disabled.
+
+ If \a next is not null, then it indicates the next material that
+ will be bound to \a painter. If \a next is the same type of
+ material as this material, then this function can choose not to
+ release resources that would be immediately re-bound to
+ \a painter in the next call to bind().
+
+ In the following example, texture unit 0 is unbound if \a painter
+ is about to switch to another effect that is not an instance
+ of \c{TexturedLitMaterial}:
+
+ \code
+ void TexturedLitMaterial::release(QGLPainter *painter, QGLAbstractMaterial *next)
+ {
+ if (!qobject_cast<TexturedLitMaterial *>(next)) {
+ painter->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ }
+ \endcode
+
+ \sa bind(), prepareToDraw()
+*/
+
+/*!
+ Prepares to draw geometry to \a painter that has the specified
+ set of vertex \a attributes. The default implementation
+ does nothing.
+
+ Multiple effects may be used to render some materials depending upon
+ the available vertex attributes. For example, if QGL::Color is
+ present in \a attributes, then a per-vertex color should be used
+ instead of a single uniform color.
+
+ This function is provided for such materials to have one last
+ chance during QGLPainter::draw() to alter the QGLPainter::effect()
+ to something that is tuned for the specific geometry. It can
+ be assumed that bind() has already been called on this material.
+
+ \sa bind(), release()
+*/
+void QGLAbstractMaterial::prepareToDraw(QGLPainter *painter, const QGLAttributeSet &attributes)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(attributes);
+}
+
+/*!
+ \fn void QGLAbstractMaterial::materialChanged()
+
+ Signal that is emitted when an object that is using this material
+ should be redrawn because some property on the material has changed.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/materials/qglabstractmaterial.h b/src/threed/materials/qglabstractmaterial.h
new file mode 100644
index 000000000..b5a60e5ae
--- /dev/null
+++ b/src/threed/materials/qglabstractmaterial.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLABSTRACTMATERIAL_H
+#define QGLABSTRACTMATERIAL_H
+
+#include <QtCore/qobject.h>
+#include "qglattributeset.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLPainter;
+class QGLMaterial;
+
+class Q_QT3D_EXPORT QGLAbstractMaterial : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QGLAbstractMaterial)
+public:
+ explicit QGLAbstractMaterial(QObject *parent = 0);
+ ~QGLAbstractMaterial();
+
+ virtual QGLMaterial *front() const;
+ virtual QGLMaterial *back() const;
+
+ virtual bool isTransparent() const = 0;
+
+ virtual void bind(QGLPainter *painter) = 0;
+ virtual void release(QGLPainter *painter, QGLAbstractMaterial *next) = 0;
+ virtual void prepareToDraw(QGLPainter *painter, const QGLAttributeSet &attributes);
+
+Q_SIGNALS:
+ void materialChanged();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/materials/qglcolormaterial.cpp b/src/threed/materials/qglcolormaterial.cpp
new file mode 100644
index 000000000..4a507f12a
--- /dev/null
+++ b/src/threed/materials/qglcolormaterial.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcolormaterial.h"
+#include "qglpainter.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLColorMaterial
+ \since 4.8
+ \brief The QGLColorMaterial class implements flat or per-vertex color materials for 3D rendering.
+ \ingroup qt3d
+ \ingroup qt3d::materials
+
+ When bound to a QGLPainter, QGLColorMaterial will select a flat
+ color drawing effect, to render fragments with color(), ignoring
+ any lights or textures that may be active on the QGLPainter state.
+ If the geometry has the QGL::Color attribute, then a per-vertex
+ color will be used instead and color() is ignored.
+
+ \sa QGLMaterial
+*/
+
+class QGLColorMaterialPrivate
+{
+public:
+ QGLColorMaterialPrivate() : color(255, 255, 255, 255) {}
+
+ QColor color;
+};
+
+/*!
+ Constructs a new flat color material and attaches it to \a parent.
+*/
+QGLColorMaterial::QGLColorMaterial(QObject *parent)
+ : QGLAbstractMaterial(parent)
+ , d_ptr(new QGLColorMaterialPrivate)
+{
+}
+
+/*!
+ Destroys this flat color material.
+*/
+QGLColorMaterial::~QGLColorMaterial()
+{
+}
+
+/*!
+ \property QGLColorMaterial::color
+ \brief the flat color to use to render the material. The default
+ color is white.
+
+ If the geometry has per-vertex colors, then this property is ignored.
+
+ \sa colorChanged()
+*/
+
+QColor QGLColorMaterial::color() const
+{
+ Q_D(const QGLColorMaterial);
+ return d->color;
+}
+
+void QGLColorMaterial::setColor(const QColor &color)
+{
+ Q_D(QGLColorMaterial);
+ if (d->color != color) {
+ d->color = color;
+ emit colorChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QGLColorMaterial::isTransparent() const
+{
+ Q_D(const QGLColorMaterial);
+ return d->color.alpha() != 255;
+}
+
+/*!
+ \reimp
+*/
+void QGLColorMaterial::bind(QGLPainter *painter)
+{
+ Q_D(const QGLColorMaterial);
+ painter->setColor(d->color);
+ // Effect is set during prepareToDraw().
+}
+
+/*!
+ \reimp
+*/
+void QGLColorMaterial::release(QGLPainter *painter, QGLAbstractMaterial *next)
+{
+ // No textures or other modes, so nothing to do here.
+ Q_UNUSED(painter);
+ Q_UNUSED(next);
+}
+
+/*!
+ \reimp
+*/
+void QGLColorMaterial::prepareToDraw
+ (QGLPainter *painter, const QGLAttributeSet &attributes)
+{
+ if (attributes.contains(QGL::Color))
+ painter->setStandardEffect(QGL::FlatPerVertexColor);
+ else
+ painter->setStandardEffect(QGL::FlatColor);
+}
+
+/*!
+ \fn void QGLColorMaterial::colorChanged()
+
+ Signal that is emitted when color() changes.
+
+ \sa color()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/materials/qglcolormaterial.h b/src/threed/materials/qglcolormaterial.h
new file mode 100644
index 000000000..6ec953ecd
--- /dev/null
+++ b/src/threed/materials/qglcolormaterial.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCOLORMATERIAL_H
+#define QGLCOLORMATERIAL_H
+
+#include "qglabstractmaterial.h"
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLColorMaterialPrivate;
+
+class Q_QT3D_EXPORT QGLColorMaterial : public QGLAbstractMaterial
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGLColorMaterial)
+ Q_DISABLE_COPY(QGLColorMaterial)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+public:
+ explicit QGLColorMaterial(QObject *parent = 0);
+ ~QGLColorMaterial();
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ bool isTransparent() const;
+ void bind(QGLPainter *painter);
+ void release(QGLPainter *painter, QGLAbstractMaterial *next);
+ void prepareToDraw(QGLPainter *painter, const QGLAttributeSet &attributes);
+
+Q_SIGNALS:
+ void colorChanged();
+
+private:
+ QScopedPointer<QGLColorMaterialPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/materials/qglmaterial.cpp b/src/threed/materials/qglmaterial.cpp
new file mode 100644
index 000000000..4d7d4d683
--- /dev/null
+++ b/src/threed/materials/qglmaterial.cpp
@@ -0,0 +1,586 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglmaterial.h"
+#include "qglmaterial_p.h"
+#include "qglpainter.h"
+#include "qgltexture2d.h"
+#include "qglmaterialcollection.h"
+#include "qgllightmodel.h"
+#include "qfileinfo.h"
+
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLMaterial
+ \brief The QGLMaterial class describes one-sided material properties for rendering fragments.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::materials
+
+ \sa QGLTwoSidedMaterial
+*/
+
+/*!
+ \qmlclass Material QGLMaterial
+ \brief The Material item describes material properties for OpenGL drawing.
+ \since 4.8
+ \ingroup qt3d::qml3d
+*/
+
+QGLMaterialPrivate::QGLMaterialPrivate()
+ : specularColor(0, 0, 0, 255),
+ emittedLight(0, 0, 0, 255),
+ shininess(0),
+ collection(0),
+ index(-1),
+ used(false)
+{
+ ambientColor.setRgbF(0.2f, 0.2f, 0.2f, 1.0f);
+ diffuseColor.setRgbF(0.8f, 0.8f, 0.8f, 1.0f);
+}
+
+/*!
+ Constructs a QGLMaterial object with its default values,
+ and attaches it to \a parent.
+*/
+QGLMaterial::QGLMaterial(QObject *parent)
+ : QGLAbstractMaterial(parent)
+ , d_ptr(new QGLMaterialPrivate)
+{
+}
+
+/*!
+ Destroys this QGLMaterial object.
+*/
+QGLMaterial::~QGLMaterial()
+{
+}
+
+/*!
+ \property QGLMaterial::ambientColor
+ \brief the ambient color of the material. The default value
+ is (0.2, 0.2, 0.2, 1.0).
+
+ \sa diffuseColor(), specularColor(), ambientColorChanged()
+*/
+
+/*!
+ \qmlproperty color Material::ambientColor
+ The ambient color of the material. The default value
+ is (0.2, 0.2, 0.2, 1.0).
+
+ \sa diffuseColor, specularColor
+*/
+
+QColor QGLMaterial::ambientColor() const
+{
+ Q_D(const QGLMaterial);
+ return d->ambientColor;
+}
+
+void QGLMaterial::setAmbientColor(const QColor& value)
+{
+ Q_D(QGLMaterial);
+ if (d->ambientColor != value) {
+ d->ambientColor = value;
+ emit ambientColorChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \property QGLMaterial::diffuseColor
+ \brief the diffuse color of the material. The default value
+ is (0.8, 0.8, 0.8, 1.0).
+
+ \sa ambientColor(), specularColor(), diffuseColorChanged()
+*/
+
+/*!
+ \qmlproperty color Material::diffuseColor
+ The diffuse color of the material. The default value
+ is (0.8, 0.8, 0.8, 1.0).
+
+ \sa ambientColor, specularColor
+*/
+
+QColor QGLMaterial::diffuseColor() const
+{
+ Q_D(const QGLMaterial);
+ return d->diffuseColor;
+}
+
+void QGLMaterial::setDiffuseColor(const QColor& value)
+{
+ Q_D(QGLMaterial);
+ if (d->diffuseColor != value) {
+ d->diffuseColor = value;
+ emit diffuseColorChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \property QGLMaterial::specularColor
+ \brief the specular color of the material. The default value
+ is (0, 0, 0, 1).
+
+ \sa ambientColor(), diffuseColor(), specularColorChanged()
+*/
+
+/*!
+ \qmlproperty color Material::specularColor
+ The specular color of the material. The default value
+ is (0, 0, 0, 1).
+
+ \sa ambientColor, diffuseColor
+*/
+
+QColor QGLMaterial::specularColor() const
+{
+ Q_D(const QGLMaterial);
+ return d->specularColor;
+}
+
+void QGLMaterial::setSpecularColor(const QColor& value)
+{
+ Q_D(QGLMaterial);
+ if (d->specularColor != value) {
+ d->specularColor = value;
+ emit specularColorChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \property QGLMaterial::emittedLight
+ \brief the emitted light intensity of the material.
+ The default value is (0.0, 0.0, 0.0, 1.0), which indicates
+ that the material does not emit any light.
+
+ \sa emittedLightChanged()
+*/
+
+/*!
+ \qmlproperty color Material::emittedLight
+ The emitted light intensity of the material.
+ The default value is (0.0, 0.0, 0.0, 1.0), which indicates
+ that the material does not emit any light.
+*/
+
+QColor QGLMaterial::emittedLight() const
+{
+ Q_D(const QGLMaterial);
+ return d->emittedLight;
+}
+
+void QGLMaterial::setEmittedLight(const QColor& value)
+{
+ Q_D(QGLMaterial);
+ if (d->emittedLight != value) {
+ d->emittedLight = value;
+ emit emittedLightChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ Sets ambientColor() to 20% of \a value, and diffuseColor() to 80% of
+ \a value. This is a convenience function for quickly setting ambient
+ and diffuse lighting colors based on a flat color.
+
+ \sa ambientColor(), diffuseColor()
+*/
+void QGLMaterial::setColor(const QColor& value)
+{
+ Q_D(QGLMaterial);
+ d->ambientColor.setRgbF
+ (value.redF() * 0.2f, value.greenF() * 0.2f,
+ value.blueF() * 0.2f, value.alphaF());
+ d->diffuseColor.setRgbF
+ (value.redF() * 0.8f, value.greenF() * 0.8f,
+ value.blueF() * 0.8f, value.alphaF());
+ emit ambientColorChanged();
+ emit diffuseColorChanged();
+ emit materialChanged();
+}
+
+/*!
+ \property QGLMaterial::shininess
+ \brief the specular exponent of the material, or how shiny it is.
+ Must be between 0 and 128. The default value is 0. A value outside
+ this range will be clamped to the range when the property is set.
+
+ \sa shininessChanged()
+*/
+
+/*!
+ \qmlproperty real Material::shininess
+ The specular exponent of the material, or how shiny it is.
+ Must be between 0 and 128. The default value is 0. A value outside
+ this range will be clamped to the range when the property is set.
+*/
+
+qreal QGLMaterial::shininess() const
+{
+ Q_D(const QGLMaterial);
+ return d->shininess;
+}
+
+void QGLMaterial::setShininess(qreal value)
+{
+ Q_D(QGLMaterial);
+ if (value < 0)
+ value = 0;
+ else if (value > 128)
+ value = 128;
+ if (d->shininess != value) {
+ d->shininess = value;
+ emit shininessChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \property QGLMaterial::texture
+ \brief the 2D texture associated with \a layer on this material;
+ null if no texture.
+
+ Layer 0 is normally the primary texture associated with the material.
+ Multiple texture layers may be specified for materials with special
+ blending effects or to specify ambient, diffuse, or specular colors
+ pixel-by-pixel.
+
+ \sa texturesChanged()
+*/
+QGLTexture2D *QGLMaterial::texture(int layer) const
+{
+ Q_D(const QGLMaterial);
+ return d->textures.value(layer, 0);
+}
+
+void QGLMaterial::setTexture(QGLTexture2D *value, int layer)
+{
+ Q_ASSERT(layer >= 0);
+ Q_D(QGLMaterial);
+ QGLTexture2D *prev = d->textures.value(layer, 0);
+ if (prev != value) {
+ delete prev;
+ d->textures[layer] = value;
+ emit texturesChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \property QGLMaterial::textureUrl
+ \brief URL of the 2D texture associated with \a layer on this material.
+
+ By default \a layer is 0, the primary texture.
+
+ If the URL has not been specified, then this property is a null QUrl.
+
+ Setting this property to a non-empty URL will replace any existing texture
+ with a new texture based on the image at the given \a url. If that
+ image is not a valid texture then the new texture will be a null texture.
+
+ If an empty url is set, this has the same effect as \c{setTexture(0)}.
+
+ \sa texture(), setTexture()
+*/
+QUrl QGLMaterial::textureUrl(int layer) const
+{
+ Q_D(const QGLMaterial);
+ QGLTexture2D *tex = d->textures.value(layer, 0);
+ if (tex)
+ return tex->url();
+ else
+ return QUrl();
+}
+
+void QGLMaterial::setTextureUrl(const QUrl &url, int layer)
+{
+ Q_ASSERT(layer >= 0);
+ if (textureUrl(layer) != url)
+ {
+ QGLTexture2D *tex = 0;
+ if (!url.isEmpty())
+ {
+ tex = new QGLTexture2D(this);
+ tex->setUrl(url);
+ }
+ setTexture(tex, layer);
+ }
+}
+
+/*!
+ \enum QGLMaterial::TextureCombineMode
+ This enum defines the mode to use when combining a texture with
+ the material colors on a QGLMaterial object.
+
+ \value Modulate Modulate the texture with the lighting
+ conditions to produce a lit texture.
+ \value Decal Combine the texture with the lighting conditions
+ to produce a decal effect.
+ \value Replace Replace with the contents of the texture,
+ ignoring colors and lighting conditions.
+*/
+
+/*!
+ \property QGLMaterial::textureCombineMode
+ \brief the texture combine mode associated with \a layer on this material.
+ The default value is \l Modulate.
+
+ \sa texturesChanged()
+*/
+
+QGLMaterial::TextureCombineMode QGLMaterial::textureCombineMode(int layer) const
+{
+ Q_D(const QGLMaterial);
+ return d->textureModes.value(layer, Modulate);
+}
+
+void QGLMaterial::setTextureCombineMode(QGLMaterial::TextureCombineMode mode, int layer)
+{
+ Q_D(QGLMaterial);
+ if (d->textureModes.value(layer, Modulate) != mode) {
+ d->textureModes[layer] = mode;
+ emit texturesChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ Returns the number of texture layers associated with this material.
+
+ The return value may be larger than the number of actual texture
+ layers if some of the intermediate layers are null. For example,
+ setting layers 0 and 2 will report textureLayerCount() as 3.
+ The main use of this value is to iterate over all layers.
+
+ \sa texture()
+*/
+int QGLMaterial::textureLayerCount() const
+{
+ Q_D(const QGLMaterial);
+ int maxLayer = -1;
+ if (!d->textures.isEmpty())
+ maxLayer = qMax(maxLayer, (d->textures.end() - 1).key());
+ return maxLayer + 1;
+}
+
+/*!
+ \reimp
+ Returns this material.
+*/
+QGLMaterial *QGLMaterial::front() const
+{
+ return const_cast<QGLMaterial *>(this);
+}
+
+/*!
+ \reimp
+*/
+bool QGLMaterial::isTransparent() const
+{
+ Q_D(const QGLMaterial);
+ bool transparent = (d->diffuseColor.alpha() != 255);
+ QMap<int, QGLTexture2D *>::ConstIterator it;
+ for (it = d->textures.begin(); it != d->textures.end(); ++it) {
+ TextureCombineMode mode = d->textureModes.value(it.key(), Modulate);
+ if (mode == Modulate) {
+ // Texture alpha adds to the current alpha.
+ if (it.value() && it.value()->hasAlphaChannel())
+ transparent = true;
+ } else if (mode == Replace) {
+ // Replace the current alpha with the texture's alpha.
+ if (it.value())
+ transparent = it.value()->hasAlphaChannel();
+ }
+ }
+ return transparent;
+}
+
+/*!
+ \reimp
+*/
+void QGLMaterial::bind(QGLPainter *painter)
+{
+ painter->setFaceMaterial(QGL::AllFaces, this);
+ const_cast<QGLLightModel *>(painter->lightModel())
+ ->setModel(QGLLightModel::OneSided); // FIXME
+ bindTextures(painter);
+}
+
+/*!
+ \internal
+*/
+void QGLMaterial::bindTextures(QGLPainter *painter)
+{
+ Q_D(const QGLMaterial);
+ QMap<int, QGLTexture2D *>::ConstIterator it;
+ for (it = d->textures.begin(); it != d->textures.end(); ++it) {
+ QGLTexture2D *tex = it.value();
+ painter->glActiveTexture(GL_TEXTURE0 + it.key());
+ if (tex)
+ tex->bind();
+ else
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGLMaterial::release(QGLPainter *painter, QGLAbstractMaterial *next)
+{
+ Q_UNUSED(next);
+ Q_D(const QGLMaterial);
+ QMap<int, QGLTexture2D *>::ConstIterator it;
+ for (it = d->textures.begin(); it != d->textures.end(); ++it) {
+ painter->glActiveTexture(GL_TEXTURE0 + it.key());
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGLMaterial::prepareToDraw
+ (QGLPainter *painter, const QGLAttributeSet &attributes)
+{
+ bindEffect(painter, attributes, false);
+}
+
+/*!
+ \internal
+*/
+void QGLMaterial::bindEffect
+ (QGLPainter *painter, const QGLAttributeSet &attributes, bool twoSided)
+{
+ Q_D(const QGLMaterial);
+ Q_UNUSED(twoSided);
+ QGL::StandardEffect effect = QGL::LitMaterial;
+ if (!d->textures.isEmpty() && attributes.contains(QGL::TextureCoord0)) {
+ // TODO: different combine modes for each layer.
+ QGLMaterial::TextureCombineMode mode =
+ d->textureModes.value(0, Modulate);
+ if (mode == Replace)
+ effect = QGL::FlatReplaceTexture2D;
+ else if (mode == Decal)
+ effect = QGL::LitDecalTexture2D;
+ else
+ effect = QGL::LitModulateTexture2D;
+ }
+ painter->setStandardEffect(effect);
+}
+
+/*!
+ \fn void QGLMaterial::ambientColorChanged()
+
+ This signal is emitted when ambientColor() changes.
+
+ \sa ambientColor(), setAmbientColor(), materialChanged()
+*/
+
+/*!
+ \fn void QGLMaterial::diffuseColorChanged()
+
+ This signal is emitted when diffuseColor() changes.
+
+ \sa diffuseColor(), setDiffuseColor(), materialChanged()
+*/
+
+/*!
+ \fn void QGLMaterial::specularColorChanged()
+
+ This signal is emitted when specularColor() changes.
+
+ \sa specularColor(), setSpecularColor(), materialChanged()
+*/
+
+/*!
+ \fn void QGLMaterial::emittedLightChanged()
+
+ This signal is emitted when emittedLight() changes.
+
+ \sa emittedLight(), setEmittedLight(), materialChanged()
+*/
+
+/*!
+ \fn void QGLMaterial::shininessChanged()
+
+ This signal is emitted when shininess() changes.
+
+ \sa shininess(), setShininess(), materialChanged()
+*/
+
+/*!
+ \fn void QGLMaterial::texturesChanged()
+
+ This signal is emitted when the texture layers associated with
+ this material change.
+
+ \sa texture(), setTexture(), materialChanged()
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QGLMaterial &material)
+{
+ dbg << &material <<
+ "-- Amb:" << material.ambientColor() <<
+ "-- Diff:" << material.diffuseColor() <<
+ "-- Spec:" << material.specularColor() <<
+ "-- Shin:" << material.shininess();
+ for (int i = 0; i < material.textureLayerCount(); ++i)
+ if (material.texture(i) != 0)
+ dbg << "\n -- Tex" << i << ":" << material.texture(i)
+ << material.texture(i)->objectName();
+ dbg << "\n";
+ return dbg;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/threed/materials/qglmaterial.h b/src/threed/materials/qglmaterial.h
new file mode 100644
index 000000000..74feb9e90
--- /dev/null
+++ b/src/threed/materials/qglmaterial.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLMATERIAL_H
+#define QGLMATERIAL_H
+
+#include "qglabstractmaterial.h"
+#include <QtCore/qobject.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtGui/qcolor.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLMaterialPrivate;
+class QGLTexture2D;
+class QGLTextureCube;
+class QGLPainter;
+class QGLMaterialCollection;
+class QGLTwoSidedMaterial;
+
+class Q_QT3D_EXPORT QGLMaterial : public QGLAbstractMaterial
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGLMaterial)
+ Q_DISABLE_COPY(QGLMaterial)
+ Q_ENUMS(TextureCombineMode)
+ Q_PROPERTY(QColor ambientColor READ ambientColor WRITE setAmbientColor NOTIFY ambientColorChanged)
+ Q_PROPERTY(QColor diffuseColor READ diffuseColor WRITE setDiffuseColor NOTIFY diffuseColorChanged)
+ Q_PROPERTY(QColor specularColor READ specularColor WRITE setSpecularColor NOTIFY specularColorChanged)
+ Q_PROPERTY(QColor emittedLight READ emittedLight WRITE setEmittedLight NOTIFY emittedLightChanged)
+ Q_PROPERTY(qreal shininess READ shininess WRITE setShininess NOTIFY shininessChanged)
+ Q_PROPERTY(QGLTexture2D *texture READ texture WRITE setTexture NOTIFY texturesChanged)
+ Q_PROPERTY(QGLMaterial::TextureCombineMode textureCombineMode READ textureCombineMode WRITE setTextureCombineMode NOTIFY texturesChanged)
+ Q_PROPERTY(QUrl textureUrl READ textureUrl WRITE setTextureUrl NOTIFY texturesChanged)
+public:
+ explicit QGLMaterial(QObject *parent = 0);
+ ~QGLMaterial();
+
+ QColor ambientColor() const;
+ void setAmbientColor(const QColor& value);
+
+ QColor diffuseColor() const;
+ void setDiffuseColor(const QColor& value);
+
+ QColor specularColor() const;
+ void setSpecularColor(const QColor& value);
+
+ QColor emittedLight() const;
+ void setEmittedLight(const QColor& value);
+
+ void setColor(const QColor& value);
+
+ qreal shininess() const;
+ void setShininess(qreal value);
+
+ QGLTexture2D *texture(int layer = 0) const;
+ void setTexture(QGLTexture2D *value, int layer = 0);
+
+ QUrl textureUrl(int layer = 0) const;
+ void setTextureUrl(const QUrl &url, int layer = 0);
+
+ enum TextureCombineMode
+ {
+ Modulate,
+ Decal,
+ Replace
+ };
+
+ QGLMaterial::TextureCombineMode textureCombineMode(int layer = 0) const;
+ void setTextureCombineMode(QGLMaterial::TextureCombineMode mode, int layer = 0);
+
+ int textureLayerCount() const;
+
+ QGLMaterial *front() const;
+ bool isTransparent() const;
+ void bind(QGLPainter *painter);
+ void release(QGLPainter *painter, QGLAbstractMaterial *next);
+ void prepareToDraw(QGLPainter *painter, const QGLAttributeSet &attributes);
+
+Q_SIGNALS:
+ void ambientColorChanged();
+ void diffuseColorChanged();
+ void specularColorChanged();
+ void emittedLightChanged();
+ void shininessChanged();
+ void texturesChanged();
+
+private:
+ friend class QGLMaterialCollection;
+ friend class QGLTwoSidedMaterial;
+
+ void bindTextures(QGLPainter *painter);
+ void bindEffect(QGLPainter *painter, const QGLAttributeSet &attributes, bool twoSided);
+
+ QScopedPointer<QGLMaterialPrivate> d_ptr;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QGLMaterial &material);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/materials/qglmaterial_p.h b/src/threed/materials/qglmaterial_p.h
new file mode 100644
index 000000000..2084f99f0
--- /dev/null
+++ b/src/threed/materials/qglmaterial_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLMATERIAL_P_H
+#define QGLMATERIAL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglmaterial.h"
+#include <QtCore/qmap.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLMaterialPrivate
+{
+public:
+ explicit QGLMaterialPrivate();
+
+ QColor ambientColor;
+ QColor diffuseColor;
+ QColor specularColor;
+ QColor emittedLight;
+ qreal shininess;
+ QMap<int, QGLTexture2D *> textures;
+ QMap<int, QGLMaterial::TextureCombineMode> textureModes;
+ QGLMaterialCollection *collection;
+ int index;
+ QString name;
+ bool used;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/materials/qgltwosidedmaterial.cpp b/src/threed/materials/qgltwosidedmaterial.cpp
new file mode 100644
index 000000000..d8d69b227
--- /dev/null
+++ b/src/threed/materials/qgltwosidedmaterial.cpp
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgltwosidedmaterial.h"
+#include "qglpainter.h"
+#include "qgllightmodel.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLTwoSidedMaterial
+ \since 4.8
+ \brief The QGLTwoSidedMaterial class implemented two-sided materials for 3D rendering.
+ \ingroup qt3d
+ \ingroup qt3d::materials
+
+ Two-sided materials consist of a front() material and a back()
+ material. The specific material rendered is determined by the
+ direction faced by a fragment when it is rendered. Fragments
+ that point towards the viewer are rendered with front(),
+ and fragments that point away from the viewer are rendered
+ with back(). In both cases, any textures that are used to
+ render the material are taken from front().
+
+ If front() and back() are the same, then the same material
+ will be used on both sides of the fragment. However, this
+ is not exactly the same as using a one-sided QGLMaterial in
+ place of the two-sided material. One-sided materials will
+ render the back of the fragment as black because the normal
+ is always pointing away from the viewer. Two-sided materials
+ reverse the back-facing normal so that back() is lit as
+ though it was on a front-facing face.
+
+ \sa QGLMaterial
+*/
+
+class QGLTwoSidedMaterialPrivate
+{
+public:
+ QGLTwoSidedMaterialPrivate() : front(0), back(0), defaultMaterial(0) {}
+
+ QGLMaterial *front;
+ QGLMaterial *back;
+ QGLMaterial *defaultMaterial;
+};
+
+/*!
+ Constructs a two-sided material object and attaches it to \a parent.
+
+ \sa setFront(), setBack()
+*/
+QGLTwoSidedMaterial::QGLTwoSidedMaterial(QObject *parent)
+ : QGLAbstractMaterial(parent)
+ , d_ptr(new QGLTwoSidedMaterialPrivate)
+{
+}
+
+/*!
+ Destroys this two-sided material object.
+*/
+QGLTwoSidedMaterial::~QGLTwoSidedMaterial()
+{
+}
+
+/*!
+ \property QGLTwoSidedMaterial::front
+ \brief the material for the front side of the object's fragments.
+
+ The default value is null, which will result in a default QGLMaterial
+ object being used when bind() is called.
+
+ \sa back(), frontChanged(), materialChanged()
+*/
+
+QGLMaterial *QGLTwoSidedMaterial::front() const
+{
+ Q_D(const QGLTwoSidedMaterial);
+ return d->front;
+}
+
+void QGLTwoSidedMaterial::setFront(QGLMaterial *material)
+{
+ Q_D(QGLTwoSidedMaterial);
+ if (d->front != material) {
+ if (d->front && d->front != d->back) {
+ disconnect(d->front, SIGNAL(materialChanged()),
+ this, SIGNAL(materialChanged()));
+ }
+ d->front = material;
+ if (d->front && d->front != d->back) {
+ connect(d->front, SIGNAL(materialChanged()),
+ this, SIGNAL(materialChanged()));
+ }
+ emit frontChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \property QGLTwoSidedMaterial::back
+ \brief the material for the back side of the object's fragments.
+
+ The default value is null, which indicates that front() should
+ be used on both the front and back sides of the object's fragments.
+
+ Textures are taken from the front() material. Any textures that
+ appear in the back() material are ignored. Only the material
+ lighting parameters from back() will be used.
+
+ \sa front(), backChanged(), materialChanged()
+*/
+
+QGLMaterial *QGLTwoSidedMaterial::back() const
+{
+ Q_D(const QGLTwoSidedMaterial);
+ return d->back;
+}
+
+void QGLTwoSidedMaterial::setBack(QGLMaterial *material)
+{
+ Q_D(QGLTwoSidedMaterial);
+ if (d->back != material) {
+ if (d->back && d->back != d->front) {
+ disconnect(d->back, SIGNAL(materialChanged()),
+ this, SIGNAL(materialChanged()));
+ }
+ d->back = material;
+ if (d->back && d->back != d->front) {
+ connect(d->back, SIGNAL(materialChanged()),
+ this, SIGNAL(materialChanged()));
+ }
+ emit backChanged();
+ emit materialChanged();
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QGLTwoSidedMaterial::isTransparent() const
+{
+ Q_D(const QGLTwoSidedMaterial);
+ if (d->front && d->front->isTransparent())
+ return true;
+ return d->back && d->back->isTransparent();
+}
+
+/*!
+ \reimp
+*/
+void QGLTwoSidedMaterial::bind(QGLPainter *painter)
+{
+ Q_D(QGLTwoSidedMaterial);
+ QGLMaterial *front = d->front;
+ if (!front) {
+ // We need to have something for the front material.
+ front = d->defaultMaterial;
+ if (!front) {
+ d->defaultMaterial = new QGLMaterial(this);
+ front = d->defaultMaterial;
+ }
+ }
+ const_cast<QGLLightModel *>(painter->lightModel())
+ ->setModel(QGLLightModel::TwoSided); // FIXME
+ if (d->back && d->back != front) {
+ painter->setFaceMaterial(QGL::FrontFaces, front);
+ painter->setFaceMaterial(QGL::BackFaces, d->back);
+ } else {
+ painter->setFaceMaterial(QGL::AllFaces, front);
+ }
+ front->bindTextures(painter);
+}
+
+/*!
+ \reimp
+*/
+void QGLTwoSidedMaterial::release(QGLPainter *painter, QGLAbstractMaterial *next)
+{
+ Q_D(const QGLTwoSidedMaterial);
+ if (d->front)
+ d->front->release(painter, next);
+ else if (d->defaultMaterial)
+ d->defaultMaterial->release(painter, next);
+}
+
+/*!
+ \reimp
+*/
+void QGLTwoSidedMaterial::prepareToDraw
+ (QGLPainter *painter, const QGLAttributeSet &attributes)
+{
+ Q_D(QGLTwoSidedMaterial);
+ QGLMaterial *front = d->front;
+ if (!front)
+ front = d->defaultMaterial;
+ front->bindEffect(painter, attributes, true);
+}
+
+/*!
+ \fn void QGLTwoSidedMaterial::frontChanged()
+
+ Signal that is emitted when the front() material pointer changes.
+
+ This signal is not emitted when a property on front() changes.
+ Use materialChanged() for that purpose instead.
+
+ \sa front(), backChanged()
+*/
+
+/*!
+ \fn void QGLTwoSidedMaterial::backChanged()
+
+ Signal that is emitted when the back() material pointer changes.
+
+ This signal is not emitted when a property on back() changes.
+ Use materialChanged() for that purpose instead.
+
+ \sa back(), frontChanged()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/materials/qgltwosidedmaterial.h b/src/threed/materials/qgltwosidedmaterial.h
new file mode 100644
index 000000000..65f544e03
--- /dev/null
+++ b/src/threed/materials/qgltwosidedmaterial.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTWOSIDEDMATERIAL_H
+#define QGLTWOSIDEDMATERIAL_H
+
+#include "qglmaterial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLTwoSidedMaterialPrivate;
+
+class Q_QT3D_EXPORT QGLTwoSidedMaterial : public QGLAbstractMaterial
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGLTwoSidedMaterial)
+ Q_DISABLE_COPY(QGLTwoSidedMaterial)
+ Q_PROPERTY(QGLMaterial *front READ front WRITE setFront NOTIFY frontChanged)
+ Q_PROPERTY(QGLMaterial *back READ back WRITE setBack NOTIFY backChanged)
+public:
+ explicit QGLTwoSidedMaterial(QObject *parent = 0);
+ ~QGLTwoSidedMaterial();
+
+ QGLMaterial *front() const;
+ void setFront(QGLMaterial *material);
+
+ QGLMaterial *back() const;
+ void setBack(QGLMaterial *material);
+
+ bool isTransparent() const;
+ void bind(QGLPainter *painter);
+ void release(QGLPainter *painter, QGLAbstractMaterial *next);
+ void prepareToDraw(QGLPainter *painter, const QGLAttributeSet &attributes);
+
+Q_SIGNALS:
+ void frontChanged();
+ void backChanged();
+
+private:
+ QScopedPointer<QGLTwoSidedMaterialPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/math3d/math3d.pri b/src/threed/math3d/math3d.pri
new file mode 100644
index 000000000..25cd3e74f
--- /dev/null
+++ b/src/threed/math3d/math3d.pri
@@ -0,0 +1,12 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += qbox3d.h \
+ qplane3d.h \
+ qray3d.h \
+ qsphere3d.h \
+ qtriangle3d.h
+SOURCES += qbox3d.cpp \
+ qplane3d.cpp \
+ qray3d.cpp \
+ qsphere3d.cpp \
+ qtriangle3d.cpp
diff --git a/src/threed/math3d/qbox3d.cpp b/src/threed/math3d/qbox3d.cpp
new file mode 100644
index 000000000..043f67d8b
--- /dev/null
+++ b/src/threed/math3d/qbox3d.cpp
@@ -0,0 +1,690 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbox3d.h"
+#include "qplane3d.h"
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QBox3D
+ \brief The QBox3D class represents an axis-aligned box in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::math
+
+ QBox3D can be used to represent the bounding box of objects in a 3D
+ scene so that they can be easily culled if they are out of view.
+
+ The sides of the box are always aligned with the x, y, and z axes of
+ the world co-ordinate system. Transforming a box with transformed()
+ will result in the smallest axis-aligned bounding box that contains
+ the transformed box.
+
+ Boxes may be null, finite, or infinite. A null box does not occupy
+ any space and does not intersect with any other box. A finite
+ box consists of a minimum() and maximum() extent in 3D space.
+ An infinite box encompasses all points in 3D space.
+
+ The extents of a finite box are also included within the box.
+ A box with minimum() and maximum() set to the same value
+ contains a single point.
+*/
+
+/*!
+ \fn QBox3D::QBox3D()
+
+ Constructs a null box in 3D space.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn QBox3D::QBox3D(const QVector3D& corner1, const QVector3D& corner2)
+
+ Constructs a finite box in 3D space from \a corner1 to \a corner2.
+ The minimum() and maximum() co-ordinates of the new box are set
+ to the minimum and maximum x, y, and z values from \a corner1 and
+ \a corner2. The \a corner1 and \a corner2 values can be any two
+ opposite corners that define the box.
+
+ \sa isFinite(), minimum(), maximum()
+*/
+
+/*!
+ \fn bool QBox3D::isNull() const
+
+ Returns true if this box is null; false otherwise.
+
+ \sa isFinite(), isInfinite(), setToNull()
+*/
+
+/*!
+ \fn bool QBox3D::isFinite() const
+
+ Returns true if this box is finite in size; false otherwise.
+
+ \sa isNull(), isInfinite(), setExtents()
+*/
+
+/*!
+ \fn bool QBox3D::isInfinite() const
+
+ Returns true if this box is infinite in size; false otherwise.
+
+ \sa isNull(), isFinite(), setToInfinite()
+*/
+
+/*!
+ \fn QVector3D QBox3D::minimum() const
+
+ Returns the minimum corner of this box.
+
+ \sa maximum(), setExtents()
+*/
+
+/*!
+ \fn QVector3D QBox3D::maximum() const
+
+ Returns the maximum corner of this box.
+
+ \sa minimum(), setExtents()
+*/
+
+/*!
+ \fn void QBox3D::setExtents(const QVector3D& corner1, const QVector3D& corner2)
+
+ Sets the extents of this box to a finite region from \a corner1 to
+ \a corner2. The minimum() and maximum() co-ordinates of the box are
+ set to the minimum and maximum x, y, and z values from \a corner1 and
+ \a corner2. The \a corner1 and \a corner2 values can be any two
+ opposite corners that define the box.
+
+ \sa minimum(), maximum()
+*/
+
+/*!
+ \fn void QBox3D::setToNull()
+
+ Sets this box to null.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn void QBox3D::setToInfinite()
+
+ Sets this box to be infinite in size.
+
+ \sa isInfinite()
+*/
+
+/*!
+ \fn QVector3D QBox3D::size() const
+
+ Returns the finite size of this box. If this box is null or
+ infinite, the returned value will be zero.
+
+ \sa center(), isNull(), isInfinite()
+*/
+
+/*!
+ \fn QVector3D QBox3D::center() const
+
+ Returns the finite center of this box. If this box is null
+ or infinite, the returned value will be zero.
+
+ \sa size(), isNull(), isInfinite()
+*/
+
+/*!
+ \fn bool QBox3D::contains(const QVector3D& point) const
+
+ Returns true if this box contains \a point; false otherwise.
+ Null boxes do not contain any points and infinite boxes contain
+ all points.
+
+ Containment is not a strict test: the point is contained if it
+ lies on one of the faces of the box.
+
+ \sa intersects()
+*/
+
+/*!
+ \fn bool QBox3D::contains(const QBox3D& box) const
+
+ Returns true if this box completely contains \a box. If this box
+ is null, then it will not contain \a box. If this box is infinite,
+ and \a box is not null, then \a box will be contained within this box.
+ If \a box is infinite, then this box must also be infinite to contain it.
+
+ \sa intersects()
+*/
+
+/*!
+ Returns true if \a box intersects this box; false otherwise.
+
+ \sa intersect(), intersected(), contains()
+*/
+bool QBox3D::intersects(const QBox3D& box) const
+{
+ if (boxtype == Null)
+ return false;
+ else if (boxtype == Infinite)
+ return box.boxtype != Null;
+ else if (box.boxtype == Null)
+ return false;
+ else if (box.boxtype == Infinite)
+ return true;
+
+ if (maxcorner.x() < box.mincorner.x())
+ return false;
+ if (mincorner.x() > box.maxcorner.x())
+ return false;
+
+ if (maxcorner.y() < box.mincorner.y())
+ return false;
+ if (mincorner.y() > box.maxcorner.y())
+ return false;
+
+ if (maxcorner.z() < box.mincorner.z())
+ return false;
+ if (mincorner.z() > box.maxcorner.z())
+ return false;
+
+ return true;
+}
+
+/*!
+ Returns true if \a ray intersects this box; false otherwise.
+
+ \sa intersection()
+*/
+bool QBox3D::intersects(const QRay3D &ray) const
+{
+ qreal minimum_t, maximum_t;
+ return intersection(ray, &minimum_t, &maximum_t);
+}
+
+static inline void trackIntersectionX
+ (const QBox3D &box, const QRay3D &ray, qreal t,
+ qreal *minimum_t, qreal *maximum_t, bool *found)
+{
+ QVector3D point = ray.point(t);
+ if (point.y() < box.minimum().y() || point.y() > box.maximum().y())
+ return;
+ if (point.z() < box.minimum().z() || point.z() > box.maximum().z())
+ return;
+ if (!(*found)) {
+ *minimum_t = *maximum_t = t;
+ *found = true;
+ } else {
+ if (t < *minimum_t)
+ *minimum_t = t;
+ if (t > *maximum_t)
+ *maximum_t = t;
+ }
+}
+
+static inline void trackIntersectionY
+ (const QBox3D &box, const QRay3D &ray, qreal t,
+ qreal *minimum_t, qreal *maximum_t, bool *found)
+{
+ QVector3D point = ray.point(t);
+ if (point.x() < box.minimum().x() || point.x() > box.maximum().x())
+ return;
+ if (point.z() < box.minimum().z() || point.z() > box.maximum().z())
+ return;
+ if (!(*found)) {
+ *minimum_t = *maximum_t = t;
+ *found = true;
+ } else {
+ if (t < *minimum_t)
+ *minimum_t = t;
+ if (t > *maximum_t)
+ *maximum_t = t;
+ }
+}
+
+static inline void trackIntersectionZ
+ (const QBox3D &box, const QRay3D &ray, qreal t,
+ qreal *minimum_t, qreal *maximum_t, bool *found)
+{
+ QVector3D point = ray.point(t);
+ if (point.x() < box.minimum().x() || point.x() > box.maximum().x())
+ return;
+ if (point.y() < box.minimum().y() || point.y() > box.maximum().y())
+ return;
+ if (!(*found)) {
+ *minimum_t = *maximum_t = t;
+ *found = true;
+ } else {
+ if (t < *minimum_t)
+ *minimum_t = t;
+ if (t > *maximum_t)
+ *maximum_t = t;
+ }
+}
+
+/*!
+ Finds the \a minimum_t and \a maximum_t values where \a ray intersects
+ this box. Returns true if intersections were found; or false if there
+ is no intersection.
+
+ If \a minimum_t and \a maximum_t are set to the same value, then the
+ intersection is at a corner or the volume of the box is zero.
+ If the t values are negative, then the intersection occurs before the
+ ray's origin point in the reverse direction of the ray.
+
+ The \a minimum_t and \a maximum_t values can be passed to QRay3D::point()
+ to determine the actual intersection points, as shown in the following
+ example:
+
+ \code
+ qreal minimum_t, maximum_t;
+ if (box.intersection(ray, &minimum_t, &maximum_t)) {
+ qDebug() << "intersections at"
+ << ray.point(minimum_t) << "and"
+ << ray.point(maximum_t);
+ }
+ \endcode
+
+ \sa intersects(), QRay3D::point()
+*/
+bool QBox3D::intersection(const QRay3D &ray, qreal *minimum_t, qreal *maximum_t) const
+{
+ bool found = false;
+ QVector3D origin = ray.origin();
+ QVector3D direction = ray.direction();
+ *minimum_t = *maximum_t = qSNaN();
+ if (boxtype == Finite) {
+ if (direction.x() != 0.0f) {
+ trackIntersectionX
+ (*this, ray, (mincorner.x() - origin.x()) / direction.x(),
+ minimum_t, maximum_t, &found);
+ trackIntersectionX
+ (*this, ray, (maxcorner.x() - origin.x()) / direction.x(),
+ minimum_t, maximum_t, &found);
+ }
+ if (direction.y() != 0.0f) {
+ trackIntersectionY
+ (*this, ray, (mincorner.y() - origin.y()) / direction.y(),
+ minimum_t, maximum_t, &found);
+ trackIntersectionY
+ (*this, ray, (maxcorner.y() - origin.y()) / direction.y(),
+ minimum_t, maximum_t, &found);
+ }
+ if (direction.z() != 0.0f) {
+ trackIntersectionZ
+ (*this, ray, (mincorner.z() - origin.z()) / direction.z(),
+ minimum_t, maximum_t, &found);
+ trackIntersectionZ
+ (*this, ray, (maxcorner.z() - origin.z()) / direction.z(),
+ minimum_t, maximum_t, &found);
+ }
+ }
+ return found;
+}
+
+/*!
+ Returns the t value at which \a ray first intersects the sides of
+ this box, or not-a-number if there is no intersection.
+
+ When the \a ray intersects this box, the return value is a
+ parametric value that can be passed to QRay3D::point() to determine
+ the actual intersection point, as shown in the following example:
+
+ \code
+ qreal t = box.intersection(ray);
+ QVector3D pt;
+ if (qIsNaN(t)) {
+ qWarning("no intersection occurred");
+ else
+ pt = ray.point(t);
+ \endcode
+
+ The \a ray might intersect at two points - as the ray passes through
+ the box - one on the near side, one on the far side; where near and far
+ are relative to the origin point of the ray. This function only
+ returns the near intersection point.
+
+ Only positive values on the ray are considered. This means that if
+ the origin point of the ray is inside the box, there is only one
+ solution, not two. To get the other solution, simply change
+ the sign of the ray's direction vector. If the origin point of
+ the ray is outside the box, and the direction points away from
+ the box, then there will be no intersection.
+
+ When the ray does not intersect the box in the positive direction,
+ or the box is not finite, then the return value is not-a-number.
+
+ \sa intersects(), QRay3D::point()
+*/
+qreal QBox3D::intersection(const QRay3D &ray) const
+{
+ qreal minimum_t, maximum_t;
+ if (intersection(ray, &minimum_t, &maximum_t)) {
+ if (minimum_t >= 0.0f)
+ return minimum_t;
+ else if (maximum_t >= 0.0f)
+ return maximum_t;
+ else
+ return qSNaN();
+ } else {
+ return qSNaN();
+ }
+}
+
+/*!
+ Intersects this box with \a box.
+
+ \sa intersected(), intersects(), unite()
+*/
+void QBox3D::intersect(const QBox3D& box)
+{
+ // Handle the simple cases first.
+ if (boxtype == Null) {
+ // Null intersected with anything is null.
+ return;
+ } else if (boxtype == Infinite) {
+ // Infinity intersected with a box is that box.
+ *this = box;
+ return;
+ } else if (box.boxtype == Null) {
+ // Anything intersected with null is null.
+ setToNull();
+ return;
+ } else if (box.boxtype == Infinite) {
+ // Box intersected with infinity is the box.
+ return;
+ }
+
+ // Intersect two finite boxes.
+ QVector3D min1 = mincorner;
+ QVector3D max1 = maxcorner;
+ QVector3D min2 = box.mincorner;
+ QVector3D max2 = box.maxcorner;
+ if (min2.x() > min1.x())
+ min1.setX(min2.x());
+ if (min2.y() > min1.y())
+ min1.setY(min2.y());
+ if (min2.z() > min1.z())
+ min1.setZ(min2.z());
+ if (max2.x() < max1.x())
+ max1.setX(max2.x());
+ if (max2.y() < max1.y())
+ max1.setY(max2.y());
+ if (max2.z() < max1.z())
+ max1.setZ(max2.z());
+ if (min1.x() > max1.x() || min1.y() > max1.y() || min1.z() > max1.z()) {
+ setToNull();
+ } else {
+ mincorner = min1;
+ maxcorner = max1;
+ }
+}
+
+/*!
+ Returns a new box which is the intersection of this box with \a box.
+
+ \sa intersect(), intersects(), united()
+*/
+QBox3D QBox3D::intersected(const QBox3D& box) const
+{
+ QBox3D result(*this);
+ result.intersect(box);
+ return result;
+}
+
+/*!
+ Unites this box with \a point by expanding it to encompass \a point.
+ If \a point is already contained within this box, then this box
+ will be unchanged.
+
+ \sa united(), intersect()
+*/
+void QBox3D::unite(const QVector3D& point)
+{
+ if (boxtype == Finite) {
+ if (point.x() < mincorner.x())
+ mincorner.setX(point.x());
+ else if (point.x() > maxcorner.x())
+ maxcorner.setX(point.x());
+ if (point.y() < mincorner.y())
+ mincorner.setY(point.y());
+ else if (point.y() > maxcorner.y())
+ maxcorner.setY(point.y());
+ if (point.z() < mincorner.z())
+ mincorner.setZ(point.z());
+ else if (point.z() > maxcorner.z())
+ maxcorner.setZ(point.z());
+ } else if (boxtype == Null) {
+ boxtype = Finite;
+ mincorner = point;
+ maxcorner = point;
+ }
+}
+
+/*!
+ Unites this box with \a box by expanding this box to encompass the
+ region defined by \a box. If \a box is already contained within
+ this box, then this box will be unchanged.
+
+ \sa united(), intersect()
+*/
+void QBox3D::unite(const QBox3D& box)
+{
+ if (box.boxtype == Finite) {
+ unite(box.minimum());
+ unite(box.maximum());
+ } else if (box.boxtype == Infinite) {
+ setToInfinite();
+ }
+}
+
+/*!
+ Returns a new box which unites this box with \a point. The returned
+ value will be the smallest box that contains both this box and \a point.
+
+ \sa unite(), intersected()
+*/
+QBox3D QBox3D::united(const QVector3D& point) const
+{
+ if (boxtype == Finite) {
+ QBox3D result(*this);
+ result.unite(point);
+ return result;
+ } else if (boxtype == Null) {
+ return QBox3D(point, point);
+ } else {
+ return *this;
+ }
+}
+
+/*!
+ Returns a new box which unites this box with \a box. The returned value
+ will be the smallest box that contains both this box and \a box.
+
+ \sa unite(), intersected()
+*/
+QBox3D QBox3D::united(const QBox3D& box) const
+{
+ if (boxtype == Finite) {
+ QBox3D result(*this);
+ result.unite(box);
+ return result;
+ } else if (boxtype == Null) {
+ return box;
+ } else {
+ return *this;
+ }
+}
+
+/*!
+ Transforms this box according to \a matrix. Each of the 8 box
+ corners are transformed and then a new box that encompasses all
+ of the transformed corner values is created.
+
+ \sa transformed()
+*/
+void QBox3D::transform(const QMatrix4x4& matrix)
+{
+ *this = transformed(matrix);
+}
+
+/*!
+ Returns this box transformed by \a matrix. Each of the 8 box
+ corners are transformed and then a new box that encompasses all
+ of the transformed corner values is returned.
+
+ \sa transform()
+*/
+QBox3D QBox3D::transformed(const QMatrix4x4& matrix) const
+{
+ if (boxtype != Finite)
+ return *this;
+ QBox3D result;
+ result.unite(matrix * mincorner);
+ result.unite(matrix * QVector3D(mincorner.x(), mincorner.y(), maxcorner.z()));
+ result.unite(matrix * QVector3D(mincorner.x(), maxcorner.y(), maxcorner.z()));
+ result.unite(matrix * QVector3D(mincorner.x(), maxcorner.y(), mincorner.z()));
+ result.unite(matrix * QVector3D(maxcorner.x(), mincorner.y(), mincorner.z()));
+ result.unite(matrix * QVector3D(maxcorner.x(), maxcorner.y(), mincorner.z()));
+ result.unite(matrix * QVector3D(maxcorner.x(), mincorner.y(), maxcorner.z()));
+ result.unite(matrix * maxcorner);
+ return result;
+}
+
+/*!
+ \fn bool QBox3D::operator==(const QBox3D& box) const
+
+ Returns true if this box is identical to \a box.
+*/
+
+/*!
+ \fn bool QBox3D::operator!=(const QBox3D& box) const
+
+ Returns true if this box is not identical to \a box.
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QBox3D& box1, const QBox3D& box2)
+ \relates QBox3D
+
+ Returns true if \a box1 and \a box2 are almost equal; false otherwise.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QBox3D &box)
+{
+ if (box.isFinite()) {
+ dbg.nospace() << "QBox3D(("
+ << box.minimum().x() << ", " << box.minimum().y() << ", "
+ << box.minimum().z() << ") - ("
+ << box.maximum().x() << ", " << box.maximum().y() << ", "
+ << box.maximum().z() << "))";
+ return dbg.space();
+ } else if (box.isNull()) {
+ dbg << "QBox3D(null)";
+ return dbg;
+ } else {
+ dbg << "QBox3D(infinite)";
+ return dbg;
+ }
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QBox3D &box)
+ \relates QBox3D
+
+ Writes the given \a box to the given \a stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QBox3D &box)
+{
+ if (box.isNull()) {
+ stream << int(0);
+ } else if (box.isInfinite()) {
+ stream << int(2);
+ } else {
+ stream << int(1);
+ stream << box.minimum();
+ stream << box.maximum();
+ }
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QBox3D &box)
+ \relates QBox3D
+
+ Reads a 3D box from the given \a stream into the given \a box
+ and returns a reference to the stream.
+*/
+
+QDataStream &operator>>(QDataStream &stream, QBox3D &box)
+{
+ int type;
+ stream >> type;
+ if (type == 1) {
+ QVector3D minimum, maximum;
+ stream >> minimum;
+ stream >> maximum;
+ box = QBox3D(minimum, maximum);
+ } else if (type == 2) {
+ box.setToInfinite();
+ } else {
+ box.setToNull();
+ }
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
diff --git a/src/threed/math3d/qbox3d.h b/src/threed/math3d/qbox3d.h
new file mode 100644
index 000000000..a31701ba9
--- /dev/null
+++ b/src/threed/math3d/qbox3d.h
@@ -0,0 +1,218 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBOX3D_H
+#define QBOX3D_H
+
+#include "qt3dglobal.h"
+#include "qray3d.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QMatrix4x4;
+
+class Q_QT3D_EXPORT QBox3D
+{
+public:
+ QBox3D();
+ QBox3D(const QVector3D& corner1, const QVector3D& corner2);
+
+ bool isNull() const;
+ bool isFinite() const;
+ bool isInfinite() const;
+
+ QVector3D minimum() const;
+ QVector3D maximum() const;
+ void setExtents(const QVector3D& corner1, const QVector3D& corner2);
+
+ void setToNull();
+ void setToInfinite();
+
+ QVector3D size() const;
+ QVector3D center() const;
+
+ bool contains(const QVector3D& point) const;
+ bool contains(const QBox3D& box) const;
+
+ bool intersects(const QRay3D& ray) const;
+ bool intersection(const QRay3D &ray, qreal *minimum_t, qreal *maximum_t) const;
+ qreal intersection(const QRay3D& ray) const;
+
+ bool intersects(const QBox3D& box) const;
+ void intersect(const QBox3D& box);
+ QBox3D intersected(const QBox3D& box) const;
+
+ void unite(const QVector3D& point);
+ void unite(const QBox3D& box);
+
+ QBox3D united(const QVector3D& point) const;
+ QBox3D united(const QBox3D& box) const;
+
+ void transform(const QMatrix4x4& matrix);
+ QBox3D transformed(const QMatrix4x4& matrix) const;
+
+ bool operator==(const QBox3D& box) const;
+ bool operator!=(const QBox3D& box) const;
+
+ friend bool qFuzzyCompare(const QBox3D& box1, const QBox3D& box2);
+
+private:
+ enum Type
+ {
+ Null,
+ Finite,
+ Infinite
+ };
+
+ QBox3D::Type boxtype;
+ QVector3D mincorner, maxcorner;
+};
+
+inline QBox3D::QBox3D() : boxtype(Null), mincorner(0, 0, 0), maxcorner(0, 0, 0) {}
+
+inline QBox3D::QBox3D(const QVector3D& corner1, const QVector3D& corner2)
+ : boxtype(Finite),
+ mincorner(qMin(corner1.x(), corner2.x()),
+ qMin(corner1.y(), corner2.y()),
+ qMin(corner1.z(), corner2.z())),
+ maxcorner(qMax(corner1.x(), corner2.x()),
+ qMax(corner1.y(), corner2.y()),
+ qMax(corner1.z(), corner2.z())) {}
+
+inline bool QBox3D::isNull() const { return (boxtype == Null); }
+inline bool QBox3D::isFinite() const { return (boxtype == Finite); }
+inline bool QBox3D::isInfinite() const { return (boxtype == Infinite); }
+
+inline QVector3D QBox3D::minimum() const { return mincorner; }
+inline QVector3D QBox3D::maximum() const { return maxcorner; }
+
+inline void QBox3D::setExtents(const QVector3D& corner1, const QVector3D& corner2)
+{
+ boxtype = Finite;
+ mincorner = QVector3D(qMin(corner1.x(), corner2.x()),
+ qMin(corner1.y(), corner2.y()),
+ qMin(corner1.z(), corner2.z()));
+ maxcorner = QVector3D(qMax(corner1.x(), corner2.x()),
+ qMax(corner1.y(), corner2.y()),
+ qMax(corner1.z(), corner2.z()));
+}
+
+inline void QBox3D::setToNull()
+{
+ boxtype = Null;
+ mincorner = QVector3D(0, 0, 0);
+ maxcorner = QVector3D(0, 0, 0);
+}
+
+inline void QBox3D::setToInfinite()
+{
+ boxtype = Infinite;
+ mincorner = QVector3D(0, 0, 0);
+ maxcorner = QVector3D(0, 0, 0);
+}
+
+inline QVector3D QBox3D::size() const { return maxcorner - mincorner; }
+inline QVector3D QBox3D::center() const { return (mincorner + maxcorner) * 0.5f; }
+
+inline bool QBox3D::contains(const QVector3D& point) const
+{
+ if (boxtype == Finite) {
+ return (point.x() >= mincorner.x() && point.x() <= maxcorner.x() &&
+ point.y() >= mincorner.y() && point.y() <= maxcorner.y() &&
+ point.z() >= mincorner.z() && point.z() <= maxcorner.z());
+ } else if (boxtype == Infinite) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+inline bool QBox3D::contains(const QBox3D& box) const
+{
+ if (box.boxtype == Finite)
+ return contains(box.mincorner) && contains(box.maxcorner);
+ else if (box.boxtype == Infinite)
+ return (boxtype == Infinite);
+ else
+ return false;
+}
+
+inline bool QBox3D::operator==(const QBox3D& box) const
+{
+ return (boxtype == box.boxtype &&
+ mincorner == box.mincorner &&
+ maxcorner == box.maxcorner);
+}
+
+inline bool QBox3D::operator!=(const QBox3D& box) const
+{
+ return (boxtype != box.boxtype ||
+ mincorner != box.mincorner ||
+ maxcorner != box.maxcorner);
+}
+
+inline bool qFuzzyCompare(const QBox3D& box1, const QBox3D& box2)
+{
+ return box1.boxtype == box2.boxtype &&
+ qFuzzyCompare(box1.mincorner, box2.mincorner) &&
+ qFuzzyCompare(box1.maxcorner, box2.maxcorner);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QBox3D &box);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_QT3D_EXPORT QDataStream &operator<<(QDataStream &stream, const QBox3D &box);
+Q_QT3D_EXPORT QDataStream &operator>>(QDataStream &stream, QBox3D &box);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QBox3D)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/math3d/qplane3d.cpp b/src/threed/math3d/qplane3d.cpp
new file mode 100644
index 000000000..9b328d28c
--- /dev/null
+++ b/src/threed/math3d/qplane3d.cpp
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplane3d.h"
+#include <QtCore/qmath.h>
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPlane3D
+ \brief The QPlane3D class models the mathematics of planes in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::math
+
+ A plane is defined by an origin() point lying on the plane, and a
+ normal() vector, which is perpendicular to the surface of the plane.
+ The normal() vector does not need to be normalized. QPlane3D is an
+ infinite surface, from which the normal() vector points out perpendicular
+ from the origin() point.
+
+ \sa QRay3D
+*/
+
+/*!
+ \fn QPlane3D::QPlane3D()
+
+ Constructs a default plane object. The defining origin() of the plane
+ is set to (0, 0, 0) and the normal() vector is to (1, 0, 0).
+*/
+
+/*!
+ \fn QPlane3D::QPlane3D(const QVector3D &point, const QVector3D &normal)
+
+ Constructs a new plane, where \a point lies on the plane, and \a normal
+ is perpendicular to it. The \a normal does not have to be normalized.
+ If \a normal is zero, the behavior of the plane is undefined.
+*/
+
+/*!
+ \fn QPlane3D::QPlane3D(const QVector3D &p, const QVector3D &q, const QVector3D &r)
+
+ Constructs a new plane defined by the three points \a p, \a q, and \a r.
+ The point \a p is used as the plane's origin() point, and a normal()
+ is constructed from the cross-product of \a q - \a p and \a r - \a q.
+*/
+
+/*!
+ \fn QVector3D QPlane3D::origin() const
+
+ Returns this plane's defining origin point. The default value is (0, 0, 0).
+
+ \sa setOrigin(), normal()
+*/
+
+/*!
+ \fn void QPlane3D::setOrigin(const QVector3D& value)
+
+ Set this plane's defining origin point to \a value.
+
+ \sa origin(), setNormal()
+*/
+
+/*!
+ \fn QVector3D QPlane3D::normal() const
+
+ Returns this plane's normal vector. The default value is (1, 0, 0).
+
+ \sa setNormal(), origin()
+*/
+
+/*!
+ \fn void QPlane3D::setNormal(const QVector3D& value)
+
+ Set this plane's normal vector to \a value. The \a value does
+ not have to be normalized. If \a value is zero, the behavior
+ of the plane is undefined.
+
+ \sa normal(), setOrigin()
+*/
+
+/*!
+ Returns true if \a point lies in this plane; false otherwise.
+*/
+bool QPlane3D::contains(const QVector3D &point) const
+{
+ return qFuzzyIsNull
+ (float(QVector3D::dotProduct(m_normal, m_origin - point)));
+}
+
+/*!
+ Returns true if all of the points on \a ray lie in this plane;
+ false otherwise.
+*/
+bool QPlane3D::contains(const QRay3D &ray) const
+{
+ return qFuzzyIsNull
+ (float(QVector3D::dotProduct(m_normal, ray.direction()))) &&
+ contains(ray.origin());
+}
+
+/*!
+ Returns true if an intersection of \a ray with this plane exists;
+ false otherwise.
+
+ \sa intersection()
+*/
+bool QPlane3D::intersects(const QRay3D &ray) const
+{
+ return !qFuzzyIsNull
+ (float(QVector3D::dotProduct(m_normal, ray.direction())));
+}
+
+/*!
+ Returns the t value at which \a ray intersects this plane, or
+ not-a-number if there is no intersection.
+
+ When the \a ray intersects this plane, the return value is a
+ parametric value that can be passed to QRay3D::point() to determine
+ the actual intersection point, as shown in the following example:
+
+ \code
+ qreal t = plane.intersection(ray);
+ QVector3D pt;
+ if (qIsNaN(t)) {
+ qWarning("no intersection occurred");
+ else
+ pt = ray.point(t);
+ \endcode
+
+ If the return value is positive, then the QRay3D::origin() of
+ \a ray begins below the plane and then extends through it.
+ If the return value is negative, then the origin begins
+ above the plane.
+
+ There are two failure cases where no single intersection point exists:
+
+ \list
+ \o when the ray is parallel to the plane (but does not lie on it)
+ \o the ray lies entirely in the plane (thus every point "intersects")
+ \endlist
+
+ This method does not distinguish between these two failure cases and
+ simply returns not-a-number for both.
+
+ \sa intersects()
+*/
+qreal QPlane3D::intersection(const QRay3D& ray) const
+{
+ qreal dotLineAndPlane = QVector3D::dotProduct(m_normal, ray.direction());
+ if (qFuzzyIsNull(float(dotLineAndPlane))) {
+ // degenerate case - ray & plane-normal vectors are at
+ // 90 degrees to each other, so either plane and ray never meet
+ // or the ray lies in the plane - return failure case.
+ return qSNaN();
+ }
+ return QVector3D::dotProduct(m_origin - ray.origin(), m_normal) /
+ dotLineAndPlane;
+}
+
+/*!
+ Returns the distance from this plane to \a point. The value will
+ be positive if \a point is above the plane in the direction
+ of normal(), and negative if \a point is below the plane.
+*/
+qreal QPlane3D::distanceTo(const QVector3D &point) const
+{
+ return QVector3D::dotProduct(point - m_origin, m_normal) /
+ m_normal.length();
+}
+
+/*!
+ \fn void QPlane3D::transform(const QMatrix4x4 &matrix)
+
+ Transforms this plane using \a matrix, replacing origin() and
+ normal() with the transformed versions.
+
+ \sa transformed()
+*/
+
+/*!
+ \fn QPlane3D QPlane3D::transformed(const QMatrix4x4 &matrix) const
+
+ Returns a new plane that is formed by transforming origin()
+ and normal() using \a matrix.
+
+ \sa transform()
+*/
+
+/*!
+ \fn bool QPlane3D::operator==(const QPlane3D &other)
+
+ Returns true if this plane is the same as \a other; false otherwise.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QPlane3D::operator!=(const QPlane3D &other)
+
+ Returns true if this plane is not the same as \a other; false otherwise.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QPlane3D &plane1, const QPlane3D &plane2)
+ \relates QPlane3D
+
+ Returns true if \a plane1 and \a plane2 are almost equal; false otherwise.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QPlane3D &plane)
+{
+ dbg.nospace() << "QPlane3D(origin("
+ << plane.origin().x() << ", " << plane.origin().y() << ", "
+ << plane.origin().z() << ") - normal("
+ << plane.normal().x() << ", " << plane.normal().y() << ", "
+ << plane.normal().z() << "))";
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QPlane3D &plane)
+ \relates QPlane3D
+
+ Writes the given \a plane to the given \a stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QPlane3D &plane)
+{
+ stream << plane.origin();
+ stream << plane.normal();
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QPlane3D &plane)
+ \relates QPlane3D
+
+ Reads a 3D plane from the given \a stream into the given \a plane
+ and returns a reference to the stream.
+*/
+
+QDataStream &operator>>(QDataStream &stream, QPlane3D &plane)
+{
+ QVector3D origin, normal;
+ stream >> origin;
+ stream >> normal;
+ plane = QPlane3D(origin, normal);
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
diff --git a/src/threed/math3d/qplane3d.h b/src/threed/math3d/qplane3d.h
new file mode 100644
index 000000000..e2dcc15ac
--- /dev/null
+++ b/src/threed/math3d/qplane3d.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLANE3D_H
+#define QPLANE3D_H
+
+#include <QtGui/qvector3d.h>
+#include <QtCore/qnumeric.h>
+#include "qray3d.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QPlane3D
+{
+public:
+ QPlane3D();
+ QPlane3D(const QVector3D &point, const QVector3D &normal);
+ QPlane3D(const QVector3D &p, const QVector3D &q, const QVector3D &r);
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D& value);
+
+ QVector3D normal() const;
+ void setNormal(const QVector3D& value);
+
+ bool contains(const QVector3D &point) const;
+ bool contains(const QRay3D &ray) const;
+
+ bool intersects(const QRay3D &ray) const;
+ qreal intersection(const QRay3D &ray) const;
+
+ qreal distanceTo(const QVector3D &point) const;
+
+ void transform(const QMatrix4x4 &matrix);
+ QPlane3D transformed(const QMatrix4x4 &matrix) const;
+
+ bool operator==(const QPlane3D &other);
+ bool operator!=(const QPlane3D &other);
+
+private:
+ QVector3D m_origin;
+ QVector3D m_normal;
+};
+
+inline QPlane3D::QPlane3D() : m_normal(1.0f, 0.0f, 0.0f) {}
+
+inline QPlane3D::QPlane3D(const QVector3D &point, const QVector3D &normal)
+ : m_origin(point), m_normal(normal)
+{
+}
+
+inline QPlane3D::QPlane3D(const QVector3D &p, const QVector3D &q, const QVector3D &r)
+ : m_origin(p), m_normal(QVector3D::crossProduct(q - p, r - q))
+{
+}
+
+inline QVector3D QPlane3D::origin() const
+{
+ return m_origin;
+}
+
+inline void QPlane3D::setOrigin(const QVector3D &value)
+{
+ m_origin = value;
+}
+
+inline QVector3D QPlane3D::normal() const
+{
+ return m_normal;
+}
+
+inline void QPlane3D::setNormal(const QVector3D& value)
+{
+ m_normal = value;
+}
+
+inline void QPlane3D::transform(const QMatrix4x4 &matrix)
+{
+ m_origin = matrix * m_origin;
+ m_normal = matrix.mapVector(m_normal);
+}
+
+inline QPlane3D QPlane3D::transformed(const QMatrix4x4 &matrix) const
+{
+ return QPlane3D(matrix * m_origin, matrix.mapVector(m_normal));
+}
+
+inline bool QPlane3D::operator==(const QPlane3D &other)
+{
+ return m_origin == other.origin() && m_normal == other.normal();
+}
+
+inline bool QPlane3D::operator!=(const QPlane3D &other)
+{
+ return m_origin != other.origin() || m_normal != other.normal();
+}
+
+inline bool qFuzzyCompare(const QPlane3D &plane1, const QPlane3D &plane2)
+{
+ return qFuzzyCompare(plane1.origin(), plane2.origin()) &&
+ qFuzzyCompare(plane1.normal(), plane2.normal());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QPlane3D &plane);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_QT3D_EXPORT QDataStream &operator<<(QDataStream &stream, const QPlane3D &plane);
+Q_QT3D_EXPORT QDataStream &operator>>(QDataStream &stream, QPlane3D &plane);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QPlane3D)
+
+QT_END_HEADER
+
+#endif // QPLANE3D_H
diff --git a/src/threed/math3d/qray3d.cpp b/src/threed/math3d/qray3d.cpp
new file mode 100644
index 000000000..38af18e7b
--- /dev/null
+++ b/src/threed/math3d/qray3d.cpp
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qray3d.h"
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QRay3D
+ \brief The QRay3D class defines a directional line in 3D space extending through an origin point.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::math
+
+ A ray is defined by the origin() point and the direction() vector.
+ Rays are infinite in length, extending out from origin() in
+ both directions. If the direction() is zero length, then the
+ behavior of the class is undefined.
+
+ A ray can be thought of as a one-dimensional co-ordinate system.
+ If the co-ordinate is \bold t then the origin() point is at
+ \bold t = 0, the point origin() + direction() is at \bold t = 1,
+ and the point origin() - direction() is at \bold t = -1.
+ The point() method can be used to obtain the position of a point
+ within this one-dimensional co-ordinate system. The fromPoint()
+ method can be used to convert a point into a value in this
+ one-dimensional co-ordinate system.
+*/
+
+/*!
+ \fn QRay3D::QRay3D()
+
+ Construct a default ray with an origin() of (0, 0, 0) and a
+ direction() of (1, 0, 0).
+*/
+
+/*!
+ \fn QRay3D::QRay3D(const QVector3D &origin, const QVector3D &direction)
+
+ Construct a ray given its defining \a origin and \a direction. The
+ \a direction does not need to be normalized.
+
+ To construct a ray that passes through two points, use the following:
+
+ \code
+ QRay3D thruAB(pointA, pointB - pointA);
+ \endcode
+*/
+
+/*!
+ \fn QVector3D QRay3D::origin() const
+
+ Returns the origin of this ray. The default value is (0, 0, 0).
+
+ \sa setOrigin(), direction()
+*/
+
+/*!
+ \fn void QRay3D::setOrigin(const QVector3D &value)
+
+ Sets the origin point of this ray to \a value.
+
+ \sa origin(), setDirection()
+ */
+
+/*!
+ \fn QVector3D QRay3D::direction() const
+
+ Returns the direction vector of this ray. The default value is (1, 0, 0).
+
+ \sa setDirection(), origin()
+*/
+
+/*!
+ \fn void QRay3D::setDirection(const QVector3D &direction)
+
+ Sets the direction vector of this ray to \a direction.
+
+ \sa direction(), setOrigin()
+*/
+
+/*!
+ Returns true if \a point lies on this ray; false otherwise.
+*/
+bool QRay3D::contains(const QVector3D &point) const
+{
+ QVector3D ppVec(point - m_origin);
+ if (ppVec.isNull()) // point coincides with origin
+ return true;
+ qreal dot = QVector3D::dotProduct(ppVec, m_direction);
+ if (qFuzzyIsNull(float(dot)))
+ return false;
+ return qFuzzyCompare(dot*dot, ppVec.lengthSquared() * m_direction.lengthSquared());
+}
+
+/*!
+ Returns true if \a ray lies on this ray; false otherwise. If true,
+ this implies that the two rays are the actually the same, but with
+ different origin() points or an inverted direction().
+*/
+bool QRay3D::contains(const QRay3D &ray) const
+{
+ qreal dot = QVector3D::dotProduct(m_direction, ray.direction());
+ if (!qFuzzyCompare(dot*dot, m_direction.lengthSquared() * ray.direction().lengthSquared()))
+ return false;
+ return contains(ray.origin());
+}
+
+/*!
+ \fn QVector3D QRay3D::point(qreal t) const
+
+ Returns the point on the ray defined by moving \a t units
+ along the ray in the direction of the direction() vector.
+ Note that \a t may be negative in which case the point returned
+ will lie behind the origin() point with respect to the
+ direction() vector.
+
+ The units for \a t are defined by direction(). The return value
+ is precisely origin() + t * direction().
+
+ \sa fromPoint(), distanceTo()
+*/
+
+/*!
+ Returns the number of direction() units along the ray from origin()
+ to \a point. Essentially, this function computes the value t, where
+ \a point = origin() + t * direction(). If \a point is not on the ray,
+ then the closest point that is on the ray will be used instead.
+
+ If the return value is positive, then \a point lies in front of
+ the origin() with respect to the direction() vector. If the return
+ value is negative, then \a point lies behind the origin() with
+ respect to the direction() vector.
+
+ \sa point(), project()
+*/
+qreal QRay3D::fromPoint(const QVector3D &point) const
+{
+ return QVector3D::dotProduct(point - m_origin, m_direction) /
+ m_direction.lengthSquared();
+}
+
+/*!
+ Returns the projection of \a vector onto this ray. In the
+ following diagram, the dotted line is the ray, and V is the
+ \a vector. The return value will be the vector V':
+
+ \image qray3d-project.png
+
+ \sa fromPoint()
+*/
+QVector3D QRay3D::project(const QVector3D &vector) const
+{
+ QVector3D norm = m_direction.normalized();
+ return QVector3D::dotProduct(vector, norm) * norm;
+}
+
+/*!
+ Returns the minimum distance from this ray to \a point, or equivalently
+ the length of a line perpendicular to this ray which passes through
+ \a point. If \a point is on the ray, then this function will return zero.
+
+ \sa point()
+*/
+qreal QRay3D::distanceTo(const QVector3D &point) const
+{
+ qreal t = fromPoint(point);
+ return (point - (m_origin + t * m_direction)).length();
+}
+
+/*!
+ \fn void QRay3D::transform(const QMatrix4x4 &matrix)
+
+ Transforms this ray using \a matrix, replacing origin() and
+ direction() with the transformed versions.
+
+ \sa transformed()
+*/
+
+/*!
+ \fn QRay3D QRay3D::transformed(const QMatrix4x4 &matrix) const
+
+ Returns a new ray that is formed by transforming origin()
+ and direction() using \a matrix.
+
+ \sa transform()
+*/
+
+/*!
+ \fn bool QRay3D::operator==(const QRay3D &other)
+
+ Returns true if this ray is the same as \a other; false otherwise.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QRay3D::operator!=(const QRay3D &other)
+
+ Returns true if this ray is not the same as \a other; false otherwise.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QRay3D &ray1, const QRay3D &ray2)
+ \relates QRay3D
+
+ Returns true if \a ray1 and \a ray2 are almost equal; false otherwise.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QRay3D &ray)
+{
+ dbg.nospace() << "QRay3D(origin("
+ << ray.origin().x() << ", " << ray.origin().y() << ", "
+ << ray.origin().z() << ") - direction("
+ << ray.direction().x() << ", " << ray.direction().y() << ", "
+ << ray.direction().z() << "))";
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QRay3D &ray)
+ \relates QRay3D
+
+ Writes the given \a ray to the given \a stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QRay3D &ray)
+{
+ stream << ray.origin();
+ stream << ray.direction();
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QRay3D &ray)
+ \relates QRay3D
+
+ Reads a 3D ray from the given \a stream into the given \a ray
+ and returns a reference to the stream.
+*/
+
+QDataStream &operator>>(QDataStream &stream, QRay3D &ray)
+{
+ QVector3D origin, direction;
+ stream >> origin;
+ stream >> direction;
+ ray = QRay3D(origin, direction);
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
diff --git a/src/threed/math3d/qray3d.h b/src/threed/math3d/qray3d.h
new file mode 100644
index 000000000..49883c2a5
--- /dev/null
+++ b/src/threed/math3d/qray3d.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRAY3D_H
+#define QRAY3D_H
+
+#include "qt3dglobal.h"
+#include <QtGui/qvector3d.h>
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QRay3D
+{
+public:
+ QRay3D();
+ QRay3D(const QVector3D &origin, const QVector3D &direction);
+
+ QVector3D origin() const;
+ void setOrigin(const QVector3D & value);
+
+ QVector3D direction() const;
+ void setDirection(const QVector3D & value);
+
+ bool contains(const QVector3D &point) const;
+ bool contains(const QRay3D &ray) const;
+
+ QVector3D point(qreal t) const;
+ qreal fromPoint(const QVector3D &point) const;
+
+ QVector3D project(const QVector3D &vector) const;
+
+ qreal distanceTo(const QVector3D &point) const;
+
+ void transform(const QMatrix4x4 &matrix);
+ QRay3D transformed(const QMatrix4x4 &matrix) const;
+
+ bool operator==(const QRay3D &other);
+ bool operator!=(const QRay3D &other);
+
+private:
+ QVector3D m_origin;
+ QVector3D m_direction;
+
+};
+
+inline QRay3D::QRay3D() : m_direction(1.0f, 0.0f, 0.0f) {}
+
+inline QRay3D::QRay3D(const QVector3D &origin, const QVector3D &direction)
+ : m_origin(origin)
+ , m_direction(direction)
+{
+}
+
+inline QVector3D QRay3D::origin() const
+{
+ return m_origin;
+}
+
+inline void QRay3D::setOrigin(const QVector3D &value)
+{
+ m_origin = value;
+}
+
+inline QVector3D QRay3D::direction() const
+{
+ return m_direction;
+}
+
+inline void QRay3D::setDirection(const QVector3D & value)
+{
+ m_direction = value;
+}
+
+inline QVector3D QRay3D::point(qreal t) const
+{
+ return m_origin + t * m_direction;
+}
+
+inline void QRay3D::transform(const QMatrix4x4 &matrix)
+{
+ m_origin = matrix * m_origin;
+ m_direction = matrix.mapVector(m_direction);
+}
+
+inline QRay3D QRay3D::transformed(const QMatrix4x4 &matrix) const
+{
+ return QRay3D(matrix * m_origin, matrix.mapVector(m_direction));
+}
+
+inline bool QRay3D::operator==(const QRay3D &other)
+{
+ return m_origin == other.origin() && m_direction == other.direction();
+}
+
+inline bool QRay3D::operator!=(const QRay3D &other)
+{
+ return m_origin != other.origin() || m_direction != other.direction();
+}
+
+inline bool qFuzzyCompare(const QRay3D &ray1, const QRay3D &ray2)
+{
+ return qFuzzyCompare(ray1.origin(), ray2.origin()) &&
+ qFuzzyCompare(ray1.direction(), ray2.direction());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QRay3D &ray);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_QT3D_EXPORT QDataStream &operator<<(QDataStream &stream, const QRay3D &ray);
+Q_QT3D_EXPORT QDataStream &operator>>(QDataStream &stream, QRay3D &ray);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QRay3D)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/math3d/qsphere3d.cpp b/src/threed/math3d/qsphere3d.cpp
new file mode 100644
index 000000000..e4b9e6e50
--- /dev/null
+++ b/src/threed/math3d/qsphere3d.cpp
@@ -0,0 +1,385 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsphere3d.h"
+#include "qray3d.h"
+#include "qbox3d.h"
+#include "qplane3d.h"
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSphere3D
+ \brief The QSphere3D class represents a mathematical sphere in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::math
+
+ QSphere3D can be used to represent the bounding regions of objects
+ in a 3D scene so that they can be easily culled if they are out of view.
+ It can also be used to assist with collision testing.
+
+ \sa QBox3D
+*/
+
+/*!
+ \fn QSphere3D::QSphere3D()
+
+ Constructs a default sphere with a center() of (0, 0, 0)
+ and radius() of 1.
+*/
+
+/*!
+ \fn QSphere3D::QSphere3D(const QVector3D &center, qreal radius)
+
+ Constructs a sphere with the specified \a center and \a radius.
+*/
+
+/*!
+ \fn QVector3D QSphere3D::center() const
+
+ Returns the center of this sphere.
+
+ \sa setCenter(), radius()
+*/
+
+/*!
+ \fn void QSphere3D::setCenter(const QVector3D &center)
+
+ Sets the \a center of this sphere.
+
+ \sa center(), setRadius()
+*/
+
+/*!
+ \fn qreal QSphere3D::radius() const
+
+ Returns the radius of this sphere.
+
+ \sa setRadius(), center()
+*/
+
+/*!
+ \fn void QSphere3D::setRadius(qreal radius)
+
+ Sets the \a radius of this sphere.
+
+ \sa radius(), setCenter()
+*/
+
+/*!
+ \fn bool QSphere3D::contains(const QVector3D &point) const
+
+ Returns true if \a point is contained within the bounds of
+ this sphere; false otherwise.
+*/
+
+/*!
+ Returns true if this sphere intersects \a ray; false otherwise.
+
+ \sa intersection()
+*/
+bool QSphere3D::intersects(const QRay3D &ray) const
+{
+ QVector3D centerToOrigin = ray.origin() - m_center;
+ qreal term1 = ray.direction().lengthSquared();
+ qreal term2 = 2.0f * QVector3D::dotProduct(centerToOrigin, ray.direction());
+ qreal term3 = centerToOrigin.lengthSquared() - m_radius * m_radius;
+ qreal det = term2 * term2 - (4.0f * term1 * term3);
+ return term1 != 0.0f && det >= 0.0f;
+}
+
+/*!
+ \fn bool QSphere3D::intersects(const QSphere3D &sphere) const
+
+ Returns true if this sphere intersects \a sphere; false otherwise.
+
+ \sa contains()
+*/
+
+/*!
+ Returns true if this sphere intersects \a box; false otherwise.
+*/
+bool QSphere3D::intersects(const QBox3D &box) const
+{
+ if (box.isFinite()) {
+ // Use Arvo's Algorithm to determine if we have an intersection.
+ qreal dist = 0.0f;
+ qreal center = m_center.x();
+ qreal minval = box.minimum().x();
+ qreal maxval = box.maximum().x();
+ if (center < minval)
+ dist += (center - minval) * (center - minval);
+ else if (center > maxval)
+ dist += (center - maxval) * (center - maxval);
+ center = m_center.y();
+ minval = box.minimum().y();
+ maxval = box.maximum().y();
+ if (center < minval)
+ dist += (center - minval) * (center - minval);
+ else if (center > maxval)
+ dist += (center - maxval) * (center - maxval);
+ center = m_center.z();
+ minval = box.minimum().z();
+ maxval = box.maximum().z();
+ if (center < minval)
+ dist += (center - minval) * (center - minval);
+ else if (center > maxval)
+ dist += (center - maxval) * (center - maxval);
+ return dist <= (m_radius * m_radius);
+ } else {
+ return box.isInfinite();
+ }
+}
+
+/*!
+ Returns true if this sphere intersects \a plane; false otherwise.
+*/
+bool QSphere3D::intersects(const QPlane3D &plane) const
+{
+ return qAbs(plane.distanceTo(m_center)) <= m_radius;
+}
+
+/*!
+ Finds the \a minimum_t and \a maximum_t values where \a ray intersects
+ this sphere. Returns true if intersections were found; or false if there
+ is no intersection.
+
+ If \a minimum_t and \a maximum_t are set to the same value, then \a ray
+ touches the surface of the sphere at a single point. If the t values are
+ negative, then the intersection occurs before the ray's origin point
+ in the reverse direction of the ray.
+
+ The \a minimum_t and \a maximum_t values can be passed to QRay3D::point()
+ to determine the actual intersection points, as shown in the following
+ example:
+
+ \code
+ qreal minimum_t, maximum_t;
+ if (sphere.intersection(ray, &minimum_t, &maximum_t)) {
+ qDebug() << "intersections at"
+ << ray.point(minimum_t) << "and"
+ << ray.point(maximum_t);
+ }
+ \endcode
+
+ \sa intersects(), QRay3D::point()
+*/
+bool QSphere3D::intersection(const QRay3D &ray, qreal *minimum_t, qreal *maximum_t) const
+{
+ QVector3D centerToOrigin = ray.origin() - m_center;
+ qreal term1 = ray.direction().lengthSquared();
+ qreal term2 = 2.0f * QVector3D::dotProduct(centerToOrigin, ray.direction());
+ qreal term3 = centerToOrigin.lengthSquared() - m_radius * m_radius;
+ qreal det = term2 * term2 - (4.0f * term1 * term3);
+ if (term1 == 0.0f || det < 0.0f) {
+ *minimum_t = qSNaN();
+ *maximum_t = qSNaN();
+ return false;
+ } else if (det == 0.0f) {
+ *minimum_t = *maximum_t = -term2 / (2.0f * term1);
+ } else {
+ qreal sqrtDet = qSqrt(det);
+ qreal t1 = (-term2 - sqrtDet) / (2.0f * term1);
+ qreal t2 = (-term2 + sqrtDet) / (2.0f * term1);
+ if (t1 < t2) {
+ *minimum_t = t1;
+ *maximum_t = t2;
+ } else {
+ *minimum_t = t2;
+ *maximum_t = t1;
+ }
+ }
+ return true;
+}
+
+/*!
+ Returns the t value at which \a ray first intersects the surface of
+ this sphere, or not-a-number if there is no intersection.
+
+ When the \a ray intersects this sphere, the return value is a
+ parametric value that can be passed to QRay3D::point() to determine
+ the actual intersection point, as shown in the following example:
+
+ \code
+ qreal t = sphere.intersection(ray);
+ QVector3D pt;
+ if (qIsNaN(t)) {
+ qWarning("no intersection occurred");
+ else
+ pt = ray.point(t);
+ \endcode
+
+ The \a ray might intersect at two points - as the ray passes through
+ the sphere - one on the near side, one on the far side; where near and far
+ are relative to the origin point of the ray. This function only
+ returns the near intersection point.
+
+ Only positive values on the ray are considered. This means that if
+ the origin point of the ray is inside the sphere, there is only one
+ solution, not two. To get the other solution, simply change
+ the sign of the ray's direction vector. If the origin point of
+ the ray is outside the sphere, and the direction points away from
+ the sphere, then there will be no intersection.
+
+ When the ray does not intersect the sphere in the positive direction,
+ then the return value is not-a-number.
+
+ \sa intersects(), QRay3D::point()
+*/
+qreal QSphere3D::intersection(const QRay3D &ray) const
+{
+ qreal minimum_t, maximum_t;
+ if (intersection(ray, &minimum_t, &maximum_t)) {
+ if (minimum_t >= 0.0f)
+ return minimum_t;
+ else if (maximum_t >= 0.0f)
+ return maximum_t;
+ else
+ return qSNaN();
+ } else {
+ return qSNaN();
+ }
+}
+
+/*!
+ \fn void QSphere3D::transform(const QMatrix4x4 &matrix)
+
+ Transforms this sphere's center() and radius() according to \a matrix.
+
+ It is assumed that \a matrix contains a uniform scale factor in the
+ x, y, and z directions. Otherwise the radius() in the result is undefined.
+
+ \sa transformed()
+*/
+
+/*!
+ Returns the result of transforming this sphere's center() and radius()
+ according to \a matrix.
+
+ It is assumed that \a matrix contains a uniform scale factor in the
+ x, y, and z directions. Otherwise the radius() in the result is undefined.
+
+ \sa transform()
+*/
+QSphere3D QSphere3D::transformed(const QMatrix4x4 &matrix) const
+{
+ return QSphere3D(matrix * m_center,
+ matrix.mapVector(QVector3D(m_radius, 0, 0)).length());
+}
+
+/*!
+ \fn bool QSphere3D::operator==(const QSphere3D &sphere) const
+
+ Returns true if this sphere is the same as \a sphere; false otherwise.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QSphere3D::operator!=(const QSphere3D &sphere) const
+
+ Returns true if this sphere is not the same as \a sphere; false otherwise.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QSphere3D &sphere1, const QSphere3D &sphere2)
+ \relates QSphere3D
+
+ Returns true if \a sphere1 and \a sphere2 are almost equal;
+ false otherwise.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QSphere3D &sphere)
+{
+ dbg.nospace() << "QSphere3D(center=("
+ << sphere.center().x() << ", " << sphere.center().y() << ", "
+ << sphere.center().z() << "), radius=" << sphere.radius() << ')';
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QSphere3D &sphere)
+ \relates QSphere3D
+
+ Writes the given \a sphere to the given \a stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QSphere3D &sphere)
+{
+ stream << sphere.center();
+ stream << double(sphere.radius());
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QSphere3D &sphere)
+ \relates QSphere3D
+
+ Reads a 3D sphere from the given \a stream into the given \a sphere
+ and returns a reference to the stream.
+*/
+
+QDataStream &operator>>(QDataStream &stream, QSphere3D &sphere)
+{
+ QVector3D center;
+ double radius;
+ stream >> center;
+ stream >> radius;
+ sphere.setCenter(center);
+ sphere.setRadius(qreal(radius));
+ return stream;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/threed/math3d/qsphere3d.h b/src/threed/math3d/qsphere3d.h
new file mode 100644
index 000000000..9f4afe037
--- /dev/null
+++ b/src/threed/math3d/qsphere3d.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSPHERE3D_H
+#define QSPHERE3D_H
+
+#include "qt3dglobal.h"
+#include <QtGui/qvector3d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QMatrix4x4;
+class QRay3D;
+class QBox3D;
+class QPlane3D;
+
+class Q_QT3D_EXPORT QSphere3D
+{
+public:
+ QSphere3D();
+ QSphere3D(const QVector3D &center, qreal radius);
+
+ QVector3D center() const;
+ void setCenter(const QVector3D &center);
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+
+ bool contains(const QVector3D &point) const;
+
+ bool intersects(const QRay3D &ray) const;
+ bool intersects(const QSphere3D &sphere) const;
+ bool intersects(const QBox3D &box) const;
+ bool intersects(const QPlane3D &plane) const;
+
+ bool intersection(const QRay3D &ray, qreal *minimum_t, qreal *maximum_t) const;
+ qreal intersection(const QRay3D &ray) const;
+
+ void transform(const QMatrix4x4 &matrix);
+ QSphere3D transformed(const QMatrix4x4 &matrix) const;
+
+ bool operator==(const QSphere3D &sphere) const;
+ bool operator!=(const QSphere3D &sphere) const;
+
+private:
+ QVector3D m_center;
+ qreal m_radius;
+};
+
+inline QSphere3D::QSphere3D() : m_radius(1.0f) {}
+
+inline QSphere3D::QSphere3D(const QVector3D &center, qreal radius)
+ : m_center(center), m_radius(radius) {}
+
+inline QVector3D QSphere3D::center() const
+{
+ return m_center;
+}
+
+inline void QSphere3D::setCenter(const QVector3D &center)
+{
+ m_center = center;
+}
+
+inline qreal QSphere3D::radius() const
+{
+ return m_radius;
+}
+
+inline void QSphere3D::setRadius(qreal radius)
+{
+ m_radius = radius;
+}
+
+inline bool QSphere3D::contains(const QVector3D &point) const
+{
+ return (point - m_center).lengthSquared() <= (m_radius * m_radius);
+}
+
+inline bool QSphere3D::intersects(const QSphere3D &sphere) const
+{
+ qreal radsum = sphere.radius() + m_radius;
+ return (sphere.center() - m_center).lengthSquared() <= (radsum * radsum);
+}
+
+inline void QSphere3D::transform(const QMatrix4x4 &matrix)
+{
+ *this = transformed(matrix);
+}
+
+inline bool QSphere3D::operator==(const QSphere3D &sphere) const
+{
+ return m_center == sphere.m_center && m_radius == sphere.m_radius;
+}
+
+inline bool QSphere3D::operator!=(const QSphere3D &sphere) const
+{
+ return m_center != sphere.m_center || m_radius != sphere.m_radius;
+}
+
+inline bool qFuzzyCompare(const QSphere3D &sphere1, const QSphere3D &sphere2)
+{
+ return qFuzzyCompare(sphere1.center(), sphere2.center()) &&
+ qFuzzyCompare(sphere1.radius(), sphere2.radius());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QSphere3D &sphere);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_QT3D_EXPORT QDataStream &operator<<(QDataStream &stream, const QSphere3D &sphere);
+Q_QT3D_EXPORT QDataStream &operator>>(QDataStream &stream, QSphere3D &sphere);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSphere3D)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/math3d/qtriangle3d.cpp b/src/threed/math3d/qtriangle3d.cpp
new file mode 100644
index 000000000..f68c85645
--- /dev/null
+++ b/src/threed/math3d/qtriangle3d.cpp
@@ -0,0 +1,379 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtriangle3d.h"
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QTriangle3D
+ \brief The QTriangle3D class represents a triangle as three points in 3D space.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::math
+
+ A triangle is defined by 3 points in 3D space. Since any 3 points define
+ a plane, the triangle can be thought of as defining a plane, and forming a
+ geometric region in that plane.
+
+ If you need a simple plane, with no particular geometry, then
+ QPlane3D is a more compact and mathematically sufficient class.
+
+ The three points are labelled p(), q() and r() for consistency with
+ textbook treatments. It is recommended that the points be supplied
+ in counter-clockwise order for correct orientation of the
+ triangle's plane().
+
+ \sa QPlane3D
+*/
+
+/*!
+ \fn QTriangle3D::QTriangle3D()
+
+ Constructs a default triangle which lies in the x-z plane,
+ with the three vertices (0, 0, 0), (1, 0, 0), and (0, 1, 0).
+*/
+
+/*!
+ \fn QTriangle3D::QTriangle3D(const QVector3D &p, const QVector3D &q, const QVector3D &r)
+
+ Constructs a triangle with the supplied \a p, \a q and \a r vertices.
+*/
+
+/*!
+ \fn QVector3D QTriangle3D::p() const
+
+ Returns the value of the P vertex on the triangle.
+
+ \sa q(), r(), setP()
+*/
+
+/*!
+ \fn void QTriangle3D::setP(const QVector3D &point)
+
+ Sets the value of the P vertex on the triangle to \a point.
+
+ \sa setQ(), setR(), p()
+*/
+
+/*!
+ \fn QVector3D QTriangle3D::q() const
+
+ Returns the value of the Q vertex on the triangle.
+
+ \sa p(), r(), setQ()
+*/
+
+/*!
+ \fn void QTriangle3D::setQ(const QVector3D &point)
+
+ Sets the value of the Q vertex on the triangle \a point.
+
+ \sa setP(), setR(), q()
+*/
+
+
+/*!
+ \fn QVector3D QTriangle3D::r() const
+
+ Returns the value of the R vertex on the triangle.
+
+ \sa p(), q(), setR()
+*/
+
+/*!
+ \fn void QTriangle3D::setR(const QVector3D &point)
+
+ Sets the value of the R vertex on the triangle \a point.
+
+ \sa setP(), setQ(), r()
+*/
+
+/*!
+ \fn QPlane3D QTriangle3D::plane() const
+
+ Returns the plane in which the triangle lies.
+
+ \sa QPlane3D
+*/
+
+/*!
+ \fn QVector3D QTriangle3D::center() const
+
+ Returns the center of the triangle, which is the geometric average of the
+ three vertices.
+*/
+
+/*!
+ \fn QVector3D QTriangle3D::faceNormal() const
+
+ Returns the vector normal to this triangle, computed from the
+ cross-product of P-Q and Q-R. The result is not normalized.
+*/
+
+/*!
+ Returns true if this triangle contains \a point; false otherwise.
+ To contain the \a point means that:
+ \list
+ \o the point lies on the same plane as the triangle, and
+ \o the point
+ \list
+ \o lies either wholly within the triangle, or
+ \o lies on one of the sides, or
+ \o coincides with one of the 3 vertices
+ \endlist
+ \endlist
+
+ \sa intersects()
+*/
+bool QTriangle3D::contains(const QVector3D &point) const
+{
+ // Check if the point is on the triangle's plane first.
+ QVector3D normal = QVector3D::crossProduct(m_q - m_p, m_r - m_q);
+ if (!qFuzzyIsNull(float(QVector3D::dotProduct(normal, m_p - point))))
+ return false;
+
+ // Compute the barycentric co-ordinates and use them to determine
+ // if the point is within the triangle.
+ QVector2D c = uv(point);
+ if (c.x() < 0.0f || c.x() > 1.0f)
+ return false;
+ if (c.y() < 0.0f || c.y() > 1.0f)
+ return false;
+ if ((c.x() + c.y()) > 1.0f)
+ return false;
+ return true;
+}
+
+/*!
+ Returns true if the \a ray intersects this triangle; false otherwise.
+
+ This function will return false if the triangle is degenerate.
+
+ \sa contains(), intersection()
+*/
+bool QTriangle3D::intersects(const QRay3D &ray) const
+{
+ qreal t = plane().intersection(ray);
+ if (qIsNaN(t))
+ return false;
+ return contains(ray.point(t));
+}
+
+/*!
+ Returns the t value at which \a ray intersects this triangle, or
+ not-a-number if there is no intersection.
+
+ When the \a ray intersects this triangle, the return value is a
+ parametric value that can be passed to QRay3D::point() to determine
+ the actual intersection point, as shown in the following example:
+
+ \code
+ qreal t = triangle.intersection(ray);
+ QVector3D pt;
+ if (qIsNaN(t)) {
+ qWarning("no intersection occurred");
+ else
+ pt = ray.point(t);
+ \endcode
+
+ \sa intersects(), contains(), QRay3D::point()
+ */
+qreal QTriangle3D::intersection(const QRay3D &ray) const
+{
+ qreal t = plane().intersection(ray);
+ if (qIsNaN(t) || contains(ray.point(t)))
+ return t;
+ return qSNaN();
+}
+
+/*!
+ Transforms the points of this triangle according to \a matrix.
+
+ \sa transformed()
+*/
+void QTriangle3D::transform(const QMatrix4x4 &matrix)
+{
+ m_p = matrix * m_p;
+ m_q = matrix * m_q;
+ m_r = matrix * m_r;
+}
+
+/*!
+ Returns a new triangle that results from transforming this
+ one using \a matrix.
+
+ \sa transform()
+*/
+QTriangle3D QTriangle3D::transformed(const QMatrix4x4 &matrix) const
+{
+ return QTriangle3D(matrix * m_p, matrix * m_q, matrix * m_r);
+}
+
+/*!
+ Returns the (u, v) barycentric co-ordinates of \a point within
+ this triangle.
+
+ The returned barycentric co-ordinates will be (1, 0) at p(),
+ (0, 1) at q(), and (0, 0) at r(). Technically, barycentric
+ co-ordinates have three components with the corners at
+ (1, 0, 0), (0, 1, 0), and (0, 0, 1). However, the third
+ component is always equal to (1 - u - v) so we do not return it.
+
+ The typical use case for this function is to convert an intersection
+ point on a triangle into the texture co-ordinate corresponding to
+ that point. If \c p, \c q, and \c r are the points on the triangle,
+ with corresponding texture co-ordinates \c tp, \c tq, and \c tr,
+ then the texture co-ordinate \c tc of \a point can be determined
+ by the following code:
+
+ \code
+ QTriangle3D triangle(p, q, r);
+ QVector2D uv = triangle.uv(point);
+ QVector2D tc = uv.x() * tp + uv.y() * tq + (1 - uv.x() - uv.y()) * tr;
+ \endcode
+
+ \sa contains(), intersection()
+*/
+QVector2D QTriangle3D::uv(const QVector3D &point) const
+{
+ // Algorithm from: http://www.blackpawn.com/texts/pointinpoly/default.html
+ // More: http://en.wikipedia.org/wiki/Barycentric_coordinates_(mathematics)
+ QVector3D rq = m_q - m_r;
+ QVector3D rp = m_p - m_r;
+ QVector3D pp = point - m_r;
+ qreal dot_rq_rq = QVector3D::dotProduct(rq, rq);
+ qreal dot_rq_rp = QVector3D::dotProduct(rq, rp);
+ qreal dot_rq_pp = QVector3D::dotProduct(rq, pp);
+ qreal dot_rp_rp = QVector3D::dotProduct(rp, rp);
+ qreal dot_rp_pp = QVector3D::dotProduct(rp, pp);
+ qreal det = dot_rq_rq * dot_rp_rp - dot_rq_rp * dot_rq_rp;
+ if (qFuzzyIsNull(float(det))) {
+ // The point is probably not in the triangle, or the triangle
+ // is degenerate. Return an out of range value for (u, v) so
+ // that contains() will fail when this case happens.
+ return QVector2D(-1.0f, -1.0f);
+ }
+ return QVector2D((dot_rq_rq * dot_rp_pp - dot_rq_rp * dot_rq_pp) / det,
+ (dot_rp_rp * dot_rq_pp - dot_rq_rp * dot_rp_pp) / det);
+}
+
+/*!
+ \fn bool QTriangle3D::operator==(const QTriangle3D &other)
+
+ Returns true if this triangle is the same as \a other; false otherwise.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QTriangle3D::operator!=(const QTriangle3D &other)
+
+ Returns true if this triangle is not the same as \a other; false otherwise.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QTriangle3D &triangle1, const QTriangle3D &triangle2)
+ \relates QTriangle3D
+
+ Returns true if \a triangle1 and \a triangle2 are almost equal;
+ false otherwise.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QTriangle3D &triangle)
+{
+ dbg.nospace() << "QTriangle3D(("
+ << triangle.p().x() << ", " << triangle.p().y() << ", "
+ << triangle.p().z() << "), ("
+ << triangle.q().x() << ", " << triangle.q().y() << ", "
+ << triangle.q().z() << "), ("
+ << triangle.r().x() << ", " << triangle.r().y() << ", "
+ << triangle.r().z() << "))";
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QTriangle3D &triangle)
+ \relates QTriangle3D
+
+ Writes the given \a triangle to the given \a stream and returns a
+ reference to the stream.
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QTriangle3D &triangle)
+{
+ stream << triangle.p();
+ stream << triangle.q();
+ stream << triangle.r();
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QTriangle3D &triangle)
+ \relates QTriangle3D
+
+ Reads a 3D triangle from the given \a stream into the given \a triangle
+ and returns a reference to the stream.
+*/
+
+QDataStream &operator>>(QDataStream &stream, QTriangle3D &triangle)
+{
+ QVector3D p, q, r;
+ stream >> p;
+ stream >> q;
+ stream >> r;
+ triangle = QTriangle3D(p, q, r);
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE
diff --git a/src/threed/math3d/qtriangle3d.h b/src/threed/math3d/qtriangle3d.h
new file mode 100644
index 000000000..cc88f9cd0
--- /dev/null
+++ b/src/threed/math3d/qtriangle3d.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTRIANGLE3D_H
+#define QTRIANGLE3D_H
+
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector2d.h>
+#include "qray3d.h"
+#include "qplane3d.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QMatrix4x4;
+
+class Q_QT3D_EXPORT QTriangle3D
+{
+public:
+ QTriangle3D();
+ QTriangle3D(const QVector3D &p, const QVector3D &q, const QVector3D &r);
+
+ QVector3D p() const;
+ void setP(const QVector3D & point);
+
+ QVector3D q() const;
+ void setQ(const QVector3D & point);
+
+ QVector3D r() const;
+ void setR(const QVector3D & point);
+
+ QPlane3D plane() const;
+ QVector3D center() const;
+ QVector3D faceNormal() const;
+
+ bool contains(const QVector3D &point) const;
+
+ bool intersects(const QRay3D &ray) const;
+ qreal intersection(const QRay3D &ray) const;
+
+ void transform(const QMatrix4x4 &matrix);
+ QTriangle3D transformed(const QMatrix4x4 &matrix) const;
+
+ QVector2D uv(const QVector3D &point) const;
+
+ bool operator==(const QTriangle3D &other);
+ bool operator!=(const QTriangle3D &other);
+
+private:
+ QVector3D m_p, m_q, m_r;
+};
+
+inline QTriangle3D::QTriangle3D()
+ : m_p(0.0f, 0.0f, 0.0f)
+ , m_q(1.0f, 0.0f, 0.0f)
+ , m_r(0.0f, 1.0f, 0.0f) {}
+
+inline QTriangle3D::QTriangle3D(const QVector3D &p, const QVector3D &q, const QVector3D &r)
+ : m_p(p)
+ , m_q(q)
+ , m_r(r) {}
+
+inline QVector3D QTriangle3D::p() const
+{
+ return m_p;
+}
+
+inline void QTriangle3D::setP(const QVector3D &point)
+{
+ m_p = point;
+}
+
+inline QVector3D QTriangle3D::q() const
+{
+ return m_q;
+}
+
+inline void QTriangle3D::setQ(const QVector3D &point)
+{
+ m_q = point;
+}
+
+inline QVector3D QTriangle3D::r() const
+{
+ return m_r;
+}
+
+inline void QTriangle3D::setR(const QVector3D &point)
+{
+ m_r = point;
+}
+
+inline QPlane3D QTriangle3D::plane() const
+{
+ return QPlane3D(m_p, m_q, m_r);
+}
+
+inline QVector3D QTriangle3D::center() const
+{
+ return (m_p + m_q + m_r) / 3.0f;
+}
+
+inline QVector3D QTriangle3D::faceNormal() const
+{
+ return QVector3D::crossProduct(m_q - m_p, m_r - m_q);
+}
+
+inline bool QTriangle3D::operator==(const QTriangle3D &other)
+{
+ return m_p == other.m_p && m_q == other.m_q && m_r == other.m_r;
+}
+
+inline bool QTriangle3D::operator!=(const QTriangle3D &other)
+{
+ return m_p != other.m_p || m_q != other.m_q || m_r != other.m_r;
+}
+
+inline bool qFuzzyCompare
+ (const QTriangle3D &triangle1, const QTriangle3D &triangle2)
+{
+ return qFuzzyCompare(triangle1.p(), triangle2.p()) &&
+ qFuzzyCompare(triangle1.q(), triangle2.q()) &&
+ qFuzzyCompare(triangle1.r(), triangle2.r());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QTriangle3D &triangle);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_QT3D_EXPORT QDataStream &operator<<(QDataStream &stream, const QTriangle3D &triangle);
+Q_QT3D_EXPORT QDataStream &operator>>(QDataStream &stream, QTriangle3D &triangle);
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QTriangle3D)
+
+QT_END_HEADER
+
+#endif // QTRIANGLE3D_H
diff --git a/src/threed/painting/painting.pri b/src/threed/painting/painting.pri
new file mode 100644
index 000000000..8f5b5951b
--- /dev/null
+++ b/src/threed/painting/painting.pri
@@ -0,0 +1,29 @@
+
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+
+HEADERS += \
+ qglabstracteffect.h \
+ qgllightmodel.h \
+ qgllightparameters.h \
+ qglpainter.h \
+ qmatrix4x4stack.h
+
+SOURCES += \
+ qglabstracteffect.cpp \
+ qglext.cpp \
+ qgllightmodel.cpp \
+ qgllightparameters.cpp \
+ qglpainter.cpp \
+ qglpickcolors.cpp \
+ qmatrix4x4stack.cpp
+
+PRIVATE_HEADERS += \
+ qglpainter_p.h \
+ qglpickcolors_p.h \
+ qglabstracteffect_p.h \
+ qmatrix4x4stack_p.h
+
+# Don't add this file to PRIVATE_HEADERS because we don't
+# want moc to run over it:
+# qglext_p.h
diff --git a/src/threed/painting/qglabstracteffect.cpp b/src/threed/painting/qglabstracteffect.cpp
new file mode 100644
index 000000000..26cacae8b
--- /dev/null
+++ b/src/threed/painting/qglabstracteffect.cpp
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglabstracteffect.h"
+#include "qglpainter_p.h"
+#include <QtOpenGL/qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLAbstractEffect
+ \since 4.8
+ \brief The QGLAbstractEffect class provides a standard interface for rendering surface material effects with GL.
+ \ingroup qt3d
+ \ingroup qt3d::painting
+
+ \section1 Vertex attributes
+
+ Vertex attributes for the effect are specified using
+ QGLPainter::setVertexAttribute() and QGLPainter::setVertexBundle(),
+ and may be independent of the effect itself. Those functions
+ will bind standard attributes to specific indexes within the
+ GL state. For example, the QGL::Position will be bound
+ to index 0, QGL::TextureCoord0 will be bound to index 3, etc.
+
+ Effect subclasses that use vertex shaders should bind their attributes
+ to these indexes using QGLShaderProgram::bindAttributeLocation()
+ just before the program is linked. For example:
+
+ \code
+ QGLShaderProgram *program = new QGLShaderProgram();
+ program->addShaderFromSourceCode(QGLShader::Vertex, vshaderSource);
+ program->addShaderFromSourceCode(QGLShader::Fragment, fshaderSource);
+ program->bindAttributeLocation("vertex", QGL::Position);
+ program->bindAttributeLocation("normal", QGL::Normal);
+ program->bindAttributeLocation("texcoord", QGL::TextureCoord0);
+ program->link();
+ \endcode
+
+ The QGLShaderProgramEffect class can assist with writing
+ shader-based effects. It will automatically bind special
+ variable names, such as \c{qt_Vertex}, \c{qt_MultiTexCoord0}, etc,
+ to the standard indexes. This alleviates the need for the
+ application to bind the names itself.
+*/
+
+/*!
+ Constructs a new effect object.
+*/
+QGLAbstractEffect::QGLAbstractEffect()
+{
+}
+
+/*!
+ Destroys this effect object.
+*/
+QGLAbstractEffect::~QGLAbstractEffect()
+{
+}
+
+/*!
+ Returns true if this effect supports object picking; false otherwise.
+ The default implementation returns false, which causes QGLPainter
+ to use the effect associated with QGL::FlatColor to perform
+ object picking.
+
+ Effects that support object picking render fragments with
+ QGLPainter::pickColor() when QGLPainter::isPicking() returns true.
+ By default, only the effect associated with QGL::FlatColor does this,
+ rendering the entire fragment with the flat pick color.
+
+ In some cases, rendering the entire fragment with the pick color
+ may not be appropriate. An alpha-blended icon texture that is
+ drawn to the screen as a quad may have an irregular shape smaller
+ than the quad. For picking, the application may not want the
+ entire quad to be "active" for object selection as it would appear
+ to allow the user to click off the icon to select it.
+
+ This situation can be handled by implementing an icon rendering
+ effect that draws the icon normally when QGLPainter::isPicking()
+ is false, and draws a mask texture defining the outline of the icon
+ with QGLPainter::pickColor() when QGLPainter::isPicking() is true.
+
+ \sa QGLPainter::setPicking()
+*/
+bool QGLAbstractEffect::supportsPicking() const
+{
+ return false;
+}
+
+/*!
+ \fn void QGLAbstractEffect::setActive(QGLPainter *painter, bool flag)
+
+ Activates or deactivates this effect on \a painter,
+ according to \a flag, on the current GL context by selecting
+ shader programs, setting lighting and material parameters, etc.
+
+ \sa update()
+*/
+
+/*!
+ \fn void QGLAbstractEffect::update(QGLPainter *painter, QGLPainter::Updates updates)
+
+ Updates the current GL context with information from \a painter
+ just prior to the drawing of triangles, quads, etc.
+
+ The \a updates parameter specifies the properties on \a painter
+ that have changed since the last call to update() or setActive().
+
+ \sa setActive()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/painting/qglabstracteffect.h b/src/threed/painting/qglabstracteffect.h
new file mode 100644
index 000000000..758bdabf6
--- /dev/null
+++ b/src/threed/painting/qglabstracteffect.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLABSTRACTEFFECT_H
+#define QGLABSTRACTEFFECT_H
+
+#include "qglpainter.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QGLAbstractEffect
+{
+public:
+ QGLAbstractEffect();
+ virtual ~QGLAbstractEffect();
+
+ virtual bool supportsPicking() const;
+ virtual void setActive(QGLPainter *painter, bool flag) = 0;
+ virtual void update(QGLPainter *painter, QGLPainter::Updates updates) = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/painting/qglabstracteffect_p.h b/src/threed/painting/qglabstracteffect_p.h
new file mode 100644
index 000000000..513c89b9b
--- /dev/null
+++ b/src/threed/painting/qglabstracteffect_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLABSTRACTEFFECT_P_H
+#define QGLABSTRACTEFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstracteffect.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+#if defined(QT_OPENGL_ES_2)
+#define QGL_SHADERS_ONLY 1
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/painting/qglext.cpp b/src/threed/painting/qglext.cpp
new file mode 100644
index 000000000..0618d79e4
--- /dev/null
+++ b/src/threed/painting/qglext.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglext_p.h"
+#include "qopenglfunctions.h"
+
+#include <QtOpenGL/private/qglextensions_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_OPENGL_ES)
+
+typedef void (QT3D_GLF_APIENTRYP q_PFNGLCLIENTACTIVETEXTUREPROC) (GLenum);
+
+class QGLMultiTextureExtensions
+{
+public:
+ QGLMultiTextureExtensions(const QGLContext * = 0)
+ {
+ clientActiveTexture = 0;
+ multiTextureResolved = false;
+ }
+
+ q_PFNGLCLIENTACTIVETEXTUREPROC clientActiveTexture;
+ bool multiTextureResolved;
+};
+
+Q_GLOBAL_STATIC(QGLResource<QGLMultiTextureExtensions>, qt_multitexture_funcs)
+
+static QGLMultiTextureExtensions *resolveMultiTextureExtensions
+ (const QGLContext *ctx)
+{
+ QGLMultiTextureExtensions *extn = qt_multitexture_funcs()->value(ctx);
+ if (!(extn->multiTextureResolved)) {
+ extn->multiTextureResolved = true;
+ if (!extn->clientActiveTexture) {
+ extn->clientActiveTexture = (q_PFNGLCLIENTACTIVETEXTUREPROC)
+ ctx->getProcAddress(QLatin1String("glClientActiveTexture"));
+ }
+ if (!extn->clientActiveTexture) {
+ extn->clientActiveTexture = (q_PFNGLCLIENTACTIVETEXTUREPROC)
+ ctx->getProcAddress(QLatin1String("glClientActiveTextureARB"));
+ }
+ }
+ return extn;
+}
+
+void qt_gl_ClientActiveTexture(GLenum texture)
+{
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!ctx)
+ return;
+ QGLMultiTextureExtensions *extn = resolveMultiTextureExtensions(ctx);
+ if (extn->clientActiveTexture)
+ extn->clientActiveTexture(texture);
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/threed/painting/qglext_p.h b/src/threed/painting/qglext_p.h
new file mode 100644
index 000000000..d34b499d7
--- /dev/null
+++ b/src/threed/painting/qglext_p.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLEXT_P_H
+#define QGLEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtOpenGL/qgl.h>
+#include "qt3dglobal.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+// Provide some useful OpenGL extension definitions.
+
+#if !defined(QT_OPENGL_ES)
+
+extern void Q_QT3D_EXPORT qt_gl_ClientActiveTexture(GLenum texture);
+
+#elif !defined(QT_OPENGL_ES_2)
+
+#define qt_gl_ClientActiveTexture glClientActiveTexture
+
+#endif
+
+class QGLExtensionChecker
+{
+public:
+ QGLExtensionChecker(const char *str)
+ : gl_extensions(str), gl_extensions_length(qstrlen(str))
+ {}
+
+ bool match(const char *str) {
+ int str_length = qstrlen(str);
+ const char *extensions = gl_extensions;
+ int extensions_length = gl_extensions_length;
+
+ while (1) {
+ // the total length that needs to be matched is the str_length +
+ // the space character that terminates the extension name
+ if (extensions_length < str_length + 1)
+ return false;
+ if (qstrncmp(extensions, str, str_length) == 0 && extensions[str_length] == ' ')
+ return true;
+
+ int split_pos = 0;
+ while (split_pos < extensions_length && extensions[split_pos] != ' ')
+ ++split_pos;
+ ++split_pos; // added for the terminating space character
+ extensions += split_pos;
+ extensions_length -= split_pos;
+ }
+ return false;
+ }
+
+private:
+ const char *gl_extensions;
+ int gl_extensions_length;
+};
+
+// Copy of some definitions from <QtOpenGL/private/qgl_p.h> so that
+// we can avoid a direct dependency upon private headers in Qt.
+
+#if QT_VERSION >= 0x040800
+
+class QGLContextGroup;
+
+#if !defined(QGL_P_H)
+
+class Q_OPENGL_EXPORT QGLContextGroupResourceBase
+{
+public:
+ QGLContextGroupResourceBase();
+ virtual ~QGLContextGroupResourceBase();
+ void insert(const QGLContext *context, void *value);
+ void *value(const QGLContext *context);
+ void cleanup(const QGLContext *context, void *value);
+ virtual void freeResource(void *value) = 0;
+
+protected:
+ QList<QGLContextGroup *> m_groups;
+
+private:
+ QAtomicInt active;
+};
+
+#endif
+
+template <class T>
+class QGLResource : public QGLContextGroupResourceBase
+{
+public:
+ T *value(const QGLContext *context) {
+ T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
+ if (!resource) {
+ resource = new T(context);
+ insert(context, resource);
+ }
+ return resource;
+ }
+
+protected:
+ void freeResource(void *resource) {
+ delete reinterpret_cast<T *>(resource);
+ }
+};
+
+#else
+
+#if !defined(QGL_P_H)
+
+class Q_OPENGL_EXPORT QGLContextResource
+{
+public:
+ typedef void (*FreeFunc)(void *);
+ QGLContextResource(FreeFunc f);
+ ~QGLContextResource();
+ void insert(const QGLContext *key, void *value);
+ void *value(const QGLContext *key);
+ void cleanup(const QGLContext *ctx, void *value);
+private:
+ FreeFunc free;
+ QAtomicInt active;
+};
+
+#endif
+
+template <class T>
+class QGLResource : public QGLContextResource
+{
+public:
+ static void freeResource(void *resource) {
+ delete reinterpret_cast<T *>(resource);
+ }
+
+ QGLResource() : QGLContextResource(freeResource) {}
+
+ T *value(const QGLContext *context) {
+ T *resource = reinterpret_cast<T *>(QGLContextResource::value(context));
+ if (!resource) {
+ resource = new T(context);
+ insert(context, resource);
+ }
+ return resource;
+ }
+};
+
+#endif
+
+#if !defined(QGL_P_H) && !defined(Q_MOC_RUN)
+
+class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QGLSignalProxy() : QObject() {}
+ void emitAboutToDestroyContext(const QGLContext *context) {
+ emit aboutToDestroyContext(context);
+ }
+ static QGLSignalProxy *instance();
+Q_SIGNALS:
+ void aboutToDestroyContext(const QGLContext *context);
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/painting/qgllightmodel.cpp b/src/threed/painting/qgllightmodel.cpp
new file mode 100644
index 000000000..bdcdadb9a
--- /dev/null
+++ b/src/threed/painting/qgllightmodel.cpp
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgllightmodel.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLLightModel
+ \brief The QGLLightModel class defines the lighting model to use for the scene.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+*/
+
+/*!
+ \qmlclass LightModel QGLLightModel
+ \brief The LightModel item defines the lighting model to use for the scene.
+ \since 4.8
+ \ingroup qt3d::qml3d
+
+ \sa Light
+*/
+
+/*!
+ \enum QGLLightModel::Model
+ This enum defines the type of lighting model to use: one-sided or two-sided.
+
+ \value OneSided One-sided lighting, with the front face material used for both front and back faces.
+ \value TwoSided Two-sided lighting, with separate front and back face materials.
+*/
+
+/*!
+ \enum QGLLightModel::ColorControl
+ This enum controls the number of colors to be generated by the lighting computation.
+
+ \value SingleColor A single color is generated by the lighting computation.
+ \value SeparateSpecularColor A separate specular color computation is
+ performed and then summed into the pixel color after texture mapping.
+*/
+
+/*!
+ \enum QGLLightModel::ViewerPosition
+ This enum defines the position of the viewer for the purposes of lighting calculations.
+
+ \value ViewerAtInfinity The viewer is at infinity along the -z axis.
+ \value LocalViewer The viewer is at the local origin in eye coordinates.
+*/
+
+class QGLLightModelPrivate
+{
+public:
+ QGLLightModelPrivate()
+ : model(QGLLightModel::OneSided),
+ colorControl(QGLLightModel::SingleColor),
+ viewerPosition(QGLLightModel::ViewerAtInfinity)
+ {
+ ambientSceneColor.setRgbF(0.2, 0.2, 0.2, 1.0);
+ }
+
+ QGLLightModel::Model model;
+ QGLLightModel::ColorControl colorControl;
+ QGLLightModel::ViewerPosition viewerPosition;
+ QColor ambientSceneColor;
+};
+
+/*!
+ Constructs a light model object with default values and attach
+ it to \a parent.
+*/
+QGLLightModel::QGLLightModel(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new QGLLightModelPrivate)
+{
+}
+
+/*!
+ Destroys this light model.
+*/
+QGLLightModel::~QGLLightModel()
+{
+}
+
+/*!
+ \property QGLLightModel::model
+ \brief the lighting model to use, either OneSided or TwoSided.
+ The default is OneSided.
+
+ \sa modelChanged()
+*/
+
+/*!
+ \qmlproperty enumeration LightModel::model
+ The lighting model to use, either OneSided or TwoSided.
+ The default is OneSided.
+*/
+
+QGLLightModel::Model QGLLightModel::model() const
+{
+ Q_D(const QGLLightModel);
+ return d->model;
+}
+
+void QGLLightModel::setModel(QGLLightModel::Model value)
+{
+ Q_D(QGLLightModel);
+ if (d->model != value) {
+ d->model = value;
+ emit modelChanged();
+ emit lightModelChanged();
+ }
+}
+
+/*!
+ \property QGLLightModel::colorControl
+ \brief the color control mode, either SingleColor or
+ SeparateSpecularColor. The default value is SingleColor.
+
+ If SingleColor is specified, then a single color is calculated
+ by the lighting computation for a vertex. If SeparateSpecularColor
+ is specified, then a separate specular color computation is
+ performed and then summed into the pixel color after texture mapping.
+
+ \sa colorControlChanged()
+*/
+
+/*!
+ \qmlproperty enumeration LightModel::colorControl
+ The color control mode, either SingleColor or
+ SeparateSpecularColor. The default value is SingleColor.
+
+ If SingleColor is specified, then a single color is calculated
+ by the lighting computation for a vertex. If SeparateSpecularColor
+ is specified, then a separate specular color computation is
+ performed and then summed into the pixel color after texture mapping.
+*/
+
+QGLLightModel::ColorControl QGLLightModel::colorControl() const
+{
+ Q_D(const QGLLightModel);
+ return d->colorControl;
+}
+
+void QGLLightModel::setColorControl(QGLLightModel::ColorControl value)
+{
+ Q_D(QGLLightModel);
+ if (d->colorControl != value) {
+ d->colorControl = value;
+ emit colorControlChanged();
+ emit lightModelChanged();
+ }
+}
+
+/*!
+ \property QGLLightModel::viewerPosition
+ \brief the viewer position, either ViewerAtInfinity or LocalViewer.
+ The default value is ViewerAtInfinity.
+
+ \sa viewerPositionChanged()
+*/
+
+/*!
+ \qmlproperty enumeration LightModel::viewerPosition
+ The viewer position, either ViewerAtInfinity or LocalViewer.
+ The default value is ViewerAtInfinity.
+*/
+
+QGLLightModel::ViewerPosition QGLLightModel::viewerPosition() const
+{
+ Q_D(const QGLLightModel);
+ return d->viewerPosition;
+}
+
+void QGLLightModel::setViewerPosition(QGLLightModel::ViewerPosition value)
+{
+ Q_D(QGLLightModel);
+ if (d->viewerPosition != value) {
+ d->viewerPosition = value;
+ emit viewerPositionChanged();
+ emit lightModelChanged();
+ }
+}
+
+/*!
+ \property QGLLightModel::ambientSceneColor
+ \brief the ambient color of the entire scene. The default value
+ is (0.2, 0.2, 0.2, 1.0).
+
+ \sa ambientSceneColorChanged()
+*/
+
+/*!
+ \qmlproperty color LightModel::ambientSceneColor
+ The ambient color of the entire scene. The default value
+ is (0.2, 0.2, 0.2, 1.0).
+*/
+
+QColor QGLLightModel::ambientSceneColor() const
+{
+ Q_D(const QGLLightModel);
+ return d->ambientSceneColor;
+}
+
+void QGLLightModel::setAmbientSceneColor(const QColor& value)
+{
+ Q_D(QGLLightModel);
+ if (d->ambientSceneColor != value) {
+ d->ambientSceneColor = value;
+ emit ambientSceneColorChanged();
+ emit lightModelChanged();
+ }
+}
+
+/*!
+ \fn void QGLLightModel::modelChanged()
+
+ This signal is emitted when model() changes.
+
+ \sa model(), lightModelChanged()
+*/
+
+/*!
+ \fn void QGLLightModel::colorControlChanged()
+
+ This signal is emitted when colorControl() changes.
+
+ \sa colorControl(), lightModelChanged()
+*/
+
+/*!
+ \fn void QGLLightModel::viewerPositionChanged()
+
+ This signal is emitted when viewerPosition() changes.
+
+ \sa viewerPosition(), lightModelChanged()
+*/
+
+/*!
+ \fn void QGLLightModel::ambientSceneColorChanged()
+
+ This signal is emitted when ambientSceneColor() changes.
+
+ \sa ambientSceneColor(), lightModelChanged()
+*/
+
+/*!
+ \fn void QGLLightModel::lightModelChanged()
+
+ This signal is emitted when one of model(), colorControl(),
+ viewerPosition(), or ambientSceneColor() changes.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/painting/qgllightmodel.h b/src/threed/painting/qgllightmodel.h
new file mode 100644
index 000000000..2ff307221
--- /dev/null
+++ b/src/threed/painting/qgllightmodel.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLLIGHTMODEL_H
+#define QGLLIGHTMODEL_H
+
+#include "qt3dglobal.h"
+#include <QtCore/qobject.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLLightModelPrivate;
+
+class Q_QT3D_EXPORT QGLLightModel : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGLLightModel)
+ Q_ENUMS(Model)
+ Q_ENUMS(ColorControl)
+ Q_ENUMS(ViewerPosition)
+ Q_PROPERTY(Model model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(ColorControl colorControl READ colorControl WRITE setColorControl NOTIFY colorControlChanged)
+ Q_PROPERTY(ViewerPosition viewerPosition READ viewerPosition WRITE setViewerPosition NOTIFY viewerPositionChanged)
+ Q_PROPERTY(QColor ambientSceneColor READ ambientSceneColor WRITE setAmbientSceneColor NOTIFY ambientSceneColorChanged)
+public:
+ explicit QGLLightModel(QObject *parent = 0);
+ ~QGLLightModel();
+
+ enum Model
+ {
+ OneSided,
+ TwoSided
+ };
+
+ enum ColorControl
+ {
+ SingleColor,
+ SeparateSpecularColor
+ };
+
+ enum ViewerPosition
+ {
+ ViewerAtInfinity,
+ LocalViewer
+ };
+
+ QGLLightModel::Model model() const;
+ void setModel(QGLLightModel::Model value);
+
+ QGLLightModel::ColorControl colorControl() const;
+ void setColorControl(QGLLightModel::ColorControl value);
+
+ QGLLightModel::ViewerPosition viewerPosition() const;
+ void setViewerPosition(QGLLightModel::ViewerPosition value);
+
+ QColor ambientSceneColor() const;
+ void setAmbientSceneColor(const QColor& value);
+
+Q_SIGNALS:
+ void modelChanged();
+ void colorControlChanged();
+ void viewerPositionChanged();
+ void ambientSceneColorChanged();
+ void lightModelChanged();
+
+private:
+ Q_DISABLE_COPY(QGLLightModel)
+
+ QScopedPointer<QGLLightModelPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/painting/qgllightparameters.cpp b/src/threed/painting/qgllightparameters.cpp
new file mode 100644
index 000000000..27530d31d
--- /dev/null
+++ b/src/threed/painting/qgllightparameters.cpp
@@ -0,0 +1,828 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgllightparameters.h"
+#include <QtCore/qmath.h>
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLLightParameters
+ \brief The QGLLightParameters class represents the parameters of a light in a 3D scene.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+
+ The functions in this class are a convenience wrapper for the OpenGL enumerations
+ which control each light source in a 3D scene. For the general ambient light in a
+ scene, not from a source refer to QGLLightModel.
+
+ The ambient, diffuse and specular components of the light can be controlled for by
+ colour, and are set by the following functions:
+ \list
+ \o setAmbientColor()
+ \o setDiffuseColor()
+ \o setSpecularColor()
+ \endlist
+ Other than changing intensity by using darker color values, see below for how to
+ change the intensity of the light with distance from the lit object.
+
+ Light sources are of two types, directional and positional, described by the
+ enumeration QGLLightParameters::LightType. By default a light source is directional.
+
+ A directional light source is infinitely distant, such that its rays are all
+ parallel, to a direction \bold vector. This vector is set by the setDirection()
+ function. If the light source is not directional when setDirection() is called, its
+ type is changed to Directional. Directional light sources model real world light
+ sources like the sun. Such light sources are not located at any particular point
+ and affect the scene evenly.
+
+ In the OpenGL model-view, a directional light is represented by a 4d vector, with
+ the 4th value, \c w, set to 0.0f. This means that the spatial data of the light
+ is not changed during certain transformations, for example translation.
+ See \l {3D Math Basis} for a fuller explanation of this.
+
+ Calling the setPosition() function defines the light source to be located at a given
+ \bold point, a finite distance from the lit object. If the light source is not
+ positional when this function is called its type is changed to Positional.
+
+ A positional light source models a real world lamp, such as a light-bulb or
+ car headlight. Since it is a finite distance from the lit object the rays diverge
+ and lighting calculations are thus more complex.
+
+ In OpenGL the light has its spatial data \c w value set to 1.0f, resulting in the
+ lights position being changed along with other objects in the scene by transformations
+ such as translation. See \l {3D Math Basis} for more.
+
+ Positional lights are by default point sources, like the light-bulb where light
+ radiates in all directions. Calling the spotAngle() function sets an angle to
+ restrict the light from a positional source to a cone like the car headlight. This
+ makes the light behave like a spotlight, where objects outside of the cone of the
+ light do not receive any light from that source.
+
+ The spotlight may be further specified by its spotExponent() which dictates the
+ behaviour of the cutoff at the lighting cone; and by the attenuation functions
+ which are the terms in the following equation:
+ \image attenuation.png
+ here \c d is the distance of the light from the lit object, and A is the attenuation
+ factor which is a multiplier of the light source, determining its intensity at the
+ lit object. The terms in the denominator are:
+ \list
+ \o constantAttenuation() - default 1.0
+ \raw HTML
+ k<sub>c</sub>
+ \endraw
+ \o linearAttenuation() - default 0.0
+ \raw HTML
+ k<sub>l</sub>
+ \endraw
+ \o quadraticAttenuation() - default 0.0
+ \raw HTML
+ k<sub>q</sub>
+ \endraw
+ \endlist
+ When these terms are large the light contributed by the source becomes much weaker
+ with distance from the object.
+*/
+
+/*!
+ \qmlclass Light QGLLightParameters
+ \brief The Light item represents the parameters of a light in a 3D scene.
+ \since 4.8
+ \ingroup qt3d::qml3d
+
+ \sa LightModel
+*/
+
+class QGLLightParametersPrivate
+{
+public:
+ QGLLightParametersPrivate() :
+ type(QGLLightParameters::Directional),
+ position(0.0f, 0.0f, 1.0f),
+ ambientColor(0, 0, 0, 255),
+ diffuseColor(255, 255, 255, 255),
+ specularColor(255, 255, 255, 255),
+ spotDirection(0.0f, 0.0f, -1.0f),
+ spotExponent(0.0f),
+ spotAngle(180.0f),
+ spotCosAngle(-1.0f),
+ constantAttenuation(1.0f),
+ linearAttenuation(0.0f),
+ quadraticAttenuation(0.0f)
+ {
+ }
+
+ QGLLightParameters::LightType type;
+ QVector3D position;
+ QColor ambientColor;
+ QColor diffuseColor;
+ QColor specularColor;
+ QVector3D spotDirection;
+ qreal spotExponent;
+ qreal spotAngle;
+ qreal spotCosAngle;
+ qreal constantAttenuation;
+ qreal linearAttenuation;
+ qreal quadraticAttenuation;
+};
+
+
+/*!
+ \enum QGLLightParameters::LightType
+ This enum defines the possible types of light.
+
+ \value Directional The default. Directional lights are infinitely
+ distant from the lit object, and its rays are parallel to a
+ direction vector. Use setDirection() to make a light Directional.
+ \value Positional Positional lights are a finite distance from the
+ lit object. Complex lighting with spot-lights, and attenuation
+ are enabled with Positional lighting. Use setPosition() to
+ make a light Positional.
+*/
+
+/*!
+ Constructs a new light parameters object with default values
+ and attaches it to \a parent.
+*/
+QGLLightParameters::QGLLightParameters(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new QGLLightParametersPrivate)
+{
+}
+
+/*!
+ Destroys this light parameters object.
+*/
+QGLLightParameters::~QGLLightParameters()
+{
+}
+
+/*!
+ \property QGLLightParameters::type
+ \brief the type of this light; Positional or Directional.
+
+ \sa position(), direction()
+*/
+
+/*!
+ \qmlproperty enumeration Light::type
+ The type of this light; Positional or Directional. The default
+ is Directional.
+
+ \sa position, direction
+*/
+
+QGLLightParameters::LightType QGLLightParameters::type() const
+{
+ Q_D(const QGLLightParameters);
+ return d->type;
+}
+
+/*!
+ \property QGLLightParameters::position
+ \brief the position of this light if it is Positional; or a null
+ QVector3D if it is Directional. By default, the light is Directional.
+
+ For a Positional light, the return value is the location in model space
+ of the light, at some finite distance from the origin. The value is
+ transformed by the model-view transformation when the light
+ parameters are applied.
+
+ When the light is Positional OpenGL will obey other parameters relating
+ to the light's position, such as attenuation and spot angle.
+
+ Setting the position converts the light from Directional to Positional.
+
+ \sa direction(), type(), positionChanged()
+*/
+
+/*!
+ \qmlproperty vector3D Light::position
+ The position of this light if it is Positional; or a zero vector
+ if it is Directional. By default, the light is Directional.
+
+ For a Positional light, the return value is the location in model space
+ of the light, at some finite distance from the origin. The value is
+ transformed by the model-view transformation when the light
+ parameters are applied.
+
+ When the light is Positional OpenGL will obey other parameters relating
+ to the light's position, such as attenuation and spot angle.
+
+ Setting the position converts the light from Directional to Positional.
+
+ \sa direction, type
+*/
+
+QVector3D QGLLightParameters::position() const
+{
+ Q_D(const QGLLightParameters);
+ if (d->type == Positional)
+ return d->position;
+ else
+ return QVector3D();
+}
+
+void QGLLightParameters::setPosition(const QVector3D& point)
+{
+ Q_D(QGLLightParameters);
+ if (d->type == Positional) {
+ if (d->position != point) {
+ // Only the position() has changed.
+ d->position = point;
+ emit positionChanged();
+ emit lightChanged();
+ }
+ } else {
+ // Both the position() and direction() are changed.
+ d->type = Positional;
+ d->position = point;
+ emit positionChanged();
+ emit directionChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::direction
+ \brief the direction of this light if it is Directional; or a null
+ QVector3D if it is Positional. By default, the light is Directional.
+
+ For a Directional light, the return value is the direction vector of
+ an infinitely distant directional light, like the sun.
+
+ The default value is (0, 0, 1), for a directional light pointing along
+ the positive z-axis.
+
+ OpenGL will ignore other parameters such as attenuation and spot angle
+ when this value is set, since a directional light has no location.
+ In order to set the direction of a spot light, use the setSpotDirection()
+ function.
+
+ Setting the direction converts the light from Positional to Directional.
+
+ \sa position(), type(), directionChanged()
+*/
+
+/*!
+ \qmlproperty vector3D Light::direction
+ The direction of this light if it is Directional; or a zero vector
+ if it is Positional. By default, the light is Directional.
+
+ For a Directional light, the return value is the direction vector of
+ an infinitely distant directional light, like the sun.
+
+ The default value is (0, 0, 1), for a directional light pointing along
+ the positive z-axis.
+
+ OpenGL will ignore other parameters such as attenuation and spot angle
+ when this value is set, since a directional light has no location.
+ In order to set the direction of a spot light, use the setSpotDirection()
+ function.
+
+ Setting the direction converts the light from Positional to Directional.
+
+ \sa position, type
+*/
+
+QVector3D QGLLightParameters::direction() const
+{
+ Q_D(const QGLLightParameters);
+ if (d->type == Directional)
+ return d->position;
+ else
+ return QVector3D();
+}
+
+void QGLLightParameters::setDirection(const QVector3D& value)
+{
+ Q_D(QGLLightParameters);
+ if (d->type == Directional) {
+ if (d->position != value) {
+ // Only the direction() has changed.
+ d->position = value;
+ emit directionChanged();
+ emit lightChanged();
+ }
+ } else {
+ // Both the position() and direction() are changed.
+ d->type = Directional;
+ d->position = value;
+ emit positionChanged();
+ emit directionChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::ambientColor
+ \brief the ambient color of this light. The default value is black.
+
+ \sa diffuseColor(), specularColor(), ambientColorChanged()
+*/
+
+/*!
+ \qmlproperty color Light::ambientColor
+ The ambient color of this light. The default value is black.
+
+ \sa diffuseColor, specularColor
+*/
+
+QColor QGLLightParameters::ambientColor() const
+{
+ Q_D(const QGLLightParameters);
+ return d->ambientColor;
+}
+
+void QGLLightParameters::setAmbientColor(const QColor& value)
+{
+ Q_D(QGLLightParameters);
+ if (d->ambientColor != value) {
+ d->ambientColor = value;
+ emit ambientColorChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::diffuseColor
+ \brief the diffuse color of this light. The default value is white.
+
+ \sa ambientColor(), specularColor(), diffuseColorChanged()
+*/
+
+/*!
+ \qmlproperty color Light::diffuseColor
+ The diffuse color of this light. The default value is white.
+
+ \sa ambientColor, specularColor
+*/
+QColor QGLLightParameters::diffuseColor() const
+{
+ Q_D(const QGLLightParameters);
+ return d->diffuseColor;
+}
+
+void QGLLightParameters::setDiffuseColor(const QColor& value)
+{
+ Q_D(QGLLightParameters);
+ if (d->diffuseColor != value) {
+ d->diffuseColor = value;
+ emit diffuseColorChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::specularColor
+ \brief the specular color of this light. The default value is white.
+
+ \sa ambientColor(), diffuseColor(), specularColorChanged()
+*/
+
+/*!
+ \qmlproperty color Light::specularColor
+ The specular color of this light. The default value is white.
+
+ \sa ambientColor, diffuseColor
+*/
+
+QColor QGLLightParameters::specularColor() const
+{
+ Q_D(const QGLLightParameters);
+ return d->specularColor;
+}
+
+void QGLLightParameters::setSpecularColor(const QColor& value)
+{
+ Q_D(QGLLightParameters);
+ if (d->specularColor != value) {
+ d->specularColor = value;
+ emit specularColorChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::spotDirection
+ \brief the direction that a spot-light is shining in.
+
+ A spotlight is a positional light that has a value other than the default
+ for spot angle. The default value is (0, 0, -1).
+
+ This parameter has no effect on a Directional light.
+
+ \sa spotExponent(), spotDirectionChanged()
+*/
+
+/*!
+ \qmlproperty vector3D Light::spotDirection
+ The direction that a spot-light is shining in.
+
+ A spotlight is a positional light that has a value other than the default
+ for spot angle. The default value is (0, 0, -1).
+
+ This parameter has no effect on a Directional light.
+
+ \sa spotExponent
+*/
+QVector3D QGLLightParameters::spotDirection() const
+{
+ Q_D(const QGLLightParameters);
+ return d->spotDirection;
+}
+
+void QGLLightParameters::setSpotDirection(const QVector3D& vector)
+{
+ Q_D(QGLLightParameters);
+ if (d->spotDirection != vector) {
+ d->spotDirection = vector;
+ emit spotDirectionChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::spotExponent
+ \brief the exponent value between 0 and 128 that indicates the
+ intensity distribution of a spot-light. The default value is 0,
+ indicating uniform light distribution.
+
+ This parameter has no effect on a Directional light.
+
+ \sa spotAngle(), setPosition(), spotExponentChanged()
+*/
+
+/*!
+ \qmlproperty real Light::spotExponent
+ The exponent value between 0 and 128 that indicates the
+ intensity distribution of a spot-light. The default value is 0,
+ indicating uniform light distribution.
+
+ This parameter has no effect on a Directional light.
+
+ \sa spotAngle, position
+*/
+
+qreal QGLLightParameters::spotExponent() const
+{
+ Q_D(const QGLLightParameters);
+ return d->spotExponent;
+}
+
+void QGLLightParameters::setSpotExponent(qreal value)
+{
+ Q_D(QGLLightParameters);
+ if (d->spotExponent != value) {
+ d->spotExponent = value;
+ emit spotExponentChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::spotAngle
+ \brief the angle over which light is spread from this light.
+ It should be between 0 and 90 for spot lights, and 180 for
+ uniform light distribution from a remote light source.
+ The default value is 180.
+
+ This parameter has no effect on a Directional light.
+
+ \sa spotCosAngle(), spotAngleChanged()
+*/
+
+/*!
+ \qmlproperty real Light::spotAngle
+ The angle over which light is spread from this light.
+ It should be between 0 and 90 for spot lights, and 180 for
+ uniform light distribution from a remote light source.
+ The default value is 180.
+
+ This parameter has no effect on a Directional light.
+*/
+
+qreal QGLLightParameters::spotAngle() const
+{
+ Q_D(const QGLLightParameters);
+ return d->spotAngle;
+}
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+void QGLLightParameters::setSpotAngle(qreal value)
+{
+ Q_D(QGLLightParameters);
+ if (d->spotAngle != value) {
+ d->spotAngle = value;
+ if (value != 180.0f)
+ d->spotCosAngle = qCos(value * M_PI / 180.0f);
+ else
+ d->spotCosAngle = -1.0f;
+ emit spotAngleChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ Returns the cosine of spotAngle(), or -1 if spotAngle() is 180.
+
+ The cosine of spotAngle() is useful in lighting algorithms.
+ This function returns a cached copy of the cosine so that it
+ does not need to be computed every time the lighting parameters
+ are read.
+
+ \sa spotAngle()
+*/
+qreal QGLLightParameters::spotCosAngle() const
+{
+ Q_D(const QGLLightParameters);
+ return d->spotCosAngle;
+}
+
+/*!
+ \property QGLLightParameters::constantAttenuation
+ \brief the constant light attenuation factor. The default value is 1.
+
+ This parameter has no effect on a Directional light.
+
+ \sa linearAttenuation(), quadraticAttenuation()
+ \sa constantAttenuationChanged()
+*/
+
+/*!
+ \qmlproperty real Light::constantAttenuation
+ The constant light attenuation factor. The default value is 1.
+
+ This parameter has no effect on a Directional light.
+
+ \sa linearAttenuation, quadraticAttenuation
+*/
+
+qreal QGLLightParameters::constantAttenuation() const
+{
+ Q_D(const QGLLightParameters);
+ return d->constantAttenuation;
+}
+
+void QGLLightParameters::setConstantAttenuation(qreal value)
+{
+ Q_D(QGLLightParameters);
+ if (d->constantAttenuation != value) {
+ d->constantAttenuation = value;
+ emit constantAttenuationChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::linearAttenuation
+ \brief the linear light attenuation factor. The default value is 0.
+
+ This parameter has no effect on a Directional light.
+
+ \sa constantAttenuation(), quadraticAttenuation()
+ \sa linearAttenuationChanged()
+*/
+
+/*!
+ \qmlproperty real Light::linearAttenuation
+ The linear light attenuation factor. The default value is 0.
+
+ This parameter has no effect on a Directional light.
+
+ \sa constantAttenuation, quadraticAttenuation
+*/
+
+qreal QGLLightParameters::linearAttenuation() const
+{
+ Q_D(const QGLLightParameters);
+ return d->linearAttenuation;
+}
+
+void QGLLightParameters::setLinearAttenuation(qreal value)
+{
+ Q_D(QGLLightParameters);
+ if (d->linearAttenuation != value) {
+ d->linearAttenuation = value;
+ emit linearAttenuationChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ \property QGLLightParameters::quadraticAttenuation
+ \brief the quadratic light attenuation factor. The default value is 0.
+
+ This parameter has no effect on a Directional light.
+
+ \sa constantAttenuation(), linearAttenuation()
+ \sa quadraticAttenuationChanged()
+*/
+
+/*!
+ \qmlproperty real Light::quadraticAttenuation
+ The quadratic light attenuation factor. The default value is 0.
+
+ This parameter has no effect on a Directional light.
+
+ \sa constantAttenuation, linearAttenuation
+*/
+
+qreal QGLLightParameters::quadraticAttenuation() const
+{
+ Q_D(const QGLLightParameters);
+ return d->quadraticAttenuation;
+}
+
+void QGLLightParameters::setQuadraticAttenuation(qreal value)
+{
+ Q_D(QGLLightParameters);
+ if (d->quadraticAttenuation != value) {
+ d->quadraticAttenuation = value;
+ emit quadraticAttenuationChanged();
+ emit lightChanged();
+ }
+}
+
+/*!
+ Returns the position of this light after transforming it from
+ world co-ordinates to eye co-ordinates using \a transform.
+
+ If the light is Directional, then direction() will be transformed,
+ after setting the w co-ordinate to 0. If the light is Positional,
+ then position() will be transformed after setting the w co-ordinate
+ to 1.
+
+ The returned result is suitable to be applied to the GL_POSITION
+ property of \c{glLight()}, assuming that the modelview transformation
+ in the GL context is set to the identity.
+
+ \sa eyeSpotDirection()
+*/
+QVector4D QGLLightParameters::eyePosition(const QMatrix4x4& transform) const
+{
+ Q_D(const QGLLightParameters);
+ if (d->type == Directional)
+ return transform * QVector4D(d->position, 0.0f);
+ else
+ return transform * QVector4D(d->position, 1.0f);
+}
+
+/*!
+ Returns the spotDirection() for this light after transforming it
+ from world co-ordinates to eye co-ordinates using the top-left
+ 3x3 submatrix within \a transform.
+
+ The returned result is suitable to be applied to the GL_SPOT_DIRECTION
+ property of \c{glLight()}, assuming that the modelview transformation
+ in the GL context is set to the identity.
+
+ \sa eyePosition()
+*/
+QVector3D QGLLightParameters::eyeSpotDirection
+ (const QMatrix4x4& transform) const
+{
+ Q_D(const QGLLightParameters);
+ return transform.mapVector(d->spotDirection);
+}
+
+/*!
+ \fn void QGLLightParameters::positionChanged()
+
+ This signal is emitted when position() changes, or when the type()
+ changes between Directional and Positional.
+
+ \sa position(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::directionChanged()
+
+ This signal is emitted when direction() changes, or when the type()
+ changes between Directional and Positional.
+
+ \sa direction(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::ambientColorChanged()
+
+ This signal is emitted when ambientColor() changes.
+
+ \sa ambientColor(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::diffuseColorChanged()
+
+ This signal is emitted when diffuseColor() changes.
+
+ \sa diffuseColor(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::specularColorChanged()
+
+ This signal is emitted when specularColor() changes.
+
+ \sa specularColor(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::spotDirectionChanged()
+
+ This signal is emitted when spotDirection() changes.
+
+ \sa spotDirection(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::spotExponentChanged()
+
+ This signal is emitted when spotExponent() changes.
+
+ \sa spotExponent(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::spotAngleChanged()
+
+ This signal is emitted when spotAngle() changes.
+
+ \sa spotAngle(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::constantAttenuationChanged()
+
+ This signal is emitted when constantAttenuation() changes.
+
+ \sa constantAttenuation(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::linearAttenuationChanged()
+
+ This signal is emitted when linearAttenuation() changes.
+
+ \sa linearAttenuation(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::quadraticAttenuationChanged()
+
+ This signal is emitted when quadraticAttenuation() changes.
+
+ \sa quadraticAttenuation(), lightChanged()
+*/
+
+/*!
+ \fn void QGLLightParameters::lightChanged()
+
+ This signal is emitted when any of the properties on the light changes.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/painting/qgllightparameters.h b/src/threed/painting/qgllightparameters.h
new file mode 100644
index 000000000..7f4a29691
--- /dev/null
+++ b/src/threed/painting/qgllightparameters.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLLIGHTPARAMETERS_H
+#define QGLLIGHTPARAMETERS_H
+
+#include "qt3dglobal.h"
+#include <QtCore/qobject.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLLightParametersPrivate;
+class QMatrix4x4;
+
+class Q_QT3D_EXPORT QGLLightParameters : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGLLightParameters)
+ Q_ENUMS(LightType)
+ Q_PROPERTY(LightType type READ type)
+ Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
+ Q_PROPERTY(QVector3D direction READ direction WRITE setDirection NOTIFY directionChanged)
+ Q_PROPERTY(QColor ambientColor READ ambientColor WRITE setAmbientColor NOTIFY ambientColorChanged)
+ Q_PROPERTY(QColor diffuseColor READ diffuseColor WRITE setDiffuseColor NOTIFY diffuseColorChanged)
+ Q_PROPERTY(QColor specularColor READ specularColor WRITE setSpecularColor NOTIFY specularColorChanged)
+ Q_PROPERTY(QVector3D spotDirection READ spotDirection WRITE setSpotDirection NOTIFY spotDirectionChanged)
+ Q_PROPERTY(qreal spotExponent READ spotExponent WRITE setSpotExponent NOTIFY spotExponentChanged)
+ Q_PROPERTY(qreal spotAngle READ spotAngle WRITE setSpotAngle NOTIFY spotAngleChanged)
+ Q_PROPERTY(qreal constantAttenuation READ constantAttenuation WRITE setConstantAttenuation NOTIFY constantAttenuationChanged)
+ Q_PROPERTY(qreal linearAttenuation READ linearAttenuation WRITE setLinearAttenuation NOTIFY linearAttenuationChanged)
+ Q_PROPERTY(qreal quadraticAttenuation READ quadraticAttenuation WRITE setQuadraticAttenuation NOTIFY quadraticAttenuationChanged)
+public:
+ enum LightType {
+ Directional,
+ Positional
+ };
+
+ QGLLightParameters(QObject *parent = 0);
+ ~QGLLightParameters();
+
+ QGLLightParameters::LightType type() const;
+
+ QVector3D position() const;
+ void setPosition(const QVector3D& value);
+
+ QVector3D direction() const;
+ void setDirection(const QVector3D& value);
+
+ QColor ambientColor() const;
+ void setAmbientColor(const QColor& value);
+
+ QColor diffuseColor() const;
+ void setDiffuseColor(const QColor& value);
+
+ QColor specularColor() const;
+ void setSpecularColor(const QColor& value);
+
+ QVector3D spotDirection() const;
+ void setSpotDirection(const QVector3D& value);
+
+ qreal spotExponent() const;
+ void setSpotExponent(qreal value);
+
+ qreal spotAngle() const;
+ void setSpotAngle(qreal value);
+
+ qreal spotCosAngle() const;
+
+ qreal constantAttenuation() const;
+ void setConstantAttenuation(qreal value);
+
+ qreal linearAttenuation() const;
+ void setLinearAttenuation(qreal value);
+
+ qreal quadraticAttenuation() const;
+ void setQuadraticAttenuation(qreal value);
+
+ QVector4D eyePosition(const QMatrix4x4& transform) const;
+ QVector3D eyeSpotDirection(const QMatrix4x4& transform) const;
+
+Q_SIGNALS:
+ void positionChanged();
+ void directionChanged();
+ void ambientColorChanged();
+ void diffuseColorChanged();
+ void specularColorChanged();
+ void spotDirectionChanged();
+ void spotExponentChanged();
+ void spotAngleChanged();
+ void constantAttenuationChanged();
+ void linearAttenuationChanged();
+ void quadraticAttenuationChanged();
+ void lightChanged();
+
+private:
+ Q_DISABLE_COPY(QGLLightParameters)
+
+ QScopedPointer<QGLLightParametersPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/painting/qglpainter.cpp b/src/threed/painting/qglpainter.cpp
new file mode 100644
index 000000000..b3f6a2c59
--- /dev/null
+++ b/src/threed/painting/qglpainter.cpp
@@ -0,0 +1,2305 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglpainter.h"
+#include "qglpainter_p.h"
+#include "qglabstracteffect.h"
+#include "qglext_p.h"
+#include <QtOpenGL/qglpixelbuffer.h>
+#include <QtOpenGL/qglshaderprogram.h>
+#include <QtOpenGL/qglframebufferobject.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpaintengine.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qmap.h>
+#if !defined(QT_NO_THREAD)
+#include <QtCore/qthreadstorage.h>
+#endif
+#include "qglflatcoloreffect_p.h"
+#include "qglflattextureeffect_p.h"
+#include "qgllitmaterialeffect_p.h"
+#include "qgllittextureeffect_p.h"
+#include "qglpickcolors_p.h"
+#include "qgltexture2d.h"
+#include "qgltexturecube.h"
+#include "qgeometrydata.h"
+#include "qglvertexbundle_p.h"
+#include "qmatrix4x4stack_p.h"
+#include "qglwidgetsurface.h"
+#include "qglpixelbuffersurface.h"
+#include "qglpaintersurface_p.h"
+
+#undef glActiveTexture
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLPainter
+ \brief The QGLPainter class provides portable API's for rendering into a GL context.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+
+ TBD - lots of TBD
+
+ All QGLPainter instances on a context share the same context state:
+ matrices, effects, vertex attributes, etc. For example, calling
+ ortho() on one QGLPainter instance for a context will alter the
+ projectionMatrix() as seen by the other QGLPainter instances.
+*/
+
+/*!
+ \enum QGLPainter::Update
+ This enum defines the values that were changed since the last QGLPainter::update().
+
+ \value UpdateColor The color has been updated.
+ \value UpdateModelViewMatrix The modelview matrix has been updated.
+ \value UpdateProjectionMatrix The projection matrix has been updated.
+ \value UpdateMatrices The combination of UpdateModelViewMatrix and
+ UpdateProjectionMatrix.
+ \value UpdateLights The lights have been updated.
+ \value UpdateMaterials The material parameters have been updated.
+ \value UpdateViewport The viewport needs to be updated because the
+ drawing surface has changed.
+ \value UpdateAll All values have been updated. This is specified
+ when an effect is activated.
+*/
+
+#define QGLPAINTER_CHECK_PRIVATE() \
+ Q_ASSERT_X(d, "QGLPainter", "begin() has not been called or it failed")
+
+QGLPainterPrivate::QGLPainterPrivate()
+ : ref(1),
+ eye(QGL::NoEye),
+ lightModel(0),
+ defaultLightModel(0),
+ defaultLight(0),
+ frontMaterial(0),
+ backMaterial(0),
+ defaultMaterial(0),
+ frontColorMaterial(0),
+ backColorMaterial(0),
+ viewingCube(QVector3D(-1, -1, -1), QVector3D(1, 1, 1)),
+ color(255, 255, 255, 255),
+ updates(QGLPainter::UpdateAll),
+ pick(0),
+ boundVertexBuffer(0),
+ boundIndexBuffer(0),
+ renderSequencer(0),
+ isFixedFunction(true) // Updated by QGLPainter::begin()
+{
+ context = 0;
+ effect = 0;
+ userEffect = 0;
+ standardEffect = QGL::FlatColor;
+ memset(stdeffects, 0, sizeof(stdeffects));
+}
+
+QGLPainterPrivate::~QGLPainterPrivate()
+{
+ delete defaultLightModel;
+ delete defaultLight;
+ delete defaultMaterial;
+ delete frontColorMaterial;
+ delete backColorMaterial;
+ for (int effect = 0; effect < QGL_MAX_STD_EFFECTS; ++effect)
+ delete stdeffects[effect];
+ delete pick;
+ qDeleteAll(cachedPrograms);
+ delete renderSequencer;
+}
+
+QGLPainterPickPrivate::QGLPainterPickPrivate()
+{
+ isPicking = false;
+ objectPickId = -1;
+ pickColorIndex = -1;
+ pickColor = 0;
+ defaultPickEffect = new QGLFlatColorEffect();
+}
+
+QGLPainterPickPrivate::~QGLPainterPickPrivate()
+{
+ delete defaultPickEffect;
+}
+
+#if !defined(QT_NO_THREAD)
+
+// QGLContext's are thread-specific, so QGLPainterPrivateCache should be too.
+
+typedef QThreadStorage<QGLPainterPrivateCache *> QGLPainterPrivateStorage;
+Q_GLOBAL_STATIC(QGLPainterPrivateStorage, painterPrivateStorage)
+static QGLPainterPrivateCache *painterPrivateCache()
+{
+ QGLPainterPrivateCache *cache = painterPrivateStorage()->localData();
+ if (!cache) {
+ cache = new QGLPainterPrivateCache();
+ painterPrivateStorage()->setLocalData(cache);
+ }
+ return cache;
+}
+
+#else
+
+Q_GLOBAL_STATIC(QGLPainterPrivateCache, painterPrivateCache)
+
+#endif
+
+QGLPainterPrivateCache::QGLPainterPrivateCache()
+{
+ connect(QGLSignalProxy::instance(),
+ SIGNAL(aboutToDestroyContext(const QGLContext *)),
+ this,
+ SLOT(contextDestroyed(const QGLContext *)));
+}
+
+QGLPainterPrivateCache::~QGLPainterPrivateCache()
+{
+}
+
+QGLPainterPrivate *QGLPainterPrivateCache::fromContext
+ (const QGLContext *context)
+{
+ QGLPainterPrivate *priv = cache.value(context, 0);
+ if (priv)
+ return priv;
+ priv = new QGLPainterPrivate();
+ priv->context = context;
+ cache.insert(context, priv);
+ return priv;
+}
+
+QGLPainterPrivateCache *QGLPainterPrivateCache::instance()
+{
+ return painterPrivateCache();
+}
+
+void QGLPainterPrivateCache::contextDestroyed(const QGLContext *context)
+{
+ QGLPainterPrivate *priv = cache.value(context, 0);
+ if (priv) {
+ priv->context = 0;
+ cache.remove(context);
+ if (!priv->ref.deref())
+ delete priv;
+ }
+ emit destroyedContext(context);
+}
+
+/*!
+ Constructs a new GL painter. Call begin() to attach the
+ painter to a GL context.
+
+ \sa begin()
+*/
+QGLPainter::QGLPainter()
+ : d_ptr(0)
+{
+}
+
+/*!
+ Constructs a new GL painter and attaches it to \a context.
+ It is not necessary to call begin() after construction.
+
+ \sa begin()
+*/
+QGLPainter::QGLPainter(const QGLContext *context)
+ : d_ptr(0)
+{
+ begin(context);
+}
+
+/*!
+ Constructs a new GL painter and attaches it to the GL
+ context associated with \a widget. It is not necessary to
+ call begin() after construction.
+
+ \sa begin(), isActive()
+*/
+QGLPainter::QGLPainter(QGLWidget *widget)
+ : d_ptr(0)
+{
+ begin(widget);
+}
+
+/*!
+ Constructs a new GL painter and attaches it to the GL context associated
+ with \a painter. It is assumed that \a painter is the currently
+ active painter and that it is associated with the current GL context.
+
+ If \a painter is not using an OpenGL paint engine, then isActive()
+ will return false; true otherwise.
+
+ This constructor is typically used when mixing regular Qt painting
+ operations and GL painting operations on a widget that is being
+ drawn using the OpenGL graphics system.
+
+ \sa begin(), isActive()
+*/
+QGLPainter::QGLPainter(QPainter *painter)
+ : d_ptr(0)
+{
+ begin(painter);
+}
+
+/*!
+ Constructs a new GL painter and attaches it to the GL context associated
+ with \a surface.
+
+ \sa begin(), isActive()
+*/
+QGLPainter::QGLPainter(QGLAbstractSurface *surface)
+ : d_ptr(0)
+{
+ begin(surface);
+}
+
+/*!
+ Destroys this GL painter.
+*/
+QGLPainter::~QGLPainter()
+{
+ end();
+}
+
+/*!
+ Begins painting on QGLContext::currentContext(). Returns false
+ if there is no GL context current.
+
+ \sa end()
+*/
+bool QGLPainter::begin()
+{
+ return begin(QGLContext::currentContext());
+}
+
+/*!
+ Begins painting on \a context. If painting was already in progress,
+ then this function will call end() first. The \a context will be
+ made current if it is not already current.
+
+ Returns true if painting can begin; false otherwise.
+
+ All QGLPainter instances on a context share the same context state:
+ matrices, the effect(), vertex attributes, etc. For example,
+ calling ortho() on one QGLPainter instance for a context will
+ alter the projectionMatrix() as seen by the other QGLPainter instances.
+
+ \sa end(), isActive()
+*/
+bool QGLPainter::begin(const QGLContext *context)
+{
+ if (!context)
+ return false;
+ end();
+ return begin(context, QGLAbstractSurface::createSurfaceForContext(context));
+}
+
+/*!
+ \internal
+*/
+bool QGLPainter::begin
+ (const QGLContext *context, QGLAbstractSurface *surface,
+ bool destroySurface)
+{
+ // If we don't have a context specified, then use the one
+ // that the surface just made current.
+ if (!context)
+ context = QGLContext::currentContext();
+
+ // Find the QGLPainterPrivate for the context, or create a new one.
+ d_ptr = painterPrivateCache()->fromContext(context);
+ d_ptr->ref.ref();
+ if (d_ptr->renderSequencer)
+ {
+ d_ptr->renderSequencer->reset();
+ d_ptr->renderSequencer->setPainter(this);
+ }
+
+ // Activate the main surface for the context.
+ QGLAbstractSurface *prevSurface;
+ if (d_ptr->surfaceStack.isEmpty()) {
+ prevSurface = 0;
+ } else {
+ // We are starting a nested begin()/end() scope, so switch
+ // to the new main surface rather than activate from scratch.
+ prevSurface = d_ptr->surfaceStack.last().surface;
+ prevSurface->deactivate(surface);
+ }
+ if (!surface->activate(prevSurface)) {
+ if (prevSurface)
+ prevSurface->activate(surface);
+ if (destroySurface)
+ delete surface;
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+ d_ptr = 0;
+ return false;
+ }
+
+ // Push a main surface descriptor onto the surface stack.
+ QGLPainterSurfaceInfo psurf;
+ psurf.surface = surface;
+ psurf.destroySurface = destroySurface;
+ psurf.mainSurface = true;
+ d_ptr->surfaceStack.append(psurf);
+
+ // Force the matrices to be updated the first time we use them.
+ d_ptr->modelViewMatrix.setDirty(true);
+ d_ptr->projectionMatrix.setDirty(true);
+
+ // Initialize the QOpenGLFunctions parent class.
+ initializeGLFunctions(context);
+
+ // Determine if the OpenGL implementation is fixed-function or not.
+ d_ptr->isFixedFunction = !hasOpenGLFeature(QOpenGLFunctions::Shaders);
+ return true;
+}
+
+/*!
+ Begins painting on the GL context associated with \a widget.
+ Returns false if \a widget is null.
+
+ \sa end()
+*/
+bool QGLPainter::begin(QGLWidget *widget)
+{
+ if (!widget)
+ return false;
+ end();
+ return begin(widget->context(), new QGLWidgetSurface(widget));
+}
+
+/*!
+ Begins painting on the GL context associated with \a painter.
+ Returns false if \a painter is not using an OpenGL paint engine.
+ It is assumed that \a painter is the currently active painter
+ and that it is associated with the current GL context.
+
+ This function is typically used when mixing regular Qt painting
+ operations and GL painting operations on a widget that is being
+ drawn using the OpenGL graphics system.
+
+ \sa end()
+*/
+bool QGLPainter::begin(QPainter *painter)
+{
+ // Validate that the painting is OpenGL-based.
+ if (!painter)
+ return false;
+ QPaintEngine *engine = painter->paintEngine();
+ if (!engine)
+ return false;
+ if (engine->type() != QPaintEngine::OpenGL &&
+ engine->type() != QPaintEngine::OpenGL2)
+ return false;
+
+ // Begin GL painting operations.
+ return begin(0, new QGLPainterSurface(painter));
+}
+
+/*!
+ Begins painting to \a surface. Returns false if \a surface is
+ null or could not be activated.
+
+ \sa end(), QGLAbstractSurface::activate()
+*/
+bool QGLPainter::begin(QGLAbstractSurface *surface)
+{
+ if (!surface)
+ return false;
+ end();
+ return begin(0, surface, false);
+}
+
+/*!
+ Ends GL painting. Returns true if painting was ended successfully;
+ false if this painter was not bound to a GL context.
+
+ The GL context that was bound to this painter will not have
+ QGLContext::doneCurrent() called on it. It is the responsibility
+ of the caller to terminate context operations.
+
+ The effect() will be left active in the GL context and will be
+ assumed to still be active the next time begin() is called.
+ If this assumption doesn't apply, then call disableEffect()
+ to disable the effect before calling end().
+
+ This function will pop all surfaces from the surface stack,
+ and return currentSurface() to null (the default drawing surface).
+
+ \sa begin(), isActive(), disableEffect()
+*/
+bool QGLPainter::end()
+{
+ Q_D(QGLPainter);
+ if (!d)
+ return false;
+
+ // Unbind the current vertex and index buffers.
+ if (d->boundVertexBuffer) {
+ QGLBuffer::release(QGLBuffer::VertexBuffer);
+ d->boundVertexBuffer = 0;
+ }
+ if (d->boundIndexBuffer) {
+ QGLBuffer::release(QGLBuffer::IndexBuffer);
+ d->boundIndexBuffer = 0;
+ }
+
+ // Pop surfaces from the surface stack until we reach a
+ // main surface. Then deactivate the main surface.
+ int size = d->surfaceStack.size();
+ while (size > 0) {
+ --size;
+ QGLPainterSurfaceInfo &surf = d->surfaceStack[size];
+ if (surf.mainSurface) {
+ if (size > 0) {
+ // There are still other surfaces on the stack, probably
+ // because we are within a nested begin()/end() scope.
+ // Re-activate the next surface down in the outer scope.
+ QGLPainterSurfaceInfo &nextSurf = d->surfaceStack[size - 1];
+ surf.surface->switchTo(nextSurf.surface);
+ } else {
+ // Last surface on the stack, so deactivate it permanently.
+ surf.surface->deactivate();
+ }
+ if (surf.destroySurface)
+ delete surf.surface;
+ break;
+ } else if (size > 0) {
+ surf.surface->deactivate(d->surfaceStack[size - 1].surface);
+ }
+ }
+ d->surfaceStack.resize(size);
+
+ // Force a viewport update if we are within a nested begin()/end().
+ d->updates |= UpdateViewport;
+
+ // Destroy the QGLPainterPrivate if this is the last reference.
+ if (!d->ref.deref())
+ delete d;
+ d_ptr = 0;
+ return true;
+}
+
+/*!
+ Returns true if this painter is currently bound to a GL context;
+ false otherwise.
+
+ \sa begin(), end()
+*/
+bool QGLPainter::isActive() const
+{
+ return (d_ptr != 0 && d_ptr->context != 0);
+}
+
+/*!
+ Returns the GL context that is bound to this painter, or null
+ if it is not currently bound.
+*/
+const QGLContext *QGLPainter::context() const
+{
+ if (d_ptr)
+ return d_ptr->context;
+ else
+ return 0;
+}
+
+/*!
+ Returns true if the underlying OpenGL implementation is OpenGL 1.x
+ or OpenGL/ES 1.x and only supports fixed-function OpenGL operations.
+ Returns false if the underlying OpenGL implementation is using
+ GLSL or GLSL/ES shaders.
+
+ If this function returns false, then the built-in effects will
+ use shaders and QGLPainter will not update the fixed-function
+ matrices in the OpenGL context when update() is called.
+ User-supplied effects will need to use shaders also or update
+ the fixed-function matrices themselves or call updateFixedFunction().
+
+ \sa update(), updateFixedFunction()
+*/
+bool QGLPainter::isFixedFunction() const
+{
+#if defined(QT_OPENGL_ES_2)
+ return false;
+#else
+ Q_D(const QGLPainter);
+ if (d)
+ return d->isFixedFunction;
+ else
+ return true;
+#endif
+}
+
+/*!
+ Sets the \a color to use to clear the color buffer when \c{glClear()}
+ is called.
+*/
+void QGLPainter::setClearColor(const QColor& color)
+{
+ glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
+}
+
+/*!
+ Sets the scissor \a rect for the current drawing surface
+ to use when \c{GL_SCISSOR_TEST} is enabled. If \a rect is empty,
+ then the scissor will be set to clip away all drawing.
+
+ Note that \a rect is in Qt co-ordinates with the origin
+ at the top-left of the drawing surface's viewport rectangle.
+ If the currentSurface() is an instance of QGLSubsurface,
+ then \a rect will be adjusted relative to the subsurface's position.
+
+ \sa currentSurface(), QGLAbstractSurface::viewportGL()
+*/
+void QGLPainter::setScissor(const QRect& rect)
+{
+ if (!rect.isEmpty()) {
+ // Adjust the rectangle by the position of the surface viewport.
+ QGLAbstractSurface *surface = currentSurface();
+ QRect viewport = surface->viewportGL();
+ QRect r(viewport.x() + rect.x(),
+ viewport.y() + viewport.height() - (rect.y() + rect.height()),
+ rect.width(), rect.height());
+ if (!r.isEmpty())
+ glScissor(r.x(), r.y(), r.width(), r.height());
+ else
+ glScissor(0, 0, 0, 0);
+ } else {
+ glScissor(0, 0, 0, 0);
+ }
+}
+
+/*!
+ Returns a reference to the projection matrix stack.
+
+ It is recommended that setCamera() be used to set the projection
+ matrix at the beginning of a scene rendering pass so that the
+ eye position can be adjusted for stereo.
+
+ \sa modelViewMatrix(), combinedMatrix(), setCamera()
+*/
+QMatrix4x4Stack& QGLPainter::projectionMatrix()
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->projectionMatrix;
+}
+
+/*!
+ Returns a reference to the modelview matrix stack.
+
+ \sa projectionMatrix(), combinedMatrix(), normalMatrix(), setCamera()
+ \sa worldMatrix()
+*/
+QMatrix4x4Stack& QGLPainter::modelViewMatrix()
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->modelViewMatrix;
+}
+
+/*!
+ \fn QMatrix4x4 QGLPainter::combinedMatrix() const
+
+ Returns the result of multiplying the projectionMatrix()
+ and the modelViewMatrix(). This combined matrix value is
+ useful for setting uniform matrix values on shader programs.
+
+ Calling this function is more efficient than calling
+ projectionMatrix() and modelViewMatrix() separately and
+ multiplying the return values.
+
+ \sa projectionMatrix(), modelViewMatrix(), normalMatrix()
+*/
+QMatrix4x4 QGLPainter::combinedMatrix() const
+{
+ const QGLPainterPrivate *d = d_func();
+ if (!d)
+ return QMatrix4x4();
+ const QMatrix4x4StackPrivate *proj = d->projectionMatrix.d_func();
+ const QMatrix4x4StackPrivate *mv = d->modelViewMatrix.d_func();
+ return proj->matrix * mv->matrix;
+}
+
+// Inverting the eye transformation will often result in values like
+// 1.5e-15 in the world matrix. Clamp these to zero to make worldMatrix()
+// more stable when removing the eye component of the modelViewMatrix().
+static inline qreal qt_gl_stablize_value(qreal value)
+{
+ return (qAbs(value) >= 0.00001f) ? value : 0.0f;
+}
+static inline QMatrix4x4 qt_gl_stablize_matrix(const QMatrix4x4 &m)
+{
+ return QMatrix4x4(qt_gl_stablize_value(m(0, 0)),
+ qt_gl_stablize_value(m(0, 1)),
+ qt_gl_stablize_value(m(0, 2)),
+ qt_gl_stablize_value(m(0, 3)),
+ qt_gl_stablize_value(m(1, 0)),
+ qt_gl_stablize_value(m(1, 1)),
+ qt_gl_stablize_value(m(1, 2)),
+ qt_gl_stablize_value(m(1, 3)),
+ qt_gl_stablize_value(m(2, 0)),
+ qt_gl_stablize_value(m(2, 1)),
+ qt_gl_stablize_value(m(2, 2)),
+ qt_gl_stablize_value(m(2, 3)),
+ qt_gl_stablize_value(m(3, 0)),
+ qt_gl_stablize_value(m(3, 1)),
+ qt_gl_stablize_value(m(3, 2)),
+ qt_gl_stablize_value(m(3, 3)));
+}
+
+/*!
+ Returns the world matrix, which is the modelViewMatrix() without
+ the eye transformation that was set in the previous call to
+ setCamera().
+
+ In the following example, the \c{world} variable will be set to the
+ translation and scale component of the modelview transformation,
+ without the "look at" component from the camera:
+
+ \code
+ painter.setCamera(camera);
+ painter.modelViewMatrix().translate(0.0f, 5.0f, 0.0f);
+ painter.modelViewMatrix().scale(1.5f);
+ QMatrix4x4 world = painter.worldMatrix();
+ \endcode
+
+ Note: the world matrix is determined by multiplying the inverse of
+ the camera's look at component with the current modelview matrix.
+ Thus, the result may not be precisely the same as constructing a
+ matrix from translate and scale operations starting with the identity.
+
+ \sa modelViewMatrix(), setCamera()
+*/
+QMatrix4x4 QGLPainter::worldMatrix() const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return qt_gl_stablize_matrix
+ (d->inverseEyeMatrix * d->modelViewMatrix.top());
+}
+
+/*!
+ \fn QMatrix3x3 QGLPainter::normalMatrix() const
+
+ Returns the normal matrix corresponding to modelViewMatrix().
+
+ The normal matrix is the transpose of the inverse of the top-left
+ 3x3 part of the 4x4 modelview matrix. If the 3x3 sub-matrix is not
+ invertible, this function returns the identity.
+
+ \sa modelViewMatrix(), combinedMatrix()
+*/
+QMatrix3x3 QGLPainter::normalMatrix() const
+{
+ const QGLPainterPrivate *d = d_func();
+ if (!d)
+ return QMatrix3x3();
+ const QMatrix4x4StackPrivate *mv = d->modelViewMatrix.d_func();
+ return mv->matrix.normalMatrix();
+}
+
+/*!
+ Returns the camera eye that is currently being used for stereo
+ rendering. The default is QGL::NoEye.
+
+ The eye is used to adjust the camera position by a small amount
+ when setCamera() is called.
+
+ \sa setEye(), setCamera()
+*/
+QGL::Eye QGLPainter::eye() const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->eye;
+}
+
+/*!
+ Sets the camera \a eye that is currently being used for stereo
+ rendering.
+
+ The \a eye is used to adjust the camera position by a small amount
+ when setCamera() is called.
+
+ \sa eye(), setCamera()
+*/
+void QGLPainter::setEye(QGL::Eye eye)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->eye = eye;
+}
+
+/*!
+ Sets the modelViewMatrix() and projectionMatrix() to the view
+ defined by \a camera. If eye() is not QGL::NoEye, then the view
+ will be adjusted for the camera's eye separation.
+
+ This function is typically called at the beginning of a scene rendering
+ pass to initialize the modelview and projection matrices.
+
+ \sa eye(), modelViewMatrix(), projectionMatrix(), worldMatrix()
+*/
+void QGLPainter::setCamera(const QGLCamera *camera)
+{
+ Q_ASSERT(camera);
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ QMatrix4x4 lookAt = camera->modelViewMatrix(d->eye);
+ d->modelViewMatrix = lookAt;
+ d->projectionMatrix = camera->projectionMatrix(aspectRatio());
+ d->inverseEyeMatrix = lookAt.inverted();
+}
+
+/*!
+ Returns true if \a point is outside the current viewing volume.
+ This is used to perform object culling checks.
+*/
+bool QGLPainter::isCullable(const QVector3D& point) const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ QVector3D projected = d->modelViewMatrix * point;
+ projected = d->projectionMatrix * projected;
+ return !d->viewingCube.contains(projected);
+}
+
+/*!
+ Returns true if \a box is completely outside the current viewing volume.
+ This is used to perform object culling checks.
+*/
+bool QGLPainter::isCullable(const QBox3D& box) const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ QBox3D projected = box.transformed(d->modelViewMatrix);
+ if (projected.minimum().z() >= 0.0f || projected.maximum().z() >= 0.0f) {
+ // The box crosses the eye line in the view. Don't do the
+ // projection or the math will go all strange with a
+ // perspective projection. Just assume that it is cullable
+ // if it passes the eye line, and hence is definitely outside
+ // the viewing volume. Note that it is possible that the box is
+ // half in front of the eye and half behind, which we handle now
+ // by truncating the box at the eye plane.
+ //
+ // If the projection is orthographic, we don't need to do this.
+ // Orthographic projections have the last row set to (0, 0, 0, 1).
+ QMatrix4x4 *proj = &(d->projectionMatrix.d_ptr->matrix);
+ if ((*proj)(3, 0) != 0.0f || (*proj)(3, 1) != 0.0f ||
+ (*proj)(3, 2) != 0.0f || (*proj)(3, 3) != 1.0f) {
+ if (projected.minimum().z() >= 0.0f)
+ return true;
+ projected.setExtents(projected.minimum(),
+ QVector3D(projected.maximum().x(),
+ projected.maximum().y(), 0.0f));
+ }
+ }
+ projected.transform(d->projectionMatrix);
+ return !d->viewingCube.intersects(projected);
+}
+
+/*!
+ Returns the current render order sequencer.
+
+ \sa QGLRenderSequencer
+*/
+QGLRenderSequencer *QGLPainter::renderSequencer()
+{
+ Q_D(QGLPainter);
+ if (!d->renderSequencer)
+ d->renderSequencer = new QGLRenderSequencer(this);
+ return d->renderSequencer;
+}
+
+/*!
+ Returns the aspect ratio of the viewport for adjusting projection
+ transformations.
+*/
+qreal QGLPainter::aspectRatio() const
+{
+ return currentSurface()->aspectRatio();
+}
+
+/*!
+ Returns the current effect that is in use, which is userEffect()
+ if it is not null, or the effect object associated with
+ standardEffect() otherwise.
+
+ If isPicking() is true, then this will return the effect object
+ that is being used to generate pick colors.
+
+ \sa userEffect(), standardEffect(), isPicking()
+*/
+QGLAbstractEffect *QGLPainter::effect() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->ensureEffect(const_cast<QGLPainter *>(this));
+ return d->effect;
+}
+
+/*!
+ Returns the user-defined effect that is being used for drawing
+ operations, or null if standardEffect() is in use.
+
+ \sa setUserEffect(), standardEffect(), effect()
+*/
+QGLAbstractEffect *QGLPainter::userEffect() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->userEffect;
+}
+
+/*!
+ Sets a user-defined \a effect to use for drawing operations
+ in the current GL context. If \a effect is null, this will
+ disable user-defined effects and return to using standardEffect().
+
+ \sa effect(), draw(), setStandardEffect()
+*/
+void QGLPainter::setUserEffect(QGLAbstractEffect *effect)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->userEffect == effect)
+ return;
+ if (d->effect)
+ d->effect->setActive(this, false);
+ d->userEffect = effect;
+ if (effect && (!d->pick || !d->pick->isPicking)) {
+ d->effect = effect;
+ d->effect->setActive(this, true);
+ d->updates = UpdateAll;
+ } else {
+ // Revert to the effect associated with standardEffect().
+ d->effect = 0;
+ d->ensureEffect(this);
+ }
+}
+
+/*!
+ Returns the standard effect to use for rendering fragments in
+ the current GL context when userEffect() is null.
+
+ \sa setStandardEffect(), userEffect()
+*/
+QGL::StandardEffect QGLPainter::standardEffect() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->standardEffect;
+}
+
+/*!
+ Sets a standard \a effect to use for rendering fragments
+ in the current GL context. This will also set userEffect()
+ to null. If \a effect is an invalid value, then the behavior
+ of QGL::FlatColor will be used instead.
+
+ \sa standardEffect(), setUserEffect()
+*/
+void QGLPainter::setStandardEffect(QGL::StandardEffect effect)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->standardEffect == effect && d->effect && d->userEffect == 0)
+ return;
+ if (d->effect)
+ d->effect->setActive(this, false);
+ d->standardEffect = effect;
+ d->userEffect = 0;
+ d->effect = 0;
+ d->ensureEffect(this);
+}
+
+/*!
+ Disables the current effect and sets userEffect() to null.
+ Unlike setUserEffect() this not activate the standardEffect()
+ until the next time effect() is called.
+
+ This function can be used to disable all effect-based drawing
+ operations prior to performing raw GL calls. The next time
+ effect() is called on this QGLPainter, the standardEffect()
+ will be reactivated. An effect can also be reactivated by
+ calling setUserEffect() or setStandardEffect().
+
+ \sa userEffect(), standardEffect()
+*/
+void QGLPainter::disableEffect()
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->effect)
+ d->effect->setActive(this, false);
+ d->userEffect = 0;
+ d->effect = 0;
+}
+
+/*!
+ Returns the cached shader program associated with \a name; or null
+ if \a name is not currently associated with a shader program.
+
+ \sa setCachedProgram()
+*/
+QGLShaderProgram *QGLPainter::cachedProgram(const QString& name) const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->cachedPrograms.value(name, 0);
+}
+
+/*!
+ Sets the cached shader \a program associated with \a name.
+
+ Effect objects can use this function to store pre-compiled
+ and pre-linked shader programs in the painter for future
+ use by the same effect. The \a program will be destroyed
+ when context() is destroyed.
+
+ If \a program is null, then the program associated with \a name
+ will be destroyed. If \a name is already present as a cached
+ program, then it will be replaced with \a program.
+
+ Names that start with "\c{qt.}" are reserved for use by Qt's
+ internal effects.
+
+ \sa cachedProgram()
+*/
+void QGLPainter::setCachedProgram
+ (const QString& name, QGLShaderProgram *program)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ QGLShaderProgram *current = d->cachedPrograms.value(name, 0);
+ if (current != program) {
+ if (program)
+ d->cachedPrograms[name] = program;
+ else
+ d->cachedPrograms.remove(name);
+ delete current;
+ }
+}
+
+void QGLPainterPrivate::createEffect(QGLPainter *painter)
+{
+ if (userEffect) {
+ if (!pick || !pick->isPicking) {
+ effect = userEffect;
+ effect->setActive(painter, true);
+ updates = QGLPainter::UpdateAll;
+ return;
+ }
+ if (userEffect->supportsPicking()) {
+ effect = userEffect;
+ effect->setActive(painter, true);
+ updates = QGLPainter::UpdateAll;
+ return;
+ }
+ effect = pick->defaultPickEffect;
+ effect->setActive(painter, true);
+ updates = QGLPainter::UpdateAll;
+ return;
+ }
+ if (uint(standardEffect) >= QGL_MAX_STD_EFFECTS)
+ effect = stdeffects[int(QGL::FlatColor)];
+ else
+ effect = stdeffects[int(standardEffect)];
+ if (!effect) {
+ switch (standardEffect) {
+ case QGL::FlatColor: default:
+ effect = new QGLFlatColorEffect();
+ break;
+ case QGL::FlatPerVertexColor:
+ effect = new QGLPerVertexColorEffect();
+ break;
+ case QGL::FlatReplaceTexture2D:
+ effect = new QGLFlatTextureEffect();
+ break;
+ case QGL::FlatDecalTexture2D:
+ effect = new QGLFlatDecalTextureEffect();
+ break;
+ case QGL::LitMaterial:
+ effect = new QGLLitMaterialEffect();
+ break;
+ case QGL::LitDecalTexture2D:
+ effect = new QGLLitDecalTextureEffect();
+ break;
+ case QGL::LitModulateTexture2D:
+ effect = new QGLLitModulateTextureEffect();
+ break;
+ }
+ if (uint(standardEffect) >= QGL_MAX_STD_EFFECTS)
+ stdeffects[int(QGL::FlatColor)] = effect;
+ else
+ stdeffects[int(standardEffect)] = effect;
+ }
+ if (!pick || !pick->isPicking || effect->supportsPicking()) {
+ effect->setActive(painter, true);
+ } else {
+ effect = pick->defaultPickEffect;
+ effect->setActive(painter, true);
+ }
+ updates = QGLPainter::UpdateAll;
+}
+
+/*!
+ Returns the last color that was set with setColor(). The default
+ value is (1, 1, 1, 1).
+
+ \sa setColor()
+*/
+QColor QGLPainter::color() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->color;
+}
+
+/*!
+ Sets the default fragment \a color for effects associated
+ with this painter. This function does not apply the color
+ to the effect until update() is called.
+
+ \sa color(), update()
+*/
+void QGLPainter::setColor(const QColor& color)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->color = color;
+ d->updates |= UpdateColor;
+}
+
+static void qt_gl_setVertexAttribute(QGL::VertexAttribute attribute, const QGLAttributeValue& value)
+{
+#if !defined(QT_OPENGL_ES_2)
+ switch (attribute) {
+ case QGL::Position:
+ glVertexPointer(value.tupleSize(), value.type(),
+ value.stride(), value.data());
+ break;
+
+ case QGL::Normal:
+ if (value.tupleSize() == 3)
+ glNormalPointer(value.type(), value.stride(), value.data());
+ break;
+
+ case QGL::Color:
+ glColorPointer(value.tupleSize(), value.type(),
+ value.stride(), value.data());
+ break;
+
+#ifdef GL_TEXTURE_COORD_ARRAY
+ case QGL::TextureCoord0:
+ case QGL::TextureCoord1:
+ case QGL::TextureCoord2:
+ {
+ int unit = (int)(attribute - QGL::TextureCoord0);
+ qt_gl_ClientActiveTexture(GL_TEXTURE0 + unit);
+ glTexCoordPointer(value.tupleSize(), value.type(),
+ value.stride(), value.data());
+ if (unit != 0) // Stay on unit 0 between requests.
+ qt_gl_ClientActiveTexture(GL_TEXTURE0);
+ }
+ break;
+#endif
+
+ default: break;
+ }
+#else
+ Q_UNUSED(attribute);
+ Q_UNUSED(value);
+#endif
+}
+
+/*!
+ Returns the set of vertex attributes that have been set on the
+ painter state by setVertexAttribute() and setVertexBundle()
+ since the last call to clearAttributes().
+
+ The most common use for this function is to determine if specific
+ attributes have been supplied on the painter so as to adjust the
+ current drawing effect accordingly. The following example will
+ use a lit texture effect if texture co-ordinates were provided
+ in the vertex bundle, or a simple lit material effect if
+ texture co-ordinates were not provided:
+
+ \code
+ painter.clearAttributes();
+ painter.setVertexBundle(bundle);
+ if (painter.attributes().contains(QGL::TextureCoord0))
+ painter.setStandardEffect(QGL::LitModulateTexture2D);
+ else
+ painter.setStandardEffect(QGL::LitMaterial);
+ \endcode
+
+ It is important to clear the attributes before setting the vertex
+ bundle, so that attributes from a previous bundle will not leak
+ through. Multiple vertex bundles may be supplied if they contain
+ different parts of the same logical piece of geometry.
+
+ \sa clearAttributes(), setVertexBundle()
+*/
+QGLAttributeSet QGLPainter::attributes() const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->attributeSet;
+}
+
+/*!
+ Clears the set of vertex attributes that have been set on the
+ painter state by setVertexAttribute() and setVertexBundle().
+ See the documentation for attributes() for more information.
+
+ \sa attributes()
+*/
+void QGLPainter::clearAttributes()
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->attributeSet.clear();
+}
+
+/*!
+ Sets a vertex \a attribute on the current GL context to \a value.
+
+ The vertex attribute is bound to the GL state on the index
+ corresponding to \a attribute. For example, QGL::Position
+ will be bound to index 0, QGL::TextureCoord0 will be bound
+ to index 3, etc.
+
+ Vertex attributes are independent of the effect() and can be
+ bound once and then used with multiple effects.
+
+ If this is the first attribute in a new piece of geometry,
+ it is recommended that clearAttributes() be called before this
+ function. This will inform QGLPainter that a new piece of geometry
+ is being provided and that the previous geometry is now invalid.
+ See the documentation for attributes() for more information.
+
+ \sa setVertexBundle(), draw(), clearAttributes(), attributes()
+*/
+void QGLPainter::setVertexAttribute
+ (QGL::VertexAttribute attribute, const QGLAttributeValue& value)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->ensureEffect(this);
+ if (d->boundVertexBuffer) {
+ QGLBuffer::release(QGLBuffer::VertexBuffer);
+ d->boundVertexBuffer = 0;
+ }
+ if (d->isFixedFunction) {
+ qt_gl_setVertexAttribute(attribute, value);
+ } else {
+ glVertexAttribPointer(GLuint(attribute), value.tupleSize(),
+ value.type(), GL_TRUE,
+ value.stride(), value.data());
+ }
+ d->attributeSet.insert(attribute);
+}
+
+/*!
+ Sets the vertex attributes on the current GL context that are
+ stored in \a buffer.
+
+ The vertex attributes are bound to the GL state on the indexes
+ that are specified within \a buffer; QGL::Position will be
+ bound to index 0, QGL::TextureCoord0 will be bound to index 3, etc.
+
+ Vertex attributes are independent of the effect() and can be
+ bound once and then used with multiple effects.
+
+ It is recommended that clearAttributes() be called before this
+ function to inform QGLPainter that a new piece of geometry is
+ being provided and that the previous geometry is now invalid.
+ See the documentation for attributes() for more information.
+
+ \sa setVertexAttribute(), draw(), clearAttributes(), attributes()
+*/
+void QGLPainter::setVertexBundle(const QGLVertexBundle& buffer)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->ensureEffect(this);
+ QGLVertexBundlePrivate *bd = const_cast<QGLVertexBundlePrivate *>(buffer.d_func());
+ if (bd->buffer.isCreated()) {
+ GLuint id = bd->buffer.bufferId();
+ if (id != d->boundVertexBuffer) {
+ bd->buffer.bind();
+ d->boundVertexBuffer = id;
+ }
+ } else if (d->boundVertexBuffer) {
+ QGLBuffer::release(QGLBuffer::VertexBuffer);
+ d->boundVertexBuffer = 0;
+ }
+ for (int index = 0; index < bd->attributes.size(); ++index) {
+ QGLVertexBundleAttribute *attr = bd->attributes[index];
+ if (d->isFixedFunction) {
+ qt_gl_setVertexAttribute(attr->attribute, attr->value);
+ } else {
+ glVertexAttribPointer(GLuint(attr->attribute),
+ attr->value.tupleSize(),
+ attr->value.type(), GL_TRUE,
+ attr->value.stride(), attr->value.data());
+ }
+ }
+ d->attributeSet.unite(buffer.attributes());
+}
+
+/*!
+ Updates the projection matrix, modelview matrix, and lighting
+ conditions in the currently active effect() object by calling
+ QGLAbstractEffect::update(). Also updates \c{glViewport()}
+ to cover the currentSurface() if necessary.
+
+ Normally this function is called automatically by draw().
+ However, if the user wishes to use raw GL functions to draw fragments,
+ it will be necessary to explicitly call this function to ensure that
+ the matrix state and lighting conditions have been set on the
+ active effect().
+
+ Note that this function informs the effect that an update is needed.
+ It does not change the GL state itself, except for \c{glViewport()}.
+ In particular, the modelview and projection matrices in the
+ fixed-function pipeline are not changed unless the effect or
+ application calls updateFixedFunction().
+
+ \sa setUserEffect(), projectionMatrix(), modelViewMatrix()
+ \sa draw(), updateFixedFunction()
+*/
+void QGLPainter::update()
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->ensureEffect(this);
+ QGLPainter::Updates updates = d->updates;
+ d->updates = 0;
+ if (d->modelViewMatrix.isDirty()) {
+ updates |= UpdateModelViewMatrix;
+ d->modelViewMatrix.setDirty(false);
+ }
+ if (d->projectionMatrix.isDirty()) {
+ updates |= UpdateProjectionMatrix;
+ d->projectionMatrix.setDirty(false);
+ }
+ if ((updates & UpdateViewport) != 0) {
+ QRect viewport = currentSurface()->viewportGL();
+ glViewport(viewport.x(), viewport.y(),
+ viewport.width(), viewport.height());
+ }
+ if (updates != 0)
+ d->effect->update(this, updates);
+}
+
+#if !defined(QT_OPENGL_ES_2)
+
+static void setLight(int light, const QGLLightParameters *parameters,
+ const QMatrix4x4& transform)
+{
+ GLfloat params[4];
+
+ QColor color = parameters->ambientColor();
+ params[0] = color.redF();
+ params[1] = color.greenF();
+ params[2] = color.blueF();
+ params[3] = color.alphaF();
+ glLightfv(light, GL_AMBIENT, params);
+
+ color = parameters->diffuseColor();
+ params[0] = color.redF();
+ params[1] = color.greenF();
+ params[2] = color.blueF();
+ params[3] = color.alphaF();
+ glLightfv(light, GL_DIFFUSE, params);
+
+ color = parameters->specularColor();
+ params[0] = color.redF();
+ params[1] = color.greenF();
+ params[2] = color.blueF();
+ params[3] = color.alphaF();
+ glLightfv(light, GL_SPECULAR, params);
+
+ QVector4D vector = parameters->eyePosition(transform);
+ params[0] = vector.x();
+ params[1] = vector.y();
+ params[2] = vector.z();
+ params[3] = vector.w();
+ glLightfv(light, GL_POSITION, params);
+
+ QVector3D spotDirection = parameters->eyeSpotDirection(transform);
+ params[0] = spotDirection.x();
+ params[1] = spotDirection.y();
+ params[2] = spotDirection.z();
+ glLightfv(light, GL_SPOT_DIRECTION, params);
+
+ params[0] = parameters->spotExponent();
+ glLightfv(light, GL_SPOT_EXPONENT, params);
+
+ params[0] = parameters->spotAngle();
+ glLightfv(light, GL_SPOT_CUTOFF, params);
+
+ params[0] = parameters->constantAttenuation();
+ glLightfv(light, GL_CONSTANT_ATTENUATION, params);
+
+ params[0] = parameters->linearAttenuation();
+ glLightfv(light, GL_LINEAR_ATTENUATION, params);
+
+ params[0] = parameters->quadraticAttenuation();
+ glLightfv(light, GL_QUADRATIC_ATTENUATION, params);
+}
+
+static void setMaterial(int face, const QGLMaterial *parameters)
+{
+ GLfloat params[17];
+
+ QColor mcolor = parameters->ambientColor();
+ params[0] = mcolor.redF();
+ params[1] = mcolor.greenF();
+ params[2] = mcolor.blueF();
+ params[3] = mcolor.alphaF();
+
+ mcolor = parameters->diffuseColor();
+ params[4] = mcolor.redF();
+ params[5] = mcolor.greenF();
+ params[6] = mcolor.blueF();
+ params[7] = mcolor.alphaF();
+
+ mcolor = parameters->specularColor();
+ params[8] = mcolor.redF();
+ params[9] = mcolor.greenF();
+ params[10] = mcolor.blueF();
+ params[11] = mcolor.alphaF();
+
+ mcolor = parameters->emittedLight();
+ params[12] = mcolor.redF();
+ params[13] = mcolor.greenF();
+ params[14] = mcolor.blueF();
+ params[15] = mcolor.alphaF();
+
+ params[16] = parameters->shininess();
+
+ glMaterialfv(face, GL_AMBIENT, params);
+ glMaterialfv(face, GL_DIFFUSE, params + 4);
+ glMaterialfv(face, GL_SPECULAR, params + 8);
+ glMaterialfv(face, GL_EMISSION, params + 12);
+ glMaterialfv(face, GL_SHININESS, params + 16);
+}
+
+#endif // !QT_OPENGL_ES_2
+
+/*!
+ Updates the fixed-function pipeline with the current painting
+ state according to the flags in \a updates.
+
+ This function is intended for use by effects in their
+ QGLAbstractEffect::update() override if they are using the
+ fixed-function pipeline. It can also be used by user
+ applications if they need the QGLPainter state to be
+ set in the fixed-function pipeline.
+
+ If the OpenGL implementation does not have a fixed-function
+ pipeline, e.g. OpenGL/ES 2.0, this function does nothing.
+
+ \sa update()
+*/
+void QGLPainter::updateFixedFunction(QGLPainter::Updates updates)
+{
+#if defined(QT_OPENGL_ES_2)
+ Q_UNUSED(updates);
+#else
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if ((updates & QGLPainter::UpdateColor) != 0) {
+ QColor color;
+ if (isPicking())
+ color = pickColor();
+ else
+ color = this->color();
+ glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
+ }
+ if ((updates & QGLPainter::UpdateModelViewMatrix) != 0) {
+ const QMatrix4x4 &matrix = d->modelViewMatrix.top();
+ glMatrixMode(GL_MODELVIEW);
+ if (sizeof(qreal) == sizeof(GLfloat)) {
+ glLoadMatrixf(reinterpret_cast<const GLfloat *>
+ (matrix.constData()));
+ } else {
+ GLfloat mat[16];
+ const qreal *m = matrix.constData();
+ for (int index = 0; index < 16; ++index)
+ mat[index] = m[index];
+ glLoadMatrixf(mat);
+ }
+ }
+ if ((updates & QGLPainter::UpdateProjectionMatrix) != 0) {
+ const QMatrix4x4 &matrix = d->projectionMatrix.top();
+ glMatrixMode(GL_PROJECTION);
+ if (sizeof(qreal) == sizeof(GLfloat)) {
+ glLoadMatrixf(reinterpret_cast<const GLfloat *>
+ (matrix.constData()));
+ } else {
+ GLfloat mat[16];
+ const qreal *m = matrix.constData();
+ for (int index = 0; index < 16; ++index)
+ mat[index] = m[index];
+ glLoadMatrixf(mat);
+ }
+ }
+ if ((updates & QGLPainter::UpdateLights) != 0) {
+ // Save the current modelview matrix and load the identity.
+ // We need to apply the light in the modelview transformation
+ // that was active when the light was specified.
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ // Enable the main light.
+ const QGLLightParameters *params = mainLight();
+ setLight(GL_LIGHT0, params, mainLightTransform());
+
+ // Restore the previous modelview transformation.
+ glPopMatrix();
+
+ // Set up the light model parameters if at least one light is enabled.
+ const QGLLightModel *lightModel = this->lightModel();
+ GLfloat values[4];
+#ifdef GL_LIGHT_MODEL_TWO_SIDE
+ if (lightModel->model() == QGLLightModel::TwoSided)
+ values[0] = 1.0f;
+ else
+ values[0] = 0.0f;
+ glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, values);
+#endif
+#ifdef GL_LIGHT_MODEL_COLOR_CONTROL
+ if (lightModel->colorControl() == QGLLightModel::SeparateSpecularColor)
+ values[0] = GL_SEPARATE_SPECULAR_COLOR;
+ else
+ values[0] = GL_SINGLE_COLOR;
+ glLightModelfv(GL_LIGHT_MODEL_COLOR_CONTROL, values);
+#endif
+#ifdef GL_LIGHT_MODEL_LOCAL_VIEWER
+ if (lightModel->viewerPosition() == QGLLightModel::LocalViewer)
+ values[0] = 1.0f;
+ else
+ values[0] = 0.0f;
+ glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, values);
+#endif
+#ifdef GL_LIGHT_MODEL_AMBIENT
+ QColor color = lightModel->ambientSceneColor();
+ values[0] = color.redF();
+ values[1] = color.blueF();
+ values[2] = color.greenF();
+ values[3] = color.alphaF();
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, values);
+#endif
+ }
+ if ((updates & QGLPainter::UpdateMaterials) != 0) {
+ const QGLMaterial *frontMaterial = faceMaterial(QGL::FrontFaces);
+ const QGLMaterial *backMaterial = faceMaterial(QGL::BackFaces);
+ if (frontMaterial == backMaterial) {
+ setMaterial(GL_FRONT_AND_BACK, frontMaterial);
+ } else {
+ setMaterial(GL_FRONT, frontMaterial);
+ setMaterial(GL_BACK, backMaterial);
+ }
+ }
+#endif
+}
+
+/*!
+ Draws primitives using \a count vertices from the arrays specified
+ by setVertexAttribute(). The type of primitive to draw is specified
+ by \a mode.
+
+ This operation will consume \a count values from the
+ enabled arrays, starting at \a index.
+
+ \sa update()
+*/
+void QGLPainter::draw(QGL::DrawingMode mode, int count, int index)
+{
+ update();
+ glDrawArrays((GLenum)mode, index, count);
+}
+
+/*!
+ \overload
+
+ Draws primitives using vertices from the arrays specified by
+ setVertexAttribute(). The type of primitive to draw is
+ specified by \a mode.
+
+ This operation will consume \a count elements of \a indices,
+ which are used to index into the enabled arrays.
+
+ \sa update()
+*/
+void QGLPainter::draw(QGL::DrawingMode mode, const ushort *indices, int count)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ update();
+ if (d->boundIndexBuffer) {
+ QGLBuffer::release(QGLBuffer::IndexBuffer);
+ d->boundIndexBuffer = 0;
+ }
+ glDrawElements(GLenum(mode), count, GL_UNSIGNED_SHORT, indices);
+}
+
+/*!
+ Pushes \a surface onto the surface stack and makes it the current
+ drawing surface for context(). If \a surface is null, then the
+ current drawing surface will be set to the main surface (e.g. the window).
+
+ Note: the \a surface object must remain valid until popped from
+ the stack or end() is called. All surfaces are popped from
+ the stack by end().
+
+ The UpdateViewport flag will be set to indicate that the
+ \c{glViewport()} should be adjusted to the extents of \a surface
+ when update() is next called.
+
+ \sa popSurface(), currentSurface(), setSurface()
+ \sa QGLAbstractSurface::activate()
+*/
+void QGLPainter::pushSurface(QGLAbstractSurface *surface)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ Q_ASSERT(surface);
+ if (!surface) {
+ // Find the most recent main surface for this painter.
+ int size = d->surfaceStack.size();
+ while (size > 0 && !d->surfaceStack[size - 1].mainSurface)
+ --size;
+ if (!size)
+ return; // Shouldn't happen, but be safe anyway.
+ surface = d->surfaceStack[size - 1].surface;
+ }
+ Q_ASSERT(!d->surfaceStack.isEmpty()); // Should have a main surface.
+ QGLAbstractSurface *current = d->surfaceStack.top().surface;
+ QGLPainterSurfaceInfo psurf;
+ psurf.surface = surface;
+ psurf.destroySurface = false;
+ psurf.mainSurface = false;
+ d->surfaceStack.append(psurf);
+ current->switchTo(surface);
+ d->updates |= UpdateViewport;
+}
+
+/*!
+ Pops the top-most drawing surface from the surface stack
+ and returns it. The next object on the stack will be made
+ the current drawing surface for context(). Returns null if the
+ surface stack is already at the main surface (e.g. the window).
+
+ The UpdateViewport flag will be set to indicate that the
+ \c{glViewport()} should be adjusted to the new surface extents
+ when update() is next called.
+
+ \sa pushSurface(), currentSurface(), setSurface()
+*/
+QGLAbstractSurface *QGLPainter::popSurface()
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ Q_ASSERT(!d->surfaceStack.isEmpty()); // Should have a main surface.
+ QGLPainterSurfaceInfo &surf = d->surfaceStack.top();
+ if (surf.mainSurface)
+ return 0;
+ QGLAbstractSurface *surface = surf.surface;
+ d->surfaceStack.pop();
+ Q_ASSERT(!d->surfaceStack.isEmpty()); // Should have a main surface.
+ QGLAbstractSurface *nextSurface = d->surfaceStack.top().surface;
+ surface->switchTo(nextSurface);
+ d->updates |= UpdateViewport;
+ return surface;
+}
+
+/*!
+ Sets the top-most drawing surface on the surface stack to \a surface
+ and activate it.
+
+ Note: if the top-most drawing surface is the main surface specified
+ during begin(), then this function will perform a pushSurface()
+ instead. Typically this function is used to replace the last
+ surface that was pushed onto the stack and avoid doing popSurface()
+ followed by pushSurface(). The main surface cannot be replaced
+ in this manner.
+
+ The UpdateViewport flag will be set to indicate that the
+ \c{glViewport()} should be adjusted to the extents of \a surface
+ when update() is next called.
+
+ \sa pushSurface(), popSurface(), currentSurface()
+*/
+void QGLPainter::setSurface(QGLAbstractSurface *surface)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ Q_ASSERT(surface);
+ Q_ASSERT(!d->surfaceStack.isEmpty()); // Should have a main surface.
+ QGLPainterSurfaceInfo &surf = d->surfaceStack.top();
+ if (surf.mainSurface) {
+ pushSurface(surface);
+ return;
+ }
+ QGLAbstractSurface *oldSurface = surf.surface;
+ surf.surface = surface;
+ oldSurface->switchTo(surface);
+ d->updates |= UpdateViewport;
+}
+
+/*!
+ Returns the current drawing surface.
+
+ \sa pushSurface(), popSurface(), setSurface()
+*/
+QGLAbstractSurface *QGLPainter::currentSurface() const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ Q_ASSERT(!d->surfaceStack.isEmpty()); // Should have a main surface.
+ return d->surfaceStack.top().surface;
+}
+
+/*!
+ Returns the current lighting model.
+
+ \sa setLightModel()
+*/
+const QGLLightModel *QGLPainter::lightModel() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (!d->lightModel) {
+ if (!d->defaultLightModel)
+ d->defaultLightModel = new QGLLightModel();
+ d->lightModel = d->defaultLightModel;
+ }
+ return d->lightModel;
+}
+
+/*!
+ Sets the current lighting model to \a value. If \a value is
+ null, then the default lighting model parameters will be used.
+
+ The light settings in the GL server will not be changed until
+ update() is called.
+
+ \sa lightModel()
+*/
+void QGLPainter::setLightModel(const QGLLightModel *value)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ d->lightModel = value;
+ d->updates |= QGLPainter::UpdateLights;
+}
+
+/*!
+ Returns the parameters for the main light in the scene.
+
+ The light parameters are specified in world co-ordinates at
+ the point when setMainLight() was called. The mainLightTransform()
+ must be applied to obtain eye co-ordinates.
+
+ This function is a convenience that returns the light with
+ identifier 0. If light 0 is not currently enabled, then a
+ default light is added to the painter with an identity
+ transform and then returned as the main light.
+
+ \sa setMainLight(), mainLightTransform(), addLight()
+*/
+const QGLLightParameters *QGLPainter::mainLight() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->lights.isEmpty()) {
+ if (!d->defaultLight)
+ d->defaultLight = new QGLLightParameters();
+ d->lights.append(d->defaultLight);
+ d->lightTransforms.append(QMatrix4x4());
+ } else if (!d->lights[0]) {
+ if (!d->defaultLight)
+ d->defaultLight = new QGLLightParameters();
+ d->lights[0] = d->defaultLight;
+ d->lightTransforms[0] = QMatrix4x4();
+ }
+ return d->lights[0];
+}
+
+/*!
+ Sets the \a parameters for the main light in the scene.
+ The mainLightTransform() is set to the current modelViewMatrix().
+
+ Light parameters are stored in world co-ordinates, not eye co-ordinates.
+ The mainLightTransform() specifies the transformation to apply to
+ convert the world co-ordinates into eye co-ordinates when the light
+ is used.
+
+ Note: the \a parameters may be ignored by effect() if it
+ has some other way to determine the lighting conditions.
+
+ The light settings in the GL server will not be changed until
+ update() is called.
+
+ This function is a convenience that sets the light with
+ identifier 0. If \a parameters is null, then light 0
+ will be removed.
+
+ \sa mainLight(), mainLightTransform(), addLight()
+*/
+void QGLPainter::setMainLight(const QGLLightParameters *parameters)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->lights.isEmpty()) {
+ if (parameters) {
+ d->lights.append(parameters);
+ d->lightTransforms.append(modelViewMatrix());
+ d->updates |= QGLPainter::UpdateLights;
+ }
+ } else if (parameters) {
+ d->lights[0] = parameters;
+ d->lightTransforms[0] = modelViewMatrix();
+ d->updates |= QGLPainter::UpdateLights;
+ } else {
+ removeLight(0);
+ }
+}
+
+/*!
+ Sets the \a parameters for the main light in the scene, and set
+ mainLightTransform() to \a transform.
+
+ Light parameters are stored in world co-ordinates, not eye co-ordinates.
+ The \a transform specifies the transformation to apply to convert the
+ world co-ordinates into eye co-ordinates when the light is used.
+
+ Note: the \a parameters may be ignored by effect() if it
+ has some other way to determine the lighting conditions.
+
+ The light settings in the GL server will not be changed until
+ update() is called.
+
+ This function is a convenience that sets the light with
+ identifier 0. If \a parameters is null, then light 0
+ will be removed.
+
+ \sa mainLight(), mainLightTransform()
+*/
+void QGLPainter::setMainLight
+ (const QGLLightParameters *parameters, const QMatrix4x4& transform)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->lights.isEmpty()) {
+ if (parameters) {
+ d->lights.append(parameters);
+ d->lightTransforms.append(transform);
+ d->updates |= QGLPainter::UpdateLights;
+ }
+ } else if (parameters) {
+ d->lights[0] = parameters;
+ d->lightTransforms[0] = transform;
+ d->updates |= QGLPainter::UpdateLights;
+ } else {
+ removeLight(0);
+ }
+}
+
+/*!
+ Returns the modelview transformation matrix for the main light that
+ was set at the time setMainLight() was called.
+
+ The light transform may be used by later painting operations to
+ convert the light from world co-ordinates into eye co-ordinates.
+ The eye transformation is set when the light is specified.
+
+ This function is a convenience that returns the tranform for the
+ light with identifier 0. If light 0 is not enabled, then the
+ function returns the identity matrix.
+
+ \sa mainLight(), setMainLight(), addLight()
+*/
+QMatrix4x4 QGLPainter::mainLightTransform() const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (!d->lights.isEmpty() && d->lights[0])
+ return d->lightTransforms[0];
+ else
+ return QMatrix4x4();
+}
+
+/*!
+ Adds a light to this painter, with the specified \a parameters.
+ The lightTransform() for the light is set to the current
+ modelViewMatrix(). Returns an identifier for the light.
+
+ Light parameters are stored in world co-ordinates, not eye co-ordinates.
+ The lightTransform() specifies the transformation to apply to
+ convert the world co-ordinates into eye co-ordinates when the light
+ is used.
+
+ Note: the \a parameters may be ignored by effect() if it
+ has some other way to determine the lighting conditions.
+
+ The light settings in the GL server will not be changed until
+ update() is called.
+
+ \sa removeLight(), light(), mainLight()
+*/
+int QGLPainter::addLight(const QGLLightParameters *parameters)
+{
+ return addLight(parameters, modelViewMatrix());
+}
+
+/*!
+ Adds a light to this painter, with the specified \a parameters.
+ The lightTransform() for the light is set to \a transform.
+ Returns an identifier for the light.
+
+ Light parameters are stored in world co-ordinates, not eye co-ordinates.
+ The \a transform specifies the transformation to apply to
+ convert the world co-ordinates into eye co-ordinates when the light
+ is used.
+
+ Note: the \a parameters may be ignored by effect() if it
+ has some other way to determine the lighting conditions.
+
+ The light settings in the GL server will not be changed until
+ update() is called.
+
+ \sa removeLight(), light(), mainLight()
+*/
+int QGLPainter::addLight(const QGLLightParameters *parameters, const QMatrix4x4 &transform)
+{
+ Q_ASSERT(parameters);
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ int lightId = 0;
+ while (lightId < d->lights.size() && d->lights[lightId] != 0)
+ ++lightId;
+ if (lightId < d->lights.size()) {
+ d->lights[lightId] = parameters;
+ d->lightTransforms[lightId] = transform;
+ } else {
+ d->lights.append(parameters);
+ d->lightTransforms.append(transform);
+ }
+ d->updates |= QGLPainter::UpdateLights;
+ return lightId;
+}
+
+/*!
+ Removes the light with the specified \a lightId.
+
+ \sa addLight(), light()
+*/
+void QGLPainter::removeLight(int lightId)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (lightId >= 0 && lightId < d->lights.size()) {
+ d->lights[lightId] = 0;
+ if (lightId >= (d->lights.size() - 1)) {
+ do {
+ d->lights.resize(lightId);
+ d->lightTransforms.resize(lightId);
+ --lightId;
+ } while (lightId >= 0 && d->lights[lightId] == 0);
+ }
+ d->updates |= QGLPainter::UpdateLights;
+ }
+}
+
+/*!
+ Returns the maximum light identifier currently in use on this painter;
+ or -1 if there are no lights.
+
+ It is possible that some light identifiers less than maximumLightId()
+ may be invalid because the lights have been removed. Use the following
+ code to locate all enabled lights:
+
+ \code
+ int maxLightId = painter.maximumLightId();
+ for (int lightId = 0; index <= maxLightId; ++index) {
+ const QGLLightParameters *params = painter.light(lightId);
+ if (params) {
+ ...
+ }
+ }
+ \endcode
+
+ \sa addLight(), light()
+*/
+int QGLPainter::maximumLightId() const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return d->lights.size() - 1;
+}
+
+/*!
+ Returns the parameters for the light with the identifier \a lightId;
+ or null if \a lightId is not valid or has been removed.
+
+ \sa addLight(), removeLight(), lightTransform()
+*/
+const QGLLightParameters *QGLPainter::light(int lightId) const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (lightId >= 0 && lightId < d->lights.size())
+ return d->lights[lightId];
+ else
+ return 0;
+}
+
+/*!
+ Returns the modelview transformation for the light with the identifier
+ \a lightId; or the identity matrix if \a lightId is not valid or has
+ been removed.
+
+ \sa addLight(), removeLight(), light()
+*/
+QMatrix4x4 QGLPainter::lightTransform(int lightId) const
+{
+ Q_D(const QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (lightId >= 0 && lightId < d->lights.size() && d->lights[lightId])
+ return d->lightTransforms[lightId];
+ else
+ return QMatrix4x4();
+}
+
+/*!
+ Returns the material that is used for drawing \a face on polygons.
+ If \a face is QGL::FrontFaces or QGL::AllFaces, then the front
+ material is returned. If \a face is QGL::BackFaces, then the
+ back material is returned.
+
+ \sa setFaceMaterial(), setFaceColor()
+*/
+const QGLMaterial *QGLPainter::faceMaterial(QGL::Face face) const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (face == QGL::BackFaces) {
+ if (!d->backMaterial) {
+ if (!d->defaultMaterial)
+ d->defaultMaterial = new QGLMaterial();
+ d->backMaterial = d->defaultMaterial;
+ }
+ return d->backMaterial;
+ } else {
+ if (!d->frontMaterial) {
+ if (!d->defaultMaterial)
+ d->defaultMaterial = new QGLMaterial();
+ d->frontMaterial = d->defaultMaterial;
+ }
+ return d->frontMaterial;
+ }
+}
+
+/*!
+ Sets the material that is used for drawing \a face on polygons
+ to \a value. If \a face is QGL::FrontFaces, then the front
+ material is set. If \a face is QGL::BackFaces, then the
+ back material is set. If \a face is QGL::AllFaces, then both
+ the front and back materials are set.
+
+ If \a value is null, then the \a face material will be set to
+ the default material properties.
+
+ The material settings in the GL server will not be changed until
+ update() is called.
+
+ \sa faceMaterial(), setFaceColor()
+*/
+void QGLPainter::setFaceMaterial
+ (QGL::Face face, const QGLMaterial *value)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (face == QGL::FrontFaces) {
+ if (d->frontMaterial == value)
+ return;
+ d->frontMaterial = value;
+ } else if (face == QGL::BackFaces) {
+ if (d->backMaterial == value)
+ return;
+ d->backMaterial = value;
+ } else {
+ if (d->frontMaterial == value && d->backMaterial == value)
+ return;
+ d->frontMaterial = value;
+ d->backMaterial = value;
+ }
+ d->updates |= QGLPainter::UpdateMaterials;
+}
+
+static QGLMaterial *createColorMaterial
+ (QGLMaterial *prev, const QColor& color)
+{
+ QGLMaterial *material;
+ if (prev)
+ material = prev;
+ else
+ material = new QGLMaterial();
+ material->setColor(color);
+ return material;
+}
+
+/*!
+ Sets the material that is used for drawing \a face on polygons
+ to \a color. This is a convenience function for setting materials
+ to simple colors.
+
+ The RGB components of the ambient color of the material will be set
+ to 20% of \a color, and the RGB components of the diffuse color of the
+ material will be set to 80% of \a color. The alpha components of
+ the ambient and diffuse material colors will both be set to the
+ alpha component of \a color.
+
+ If \a face is QGL::FrontFaces, then the front material is set.
+ If \a face is QGL::BackFaces, then the back material is set.
+ If \a face is QGL::AllFaces, then both the front and back
+ materials are set.
+
+ The material settings in the GL server will not be changed until
+ update() is called.
+
+ \sa faceMaterial(), setFaceMaterial()
+*/
+void QGLPainter::setFaceColor(QGL::Face face, const QColor& color)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (face == QGL::FrontFaces) {
+ d->frontColorMaterial =
+ createColorMaterial(d->frontColorMaterial, color);
+ d->frontMaterial = d->frontColorMaterial;
+ } else if (face == QGL::BackFaces) {
+ d->backColorMaterial =
+ createColorMaterial(d->backColorMaterial, color);
+ d->backMaterial = d->backColorMaterial;
+ } else {
+ d->frontColorMaterial =
+ createColorMaterial(d->frontColorMaterial, color);
+ d->backColorMaterial =
+ createColorMaterial(d->backColorMaterial, color);
+ d->frontMaterial = d->frontColorMaterial;
+ d->backMaterial = d->backColorMaterial;
+ }
+ d->updates |= QGLPainter::UpdateMaterials;
+}
+
+/*!
+ Returns true if this painter is in object picking mode;
+ false if this painter is in normal rendering mode.
+
+ \sa setPicking(), objectPickId()
+*/
+bool QGLPainter::isPicking() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return (d->pick ? d->pick->isPicking : false);
+}
+
+/*!
+ Enables or disables object picking mode according to \a value.
+
+ If \a value is true, then the effect() will be overridden with a
+ simple flat color effect that renders objects with pickColor().
+ These colors can be read back later with pickObject().
+
+ \sa isPicking(), objectPickId(), pickObject()
+*/
+void QGLPainter::setPicking(bool value)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (!d->pick)
+ d->pick = new QGLPainterPickPrivate();
+ if (d->pick->isPicking != value) {
+ // Switch to/from the pick effect.
+ d->pick->isPicking = value;
+ if (d->effect)
+ d->effect->setActive(this, false);
+ d->effect = 0;
+ d->ensureEffect(this);
+ }
+}
+
+/*!
+ Returns the current object pick identifier. The default value
+ is -1 which indicates that rendered objects should not have a
+ pickColor() associated with them.
+
+ \sa setObjectPickId(), clearPickObjects(), pickObject()
+*/
+int QGLPainter::objectPickId() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ return (d->pick ? d->pick->objectPickId : -1);
+}
+
+/*!
+ Sets the current object pick identifier to \a value. If \a value
+ is -1, then subsequent objects will be rendered without a pickColor().
+
+ If value is not -1, then the pickColor() is changed to a color
+ that represents that object pick identifier. If \a value has been
+ seen previously, then the same pickColor() as last time will
+ be returned.
+
+ The function call will be ignored if isPicking() is false.
+
+ \sa objectPickId(), clearPickObjects(), pickObject()
+*/
+void QGLPainter::setObjectPickId(int value)
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (!d->pick || !d->pick->isPicking)
+ return;
+ d->pick->objectPickId = value;
+ if (value != -1) {
+ QRgb color = d->pick->pickObjectToColor.value(value, 0);
+ if (!color) {
+ color = qt_qgl_pick_color(d->pick->pickColorIndex++);
+ d->pick->pickObjectToColor[value] = color;
+ d->pick->pickColorToObject[color] = value;
+ }
+ d->pick->pickColor = color;
+ d->updates |= UpdateColor;
+ } else {
+ d->pick->pickColor = 0;
+ d->updates |= UpdateColor;
+ }
+}
+
+/*!
+ Clears the objectPickId() to pickColor() mappings that
+ were used previously. This will also set objectPickId()
+ to -1 and pickColor() to (0, 0, 0, 1).
+
+ The function call will be ignored if isPicking() is false.
+
+ \sa objectPickId(), pickColor()
+*/
+void QGLPainter::clearPickObjects()
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->pick && d->pick->isPicking) {
+ d->pick->pickObjectToColor.clear();
+ d->pick->pickColorToObject.clear();
+ d->pick->pickColorIndex = 0;
+ d->pick->objectPickId = -1;
+ d->pick->pickColor = 0;
+ d->updates |= UpdateColor;
+ }
+}
+
+/*!
+ Returns the current pick color to use to render the object
+ associated with objectPickId(). The returned color will
+ be (0, 0, 0, 1) if objectPickId() is -1.
+
+ \sa objectPickId(), clearPickObjects()
+*/
+QColor QGLPainter::pickColor() const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+ if (d->pick) {
+ QColor color;
+ color.setRgb(d->pick->pickColor);
+ return color;
+ } else {
+ return Qt::black;
+ }
+}
+
+/*!
+ Picks the color at (\a x, \a y) in the color buffer and
+ returns the objectPickId() that corresponds to that color.
+ Returns -1 if (\a x, \a y) is not positioned over a
+ recognized object. The origin (0, 0) is assumed to be
+ the bottom-left corner of the drawing surface.
+
+ \sa objectPickId()
+*/
+int QGLPainter::pickObject(int x, int y) const
+{
+ Q_D(QGLPainter);
+ QGLPAINTER_CHECK_PRIVATE();
+
+ if (!d->pick)
+ {
+ return -1;
+ }
+
+ // Fetch the color at the specified pixel.
+ unsigned char data[4] = {0, 0, 0, 0};
+ glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ QRgb color = qRgb(data[0], data[1], data[2]);
+
+ // Normalize the color to account for floating-point rounding.
+ color = qt_qgl_normalize_pick_color(color); // XXX: detect RGB444 screens.
+
+ // Map the color back to an object identifier.
+ return d->pick->pickColorToObject.value(color, -1);
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/painting/qglpainter.h b/src/threed/painting/qglpainter.h
new file mode 100644
index 000000000..5d805f0bf
--- /dev/null
+++ b/src/threed/painting/qglpainter.h
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPAINTER_H
+#define QGLPAINTER_H
+
+#include <QtOpenGL/qgl.h>
+#include "qglnamespace.h"
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qmatrix4x4.h>
+#include "qbox3d.h"
+#include "qopenglfunctions.h"
+#include "qglvertexbundle.h"
+#include "qglindexbuffer.h"
+#include "qgllightmodel.h"
+#include "qgllightparameters.h"
+#include "qglmaterial.h"
+#include "qglabstractsurface.h"
+#include "qmatrix4x4stack.h"
+#include "qglcamera.h"
+#include "qvector2darray.h"
+#include "qvector3darray.h"
+#include "qvector4darray.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLAbstractEffect;
+class QGLPainterPrivate;
+class QGLTexture2D;
+class QGLTextureCube;
+class QGeometryData;
+class QGLShaderProgram;
+class QGLFramebufferObject;
+class QGLSceneNode;
+class QGLRenderSequencer;
+class QGLAbstractSurface;
+
+class Q_QT3D_EXPORT QGLPainter : public QOpenGLFunctions
+{
+public:
+ QGLPainter();
+ explicit QGLPainter(const QGLContext *context);
+ explicit QGLPainter(QGLWidget *widget);
+ explicit QGLPainter(QPainter *painter);
+ explicit QGLPainter(QGLAbstractSurface *surface);
+ virtual ~QGLPainter();
+
+ bool begin();
+ bool begin(const QGLContext *context);
+ bool begin(QGLWidget *widget);
+ bool begin(QPainter *painter);
+ bool begin(QGLAbstractSurface *surface);
+ bool end();
+ bool isActive() const;
+
+ const QGLContext *context() const;
+
+ bool isFixedFunction() const;
+
+ enum Update
+ {
+ UpdateColor = 0x00000001,
+ UpdateModelViewMatrix = 0x00000002,
+ UpdateProjectionMatrix = 0x00000004,
+ UpdateMatrices = 0x00000006,
+ UpdateLights = 0x00000008,
+ UpdateMaterials = 0x00000010,
+ UpdateViewport = 0x00000020,
+ UpdateAll = 0x7FFFFFFF
+ };
+ Q_DECLARE_FLAGS(Updates, Update);
+
+ void setClearColor(const QColor& color);
+
+ void setScissor(const QRect& rect);
+
+ QMatrix4x4Stack& projectionMatrix();
+ QMatrix4x4Stack& modelViewMatrix();
+ QMatrix4x4 combinedMatrix() const;
+ QMatrix3x3 normalMatrix() const;
+ QMatrix4x4 worldMatrix() const;
+
+ QGL::Eye eye() const;
+ void setEye(QGL::Eye eye);
+
+ void setCamera(const QGLCamera *camera);
+
+ bool isCullable(const QVector3D& point) const;
+ bool isCullable(const QBox3D& box) const;
+ QGLRenderSequencer *renderSequencer();
+
+ qreal aspectRatio() const;
+
+ QGLAbstractEffect *effect() const;
+
+ QGLAbstractEffect *userEffect() const;
+ void setUserEffect(QGLAbstractEffect *effect);
+
+ QGL::StandardEffect standardEffect() const;
+ void setStandardEffect(QGL::StandardEffect effect);
+
+ void disableEffect();
+
+ QGLShaderProgram *cachedProgram(const QString& name) const;
+ void setCachedProgram(const QString& name, QGLShaderProgram *program);
+
+ QColor color() const;
+ void setColor(const QColor& color);
+
+ QGLAttributeSet attributes() const;
+ void clearAttributes();
+
+ void setVertexAttribute
+ (QGL::VertexAttribute attribute, const QGLAttributeValue& value);
+ void setVertexBundle(const QGLVertexBundle& buffer);
+
+ void update();
+ void updateFixedFunction(QGLPainter::Updates updates);
+
+ void draw(QGL::DrawingMode mode, int count, int index = 0);
+ void draw(QGL::DrawingMode mode, const ushort *indices, int count);
+ void draw(QGL::DrawingMode mode, const QGLIndexBuffer& indices);
+ virtual void draw(QGL::DrawingMode mode, const QGLIndexBuffer& indices, int offset, int count);
+
+ void pushSurface(QGLAbstractSurface *surface);
+ QGLAbstractSurface *popSurface();
+ void setSurface(QGLAbstractSurface *surface);
+ QGLAbstractSurface *currentSurface() const;
+
+ const QGLLightModel *lightModel() const;
+ void setLightModel(const QGLLightModel *value);
+
+ const QGLLightParameters *mainLight() const;
+ void setMainLight(const QGLLightParameters *parameters);
+ void setMainLight
+ (const QGLLightParameters *parameters, const QMatrix4x4& transform);
+ QMatrix4x4 mainLightTransform() const;
+
+ int addLight(const QGLLightParameters *parameters);
+ int addLight(const QGLLightParameters *parameters, const QMatrix4x4 &transform);
+ void removeLight(int lightId);
+
+ int maximumLightId() const;
+ const QGLLightParameters *light(int lightId) const;
+ QMatrix4x4 lightTransform(int lightId) const;
+
+ const QGLMaterial *faceMaterial(QGL::Face face) const;
+ void setFaceMaterial(QGL::Face face, const QGLMaterial *value);
+ void setFaceColor(QGL::Face face, const QColor& color);
+
+ bool isPicking() const;
+ void setPicking(bool value);
+
+ int objectPickId() const;
+ void setObjectPickId(int value);
+ void clearPickObjects();
+
+ QColor pickColor() const;
+
+ int pickObject(int x, int y) const;
+
+private:
+ Q_DISABLE_COPY(QGLPainter)
+
+ QGLPainterPrivate *d_ptr;
+
+ QGLPainterPrivate *d_func() const { return d_ptr; }
+
+ friend class QGLAbstractEffect;
+
+ bool begin(const QGLContext *context, QGLAbstractSurface *surface,
+ bool destroySurface = true);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLPainter::Updates)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/painting/qglpainter_p.h b/src/threed/painting/qglpainter_p.h
new file mode 100644
index 000000000..82f901797
--- /dev/null
+++ b/src/threed/painting/qglpainter_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPAINTER_P_H
+#define QGLPAINTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglpainter.h"
+#include "qglrendersequencer.h"
+
+#include <QtCore/qatomic.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QGL_MAX_LIGHTS 32
+#define QGL_MAX_STD_EFFECTS 16
+
+class QGLPainterPickPrivate
+{
+public:
+ QGLPainterPickPrivate();
+ ~QGLPainterPickPrivate();
+
+ bool isPicking;
+ int objectPickId;
+ int pickColorIndex;
+ QRgb pickColor;
+ QMap<int, QRgb> pickObjectToColor;
+ QMap<QRgb, int> pickColorToObject;
+ QGLAbstractEffect *defaultPickEffect;
+};
+
+struct QGLPainterSurfaceInfo
+{
+ QGLAbstractSurface *surface;
+ bool destroySurface;
+ bool mainSurface;
+};
+
+class QGLPainterPrivate
+{
+public:
+ QGLPainterPrivate();
+ ~QGLPainterPrivate();
+
+ QAtomicInt ref;
+ const QGLContext *context;
+ QMatrix4x4Stack projectionMatrix;
+ QMatrix4x4Stack modelViewMatrix;
+ QMatrix4x4 inverseEyeMatrix;
+ QGL::Eye eye;
+ QGLAbstractEffect *effect;
+ QGLAbstractEffect *userEffect;
+ QGL::StandardEffect standardEffect;
+ QGLAbstractEffect *stdeffects[QGL_MAX_STD_EFFECTS];
+ const QGLLightModel *lightModel;
+ QGLLightModel *defaultLightModel;
+ QGLLightParameters *defaultLight;
+ QArray<const QGLLightParameters *> lights;
+ QArray<QMatrix4x4> lightTransforms;
+ const QGLMaterial *frontMaterial;
+ const QGLMaterial *backMaterial;
+ QGLMaterial *defaultMaterial;
+ QGLMaterial *frontColorMaterial;
+ QGLMaterial *backColorMaterial;
+ QBox3D viewingCube;
+ QColor color;
+ QGLPainter::Updates updates;
+ QGLPainterPickPrivate *pick;
+ QMap<QString, QGLShaderProgram *> cachedPrograms;
+ QStack<QGLPainterSurfaceInfo> surfaceStack;
+ GLuint boundVertexBuffer;
+ GLuint boundIndexBuffer;
+ QGLRenderSequencer *renderSequencer;
+ bool isFixedFunction;
+ QGLAttributeSet attributeSet;
+
+ inline void ensureEffect(QGLPainter *painter)
+ { if (!effect) createEffect(painter); }
+ void createEffect(QGLPainter *painter);
+};
+
+class QGLPainterPrivateCache : public QObject
+{
+ Q_OBJECT
+public:
+ QGLPainterPrivateCache();
+ ~QGLPainterPrivateCache();
+
+ QMap<const QGLContext *, QGLPainterPrivate *> cache;
+
+ QGLPainterPrivate *fromContext(const QGLContext *context);
+
+ static QGLPainterPrivateCache *instance();
+
+public Q_SLOTS:
+ void contextDestroyed(const QGLContext *context);
+
+Q_SIGNALS:
+ void destroyedContext(const QGLContext *context);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/threed/painting/qglpickcolors.cpp b/src/threed/painting/qglpickcolors.cpp
new file mode 100644
index 000000000..ff94ea40a
--- /dev/null
+++ b/src/threed/painting/qglpickcolors.cpp
@@ -0,0 +1,1125 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if !defined(QGL_GENERATOR_PROGRAM)
+
+#include "qglpickcolors_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// The following tables are generated by the program listed at the
+// end of this source file.
+
+static int const pickColors[4096] = {
+ 0xffffff, 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff,
+ 0xff8000, 0x80ff00, 0x8000ff, 0xff0080, 0x0080ff, 0x00ff80, 0xff80ff,
+ 0x80ffff, 0xffff80, 0x80ff80, 0xff8080, 0x8080ff, 0x808080, 0x800000,
+ 0x008000, 0x000080, 0x808000, 0x800080, 0x008080, 0xff80c0, 0x80c0ff,
+ 0xc0ff80, 0xffc080, 0x80ffc0, 0xc080ff, 0xffc000, 0xc0ff00, 0xc000ff,
+ 0xff00c0, 0x00c0ff, 0x00ffc0, 0xffc0ff, 0xc0ffff, 0xffffc0, 0xc0ffc0,
+ 0xffc0c0, 0xc0c0ff, 0x80c000, 0xc08000, 0xc00080, 0x8000c0, 0x00c080,
+ 0x0080c0, 0x80c080, 0xc08080, 0x8080c0, 0xc080c0, 0x80c0c0, 0xc0c080,
+ 0xc0c0c0, 0xc00000, 0x00c000, 0x0000c0, 0xc0c000, 0xc000c0, 0x00c0c0,
+ 0xff8040, 0x8040ff, 0x40ff80, 0xff4080, 0x80ff40, 0x4080ff, 0xffc040,
+ 0xc040ff, 0x40ffc0, 0xff40c0, 0xc0ff40, 0x40c0ff, 0xff4000, 0x40ff00,
+ 0x4000ff, 0xff0040, 0x0040ff, 0x00ff40, 0xff40ff, 0x40ffff, 0xffff40,
+ 0x40ff40, 0xff4040, 0x4040ff, 0x80c040, 0xc04080, 0x4080c0, 0x8040c0,
+ 0xc08040, 0x40c080, 0x804000, 0x408000, 0x400080, 0x800040, 0x004080,
+ 0x008040, 0x804080, 0x408080, 0x808040, 0x408040, 0x804040, 0x404080,
+ 0xc04000, 0x40c000, 0x4000c0, 0xc00040, 0x0040c0, 0x00c040, 0xc040c0,
+ 0x40c0c0, 0xc0c040, 0x40c040, 0xc04040, 0x4040c0, 0x404040, 0x400000,
+ 0x004000, 0x000040, 0x404000, 0x400040, 0x004040, 0xff80e0, 0x80e0ff,
+ 0xe0ff80, 0xffe080, 0x80ffe0, 0xe080ff, 0xffc0e0, 0xc0e0ff, 0xe0ffc0,
+ 0xffe0c0, 0xc0ffe0, 0xe0c0ff, 0xff40e0, 0x40e0ff, 0xe0ff40, 0xffe040,
+ 0x40ffe0, 0xe040ff, 0xffe000, 0xe0ff00, 0xe000ff, 0xff00e0, 0x00e0ff,
+ 0x00ffe0, 0xffe0ff, 0xe0ffff, 0xffffe0, 0xe0ffe0, 0xffe0e0, 0xe0e0ff,
+ 0x80c0e0, 0xc0e080, 0xe080c0, 0x80e0c0, 0xc080e0, 0xe0c080, 0x8040e0,
+ 0x40e080, 0xe08040, 0x80e040, 0x4080e0, 0xe04080, 0x80e000, 0xe08000,
+ 0xe00080, 0x8000e0, 0x00e080, 0x0080e0, 0x80e080, 0xe08080, 0x8080e0,
+ 0xe080e0, 0x80e0e0, 0xe0e080, 0xc040e0, 0x40e0c0, 0xe0c040, 0xc0e040,
+ 0x40c0e0, 0xe040c0, 0xc0e000, 0xe0c000, 0xe000c0, 0xc000e0, 0x00e0c0,
+ 0x00c0e0, 0xc0e0c0, 0xe0c0c0, 0xc0c0e0, 0xe0c0e0, 0xc0e0e0, 0xe0e0c0,
+ 0x40e000, 0xe04000, 0xe00040, 0x4000e0, 0x00e040, 0x0040e0, 0x40e040,
+ 0xe04040, 0x4040e0, 0xe040e0, 0x40e0e0, 0xe0e040, 0xe0e0e0, 0xe00000,
+ 0x00e000, 0x0000e0, 0xe0e000, 0xe000e0, 0x00e0e0, 0xff8060, 0x8060ff,
+ 0x60ff80, 0xff6080, 0x80ff60, 0x6080ff, 0xffc060, 0xc060ff, 0x60ffc0,
+ 0xff60c0, 0xc0ff60, 0x60c0ff, 0xff4060, 0x4060ff, 0x60ff40, 0xff6040,
+ 0x40ff60, 0x6040ff, 0xffe060, 0xe060ff, 0x60ffe0, 0xff60e0, 0xe0ff60,
+ 0x60e0ff, 0xff6000, 0x60ff00, 0x6000ff, 0xff0060, 0x0060ff, 0x00ff60,
+ 0xff60ff, 0x60ffff, 0xffff60, 0x60ff60, 0xff6060, 0x6060ff, 0x80c060,
+ 0xc06080, 0x6080c0, 0x8060c0, 0xc08060, 0x60c080, 0x804060, 0x406080,
+ 0x608040, 0x806040, 0x408060, 0x604080, 0x80e060, 0xe06080, 0x6080e0,
+ 0x8060e0, 0xe08060, 0x60e080, 0x806000, 0x608000, 0x600080, 0x800060,
+ 0x006080, 0x008060, 0x806080, 0x608080, 0x808060, 0x608060, 0x806060,
+ 0x606080, 0xc04060, 0x4060c0, 0x60c040, 0xc06040, 0x40c060, 0x6040c0,
+ 0xc0e060, 0xe060c0, 0x60c0e0, 0xc060e0, 0xe0c060, 0x60e0c0, 0xc06000,
+ 0x60c000, 0x6000c0, 0xc00060, 0x0060c0, 0x00c060, 0xc060c0, 0x60c0c0,
+ 0xc0c060, 0x60c060, 0xc06060, 0x6060c0, 0x40e060, 0xe06040, 0x6040e0,
+ 0x4060e0, 0xe04060, 0x60e040, 0x406000, 0x604000, 0x600040, 0x400060,
+ 0x006040, 0x004060, 0x406040, 0x604040, 0x404060, 0x604060, 0x406060,
+ 0x606040, 0xe06000, 0x60e000, 0x6000e0, 0xe00060, 0x0060e0, 0x00e060,
+ 0xe060e0, 0x60e0e0, 0xe0e060, 0x60e060, 0xe06060, 0x6060e0, 0x606060,
+ 0x600000, 0x006000, 0x000060, 0x606000, 0x600060, 0x006060, 0xff80a0,
+ 0x80a0ff, 0xa0ff80, 0xffa080, 0x80ffa0, 0xa080ff, 0xffc0a0, 0xc0a0ff,
+ 0xa0ffc0, 0xffa0c0, 0xc0ffa0, 0xa0c0ff, 0xff40a0, 0x40a0ff, 0xa0ff40,
+ 0xffa040, 0x40ffa0, 0xa040ff, 0xffe0a0, 0xe0a0ff, 0xa0ffe0, 0xffa0e0,
+ 0xe0ffa0, 0xa0e0ff, 0xff60a0, 0x60a0ff, 0xa0ff60, 0xffa060, 0x60ffa0,
+ 0xa060ff, 0xffa000, 0xa0ff00, 0xa000ff, 0xff00a0, 0x00a0ff, 0x00ffa0,
+ 0xffa0ff, 0xa0ffff, 0xffffa0, 0xa0ffa0, 0xffa0a0, 0xa0a0ff, 0x80c0a0,
+ 0xc0a080, 0xa080c0, 0x80a0c0, 0xc080a0, 0xa0c080, 0x8040a0, 0x40a080,
+ 0xa08040, 0x80a040, 0x4080a0, 0xa04080, 0x80e0a0, 0xe0a080, 0xa080e0,
+ 0x80a0e0, 0xe080a0, 0xa0e080, 0x8060a0, 0x60a080, 0xa08060, 0x80a060,
+ 0x6080a0, 0xa06080, 0x80a000, 0xa08000, 0xa00080, 0x8000a0, 0x00a080,
+ 0x0080a0, 0x80a080, 0xa08080, 0x8080a0, 0xa080a0, 0x80a0a0, 0xa0a080,
+ 0xc040a0, 0x40a0c0, 0xa0c040, 0xc0a040, 0x40c0a0, 0xa040c0, 0xc0e0a0,
+ 0xe0a0c0, 0xa0c0e0, 0xc0a0e0, 0xe0c0a0, 0xa0e0c0, 0xc060a0, 0x60a0c0,
+ 0xa0c060, 0xc0a060, 0x60c0a0, 0xa060c0, 0xc0a000, 0xa0c000, 0xa000c0,
+ 0xc000a0, 0x00a0c0, 0x00c0a0, 0xc0a0c0, 0xa0c0c0, 0xc0c0a0, 0xa0c0a0,
+ 0xc0a0a0, 0xa0a0c0, 0x40e0a0, 0xe0a040, 0xa040e0, 0x40a0e0, 0xe040a0,
+ 0xa0e040, 0x4060a0, 0x60a040, 0xa04060, 0x40a060, 0x6040a0, 0xa06040,
+ 0x40a000, 0xa04000, 0xa00040, 0x4000a0, 0x00a040, 0x0040a0, 0x40a040,
+ 0xa04040, 0x4040a0, 0xa040a0, 0x40a0a0, 0xa0a040, 0xe060a0, 0x60a0e0,
+ 0xa0e060, 0xe0a060, 0x60e0a0, 0xa060e0, 0xe0a000, 0xa0e000, 0xa000e0,
+ 0xe000a0, 0x00a0e0, 0x00e0a0, 0xe0a0e0, 0xa0e0e0, 0xe0e0a0, 0xa0e0a0,
+ 0xe0a0a0, 0xa0a0e0, 0x60a000, 0xa06000, 0xa00060, 0x6000a0, 0x00a060,
+ 0x0060a0, 0x60a060, 0xa06060, 0x6060a0, 0xa060a0, 0x60a0a0, 0xa0a060,
+ 0xa0a0a0, 0xa00000, 0x00a000, 0x0000a0, 0xa0a000, 0xa000a0, 0x00a0a0,
+ 0xff8020, 0x8020ff, 0x20ff80, 0xff2080, 0x80ff20, 0x2080ff, 0xffc020,
+ 0xc020ff, 0x20ffc0, 0xff20c0, 0xc0ff20, 0x20c0ff, 0xff4020, 0x4020ff,
+ 0x20ff40, 0xff2040, 0x40ff20, 0x2040ff, 0xffe020, 0xe020ff, 0x20ffe0,
+ 0xff20e0, 0xe0ff20, 0x20e0ff, 0xff6020, 0x6020ff, 0x20ff60, 0xff2060,
+ 0x60ff20, 0x2060ff, 0xffa020, 0xa020ff, 0x20ffa0, 0xff20a0, 0xa0ff20,
+ 0x20a0ff, 0xff2000, 0x20ff00, 0x2000ff, 0xff0020, 0x0020ff, 0x00ff20,
+ 0xff20ff, 0x20ffff, 0xffff20, 0x20ff20, 0xff2020, 0x2020ff, 0x80c020,
+ 0xc02080, 0x2080c0, 0x8020c0, 0xc08020, 0x20c080, 0x804020, 0x402080,
+ 0x208040, 0x802040, 0x408020, 0x204080, 0x80e020, 0xe02080, 0x2080e0,
+ 0x8020e0, 0xe08020, 0x20e080, 0x806020, 0x602080, 0x208060, 0x802060,
+ 0x608020, 0x206080, 0x80a020, 0xa02080, 0x2080a0, 0x8020a0, 0xa08020,
+ 0x20a080, 0x802000, 0x208000, 0x200080, 0x800020, 0x002080, 0x008020,
+ 0x802080, 0x208080, 0x808020, 0x208020, 0x802020, 0x202080, 0xc04020,
+ 0x4020c0, 0x20c040, 0xc02040, 0x40c020, 0x2040c0, 0xc0e020, 0xe020c0,
+ 0x20c0e0, 0xc020e0, 0xe0c020, 0x20e0c0, 0xc06020, 0x6020c0, 0x20c060,
+ 0xc02060, 0x60c020, 0x2060c0, 0xc0a020, 0xa020c0, 0x20c0a0, 0xc020a0,
+ 0xa0c020, 0x20a0c0, 0xc02000, 0x20c000, 0x2000c0, 0xc00020, 0x0020c0,
+ 0x00c020, 0xc020c0, 0x20c0c0, 0xc0c020, 0x20c020, 0xc02020, 0x2020c0,
+ 0x40e020, 0xe02040, 0x2040e0, 0x4020e0, 0xe04020, 0x20e040, 0x406020,
+ 0x602040, 0x204060, 0x402060, 0x604020, 0x206040, 0x40a020, 0xa02040,
+ 0x2040a0, 0x4020a0, 0xa04020, 0x20a040, 0x402000, 0x204000, 0x200040,
+ 0x400020, 0x002040, 0x004020, 0x402040, 0x204040, 0x404020, 0x204020,
+ 0x402020, 0x202040, 0xe06020, 0x6020e0, 0x20e060, 0xe02060, 0x60e020,
+ 0x2060e0, 0xe0a020, 0xa020e0, 0x20e0a0, 0xe020a0, 0xa0e020, 0x20a0e0,
+ 0xe02000, 0x20e000, 0x2000e0, 0xe00020, 0x0020e0, 0x00e020, 0xe020e0,
+ 0x20e0e0, 0xe0e020, 0x20e020, 0xe02020, 0x2020e0, 0x60a020, 0xa02060,
+ 0x2060a0, 0x6020a0, 0xa06020, 0x20a060, 0x602000, 0x206000, 0x200060,
+ 0x600020, 0x002060, 0x006020, 0x602060, 0x206060, 0x606020, 0x206020,
+ 0x602020, 0x202060, 0xa02000, 0x20a000, 0x2000a0, 0xa00020, 0x0020a0,
+ 0x00a020, 0xa020a0, 0x20a0a0, 0xa0a020, 0x20a020, 0xa02020, 0x2020a0,
+ 0x202020, 0x200000, 0x002000, 0x000020, 0x202000, 0x200020, 0x002020,
+ 0xff80f0, 0x80f0ff, 0xf0ff80, 0xfff080, 0x80fff0, 0xf080ff, 0xffc0f0,
+ 0xc0f0ff, 0xf0ffc0, 0xfff0c0, 0xc0fff0, 0xf0c0ff, 0xff40f0, 0x40f0ff,
+ 0xf0ff40, 0xfff040, 0x40fff0, 0xf040ff, 0xffe0f0, 0xe0f0ff, 0xf0ffe0,
+ 0xfff0e0, 0xe0fff0, 0xf0e0ff, 0xff60f0, 0x60f0ff, 0xf0ff60, 0xfff060,
+ 0x60fff0, 0xf060ff, 0xffa0f0, 0xa0f0ff, 0xf0ffa0, 0xfff0a0, 0xa0fff0,
+ 0xf0a0ff, 0xff20f0, 0x20f0ff, 0xf0ff20, 0xfff020, 0x20fff0, 0xf020ff,
+ 0xfff000, 0xf0ff00, 0xf000ff, 0xff00f0, 0x00f0ff, 0x00fff0, 0xfff0ff,
+ 0xf0ffff, 0xfffff0, 0xf0fff0, 0xfff0f0, 0xf0f0ff, 0x80c0f0, 0xc0f080,
+ 0xf080c0, 0x80f0c0, 0xc080f0, 0xf0c080, 0x8040f0, 0x40f080, 0xf08040,
+ 0x80f040, 0x4080f0, 0xf04080, 0x80e0f0, 0xe0f080, 0xf080e0, 0x80f0e0,
+ 0xe080f0, 0xf0e080, 0x8060f0, 0x60f080, 0xf08060, 0x80f060, 0x6080f0,
+ 0xf06080, 0x80a0f0, 0xa0f080, 0xf080a0, 0x80f0a0, 0xa080f0, 0xf0a080,
+ 0x8020f0, 0x20f080, 0xf08020, 0x80f020, 0x2080f0, 0xf02080, 0x80f000,
+ 0xf08000, 0xf00080, 0x8000f0, 0x00f080, 0x0080f0, 0x80f080, 0xf08080,
+ 0x8080f0, 0xf080f0, 0x80f0f0, 0xf0f080, 0xc040f0, 0x40f0c0, 0xf0c040,
+ 0xc0f040, 0x40c0f0, 0xf040c0, 0xc0e0f0, 0xe0f0c0, 0xf0c0e0, 0xc0f0e0,
+ 0xe0c0f0, 0xf0e0c0, 0xc060f0, 0x60f0c0, 0xf0c060, 0xc0f060, 0x60c0f0,
+ 0xf060c0, 0xc0a0f0, 0xa0f0c0, 0xf0c0a0, 0xc0f0a0, 0xa0c0f0, 0xf0a0c0,
+ 0xc020f0, 0x20f0c0, 0xf0c020, 0xc0f020, 0x20c0f0, 0xf020c0, 0xc0f000,
+ 0xf0c000, 0xf000c0, 0xc000f0, 0x00f0c0, 0x00c0f0, 0xc0f0c0, 0xf0c0c0,
+ 0xc0c0f0, 0xf0c0f0, 0xc0f0f0, 0xf0f0c0, 0x40e0f0, 0xe0f040, 0xf040e0,
+ 0x40f0e0, 0xe040f0, 0xf0e040, 0x4060f0, 0x60f040, 0xf04060, 0x40f060,
+ 0x6040f0, 0xf06040, 0x40a0f0, 0xa0f040, 0xf040a0, 0x40f0a0, 0xa040f0,
+ 0xf0a040, 0x4020f0, 0x20f040, 0xf04020, 0x40f020, 0x2040f0, 0xf02040,
+ 0x40f000, 0xf04000, 0xf00040, 0x4000f0, 0x00f040, 0x0040f0, 0x40f040,
+ 0xf04040, 0x4040f0, 0xf040f0, 0x40f0f0, 0xf0f040, 0xe060f0, 0x60f0e0,
+ 0xf0e060, 0xe0f060, 0x60e0f0, 0xf060e0, 0xe0a0f0, 0xa0f0e0, 0xf0e0a0,
+ 0xe0f0a0, 0xa0e0f0, 0xf0a0e0, 0xe020f0, 0x20f0e0, 0xf0e020, 0xe0f020,
+ 0x20e0f0, 0xf020e0, 0xe0f000, 0xf0e000, 0xf000e0, 0xe000f0, 0x00f0e0,
+ 0x00e0f0, 0xe0f0e0, 0xf0e0e0, 0xe0e0f0, 0xf0e0f0, 0xe0f0f0, 0xf0f0e0,
+ 0x60a0f0, 0xa0f060, 0xf060a0, 0x60f0a0, 0xa060f0, 0xf0a060, 0x6020f0,
+ 0x20f060, 0xf06020, 0x60f020, 0x2060f0, 0xf02060, 0x60f000, 0xf06000,
+ 0xf00060, 0x6000f0, 0x00f060, 0x0060f0, 0x60f060, 0xf06060, 0x6060f0,
+ 0xf060f0, 0x60f0f0, 0xf0f060, 0xa020f0, 0x20f0a0, 0xf0a020, 0xa0f020,
+ 0x20a0f0, 0xf020a0, 0xa0f000, 0xf0a000, 0xf000a0, 0xa000f0, 0x00f0a0,
+ 0x00a0f0, 0xa0f0a0, 0xf0a0a0, 0xa0a0f0, 0xf0a0f0, 0xa0f0f0, 0xf0f0a0,
+ 0x20f000, 0xf02000, 0xf00020, 0x2000f0, 0x00f020, 0x0020f0, 0x20f020,
+ 0xf02020, 0x2020f0, 0xf020f0, 0x20f0f0, 0xf0f020, 0xf0f0f0, 0xf00000,
+ 0x00f000, 0x0000f0, 0xf0f000, 0xf000f0, 0x00f0f0, 0xff80b0, 0x80b0ff,
+ 0xb0ff80, 0xffb080, 0x80ffb0, 0xb080ff, 0xffc0b0, 0xc0b0ff, 0xb0ffc0,
+ 0xffb0c0, 0xc0ffb0, 0xb0c0ff, 0xff40b0, 0x40b0ff, 0xb0ff40, 0xffb040,
+ 0x40ffb0, 0xb040ff, 0xffe0b0, 0xe0b0ff, 0xb0ffe0, 0xffb0e0, 0xe0ffb0,
+ 0xb0e0ff, 0xff60b0, 0x60b0ff, 0xb0ff60, 0xffb060, 0x60ffb0, 0xb060ff,
+ 0xffa0b0, 0xa0b0ff, 0xb0ffa0, 0xffb0a0, 0xa0ffb0, 0xb0a0ff, 0xff20b0,
+ 0x20b0ff, 0xb0ff20, 0xffb020, 0x20ffb0, 0xb020ff, 0xfff0b0, 0xf0b0ff,
+ 0xb0fff0, 0xffb0f0, 0xf0ffb0, 0xb0f0ff, 0xffb000, 0xb0ff00, 0xb000ff,
+ 0xff00b0, 0x00b0ff, 0x00ffb0, 0xffb0ff, 0xb0ffff, 0xffffb0, 0xb0ffb0,
+ 0xffb0b0, 0xb0b0ff, 0x80c0b0, 0xc0b080, 0xb080c0, 0x80b0c0, 0xc080b0,
+ 0xb0c080, 0x8040b0, 0x40b080, 0xb08040, 0x80b040, 0x4080b0, 0xb04080,
+ 0x80e0b0, 0xe0b080, 0xb080e0, 0x80b0e0, 0xe080b0, 0xb0e080, 0x8060b0,
+ 0x60b080, 0xb08060, 0x80b060, 0x6080b0, 0xb06080, 0x80a0b0, 0xa0b080,
+ 0xb080a0, 0x80b0a0, 0xa080b0, 0xb0a080, 0x8020b0, 0x20b080, 0xb08020,
+ 0x80b020, 0x2080b0, 0xb02080, 0x80f0b0, 0xf0b080, 0xb080f0, 0x80b0f0,
+ 0xf080b0, 0xb0f080, 0x80b000, 0xb08000, 0xb00080, 0x8000b0, 0x00b080,
+ 0x0080b0, 0x80b080, 0xb08080, 0x8080b0, 0xb080b0, 0x80b0b0, 0xb0b080,
+ 0xc040b0, 0x40b0c0, 0xb0c040, 0xc0b040, 0x40c0b0, 0xb040c0, 0xc0e0b0,
+ 0xe0b0c0, 0xb0c0e0, 0xc0b0e0, 0xe0c0b0, 0xb0e0c0, 0xc060b0, 0x60b0c0,
+ 0xb0c060, 0xc0b060, 0x60c0b0, 0xb060c0, 0xc0a0b0, 0xa0b0c0, 0xb0c0a0,
+ 0xc0b0a0, 0xa0c0b0, 0xb0a0c0, 0xc020b0, 0x20b0c0, 0xb0c020, 0xc0b020,
+ 0x20c0b0, 0xb020c0, 0xc0f0b0, 0xf0b0c0, 0xb0c0f0, 0xc0b0f0, 0xf0c0b0,
+ 0xb0f0c0, 0xc0b000, 0xb0c000, 0xb000c0, 0xc000b0, 0x00b0c0, 0x00c0b0,
+ 0xc0b0c0, 0xb0c0c0, 0xc0c0b0, 0xb0c0b0, 0xc0b0b0, 0xb0b0c0, 0x40e0b0,
+ 0xe0b040, 0xb040e0, 0x40b0e0, 0xe040b0, 0xb0e040, 0x4060b0, 0x60b040,
+ 0xb04060, 0x40b060, 0x6040b0, 0xb06040, 0x40a0b0, 0xa0b040, 0xb040a0,
+ 0x40b0a0, 0xa040b0, 0xb0a040, 0x4020b0, 0x20b040, 0xb04020, 0x40b020,
+ 0x2040b0, 0xb02040, 0x40f0b0, 0xf0b040, 0xb040f0, 0x40b0f0, 0xf040b0,
+ 0xb0f040, 0x40b000, 0xb04000, 0xb00040, 0x4000b0, 0x00b040, 0x0040b0,
+ 0x40b040, 0xb04040, 0x4040b0, 0xb040b0, 0x40b0b0, 0xb0b040, 0xe060b0,
+ 0x60b0e0, 0xb0e060, 0xe0b060, 0x60e0b0, 0xb060e0, 0xe0a0b0, 0xa0b0e0,
+ 0xb0e0a0, 0xe0b0a0, 0xa0e0b0, 0xb0a0e0, 0xe020b0, 0x20b0e0, 0xb0e020,
+ 0xe0b020, 0x20e0b0, 0xb020e0, 0xe0f0b0, 0xf0b0e0, 0xb0e0f0, 0xe0b0f0,
+ 0xf0e0b0, 0xb0f0e0, 0xe0b000, 0xb0e000, 0xb000e0, 0xe000b0, 0x00b0e0,
+ 0x00e0b0, 0xe0b0e0, 0xb0e0e0, 0xe0e0b0, 0xb0e0b0, 0xe0b0b0, 0xb0b0e0,
+ 0x60a0b0, 0xa0b060, 0xb060a0, 0x60b0a0, 0xa060b0, 0xb0a060, 0x6020b0,
+ 0x20b060, 0xb06020, 0x60b020, 0x2060b0, 0xb02060, 0x60f0b0, 0xf0b060,
+ 0xb060f0, 0x60b0f0, 0xf060b0, 0xb0f060, 0x60b000, 0xb06000, 0xb00060,
+ 0x6000b0, 0x00b060, 0x0060b0, 0x60b060, 0xb06060, 0x6060b0, 0xb060b0,
+ 0x60b0b0, 0xb0b060, 0xa020b0, 0x20b0a0, 0xb0a020, 0xa0b020, 0x20a0b0,
+ 0xb020a0, 0xa0f0b0, 0xf0b0a0, 0xb0a0f0, 0xa0b0f0, 0xf0a0b0, 0xb0f0a0,
+ 0xa0b000, 0xb0a000, 0xb000a0, 0xa000b0, 0x00b0a0, 0x00a0b0, 0xa0b0a0,
+ 0xb0a0a0, 0xa0a0b0, 0xb0a0b0, 0xa0b0b0, 0xb0b0a0, 0x20f0b0, 0xf0b020,
+ 0xb020f0, 0x20b0f0, 0xf020b0, 0xb0f020, 0x20b000, 0xb02000, 0xb00020,
+ 0x2000b0, 0x00b020, 0x0020b0, 0x20b020, 0xb02020, 0x2020b0, 0xb020b0,
+ 0x20b0b0, 0xb0b020, 0xf0b000, 0xb0f000, 0xb000f0, 0xf000b0, 0x00b0f0,
+ 0x00f0b0, 0xf0b0f0, 0xb0f0f0, 0xf0f0b0, 0xb0f0b0, 0xf0b0b0, 0xb0b0f0,
+ 0xb0b0b0, 0xb00000, 0x00b000, 0x0000b0, 0xb0b000, 0xb000b0, 0x00b0b0,
+ 0xff8050, 0x8050ff, 0x50ff80, 0xff5080, 0x80ff50, 0x5080ff, 0xffc050,
+ 0xc050ff, 0x50ffc0, 0xff50c0, 0xc0ff50, 0x50c0ff, 0xff4050, 0x4050ff,
+ 0x50ff40, 0xff5040, 0x40ff50, 0x5040ff, 0xffe050, 0xe050ff, 0x50ffe0,
+ 0xff50e0, 0xe0ff50, 0x50e0ff, 0xff6050, 0x6050ff, 0x50ff60, 0xff5060,
+ 0x60ff50, 0x5060ff, 0xffa050, 0xa050ff, 0x50ffa0, 0xff50a0, 0xa0ff50,
+ 0x50a0ff, 0xff2050, 0x2050ff, 0x50ff20, 0xff5020, 0x20ff50, 0x5020ff,
+ 0xfff050, 0xf050ff, 0x50fff0, 0xff50f0, 0xf0ff50, 0x50f0ff, 0xffb050,
+ 0xb050ff, 0x50ffb0, 0xff50b0, 0xb0ff50, 0x50b0ff, 0xff5000, 0x50ff00,
+ 0x5000ff, 0xff0050, 0x0050ff, 0x00ff50, 0xff50ff, 0x50ffff, 0xffff50,
+ 0x50ff50, 0xff5050, 0x5050ff, 0x80c050, 0xc05080, 0x5080c0, 0x8050c0,
+ 0xc08050, 0x50c080, 0x804050, 0x405080, 0x508040, 0x805040, 0x408050,
+ 0x504080, 0x80e050, 0xe05080, 0x5080e0, 0x8050e0, 0xe08050, 0x50e080,
+ 0x806050, 0x605080, 0x508060, 0x805060, 0x608050, 0x506080, 0x80a050,
+ 0xa05080, 0x5080a0, 0x8050a0, 0xa08050, 0x50a080, 0x802050, 0x205080,
+ 0x508020, 0x805020, 0x208050, 0x502080, 0x80f050, 0xf05080, 0x5080f0,
+ 0x8050f0, 0xf08050, 0x50f080, 0x80b050, 0xb05080, 0x5080b0, 0x8050b0,
+ 0xb08050, 0x50b080, 0x805000, 0x508000, 0x500080, 0x800050, 0x005080,
+ 0x008050, 0x805080, 0x508080, 0x808050, 0x508050, 0x805050, 0x505080,
+ 0xc04050, 0x4050c0, 0x50c040, 0xc05040, 0x40c050, 0x5040c0, 0xc0e050,
+ 0xe050c0, 0x50c0e0, 0xc050e0, 0xe0c050, 0x50e0c0, 0xc06050, 0x6050c0,
+ 0x50c060, 0xc05060, 0x60c050, 0x5060c0, 0xc0a050, 0xa050c0, 0x50c0a0,
+ 0xc050a0, 0xa0c050, 0x50a0c0, 0xc02050, 0x2050c0, 0x50c020, 0xc05020,
+ 0x20c050, 0x5020c0, 0xc0f050, 0xf050c0, 0x50c0f0, 0xc050f0, 0xf0c050,
+ 0x50f0c0, 0xc0b050, 0xb050c0, 0x50c0b0, 0xc050b0, 0xb0c050, 0x50b0c0,
+ 0xc05000, 0x50c000, 0x5000c0, 0xc00050, 0x0050c0, 0x00c050, 0xc050c0,
+ 0x50c0c0, 0xc0c050, 0x50c050, 0xc05050, 0x5050c0, 0x40e050, 0xe05040,
+ 0x5040e0, 0x4050e0, 0xe04050, 0x50e040, 0x406050, 0x605040, 0x504060,
+ 0x405060, 0x604050, 0x506040, 0x40a050, 0xa05040, 0x5040a0, 0x4050a0,
+ 0xa04050, 0x50a040, 0x402050, 0x205040, 0x504020, 0x405020, 0x204050,
+ 0x502040, 0x40f050, 0xf05040, 0x5040f0, 0x4050f0, 0xf04050, 0x50f040,
+ 0x40b050, 0xb05040, 0x5040b0, 0x4050b0, 0xb04050, 0x50b040, 0x405000,
+ 0x504000, 0x500040, 0x400050, 0x005040, 0x004050, 0x405040, 0x504040,
+ 0x404050, 0x504050, 0x405050, 0x505040, 0xe06050, 0x6050e0, 0x50e060,
+ 0xe05060, 0x60e050, 0x5060e0, 0xe0a050, 0xa050e0, 0x50e0a0, 0xe050a0,
+ 0xa0e050, 0x50a0e0, 0xe02050, 0x2050e0, 0x50e020, 0xe05020, 0x20e050,
+ 0x5020e0, 0xe0f050, 0xf050e0, 0x50e0f0, 0xe050f0, 0xf0e050, 0x50f0e0,
+ 0xe0b050, 0xb050e0, 0x50e0b0, 0xe050b0, 0xb0e050, 0x50b0e0, 0xe05000,
+ 0x50e000, 0x5000e0, 0xe00050, 0x0050e0, 0x00e050, 0xe050e0, 0x50e0e0,
+ 0xe0e050, 0x50e050, 0xe05050, 0x5050e0, 0x60a050, 0xa05060, 0x5060a0,
+ 0x6050a0, 0xa06050, 0x50a060, 0x602050, 0x205060, 0x506020, 0x605020,
+ 0x206050, 0x502060, 0x60f050, 0xf05060, 0x5060f0, 0x6050f0, 0xf06050,
+ 0x50f060, 0x60b050, 0xb05060, 0x5060b0, 0x6050b0, 0xb06050, 0x50b060,
+ 0x605000, 0x506000, 0x500060, 0x600050, 0x005060, 0x006050, 0x605060,
+ 0x506060, 0x606050, 0x506050, 0x605050, 0x505060, 0xa02050, 0x2050a0,
+ 0x50a020, 0xa05020, 0x20a050, 0x5020a0, 0xa0f050, 0xf050a0, 0x50a0f0,
+ 0xa050f0, 0xf0a050, 0x50f0a0, 0xa0b050, 0xb050a0, 0x50a0b0, 0xa050b0,
+ 0xb0a050, 0x50b0a0, 0xa05000, 0x50a000, 0x5000a0, 0xa00050, 0x0050a0,
+ 0x00a050, 0xa050a0, 0x50a0a0, 0xa0a050, 0x50a050, 0xa05050, 0x5050a0,
+ 0x20f050, 0xf05020, 0x5020f0, 0x2050f0, 0xf02050, 0x50f020, 0x20b050,
+ 0xb05020, 0x5020b0, 0x2050b0, 0xb02050, 0x50b020, 0x205000, 0x502000,
+ 0x500020, 0x200050, 0x005020, 0x002050, 0x205020, 0x502020, 0x202050,
+ 0x502050, 0x205050, 0x505020, 0xf0b050, 0xb050f0, 0x50f0b0, 0xf050b0,
+ 0xb0f050, 0x50b0f0, 0xf05000, 0x50f000, 0x5000f0, 0xf00050, 0x0050f0,
+ 0x00f050, 0xf050f0, 0x50f0f0, 0xf0f050, 0x50f050, 0xf05050, 0x5050f0,
+ 0xb05000, 0x50b000, 0x5000b0, 0xb00050, 0x0050b0, 0x00b050, 0xb050b0,
+ 0x50b0b0, 0xb0b050, 0x50b050, 0xb05050, 0x5050b0, 0x505050, 0x500000,
+ 0x005000, 0x000050, 0x505000, 0x500050, 0x005050, 0xff80d0, 0x80d0ff,
+ 0xd0ff80, 0xffd080, 0x80ffd0, 0xd080ff, 0xffc0d0, 0xc0d0ff, 0xd0ffc0,
+ 0xffd0c0, 0xc0ffd0, 0xd0c0ff, 0xff40d0, 0x40d0ff, 0xd0ff40, 0xffd040,
+ 0x40ffd0, 0xd040ff, 0xffe0d0, 0xe0d0ff, 0xd0ffe0, 0xffd0e0, 0xe0ffd0,
+ 0xd0e0ff, 0xff60d0, 0x60d0ff, 0xd0ff60, 0xffd060, 0x60ffd0, 0xd060ff,
+ 0xffa0d0, 0xa0d0ff, 0xd0ffa0, 0xffd0a0, 0xa0ffd0, 0xd0a0ff, 0xff20d0,
+ 0x20d0ff, 0xd0ff20, 0xffd020, 0x20ffd0, 0xd020ff, 0xfff0d0, 0xf0d0ff,
+ 0xd0fff0, 0xffd0f0, 0xf0ffd0, 0xd0f0ff, 0xffb0d0, 0xb0d0ff, 0xd0ffb0,
+ 0xffd0b0, 0xb0ffd0, 0xd0b0ff, 0xff50d0, 0x50d0ff, 0xd0ff50, 0xffd050,
+ 0x50ffd0, 0xd050ff, 0xffd000, 0xd0ff00, 0xd000ff, 0xff00d0, 0x00d0ff,
+ 0x00ffd0, 0xffd0ff, 0xd0ffff, 0xffffd0, 0xd0ffd0, 0xffd0d0, 0xd0d0ff,
+ 0x80c0d0, 0xc0d080, 0xd080c0, 0x80d0c0, 0xc080d0, 0xd0c080, 0x8040d0,
+ 0x40d080, 0xd08040, 0x80d040, 0x4080d0, 0xd04080, 0x80e0d0, 0xe0d080,
+ 0xd080e0, 0x80d0e0, 0xe080d0, 0xd0e080, 0x8060d0, 0x60d080, 0xd08060,
+ 0x80d060, 0x6080d0, 0xd06080, 0x80a0d0, 0xa0d080, 0xd080a0, 0x80d0a0,
+ 0xa080d0, 0xd0a080, 0x8020d0, 0x20d080, 0xd08020, 0x80d020, 0x2080d0,
+ 0xd02080, 0x80f0d0, 0xf0d080, 0xd080f0, 0x80d0f0, 0xf080d0, 0xd0f080,
+ 0x80b0d0, 0xb0d080, 0xd080b0, 0x80d0b0, 0xb080d0, 0xd0b080, 0x8050d0,
+ 0x50d080, 0xd08050, 0x80d050, 0x5080d0, 0xd05080, 0x80d000, 0xd08000,
+ 0xd00080, 0x8000d0, 0x00d080, 0x0080d0, 0x80d080, 0xd08080, 0x8080d0,
+ 0xd080d0, 0x80d0d0, 0xd0d080, 0xc040d0, 0x40d0c0, 0xd0c040, 0xc0d040,
+ 0x40c0d0, 0xd040c0, 0xc0e0d0, 0xe0d0c0, 0xd0c0e0, 0xc0d0e0, 0xe0c0d0,
+ 0xd0e0c0, 0xc060d0, 0x60d0c0, 0xd0c060, 0xc0d060, 0x60c0d0, 0xd060c0,
+ 0xc0a0d0, 0xa0d0c0, 0xd0c0a0, 0xc0d0a0, 0xa0c0d0, 0xd0a0c0, 0xc020d0,
+ 0x20d0c0, 0xd0c020, 0xc0d020, 0x20c0d0, 0xd020c0, 0xc0f0d0, 0xf0d0c0,
+ 0xd0c0f0, 0xc0d0f0, 0xf0c0d0, 0xd0f0c0, 0xc0b0d0, 0xb0d0c0, 0xd0c0b0,
+ 0xc0d0b0, 0xb0c0d0, 0xd0b0c0, 0xc050d0, 0x50d0c0, 0xd0c050, 0xc0d050,
+ 0x50c0d0, 0xd050c0, 0xc0d000, 0xd0c000, 0xd000c0, 0xc000d0, 0x00d0c0,
+ 0x00c0d0, 0xc0d0c0, 0xd0c0c0, 0xc0c0d0, 0xd0c0d0, 0xc0d0d0, 0xd0d0c0,
+ 0x40e0d0, 0xe0d040, 0xd040e0, 0x40d0e0, 0xe040d0, 0xd0e040, 0x4060d0,
+ 0x60d040, 0xd04060, 0x40d060, 0x6040d0, 0xd06040, 0x40a0d0, 0xa0d040,
+ 0xd040a0, 0x40d0a0, 0xa040d0, 0xd0a040, 0x4020d0, 0x20d040, 0xd04020,
+ 0x40d020, 0x2040d0, 0xd02040, 0x40f0d0, 0xf0d040, 0xd040f0, 0x40d0f0,
+ 0xf040d0, 0xd0f040, 0x40b0d0, 0xb0d040, 0xd040b0, 0x40d0b0, 0xb040d0,
+ 0xd0b040, 0x4050d0, 0x50d040, 0xd04050, 0x40d050, 0x5040d0, 0xd05040,
+ 0x40d000, 0xd04000, 0xd00040, 0x4000d0, 0x00d040, 0x0040d0, 0x40d040,
+ 0xd04040, 0x4040d0, 0xd040d0, 0x40d0d0, 0xd0d040, 0xe060d0, 0x60d0e0,
+ 0xd0e060, 0xe0d060, 0x60e0d0, 0xd060e0, 0xe0a0d0, 0xa0d0e0, 0xd0e0a0,
+ 0xe0d0a0, 0xa0e0d0, 0xd0a0e0, 0xe020d0, 0x20d0e0, 0xd0e020, 0xe0d020,
+ 0x20e0d0, 0xd020e0, 0xe0f0d0, 0xf0d0e0, 0xd0e0f0, 0xe0d0f0, 0xf0e0d0,
+ 0xd0f0e0, 0xe0b0d0, 0xb0d0e0, 0xd0e0b0, 0xe0d0b0, 0xb0e0d0, 0xd0b0e0,
+ 0xe050d0, 0x50d0e0, 0xd0e050, 0xe0d050, 0x50e0d0, 0xd050e0, 0xe0d000,
+ 0xd0e000, 0xd000e0, 0xe000d0, 0x00d0e0, 0x00e0d0, 0xe0d0e0, 0xd0e0e0,
+ 0xe0e0d0, 0xd0e0d0, 0xe0d0d0, 0xd0d0e0, 0x60a0d0, 0xa0d060, 0xd060a0,
+ 0x60d0a0, 0xa060d0, 0xd0a060, 0x6020d0, 0x20d060, 0xd06020, 0x60d020,
+ 0x2060d0, 0xd02060, 0x60f0d0, 0xf0d060, 0xd060f0, 0x60d0f0, 0xf060d0,
+ 0xd0f060, 0x60b0d0, 0xb0d060, 0xd060b0, 0x60d0b0, 0xb060d0, 0xd0b060,
+ 0x6050d0, 0x50d060, 0xd06050, 0x60d050, 0x5060d0, 0xd05060, 0x60d000,
+ 0xd06000, 0xd00060, 0x6000d0, 0x00d060, 0x0060d0, 0x60d060, 0xd06060,
+ 0x6060d0, 0xd060d0, 0x60d0d0, 0xd0d060, 0xa020d0, 0x20d0a0, 0xd0a020,
+ 0xa0d020, 0x20a0d0, 0xd020a0, 0xa0f0d0, 0xf0d0a0, 0xd0a0f0, 0xa0d0f0,
+ 0xf0a0d0, 0xd0f0a0, 0xa0b0d0, 0xb0d0a0, 0xd0a0b0, 0xa0d0b0, 0xb0a0d0,
+ 0xd0b0a0, 0xa050d0, 0x50d0a0, 0xd0a050, 0xa0d050, 0x50a0d0, 0xd050a0,
+ 0xa0d000, 0xd0a000, 0xd000a0, 0xa000d0, 0x00d0a0, 0x00a0d0, 0xa0d0a0,
+ 0xd0a0a0, 0xa0a0d0, 0xd0a0d0, 0xa0d0d0, 0xd0d0a0, 0x20f0d0, 0xf0d020,
+ 0xd020f0, 0x20d0f0, 0xf020d0, 0xd0f020, 0x20b0d0, 0xb0d020, 0xd020b0,
+ 0x20d0b0, 0xb020d0, 0xd0b020, 0x2050d0, 0x50d020, 0xd02050, 0x20d050,
+ 0x5020d0, 0xd05020, 0x20d000, 0xd02000, 0xd00020, 0x2000d0, 0x00d020,
+ 0x0020d0, 0x20d020, 0xd02020, 0x2020d0, 0xd020d0, 0x20d0d0, 0xd0d020,
+ 0xf0b0d0, 0xb0d0f0, 0xd0f0b0, 0xf0d0b0, 0xb0f0d0, 0xd0b0f0, 0xf050d0,
+ 0x50d0f0, 0xd0f050, 0xf0d050, 0x50f0d0, 0xd050f0, 0xf0d000, 0xd0f000,
+ 0xd000f0, 0xf000d0, 0x00d0f0, 0x00f0d0, 0xf0d0f0, 0xd0f0f0, 0xf0f0d0,
+ 0xd0f0d0, 0xf0d0d0, 0xd0d0f0, 0xb050d0, 0x50d0b0, 0xd0b050, 0xb0d050,
+ 0x50b0d0, 0xd050b0, 0xb0d000, 0xd0b000, 0xd000b0, 0xb000d0, 0x00d0b0,
+ 0x00b0d0, 0xb0d0b0, 0xd0b0b0, 0xb0b0d0, 0xd0b0d0, 0xb0d0d0, 0xd0d0b0,
+ 0x50d000, 0xd05000, 0xd00050, 0x5000d0, 0x00d050, 0x0050d0, 0x50d050,
+ 0xd05050, 0x5050d0, 0xd050d0, 0x50d0d0, 0xd0d050, 0xd0d0d0, 0xd00000,
+ 0x00d000, 0x0000d0, 0xd0d000, 0xd000d0, 0x00d0d0, 0xff8070, 0x8070ff,
+ 0x70ff80, 0xff7080, 0x80ff70, 0x7080ff, 0xffc070, 0xc070ff, 0x70ffc0,
+ 0xff70c0, 0xc0ff70, 0x70c0ff, 0xff4070, 0x4070ff, 0x70ff40, 0xff7040,
+ 0x40ff70, 0x7040ff, 0xffe070, 0xe070ff, 0x70ffe0, 0xff70e0, 0xe0ff70,
+ 0x70e0ff, 0xff6070, 0x6070ff, 0x70ff60, 0xff7060, 0x60ff70, 0x7060ff,
+ 0xffa070, 0xa070ff, 0x70ffa0, 0xff70a0, 0xa0ff70, 0x70a0ff, 0xff2070,
+ 0x2070ff, 0x70ff20, 0xff7020, 0x20ff70, 0x7020ff, 0xfff070, 0xf070ff,
+ 0x70fff0, 0xff70f0, 0xf0ff70, 0x70f0ff, 0xffb070, 0xb070ff, 0x70ffb0,
+ 0xff70b0, 0xb0ff70, 0x70b0ff, 0xff5070, 0x5070ff, 0x70ff50, 0xff7050,
+ 0x50ff70, 0x7050ff, 0xffd070, 0xd070ff, 0x70ffd0, 0xff70d0, 0xd0ff70,
+ 0x70d0ff, 0xff7000, 0x70ff00, 0x7000ff, 0xff0070, 0x0070ff, 0x00ff70,
+ 0xff70ff, 0x70ffff, 0xffff70, 0x70ff70, 0xff7070, 0x7070ff, 0x80c070,
+ 0xc07080, 0x7080c0, 0x8070c0, 0xc08070, 0x70c080, 0x804070, 0x407080,
+ 0x708040, 0x807040, 0x408070, 0x704080, 0x80e070, 0xe07080, 0x7080e0,
+ 0x8070e0, 0xe08070, 0x70e080, 0x806070, 0x607080, 0x708060, 0x807060,
+ 0x608070, 0x706080, 0x80a070, 0xa07080, 0x7080a0, 0x8070a0, 0xa08070,
+ 0x70a080, 0x802070, 0x207080, 0x708020, 0x807020, 0x208070, 0x702080,
+ 0x80f070, 0xf07080, 0x7080f0, 0x8070f0, 0xf08070, 0x70f080, 0x80b070,
+ 0xb07080, 0x7080b0, 0x8070b0, 0xb08070, 0x70b080, 0x805070, 0x507080,
+ 0x708050, 0x807050, 0x508070, 0x705080, 0x80d070, 0xd07080, 0x7080d0,
+ 0x8070d0, 0xd08070, 0x70d080, 0x807000, 0x708000, 0x700080, 0x800070,
+ 0x007080, 0x008070, 0x807080, 0x708080, 0x808070, 0x708070, 0x807070,
+ 0x707080, 0xc04070, 0x4070c0, 0x70c040, 0xc07040, 0x40c070, 0x7040c0,
+ 0xc0e070, 0xe070c0, 0x70c0e0, 0xc070e0, 0xe0c070, 0x70e0c0, 0xc06070,
+ 0x6070c0, 0x70c060, 0xc07060, 0x60c070, 0x7060c0, 0xc0a070, 0xa070c0,
+ 0x70c0a0, 0xc070a0, 0xa0c070, 0x70a0c0, 0xc02070, 0x2070c0, 0x70c020,
+ 0xc07020, 0x20c070, 0x7020c0, 0xc0f070, 0xf070c0, 0x70c0f0, 0xc070f0,
+ 0xf0c070, 0x70f0c0, 0xc0b070, 0xb070c0, 0x70c0b0, 0xc070b0, 0xb0c070,
+ 0x70b0c0, 0xc05070, 0x5070c0, 0x70c050, 0xc07050, 0x50c070, 0x7050c0,
+ 0xc0d070, 0xd070c0, 0x70c0d0, 0xc070d0, 0xd0c070, 0x70d0c0, 0xc07000,
+ 0x70c000, 0x7000c0, 0xc00070, 0x0070c0, 0x00c070, 0xc070c0, 0x70c0c0,
+ 0xc0c070, 0x70c070, 0xc07070, 0x7070c0, 0x40e070, 0xe07040, 0x7040e0,
+ 0x4070e0, 0xe04070, 0x70e040, 0x406070, 0x607040, 0x704060, 0x407060,
+ 0x604070, 0x706040, 0x40a070, 0xa07040, 0x7040a0, 0x4070a0, 0xa04070,
+ 0x70a040, 0x402070, 0x207040, 0x704020, 0x407020, 0x204070, 0x702040,
+ 0x40f070, 0xf07040, 0x7040f0, 0x4070f0, 0xf04070, 0x70f040, 0x40b070,
+ 0xb07040, 0x7040b0, 0x4070b0, 0xb04070, 0x70b040, 0x405070, 0x507040,
+ 0x704050, 0x407050, 0x504070, 0x705040, 0x40d070, 0xd07040, 0x7040d0,
+ 0x4070d0, 0xd04070, 0x70d040, 0x407000, 0x704000, 0x700040, 0x400070,
+ 0x007040, 0x004070, 0x407040, 0x704040, 0x404070, 0x704070, 0x407070,
+ 0x707040, 0xe06070, 0x6070e0, 0x70e060, 0xe07060, 0x60e070, 0x7060e0,
+ 0xe0a070, 0xa070e0, 0x70e0a0, 0xe070a0, 0xa0e070, 0x70a0e0, 0xe02070,
+ 0x2070e0, 0x70e020, 0xe07020, 0x20e070, 0x7020e0, 0xe0f070, 0xf070e0,
+ 0x70e0f0, 0xe070f0, 0xf0e070, 0x70f0e0, 0xe0b070, 0xb070e0, 0x70e0b0,
+ 0xe070b0, 0xb0e070, 0x70b0e0, 0xe05070, 0x5070e0, 0x70e050, 0xe07050,
+ 0x50e070, 0x7050e0, 0xe0d070, 0xd070e0, 0x70e0d0, 0xe070d0, 0xd0e070,
+ 0x70d0e0, 0xe07000, 0x70e000, 0x7000e0, 0xe00070, 0x0070e0, 0x00e070,
+ 0xe070e0, 0x70e0e0, 0xe0e070, 0x70e070, 0xe07070, 0x7070e0, 0x60a070,
+ 0xa07060, 0x7060a0, 0x6070a0, 0xa06070, 0x70a060, 0x602070, 0x207060,
+ 0x706020, 0x607020, 0x206070, 0x702060, 0x60f070, 0xf07060, 0x7060f0,
+ 0x6070f0, 0xf06070, 0x70f060, 0x60b070, 0xb07060, 0x7060b0, 0x6070b0,
+ 0xb06070, 0x70b060, 0x605070, 0x507060, 0x706050, 0x607050, 0x506070,
+ 0x705060, 0x60d070, 0xd07060, 0x7060d0, 0x6070d0, 0xd06070, 0x70d060,
+ 0x607000, 0x706000, 0x700060, 0x600070, 0x007060, 0x006070, 0x607060,
+ 0x706060, 0x606070, 0x706070, 0x607070, 0x707060, 0xa02070, 0x2070a0,
+ 0x70a020, 0xa07020, 0x20a070, 0x7020a0, 0xa0f070, 0xf070a0, 0x70a0f0,
+ 0xa070f0, 0xf0a070, 0x70f0a0, 0xa0b070, 0xb070a0, 0x70a0b0, 0xa070b0,
+ 0xb0a070, 0x70b0a0, 0xa05070, 0x5070a0, 0x70a050, 0xa07050, 0x50a070,
+ 0x7050a0, 0xa0d070, 0xd070a0, 0x70a0d0, 0xa070d0, 0xd0a070, 0x70d0a0,
+ 0xa07000, 0x70a000, 0x7000a0, 0xa00070, 0x0070a0, 0x00a070, 0xa070a0,
+ 0x70a0a0, 0xa0a070, 0x70a070, 0xa07070, 0x7070a0, 0x20f070, 0xf07020,
+ 0x7020f0, 0x2070f0, 0xf02070, 0x70f020, 0x20b070, 0xb07020, 0x7020b0,
+ 0x2070b0, 0xb02070, 0x70b020, 0x205070, 0x507020, 0x702050, 0x207050,
+ 0x502070, 0x705020, 0x20d070, 0xd07020, 0x7020d0, 0x2070d0, 0xd02070,
+ 0x70d020, 0x207000, 0x702000, 0x700020, 0x200070, 0x007020, 0x002070,
+ 0x207020, 0x702020, 0x202070, 0x702070, 0x207070, 0x707020, 0xf0b070,
+ 0xb070f0, 0x70f0b0, 0xf070b0, 0xb0f070, 0x70b0f0, 0xf05070, 0x5070f0,
+ 0x70f050, 0xf07050, 0x50f070, 0x7050f0, 0xf0d070, 0xd070f0, 0x70f0d0,
+ 0xf070d0, 0xd0f070, 0x70d0f0, 0xf07000, 0x70f000, 0x7000f0, 0xf00070,
+ 0x0070f0, 0x00f070, 0xf070f0, 0x70f0f0, 0xf0f070, 0x70f070, 0xf07070,
+ 0x7070f0, 0xb05070, 0x5070b0, 0x70b050, 0xb07050, 0x50b070, 0x7050b0,
+ 0xb0d070, 0xd070b0, 0x70b0d0, 0xb070d0, 0xd0b070, 0x70d0b0, 0xb07000,
+ 0x70b000, 0x7000b0, 0xb00070, 0x0070b0, 0x00b070, 0xb070b0, 0x70b0b0,
+ 0xb0b070, 0x70b070, 0xb07070, 0x7070b0, 0x50d070, 0xd07050, 0x7050d0,
+ 0x5070d0, 0xd05070, 0x70d050, 0x507000, 0x705000, 0x700050, 0x500070,
+ 0x007050, 0x005070, 0x507050, 0x705050, 0x505070, 0x705070, 0x507070,
+ 0x707050, 0xd07000, 0x70d000, 0x7000d0, 0xd00070, 0x0070d0, 0x00d070,
+ 0xd070d0, 0x70d0d0, 0xd0d070, 0x70d070, 0xd07070, 0x7070d0, 0x707070,
+ 0x700000, 0x007000, 0x000070, 0x707000, 0x700070, 0x007070, 0xff8030,
+ 0x8030ff, 0x30ff80, 0xff3080, 0x80ff30, 0x3080ff, 0xffc030, 0xc030ff,
+ 0x30ffc0, 0xff30c0, 0xc0ff30, 0x30c0ff, 0xff4030, 0x4030ff, 0x30ff40,
+ 0xff3040, 0x40ff30, 0x3040ff, 0xffe030, 0xe030ff, 0x30ffe0, 0xff30e0,
+ 0xe0ff30, 0x30e0ff, 0xff6030, 0x6030ff, 0x30ff60, 0xff3060, 0x60ff30,
+ 0x3060ff, 0xffa030, 0xa030ff, 0x30ffa0, 0xff30a0, 0xa0ff30, 0x30a0ff,
+ 0xff2030, 0x2030ff, 0x30ff20, 0xff3020, 0x20ff30, 0x3020ff, 0xfff030,
+ 0xf030ff, 0x30fff0, 0xff30f0, 0xf0ff30, 0x30f0ff, 0xffb030, 0xb030ff,
+ 0x30ffb0, 0xff30b0, 0xb0ff30, 0x30b0ff, 0xff5030, 0x5030ff, 0x30ff50,
+ 0xff3050, 0x50ff30, 0x3050ff, 0xffd030, 0xd030ff, 0x30ffd0, 0xff30d0,
+ 0xd0ff30, 0x30d0ff, 0xff7030, 0x7030ff, 0x30ff70, 0xff3070, 0x70ff30,
+ 0x3070ff, 0xff3000, 0x30ff00, 0x3000ff, 0xff0030, 0x0030ff, 0x00ff30,
+ 0xff30ff, 0x30ffff, 0xffff30, 0x30ff30, 0xff3030, 0x3030ff, 0x80c030,
+ 0xc03080, 0x3080c0, 0x8030c0, 0xc08030, 0x30c080, 0x804030, 0x403080,
+ 0x308040, 0x803040, 0x408030, 0x304080, 0x80e030, 0xe03080, 0x3080e0,
+ 0x8030e0, 0xe08030, 0x30e080, 0x806030, 0x603080, 0x308060, 0x803060,
+ 0x608030, 0x306080, 0x80a030, 0xa03080, 0x3080a0, 0x8030a0, 0xa08030,
+ 0x30a080, 0x802030, 0x203080, 0x308020, 0x803020, 0x208030, 0x302080,
+ 0x80f030, 0xf03080, 0x3080f0, 0x8030f0, 0xf08030, 0x30f080, 0x80b030,
+ 0xb03080, 0x3080b0, 0x8030b0, 0xb08030, 0x30b080, 0x805030, 0x503080,
+ 0x308050, 0x803050, 0x508030, 0x305080, 0x80d030, 0xd03080, 0x3080d0,
+ 0x8030d0, 0xd08030, 0x30d080, 0x807030, 0x703080, 0x308070, 0x803070,
+ 0x708030, 0x307080, 0x803000, 0x308000, 0x300080, 0x800030, 0x003080,
+ 0x008030, 0x803080, 0x308080, 0x808030, 0x308030, 0x803030, 0x303080,
+ 0xc04030, 0x4030c0, 0x30c040, 0xc03040, 0x40c030, 0x3040c0, 0xc0e030,
+ 0xe030c0, 0x30c0e0, 0xc030e0, 0xe0c030, 0x30e0c0, 0xc06030, 0x6030c0,
+ 0x30c060, 0xc03060, 0x60c030, 0x3060c0, 0xc0a030, 0xa030c0, 0x30c0a0,
+ 0xc030a0, 0xa0c030, 0x30a0c0, 0xc02030, 0x2030c0, 0x30c020, 0xc03020,
+ 0x20c030, 0x3020c0, 0xc0f030, 0xf030c0, 0x30c0f0, 0xc030f0, 0xf0c030,
+ 0x30f0c0, 0xc0b030, 0xb030c0, 0x30c0b0, 0xc030b0, 0xb0c030, 0x30b0c0,
+ 0xc05030, 0x5030c0, 0x30c050, 0xc03050, 0x50c030, 0x3050c0, 0xc0d030,
+ 0xd030c0, 0x30c0d0, 0xc030d0, 0xd0c030, 0x30d0c0, 0xc07030, 0x7030c0,
+ 0x30c070, 0xc03070, 0x70c030, 0x3070c0, 0xc03000, 0x30c000, 0x3000c0,
+ 0xc00030, 0x0030c0, 0x00c030, 0xc030c0, 0x30c0c0, 0xc0c030, 0x30c030,
+ 0xc03030, 0x3030c0, 0x40e030, 0xe03040, 0x3040e0, 0x4030e0, 0xe04030,
+ 0x30e040, 0x406030, 0x603040, 0x304060, 0x403060, 0x604030, 0x306040,
+ 0x40a030, 0xa03040, 0x3040a0, 0x4030a0, 0xa04030, 0x30a040, 0x402030,
+ 0x203040, 0x304020, 0x403020, 0x204030, 0x302040, 0x40f030, 0xf03040,
+ 0x3040f0, 0x4030f0, 0xf04030, 0x30f040, 0x40b030, 0xb03040, 0x3040b0,
+ 0x4030b0, 0xb04030, 0x30b040, 0x405030, 0x503040, 0x304050, 0x403050,
+ 0x504030, 0x305040, 0x40d030, 0xd03040, 0x3040d0, 0x4030d0, 0xd04030,
+ 0x30d040, 0x407030, 0x703040, 0x304070, 0x403070, 0x704030, 0x307040,
+ 0x403000, 0x304000, 0x300040, 0x400030, 0x003040, 0x004030, 0x403040,
+ 0x304040, 0x404030, 0x304030, 0x403030, 0x303040, 0xe06030, 0x6030e0,
+ 0x30e060, 0xe03060, 0x60e030, 0x3060e0, 0xe0a030, 0xa030e0, 0x30e0a0,
+ 0xe030a0, 0xa0e030, 0x30a0e0, 0xe02030, 0x2030e0, 0x30e020, 0xe03020,
+ 0x20e030, 0x3020e0, 0xe0f030, 0xf030e0, 0x30e0f0, 0xe030f0, 0xf0e030,
+ 0x30f0e0, 0xe0b030, 0xb030e0, 0x30e0b0, 0xe030b0, 0xb0e030, 0x30b0e0,
+ 0xe05030, 0x5030e0, 0x30e050, 0xe03050, 0x50e030, 0x3050e0, 0xe0d030,
+ 0xd030e0, 0x30e0d0, 0xe030d0, 0xd0e030, 0x30d0e0, 0xe07030, 0x7030e0,
+ 0x30e070, 0xe03070, 0x70e030, 0x3070e0, 0xe03000, 0x30e000, 0x3000e0,
+ 0xe00030, 0x0030e0, 0x00e030, 0xe030e0, 0x30e0e0, 0xe0e030, 0x30e030,
+ 0xe03030, 0x3030e0, 0x60a030, 0xa03060, 0x3060a0, 0x6030a0, 0xa06030,
+ 0x30a060, 0x602030, 0x203060, 0x306020, 0x603020, 0x206030, 0x302060,
+ 0x60f030, 0xf03060, 0x3060f0, 0x6030f0, 0xf06030, 0x30f060, 0x60b030,
+ 0xb03060, 0x3060b0, 0x6030b0, 0xb06030, 0x30b060, 0x605030, 0x503060,
+ 0x306050, 0x603050, 0x506030, 0x305060, 0x60d030, 0xd03060, 0x3060d0,
+ 0x6030d0, 0xd06030, 0x30d060, 0x607030, 0x703060, 0x306070, 0x603070,
+ 0x706030, 0x307060, 0x603000, 0x306000, 0x300060, 0x600030, 0x003060,
+ 0x006030, 0x603060, 0x306060, 0x606030, 0x306030, 0x603030, 0x303060,
+ 0xa02030, 0x2030a0, 0x30a020, 0xa03020, 0x20a030, 0x3020a0, 0xa0f030,
+ 0xf030a0, 0x30a0f0, 0xa030f0, 0xf0a030, 0x30f0a0, 0xa0b030, 0xb030a0,
+ 0x30a0b0, 0xa030b0, 0xb0a030, 0x30b0a0, 0xa05030, 0x5030a0, 0x30a050,
+ 0xa03050, 0x50a030, 0x3050a0, 0xa0d030, 0xd030a0, 0x30a0d0, 0xa030d0,
+ 0xd0a030, 0x30d0a0, 0xa07030, 0x7030a0, 0x30a070, 0xa03070, 0x70a030,
+ 0x3070a0, 0xa03000, 0x30a000, 0x3000a0, 0xa00030, 0x0030a0, 0x00a030,
+ 0xa030a0, 0x30a0a0, 0xa0a030, 0x30a030, 0xa03030, 0x3030a0, 0x20f030,
+ 0xf03020, 0x3020f0, 0x2030f0, 0xf02030, 0x30f020, 0x20b030, 0xb03020,
+ 0x3020b0, 0x2030b0, 0xb02030, 0x30b020, 0x205030, 0x503020, 0x302050,
+ 0x203050, 0x502030, 0x305020, 0x20d030, 0xd03020, 0x3020d0, 0x2030d0,
+ 0xd02030, 0x30d020, 0x207030, 0x703020, 0x302070, 0x203070, 0x702030,
+ 0x307020, 0x203000, 0x302000, 0x300020, 0x200030, 0x003020, 0x002030,
+ 0x203020, 0x302020, 0x202030, 0x302030, 0x203030, 0x303020, 0xf0b030,
+ 0xb030f0, 0x30f0b0, 0xf030b0, 0xb0f030, 0x30b0f0, 0xf05030, 0x5030f0,
+ 0x30f050, 0xf03050, 0x50f030, 0x3050f0, 0xf0d030, 0xd030f0, 0x30f0d0,
+ 0xf030d0, 0xd0f030, 0x30d0f0, 0xf07030, 0x7030f0, 0x30f070, 0xf03070,
+ 0x70f030, 0x3070f0, 0xf03000, 0x30f000, 0x3000f0, 0xf00030, 0x0030f0,
+ 0x00f030, 0xf030f0, 0x30f0f0, 0xf0f030, 0x30f030, 0xf03030, 0x3030f0,
+ 0xb05030, 0x5030b0, 0x30b050, 0xb03050, 0x50b030, 0x3050b0, 0xb0d030,
+ 0xd030b0, 0x30b0d0, 0xb030d0, 0xd0b030, 0x30d0b0, 0xb07030, 0x7030b0,
+ 0x30b070, 0xb03070, 0x70b030, 0x3070b0, 0xb03000, 0x30b000, 0x3000b0,
+ 0xb00030, 0x0030b0, 0x00b030, 0xb030b0, 0x30b0b0, 0xb0b030, 0x30b030,
+ 0xb03030, 0x3030b0, 0x50d030, 0xd03050, 0x3050d0, 0x5030d0, 0xd05030,
+ 0x30d050, 0x507030, 0x703050, 0x305070, 0x503070, 0x705030, 0x307050,
+ 0x503000, 0x305000, 0x300050, 0x500030, 0x003050, 0x005030, 0x503050,
+ 0x305050, 0x505030, 0x305030, 0x503030, 0x303050, 0xd07030, 0x7030d0,
+ 0x30d070, 0xd03070, 0x70d030, 0x3070d0, 0xd03000, 0x30d000, 0x3000d0,
+ 0xd00030, 0x0030d0, 0x00d030, 0xd030d0, 0x30d0d0, 0xd0d030, 0x30d030,
+ 0xd03030, 0x3030d0, 0x703000, 0x307000, 0x300070, 0x700030, 0x003070,
+ 0x007030, 0x703070, 0x307070, 0x707030, 0x307030, 0x703030, 0x303070,
+ 0x303030, 0x300000, 0x003000, 0x000030, 0x303000, 0x300030, 0x003030,
+ 0xff8090, 0x8090ff, 0x90ff80, 0xff9080, 0x80ff90, 0x9080ff, 0xffc090,
+ 0xc090ff, 0x90ffc0, 0xff90c0, 0xc0ff90, 0x90c0ff, 0xff4090, 0x4090ff,
+ 0x90ff40, 0xff9040, 0x40ff90, 0x9040ff, 0xffe090, 0xe090ff, 0x90ffe0,
+ 0xff90e0, 0xe0ff90, 0x90e0ff, 0xff6090, 0x6090ff, 0x90ff60, 0xff9060,
+ 0x60ff90, 0x9060ff, 0xffa090, 0xa090ff, 0x90ffa0, 0xff90a0, 0xa0ff90,
+ 0x90a0ff, 0xff2090, 0x2090ff, 0x90ff20, 0xff9020, 0x20ff90, 0x9020ff,
+ 0xfff090, 0xf090ff, 0x90fff0, 0xff90f0, 0xf0ff90, 0x90f0ff, 0xffb090,
+ 0xb090ff, 0x90ffb0, 0xff90b0, 0xb0ff90, 0x90b0ff, 0xff5090, 0x5090ff,
+ 0x90ff50, 0xff9050, 0x50ff90, 0x9050ff, 0xffd090, 0xd090ff, 0x90ffd0,
+ 0xff90d0, 0xd0ff90, 0x90d0ff, 0xff7090, 0x7090ff, 0x90ff70, 0xff9070,
+ 0x70ff90, 0x9070ff, 0xff3090, 0x3090ff, 0x90ff30, 0xff9030, 0x30ff90,
+ 0x9030ff, 0xff9000, 0x90ff00, 0x9000ff, 0xff0090, 0x0090ff, 0x00ff90,
+ 0xff90ff, 0x90ffff, 0xffff90, 0x90ff90, 0xff9090, 0x9090ff, 0x80c090,
+ 0xc09080, 0x9080c0, 0x8090c0, 0xc08090, 0x90c080, 0x804090, 0x409080,
+ 0x908040, 0x809040, 0x408090, 0x904080, 0x80e090, 0xe09080, 0x9080e0,
+ 0x8090e0, 0xe08090, 0x90e080, 0x806090, 0x609080, 0x908060, 0x809060,
+ 0x608090, 0x906080, 0x80a090, 0xa09080, 0x9080a0, 0x8090a0, 0xa08090,
+ 0x90a080, 0x802090, 0x209080, 0x908020, 0x809020, 0x208090, 0x902080,
+ 0x80f090, 0xf09080, 0x9080f0, 0x8090f0, 0xf08090, 0x90f080, 0x80b090,
+ 0xb09080, 0x9080b0, 0x8090b0, 0xb08090, 0x90b080, 0x805090, 0x509080,
+ 0x908050, 0x809050, 0x508090, 0x905080, 0x80d090, 0xd09080, 0x9080d0,
+ 0x8090d0, 0xd08090, 0x90d080, 0x807090, 0x709080, 0x908070, 0x809070,
+ 0x708090, 0x907080, 0x803090, 0x309080, 0x908030, 0x809030, 0x308090,
+ 0x903080, 0x809000, 0x908000, 0x900080, 0x800090, 0x009080, 0x008090,
+ 0x809080, 0x908080, 0x808090, 0x908090, 0x809090, 0x909080, 0xc04090,
+ 0x4090c0, 0x90c040, 0xc09040, 0x40c090, 0x9040c0, 0xc0e090, 0xe090c0,
+ 0x90c0e0, 0xc090e0, 0xe0c090, 0x90e0c0, 0xc06090, 0x6090c0, 0x90c060,
+ 0xc09060, 0x60c090, 0x9060c0, 0xc0a090, 0xa090c0, 0x90c0a0, 0xc090a0,
+ 0xa0c090, 0x90a0c0, 0xc02090, 0x2090c0, 0x90c020, 0xc09020, 0x20c090,
+ 0x9020c0, 0xc0f090, 0xf090c0, 0x90c0f0, 0xc090f0, 0xf0c090, 0x90f0c0,
+ 0xc0b090, 0xb090c0, 0x90c0b0, 0xc090b0, 0xb0c090, 0x90b0c0, 0xc05090,
+ 0x5090c0, 0x90c050, 0xc09050, 0x50c090, 0x9050c0, 0xc0d090, 0xd090c0,
+ 0x90c0d0, 0xc090d0, 0xd0c090, 0x90d0c0, 0xc07090, 0x7090c0, 0x90c070,
+ 0xc09070, 0x70c090, 0x9070c0, 0xc03090, 0x3090c0, 0x90c030, 0xc09030,
+ 0x30c090, 0x9030c0, 0xc09000, 0x90c000, 0x9000c0, 0xc00090, 0x0090c0,
+ 0x00c090, 0xc090c0, 0x90c0c0, 0xc0c090, 0x90c090, 0xc09090, 0x9090c0,
+ 0x40e090, 0xe09040, 0x9040e0, 0x4090e0, 0xe04090, 0x90e040, 0x406090,
+ 0x609040, 0x904060, 0x409060, 0x604090, 0x906040, 0x40a090, 0xa09040,
+ 0x9040a0, 0x4090a0, 0xa04090, 0x90a040, 0x402090, 0x209040, 0x904020,
+ 0x409020, 0x204090, 0x902040, 0x40f090, 0xf09040, 0x9040f0, 0x4090f0,
+ 0xf04090, 0x90f040, 0x40b090, 0xb09040, 0x9040b0, 0x4090b0, 0xb04090,
+ 0x90b040, 0x405090, 0x509040, 0x904050, 0x409050, 0x504090, 0x905040,
+ 0x40d090, 0xd09040, 0x9040d0, 0x4090d0, 0xd04090, 0x90d040, 0x407090,
+ 0x709040, 0x904070, 0x409070, 0x704090, 0x907040, 0x403090, 0x309040,
+ 0x904030, 0x409030, 0x304090, 0x903040, 0x409000, 0x904000, 0x900040,
+ 0x400090, 0x009040, 0x004090, 0x409040, 0x904040, 0x404090, 0x904090,
+ 0x409090, 0x909040, 0xe06090, 0x6090e0, 0x90e060, 0xe09060, 0x60e090,
+ 0x9060e0, 0xe0a090, 0xa090e0, 0x90e0a0, 0xe090a0, 0xa0e090, 0x90a0e0,
+ 0xe02090, 0x2090e0, 0x90e020, 0xe09020, 0x20e090, 0x9020e0, 0xe0f090,
+ 0xf090e0, 0x90e0f0, 0xe090f0, 0xf0e090, 0x90f0e0, 0xe0b090, 0xb090e0,
+ 0x90e0b0, 0xe090b0, 0xb0e090, 0x90b0e0, 0xe05090, 0x5090e0, 0x90e050,
+ 0xe09050, 0x50e090, 0x9050e0, 0xe0d090, 0xd090e0, 0x90e0d0, 0xe090d0,
+ 0xd0e090, 0x90d0e0, 0xe07090, 0x7090e0, 0x90e070, 0xe09070, 0x70e090,
+ 0x9070e0, 0xe03090, 0x3090e0, 0x90e030, 0xe09030, 0x30e090, 0x9030e0,
+ 0xe09000, 0x90e000, 0x9000e0, 0xe00090, 0x0090e0, 0x00e090, 0xe090e0,
+ 0x90e0e0, 0xe0e090, 0x90e090, 0xe09090, 0x9090e0, 0x60a090, 0xa09060,
+ 0x9060a0, 0x6090a0, 0xa06090, 0x90a060, 0x602090, 0x209060, 0x906020,
+ 0x609020, 0x206090, 0x902060, 0x60f090, 0xf09060, 0x9060f0, 0x6090f0,
+ 0xf06090, 0x90f060, 0x60b090, 0xb09060, 0x9060b0, 0x6090b0, 0xb06090,
+ 0x90b060, 0x605090, 0x509060, 0x906050, 0x609050, 0x506090, 0x905060,
+ 0x60d090, 0xd09060, 0x9060d0, 0x6090d0, 0xd06090, 0x90d060, 0x607090,
+ 0x709060, 0x906070, 0x609070, 0x706090, 0x907060, 0x603090, 0x309060,
+ 0x906030, 0x609030, 0x306090, 0x903060, 0x609000, 0x906000, 0x900060,
+ 0x600090, 0x009060, 0x006090, 0x609060, 0x906060, 0x606090, 0x906090,
+ 0x609090, 0x909060, 0xa02090, 0x2090a0, 0x90a020, 0xa09020, 0x20a090,
+ 0x9020a0, 0xa0f090, 0xf090a0, 0x90a0f0, 0xa090f0, 0xf0a090, 0x90f0a0,
+ 0xa0b090, 0xb090a0, 0x90a0b0, 0xa090b0, 0xb0a090, 0x90b0a0, 0xa05090,
+ 0x5090a0, 0x90a050, 0xa09050, 0x50a090, 0x9050a0, 0xa0d090, 0xd090a0,
+ 0x90a0d0, 0xa090d0, 0xd0a090, 0x90d0a0, 0xa07090, 0x7090a0, 0x90a070,
+ 0xa09070, 0x70a090, 0x9070a0, 0xa03090, 0x3090a0, 0x90a030, 0xa09030,
+ 0x30a090, 0x9030a0, 0xa09000, 0x90a000, 0x9000a0, 0xa00090, 0x0090a0,
+ 0x00a090, 0xa090a0, 0x90a0a0, 0xa0a090, 0x90a090, 0xa09090, 0x9090a0,
+ 0x20f090, 0xf09020, 0x9020f0, 0x2090f0, 0xf02090, 0x90f020, 0x20b090,
+ 0xb09020, 0x9020b0, 0x2090b0, 0xb02090, 0x90b020, 0x205090, 0x509020,
+ 0x902050, 0x209050, 0x502090, 0x905020, 0x20d090, 0xd09020, 0x9020d0,
+ 0x2090d0, 0xd02090, 0x90d020, 0x207090, 0x709020, 0x902070, 0x209070,
+ 0x702090, 0x907020, 0x203090, 0x309020, 0x902030, 0x209030, 0x302090,
+ 0x903020, 0x209000, 0x902000, 0x900020, 0x200090, 0x009020, 0x002090,
+ 0x209020, 0x902020, 0x202090, 0x902090, 0x209090, 0x909020, 0xf0b090,
+ 0xb090f0, 0x90f0b0, 0xf090b0, 0xb0f090, 0x90b0f0, 0xf05090, 0x5090f0,
+ 0x90f050, 0xf09050, 0x50f090, 0x9050f0, 0xf0d090, 0xd090f0, 0x90f0d0,
+ 0xf090d0, 0xd0f090, 0x90d0f0, 0xf07090, 0x7090f0, 0x90f070, 0xf09070,
+ 0x70f090, 0x9070f0, 0xf03090, 0x3090f0, 0x90f030, 0xf09030, 0x30f090,
+ 0x9030f0, 0xf09000, 0x90f000, 0x9000f0, 0xf00090, 0x0090f0, 0x00f090,
+ 0xf090f0, 0x90f0f0, 0xf0f090, 0x90f090, 0xf09090, 0x9090f0, 0xb05090,
+ 0x5090b0, 0x90b050, 0xb09050, 0x50b090, 0x9050b0, 0xb0d090, 0xd090b0,
+ 0x90b0d0, 0xb090d0, 0xd0b090, 0x90d0b0, 0xb07090, 0x7090b0, 0x90b070,
+ 0xb09070, 0x70b090, 0x9070b0, 0xb03090, 0x3090b0, 0x90b030, 0xb09030,
+ 0x30b090, 0x9030b0, 0xb09000, 0x90b000, 0x9000b0, 0xb00090, 0x0090b0,
+ 0x00b090, 0xb090b0, 0x90b0b0, 0xb0b090, 0x90b090, 0xb09090, 0x9090b0,
+ 0x50d090, 0xd09050, 0x9050d0, 0x5090d0, 0xd05090, 0x90d050, 0x507090,
+ 0x709050, 0x905070, 0x509070, 0x705090, 0x907050, 0x503090, 0x309050,
+ 0x905030, 0x509030, 0x305090, 0x903050, 0x509000, 0x905000, 0x900050,
+ 0x500090, 0x009050, 0x005090, 0x509050, 0x905050, 0x505090, 0x905090,
+ 0x509090, 0x909050, 0xd07090, 0x7090d0, 0x90d070, 0xd09070, 0x70d090,
+ 0x9070d0, 0xd03090, 0x3090d0, 0x90d030, 0xd09030, 0x30d090, 0x9030d0,
+ 0xd09000, 0x90d000, 0x9000d0, 0xd00090, 0x0090d0, 0x00d090, 0xd090d0,
+ 0x90d0d0, 0xd0d090, 0x90d090, 0xd09090, 0x9090d0, 0x703090, 0x309070,
+ 0x907030, 0x709030, 0x307090, 0x903070, 0x709000, 0x907000, 0x900070,
+ 0x700090, 0x009070, 0x007090, 0x709070, 0x907070, 0x707090, 0x907090,
+ 0x709090, 0x909070, 0x309000, 0x903000, 0x900030, 0x300090, 0x009030,
+ 0x003090, 0x309030, 0x903030, 0x303090, 0x903090, 0x309090, 0x909030,
+ 0x909090, 0x900000, 0x009000, 0x000090, 0x909000, 0x900090, 0x009090,
+ 0xff8010
+};
+
+static unsigned char const pickMapComponent[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+ 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+ 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+ 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
+ 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
+ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0,
+ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static unsigned char const pickMapComponent444[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x00, 0x00, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
+ 0x00, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+ 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+ 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+ 0xb0, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0xe0,
+ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0,
+ 0xe0, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+#define MAX_PICK_COLORS 4096
+
+// Get the value at "index" to use for color picking. Returns a zero
+// QRgb when the table has been exhausted.
+QRgb qt_qgl_pick_color(int index)
+{
+ if (index >= 0 && index < MAX_PICK_COLORS)
+ return QRgb(pickColors[index] | 0xff000000);
+ else
+ return 0;
+}
+
+// Normalize a color that was picked out of a screen color buffer
+// so that it is a better match for something that was generated
+// by qt_qgl_pick_color(). Rounding discrepancies in the
+// low bits due to floating-point conversions are factored out.
+QRgb qt_qgl_normalize_pick_color(QRgb color, bool is444)
+{
+ int red, green, blue;
+ if (!is444) {
+ // RGB565, RGB555, and RGB888 screens (alpha is ignored).
+ red = pickMapComponent[qRed(color)];
+ green = pickMapComponent[qGreen(color)];
+ blue = pickMapComponent[qBlue(color)];
+ } else {
+ // RGB444 screens need a little more care when normalizing.
+ red = pickMapComponent444[qRed(color)];
+ green = pickMapComponent444[qGreen(color)];
+ blue = pickMapComponent444[qBlue(color)];
+ }
+ return qRgb(red, green, blue);
+}
+
+QT_END_NAMESPACE
+
+#else // QGL_GENERATOR_PROGRAM
+
+#include <stdio.h>
+
+static unsigned char singlePatterns[] = {
+ 1, 1, 1,
+
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1,
+ 1, 1, 0,
+ 1, 0, 1,
+ 0, 1, 1
+};
+#define NUM_SINGLE_PATTERNS 7
+
+static unsigned char doublePatterns[] = {
+ 1, 2, 0,
+ 2, 1, 0,
+ 2, 0, 1,
+ 1, 0, 2,
+ 0, 2, 1,
+ 0, 1, 2,
+
+ 1, 2, 1,
+ 2, 1, 1,
+ 1, 1, 2,
+ 2, 1, 2,
+ 1, 2, 2,
+ 2, 2, 1
+};
+#define NUM_DOUBLE_PATTERNS 12
+
+static unsigned char triplePatterns[] = {
+ 1, 2, 3,
+ 2, 3, 1,
+ 3, 1, 2,
+ 1, 3, 2,
+ 2, 1, 3,
+ 3, 2, 1
+};
+#define NUM_TRIPLE_PATTERNS 6
+
+static unsigned char values[] = {
+ 0x00,
+ 0xff, 0x80, 0xc0, 0x40, 0xe0, 0x60, 0xa0, 0x20,
+ 0xf0, 0xb0, 0x50, 0xd0, 0x70, 0x30, 0x90, 0x10
+};
+#define NUM_VALUES 16
+#define NUM_VALUES_444 10
+
+#define MAX_GENERATE 4096
+
+static unsigned char used[17][17][17];
+static int generated = 0;
+
+static void genPattern(int red, int green, int blue)
+{
+ ++red;
+ ++green;
+ ++blue;
+ if (used[red][green][blue] || generated >= MAX_GENERATE)
+ return;
+ used[red][green][blue] = 1;
+ if ((generated % 7) == 0)
+ printf("\n ");
+ printf("0x%02x%02x%02x", values[red], values[green], values[blue]);
+ ++generated;
+ if (generated < MAX_GENERATE && (generated % 7) != 0)
+ printf(", ");
+ else if (generated < MAX_GENERATE)
+ printf(",");
+}
+
+static void genSinglePatterns(int value)
+{
+ int index, red, green, blue;
+ for (index = 0; index < NUM_SINGLE_PATTERNS; ++index) {
+ if (singlePatterns[index * 3] == 0)
+ red = -1;
+ else
+ red = value;
+ if (singlePatterns[index * 3 + 1] == 0)
+ green = -1;
+ else
+ green = value;
+ if (singlePatterns[index * 3 + 2] == 0)
+ blue = -1;
+ else
+ blue = value;
+ genPattern(red, green, blue);
+ }
+}
+
+static void genDoublePatterns(int value1, int value2)
+{
+ int index, red, green, blue;
+ for (index = 0; index < NUM_DOUBLE_PATTERNS; ++index) {
+ if (doublePatterns[index * 3] == 0)
+ red = -1;
+ else if (doublePatterns[index * 3] == 1)
+ red = value1;
+ else
+ red = value2;
+ if (doublePatterns[index * 3 + 1] == 0)
+ green = -1;
+ else if (doublePatterns[index * 3 + 1] == 1)
+ green = value1;
+ else
+ green = value2;
+ if (doublePatterns[index * 3 + 2] == 0)
+ blue = -1;
+ else if (doublePatterns[index * 3 + 2] == 1)
+ blue = value1;
+ else
+ blue = value2;
+ genPattern(red, green, blue);
+ }
+}
+
+static void genTriplePatterns(int value1, int value2, int value3)
+{
+ int index, red, green, blue;
+ for (index = 0; index < NUM_TRIPLE_PATTERNS; ++index) {
+ if (triplePatterns[index * 3] == 0)
+ red = -1;
+ else if (triplePatterns[index * 3] == 1)
+ red = value1;
+ else if (triplePatterns[index * 3] == 2)
+ red = value2;
+ else
+ red = value3;
+ if (triplePatterns[index * 3 + 1] == 0)
+ green = -1;
+ else if (triplePatterns[index * 3 + 1] == 1)
+ green = value1;
+ else if (triplePatterns[index * 3 + 1] == 2)
+ green = value2;
+ else
+ green = value3;
+ if (triplePatterns[index * 3 + 2] == 0)
+ blue = -1;
+ else if (triplePatterns[index * 3 + 2] == 1)
+ blue = value1;
+ else if (triplePatterns[index * 3 + 2] == 2)
+ blue = value2;
+ else
+ blue = value3;
+ genPattern(red, green, blue);
+ }
+}
+
+static void genPatternRange(int limit)
+{
+ // This will generate 4912 unique color values which are
+ // reasonably well-spaced in the RGB color cube.
+ int first, second, third;
+ for (first = 0; first < limit; ++first) {
+ genSinglePatterns(first);
+ for (second = first + 1; second < limit; ++second) {
+ genDoublePatterns(first, second);
+ for (third = second + 1; third < limit; ++third) {
+ genTriplePatterns(first, second, third);
+ }
+ }
+ }
+}
+
+static void generateComponentMap(void)
+{
+ int map[256];
+ int index, value, index2;
+
+ for (index = 0; index < 256; ++index)
+ map[index] = 0;
+
+ for (index = 0; index < NUM_VALUES; ++index) {
+ value = values[index + 1];
+ for (index2 = value - 8; index2 < (value + 8); ++index2) {
+ if (index2 >= 0 && index2 < 256)
+ map[index2] = value;
+ }
+ }
+
+ for (index = 0; index < 256; ++index) {
+ if ((index % 8) == 0)
+ printf(" ");
+ printf("0x%02x", map[index]);
+ if (index < 255)
+ printf(",");
+ if ((index % 8) == 7)
+ printf("\n");
+ else if (index < 255)
+ printf(" ");
+ }
+
+ // Validate the reversibility of RGB565 and RGB555 mappings.
+ for (index = 0; index < 17; ++index) {
+ // Integer truncation test - 5-bit for red and blue (and green RGB555).
+ value = values[index] * 31 / 255;
+ index2 = value * 255 / 31;
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (i5) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+
+ // Integer truncation test - 6-bit for green.
+ value = values[index] * 63 / 255;
+ index2 = value * 255 / 63;
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (i6) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+
+ // Floating point rounding test - 5-bit for red and blue.
+ value = (int)((values[index] * 31.0 / 255.0) + 0.5);
+ index2 = (int)((value * 255.0 / 31.0) + 0.5);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (f5) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+
+ // Floating point rounding test - 6-bit for green.
+ value = (int)((values[index] * 63.0 / 255.0) + 0.5);
+ index2 = (int)((value * 255.0 / 63.0) + 0.5);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (f6) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+
+ // Test 5-bit to 8-bit conversion using doubling (ABCDE -> ABCDEABC).
+ value = values[index] * 31 / 255;
+ index2 = (value << 3) | (value >> 2);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (di5) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+ value = (int)((values[index] * 31.0 / 255.0) + 0.5);
+ index2 = (value << 3) | (value >> 2);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (df5) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+
+ // Test 6-bit to 8-bit conversion using doubling (ABCDEF -> ABCDEFAB).
+ value = values[index] * 63 / 255;
+ index2 = (value << 2) | (value >> 4);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (di6) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+ value = (int)((values[index] * 63.0 / 255.0) + 0.5);
+ index2 = (value << 2) | (value >> 4);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB565 (df6) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+ }
+}
+
+static void generateComponentMap444(void)
+{
+ int map[256];
+ int index, value, index2;
+
+ for (index = 0; index < 256; ++index)
+ map[index] = 0;
+
+ // Populate mappings for integer conversion with truncation.
+ for (index = 0; index < NUM_VALUES_444; ++index) {
+ value = values[index + 1] * 15 / 255;
+ value = value * 255 / 15;
+ if (value > 255)
+ value = 255;
+ else if (value < 0)
+ value = 0;
+ for (index2 = value - 8; index2 < (value + 7); ++index2) {
+ if (index2 >= 0 && index2 < 256)
+ map[index2] = values[index + 1];
+ }
+ }
+
+ // Add some extra mappings for floating-point conversion with rounding.
+ for (index = 0; index < NUM_VALUES_444; ++index) {
+ value = (int)((values[index + 1] * 15.0 / 255.0) + 0.5);
+ value = (int)((value * 255.0 / 15.0) + 0.5);
+ if (value > 255)
+ value = 255;
+ else if (value < 0)
+ value = 0;
+ for (index2 = value - 8; index2 < (value + 7); ++index2) {
+ if (index2 >= 0 && index2 < 256 && map[index2] == 0)
+ map[index2] = values[index + 1];
+ }
+ }
+
+ for (index = 0; index < 256; ++index) {
+ if ((index % 8) == 0)
+ printf(" ");
+ printf("0x%02x", map[index]);
+ if (index < 255)
+ printf(",");
+ if ((index % 8) == 7)
+ printf("\n");
+ else if (index < 255)
+ printf(" ");
+ }
+
+ // Validate the reversibility of RGB444 mappings.
+ for (index = 0; index <= NUM_VALUES_444; ++index) {
+ // Integer truncation test.
+ value = values[index] * 15 / 255;
+ index2 = value * 255 / 15;
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB444 (i) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+
+ // Floating point rounding test.
+ value = (int)((values[index] * 15.0 / 255.0) + 0.5);
+ index2 = (int)((value * 255.0 / 15.0) + 0.5);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB444 (f) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+
+ // Test 4-bit to 8-bit conversion using doubling (ABCD -> ABCDABCD).
+ value = values[index] * 15 / 255;
+ index2 = value | (value << 4);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB444 (di) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+ value = (int)((values[index] * 15.0 / 255.0) + 0.5);
+ index2 = value | (value << 4);
+ if (values[index] != map[index2]) {
+ fprintf(stderr, "RGB444 (df) failure: 0x%02X -> 0x%02X -> 0x%02X\n",
+ values[index], index2, map[index2]);
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int limit;
+
+ // Run the generator multiple times using more and more of
+ // the elements in the "values" table, and limit to a maximum
+ // of 1024 colors.
+ //
+ // This will sort the output so that colors that involve elements
+ // early in the table will be generated first. All combinations
+ // of early elements are exhausted before moving onto later values.
+ //
+ // The result of this sorting should be to maximize the spacing
+ // between colors that appear early in the generated output.
+ // This should produce better results for color picking on
+ // low-end devices with RGB565, RGB555, and RGB444 displays.
+ printf("static int const pickColors[%d] = {", MAX_GENERATE);
+ for (limit = 1; limit <= NUM_VALUES; ++limit)
+ genPatternRange(limit);
+ printf("\n};\n\n");
+
+ // Generate a component mapping table for mapping 8-bit RGB
+ // components to the nearest normalized value.
+ printf("static unsigned char const pickMapComponent[256] = {\n");
+ generateComponentMap();
+ printf("};\n\n");
+
+ // Generate a separate mapping table for RGB444, which needs a
+ // little more care to deal with truncation errors.
+ printf("static unsigned char const pickMapComponent444[256] = {\n");
+ generateComponentMap444();
+ printf("};\n\n");
+
+ printf("#define MAX_PICK_COLORS %d\n\n", MAX_GENERATE);
+
+ return 0;
+}
+
+#endif // QGL_GENERATOR_PROGRAM
diff --git a/src/threed/painting/qglpickcolors_p.h b/src/threed/painting/qglpickcolors_p.h
new file mode 100644
index 000000000..90c060af4
--- /dev/null
+++ b/src/threed/painting/qglpickcolors_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPICKCOLORS_P_H
+#define QGLPICKCOLORS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtGui/qrgb.h>
+
+QT_BEGIN_NAMESPACE
+
+QRgb qt_qgl_pick_color(int index);
+QRgb qt_qgl_normalize_pick_color(QRgb color, bool is444 = false);
+
+#endif
diff --git a/src/threed/painting/qmatrix4x4stack.cpp b/src/threed/painting/qmatrix4x4stack.cpp
new file mode 100644
index 000000000..fb38fa0df
--- /dev/null
+++ b/src/threed/painting/qmatrix4x4stack.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmatrix4x4stack.h"
+#include "qmatrix4x4stack_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QMatrix4x4Stack
+ \brief The QMatrix4x4Stack class manages stacks of transformation matrices in GL applications.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+
+ Transformation matrices are one of the basic building blocks of
+ 3D applications, allowing object models to be positioned, scaled,
+ rotated, and projected onto the screen.
+
+ GL systems support several standard kinds of matrices, particularly
+ modelview and projection matrices. These matrices are typically
+ organized into stacks, which allow the current matrix state to be
+ saved with push() and restored later with pop().
+
+ QMatrix4x4Stack assists QGLPainter with the management of matrix
+ stacks, providing operations to set and modify transformation
+ matrices in each of the standard matrix stacks.
+
+ In the following example, a standard orthographic projection matrix for a
+ view is set via the QGLPainter::projectionMatrix() stack, and
+ then a modelview matrix is set via the QGLPainter::modelViewMatrix()
+ stack to scale and translate an object prior to drawing:
+
+ \code
+ QGLPainter painter(this);
+
+ QMatrix4x4 projm;
+ projm.ortho(window->rect());
+ painter.projectionMatrix() = projm;
+
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().translate(-1.0f, 2.0f, 0.0f);
+ painter.modelViewMatrix().scale(0.5f);
+ \endcode
+
+ Later, the application can save the current modelview matrix state
+ and draw a different object with a different modelview matrix:
+
+ \code
+ painter.modelViewMatrix().push();
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ For efficiency, the matrix values are kept client-side until they
+ are needed by a QGLPainter::draw() operation. Until then, changes
+ to the matrix will not be reflected in the GL server. The application
+ can force the GL server to update the server with a call to
+ QGLPainter::update().
+
+ QMatrix4x4Stack is supported on all GL platforms, including OpenGL/ES 2.0
+ which doesn't support matrix stacks natively. On that platform, the
+ matrix stack is simulated in client memory. When the application
+ selects a shader program to draw under OpenGL/ES 2.0, it calls
+ top() to obtain the actual value to be set on the shader program.
+
+ \sa QGLPainter
+*/
+
+/*!
+ Creates a matrix stack.
+*/
+QMatrix4x4Stack::QMatrix4x4Stack()
+ : d_ptr(new QMatrix4x4StackPrivate)
+{
+}
+
+/*!
+ Destroy this matrix stack.
+*/
+QMatrix4x4Stack::~QMatrix4x4Stack()
+{
+}
+
+/*!
+ Pushes the current matrix onto the matrix stack. The matrix can
+ be restored with pop(). The new top of stack will have the
+ same value as the previous top of stack.
+
+ The depths of the traditional \c{GL_MODELVIEW} and \c{GL_PROJECTION}
+ matrix stacks in the GL server are system-dependent and easy to
+ overflow in nested rendering code using \c{glPushMatrix()}.
+ By contrast, the push() function provides an arbitrary-sized stack
+ in client memory.
+
+ \sa pop(), top()
+*/
+void QMatrix4x4Stack::push()
+{
+ Q_D(QMatrix4x4Stack);
+ d->stack.push(d->matrix);
+}
+
+/*!
+ Pops the top-most matrix from this matrix stack and sets the
+ current matrix to the next value down. Does nothing if the
+ matrix stack contains a single entry.
+
+ \sa push()
+*/
+void QMatrix4x4Stack::pop()
+{
+ Q_D(QMatrix4x4Stack);
+ if (!d->stack.isEmpty())
+ d->matrix = d->stack.pop();
+ d->isDirty = true;
+}
+
+/*!
+ Set the matrix at the top of this matrix stack to the identity matrix.
+
+ \sa operator=()
+*/
+void QMatrix4x4Stack::setToIdentity()
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.setToIdentity();
+ d->isDirty = true;
+}
+
+/*!
+ Returns a const reference to the current matrix at the top of this
+ matrix stack. This is typically used to fetch the matrix so it can
+ be set on user-defined shader programs.
+
+ \sa operator=()
+*/
+const QMatrix4x4 &QMatrix4x4Stack::top() const
+{
+ Q_D(const QMatrix4x4Stack);
+ return d->matrix;
+}
+
+/*!
+ \fn QMatrix4x4Stack::operator const QMatrix4x4 &() const
+
+ Returns a const reference to the current matrix at the top of
+ this matrix stack.
+
+ \sa top()
+*/
+
+/*!
+ Assigns \a matrix to the matrix at the top of this matrix stack.
+
+ \sa top()
+*/
+QMatrix4x4Stack& QMatrix4x4Stack::operator=(const QMatrix4x4& matrix)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix = matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the matrix at the top of this matrix stack by \a matrix.
+
+ \sa top()
+*/
+QMatrix4x4Stack& QMatrix4x4Stack::operator*=(const QMatrix4x4& matrix)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix *= matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that translates coordinates by (\a x, \a y, \a z). The following example
+ translates the modelview matrix by (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().translate(1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), rotate()
+*/
+void QMatrix4x4Stack::translate(qreal x, qreal y, qreal z)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.translate(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix statck by another
+ that translates coordinates by the components of \a vector.
+
+ \sa scale(), rotate()
+*/
+void QMatrix4x4Stack::translate(const QVector3D& vector)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.translate(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components \a x, \a y, and \a z.
+ The following example scales the modelview matrix by (1, 2, 1):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(1.0f, 2.0f, 1.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QMatrix4x4Stack::scale(qreal x, qreal y, qreal z)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.scale(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the given \a factor. The following example
+ scales the modelview matrix by a factor of 2:
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QMatrix4x4Stack::scale(qreal factor)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.scale(factor);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components of \a vector.
+
+ \sa translate(), rotate()
+*/
+void QMatrix4x4Stack::scale(const QVector3D& vector)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.scale(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about the vector
+ (\a x, \a y, \a z). The following example rotates the modelview
+ matrix by 45 degress about the vector (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().rotate(45.0f, 1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), translate()
+*/
+void QMatrix4x4Stack::rotate(qreal angle, qreal x, qreal y, qreal z)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.rotate(angle, x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about \a vector.
+
+ \sa scale(), translate()
+*/
+void QMatrix4x4Stack::rotate(qreal angle, const QVector3D& vector)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.rotate(angle, vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by the
+ \a quaternion. Thus \c {painter->modelViewMatrix().rotate(quaternion)}
+ is equivalent to the following code:
+ \code
+ QMatrix4x4 mat;
+ mat.rotate(quaternion);
+ painter->modelViewMatrix() *= mat;
+ \endcode
+ which rotates coordinates according to the given \a quaternion.
+
+ \sa scale(), translate()
+*/
+void QMatrix4x4Stack::rotate(const QQuaternion &quaternion)
+{
+ Q_D(QMatrix4x4Stack);
+ d->matrix.rotate(quaternion);
+ d->isDirty = true;
+}
+
+/*!
+ Returns true if the top of this matrix stack has been modified;
+ false otherwise.
+
+ \sa setDirty()
+*/
+bool QMatrix4x4Stack::isDirty() const
+{
+ Q_D(const QMatrix4x4Stack);
+ return d->isDirty;
+}
+
+/*!
+ Sets the \a dirty flag on this matrix stack, which indicates
+ if it has been modified.
+
+ A matrix stack may also be set to dirty by translate(),
+ scale(), operator*(), etc.
+
+ \sa isDirty()
+*/
+void QMatrix4x4Stack::setDirty(bool dirty)
+{
+ Q_D(QMatrix4x4Stack);
+ d->isDirty = dirty;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/painting/qmatrix4x4stack.h b/src/threed/painting/qmatrix4x4stack.h
new file mode 100644
index 000000000..1e392455c
--- /dev/null
+++ b/src/threed/painting/qmatrix4x4stack.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMATRIX4X4STACK_H
+#define QMATRIX4X4STACK_H
+
+#include "qt3dglobal.h"
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QMatrix4x4StackPrivate;
+
+class Q_QT3D_EXPORT QMatrix4x4Stack
+{
+public:
+ QMatrix4x4Stack();
+ ~QMatrix4x4Stack();
+
+ const QMatrix4x4 &top() const;
+
+ void push();
+ void pop();
+
+ void setToIdentity();
+
+ void translate(qreal x, qreal y, qreal z);
+ void translate(const QVector3D& vector);
+ void scale(qreal x, qreal y, qreal z);
+ void scale(qreal factor);
+ void scale(const QVector3D& vector);
+ void rotate(qreal angle, qreal x, qreal y, qreal z);
+ void rotate(qreal angle, const QVector3D& vector);
+ void rotate(const QQuaternion &quaternion);
+
+ QMatrix4x4Stack& operator=(const QMatrix4x4& matrix);
+ QMatrix4x4Stack& operator*=(const QMatrix4x4& matrix);
+
+ operator const QMatrix4x4 &() const;
+
+ bool isDirty() const;
+ void setDirty(bool dirty);
+
+private:
+ Q_DISABLE_COPY(QMatrix4x4Stack)
+ Q_DECLARE_PRIVATE(QMatrix4x4Stack)
+
+ QScopedPointer<QMatrix4x4StackPrivate> d_ptr;
+
+ friend class QGLPainter;
+};
+
+inline QMatrix4x4Stack::operator const QMatrix4x4 &() const
+{
+ return top();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/painting/qmatrix4x4stack_p.h b/src/threed/painting/qmatrix4x4stack_p.h
new file mode 100644
index 000000000..9c96d7869
--- /dev/null
+++ b/src/threed/painting/qmatrix4x4stack_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMATRIX4X4STACK_P_H
+#define QMATRIX4X4STACK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qstack.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QMatrix4x4StackPrivate
+{
+public:
+ QMatrix4x4StackPrivate() : isDirty(true) {}
+
+ QMatrix4x4 matrix;
+ QStack<QMatrix4x4> stack;
+ bool isDirty;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/scene/qglabstractscene.cpp b/src/threed/scene/qglabstractscene.cpp
new file mode 100644
index 000000000..9f18749a0
--- /dev/null
+++ b/src/threed/scene/qglabstractscene.cpp
@@ -0,0 +1,527 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglabstractscene.h"
+#include "qglsceneformatplugin.h"
+#include "qglpicknode.h"
+
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/private/qfactoryloader_p.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qpluginloader.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLAbstractScene
+ \brief The QGLAbstractScene class represents a 3D scene consisting of zero or more QGLSceneNode instances.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ Scenes are typically created by 3D modelling packages and then loaded
+ into the application via a QGLSceneFormatPlugin; but they can also be
+ constructed programatically. The functions in this
+ class provide access to major scene objects so that they can be
+ applied or drawn whenever the application decides.
+
+ QGLAbstractScene presents a very simple model of a 3D scene. Subclasses
+ implement the specific scene graph and object representations in a
+ manner specific to the package's format. Subclasses may also provide
+ functionality to create new objects at runtime, but this is not required.
+
+ The scene is defined to consist of a number of important objects
+ of the following types:
+
+ \list
+ \o Camera objects define a viewing position in world-coordinates and a
+ projection that maps 3D world co-ordinates to 2D screen co-ordinates.
+ Camera objects should inherit from QGLCamera.
+ \o Main objects designate the major elements of the scene besides
+ cameras, lights, and effects. Usually they inherit from QGLSceneNode.
+ \o Light objects define positions and parameters for lighting the scene.
+ Light objects should inherit from QGLLightParameters.
+ \o Effect objects define materials, shaders, and textures for use in
+ rendering the surface of objects. Normally effects are activated
+ automatically when main objects are drawn. But effects can be used
+ independently if the 3D format is acting as a library of effects.
+ \o Mesh objects define geometry information independently of effects.
+ Normally meshes are drawn automatically with an appropriate effect
+ when main objects are drawn. But meshes can be used independently
+ if the 3D format is acting as a library of meshes. Mesh objects
+ should inherit from QGLSceneNode.
+ \endlist
+
+ Typically, the full scene represented by an external model format
+ is not interesting to the application. 3D modelling packages
+ regularly insert cameras, lights, effects, and other library
+ objects that are useful to the modelling package, but not the
+ application. The mainNode() is usually the most interesting
+ to applications.
+
+ QGLAbstractScene makes it easy to access the major scene elements
+ with object(), objects(), and mainNode().
+
+ There are many other kinds of objects in the scene that may not
+ be accessible via QGLAbstractScene because they are not considered
+ "important" enough. For example, a file that contains the data
+ for a skateboard object would contain many objects for the board,
+ wheels, texturing effects, animations, and so on. The application
+ may only be interested in the skateboard as a whole, and not its
+ sub-components. The skateboard would be considered an important
+ main object in this case, which can be easily accessed and
+ incorporated into the application's logic.
+
+ Each Subclass needs to provide its own policy for deciding which
+ objects are considered "important".
+
+ \sa QGLSceneNode, QGLSceneFormatPlugin
+*/
+
+class QGLAbstractScenePrivate
+{
+public:
+ QGLAbstractScenePrivate()
+ : picking(false), nextPickId(-1), pickNodesDirty(true) {}
+ bool picking;
+ int nextPickId;
+ QList<QGLPickNode*> pickNodes;
+ QSet<QGLSceneNode*> pickable;
+ bool pickNodesDirty;
+};
+
+/*!
+ Constructs a 3D scene and attaches it to \a parent.
+*/
+QGLAbstractScene::QGLAbstractScene(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new QGLAbstractScenePrivate)
+{
+}
+
+/*!
+ Destroys this 3D scene.
+*/
+QGLAbstractScene::~QGLAbstractScene()
+{
+}
+
+/*!
+ \internal
+*/
+void QGLAbstractScene::childEvent(QChildEvent *event)
+{
+ Q_D(QGLAbstractScene);
+ if (event->type() == QEvent::ChildAdded)
+ d->pickNodesDirty = true;
+}
+
+/*!
+ Sets this scene to be pickable if \a enable is true, otherwise picking
+ is disabled. If the scene is set to be pickable, pick nodes are
+ generated by calling generatePickNodes().
+
+ \sa generatePickNodes(), pickable()
+*/
+void QGLAbstractScene::setPickable(bool enable)
+{
+ Q_D(QGLAbstractScene);
+ if (enable != d->picking)
+ {
+ d->picking = enable;
+ if (d->picking)
+ generatePickNodes();
+ }
+}
+
+/*!
+ Returns true if this scene is pickable.
+
+ \sa setPickable()
+*/
+bool QGLAbstractScene::pickable() const
+{
+ Q_D(const QGLAbstractScene);
+ return d->picking;
+}
+
+/*!
+ Generates QGLPickNode instances for important QGLSceneNode instances that are
+ pickable. Objects that are either not important or not pickable can
+ be omitted. The default implementation simply generates pick nodes
+ for every top level object of type QGLSceneNode.
+
+ Sub-classes may implement different schemes for picking. When doing
+ so parent the QGLPickNode objects onto the scene, so that they will
+ appear in the list returned by pickNodes()
+
+ \sa pickNodes(), setPickable()
+*/
+void QGLAbstractScene::generatePickNodes()
+{
+ Q_D(QGLAbstractScene);
+ QList<QObject *> objs = objects();
+ QList<QObject *>::iterator it = objs.begin();
+ d->pickNodes.clear();
+ for ( ; it != objs.end(); ++it)
+ {
+ QGLSceneNode *n = qobject_cast<QGLSceneNode *>(*it);
+ if (d) {
+ if (!d->pickable.contains(n)) {
+ n->setPickNode(new QGLPickNode(this));
+ d->pickable.insert(n);
+ }
+ d->pickNodes.append(n->pickNode());
+ }
+ }
+}
+
+/*!
+ Increments and returns the next available pick id for this scene.
+*/
+int QGLAbstractScene::nextPickId()
+{
+ return ++d_ptr->nextPickId;
+}
+
+/*!
+ Returns a list of the pick nodes that have been parented onto this
+ scene.
+
+ \sa generatePickNodes()
+*/
+QList<QGLPickNode *> QGLAbstractScene::pickNodes() const
+{
+ if (d_ptr->pickNodesDirty)
+ {
+ const_cast<QGLAbstractScene*>(this)->generatePickNodes();
+ d_ptr->pickNodesDirty = false;
+ }
+ return d_ptr->pickNodes;
+}
+
+/*!
+ \fn QList<QObject *> QGLAbstractScene::objects() const
+
+ Returns a list of all objects in the scene which are considered
+ important.
+
+ Important objects will typically be the main mesh object, cameras,
+ lights, and other top-level objects. Sub-meshes and effects
+ are normally not considered important unless the scene is
+ acting as a library of meshes and effects.
+
+ \sa objectNames(), object(), mainNode()
+*/
+
+/*!
+ Returns a list of the names of all objects in the scene which
+ are considered important, and which have non-empty names
+ associated with them.
+
+ The default implementation calls objects() and then compiles a list
+ of all non-empty object names.
+
+ \sa objects()
+*/
+QStringList QGLAbstractScene::objectNames() const
+{
+ QList<QObject *> objs = objects();
+ QStringList names;
+ for (int index = 0; index < objs.count(); ++index) {
+ QObject *object = objs.at(index);
+ if (object) {
+ QString name = object->objectName();
+ if (!name.isEmpty())
+ names += name;
+ }
+ }
+ return names;
+}
+
+/*!
+ Returns the scene object that has the specified \a name;
+ or null if the object was not found.
+
+ The default implementation searches objects() for an object that
+ matches \a name.
+
+ \sa objects()
+*/
+QObject *QGLAbstractScene::object(const QString& name) const
+{
+ if (name.isEmpty())
+ return 0;
+ QList<QObject *> objs = objects();
+ for (int index = 0; index < objs.count(); ++index) {
+ QObject *object = objs.at(index);
+ if (object && object->objectName() == name)
+ return object;
+ }
+ return 0;
+}
+
+
+/*!
+ \fn QGLSceneNode *QGLAbstractScene::mainNode() const
+
+ Returns the main mesh node in the scene, or null if the scene
+ does not contain a main mesh node.
+
+ \sa objects()
+*/
+
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QGLSceneFormatFactoryInterface_iid, QLatin1String("/sceneformats")))
+#endif
+
+/*!
+ Loads a scene from \a device in the specified \a format using
+ the registered scene format plugins. If \a format is an empty
+ string, then the format will be autodetected from the filename
+ extension of \a device. The \a url specifies the location of
+ the data in \a device so that relative resources can be located.
+
+ The \a options string is passed to the underlying format loader
+ and its meaning and format depend on the loader. For example the
+ format string for the .3ds loader accepts the following options:
+ \list
+ \o ForceSmooth - average normals for a smooth appearance
+ \o ForceFaceted - per face normals for a faceted appearance
+ \o NativeIndices - map native indices for poorly smoothed models
+ \o CorrectNormals - fix inverted normals on models with bad windings
+ \o CorrectAcute - fix normals on models that smooth acute angles
+ \endlist
+
+ The options may be specified globally for the whole model, or just
+ for a particular mesh.
+
+ In this example smoothing is forced on globally, and native indices
+ are used on just the mesh called "BattCoverMesh".
+
+ \code
+ QString op = "ForceSmooth BattCoverMesh=NativeIndices";
+ QString file = "music-player.3ds";
+ QGLAbstractScene *scene = QGLAbstractScene::loadScene(file, QString(), op);
+ \endcode
+
+ Returns the scene object, or null if the scene could not be loaded
+ or the \a format was not supported by any of the plugins.
+
+ \sa QGLSceneFormatPlugin
+*/
+QGLAbstractScene *QGLAbstractScene::loadScene
+ (QIODevice *device, const QUrl& url, const QString& format, const QString &options)
+{
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ if (!device)
+ return 0;
+
+ QFactoryLoader *l = loader();
+ QStringList keys = l->keys();
+
+ // If the format is not specified, then use the filename/url extension.
+ QString fmt = format;
+ if (fmt.isEmpty()) {
+ QFile *file = qobject_cast<QFile *>(device);
+ QString name;
+ if (file) {
+ name = file->fileName();
+ } else {
+ QNetworkReply *reply = qobject_cast<QNetworkReply *>(device);
+ if (reply)
+ name = reply->url().path();
+ }
+ int dot = name.lastIndexOf(QLatin1Char('.'));
+ QString suffix = name.mid(dot+1).toLower();
+ int index = keys.indexOf(suffix);
+ if (index >= 0)
+ fmt = suffix;
+ }
+
+ // Find the plugin that handles the format and ask it to create a handler.
+ if (QGLSceneFormatFactoryInterface *factory
+ = qobject_cast<QGLSceneFormatFactoryInterface*>
+ (l->instance(fmt))) {
+ QGLSceneFormatHandler *handler = factory->create(device, url, fmt);
+ if (handler) {
+ handler->setDevice(device);
+ handler->setUrl(url);
+ handler->setFormat(format);
+ if (!options.isEmpty())
+ handler->decodeOptions(options);
+ QGLAbstractScene *scene = handler->read();
+ delete handler;
+ return scene;
+ }
+ }
+
+ // If we get here, then the format is not supported by any of the plugins.
+#ifndef QT_NO_DEBUG
+ qWarning("Could not create handler for format %s"
+ "- check plugins are installed correctly in %s",
+ qPrintable(fmt),
+ qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
+#endif
+ return 0;
+#else // QT_NO_LIBRARY || QT_NO_SETTINGS
+ Q_UNUSED(device);
+ Q_UNUSED(url);
+ Q_UNUSED(format);
+ return 0;
+#endif // QT_NO_LIBRARY || QT_NO_SETTINGS
+}
+
+/*!
+ Loads a scene from \a fileName in the specified \a format, with the
+ supplied \a options, and using the registered scene format plugins.
+
+ If \a format is an empty string, then the format will be autodetected
+ from the extension of \a fileName.
+
+ The \a options string is passed to the underlying format loader
+ and its meaning and format depend on the loader. See the doc above
+ for loadScene() for details on the 3ds format options.
+
+ Returns the scene object, or null if the scene could not be loaded
+ or the \a format was not supported by any of the plugins.
+
+ \sa QGLSceneFormatPlugin
+*/
+QGLAbstractScene *QGLAbstractScene::loadScene
+ (const QString& fileName, const QString& format, const QString &options)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ if (options.contains(QLatin1String("ShowWarnings")))
+ qWarning("Could not read %s", qPrintable(fileName));
+ return 0;
+ }
+ QFileInfo fi(fileName);
+ QUrl url = QUrl::fromLocalFile(fi.absoluteFilePath());
+ return loadScene(&file, url, format, options);
+}
+
+/*!
+ \enum QGLAbstractScene::FormatListType
+ This enum specifies the format of the list returned by the supportedFormats() function.
+
+ \value AsFilter Return a format list that may be used as a filter.
+ \value AsSuffix Return a format list that is simply the filename suffixes.
+*/
+
+/*!
+ Returns a list of all supported formats known by currently available
+ sceneformat plugins, in the format type \a t.
+
+ If \a t is QGLAbstractScene::AsFilter then the result may be passed
+ to QDir::setNameFilters(), or used in other filters. This is the default.
+
+ For example to create a file dialog to load model files use this:
+ \code
+ QString modelsDir = QDir::toNativeSeperators(QDir::homePath());
+ QString filter = tr("Models (%1)").arg(QAbstractScene::supportedFormats().join(" "));
+ QString fileName = QFileDialog::getOpenFileName(this,
+ tr("Open File"), modelsDir, filter));
+ \endcode
+
+ Otherwise (when \a t is QGLAbstractScene::AsSuffix) it is simply a list
+ of file name suffixes.
+
+ Note that this function may be expensive to
+ call since it scans for available plugins, and loads each one it
+ finds to get an accurate report of formats supported at run-time.
+*/
+QStringList QGLAbstractScene::supportedFormats(QGLAbstractScene::FormatListType t)
+{
+ QStringList formats;
+ QSet<QString> formatSet;
+ QSet<QString> dirSet;
+ QStringList pluginPaths = QCoreApplication::libraryPaths();
+ QStringList::const_iterator it = pluginPaths.constBegin();
+ for ( ; it != pluginPaths.constEnd(); ++it)
+ {
+ QString path = *it;
+ QDir sceneformatDir(path + QLatin1String("/sceneformats"));
+ path = sceneformatDir.absolutePath();
+ if (!sceneformatDir.exists() || dirSet.contains(path))
+ continue;
+ dirSet.insert(path);
+ sceneformatDir.setFilter(QDir::Files);
+ QStringList entries = sceneformatDir.entryList();
+ QStringList::const_iterator fit = entries.constBegin();
+ for ( ; fit != entries.constEnd(); ++fit)
+ {
+ QString fi = *fit;
+ QPluginLoader loader(sceneformatDir.absoluteFilePath(fi));
+ QObject *inst = loader.instance();
+ QGLSceneFormatFactoryInterface *iface = qobject_cast<QGLSceneFormatFactoryInterface*>(inst);
+ if (iface)
+ {
+ QStringList formatKeys = iface->keys();
+ QStringList::const_iterator kit = formatKeys.constBegin();
+ for ( ; kit != formatKeys.constEnd(); ++kit)
+ {
+ QString k = *kit;
+ if (!formatSet.contains(k) && !k.contains("/")) // dont add mime-type keys
+ {
+ if (t == AsFilter)
+ k.prepend("*.");
+ formatSet.insert(k);
+ formats.append(k);
+ }
+ }
+ }
+ }
+ }
+ return formats;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/threed/scene/qglabstractscene.h b/src/threed/scene/qglabstractscene.h
new file mode 100644
index 000000000..72b3d4828
--- /dev/null
+++ b/src/threed/scene/qglabstractscene.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLABSTRACTSCENE_H
+#define QGLABSTRACTSCENE_H
+
+#include "qt3dglobal.h"
+#include "qglscenenode.h"
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLAbstractScenePrivate;
+class QIODevice;
+class QGLPickNode;
+
+class Q_QT3D_EXPORT QGLAbstractScene : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QGLAbstractScene(QObject *parent = 0);
+ virtual ~QGLAbstractScene();
+
+ virtual void setPickable(bool enable);
+ virtual bool pickable() const;
+ virtual void generatePickNodes();
+ QList<QGLPickNode *> pickNodes() const;
+ int nextPickId();
+
+ virtual QList<QObject *> objects() const = 0;
+ virtual QStringList objectNames() const;
+ virtual QObject *object(const QString& name) const;
+ virtual QGLSceneNode *mainNode() const = 0;
+
+ static QGLAbstractScene *loadScene
+ (QIODevice *device, const QUrl& url, const QString& format = QString(),
+ const QString& options = QString());
+ static QGLAbstractScene *loadScene
+ (const QString& fileName, const QString& format = QString(),
+ const QString& options = QString());
+
+ enum FormatListType {
+ AsFilter, AsSuffix
+ };
+
+ static QStringList supportedFormats(FormatListType t = AsFilter);
+
+protected:
+ void childEvent(QChildEvent * event);
+
+private:
+ QScopedPointer<QGLAbstractScenePrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGLAbstractScene)
+ Q_DECLARE_PRIVATE(QGLAbstractScene)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/scene/qglpicknode.cpp b/src/threed/scene/qglpicknode.cpp
new file mode 100644
index 000000000..06a4245b3
--- /dev/null
+++ b/src/threed/scene/qglpicknode.cpp
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglpicknode.h"
+#include "qglabstractscene.h"
+
+#include <QtGui/qevent.h>
+
+/*!
+ \class QGLPickNode
+ \brief The QGLPickNode class enables picking for objects in a 3D scene.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ QGLPickNode is a QObject sub-class, relatively light-weight, that can
+ shadow QSceneObject instances and provide picking capability. The
+ QGLPickNode instance receives events sent to it by picking views, such
+ as the QGLView class, and emits relevant signals in response.
+
+ QGLSceneObjects wanting to support picking, should implement the methods
+ \list
+ \o QGLSceneNode::pickNode()
+ \o QGLSceneNode::setPickNode()
+ \endlist
+ and also implement rendering such that the QGLPainter has the relevant
+ \l{QGLPainter::setObjectPickId()}{pick id function} called.
+
+ These functions are already implemented for the QGLSceneNode object type.
+
+ Picking can then be simply enabled by calling the QGLAbstractScene function
+ setPickable() to turn on picking and generate pick nodes for the relevant
+ scene objects.
+
+ In order to respond to picking, the view class should simply register the
+ picknodes, and connect a relevant slot to the pick nodes signal.
+
+ For the QGLView class that code is simply:
+ \code
+ QList<QGLPickNode *>nodes = manager->pickNodes();
+ foreach (QGLPickNode *node, nodes)
+ {
+ registerObject(node->id(), node);
+ connect(node, SIGNAL(clicked()),
+ this, SLOT(objectPicked()));
+ }
+ \endcode
+
+ The pick nodes should be unregistered with similar code for the QGLView if
+ switching to a different scene.
+
+ To be able to recover the relevant QGLSceneNode inside the called slot,
+ the object may be set onto the QGLPickNode with the setTarget() function,
+ and recovered with target() inside the slot, since the QGLPickNode will
+ be the sender() for the slot.
+
+ QGLSceneNode already sets itself as the target during the pick enable step.
+
+ \sa QGLSceneNode, QGLView
+*/
+
+/*!
+ Construct a new QGLPickNode object managed by and parented onto
+ the \a parent scene. The nextPickId() function will be called on
+ \a parent to assign a pick id to this new node.
+*/
+QGLPickNode::QGLPickNode(QGLAbstractScene *parent) :
+ QObject(parent), m_id(-1), m_target(0)
+{
+ if (parent)
+ m_id = parent->nextPickId();
+}
+
+/*!
+ \fn int QGLPickNode::id() const
+ Returns the unique id for this node. This value is assigned by
+ the parent scene for this node and should be different for every
+ node in the scene. Returns -1 if the id has not been set yet.
+
+ \sa setId()
+*/
+
+/*!
+ \fn void QGLPickNode::setId(int id)
+ Sets the unique \a id for this node. Generally this function should not
+ be needed, since the constructor causes a unique id to be obtained
+ from the parent scene. This function exists mainly for testing
+ purposes.
+
+ \sa id()
+*/
+
+/*!
+ \fn QGLSceneNode *QGLPickNode::target() const
+ Returns the QGLSceneNode which is the target of this pick node;
+ null if the target has not been set yet.
+
+ \sa setTarget()
+*/
+
+/*!
+ \fn void QGLPickNode::setTarget(QGLSceneNode *target)
+ Sets the \a target for this pick node.
+
+ \sa target()
+*/
+
+/*!
+ \fn void QGLPickNode::pressed()
+ Signal emitted when the scene object for this node has the mouse pressed
+ while the cursor is on the object in the scene.
+*/
+
+/*!
+ \fn void QGLPickNode::released()
+ Signal emitted when the scene object for this node has the mouse released
+ while the cursor is on the object in the scene.
+*/
+
+/*!
+ \fn void QGLPickNode::clicked()
+ Signal emitted when the scene object for this node has the mouse pressed
+ and then released while the cursor is on the object in the scene.
+*/
+
+/*!
+ \fn void QGLPickNode::doubleClicked()
+ Signal emitted when the scene object for this node has the mouse clicked
+ twice in succession while the cursor is on the object in the scene.
+*/
+
+/*!
+ \fn void QGLPickNode::hoverChanged()
+ Signal emitted when the scene object for this node has the mouse moved
+ into or out of this object in the scene.
+*/
+
+/*!
+ \internal
+*/
+bool QGLPickNode::event(QEvent *e)
+{
+ // ripped off from teaservice demo, but not before the same code
+ // was ripped off and put in item3d.cpp - those should probably all
+ // use this implementation here
+ if (e->type() == QEvent::MouseButtonPress)
+ {
+ QMouseEvent *me = (QMouseEvent *)e;
+ if (me->button() == Qt::LeftButton)
+ emit pressed();
+ }
+ else if (e->type() == QEvent::MouseButtonRelease)
+ {
+ QMouseEvent *me = (QMouseEvent *)e;
+ if (me->button() == Qt::LeftButton)
+ {
+ emit released();
+ if (me->x() >= 0) // Positive: inside object, Negative: outside.
+ emit clicked();
+ }
+ }
+ else if (e->type() == QEvent::MouseButtonDblClick)
+ {
+ emit doubleClicked();
+ }
+ else if (e->type() == QEvent::Enter)
+ {
+ //m_hovering = true;
+ emit hoverChanged();
+ }
+ else if (e->type() == QEvent::Leave)
+ {
+ //m_hovering = false;
+ emit hoverChanged();
+ }
+ return QObject::event(e);
+}
diff --git a/src/threed/scene/qglpicknode.h b/src/threed/scene/qglpicknode.h
new file mode 100644
index 000000000..c4c90e1a3
--- /dev/null
+++ b/src/threed/scene/qglpicknode.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPICKNODE_H
+#define QGLPICKNODE_H
+
+#include <QtCore/qobject.h>
+#include "qt3dglobal.h"
+
+class QGLAbstractScene;
+class QGLSceneNode;
+class QEvent;
+
+class Q_QT3D_EXPORT QGLPickNode : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QGLPickNode(QGLAbstractScene *parent = 0);
+ int id() const { return m_id; }
+ void setId(int id) { m_id = id; }
+
+ QGLSceneNode *target() const { return m_target; }
+ void setTarget(QGLSceneNode *target) { m_target = target; }
+
+Q_SIGNALS:
+ void pressed();
+ void released();
+ void clicked();
+ void doubleClicked();
+ void hoverChanged();
+
+public Q_SLOTS:
+
+protected:
+ bool event(QEvent *e);
+ int m_id;
+ QGLSceneNode *m_target;
+};
+
+#endif // QGLPICKNODE_H
diff --git a/src/threed/scene/qglrenderorder.cpp b/src/threed/scene/qglrenderorder.cpp
new file mode 100644
index 000000000..d5250de18
--- /dev/null
+++ b/src/threed/scene/qglrenderorder.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglrenderorder.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLRenderOrder
+ \brief The QGLRenderOrder class represents an order of a scene node during rendering.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ The QGLRenderOrder class works with the QGLRenderSequencer to optimize
+ the rendering order of scene nodes.
+
+ The class encapsulates the ordering with which QGLSceneNodes appear in the
+ rendering of a scene. Every scene node that has the same rendering properties
+ maps to the same QGLRenderOrder.
+
+ QGLRenderOrder instances are based on a scene node, and the path through
+ the scene graph by which the node was reached. This is necessary since the
+ same node may appear with different rendering properties in multiple
+ different places in the rendering graph.
+
+ For example a node holding a model of a pawn chess piece may appear in
+ several different places on a board, some with a white material and some
+ with a black material.
+
+ To capture this concept QGLRenderOrder instances are constructed from a
+ pointer to a QGLSceneNode, and a QGLRenderState instance.
+
+ A render order then calculates the effective values of its various attributes
+ based on both the node, and the state.
+
+ Custom render orders may be created by sub-classing QGLRenderOrderComparator
+ and reimplementing the following methods:
+ \list
+ \i isEqualTo()
+ \i isLessThan()
+ \endlist
+
+ By default all nodes which have the same effect type are rendered together,
+ and then within that, those nodes which have the same material are
+ rendered together.
+
+ \sa QGLRenderOrderComparator
+*/
+
+/*!
+ \fn QGLRenderOrder::QGLRenderOrder(const QGLSceneNode *node, const QGLRenderState &state)
+ Creates a new QGLRenderOrder instance that encapsulates the order in this
+ render pass represented by the given \a node and \a state. The \a node
+ defaults to NULL, and the \a state defaults to a default constructed
+ invalid QGLRenderState.
+*/
+
+/*!
+ \fn QGLRenderOrder::~QGLRenderOrder()
+ Destroys this QGLRenderOrder and recovers any resources.
+*/
+
+/*!
+ Returns a hash value representing the effect set onto the node for
+ this render order.
+*/
+uint QGLRenderOrder::effectHash() const
+{
+ quint64 result = 0;
+ if (effectiveHasEffect())
+ {
+ QGLAbstractEffect *eff = effectiveUserEffect();
+ if (eff)
+ result = reinterpret_cast<quint64>(eff);
+ else
+ result = effectiveStandardEffect();
+ Q_ASSERT(result);
+ }
+ return qHash(result);
+}
+
+/*!
+ Returns true if this QGLRenderOrder is equal to the \a rhs, otherwise
+ returns false. Reimplement this function when creating a sub-class of
+ QGLRenderOrder.
+
+ \sa isLessThan()
+*/
+bool QGLRenderOrder::isEqual(const QGLRenderOrder &rhs) const
+{
+ if (this == &rhs)
+ return true;
+ bool result = false;
+ bool thisHasEffect = effectiveHasEffect();
+ bool thatHasEffect = rhs.effectiveHasEffect();
+ if (thisHasEffect && thatHasEffect)
+ {
+ QGLAbstractEffect *eff = effectiveUserEffect();
+ if (eff)
+ result = (eff == rhs.effectiveUserEffect());
+ else
+ result = (effectiveStandardEffect() == rhs.effectiveStandardEffect());
+ }
+ else
+ {
+ result = (thisHasEffect == thatHasEffect);
+ }
+ if (result)
+ {
+ result = (effectiveMaterial() == rhs.effectiveMaterial());
+ }
+ if (result)
+ {
+ result = (effectiveBackMaterial() == rhs.effectiveBackMaterial());
+ }
+ return result;
+}
+
+/*!
+ Returns true if this QGLRenderOrder is less than the \a rhs, otherwise
+ returns false. Reimplement this function when creating a sub-class of
+ QGLRenderOrder.
+
+ The default implementation sorts first by effect, second by material (front
+ then back).
+
+ Sorting by material is ordered by pointer comparison.
+
+ Sorting by effect is based on the following order, from lowest to
+ highest:
+ \list
+ \o No effect - hasEffect() == true
+ \o Standard effect - ordered by numerical value, eg QGL::FlatColor < QGL::LitMaterial
+ \o User effect - ordered by pointer comparison
+ \endlist
+ So a node with \c{hasEffect() == false} node is \i{less than} a node with
+ a custom user effect, for example.
+
+ \sa isEqual()
+*/
+bool QGLRenderOrder::isLessThan(const QGLRenderOrder &rhs) const
+{
+ bool result = false;
+ bool thisHasEffect = effectiveHasEffect();
+ bool thatHasEffect = rhs.effectiveHasEffect();
+ if (thisHasEffect && thatHasEffect)
+ {
+ QGLAbstractEffect *eff = effectiveUserEffect();
+ if (eff)
+ result = (eff < rhs.effectiveUserEffect());
+ else
+ result = !rhs.effectiveUserEffect() &&
+ (effectiveStandardEffect() < rhs.effectiveStandardEffect());
+ }
+ else
+ {
+ result = !thisHasEffect;
+ }
+ if (!result)
+ {
+ result = (effectiveMaterial() < rhs.effectiveMaterial());
+ }
+ if (!result)
+ {
+ result = (effectiveBackMaterial() < rhs.effectiveBackMaterial());
+ }
+ return result;
+}
+
+/*!
+ \fn bool QGLRenderOrder::isValid() const
+ Returns true if this is a valid QGLRenderOrder, that is it was
+ initialized with a non-null QGLSceneNode.
+*/
+
+/*!
+ \fn bool QGLRenderOrder::operator!=(const QGLRenderOrder &rhs) const
+ Returns true if this QGLRenderOrder is not equal to the \a rhs, otherwise
+ returns false. This function simply returns \c{!isEqual(rhs)}.
+*/
+
+/*!
+ \fn bool QGLRenderOrder::bool operator==(const QGLRenderOrder &rhs) const
+ Returns true if this QGLRenderOrder is equal to the \a rhs, otherwise
+ returns false. This function simply returns \c{isEqual(rhs)}.
+*/
+
+/*!
+ \fn bool QGLRenderOrder::operator<(const QGLRenderOrder &rhs) const
+ Returns true if this QGLRenderOrder is less than to the \a rhs, otherwise
+ returns false. This function simply returns \c{isLessThan(rhs)}.
+*/
+
+/*!
+ \fn const QGLSceneNode *QGLRenderOrder::node() const
+ Returns a pointer to the scene node for which the render order is held by
+ this QGLRenderOrder instance. This is simply the value passed to the
+ constructor.
+*/
+
+/*!
+ \fn QGLRenderState QGLRenderOrder::state() const
+ Returns a pointer to the render state for this order. This is simply the
+ value passed to the constructor.
+*/
+
+/*!
+ \fn void QGLRenderOrder::setState(const QGLRenderState &state)
+ Sets the \a state for this order.
+*/
+
+/*!
+ \fn QGLAbstractEffect *QGLRenderOrder::effectiveUserEffect() const
+ Returns the effective user effect of the node set for this render
+ order, taking into account any effect inherited from parent nodes
+ as specified by the render state().
+
+ \sa state(), effectiveHasEffect()
+*/
+
+/*!
+ \fn QGL::StandardEffect QGLRenderOrder::effectiveStandardEffect() const
+ Returns the effective standard effect of the node set for this render
+ order, taking into account any effect inherited from parent nodes
+ as specified by the render state().
+
+ \sa state(), effectiveHasEffect()
+*/
+
+/*!
+ \fn QGLMaterial *QGLRenderOrder::effectiveMaterial() const
+ Returns the effective material of the node set for this render
+ order, taking into account any effect inherited from parent nodes
+ as specified by the render state().
+
+ \sa state(), effectiveBackMaterial()
+*/
+
+/*!
+ \fn QGLMaterial *QGLRenderOrder::effectiveBackMaterial() const
+ Returns the effective back material of the node set for this render
+ order, taking into account any effect inherited from parent nodes
+ as specified by the render state().
+
+ \sa state(), effectiveMaterial()
+*/
+
+/*!
+ \fn bool QGLRenderOrder::effectiveHasEffect() const
+ Returns the effective value of whether an effect is set on the node
+ set for this render order, taking into account any effect inherited
+ from parent nodes as specified by the render state().
+
+ \sa state()
+*/
+
+/*!
+ \fn uint qHash(const QGLRenderOrder &order)
+ \relates QGLRenderOrder
+ Returns a hash value representation of the \a order.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QGLRenderOrder &order)
+{
+ if (order.isValid())
+ dbg << "QGLRenderOrder for node:" << order.node()
+ << "-- effect hash:" << order.effectHash()
+ << "-- material:" << order.node()->material()
+ << "-- back material:" << order.node()->backMaterial();
+ else
+ dbg << "QGLRenderOrder -- invalid";
+ return dbg;
+}
+
+#endif
+
+
+QT_END_NAMESPACE
diff --git a/src/threed/scene/qglrenderorder.h b/src/threed/scene/qglrenderorder.h
new file mode 100644
index 000000000..3a1071a4a
--- /dev/null
+++ b/src/threed/scene/qglrenderorder.h
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QGLRENDERORDER_H
+#define QGLRENDERORDER_H
+
+#include "qglscenenode.h"
+#include "qglrenderstate.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QGLRenderOrder
+{
+public:
+ explicit QGLRenderOrder(const QGLSceneNode *node = 0, const QGLRenderState &state = QGLRenderState())
+ : m_node(node)
+ , m_state(state)
+ {
+ }
+ ~QGLRenderOrder() {}
+
+ uint effectHash() const;
+ bool isEqual(const QGLRenderOrder &rhs) const;
+ bool isLessThan(const QGLRenderOrder &rhs) const;
+ inline bool isValid() const;
+
+ inline bool operator!=(const QGLRenderOrder &rhs) const;
+ inline bool operator==(const QGLRenderOrder &rhs) const;
+ inline bool operator<(const QGLRenderOrder &rhs) const;
+
+ inline const QGLSceneNode *node() const;
+ inline void setState(const QGLRenderState &state);
+ inline QGLRenderState state() const;
+ inline QGLAbstractEffect *effectiveUserEffect() const;
+ inline QGL::StandardEffect effectiveStandardEffect() const;
+ inline QGLMaterial *effectiveMaterial() const;
+ inline QGLMaterial *effectiveBackMaterial() const;
+ inline bool effectiveHasEffect() const;
+private:
+ const QGLSceneNode *m_node;
+ QGLRenderState m_state;
+};
+
+
+inline bool QGLRenderOrder::isValid() const
+{
+ return m_node;
+}
+
+inline bool QGLRenderOrder::operator!=(const QGLRenderOrder &rhs) const
+{
+ return !isEqual(rhs);
+}
+
+inline bool QGLRenderOrder::operator==(const QGLRenderOrder &rhs) const
+{
+ return isEqual(rhs);
+}
+
+inline bool QGLRenderOrder::operator<(const QGLRenderOrder &rhs) const
+{
+ return isLessThan(rhs);
+}
+
+inline const QGLSceneNode *QGLRenderOrder::node() const
+{
+ return m_node;
+}
+
+inline QGLRenderState QGLRenderOrder::state() const
+{
+ return m_state;
+}
+
+inline void QGLRenderOrder::setState(const QGLRenderState &state)
+{
+ m_state = state;
+}
+
+inline QGLAbstractEffect *QGLRenderOrder::effectiveUserEffect() const
+{
+ QGLAbstractEffect *result = 0;
+ if (m_node)
+ {
+ if (m_node->userEffect())
+ result = m_node->userEffect();
+ else if (m_state.userEffect())
+ result = m_state.userEffect();
+ }
+ return result;
+}
+
+inline QGL::StandardEffect QGLRenderOrder::effectiveStandardEffect() const
+{
+ QGL::StandardEffect result = QGL::FlatColor;
+ if (m_node)
+ {
+ if (m_node->hasEffect())
+ result = m_node->effect();
+ else if (m_state.hasEffect())
+ result = m_state.standardEffect();
+ }
+ return result;
+}
+
+inline QGLMaterial *QGLRenderOrder::effectiveMaterial() const
+{
+ QGLMaterial *result = 0;
+ if (m_node)
+ {
+ if (m_node->material())
+ result = m_node->material();
+ else if (m_state.material())
+ result = m_state.material();
+ }
+ return result;
+}
+
+inline QGLMaterial *QGLRenderOrder::effectiveBackMaterial() const
+{
+ QGLMaterial *result = 0;
+ if (m_node)
+ {
+ if (m_node->backMaterial())
+ result = m_node->backMaterial();
+ else if (m_state.backMaterial())
+ result = m_state.backMaterial();
+ }
+ return result;
+}
+
+inline bool QGLRenderOrder::effectiveHasEffect() const
+{
+ bool result = false;
+ if (m_node)
+ {
+ if (m_node->hasEffect())
+ result = true;
+ else
+ result = m_state.hasEffect();
+ }
+ return result;
+}
+
+inline uint qHash(const QGLRenderOrder &order)
+{
+ quint64 result = order.effectHash();
+ return result ^ reinterpret_cast<quint64>(order.effectiveMaterial());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QGLRenderOrder &order);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGLRENDERORDER_H
diff --git a/src/threed/scene/qglrenderordercomparator.cpp b/src/threed/scene/qglrenderordercomparator.cpp
new file mode 100644
index 000000000..36da2838a
--- /dev/null
+++ b/src/threed/scene/qglrenderordercomparator.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglrenderordercomparator.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLRenderOrderComparator
+ \brief The QGLRenderOrderComparator class compares QGLRenderOrder instances.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ The QGLRenderOrderComparator class works with the QGLRenderSequencer and
+ QGLRenderOrder classes to optimize the rendering order of scene nodes.
+
+ This class is responsible for comparing QGLRenderOrder instances for
+ the QGLRenderSequencer.
+
+ Custom render orders may be created by sub-classing QGLRenderOrderComparator
+ and reimplementing the following method:
+ \list
+ \i bool operator()(const QGLRenderOrder &lhs, const QGLRenderOrder &rhs)
+ \endlist
+
+ Then set an instance of your class onto QGLPainter:
+
+ \code
+ void MyView::initializeGL(QGLPainter *painter)
+ {
+ painter->renderSequencer()->setRenderOrderComparator(new MyRenderOrderComparator);
+ }
+
+ void MyView::paintGL(QGLPainter *painter)
+ {
+ // draw uses QGLRenderOrder sub-class instances from m_renderOrderFactory
+ complexScene->draw(painter);
+ }
+ \endcode
+
+ See the QGLRenderOrder class documentation for more details.
+
+ \sa QGLRenderOrder
+*/
+
+/*!
+ \fn QGLRenderOrderComparator::QGLRenderOrderComparator()
+ Construct a new QGLRenderOrderComparator.
+*/
+
+/*!
+ \fn QGLRenderOrderComparator::~QGLRenderOrderComparator()
+ Destroys this QGLRenderOrderComparator, recovering any resources.
+*/
+
+/*!
+ Returns true if the \a lhs render order is less than the \a rhs;
+ otherwise returns false.
+
+ Reimplement this function when creating custom render orders.
+*/
+bool QGLRenderOrderComparator::isLessThan(const QGLRenderOrder &lhs, const QGLRenderOrder &rhs)
+{
+ bool result = false;
+ bool lhsHasEffect = lhs.effectiveHasEffect();
+ bool rhsHasEffect = rhs.effectiveHasEffect();
+ if (lhsHasEffect && rhsHasEffect)
+ {
+ QGLAbstractEffect *eff = lhs.effectiveUserEffect();
+ if (eff)
+ result = (eff < rhs.effectiveUserEffect());
+ else
+ result = !rhs.effectiveUserEffect() &&
+ (lhs.effectiveStandardEffect() < rhs.effectiveStandardEffect());
+ }
+ else
+ {
+ result = !lhsHasEffect;
+ }
+ if (!result)
+ {
+ result = (lhs.effectiveMaterial() < rhs.effectiveMaterial());
+ }
+ if (!result)
+ {
+ result = (lhs.effectiveBackMaterial() < rhs.effectiveBackMaterial());
+ }
+ return result;
+}
+
+/*!
+ Returns true if the \a lhs render order is equal to the \a rhs;
+ otherwise returns false.
+
+ Reimplement this function when creating custom render orders.
+*/
+bool QGLRenderOrderComparator::isEqualTo(const QGLRenderOrder &lhs, const QGLRenderOrder &rhs)
+{
+ bool result = false;
+ bool lhsHasEffect = lhs.effectiveHasEffect();
+ bool rhsHasEffect = rhs.effectiveHasEffect();
+ if (lhsHasEffect && rhsHasEffect)
+ {
+ QGLAbstractEffect *eff = lhs.effectiveUserEffect();
+ if (eff)
+ result = (eff == rhs.effectiveUserEffect());
+ else
+ result = (lhs.effectiveStandardEffect() == rhs.effectiveStandardEffect());
+ }
+ else
+ {
+ result = (lhsHasEffect == rhsHasEffect);
+ }
+ if (result)
+ {
+ result = (lhs.effectiveMaterial() == rhs.effectiveMaterial());
+ }
+ if (result)
+ {
+ result = (lhs.effectiveBackMaterial() == rhs.effectiveBackMaterial());
+ }
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/scene/qglrenderordercomparator.h b/src/threed/scene/qglrenderordercomparator.h
new file mode 100644
index 000000000..e71102751
--- /dev/null
+++ b/src/threed/scene/qglrenderordercomparator.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLRenderOrderComparator_H
+#define QGLRenderOrderComparator_H
+
+#include "qglrenderorder.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLSceneNode;
+
+class Q_QT3D_EXPORT QGLRenderOrderComparator
+{
+public:
+ QGLRenderOrderComparator() {}
+ virtual ~QGLRenderOrderComparator() {}
+
+ virtual bool isLessThan(const QGLRenderOrder &lhs, const QGLRenderOrder &rhs);
+ virtual bool isEqualTo(const QGLRenderOrder &lhs, const QGLRenderOrder &rhs);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGLRenderOrderComparator_H
diff --git a/src/threed/scene/qglrendersequencer.cpp b/src/threed/scene/qglrendersequencer.cpp
new file mode 100644
index 000000000..b819cabf9
--- /dev/null
+++ b/src/threed/scene/qglrendersequencer.cpp
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglrendersequencer.h"
+#include "qglrenderorder.h"
+#include "qglpainter.h"
+#include "qglrenderordercomparator.h"
+#include "qglrenderstate.h"
+
+#include <QtCore/qstack.h>
+
+/*!
+ \class QGLRenderSequencer
+ \brief The QGLRenderSequencer class orders the rendering of QGLSceneNode instances.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ The QGLRenderSequencer class works with the QGLRenderOrderComparator and
+ QGLRenderOrder classes to optimize the rendering order of scene nodes.
+
+ In general instances of this class are managed by QGLPainter and it should
+ not be necessary to explicitly create or manipulate them.
+
+ The render sequencer works by tracking instances of QGLRenderOrder objects
+ in a queue. As the scene graph is traversed during a call to a top-level
+ node's QGLSceneNode::draw() function, the sequencer adds one QGLRenderOrder
+ to the queue for each unique combination of rendering attributes.
+
+ The top level scene graph node loops once for each unique combination - it
+ does this in QGLSceneNode::draw() by calling nextInSequence(). At
+ each iteration, a current QGLRenderOrder is maintained, and only nodes
+ matching that order - as determined by \l{QGLRenderOrder::operator==()} -
+ are rendered in that pass. Non-matching nodes are added to a queue in the
+ order specified by \l{QGLRenderOrder::operator<()}.
+
+
+ Once an iteration/pass of
+ the scene graph is done, the next order is pulled from the front of the queue
+ and the current QGLRenderOrder is set to it.
+
+ Since the rendering attributes at a node are a function both of that node,
+ and attributes inherited from its parents, and since a given node may appear
+ multiple times at different places in the scene, it can thus have different
+ attributes and orders in each place. So there is no one-to-one mapping
+ between nodes and attributes.
+
+ To deal with this, QGLRenderOrder mappings are discovered during rendering.
+ There is no discovery pass. First, the initial QGLRenderOrder is lazily set
+ when the first geometry is actually drawn to the GPU - latching in that order
+ as the first current order. From that point, orders discovered that are
+ distinct from the current one are skipped in this rendering pass - by returning
+ false from renderInSequence() - and are instead added to the queue for rendering
+ on a subsequent pass.
+
+ When the final pass has been made, renderInSequence() returns false to the
+ top level QGLSceneNode, indicating that looping over passes is complete.
+
+ \sa QGLRenderOrder
+*/
+
+class QGLRenderSequencerPrivate
+{
+public:
+ QGLRenderSequencerPrivate(QGLPainter *painter);
+ ~QGLRenderSequencerPrivate();
+ QGLSceneNode *top;
+ QLinkedList<QGLRenderOrder> queue;
+ QStack<QGLRenderState> stack;
+ QSet<QGLRenderOrder> exclude;
+ QGLRenderOrder current;
+ QGLPainter *painter;
+ QGLRenderOrderComparator *compare;
+ bool latched;
+};
+
+QGLRenderSequencerPrivate::QGLRenderSequencerPrivate(QGLPainter *painter)
+ : top(0)
+ , current(QGLRenderOrder())
+ , painter(painter)
+ , compare(new QGLRenderOrderComparator)
+ , latched(false)
+{
+}
+
+QGLRenderSequencerPrivate::~QGLRenderSequencerPrivate()
+{
+ delete compare;
+}
+
+/*!
+ Construct a new QGLRenderSequencer for the \a painter.
+*/
+QGLRenderSequencer::QGLRenderSequencer(QGLPainter *painter)
+ : d(new QGLRenderSequencerPrivate(painter))
+{
+}
+
+/*!
+ Sets the render sequencer to operate on \a painter.
+*/
+void QGLRenderSequencer::setPainter(QGLPainter *painter)
+{
+ d->painter = painter;
+}
+
+/*!
+ Returns the current top node of the rendering tree, or NULL if the
+ sequencer has been reset.
+*/
+QGLSceneNode *QGLRenderSequencer::top() const
+{
+ return d->top;
+}
+
+/*!
+ Sets the current top node of the rendering tree to \a top.
+*/
+void QGLRenderSequencer::setTop(QGLSceneNode *top)
+{
+ d->top = top;
+}
+
+/*!
+ Reset this sequencer to start from the top of the scene graph again.
+ After this call the top() function will return NULL, and any scene
+ node passed to the renderInSequence() function will be treated as the
+ top of the scene graph. Also effects and materials will be ignored
+ until latched in - QGLPainter::draw() will call latch() to achieve this.
+
+ \sa top()
+*/
+void QGLRenderSequencer::reset()
+{
+ d->top = 0;
+ d->latched = false;
+ d->exclude.clear();
+ d->stack.clear();
+ d->current = QGLRenderOrder();
+}
+
+/*!
+ Returns true if there is a next rendering state in the queue; and if there
+ is a new order will be pulled from the queue, and its rendering attributes
+ - materials, effects and so on - will be applied to the painter for this
+ sequencer. Returns false when no more rendering states are queued and
+ scene is completely rendered.
+*/
+bool QGLRenderSequencer::nextInSequence()
+{
+ bool nextAvailable = true;
+ if (d->queue.size() > 0)
+ {
+ // process thru next render order
+ d->current = d->queue.takeFirst();
+ }
+ else
+ {
+ // end top level loop
+ nextAvailable = false;
+ }
+ return nextAvailable;
+}
+
+/*!
+ Returns true, when this \a node should be rendered, in the order dictated
+ by QGLRenderOrder objects generated by the current render order Comparator.
+ The \a node must be non-NULL.
+
+ When this function returns false, indicating that rendering should be
+ skipped for the current pass, a check is made to ensure that a state object
+ for this nodes rendering attributes is queued up for a later pass.
+
+ To customize the ordering, reimplement QGLRenderOrder and
+ QGLRenderOrderComparator; then set the custom Comparator onto the current
+ painter using setcompare().
+
+ \sa reset(), top(), nextInSequence()
+*/
+bool QGLRenderSequencer::renderInSequence(QGLSceneNode *node)
+{
+ Q_ASSERT(node);
+ Q_ASSERT(d->top);
+ bool doRender = true;
+ QGLRenderState state;
+ if (!d->stack.empty())
+ state = d->stack.top();
+ QGLRenderOrder o(node, state);
+ if (!d->current.isValid())
+ d->current = o;
+ if (d->latched && !d->compare->isEqualTo(o, d->current))
+ {
+ if (!d->exclude.contains(o))
+ insertNew(o);
+ doRender = false;
+ }
+ else
+ {
+ if (!d->latched)
+ d->exclude.insert(o);
+ }
+ return doRender;
+}
+
+/*!
+ Marks the render state for the \a node as started for this rendering pass. Call
+ this before rendering \a node, or any child nodes of \a node.
+
+ Once the rendering state is no longer valid, call endState().
+
+ To actually apply the effective state, as inherited from previous calls to
+ beginState() call the applyState() function.
+
+ \sa endState(), applyState()
+*/
+void QGLRenderSequencer::beginState(QGLSceneNode *node)
+{
+ QGLRenderState state;
+ if (!d->stack.empty())
+ state = d->stack.top();
+ state.updateFrom(node);
+ d->stack.push(state);
+}
+
+/*!
+ Marks the render state for the \a node as done for this rendering pass.
+
+ If a node has called beginState(), then this function must be called to maintain
+ the rendering stack. If this function call is not matched by a previous
+ beginState() call undefined behaviour may result. In debug mode it may assert.
+
+ \sa beginState(), applyState()
+*/
+void QGLRenderSequencer::endState(QGLSceneNode *node)
+{
+#ifndef QT_NO_DEBUG_STREAM
+ const QGLSceneNode *n = d->stack.top().node();
+ Q_UNUSED(n);
+ Q_UNUSED(node);
+ Q_ASSERT(n == node);
+#endif
+ d->stack.pop();
+}
+
+/*!
+ Applies the current rendering state to the painter for this sequencer.
+
+ \sa beginState(), endState()
+*/
+void QGLRenderSequencer::applyState()
+{
+ d->latched = true;
+ QGLRenderState s = d->stack.top();
+ if (s.hasEffect() && !d->painter->isPicking())
+ {
+ if (s.userEffect())
+ {
+ if (d->painter->userEffect() != s.userEffect())
+ d->painter->setUserEffect(s.userEffect());
+ }
+ else
+ {
+ if (d->painter->userEffect() ||
+ d->painter->standardEffect() != s.standardEffect())
+ d->painter->setStandardEffect(s.standardEffect());
+ }
+ }
+ if (s.material() && !d->painter->isPicking())
+ {
+ QGLMaterial *mat = s.material();
+ if (1) //FIXME: d->painter->faceMaterial(QGL::FrontFaces) != mat)
+ {
+ d->painter->setFaceMaterial(QGL::FrontFaces, mat);
+ int texUnit = 0;
+ for (int i = 0; i < mat->textureLayerCount(); ++i)
+ {
+ QGLTexture2D *tex = mat->texture(i);
+ if (tex)
+ {
+ d->painter->glActiveTexture(GL_TEXTURE0 + texUnit);
+ tex->bind();
+ ++texUnit;
+ }
+ }
+ }
+ }
+}
+
+void QGLRenderSequencer::insertNew(const QGLRenderOrder &order)
+{
+ QLinkedList<QGLRenderOrder>::iterator it = d->queue.begin();
+ for ( ; it != d->queue.end(); ++it)
+ {
+ const QGLRenderOrder o = *it;
+ if (d->compare->isLessThan(order, o))
+ break;
+ }
+ d->queue.insert(it, order);
+ d->exclude.insert(order);
+}
+
+/*!
+ Returns the current render order comparator. By default this is an
+ instance of the base class QGLRenderOrderComparator.
+
+ \sa setComparator()
+*/
+QGLRenderOrderComparator *QGLRenderSequencer::comparator() const
+{
+ return d->compare;
+}
+
+/*!
+ Sets the current render order \a comparator. This is only needed if a
+ custom rendering order is to be created. The argument \a comparator
+ must be non-null, or undefined behaviour will result.
+
+ Any existing current comparator is destroyed.
+
+ \sa renderInSequence(), comparator()
+*/
+void QGLRenderSequencer::setComparator(QGLRenderOrderComparator *comparator)
+{
+ Q_ASSERT(comparator);
+ delete d->compare;
+ d->compare = comparator;
+}
diff --git a/src/threed/scene/qglrendersequencer.h b/src/threed/scene/qglrendersequencer.h
new file mode 100644
index 000000000..a2eeffac6
--- /dev/null
+++ b/src/threed/scene/qglrendersequencer.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QGLRENDERSEQUENCER_H
+#define QGLRENDERSEQUENCER_H
+
+#include <QtCore/qlinkedlist.h>
+#include <QtCore/qset.h>
+
+#include "qglrenderorder.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLSceneNode;
+class QGLPainter;
+class QGLRenderOrderComparator;
+class QGLRenderSequencerPrivate;
+
+class Q_QT3D_EXPORT QGLRenderSequencer
+{
+public:
+ explicit QGLRenderSequencer(QGLPainter *painter);
+ void setPainter(QGLPainter *painter);
+ bool renderInSequence(QGLSceneNode *node);
+ bool nextInSequence();
+ void beginState(QGLSceneNode *node);
+ void endState(QGLSceneNode *node);
+ void reset();
+ QGLSceneNode *top() const;
+ void setTop(QGLSceneNode *top);
+ QGLRenderOrderComparator *comparator() const;
+ void setComparator(QGLRenderOrderComparator *comparator);
+ void applyState();
+private:
+ void insertNew(const QGLRenderOrder &order);
+
+ QGLRenderSequencerPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGLRENDERSEQUENCER_H
diff --git a/src/threed/scene/qglrenderstate.cpp b/src/threed/scene/qglrenderstate.cpp
new file mode 100644
index 000000000..8a2fa6cfe
--- /dev/null
+++ b/src/threed/scene/qglrenderstate.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglrenderstate.h"
+
+/*!
+ \class QGLRenderState
+ \brief The QGLRenderState class encapsulates the states of a rendering pass.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ The QGLRenderState class works with the QGLRenderOrder class to optimize
+ the rendering order of scene nodes.
+
+ In general instances of this class are managed by the render sequencer
+ and it should not be necessary to explicitly create or manipulate them.
+
+ A QGLRenderState instance encapsulates rendering properties for a given
+ path through the rendering process. The state includes properties such as
+ effects, and materials; which may either be directly set on a scene node,
+ or inherited from its parents.
+
+ QGLRenderState may be subclassed in advanced applications to provide a
+ different inheritance pattern for rendering properties - reimplement the
+ updateFrom() function to do this. The default implementation simply sets
+ an effect on the state if the argument node has an effect (found by
+ calling the QGLSceneNode::hasEffect() function), and sets a material on
+ the state if the node has a non-null material; otherwise the existing
+ state is left as it is.
+
+ The render sequencer will ensure that the relevant render state is set
+ onto the painter at the beginning of the pass which renders all nodes
+ with that state.
+
+ \sa QGLRenderOrder
+*/
+
+class QGLRenderStatePrivate : public QSharedData
+{
+public:
+ QGLRenderStatePrivate();
+ ~QGLRenderStatePrivate();
+ QGLRenderStatePrivate *clone() const;
+
+ QBasicAtomicInt ref;
+
+ bool hasEffect;
+ QGLMaterial *material;
+ QGLMaterial *backMaterial;
+ QGL::StandardEffect standardEffect;
+ QGLAbstractEffect *userEffect;
+ const QGLSceneNode *node;
+};
+
+QGLRenderStatePrivate::QGLRenderStatePrivate()
+ : hasEffect(false)
+ , material(0)
+ , backMaterial(0)
+ , standardEffect(QGL::FlatColor)
+ , userEffect(0)
+ , node(0)
+{
+ ref = 0;
+}
+
+QGLRenderStatePrivate::~QGLRenderStatePrivate()
+{
+}
+
+QGLRenderStatePrivate *QGLRenderStatePrivate::clone() const
+{
+ QGLRenderStatePrivate *r = new QGLRenderStatePrivate;
+ r->hasEffect = hasEffect;
+ r->material = material;
+ r->backMaterial = backMaterial;
+ r->standardEffect = standardEffect;
+ r->userEffect = userEffect;
+ r->node = node;
+ return r;
+}
+
+/*!
+ Creates a new QGLRenderState empty of any values.
+*/
+QGLRenderState::QGLRenderState()
+ : d(0)
+{
+}
+
+/*!
+ Creates a new QGLRenderState as a copy of \a other
+*/
+QGLRenderState::QGLRenderState(const QGLRenderState &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Destroys this QGLRenderState recovering and resources.
+*/
+QGLRenderState::~QGLRenderState()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Assigns this QGLRenderState to be a copy of \a rhs.
+*/
+QGLRenderState &QGLRenderState::operator=(const QGLRenderState &rhs)
+{
+ if (d != rhs.d)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = rhs.d;
+ if (d)
+ d->ref.ref();
+ }
+ return *this;
+}
+
+/*!
+ Sets the values of this QGLRenderState from the \a node, where
+ the node has a value. For example if the \a node has an effect
+ but no material, then this state will have its effect changed to
+ that of the node, but this state's material will be unchanged.
+*/
+void QGLRenderState::updateFrom(const QGLSceneNode *node)
+{
+ detach();
+ if (node->hasEffect())
+ {
+ d->hasEffect = true;
+ if (node->userEffect())
+ d->userEffect = node->userEffect();
+ else
+ d->standardEffect = node->effect();
+ }
+ if (node->material())
+ d->material = node->material();
+ if (node->backMaterial())
+ d->backMaterial = node->backMaterial();
+ d->node = node;
+}
+
+/*!
+ Returns the user effect stored on this QGLRenderState, or null if no
+ user effect has been set. The default value is null.
+*/
+QGLAbstractEffect *QGLRenderState::userEffect() const
+{
+ QGLAbstractEffect *e = 0;
+ if (d)
+ e = d->userEffect;
+ return e;
+}
+
+/*!
+ Returns the standard effect stored on this QGLRenderState. The
+ default value is QGL::FlatColor. To determine if an effect has
+ been specifically set call hasEffect().
+*/
+QGL::StandardEffect QGLRenderState::standardEffect() const
+{
+ QGL::StandardEffect e = QGL::FlatColor;
+ if (d)
+ e = d->standardEffect;
+ return e;
+}
+
+/*!
+ Returns true is there is a valid effect on this QGLRenderState. The
+ default value is false.
+*/
+bool QGLRenderState::hasEffect() const
+{
+ bool r = false;
+ if (d)
+ r = d->hasEffect;
+ return r;
+}
+
+/*!
+ Returns the material stored on this QGLRenderState, or null if no
+ material has been set. The default value is null.
+*/
+QGLMaterial *QGLRenderState::material() const
+{
+ QGLMaterial *m = 0;
+ if (d)
+ m = d->material;
+ return m;
+}
+
+/*!
+ Returns the back material stored on this QGLRenderState, or null if no
+ back material has been set. The default value is null.
+*/
+QGLMaterial *QGLRenderState::backMaterial() const
+{
+ QGLMaterial *m = 0;
+ if (d)
+ m = d->backMaterial;
+ return m;
+}
+
+/*!
+ Returns the node used to populate this QGLRenderState.
+*/
+const QGLSceneNode *QGLRenderState::node() const
+{
+ const QGLSceneNode *s = 0;
+ if (d)
+ s = d->node;
+ return s;
+}
+
+/*!
+ Returns true if this is a valid representation of a render state, that
+ is if it has ever been updated from a node; and false otherwise.
+*/
+bool QGLRenderState::isValid() const
+{
+ if (d && d->node)
+ return true;
+ return false;
+}
+
+/*!
+ \fn bool QGLRenderState::operator==(const QGLRenderState &rhs) const
+ Returns true if this state is equal to \a rhs, that is if each of the
+ materials, effects and values are equal to those of \a rhs.
+*/
+void QGLRenderState::detach()
+{
+ if (!d) // lazy creation of data block
+ {
+ d = new QGLRenderStatePrivate;
+ d->ref.ref();
+ }
+ else
+ {
+ if (d->ref > 1) // being shared, must detach
+ {
+ QGLRenderStatePrivate *temp = d->clone();
+ d->ref.deref();
+ d = temp;
+ d->ref.ref();
+ }
+ }
+}
+
+/*!
+ Returns a hash value representing this state.
+*/
+uint QGLRenderState::hash() const
+{
+ const QByteArray bytes((const char *)d, sizeof(d));
+ return qHash(bytes);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QGLRenderState &order)
+{
+ dbg << "QGLRenderState" << &order << "-- user effect:" << order.userEffect()
+ << "-- standardEffect:" << order.standardEffect()
+ << "-- hasEffect:" << order.hasEffect()
+ << "-- material:" << order.material()
+ << "-- back material:" << order.backMaterial()
+ << "-- node:" << order.node();
+ return dbg;
+}
+
+#endif
diff --git a/src/threed/scene/qglrenderstate.h b/src/threed/scene/qglrenderstate.h
new file mode 100644
index 000000000..4f2593cc9
--- /dev/null
+++ b/src/threed/scene/qglrenderstate.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QGLRENDERSTATE_H
+#define QGLRENDERSTATE_H
+
+#include "qglnamespace.h"
+#include "qglscenenode.h"
+
+#include <QtCore/qshareddata.h>
+
+class QGLAbstractEffect;
+class QGLMaterial;
+
+class QGLRenderStatePrivate;
+
+class Q_QT3D_EXPORT QGLRenderState
+{
+public:
+ QGLRenderState();
+ QGLRenderState(const QGLRenderState &other);
+ virtual ~QGLRenderState();
+ QGLRenderState &operator=(const QGLRenderState &rhs);
+ virtual void updateFrom(const QGLSceneNode *node);
+ QGLAbstractEffect *userEffect() const;
+ QGL::StandardEffect standardEffect() const;
+ bool hasEffect() const;
+ QGLMaterial *material() const;
+ QGLMaterial *backMaterial() const;
+ const QGLSceneNode *node() const;
+ uint hash() const;
+ bool operator==(const QGLRenderState &rhs) const
+ {
+ if (userEffect() != rhs.userEffect())
+ return false;
+ if (standardEffect() != rhs.standardEffect())
+ return false;
+ if (hasEffect() != rhs.hasEffect())
+ return false;
+ if (material() != rhs.material())
+ return false;
+ if (backMaterial() != rhs.backMaterial())
+ return false;
+ return true;
+ }
+ bool isValid() const;
+private:
+ void detach();
+ QGLRenderStatePrivate *d;
+};
+
+inline uint qHash(const QGLRenderState &s)
+{
+ return s.hash();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QGLRenderState &order);
+#endif
+
+#endif // QGLRENDERSTATE_H
diff --git a/src/threed/scene/qglsceneformatplugin.cpp b/src/threed/scene/qglsceneformatplugin.cpp
new file mode 100644
index 000000000..d1b26b9f7
--- /dev/null
+++ b/src/threed/scene/qglsceneformatplugin.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglsceneformatplugin.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLSceneFormatHandler
+ \brief The QGLSceneFormatHandler class defines the common format I/O interface for loading 3D scene formats.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ \sa QGLSceneFormatPlugin
+*/
+
+class QGLSceneFormatHandlerPrivate
+{
+public:
+ QGLSceneFormatHandlerPrivate()
+ {
+ device = 0;
+ }
+
+ QIODevice *device;
+ QString format;
+ QUrl url;
+};
+
+/*!
+ Constructs a 3D scene format handler.
+*/
+QGLSceneFormatHandler::QGLSceneFormatHandler()
+{
+ d_ptr = new QGLSceneFormatHandlerPrivate();
+}
+
+/*!
+ Destroys this 3D scene format handler.
+*/
+QGLSceneFormatHandler::~QGLSceneFormatHandler()
+{
+ delete d_ptr;
+}
+
+/*!
+ Returns the device currently assigned to the 3D scene format handler.
+ Returns null if no device has been assigned.
+
+ \sa setDevice()
+*/
+QIODevice *QGLSceneFormatHandler::device() const
+{
+ return d_ptr->device;
+}
+
+/*!
+ Sets the device for this 3D scene format handler to \a device.
+ The handler will use this device when reading 3D scenes.
+
+ The device can only be set once and must be set before calling
+ read(). If you need to read multiple files, construct multiple
+ instances of the appropriate QGLSceneFormatHandler subclass.
+
+ \sa device()
+*/
+void QGLSceneFormatHandler::setDevice(QIODevice *device)
+{
+ d_ptr->device = device;
+}
+
+/*!
+ Returns the format that is currently assigned to this 3D scene
+ format handler. Returns an empty string if no format has been assigned.
+
+ \sa setFormat()
+*/
+QString QGLSceneFormatHandler::format() const
+{
+ return d_ptr->format;
+}
+
+/*!
+ Sets the format of this 3D scene format handler to \a format.
+
+ \sa format()
+*/
+void QGLSceneFormatHandler::setFormat(const QString& format)
+{
+ d_ptr->format = format;
+}
+
+/*!
+ Returns the url of the data provided by device(). This is
+ typically used when the data in device() refers to additional
+ files that need to be located relative to the original
+ directory.
+
+ \sa setUrl()
+*/
+QUrl QGLSceneFormatHandler::url() const
+{
+ return d_ptr->url;
+}
+
+/*!
+ Sets the \a url of the data provided by device().
+
+ \sa url()
+*/
+void QGLSceneFormatHandler::setUrl(const QUrl& url)
+{
+ d_ptr->url = url;
+}
+
+/*!
+ Decodes and applies \a options to this handler. Generally this will be
+ called by the QGLAbstractScene::loadScene() method prior to reading
+ the model data with read(). Exactly what the string value may contain
+ and the meaning of the encoded options depends on each individual plugin.
+
+ This default implementation simply does nothing.
+*/
+void QGLSceneFormatHandler::decodeOptions(const QString &options)
+{
+ Q_UNUSED(options);
+}
+
+/*!
+ \fn QGLAbstractScene *QGLSceneFormatHandler::read()
+
+ Reads a 3D scene from device() and returns it. Returns null if
+ the format of device() is invalid and a scene could not be read.
+*/
+
+/*!
+ \class QGLSceneFormatFactoryInterface
+ \brief The QGLSceneFormatFactoryInterface class provides the factory interface for QGLSceneFormatPlugin.
+ \internal
+*/
+
+/*!
+ \class QGLSceneFormatPlugin
+ \brief The QGLSceneFormatPlugin class defines an interface for loading 3D object and scene formats.
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ \sa QGLSceneFormatHandler
+*/
+
+/*!
+ Constructs a 3D scene format plugin with the given \a parent. This is
+ invoked automatically by the Q_EXPORT_PLUGIN2() macro.
+*/
+QGLSceneFormatPlugin::QGLSceneFormatPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys this 3D scene format plugin. This is invoked automatically
+ when the plugin is unloaded.
+*/
+QGLSceneFormatPlugin::~QGLSceneFormatPlugin()
+{
+}
+
+/*!
+ \fn QStringList QGLSceneFormatPlugin::keys() const
+
+ Returns the list of format keys this plugin supports. These keys
+ are usually the names of the 3D scene formats that are implemented in
+ the plugin (e.g., "3ds", "obj", etc). The returned elements must
+ be in lower case.
+
+ \sa create()
+*/
+
+/*!
+ \fn QGLSceneFormatHandler *QGLSceneFormatPlugin::create(QIODevice *device, const QUrl& url, const QString &format) const
+
+ Creates and returns a QGLSceneFormatHandler for handling the data in
+ \a device according to \a format. The \a url specifies the original
+ location of the data for resolving relative resource references.
+
+ \sa keys()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/threed/scene/qglsceneformatplugin.h b/src/threed/scene/qglsceneformatplugin.h
new file mode 100644
index 000000000..8ea069626
--- /dev/null
+++ b/src/threed/scene/qglsceneformatplugin.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSCENEFORMATPLUGIN_H
+#define QGLSCENEFORMATPLUGIN_H
+
+#include "qt3dglobal.h"
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLAbstractScene;
+class QGLSceneFormatHandlerPrivate;
+
+class Q_QT3D_EXPORT QGLSceneFormatHandler
+{
+public:
+ QGLSceneFormatHandler();
+ virtual ~QGLSceneFormatHandler();
+
+ QIODevice *device() const;
+ void setDevice(QIODevice *device);
+
+ QString format() const;
+ void setFormat(const QString& format);
+
+ QUrl url() const;
+ void setUrl(const QUrl& url);
+
+ virtual QGLAbstractScene *read() = 0;
+
+ virtual void decodeOptions(const QString &options);
+
+private:
+ QGLSceneFormatHandlerPrivate *d_ptr;
+};
+
+struct Q_QT3D_EXPORT QGLSceneFormatFactoryInterface : public QFactoryInterface
+{
+ virtual QGLSceneFormatHandler *create(QIODevice *device, const QUrl& url, const QString &format = QString()) const = 0;
+};
+
+#define QGLSceneFormatFactoryInterface_iid \
+ "com.trolltech.Qt.QGLSceneFormatFactoryInterface"
+Q_DECLARE_INTERFACE(QGLSceneFormatFactoryInterface, QGLSceneFormatFactoryInterface_iid)
+
+class Q_QT3D_EXPORT QGLSceneFormatPlugin : public QObject, public QGLSceneFormatFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QGLSceneFormatFactoryInterface:QFactoryInterface)
+public:
+ explicit QGLSceneFormatPlugin(QObject *parent = 0);
+ virtual ~QGLSceneFormatPlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QGLSceneFormatHandler *create(QIODevice *device, const QUrl& url, const QString &format = QString()) const = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/scene/qglscenenode.cpp b/src/threed/scene/qglscenenode.cpp
new file mode 100644
index 000000000..839afa51e
--- /dev/null
+++ b/src/threed/scene/qglscenenode.cpp
@@ -0,0 +1,1794 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglabstractscene.h"
+#include "qglscenenode.h"
+#include "qglscenenode_p.h"
+#include "qglpicknode.h"
+#include "qglpainter.h"
+#include "qgeometrydata.h"
+#include "qglmaterialcollection.h"
+#include "qmatrix4x4.h"
+#include "qglrendersequencer.h"
+#include "qglabstracteffect.h"
+#include "qgraphicstransform3d.h"
+
+#include <QtGui/qmatrix4x4.h>
+#if !defined(QT_NO_THREAD)
+#include <QtCore/qthread.h>
+#include <QtGui/qapplication.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLSceneNode
+ \brief The QGLSceneNode class defines a node in a 3D scene.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::scene
+
+ QGLSceneNode represents one component of a scene. The QGLSceneNode
+ class manages materials, effects and transformations for itself and
+ for its child nodes.
+
+ As a general approach to 3D applications, a tree of QGLSceneNodes may
+ be constructed, geometry added to them, materials and transformations
+ applied, all during application initialization; and then by simply
+ calling the draw() function the scene is easily rendered for each frame.
+
+ \section1 Geometry
+
+ Multiple QGLSceneNodes can reference the same geometry, whilst
+ applying different transformations and treatments to it. Since
+ QGLSceneNode is a QObject sub class it cannot be copied directly, so
+ instead use the clone() function for this purpose.
+
+ A scene node allows referencing into sub-parts of geometry, via the start
+ and count properties.
+
+ The start index is an offset into the geometry at which drawing will start.
+ The default start index is 0, so that drawing will start from the beginning
+ of the geometry. The count dictates how many vertices will be drawn. The
+ default count is 0, which instructs the underlying geometry to draw all
+ vertices.
+
+ A node may have no geometry, that is \c{geometry().count() == 0}. This is
+ useful for example to have one node controlling or collecting together
+ several child nodes to be manipulated as a unit.
+
+ \section1 Materials
+
+ Also a node may have a local material. This allows drawing the same geometry
+ with different materials (which includes different textures).
+
+ When accessing a QGLSceneNode via QML, or for simple applications, the
+ pointer based material functions are convenient and intuitive, saving the
+ trouble of adding the material pointer to the correct palette:
+ \list
+ \i material()
+ \i setMaterial()
+ \i backMaterial()
+ \i setBackMaterial()
+ \endlist
+
+ For more complex applications; for example building model loaders, or for
+ larger scenes; where you need to explicitly manage materials via a palette,
+ use the index based functions:
+ \list
+ \i materialIndex()
+ \i setMaterialIndex()
+ \i backMaterialIndex()
+ \i setBackMaterialIndex()
+ \endlist
+
+ The behaviour of both with respect to faces is the same - if a material()
+ is specified but no backMaterial() is specified, then the material() is
+ applied to both faces; if both material() and backMaterial() are non-null
+ then they are applied to their specific faces.
+
+ \section1 Transformations
+
+ Typically the local transformation matrix is set by the process that
+ constructed the node: in the case of an imported model, it is likely
+ to have been specified by the model file. To make individual changes
+ to the location or orientation of this node, use the position() and
+ transforms() properties.
+
+ \section1 Scene Graph
+
+ Use childNodes() to obtain the list of child nodes, and add and remove
+ child nodes by the addNode() and removeNode() methods. If a QGLSceneNode
+ is constructed with a QGLSceneNode parent, then addNode() will be
+ called implicitly on the parent.
+
+ A child may be a child multiple times, a child may be under more than one
+ parent, and several parents may reference the same child. There is however
+ no protection against cycles, so a child must not be a parent of itself,
+ even if indirectly.
+
+ A child node for the purposes of rendering means a child added via the
+ addNode() method. The default QGLSceneNode constructor will check to
+ see if its parent is a QGLSceneNode and add itself via the addNode()
+ function if it is.
+
+ To help debug a scene, use the qDumpScene() function to get a printout
+ on stderr of the entire structure of the scene below the argument node.
+
+ \section1 Debugging Lighting Normals
+
+ The ViewNormals option is an advanced feature for use when inspecting
+ and debugging models or geometry in a scene. The lighting normals
+ are displayed as a straight line from the vertex pointing in
+ the direction of the lighting normal. This is useful for
+ example to show where normals are inverted or wrongly
+ calculated.
+
+ The setting of the ViewNormals flag is not propagated to child nodes,
+ instead set the flag to true for the node or nodes where its
+ needed. To set the flag on all child nodes use code like:
+
+ \code
+ foreach (QGLSceneNode *node, scene.allChildren())
+ node->setNormalViewEnabled(true);
+ \endcode
+
+ \image spiky-teapot.png
+
+ \sa QGLAbstractScene
+*/
+
+/*!
+ \enum QGLSceneNode::Option
+ This enum defines option flags for QGLSceneNode.
+
+ \value CullBoundingBox Perform a cull using boundingBox() before
+ attempting to draw the geometry(). Default is true.
+ \value ViewNormals Enables the display of lighting normals for
+ debugging purposes. Default is false.
+
+ \sa setOptions()
+*/
+
+/*!
+ Constructs a new scene node and attaches it to \a parent. If parent is
+ a QGLSceneNode then this node is added to it as a child.
+*/
+QGLSceneNode::QGLSceneNode(QObject *parent)
+ : QObject(parent)
+ , d_ptr(new QGLSceneNodePrivate())
+{
+ QGLSceneNode *sceneParent = qobject_cast<QGLSceneNode*>(parent);
+ if (sceneParent)
+ sceneParent->addNode(this);
+}
+
+/*!
+ \internal
+ Used by clone().
+*/
+QGLSceneNode::QGLSceneNode(QGLSceneNodePrivate *d, QObject *parent)
+ : QObject(parent)
+ , d_ptr(d)
+{
+ QGLSceneNode *sceneParent = qobject_cast<QGLSceneNode*>(parent);
+ if (sceneParent)
+ sceneParent->addNode(this);
+}
+
+/*!
+ Constructs a new scene node referencing \a geometry and attaches it to
+ \a parent. If parent is a QGLSceneNode then this node is added to it
+ as a child.
+*/
+QGLSceneNode::QGLSceneNode(const QGeometryData &geometry, QObject *parent)
+ : QObject(parent)
+ , d_ptr(new QGLSceneNodePrivate())
+{
+ Q_D(QGLSceneNode);
+ d->geometry = geometry;
+ QGLSceneNode *sceneParent = qobject_cast<QGLSceneNode*>(parent);
+ if (sceneParent)
+ sceneParent->addNode(this);
+}
+
+/*!
+ Destroys this scene node.
+*/
+QGLSceneNode::~QGLSceneNode()
+{
+ Q_D(QGLSceneNode);
+
+ // Detach ourselves from our children. The children will be
+ // deleted separately when their QObject::parent() deletes them.
+ for (int index = 0; index < d->childNodes.count(); ++index)
+ d->childNodes.at(index)->d_ptr->parentNodes.removeOne(this);
+
+ // Detach ourselves from our remaining parents, and notify them
+ // to update their bounding boxes. This won't be needed if we
+ // are recursively destroying a tree of nodes because the parent
+ // already detached from this node above.
+ for (int index = 0; index < d->parentNodes.count(); ++index) {
+ QGLSceneNode *parent = d->parentNodes.at(index);
+ parent->d_ptr->childNodes.removeOne(this);
+ parent->invalidateBoundingBox();
+ }
+}
+
+/*!
+ Returns the drawing options associated with this node.
+ The default is CullBoundingBox.
+
+ \sa setOptions(), setOption()
+*/
+QGLSceneNode::Options QGLSceneNode::options() const
+{
+ Q_D(const QGLSceneNode);
+ return d->options;
+}
+
+/*!
+ Sets the drawing \a options associated with this node.
+
+ \sa options(), setOption()
+*/
+void QGLSceneNode::setOptions(QGLSceneNode::Options options)
+{
+ Q_D(QGLSceneNode);
+ if (d->options != options) {
+ d->options = options;
+ emit updated();
+ }
+}
+
+/*!
+ Enables or disables \a option according to \a value.
+
+ \sa options(), setOptions()
+*/
+void QGLSceneNode::setOption(QGLSceneNode::Option option, bool value)
+{
+ Q_D(QGLSceneNode);
+ QGLSceneNode::Options opts = d->options;
+ if (value)
+ opts |= option;
+ else
+ opts &= ~option;
+ if (d->options != opts) {
+ d->options = opts;
+ emit updated();
+ }
+}
+
+/*!
+ Returns the geometry associated with this node, or a null QGeometryData
+ if no geometry has been associated with it.
+
+ \sa setGeometry()
+*/
+QGeometryData QGLSceneNode::geometry() const
+{
+ Q_D(const QGLSceneNode);
+ return d->geometry;
+}
+
+/*!
+ Sets the geometry associated with this node to be \a geometry.
+ Typically the \a geometry will be some type of mesh object. The
+ default implementation of the QGLSceneNode::draw() method will call
+ the geometry's draw() method.
+
+ \sa geometry()
+*/
+void QGLSceneNode::setGeometry(QGeometryData geometry)
+{
+ Q_D(QGLSceneNode);
+ d->geometry = geometry;
+ emit updated();
+}
+
+/*!
+ Returns a bounding box for the portion of the geometry referenced by
+ this scene node. If the value of start() is 0, and count() is the same
+ as geometry()->size() then the bounding box will be the same as
+ geometry()->boundingBox(). However if the scene node only references
+ some part of the geometry, a bounding box for this section is calculated.
+
+ If this scene node has child nodes then the bounding box will be the
+ calculated union of the bounding box for this nodes geometry (if any) and
+ the bounding boxes of the children.
+
+ The calculated value is cached and returned on subsequent calls, but
+ could be expensive to calculate initially.
+*/
+QBox3D QGLSceneNode::boundingBox() const
+{
+ Q_D(const QGLSceneNode);
+ if (d->boxValid)
+ return d->bb;
+ d->bb = QBox3D();
+ if (d->geometry.count() > 0)
+ {
+ if (d->start == 0 && (d->count == d->geometry.count() || d->count == 0))
+ {
+ d->bb = d->geometry.boundingBox();
+ }
+ else
+ {
+ QGL::IndexArray indices = d->geometry.indices();
+ for (int i = d->start; i < (d->start + d->count); ++i)
+ {
+ int ix = indices.at(i);
+ d->bb.unite(d->geometry.vertexAt(ix));
+ }
+ }
+ }
+ QList<QGLSceneNode*>::const_iterator it = d->childNodes.constBegin();
+ for ( ; it != d->childNodes.constEnd(); ++it)
+ {
+ QGLSceneNode *n = *it;
+ QBox3D b = n->boundingBox();
+ d->bb.unite(b);
+ }
+ d->bb.transform(transform());
+ d->boxValid = true;
+ return d->bb;
+}
+
+// Calculate the resulting matrix from the position, local transform,
+// and list of transforms.
+QMatrix4x4 QGLSceneNode::transform() const
+{
+ Q_D(const QGLSceneNode);
+ QMatrix4x4 m;
+ if (!d->translate.isNull())
+ m.translate(d->translate);
+ if (!d->localTransform.isIdentity())
+ m *= d->localTransform;
+ for (int index = d->transforms.size() - 1; index >= 0; --index)
+ d->transforms.at(index)->applyTo(&m);
+ return m;
+}
+
+/*!
+ Returns the local transform associated with this node. If no
+ local transform has been explicitly set, this method returns a
+ QMatrix4x4 set to the identity matrix.
+
+ The local transform is typically set during model loading or
+ geometry construction, and is a feature of the geometry.
+
+ In general to change the location or orientation of the node
+ use the position() or transforms() properties instead.
+
+ \sa setLocalTransform(), position(), transforms()
+*/
+QMatrix4x4 QGLSceneNode::localTransform() const
+{
+ Q_D(const QGLSceneNode);
+ return d->localTransform;
+}
+
+/*!
+ Sets the local transform associated with this node to be \a transform.
+ The default implementation of the QGLSceneNode::draw() method will
+ apply this transform to the QGLPainter before drawing any geometry.
+
+ \sa localTransform()
+*/
+void QGLSceneNode::setLocalTransform(const QMatrix4x4 &transform)
+{
+ Q_D(QGLSceneNode);
+ if (d->localTransform != transform)
+ {
+ d->localTransform = transform;
+ emit updated();
+ invalidateTransform();
+ }
+}
+
+/*!
+ \property QGLSceneNode::position
+ \brief The amounts of x, y and z axis translation for this node.
+
+ Since most nodes are situated relative to \c{(0, 0, 0)} when imported as
+ part of a model or constructed programatically, the translation is
+ effectively the position of the model in the scene.
+
+ The x, y and z axis translations can also be specified individually as
+ separate properties \l x, \l y, and \l z
+
+ \sa x(), y(), z()
+*/
+QVector3D QGLSceneNode::position() const
+{
+ Q_D(const QGLSceneNode);
+ return d->translate;
+}
+
+void QGLSceneNode::setPosition(const QVector3D &p)
+{
+ Q_D(QGLSceneNode);
+ if (p != d->translate)
+ {
+ d->translate = p;
+ emit updated();
+ invalidateTransform();
+ }
+}
+
+/*!
+ \property QGLSceneNode::x
+ \brief The amount of x axis translation for this node.
+
+ \sa position()
+*/
+qreal QGLSceneNode::x() const
+{
+ Q_D(const QGLSceneNode);
+ return d->translate.x();
+}
+
+void QGLSceneNode::setX(qreal x)
+{
+ Q_D(QGLSceneNode);
+ if (x != d->translate.x())
+ {
+ d->translate.setX(x);
+ emit updated();
+ invalidateTransform();
+ }
+}
+
+/*!
+ \property QGLSceneNode::y
+ \brief The amount of y axis translation for this node.
+
+ \sa position()
+*/
+qreal QGLSceneNode::y() const
+{
+ Q_D(const QGLSceneNode);
+ return d->translate.y();
+}
+
+void QGLSceneNode::setY(qreal y)
+{
+ Q_D(QGLSceneNode);
+ if (y != d->translate.y())
+ {
+ d->translate.setY(y);
+ emit updated();
+ invalidateTransform();
+ }
+}
+
+/*!
+ \property QGLSceneNode::z
+ \brief The amount of z axis translation for this node.
+
+ \sa position()
+*/
+qreal QGLSceneNode::z() const
+{
+ Q_D(const QGLSceneNode);
+ return d->translate.z();
+}
+
+void QGLSceneNode::setZ(qreal z)
+{
+ Q_D(QGLSceneNode);
+ if (z != d->translate.z())
+ {
+ d->translate.setZ(z);
+ emit updated();
+ invalidateTransform();
+ }
+}
+
+/*!
+ Returns the list of transformations to apply to this node.
+ The default is the empty list.
+
+ The transformations are applied to the node itself, so a
+ QGraphicsScale3D followed by a QGraphicsTranslation3D will
+ first scale the node in its local co-ordinate system,
+ and then translate the node a new location.
+
+ In the mathematical sense, the transformations are applied to
+ the modelview matrix in the reverse order in which they appear
+ in this list.
+
+ The position() is applied after all other transformations
+ have been applied.
+
+ \sa setTransforms(), addTransform(), position()
+*/
+QList<QGraphicsTransform3D *> QGLSceneNode::transforms() const
+{
+ Q_D(const QGLSceneNode);
+ return d->transforms;
+}
+
+/*!
+ Sets the list of transformations to apply to this node to \a transforms.
+
+ The transformations are applied to the node itself, so a
+ QGraphicsScale3D followed by a QGraphicsTranslation3D will
+ first scale the node in its local co-ordinate system,
+ and then translate the node a new location.
+
+ In the mathematical sense, the transformations are applied to
+ the modelview matrix in the reverse order in which they appear
+ in \a transforms.
+
+ The position() is applied after all other transformations
+ have been applied.
+
+ \sa transforms(), addTransform(), position()
+*/
+void QGLSceneNode::setTransforms(const QList<QGraphicsTransform3D *> &transforms)
+{
+ Q_D(QGLSceneNode);
+ for (int index = 0; index < d->transforms.size(); ++index) {
+ QGraphicsTransform3D *transform = d->transforms.at(index);
+ disconnect(transform, SIGNAL(transformChanged()), this, SLOT(transformChanged()));
+ }
+ d->transforms.clear();
+ for (int index = 0; index < transforms.size(); ++index) {
+ QGraphicsTransform3D *transform = transforms.at(index);
+ if (transform) {
+ connect(transform, SIGNAL(transformChanged()), this, SLOT(transformChanged()));
+ d->transforms.append(transform);
+ }
+ }
+ emit updated();
+ invalidateTransform();
+}
+
+/*!
+ Adds a single \a transform to this node, to be applied to the
+ node after all current members of transformations() have been applied.
+
+ In the mathematical sense, \a transform is applied to the modelview
+ matrix before the current members of transformations() are applied
+ in reverse order.
+
+ \sa transforms(), setTransforms()
+*/
+void QGLSceneNode::addTransform(QGraphicsTransform3D *transform)
+{
+ Q_D(QGLSceneNode);
+ if (!transform)
+ return; // Avoid nulls getting into the transform list.
+ connect(transform, SIGNAL(transformChanged()), this, SLOT(transformChanged()));
+ d->transforms.append(transform);
+ emit updated();
+ invalidateTransform();
+}
+
+/*!
+ \internal
+*/
+void QGLSceneNode::transformChanged()
+{
+ invalidateTransform();
+ emit updated();
+}
+
+/*!
+ Returns the drawing mode to use to render geometry(). The default
+ is QGL::Triangles.
+
+ \sa setDrawingMode()
+*/
+QGL::DrawingMode QGLSceneNode::drawingMode() const
+{
+ Q_D(const QGLSceneNode);
+ return d->drawingMode;
+}
+
+/*!
+ Sets the drawing \a mode to use to render geometry().
+
+ Note: this function changes the drawing mode, but the underlying
+ geometry() still consists of the triangles that were added.
+ Thus, this function is only useful for converting the drawing mode
+ into QGL::Points to display the geometry() as a point cloud
+ instead of a triangle mesh. The other enums from QGL::DrawingMode
+ will give unpredictable results.
+
+ \sa drawingMode()
+*/
+void QGLSceneNode::setDrawingMode(QGL::DrawingMode mode)
+{
+ Q_D(QGLSceneNode);
+ if (d->drawingMode != mode)
+ {
+ d->drawingMode = mode;
+ emit updated();
+ }
+}
+
+/*!
+ Returns the drawing width for this node.
+
+ Drawing width is used only when drawing lines or points (ie. when
+ the drawing mode is points, lines, line-strips, etc).
+
+ \sa drawingMode()
+*/
+qreal QGLSceneNode::drawingWidth() const
+{
+ Q_D(const QGLSceneNode);
+ return d->drawingWidth;
+}
+
+/*!
+ Sets the drawing \a width to the given value.
+
+ Drawing width is used only when drawing lines or points (ie. when
+ the drawing mode is points, lines, line-strips, etc).
+
+ \sa drawingMode()
+*/
+void QGLSceneNode::setDrawingWidth(qreal width)
+{
+ Q_D(QGLSceneNode);
+ d->drawingWidth = width;
+}
+
+
+/*!
+ Returns the local effect associated with this node. The default value
+ is QGL::FlatColor. If the value of hasEffect() is false, then this
+ the value of effect() is ignored.
+
+ \sa setEffect(), hasEffect()
+*/
+QGL::StandardEffect QGLSceneNode::effect() const
+{
+ Q_D(const QGLSceneNode);
+ return d->localEffect;
+}
+
+/*!
+ Sets the local effect associated with this node to be \a effect. hasEffect()
+ will return true after calling this method.
+
+ The QGLSceneNode::draw() function will ensure that \a effect is applied to the
+ QGLPainter before drawing any geometry.
+
+ \sa effect(), hasEffect()
+*/
+void QGLSceneNode::setEffect(QGL::StandardEffect effect)
+{
+ Q_D(QGLSceneNode);
+ if (d->localEffect != effect || !d->hasEffect) {
+ d->localEffect = effect;
+ d->hasEffect = true;
+ emit updated();
+ }
+}
+
+/*!
+ Returns the user effect associated with this node, or NULL if one is not
+ set. The default value is NULL. If the value of hasEffect() is false,
+ then this effect is ignored.
+
+ \sa setUserEffect(), hasEffect()
+*/
+QGLAbstractEffect *QGLSceneNode::userEffect() const
+{
+ Q_D(const QGLSceneNode);
+ return d->customEffect;
+}
+
+/*!
+ Sets the local effect associated with this node to be the custom
+ \a effect. hasEffect() will return true after calling this method.
+
+ This custom effect will supersede any standard effect.
+
+ The default implementation of QGLSceneNode::apply() will set this effect
+ during initialization of the model.
+
+ The default implementation of the QGLSceneNode::draw() method will
+ ensure that \a effect is applied to the QGLPainter before drawing
+ any geometry.
+
+ \sa userEffect(), hasEffect()
+*/
+void QGLSceneNode::setUserEffect(QGLAbstractEffect *effect)
+{
+ Q_D(QGLSceneNode);
+ if (d->customEffect != effect || !d->hasEffect) {
+ d->customEffect = effect;
+ d->hasEffect = true;
+ emit updated();
+ }
+}
+
+
+ /*!
+ Returns true if the local effect on this node is enabled, otherwise
+ returns false.
+
+ \sa setEffectEnabled(), setEffect()
+ */
+bool QGLSceneNode::hasEffect() const
+{
+ Q_D(const QGLSceneNode);
+ return d->hasEffect;
+}
+
+/*!
+ Sets whether the current value of effect() or userEffect() will be
+ applied to the QGLPainter prior to drawing. If \a enabled is true,
+ then the effect is applied, otherwise it is not.
+
+ \sa setEffect(), effect(), hasEffect()
+*/
+void QGLSceneNode::setEffectEnabled(bool enabled)
+{
+ Q_D(QGLSceneNode);
+ if (d->hasEffect != enabled) {
+ d->hasEffect = enabled;
+ emit updated();
+ }
+}
+
+/*!
+ Returns the starting index within geometry() that should be used
+ to render fragments for this scene node. The default value is 0,
+ indicating that the 0'th logical vertex in geometry() is the start.
+
+ \sa setStart(), count()
+*/
+int QGLSceneNode::start() const
+{
+ Q_D(const QGLSceneNode);
+ return d->start;
+}
+
+/*!
+ Sets the \a start index within geometry() that should be used
+ to render fragments for this scene node.
+
+ \sa start(), setCount()
+*/
+void QGLSceneNode::setStart(int start)
+{
+ Q_D(QGLSceneNode);
+ if (start != d->start)
+ {
+ d->start = start;
+ emit updated();
+ invalidateBoundingBox();
+ }
+}
+
+/*!
+ Returns the count of the vertices to render from geometry()
+ for this scene node. The default is zero, meaning that this node
+ uses all vertices from start() up to the last logical vertex
+ in the underlying geometry().
+
+ \sa setCount(), start()
+*/
+int QGLSceneNode::count() const
+{
+ Q_D(const QGLSceneNode);
+ return d->count;
+}
+
+/*!
+ Sets the \a count of the vertices to render from geometry()
+ for this scene node.
+
+ \sa count(), setStart()
+*/
+void QGLSceneNode::setCount(int count)
+{
+ Q_D(QGLSceneNode);
+ if (count != d->count)
+ {
+ d->count = count;
+ emit updated();
+ invalidateBoundingBox();
+ }
+}
+
+/*!
+ Returns the material index for this scene node.
+
+ \sa setMaterialIndex()
+*/
+int QGLSceneNode::materialIndex() const
+{
+ Q_D(const QGLSceneNode);
+ return d->material;
+}
+
+/*!
+ Sets the material index for this scene node to \a material.
+
+ \sa materialIndex()
+*/
+void QGLSceneNode::setMaterialIndex(int material)
+{
+ Q_D(QGLSceneNode);
+ if (d->material != material) {
+ d->material = material;
+ emit updated();
+ }
+}
+
+/*!
+ Returns the back material index for this scene node.
+
+ \sa setBackMaterialIndex()
+*/
+int QGLSceneNode::backMaterialIndex() const
+{
+ Q_D(const QGLSceneNode);
+ return d->backMaterial;
+}
+
+/*!
+ Sets the back material index for this scene node to \a material.
+
+ \sa materialIndex()
+*/
+void QGLSceneNode::setBackMaterialIndex(int material)
+{
+ Q_D(QGLSceneNode);
+ if (d->backMaterial != material) {
+ d->backMaterial = material;
+ emit updated();
+ }
+}
+
+/*!
+ \property QGLSceneNode::material
+ \brief This property is a pointer to a QGLMaterial instance for this node.
+
+ This material is applied to all faces if the backMaterial() property
+ is set to null, which is the default. If the backMaterial() property is non-null
+ then this material is only applied to the front faces.
+
+ To apply a material to the back faces use the backMaterial() property.
+
+ Getting this property is exactly equivalent to
+ \c{palette()->material(materialIndex())}.
+
+ Setting this property causes the material if not already in this nodes palette to be
+ added, and then the corresponding index to be set for this scene node.
+
+ Setting this property is equivalent to:
+ \code
+ int index = d->palette->indexOf(material);
+ if (index == -1)
+ index = d->palette->addMaterial(material);
+ setMaterialIndex(index);
+ \endcode
+
+ If setting this property, when no palette exists one is created, as a
+ convenience - but this is suitable only for experimental code and for
+ \bold{very small numbers of nodes}. In debug mode a warning is
+ printed in this case.
+
+ Generally one common palette should be created, and set on each node. This
+ also allows nodes to share materials and their textures.
+
+ \sa materialIndex(), setMaterialIndex()
+*/
+QGLMaterial *QGLSceneNode::material() const
+{
+ Q_D(const QGLSceneNode);
+ if (d->palette)
+ return d->palette->material(d->material);
+ return 0;
+}
+
+void QGLSceneNode::setMaterial(QGLMaterial *material)
+{
+ Q_D(QGLSceneNode);
+ if (!d->palette)
+ d->palette = new QGLMaterialCollection(this);
+ int ix = d->palette->indexOf(material);
+ if (ix == -1)
+ ix = d->palette->addMaterial(material);
+ setMaterialIndex(ix);
+}
+
+/*!
+ \property QGLSceneNode::backMaterial
+ \brief This property is a pointer to any QGLMaterial instance for this node's back faces.
+
+ This material is applied to the back faces, if non-null. The default value
+ of this property is null. When this property is null, any non-null material
+ set on the material() property will be applied to front and back faces.
+
+ To apply a material to the front faces use the material() property.
+
+ Getting this property is exactly equivalent to
+ \c{palette()->material(backMaterialIndex())}.
+
+ Setting this property causes the material if not already in this nodes palette to be
+ added, and then the corresponding index to be set for this scene node.
+
+ Setting this property is exactly equivalent to:
+ \code
+ int index = d->palette->indexOf(material);
+ if (index == -1)
+ index = d->palette->addMaterial(material);
+ setBackMaterialIndex(index);
+ \endcode
+*/
+QGLMaterial *QGLSceneNode::backMaterial() const
+{
+ Q_D(const QGLSceneNode);
+ if (d->palette)
+ return d->palette->material(d->backMaterial);
+ return 0;
+}
+
+void QGLSceneNode::setBackMaterial(QGLMaterial *material)
+{
+ Q_D(QGLSceneNode);
+ if (!d->palette)
+ d->palette = new QGLMaterialCollection(this);
+ int ix = d->palette->indexOf(material);
+ if (ix == -1)
+ ix = d->palette->addMaterial(material);
+ setBackMaterialIndex(ix);
+}
+/*!
+ Returns the palette of materials used by this scene node, or NULL
+ if no palette has been set.
+
+ \sa setPalette()
+*/
+QGLMaterialCollection *QGLSceneNode::palette() const
+{
+ Q_D(const QGLSceneNode);
+ return d->palette;
+}
+
+/*!
+ Sets the palette of materials for this scene node to \a palette.
+
+ \sa palette()
+*/
+void QGLSceneNode::setPalette(QGLMaterialCollection *palette)
+{
+ Q_D(QGLSceneNode);
+ if (d->palette != palette) {
+ d->palette = palette;
+ emit updated();
+ }
+}
+
+/*!
+ Returns a list of the child nodes for this node. This list is not
+ recursively generated, it includes only the nodes which are
+ immediate children of this node.
+
+ \sa allChildren()
+*/
+QList<QGLSceneNode*> QGLSceneNode::children() const
+{
+ Q_D(const QGLSceneNode);
+ return d->childNodes;
+}
+
+/*!
+ Returns a list including recursively all child nodes under
+ this node. Each child node only appears once, even if it is included
+ multiple times in the scene graph.
+
+ \sa children()
+*/
+QList<QGLSceneNode*> QGLSceneNode::allChildren() const
+{
+ Q_D(const QGLSceneNode);
+ QList<QGLSceneNode*> allSceneNodes;
+ QList<QGLSceneNode*> gather;
+ QList<QGLSceneNode*>::const_iterator it = d->childNodes.constBegin();
+ for ( ; it != d->childNodes.constEnd(); ++it)
+ if (!gather.contains(*it))
+ gather.append(*it);
+ while (gather.count() > 0)
+ {
+ QGLSceneNode *node = gather.takeFirst();
+ if (!allSceneNodes.contains(node))
+ {
+ allSceneNodes.append(node);
+ gather.append(node->children());
+ }
+ }
+ return allSceneNodes;
+}
+
+/*!
+ Adds the \a node to the list of child nodes for this node.
+
+ This function does nothing if \a node is null or is already a child
+ of this node. If the aim is to have the same geometry displayed several times under a
+ given node, each time with different transformations, use the clone()
+ call to create copies of the node and then apply the transformations to
+ the copies.
+
+ Alternatively, create modifier nodes with the transformations and add the
+ geometry bearing node to each with addNode():
+ \code
+ QGLBuilder builder;
+ builder << CarWheel(5.0f); // some car wheel geometry
+ QGLSceneNode wheel = builder.finalizedSceneNode();
+ QGLSceneNode frontLeft = new QGLSceneNode(m_sceneRoot);
+ frontLeft->addNode(wheel);
+ frontLeft->setPosition(QVector3D(1.0f, 2.0f, 0.0f));
+ QGLSceneNode frontRight = new QGLSceneNode(m_sceneRoot);
+ frontRight->addNode(wheel);
+ frontRight->setPosition(QVector3D(-1.0f, 2.0f, 0.0f));
+ QGLSceneNode backLeft = new QGLSceneNode(m_sceneRoot);
+ backLeft->addNode(wheel);
+ backLeft->setPosition(QVector3D(1.0f, -2.0f, 0.0f));
+ QGLSceneNode backRight = new QGLSceneNode(m_sceneRoot);
+ backRight->addNode(wheel);
+ backRight->setPosition(QVector3D(-1.0f, -2.0f, 0.0f));
+ \endcode
+
+ Because a child node can be validly added to many different nodes,
+ calling addNode() does not normally affect the QObject::parent()
+ ownership. However, if \a node does not currently have a
+ QObject::parent(), the parent will be set to this node.
+
+ \sa removeNode(), clone(), addNodes()
+*/
+void QGLSceneNode::addNode(QGLSceneNode *node)
+{
+ Q_D(QGLSceneNode);
+ if (!node || node->d_ptr->parentNodes.contains(this))
+ return; // Invalid node, or already under this parent.
+ invalidateBoundingBox();
+ d->childNodes.append(node);
+ node->d_ptr->parentNodes.append(this);
+ if (!node->parent())
+ node->setParent(this);
+ connect(node, SIGNAL(updated()), this, SIGNAL(updated()));
+ emit updated();
+}
+
+/*!
+ Adds the members of \a nodes to the list of child nodes
+ for this node.
+
+ \sa addNode(), removeNodes()
+*/
+void QGLSceneNode::addNodes(const QList<QGLSceneNode *> &nodes)
+{
+ Q_D(QGLSceneNode);
+ for (int index = 0; index < nodes.count(); ++index) {
+ QGLSceneNode *node = nodes.at(index);
+ if (!node || node->d_ptr->parentNodes.contains(this))
+ continue; // Invalid node, or already under this parent.
+ d->childNodes.append(node);
+ node->d_ptr->parentNodes.append(this);
+ if (!node->parent())
+ node->setParent(this);
+ connect(node, SIGNAL(updated()), this, SIGNAL(updated()));
+ }
+ invalidateBoundingBox();
+ emit updated();
+}
+
+/*!
+ Removes the child node matching \a node from this node.
+
+ If the QObject::parent() ownership of \a node was set to this
+ node, then its parent will be changed to another parent node if it
+ had multiple parents.
+
+ If \a node had only a single parent, then its parent will be set to null,
+ effectively detaching it from the QObject ownership rules of the scene
+ graph. The caller is then responsible for deleting \a node.
+
+ If the QObject::parent() of \a node was not a scene node parent,
+ then it will be left unmodified.
+
+ \sa addNode(), removeNodes()
+*/
+void QGLSceneNode::removeNode(QGLSceneNode *node)
+{
+ Q_D(QGLSceneNode);
+ if (!node || !node->d_ptr->parentNodes.contains(this))
+ return; // Invalid node or not attached to this parent.
+ d->childNodes.removeOne(node);
+ node->d_ptr->parentNodes.removeOne(this);
+ if (node->parent() == this) {
+ // Transfer QObject ownership to another parent, or null.
+ if (!node->d_ptr->parentNodes.isEmpty())
+ node->setParent(node->d_ptr->parentNodes[0]);
+ else
+ node->setParent(0);
+ }
+ disconnect(node, SIGNAL(updated()), this, SIGNAL(updated()));
+ invalidateBoundingBox();
+ emit updated();
+}
+
+/*!
+ Removes the members of \a nodes from the list of child nodes
+ for this node.
+
+ \sa removeNode(), addNodes()
+*/
+void QGLSceneNode::removeNodes(const QList<QGLSceneNode *> &nodes)
+{
+ Q_D(QGLSceneNode);
+ for (int index = 0; index < nodes.count(); ++index) {
+ QGLSceneNode *node = nodes.at(index);
+ if (!node || !node->d_ptr->parentNodes.contains(this))
+ continue; // Invalid node or not attached to this parent.
+ d->childNodes.removeOne(node);
+ node->d_ptr->parentNodes.removeOne(this);
+ if (node->parent() == this) {
+ // Transfer QObject ownership to another parent, or null.
+ if (!node->d_ptr->parentNodes.isEmpty())
+ node->setParent(node->d_ptr->parentNodes[0]);
+ else
+ node->setParent(0);
+ }
+ disconnect(node, SIGNAL(updated()), this, SIGNAL(updated()));
+ }
+ invalidateBoundingBox();
+ emit updated();
+}
+
+void QGLSceneNode::invalidateBoundingBox() const
+{
+ Q_D(const QGLSceneNode);
+ d->boxValid = false;
+ d->invalidateParentBoundingBox();
+}
+
+void QGLSceneNode::invalidateTransform() const
+{
+ invalidateBoundingBox();
+}
+
+void QGLSceneNode::drawNormalIndicators(QGLPainter *painter)
+{
+ Q_D(QGLSceneNode);
+ QVector3DArray verts;
+ QGL::IndexArray indices = d->geometry.indices();
+ for (int i = d->start; i < (d->start + d->count); ++i)
+ {
+ int ix = indices[i];
+ QVector3D a = d->geometry.vertexAt(ix);
+ QVector3D b = a + d->geometry.normalAt(ix);
+ verts.append(a, b);
+ }
+ painter->setVertexAttribute(QGL::Position, QGLAttributeValue(verts));
+ glLineWidth(2.0f);
+ painter->draw(QGL::Lines, verts.size());
+}
+
+const QGLMaterial *QGLSceneNode::setPainterMaterial(int material, QGLPainter *painter,
+ QGL::Face faces, bool &changedTex)
+{
+ Q_D(QGLSceneNode);
+ QGLMaterial *mat = d->palette->material(material);
+ const QGLMaterial *saveMat = 0;
+ if (painter->faceMaterial(faces) != mat)
+ {
+ saveMat = painter->faceMaterial(faces);
+ painter->setFaceMaterial(faces, mat);
+ int texUnit = 0;
+ for (int i = 0; i < mat->textureLayerCount(); ++i)
+ {
+ QGLTexture2D *tex = mat->texture(i);
+ if (tex)
+ {
+ painter->glActiveTexture(GL_TEXTURE0 + texUnit);
+ tex->bind();
+ changedTex = true;
+ ++texUnit;
+ }
+ }
+ }
+ return saveMat;
+}
+
+/*!
+ Draws the geometry of the node onto the \a painter.
+
+ This is the function which performs the actual drawing step in the
+ draw function below.
+
+ \list
+ \o calls draw(start, count) on this nodes geometry object (if any)
+ \endlist
+
+ Override this function to perform special processing on this node,
+ after transformation & culling are applied and before sequencing of
+ materials & effects are done; but just before (or after) the
+ actual draw step.
+
+ This default implementation simply draws the nodes geometry onto
+ the painter.
+
+ Example:
+ \code
+ void MySpecialNode::geometryDraw(QGLPainter *painter)
+ {
+ // at this point the node has survived culling, the model-view
+ // matrix is transformed into this nodes frame of reference,
+ // materials & effects have been applied as this node appears
+ // in its place in the render sequence
+
+ doMySpecialProcessing();
+
+ // call parent implementation to do actual draw
+ QGLSceneNode::geometryDraw(painter);
+ }
+ \endcode
+*/
+void QGLSceneNode::drawGeometry(QGLPainter *painter)
+{
+ Q_D(QGLSceneNode);
+ if (d->count && d->geometry.count() > 0)
+ d->geometry.draw(painter, d->start, d->count, d->drawingMode, d->drawingWidth);
+}
+
+/*!
+ Draws this scene node on the \a painter.
+
+ In detail this function:
+ \list
+ \o ensures the effect specified by effect() is current on the painter
+ \o sets the nodes materials onto the painter, if valid materials are present
+ \o moves the model-view to the x, y, z position
+ \o applies any local transforms() that may be set for this node
+ \o calls draw() for all the child nodes
+ \o calls draw(start, count) on this nodes geometry object (if any)
+ \o restores the geometry's original materials if they were changed
+ \o restores the model-view matrix if any local transform was applied
+ \endlist
+
+ Note that the draw() method does \bold not restore the effect. If the first
+ step above results in a change to the current QGL::Standard effect then it
+ will remain set to that effect. In general any painting method should
+ ensure the effect it requires is current.
+
+ The way draw is implemented ensures that this nodes effects, materials and
+ transformations will apply by default to its child nodes. Transformations
+ are cumulative, but effects and materials override those of any parent node.
+*/
+void QGLSceneNode::draw(QGLPainter *painter)
+{
+ Q_D(QGLSceneNode);
+ bool wasTransformed = false;
+
+ QGLRenderSequencer *seq = painter->renderSequencer();
+
+ if (seq->top() != this)
+ {
+ QMatrix4x4 m = transform();
+
+ if (!m.isIdentity())
+ {
+ painter->modelViewMatrix().push();
+ painter->modelViewMatrix() *= m;
+ wasTransformed = true;
+ }
+
+ if (d->options & CullBoundingBox)
+ {
+ QBox3D bb = boundingBox();
+ if (bb.isFinite() && !bb.isNull() && painter->isCullable(bb))
+ {
+ if (wasTransformed)
+ painter->modelViewMatrix().pop();
+ return;
+ }
+ }
+ }
+
+ if (seq->top() == NULL)
+ {
+ seq->setTop(this);
+ while (true)
+ {
+ draw(painter); // recursively draw myself for each state
+ if (!seq->nextInSequence())
+ break;
+ }
+ seq->reset();
+ }
+ else
+ {
+ bool stateEntered = false;
+ if (d->childNodes.size() > 0)
+ {
+ seq->beginState(this);
+ stateEntered = true;
+ QList<QGLSceneNode*>::iterator cit = d->childNodes.begin();
+ for ( ; cit != d->childNodes.end(); ++cit)
+ (*cit)->draw(painter);
+ }
+
+ if (d->count && (d->geometry.count() > 0) && seq->renderInSequence(this))
+ {
+ bool idSaved = false;
+ int id = -1;
+ if (d->pickNode && painter->isPicking())
+ {
+ idSaved = true;
+ id = painter->objectPickId();
+ painter->setObjectPickId(d->pickNode->id());
+ }
+
+ if (!stateEntered)
+ {
+ stateEntered = true;
+ seq->beginState(this);
+ }
+ seq->applyState();
+
+ drawGeometry(painter);
+
+ if (idSaved)
+ painter->setObjectPickId(id);
+
+ if (d->options & ViewNormals)
+ drawNormalIndicators(painter);
+ }
+ if (stateEntered)
+ seq->endState(this);
+ }
+ if (wasTransformed)
+ painter->modelViewMatrix().pop();
+}
+
+/*!
+ Returns the pick node for this scene node, if one was set; otherwise
+ NULL (0) is returned.
+
+ \sa setPickNode()
+*/
+QGLPickNode *QGLSceneNode::pickNode() const
+{
+ Q_D(const QGLSceneNode);
+ return d->pickNode;
+}
+
+/*!
+ Sets the pick node for this scene node to \a node.
+
+ \sa pickNode()
+*/
+void QGLSceneNode::setPickNode(QGLPickNode *node)
+{
+ Q_D(QGLSceneNode);
+ // TODO - resolve recursive picking - not supported by
+ // color based pick AFAICT
+ d->pickNode = node;
+ node->setTarget(this);
+}
+
+/*!
+ Creates a new QGLSceneNode that is a copy of this scene node, with
+ \a parent as the parent of the new copy. If parent is NULL then parent
+ is set to this nodes parent.
+
+ The copy will reference the same underlying geometry, child nodes, and
+ have all effects, transforms and other properties copied from this node.
+ The only property that is not copied is pickNode().
+
+ \sa cloneNoChildren()
+*/
+QGLSceneNode *QGLSceneNode::clone(QObject *parent) const
+{
+ Q_D(const QGLSceneNode);
+ QGLSceneNode *node = new QGLSceneNode
+ (new QGLSceneNodePrivate(d), parent ? parent : this->parent());
+ for (int index = 0; index < d->transforms.size(); ++index)
+ node->addTransform(d->transforms.at(index)->clone(node));
+ node->addNodes(d->childNodes);
+ return node;
+}
+
+/*!
+ Creates a new QGLSceneNode that is a copy of this scene node, with
+ \a parent as the parent of the new copy. If parent is NULL then parent
+ is set to this nodes parent.
+
+ The copy will reference the same underlying geometry, and
+ have all effects, transforms and other properties copied from this node.
+ The children() and pickNodes() are not cloned.
+
+ \sa clone()
+*/
+QGLSceneNode *QGLSceneNode::cloneNoChildren(QObject *parent) const
+{
+ Q_D(const QGLSceneNode);
+ QGLSceneNode *node = new QGLSceneNode
+ (new QGLSceneNodePrivate(d), parent ? parent : this->parent());
+ for (int index = 0; index < d->transforms.size(); ++index)
+ node->addTransform(d->transforms.at(index)->clone(node));
+ return node;
+}
+
+/*!
+ Creates a new QGLSceneNode that is a copy of this scene node, with
+ \a parent as the parent of the new copy. If parent is NULL then parent
+ is set to this nodes parent.
+
+ The copy will reference the same underlying geometry and
+ have all effects, transforms and other properties copied from this node.
+
+ The copy returned will have the same child nodes, except all child nodes
+ whose objectName() is equal to \a name.
+
+ \sa clone(), only()
+*/
+QGLSceneNode *QGLSceneNode::allExcept(const QString &name, QObject *parent) const
+{
+ Q_D(const QGLSceneNode);
+ QGLSceneNode *node = cloneNoChildren(parent);
+ for (int index = 0; index < d->childNodes.count(); ++index) {
+ QGLSceneNode *child = d->childNodes.at(index);
+ if (child->objectName() != name)
+ node->addNode(child);
+ }
+ return node;
+}
+
+/*!
+ Creates a new QGLSceneNode that is a copy of this scene node, with
+ \a parent as the parent of the new copy. If parent is NULL then parent
+ is set to this nodes parent.
+
+ The copy will reference the same underlying geometry and
+ have all effects, transforms and other properties copied from this node.
+
+ The copy returned will have only one child node. This child node will be
+ the first child node of this one which has its objectName() equal to \a name.
+
+ \sa clone(), allExcept()
+*/
+QGLSceneNode *QGLSceneNode::only(const QString &name, QObject *parent) const
+{
+ Q_D(const QGLSceneNode);
+ QGLSceneNode *node = cloneNoChildren(parent);
+ for (int index = 0; index < d->childNodes.count(); ++index) {
+ QGLSceneNode *child = d->childNodes.at(index);
+ if (child->objectName() == name) {
+ node->addNode(child);
+ break;
+ }
+ }
+ return node;
+}
+
+/*!
+ Creates a new QGLSceneNode that is a copy of this scene node, with
+ \a parent as the parent of the new copy. If parent is NULL then parent
+ is set to this nodes parent.
+
+ The copy will reference the same underlying geometry and
+ have all effects, transforms and other properties copied from this node.
+
+ The copy returned will have the same child nodes, except all child nodes
+ whose objectName() is in the list of \a names.
+
+ \sa clone(), only()
+*/
+QGLSceneNode *QGLSceneNode::allExcept(const QStringList &names, QObject *parent) const
+{
+ Q_D(const QGLSceneNode);
+ QGLSceneNode *node = cloneNoChildren(parent);
+ QSet<QString> chk = QSet<QString>::fromList(names);
+ for (int index = 0; index < d->childNodes.count(); ++index) {
+ QGLSceneNode *child = d->childNodes.at(index);
+ if (!chk.contains(child->objectName()))
+ node->addNode(child);
+ }
+ return node;
+}
+
+/*!
+ Creates a new QGLSceneNode that is a copy of this scene node, with
+ \a parent as the parent of the new copy. If parent is NULL then parent
+ is set to this nodes parent.
+
+ The copy will reference the same underlying geometry and
+ have all effects, transforms and other properties copied from this node.
+
+ The copy returned will have only the child nodes from this
+ whose objectName() is in the list of \a names.
+
+ \sa clone(), allExcept()
+*/
+QGLSceneNode *QGLSceneNode::only(const QStringList &names, QObject *parent) const
+{
+ Q_D(const QGLSceneNode);
+ QGLSceneNode *node = cloneNoChildren(parent);
+ QSet<QString> chk = QSet<QString>::fromList(names);
+ for (int index = 0; index < d->childNodes.count(); ++index) {
+ QGLSceneNode *child = d->childNodes.at(index);
+ if (chk.contains(child->objectName()))
+ node->addNode(child);
+ }
+ return node;
+}
+
+/*!
+ \fn QGLSceneNode::updated()
+ Signals that some property of this scene node, or one of its children,
+ has changed in a manner that will require that the node be redrawn.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+#include "qglmaterialcollection.h"
+#include "qgltexture2d.h"
+/*!
+ \relates QGLSceneNode
+ Print a description of \a node, and all its descendants, to stderr. Only
+ available when compiled in debug mode (without QT_NO_DEBUG defined).
+ The \a indent and \a loop parameters are used internally.
+*/
+void qDumpScene(QGLSceneNode *node, int indent, const QSet<QGLSceneNode *> &loop)
+{
+#if !defined(QT_NO_THREAD)
+ QCoreApplication *app = QApplication::instance();
+ QThread *appThread = 0;
+ if (app)
+ appThread = QApplication::instance()->thread();
+#endif
+ QSet<QGLSceneNode *> lp = loop;
+ lp.insert(node);
+ QString ind;
+ ind.fill(QLatin1Char(' '), indent * 4);
+ fprintf(stderr, "\n%s ======== Node: %p - %s =========\n", qPrintable(ind), node,
+ qPrintable(node->objectName()));
+#if !defined(QT_NO_THREAD)
+ if (appThread && appThread != node->thread())
+ fprintf(stderr, "\n%s from thread: %p\n", qPrintable(ind), node->thread());
+#endif
+ fprintf(stderr, "%s start: %d count: %d children:", qPrintable(ind), node->start(), node->count());
+ {
+ QList<QGLSceneNode*> children = node->children();
+ QList<QGLSceneNode*>::const_iterator it = children.constBegin();
+ for (int i = 0; it != children.constEnd(); ++it, ++i)
+ fprintf(stderr, "%d: %p ", i, *it);
+ }
+ fprintf(stderr, "\n");
+ if (!node->position().isNull())
+ {
+ QVector3D p = node->position();
+ fprintf(stderr, "%s position: (%0.4f, %0.4f, %0.4f)\n", qPrintable(ind),
+ p.x(), p.y(), p.z());
+ }
+ if (node->localTransform().isIdentity())
+ {
+ fprintf(stderr, "%s local transform: identity\n", qPrintable(ind));
+ }
+ else
+ {
+ fprintf(stderr, "%s local transform:\n", qPrintable(ind));
+ QMatrix4x4 m = node->localTransform();
+ for (int i = 0; i < 4; ++i)
+ fprintf(stderr, "%s %0.4f %0.4f %0.4f %0.4f\n",
+ qPrintable(ind), m(i, 0), m(i, 1), m(i, 2), m(i, 3));
+ }
+ if (!node->geometry().isEmpty())
+ {
+ fprintf(stderr, "%s geometry: %d indexes, %d vertices\n",
+ qPrintable(ind), node->geometry().count(), node->geometry().count(QGL::Position));
+ }
+ else
+ {
+ fprintf(stderr, "%s geometry: NULL\n", qPrintable(ind));
+ }
+ if (node->materialIndex() != -1)
+ {
+ fprintf(stderr, "%s material: %d", qPrintable(ind), node->materialIndex());
+ QGLMaterial *mat = node->material();
+ QGLMaterialCollection *pal = node->palette();
+ if (pal)
+ fprintf(stderr, "%s palette: %p", qPrintable(ind), pal);
+ else
+ fprintf(stderr, "%s no palette", qPrintable(ind));
+ if (pal)
+ {
+ mat = pal->material(node->materialIndex());
+ if (mat)
+ fprintf(stderr, "%s mat name from pal: %s ", qPrintable(ind),
+ qPrintable(pal->material(node->materialIndex())->objectName()));
+ else
+ fprintf(stderr, "%s indexed material %d does not exist in palette!",
+ qPrintable(ind), node->materialIndex());
+ }
+ if (mat)
+ {
+ if (mat->objectName().isEmpty())
+ fprintf(stderr, " -- %p:", mat);
+ else
+ fprintf(stderr, " -- \"%s\":",
+ qPrintable(mat->objectName()));
+ fprintf(stderr, " Amb: %s - Diff: %s - Spec: %s - Shin: %0.2f\n",
+ qPrintable(mat->ambientColor().name()),
+ qPrintable(mat->diffuseColor().name()),
+ qPrintable(mat->specularColor().name()),
+ mat->shininess());
+ for (int i = 0; i < mat->textureLayerCount(); ++i)
+ {
+ if (mat->texture(i) != 0)
+ {
+ QGLTexture2D *tex = mat->texture(i);
+ if (tex->objectName().isEmpty())
+ fprintf(stderr, "%s texture %p", qPrintable(ind), tex);
+ else
+ fprintf(stderr, "%s texture %s", qPrintable(ind),
+ qPrintable(tex->objectName()));
+ QSize sz = tex->size();
+ fprintf(stderr, " - size: %d (w) x %d (h)\n", sz.width(), sz.height());
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s - could not find indexed material!!", qPrintable(ind));
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s material: NONE\n", qPrintable(ind));
+ }
+
+ if (node->hasEffect())
+ {
+ if (node->userEffect())
+ {
+ fprintf(stderr, "%s user effect %p\n", qPrintable(ind),
+ node->userEffect());
+ }
+ else
+ {
+ switch (node->effect())
+ {
+ case QGL::FlatColor:
+ fprintf(stderr, "%s flat color effect\n", qPrintable(ind)); break;
+ case QGL::FlatPerVertexColor:
+ fprintf(stderr, "%s flat per vertex color effect\n", qPrintable(ind)); break;
+ case QGL::FlatReplaceTexture2D:
+ fprintf(stderr, "%s flat replace texture 2D effect\n", qPrintable(ind)); break;
+ case QGL::FlatDecalTexture2D:
+ fprintf(stderr, "%s flat decal texture 2D effect\n", qPrintable(ind)); break;
+ case QGL::LitMaterial:
+ fprintf(stderr, "%s lit material effect\n", qPrintable(ind)); break;
+ case QGL::LitDecalTexture2D:
+ fprintf(stderr, "%s lit decal texture 2D effect\n", qPrintable(ind)); break;
+ case QGL::LitModulateTexture2D:
+ fprintf(stderr, "%s lit modulate texture 2D effect\n", qPrintable(ind)); break;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s no effect set\n", qPrintable(ind));
+ }
+ QList<QGLSceneNode*> children = node->children();
+ QList<QGLSceneNode*>::const_iterator it = children.constBegin();
+ for ( ; it != children.constEnd(); ++it)
+ if (!lp.contains(*it))
+ qDumpScene(*it, indent + 1);
+}
+
+QDebug operator<<(QDebug dbg, const QGLSceneNode &node)
+{
+ dbg << &node << "\n start:" << node.start() << " count:" << node.count();
+ QList<QGLSceneNode*> children = node.children();
+ QList<QGLSceneNode*>::const_iterator it = children.constBegin();
+ for ( ; it != children.constEnd(); ++it)
+ dbg << "\n child:" << *it;
+
+ if (node.localTransform().isIdentity())
+ dbg << "\n local transform: identity";
+ else
+ dbg << "\n local transform:\n" << node.localTransform();
+
+ if (node.geometry().count() > 0)
+ {
+ QGLMaterial *mat = node.material();
+ QString mdesc;
+ if (mat)
+ mdesc = mat->objectName();
+ dbg << "\n geometry:" << node.geometry();
+ dbg << "\n material" << node.material() << ": " << mat << mdesc;
+ }
+ else
+ {
+ dbg << "\n geometry: NULL";
+ dbg << "\n material" << node.material();
+ }
+
+ if (node.hasEffect())
+ {
+ if (node.userEffect())
+ {
+ dbg << "\n user effect";
+ }
+ else
+ {
+ switch (node.effect())
+ {
+ case QGL::FlatColor:
+ dbg << "\n flat color effect"; break;
+ case QGL::FlatPerVertexColor:
+ dbg << "\n flat per vertex color effect"; break;
+ case QGL::FlatReplaceTexture2D:
+ dbg << "\n flat replace texture 2D effect"; break;
+ case QGL::FlatDecalTexture2D:
+ dbg << "\n flat decal texture 2D effect"; break;
+ case QGL::LitMaterial:
+ dbg << "\n lit material effect"; break;
+ case QGL::LitDecalTexture2D:
+ dbg << "\n lit decal texture 2D effect"; break;
+ case QGL::LitModulateTexture2D:
+ dbg << "\n lit modulate texture 2D effect"; break;
+ }
+ }
+ }
+ else
+ {
+ dbg << "\n no effect set";
+ }
+ return dbg;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/threed/scene/qglscenenode.h b/src/threed/scene/qglscenenode.h
new file mode 100644
index 000000000..7d172c55a
--- /dev/null
+++ b/src/threed/scene/qglscenenode.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSCENENODE_H
+#define QGLSCENENODE_H
+
+#include <QtCore/qobject.h>
+
+#include "qgeometrydata.h"
+#include "qglmaterialcollection.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLSceneNodePrivate;
+class QGLAbstractEffect;
+class QGLPickNode;
+class QGraphicsTransform3D;
+
+class Q_QT3D_EXPORT QGLSceneNode : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGLSceneNode)
+ Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY updated)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY updated)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY updated)
+ Q_PROPERTY(qreal z READ z WRITE setZ NOTIFY updated)
+ Q_PROPERTY(QGLMaterial *material READ material WRITE setMaterial NOTIFY updated)
+ Q_PROPERTY(QGLMaterial *backMaterial READ backMaterial WRITE setBackMaterial NOTIFY updated)
+public:
+ explicit QGLSceneNode(QObject *parent = 0);
+ explicit QGLSceneNode(const QGeometryData &geometry, QObject *parent = 0);
+ virtual ~QGLSceneNode();
+
+ enum Option
+ {
+ CullBoundingBox = 0x0001,
+ ViewNormals = 0x0002
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ QGLSceneNode::Options options() const;
+ void setOptions(QGLSceneNode::Options options);
+ void setOption(QGLSceneNode::Option option, bool value);
+
+ QGeometryData geometry() const;
+ void setGeometry(QGeometryData);
+
+ QBox3D boundingBox() const;
+
+ QMatrix4x4 localTransform() const;
+ void setLocalTransform(const QMatrix4x4 &);
+ QVector3D position() const;
+ void setPosition(const QVector3D &p);
+ qreal x() const;
+ void setX(qreal x);
+ qreal y() const;
+ void setY(qreal y);
+ qreal z() const;
+ void setZ(qreal z);
+
+ QList<QGraphicsTransform3D *> transforms() const;
+ void setTransforms(const QList<QGraphicsTransform3D *> &transforms);
+ void addTransform(QGraphicsTransform3D *transform);
+
+ QGL::DrawingMode drawingMode() const;
+ void setDrawingMode(QGL::DrawingMode mode);
+
+ qreal drawingWidth() const;
+ void setDrawingWidth(qreal width);
+
+ QGL::StandardEffect effect() const;
+ void setEffect(QGL::StandardEffect);
+
+ QGLAbstractEffect *userEffect() const;
+ void setUserEffect(QGLAbstractEffect *effect);
+
+ bool hasEffect() const;
+ void setEffectEnabled(bool);
+
+ int start() const;
+ void setStart(int start);
+
+ int count() const;
+ void setCount(int count);
+
+ int materialIndex() const;
+ void setMaterialIndex(int material);
+ int backMaterialIndex() const;
+ void setBackMaterialIndex(int material);
+
+ QGLMaterial *material() const;
+ void setMaterial(QGLMaterial *material);
+ QGLMaterial *backMaterial() const;
+ void setBackMaterial(QGLMaterial *material);
+
+ QGLMaterialCollection *palette() const;
+ void setPalette(QGLMaterialCollection *palette);
+
+ QList<QGLSceneNode*> allChildren() const;
+ QList<QGLSceneNode *> children() const;
+
+ void addNode(QGLSceneNode *node);
+ void addNodes(const QList<QGLSceneNode *> &nodes);
+ void removeNode(QGLSceneNode *node);
+ void removeNodes(const QList<QGLSceneNode *> &nodes);
+
+ virtual void draw(QGLPainter *painter);
+
+ QGLPickNode *pickNode() const;
+ void setPickNode(QGLPickNode *node);
+
+ Q_INVOKABLE QGLSceneNode *clone(QObject *parent = 0) const;
+ Q_INVOKABLE QGLSceneNode *cloneNoChildren(QObject *parent = 0) const;
+ Q_INVOKABLE QGLSceneNode *allExcept(const QString &name, QObject *parent = 0) const;
+ Q_INVOKABLE QGLSceneNode *only(const QString &name, QObject *parent = 0) const;
+ Q_INVOKABLE QGLSceneNode *allExcept(const QStringList &names, QObject *parent = 0) const;
+ Q_INVOKABLE QGLSceneNode *only(const QStringList &names, QObject *parent = 0) const;
+
+Q_SIGNALS:
+ void updated();
+
+protected:
+ virtual void drawGeometry(QGLPainter *painter);
+
+private Q_SLOTS:
+ void transformChanged();
+
+private:
+ QMatrix4x4 transform() const;
+ void invalidateBoundingBox() const;
+ void invalidateTransform() const;
+ void drawNormalIndicators(QGLPainter *painter);
+ const QGLMaterial *setPainterMaterial(int material, QGLPainter *painter,
+ QGL::Face faces, bool &changedTex);
+
+ Q_DISABLE_COPY(QGLSceneNode)
+
+ QScopedPointer<QGLSceneNodePrivate> d_ptr;
+
+ QGLSceneNode(QGLSceneNodePrivate *d, QObject *parent);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLSceneNode::Options)
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QT3D_EXPORT void qDumpScene(QGLSceneNode *, int indent = 0, const QSet<QGLSceneNode*> &loop = QSet<QGLSceneNode*>());
+
+Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QGLSceneNode &node);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/scene/qglscenenode_p.h b/src/threed/scene/qglscenenode_p.h
new file mode 100644
index 000000000..37dcb3629
--- /dev/null
+++ b/src/threed/scene/qglscenenode_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSCENENODE_P_H
+#define QGLSCENENODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglnamespace.h"
+#include "qglscenenode.h"
+#include "qgraphicstransform3d.h"
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qset.h>
+
+class QGLAbstractEffect;
+class QGLPickNode;
+
+class QGLSceneNodePrivate
+{
+public:
+ QGLSceneNodePrivate()
+ : palette(0)
+ , localEffect(QGL::FlatColor) // 0 - zero
+ , customEffect(0)
+ , hasEffect(false)
+ , material(-1)
+ , backMaterial(-1)
+ , start(0)
+ , count(0)
+ , options(QGLSceneNode::CullBoundingBox)
+ , pickNode(0)
+ , boxValid(false)
+ , drawingMode(QGL::Triangles)
+ {
+ }
+
+ // This constructor is used by QGLSceneNode::clone().
+ QGLSceneNodePrivate(const QGLSceneNodePrivate *other)
+ : geometry(other->geometry)
+ , palette(other->palette)
+ , localTransform(other->localTransform)
+ , translate(other->translate)
+ , localEffect(other->localEffect)
+ , customEffect(other->customEffect)
+ , hasEffect(other->hasEffect)
+ , material(other->material)
+ , backMaterial(other->backMaterial)
+ , start(other->start)
+ , count(other->count)
+ , options(other->options)
+ , pickNode(0) // Explicitly not cloned.
+ , bb(other->bb)
+ , boxValid(other->boxValid)
+ , drawingMode(other->drawingMode)
+ , drawingWidth(1.0)
+ {
+ }
+
+ inline void invalidateParentBoundingBox() const
+ {
+ QList<QGLSceneNode*>::const_iterator it = parentNodes.constBegin();
+ for ( ; it != parentNodes.constEnd(); ++it)
+ (*it)->invalidateBoundingBox();
+ }
+
+ QGeometryData geometry;
+ QGLMaterialCollection *palette;
+ QMatrix4x4 localTransform;
+ QVector3D translate;
+ QList<QGraphicsTransform3D *> transforms;
+ QGL::StandardEffect localEffect;
+ QGLAbstractEffect *customEffect;
+ QList<QGLSceneNode*> childNodes;
+ QList<QGLSceneNode*> parentNodes;
+ bool hasEffect;
+ int material;
+ int backMaterial;
+ int start;
+ int count;
+ QGLSceneNode::Options options;
+ QGLPickNode *pickNode;
+ mutable QBox3D bb;
+ mutable bool boxValid;
+ QGL::DrawingMode drawingMode;
+ qreal drawingWidth;
+};
+
+#endif // QGLSCENENODE_P_H
diff --git a/src/threed/scene/scene.pri b/src/threed/scene/scene.pri
new file mode 100644
index 000000000..14d5e989b
--- /dev/null
+++ b/src/threed/scene/scene.pri
@@ -0,0 +1,19 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += qglabstractscene.h \
+ qglsceneformatplugin.h \
+ qglscenenode.h \
+ qglpicknode.h \
+ qglrendersequencer.h \
+ qglrenderorder.h \
+ qglrenderordercomparator.h \
+ qglrenderstate.h
+SOURCES += qglabstractscene.cpp \
+ qglsceneformatplugin.cpp \
+ qglscenenode.cpp \
+ qglpicknode.cpp \
+ qglrendersequencer.cpp \
+ qglrenderorder.cpp \
+ qglrenderordercomparator.cpp \
+ qglrenderstate.cpp
+PRIVATE_HEADERS += qglscenenode_p.h
diff --git a/src/threed/surfaces/qglabstractsurface.cpp b/src/threed/surfaces/qglabstractsurface.cpp
new file mode 100644
index 000000000..b840c0bb9
--- /dev/null
+++ b/src/threed/surfaces/qglabstractsurface.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglabstractsurface.h"
+#include "qglcontextsurface_p.h"
+#include "qglframebufferobjectsurface.h"
+#include "qglpixelbuffersurface.h"
+#include "qglsubsurface.h"
+#include "qglwidgetsurface.h"
+#include <QtGui/qpaintdevice.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLAbstractSurface
+ \brief The QGLAbstractSurface class represents an OpenGL drawing surface.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+
+ OpenGL can be used to draw into a number of different surface types:
+ windows, pixel buffers (pbuffers), framebuffer objects, and so on.
+ It is also possible to use only part of a surface by setting
+ the \c{glViewport()} to restrict drawing to that part. An example
+ of a subsurface may be the left or right eye image of a stereoscopic
+ pair that is rendered into the two halves of a window.
+
+ Activating a surface for OpenGL drawing, and deactivating it afterwards
+ can be quite varied across surface types. Sometimes it is enough
+ to just make a QGLContext current and set the \c{glViewport()}.
+ Other times a context must be made current, followed by binding a
+ framebuffer object, and finally setting the \c{glViewport()}.
+
+ QGLAbstractSurface and its subclasses simplify the activation and
+ deactivation of surfaces by encapsulating the logic needed to
+ use a particular kind of surface into activate() and deactivate()
+ respectively.
+
+ Normally surfaces are activated by calling QGLPainter::pushSurface()
+ as in the following example of switching drawing to a framebuffer
+ object:
+
+ \code
+ QGLPainter painter;
+ painter.begin(widget);
+ QGLFramebufferObjectSurface surface(fbo);
+ painter.pushSurface(&surface);
+ ... // draw into the fbo
+ painter.popSurface();
+ ... // draw into the widget
+ \endcode
+
+ QGLPainter maintains a stack of surfaces, starting with the paint
+ device specified to QGLPainter::begin() (usually a widget).
+ The QGLPainter::pushSurface() function calls deactivate() on the
+ current surface, activate() on the new surface, and then adjusts the
+ \c{glViewport()} to match the value of viewportGL() for the new surface.
+ When QGLPainter::popSurface() is called, the previous surface
+ is re-activated and the \c{glViewport()} changed accordingly.
+
+ \sa QGLFramebufferObjectSurface, QGLWidgetSurface, QGLSubsurface
+ \sa QGLPixelBufferSurface, QGLPainter::pushSurface()
+*/
+
+/*!
+ \enum QGLAbstractSurface::SurfaceType
+ This enum defines the type of a QGLAbstractSurface.
+
+ \value Widget Instance of QGLWidgetSurface.
+ \value FramebufferObject Instance of QGLFramebufferObjectSurface.
+ \value PixelBuffer Instance of QGLPixelBufferSurface.
+ \value Subsurface Instance of QGLSubsurface.
+ \value User First user-defined surface type for use by applications.
+*/
+
+/*!
+ \fn QGLAbstractSurface::QGLAbstractSurface(int surfaceType)
+
+ Constructs an OpenGL drawing surface of the specified \a surfaceType.
+*/
+
+/*!
+ Destroys this OpenGL drawing surface.
+*/
+QGLAbstractSurface::~QGLAbstractSurface()
+{
+}
+
+/*!
+ \fn int QGLAbstractSurface::surfaceType() const
+
+ Returns the type of this surface.
+*/
+
+/*!
+ \fn QPaintDevice *QGLAbstractSurface::device() const
+
+ Returns the raw device that this surface will draw on.
+
+ If the surface is an instance of QGLSubsurface, then this will
+ return the device of the surface that underlies the subsurface.
+ The viewportRect() defines the region to render into.
+
+ \sa viewportRect()
+*/
+
+/*!
+ \fn bool QGLAbstractSurface::activate(QGLAbstractSurface *prevSurface)
+
+ Activate this surface by making its context current, and binding
+ the associated framebuffer object, if any.
+
+ If \a prevSurface is null, then that surface has just been deactivated
+ in the process of switching to this surface. This may allow activate()
+ to optimize the transition to avoid unnecessary state changes.
+
+ Returns true if the surface was activated; false otherwise.
+
+ \sa deactivate(), switchTo()
+*/
+
+/*!
+ \fn void QGLAbstractSurface::deactivate(QGLAbstractSurface *nextSurface)
+
+ Deactivate this surface from the current context, but leave the
+ context current. Typically this will release the framebuffer
+ object associated with the surface.
+
+ If \a nextSurface is null, then that surface will be activated next
+ in the process of switching away from this surface. This may allow
+ deactivate() to optimize the transition to avoid unnecessary state
+ changes.
+
+ \sa activate(), switchTo()
+*/
+
+/*!
+ Returns the rectangle of the surface device() that is occupied by
+ the viewport for this surface. The origin is at the top-left.
+
+ This function calls viewportGL() and then flips the rectangle
+ upside down using the height of device() so that the origin
+ is at the top-left instead of the bottom-right.
+
+ \sa viewportGL(), device()
+*/
+QRect QGLAbstractSurface::viewportRect() const
+{
+ QRect view = viewportGL();
+ QPaintDevice *dev = device();
+ int height;
+ if (dev->devType() == QInternal::Widget)
+ height = static_cast<QWidget *>(dev)->height();
+ else
+ height = dev->height();
+ return QRect(view.x(), height - (view.y() + view.height()),
+ view.width(), view.height());
+}
+
+/*!
+ \fn QRect QGLAbstractSurface::viewportGL() const
+
+ Returns the rectangle of the surface device() that is occupied by
+ the viewport for this surface. The origin is at the bottom-left,
+ which makes the value suitable for passing to \c{glViewport()}:
+
+ \code
+ QRect viewport = surface->viewportGL();
+ glViewport(viewport.x(), viewport.y(), viewport.width(), viewport.height());
+ \endcode
+
+ Normally the viewport rectangle is the full extent of the device(),
+ but it could be smaller if the application only wishes to draw
+ into a subpart of the device(). An example would be rendering left
+ and right stereo eye images into the two halves of a QGLWidget.
+ The eye surfaces would typically be instances of QGLSubsurface.
+
+ \sa viewportRect(), device()
+*/
+
+/*!
+ Returns the aspect ratio of viewportGL() after correcting for the
+ DPI of device().
+
+ The return value is used to correct perspective and orthographic
+ projections for the aspect ratio of the drawing surface. Subclasses
+ may override this function to adjust the return value if the DPI of
+ device() is not sufficient to determine the aspect ratio.
+*/
+qreal QGLAbstractSurface::aspectRatio() const
+{
+ // Get the size of the current viewport.
+ QSize size = viewportGL().size();
+ if (size.width() == 0 || size.height() == 0 ||
+ size.width() == size.height())
+ return 1.0f;
+
+ // Use the device's DPI setting to determine the pixel aspect ratio.
+ QPaintDevice *device = this->device();
+ int dpiX = device->logicalDpiX();
+ int dpiY = device->logicalDpiY();
+ if (dpiX <= 0 || dpiY <= 0)
+ dpiX = dpiY = 1;
+
+ // Return the final aspect ratio based on viewport and pixel size.
+ return ((qreal)(size.width() * dpiY)) / ((qreal)(size.height() * dpiX));
+}
+
+/*!
+ Switches from this surface to \a nextSurface by calling deactivate()
+ on this surface and activate() on \a nextSurface.
+
+ Returns true if \a nextSurface was activated, or false otherwise.
+ If \a nextSurface could not be activated, then this surface will
+ remain activated.
+
+ \sa activate(), deactivate()
+*/
+bool QGLAbstractSurface::switchTo(QGLAbstractSurface *nextSurface)
+{
+ if (nextSurface) {
+ deactivate(nextSurface);
+ if (nextSurface->activate(this))
+ return true;
+ activate();
+ return false;
+ } else {
+ deactivate();
+ return true;
+ }
+}
+
+/*!
+ Creates an OpenGL drawing surface for the specified paint \a device.
+ Returns null if it is not possible to create a surface for \a device.
+
+ \sa createSurfaceForContext()
+*/
+QGLAbstractSurface *QGLAbstractSurface::createSurfaceForDevice
+ (QPaintDevice *device)
+{
+ Q_ASSERT(device);
+ switch (device->devType()) {
+ case QInternal::Widget: {
+ QGLWidget *glw = qobject_cast<QGLWidget *>
+ (static_cast<QWidget *>(device));
+ if (glw)
+ return new QGLWidgetSurface(glw);
+ else
+ return 0;
+ }
+ case QInternal::Pbuffer:
+ return new QGLPixelBufferSurface(static_cast<QGLPixelBuffer *>(device));
+ case QInternal::FramebufferObject:
+ return new QGLFramebufferObjectSurface
+ (static_cast<QGLFramebufferObject *>(device));
+ default:
+ return 0;
+ }
+}
+
+/*!
+ Creates an OpenGL drawing surface for the paint device
+ underlying \a context. If the paint device is not recognized,
+ then a generic surface will be created that makes \a context
+ current when the surface is activated.
+
+ \sa createSurfaceForDevice()
+*/
+QGLAbstractSurface *QGLAbstractSurface::createSurfaceForContext
+ (const QGLContext *context)
+{
+ Q_ASSERT(context);
+ QGLAbstractSurface *surface = createSurfaceForDevice(context->device());
+ if (!surface)
+ surface = new QGLContextSurface(context);
+ return surface;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglabstractsurface.h b/src/threed/surfaces/qglabstractsurface.h
new file mode 100644
index 000000000..aa6aaa5fb
--- /dev/null
+++ b/src/threed/surfaces/qglabstractsurface.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLABSTRACTSURFACE_H
+#define QGLABSTRACTSURFACE_H
+
+#include "qt3dglobal.h"
+#include <QtOpenGL/qgl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QGLAbstractSurface
+{
+public:
+ virtual ~QGLAbstractSurface();
+
+ enum SurfaceType
+ {
+ Widget,
+ FramebufferObject,
+ PixelBuffer,
+ Subsurface,
+ User = 1000
+ };
+
+ int surfaceType() const { return m_type; }
+
+ virtual QPaintDevice *device() const = 0;
+ virtual bool activate(QGLAbstractSurface *prevSurface = 0) = 0;
+ virtual void deactivate(QGLAbstractSurface *nextSurface = 0) = 0;
+ virtual QRect viewportGL() const = 0;
+ QRect viewportRect() const;
+ virtual qreal aspectRatio() const;
+
+ bool switchTo(QGLAbstractSurface *nextSurface);
+
+ static QGLAbstractSurface *createSurfaceForDevice(QPaintDevice *device);
+ static QGLAbstractSurface *createSurfaceForContext(const QGLContext *context);
+
+protected:
+ QGLAbstractSurface(int surfaceType) : m_type(surfaceType) {}
+
+private:
+ int m_type;
+
+ Q_DISABLE_COPY(QGLAbstractSurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qglcontextsurface.cpp b/src/threed/surfaces/qglcontextsurface.cpp
new file mode 100644
index 000000000..6272e712b
--- /dev/null
+++ b/src/threed/surfaces/qglcontextsurface.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcontextsurface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPaintDevice *QGLContextSurface::device() const
+{
+ return m_context->device();
+}
+
+bool QGLContextSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ Q_UNUSED(prevSurface);
+ if (QGLContext::currentContext() != m_context)
+ const_cast<QGLContext *>(m_context)->makeCurrent();
+ return true;
+}
+
+void QGLContextSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ Q_UNUSED(nextSurface);
+}
+
+QRect QGLContextSurface::viewportGL() const
+{
+ QPaintDevice *device = m_context->device();
+ return QRect(0, 0, device->width(), device->height());
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglcontextsurface_p.h b/src/threed/surfaces/qglcontextsurface_p.h
new file mode 100644
index 000000000..4cf14ff9c
--- /dev/null
+++ b/src/threed/surfaces/qglcontextsurface_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCONTEXTSURFACE_P_H
+#define QGLCONTEXTSURFACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstractsurface.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLContextSurface : public QGLAbstractSurface
+{
+public:
+ explicit QGLContextSurface(const QGLContext *context)
+ : QGLAbstractSurface(502)
+ , m_context(context) {}
+ ~QGLContextSurface() {}
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface);
+ void deactivate(QGLAbstractSurface *nextSurface);
+ QRect viewportGL() const;
+
+private:
+ const QGLContext *m_context;
+
+ Q_DISABLE_COPY(QGLContextSurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qgldrawbuffersurface.cpp b/src/threed/surfaces/qgldrawbuffersurface.cpp
new file mode 100644
index 000000000..aabbd2c14
--- /dev/null
+++ b/src/threed/surfaces/qgldrawbuffersurface.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgldrawbuffersurface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPaintDevice *QGLDrawBufferSurface::device() const
+{
+ return m_surface->device();
+}
+
+bool QGLDrawBufferSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ if (!m_surface->activate(prevSurface))
+ return false;
+#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT)
+ glDrawBuffer(m_buffer);
+#endif
+ return true;
+}
+
+void QGLDrawBufferSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ m_surface->deactivate(nextSurface);
+}
+
+QRect QGLDrawBufferSurface::viewportGL() const
+{
+ return m_surface->viewportGL();
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qgldrawbuffersurface_p.h b/src/threed/surfaces/qgldrawbuffersurface_p.h
new file mode 100644
index 000000000..5354e2efa
--- /dev/null
+++ b/src/threed/surfaces/qgldrawbuffersurface_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLDRAWBUFFERSURFACE_P_H
+#define QGLDRAWBUFFERSURFACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstractsurface.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLDrawBufferSurface : public QGLAbstractSurface
+{
+public:
+ QGLDrawBufferSurface(QGLAbstractSurface *surface, GLenum buffer)
+ : QGLAbstractSurface(500)
+ , m_surface(surface), m_buffer(buffer) {}
+ ~QGLDrawBufferSurface() {}
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface);
+ void deactivate(QGLAbstractSurface *nextSurface);
+ QRect viewportGL() const;
+
+private:
+ QGLAbstractSurface *m_surface;
+ GLenum m_buffer;
+
+ Q_DISABLE_COPY(QGLDrawBufferSurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qglframebufferobjectsurface.cpp b/src/threed/surfaces/qglframebufferobjectsurface.cpp
new file mode 100644
index 000000000..c4b8539d4
--- /dev/null
+++ b/src/threed/surfaces/qglframebufferobjectsurface.cpp
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglframebufferobjectsurface.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLFramebufferObjectSurface
+ \brief The QGLFramebufferObjectSurface class represents a framebuffer object that is being used as an OpenGL drawing surface.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+*/
+
+class QGLFramebufferObjectSurfacePrivate
+{
+public:
+ QGLFramebufferObjectSurfacePrivate
+ (QGLFramebufferObject *fbo, const QGLContext *ctx)
+ : framebufferObject(fbo), context(ctx) {}
+
+ QGLFramebufferObject *framebufferObject;
+ const QGLContext *context;
+};
+
+/*!
+ Constructs a default framebuffer object surface. This constructor
+ should be followed by a call to setFramebufferObject().
+*/
+QGLFramebufferObjectSurface::QGLFramebufferObjectSurface()
+ : QGLAbstractSurface(QGLAbstractSurface::FramebufferObject)
+ , d_ptr(new QGLFramebufferObjectSurfacePrivate(0, 0))
+{
+}
+
+/*!
+ Constructs a framebuffer object surface for \a fbo and \a context.
+ If \a context is null, then the framebuffer will be bound to the
+ current context when activate() is called.
+*/
+QGLFramebufferObjectSurface::QGLFramebufferObjectSurface
+ (QGLFramebufferObject *fbo, const QGLContext *context)
+ : QGLAbstractSurface(QGLAbstractSurface::FramebufferObject)
+ , d_ptr(new QGLFramebufferObjectSurfacePrivate(fbo, context))
+{
+}
+
+/*!
+ Destroys this framebuffer object surface.
+*/
+QGLFramebufferObjectSurface::~QGLFramebufferObjectSurface()
+{
+}
+
+/*!
+ Returns the context that owns framebufferObject(); or null
+ if the framebufferObject() should be assumed to be owned by
+ the current context when activate() is called.
+
+ \sa setContext(), framebufferObject()
+*/
+const QGLContext *QGLFramebufferObjectSurface::context() const
+{
+ Q_D(const QGLFramebufferObjectSurface);
+ return d->context;
+}
+
+/*!
+ Sets the \a context that owns framebufferObject().
+
+ When activate() is called, it checks to see if \a context is sharing
+ with the current context. If it is, then the framebufferObject()
+ is directly bound to the current context. Otherwise, \a context
+ is made current and then framebufferObject() is bound.
+
+ If \a context is null, then framebufferObject() will be bound
+ to whatever the current context is when activate() is called.
+
+ \sa context()
+*/
+void QGLFramebufferObjectSurface::setContext(const QGLContext *context)
+{
+ Q_D(QGLFramebufferObjectSurface);
+ d->context = context;
+}
+
+/*!
+ Returns the framebuffer object for this surface, or null if
+ it has not been set yet.
+
+ \sa setFramebufferObject(), context()
+*/
+QGLFramebufferObject *QGLFramebufferObjectSurface::framebufferObject() const
+{
+ Q_D(const QGLFramebufferObjectSurface);
+ return d->framebufferObject;
+}
+
+/*!
+ Sets the framebuffer object for this surface to \a fbo.
+
+ \sa framebufferObject()
+*/
+void QGLFramebufferObjectSurface::setFramebufferObject
+ (QGLFramebufferObject *fbo)
+{
+ Q_D(QGLFramebufferObjectSurface);
+ d->framebufferObject = fbo;
+}
+
+/*!
+ \reimp
+*/
+QPaintDevice *QGLFramebufferObjectSurface::device() const
+{
+ Q_D(const QGLFramebufferObjectSurface);
+ return d->framebufferObject;
+}
+
+/*!
+ \reimp
+*/
+bool QGLFramebufferObjectSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ Q_UNUSED(prevSurface);
+ Q_D(QGLFramebufferObjectSurface);
+ if (d->context) {
+ if (!QGLContext::areSharing(QGLContext::currentContext(), d->context))
+ const_cast<QGLContext *>(d->context)->makeCurrent();
+ } else {
+ // If we don't have a current context, then something is wrong.
+ Q_ASSERT(QGLContext::currentContext());
+ }
+ if (d->framebufferObject)
+ return d->framebufferObject->bind();
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QGLFramebufferObjectSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ Q_D(QGLFramebufferObjectSurface);
+ if (d->framebufferObject) {
+ if (nextSurface && nextSurface->surfaceType() == FramebufferObject) {
+ // If we are about to switch to another fbo that is on the
+ // same context, then don't bother doing the release().
+ // This saves an unnecessary glBindFramebuffer(0) call.
+ if (static_cast<QGLFramebufferObjectSurface *>(nextSurface)
+ ->context() == d->context)
+ return;
+ }
+ d->framebufferObject->release();
+ }
+}
+
+/*!
+ \reimp
+*/
+QRect QGLFramebufferObjectSurface::viewportGL() const
+{
+ Q_D(const QGLFramebufferObjectSurface);
+ if (d->framebufferObject)
+ return QRect(QPoint(0, 0), d->framebufferObject->size());
+ else
+ return QRect();
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglframebufferobjectsurface.h b/src/threed/surfaces/qglframebufferobjectsurface.h
new file mode 100644
index 000000000..df38c3156
--- /dev/null
+++ b/src/threed/surfaces/qglframebufferobjectsurface.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLFRAMEBUFFEROBJECTSURFACE_H
+#define QGLFRAMEBUFFEROBJECTSURFACE_H
+
+#include "qglabstractsurface.h"
+#include <QtOpenGL/qglframebufferobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLFramebufferObjectSurfacePrivate;
+
+class Q_QT3D_EXPORT QGLFramebufferObjectSurface : public QGLAbstractSurface
+{
+public:
+ QGLFramebufferObjectSurface();
+ explicit QGLFramebufferObjectSurface
+ (QGLFramebufferObject *fbo, const QGLContext *context = 0);
+ ~QGLFramebufferObjectSurface();
+
+ const QGLContext *context() const;
+ void setContext(const QGLContext *context);
+
+ QGLFramebufferObject *framebufferObject() const;
+ void setFramebufferObject(QGLFramebufferObject *fbo);
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface = 0);
+ void deactivate(QGLAbstractSurface *nextSurface = 0);
+ QRect viewportGL() const;
+
+private:
+ QScopedPointer<QGLFramebufferObjectSurfacePrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLFramebufferObjectSurface)
+ Q_DISABLE_COPY(QGLFramebufferObjectSurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qglmaskedsurface.cpp b/src/threed/surfaces/qglmaskedsurface.cpp
new file mode 100644
index 000000000..b953c85ab
--- /dev/null
+++ b/src/threed/surfaces/qglmaskedsurface.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglmaskedsurface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLMaskedSurface
+ \brief The QGLMaskedSurface class represents a masked copy of another OpenGL drawing surface.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+ \internal
+
+ Masked surfaces are typically used to render red-cyan anaglyph images
+ into an underlying surface(). For the left eye image, the mask()
+ is set to RedMask | AlphaMask. Then for the right eye image, the mask()
+ is set to GreenMask | BlueMask.
+*/
+
+/*!
+ \enum QGLMaskedSurface::BufferMaskBit
+ This enum defines the channels to mask with QGLMaskedSurface.
+
+ \value RedMask Allow the red channel to be written to the color buffer.
+ \value GreenMask Allow the green channel to be written to the color buffer.
+ \value BlueMask Allow the blue channel to be written to the color buffer.
+ \value AlphaMask Allow the alpha channel to be written to the color buffer.
+*/
+
+class QGLMaskedSurfacePrivate
+{
+public:
+ QGLMaskedSurfacePrivate
+ (QGLAbstractSurface *surf = 0,
+ QGLMaskedSurface::BufferMask msk = QGLMaskedSurface::RedMask |
+ QGLMaskedSurface::GreenMask |
+ QGLMaskedSurface::BlueMask |
+ QGLMaskedSurface::AlphaMask)
+ : surface(surf), mask(msk) {}
+
+ QGLAbstractSurface *surface;
+ QGLMaskedSurface::BufferMask mask;
+};
+
+#define MaskedSurfaceType 501
+
+/*!
+ Constructs a masked OpenGL drawing surface with surface() initially
+ set to null and mask() initially set to allow all channels to be
+ written to the color buffer.
+*/
+QGLMaskedSurface::QGLMaskedSurface()
+ : QGLAbstractSurface(MaskedSurfaceType)
+ , d_ptr(new QGLMaskedSurfacePrivate)
+{
+}
+
+/*!
+ Constructs a masked OpenGL drawing surface that applies \a mask
+ to \a surface when activate() is called.
+*/
+QGLMaskedSurface::QGLMaskedSurface
+ (QGLAbstractSurface *surface, QGLMaskedSurface::BufferMask mask)
+ : QGLAbstractSurface(MaskedSurfaceType)
+ , d_ptr(new QGLMaskedSurfacePrivate(surface, mask))
+{
+}
+
+/*!
+ Destroys this masked OpenGL drawing surface.
+*/
+QGLMaskedSurface::~QGLMaskedSurface()
+{
+}
+
+/*!
+ Returns the underlying surface that mask() will be applied to
+ when activate() is called.
+
+ \sa setSurface(), mask()
+*/
+QGLAbstractSurface *QGLMaskedSurface::surface() const
+{
+ Q_D(const QGLMaskedSurface);
+ return d->surface;
+}
+
+/*!
+ Sets the underlying \a surface that mask() will be applied to
+ when activate() is called.
+
+ \sa surface(), setMask()
+*/
+void QGLMaskedSurface::setSurface(QGLAbstractSurface *surface)
+{
+ Q_D(QGLMaskedSurface);
+ d->surface = surface;
+}
+
+/*!
+ Returns the color mask to apply to surface() when activate()
+ is called.
+
+ \sa setMask(), surface()
+*/
+QGLMaskedSurface::BufferMask QGLMaskedSurface::mask() const
+{
+ Q_D(const QGLMaskedSurface);
+ return d->mask;
+}
+
+/*!
+ Sets the color \a mask to apply to surface() when activate()
+ is called.
+
+ \sa mask(), setSurface()
+*/
+void QGLMaskedSurface::setMask(QGLMaskedSurface::BufferMask mask)
+{
+ Q_D(QGLMaskedSurface);
+ d->mask = mask;
+}
+
+/*!
+ \reimp
+*/
+QPaintDevice *QGLMaskedSurface::device() const
+{
+ Q_D(const QGLMaskedSurface);
+ return d->surface ? d->surface->device() : 0;
+}
+
+/*!
+ \reimp
+*/
+bool QGLMaskedSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ Q_D(const QGLMaskedSurface);
+ if (!d->surface || !d->surface->activate(prevSurface))
+ return false;
+ glColorMask((d->mask & RedMask) != 0, (d->mask & GreenMask) != 0,
+ (d->mask & BlueMask) != 0, (d->mask & AlphaMask) != 0);
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QGLMaskedSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ Q_D(QGLMaskedSurface);
+ if (d->surface)
+ d->surface->deactivate(nextSurface);
+ if (nextSurface && nextSurface->surfaceType() == MaskedSurfaceType) {
+ // If we are about to switch to another masked surface for
+ // the same underlying surface, then don't bother calling
+ // glColorMask() for this one.
+ QGLMaskedSurface *next = static_cast<QGLMaskedSurface *>(nextSurface);
+ if (d->surface == next->surface())
+ return;
+ }
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+}
+
+/*!
+ \reimp
+*/
+QRect QGLMaskedSurface::viewportGL() const
+{
+ Q_D(const QGLMaskedSurface);
+ return d->surface ? d->surface->viewportGL() : QRect();
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglmaskedsurface_p.h b/src/threed/surfaces/qglmaskedsurface_p.h
new file mode 100644
index 000000000..4a04ca32e
--- /dev/null
+++ b/src/threed/surfaces/qglmaskedsurface_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLMASKEDSURFACE_H
+#define QGLMASKEDSURFACE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstractsurface.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLMaskedSurfacePrivate;
+
+class QGLMaskedSurface : public QGLAbstractSurface
+{
+public:
+ enum BufferMaskBit
+ {
+ RedMask = 0x0001,
+ GreenMask = 0x0002,
+ BlueMask = 0x0004,
+ AlphaMask = 0x0008
+ };
+ Q_DECLARE_FLAGS(BufferMask, BufferMaskBit)
+
+ QGLMaskedSurface();
+ QGLMaskedSurface
+ (QGLAbstractSurface *surface, QGLMaskedSurface::BufferMask mask);
+ ~QGLMaskedSurface();
+
+ QGLAbstractSurface *surface() const;
+ void setSurface(QGLAbstractSurface *surface);
+
+ QGLMaskedSurface::BufferMask mask() const;
+ void setMask(QGLMaskedSurface::BufferMask mask);
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface = 0);
+ void deactivate(QGLAbstractSurface *nextSurface = 0);
+ QRect viewportGL() const;
+
+private:
+ QScopedPointer<QGLMaskedSurfacePrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLMaskedSurface)
+ Q_DISABLE_COPY(QGLMaskedSurface)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLMaskedSurface::BufferMask)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qglpaintersurface.cpp b/src/threed/surfaces/qglpaintersurface.cpp
new file mode 100644
index 000000000..b2bb379fc
--- /dev/null
+++ b/src/threed/surfaces/qglpaintersurface.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglpaintersurface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPaintDevice *QGLPainterSurface::device() const
+{
+ return m_painter->device();
+}
+
+bool QGLPainterSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ if (m_painterContext != QGLContext::currentContext())
+ const_cast<QGLContext *>(m_painterContext)->makeCurrent();
+ if (!prevSurface)
+ m_painter->beginNativePainting();
+ return true;
+}
+
+void QGLPainterSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ if (!nextSurface)
+ m_painter->endNativePainting();
+}
+
+QRect QGLPainterSurface::viewportGL() const
+{
+ QPaintDevice *device = m_painter->device();
+ return QRect(0, 0, device->width(), device->height());
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglpaintersurface_p.h b/src/threed/surfaces/qglpaintersurface_p.h
new file mode 100644
index 000000000..3a6414e27
--- /dev/null
+++ b/src/threed/surfaces/qglpaintersurface_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPAINTERSURFACE_P_H
+#define QGLPAINTERSURFACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qglabstractsurface.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLPainterSurface : public QGLAbstractSurface
+{
+public:
+ explicit QGLPainterSurface(QPainter *painter)
+ : QGLAbstractSurface(503)
+ , m_painter(painter), m_painterContext(QGLContext::currentContext()) {}
+ ~QGLPainterSurface() {}
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface);
+ void deactivate(QGLAbstractSurface *nextSurface);
+ QRect viewportGL() const;
+
+private:
+ QPainter *m_painter;
+ const QGLContext *m_painterContext;
+
+ Q_DISABLE_COPY(QGLPainterSurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qglpixelbuffersurface.cpp b/src/threed/surfaces/qglpixelbuffersurface.cpp
new file mode 100644
index 000000000..33e7a9eff
--- /dev/null
+++ b/src/threed/surfaces/qglpixelbuffersurface.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglpixelbuffersurface.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLPixelBufferSurface
+ \brief The QGLPixelBufferSurface class represents a pixel buffer that is being used as an OpenGL drawing surface.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+*/
+
+/*!
+ Constructs a default pixel buffer surface. This constructor
+ should be followed by a call to setPixelBuffer().
+*/
+QGLPixelBufferSurface::QGLPixelBufferSurface()
+ : QGLAbstractSurface(QGLAbstractSurface::PixelBuffer)
+ , m_pbuffer(0)
+{
+}
+
+/*!
+ Constructs a pixel buffer surface for \a pbuffer.
+*/
+QGLPixelBufferSurface::QGLPixelBufferSurface(QGLPixelBuffer *pbuffer)
+ : QGLAbstractSurface(QGLAbstractSurface::PixelBuffer)
+ , m_pbuffer(pbuffer)
+{
+}
+
+/*!
+ Destroys this pixel buffer surface.
+*/
+QGLPixelBufferSurface::~QGLPixelBufferSurface()
+{
+}
+
+/*!
+ Returns the pixel buffer for this surface, or null if
+ it has not been set yet.
+
+ \sa setPixelBuffer()
+*/
+QGLPixelBuffer *QGLPixelBufferSurface::pixelBuffer() const
+{
+ return m_pbuffer;
+}
+
+/*!
+ Sets the framebuffer object for this surface to \a pbuffer.
+
+ \sa pixelBuffer()
+*/
+void QGLPixelBufferSurface::setPixelBuffer
+ (QGLPixelBuffer *pbuffer)
+{
+ m_pbuffer = pbuffer;
+}
+
+/*!
+ \reimp
+*/
+QPaintDevice *QGLPixelBufferSurface::device() const
+{
+ return m_pbuffer;
+}
+
+/*!
+ \reimp
+*/
+bool QGLPixelBufferSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ Q_UNUSED(prevSurface);
+ if (m_pbuffer)
+ return m_pbuffer->makeCurrent();
+ else
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QGLPixelBufferSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ // Nothing to do here - leave the context current.
+ Q_UNUSED(nextSurface);
+}
+
+/*!
+ \reimp
+*/
+QRect QGLPixelBufferSurface::viewportGL() const
+{
+ if (m_pbuffer)
+ return QRect(0, 0, m_pbuffer->width(), m_pbuffer->height());
+ else
+ return QRect();
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglpixelbuffersurface.h b/src/threed/surfaces/qglpixelbuffersurface.h
new file mode 100644
index 000000000..e0e977599
--- /dev/null
+++ b/src/threed/surfaces/qglpixelbuffersurface.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPIXELBUFFERSURFACE_H
+#define QGLPIXELBUFFERSURFACE_H
+
+#include "qglabstractsurface.h"
+#include <QtOpenGL/qglpixelbuffer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QGLPixelBufferSurface : public QGLAbstractSurface
+{
+public:
+ QGLPixelBufferSurface();
+ explicit QGLPixelBufferSurface(QGLPixelBuffer *pbuffer);
+ ~QGLPixelBufferSurface();
+
+ QGLPixelBuffer *pixelBuffer() const;
+ void setPixelBuffer(QGLPixelBuffer *pbuffer);
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface = 0);
+ void deactivate(QGLAbstractSurface *nextSurface = 0);
+ QRect viewportGL() const;
+
+private:
+ QGLPixelBuffer *m_pbuffer;
+
+ Q_DISABLE_COPY(QGLPixelBufferSurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qglsubsurface.cpp b/src/threed/surfaces/qglsubsurface.cpp
new file mode 100644
index 000000000..1da4ffd55
--- /dev/null
+++ b/src/threed/surfaces/qglsubsurface.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglsubsurface.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLSubsurface
+ \brief The QGLSubsurface class represents a sub-surface of another OpenGL drawing surface.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+*/
+
+class QGLSubsurfacePrivate
+{
+public:
+ QGLSubsurfacePrivate() : surface(0) {}
+ QGLSubsurfacePrivate(QGLAbstractSurface *surf, const QRect &rgn)
+ : surface(surf), region(rgn) {}
+
+ QGLAbstractSurface *surface;
+ QRect region;
+};
+
+/*!
+ Constructs a new subsurface. This constructor should be followed
+ by calls to setSurface() and setRegion().
+*/
+QGLSubsurface::QGLSubsurface()
+ : QGLAbstractSurface(QGLAbstractSurface::Subsurface)
+ , d_ptr(new QGLSubsurfacePrivate)
+{
+}
+
+/*!
+ Constructs a new subsurface that occupies \a region within
+ \a surface. The \a region has its origin at the top-left
+ of \a surface.
+*/
+QGLSubsurface::QGLSubsurface
+ (QGLAbstractSurface *surface, const QRect &region)
+ : QGLAbstractSurface(QGLAbstractSurface::Subsurface)
+ , d_ptr(new QGLSubsurfacePrivate(surface, region))
+{
+}
+
+/*!
+ Destroys this subsurface.
+*/
+QGLSubsurface::~QGLSubsurface()
+{
+}
+
+/*!
+ Returns the surface behind this subsurface, or null if the
+ surface has not been set.
+
+ \sa setSurface(), region()
+*/
+QGLAbstractSurface *QGLSubsurface::surface() const
+{
+ Q_D(const QGLSubsurface);
+ return d->surface;
+}
+
+/*!
+ Sets the \a surface behind this subsurface.
+
+ \sa surface(), setRegion()
+*/
+void QGLSubsurface::setSurface(QGLAbstractSurface *surface)
+{
+ Q_D(QGLSubsurface);
+ d->surface = surface;
+}
+
+/*!
+ Returns the region within surface() that is occupied by this
+ subsurface, relative to the viewportRect() of surface().
+ The origin is at the top-left of surface().
+
+ \sa setRegion(), surface()
+*/
+QRect QGLSubsurface::region() const
+{
+ Q_D(const QGLSubsurface);
+ return d->region;
+}
+
+/*!
+ Sets the \a region within surface() that is occupied by this
+ subsurface, relative to the viewportRect() of surface().
+ The origin is at the top-left of surface().
+
+ \sa region(), setSurface()
+*/
+void QGLSubsurface::setRegion(const QRect &region)
+{
+ Q_D(QGLSubsurface);
+ d->region = region;
+}
+
+/*!
+ \reimp
+*/
+QPaintDevice *QGLSubsurface::device() const
+{
+ Q_D(const QGLSubsurface);
+ if (d->surface)
+ return d->surface->device();
+ else
+ return 0;
+}
+
+/*!
+ \reimp
+*/
+bool QGLSubsurface::activate(QGLAbstractSurface *prevSurface)
+{
+ Q_D(QGLSubsurface);
+ if (d->surface)
+ return d->surface->activate(prevSurface);
+ else
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QGLSubsurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ Q_D(QGLSubsurface);
+ if (d->surface)
+ d->surface->deactivate(nextSurface);
+}
+
+/*!
+ \reimp
+*/
+QRect QGLSubsurface::viewportGL() const
+{
+ Q_D(const QGLSubsurface);
+ if (d->surface) {
+ // The underlying surface's viewportGL() has its origin
+ // at the bottom-left, whereas d->region has its origin
+ // at the top-left. Flip the sub-region and adjust.
+ QRect rect = d->surface->viewportGL();
+ return QRect(rect.x() + d->region.x(),
+ rect.y() + rect.height() -
+ (d->region.y() + d->region.height()),
+ d->region.width(), d->region.height());
+ } else {
+ // Don't know the actual height of the surrounding surface,
+ // so the best we can do is assume the region is bottom-aligned.
+ return QRect(d->region.x(), 0, d->region.width(), d->region.height());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglsubsurface.h b/src/threed/surfaces/qglsubsurface.h
new file mode 100644
index 000000000..fb2da3868
--- /dev/null
+++ b/src/threed/surfaces/qglsubsurface.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSUBSURFACE_H
+#define QGLSUBSURFACE_H
+
+#include "qglabstractsurface.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLSubsurfacePrivate;
+
+class Q_QT3D_EXPORT QGLSubsurface : public QGLAbstractSurface
+{
+public:
+ QGLSubsurface();
+ QGLSubsurface(QGLAbstractSurface *surface, const QRect &region);
+ ~QGLSubsurface();
+
+ QGLAbstractSurface *surface() const;
+ void setSurface(QGLAbstractSurface *subSurface);
+
+ QRect region() const;
+ void setRegion(const QRect &region);
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface = 0);
+ void deactivate(QGLAbstractSurface *nextSurface = 0);
+ QRect viewportGL() const;
+
+private:
+ QScopedPointer<QGLSubsurfacePrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLSubsurface)
+ Q_DISABLE_COPY(QGLSubsurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/qglwidgetsurface.cpp b/src/threed/surfaces/qglwidgetsurface.cpp
new file mode 100644
index 000000000..4a10a5159
--- /dev/null
+++ b/src/threed/surfaces/qglwidgetsurface.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglwidgetsurface.h"
+#include <QtGui/qpainter.h>
+#include <QtGui/qpaintengine.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLWidgetSurface
+ \brief The QGLWidgetSurface class represents a QGLWidget that is begin used as an OpenGL drawing surface.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::painting
+*/
+
+/*!
+ Constructs a widget surface. This constructor should be followed
+ by a call to setWidget().
+*/
+QGLWidgetSurface::QGLWidgetSurface()
+ : QGLAbstractSurface(QGLAbstractSurface::Widget)
+ , m_widget(0)
+{
+}
+
+/*!
+ Constructs a widget surface for \a widget.
+*/
+QGLWidgetSurface::QGLWidgetSurface(QGLWidget *widget)
+ : QGLAbstractSurface(QGLAbstractSurface::Widget)
+ , m_widget(widget)
+{
+}
+
+/*!
+ Destroys this widget surface.
+*/
+QGLWidgetSurface::~QGLWidgetSurface()
+{
+}
+
+/*!
+ Returns the widget that is underlying this surface.
+
+ \sa setWidget()
+*/
+QGLWidget *QGLWidgetSurface::widget() const
+{
+ return m_widget;
+}
+
+/*!
+ Sets the \a widget that is underlying this surface.
+
+ \sa widget()
+*/
+void QGLWidgetSurface::setWidget(QGLWidget *widget)
+{
+ m_widget = widget;
+}
+
+/*!
+ \reimp
+*/
+QPaintDevice *QGLWidgetSurface::device() const
+{
+ return m_widget;
+}
+
+/*!
+ \reimp
+*/
+bool QGLWidgetSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ Q_UNUSED(prevSurface);
+ if (m_widget) {
+ const QGLContext *context = m_widget->context();
+ if (QGLContext::currentContext() != context)
+ const_cast<QGLContext *>(context)->makeCurrent();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QGLWidgetSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ // Nothing to do here - leave the context current.
+ Q_UNUSED(nextSurface);
+}
+
+/*!
+ \reimp
+*/
+QRect QGLWidgetSurface::viewportGL() const
+{
+ if (m_widget)
+ return m_widget->rect(); // Origin assumed to be (0, 0).
+ else
+ return QRect();
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/surfaces/qglwidgetsurface.h b/src/threed/surfaces/qglwidgetsurface.h
new file mode 100644
index 000000000..22fff4164
--- /dev/null
+++ b/src/threed/surfaces/qglwidgetsurface.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLWIDGETSURFACE_H
+#define QGLWIDGETSURFACE_H
+
+#include "qglabstractsurface.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLWidgetSurfacePrivate;
+
+class Q_QT3D_EXPORT QGLWidgetSurface : public QGLAbstractSurface
+{
+public:
+ QGLWidgetSurface();
+ explicit QGLWidgetSurface(QGLWidget *widget);
+ ~QGLWidgetSurface();
+
+ QGLWidget *widget() const;
+ void setWidget(QGLWidget *widget);
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface = 0);
+ void deactivate(QGLAbstractSurface *nextSurface = 0);
+ QRect viewportGL() const;
+
+private:
+ QGLWidget *m_widget;
+
+ Q_DISABLE_COPY(QGLWidgetSurface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/surfaces/surfaces.pri b/src/threed/surfaces/surfaces.pri
new file mode 100644
index 000000000..964f924a0
--- /dev/null
+++ b/src/threed/surfaces/surfaces.pri
@@ -0,0 +1,23 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += \
+ qglabstractsurface.h \
+ qglframebufferobjectsurface.h \
+ qglpixelbuffersurface.h \
+ qglsubsurface.h \
+ qglwidgetsurface.h
+SOURCES += \
+ qglabstractsurface.cpp \
+ qglcontextsurface.cpp \
+ qgldrawbuffersurface.cpp \
+ qglframebufferobjectsurface.cpp \
+ qglmaskedsurface.cpp \
+ qglpaintersurface.cpp \
+ qglpixelbuffersurface.cpp \
+ qglsubsurface.cpp \
+ qglwidgetsurface.cpp
+PRIVATE_HEADERS += \
+ qglcontextsurface_p.h \
+ qgldrawbuffersurface_p.h \
+ qglmaskedsurface_p.h \
+ qglpaintersurface_p.h
diff --git a/src/threed/textures/qareaallocator.cpp b/src/threed/textures/qareaallocator.cpp
new file mode 100644
index 000000000..d6d92de88
--- /dev/null
+++ b/src/threed/textures/qareaallocator.cpp
@@ -0,0 +1,877 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qareaallocator.h"
+#include "qglnamespace.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAreaAllocator
+ \brief The QAreaAllocator class provides facilities for allocating sub-regions from a rectangular image.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::textures
+ \internal
+
+ Performance on a system can sometimes be improved by storing
+ multiple small images in a single large image. This reduces
+ memory allocation overhead and GPU state switching costs.
+
+ QAreaAllocator and its subclasses implement standard strategies
+ for sub-region allocation in images without tying those strategies
+ to specific technologies such as raster, OpenGL, etc.
+
+ Allocations are managed in a virtual two-dimensional space.
+ The caller performs the actual texture upload based on the sub-region
+ that allocate() returns.
+
+ The caller can return a sub-region to the allocation pool with
+ release(). Note that not all strategies support release().
+
+ \sa QSimpleAreaAllocator, QGeneralAreaAllocator, QUniformAreaAllocator
+*/
+
+/*!
+ \class QSimpleAreaAllocator
+ \brief The QSimpleAreaAllocator class provides a simple allocation policy for simple-sized sub-allocations.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::textures
+ \internal
+
+ QSimpleAreaAllocator uses a trivial allocation strategy whereby
+ sub-regions are allocated in rows, with a new row started each
+ time the previous row fills up. Space is never reclaimed by
+ release().
+
+ This allocator is suitable for use when the allocations will all
+ be of a similar size and all regions will be discarded at
+ the same time when the allocator is destroyed. An example would
+ be a font glyph manager.
+
+ \sa QAreaAllocator, QGeneralAreaAllocator
+*/
+
+/*!
+ \class QGeneralAreaAllocator
+ \brief The QGeneralAreaAllocator class provides a general allocation policy for sub-regions in an image.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::textures
+ \internal
+
+ QGeneralAreaAllocator can handle arbitrary-sized allocations up to
+ size(), in any order, and can release() previously allocated regions.
+ It uses a binary subdivision algorithm on the image, which may result
+ in fragmentation under heavy load.
+
+ While technically any size sub-region up to size() can be allocated,
+ once subdivision begins, the sizes that can be allocated will reduce
+ substantially. It is recommended that incoming requests be size() / 4
+ or less for best performance.
+
+ If the sub-region sizes to be allocated are very similar, and release()
+ is not necessary, then QSimpleAreaAllocator may work better than
+ QGeneralAreaAllocator. If the sizes are very similar, and
+ release() is necessary, then QUniformAreaAllocator may work better
+ than QGeneralAreaAllocator.
+
+ \sa QAreaAllocator, QSimpleAreaAllocator, QUniformAreaAllocator
+*/
+
+/*!
+ \class QUniformAreaAllocator
+ \brief The QUniformAreaAllocator class provides an allocation policy for uniform-sized areas.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::textures
+ \internal
+
+ QUniformAreaAllocator allocates any size up to uniformSize()
+ by dividing size() up into a grid of uniformSize() areas.
+ Areas can be deallocated with release() and returned to the pool.
+
+ This allocator is suitable for use when the allocations will all
+ be of a similar size. Unlike QSimpleAreaAllocator, this class
+ can release allocations.
+
+ \sa QAreaAllocator, QSimpleAreaAllocator, QGeneralAreaAllocator
+*/
+
+/*!
+ \internal
+
+ Constructs a new area allocator that is initially \a size pixels
+ in size.
+
+ \sa expand()
+*/
+QAreaAllocator::QAreaAllocator(const QSize &size)
+ : m_size(size)
+ , m_minAlloc(1, 1)
+ , m_margin(0, 0)
+{
+}
+
+/*!
+ \internal
+
+ Destroys this area allocator.
+*/
+QAreaAllocator::~QAreaAllocator()
+{
+}
+
+/*!
+ \fn QSize QAreaAllocator::size() const
+ \internal
+
+ Returns the current size of the area being used by this allocator.
+*/
+
+/*!
+ \fn QSize QAreaAllocator::minimumAllocation() const
+ \internal
+
+ Returns the minimum allocation size in the x and y directions
+ for areas returned by allocate(). The default is (1, 1).
+
+ \sa setMinimumAllocation()
+*/
+
+/*!
+ \fn void QAreaAllocator::setMinimumAllocation(const QSize &size)
+ \internal
+
+ Sets the minimum allocation \a size in the x and y directions
+ for areas returned by allocate().
+
+ For example, setting the minimum allocation to (8, 8) will force
+ all allocations to be aligned on an 8-pixel boundary.
+
+ \sa minimumAllocation()
+*/
+
+/*!
+ \fn QSize QAreaAllocator::margin() const
+ \internal
+
+ Returns the margin that should be left between allocated items
+ in the x and y directions. The default is (0, 0).
+
+ This may be needed when using OpenGL textures because of
+ rounding errors in the floating-point representation of
+ texture co-ordinates. Leaving a small margin between allocations
+ can help avoid adjacent images from bleeding into each other.
+
+ \sa setMargin()
+*/
+
+/*!
+ \fn void QAreaAllocator::setMargin(const QSize &margin)
+ \internal
+
+ Sets the \a margin that should be left between allocated items
+ in the x and y directions.
+
+ \sa margin()
+*/
+
+/*!
+ \internal
+
+ Expands this allocator to encompass the width and height of \a size.
+ If the area is already larger, this function does nothing.
+
+ The rectangles that were returned for previous allocations will
+ remain valid.
+
+ \sa expandBy()
+*/
+void QAreaAllocator::expand(const QSize &size)
+{
+ int newWidth = qMax(m_size.width(), size.width());
+ int newHeight = qMax(m_size.height(), size.height());
+ m_size = QSize(newWidth, newHeight);
+}
+
+/*!
+ \internal
+
+ Expands this allocator by \a size pixels in the x and y directions.
+
+ For example, expanding by (0, 128) will add 128 additional pixels
+ of height but will leave the width unchanged.
+
+ \sa expand()
+*/
+void QAreaAllocator::expandBy(const QSize &size)
+{
+ expand(m_size + size);
+}
+
+/*!
+ \fn QRect QAreaAllocator::allocate(const QSize &size)
+ \internal
+
+ Allocates \a size pixels from this allocator and returns the rectangle
+ that should be used by the caller. Returns a null rectangle if
+ this allocator does not have sufficient space to accommodate \a size.
+
+ \sa release()
+*/
+
+/*!
+ \internal
+
+ Allocates and returns a list of rectangles corresponding to the
+ elements of \a sizes. The returned list will have less elements
+ than \a sizes if there is insufficient space to accommodate
+ all of the allocation requests. The values that are in the returned
+ list will be allocated and need to be passed to release() to
+ deallocate them.
+
+ The default implementation will call the subclass allocate() once
+ for each size until all \a sizes have been allocated or an
+ allocation fails. Subclasses may override this method to
+ reorder the allocations for best-fit.
+
+ \sa release()
+*/
+QList<QRect> QAreaAllocator::allocate(const QList<QSize> &sizes)
+{
+ QList<QRect> rects;
+ QRect rect;
+ for (int index = 0; index < sizes.count(); ++index) {
+ rect = allocate(sizes[index]);
+ if (rect.isNull())
+ break;
+ rects.append(rect);
+ }
+ return rects;
+}
+
+/*!
+ \internal
+
+ Releases the space occupied by \a rect back to the allocator.
+ The default implementation does nothing.
+
+ The \a rect must have been returned by a previous call to allocate().
+ Otherwise the behaviour is undefined.
+
+ \sa allocate()
+*/
+void QAreaAllocator::release(const QRect &rect)
+{
+ Q_UNUSED(rect);
+}
+
+/*!
+ \internal
+
+ Releases the space occupied by the members of \a rects back to
+ the allocator. The default implementation calls release() for
+ each rectangle in the list.
+
+ The members of \a rects must have been returned by previous calls
+ to allocate(). Otherwise the behaviour is undefined.
+
+ \sa allocate()
+*/
+void QAreaAllocator::release(const QList<QRect> &rects)
+{
+ for (int index = 0; index < rects.count(); ++index)
+ release(rects[index]);
+}
+
+/*!
+ \internal
+
+ Returns a rough estimate of the number of bytes of overhead that
+ are currently in use to store the house-keeping data structures
+ for this area allocator. The default implementation returns zero.
+*/
+int QAreaAllocator::overhead() const
+{
+ return 0;
+}
+
+/*!
+ \internal
+
+ Returns \a size, after rounding it up to account for
+ minimumAllocation() and margin().
+
+ This is a convenience function, provided for subclass overrides
+ of allocate().
+
+ \sa allocate()
+*/
+QSize QAreaAllocator::roundAllocation(const QSize &size) const
+{
+ int width = size.width() + m_margin.width();
+ int height = size.height() + m_margin.height();
+ int extra = width % m_minAlloc.width();
+ if (extra)
+ width += m_minAlloc.width() - extra;
+ extra = height % m_minAlloc.height();
+ if (extra)
+ height += m_minAlloc.height() - extra;
+ return QSize(width, height);
+}
+
+/*!
+ \internal
+
+ Constructs a simple area allocator that is initially \a size pixels
+ in size.
+*/
+QSimpleAreaAllocator::QSimpleAreaAllocator(const QSize &size)
+ : QAreaAllocator(size)
+ , m_row(0)
+ , m_column(0)
+ , m_rowHeight(0)
+{
+}
+
+/*!
+ \internal
+
+ Destroys this simple area allocator.
+*/
+QSimpleAreaAllocator::~QSimpleAreaAllocator()
+{
+}
+
+/*!
+ \internal
+*/
+QRect QSimpleAreaAllocator::allocate(const QSize &size)
+{
+ // Round up the allocation size to account for the margin and
+ // minimum allocation parameters.
+ QSize rounded = roundAllocation(size);
+ int width = rounded.width();
+ int height = rounded.height();
+
+ // Bail out if the size is obviously too small or too big.
+ if (width <= 0 || width > m_size.width())
+ return QRect();
+ if (height <= 0 || height > (m_size.height() - m_row))
+ return QRect();
+
+ // Do we need to place this allocation on a new row?
+ int row = m_row;
+ int column = m_column;
+ int rowHeight = m_rowHeight;
+ if ((column + width) > m_size.width()) {
+ row += m_rowHeight;
+ column = 0;
+ rowHeight = 0;
+ if (height > (m_size.height() - row))
+ return QRect();
+ }
+
+ // Update the current allocation position.
+ m_row = row;
+ m_column = column + width;
+ m_rowHeight = qMax(rowHeight, height);
+
+ // Return the allocation, using the original size without rounding.
+ return QRect(column, row, size.width(), size.height());
+}
+
+/*!
+ \internal
+
+ Constructs a general area allocator that is initially \a size pixels
+ in size. The \a size will be rounded up to the next power of two,
+ to simplify the internal allocation policy.
+
+ This constructor sets minimumAllocation() to (8, 8) to reduce the
+ housekeeping overhead of the internal data structures.
+*/
+QGeneralAreaAllocator::QGeneralAreaAllocator(const QSize &size)
+ : QAreaAllocator(QGL::nextPowerOfTwo(size))
+{
+ m_root = new Node();
+ m_root->rect = QRect(0, 0, m_size.width(), m_size.height());
+ m_root->largestFree = m_size;
+ m_root->parent = 0;
+ m_root->left = 0;
+ m_root->right = 0;
+ m_nodeCount = 1;
+ setMinimumAllocation(QSize(8, 8));
+}
+
+/*!
+ \internal
+
+ Destroys this general area allocator.
+*/
+QGeneralAreaAllocator::~QGeneralAreaAllocator()
+{
+ freeNode(m_root);
+}
+
+/*!
+ \internal
+*/
+void QGeneralAreaAllocator::freeNode(Node *node)
+{
+ if (node) {
+ freeNode(node->left);
+ freeNode(node->right);
+ }
+ delete node;
+}
+
+/*!
+ \internal
+
+ The \a size will be rounded up to the next power of two.
+ Use size() to determine the actual size after expansion.
+*/
+void QGeneralAreaAllocator::expand(const QSize &size)
+{
+ QAreaAllocator::expand(QGL::nextPowerOfTwo(size));
+
+ if (m_root->rect.size() == m_size)
+ return; // No change.
+ if (!m_root->left && m_root->largestFree.width() > 0) {
+ // No allocations have occurred, so just adjust the root size.
+ m_root->rect = QRect(0, 0, m_size.width(), m_size.height());
+ m_root->largestFree = m_size;
+ return;
+ }
+
+ // Add extra nodes above the current root to expand the tree.
+ Node *oldRoot = m_root;
+ Split split;
+ if (m_size.width() >= m_size.height())
+ split = SplitOnX;
+ else
+ split = SplitOnY;
+ while (m_root->rect.size() != m_size) {
+ if (m_root->rect.width() == m_size.width())
+ split = SplitOnY;
+ else if (m_root->rect.height() == m_size.height())
+ split = SplitOnX;
+ Node *parent = new Node();
+ Node *right = new Node();
+ m_nodeCount += 2;
+ m_root->parent = parent;
+ parent->parent = 0;
+ parent->left = m_root;
+ parent->right = right;
+ parent->largestFree = m_root->rect.size();
+ right->parent = parent;
+ right->left = 0;
+ right->right = 0;
+ right->largestFree = m_root->rect.size();
+ if (split == SplitOnX) {
+ parent->rect = QRect(m_root->rect.x(), m_root->rect.y(),
+ m_root->rect.width() * 2,
+ m_root->rect.height());
+ right->rect = QRect(m_root->rect.x() + m_root->rect.width(),
+ m_root->rect.y(),
+ m_root->rect.width(), m_root->rect.height());
+ } else {
+ parent->rect = QRect(m_root->rect.x(), m_root->rect.y(),
+ m_root->rect.width(),
+ m_root->rect.height() * 2);
+ right->rect = QRect(m_root->rect.x(),
+ m_root->rect.y() + m_root->rect.width(),
+ m_root->rect.width(), m_root->rect.height());
+ }
+ split = (split == SplitOnX ? SplitOnY : SplitOnX);
+ m_root = parent;
+ }
+ updateLargestFree(oldRoot);
+}
+
+static inline bool fitsWithin(const QSize &size1, const QSize &size2)
+{
+ return size1.width() <= size2.width() && size1.height() <= size2.height();
+}
+
+/*!
+ \internal
+*/
+QRect QGeneralAreaAllocator::allocate(const QSize &size)
+{
+ QSize rounded = roundAllocation(size);
+ rounded = QGL::nextPowerOfTwo(rounded);
+ if (rounded.width() <= 0 || rounded.width() > m_size.width() ||
+ rounded.height() <= 0 || rounded.height() > m_size.height())
+ return QRect();
+ QPoint point = allocateFromNode(rounded, m_root);
+ if (point.x() >= 0)
+ return QRect(point, size);
+ else
+ return QRect();
+}
+
+/*!
+ \internal
+*/
+QPoint QGeneralAreaAllocator::allocateFromNode(const QSize &size, Node *node)
+{
+ // Find the best node to insert into, which should be
+ // a node with the least amount of unused space that is
+ // big enough to contain the requested size.
+ while (node != 0) {
+ // Go down a level and determine if the left or right
+ // sub-tree contains the best chance of allocation.
+ Node *left = node->left;
+ Node *right = node->right;
+ if (left && fitsWithin(size, left->largestFree)) {
+ if (right && fitsWithin(size, right->largestFree)) {
+ if (left->largestFree.width() < right->largestFree.width() ||
+ left->largestFree.height() < right->largestFree.height()) {
+ // The largestFree values may be a little oversized,
+ // so try the left sub-tree and then the right sub-tree.
+ QPoint point = allocateFromNode(size, left);
+ if (point.x() >= 0)
+ return point;
+ else
+ return allocateFromNode(size, right);
+ } else {
+ node = right;
+ }
+ } else {
+ node = left;
+ }
+ } else if (right && fitsWithin(size, right->largestFree)) {
+ node = right;
+ } else if (left || right) {
+ // Neither sub-node has enough space to allocate from.
+ return QPoint(-1, -1);
+ } else if (fitsWithin(size, node->largestFree)) {
+ // Do we need to split this node into smaller pieces?
+ Split split;
+ if (fitsWithin(QSize(size.width() * 2, size.height() * 2),
+ node->largestFree)) {
+ // Split in either direction: choose the inverse of
+ // the parent node's split direction to try to balance
+ // out the wasted space as further subdivisions happen.
+ if (node->parent &&
+ node->parent->left->rect.x() ==
+ node->parent->right->rect.x())
+ split = SplitOnX;
+ else if (node->parent)
+ split = SplitOnY;
+ else if (node->rect.width() >= node->rect.height())
+ split = SplitOnX;
+ else
+ split = SplitOnY;
+ } else if (fitsWithin(QSize(size.width() * 2, size.height()),
+ node->largestFree)) {
+ // Split along the X direction.
+ split = SplitOnX;
+ } else if (fitsWithin(QSize(size.width(), size.height() * 2),
+ node->largestFree)) {
+ // Split along the Y direction.
+ split = SplitOnY;
+ } else {
+ // Cannot split further - allocate this node.
+ node->largestFree = QSize(0, 0);
+ updateLargestFree(node);
+ return node->rect.topLeft();
+ }
+
+ // Split the node, then go around again using the left sub-tree.
+ node = splitNode(node, split);
+ } else {
+ // Cannot possibly fit into this node.
+ break;
+ }
+ }
+ return QPoint(-1, -1);
+}
+
+/*!
+ \internal
+*/
+QGeneralAreaAllocator::Node *QGeneralAreaAllocator::splitNode
+ (Node *node, Split split)
+{
+ Node *left = new Node();
+ Node *right = new Node();
+ m_nodeCount += 2;
+ left->parent = node;
+ left->left = 0;
+ left->right = 0;
+ right->parent = node;
+ right->left = 0;
+ right->right = 0;
+ node->left = left;
+ node->right = right;
+ if (split == SplitOnX) {
+ left->rect = QRect(node->rect.x(), node->rect.y(),
+ node->rect.width() / 2,
+ node->rect.height());
+ right->rect = QRect(left->rect.right() + 1, node->rect.y(),
+ node->rect.width() / 2,
+ node->rect.height());
+ } else {
+ left->rect = QRect(node->rect.x(), node->rect.y(),
+ node->rect.width(),
+ node->rect.height() / 2);
+ right->rect = QRect(node->rect.x(), left->rect.bottom() + 1,
+ node->rect.width(),
+ node->rect.height() / 2);
+ }
+ left->largestFree = left->rect.size();
+ right->largestFree = right->rect.size();
+ node->largestFree = right->largestFree;
+ return left;
+}
+
+/*!
+ \internal
+*/
+void QGeneralAreaAllocator::updateLargestFree(Node *node)
+{
+ while ((node = node->parent) != 0) {
+ node->largestFree =
+ QSize(qMax(node->left->largestFree.width(),
+ node->right->largestFree.width()),
+ qMax(node->left->largestFree.height(),
+ node->right->largestFree.height()));
+ }
+}
+
+/*!
+ \internal
+*/
+void QGeneralAreaAllocator::release(const QRect &rect)
+{
+ // Locate the node that contains the allocated region.
+ Node *node = m_root;
+ QPoint point = rect.topLeft();
+ while (node != 0) {
+ if (node->left && node->left->rect.contains(point))
+ node = node->left;
+ else if (node->right && node->right->rect.contains(point))
+ node = node->right;
+ else if (node->rect.contains(point))
+ break;
+ else
+ return; // Point is completely outside the tree.
+ }
+ if (!node)
+ return;
+
+ // Mark the node as free and then work upwards through the tree
+ // recombining and deleting nodes until we reach a sibling
+ // that is still allocated.
+ node->largestFree = node->rect.size();
+ while (node->parent) {
+ if (node->parent->left == node) {
+ if (node->parent->right->largestFree !=
+ node->parent->right->rect.size())
+ break;
+ } else {
+ if (node->parent->left->largestFree !=
+ node->parent->left->rect.size())
+ break;
+ }
+ node = node->parent;
+ freeNode(node->left);
+ freeNode(node->right);
+ m_nodeCount -= 2;
+ node->left = 0;
+ node->right = 0;
+ node->largestFree = node->rect.size();
+ }
+
+ // Make the rest of our ancestors have the correct "largest free size".
+ updateLargestFree(node);
+}
+
+/*!
+ \internal
+*/
+int QGeneralAreaAllocator::overhead() const
+{
+ return m_nodeCount * sizeof(Node);
+}
+
+/*!
+ \internal
+
+ Constructs a uniform area allocator that is initially \a size pixels
+ in size. The \a uniformSize specifies the single allocation size
+ that is supported. All allocate() requests must be \a uniformSize
+ or less.
+*/
+QUniformAreaAllocator::QUniformAreaAllocator
+ (const QSize &size, const QSize &uniformSize)
+ : QAreaAllocator(size), m_uniformSize(uniformSize), m_firstFree(0)
+{
+ Q_ASSERT(uniformSize.width() > 0 && uniformSize.height() > 0);
+ Q_ASSERT(size.width() >= uniformSize.width() &&
+ size.height() >= uniformSize.height());
+ m_gridSize = QSize(size.width() / uniformSize.width(),
+ size.height() / uniformSize.height());
+ int count = m_gridSize.width() * m_gridSize.height();
+ m_grid = new int [count];
+ for (int index = 0; index < (count - 1); ++index)
+ m_grid[index] = index + 1;
+ m_grid[count - 1] = -1;
+}
+
+/*!
+ \internal
+
+ Destroys this uniform area allocator.
+*/
+QUniformAreaAllocator::~QUniformAreaAllocator()
+{
+ delete [] m_grid;
+}
+
+/*!
+ \fn QSize QUniformAreaAllocator::uniformSize() const
+ \internal
+
+ Returns the uniform size of all allocations.
+
+ \sa allocate()
+*/
+
+/*!
+ \internal
+*/
+void QUniformAreaAllocator::expand(const QSize &size)
+{
+ QAreaAllocator::expand(size);
+
+ QSize newGridSize = QSize(m_size.width() / m_uniformSize.width(),
+ m_size.height() / m_uniformSize.height());
+ if (m_gridSize == newGridSize)
+ return;
+
+ // Create a new grid.
+ int newCount = newGridSize.width() * newGridSize.height();
+ int *newGrid = new int [newCount];
+
+ // Copy across the free blocks from the old grid.
+ int posn = m_firstFree;
+ int newFirstFree = -1;
+ while (posn != -1) {
+ int x = posn % m_gridSize.width();
+ int y = posn / m_gridSize.width();
+ int newPosn = x + y * newGridSize.width();
+ newGrid[newPosn] = newFirstFree;
+ newFirstFree = newPosn;
+ posn = m_grid[posn];
+ }
+
+ // Add free blocks within the expanded area of the new grid.
+ for (int y = 0; y < m_gridSize.height(); ++y) {
+ int newPosn = y * newGridSize.width() + m_gridSize.width();
+ for (int x = m_gridSize.width(); x < newGridSize.width(); ++x) {
+ newGrid[newPosn] = newFirstFree;
+ newFirstFree = newPosn;
+ ++newPosn;
+ }
+ }
+ for (int y = m_gridSize.height(); y < newGridSize.height(); ++y) {
+ int newPosn = y * newGridSize.width();
+ for (int x = 0; x < newGridSize.width(); ++x) {
+ newGrid[newPosn] = newFirstFree;
+ newFirstFree = newPosn;
+ ++newPosn;
+ }
+ }
+
+ // Replace the old grid.
+ delete [] m_grid;
+ m_grid = newGrid;
+ m_gridSize = newGridSize;
+ m_firstFree = newFirstFree;
+}
+
+/*!
+ \internal
+*/
+QRect QUniformAreaAllocator::allocate(const QSize &size)
+{
+ QSize rounded = roundAllocation(size);
+ if (rounded.width() > m_uniformSize.width() ||
+ rounded.height() > m_uniformSize.height())
+ return QRect();
+ int posn = m_firstFree;
+ if (posn == -1)
+ return QRect();
+ m_firstFree = m_grid[posn];
+ int x = posn % m_gridSize.width();
+ int y = posn / m_gridSize.width();
+ return QRect(x * m_uniformSize.width(), y * m_uniformSize.height(),
+ size.width(), size.height());
+}
+
+/*!
+ \internal
+*/
+void QUniformAreaAllocator::release(const QRect &rect)
+{
+ int x = rect.x() / m_uniformSize.width();
+ int y = rect.y() / m_uniformSize.height();
+ int posn = x + y * m_gridSize.width();
+ Q_ASSERT(posn >= 0 && posn < m_gridSize.width() * m_gridSize.height());
+ m_grid[posn] = m_firstFree;
+ m_firstFree = posn;
+}
+
+/*!
+ \internal
+*/
+int QUniformAreaAllocator::overhead() const
+{
+ return sizeof(int) * m_gridSize.width() * m_gridSize.height();
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/textures/qareaallocator.h b/src/threed/textures/qareaallocator.h
new file mode 100644
index 000000000..a4d4f3dff
--- /dev/null
+++ b/src/threed/textures/qareaallocator.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAREAALLOCATOR_P_H
+#define QAREAALLOCATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qt3dglobal.h"
+#include <QtCore/qsize.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class Q_QT3D_EXPORT QAreaAllocator
+{
+public:
+ QAreaAllocator(const QSize &size);
+ virtual ~QAreaAllocator();
+
+ QSize size() const { return m_size; }
+
+ QSize minimumAllocation() const { return m_minAlloc; }
+ void setMinimumAllocation(const QSize &size) { m_minAlloc = size; }
+
+ QSize margin() const { return m_margin; }
+ void setMargin(const QSize &margin) { m_margin = margin; }
+
+ virtual void expand(const QSize &size);
+ void expandBy(const QSize &size);
+
+ virtual QRect allocate(const QSize &size) = 0;
+ virtual QList<QRect> allocate(const QList<QSize> &sizes);
+ virtual void release(const QRect &rect);
+ virtual void release(const QList<QRect> &rects);
+
+ virtual int overhead() const;
+
+protected:
+ QSize m_size;
+ QSize m_minAlloc;
+ QSize m_margin;
+
+ QSize roundAllocation(const QSize &size) const;
+};
+
+class Q_QT3D_EXPORT QSimpleAreaAllocator : public QAreaAllocator
+{
+public:
+ QSimpleAreaAllocator(const QSize &size);
+ virtual ~QSimpleAreaAllocator();
+
+ QRect allocate(const QSize &size);
+
+private:
+ int m_row;
+ int m_column;
+ int m_rowHeight;
+};
+
+class Q_QT3D_EXPORT QGeneralAreaAllocator : public QAreaAllocator
+{
+public:
+ QGeneralAreaAllocator(const QSize &size);
+ virtual ~QGeneralAreaAllocator();
+
+ void expand(const QSize &size);
+ QRect allocate(const QSize &size);
+ void release(const QRect &rect);
+ int overhead() const;
+
+private:
+ enum Split { SplitOnX, SplitOnY };
+
+ struct Node
+ {
+ QRect rect;
+ QSize largestFree;
+ Node *parent;
+ Node *left;
+ Node *right;
+ };
+
+ Node *m_root;
+ int m_nodeCount;
+
+ static void freeNode(Node *node);
+ QPoint allocateFromNode(const QSize &size, Node *node);
+ Node *splitNode(Node *node, Split split);
+ static void updateLargestFree(Node *node);
+};
+
+class Q_QT3D_EXPORT QUniformAreaAllocator : public QAreaAllocator
+{
+public:
+ QUniformAreaAllocator(const QSize &size, const QSize &uniformSize);
+ virtual ~QUniformAreaAllocator();
+
+ QSize uniformSize() const { return m_uniformSize; }
+
+ void expand(const QSize &size);
+ QRect allocate(const QSize &size);
+ void release(const QRect &rect);
+ int overhead() const;
+
+private:
+ QSize m_uniformSize;
+ QSize m_gridSize;
+ int *m_grid;
+ int m_firstFree;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/textures/qglsharedresource.cpp b/src/threed/textures/qglsharedresource.cpp
new file mode 100644
index 000000000..91bef8972
--- /dev/null
+++ b/src/threed/textures/qglsharedresource.cpp
@@ -0,0 +1,236 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglsharedresource_p.h"
+#include <QtCore/qmutex.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(Q_MOC_RUN)
+
+class Q_OPENGL_EXPORT QGLSignalProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QGLSignalProxy() : QObject() {}
+ void emitAboutToDestroyContext(const QGLContext *context) {
+ emit aboutToDestroyContext(context);
+ }
+ static QGLSignalProxy *instance();
+Q_SIGNALS:
+ void aboutToDestroyContext(const QGLContext *context);
+};
+
+#endif
+
+class QGLContextInfo
+{
+public:
+ QGLContextInfo(const QGLContext *ctx) : m_context(ctx), m_resources(0) {}
+ ~QGLContextInfo();
+
+ const QGLContext *m_context;
+ QGLSharedResource *m_resources;
+};
+
+QGLContextInfo::~QGLContextInfo()
+{
+ // Detach this information block from all of the shared resources
+ // that used to be owned by it.
+ QGLSharedResource *resource = m_resources;
+ while (resource != 0) {
+ resource->m_contextInfo = 0;
+ resource->m_id = 0;
+ resource = resource->m_next;
+ }
+}
+
+class QGLContextManager : public QObject
+{
+ Q_OBJECT
+public:
+ QGLContextManager(QObject *parent = 0);
+ ~QGLContextManager();
+
+ QMutex managerLock;
+
+ QGLContextInfo *contextInfo(const QGLContext *ctx);
+
+private Q_SLOTS:
+ void aboutToDestroyContext(const QGLContext *ctx);
+
+private:
+ QList<QGLContextInfo *> m_contexts;
+};
+
+Q_GLOBAL_STATIC(QGLContextManager, qt_gl_context_manager)
+
+QGLContextManager::QGLContextManager(QObject *parent)
+ : QObject(parent)
+{
+ QGLSignalProxy *proxy = QGLSignalProxy::instance();
+ QThread *mainThread = qApp->thread();
+ if (thread() != mainThread) {
+ // The manager and signal proxy have been created for the first
+ // time in a background thread. For safety, move both objects
+ // to the main thread.
+ moveToThread(mainThread);
+ proxy->moveToThread(mainThread);
+ }
+ connect(proxy, SIGNAL(aboutToDestroyContext(const QGLContext *)),
+ this, SLOT(aboutToDestroyContext(const QGLContext *)));
+}
+
+QGLContextManager::~QGLContextManager()
+{
+ QMutexLocker locker(&managerLock);
+ qDeleteAll(m_contexts);
+}
+
+QGLContextInfo *QGLContextManager::contextInfo(const QGLContext *ctx)
+{
+ QGLContextInfo *info;
+ for (int index = 0; index < m_contexts.size(); ++index) {
+ info = m_contexts[index];
+ if (info->m_context == ctx)
+ return info;
+ }
+ info = new QGLContextInfo(ctx);
+ m_contexts.append(info);
+ return info;
+}
+
+Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *);
+
+void QGLContextManager::aboutToDestroyContext(const QGLContext *ctx)
+{
+ QMutexLocker locker(&managerLock);
+ int index = 0;
+ while (index < m_contexts.size()) {
+ QGLContextInfo *info = m_contexts[index];
+ if (info->m_context == ctx) {
+ const QGLContext *transfer = qt_gl_transfer_context(ctx);
+ if (transfer) {
+ // Transfer ownership to another context in the same sharing
+ // group. This may result in multiple QGLContextInfo objects
+ // for the same context, which is ok.
+ info->m_context = transfer;
+ } else {
+ // All contexts in the sharing group have been deleted,
+ // so detach all of the shared resources.
+ m_contexts.removeAt(index);
+ delete info;
+ continue;
+ }
+ }
+ ++index;
+ }
+}
+
+const QGLContext *QGLSharedResource::context() const
+{
+ // Hope that the context will not be destroyed in another thread
+ // while we are doing this so we don't have to acquire the lock.
+ return m_contextInfo ? m_contextInfo->m_context : 0;
+}
+
+void QGLSharedResource::attach(const QGLContext *context, GLuint id)
+{
+ Q_ASSERT(!m_contextInfo);
+ QGLContextManager *manager = qt_gl_context_manager();
+ QMutexLocker locker(&(manager->managerLock));
+ m_contextInfo = manager->contextInfo(context);
+ m_id = id;
+ m_next = m_contextInfo->m_resources;
+ m_prev = 0;
+ if (m_contextInfo->m_resources)
+ m_contextInfo->m_resources->m_prev = this;
+ m_contextInfo->m_resources = this;
+}
+
+void QGLSharedResource::destroy()
+{
+ // Detach this resource from the context information block.
+ QGLContextManager *manager = qt_gl_context_manager();
+ const QGLContext *owner = 0;
+ GLuint id = 0;
+ manager->managerLock.lock();
+ if (m_contextInfo) {
+ if (m_next)
+ m_next->m_prev = m_prev;
+ if (m_prev)
+ m_prev->m_next = m_next;
+ else
+ m_contextInfo->m_resources = m_next;
+ owner = m_contextInfo->m_context;
+ id = m_id;
+ }
+ m_contextInfo = 0;
+ m_id = 0;
+ m_next = 0;
+ m_prev = 0;
+ manager->managerLock.unlock();
+
+ // Switch back to the owning context temporarily and delete the id.
+ if (owner && id) {
+ QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLContext *oldContext;
+ QGLContext *doneContext;
+ if (currentContext != owner && !QGLContext::areSharing(owner, currentContext)) {
+ oldContext = currentContext;
+ doneContext = const_cast<QGLContext *>(owner);
+ doneContext->makeCurrent();
+ } else {
+ oldContext = 0;
+ doneContext = 0;
+ }
+ m_destroyFunc(id);
+ if (oldContext)
+ oldContext->makeCurrent();
+ else if (!currentContext && doneContext)
+ doneContext->doneCurrent();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qglsharedresource.moc"
diff --git a/src/threed/textures/qglsharedresource_p.h b/src/threed/textures/qglsharedresource_p.h
new file mode 100644
index 000000000..9aafe70a8
--- /dev/null
+++ b/src/threed/textures/qglsharedresource_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLSHAREDRESOURCE_P_H
+#define QGLSHAREDRESOURCE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtOpenGL/qgl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGLContextManager;
+class QGLContextInfo;
+
+class QGLSharedResource
+{
+public:
+ typedef void (*DestroyResourceFunc)(GLuint id);
+ QGLSharedResource(DestroyResourceFunc destroyFunc)
+ : m_destroyFunc(destroyFunc), m_contextInfo(0), m_id(0)
+ , m_next(0), m_prev(0) {}
+ ~QGLSharedResource() { destroy(); }
+
+ const QGLContext *context() const;
+ GLuint id() const { return m_id; }
+ void clearId() { m_id = 0; }
+
+ void attach(const QGLContext *context, GLuint id);
+ void destroy();
+
+private:
+ DestroyResourceFunc m_destroyFunc;
+ QGLContextInfo *m_contextInfo;
+ GLuint m_id;
+ QGLSharedResource *m_next;
+ QGLSharedResource *m_prev;
+
+ friend class QGLContextManager;
+ friend class QGLContextInfo;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/textures/qgltexture2d.cpp b/src/threed/textures/qgltexture2d.cpp
new file mode 100644
index 000000000..d45a1dc04
--- /dev/null
+++ b/src/threed/textures/qgltexture2d.cpp
@@ -0,0 +1,697 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgltexture2d.h"
+#include "qgltexture2d_p.h"
+#include "qgltextureutils_p.h"
+#include "qglpainter_p.h"
+#include "qglext_p.h"
+
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLTexture2D
+ \brief The QGLTexture2D class represents a 2D texture object for GL painting operations.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::textures
+
+ QGLTexture2D contains a QImage and settings for texture filters,
+ wrap modes, and mipmap generation. When bind() is called, this
+ information is uploaded to the GL server if it has changed since
+ the last time bind() was called.
+
+ Once a QGLTexture2D object is created, it can be bound to multiple
+ GL contexts. Internally, a separate texture identifier is created
+ for each context. This makes QGLTexture2D easier to use than
+ raw GL texture identifiers because the application does not need
+ to be as concerned with whether the texture identifier is valid
+ in the current context. The application merely calls bind() and
+ QGLTexture2D will create a new texture identifier for the context
+ if necessary.
+
+ QGLTexture2D internally points to a reference-counted object that
+ represents the current texture state. If the QGLTexture2D is copied,
+ the internal pointer is the same. Modifications to one QGLTexture2D
+ copy will affect all of the other copies in the system.
+
+ The texture identifiers will be destroyed when the last QGLTexture2D
+ reference is destroyed, or when a context is destroyed that contained a
+ texture identifier that was created by QGLTexture2D.
+
+ QGLTexture2D can also be used for uploading 1D textures into the
+ GL server by specifying an image() with a height of 1.
+
+ \sa QGLTextureCube
+*/
+
+QGLTexture2DPrivate::QGLTexture2DPrivate()
+{
+ horizontalWrap = QGL::Repeat;
+ verticalWrap = QGL::Repeat;
+ bindOptions = QGLContext::DefaultBindOption;
+#if !defined(QT_OPENGL_ES)
+ mipmapSupported = false;
+ mipmapSupportedKnown = false;
+#endif
+ imageGeneration = 0;
+ parameterGeneration = 0;
+ infos = 0;
+}
+
+QGLTexture2DPrivate::~QGLTexture2DPrivate()
+{
+ // Destroy the texture id's in the GL server in their original contexts.
+ QGLTexture2DTextureInfo *current = infos;
+ QGLTexture2DTextureInfo *next;
+ const QGLContext *currentContext =
+ const_cast<QGLContext *>(QGLContext::currentContext());
+ const QGLContext *firstContext = currentContext;
+ while (current != 0) {
+ next = current->next;
+ if (current->isLiteral)
+ current->tex.clearId(); // Don't delete literal id's.
+ delete current;
+ current = next;
+ }
+ if (firstContext != currentContext) {
+ if (firstContext)
+ const_cast<QGLContext *>(firstContext)->makeCurrent();
+ else if (currentContext)
+ const_cast<QGLContext *>(currentContext)->doneCurrent();
+ }
+}
+
+/*!
+ Constructs a null texture object and attaches it to \a parent.
+
+ \sa isNull()
+*/
+QGLTexture2D::QGLTexture2D(QObject *parent)
+ : QObject(parent), d_ptr(new QGLTexture2DPrivate())
+{
+}
+
+/*!
+ Destroys this texture object. If this object is the last
+ reference to the underlying GL texture, then the underlying
+ GL texture will also be deleted.
+*/
+QGLTexture2D::~QGLTexture2D()
+{
+}
+
+/*!
+ Returns true if this texture object is null; that is, image()
+ is null and textureId() is zero.
+*/
+bool QGLTexture2D::isNull() const
+{
+ Q_D(const QGLTexture2D);
+ return d->image.isNull() && !d->infos;
+}
+
+/*!
+ Returns true if this texture has an alpha channel; false if the
+ texture is fully opaque.
+*/
+bool QGLTexture2D::hasAlphaChannel() const
+{
+ Q_D(const QGLTexture2D);
+ if (!d->image.isNull())
+ return d->image.hasAlphaChannel();
+ QGLTexture2DTextureInfo *info = d->infos;
+ if (info)
+ return info->tex.hasAlpha();
+ return false;
+}
+
+/*!
+ Returns the size of this texture. If the underlying OpenGL
+ implementation requires texture sizes to be a power of two,
+ then this function will return the next power of two equal
+ to or greater than requestedSize()
+
+ \sa setSize(), requestedSize()
+*/
+QSize QGLTexture2D::size() const
+{
+ Q_D(const QGLTexture2D);
+ return d->size;
+}
+
+/*!
+ Sets the size of this texture to \a value. If the underlying
+ OpenGL implementation requires texture sizes to be a power of
+ two, then requestedSize() will be set to \a value, and the
+ actual size will be set to the next power of two equal
+ to or greater than \a value. Otherwise both size() and
+ requestedSize() will be set to \a value.
+
+ \sa size(), requestedSize()
+*/
+void QGLTexture2D::setSize(const QSize& value)
+{
+ Q_D(QGLTexture2D);
+ if (d->requestedSize == value)
+ return;
+ if (!(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
+ && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))
+ d->size = QGL::nextPowerOfTwo(value);
+ else
+ d->size = value;
+ d->requestedSize = value;
+ ++(d->imageGeneration);
+}
+
+/*!
+ Returns the size that was previously set with setSize() before
+ it was rounded to a power of two.
+
+ \sa size(), setSize()
+*/
+QSize QGLTexture2D::requestedSize() const
+{
+ Q_D(const QGLTexture2D);
+ return d->requestedSize;
+}
+
+/*!
+ Returns the image that is currently associated with this texture.
+ The image may not have been uploaded into the GL server yet.
+ Uploads occur upon the next call to bind().
+
+ \sa setImage()
+*/
+QImage QGLTexture2D::image() const
+{
+ Q_D(const QGLTexture2D);
+ return d->image;
+}
+
+/*!
+ Sets the \a image that is associated with this texture. The image
+ will be uploaded into the GL server the next time bind() is called.
+
+ If setSize() or setImage() has been called previously, then \a image
+ will be scaled to size() when it is uploaded.
+
+ If \a image is null, then this function is equivalent to clearImage().
+
+ \sa image(), setSize(), copyImage(), setPixmap()
+*/
+void QGLTexture2D::setImage(const QImage& image)
+{
+ Q_D(QGLTexture2D);
+ d->compressedData = QByteArray(); // Clear compressed file data.
+ if (image.isNull()) {
+ // Don't change the imageGeneration, because we aren't actually
+ // changing the image in the GL server, only the client copy.
+ d->image = image;
+ } else {
+ if (!d->size.isValid())
+ setSize(image.size());
+ d->image = image;
+ ++(d->imageGeneration);
+ }
+}
+
+/*!
+ Sets the image that is associated with this texture to \a pixmap.
+
+ This is a convenience that calls setImage() after converting
+ \a pixmap into a QImage. It may be more efficient on some
+ platforms than the application calling QPixmap::toImage().
+
+ \sa setImage()
+*/
+void QGLTexture2D::setPixmap(const QPixmap& pixmap)
+{
+ QImage image = pixmap.toImage();
+ if (pixmap.depth() == 16 && !image.hasAlphaChannel()) {
+ // If the system depth is 16 and the pixmap doesn't have an alpha channel
+ // then we convert it to RGB16 in the hope that it gets uploaded as a 16
+ // bit texture which is much faster to access than a 32-bit one.
+ image = image.convertToFormat(QImage::Format_RGB16);
+ }
+ setImage(image);
+}
+
+/*!
+ Clears the image() that is associated with this texture, but the
+ GL texture will retain its current value. This can be used to
+ release client-side memory that is no longer required once the
+ image has been uploaded into the GL server.
+
+ The following code will queue \c image to be uploaded, immediately
+ force it to be uploaded into the current GL context, and then
+ clear the client copy:
+
+ \code
+ texture.setImage(image);
+ texture.bind();
+ texture.clearImage()
+ \endcode
+
+ \sa image(), setImage()
+*/
+void QGLTexture2D::clearImage()
+{
+ Q_D(QGLTexture2D);
+ d->image = QImage();
+}
+
+#ifndef GL_GENERATE_MIPMAP_SGIS
+#define GL_GENERATE_MIPMAP_SGIS 0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
+#endif
+
+/*!
+ Sets this texture to the contents of a compressed image file
+ at \a path. Returns true if the file exists and has a supported
+ compressed format; false otherwise.
+
+ The DDS, ETC1, PVRTC2, and PVRTC4 compression formats are
+ supported, assuming that the GL implementation has the
+ appropriate extension.
+
+ \sa setImage(), setSize()
+*/
+bool QGLTexture2D::setCompressedFile(const QString &path)
+{
+ Q_D(QGLTexture2D);
+ d->image = QImage();
+ QFile f(path);
+ if (!f.open(QIODevice::ReadOnly))
+ {
+ qWarning("QGLTexture2D::setCompressedFile(%s): File could not be read",
+ qPrintable(path));
+ return false;
+ }
+ QByteArray data = f.readAll();
+ f.close();
+
+ bool hasAlpha, isFlipped;
+ if (!QGLBoundTexture::canBindCompressedTexture
+ (data.constData(), data.size(), 0, &hasAlpha, &isFlipped)) {
+ qWarning("QGLTexture2D::setCompressedFile(%s): Format is not supported",
+ path.toLocal8Bit().constData());
+ return false;
+ }
+
+ QFileInfo fi(path);
+ d->url = QUrl::fromLocalFile(fi.absoluteFilePath());
+
+ // The 3DS loader expects the flip state to be set before bind().
+ if (isFlipped)
+ d->bindOptions &= ~QGLContext::InvertedYBindOption;
+ else
+ d->bindOptions |= QGLContext::InvertedYBindOption;
+
+ d->compressedData = data;
+ ++(d->imageGeneration);
+ return true;
+}
+
+/*!
+ Returns the url that was last set with setUrl.
+*/
+QUrl QGLTexture2D::url() const
+{
+ Q_D(const QGLTexture2D);
+ return d->url;
+}
+
+/*!
+ Sets this texture to have the contents of the image stored at \a url.
+*/
+void QGLTexture2D::setUrl(const QUrl &url)
+{
+ Q_D(QGLTexture2D);
+ if (d->url == url)
+ return;
+ d->url = url;
+
+ if (url.isEmpty())
+ {
+ d->image = QImage();
+ }
+ else
+ {
+ if (url.scheme() == QLatin1String("file"))
+ {
+ QString fileName = url.toLocalFile();
+ if (fileName.endsWith(QLatin1String(".dds"), Qt::CaseInsensitive))
+ {
+ setCompressedFile(fileName);
+ }
+ else
+ {
+ QImage im(fileName);
+ if (im.isNull())
+ qWarning("Could not load texture: %s", qPrintable(fileName));
+ setImage(im);
+ }
+ }
+ else
+ {
+ qWarning("Network URLs not yet supported");
+ /*
+ if (d->textureReply)
+ d->textureReply->deleteLater();
+ QNetworkRequest req(d->textureUrl);
+ req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ d->textureReply = qmlEngine(this)->networkAccessManager()->get(req);
+ QObject::connect(d->textureReply, SIGNAL(finished()),
+ this, SLOT(textureRequestFinished()));
+ */
+ }
+ }
+}
+
+/*!
+ Copies the contents of \a image to \a offset in this texture
+ within the current GL context.
+
+ Unlike setImage(), this function copies the image data to the
+ GL server immediately using \c{glTexSubImage2D()}. This is typically
+ used to update the contents of a texture after it has been created.
+
+ It is assumed that the application has already called bind() on
+ this texture to bind it to the current GL context.
+
+ If the texture has been created in multiple contexts, only the
+ texture identifier for the current context will be updated.
+
+ \sa setImage(), bind()
+*/
+void QGLTexture2D::copyImage(const QImage& image, const QPoint& offset)
+{
+ QImage img = QGLWidget::convertToGLFormat(image);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x(), offset.y(),
+ img.width(), img.height(), GL_RGBA,
+ GL_UNSIGNED_BYTE, img.bits());
+#if defined(QT_OPENGL_ES_2)
+ Q_D(QGLTexture2D);
+ if (d->bindOptions & QGLContext::MipmapBindOption)
+ glGenerateMipmap(GL_TEXTURE_2D);
+#endif
+}
+
+/*!
+ Returns the options to use when binding the image() to an OpenGL
+ context for the first time. The default options are
+ QGLContext::LinearFilteringBindOption |
+ QGLContext::InvertedYBindOption | QGLContext::MipmapBindOption.
+
+ \sa setBindOptions()
+*/
+QGLContext::BindOptions QGLTexture2D::bindOptions() const
+{
+ Q_D(const QGLTexture2D);
+ return d->bindOptions;
+}
+
+/*!
+ Sets the \a options to use when binding the image() to an
+ OpenGL context. If the image() has already been bound,
+ then changing the options will cause it to be recreated
+ from image() the next time bind() is called.
+
+ \sa bindOptions(), bind()
+*/
+void QGLTexture2D::setBindOptions(QGLContext::BindOptions options)
+{
+ Q_D(QGLTexture2D);
+ if (d->bindOptions != options) {
+ d->bindOptions = options;
+ ++(d->imageGeneration);
+ }
+}
+
+/*!
+ Returns the wrapping mode for horizontal texture co-ordinates.
+ The default value is QGL::Repeat.
+
+ \sa setHorizontalWrap(), verticalWrap()
+*/
+QGL::TextureWrap QGLTexture2D::horizontalWrap() const
+{
+ Q_D(const QGLTexture2D);
+ return d->horizontalWrap;
+}
+
+/*!
+ Sets the wrapping mode for horizontal texture co-ordinates to \a value.
+
+ If \a value is not supported by the OpenGL implementation, it will be
+ replaced with a value that is supported. If the application desires a
+ very specific \a value, it can call horizontalWrap() to check that
+ the specific value was actually set.
+
+ The \a value will not be applied to the texture in the GL
+ server until the next call to bind().
+
+ \sa horizontalWrap(), setVerticalWrap()
+*/
+void QGLTexture2D::setHorizontalWrap(QGL::TextureWrap value)
+{
+ Q_D(QGLTexture2D);
+ value = qt_gl_modify_texture_wrap(value);
+ if (d->horizontalWrap != value) {
+ d->horizontalWrap = value;
+ ++(d->parameterGeneration);
+ }
+}
+
+/*!
+ Returns the wrapping mode for vertical texture co-ordinates.
+ The default value is QGL::Repeat.
+
+ \sa setVerticalWrap(), horizontalWrap()
+*/
+QGL::TextureWrap QGLTexture2D::verticalWrap() const
+{
+ Q_D(const QGLTexture2D);
+ return d->verticalWrap;
+}
+
+/*!
+ Sets the wrapping mode for vertical texture co-ordinates to \a value.
+
+ If \a value is not supported by the OpenGL implementation, it will be
+ replaced with a value that is supported. If the application desires a
+ very specific \a value, it can call verticalWrap() to check that
+ the specific value was actually set.
+
+ The \a value will not be applied to the texture in the GL
+ server until the next call to bind().
+
+ \sa verticalWrap(), setHorizontalWrap()
+*/
+void QGLTexture2D::setVerticalWrap(QGL::TextureWrap value)
+{
+ Q_D(QGLTexture2D);
+ value = qt_gl_modify_texture_wrap(value);
+ if (d->verticalWrap != value) {
+ d->verticalWrap = value;
+ ++(d->parameterGeneration);
+ }
+}
+
+/*!
+ Binds this texture to the 2D texture target.
+
+ If this texture object is not associated with an identifier in
+ the current context, then a new identifier will be created,
+ and image() uploaded into the GL server.
+
+ If setImage() or setSize() was called since the last upload,
+ then image() will be re-uploaded to the GL server.
+
+ Returns false if the texture could not be bound for some reason.
+
+ \sa release(), textureId(), setImage()
+*/
+bool QGLTexture2D::bind() const
+{
+ Q_D(const QGLTexture2D);
+ return const_cast<QGLTexture2DPrivate *>(d)->bind(GL_TEXTURE_2D);
+}
+
+bool QGLTexture2DPrivate::bind(GLenum target)
+{
+ // Get the current context. If we don't have one, then we
+ // cannot bind the texture.
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!ctx)
+ return false;
+
+ // Find the information block for the context, or create one.
+ QGLTexture2DTextureInfo *info = infos;
+ QGLTexture2DTextureInfo *prev = 0;
+ while (info != 0 && !QGLContext::areSharing(info->tex.context(), ctx)) {
+ if (info->isLiteral)
+ return false; // Cannot create extra texture id's for literals.
+ prev = info;
+ info = info->next;
+ }
+ if (!info) {
+ info = new QGLTexture2DTextureInfo
+ (ctx, 0, imageGeneration - 1, parameterGeneration - 1);
+ if (prev)
+ prev->next = info;
+ else
+ infos = info;
+ }
+
+ if (!info->tex.textureId() || imageGeneration != info->imageGeneration) {
+ // Create the texture contents and upload a new image.
+ info->tex.setOptions(bindOptions);
+ if (!compressedData.isEmpty()) {
+ info->tex.bindCompressedTexture
+ (compressedData.constData(), compressedData.size());
+ } else {
+ info->tex.startUpload(ctx, target, image.size());
+ bindImages(info);
+ info->tex.finishUpload(target);
+ }
+ info->imageGeneration = imageGeneration;
+ } else {
+ // Bind the existing texture to the texture target.
+ glBindTexture(target, info->tex.textureId());
+ }
+
+ // If the parameter generation has changed, then alter the parameters.
+ if (parameterGeneration != info->parameterGeneration) {
+ info->parameterGeneration = parameterGeneration;
+ q_glTexParameteri(target, GL_TEXTURE_WRAP_S, horizontalWrap);
+ q_glTexParameteri(target, GL_TEXTURE_WRAP_T, verticalWrap);
+ }
+
+ // Texture is ready to be used.
+ return true;
+}
+
+void QGLTexture2DPrivate::bindImages(QGLTexture2DTextureInfo *info)
+{
+ QSize scaledSize(size);
+#if defined(QT_OPENGL_ES_2)
+ if ((bindOptions & QGLContext::MipmapBindOption) ||
+ horizontalWrap != QGL::ClampToEdge ||
+ verticalWrap != QGL::ClampToEdge) {
+ // ES 2.0 does not support NPOT textures when mipmaps are in use,
+ // or if the wrap mode isn't ClampToEdge.
+ scaledSize = QGL::nextPowerOfTwo(scaledSize);
+ }
+#endif
+ if (!image.isNull())
+ info->tex.uploadFace(GL_TEXTURE_2D, image, scaledSize);
+ else if (size.isValid())
+ info->tex.createFace(GL_TEXTURE_2D, scaledSize);
+}
+
+/*!
+ Releases the texture associated with the 2D texture target.
+ This is equivalent to \c{glBindTexture(GL_TEXTURE_2D, 0)}.
+
+ \sa bind()
+*/
+void QGLTexture2D::release() const
+{
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+/*!
+ Returns the identifier associated with this texture object in
+ the current context.
+
+ Returns zero if the texture has not previously been bound to
+ the 2D texture target in the current context with bind().
+
+ \sa bind()
+*/
+GLuint QGLTexture2D::textureId() const
+{
+ Q_D(const QGLTexture2D);
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!ctx)
+ return 0;
+ QGLTexture2DTextureInfo *info = d->infos;
+ while (info != 0 && !QGLContext::areSharing(info->tex.context(), ctx))
+ info = info->next;
+ return info ? info->tex.textureId() : 0;
+}
+
+/*!
+ Constructs a QGLTexture2D object that wraps the supplied literal
+ texture identifier \a id, with the dimensions specified by \a size.
+
+ The \a id is assumed to have been created by the application in
+ the current GL context, and it will be destroyed by the application
+ after the returned QGLTexture2D object is destroyed.
+
+ This function is intended for interfacing to existing code that
+ uses raw GL texture identifiers. The returned QGLTexture2D can
+ only be used with the current GL context.
+
+ \sa textureId()
+*/
+QGLTexture2D *QGLTexture2D::fromTextureId(GLuint id, const QSize& size)
+{
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!id || !ctx)
+ return 0;
+
+ QGLTexture2D *texture = new QGLTexture2D();
+ if (!size.isNull())
+ texture->setSize(size);
+ QGLTexture2DTextureInfo *info = new QGLTexture2DTextureInfo
+ (ctx, id, texture->d_ptr->imageGeneration,
+ texture->d_ptr->parameterGeneration, true);
+ texture->d_ptr->infos = info;
+ return texture;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/textures/qgltexture2d.h b/src/threed/textures/qgltexture2d.h
new file mode 100644
index 000000000..5379c6dfa
--- /dev/null
+++ b/src/threed/textures/qgltexture2d.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTEXTURE2D_H
+#define QGLTEXTURE2D_H
+
+#include "qglnamespace.h"
+#include <QtOpenGL/qgl.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLTexture2DPrivate;
+
+class Q_QT3D_EXPORT QGLTexture2D : public QObject
+{
+ Q_OBJECT
+public:
+ QGLTexture2D(QObject *parent = 0);
+ ~QGLTexture2D();
+
+ bool isNull() const;
+ bool hasAlphaChannel() const;
+
+ QSize size() const;
+ void setSize(const QSize& value);
+ QSize requestedSize() const;
+
+ QImage image() const;
+ void setImage(const QImage& image);
+ bool setCompressedFile(const QString &path);
+ QUrl url() const;
+ void setUrl(const QUrl &url);
+
+ void setPixmap(const QPixmap& pixmap);
+
+ void clearImage();
+
+ void copyImage(const QImage& image, const QPoint& offset = QPoint(0, 0));
+
+ QGLContext::BindOptions bindOptions() const;
+ void setBindOptions(QGLContext::BindOptions options);
+
+ QGL::TextureWrap horizontalWrap() const;
+ void setHorizontalWrap(QGL::TextureWrap value);
+
+ QGL::TextureWrap verticalWrap() const;
+ void setVerticalWrap(QGL::TextureWrap value);
+
+ bool bind() const;
+ void release() const;
+
+ GLuint textureId() const;
+
+ static QGLTexture2D *fromTextureId(GLuint id, const QSize& size);
+
+private:
+ QScopedPointer<QGLTexture2DPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGLTexture2D)
+ Q_DECLARE_PRIVATE(QGLTexture2D)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/textures/qgltexture2d_p.h b/src/threed/textures/qgltexture2d_p.h
new file mode 100644
index 000000000..d226751bd
--- /dev/null
+++ b/src/threed/textures/qgltexture2d_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTEXTURE2D_P_H
+#define QGLTEXTURE2D_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgltexture2d.h"
+#include "qgltextureutils_p.h"
+#include "qurl.h"
+
+#include <QtCore/qatomic.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLTexture2DTextureInfo
+{
+public:
+ QGLTexture2DTextureInfo
+ (const QGLContext *context, GLuint textureId, uint imageGeneration,
+ uint parameterGeneration, bool isLiteral = false)
+ {
+ if (textureId)
+ tex.setTextureId(context, textureId);
+ this->imageGeneration = imageGeneration;
+ this->parameterGeneration = parameterGeneration;
+ this->isLiteral = isLiteral;
+ this->next = 0;
+ }
+
+ QGLBoundTexture tex;
+ uint imageGeneration;
+ uint parameterGeneration;
+ bool isLiteral;
+ QGLTexture2DTextureInfo *next;
+};
+
+class DDSFormat;
+
+class QGLTexture2DPrivate
+{
+public:
+ QGLTexture2DPrivate();
+ ~QGLTexture2DPrivate();
+
+ QSize size;
+ QSize requestedSize;
+ QImage image;
+ QUrl url;
+ QByteArray compressedData;
+ QGLContext::BindOptions bindOptions;
+ QGL::TextureWrap horizontalWrap;
+ QGL::TextureWrap verticalWrap;
+#if !defined(QT_OPENGL_ES)
+ bool mipmapSupported;
+ bool mipmapSupportedKnown;
+#endif
+ uint imageGeneration;
+ uint parameterGeneration;
+ QGLTexture2DTextureInfo *infos;
+
+ bool bind(GLenum target);
+ virtual void bindImages(QGLTexture2DTextureInfo *info);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/threed/textures/qgltexturecube.cpp b/src/threed/textures/qgltexturecube.cpp
new file mode 100644
index 000000000..9947d1b65
--- /dev/null
+++ b/src/threed/textures/qgltexturecube.cpp
@@ -0,0 +1,549 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgltexturecube.h"
+#include "qgltexture2d_p.h"
+#include "qgltextureutils_p.h"
+#include "qglpainter_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLTextureCube
+ \brief The QGLTextureCube class represents a cube map texture object for GL painting operations.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::textures
+
+ QGLTextureCube contains six QImage objects for each of the cube
+ map faces and settings for texture filters, wrap modes, and mipmap
+ generation. When bind() is called, this information is uploaded to
+ the GL server if it has changed since the last time bind() was called.
+
+ Once a QGLTextureCube object is created, it can be bound to multiple
+ GL contexts. Internally, a separate texture identifier is created
+ for each context. This makes QGLTextureCube easier to use than
+ raw GL texture identifiers because the application does not need
+ to be as concerned with whether the texture identifier is valid
+ in the current context. The application merely calls bind() and
+ QGLTextureCube will create a new texture identifier for the context
+ if necessary.
+
+ QGLTextureCube internally points to a reference-counted object that
+ represents the current texture state. If the QGLTextureCube is copied,
+ the internal pointer is the same. Modifications to one QGLTextureCube
+ copy will affect all of the other copies in the system.
+
+ The texture identifiers will be destroyed when the last QGLTextureCube
+ reference is destroyed, or when a context is destroyed that contained a
+ texture identifier that was created by QGLTextureCube.
+
+ \sa QGLTexture2D
+*/
+
+/*!
+ \enum QGLTextureCube::Face
+ This enum defines the face of a cube map texture that is affected
+ by a texture operation on QGLTextureCube instances.
+
+ \value PositiveX The positive X face of the cube map.
+ \value NegativeX The negative X face of the cube map.
+ \value PositiveY The positive Y face of the cube map.
+ \value NegativeY The negative Y face of the cube map.
+ \value PositiveZ The positive Z face of the cube map.
+ \value NegativeZ The negative Z face of the cube map.
+*/
+
+class QGLTextureCubePrivate : public QGLTexture2DPrivate
+{
+public:
+ QGLTextureCubePrivate();
+ ~QGLTextureCubePrivate();
+
+ void bindImages(QGLTexture2DTextureInfo *info);
+
+ QImage otherImages[5];
+ uint changedFaces;
+};
+
+QGLTextureCubePrivate::QGLTextureCubePrivate()
+{
+ changedFaces = 0;
+}
+
+QGLTextureCubePrivate::~QGLTextureCubePrivate()
+{
+}
+
+void QGLTextureCubePrivate::bindImages(QGLTexture2DTextureInfo *info)
+{
+ QSize scaledSize(size);
+#if defined(QT_OPENGL_ES_2)
+ if ((bindOptions & QGLContext::MipmapBindOption) ||
+ horizontalWrap != QGL::ClampToEdge ||
+ verticalWrap != QGL::ClampToEdge) {
+ // ES 2.0 does not support NPOT textures when mipmaps are in use,
+ // or if the wrap mode isn't ClampToEdge.
+ scaledSize = QGL::nextPowerOfTwo(scaledSize);
+ }
+#endif
+
+ // Handle the first face.
+ if (!image.isNull())
+ info->tex.uploadFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X, image, scaledSize);
+ else if (size.isValid())
+ info->tex.createFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X, scaledSize);
+
+ // Handle the other faces.
+ for (int face = 1; face < 6; ++face) {
+ if (!otherImages[face - 1].isNull()) {
+ info->tex.uploadFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
+ otherImages[face - 1], scaledSize);
+ } else {
+ info->tex.createFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, scaledSize);
+ }
+ }
+}
+
+/*!
+ Constructs a null texture object.
+
+ \sa isNull()
+*/
+QGLTextureCube::QGLTextureCube()
+ : d_ptr(new QGLTextureCubePrivate())
+{
+}
+
+/*!
+ Destroys this texture object. If this object is the last
+ reference to the underlying GL texture, then the underlying
+ GL texture will also be deleted.
+*/
+QGLTextureCube::~QGLTextureCube()
+{
+}
+
+/*!
+ Returns true if this texture object is null; that is, all image()
+ values are null and textureId() is zero.
+*/
+bool QGLTextureCube::isNull() const
+{
+ // TODO
+ Q_D(const QGLTextureCube);
+ return !d->infos;
+}
+
+/*!
+ Returns true if this texture has an alpha channel; false if the
+ texture is fully opaque.
+*/
+bool QGLTextureCube::hasAlphaChannel() const
+{
+ Q_D(const QGLTextureCube);
+ if (!d->image.isNull() && d->image.hasAlphaChannel())
+ return true;
+ for (int face = 0; face < 5; ++face) {
+ if (!d->otherImages[face].isNull()) {
+ if (d->otherImages[face].hasAlphaChannel())
+ return true;
+ }
+ }
+ QGLTexture2DTextureInfo *info = d->infos;
+ if (info)
+ return info->tex.hasAlpha();
+ return false;
+}
+
+/*!
+ Returns the size of this texture. If the underlying OpenGL
+ implementation requires texture sizes to be a power of two,
+ then this function will return the next power of two equal
+ to or greater than requestedSize()
+
+ \sa setSize(), requestedSize()
+*/
+QSize QGLTextureCube::size() const
+{
+ Q_D(const QGLTextureCube);
+ return d->size;
+}
+
+/*!
+ Sets the size of this texture to \a value. If the underlying
+ OpenGL implementation requires texture sizes to be a power of
+ two, then requestedSize() will be set to \a value, and the
+ actual size will be set to the next power of two equal
+ to or greater than \a value. Otherwise both size() and
+ requestedSize() will be set to \a value.
+
+ \sa size(), requestedSize()
+*/
+void QGLTextureCube::setSize(const QSize& value)
+{
+ Q_D(QGLTextureCube);
+ if (d->requestedSize == value)
+ return;
+ if (!(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) &&
+ !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))
+ d->size = QGL::nextPowerOfTwo(value);
+ else
+ d->size = value;
+ d->requestedSize = value;
+ ++(d->imageGeneration);
+}
+
+/*!
+ Returns the size that was previously set with setSize() before
+ it was rounded to a power of two.
+
+ \sa size(), setSize()
+*/
+QSize QGLTextureCube::requestedSize() const
+{
+ Q_D(const QGLTextureCube);
+ return d->requestedSize;
+}
+
+/*!
+ Returns the image that is currently associated with the specified
+ \a face of this cube map texture. The image may not have been
+ uploaded into the GL server yet. Uploads occur upon the next
+ call to bind().
+
+ \sa setImage()
+*/
+QImage QGLTextureCube::image(QGLTextureCube::Face face) const
+{
+ Q_D(const QGLTextureCube);
+ if (uint(face) >= 6)
+ return QImage();
+ if (face == 0)
+ return d->image;
+ else
+ return d->otherImages[face - 1];
+}
+
+/*!
+ Sets the \a image that is associated with this texture on the
+ specified \a face of the cube map. The image will be uploaded
+ into the GL server the next time bind() is called.
+
+ If setSize() or setImage() has been called previously, then \a image
+ will be scaled to size() when it is uploaded.
+
+ If \a image is null, then this function is equivalent to clearImage().
+
+ \sa image(), setSize(), copyImage()
+*/
+void QGLTextureCube::setImage
+ (QGLTextureCube::Face face, const QImage& image)
+{
+ Q_D(QGLTextureCube);
+ if (uint(face) >= 6)
+ return;
+ if (image.isNull()) {
+ // Don't change the imageGeneration, because we aren't actually
+ // changing the image in the GL server, only the client copy.
+ if (face == 0)
+ d->image = image;
+ else
+ d->otherImages[face - 1] = image;
+ } else {
+ if (!d->size.isValid())
+ setSize(image.size());
+ if (face == 0)
+ d->image = image;
+ else
+ d->otherImages[face - 1] = image;
+ ++(d->imageGeneration);
+ d->changedFaces |= (1 << face);
+ }
+}
+
+/*!
+ Clears the image() that is associated with this texture on the
+ specified \a face of the cube map. The GL texture will retain
+ its current value. This can be used to release client-side memory
+ that is no longer required once the image has been uploaded into
+ the GL server.
+
+ The following code will queue \c image to be uploaded as the
+ positive X face of the cube map, immediately force it to
+ be uploaded into the current GL context, and then clear the
+ client copy:
+
+ \code
+ texture.setImage(QGLTextureCube::PositiveX, image);
+ texture.bind();
+ texture.clearImage(QGLTextureCube::PositiveX);
+ \endcode
+
+ \sa image(), setImage()
+*/
+void QGLTextureCube::clearImage(QGLTextureCube::Face face)
+{
+ Q_D(QGLTextureCube);
+ if (face == 0)
+ d->image = QImage();
+ else
+ d->otherImages[face - 1] = QImage();
+}
+
+/*!
+ Copies the contents of \a image to \a offset in this texture
+ within the current GL context. The \a face parameter indicates
+ which face of the cube map should be altered.
+
+ Unlike setImage(), this function copies the image data to the
+ GL server immediately using \c{glTexSubImage2D()}. This is typically
+ used to update the contents of a texture after it has been created.
+
+ It is assumed that the application has already called bind() on
+ this texture to bind it to the current GL context.
+
+ If the texture has been created in multiple contexts, only the
+ texture identifier for the current context will be updated.
+
+ \sa setImage(), bind()
+*/
+void QGLTextureCube::copyImage
+ (QGLTextureCube::Face face, const QImage& image, const QPoint& offset)
+{
+ if (uint(face) >= 6)
+ return; // Invalid face number.
+ QImage img = QGLWidget::convertToGLFormat(image);
+ glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + int(face),
+ 0, offset.x(), offset.y(),
+ img.width(), img.height(), GL_RGBA,
+ GL_UNSIGNED_BYTE, img.bits());
+#if defined(QT_OPENGL_ES_2)
+ Q_D(QGLTextureCube);
+ if (d->bindOptions & QGLContext::MipmapBindOption)
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+#endif
+}
+
+/*!
+ Returns the options to use when binding the image() to an OpenGL
+ context for the first time. The default options are
+ QGLContext::LinearFilteringBindOption |
+ QGLContext::InvertedYBindOption | QGLContext::MipmapBindOption.
+
+ \sa setBindOptions()
+*/
+QGLContext::BindOptions QGLTextureCube::bindOptions() const
+{
+ Q_D(const QGLTextureCube);
+ return d->bindOptions;
+}
+
+/*!
+ Sets the \a options to use when binding the image() to an
+ OpenGL context. If the image() has already been bound,
+ then changing the options will cause it to be recreated
+ from image() the next time bind() is called.
+
+ \sa bindOptions(), bind()
+*/
+void QGLTextureCube::setBindOptions(QGLContext::BindOptions options)
+{
+ Q_D(QGLTextureCube);
+ if (d->bindOptions != options) {
+ d->bindOptions = options;
+ ++(d->imageGeneration);
+ }
+}
+
+/*!
+ Returns the wrapping mode for horizontal texture co-ordinates.
+ The default value is QGL::Repeat.
+
+ \sa setHorizontalWrap(), verticalWrap()
+*/
+QGL::TextureWrap QGLTextureCube::horizontalWrap() const
+{
+ Q_D(const QGLTextureCube);
+ return d->horizontalWrap;
+}
+
+/*!
+ Sets the wrapping mode for horizontal texture co-ordinates to \a value.
+
+ If \a value is not supported by the OpenGL implementation, it will be
+ replaced with a value that is supported. If the application desires a
+ very specific \a value, it can call horizontalWrap() to check that
+ the specific value was actually set.
+
+ The \a value will not be applied to the texture in the GL
+ server until the next call to bind().
+
+ \sa horizontalWrap(), setVerticalWrap()
+*/
+void QGLTextureCube::setHorizontalWrap(QGL::TextureWrap value)
+{
+ Q_D(QGLTextureCube);
+ value = qt_gl_modify_texture_wrap(value);
+ if (d->horizontalWrap != value) {
+ d->horizontalWrap = value;
+ ++(d->parameterGeneration);
+ }
+}
+
+/*!
+ Returns the wrapping mode for vertical texture co-ordinates.
+ The default value is QGL::Repeat.
+
+ \sa setVerticalWrap(), horizontalWrap()
+*/
+QGL::TextureWrap QGLTextureCube::verticalWrap() const
+{
+ Q_D(const QGLTextureCube);
+ return d->verticalWrap;
+}
+
+/*!
+ Sets the wrapping mode for vertical texture co-ordinates to \a value.
+
+ If \a value is not supported by the OpenGL implementation, it will be
+ replaced with a value that is supported. If the application desires a
+ very specific \a value, it can call verticalWrap() to check that
+ the specific value was actually set.
+
+ The \a value will not be applied to the texture in the GL
+ server until the next call to bind().
+
+ \sa verticalWrap(), setHorizontalWrap()
+*/
+void QGLTextureCube::setVerticalWrap(QGL::TextureWrap value)
+{
+ Q_D(QGLTextureCube);
+ value = qt_gl_modify_texture_wrap(value);
+ if (d->verticalWrap != value) {
+ d->verticalWrap = value;
+ ++(d->parameterGeneration);
+ }
+}
+
+/*!
+ Binds this texture to the cube map texture target.
+
+ If this texture object is not associated with an identifier in
+ the current context, then a new identifier will be created,
+ and the face images will be uploaded into the GL server.
+
+ If setImage() or setSize() was called since the last upload,
+ then the face images will be re-uploaded to the GL server.
+
+ Returns false if the texture could not be bound for some reason.
+
+ \sa release(), textureId(), setImage()
+*/
+bool QGLTextureCube::bind() const
+{
+ Q_D(const QGLTextureCube);
+ return const_cast<QGLTextureCubePrivate *>(d)->bind(GL_TEXTURE_CUBE_MAP);
+}
+
+/*!
+ Releases the texture associated with the cube map texture target.
+ This is equivalent to \c{glBindTexture(GL_TEXTURE_CUBE_MAP, 0)}.
+
+ \sa bind()
+*/
+void QGLTextureCube::release()
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+}
+
+/*!
+ Returns the identifier associated with this texture object in
+ the current context.
+
+ Returns zero if the texture has not previously been bound to
+ the 2D texture target in the current context with bind().
+
+ \sa bind()
+*/
+GLuint QGLTextureCube::textureId() const
+{
+ Q_D(const QGLTextureCube);
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!ctx)
+ return 0;
+ QGLTexture2DTextureInfo *info = d->infos;
+ while (info != 0 && info->tex.context() != ctx)
+ info = info->next;
+ return info ? info->tex.textureId() : 0;
+}
+
+/*!
+ Constructs a QGLTextureCube object that wraps the supplied literal
+ texture identifier \a id, with the dimensions specified by \a size.
+
+ The \a id is assumed to have been created by the application in
+ the current GL context, and it will be destroyed by the application
+ after the returned QGLTextureCube object is destroyed.
+
+ This function is intended for interfacing to existing code that
+ uses raw GL texture identifiers. The returned QGLTextureCube can
+ only be used with the current GL context.
+
+ \sa textureId()
+*/
+QGLTextureCube *QGLTextureCube::fromTextureId(GLuint id, const QSize& size)
+{
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!id || !ctx)
+ return 0;
+
+ QGLTextureCube *texture = new QGLTextureCube();
+ if (!size.isNull())
+ texture->setSize(size);
+ QGLTexture2DTextureInfo *info = new QGLTexture2DTextureInfo
+ (ctx, id, texture->d_ptr->imageGeneration,
+ texture->d_ptr->parameterGeneration, true);
+ texture->d_ptr->infos = info;
+ return texture;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/textures/qgltexturecube.h b/src/threed/textures/qgltexturecube.h
new file mode 100644
index 000000000..dfa445abc
--- /dev/null
+++ b/src/threed/textures/qgltexturecube.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTEXTURECUBEMAP_H
+#define QGLTEXTURECUBEMAP_H
+
+#include "qglnamespace.h"
+#include <QtOpenGL/qgl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLTextureCubePrivate;
+
+class Q_QT3D_EXPORT QGLTextureCube
+{
+public:
+ QGLTextureCube();
+ ~QGLTextureCube();
+
+ enum Face
+ {
+ PositiveX,
+ NegativeX,
+ PositiveY,
+ NegativeY,
+ PositiveZ,
+ NegativeZ
+ };
+
+ bool isNull() const;
+ bool hasAlphaChannel() const;
+
+ QSize size() const;
+ void setSize(const QSize& value);
+ QSize requestedSize() const;
+
+ QImage image(QGLTextureCube::Face face) const;
+ void setImage(QGLTextureCube::Face face, const QImage& image);
+ void clearImage(QGLTextureCube::Face face);
+
+ void copyImage(QGLTextureCube::Face face, const QImage& image, const QPoint& offset = QPoint(0, 0));
+
+ QGLContext::BindOptions bindOptions() const;
+ void setBindOptions(QGLContext::BindOptions options);
+
+ QGL::TextureWrap horizontalWrap() const;
+ void setHorizontalWrap(QGL::TextureWrap value);
+
+ QGL::TextureWrap verticalWrap() const;
+ void setVerticalWrap(QGL::TextureWrap value);
+
+ bool bind() const;
+ static void release();
+
+ GLuint textureId() const;
+
+ static QGLTextureCube *fromTextureId(GLuint id, const QSize& size);
+
+private:
+ QScopedPointer<QGLTextureCubePrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGLTextureCube)
+ Q_DECLARE_PRIVATE(QGLTextureCube)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/textures/qgltextureutils.cpp b/src/threed/textures/qgltextureutils.cpp
new file mode 100644
index 000000000..47c5de489
--- /dev/null
+++ b/src/threed/textures/qgltextureutils.cpp
@@ -0,0 +1,785 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgltextureutils_p.h"
+#include "qglext_p.h"
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+QGL::TextureWrap qt_gl_modify_texture_wrap(QGL::TextureWrap value)
+{
+ switch (value) {
+#if defined(QT_OPENGL_ES)
+ case QGL::Clamp:
+ value = QGL::ClampToEdge;
+ break;
+#endif
+#if !defined(QT_OPENGL_ES)
+ case QGL::ClampToBorder:
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_3)
+ == 0)
+ value = QGL::Clamp;
+ break;
+#else
+ case QGL::ClampToBorder:
+ value = QGL::ClampToEdge;
+ break;
+#endif
+#if !defined(QT_OPENGL_ES)
+ case QGL::ClampToEdge:
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
+ == 0)
+ value = QGL::Clamp;
+ break;
+#endif
+#if !defined(QT_OPENGL_ES)
+ case QGL::MirroredRepeat:
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_4)
+ == 0)
+ value = QGL::Repeat;
+ break;
+#elif !defined(QT_OPENGL_ES_2)
+ case QGL::MirroredRepeat:
+ value = QGL::Repeat;
+ break;
+#endif
+ default: break;
+ }
+ return value;
+}
+
+QGLTextureExtensions::QGLTextureExtensions(const QGLContext *ctx)
+ : npotTextures(false)
+ , generateMipmap(false)
+ , bgraTextureFormat(false)
+ , ddsTextureCompression(false)
+ , etc1TextureCompression(false)
+ , pvrtcTextureCompression(false)
+ , compressedTexImage2D(0)
+{
+ Q_UNUSED(ctx);
+ QGLExtensionChecker extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
+ if (extensions.match("GL_ARB_texture_non_power_of_two"))
+ npotTextures = true;
+ if (extensions.match("GL_SGIS_generate_mipmap"))
+ generateMipmap = true;
+ if (extensions.match("GL_EXT_bgra"))
+ bgraTextureFormat = true;
+ if (extensions.match("GL_EXT_texture_compression_s3tc"))
+ ddsTextureCompression = true;
+ if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture"))
+ etc1TextureCompression = true;
+ if (extensions.match("GL_IMG_texture_compression_pvrtc"))
+ pvrtcTextureCompression = true;
+#if defined(QT_OPENGL_ES_2)
+ npotTextures = true;
+ generateMipmap = true;
+#endif
+#if !defined(QT_OPENGL_ES)
+ if (extensions.match("GL_ARB_texture_compression")) {
+ compressedTexImage2D = (q_glCompressedTexImage2DARB)
+ ctx->getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
+ }
+#else
+ compressedTexImage2D = glCompressedTexImage2D;
+#endif
+}
+
+QGLTextureExtensions::~QGLTextureExtensions()
+{
+}
+
+Q_GLOBAL_STATIC(QGLResource<QGLTextureExtensions>, qt_gl_texture_extensions)
+
+QGLTextureExtensions *QGLTextureExtensions::extensions()
+{
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (!ctx)
+ return 0;
+ return qt_gl_texture_extensions()->value(ctx);
+}
+
+static void qt_gl_destroyTextureId(GLuint id)
+{
+ glDeleteTextures(1, &id);
+}
+
+QGLBoundTexture::QGLBoundTexture()
+ : m_resource(qt_gl_destroyTextureId)
+ , m_options(QGLContext::DefaultBindOption)
+ , m_hasAlpha(false)
+{
+}
+
+QGLBoundTexture::~QGLBoundTexture()
+{
+}
+
+// #define QGL_BIND_TEXTURE_DEBUG
+
+void QGLBoundTexture::startUpload(const QGLContext *ctx, GLenum target, const QSize &imageSize)
+{
+ Q_UNUSED(imageSize);
+
+ QGLTextureExtensions *extensions = QGLTextureExtensions::extensions();
+ if (!extensions)
+ return;
+
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf("QGLBoundTexture::startUpload(), imageSize=(%d,%d), options=%x\n",
+ imageSize.width(), imageSize.height(), int(m_options));
+ time.start();
+#endif
+
+#ifndef QT_NO_DEBUG
+ // Reset the gl error stack...
+ while (glGetError() != GL_NO_ERROR) ;
+#endif
+
+ // Create the texture id for the target, which should be one of
+ // GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
+ GLuint id = m_resource.id();
+ if (id) {
+ glBindTexture(target, 0); // Just in case texture is bound.
+ m_resource.destroy();
+ }
+ id = 0;
+ glGenTextures(1, &id);
+ glBindTexture(target, id);
+ m_resource.attach(ctx, id);
+
+ GLuint filtering = m_options & QGLContext::LinearFilteringBindOption ? GL_LINEAR : GL_NEAREST;
+
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - setting options (%d ms)\n", time.elapsed());
+#endif
+ q_glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filtering);
+
+ if (QGLContext::currentContext()->format().directRendering()
+ && extensions->generateMipmap
+ && (m_options & QGLContext::MipmapBindOption))
+ {
+#if !defined(QT_OPENGL_ES_2)
+ glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
+ q_glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
+#else
+ glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
+#endif
+ q_glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
+ m_options & QGLContext::LinearFilteringBindOption
+ ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST);
+ } else {
+ q_glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filtering);
+ m_options &= ~QGLContext::MipmapBindOption;
+ }
+}
+
+// map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout
+static inline void qt_gl_byteSwapImage(QImage &img, GLenum pixel_type)
+{
+ const int width = img.width();
+ const int height = img.height();
+
+ if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
+ || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian))
+ {
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
+ }
+ } else {
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
+ }
+ }
+}
+
+// #define QGL_BIND_TEXTURE_DEBUG
+
+void QGLBoundTexture::uploadFace
+ (GLenum target, const QImage &image, const QSize &scaleSize, GLenum format)
+{
+ GLenum internalFormat(format);
+
+ // Resolve the texture-related extensions for the current context.
+ QGLTextureExtensions *extensions = QGLTextureExtensions::extensions();
+ if (!extensions)
+ return;
+
+ // Adjust the image size for scaling and power of two.
+ QSize size = (!scaleSize.isEmpty() ? scaleSize : image.size());
+ if (!extensions->npotTextures)
+ size = QGL::nextPowerOfTwo(size);
+ QImage img(image);
+ if (size != image.size()) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - scaling up to %dx%d (%d ms) \n", size.width(), size.height(), time.elapsed());
+#endif
+ img = img.scaled(size);
+ }
+ m_size = size;
+
+ QImage::Format target_format = img.format();
+ bool premul = m_options & QGLContext::PremultipliedAlphaBindOption;
+ GLenum externalFormat;
+ GLuint pixel_type;
+ if (extensions->bgraTextureFormat) {
+ externalFormat = GL_BGRA;
+ if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
+ pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ else
+ pixel_type = GL_UNSIGNED_BYTE;
+ } else {
+ externalFormat = GL_RGBA;
+ pixel_type = GL_UNSIGNED_BYTE;
+ }
+
+ switch (target_format) {
+ case QImage::Format_ARGB32:
+ if (premul) {
+ img = img.convertToFormat(target_format = QImage::Format_ARGB32_Premultiplied);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting ARGB32 -> ARGB32_Premultiplied (%d ms) \n", time.elapsed());
+#endif
+ }
+ break;
+ case QImage::Format_ARGB32_Premultiplied:
+ if (!premul) {
+ img = img.convertToFormat(target_format = QImage::Format_ARGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting ARGB32_Premultiplied -> ARGB32 (%d ms)\n", time.elapsed());
+#endif
+ }
+ break;
+ case QImage::Format_RGB16:
+ pixel_type = GL_UNSIGNED_SHORT_5_6_5;
+ externalFormat = GL_RGB;
+ internalFormat = GL_RGB;
+ break;
+ case QImage::Format_RGB32:
+ break;
+ default:
+ if (img.hasAlphaChannel()) {
+ img = img.convertToFormat(premul
+ ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_ARGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting to 32-bit alpha format (%d ms)\n", time.elapsed());
+#endif
+ } else {
+ img = img.convertToFormat(QImage::Format_RGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting to 32-bit (%d ms)\n", time.elapsed());
+#endif
+ }
+ }
+
+ if (m_options & QGLContext::InvertedYBindOption) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - flipping bits over y (%d ms)\n", time.elapsed());
+#endif
+ if (img.isDetached()) {
+ int ipl = img.bytesPerLine() / 4;
+ int h = img.height();
+ for (int y=0; y<h/2; ++y) {
+ int *a = (int *) img.scanLine(y);
+ int *b = (int *) img.scanLine(h - y - 1);
+ for (int x=0; x<ipl; ++x)
+ qSwap(a[x], b[x]);
+ }
+ } else {
+ // Create a new image and copy across. If we use the
+ // above in-place code then a full copy of the image is
+ // made before the lines are swapped, which processes the
+ // data twice. This version should only do it once.
+ img = img.mirrored();
+ }
+ }
+
+ if (externalFormat == GL_RGBA) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - doing byte swapping (%d ms)\n", time.elapsed());
+#endif
+ // The only case where we end up with a depth different from
+ // 32 in the switch above is for the RGB16 case, where we set
+ // the format to GL_RGB
+ Q_ASSERT(img.depth() == 32);
+ qt_gl_byteSwapImage(img, pixel_type);
+ }
+#ifdef QT_OPENGL_ES
+ // OpenGL/ES requires that the internal and external formats be
+ // identical.
+ internalFormat = externalFormat;
+#endif
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n",
+ img.format(), externalFormat, internalFormat, pixel_type);
+#endif
+
+ const QImage &constRef = img; // to avoid detach in bits()...
+ glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat,
+ pixel_type, constRef.bits());
+
+ m_hasAlpha = (internalFormat != GL_RGB);
+}
+
+void QGLBoundTexture::createFace
+ (GLenum target, const QSize &size, GLenum format)
+{
+ glTexImage2D(target, 0, format, size.width(),
+ size.height(), 0, format, GL_UNSIGNED_BYTE, 0);
+ m_hasAlpha = (format != GL_RGB);
+}
+
+void QGLBoundTexture::finishUpload(GLenum target)
+{
+ Q_UNUSED(target);
+
+#if defined(QT_OPENGL_ES_2)
+ // OpenGL/ES 2.0 needs to generate mipmaps after all cubemap faces
+ // have been uploaded.
+ if (m_options & QGLContext::MipmapBindOption) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - generating mipmaps (%d ms)\n", time.elapsed());
+#endif
+ glGenerateMipmap(target);
+ }
+#endif
+
+#ifndef QT_NO_DEBUG
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ qWarning(" - texture upload failed, error code 0x%x, enum: %d (%x)\n", error, target, target);
+ }
+#endif
+
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ static int totalUploadTime = 0;
+ totalUploadTime += time.elapsed();
+ printf(" - upload done in (%d ms) time=%d\n", time.elapsed(), totalUploadTime);
+#endif
+}
+
+// DDS format structure
+struct DDSFormat {
+ quint32 dwSize;
+ quint32 dwFlags;
+ quint32 dwHeight;
+ quint32 dwWidth;
+ quint32 dwLinearSize;
+ quint32 dummy1;
+ quint32 dwMipMapCount;
+ quint32 dummy2[11];
+ struct {
+ quint32 dummy3[2];
+ quint32 dwFourCC;
+ quint32 dummy4[5];
+ } ddsPixelFormat;
+};
+
+// compressed texture pixel formats
+#define FOURCC_DXT1 0x31545844
+#define FOURCC_DXT2 0x32545844
+#define FOURCC_DXT3 0x33545844
+#define FOURCC_DXT4 0x34545844
+#define FOURCC_DXT5 0x35545844
+
+#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+#endif
+
+// PVR header format for container files that store textures compressed
+// with the ETC1, PVRTC2, and PVRTC4 encodings. Format information from the
+// PowerVR SDK at http://www.imgtec.com/powervr/insider/powervr-sdk.asp
+// "PVRTexTool Reference Manual, version 1.11f".
+struct PvrHeader
+{
+ quint32 headerSize;
+ quint32 height;
+ quint32 width;
+ quint32 mipMapCount;
+ quint32 flags;
+ quint32 dataSize;
+ quint32 bitsPerPixel;
+ quint32 redMask;
+ quint32 greenMask;
+ quint32 blueMask;
+ quint32 alphaMask;
+ quint32 magic;
+ quint32 surfaceCount;
+};
+
+#define PVR_MAGIC 0x21525650 // "PVR!" in little-endian
+
+#define PVR_FORMAT_MASK 0x000000FF
+#define PVR_FORMAT_PVRTC2 0x00000018
+#define PVR_FORMAT_PVRTC4 0x00000019
+#define PVR_FORMAT_ETC1 0x00000036
+
+#define PVR_HAS_MIPMAPS 0x00000100
+#define PVR_TWIDDLED 0x00000200
+#define PVR_NORMAL_MAP 0x00000400
+#define PVR_BORDER_ADDED 0x00000800
+#define PVR_CUBE_MAP 0x00001000
+#define PVR_FALSE_COLOR_MIPMAPS 0x00002000
+#define PVR_VOLUME_TEXTURE 0x00004000
+#define PVR_ALPHA_IN_TEXTURE 0x00008000
+#define PVR_VERTICAL_FLIP 0x00010000
+
+#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+#ifndef GL_ETC1_RGB8_OES
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+bool QGLBoundTexture::canBindCompressedTexture
+ (const char *buf, int len, const char *format, bool *hasAlpha,
+ bool *isFlipped)
+{
+ if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
+ // Compressed texture loading only supported on little-endian
+ // systems such as x86 and ARM at the moment.
+ return false;
+ }
+ if (!format) {
+ // Auto-detect the format from the header.
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
+ *hasAlpha = true;
+ *isFlipped = true;
+ return true;
+ } else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
+ const PvrHeader *pvrHeader =
+ reinterpret_cast<const PvrHeader *>(buf);
+ *hasAlpha = (pvrHeader->alphaMask != 0);
+ *isFlipped = ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0);
+ return true;
+ }
+ } else {
+ // Validate the format against the header.
+ if (!qstricmp(format, "DDS")) {
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
+ *hasAlpha = true;
+ *isFlipped = true;
+ return true;
+ }
+ } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
+ if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
+ const PvrHeader *pvrHeader =
+ reinterpret_cast<const PvrHeader *>(buf);
+ *hasAlpha = (pvrHeader->alphaMask != 0);
+ *isFlipped = ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QGLBoundTexture::bindCompressedTexture
+ (const char *buf, int len, const char *format)
+{
+ if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
+ // Compressed texture loading only supported on little-endian
+ // systems such as x86 and ARM at the moment.
+ return false;
+ }
+#if !defined(QT_OPENGL_ES)
+ QGLTextureExtensions *extensions = QGLTextureExtensions::extensions();
+ if (!extensions)
+ return false;
+ if (!extensions->compressedTexImage2D) {
+ qWarning("QGLContext::bindTexture(): The GL implementation does "
+ "not support texture compression extensions.");
+ return false;
+ }
+#endif
+ if (!format) {
+ // Auto-detect the format from the header.
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
+ return bindCompressedTextureDDS(buf, len);
+ else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
+ return bindCompressedTexturePVR(buf, len);
+ } else {
+ // Validate the format against the header.
+ if (!qstricmp(format, "DDS")) {
+ if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
+ return bindCompressedTextureDDS(buf, len);
+ } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
+ if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
+ return bindCompressedTexturePVR(buf, len);
+ }
+ }
+ return false;
+}
+
+bool QGLBoundTexture::bindCompressedTexture
+ (const QString& fileName, const char *format)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+ QByteArray contents = file.readAll();
+ file.close();
+ return bindCompressedTexture
+ (contents.constData(), contents.size(), format);
+}
+
+bool QGLBoundTexture::bindCompressedTextureDDS(const char *buf, int len)
+{
+ QGLTextureExtensions *extensions = QGLTextureExtensions::extensions();
+ if (!extensions)
+ return false;
+
+ // Bail out if the necessary extension is not present.
+ if (!extensions->ddsTextureCompression) {
+ qWarning("QGLBoundTexture::bindCompressedTextureDDS(): DDS texture compression is not supported.");
+ return false;
+ }
+
+ const DDSFormat *ddsHeader = reinterpret_cast<const DDSFormat *>(buf + 4);
+ if (!ddsHeader->dwLinearSize) {
+ qWarning("QGLBoundTexture::bindCompressedTextureDDS(): DDS image size is not valid.");
+ return false;
+ }
+
+ int blockSize = 16;
+ GLenum format;
+
+ switch(ddsHeader->ddsPixelFormat.dwFourCC) {
+ case FOURCC_DXT1:
+ format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ blockSize = 8;
+ break;
+ case FOURCC_DXT3:
+ format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ break;
+ case FOURCC_DXT5:
+ format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ break;
+ default:
+ qWarning("QGLBoundTexture::bindCompressedTextureDDS(): DDS image format not supported.");
+ return false;
+ }
+
+ const GLubyte *pixels =
+ reinterpret_cast<const GLubyte *>(buf + ddsHeader->dwSize + 4);
+
+ GLuint id = m_resource.id();
+ if (id) {
+ glBindTexture(GL_TEXTURE_2D, 0); // Just in case it is bound.
+ m_resource.destroy();
+ }
+ id = 0;
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ q_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ q_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ m_resource.attach(QGLContext::currentContext(), id);
+
+ int size;
+ int offset = 0;
+ int available = len - int(ddsHeader->dwSize + 4);
+ int w = ddsHeader->dwWidth;
+ int h = ddsHeader->dwHeight;
+
+ // load mip-maps
+ for (int i = 0; i < (int) ddsHeader->dwMipMapCount; ++i) {
+ if (w == 0) w = 1;
+ if (h == 0) h = 1;
+
+ size = ((w+3)/4) * ((h+3)/4) * blockSize;
+ if (size > available)
+ break;
+ extensions->compressedTexImage2D
+ (GL_TEXTURE_2D, i, format, w, h, 0, size, pixels + offset);
+ offset += size;
+ available -= size;
+
+ // half size for each mip-map level
+ w = w/2;
+ h = h/2;
+ }
+
+ // DDS images are not inverted.
+ m_options &= ~QGLContext::InvertedYBindOption;
+
+ m_size = QSize(ddsHeader->dwWidth, ddsHeader->dwHeight);
+ m_hasAlpha = false;
+ return true;
+}
+
+bool QGLBoundTexture::bindCompressedTexturePVR(const char *buf, int len)
+{
+ QGLTextureExtensions *extensions = QGLTextureExtensions::extensions();
+ if (!extensions)
+ return false;
+
+ // Determine which texture format we will be loading.
+ const PvrHeader *pvrHeader = reinterpret_cast<const PvrHeader *>(buf);
+ GLenum textureFormat;
+ quint32 minWidth, minHeight;
+ switch (pvrHeader->flags & PVR_FORMAT_MASK) {
+ case PVR_FORMAT_PVRTC2:
+ if (pvrHeader->alphaMask)
+ textureFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+ else
+ textureFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+ minWidth = 16;
+ minHeight = 8;
+ break;
+
+ case PVR_FORMAT_PVRTC4:
+ if (pvrHeader->alphaMask)
+ textureFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+ else
+ textureFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+ minWidth = 8;
+ minHeight = 8;
+ break;
+
+ case PVR_FORMAT_ETC1:
+ textureFormat = GL_ETC1_RGB8_OES;
+ minWidth = 4;
+ minHeight = 4;
+ break;
+
+ default:
+ qWarning("QGLBoundTexture::bindCompressedTexturePVR(): PVR image format 0x%x not supported.", int(pvrHeader->flags & PVR_FORMAT_MASK));
+ return false;
+ }
+
+ // Bail out if the necessary extension is not present.
+ if (textureFormat == GL_ETC1_RGB8_OES) {
+ if (!extensions->etc1TextureCompression) {
+ qWarning("QGLBoundTexture::bindCompressedTexturePVR(): ETC1 texture compression is not supported.");
+ return false;
+ }
+ } else {
+ if (!extensions->pvrtcTextureCompression) {
+ qWarning("QGLBoundTexture::bindCompressedTexturePVR(): PVRTC texture compression is not supported.");
+ return false;
+ }
+ }
+
+ // Boundary check on the buffer size.
+ quint32 bufferSize = pvrHeader->headerSize + pvrHeader->dataSize;
+ if (bufferSize > quint32(len)) {
+ qWarning("QGLBoundTexture::bindCompressedTexturePVR(): PVR image size is not valid.");
+ return false;
+ }
+
+ // Create the texture.
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ GLuint id = m_resource.id();
+ if (id) {
+ glBindTexture(GL_TEXTURE_2D, 0); // Just in case it is bound.
+ m_resource.destroy();
+ }
+ id = 0;
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ m_resource.attach(QGLContext::currentContext(), id);
+ if (pvrHeader->mipMapCount) {
+ if ((m_options & QGLContext::LinearFilteringBindOption) != 0) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ } else {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ }
+ } else if ((m_options & QGLContext::LinearFilteringBindOption) != 0) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+
+ // Load the compressed mipmap levels.
+ const GLubyte *buffer =
+ reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize);
+ bufferSize = pvrHeader->dataSize;
+ quint32 level = 0;
+ quint32 width = pvrHeader->width;
+ quint32 height = pvrHeader->height;
+ while (bufferSize > 0 && level <= pvrHeader->mipMapCount) {
+ quint32 size =
+ (qMax(width, minWidth) * qMax(height, minHeight) *
+ pvrHeader->bitsPerPixel) / 8;
+ if (size > bufferSize)
+ break;
+ extensions->compressedTexImage2D
+ (GL_TEXTURE_2D, GLint(level), textureFormat,
+ GLsizei(width), GLsizei(height), 0, GLsizei(size), buffer);
+ width /= 2;
+ height /= 2;
+ buffer += size;
+ ++level;
+ }
+
+ // Restore the default pixel alignment for later texture uploads.
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ // Set the invert flag for the texture. The "vertical flip"
+ // flag in PVR is the opposite sense to our sense of inversion.
+ if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0)
+ m_options &= ~QGLContext::InvertedYBindOption;
+ else
+ m_options |= QGLContext::InvertedYBindOption;
+
+ m_size = QSize(pvrHeader->width, pvrHeader->height);
+ m_hasAlpha = (pvrHeader->alphaMask != 0);
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/textures/qgltextureutils_p.h b/src/threed/textures/qgltextureutils_p.h
new file mode 100644
index 000000000..2dc7ea4c5
--- /dev/null
+++ b/src/threed/textures/qgltextureutils_p.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTEXTUREUTILS_P_H
+#define QGLTEXTUREUTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtOpenGL/qgl.h>
+#include <QtCore/qdatetime.h>
+#include "qglnamespace.h"
+#include "qopenglfunctions.h"
+#include "qglsharedresource_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef GL_BGRA
+#define GL_BGRA 0x80E1
+#endif
+#ifndef GL_UNSIGNED_SHORT_5_6_5
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#endif
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#endif
+#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#endif
+
+#ifndef GL_GENERATE_MIPMAP_SGIS
+#define GL_GENERATE_MIPMAP_SGIS 0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
+#endif
+
+#if !defined(QT_OPENGL_ES)
+#define q_glTexParameteri(target,name,value) \
+ glTexParameteri((target), (name), int(value))
+#else
+#define q_glTexParameteri(target,name,value) \
+ glTexParameterf((target), (name), GLfloat(int(value)))
+#endif
+
+// Modify a wrapping mode to account for platform differences.
+QGL::TextureWrap qt_gl_modify_texture_wrap(QGL::TextureWrap value);
+
+typedef void (QT3D_GLF_APIENTRYP q_glCompressedTexImage2DARB)
+ (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+
+class QGLTextureExtensions
+{
+public:
+ QGLTextureExtensions(const QGLContext *ctx);
+ ~QGLTextureExtensions();
+
+ int npotTextures : 1;
+ int generateMipmap : 1;
+ int bgraTextureFormat : 1;
+ int ddsTextureCompression : 1;
+ int etc1TextureCompression : 1;
+ int pvrtcTextureCompression : 1;
+ q_glCompressedTexImage2DARB compressedTexImage2D;
+
+ static QGLTextureExtensions *extensions();
+};
+
+class QGLBoundTexture
+{
+public:
+ QGLBoundTexture();
+ ~QGLBoundTexture();
+
+ const QGLContext *context() const { return m_resource.context(); }
+
+ GLuint textureId() const { return m_resource.id(); }
+ void setTextureId(const QGLContext *ctx, GLuint id)
+ { m_resource.attach(ctx, id); }
+ void clearId() { m_resource.clearId(); }
+
+ QGLContext::BindOptions options() const { return m_options; }
+ void setOptions(QGLContext::BindOptions options) { m_options = options; }
+
+ QSize size() const { return m_size; }
+ bool hasAlpha() const { return m_hasAlpha; }
+
+ void startUpload(const QGLContext *ctx, GLenum target, const QSize &imageSize);
+ void uploadFace(GLenum target, const QImage &image, const QSize &scaleSize,
+ GLenum format = GL_RGBA);
+ void createFace(GLenum target, const QSize &size, GLenum format = GL_RGBA);
+ void finishUpload(GLenum target);
+
+ static bool canBindCompressedTexture
+ (const char *buf, int len, const char *format, bool *hasAlpha,
+ bool *isFlipped);
+ bool bindCompressedTexture
+ (const QString& fileName, const char *format = 0);
+ bool bindCompressedTexture
+ (const char *buf, int len, const char *format = 0);
+ bool bindCompressedTextureDDS(const char *buf, int len);
+ bool bindCompressedTexturePVR(const char *buf, int len);
+
+private:
+ QGLSharedResource m_resource;
+ QGLContext::BindOptions m_options;
+ QSize m_size;
+ bool m_hasAlpha;
+ QTime time;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/threed/textures/textures.pri b/src/threed/textures/textures.pri
new file mode 100644
index 000000000..c17c1531e
--- /dev/null
+++ b/src/threed/textures/textures.pri
@@ -0,0 +1,15 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += \
+ qgltexture2d.h \
+ qgltexturecube.h \
+ qareaallocator.h
+SOURCES += \
+ qareaallocator.cpp \
+ qglsharedresource.cpp \
+ qgltexture2d.cpp \
+ qgltexturecube.cpp \
+ qgltextureutils.cpp
+PRIVATE_HEADERS += \
+ qglsharedresource_p.h \
+ qgltexture2d_p.h
diff --git a/src/threed/threed.pri b/src/threed/threed.pri
new file mode 100644
index 000000000..84e11aedd
--- /dev/null
+++ b/src/threed/threed.pri
@@ -0,0 +1,13 @@
+include(global/global.pri)
+include(painting/painting.pri)
+include(arrays/arrays.pri)
+include(effects/effects.pri)
+include(materials/materials.pri)
+include(geometry/geometry.pri)
+include(viewing/viewing.pri)
+include(math3d/math3d.pri)
+include(scene/scene.pri)
+include(graphicsview/graphicsview.pri)
+include(textures/textures.pri)
+include(surfaces/surfaces.pri)
+include(api/api.pri)
diff --git a/src/threed/threed.pro b/src/threed/threed.pro
new file mode 100644
index 000000000..00e8d60c4
--- /dev/null
+++ b/src/threed/threed.pro
@@ -0,0 +1,67 @@
+TEMPLATE = lib
+TARGET = Qt3D$${QT_LIBINFIX}
+gcov {
+ CONFIG += staticlib warn_on
+ QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
+ QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
+} else {
+ CONFIG += dll warn_on
+}
+QT += opengl \
+ network
+DESTDIR = $$[QT_INSTALL_LIBS]
+
+win32 {
+ DLLDESTDIR = ../../bin
+ !static:DEFINES += QT_MAKEDLL
+
+ CONFIG(debug, debug|release) {
+ TARGET = $$member(TARGET, 0)d
+ }
+}
+
+symbian {
+ DEFINES += QT_MAKEDLL
+ CONFIG += epocallowdlldata
+ contains(QT_EDITION, OpenSource) {
+ TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData
+ } else {
+ TARGET.CAPABILITY = All -Tcb
+ }
+}
+
+include(threed.pri)
+PUBLIC_HEADERS = $$HEADERS
+HEADERS += $$PRIVATE_HEADERS
+DEFINES += QT_BUILD_Qt3D_LIB
+
+!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL
+
+INSTALL_HEADERS = ""
+for (hdr, PUBLIC_HEADERS) {
+ found_vdir = $$PWD
+ for (vdir, VPATH) {
+ found_vdir = $$vdir
+ exists($$found_vdir/$$hdr):break()
+ }
+ INSTALL_HEADERS += $$found_vdir/$$hdr
+}
+
+# If Qt has been configured to build frameworks, then the build will put
+# the Qt3D library into a framework bundle, so put the headers in the bundle
+# as well. Other OS's, or mac without frameworks, install the headers into
+# the Qt build tree directly.
+macx:CONFIG(qt_framework, qt_framework|qt_no_framework) {
+ CONFIG += lib_bundle
+ FRAMEWORK_HEADERS.version = Versions
+ FRAMEWORK_HEADERS.path = Headers
+ FRAMEWORK_HEADERS.files = $$INSTALL_HEADERS
+ QMAKE_BUNDLE_DATA += FRAMEWORK_HEADERS
+} else {
+ exportHeaders.input = PUBLIC_HEADERS
+ exportHeaders.output = $$[QT_INSTALL_HEADERS]/Qt3D/${QMAKE_FILE_IN_BASE}${QMAKE_FILE_EXT}
+ exportHeaders.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+ exportHeaders.CONFIG += no_link_no_clean
+ exportHeaders.variable_out = PRE_TARGETDEPS
+ QMAKE_EXTRA_COMPILERS += exportHeaders
+}
diff --git a/src/threed/viewing/qglcamera.cpp b/src/threed/viewing/qglcamera.cpp
new file mode 100644
index 000000000..3cbb43b1a
--- /dev/null
+++ b/src/threed/viewing/qglcamera.cpp
@@ -0,0 +1,1310 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcamera.h"
+#include "qglpainter.h"
+#include <QtGui/qquaternion.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLCamera
+ \brief The QGLCamera class defines the projection to apply to simulate a camera's position, orientation, and optics.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::viewing
+
+ \section1 Modelview and projection transformations
+
+ A QGLCamera instance is applied to the scene in two phases:
+ modelview transformation and projection transformation.
+
+ During the modelview transformation, the eye(), center(), and
+ upVector() are used to generate a 4x4 transformation matrix that
+ reflects the viewer's current position and orientation.
+
+ During the projection transformation, the projectionType(),
+ nearPlane(), farPlane(), fieldOfView(), and viewSize() are used
+ to define a viewing volume as a 4x4 transformation matrix.
+
+ The modelview transformation matrix is returned by modelViewMatrix().
+ The projection transformation matrix is returned by projectionMatrix().
+
+ \section1 Positioning and orienting the view
+
+ The viewer position and orientation are defined by eye(), center(),
+ and upVector(). The location of the viewer in world co-ordinates is
+ given by eye(), the viewer is looking at the object of interest located
+ at center(), and the upVector() specifies the direction that should
+ be considered "up" with respect to the viewer.
+
+ The vector from the eye() to the center() is called the "view vector",
+ and the cross-product of the view vector and upVector() is called
+ the "side vector". The view vector specifies the direction the
+ viewer is looking, and the side vector points off to the right of
+ the viewer.
+
+ It is recommended that the view vector and upVector() be at right angles
+ to each other, but this is not required as long as the angle between
+ them is close to 90 degrees.
+
+ The most common use of view and up vectors that are not at right angles
+ is to simulate a human eye at a specific height above the ground looking
+ down at a lower object or up at a higher object. In this case, the
+ the view vector will not be true horizontal, but the upVector() indicating
+ the human's upright stance will be true vertical.
+
+ \section1 Zooming the camera image
+
+ There are two ways to zoom the image seen through the camera: either
+ the camera eye() position can be moved closer to the object of interest,
+ or the field of view of the camera lens can be changed to make it appear
+ as though the object is moving closer.
+
+ Changing the eye() position changes the lighting calculation in the
+ scene because the viewer is in a different position, changing the
+ angle of light reflection on the object's surface.
+
+ The setFieldOfView() function can be used to simulate the effect of a
+ camera lens. The smaller the fieldOfView(), the closer the object
+ will appear. The lighting calculation will be the same as for the
+ unzoomed scene.
+
+ If fieldOfView() is zero, then a standard perspective frustum of
+ viewSize() is used to define the viewing volume. The viewSize()
+ can be adjusted with setViewSize() to zoom the view. A smaller
+ viewSize() will make the the object appear closer.
+
+ The fieldOfView() or viewSize() is applied as part of the
+ projectionMatrix().
+
+ \section1 Rotating the viewer or object of interest
+
+ Rotating a viewer in 3D space is a very delicate process. It is very
+ easy to construct the rotation incorrectly and end up in a "gimbal lock"
+ state where further rotations are impossible in certain directions.
+
+ To help alleviate this problem, QGLCamera uses a quaternion-based
+ approach to generate rotations. A quaternion is a compact representation
+ of a rotation in 3D space. Rotations can be combined through quaternion
+ multiplication. More information on quaternions can be found in the
+ documentation for QQuaternion.
+
+ Before rotating the view, you should first decide the type
+ of rotation you want to perform:
+
+ \list
+ \i Tilting or panning a fixed eye to reveal the scene in different
+ directions and orientations. This is equivalent to mounting a camera
+ on a fixed tripod and then adjusting the direction of view and
+ orientation with the tripod controls.
+ \i Rotating a moving viewer about the object of interest. This is
+ equivalent to moving the viewer around the object at a fixed distance,
+ but with the viewer always pointing at the object.
+ \endlist
+
+ In the QGLCamera class, the first type of rotation is performed with
+ rotateEye() and the second with rotateCenter(). Each of these functions
+ take a quaternion argument that defines the type of rotation to perform.
+
+ The tilt(), pan(), and roll() functions return values that can help with
+ constructing the rotation quaternions to pass to rotateEye() and
+ rotateCenter(). Tilt and pan are also known as "pitch" and "yaw" in
+ flight dynamics.
+
+ Three axes of rotation are used to compute the quaternions. The tilt()
+ quaternion is computed with respect to the side vector, the pan()
+ quaterion is computed with respect to the upVector(), and the roll()
+ quaternion is computed with respect to the view vector.
+
+ The following example tilts the direction the eye() is pointing
+ by 5 degrees, and then pans by 45 degrees:
+
+ \code
+ camera.rotateEye(camera.tilt(5));
+ camera.rotateEye(camera.pan(45));
+ \endcode
+
+ The next example performs the two rotations in a single fluid step
+ (note that the rotation to be performed first is multiplied last):
+
+ \code
+ camera.rotateEye(camera.pan(45) * camera.tilt(5));
+ \endcode
+
+ These two examples will not produce the same visual result, even though
+ it looks like they might. In the first example, the upVector() is tilted
+ before the pan() quaternion is computed. In the second example, the pan()
+ quaternion is computed using the original upVector().
+
+ This difference in behavior is useful in different situations. Some
+ applications may wish to perform all rotations relative to the original
+ viewer orientation, and other applications may wish to perform rotations
+ relative to the current viewer orientation. These application types
+ correspond to the second and first examples above.
+
+ \section1 Moving the viewer or object of interest
+
+ The simplest way to move the viewer or object of interest is to call
+ setEye() or setCenter() respectively and supply a new position in
+ world co-ordinates. However, this can lead to non-intuitive movements
+ if the viewer orientation is not aligned with the world co-ordinate axes.
+
+ For example, subtracting 3 from the eye() x co-ordinate will appear to
+ move the eye left 3 units if the viewer orientation is aligned with the
+ world co-ordinate axes. But it will not appear to move the eye left 3
+ units in any other orientation.
+
+ The translation() function can be used to construct a translation
+ vector that is aligned with the viewer's current orientation.
+ Movement in the x direction will move along the side vector, movement in
+ the y direction will move along upVector(), and movement in the z
+ direction will move along the view vector.
+
+ The translation() function is useful when implementing operations such
+ as "step left", "jump up", and so on where the movement should be
+ interpreted relative to the viewer's current orientation, not the
+ world co-ordinate axes,
+
+ In other words, the following two lines of code are not equivalent
+ unless the view is oriented with the world co-ordinate axes:
+
+ \code
+ camera.translateEye(camera.translation(x, y, z));
+
+ camera.translateEye(QVector3D(x, y, z));
+ \endcode
+
+ The following example translates the eye() position while
+ keeping the object of interest at the original center():
+
+ \code
+ camera.translateEye(camera.translation(x, y, z));
+ \endcode
+
+ The following example translates the object of interest at
+ center() while keeping the eye() position fixed:
+
+ \code
+ camera.translateCenter(camera.translation(x, y, z));
+ \endcode
+
+ The following example translates both the eye() and the center()
+ by the same amount, which will maintain the original view vector.
+
+ \code
+ QVector3D vector = camera.translation(x, y, z);
+ camera.translateEye(vector);
+ camera.translateCenter(vector);
+ \endcode
+
+ It is important that the translation vector for center() be computed
+ before eye() is translated if both eye() and center() must move by the
+ same amount. The following code translates center() in the viewer
+ orientation after the eye() is translated:
+
+ \code
+ camera.translateEye(camera.translation(x, y, z));
+ camera.translateCenter(camera.translation(x, y, z));
+ \endcode
+
+ Translating both eye() and center() by the same amount can be used
+ to simulate sliding a viewer past a scene while always looking in the
+ same direction (for example, filming a scene from a moving vehicle).
+ An alternative is to fix the viewer and move the scene itself:
+ the negation of the translation() vector can be applied to the
+ scene's modelview transformation.
+
+ \section1 Motion tracking
+
+ Viewing of 3D scenes can be enhanced if there is some way to track
+ the motion of the viewer or the orientation of the display device.
+
+ Applications can use setMotionAdjustment() to alter the position
+ of the camera to account for the viewer's motion. This indicates
+ the viewer's position relative to the center of the screen.
+ The motionAdjustment() vector is used to determine by how much
+ the camera position should be adjusted. The distance of the viewer
+ from the screen is ignored.
+
+ On handheld devices that use accelerometers to determine the
+ orientation of the device, the down vector due to gravity
+ can be adjusted to serve as a motion tracking vector.
+
+ The output of motion tracking hardware can be very noisy,
+ with minor fluctuations due to viewer twitch movements or
+ environmental factors. The application is responsible for
+ cleaning up the signal and removing these fluctuations before
+ setMotionAdjustment() is called.
+
+ \section1 Stereo projections
+
+ QGLCamera can adjust the camera position for rendering separate left
+ and right eye images by setting eyeSeparation() to a non-zero value.
+ The eyeSeparation() is in world co-ordinates.
+
+ Objects that are placed at center() will coincide in the left and
+ right eye images, establishing the logical center of the stereo
+ effect. Objects that are closer to the eye() will be rendered
+ to appear closer in the stereo effect, and objects that are further
+ away from eye() than center() will be rendered to appear further away.
+
+ Perspective and Orthographic projections incorporate the
+ eyeSeparation() into the modelViewMatrix() by altering the
+ eye() position.
+
+ \sa QGLView, QGLPainter
+*/
+
+/*!
+ \qmlclass Camera QGLCamera
+ \brief The Camera item defines the viewing position and projection for a 3D scene.
+ \since 4.8
+ \ingroup qt3d::qml3d
+
+ Camera instances are defined on a \l Viewport item using the
+ Viewport::camera property:
+
+ \code
+ import Qt 4.7
+ import Qt3D 1.0
+
+ Viewport {
+ width: 640; height: 480
+ camera: Camera {
+ eye: Qt.vector3d(-1, 2, 10)
+ }
+ light: Light {}
+ Item3D {
+ mesh: Mesh { source: "meshes/teapot.bez" }
+ effect: Effect {}
+ }
+ }
+ \endcode
+
+ \section1 Positioning and orienting the view
+
+ The viewer position and orientation are defined by \l eye, \l center,
+ and \l upVector. The location of the viewer in world co-ordinates is
+ given by \l eye, the viewer is looking at the object of interest located
+ at \l center, and the \l upVector specifies the direction that should
+ be considered "up" with respect to the viewer.
+
+ The vector from the \l eye to the \l center is called the "view vector",
+ and the cross-product of the view vector and \l upVector is called
+ the "side vector". The view vector specifies the direction the
+ viewer is looking, and the side vector points off to the right of
+ the viewer.
+
+ It is recommended that the view vector and \l upVector be at right angles
+ to each other, but this is not required as long as the angle between
+ them is close to 90 degrees.
+
+ The most common use of view and up vectors that are not at right angles
+ is to simulate a human eye at a specific height above the ground looking
+ down at a lower object or up at a higher object. In this case, the
+ the view vector will not be true horizontal, but the \l upVector
+ indicating the human's upright stance will be true vertical.
+
+ \section1 Zooming the camera image
+
+ There are two ways to zoom the image seen through the camera: either
+ the camera \l eye position can be moved closer to the object of interest,
+ or the field of view of the camera lens can be changed to make it appear
+ as though the object is moving closer.
+
+ Changing the \l eye position changes the lighting calculation in the
+ scene because the viewer is in a different position, changing the
+ angle of light reflection on the object's surface.
+
+ The \l fieldOfView property function can be used to simulate the effect
+ of a camera lens. The smaller the \l fieldOfView, the closer the object
+ will appear. The lighting calculation will be the same as for the
+ unzoomed scene.
+
+ If \l fieldOfView is zero, then a standard perspective frustum of
+ is used to define the viewing volume based on the width and height
+ of the \l Viewport.
+
+ \section1 Stereo projections
+
+ Camera can adjust the camera position for rendering separate left
+ and right eye images by setting the \l eyeSeparation property
+ to a non-zero value. The \l eyeSeparation is in world co-ordinates.
+
+ Objects that are placed at \l center will coincide in the left and
+ right eye images, establishing the logical center of the stereo
+ effect. Objects that are closer to the \l eye will be rendered
+ to appear closer in the stereo effect, and objects that are further
+ away from \l eye than \l center will be rendered to appear further away.
+
+ \sa Viewport
+*/
+
+class QGLCameraPrivate
+{
+public:
+ QGLCameraPrivate();
+
+ QGLCamera::ProjectionType projectionType;
+ qreal fieldOfView;
+ qreal nearPlane;
+ qreal farPlane;
+ QSizeF viewSize;
+ QSizeF minViewSize;
+ int screenRotation;
+ QVector3D eye;
+ QVector3D upVector;
+ QVector3D center;
+ QVector3D viewVector;
+ qreal eyeSeparation;
+ QVector3D motionAdjustment;
+ QQuaternion motionQuaternion;
+ bool adjustForAspectRatio;
+};
+
+QGLCameraPrivate::QGLCameraPrivate()
+ : projectionType(QGLCamera::Perspective),
+ fieldOfView(0.0f),
+ nearPlane(5.0f),
+ farPlane(1000.0f),
+ viewSize(2.0f, 2.0f),
+ minViewSize(0.0001f, 0.0001f),
+ screenRotation(0),
+ eye(0.0f, 0.0f, 10.0f),
+ upVector(0.0f, 1.0f, 0.0f),
+ center(0.0f, 0.0f, 0.0f),
+ viewVector(0.0f, 0.0f, -10.0f),
+ eyeSeparation(0.0f),
+ motionAdjustment(0.0f, 0.0f, 1.0f),
+ adjustForAspectRatio(true)
+{
+}
+
+/*!
+ Constructs a QGLCamera with the default properties and
+ attaches it to \a parent.
+*/
+QGLCamera::QGLCamera(QObject *parent)
+ : QObject(parent), d_ptr(new QGLCameraPrivate)
+{
+}
+
+/*!
+ Destroys this QGLCamera object.
+*/
+QGLCamera::~QGLCamera()
+{
+ delete d_ptr;
+}
+
+/*!
+ \enum QGLCamera::ProjectionType
+ This enum defines the type of view projection to use for a QGLCamera.
+
+ \value Perspective Use a perspective view.
+ \value Orthographic Use an orthographic view.
+*/
+
+/*!
+ \property QGLCamera::projectionType
+ \brief the projection type for this camera. The default is Perspective.
+*/
+
+/*!
+ \qmlproperty enumeration Camera::projectionType
+
+ The projection type for this camera, which is one of:
+
+ \list
+ \o Perspective Use a perspective view. This is the default.
+ \o Orthographic Use an orthographic view.
+ \endlist
+*/
+
+QGLCamera::ProjectionType QGLCamera::projectionType() const
+{
+ Q_D(const QGLCamera);
+ return d->projectionType;
+}
+
+void QGLCamera::setProjectionType(QGLCamera::ProjectionType value)
+{
+ Q_D(QGLCamera);
+ if (d->projectionType != value) {
+ d->projectionType = value;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::fieldOfView
+ \brief the field of view in degrees for a perspective projection.
+
+ The default value is zero, which indicates a standard perspective
+ frustum view volume of viewSize() in size. If the value is not
+ zero, then viewSize() is ignored.
+
+ This value is ignored if projectionType() is not Perspective.
+
+ \sa viewSize()
+*/
+
+/*!
+ \qmlproperty real Camera::fieldOfView
+ The field of view in degrees for a perspective projection.
+
+ The default value is zero, which indicates a standard perspective
+ frustum view volume.
+
+ This value is ignored if projectionType is not Perspective.
+
+ \sa projectionType
+*/
+
+qreal QGLCamera::fieldOfView() const
+{
+ Q_D(const QGLCamera);
+ return d->fieldOfView;
+}
+
+void QGLCamera::setFieldOfView(qreal angle)
+{
+ Q_D(QGLCamera);
+ if (d->fieldOfView != angle) {
+ d->fieldOfView = angle;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::nearPlane
+ \brief the distance from the eye to the near clipping plane.
+ The default value is 5.
+
+ \sa farPlane()
+*/
+
+/*!
+ \qmlproperty real Camera::nearPlane
+ The distance from the eye to the near clipping plane.
+ The default value is 5.
+
+ \sa farPlane
+*/
+
+qreal QGLCamera::nearPlane() const
+{
+ Q_D(const QGLCamera);
+ return d->nearPlane;
+}
+
+void QGLCamera::setNearPlane(qreal value)
+{
+ Q_D(QGLCamera);
+ if (d->nearPlane != value) {
+ d->nearPlane = value;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::farPlane
+ \brief the distance from the eye to the far clipping plane.
+ The default value is 1000.
+
+ \sa nearPlane()
+*/
+
+/*!
+ \qmlproperty real Camera::farPlane
+ The distance from the eye to the far clipping plane.
+ The default value is 1000.
+
+ \sa nearPlane
+*/
+
+qreal QGLCamera::farPlane() const
+{
+ Q_D(const QGLCamera);
+ return d->farPlane;
+}
+
+void QGLCamera::setFarPlane(qreal value)
+{
+ Q_D(QGLCamera);
+ if (d->farPlane != value) {
+ d->farPlane = value;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::viewSize
+ \brief the size of the front of the projection viewing volume.
+ The viewing volume is assumed to be centered on the origin.
+
+ The default value is (2, 2), which indicates a viewing volume front
+ from (-1, -1) to (1, 1).
+
+ If the width or height of the viewing volume is negative, then the
+ co-ordinates will be swapped. For example, a size of (2, -2) will
+ flip the vertical axis upside down for a viewing volume from
+ (-1, 1) to (1, -1).
+
+ The view size will be further adjusted by the window's aspect ratio
+ when projectionMatrix() is called. For best results, the width and
+ height of the view size should be the same to define an ideal square
+ viewing volume, which is then extended to the final viewing volume
+ width and height based on the window's aspect ratio.
+
+ \sa projectionMatrix(), minViewSize()
+*/
+QSizeF QGLCamera::viewSize() const
+{
+ Q_D(const QGLCamera);
+ return d->viewSize;
+}
+
+void QGLCamera::setViewSize(const QSizeF& size)
+{
+ Q_D(QGLCamera);
+ QSizeF sz(size);
+ if (qAbs(sz.width()) < d->minViewSize.width()) {
+ if (sz.width() >= 0.0f)
+ sz.setWidth(d->minViewSize.width());
+ else
+ sz.setWidth(-d->minViewSize.width());
+ }
+ if (qAbs(sz.height()) < d->minViewSize.height()) {
+ if (sz.height() >= 0.0f)
+ sz.setHeight(d->minViewSize.height());
+ else
+ sz.setHeight(-d->minViewSize.height());
+ }
+ if (d->viewSize != sz) {
+ d->viewSize = sz;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::minViewSize
+ \brief the minimum size of the front of the projection viewing volume.
+
+ The minimum view size is used to clamp viewSize() when zooming
+ the camera closer to an object to prevent it "passing through"
+ the object and causing the scale factor to become infinite.
+
+ The default value is (0.0001, 0.0001).
+
+ \sa projectionMatrix(), viewSize()
+*/
+QSizeF QGLCamera::minViewSize() const
+{
+ Q_D(const QGLCamera);
+ return d->minViewSize;
+}
+
+void QGLCamera::setMinViewSize(const QSizeF& size)
+{
+ Q_D(QGLCamera);
+ if (d->minViewSize != size) {
+ d->minViewSize = size;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::screenRotation
+ \brief the screen rotation angle in degrees. The default
+ value is 0. If this value is 90 or 270, then the view
+ will be flipped width for height. The only supported values
+ are 0, 90, 180, and 270. The screen is rotated around the
+ positive z axis.
+
+ This setting is intended for simple screen rotations on handheld
+ devices that can be held in either portrait or landscape orientations.
+ The entire screen image is rotated so that it can be viewed in a
+ different device orientation.
+
+ Use rotateEye() or rotateCenter() for more complex rotations
+ that are not aligned with 0, 90, 180, or 270 degrees.
+*/
+
+int QGLCamera::screenRotation() const
+{
+ Q_D(const QGLCamera);
+ return d->screenRotation;
+}
+
+void QGLCamera::setScreenRotation(int angle)
+{
+ Q_D(QGLCamera);
+ if (d->screenRotation != angle) {
+ d->screenRotation = angle;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::eye
+ \brief the position of the viewer's eye. The default value is (0, 0, 10).
+
+ \sa translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+
+/*!
+ \qmlproperty vector3D Camera::eye
+ The position of the viewer's eye. The default value is (0, 0, 10).
+
+ \sa upVector, center, eyeSeparation
+*/
+QVector3D QGLCamera::eye() const
+{
+ Q_D(const QGLCamera);
+ return d->eye;
+}
+
+void QGLCamera::setEye(const QVector3D& vertex)
+{
+ Q_D(QGLCamera);
+ if (d->eye != vertex) {
+ d->eye = vertex;
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+ }
+}
+
+/*!
+ Adjusts the position of the viewer's eye by the components
+ (\a x, \a y, \a z), where the components are interpreted relative
+ to the viewer's current orientation. See translation() for more
+ information.
+
+ This function is accessible to QML on the Camera item.
+
+ \sa eye(), setEye(), translateCenter()
+*/
+void QGLCamera::translateEye(qreal x, qreal y, qreal z)
+{
+ Q_D(QGLCamera);
+ d->eye += translation(x, y, z);
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+}
+
+/*!
+ \property QGLCamera::upVector
+ \brief the up vector for the viewer. The default value is (0, 1, 0).
+
+ \sa eye(), center()
+*/
+
+/*!
+ \qmlproperty vector3D Camera::upVector
+ The up vector for the viewer. The default value is (0, 1, 0).
+
+ \sa eye, center
+*/
+
+QVector3D QGLCamera::upVector() const
+{
+ Q_D(const QGLCamera);
+ return d->upVector;
+}
+
+void QGLCamera::setUpVector(const QVector3D& vector)
+{
+ Q_D(QGLCamera);
+ if (d->upVector != vector) {
+ d->upVector = vector;
+ emit viewChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::center
+ \brief the center of the view visible from the viewer's position.
+ The default value is (0, 0, 0).
+
+ \sa translateCenter(), eye(), upVector()
+*/
+
+/*!
+ \qmlproperty vector3D Camera::center
+ The center of the view visible from the viewer's position.
+ The default value is (0, 0, 0).
+
+ \sa eye, upVector
+*/
+
+QVector3D QGLCamera::center() const
+{
+ Q_D(const QGLCamera);
+ return d->center;
+}
+
+void QGLCamera::setCenter(const QVector3D& vertex)
+{
+ Q_D(QGLCamera);
+ if (d->center != vertex) {
+ d->center = vertex;
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+ }
+}
+
+/*!
+ Adjusts the center of the view by the components (\a x, \a y, \a z),
+ where the components are interpreted relative to the viewer's current
+ orientation. See translation() for more information.
+
+ This function is accessible to QML on the Camera item.
+
+ \sa center(), setCenter(), translateEye()
+*/
+void QGLCamera::translateCenter(qreal x, qreal y, qreal z)
+{
+ Q_D(QGLCamera);
+ d->center += translation(x, y, z);
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+}
+
+/*!
+ \property QGLCamera::eyeSeparation
+ \brief the separation between the eyes when stereo viewing is in use,
+ with eye() specifying the mid-point between the eyes. The default
+ value is 0.
+
+ \sa eye()
+*/
+
+/*!
+ \qmlproperty real Camera::eyeSeparation
+ The separation between the eyes when stereo viewing is in use,
+ with \l eye property specifying the mid-point between the eyes.
+ The default value is 0.
+
+ \sa eye
+*/
+
+qreal QGLCamera::eyeSeparation() const
+{
+ Q_D(const QGLCamera);
+ return d->eyeSeparation;
+}
+
+void QGLCamera::setEyeSeparation(qreal value)
+{
+ Q_D(QGLCamera);
+ if (d->eyeSeparation != value) {
+ d->eyeSeparation = value;
+ emit viewChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::motionAdjustment
+ \brief the adjustment vector to apply to the eye() for user motion.
+
+ This property is typically used to implement motion tracking.
+ It is interpreted as a vector from the center of the screen to the
+ current position of the viewer. The angle between the motion
+ adjustment vector and the screen center is used to adjust the
+ position of the eye() when modelViewMatrix() is called.
+
+ The default value is (0, 0, 1), which indicates a viewer
+ directly in front of the center of the screen.
+
+ The units for the vector are unspecified. They could be
+ meters, centimeters, or the force due to gravity in various
+ directions from an accelerometer. The angle defined
+ by the vector is used to perform the adjustment, not its
+ magnitude.
+
+ The output of motion tracking hardware can be very noisy,
+ with minor fluctuations due to viewer twitch movements or
+ environmental factors. The application is responsible for
+ cleaning up the signal and removing these fluctuations before
+ altering this property.
+
+ \sa eye(), modelViewMatrix()
+*/
+
+QVector3D QGLCamera::motionAdjustment() const
+{
+ Q_D(const QGLCamera);
+ return d->motionAdjustment;
+}
+
+void QGLCamera::setMotionAdjustment(const QVector3D& vector)
+{
+ Q_D(QGLCamera);
+ if (d->motionAdjustment != vector) {
+ d->motionAdjustment = vector;
+ if (vector.x() == 0.0f && vector.y() == 0.0f) {
+ // If the vector is centered, then don't perform any rotations.
+ d->motionQuaternion = QQuaternion();
+ } else {
+ // Determine the pan and tilt angles from the vector.
+ QVector3D view = -vector.normalized();
+ if (view.z() < 0.0f)
+ view = -view;
+ qreal xangle = asin(view.x()) * 180.0f / M_PI;
+ qreal yangle = asin(-view.y()) * 180.0f / M_PI;
+
+ // Construct the pan and tilt quaternions.
+ if (qFuzzyIsNull(xangle))
+ d->motionQuaternion = tilt(yangle);
+ else if (qFuzzyIsNull(yangle))
+ d->motionQuaternion = pan(xangle);
+ else
+ d->motionQuaternion = tilt(yangle) * pan(xangle);
+ }
+ emit viewChanged();
+ }
+}
+
+/*!
+ \property QGLCamera::adjustForAspectRatio
+ \brief the adjustment state of the aspect ratio in the viewing volume.
+
+ By default, QGLCamera adjusts the viewing volume for the aspect
+ ratio of the window so that pixels appear square without the
+ application needing to adjust viewSize() manually.
+
+ If this property is false, then the aspect ratio adjustment is
+ not performed.
+*/
+
+/*!
+ \qmlproperty bool Camera::adjustForAspectRatio
+ The adjustment state of the aspect ratio in the viewing volume.
+
+ By default, the camera adjusts the viewing volume for the aspect
+ ratio of the window so that pixels appear square without the
+ application needing to adjust the view size manually.
+
+ If this property is false, then the aspect ratio adjustment is
+ not performed.
+
+ \sa projectionType
+*/
+
+bool QGLCamera::adjustForAspectRatio() const
+{
+ Q_D(const QGLCamera);
+ return d->adjustForAspectRatio;
+}
+
+void QGLCamera::setAdjustForAspectRatio(bool value)
+{
+ Q_D(QGLCamera);
+ if (d->adjustForAspectRatio != value) {
+ d->adjustForAspectRatio = value;
+ emit viewChanged();
+ }
+}
+
+/*!
+ Returns the quaternion corresponding to tilting the view up or
+ down by \a angle degrees. The returned quaternion can be applied to
+ the eye() position with rotateEye() or to the center() position with
+ rotateCenter().
+
+ \sa pan(), roll(), rotateEye(), rotateCenter()
+*/
+QQuaternion QGLCamera::tilt(qreal angle) const
+{
+ Q_D(const QGLCamera);
+ QVector3D side = QVector3D::crossProduct(d->viewVector, d->upVector);
+ return QQuaternion::fromAxisAndAngle(side, angle);
+}
+
+/*!
+ Returns the quaternion corresponding to panning the view left or
+ right by \a angle degrees. The returned quaternion can be applied to
+ the eye() position with rotateEye() or to the center() position with
+ rotateCenter().
+
+ \sa tilt(), roll(), rotateEye(), rotateCenter()
+*/
+QQuaternion QGLCamera::pan(qreal angle) const
+{
+ Q_D(const QGLCamera);
+ return QQuaternion::fromAxisAndAngle(d->upVector, angle);
+}
+
+/*!
+ Returns the quaternion corresponding to rolling the view left or
+ right by \a angle degrees. The returned quaternion can be applied to
+ the eye() position with rotateEye() or to the center() position with
+ rotateCenter().
+
+ \sa tilt(), pan(), rotateEye(), rotateCenter()
+*/
+QQuaternion QGLCamera::roll(qreal angle) const
+{
+ Q_D(const QGLCamera);
+ return QQuaternion::fromAxisAndAngle(d->viewVector, angle);
+}
+
+/*!
+ Rotates the orientation of the eye() according to the quaternion \a q.
+ The eye() will remain in the same position, but the upVector() and
+ center() may be altered by the rotation.
+
+ \sa rotateCenter(), tilt(), pan(), roll()
+*/
+void QGLCamera::rotateEye(const QQuaternion& q)
+{
+ Q_D(QGLCamera);
+ d->upVector = q.rotatedVector(d->upVector);
+ d->viewVector = q.rotatedVector(d->viewVector);
+ d->center = d->eye + d->viewVector;
+ emit viewChanged();
+}
+
+/*!
+ Rotates the position and orientation of the eye() around center()
+ according to the quaternion \a q. The center() will remain in the
+ same position, but the upVector() and eye() may be altered by
+ the rotation.
+
+ \sa rotateEye(), tilt(), pan(), roll()
+*/
+void QGLCamera::rotateCenter(const QQuaternion& q)
+{
+ Q_D(QGLCamera);
+ d->upVector = q.rotatedVector(d->upVector);
+ d->viewVector = q.rotatedVector(d->viewVector);
+ d->eye = d->center - d->viewVector;
+ emit viewChanged();
+}
+
+/*!
+ Returns a translation vector that can be used to adjust the eye()
+ or center() by \a x units side-ways, \a y units up,
+ and \a z units forwards.
+
+ This function is useful when implementing operations such as
+ "step left", "jump up", and so on where the movement should be
+ interpreted relative to the viewer's current orientation, not the
+ world co-ordinate axes.
+
+ The following example moves the eye() 2 units to the right of the
+ current eye position while keeping the same center() of interest:
+
+ \code
+ camera.setEye(camera.eye() + camera.translation(2, 0, 0));
+ \endcode
+
+ \sa translateEye(), translateCenter()
+*/
+QVector3D QGLCamera::translation(qreal x, qreal y, qreal z) const
+{
+ Q_D(const QGLCamera);
+ QVector3D vector(0.0f, 0.0f, 0.0f);
+ if (x != 0.0f)
+ vector += QVector3D::normal(d->viewVector, d->upVector) * x;
+ if (y != 0.0f)
+ vector += d->upVector.normalized() * y;
+ if (z != 0.0f)
+ vector += d->viewVector.normalized() * z;
+ return vector;
+}
+
+/*!
+ Returns the transformation matrix to apply to the projection matrix
+ to present the scene as viewed from the camera position.
+
+ The \a aspectRatio specifies the aspect ratio of the window the
+ camera view is being displayed in. An \a aspectRatio of 1 indicates that
+ the window is square. An \a aspectRatio greater than 1 indicates that
+ the window is wider than it is high. An \a aspectRatio less than 1
+ indicates that the window is higher than it is wide.
+
+ \sa modelViewMatrix()
+*/
+QMatrix4x4 QGLCamera::projectionMatrix(qreal aspectRatio) const
+{
+ Q_D(const QGLCamera);
+ QMatrix4x4 m;
+ if (!d->adjustForAspectRatio)
+ aspectRatio = 1.0f;
+ if (d->screenRotation != 0) {
+ m.rotate((qreal)(d->screenRotation), 0.0f, 0.0f, 1.0f);
+ if (d->screenRotation == 90 || d->screenRotation == 270) {
+ if (aspectRatio != 0.0f)
+ aspectRatio = 1.0f / aspectRatio;
+ }
+ }
+ if (d->projectionType == Perspective && d->fieldOfView != 0.0f) {
+ m.perspective(d->fieldOfView, aspectRatio,
+ d->nearPlane, d->farPlane);
+ } else {
+ qreal halfWidth = d->viewSize.width() / 2.0f;
+ qreal halfHeight = d->viewSize.height() / 2.0f;
+ if (aspectRatio > 1.0f) {
+ halfWidth *= aspectRatio;
+ } else if (aspectRatio > 0.0f && aspectRatio < 1.0f) {
+ halfHeight /= aspectRatio;
+ }
+ if (d->projectionType == Perspective) {
+ m.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight,
+ d->nearPlane, d->farPlane);
+ } else {
+ m.ortho(-halfWidth, halfWidth, -halfHeight, halfHeight,
+ d->nearPlane, d->farPlane);
+ }
+ }
+ return m;
+}
+
+/*!
+ Returns the transformation to apply to the modelview matrix
+ to present the scene as viewed from the eye position.
+
+ The \a eye parameter is used to adjust the camera's position
+ horizontally by half of eyeSeparation() if \a eye is QGL::LeftEye
+ or QGL::RightEye.
+
+ \sa projectionMatrix()
+*/
+QMatrix4x4 QGLCamera::modelViewMatrix(QGL::Eye eye) const
+{
+ Q_D(const QGLCamera);
+ QMatrix4x4 m;
+ QVector3D adjust;
+ if (eye == QGL::LeftEye)
+ adjust = translation(-d->eyeSeparation / 2.0f, 0.0f, 0.0f);
+ else if (eye == QGL::RightEye)
+ adjust = translation(d->eyeSeparation / 2.0f, 0.0f, 0.0f);
+ if (d->motionQuaternion.isIdentity()) {
+ m.lookAt(d->eye + adjust, d->center, d->upVector);
+ } else {
+ QVector3D up = d->motionQuaternion.rotatedVector(d->upVector);
+ QVector3D view = d->motionQuaternion.rotatedVector(d->viewVector);
+ m.lookAt(d->center - view + adjust, d->center, up);
+ }
+ return m;
+}
+
+/*!
+ Maps \a point from viewport co-ordinates to eye co-ordinates.
+ The size of the viewport is given by \a viewportSize, and its
+ aspect ratio by \a aspectRatio.
+
+ The returned vector will have its x and y components set to the
+ position of the point on the near plane, and the z component
+ set to -nearPlane().
+
+ This function is used for converting a mouse event's position
+ into eye co-ordinates within the current camera view.
+*/
+QVector3D QGLCamera::mapPoint
+ (const QPoint& point, qreal aspectRatio, const QSize& viewportSize) const
+{
+ Q_D(const QGLCamera);
+
+ // Rotate the co-ordinate system to account for the screen rotation.
+ int x = point.x();
+ int y = point.y();
+ int width = viewportSize.width();
+ int height = viewportSize.height();
+ if (!d->adjustForAspectRatio)
+ aspectRatio = 1.0f;
+ if (d->screenRotation == 90) {
+ if (aspectRatio != 0.0f)
+ aspectRatio = 1.0f / aspectRatio;
+ qSwap(x, y);
+ qSwap(width, height);
+ y = height - 1 - y;
+ } else if (d->screenRotation == 180) {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ } else if (d->screenRotation == 270) {
+ if (aspectRatio != 0.0f)
+ aspectRatio = 1.0f / aspectRatio;
+ qSwap(x, y);
+ qSwap(width, height);
+ }
+
+ // Determine the relative distance from the middle of the screen.
+ // After this xrel and yrel are typically between -1.0 and +1.0
+ // (unless the point was outside the viewport). The yrel is
+ // flipped upside down to account for the incoming co-ordinate
+ // being left-handed, but the world being right-handed.
+ qreal xrel, yrel;
+ if (width)
+ xrel = (((qreal)(x * 2)) - (qreal)width) / (qreal)width;
+ else
+ xrel = 0.0f;
+ if (height)
+ yrel = -(((qreal)(y * 2)) - (qreal)height) / (qreal)height;
+ else
+ yrel = 0.0f;
+
+ // Reverse the projection and return the point in world co-ordinates.
+ QMatrix4x4 m = projectionMatrix(aspectRatio);
+ QMatrix4x4 invm = m.inverted();
+ return invm.map(QVector3D(xrel, yrel, -1.0f));
+}
+
+/*!
+ \fn void QGLCamera::projectionChanged()
+
+ This signal is emitted when one of projectionType(), fieldOfView(),
+ nearPlane(), farPlane(), viewSize(), or screenRotation() changes,
+ indicating a modification to the optical properties of the camera
+ looking at the scene.
+
+ \sa viewChanged()
+*/
+
+/*!
+ \fn void QGLCamera::viewChanged()
+
+ This signal is emitted when one of eye(), upVector(), or center()
+ changes, indicating a modification to the viewer's position or
+ orientation.
+
+ \sa projectionChanged()
+*/
+
+/*!
+ \enum QGLCamera::RotateOrder
+ This enum defines the order to perform a tilt, pan, and roll
+ of a QGLCamera eye or center.
+
+ \value TiltPanRoll Tilt, then pan, then roll.
+ \value TiltRollPan Tilt, then roll, then pan.
+ \value PanTiltRoll Pan, then tilt, then roll.
+ \value PanRollTilt Pan, then roll, then tilt.
+ \value RollTiltPan Roll, then tilt, then pan.
+ \value RollPanTilt Roll, then pan, then tilt.
+*/
+
+/*!
+ Tilts the center() up or down by \a tiltAngle degrees,
+ pans the center() left or right by \a panAngle degrees,
+ and rolls the center() left or right by \a rollAngle degrees,
+ all in a single fluid movement. The \a order parameter
+ indicates the order in which to perform the rotations.
+
+ This function is accessible to QML on the Camera item.
+ It is provided as a convenience for navigation items that
+ rotate the center in multiple directions at the same time
+ based on mouse movements.
+
+ \sa tiltPanRollEye()
+*/
+void QGLCamera::tiltPanRollCenter
+ (qreal tiltAngle, qreal panAngle, qreal rollAngle,
+ QGLCamera::RotateOrder order)
+{
+ switch (order) {
+ case QGLCamera::TiltPanRoll:
+ rotateCenter(roll(rollAngle) * pan(panAngle) * tilt(tiltAngle));
+ break;
+ case QGLCamera::TiltRollPan:
+ rotateCenter(pan(panAngle) * roll(rollAngle) * tilt(tiltAngle));
+ break;
+ case QGLCamera::PanTiltRoll:
+ rotateCenter(roll(rollAngle) * tilt(tiltAngle) * pan(panAngle));
+ break;
+ case QGLCamera::PanRollTilt:
+ rotateCenter(tilt(tiltAngle) * roll(rollAngle) * pan(panAngle));
+ break;
+ case QGLCamera::RollTiltPan:
+ rotateCenter(pan(panAngle) * tilt(tiltAngle) * roll(rollAngle));
+ break;
+ case QGLCamera::RollPanTilt:
+ rotateCenter(tilt(tiltAngle) * pan(panAngle) * roll(rollAngle));
+ break;
+ }
+}
+
+/*!
+ Tilts the eye() up or down by \a tiltAngle degrees,
+ pans the eye() left or right by \a panAngle degrees,
+ and rolls the eye() left or right by \a rollAngle degrees,
+ all in a single fluid movement. The \a order parameter
+ indicates the order in which to perform the rotations.
+
+ This function is accessible to QML on the Camera item.
+ It is provided as a convenience for navigation items that
+ rotate the eye in multiple directions at the same time
+ based on mouse movements.
+
+ \sa tiltPanRollCenter()
+*/
+void QGLCamera::tiltPanRollEye
+ (qreal tiltAngle, qreal panAngle, qreal rollAngle,
+ QGLCamera::RotateOrder order)
+{
+ switch (order) {
+ case QGLCamera::TiltPanRoll:
+ rotateEye(roll(rollAngle) * pan(panAngle) * tilt(tiltAngle));
+ break;
+ case QGLCamera::TiltRollPan:
+ rotateEye(pan(panAngle) * roll(rollAngle) * tilt(tiltAngle));
+ break;
+ case QGLCamera::PanTiltRoll:
+ rotateEye(roll(rollAngle) * tilt(tiltAngle) * pan(panAngle));
+ break;
+ case QGLCamera::PanRollTilt:
+ rotateEye(tilt(tiltAngle) * roll(rollAngle) * pan(panAngle));
+ break;
+ case QGLCamera::RollTiltPan:
+ rotateEye(pan(panAngle) * tilt(tiltAngle) * roll(rollAngle));
+ break;
+ case QGLCamera::RollPanTilt:
+ rotateEye(tilt(tiltAngle) * pan(panAngle) * roll(rollAngle));
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/viewing/qglcamera.h b/src/threed/viewing/qglcamera.h
new file mode 100644
index 000000000..360712030
--- /dev/null
+++ b/src/threed/viewing/qglcamera.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCAMERA_H
+#define QGLCAMERA_H
+
+#include "qt3dglobal.h"
+#include "qglnamespace.h"
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qquaternion.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLCameraPrivate;
+class QGLPainter;
+
+class Q_QT3D_EXPORT QGLCamera : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(ProjectionType RotateOrder)
+ Q_PROPERTY(ProjectionType projectionType READ projectionType WRITE setProjectionType NOTIFY projectionChanged)
+ Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY projectionChanged)
+ Q_PROPERTY(qreal nearPlane READ nearPlane WRITE setNearPlane NOTIFY projectionChanged)
+ Q_PROPERTY(qreal farPlane READ farPlane WRITE setFarPlane NOTIFY projectionChanged)
+ Q_PROPERTY(QSizeF viewSize READ viewSize WRITE setViewSize NOTIFY projectionChanged SCRIPTABLE false)
+ Q_PROPERTY(QSizeF minViewSize READ minViewSize WRITE setMinViewSize NOTIFY projectionChanged SCRIPTABLE false)
+ Q_PROPERTY(int screenRotation READ screenRotation WRITE setScreenRotation NOTIFY projectionChanged SCRIPTABLE false)
+ Q_PROPERTY(QVector3D eye READ eye WRITE setEye NOTIFY viewChanged)
+ Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector NOTIFY viewChanged)
+ Q_PROPERTY(QVector3D center READ center WRITE setCenter NOTIFY viewChanged)
+ Q_PROPERTY(qreal eyeSeparation READ eyeSeparation WRITE setEyeSeparation NOTIFY viewChanged)
+ Q_PROPERTY(QVector3D motionAdjustment READ motionAdjustment WRITE setMotionAdjustment DESIGNABLE false NOTIFY viewChanged SCRIPTABLE false)
+ Q_PROPERTY(bool adjustForAspectRatio READ adjustForAspectRatio WRITE setAdjustForAspectRatio NOTIFY viewChanged)
+public:
+ explicit QGLCamera(QObject *parent = 0);
+ ~QGLCamera();
+
+ enum ProjectionType
+ {
+ Perspective,
+ Orthographic
+ };
+
+ QGLCamera::ProjectionType projectionType() const;
+ void setProjectionType(QGLCamera::ProjectionType value);
+
+ qreal fieldOfView() const;
+ void setFieldOfView(qreal angle);
+
+ qreal nearPlane() const;
+ void setNearPlane(qreal value);
+
+ qreal farPlane() const;
+ void setFarPlane(qreal value);
+
+ QSizeF viewSize() const;
+ void setViewSize(const QSizeF& size);
+
+ QSizeF minViewSize() const;
+ void setMinViewSize(const QSizeF& size);
+
+ int screenRotation() const;
+ void setScreenRotation(int angle);
+
+ QVector3D eye() const;
+ void setEye(const QVector3D& vertex);
+
+ QVector3D upVector() const;
+ void setUpVector(const QVector3D& vector);
+
+ QVector3D center() const;
+ void setCenter(const QVector3D& vertex);
+
+ qreal eyeSeparation() const;
+ void setEyeSeparation(qreal value);
+
+ QVector3D motionAdjustment() const;
+ void setMotionAdjustment(const QVector3D& vector);
+
+ bool adjustForAspectRatio() const;
+ void setAdjustForAspectRatio(bool value);
+
+ QQuaternion tilt(qreal angle) const;
+ QQuaternion pan(qreal angle) const;
+ QQuaternion roll(qreal angle) const;
+
+ void rotateEye(const QQuaternion& q);
+ void rotateCenter(const QQuaternion& q);
+
+ QVector3D translation(qreal x, qreal y, qreal z) const;
+
+ QMatrix4x4 projectionMatrix(qreal aspectRatio) const;
+ QMatrix4x4 modelViewMatrix(QGL::Eye eye = QGL::NoEye) const;
+
+ QVector3D mapPoint
+ (const QPoint& point, qreal aspectRatio,
+ const QSize& viewportSize) const;
+
+ enum RotateOrder
+ {
+ TiltPanRoll,
+ TiltRollPan,
+ PanTiltRoll,
+ PanRollTilt,
+ RollTiltPan,
+ RollPanTilt
+ };
+
+public Q_SLOTS:
+ void translateEye(qreal x, qreal y, qreal z);
+ void translateCenter(qreal x, qreal y, qreal z);
+
+ void tiltPanRollCenter(qreal tiltAngle, qreal panAngle, qreal rollAngle,
+ QGLCamera::RotateOrder order = TiltPanRoll);
+ void tiltPanRollEye(qreal tiltAngle, qreal panAngle, qreal rollAngle,
+ QGLCamera::RotateOrder order = TiltPanRoll);
+
+Q_SIGNALS:
+ void projectionChanged();
+ void viewChanged();
+
+private:
+ QGLCameraPrivate *d_ptr;
+
+ QGLCameraPrivate *d_func() const { return d_ptr; }
+
+ Q_DISABLE_COPY(QGLCamera)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/viewing/qglcameraanimation.cpp b/src/threed/viewing/qglcameraanimation.cpp
new file mode 100644
index 000000000..50fa6a76b
--- /dev/null
+++ b/src/threed/viewing/qglcameraanimation.cpp
@@ -0,0 +1,543 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcameraanimation.h"
+#include "qglcamera.h"
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLCameraAnimation
+ \brief The QGLCameraAnimation class implements smooth animations between two camera positions.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::viewing
+
+ QGLCameraAnimation modifies the camera() object to fall on a smooth
+ path between startEye(), startUpVector(), startCenter() and
+ endEye(), endUpVector(), endCenter. The animation will attempt to
+ keep the eye and center at the same relative distance from each other
+ throughout the animation, as though one object is flying around another.
+
+ \sa QGLCamera
+*/
+
+class QGLCameraAnimationPrivate
+{
+public:
+ enum PointOfRotation
+ {
+ Center,
+ CenterDual,
+ Eye,
+ EyeDual,
+ Both
+ };
+
+ QGLCameraAnimationPrivate()
+ : camera(0)
+ , startEye(0.0f, 0.0f, 10.f)
+ , startUpVector(0.0f, 1.0f, 0.0f)
+ , startCenter(0.0f, 0.0f, 0.0f)
+ , endEye(0.0f, 0.0f, 10.f)
+ , endUpVector(0.0f, 1.0f, 0.0f)
+ , endCenter(0.0f, 0.0f, 0.0f)
+ , duration(250)
+ , dirty(true)
+ , pointOfRotation(Both)
+ , lengthStart(1.0f)
+ , lengthEnd(1.0f)
+ {
+ }
+
+ QGLCamera *camera;
+ QVector3D startEye;
+ QVector3D startUpVector;
+ QVector3D startCenter;
+ QVector3D endEye;
+ QVector3D endUpVector;
+ QVector3D endCenter;
+ int duration;
+ bool dirty;
+ QEasingCurve easingCurve;
+
+ // Derived values for use during the animation.
+ PointOfRotation pointOfRotation;
+ QVector3D upVectorAxis;
+ qreal upVectorAngle;
+ QVector3D pointAxis;
+ qreal pointAngle;
+ QVector3D centerTranslate;
+ QVector3D eyeTranslate;
+ qreal lengthStart;
+ qreal lengthEnd;
+
+ static void rotateBetween(const QVector3D &start, const QVector3D &end,
+ const QVector3D &defaultAxis,
+ QVector3D *rotationAxis, qreal *rotationAngle);
+ void deriveRotations();
+};
+
+static inline bool fuzzyCompareVectors(const QVector3D &v1, const QVector3D &v2)
+{
+ return qAbs(v1.x() - v2.x()) <= 0.00001 &&
+ qAbs(v1.y() - v2.y()) <= 0.00001 &&
+ qAbs(v1.z() - v2.z()) <= 0.00001;
+}
+
+// Determine how to rotate between the "start" and "end" vectors.
+// We use the cross-product of the two vectors as the axis of rotation
+// or "defaultAxis" if the cross-product is zero (180 degree rotation).
+void QGLCameraAnimationPrivate::rotateBetween
+ (const QVector3D &start, const QVector3D &end, const QVector3D &defaultAxis,
+ QVector3D *rotationAxis, qreal *rotationAngle)
+{
+ QVector3D nstart = start.normalized();
+ QVector3D nend = end.normalized();
+ if (qFuzzyCompare(nstart, nend)) {
+ // Vectors are the same, so no rotation to perform.
+ *rotationAxis = QVector3D(0, 1, 0);
+ *rotationAngle = 0.0f;
+ } else {
+ QVector3D axis = QVector3D::crossProduct(nstart, nend);
+ if (qFuzzyIsNull(axis.x()) && qFuzzyIsNull(axis.y()) &&
+ qFuzzyIsNull(axis.z())) {
+ // Vectors are probably at 180 degrees to each other.
+ // We can pick either direction; arbitrarily pick anti-clockwise.
+ *rotationAxis = defaultAxis;
+ *rotationAngle = 180.0f;
+ } else {
+ // Compute the smallest angle between the two vectors
+ // from the cosine of the angle (i.e. the dot product).
+ *rotationAxis = axis;
+ *rotationAngle =
+ qAcos(QVector3D::dotProduct(nstart, nend)) * 180.0f / M_PI;
+ }
+ }
+}
+
+void QGLCameraAnimationPrivate::deriveRotations()
+{
+ // If the center points are the same, rotate the eye around the center.
+ // If the eye points are the same, rotate the center around the eye.
+ // If both are different, then interpolate along linear vectors.
+ if (qFuzzyCompare(startCenter, endCenter)) {
+ if (qFuzzyCompare(startEye, endEye)) {
+ // Center and eye both stay the same: nothing to do.
+ pointOfRotation = Both;
+ centerTranslate = QVector3D();
+ eyeTranslate = QVector3D();
+ } else {
+ // Centers are the same, rotate the eye position.
+ pointOfRotation = Center;
+ rotateBetween(startEye - startCenter, endEye - startCenter,
+ startUpVector, &pointAxis, &pointAngle);
+ lengthStart = (startEye - startCenter).length();
+ lengthEnd = (endEye - startCenter).length();
+
+ // Rotate the start up vector to the final position. If it is
+ // different than the end up vector, we need to perform the
+ // animation in two steps: rotate eye, then rotate up.
+ QQuaternion q =
+ QQuaternion::fromAxisAndAngle(pointAxis, pointAngle);
+ QVector3D up = q.rotatedVector(startUpVector);
+ if (!fuzzyCompareVectors(startUpVector, endUpVector) &&
+ !fuzzyCompareVectors(up, endUpVector)) {
+ pointOfRotation = CenterDual;
+ rotateBetween(up, endUpVector, endEye - endCenter,
+ &upVectorAxis, &upVectorAngle);
+ }
+ }
+ } else if (qFuzzyCompare(startEye, endEye)) {
+ // Eyes are the same, rotate the center position.
+ pointOfRotation = Eye;
+ rotateBetween(startCenter - startEye, endCenter - startEye,
+ startUpVector, &pointAxis, &pointAngle);
+ lengthStart = (startCenter - startEye).length();
+ lengthEnd = (startCenter - endEye).length();
+
+ // Rotate the start up vector to the final position. If it is
+ // different than the end up vector, we need to perform the
+ // animation in two steps: rotate eye, then rotate up.
+ QQuaternion q =
+ QQuaternion::fromAxisAndAngle(pointAxis, pointAngle);
+ QVector3D up = q.rotatedVector(startUpVector);
+ if (!fuzzyCompareVectors(startUpVector, endUpVector) &&
+ !fuzzyCompareVectors(up, endUpVector)) {
+ pointOfRotation = EyeDual;
+ rotateBetween(up, endUpVector, endCenter - endEye,
+ &upVectorAxis, &upVectorAngle);
+ }
+ } else {
+ // Both center and eye are changing, so perform a linear translation.
+ pointOfRotation = Both;
+ centerTranslate = endCenter - startCenter;
+ eyeTranslate = endEye - startEye;
+ }
+
+ // If we are doing a single movement, then determine how to
+ // rotate the up vector during the movement.
+ if (pointOfRotation != CenterDual) {
+ rotateBetween(startUpVector, endUpVector, startCenter - startEye,
+ &upVectorAxis, &upVectorAngle);
+ }
+}
+
+/*!
+ Constructs a new camera animation object and attaches it to \a parent.
+*/
+QGLCameraAnimation::QGLCameraAnimation(QObject *parent)
+ : QAbstractAnimation(parent)
+ , d_ptr(new QGLCameraAnimationPrivate)
+{
+}
+
+/*!
+ Destroys this camera animation object.
+*/
+QGLCameraAnimation::~QGLCameraAnimation()
+{
+}
+
+/*!
+ \property QGLCameraAnimation::camera
+ \brief the camera that will be animated by this animation object;
+ null if the camera has not yet been set.
+*/
+
+QGLCamera *QGLCameraAnimation::camera() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->camera;
+}
+
+void QGLCameraAnimation::setCamera(QGLCamera *camera)
+{
+ Q_D(QGLCameraAnimation);
+ d->camera = camera;
+}
+
+/*!
+ \property QGLCameraAnimation::startEye
+ \brief the position of the viewer's eye at the start of the animation.
+ The default value is (0, 0, 10).
+
+ \sa startUpVector(), startCenter(), endEye()
+*/
+
+QVector3D QGLCameraAnimation::startEye() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->startEye;
+}
+
+void QGLCameraAnimation::setStartEye(const QVector3D &eye)
+{
+ Q_D(QGLCameraAnimation);
+ d->startEye = eye;
+ d->dirty = true;
+}
+
+/*!
+ \property QGLCameraAnimation::startUpVector
+ \brief the up vector for the viewer at the start of the animation.
+ The default value is (0, 1, 0).
+
+ \sa startEye(), startCenter(), endUpVector()
+*/
+
+QVector3D QGLCameraAnimation::startUpVector() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->startUpVector;
+}
+
+void QGLCameraAnimation::setStartUpVector(const QVector3D &upVector)
+{
+ Q_D(QGLCameraAnimation);
+ d->startUpVector = upVector;
+ d->dirty = true;
+}
+
+/*!
+ \property QGLCameraAnimation::startCenter
+ \brief the center of the view visible from the viewer's position
+ at the start of the animation. The default value is (0, 0, 0).
+
+ \sa startEye(), startUpVector(), endCenter()
+*/
+
+QVector3D QGLCameraAnimation::startCenter() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->startCenter;
+}
+
+void QGLCameraAnimation::setStartCenter(const QVector3D &center)
+{
+ Q_D(QGLCameraAnimation);
+ d->startCenter = center;
+ d->dirty = true;
+}
+
+/*!
+ \property QGLCameraAnimation::endEye
+ \brief the position of the viewer's eye at the end of the animation.
+ The default value is (0, 0, 10).
+
+ \sa endUpVector(), endCenter(), startEye()
+*/
+
+QVector3D QGLCameraAnimation::endEye() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->endEye;
+}
+
+void QGLCameraAnimation::setEndEye(const QVector3D &eye)
+{
+ Q_D(QGLCameraAnimation);
+ d->endEye = eye;
+ d->dirty = true;
+}
+
+/*!
+ \property QGLCameraAnimation::endUpVector
+ \brief the up vector for the viewer at the end of the animation.
+ The default value is (0, 1, 0).
+
+ \sa endEye(), endCenter(), startUpVector()
+*/
+
+QVector3D QGLCameraAnimation::endUpVector() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->endUpVector;
+}
+
+void QGLCameraAnimation::setEndUpVector(const QVector3D &upVector)
+{
+ Q_D(QGLCameraAnimation);
+ d->endUpVector = upVector;
+ d->dirty = true;
+}
+
+/*!
+ \property QGLCameraAnimation::endCenter
+ \brief the center of the view visible from the viewer's position
+ at the end of the animation. The default value is (0, 0, 0).
+
+ \sa endEye(), endUpVector(), startCenter()
+*/
+
+QVector3D QGLCameraAnimation::endCenter() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->endCenter;
+}
+
+void QGLCameraAnimation::setEndCenter(const QVector3D &center)
+{
+ Q_D(QGLCameraAnimation);
+ d->endCenter = center;
+ d->dirty = true;
+}
+
+/*!
+ \property QGLCameraAnimation::duration
+ \brief the duration of the animation in milliseconds. The default
+ value is 250 milliseconds.
+
+ \sa easingCurve()
+*/
+
+int QGLCameraAnimation::duration() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->duration;
+}
+
+void QGLCameraAnimation::setDuration(int duration)
+{
+ Q_D(QGLCameraAnimation);
+ d->duration = duration;
+}
+
+/*!
+ \property QGLCameraAnimation::easingCurve
+ \brief the easing curve to use for the animation. The default
+ value is a linear easing curve.
+
+ \sa duration()
+*/
+
+QEasingCurve QGLCameraAnimation::easingCurve() const
+{
+ Q_D(const QGLCameraAnimation);
+ return d->easingCurve;
+}
+
+void QGLCameraAnimation::setEasingCurve(const QEasingCurve &easing)
+{
+ Q_D(QGLCameraAnimation);
+ d->easingCurve = easing;
+}
+
+/*!
+ \internal
+*/
+void QGLCameraAnimation::updateCurrentTime(int currentTime)
+{
+ Q_D(QGLCameraAnimation);
+ if (!d->camera)
+ return; // Nothing to do if no camera to modify.
+ if (currentTime >= d->duration) {
+ d->camera->setEye(d->endEye);
+ d->camera->setUpVector(d->endUpVector);
+ d->camera->setCenter(d->endCenter);
+ } else if (currentTime <= 0) {
+ d->camera->setEye(d->startEye);
+ d->camera->setUpVector(d->startUpVector);
+ d->camera->setCenter(d->startCenter);
+ } else {
+ // Derive the rotation parameters we need if arguments have changed.
+ if (d->dirty) {
+ d->dirty = false;
+ d->deriveRotations();
+ }
+
+ // Calculate the progress and modify it with the easing curve.
+ qreal progress = d->easingCurve.valueForProgress
+ (qreal(currentTime) / qreal(d->duration));
+
+ // Calculate the new eye and center locations.
+ QVector3D eye = d->startEye;
+ QVector3D center = d->startCenter;
+ QVector3D upVector = d->startUpVector;
+ if (d->pointOfRotation == QGLCameraAnimationPrivate::Center) {
+ QQuaternion q = QQuaternion::fromAxisAndAngle
+ (d->pointAxis, d->pointAngle * progress);
+ eye = q.rotatedVector(eye - d->startCenter);
+ if (d->lengthStart != d->lengthEnd) {
+ qreal length = (1.0f - progress) * d->lengthStart +
+ progress * d->lengthEnd;
+ eye = eye.normalized() * length;
+ }
+ eye += d->startCenter;
+ } else if (d->pointOfRotation == QGLCameraAnimationPrivate::CenterDual) {
+ if (progress < 0.5f) {
+ // First half of the animation - rotate the eye position.
+ QQuaternion q = QQuaternion::fromAxisAndAngle
+ (d->pointAxis, d->pointAngle * progress * 2.0f);
+ eye = q.rotatedVector(eye - d->startCenter);
+ if (d->lengthStart != d->lengthEnd) {
+ qreal length = (1.0f - progress) * d->lengthStart +
+ progress * d->lengthEnd;
+ eye = eye.normalized() * length;
+ }
+ eye += d->startCenter;
+ upVector = q.rotatedVector(upVector);
+ } else {
+ // Second half of the animation - rotate the up vector.
+ QQuaternion q = QQuaternion::fromAxisAndAngle
+ (d->upVectorAxis,
+ d->upVectorAngle * (progress - 0.5f) * 2.0f) *
+ QQuaternion::fromAxisAndAngle
+ (d->pointAxis, d->pointAngle);
+ eye = d->endEye;
+ upVector = q.rotatedVector(upVector);
+ }
+ } else if (d->pointOfRotation == QGLCameraAnimationPrivate::Eye) {
+ QQuaternion q = QQuaternion::fromAxisAndAngle
+ (d->pointAxis, d->pointAngle * progress);
+ center = q.rotatedVector(center - d->startEye);
+ if (d->lengthStart != d->lengthEnd) {
+ qreal length = (1.0f - progress) * d->lengthStart +
+ progress * d->lengthEnd;
+ center = center.normalized() * length;
+ }
+ center += d->startEye;
+ } else if (d->pointOfRotation == QGLCameraAnimationPrivate::EyeDual) {
+ if (progress < 0.5f) {
+ // First half of the animation - rotate the center position.
+ QQuaternion q = QQuaternion::fromAxisAndAngle
+ (d->pointAxis, d->pointAngle * progress * 2.0f);
+ center = q.rotatedVector(center - d->startEye);
+ if (d->lengthStart != d->lengthEnd) {
+ qreal length = (1.0f - progress) * d->lengthStart +
+ progress * d->lengthEnd;
+ center = center.normalized() * length;
+ }
+ center += d->startEye;
+ upVector = q.rotatedVector(upVector);
+ } else {
+ // Second half of the animation - rotate the up vector.
+ QQuaternion q = QQuaternion::fromAxisAndAngle
+ (d->upVectorAxis,
+ d->upVectorAngle * (progress - 0.5f) * 2.0f) *
+ QQuaternion::fromAxisAndAngle
+ (d->pointAxis, d->pointAngle);
+ center = d->endCenter;
+ upVector = q.rotatedVector(upVector);
+ }
+ } else {
+ eye += d->eyeTranslate * progress;
+ center += d->centerTranslate * progress;
+ }
+
+ // Calculate the new up vector for single-step animations.
+ if (d->pointOfRotation != QGLCameraAnimationPrivate::CenterDual &&
+ d->pointOfRotation != QGLCameraAnimationPrivate::EyeDual) {
+ if (d->upVectorAngle != 0.0f) {
+ QQuaternion q = QQuaternion::fromAxisAndAngle
+ (d->upVectorAxis, d->upVectorAngle * progress);
+ upVector = q.rotatedVector(upVector);
+ }
+ }
+
+ d->camera->setEye(eye);
+ d->camera->setUpVector(upVector);
+ d->camera->setCenter(center);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/threed/viewing/qglcameraanimation.h b/src/threed/viewing/qglcameraanimation.h
new file mode 100644
index 000000000..23172c66d
--- /dev/null
+++ b/src/threed/viewing/qglcameraanimation.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLCAMERAANIMATION_H
+#define QGLCAMERAANIMATION_H
+
+#include <QtCore/qabstractanimation.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtGui/qvector3d.h>
+#include "qt3dglobal.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLCamera;
+class QGLCameraAnimationPrivate;
+
+class Q_QT3D_EXPORT QGLCameraAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+ Q_PROPERTY(QGLCamera *camera READ camera WRITE setCamera)
+ Q_PROPERTY(QVector3D startEye READ startEye WRITE setStartEye)
+ Q_PROPERTY(QVector3D startUpVector READ startUpVector WRITE setStartUpVector)
+ Q_PROPERTY(QVector3D startCenter READ startCenter WRITE setStartCenter)
+ Q_PROPERTY(QVector3D endEye READ endEye WRITE setEndEye)
+ Q_PROPERTY(QVector3D endUpVector READ endUpVector WRITE setEndUpVector)
+ Q_PROPERTY(QVector3D endCenter READ endCenter WRITE setEndCenter)
+ Q_PROPERTY(int duration READ duration WRITE setDuration)
+ Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve)
+public:
+ explicit QGLCameraAnimation(QObject *parent = 0);
+ ~QGLCameraAnimation();
+
+ QGLCamera *camera() const;
+ void setCamera(QGLCamera *camera);
+
+ QVector3D startEye() const;
+ void setStartEye(const QVector3D &eye);
+
+ QVector3D startUpVector() const;
+ void setStartUpVector(const QVector3D &upVector);
+
+ QVector3D startCenter() const;
+ void setStartCenter(const QVector3D &center);
+
+ QVector3D endEye() const;
+ void setEndEye(const QVector3D &eye);
+
+ QVector3D endUpVector() const;
+ void setEndUpVector(const QVector3D &upVector);
+
+ QVector3D endCenter() const;
+ void setEndCenter(const QVector3D &center);
+
+ int duration() const;
+ void setDuration(int duration);
+
+ QEasingCurve easingCurve() const;
+ void setEasingCurve(const QEasingCurve &easing);
+
+protected:
+ void updateCurrentTime(int currentTime);
+
+private:
+ QScopedPointer<QGLCameraAnimationPrivate> d_ptr;
+
+ Q_DISABLE_COPY(QGLCameraAnimation)
+ Q_DECLARE_PRIVATE(QGLCameraAnimation)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/viewing/qglview.cpp b/src/threed/viewing/qglview.cpp
new file mode 100644
index 000000000..044aca960
--- /dev/null
+++ b/src/threed/viewing/qglview.cpp
@@ -0,0 +1,1475 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglview.h"
+#include "qglframebufferobject.h"
+#include "qglsubsurface.h"
+#include "qglmaskedsurface_p.h"
+#include "qglwidgetsurface.h"
+#include "qgldrawbuffersurface_p.h"
+#include <QtGui/qevent.h>
+#include <QtCore/qmap.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGLView
+ \brief The QGLView class extends QGLWidget with support for 3D viewing.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::viewing
+
+ \section1 Navigating
+
+ Navigation in 3D space is possible under keyboard and mouse control.
+
+ Holding down the left mouse button and dragging it will rotate the
+ camera() position around the object being viewed. Holding down the
+ left mouse button and the Shift key pans the view in a plane without
+ rotating the viewed object.
+
+ Using the mouse wheel, the view can be zoomed in or out. If the
+ system does not have a mouse wheel, then holding down the left mouse
+ button and the Control key and moving the mouse up and down will
+ also zoom in and out.
+
+ On the keyboard, the left, right, up, and down keys can also be used
+ to shift the camera() position around the object being viewed. Shift
+ and Control modify keys the same way they modify the left mouse
+ button above. Hitting the Home key will cause the camera position
+ to be reset to its original position.
+
+ \section1 Stereo viewing support
+
+ If the hardware supports stereo buffers, then each time the scene needs
+ to be painted, QGLView renders it twice: first from the perspective of
+ the left eye, and then from the perspective of the right eye.
+ The separation between the eye positions is specified by
+ QGLCamera::eyeSeparation(). If the eye separation is zero,
+ then stereo viewing is disabled and only a single image will
+ be rendered per frame.
+
+ Three kinds of stereo viewing are possible: hardware stereo,
+ anaglyph stereo, and double image stereo.
+
+ Hardware stereo relies upon specialized hardware that can render
+ the left and right eye images into separate buffers and then show
+ them independently to each eye through the use of polarized glasses
+ or similar technology. Hardware stereo is used if the \c{-stereo-hw}
+ command-line option is supplied or if the user explicitly requests
+ stereo buffers when the QGLView is constructed:
+
+ \code
+ QGLFormat format(QGLFormat::defaultFormat());
+ format.setOption(QGL::StereoBuffers);
+ QGLView view(format);
+ \endcode
+
+ Anaglyph stereo is used when the hardware doesn't have specialized
+ stereo buffer support. The left eye image is masked by a red
+ filter and the right eye image is masked by a cyan filter. This makes
+ the resulting images suitable for viewing with standard red-cyan
+ anaglyph glasses.
+
+ When using red-cyan anaglyphs, it is recommended that the
+ scene use non-primary object colors. Pure primary colors such
+ as red, green, and blue will only appear to one of the viewer's
+ eyes and will inhibit the 3D effect. Non-primary colors or
+ grayscale should be used to get the best effects.
+
+ Red-cyan anaglyphs can be disorienting to some viewers. If hardware
+ stereo is not available and stereo viewing is not critical to
+ the application, then stereo can be disabled by setting
+ QGLCamera::eyeSeparation() to zero.
+
+ Double image stereo involves drawing the left and right eye
+ images in a double-wide or double-high window, with the hardware
+ combining the images. Four different configurations are available:
+ LeftRight, RightLeft, TopBottom,
+ and BottomTop, according to the layout of the eye images.
+ Double image stereo is selected by calling setStereoType(). It is
+ the responsibility of the application to resize the window to
+ twice its normal size to accommodate the images.
+
+ Ctrl-Left and Ctrl-Right can be used to make the eye separation
+ smaller or larger under keyboard control.
+
+ A number of command-line options are available to select the
+ stereo mode of the QGLView so that the application does not
+ need to select the mode itself:
+
+ \table
+ \row \o \c{-stereo-hw} \o \l Hardware.
+ \row \o \c{-stereo-lr} \o LeftRight.
+ \row \o \c{-stereo-rl} \o RightLeft.
+ \row \o \c{-stereo-tb} \o TopBottom.
+ \row \o \c{-stereo-bt} \o BottomTop.
+ \row \o \c{-stereo-stretched-lr} \o StretchedLeftRight.
+ \row \o \c{-stereo-stretched-rl} \o StretchedRightLeft.
+ \row \o \c{-stereo-stretched-tb} \o StretchedTopBottom.
+ \row \o \c{-stereo-stretched-bt} \o StretchedBottomTop.
+ \endtable
+
+ The option can also be supplied in the \c{Quick3D_OPTIONS} environment
+ variable:
+
+ \code
+ $ Quick3D_OPTIONS="-stereo-lr" ./cubehouse
+ \endcode
+
+ If the application sets the stereo type with setStereoType(),
+ that will be used. Next is the command-line setting, and finally
+ the contents of the environment variable.
+
+ \sa {Stereo Viewing Example}
+*/
+
+/*!
+ \enum QGLView::Option
+ This enum defines an option for QGLView.
+
+ \value ObjectPicking Object picking is enabled. Disabled by default.
+ \value ShowPicking Objects are rendered with their pick colors instead
+ of their normal colors and materials. This can help debug
+ problems with object picking. Disabled by default.
+ \value CameraNavigation Camera navigation using the keyboard and mouse
+ is enabled. Enabled by default.
+ \omitvalue PaintingLog
+*/
+
+/*!
+ \enum QGLView::StereoType
+ This enum defines the type of stereo viewing technology being used by QGLView.
+
+ \value Hardware Specialized stereo hardware is being used.
+ \value RedCyanAnaglyph Stereo is being simulated for viewing by
+ red-cyan anaglyph classes.
+ \value LeftRight The view is double-wide with the left eye
+ image on the left of the window.
+ \value RightLeft The view is double-wide with the left eye
+ image on the right of the window.
+ \value TopBottom The view is double-high with the left eye
+ image on the top of the window.
+ \value BottomTop The view is double-high with the left eye
+ image on the bottom of the window.
+ \value StretchedLeftRight Same as LeftRight, but with the
+ left and right eye images stretched to double their width.
+ \value StretchedRightLeft Same as RightLeft, but with the
+ left and right eye images stretched to double their width.
+ \value StretchedTopBottom Same as TopBottom, but with the
+ left and right eye images stretched to double their height.
+ \value StretchedBottomTop Same as BottomTop, but with the
+ left and right eye images stretched to double their height.
+*/
+
+class QGLViewPrivate
+{
+public:
+ QGLViewPrivate(QGLView *parent)
+ : view(parent), mainSurface(parent)
+ {
+ options = QGLView::CameraNavigation;
+ fbo = 0;
+ leftSurface = 0;
+ rightSurface = 0;
+
+ if (parent->format().stereo())
+ stereoType = QGLView::Hardware;
+ else
+ stereoType = QGLView::RedCyanAnaglyph;
+
+ pickBufferForceUpdate = true;
+ pickBufferMaybeInvalid = true;
+ updateQueued = false;
+
+ pressedObject = 0;
+ pressedButton = Qt::NoButton;
+ enteredObject = 0;
+
+ defaultCamera = new QGLCamera(parent);
+ camera = defaultCamera;
+
+ panning = false;
+ startPan = QPoint(-1, -1);
+ lastPan = QPoint(-1, -1);
+ panModifiers = Qt::NoModifier;
+
+ QObject::connect(defaultCamera, SIGNAL(projectionChanged()),
+ parent, SLOT(cameraChanged()));
+ QObject::connect(defaultCamera, SIGNAL(viewChanged()),
+ parent, SLOT(cameraChanged()));
+
+ logTime.start();
+ lastFrameTime.start();
+ QByteArray env = qgetenv("Quick3D_LOG_EVENTS");
+ if (env == "1")
+ options |= QGLView::PaintingLog;
+ }
+ ~QGLViewPrivate()
+ {
+ delete fbo;
+ delete leftSurface;
+ delete rightSurface;
+ }
+
+ QGLView *view;
+ QGLView::Options options;
+ QGLView::StereoType stereoType;
+ QGLFramebufferObject *fbo;
+ QGLWidgetSurface mainSurface;
+ QGLAbstractSurface *leftSurface;
+ QGLAbstractSurface *rightSurface;
+ bool pickBufferForceUpdate;
+ bool pickBufferMaybeInvalid;
+ bool updateQueued;
+ QMap<int, QObject *> objects;
+ QObject *pressedObject;
+ Qt::MouseButton pressedButton;
+ QObject *enteredObject;
+ QGLCamera *defaultCamera;
+ QGLCamera *camera;
+ bool panning;
+ QPoint startPan;
+ QPoint lastPan;
+ QVector3D startEye;
+ QVector3D startCenter;
+ QVector3D startUpVector;
+ Qt::KeyboardModifiers panModifiers;
+ QTime logTime;
+ QTime enterTime;
+ QTime lastFrameTime;
+
+ inline void logEnter(const char *message);
+ inline void logLeave(const char *message);
+
+ void processStereoOptions(QGLView *view);
+ void processStereoOptions(QGLView *view, const QString &arg);
+
+ QGLAbstractSurface *leftEyeSurface(const QSize &size);
+ QGLAbstractSurface *rightEyeSurface(const QSize &size);
+ QGLAbstractSurface *bothEyesSurface();
+};
+
+inline void QGLViewPrivate::logEnter(const char *message)
+{
+ if ((options & QGLView::PaintingLog) == 0)
+ return;
+ int ms = logTime.elapsed();
+ enterTime.start();
+ int sinceLast = lastFrameTime.restart();
+ qDebug("LOG[%d:%02d:%02d.%03d]: ENTER: %s (%d ms since last enter)",
+ ms / 3600000, (ms / 60000) % 60,
+ (ms / 1000) % 60, ms % 1000, message, sinceLast);
+}
+
+inline void QGLViewPrivate::logLeave(const char *message)
+{
+ if ((options & QGLView::PaintingLog) == 0)
+ return;
+ int ms = logTime.elapsed();
+ int duration = enterTime.elapsed();
+ qDebug("LOG[%d:%02d:%02d.%03d]: LEAVE: %s (%d ms elapsed)",
+ ms / 3600000, (ms / 60000) % 60,
+ (ms / 1000) % 60, ms % 1000, message, duration);
+}
+
+static QString qt_gl_stereo_arg()
+{
+ QStringList args = QApplication::arguments();
+ foreach (QString arg, args) {
+ if (arg.startsWith(QLatin1String("-stereo-")))
+ return arg;
+ }
+ QByteArray options(qgetenv("Quick3D_OPTIONS"));
+ args = QString::fromLocal8Bit
+ (options.constData(), options.size()).split(QLatin1Char(' '));
+ foreach (QString arg, args) {
+ if (arg.startsWith(QLatin1String("-stereo-")))
+ return arg;
+ }
+ return QString();
+}
+
+void QGLViewPrivate::processStereoOptions(QGLView *view)
+{
+ if (stereoType == QGLView::Hardware)
+ return;
+ QString arg = qt_gl_stereo_arg();
+ if (!arg.isEmpty())
+ processStereoOptions(view, arg);
+}
+
+void QGLViewPrivate::processStereoOptions(QGLView *view, const QString &arg)
+{
+ // If the command-line contains an option that starts with "-stereo-",
+ // then convert it into options that define the size and type of
+ // stereo window to use for a top-level QGLView. Possible options:
+ //
+ // hw - use hardware stereo
+ // lr, rl, tb, bt - specify the eye order (default is left-right)
+ // stretched - used stretched versions of double wide/high modes.
+ //
+ QStringList opts = arg.mid(8).split(QLatin1Char('-'));
+ QGLView::StereoType stereoType;
+ bool stretched = opts.contains(QLatin1String("stretched"));
+ if (opts.contains(QLatin1String("rl"))) {
+ stereoType = stretched ? QGLView::StretchedRightLeft : QGLView::RightLeft;
+ } else if (opts.contains(QLatin1String("tb"))) {
+ stereoType = stretched ? QGLView::StretchedTopBottom : QGLView::TopBottom;
+ } else if (opts.contains(QLatin1String("bt"))) {
+ stereoType = stretched ? QGLView::StretchedBottomTop : QGLView::BottomTop;
+ } else {
+ stereoType = stretched ? QGLView::StretchedLeftRight : QGLView::LeftRight;
+ }
+ view->setStereoType(stereoType);
+}
+
+class QGLViewSubsurface : public QGLSubsurface
+{
+public:
+ QGLViewSubsurface(QGLAbstractSurface *surface, const QRect &region,
+ qreal adjust)
+ : QGLSubsurface(surface, region), m_adjust(adjust) {}
+
+ qreal aspectRatio() const;
+
+private:
+ qreal m_adjust;
+};
+
+qreal QGLViewSubsurface::aspectRatio() const
+{
+ return QGLSubsurface::aspectRatio() * m_adjust;
+}
+
+// Returns the surface to use to render the left eye image.
+QGLAbstractSurface *QGLViewPrivate::leftEyeSurface(const QSize &size)
+{
+ QRect viewport;
+ qreal adjust = 1.0f;
+ switch (stereoType) {
+ case QGLView::Hardware:
+#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT)
+ if (!leftSurface) {
+ leftSurface = new QGLDrawBufferSurface
+ (&mainSurface,
+ view->doubleBuffer() ? GL_BACK_LEFT : GL_FRONT_LEFT);
+ }
+ return leftSurface;
+#endif
+ case QGLView::RedCyanAnaglyph:
+ if (!leftSurface) {
+ leftSurface = new QGLMaskedSurface
+ (&mainSurface,
+ QGLMaskedSurface::RedMask | QGLMaskedSurface::AlphaMask);
+ }
+ return leftSurface;
+ case QGLView::LeftRight:
+ viewport = QRect(0, 0, size.width() / 2, size.height());
+ break;
+ case QGLView::RightLeft:
+ viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height());
+ break;
+ case QGLView::TopBottom:
+ viewport = QRect(0, 0, size.width(), size.height() / 2);
+ break;
+ case QGLView::BottomTop:
+ viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2);
+ break;
+ case QGLView::StretchedLeftRight:
+ viewport = QRect(0, 0, size.width() / 2, size.height());
+ adjust = 2.0f;
+ break;
+ case QGLView::StretchedRightLeft:
+ viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height());
+ adjust = 2.0f;
+ break;
+ case QGLView::StretchedTopBottom:
+ viewport = QRect(0, 0, size.width(), size.height() / 2);
+ adjust = 0.5f;
+ break;
+ case QGLView::StretchedBottomTop:
+ viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2);
+ adjust = 0.5f;
+ break;
+ }
+ if (!leftSurface) {
+ if (adjust == 1.0f)
+ leftSurface = new QGLSubsurface(&mainSurface, viewport);
+ else
+ leftSurface = new QGLViewSubsurface(&mainSurface, viewport, adjust);
+ } else {
+ static_cast<QGLSubsurface *>(leftSurface)->setRegion(viewport);
+ }
+ return leftSurface;
+}
+
+// Returns the surface to use to render the right eye image.
+QGLAbstractSurface *QGLViewPrivate::rightEyeSurface(const QSize &size)
+{
+ QRect viewport;
+ qreal adjust = 1.0f;
+ switch (stereoType) {
+ case QGLView::Hardware:
+#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT)
+ if (!rightSurface) {
+ rightSurface = new QGLDrawBufferSurface
+ (&mainSurface,
+ view->doubleBuffer() ? GL_BACK_RIGHT : GL_FRONT_RIGHT);
+ }
+ return rightSurface;
+#endif
+ case QGLView::RedCyanAnaglyph:
+ if (!rightSurface) {
+ rightSurface = new QGLMaskedSurface
+ (&mainSurface,
+ QGLMaskedSurface::GreenMask | QGLMaskedSurface::BlueMask);
+ }
+ return rightSurface;
+ case QGLView::LeftRight:
+ viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height());
+ break;
+ case QGLView::RightLeft:
+ viewport = QRect(0, 0, size.width() / 2, size.height());
+ break;
+ case QGLView::TopBottom:
+ viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2);
+ break;
+ case QGLView::BottomTop:
+ viewport = QRect(0, 0, size.width(), size.height() / 2);
+ break;
+ case QGLView::StretchedLeftRight:
+ viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height());
+ adjust = 2.0f;
+ break;
+ case QGLView::StretchedRightLeft:
+ viewport = QRect(0, 0, size.width() / 2, size.height());
+ adjust = 2.0f;
+ break;
+ case QGLView::StretchedTopBottom:
+ viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2);
+ adjust = 0.5f;
+ break;
+ case QGLView::StretchedBottomTop:
+ viewport = QRect(0, 0, size.width(), size.height() / 2);
+ adjust = 0.5f;
+ break;
+ }
+ if (!rightSurface) {
+ if (adjust == 1.0f)
+ rightSurface = new QGLSubsurface(&mainSurface, viewport);
+ else
+ rightSurface = new QGLViewSubsurface(&mainSurface, viewport, adjust);
+ } else {
+ static_cast<QGLSubsurface *>(rightSurface)->setRegion(viewport);
+ }
+ return rightSurface;
+}
+
+// Returns a surface that can be used to render a non-stereoscopic
+// image into both eyes at the same time. Returns null if the eyes
+// must be rendered one at a time.
+QGLAbstractSurface *QGLViewPrivate::bothEyesSurface()
+{
+ switch (stereoType) {
+ case QGLView::Hardware:
+#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT)
+ return 0;
+#endif
+ case QGLView::RedCyanAnaglyph:
+ return &mainSurface;
+ default:
+ return 0;
+ }
+}
+
+static QGLFormat makeStereoGLFormat(const QGLFormat& format)
+{
+#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT)
+ QGLFormat fmt(format);
+ if (qt_gl_stereo_arg() == QLatin1String("-stereo-hw"))
+ fmt.setOption(QGL::StereoBuffers);
+ return fmt;
+#else
+ QGLFormat fmt(format);
+ fmt.setOption(QGL::NoStereoBuffers);
+ return fmt;
+#endif
+}
+
+/*!
+ Constructs a new view widget and attaches it to \a parent.
+
+ This constructor will request a stereo rendering context if
+ the hardware supports it.
+*/
+QGLView::QGLView(QWidget *parent)
+ : QGLWidget(makeStereoGLFormat(QGLFormat::defaultFormat()), parent)
+{
+ d = new QGLViewPrivate(this);
+ setMouseTracking(true);
+ if (!parent)
+ d->processStereoOptions(this);
+}
+
+/*!
+ Constructs a new view widget and attaches it to \a parent.
+ The \a format argument specifies the desired QGLFormat
+ rendering options.
+
+ If \a format does not include the stereo option, then a stereo
+ viewing context will not be requested.
+*/
+QGLView::QGLView(const QGLFormat& format, QWidget *parent)
+ : QGLWidget(format, parent)
+{
+ d = new QGLViewPrivate(this);
+ setMouseTracking(true);
+ if (!parent)
+ d->processStereoOptions(this);
+}
+
+/*!
+ Destroys this view widget.
+*/
+QGLView::~QGLView()
+{
+ delete d;
+}
+
+/*!
+ Returns the options for this view. The default value is
+ CameraNavigation.
+
+ \sa setOptions(), setOption()
+*/
+QGLView::Options QGLView::options() const
+{
+ return d->options;
+}
+
+/*!
+ Sets the options for this view to \a value.
+
+ \sa options(), setOption()
+*/
+void QGLView::setOptions(QGLView::Options value)
+{
+ d->options = value;
+}
+
+/*!
+ Enables or disables \a option according to \a value.
+
+ \sa options(), setOptions()
+*/
+void QGLView::setOption(QGLView::Option option, bool value)
+{
+ if (value)
+ d->options |= option;
+ else
+ d->options &= ~option;
+}
+
+/*!
+ Returns the type of stereo viewing technology that is in use.
+
+ \sa setStereoType()
+*/
+QGLView::StereoType QGLView::stereoType() const
+{
+ return d->stereoType;
+}
+
+/*!
+ Sets the \a type of stereo viewing technology that is in use.
+ The request takes effect at the next repaint.
+
+ The request is ignored stereoType() or \a type is Hardware,
+ because hardware stereo can only be enabled if the hardware
+ supports it, and then it can never be disabled.
+
+ \sa stereoType()
+*/
+void QGLView::setStereoType(QGLView::StereoType type)
+{
+ if (d->stereoType == Hardware || type == Hardware)
+ return;
+ if (d->stereoType == type)
+ return;
+ d->stereoType = type;
+
+ // Destroy the current surface objects so that they will
+ // be re-generated the next time we paint the widget.
+ delete d->leftSurface;
+ delete d->rightSurface;
+ d->leftSurface = 0;
+ d->rightSurface = 0;
+}
+
+/*!
+ Registers an \a object with this view to be notified when
+ \a objectId is selected with the mouse. The \a object must
+ persist for the lifetime of the QGLView, or until
+ deregisterObject() is called for \a objectId.
+
+ \sa deregisterObject(), objectForPoint()
+*/
+void QGLView::registerObject(int objectId, QObject *object)
+{
+ d->objects[objectId] = object;
+}
+
+/*!
+ Deregisters the object associated with \a objectId.
+
+ \sa registerObject()
+*/
+void QGLView::deregisterObject(int objectId)
+{
+ d->objects.remove(objectId);
+}
+
+/*!
+ Returns the camera parameters. The camera defines the projection
+ to apply to convert eye co-ordinates into window co-ordinates,
+ and the position and orientation of the viewer's eye.
+
+ \sa setCamera()
+*/
+QGLCamera *QGLView::camera() const
+{
+ return d->camera;
+}
+
+/*!
+ Sets the camera parameters to \a value. The camera defines the
+ projection to apply to convert eye co-ordinates into window
+ co-ordinates, and the position and orientation of the viewer's eye.
+
+ If \a value is null, then the default camera object will be used.
+
+ This function will call update() to force the view to
+ update with the new camera parameters upon the next event loop.
+
+ \sa camera()
+*/
+void QGLView::setCamera(QGLCamera *value)
+{
+ if (!value)
+ value = d->defaultCamera;
+
+ if (d->camera == value)
+ return;
+
+ disconnect(d->camera, SIGNAL(projectionChanged()),
+ this, SLOT(cameraChanged()));
+ disconnect(d->camera, SIGNAL(viewChanged()),
+ this, SLOT(cameraChanged()));
+
+ d->camera = value;
+
+ connect(d->camera, SIGNAL(projectionChanged()),
+ this, SLOT(cameraChanged()));
+ connect(d->camera, SIGNAL(viewChanged()),
+ this, SLOT(cameraChanged()));
+
+ cameraChanged();
+}
+
+/*!
+ Maps \a point from viewport co-ordinates to eye co-ordinates.
+
+ The returned vector will have its x and y components set to the
+ position of the point on the near plane, and the z component
+ set to the inverse of the camera's near plane.
+
+ This function is used for converting a mouse event's position
+ into eye co-ordinates within the current camera view.
+
+ \sa QGLCamera::mapPoint()
+*/
+QVector3D QGLView::mapPoint(const QPoint &point) const
+{
+ QSize viewportSize(size());
+ qreal aspectRatio;
+
+ // Get the size of the underlying paint device.
+ int width = viewportSize.width();
+ int height = viewportSize.height();
+
+ // Use the device's DPI setting to determine the pixel aspect ratio.
+ int dpiX = logicalDpiX();
+ int dpiY = logicalDpiY();
+ if (dpiX <= 0 || dpiY <= 0)
+ dpiX = dpiY = 1;
+
+ // Derive the aspect ratio based on window and pixel size.
+ if (width <= 0 || height <= 0)
+ aspectRatio = 1.0f;
+ else
+ aspectRatio = ((qreal)(width * dpiY)) / ((qreal)(height * dpiX));
+
+ // Map the point into eye co-ordinates.
+ return d->camera->mapPoint(point, aspectRatio, viewportSize);
+}
+
+void QGLView::cameraChanged()
+{
+ // The pick buffer will need to be refreshed at the new camera position.
+ d->pickBufferForceUpdate = true;
+
+ // Queue an update for the next event loop.
+ update();
+}
+
+/*!
+ \internal
+*/
+void QGLView::initializeGL()
+{
+ d->logEnter("QGLView::initializeGL");
+ QGLPainter painter;
+ painter.begin();
+
+ // Set the default depth buffer options.
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDepthMask(GL_TRUE);
+#if defined(QT_OPENGL_ES)
+ glDepthRangef(0.0f, 1.0f);
+#else
+ glDepthRange(0.0f, 1.0f);
+#endif
+
+ // Set the default blend options.
+ if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendColor))
+ painter.glBlendColor(0, 0, 0, 0);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendEquation))
+ painter.glBlendEquation(GL_FUNC_ADD);
+ else if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendEquationSeparate))
+ painter.glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
+
+ glDisable(GL_CULL_FACE);
+ initializeGL(&painter);
+ d->logLeave("QGLView::initializeGL");
+}
+
+/*!
+ \internal
+*/
+void QGLView::resizeGL(int w, int h)
+{
+ // Set up the standard viewport for the new window size.
+ glViewport(0, 0, w, h);
+
+ // We will need to regenerate the pick buffer.
+ d->pickBufferForceUpdate = true;
+}
+
+/*!
+ \internal
+*/
+void QGLView::paintGL()
+{
+ d->logEnter("QGLView::paintGL");
+ // We may need to regenerate the pick buffer on the next mouse event.
+ d->pickBufferMaybeInvalid = true;
+
+ // Paint the scene contents.
+ QGLPainter painter;
+ QGLAbstractSurface *surface;
+ painter.begin();
+ if (d->options & QGLView::ShowPicking &&
+ d->stereoType == QGLView::RedCyanAnaglyph) {
+ // If showing picking, then render normally. This really
+ // only works if we aren't using hardware or double stereo.
+ painter.setPicking(true);
+ painter.clearPickObjects();
+ painter.setEye(QGL::NoEye);
+ earlyPaintGL(&painter);
+ painter.setCamera(d->camera);
+ paintGL(&painter);
+ painter.setPicking(false);
+ } else if (d->camera->eyeSeparation() == 0.0f &&
+ (surface = d->bothEyesSurface()) != 0) {
+ // No camera separation, so render the same image into both buffers.
+ painter.pushSurface(surface);
+ painter.setEye(QGL::NoEye);
+ earlyPaintGL(&painter);
+ painter.setCamera(d->camera);
+ paintGL(&painter);
+ painter.popSurface();
+ } else {
+ // Paint the scene twice, from the perspective of each camera.
+ QSize size(this->size());
+ painter.setEye(QGL::LeftEye);
+ if (d->stereoType != QGLView::Hardware)
+ earlyPaintGL(&painter); // Clear both eyes at the same time.
+ painter.pushSurface(d->leftEyeSurface(size));
+ if (d->stereoType == QGLView::Hardware)
+ earlyPaintGL(&painter); // Clear the left eye only.
+ earlyPaintGL(&painter);
+ painter.setCamera(d->camera);
+ paintGL(&painter);
+ if (d->stereoType == QGLView::RedCyanAnaglyph)
+ glClear(GL_DEPTH_BUFFER_BIT);
+ painter.setEye(QGL::RightEye);
+ painter.setSurface(d->rightEyeSurface(size));
+ if (d->stereoType == QGLView::Hardware)
+ earlyPaintGL(&painter); // Clear the right eye only.
+ painter.setCamera(d->camera);
+ paintGL(&painter);
+ painter.popSurface();
+ }
+ d->logLeave("QGLView::paintGL");
+}
+
+/*!
+ Initializes the current GL context represented by \a painter.
+
+ \sa paintGL()
+*/
+void QGLView::initializeGL(QGLPainter *painter)
+{
+ Q_UNUSED(painter);
+}
+
+/*!
+ Performs early painting operations just after \a painter
+ is initialized but before the camera is set up. The default
+ implementation clears the color buffer and depth buffer.
+
+ This function is typically overridden to draw scene backdrops
+ on the color buffer before the rest of the scene is drawn
+ by paintGL().
+
+ \sa paintGL()
+*/
+void QGLView::earlyPaintGL(QGLPainter *painter)
+{
+ Q_UNUSED(painter);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+/*!
+ \fn void QGLView::paintGL(QGLPainter *painter)
+
+ Paints the scene onto \a painter. The color and depth buffers
+ will have already been cleared, and the camera() position set.
+
+ If QGLPainter::isPicking() is set for \a painter, then the
+ function should paint the scene onto \a painter in
+ "object picking mode". The scene will be rendered into a
+ background buffer using flat colors so that mouse events
+ can determine which object lies under the mouse pointer.
+
+ The default implementation of picking will typically just
+ render the scene normally. However, some applications
+ may wish to render a simpler scene that omits unselectable
+ objects and uses simpler meshes for the selectable objects.
+
+ \sa earlyPaintGL()
+*/
+
+/*!
+ Processes the mouse press event \a e.
+*/
+void QGLView::mousePressEvent(QMouseEvent *e)
+{
+ QObject *object;
+ if (!d->panning && (d->options & QGLView::ObjectPicking) != 0)
+ object = objectForPoint(e->pos());
+ else
+ object = 0;
+ if (d->pressedObject) {
+ // Send the press event to the pressed object. Use a position
+ // of (0, 0) if the mouse is still within the pressed object,
+ // or (-1, -1) if the mouse is no longer within the pressed object.
+ QMouseEvent event
+ (QEvent::MouseButtonPress,
+ (d->pressedObject == object) ? QPoint(0, 0) : QPoint(-1, -1),
+ e->globalPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(d->pressedObject, &event);
+ } else if (object) {
+ // Record the object that was pressed and forward the event.
+ d->pressedObject = object;
+ d->enteredObject = 0;
+ d->pressedButton = e->button();
+
+ // Send a mouse press event for (0, 0).
+ QMouseEvent event(QEvent::MouseButtonPress, QPoint(0, 0),
+ e->globalPos(), e->button(), e->buttons(),
+ e->modifiers());
+ QCoreApplication::sendEvent(object, &event);
+ } else if ((d->options & QGLView::CameraNavigation) != 0 &&
+ e->button() == Qt::LeftButton) {
+ d->panning = true;
+ d->lastPan = d->startPan = e->pos();
+ d->startEye = d->camera->eye();
+ d->startCenter = d->camera->center();
+ d->startUpVector = d->camera->upVector();
+ d->panModifiers = e->modifiers();
+#ifndef QT_NO_CURSOR
+ setCursor(Qt::ClosedHandCursor);
+#endif
+ }
+ QGLWidget::mousePressEvent(e);
+}
+
+/*!
+ Processes the mouse release event \a e.
+*/
+void QGLView::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (d->panning && e->button() == Qt::LeftButton) {
+ d->panning = false;
+#ifndef QT_NO_CURSOR
+ unsetCursor();
+#endif
+ }
+ if (d->pressedObject) {
+ // Notify the previously pressed object about the release.
+ QObject *object = objectForPoint(e->pos());
+ QObject *pressed = d->pressedObject;
+ if (e->button() == d->pressedButton) {
+ d->pressedObject = 0;
+ d->pressedButton = Qt::NoButton;
+ d->enteredObject = object;
+
+ // Send the release event to the pressed object. Use a position
+ // of (0, 0) if the mouse is still within the pressed object,
+ // or (-1, -1) if the mouse is no longer within the pressed object.
+ QMouseEvent event
+ (QEvent::MouseButtonRelease,
+ (pressed == object) ? QPoint(0, 0) : QPoint(-1, -1),
+ e->globalPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(pressed, &event);
+
+ // Send leave and enter events if necessary.
+ if (object != pressed) {
+ sendLeaveEvent(pressed);
+ if (object)
+ sendEnterEvent(object);
+ }
+ } else {
+ // Some other button than the original was released.
+ // Forward the event to the pressed object.
+ QMouseEvent event
+ (QEvent::MouseButtonRelease,
+ (pressed == object) ? QPoint(0, 0) : QPoint(-1, -1),
+ e->globalPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(pressed, &event);
+ }
+ }
+ QGLWidget::mouseReleaseEvent(e);
+}
+
+/*!
+ Processes the mouse double click event \a e.
+*/
+void QGLView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ if ((d->options & QGLView::ObjectPicking) != 0) {
+ QObject *object = objectForPoint(e->pos());
+ if (object) {
+ // Simulate a double click event for (0, 0).
+ QMouseEvent event
+ (QEvent::MouseButtonDblClick, QPoint(0, 0),
+ e->globalPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(object, &event);
+ }
+ }
+ QGLWidget::mouseDoubleClickEvent(e);
+}
+
+/*!
+ Processes the mouse move event \a e.
+*/
+void QGLView::mouseMoveEvent(QMouseEvent *e)
+{
+ if (d->panning) {
+ QPoint delta = e->pos() - d->startPan;
+ if (e->modifiers() == d->panModifiers) {
+ d->camera->setEye(d->startEye);
+ d->camera->setCenter(d->startCenter);
+ d->camera->setUpVector(d->startUpVector);
+ } else {
+ d->startPan = d->lastPan;
+ delta = e->pos() - d->startPan;
+ d->startEye = d->camera->eye();
+ d->startCenter = d->camera->center();
+ d->startUpVector = d->camera->upVector();
+ d->panModifiers = e->modifiers();
+ }
+ d->lastPan = e->pos();
+ if ((e->modifiers() & Qt::ControlModifier) != 0)
+ wheel(delta.y() * -60);
+ else if ((e->modifiers() & Qt::ShiftModifier) != 0)
+ pan(delta.x(), delta.y());
+ else
+ rotate(delta.x(), delta.y());
+ } else if ((d->options & QGLView::ObjectPicking) != 0) {
+ QObject *object = objectForPoint(e->pos());
+ if (d->pressedObject) {
+ // Send the move event to the pressed object. Use a position
+ // of (0, 0) if the mouse is still within the pressed object,
+ // or (-1, -1) if the mouse is no longer within the pressed object.
+ QMouseEvent event
+ (QEvent::MouseMove,
+ (d->pressedObject == object) ? QPoint(0, 0) : QPoint(-1, -1),
+ e->globalPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(d->pressedObject, &event);
+ } else if (object) {
+ if (object != d->enteredObject) {
+ if (d->enteredObject)
+ sendLeaveEvent(d->enteredObject);
+ d->enteredObject = object;
+ sendEnterEvent(d->enteredObject);
+ }
+ QMouseEvent event
+ (QEvent::MouseMove, QPoint(0, 0),
+ e->globalPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(object, &event);
+ } else if (d->enteredObject) {
+ sendLeaveEvent(d->enteredObject);
+ d->enteredObject = 0;
+ }
+ }
+ QGLWidget::mouseMoveEvent(e);
+}
+
+/*!
+ Processes the leave event \a e.
+*/
+void QGLView::leaveEvent(QEvent *e)
+{
+ if (!d->pressedObject && d->enteredObject) {
+ sendLeaveEvent(d->enteredObject);
+ d->enteredObject = 0;
+ }
+ QGLWidget::leaveEvent(e);
+}
+
+#ifndef QT_NO_WHEELEVENT
+
+/*!
+ Processes the wheel event \a e.
+*/
+void QGLView::wheelEvent(QWheelEvent *e)
+{
+ if ((d->options & QGLView::CameraNavigation) != 0)
+ wheel(e->delta());
+ QGLWidget::wheelEvent(e);
+}
+
+#endif
+
+/*!
+ Processes the key press event \a e.
+*/
+void QGLView::keyPressEvent(QKeyEvent *e)
+{
+ QGLCamera *camera;
+ qreal sep;
+
+ if ((d->options & QGLView::CameraNavigation) == 0) {
+ QGLWidget::keyPressEvent(e);
+ return;
+ }
+ switch (e->key()) {
+
+ case Qt::Key_Escape:
+ case Qt::Key_Q:
+ {
+ if (parentWidget() == 0)
+ close();
+ }
+
+ case Qt::Key_Left:
+ {
+ if ((e->modifiers() & Qt::ShiftModifier) != 0) {
+ pan(-10, 0);
+ } else if ((e->modifiers() & Qt::ControlModifier) != 0) {
+ camera = this->camera();
+ sep = camera->eyeSeparation();
+ sep -= (sep / 10.0f);
+ if (sep < 0.0f)
+ sep = 0.0f;
+ camera->setEyeSeparation(sep);
+ e->accept();
+ return;
+ } else {
+ rotate(-10, 0);
+ }
+ }
+ break;
+
+ case Qt::Key_Right:
+ {
+ if ((e->modifiers() & Qt::ShiftModifier) != 0) {
+ pan(10, 0);
+ } else if ((e->modifiers() & Qt::ControlModifier) != 0) {
+ camera = this->camera();
+ sep = camera->eyeSeparation();
+ sep += (sep / 10.0f);
+ camera->setEyeSeparation(sep);
+ e->accept();
+ return;
+ } else {
+ rotate(10, 0);
+ }
+ }
+ break;
+
+ case Qt::Key_Up:
+ {
+ if ((e->modifiers() & Qt::ControlModifier) != 0)
+ wheel(120);
+ else if ((e->modifiers() & Qt::ShiftModifier) != 0)
+ pan(0, -10);
+ else
+ rotate(0, -10);
+ }
+ break;
+
+ case Qt::Key_Down:
+ {
+ if ((e->modifiers() & Qt::ControlModifier) != 0)
+ wheel(-120);
+ else if ((e->modifiers() & Qt::ShiftModifier) != 0)
+ pan(0, 10);
+ else
+ rotate(0, 10);
+ }
+ break;
+ }
+ QGLWidget::keyPressEvent(e);
+}
+
+class QGLViewPickSurface : public QGLAbstractSurface
+{
+public:
+ QGLViewPickSurface(QGLView *view, QGLFramebufferObject *fbo,
+ const QSize &areaSize);
+
+ QPaintDevice *device() const;
+ bool activate(QGLAbstractSurface *prevSurface);
+ void deactivate(QGLAbstractSurface *nextSurface);
+ QRect viewportGL() const;
+
+private:
+ QGLView *m_view;
+ QGLFramebufferObject *m_fbo;
+ QRect m_viewportGL;
+};
+
+QGLViewPickSurface::QGLViewPickSurface
+ (QGLView *view, QGLFramebufferObject *fbo, const QSize &areaSize)
+ : QGLAbstractSurface(504)
+ , m_view(view)
+ , m_fbo(fbo)
+ , m_viewportGL(QPoint(0, 0), areaSize)
+{
+}
+
+QPaintDevice *QGLViewPickSurface::device() const
+{
+ return m_view;
+}
+
+bool QGLViewPickSurface::activate(QGLAbstractSurface *prevSurface)
+{
+ Q_UNUSED(prevSurface);
+ if (m_fbo)
+ m_fbo->bind();
+ return true;
+}
+
+void QGLViewPickSurface::deactivate(QGLAbstractSurface *nextSurface)
+{
+ Q_UNUSED(nextSurface);
+ if (m_fbo)
+ m_fbo->release();
+}
+
+QRect QGLViewPickSurface::viewportGL() const
+{
+ return m_viewportGL;
+}
+
+/*!
+ Returns the registered object that is under the mouse position
+ specified by \a point. This function may need to regenerate
+ the contents of the pick buffer by repainting the scene
+ with paintGL().
+
+ \sa registerObject()
+*/
+QObject *QGLView::objectForPoint(const QPoint &point)
+{
+ QPoint pt(point);
+
+ // What is the size of the drawing area after correcting for stereo?
+ // Also adjust the mouse position to always be in the left half.
+ QSize areaSize = size();
+ switch (d->stereoType) {
+ case QGLView::LeftRight:
+ case QGLView::RightLeft:
+ areaSize = QSize(areaSize.width() / 2, areaSize.height());
+ if (pt.x() >= areaSize.width())
+ pt.setX(pt.x() - areaSize.width());
+ break;
+ case QGLView::TopBottom:
+ case QGLView::BottomTop:
+ areaSize = QSize(areaSize.width(), areaSize.height() / 2);
+ if (pt.y() >= areaSize.height())
+ pt.setY(pt.y() - areaSize.height());
+ break;
+ case QGLView::StretchedLeftRight:
+ case QGLView::StretchedRightLeft: {
+ int halfwid = areaSize.width() / 2;
+ if (pt.x() >= halfwid)
+ pt.setX((pt.x() - halfwid) * 2);
+ else
+ pt.setX(pt.x() * 2);
+ break; }
+ case QGLView::StretchedTopBottom:
+ case QGLView::StretchedBottomTop: {
+ int halfht = areaSize.height() / 2;
+ if (pt.y() >= halfht)
+ pt.setY((pt.y() - halfht) * 2);
+ else
+ pt.setY(pt.y() * 2);
+ break; }
+ default: break;
+ }
+
+ // Check the area boundaries in case a mouse move has
+ // moved the pointer outside the window.
+ if (pt.x() < 0 || pt.x() >= areaSize.width() ||
+ pt.y() < 0 || pt.y() >= areaSize.height())
+ return 0;
+
+ // Do we need to refresh the pick buffer contents?
+ QGLPainter painter(this);
+ if (d->pickBufferForceUpdate) {
+ // Initialize the painter, which will make the window context current.
+ painter.setPicking(true);
+ painter.clearPickObjects();
+
+ // Create a framebuffer object as big as the window to act
+ // as the pick buffer if we are single buffered. If we are
+ // double-buffered, then use the window back buffer.
+ bool useBackBuffer = doubleBuffer();
+ if (!useBackBuffer) {
+ QSize fbosize = QGL::nextPowerOfTwo(areaSize);
+ if (!d->fbo) {
+ d->fbo = new QGLFramebufferObject(fbosize, QGLFramebufferObject::CombinedDepthStencil);
+ } else if (d->fbo->size() != fbosize) {
+ delete d->fbo;
+ d->fbo = new QGLFramebufferObject(fbosize, QGLFramebufferObject::CombinedDepthStencil);
+ }
+ }
+
+ // Render the pick version of the scene.
+ QGLViewPickSurface surface(this, d->fbo, areaSize);
+ painter.pushSurface(&surface);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ painter.setEye(QGL::NoEye);
+ painter.setCamera(d->camera);
+ paintGL(&painter);
+ painter.setPicking(false);
+ painter.popSurface();
+
+ // The pick buffer contents are now valid, unless we are using
+ // the back buffer - we cannot rely upon it being valid next time.
+ d->pickBufferForceUpdate = useBackBuffer;
+ d->pickBufferMaybeInvalid = false;
+ }
+
+ // Pick the object under the mouse.
+ if (d->fbo)
+ d->fbo->bind();
+ int objectId = painter.pickObject(pt.x(), areaSize.height() - 1 - pt.y());
+ QObject *object = d->objects.value(objectId, 0);
+ if (d->fbo)
+ d->fbo->release();
+
+ // Release the framebuffer object and return.
+ painter.end();
+ doneCurrent();
+ return object;
+}
+
+void QGLView::sendEnterEvent(QObject *object)
+{
+ QEvent event(QEvent::Enter);
+ QCoreApplication::sendEvent(object, &event);
+}
+
+void QGLView::sendLeaveEvent(QObject *object)
+{
+ QEvent event(QEvent::Leave);
+ QCoreApplication::sendEvent(object, &event);
+}
+
+// Zoom in and out according to the change in wheel delta.
+void QGLView::wheel(int delta)
+{
+ qreal scale = qAbs(viewDelta(delta, delta).x());
+ if (delta < 0)
+ scale = -scale;
+ if (scale >= 0.0f)
+ scale += 1.0f;
+ else
+ scale = 1.0f / (1.0f - scale);
+ qreal fov = d->camera->fieldOfView();
+ if (fov != 0.0f)
+ d->camera->setFieldOfView(d->camera->fieldOfView() / scale);
+ else
+ d->camera->setViewSize(d->camera->viewSize() / scale);
+}
+
+// Pan left/right/up/down without rotating about the object.
+void QGLView::pan(int deltax, int deltay)
+{
+ QPointF delta = viewDelta(deltax, deltay);
+ QVector3D t = d->camera->translation(delta.x(), -delta.y(), 0.0f);
+
+ // Technically panning the eye left should make the object appear to
+ // move off to the right, but this looks weird on-screen where the user
+ // actually thinks they are picking up the object and dragging it rather
+ // than moving the eye. We therefore apply the inverse of the translation
+ // to make it "look right".
+ d->camera->setEye(d->camera->eye() - t);
+ d->camera->setCenter(d->camera->center() - t);
+}
+
+// Rotate about the object being viewed.
+void QGLView::rotate(int deltax, int deltay)
+{
+ int rotation = d->camera->screenRotation();
+ if (rotation == 90 || rotation == 270) {
+ qSwap(deltax, deltay);
+ }
+ if (rotation == 90 || rotation == 180) {
+ deltax = -deltax;
+ }
+ if (rotation == 180 || rotation == 270) {
+ deltay = -deltay;
+ }
+ qreal anglex = deltax * 90.0f / width();
+ qreal angley = deltay * 90.0f / height();
+ QQuaternion q = d->camera->pan(-anglex);
+ q *= d->camera->tilt(-angley);
+ d->camera->rotateCenter(q);
+}
+
+/*!
+ Converts \a deltax and \a deltay into percentages of the
+ view width and height. Returns a QPointF containing the
+ percentage values, typically between -1 and 1.
+
+ This function is typically used by subclasses to convert a
+ change in mouse position into a relative distance travelled
+ across the field of view.
+
+ The returned value is corrected for the camera() screen
+ rotation and view size.
+*/
+QPointF QGLView::viewDelta(int deltax, int deltay) const
+{
+ int w = width();
+ int h = height();
+ bool scaleToWidth;
+ qreal scaleFactor, scaleX, scaleY;
+ QSizeF viewSize = d->camera->viewSize();
+ if (w >= h) {
+ if (viewSize.width() >= viewSize.height())
+ scaleToWidth = true;
+ else
+ scaleToWidth = false;
+ } else {
+ if (viewSize.width() >= viewSize.height())
+ scaleToWidth = false;
+ else
+ scaleToWidth = true;
+ }
+ int rotation = d->camera->screenRotation();
+ if (rotation == 90 || rotation == 270) {
+ scaleToWidth = !scaleToWidth;
+ qSwap(deltax, deltay);
+ }
+ if (rotation == 90 || rotation == 180) {
+ deltax = -deltax;
+ }
+ if (rotation == 180 || rotation == 270) {
+ deltay = -deltay;
+ }
+ if (scaleToWidth) {
+ scaleFactor = 2.0f / viewSize.width();
+ scaleX = scaleFactor * ((qreal)h) / ((qreal)w);
+ scaleY = scaleFactor;
+ } else {
+ scaleFactor = 2.0f / viewSize.height();
+ scaleX = scaleFactor;
+ scaleY = scaleFactor * ((qreal)w) / ((qreal)h);
+ }
+ return QPointF(deltax * scaleX / w, deltay * scaleY / h);
+}
+
+/*!
+ \fn QPointF QGLView::viewDelta(const QPoint &delta) const
+ \overload
+
+ Converts the x and y components of \a delta into percentages
+ of the view width and height. Returns a QPointF containing
+ the percentage values, typically between -1 and 1.
+*/
+
+
+QT_END_NAMESPACE
diff --git a/src/threed/viewing/qglview.h b/src/threed/viewing/qglview.h
new file mode 100644
index 000000000..bd5934335
--- /dev/null
+++ b/src/threed/viewing/qglview.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLVIEW_H
+#define QGLVIEW_H
+
+#include "qglpainter.h"
+#include "qglcamera.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+class QGLViewPrivate;
+
+class Q_QT3D_EXPORT QGLView : public QGLWidget
+{
+ Q_OBJECT
+public:
+ explicit QGLView(QWidget *parent=0);
+ explicit QGLView(const QGLFormat& format, QWidget *parent=0);
+ ~QGLView();
+
+ enum Option
+ {
+ ObjectPicking = 0x0001,
+ ShowPicking = 0x0002,
+ CameraNavigation = 0x0004,
+ PaintingLog = 0x0008
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ QGLView::Options options() const;
+ void setOptions(QGLView::Options value);
+ void setOption(QGLView::Option option, bool value);
+
+ enum StereoType
+ {
+ Hardware,
+ RedCyanAnaglyph,
+ LeftRight,
+ RightLeft,
+ TopBottom,
+ BottomTop,
+ StretchedLeftRight,
+ StretchedRightLeft,
+ StretchedTopBottom,
+ StretchedBottomTop
+ };
+
+ QGLView::StereoType stereoType() const;
+ void setStereoType(QGLView::StereoType type);
+
+ void registerObject(int objectId, QObject *object);
+ void deregisterObject(int objectId);
+ QObject *objectForPoint(const QPoint &point);
+
+ QGLCamera *camera() const;
+ void setCamera(QGLCamera *camera);
+
+ QVector3D mapPoint(const QPoint &point) const;
+
+protected:
+ void initializeGL();
+ void resizeGL(int w, int h);
+ void paintGL();
+ virtual void initializeGL(QGLPainter *painter);
+ virtual void earlyPaintGL(QGLPainter *painter);
+ virtual void paintGL(QGLPainter *painter) = 0;
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseDoubleClickEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void leaveEvent(QEvent *e);
+#ifndef QT_NO_WHEELEVENT
+ void wheelEvent(QWheelEvent *e);
+#endif
+ void keyPressEvent(QKeyEvent *e);
+
+ QPointF viewDelta(int deltax, int deltay) const;
+ QPointF viewDelta(const QPoint &delta) const
+ { return viewDelta(delta.x(), delta.y()); }
+
+private Q_SLOTS:
+ void cameraChanged();
+
+private:
+ QGLViewPrivate *d;
+
+ static void sendEnterEvent(QObject *object);
+ static void sendLeaveEvent(QObject *object);
+
+ void wheel(int delta);
+ void pan(int deltax, int deltay);
+ void rotate(int deltax, int deltay);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLView::Options)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/threed/viewing/viewing.pri b/src/threed/viewing/viewing.pri
new file mode 100644
index 000000000..60125f491
--- /dev/null
+++ b/src/threed/viewing/viewing.pri
@@ -0,0 +1,12 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+
+HEADERS += \
+ qglcamera.h \
+ qglcameraanimation.h \
+ qglview.h
+
+SOURCES += \
+ qglcamera.cpp \
+ qglcameraanimation.cpp \
+ qglview.cpp