summaryrefslogtreecommitdiff
path: root/cogl
diff options
context:
space:
mode:
authorRui Matos <tiagomatos@gmail.com>2016-04-22 16:44:31 +0200
committerRui Matos <tiagomatos@gmail.com>2016-04-22 16:44:31 +0200
commit2d2835f02a80cc34feb5c4384a6a75c2406d4381 (patch)
treeb3c362ca6331b664524796ad04f7bd6e910875c1 /cogl
parente6b14a36c55ecc3b077b5c9d21d1ad6d493f438d (diff)
downloadmutter-2d2835f02a80cc34feb5c4384a6a75c2406d4381.tar.gz
move everything into a cogl/ directory
Diffstat (limited to 'cogl')
-rw-r--r--cogl/.gitignore107
-rw-r--r--cogl/Makefile.am560
-rw-r--r--cogl/build/autotools/Makefile.am.enums52
-rw-r--r--cogl/build/autotools/as-compiler-flag.m462
-rw-r--r--cogl/build/autotools/introspection.m494
-rw-r--r--cogl/cogl-gles2/GLES2/gl2.h169
-rw-r--r--cogl/cogl-gles2/GLES2/gl2ext.h1498
-rw-r--r--cogl/cogl-gles2/GLES2/gl2platform.h28
-rw-r--r--cogl/cogl-gles2/Makefile.am31
-rw-r--r--cogl/cogl-gles2/cogl-gles2-api.c1048
-rw-r--r--cogl/cogl-gles2/mutter-cogl-gles2-1.0.pc.in13
-rw-r--r--cogl/cogl-pango/Makefile.am109
-rw-r--r--cogl/cogl-pango/cogl-pango-display-list.c499
-rw-r--r--cogl/cogl-pango/cogl-pango-display-list.h84
-rw-r--r--cogl/cogl-pango/cogl-pango-fontmap.c184
-rw-r--r--cogl/cogl-pango/cogl-pango-glyph-cache.c433
-rw-r--r--cogl/cogl-pango/cogl-pango-glyph-cache.h100
-rw-r--r--cogl/cogl-pango/cogl-pango-pipeline-cache.c242
-rw-r--r--cogl/cogl-pango/cogl-pango-pipeline-cache.h72
-rw-r--r--cogl/cogl-pango/cogl-pango-private.h65
-rw-r--r--cogl/cogl-pango/cogl-pango-render.c929
-rw-r--r--cogl/cogl-pango/cogl-pango.h298
-rw-r--r--cogl/cogl-pango/cogl-pango.symbols12
-rw-r--r--cogl/cogl-pango/mutter-cogl-pango-1.0.pc.in13
-rw-r--r--cogl/cogl-path/Makefile.am104
-rw-r--r--cogl/cogl-path/cogl-path-enum-types.c.in50
-rw-r--r--cogl/cogl-path/cogl-path-enum-types.h.in25
-rw-r--r--cogl/cogl-path/cogl-path-private.h126
-rw-r--r--cogl/cogl-path/cogl-path-types.h85
-rw-r--r--cogl/cogl-path/cogl-path.c1602
-rw-r--r--cogl/cogl-path/cogl-path.h68
-rw-r--r--cogl/cogl-path/cogl-path.symbols59
-rw-r--r--cogl/cogl-path/cogl1-path-functions.h467
-rw-r--r--cogl/cogl-path/cogl1-path.c353
-rw-r--r--cogl/cogl-path/cogl2-path-functions.h545
-rw-r--r--cogl/cogl-path/mutter-cogl-path-1.0.pc.in13
-rw-r--r--cogl/cogl-path/tesselator/GL/glu.h47
-rw-r--r--cogl/cogl-path/tesselator/README446
-rw-r--r--cogl/cogl-path/tesselator/dict-list.h100
-rw-r--r--cogl/cogl-path/tesselator/dict.c111
-rw-r--r--cogl/cogl-path/tesselator/dict.h100
-rw-r--r--cogl/cogl-path/tesselator/geom.c264
-rw-r--r--cogl/cogl-path/tesselator/geom.h84
-rw-r--r--cogl/cogl-path/tesselator/gluos.h1
-rw-r--r--cogl/cogl-path/tesselator/memalloc.h49
-rw-r--r--cogl/cogl-path/tesselator/mesh.c798
-rw-r--r--cogl/cogl-path/tesselator/mesh.h266
-rw-r--r--cogl/cogl-path/tesselator/normal.c257
-rw-r--r--cogl/cogl-path/tesselator/normal.h45
-rw-r--r--cogl/cogl-path/tesselator/priorityq-heap.c256
-rw-r--r--cogl/cogl-path/tesselator/priorityq-heap.h107
-rw-r--r--cogl/cogl-path/tesselator/priorityq-sort.h117
-rw-r--r--cogl/cogl-path/tesselator/priorityq.c261
-rw-r--r--cogl/cogl-path/tesselator/priorityq.h117
-rw-r--r--cogl/cogl-path/tesselator/render.c502
-rw-r--r--cogl/cogl-path/tesselator/render.h52
-rw-r--r--cogl/cogl-path/tesselator/sweep.c1361
-rw-r--r--cogl/cogl-path/tesselator/sweep.h77
-rw-r--r--cogl/cogl-path/tesselator/tess.c632
-rw-r--r--cogl/cogl-path/tesselator/tess.h165
-rw-r--r--cogl/cogl-path/tesselator/tesselator.h122
-rw-r--r--cogl/cogl-path/tesselator/tessmono.c201
-rw-r--r--cogl/cogl-path/tesselator/tessmono.h71
-rw-r--r--cogl/cogl/Makefile.am547
-rw-r--r--cogl/cogl/cogl-atlas-texture-private.h (renamed from cogl/cogl-atlas-texture-private.h)0
-rw-r--r--cogl/cogl/cogl-atlas-texture.c (renamed from cogl/cogl-atlas-texture.c)0
-rw-r--r--cogl/cogl/cogl-atlas-texture.h (renamed from cogl/cogl-atlas-texture.h)0
-rw-r--r--cogl/cogl/cogl-atlas.c (renamed from cogl/cogl-atlas.c)0
-rw-r--r--cogl/cogl/cogl-atlas.h (renamed from cogl/cogl-atlas.h)0
-rw-r--r--cogl/cogl/cogl-attribute-buffer-private.h (renamed from cogl/cogl-attribute-buffer-private.h)0
-rw-r--r--cogl/cogl/cogl-attribute-buffer.c (renamed from cogl/cogl-attribute-buffer.c)0
-rw-r--r--cogl/cogl/cogl-attribute-buffer.h (renamed from cogl/cogl-attribute-buffer.h)0
-rw-r--r--cogl/cogl/cogl-attribute-private.h (renamed from cogl/cogl-attribute-private.h)0
-rw-r--r--cogl/cogl/cogl-attribute.c (renamed from cogl/cogl-attribute.c)0
-rw-r--r--cogl/cogl/cogl-attribute.h (renamed from cogl/cogl-attribute.h)0
-rw-r--r--cogl/cogl/cogl-bitmap-conversion.c (renamed from cogl/cogl-bitmap-conversion.c)0
-rw-r--r--cogl/cogl/cogl-bitmap-packing.h (renamed from cogl/cogl-bitmap-packing.h)0
-rw-r--r--cogl/cogl/cogl-bitmap-pixbuf.c (renamed from cogl/cogl-bitmap-pixbuf.c)0
-rw-r--r--cogl/cogl/cogl-bitmap-private.h (renamed from cogl/cogl-bitmap-private.h)0
-rw-r--r--cogl/cogl/cogl-bitmap.c (renamed from cogl/cogl-bitmap.c)0
-rw-r--r--cogl/cogl/cogl-bitmap.h (renamed from cogl/cogl-bitmap.h)0
-rw-r--r--cogl/cogl/cogl-bitmask.c (renamed from cogl/cogl-bitmask.c)0
-rw-r--r--cogl/cogl/cogl-bitmask.h (renamed from cogl/cogl-bitmask.h)0
-rw-r--r--cogl/cogl/cogl-blend-string.c (renamed from cogl/cogl-blend-string.c)0
-rw-r--r--cogl/cogl/cogl-blend-string.h (renamed from cogl/cogl-blend-string.h)0
-rw-r--r--cogl/cogl/cogl-blit.c (renamed from cogl/cogl-blit.c)0
-rw-r--r--cogl/cogl/cogl-blit.h (renamed from cogl/cogl-blit.h)0
-rw-r--r--cogl/cogl/cogl-boxed-value.c (renamed from cogl/cogl-boxed-value.c)0
-rw-r--r--cogl/cogl/cogl-boxed-value.h (renamed from cogl/cogl-boxed-value.h)0
-rw-r--r--cogl/cogl/cogl-buffer-private.h (renamed from cogl/cogl-buffer-private.h)0
-rw-r--r--cogl/cogl/cogl-buffer.c (renamed from cogl/cogl-buffer.c)0
-rw-r--r--cogl/cogl/cogl-buffer.h (renamed from cogl/cogl-buffer.h)0
-rw-r--r--cogl/cogl/cogl-clip-stack.c (renamed from cogl/cogl-clip-stack.c)0
-rw-r--r--cogl/cogl/cogl-clip-stack.h (renamed from cogl/cogl-clip-stack.h)0
-rw-r--r--cogl/cogl/cogl-closure-list-private.h (renamed from cogl/cogl-closure-list-private.h)0
-rw-r--r--cogl/cogl/cogl-closure-list.c (renamed from cogl/cogl-closure-list.c)0
-rw-r--r--cogl/cogl/cogl-color-private.h (renamed from cogl/cogl-color-private.h)0
-rw-r--r--cogl/cogl/cogl-color.c (renamed from cogl/cogl-color.c)0
-rw-r--r--cogl/cogl/cogl-color.h (renamed from cogl/cogl-color.h)0
-rw-r--r--cogl/cogl/cogl-config-private.h (renamed from cogl/cogl-config-private.h)0
-rw-r--r--cogl/cogl/cogl-config.c (renamed from cogl/cogl-config.c)0
-rw-r--r--cogl/cogl/cogl-context-private.h (renamed from cogl/cogl-context-private.h)0
-rw-r--r--cogl/cogl/cogl-context.c (renamed from cogl/cogl-context.c)0
-rw-r--r--cogl/cogl/cogl-context.h (renamed from cogl/cogl-context.h)0
-rw-r--r--cogl/cogl/cogl-debug-options.h (renamed from cogl/cogl-debug-options.h)0
-rw-r--r--cogl/cogl/cogl-debug.c (renamed from cogl/cogl-debug.c)0
-rw-r--r--cogl/cogl/cogl-debug.h (renamed from cogl/cogl-debug.h)0
-rw-r--r--cogl/cogl/cogl-defines.h.in (renamed from cogl/cogl-defines.h.in)0
-rw-r--r--cogl/cogl/cogl-deprecated.h (renamed from cogl/cogl-deprecated.h)0
-rw-r--r--cogl/cogl/cogl-depth-state-private.h (renamed from cogl/cogl-depth-state-private.h)0
-rw-r--r--cogl/cogl/cogl-depth-state.c (renamed from cogl/cogl-depth-state.c)0
-rw-r--r--cogl/cogl/cogl-depth-state.h (renamed from cogl/cogl-depth-state.h)0
-rw-r--r--cogl/cogl/cogl-display-private.h (renamed from cogl/cogl-display-private.h)0
-rw-r--r--cogl/cogl/cogl-display.c (renamed from cogl/cogl-display.c)0
-rw-r--r--cogl/cogl/cogl-display.h (renamed from cogl/cogl-display.h)0
-rw-r--r--cogl/cogl/cogl-driver.h (renamed from cogl/cogl-driver.h)0
-rw-r--r--cogl/cogl/cogl-egl-defines.h.in (renamed from cogl/cogl-egl-defines.h.in)0
-rw-r--r--cogl/cogl/cogl-egl-private.h (renamed from cogl/cogl-egl-private.h)0
-rw-r--r--cogl/cogl/cogl-egl.h (renamed from cogl/cogl-egl.h)0
-rw-r--r--cogl/cogl/cogl-enum-types.c.in (renamed from cogl/cogl-enum-types.c.in)0
-rw-r--r--cogl/cogl/cogl-enum-types.h.in (renamed from cogl/cogl-enum-types.h.in)0
-rw-r--r--cogl/cogl/cogl-error-private.h (renamed from cogl/cogl-error-private.h)0
-rw-r--r--cogl/cogl/cogl-error.c (renamed from cogl/cogl-error.c)0
-rw-r--r--cogl/cogl/cogl-error.h (renamed from cogl/cogl-error.h)0
-rw-r--r--cogl/cogl/cogl-euler.c (renamed from cogl/cogl-euler.c)0
-rw-r--r--cogl/cogl/cogl-euler.h (renamed from cogl/cogl-euler.h)0
-rw-r--r--cogl/cogl/cogl-feature-private.c (renamed from cogl/cogl-feature-private.c)0
-rw-r--r--cogl/cogl/cogl-feature-private.h (renamed from cogl/cogl-feature-private.h)0
-rw-r--r--cogl/cogl/cogl-fence-private.h (renamed from cogl/cogl-fence-private.h)0
-rw-r--r--cogl/cogl/cogl-fence.c (renamed from cogl/cogl-fence.c)0
-rw-r--r--cogl/cogl/cogl-fence.h (renamed from cogl/cogl-fence.h)0
-rw-r--r--cogl/cogl/cogl-flags.h (renamed from cogl/cogl-flags.h)0
-rw-r--r--cogl/cogl/cogl-frame-info-private.h (renamed from cogl/cogl-frame-info-private.h)0
-rw-r--r--cogl/cogl/cogl-frame-info.c (renamed from cogl/cogl-frame-info.c)0
-rw-r--r--cogl/cogl/cogl-frame-info.h (renamed from cogl/cogl-frame-info.h)0
-rw-r--r--cogl/cogl/cogl-framebuffer-private.h (renamed from cogl/cogl-framebuffer-private.h)0
-rw-r--r--cogl/cogl/cogl-framebuffer.c (renamed from cogl/cogl-framebuffer.c)0
-rw-r--r--cogl/cogl/cogl-framebuffer.h (renamed from cogl/cogl-framebuffer.h)0
-rw-r--r--cogl/cogl/cogl-gl-header.h.in (renamed from cogl/cogl-gl-header.h.in)0
-rw-r--r--cogl/cogl/cogl-gles2-context-private.h (renamed from cogl/cogl-gles2-context-private.h)0
-rw-r--r--cogl/cogl/cogl-gles2-context.c (renamed from cogl/cogl-gles2-context.c)0
-rw-r--r--cogl/cogl/cogl-gles2-types.h (renamed from cogl/cogl-gles2-types.h)0
-rw-r--r--cogl/cogl/cogl-gles2.h (renamed from cogl/cogl-gles2.h)0
-rw-r--r--cogl/cogl/cogl-glib-source.c (renamed from cogl/cogl-glib-source.c)0
-rw-r--r--cogl/cogl/cogl-glib-source.h (renamed from cogl/cogl-glib-source.h)0
-rw-r--r--cogl/cogl/cogl-glsl-shader-boilerplate.h (renamed from cogl/cogl-glsl-shader-boilerplate.h)0
-rw-r--r--cogl/cogl/cogl-glsl-shader-private.h (renamed from cogl/cogl-glsl-shader-private.h)0
-rw-r--r--cogl/cogl/cogl-glsl-shader.c (renamed from cogl/cogl-glsl-shader.c)0
-rw-r--r--cogl/cogl/cogl-glx-display-private.h (renamed from cogl/cogl-glx-display-private.h)0
-rw-r--r--cogl/cogl/cogl-glx-renderer-private.h (renamed from cogl/cogl-glx-renderer-private.h)0
-rw-r--r--cogl/cogl/cogl-glx.h (renamed from cogl/cogl-glx.h)0
-rw-r--r--cogl/cogl/cogl-gpu-info-private.h (renamed from cogl/cogl-gpu-info-private.h)0
-rw-r--r--cogl/cogl/cogl-gpu-info.c (renamed from cogl/cogl-gpu-info.c)0
-rw-r--r--cogl/cogl/cogl-gtype-private.h (renamed from cogl/cogl-gtype-private.h)0
-rw-r--r--cogl/cogl/cogl-gtype.c (renamed from cogl/cogl-gtype.c)0
-rw-r--r--cogl/cogl/cogl-i18n-private.h (renamed from cogl/cogl-i18n-private.h)0
-rw-r--r--cogl/cogl/cogl-index-buffer-private.h (renamed from cogl/cogl-index-buffer-private.h)0
-rw-r--r--cogl/cogl/cogl-index-buffer.c (renamed from cogl/cogl-index-buffer.c)0
-rw-r--r--cogl/cogl/cogl-index-buffer.h (renamed from cogl/cogl-index-buffer.h)0
-rw-r--r--cogl/cogl/cogl-indices-private.h (renamed from cogl/cogl-indices-private.h)0
-rw-r--r--cogl/cogl/cogl-indices.c (renamed from cogl/cogl-indices.c)0
-rw-r--r--cogl/cogl/cogl-indices.h (renamed from cogl/cogl-indices.h)0
-rw-r--r--cogl/cogl/cogl-journal-private.h (renamed from cogl/cogl-journal-private.h)0
-rw-r--r--cogl/cogl/cogl-journal.c (renamed from cogl/cogl-journal.c)0
-rw-r--r--cogl/cogl/cogl-kms-display.h (renamed from cogl/cogl-kms-display.h)0
-rw-r--r--cogl/cogl/cogl-kms-renderer.h (renamed from cogl/cogl-kms-renderer.h)0
-rw-r--r--cogl/cogl/cogl-list.c (renamed from cogl/cogl-list.c)0
-rw-r--r--cogl/cogl/cogl-list.h (renamed from cogl/cogl-list.h)0
-rw-r--r--cogl/cogl/cogl-macros.h (renamed from cogl/cogl-macros.h)0
-rw-r--r--cogl/cogl/cogl-magazine-private.h (renamed from cogl/cogl-magazine-private.h)0
-rw-r--r--cogl/cogl/cogl-magazine.c (renamed from cogl/cogl-magazine.c)0
-rw-r--r--cogl/cogl/cogl-matrix-private.h (renamed from cogl/cogl-matrix-private.h)0
-rw-r--r--cogl/cogl/cogl-matrix-stack-private.h (renamed from cogl/cogl-matrix-stack-private.h)0
-rw-r--r--cogl/cogl/cogl-matrix-stack.c (renamed from cogl/cogl-matrix-stack.c)0
-rw-r--r--cogl/cogl/cogl-matrix-stack.h (renamed from cogl/cogl-matrix-stack.h)0
-rw-r--r--cogl/cogl/cogl-matrix.c (renamed from cogl/cogl-matrix.c)0
-rw-r--r--cogl/cogl/cogl-matrix.h (renamed from cogl/cogl-matrix.h)0
-rw-r--r--cogl/cogl/cogl-memory-stack-private.h (renamed from cogl/cogl-memory-stack-private.h)0
-rw-r--r--cogl/cogl/cogl-memory-stack.c (renamed from cogl/cogl-memory-stack.c)0
-rw-r--r--cogl/cogl/cogl-meta-texture.c (renamed from cogl/cogl-meta-texture.c)0
-rw-r--r--cogl/cogl/cogl-meta-texture.h (renamed from cogl/cogl-meta-texture.h)0
-rw-r--r--cogl/cogl/cogl-node-private.h (renamed from cogl/cogl-node-private.h)0
-rw-r--r--cogl/cogl/cogl-node.c (renamed from cogl/cogl-node.c)0
-rw-r--r--cogl/cogl/cogl-object-private.h (renamed from cogl/cogl-object-private.h)0
-rw-r--r--cogl/cogl/cogl-object.c (renamed from cogl/cogl-object.c)0
-rw-r--r--cogl/cogl/cogl-object.h (renamed from cogl/cogl-object.h)0
-rw-r--r--cogl/cogl/cogl-offscreen.h (renamed from cogl/cogl-offscreen.h)0
-rw-r--r--cogl/cogl/cogl-onscreen-private.h (renamed from cogl/cogl-onscreen-private.h)0
-rw-r--r--cogl/cogl/cogl-onscreen-template-private.h (renamed from cogl/cogl-onscreen-template-private.h)0
-rw-r--r--cogl/cogl/cogl-onscreen-template.c (renamed from cogl/cogl-onscreen-template.c)0
-rw-r--r--cogl/cogl/cogl-onscreen-template.h (renamed from cogl/cogl-onscreen-template.h)0
-rw-r--r--cogl/cogl/cogl-onscreen.c (renamed from cogl/cogl-onscreen.c)0
-rw-r--r--cogl/cogl/cogl-onscreen.h (renamed from cogl/cogl-onscreen.h)0
-rw-r--r--cogl/cogl/cogl-output-private.h (renamed from cogl/cogl-output-private.h)0
-rw-r--r--cogl/cogl/cogl-output.c (renamed from cogl/cogl-output.c)0
-rw-r--r--cogl/cogl/cogl-output.h (renamed from cogl/cogl-output.h)0
-rw-r--r--cogl/cogl/cogl-pango.h (renamed from cogl/cogl-pango.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-cache.c (renamed from cogl/cogl-pipeline-cache.c)0
-rw-r--r--cogl/cogl/cogl-pipeline-cache.h (renamed from cogl/cogl-pipeline-cache.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-debug.c (renamed from cogl/cogl-pipeline-debug.c)0
-rw-r--r--cogl/cogl/cogl-pipeline-hash-table.c (renamed from cogl/cogl-pipeline-hash-table.c)0
-rw-r--r--cogl/cogl/cogl-pipeline-hash-table.h (renamed from cogl/cogl-pipeline-hash-table.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-layer-private.h (renamed from cogl/cogl-pipeline-layer-private.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-layer-state-private.h (renamed from cogl/cogl-pipeline-layer-state-private.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-layer-state.c (renamed from cogl/cogl-pipeline-layer-state.c)0
-rw-r--r--cogl/cogl/cogl-pipeline-layer-state.h (renamed from cogl/cogl-pipeline-layer-state.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-layer.c (renamed from cogl/cogl-pipeline-layer.c)0
-rw-r--r--cogl/cogl/cogl-pipeline-private.h (renamed from cogl/cogl-pipeline-private.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-snippet-private.h (renamed from cogl/cogl-pipeline-snippet-private.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-snippet.c (renamed from cogl/cogl-pipeline-snippet.c)0
-rw-r--r--cogl/cogl/cogl-pipeline-state-private.h (renamed from cogl/cogl-pipeline-state-private.h)0
-rw-r--r--cogl/cogl/cogl-pipeline-state.c (renamed from cogl/cogl-pipeline-state.c)0
-rw-r--r--cogl/cogl/cogl-pipeline-state.h (renamed from cogl/cogl-pipeline-state.h)0
-rw-r--r--cogl/cogl/cogl-pipeline.c (renamed from cogl/cogl-pipeline.c)0
-rw-r--r--cogl/cogl/cogl-pipeline.h (renamed from cogl/cogl-pipeline.h)0
-rw-r--r--cogl/cogl/cogl-pixel-buffer-private.h (renamed from cogl/cogl-pixel-buffer-private.h)0
-rw-r--r--cogl/cogl/cogl-pixel-buffer.c (renamed from cogl/cogl-pixel-buffer.c)0
-rw-r--r--cogl/cogl/cogl-pixel-buffer.h (renamed from cogl/cogl-pixel-buffer.h)0
-rw-r--r--cogl/cogl/cogl-point-in-poly-private.h (renamed from cogl/cogl-point-in-poly-private.h)0
-rw-r--r--cogl/cogl/cogl-point-in-poly.c (renamed from cogl/cogl-point-in-poly.c)0
-rw-r--r--cogl/cogl/cogl-poll-private.h (renamed from cogl/cogl-poll-private.h)0
-rw-r--r--cogl/cogl/cogl-poll.c (renamed from cogl/cogl-poll.c)0
-rw-r--r--cogl/cogl/cogl-poll.h (renamed from cogl/cogl-poll.h)0
-rw-r--r--cogl/cogl/cogl-primitive-private.h (renamed from cogl/cogl-primitive-private.h)0
-rw-r--r--cogl/cogl/cogl-primitive-texture.c (renamed from cogl/cogl-primitive-texture.c)0
-rw-r--r--cogl/cogl/cogl-primitive-texture.h (renamed from cogl/cogl-primitive-texture.h)0
-rw-r--r--cogl/cogl/cogl-primitive.c (renamed from cogl/cogl-primitive.c)0
-rw-r--r--cogl/cogl/cogl-primitive.h (renamed from cogl/cogl-primitive.h)0
-rw-r--r--cogl/cogl/cogl-primitives-private.h (renamed from cogl/cogl-primitives-private.h)0
-rw-r--r--cogl/cogl/cogl-primitives.c (renamed from cogl/cogl-primitives.c)0
-rw-r--r--cogl/cogl/cogl-primitives.h (renamed from cogl/cogl-primitives.h)0
-rw-r--r--cogl/cogl/cogl-private.h (renamed from cogl/cogl-private.h)0
-rw-r--r--cogl/cogl/cogl-profile.c (renamed from cogl/cogl-profile.c)0
-rw-r--r--cogl/cogl/cogl-profile.h (renamed from cogl/cogl-profile.h)0
-rw-r--r--cogl/cogl/cogl-quaternion-private.h (renamed from cogl/cogl-quaternion-private.h)0
-rw-r--r--cogl/cogl/cogl-quaternion.c (renamed from cogl/cogl-quaternion.c)0
-rw-r--r--cogl/cogl/cogl-quaternion.h (renamed from cogl/cogl-quaternion.h)0
-rw-r--r--cogl/cogl/cogl-rectangle-map.c (renamed from cogl/cogl-rectangle-map.c)0
-rw-r--r--cogl/cogl/cogl-rectangle-map.h (renamed from cogl/cogl-rectangle-map.h)0
-rw-r--r--cogl/cogl/cogl-renderer-private.h (renamed from cogl/cogl-renderer-private.h)0
-rw-r--r--cogl/cogl/cogl-renderer.c (renamed from cogl/cogl-renderer.c)0
-rw-r--r--cogl/cogl/cogl-renderer.h (renamed from cogl/cogl-renderer.h)0
-rw-r--r--cogl/cogl/cogl-sampler-cache-private.h (renamed from cogl/cogl-sampler-cache-private.h)0
-rw-r--r--cogl/cogl/cogl-sampler-cache.c (renamed from cogl/cogl-sampler-cache.c)0
-rw-r--r--cogl/cogl/cogl-snippet-private.h (renamed from cogl/cogl-snippet-private.h)0
-rw-r--r--cogl/cogl/cogl-snippet.c (renamed from cogl/cogl-snippet.c)0
-rw-r--r--cogl/cogl/cogl-snippet.h (renamed from cogl/cogl-snippet.h)0
-rw-r--r--cogl/cogl/cogl-spans.c (renamed from cogl/cogl-spans.c)0
-rw-r--r--cogl/cogl/cogl-spans.h (renamed from cogl/cogl-spans.h)0
-rw-r--r--cogl/cogl/cogl-sub-texture-private.h (renamed from cogl/cogl-sub-texture-private.h)0
-rw-r--r--cogl/cogl/cogl-sub-texture.c (renamed from cogl/cogl-sub-texture.c)0
-rw-r--r--cogl/cogl/cogl-sub-texture.h (renamed from cogl/cogl-sub-texture.h)0
-rw-r--r--cogl/cogl/cogl-swap-chain-private.h (renamed from cogl/cogl-swap-chain-private.h)0
-rw-r--r--cogl/cogl/cogl-swap-chain.c (renamed from cogl/cogl-swap-chain.c)0
-rw-r--r--cogl/cogl/cogl-swap-chain.h (renamed from cogl/cogl-swap-chain.h)0
-rw-r--r--cogl/cogl/cogl-texture-2d-gl.h (renamed from cogl/cogl-texture-2d-gl.h)0
-rw-r--r--cogl/cogl/cogl-texture-2d-private.h (renamed from cogl/cogl-texture-2d-private.h)0
-rw-r--r--cogl/cogl/cogl-texture-2d-sliced-private.h (renamed from cogl/cogl-texture-2d-sliced-private.h)0
-rw-r--r--cogl/cogl/cogl-texture-2d-sliced.c (renamed from cogl/cogl-texture-2d-sliced.c)0
-rw-r--r--cogl/cogl/cogl-texture-2d-sliced.h (renamed from cogl/cogl-texture-2d-sliced.h)0
-rw-r--r--cogl/cogl/cogl-texture-2d.c (renamed from cogl/cogl-texture-2d.c)0
-rw-r--r--cogl/cogl/cogl-texture-2d.h (renamed from cogl/cogl-texture-2d.h)0
-rw-r--r--cogl/cogl/cogl-texture-3d-private.h (renamed from cogl/cogl-texture-3d-private.h)0
-rw-r--r--cogl/cogl/cogl-texture-3d.c (renamed from cogl/cogl-texture-3d.c)0
-rw-r--r--cogl/cogl/cogl-texture-3d.h (renamed from cogl/cogl-texture-3d.h)0
-rw-r--r--cogl/cogl/cogl-texture-driver.h (renamed from cogl/cogl-texture-driver.h)0
-rw-r--r--cogl/cogl/cogl-texture-private.h (renamed from cogl/cogl-texture-private.h)0
-rw-r--r--cogl/cogl/cogl-texture-rectangle-private.h (renamed from cogl/cogl-texture-rectangle-private.h)0
-rw-r--r--cogl/cogl/cogl-texture-rectangle.c (renamed from cogl/cogl-texture-rectangle.c)0
-rw-r--r--cogl/cogl/cogl-texture-rectangle.h (renamed from cogl/cogl-texture-rectangle.h)0
-rw-r--r--cogl/cogl/cogl-texture.c (renamed from cogl/cogl-texture.c)0
-rw-r--r--cogl/cogl/cogl-texture.h (renamed from cogl/cogl-texture.h)0
-rw-r--r--cogl/cogl/cogl-types.h (renamed from cogl/cogl-types.h)0
-rw-r--r--cogl/cogl/cogl-util.c (renamed from cogl/cogl-util.c)0
-rw-r--r--cogl/cogl/cogl-util.h (renamed from cogl/cogl-util.h)0
-rw-r--r--cogl/cogl/cogl-vector.c (renamed from cogl/cogl-vector.c)0
-rw-r--r--cogl/cogl/cogl-vector.h (renamed from cogl/cogl-vector.h)0
-rw-r--r--cogl/cogl/cogl-version.h (renamed from cogl/cogl-version.h)0
-rw-r--r--cogl/cogl/cogl-wayland-server.h (renamed from cogl/cogl-wayland-server.h)0
-rw-r--r--cogl/cogl/cogl-x11-renderer-private.h (renamed from cogl/cogl-x11-renderer-private.h)0
-rw-r--r--cogl/cogl/cogl-xlib-private.h (renamed from cogl/cogl-xlib-private.h)0
-rw-r--r--cogl/cogl/cogl-xlib-renderer-private.h (renamed from cogl/cogl-xlib-renderer-private.h)0
-rw-r--r--cogl/cogl/cogl-xlib-renderer.c (renamed from cogl/cogl-xlib-renderer.c)0
-rw-r--r--cogl/cogl/cogl-xlib-renderer.h (renamed from cogl/cogl-xlib-renderer.h)0
-rw-r--r--cogl/cogl/cogl-xlib.c (renamed from cogl/cogl-xlib.c)0
-rw-r--r--cogl/cogl/cogl-xlib.h (renamed from cogl/cogl-xlib.h)0
-rw-r--r--cogl/cogl/cogl.c (renamed from cogl/cogl.c)0
-rw-r--r--cogl/cogl/cogl.h (renamed from cogl/cogl.h)0
-rw-r--r--cogl/cogl/cogl.symbols (renamed from cogl/cogl.symbols)0
-rw-r--r--cogl/cogl/cogl1-context.h (renamed from cogl/cogl1-context.h)0
-rw-r--r--cogl/cogl/cogl2-experimental.h (renamed from cogl/cogl2-experimental.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-auto-texture.c (renamed from cogl/deprecated/cogl-auto-texture.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-auto-texture.h (renamed from cogl/deprecated/cogl-auto-texture.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-clip-state.c (renamed from cogl/deprecated/cogl-clip-state.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-clip-state.h (renamed from cogl/deprecated/cogl-clip-state.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-clutter-xlib.h (renamed from cogl/deprecated/cogl-clutter-xlib.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-clutter.c (renamed from cogl/deprecated/cogl-clutter.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-clutter.h (renamed from cogl/deprecated/cogl-clutter.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-fixed.c (renamed from cogl/deprecated/cogl-fixed.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-fixed.h (renamed from cogl/deprecated/cogl-fixed.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-framebuffer-deprecated.c (renamed from cogl/deprecated/cogl-framebuffer-deprecated.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-framebuffer-deprecated.h (renamed from cogl/deprecated/cogl-framebuffer-deprecated.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-material-compat.c (renamed from cogl/deprecated/cogl-material-compat.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-material-compat.h (renamed from cogl/deprecated/cogl-material-compat.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-program-private.h (renamed from cogl/deprecated/cogl-program-private.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-program.c (renamed from cogl/deprecated/cogl-program.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-shader-private.h (renamed from cogl/deprecated/cogl-shader-private.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-shader.c (renamed from cogl/deprecated/cogl-shader.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-shader.h (renamed from cogl/deprecated/cogl-shader.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-texture-deprecated.c (renamed from cogl/deprecated/cogl-texture-deprecated.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-texture-deprecated.h (renamed from cogl/deprecated/cogl-texture-deprecated.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-type-casts.h (renamed from cogl/deprecated/cogl-type-casts.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-vertex-buffer-private.h (renamed from cogl/deprecated/cogl-vertex-buffer-private.h)0
-rw-r--r--cogl/cogl/deprecated/cogl-vertex-buffer.c (renamed from cogl/deprecated/cogl-vertex-buffer.c)0
-rw-r--r--cogl/cogl/deprecated/cogl-vertex-buffer.h (renamed from cogl/deprecated/cogl-vertex-buffer.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-attribute-gl-private.h (renamed from cogl/driver/gl/cogl-attribute-gl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-attribute-gl.c (renamed from cogl/driver/gl/cogl-attribute-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-buffer-gl-private.h (renamed from cogl/driver/gl/cogl-buffer-gl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-buffer-gl.c (renamed from cogl/driver/gl/cogl-buffer-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-clip-stack-gl-private.h (renamed from cogl/driver/gl/cogl-clip-stack-gl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-clip-stack-gl.c (renamed from cogl/driver/gl/cogl-clip-stack-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h (renamed from cogl/driver/gl/cogl-framebuffer-gl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-framebuffer-gl.c (renamed from cogl/driver/gl/cogl-framebuffer-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed-private.h (renamed from cogl/driver/gl/cogl-pipeline-fragend-fixed-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed.c (renamed from cogl/driver/gl/cogl-pipeline-fragend-fixed.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h (renamed from cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl.c (renamed from cogl/driver/gl/cogl-pipeline-fragend-glsl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-opengl-private.h (renamed from cogl/driver/gl/cogl-pipeline-opengl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-opengl.c (renamed from cogl/driver/gl/cogl-pipeline-opengl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-progend-fixed-private.h (renamed from cogl/driver/gl/cogl-pipeline-progend-fixed-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-progend-fixed.c (renamed from cogl/driver/gl/cogl-pipeline-progend-fixed.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h (renamed from cogl/driver/gl/cogl-pipeline-progend-glsl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-progend-glsl.c (renamed from cogl/driver/gl/cogl-pipeline-progend-glsl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed-private.h (renamed from cogl/driver/gl/cogl-pipeline-vertend-fixed-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed.c (renamed from cogl/driver/gl/cogl-pipeline-vertend-fixed.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h (renamed from cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl.c (renamed from cogl/driver/gl/cogl-pipeline-vertend-glsl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h (renamed from cogl/driver/gl/cogl-texture-2d-gl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-texture-2d-gl.c (renamed from cogl/driver/gl/cogl-texture-2d-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-texture-gl-private.h (renamed from cogl/driver/gl/cogl-texture-gl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-texture-gl.c (renamed from cogl/driver/gl/cogl-texture-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/cogl-util-gl-private.h (renamed from cogl/driver/gl/cogl-util-gl-private.h)0
-rw-r--r--cogl/cogl/driver/gl/cogl-util-gl.c (renamed from cogl/driver/gl/cogl-util-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/gl/cogl-driver-gl.c (renamed from cogl/driver/gl/gl/cogl-driver-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h (renamed from cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h)0
-rw-r--r--cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c (renamed from cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c)0
-rw-r--r--cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h (renamed from cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h)0
-rw-r--r--cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c (renamed from cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c)0
-rw-r--r--cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c (renamed from cogl/driver/gl/gl/cogl-texture-driver-gl.c)0
-rw-r--r--cogl/cogl/driver/gl/gles/cogl-driver-gles.c (renamed from cogl/driver/gl/gles/cogl-driver-gles.c)0
-rw-r--r--cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c (renamed from cogl/driver/gl/gles/cogl-texture-driver-gles.c)0
-rw-r--r--cogl/cogl/driver/nop/cogl-attribute-nop-private.h (renamed from cogl/driver/nop/cogl-attribute-nop-private.h)0
-rw-r--r--cogl/cogl/driver/nop/cogl-attribute-nop.c (renamed from cogl/driver/nop/cogl-attribute-nop.c)0
-rw-r--r--cogl/cogl/driver/nop/cogl-clip-stack-nop-private.h (renamed from cogl/driver/nop/cogl-clip-stack-nop-private.h)0
-rw-r--r--cogl/cogl/driver/nop/cogl-clip-stack-nop.c (renamed from cogl/driver/nop/cogl-clip-stack-nop.c)0
-rw-r--r--cogl/cogl/driver/nop/cogl-driver-nop.c (renamed from cogl/driver/nop/cogl-driver-nop.c)0
-rw-r--r--cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h (renamed from cogl/driver/nop/cogl-framebuffer-nop-private.h)0
-rw-r--r--cogl/cogl/driver/nop/cogl-framebuffer-nop.c (renamed from cogl/driver/nop/cogl-framebuffer-nop.c)0
-rw-r--r--cogl/cogl/driver/nop/cogl-texture-2d-nop-private.h (renamed from cogl/driver/nop/cogl-texture-2d-nop-private.h)0
-rw-r--r--cogl/cogl/driver/nop/cogl-texture-2d-nop.c (renamed from cogl/driver/nop/cogl-texture-2d-nop.c)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-all-functions.h (renamed from cogl/gl-prototypes/cogl-all-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-core-functions.h (renamed from cogl/gl-prototypes/cogl-core-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-fixed-functions.h (renamed from cogl/gl-prototypes/cogl-fixed-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-gles1-functions.h (renamed from cogl/gl-prototypes/cogl-gles1-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-gles2-functions.h (renamed from cogl/gl-prototypes/cogl-gles2-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-glsl-functions.h (renamed from cogl/gl-prototypes/cogl-glsl-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-in-gles-core-functions.h (renamed from cogl/gl-prototypes/cogl-in-gles-core-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-in-gles1-core-functions.h (renamed from cogl/gl-prototypes/cogl-in-gles1-core-functions.h)0
-rw-r--r--cogl/cogl/gl-prototypes/cogl-in-gles2-core-functions.h (renamed from cogl/gl-prototypes/cogl-in-gles2-core-functions.h)0
-rw-r--r--cogl/cogl/mutter-cogl-1.0.pc.in (renamed from cogl/mutter-cogl-1.0.pc.in)0
-rw-r--r--cogl/cogl/winsys/cogl-texture-pixmap-x11-private.h (renamed from cogl/winsys/cogl-texture-pixmap-x11-private.h)0
-rw-r--r--cogl/cogl/winsys/cogl-texture-pixmap-x11.c (renamed from cogl/winsys/cogl-texture-pixmap-x11.c)0
-rw-r--r--cogl/cogl/winsys/cogl-texture-pixmap-x11.h (renamed from cogl/winsys/cogl-texture-pixmap-x11.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h (renamed from cogl/winsys/cogl-winsys-egl-feature-functions.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-egl-kms-private.h (renamed from cogl/winsys/cogl-winsys-egl-kms-private.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-egl-kms.c (renamed from cogl/winsys/cogl-winsys-egl-kms.c)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-egl-private.h (renamed from cogl/winsys/cogl-winsys-egl-private.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-egl-x11-private.h (renamed from cogl/winsys/cogl-winsys-egl-x11-private.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-egl-x11.c (renamed from cogl/winsys/cogl-winsys-egl-x11.c)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-egl.c (renamed from cogl/winsys/cogl-winsys-egl.c)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-glx-feature-functions.h (renamed from cogl/winsys/cogl-winsys-glx-feature-functions.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-glx-private.h (renamed from cogl/winsys/cogl-winsys-glx-private.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-glx.c (renamed from cogl/winsys/cogl-winsys-glx.c)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-private.h (renamed from cogl/winsys/cogl-winsys-private.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-stub-private.h (renamed from cogl/winsys/cogl-winsys-stub-private.h)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys-stub.c (renamed from cogl/winsys/cogl-winsys-stub.c)0
-rw-r--r--cogl/cogl/winsys/cogl-winsys.c (renamed from cogl/winsys/cogl-winsys.c)0
-rw-r--r--cogl/config-custom.h32
-rw-r--r--cogl/configure.ac1036
-rw-r--r--cogl/test-fixtures/Makefile.am21
-rw-r--r--cogl/test-fixtures/test-unit.h31
-rw-r--r--cogl/test-fixtures/test-utils.c535
-rw-r--r--cogl/test-fixtures/test-utils.h287
-rw-r--r--cogl/tests/Makefile.am31
-rw-r--r--cogl/tests/README63
-rw-r--r--cogl/tests/config.env.in3
-rw-r--r--cogl/tests/conform/Makefile.am176
-rw-r--r--cogl/tests/conform/test-alpha-test.c73
-rw-r--r--cogl/tests/conform/test-alpha-textures.c123
-rw-r--r--cogl/tests/conform/test-atlas-migration.c145
-rw-r--r--cogl/tests/conform/test-backface-culling.c311
-rw-r--r--cogl/tests/conform/test-blend-strings.c430
-rw-r--r--cogl/tests/conform/test-blend.c64
-rw-r--r--cogl/tests/conform/test-color-hsl.c45
-rw-r--r--cogl/tests/conform/test-color-mask.c110
-rw-r--r--cogl/tests/conform/test-conform-main.c157
-rw-r--r--cogl/tests/conform/test-copy-replace-texture.c120
-rw-r--r--cogl/tests/conform/test-custom-attributes.c301
-rw-r--r--cogl/tests/conform/test-depth-test.c301
-rw-r--r--cogl/tests/conform/test-euler-quaternion.c81
-rw-r--r--cogl/tests/conform/test-fence.c63
-rw-r--r--cogl/tests/conform/test-fixed.c18
-rw-r--r--cogl/tests/conform/test-fixtures.c12
-rw-r--r--cogl/tests/conform/test-framebuffer-get-bits.c40
-rw-r--r--cogl/tests/conform/test-gles2-context.c962
-rw-r--r--cogl/tests/conform/test-just-vertex-shader.c205
-rw-r--r--cogl/tests/conform/test-layer-remove.c145
-rw-r--r--cogl/tests/conform/test-map-buffer-range.c123
-rw-r--r--cogl/tests/conform/test-materials.c253
-rw-r--r--cogl/tests/conform/test-multitexture.c206
-rw-r--r--cogl/tests/conform/test-no-gl-header.c16
-rw-r--r--cogl/tests/conform/test-npot-texture.c170
-rw-r--r--cogl/tests/conform/test-object.c86
-rw-r--r--cogl/tests/conform/test-offscreen.c199
-rw-r--r--cogl/tests/conform/test-path-clip.c68
-rw-r--r--cogl/tests/conform/test-path.c215
-rw-r--r--cogl/tests/conform/test-pipeline-cache-unrefs-texture.c91
-rw-r--r--cogl/tests/conform/test-pipeline-shader-state.c93
-rw-r--r--cogl/tests/conform/test-pipeline-uniforms.c415
-rw-r--r--cogl/tests/conform/test-pipeline-user-matrix.c140
-rw-r--r--cogl/tests/conform/test-pixel-buffer.c269
-rw-r--r--cogl/tests/conform/test-point-size-attribute.c166
-rw-r--r--cogl/tests/conform/test-point-size.c99
-rw-r--r--cogl/tests/conform/test-point-sprite.c194
-rw-r--r--cogl/tests/conform/test-premult.c301
-rw-r--r--cogl/tests/conform/test-primitive-and-journal.c122
-rw-r--r--cogl/tests/conform/test-primitive.c334
-rw-r--r--cogl/tests/conform/test-read-texture-formats.c222
-rw-r--r--cogl/tests/conform/test-readpixels.c178
-rw-r--r--cogl/tests/conform/test-snippets.c815
-rw-r--r--cogl/tests/conform/test-sparse-pipeline.c62
-rw-r--r--cogl/tests/conform/test-sub-texture.c325
-rw-r--r--cogl/tests/conform/test-texture-3d.c274
-rw-r--r--cogl/tests/conform/test-texture-get-set-data.c144
-rw-r--r--cogl/tests/conform/test-texture-mipmaps.c136
-rw-r--r--cogl/tests/conform/test-texture-no-allocate.c80
-rw-r--r--cogl/tests/conform/test-texture-pixmap-x11.c245
-rw-r--r--cogl/tests/conform/test-texture-rectangle.c276
-rw-r--r--cogl/tests/conform/test-texture-rg.c74
-rw-r--r--cogl/tests/conform/test-version.c85
-rw-r--r--cogl/tests/conform/test-vertex-buffer-contiguous.c257
-rw-r--r--cogl/tests/conform/test-vertex-buffer-interleved.c162
-rw-r--r--cogl/tests/conform/test-vertex-buffer-mutability.c198
-rw-r--r--cogl/tests/conform/test-viewport.c416
-rw-r--r--cogl/tests/conform/test-wrap-modes.c296
-rw-r--r--cogl/tests/conform/test-wrap-rectangle-textures.c175
-rw-r--r--cogl/tests/conform/test-write-texture-formats.c184
-rw-r--r--cogl/tests/data/Makefile.am3
-rw-r--r--cogl/tests/data/valgrind.suppressions173
-rw-r--r--cogl/tests/micro-perf/Makefile.am24
-rw-r--r--cogl/tests/micro-perf/test-journal.c190
-rwxr-xr-xcogl/tests/run-tests.sh157
-rwxr-xr-xcogl/tests/test-launcher.sh39
-rw-r--r--cogl/tests/unit/Makefile.am83
-rw-r--r--cogl/tests/unit/test-unit-main.c45
465 files changed, 31619 insertions, 535 deletions
diff --git a/cogl/.gitignore b/cogl/.gitignore
new file mode 100644
index 000000000..25c354b0d
--- /dev/null
+++ b/cogl/.gitignore
@@ -0,0 +1,107 @@
+ABOUT-NLS
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+compile
+*.pc
+.deps
+.libs
+.dirstamp
+*.o
+*.lo
+*.la
+*.gcov
+*.exe
+/README
+stamp-enum-types
+stamp-marshal
+/build/autotools/*.m4
+/build/win32/*.bat
+!/build/autotools/acglib.m4
+!/build/autotools/introspection.m4
+!/build/autotools/as-glibconfig.m4
+!/build/autotools/as-linguas.m4
+!/build/autotools/as-compiler-flag.m4
+/build/config.guess
+/build/config.rpath
+/build/config.sub
+*.gir
+*.typelib
+/cogl-pango/cogl-pango.rc
+/cogl/cogl.rc
+/cogl/cogl-defines.h
+/cogl/cogl-defines.h.win32
+/cogl/cogl-defines.h.win32_SDL
+/cogl/cogl-egl-defines.h
+/cogl/cogl-enum-types.c
+/cogl/cogl-enum-types.h
+/cogl/cogl-gl-header.h
+/cogl-path/cogl-path-enum-types.c
+/cogl-path/cogl-path-enum-types.h
+config.h
+config.h.in
+config.h.win32
+config.log
+config.lt
+config.status
+configure
+depcomp
+/deps/glib/glibconfig.h
+/deps/gmodule/gmoduleconf.h
+/doc/reference/cogl/cogl-docs.xml
+/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml
+/doc/reference/cogl-gst/cogl-gst-docs.xml
+/examples/cogl-basic-video-player
+/examples/cogl-crate
+/examples/cogl-gles2-context
+/examples/cogl-gles2-gears
+/examples/cogl-hello
+/examples/cogl-info
+/examples/cogl-msaa
+/examples/cogl-point-sprites
+/examples/cogl-sdl-hello
+/examples/cogl-sdl2-hello
+/examples/cogl-stereo
+/examples/cogl-x11-foreign
+/examples/cogl-x11-tfp
+/examples/cogland
+gtk-doc.make
+install-sh
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+stamp-h1
+TAGS
+/tests/tools/disable-npots.sh
+/tests/conform/test-launcher.sh
+/tests/interactive/wrapper.sh
+/tests/conform/*.bat
+/tests/conform/config.env
+/tests/conform/.log
+/tests/unit/.log
+/tests/micro-perf/test-journal
+/tests/config.env
+/po/POTFILES
+/po/*.gmo
+/po/Makefile.in.in
+/po/Makevars.template
+/po/Rules-quot
+/po/boldquot.sed
+/po/en@boldquot.header
+/po/en@quot.header
+/po/insert-header.sin
+/po/quot.sed
+/po/remove-potcdate.sin
+/po/remove-potcdate.sed
+/po/stamp-po
+*.swn
+*.swo
+*.swp
+*~
+*.orig
+*.rej
+.DS_Store
+.testlogs-*
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index e34c76806..25f12fffc 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -1,547 +1,37 @@
-# preamble
+SUBDIRS = test-fixtures
-NULL =
+SUBDIRS += cogl
-SUBDIRS =
-
-BUILT_SOURCES =
-
-EXTRA_DIST =
-CLEANFILES =
-DISTCLEANFILES =
-
-AM_CPPFLAGS = \
- -I$(top_srcdir) \
- -I$(top_builddir) \
- -I$(srcdir)/deprecated \
- -I$(srcdir)/winsys \
- -I$(srcdir)/driver/gl \
- -I$(srcdir)/driver/gl/gl \
- -I$(srcdir)/driver/gl/gles \
- $(NULL)
-
-AM_CPPFLAGS += \
- -DG_LOG_DOMAIN=\"Cogl\" \
- -DCOGL_COMPILATION \
- -DCOGL_GL_LIBNAME=\"$(COGL_GL_LIBNAME)\" \
- -DCOGL_GLES1_LIBNAME=\"$(COGL_GLES1_LIBNAME)\" \
- -DCOGL_GLES2_LIBNAME=\"$(COGL_GLES2_LIBNAME)\" \
- -DCOGL_LOCALEDIR=\""$(localedir)"\" \
- $(NULL)
-
-if HAVE_COGL_DEFAULT_DRIVER
-AM_CPPFLAGS += \
- -DCOGL_DEFAULT_DRIVER=\"$(COGL_DEFAULT_DRIVER)\"
-endif
-
-
-AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
-
-BUILT_SOURCES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h
-DISTCLEANFILES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h
-EXTRA_DIST += cogl-defines.h.in cogl-egl-defines.h.in cogl-gl-header.h.in
-
-pc_files = mutter-cogl-1.0.pc
-
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = $(pc_files)
-
-DISTCLEANFILES += $(pc_files)
-
-cogl_deprecated_h = \
- deprecated/cogl-clip-state.h \
- deprecated/cogl-fixed.h \
- deprecated/cogl-material-compat.h \
- deprecated/cogl-vertex-buffer.h \
- deprecated/cogl-shader.h \
- deprecated/cogl-clutter.h \
- deprecated/cogl-type-casts.h \
- deprecated/cogl-framebuffer-deprecated.h \
- deprecated/cogl-texture-deprecated.h \
- deprecated/cogl-auto-texture.h \
- $(NULL)
-
-# public 1.x api headers
-cogl_1_public_h = \
- $(cogl_deprecated_h) \
- cogl1-context.h \
- cogl-bitmap.h \
- cogl-color.h \
- cogl-matrix.h \
- cogl-offscreen.h \
- cogl-primitives.h \
- cogl-texture.h \
- cogl-types.h \
- cogl.h \
- $(NULL)
-
-# experimental 2.0 api headers
-# Note: we don't run glib-mkenums over these headers
-cogl_experimental_h = \
- cogl-object.h \
- cogl-renderer.h \
- cogl-swap-chain.h \
- cogl-onscreen-template.h \
- cogl-display.h \
- cogl-context.h \
- cogl-pipeline.h \
- cogl-pipeline-state.h \
- cogl-pipeline-layer-state.h \
- cogl-snippet.h \
- cogl-gles2.h \
- cogl-gles2-types.h \
- cogl-index-buffer.h \
- cogl-attribute-buffer.h \
- cogl-indices.h \
- cogl-attribute.h \
- cogl-primitive.h \
- cogl-framebuffer.h \
- cogl-onscreen.h \
- cogl-frame-info.h \
- cogl-vector.h \
- cogl-euler.h \
- cogl-output.h \
- cogl-quaternion.h \
- cogl-matrix-stack.h \
- cogl-poll.h \
- cogl-texture-3d.h \
- cogl-texture-2d.h \
- cogl-texture-2d-gl.h \
- cogl-texture-rectangle.h \
- cogl-texture-2d-sliced.h \
- cogl-sub-texture.h \
- cogl-atlas-texture.h \
- cogl-meta-texture.h \
- cogl-primitive-texture.h \
- cogl-depth-state.h \
- cogl-buffer.h \
- cogl-pixel-buffer.h \
- cogl2-experimental.h \
- cogl-macros.h \
- cogl-fence.h \
- cogl-version.h \
- cogl-error.h \
- $(NULL)
-
-cogl_additional_experimental_h = \
- cogl-bitmap.h \
- cogl-color.h \
- cogl-matrix.h \
- cogl-texture.h \
- cogl-types.h \
- cogl-gtype-private.h \
- $(NULL)
-
-cogl_nodist_experimental_h = \
- $(NULL)
-
-# nop driver
-cogl_driver_sources = \
- driver/nop/cogl-driver-nop.c \
- driver/nop/cogl-framebuffer-nop-private.h \
- driver/nop/cogl-framebuffer-nop.c \
- driver/nop/cogl-attribute-nop-private.h \
- driver/nop/cogl-attribute-nop.c \
- driver/nop/cogl-clip-stack-nop-private.h \
- driver/nop/cogl-clip-stack-nop.c \
- driver/nop/cogl-texture-2d-nop-private.h \
- driver/nop/cogl-texture-2d-nop.c \
- $(NULL)
-
-# gl driver sources
-cogl_gl_prototypes_h = \
- gl-prototypes/cogl-gles2-functions.h \
- gl-prototypes/cogl-core-functions.h \
- gl-prototypes/cogl-in-gles-core-functions.h \
- gl-prototypes/cogl-in-gles2-core-functions.h \
- gl-prototypes/cogl-glsl-functions.h \
- $(NULL)
-
-cogl_driver_sources += \
- driver/gl/cogl-util-gl-private.h \
- driver/gl/cogl-util-gl.c \
- driver/gl/cogl-framebuffer-gl-private.h \
- driver/gl/cogl-framebuffer-gl.c \
- driver/gl/cogl-texture-gl-private.h \
- driver/gl/cogl-texture-gl.c \
- driver/gl/cogl-texture-2d-gl-private.h \
- driver/gl/cogl-texture-2d-gl.c \
- driver/gl/cogl-attribute-gl-private.h \
- driver/gl/cogl-attribute-gl.c \
- driver/gl/cogl-clip-stack-gl-private.h \
- driver/gl/cogl-clip-stack-gl.c \
- driver/gl/cogl-buffer-gl-private.h \
- driver/gl/cogl-buffer-gl.c \
- driver/gl/cogl-pipeline-opengl.c \
- driver/gl/cogl-pipeline-opengl-private.h \
- driver/gl/cogl-pipeline-fragend-glsl.c \
- driver/gl/cogl-pipeline-fragend-glsl-private.h \
- driver/gl/gl/cogl-pipeline-fragend-arbfp.c \
- driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h \
- driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c \
- driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h \
- driver/gl/cogl-pipeline-fragend-fixed.c \
- driver/gl/cogl-pipeline-fragend-fixed-private.h \
- driver/gl/cogl-pipeline-vertend-glsl.c \
- driver/gl/cogl-pipeline-vertend-glsl-private.h \
- driver/gl/cogl-pipeline-vertend-fixed.c \
- driver/gl/cogl-pipeline-vertend-fixed-private.h \
- driver/gl/cogl-pipeline-progend-fixed.c \
- driver/gl/cogl-pipeline-progend-fixed-private.h \
- driver/gl/cogl-pipeline-progend-glsl.c \
- driver/gl/cogl-pipeline-progend-glsl-private.h \
- $(NULL)
-
-if COGL_DRIVER_GL_SUPPORTED
-cogl_driver_sources += \
- driver/gl/gl/cogl-driver-gl.c \
- driver/gl/gl/cogl-texture-driver-gl.c \
- $(NULL)
-endif
-
-if COGL_DRIVER_GLES_SUPPORTED
-cogl_driver_sources += \
- driver/gl/gles/cogl-driver-gles.c \
- driver/gl/gles/cogl-texture-driver-gles.c \
- $(NULL)
-endif
-
-# winsys sources, common to all backends
-cogl_winsys_common_sources = \
- winsys/cogl-winsys-private.h \
- winsys/cogl-winsys.c \
- $(NULL)
-
-# sources
-cogl_sources_c = \
- $(cogl_driver_sources) \
- $(cogl_winsys_common_sources) \
- cogl-private.h \
- cogl-i18n-private.h \
- cogl-debug.h \
- cogl-debug-options.h \
- cogl-gpu-info.c \
- cogl-gpu-info-private.h \
- cogl-context-private.h \
- cogl-context.c \
- cogl-renderer-private.h \
- cogl-renderer.h \
- cogl-renderer.c \
- cogl-swap-chain-private.h \
- cogl-swap-chain.h \
- cogl-swap-chain.c \
- cogl-onscreen-template-private.h \
- cogl-onscreen-template.h \
- cogl-onscreen-template.c \
- cogl-display-private.h \
- cogl-display.h \
- cogl-display.c \
- cogl-driver.h \
- cogl.c \
- cogl-object-private.h \
- cogl-object.h \
- cogl-object.c \
- cogl-util.h \
- cogl-util.c \
- cogl-bitmap-private.h \
- cogl-bitmap.c \
- cogl-bitmap-conversion.c \
- cogl-bitmap-packing.h \
- cogl-primitives-private.h \
- cogl-primitives.h \
- cogl-primitives.c \
- cogl-bitmap-pixbuf.c \
- cogl-clip-stack.h \
- cogl-clip-stack.c \
- cogl-feature-private.h \
- cogl-feature-private.c \
- cogl-color-private.h \
- cogl-color.c \
- cogl-buffer-private.h \
- cogl-buffer.c \
- cogl-pixel-buffer-private.h \
- cogl-pixel-buffer.c \
- cogl-index-buffer-private.h \
- cogl-index-buffer.c \
- cogl-attribute-buffer-private.h \
- cogl-attribute-buffer.c \
- cogl-indices-private.h \
- cogl-indices.c \
- cogl-attribute-private.h \
- cogl-attribute.c \
- cogl-primitive-private.h \
- cogl-primitive.c \
- cogl-matrix.c \
- cogl-vector.c \
- cogl-euler.c \
- cogl-quaternion-private.h \
- cogl-quaternion.c \
- cogl-matrix-private.h \
- cogl-matrix-stack.c \
- cogl-matrix-stack-private.h \
- cogl-depth-state.c \
- cogl-depth-state-private.h \
- cogl-node.c \
- cogl-node-private.h \
- cogl-pipeline.c \
- cogl-pipeline-private.h \
- cogl-pipeline-layer.c \
- cogl-pipeline-layer-private.h \
- cogl-pipeline-state.c \
- cogl-pipeline-layer-state-private.h \
- cogl-pipeline-layer-state.c \
- cogl-pipeline-state-private.h \
- cogl-pipeline-debug.c \
- cogl-glsl-shader.c \
- cogl-glsl-shader-private.h \
- cogl-glsl-shader-boilerplate.h \
- cogl-pipeline-snippet-private.h \
- cogl-pipeline-snippet.c \
- cogl-pipeline-cache.h \
- cogl-pipeline-cache.c \
- cogl-pipeline-hash-table.h \
- cogl-pipeline-hash-table.c \
- cogl-sampler-cache.c \
- cogl-sampler-cache-private.h \
- cogl-blend-string.c \
- cogl-blend-string.h \
- cogl-debug.c \
- cogl-sub-texture-private.h \
- cogl-texture-private.h \
- cogl-texture-2d-private.h \
- cogl-texture-2d-sliced-private.h \
- cogl-texture-3d-private.h \
- cogl-texture-driver.h \
- cogl-sub-texture.c \
- cogl-texture.c \
- cogl-texture-2d.c \
- cogl-texture-2d-sliced.c \
- cogl-texture-3d.c \
- cogl-texture-rectangle-private.h \
- cogl-texture-rectangle.c \
- cogl-rectangle-map.h \
- cogl-rectangle-map.c \
- cogl-atlas.h \
- cogl-atlas.c \
- cogl-atlas-texture-private.h \
- cogl-atlas-texture.c \
- cogl-meta-texture.c \
- cogl-primitive-texture.c \
- cogl-blit.h \
- cogl-blit.c \
- cogl-spans.h \
- cogl-spans.c \
- cogl-journal-private.h \
- cogl-journal.c \
- cogl-frame-info-private.h \
- cogl-frame-info.c \
- cogl-framebuffer-private.h \
- cogl-framebuffer.c \
- cogl-onscreen-private.h \
- cogl-onscreen.c \
- cogl-output-private.h \
- cogl-output.c \
- cogl-profile.h \
- cogl-profile.c \
- cogl-flags.h \
- cogl-bitmask.h \
- cogl-bitmask.c \
- cogl-gtype.c \
- cogl-gtype-private.h \
- cogl-point-in-poly-private.h \
- cogl-point-in-poly.c \
- cogl-list.c \
- cogl-list.h \
- winsys/cogl-winsys-stub-private.h \
- winsys/cogl-winsys-stub.c \
- cogl-config-private.h \
- cogl-config.c \
- cogl-boxed-value.h \
- cogl-boxed-value.c \
- cogl-snippet-private.h \
- cogl-snippet.c \
- cogl-poll-private.h \
- cogl-poll.c \
- gl-prototypes/cogl-all-functions.h \
- gl-prototypes/cogl-gles1-functions.h \
- gl-prototypes/cogl-gles2-functions.h \
- gl-prototypes/cogl-core-functions.h \
- gl-prototypes/cogl-in-gles-core-functions.h \
- gl-prototypes/cogl-in-gles1-core-functions.h \
- gl-prototypes/cogl-in-gles2-core-functions.h \
- gl-prototypes/cogl-fixed-functions.h \
- gl-prototypes/cogl-glsl-functions.h \
- cogl-memory-stack-private.h \
- cogl-memory-stack.c \
- cogl-magazine-private.h \
- cogl-magazine.c \
- cogl-gles2-context-private.h \
- cogl-gles2-context.c \
- cogl-error-private.h \
- cogl-error.c \
- cogl-closure-list-private.h \
- cogl-closure-list.c \
- cogl-fence.c \
- cogl-fence-private.h \
- deprecated/cogl-clip-state.c \
- deprecated/cogl-fixed.c \
- deprecated/cogl-vertex-buffer-private.h \
- deprecated/cogl-vertex-buffer.c \
- deprecated/cogl-material-compat.c \
- deprecated/cogl-program.c \
- deprecated/cogl-program-private.h \
- deprecated/cogl-auto-texture.c \
- deprecated/cogl-shader-private.h \
- deprecated/cogl-shader.c \
- deprecated/cogl-clutter.c \
- deprecated/cogl-framebuffer-deprecated.c \
- deprecated/cogl-texture-deprecated.c \
- $(NULL)
-
-cogl_experimental_h += cogl-glib-source.h
-cogl_sources_c += cogl-glib-source.c
-
-if SUPPORT_XLIB
-cogl_deprecated_h += deprecated/cogl-clutter-xlib.h
-cogl_1_public_h += cogl-xlib-renderer.h
-
-cogl_experimental_h += \
- winsys/cogl-texture-pixmap-x11.h \
- cogl-xlib.h
-
-cogl_sources_c += \
- cogl-x11-renderer-private.h \
- cogl-xlib-renderer-private.h \
- cogl-xlib-renderer.c \
- cogl-xlib.c \
- cogl-xlib-private.h \
- winsys/cogl-texture-pixmap-x11.c \
- winsys/cogl-texture-pixmap-x11-private.h
-endif
-if SUPPORT_GLX
-cogl_experimental_h += cogl-glx.h
-cogl_sources_c += \
- cogl-glx-renderer-private.h \
- cogl-glx-display-private.h \
- winsys/cogl-winsys-glx-feature-functions.h \
- winsys/cogl-winsys-glx-private.h \
- winsys/cogl-winsys-glx.c
-endif
-if SUPPORT_WAYLAND_EGL_SERVER
-cogl_experimental_h += cogl-wayland-server.h
-endif
-if SUPPORT_EGL_PLATFORM_KMS
-cogl_experimental_h += \
- cogl-kms-renderer.h \
- cogl-kms-display.h
-cogl_sources_c += \
- winsys/cogl-winsys-egl-kms.c \
- winsys/cogl-winsys-egl-kms-private.h
-endif
-if SUPPORT_EGL_PLATFORM_XLIB
-cogl_sources_c += \
- winsys/cogl-winsys-egl-x11.c \
- winsys/cogl-winsys-egl-x11-private.h
-endif
-if SUPPORT_EGL
-cogl_experimental_h += cogl-egl.h
-cogl_nodist_experimental_h += cogl-egl-defines.h
-
-cogl_sources_c += \
- cogl-egl-private.h \
- winsys/cogl-winsys-egl.c \
- winsys/cogl-winsys-egl-feature-functions.h \
- winsys/cogl-winsys-egl-private.h
-endif
-
-# glib-mkenums rules
-glib_enum_h = cogl-enum-types.h
-glib_enum_c = cogl-enum-types.c
-glib_enum_headers = $(cogl_1_public_h)
-include $(top_srcdir)/build/autotools/Makefile.am.enums
-
-mutterlibdir = $(libdir)/mutter
-mutterlib_LTLIBRARIES = libmutter-cogl.la
-
-libmutter_cogl_la_LIBADD = $(LIBM) $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
-if UNIT_TESTS
-libmutter_cogl_la_LIBADD += $(top_builddir)/test-fixtures/libtest-fixtures.la
+if BUILD_COGL_PATH
+SUBDIRS += cogl-path
endif
-# XXX: The aim is to eventually get rid of all private API exports
-# for cogl-pango.
-libmutter_cogl_la_LDFLAGS = \
- -no-undefined \
- -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@ \
- -export-dynamic \
- -rpath $(mutterlibdir) \
- -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_).*"
-
-libmutter_cogl_la_SOURCES = $(cogl_sources_c)
-nodist_libmutter_cogl_la_SOURCES = $(BUILT_SOURCES)
-
-# Cogl installed headers
-cogl_headers = \
- $(cogl_1_public_h) \
- cogl-deprecated.h \
- cogl-pango.h \
- $(NULL)
-
-cogl_base_includedir = $(includedir)/mutter
-cogldeprecatedincludedir = $(cogl_base_includedir)/cogl/cogl/deprecated
-cogldeprecatedinclude_HEADERS = $(cogl_deprecated_h)
-
-coglincludedir = $(cogl_base_includedir)/cogl/cogl
-coglinclude_HEADERS = $(cogl_headers) $(cogl_experimental_h)
-nodist_coglinclude_HEADERS = $(cogl_nodist_experimental_h) cogl-defines.h cogl-enum-types.h
-
-cogl_proto_includedir = $(cogl_base_includedir)/cogl/cogl/gl-prototypes
-cogl_proto_include_HEADERS = $(cogl_gl_prototypes_h)
-
-EXTRA_DIST += \
- cogl.symbols
--include $(INTROSPECTION_MAKEFILE)
-
-INTROSPECTION_GIRS =
-
-if HAVE_INTROSPECTION
-Cogl-1.0.gir: libmutter-cogl.la Makefile
-
-Cogl_1_0_gir_NAMESPACE = Cogl
-Cogl_1_0_gir_VERSION = 1.0
-Cogl_1_0_gir_LIBS = libmutter-cogl.la
-if UNIT_TESTS
-Cogl_1_0_gir_LIBS += $(top_builddir)/test-fixtures/libtest-fixtures.la
+if BUILD_COGL_PANGO
+SUBDIRS += cogl-pango
endif
-Cogl_1_0_gir_FILES = $(cogl_1_public_h) cogl-enum-types.h
-Cogl-2.0.gir: libmutter-cogl.la Makefile
-
-Cogl_2_0_gir_NAMESPACE = Cogl
-Cogl_2_0_gir_VERSION = 2.0
-Cogl_2_0_gir_LIBS = libmutter-cogl.la
-if UNIT_TESTS
-Cogl_2_0_gir_LIBS += $(top_builddir)/test-fixtures/libtest-fixtures.la
+if BUILD_COGL_GLES2
+SUBDIRS += cogl-gles2
endif
-Cogl_2_0_gir_FILES = $(cogl_experimental_h) $(cogl_additional_experimental_h) cogl-enum-types.h
-
-Cogl_1_0_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) -UCOGL_ENABLE_EXPERIMENTAL_API -UCOGL_ENABLE_EXPERIMENTAL_2_0_API -UCOGL_COMPILATION -D__COGL_H_INSIDE__ -D__COGL_XLIB_H_INSIDE__ -D__COGL_EGL_H_INSIDE__ -D__COGL_GLX_H_INSIDE__ -DCOGL_GIR_SCANNING
-Cogl_1_0_gir_INCLUDES = GL-1.0 GObject-2.0
-Cogl_1_0_gir_EXPORT_PACKAGES = cogl-1.0
-Cogl_1_0_gir_SCANNERFLAGS = --warn-all --c-include='cogl/cogl.h'
-Cogl_2_0_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) -DCOGL_ENABLE_EXPERIMENTAL_API=1 -UCOGL_COMPILATION -D__COGL_H_INSIDE__ -D__COGL_XLIB_H_INSIDE__ -DCOGL_GIR_SCANNING
-Cogl_2_0_gir_INCLUDES = GL-1.0 GObject-2.0
-Cogl_2_0_gir_EXPORT_PACKAGES = cogl-2.0-experimental
-Cogl_2_0_gir_SCANNERFLAGS = --warn-all --c-include='cogl/cogl.h' --symbol-prefix=cogl --symbol-prefix=cogl2
+SUBDIRS += tests
-INTROSPECTION_GIRS += Cogl-1.0.gir Cogl-2.0.gir
+ACLOCAL_AMFLAGS = -I build/autotools ${ACLOCAL_FLAGS}
-girdir = $(mutterlibdir)
-gir_DATA = $(INTROSPECTION_GIRS)
+EXTRA_DIST = \
+ config-custom.h
-typelibdir = $(mutterlibdir)
-typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+# .changelog expects these to be initializes
+CLEANFILES=
+DISTCLEANFILES=
-CLEANFILES += $(gir_DATA) $(typelib_DATA)
-endif
+DISTCHECK_CONFIGURE_FLAGS = \
+ --enable-maintainer-flags \
+ --enable-profile \
+ --enable-gles2 \
+ --enable-gl \
+ --enable-xlib-egl-platform \
+ --enable-wayland-egl-platform \
+ --enable-glx \
+ --enable-wayland-egl-server \
+ --enable-cogl-gst
diff --git a/cogl/build/autotools/Makefile.am.enums b/cogl/build/autotools/Makefile.am.enums
new file mode 100644
index 000000000..2fd69d5bd
--- /dev/null
+++ b/cogl/build/autotools/Makefile.am.enums
@@ -0,0 +1,52 @@
+# Rules for generating enumeration types using glib-mkenums
+#
+# Define:
+# glib_enum_h = header template file
+# glib_enum_c = source template file
+# glib_enum_headers = list of headers to parse
+#
+# before including Makefile.am.enums. You will also need to have
+# the following targets already defined:
+#
+# CLEANFILES
+# DISTCLEANFILES
+# BUILT_SOURCES
+# EXTRA_DIST
+#
+# Author: Emmanuele Bassi <ebassi@linux.intel.com>
+
+# Basic sanity checks
+$(if $(GLIB_MKENUMS),,$(error Need to define GLIB_MKENUMS))
+
+$(if $(or $(glib_enum_h), \
+ $(glib_enum_c)),, \
+ $(error Need to define glib_enum_h and glib_enum_c))
+
+$(if $(glib_enum_headers),,$(error Need to define glib_enum_headers))
+
+enum_tmpl_h=$(addprefix $(srcdir)/, $(glib_enum_h:.h=.h.in))
+enum_tmpl_c=$(addprefix $(srcdir)/, $(glib_enum_c:.c=.c.in))
+enum_headers=$(addprefix $(srcdir)/, $(glib_enum_headers))
+
+CLEANFILES += stamp-enum-types
+DISTCLEANFILES += $(glib_enum_h) $(glib_enum_c)
+BUILT_SOURCES += $(glib_enum_h) $(glib_enum_c)
+EXTRA_DIST += $(enum_tmpl_h) $(enum_tmpl_c)
+
+stamp-enum-types: $(enum_headers) $(enum_tmpl_h)
+ $(AM_V_GEN)$(GLIB_MKENUMS) \
+ --template $(enum_tmpl_h) \
+ $(enum_headers) > xgen-eh \
+ && (cmp -s xgen-eh $(glib_enum_h) || cp -f xgen-eh $(glib_enum_h)) \
+ && rm -f xgen-eh \
+ && echo timestamp > $(@F)
+
+$(glib_enum_h): stamp-enum-types
+ @true
+
+$(glib_enum_c): $(enum_headers) $(enum_tmpl_h) $(enum_tmpl_c)
+ $(AM_V_GEN)$(GLIB_MKENUMS) \
+ --template $(enum_tmpl_c) \
+ $(enum_headers) > xgen-ec \
+ && cp -f xgen-ec $(glib_enum_c) \
+ && rm -f xgen-ec
diff --git a/cogl/build/autotools/as-compiler-flag.m4 b/cogl/build/autotools/as-compiler-flag.m4
new file mode 100644
index 000000000..0f660cf07
--- /dev/null
+++ b/cogl/build/autotools/as-compiler-flag.m4
@@ -0,0 +1,62 @@
+dnl as-compiler-flag.m4 0.1.0
+
+dnl autostars m4 macro for detection of compiler flags
+
+dnl David Schleef <ds@schleef.org>
+
+dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $
+
+dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
+dnl Tries to compile with the given CFLAGS.
+dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags,
+dnl and ACTION-IF-NOT-ACCEPTED otherwise.
+
+AC_DEFUN([AS_COMPILER_FLAG],
+[
+ AC_MSG_CHECKING([to see if compiler understands $1])
+
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+
+ AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+ CFLAGS="$save_CFLAGS"
+
+ if test "X$flag_ok" = Xyes ; then
+ m4_ifvaln([$2],[$2])
+ true
+ else
+ m4_ifvaln([$3],[$3])
+ true
+ fi
+ AC_MSG_RESULT([$flag_ok])
+])
+
+dnl AS_COMPILER_FLAGS(VAR, FLAGS)
+dnl Tries to compile with the given CFLAGS.
+
+AC_DEFUN([AS_COMPILER_FLAGS],
+[
+ list=$2
+ flags_supported=""
+ flags_unsupported=""
+ AC_MSG_CHECKING([for supported compiler flags])
+ for each in $list
+ do
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $each"
+ AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+ CFLAGS="$save_CFLAGS"
+
+ if test "X$flag_ok" = Xyes ; then
+ flags_supported="$flags_supported $each"
+ else
+ flags_unsupported="$flags_unsupported $each"
+ fi
+ done
+ AC_MSG_RESULT([$flags_supported])
+ if test "X$flags_unsupported" != X ; then
+ AC_MSG_WARN([unsupported compiler flags: $flags_unsupported])
+ fi
+ $1="$$1 $flags_supported"
+])
+
diff --git a/cogl/build/autotools/introspection.m4 b/cogl/build/autotools/introspection.m4
new file mode 100644
index 000000000..589721c5a
--- /dev/null
+++ b/cogl/build/autotools/introspection.m4
@@ -0,0 +1,94 @@
+dnl -*- mode: autoconf -*-
+dnl Copyright 2009 Johan Dahlin
+dnl
+dnl This file is free software; the author(s) gives unlimited
+dnl permission to copy and/or distribute it, with or without
+dnl modifications, as long as this notice is preserved.
+dnl
+
+# serial 1
+
+m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL],
+[
+ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
+ AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
+ AC_BEFORE([LT_INIT],[$0])dnl setup libtool first
+
+ dnl enable/disable introspection
+ m4_if([$2], [require],
+ [dnl
+ enable_introspection=yes
+ ],[dnl
+ AC_ARG_ENABLE(introspection,
+ AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]],
+ [Enable introspection for this build]),,
+ [enable_introspection=auto])
+ ])dnl
+
+ AC_MSG_CHECKING([for gobject-introspection])
+
+ dnl presence/version checking
+ AS_CASE([$enable_introspection],
+ [no], [dnl
+ found_introspection="no (disabled, use --enable-introspection to enable)"
+ ],dnl
+ [yes],[dnl
+ PKG_CHECK_EXISTS([gobject-introspection-1.0],,
+ AC_MSG_ERROR([gobject-introspection-1.0 is not installed]))
+ PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1],
+ found_introspection=yes,
+ AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME]))
+ ],dnl
+ [auto],[dnl
+ PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no)
+ ],dnl
+ [dnl
+ AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@])
+ ])dnl
+
+ AC_MSG_RESULT([$found_introspection])
+
+ INTROSPECTION_SCANNER=
+ INTROSPECTION_COMPILER=
+ INTROSPECTION_GENERATE=
+ INTROSPECTION_GIRDIR=
+ INTROSPECTION_TYPELIBDIR=
+ if test "x$found_introspection" = "xyes"; then
+ INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
+ INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0`
+ INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0`
+ INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0`
+ INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
+ INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0`
+ INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0`
+ INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection
+ fi
+ AC_SUBST(INTROSPECTION_SCANNER)
+ AC_SUBST(INTROSPECTION_COMPILER)
+ AC_SUBST(INTROSPECTION_GENERATE)
+ AC_SUBST(INTROSPECTION_GIRDIR)
+ AC_SUBST(INTROSPECTION_TYPELIBDIR)
+ AC_SUBST(INTROSPECTION_CFLAGS)
+ AC_SUBST(INTROSPECTION_LIBS)
+ AC_SUBST(INTROSPECTION_MAKEFILE)
+
+ AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes")
+])
+
+
+dnl Usage:
+dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version])
+
+AC_DEFUN([GOBJECT_INTROSPECTION_CHECK],
+[
+ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1])
+])
+
+dnl Usage:
+dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version])
+
+
+AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE],
+[
+ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require])
+])
diff --git a/cogl/cogl-gles2/GLES2/gl2.h b/cogl/cogl-gles2/GLES2/gl2.h
new file mode 100644
index 000000000..718fb3b9b
--- /dev/null
+++ b/cogl/cogl-gles2/GLES2/gl2.h
@@ -0,0 +1,169 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 16803 $ on $Date:: 2012-02-02 09:49:18 -0800 #$ */
+
+#include <GLES2/gl2platform.h>
+#include <cogl/cogl-gles2-types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/cogl/cogl-gles2/GLES2/gl2ext.h b/cogl/cogl-gles2/GLES2/gl2ext.h
new file mode 100644
index 000000000..e4016a5ad
--- /dev/null
+++ b/cogl/cogl-gles2/GLES2/gl2ext.h
@@ -0,0 +1,1498 @@
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 16994 $ on $Date:: 2012-02-29 18:29:34 -0800 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_UNSIGNED_INT 0x1405
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_float */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_texture_half_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_npot */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
+#define GL_MAX_SAMPLES_ANGLE 0x8D57
+#endif
+
+/* GL_ANGLE_instanced_arrays */
+#ifndef GL_ANGLE_instanced_arrays
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_TEXTURE_USAGE_ANGLE 0x93A2
+#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3
+#endif
+
+/* GL_ANGLE_translated_shader_source */
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_RGB_422_APPLE 0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
+#define GL_MAX_SAMPLES_APPLE 0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_MALI_SHADER_BINARY_ARM 0x8F60
+#endif
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_RGBA16F_EXT 0x881A
+#define GL_RGB16F_EXT 0x881B
+#define GL_RG16F_EXT 0x822F
+#define GL_R16F_EXT 0x822D
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211
+#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
+#define GL_PROGRAM_OBJECT_EXT 0x8B40
+#define GL_SHADER_OBJECT_EXT 0x8B48
+#define GL_BUFFER_OBJECT_EXT 0x9151
+#define GL_QUERY_OBJECT_EXT 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
+#endif
+
+/* GL_EXT_debug_marker */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_COLOR_EXT 0x1800
+#define GL_DEPTH_EXT 0x1801
+#define GL_STENCIL_EXT 0x1802
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x9134
+#define GL_MAX_SAMPLES_EXT 0x9135
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
+#define GL_CURRENT_QUERY_EXT 0x8865
+#define GL_QUERY_RESULT_EXT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_BGRA_EXT 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_VERTEX_SHADER_BIT_EXT 0x00000001
+#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002
+#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE_EXT 0x8258
+#define GL_ACTIVE_PROGRAM_EXT 0x8259
+#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A
+#endif
+
+/* GL_EXT_shader_texture_lod */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C
+#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D
+#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E
+#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_RED_EXT 0x1903
+#define GL_RG_EXT 0x8227
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+#define GL_ALPHA8_EXT 0x803C
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_RGBA32F_EXT 0x8814
+#define GL_RGB32F_EXT 0x8815
+#define GL_ALPHA32F_EXT 0x8816
+#define GL_LUMINANCE32F_EXT 0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
+/* reuse GL_RGBA16F_EXT */
+/* reuse GL_RGB16F_EXT */
+#define GL_ALPHA16F_EXT 0x881C
+#define GL_LUMINANCE16F_EXT 0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGB10_EXT 0x8052
+#define GL_BGRA8_EXT 0x93A1
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#define GL_R32F_EXT 0x822E
+#define GL_RG32F_EXT 0x8230
+#define GL_R16F_EXT 0x822D
+#define GL_RG16F_EXT 0x822F
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_SHADER_BINARY_DMP 0x9250
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_SGX_PROGRAM_BINARY_IMG 0x9130
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA_IMG 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_SGX_BINARY_IMG 0x8C0A
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#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
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134
+#define GL_MAX_SAMPLES_IMG 0x9135
+#define GL_TEXTURE_SAMPLES_IMG 0x9136
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_COVERAGE_COMPONENT_NV 0x8ED0
+#define GL_COVERAGE_COMPONENT4_NV 0x8ED1
+#define GL_COVERAGE_ATTACHMENT_NV 0x8ED2
+#define GL_COVERAGE_BUFFERS_NV 0x8ED3
+#define GL_COVERAGE_SAMPLES_NV 0x8ED4
+#define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5
+#define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6
+#define GL_COVERAGE_AUTOMATIC_NV 0x8ED7
+#define GL_COVERAGE_BUFFER_BIT_NV 0x8000
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_NV 0x8824
+#define GL_DRAW_BUFFER0_NV 0x8825
+#define GL_DRAW_BUFFER1_NV 0x8826
+#define GL_DRAW_BUFFER2_NV 0x8827
+#define GL_DRAW_BUFFER3_NV 0x8828
+#define GL_DRAW_BUFFER4_NV 0x8829
+#define GL_DRAW_BUFFER5_NV 0x882A
+#define GL_DRAW_BUFFER6_NV 0x882B
+#define GL_DRAW_BUFFER7_NV 0x882C
+#define GL_DRAW_BUFFER8_NV 0x882D
+#define GL_DRAW_BUFFER9_NV 0x882E
+#define GL_DRAW_BUFFER10_NV 0x882F
+#define GL_DRAW_BUFFER11_NV 0x8830
+#define GL_DRAW_BUFFER12_NV 0x8831
+#define GL_DRAW_BUFFER13_NV 0x8832
+#define GL_DRAW_BUFFER14_NV 0x8833
+#define GL_DRAW_BUFFER15_NV 0x8834
+#define GL_COLOR_ATTACHMENT0_NV 0x8CE0
+#define GL_COLOR_ATTACHMENT1_NV 0x8CE1
+#define GL_COLOR_ATTACHMENT2_NV 0x8CE2
+#define GL_COLOR_ATTACHMENT3_NV 0x8CE3
+#define GL_COLOR_ATTACHMENT4_NV 0x8CE4
+#define GL_COLOR_ATTACHMENT5_NV 0x8CE5
+#define GL_COLOR_ATTACHMENT6_NV 0x8CE6
+#define GL_COLOR_ATTACHMENT7_NV 0x8CE7
+#define GL_COLOR_ATTACHMENT8_NV 0x8CE8
+#define GL_COLOR_ATTACHMENT9_NV 0x8CE9
+#define GL_COLOR_ATTACHMENT10_NV 0x8CEA
+#define GL_COLOR_ATTACHMENT11_NV 0x8CEB
+#define GL_COLOR_ATTACHMENT12_NV 0x8CEC
+#define GL_COLOR_ATTACHMENT13_NV 0x8CED
+#define GL_COLOR_ATTACHMENT14_NV 0x8CEE
+#define GL_COLOR_ATTACHMENT15_NV 0x8CEF
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF
+/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_READ_BUFFER_NV 0x0C02
+#endif
+
+/* GL_NV_read_buffer_front */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_compression_s3tc_update */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_npot_2D_mipmap */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_ALPHA_TEST_QCOM 0x0BC0
+#define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1
+#define GL_ALPHA_TEST_REF_QCOM 0x0BC2
+#endif
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
+#define GL_TEXTURE_TYPE_QCOM 0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
+#define GL_TEXTURE_TARGET_QCOM 0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
+#define GL_STATE_RESTORE 0x8BDC
+#endif
+
+/* GL_QCOM_extended_get2 */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_WRITEONLY_RENDERING_QCOM 0x8823
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_SHADER_BINARY_VIV 0x8FC4
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_OES_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array);
+GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
+GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_ANGLE_instanced_arrays
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
+#endif
+typedef void (GL_APIENTRYP PFLGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFLGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+typedef void (GL_APIENTRYP PFLGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor);
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_ANGLE_pack_reverse_row_order 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_ANGLE_texture_compression_dxt3 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_ANGLE_texture_compression_dxt5 1
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_ANGLE_texture_usage 1
+#endif
+
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_ANGLE_translated_shader_source 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
+#endif
+typedef void (GL_APIENTRYP PFLGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_ARM_mali_shader_binary 1
+#endif
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_EXT_color_buffer_half_float 1
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_EXT_discard_framebuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_EXT_occlusion_query_boolean 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids);
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id);
+GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target);
+GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_EXT_read_format_bgra 1
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program);
+GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program);
+GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings);
+GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines);
+GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines);
+GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+
+/* GL_EXT_shader_texture_lod */
+#ifndef GL_EXT_shader_texture_lod
+#define GL_EXT_shader_texture_lod 1
+#endif
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_EXT_shadow_samplers 1
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_EXT_texture_rg 1
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_EXT_unpack_subimage 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_DMP_shader_binary 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_IMG_program_binary 1
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_IMG_shader_binary 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_IMG_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 1
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_NV_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_NV_fbo_color_attachments 1
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_NV_read_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
+#endif
+
+/* GL_NV_read_buffer_front */
+#ifndef GL_NV_read_buffer_front
+#define GL_NV_read_buffer_front 1
+#endif
+
+/* GL_NV_read_depth */
+#ifndef GL_NV_read_depth
+#define GL_NV_read_depth 1
+#endif
+
+/* GL_NV_read_depth_stencil */
+#ifndef GL_NV_read_depth_stencil
+#define GL_NV_read_depth_stencil 1
+#endif
+
+/* GL_NV_read_stencil */
+#ifndef GL_NV_read_stencil
+#define GL_NV_read_stencil 1
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+#ifndef GL_NV_texture_compression_s3tc_update
+#define GL_NV_texture_compression_s3tc_update 1
+#endif
+
+/* GL_NV_texture_npot_2D_mipmap */
+#ifndef GL_NV_texture_npot_2D_mipmap
+#define GL_NV_texture_npot_2D_mipmap 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_QCOM_alpha_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
+#endif
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_QCOM_extended_get 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
+GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
+#endif
+
+/* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_extended_get2
+#define GL_QCOM_extended_get2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
+GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 1
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_QCOM_tiled_rendering 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
+#endif
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_VIV_shader_binary 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/cogl/cogl-gles2/GLES2/gl2platform.h b/cogl/cogl-gles2/GLES2/gl2platform.h
new file mode 100644
index 000000000..8bc44b07e
--- /dev/null
+++ b/cogl/cogl-gles2/GLES2/gl2platform.h
@@ -0,0 +1,28 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#ifndef GL_APICALL
+#define GL_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY
+#endif
+
+#endif /* __gl2platform_h_ */
diff --git a/cogl/cogl-gles2/Makefile.am b/cogl/cogl-gles2/Makefile.am
new file mode 100644
index 000000000..47baafcc0
--- /dev/null
+++ b/cogl/cogl-gles2/Makefile.am
@@ -0,0 +1,31 @@
+# preamble
+
+NULL =
+
+mutterlibdir = $(libdir)/mutter
+mutterlib_LTLIBRARIES = libmutter-cogl-gles2.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_builddir)
+
+AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
+
+libmutter_cogl_gles2_la_SOURCES = cogl-gles2-api.c
+libmutter_cogl_gles2_la_LDFLAGS = \
+ -no-undefined \
+ -rpath $(mutterlibdir) \
+ -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@ \
+ -export-dynamic \
+ -export-symbols-regex "^gl*"
+
+coglgles2includedir = $(includedir)/mutter/cogl/cogl-gles2/GLES2
+coglgles2include_HEADERS = \
+ GLES2/gl2.h \
+ GLES2/gl2ext.h \
+ GLES2/gl2platform.h
+
+pc_files = mutter-cogl-gles2-1.0.pc
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pc_files)
diff --git a/cogl/cogl-gles2/cogl-gles2-api.c b/cogl/cogl-gles2/cogl-gles2-api.c
new file mode 100644
index 000000000..22ab2b716
--- /dev/null
+++ b/cogl/cogl-gles2/cogl-gles2-api.c
@@ -0,0 +1,1048 @@
+
+#include <GLES2/gl2.h>
+
+#include <cogl/cogl-gles2.h>
+
+void
+glBindTexture (GLenum target, GLuint texture)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBindTexture (target, texture);
+}
+
+void
+glBlendFunc (GLenum sfactor, GLenum dfactor)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBlendFunc (sfactor, dfactor);
+}
+
+void
+glClear (GLbitfield mask)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glClear (mask);
+}
+
+void
+glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glClearColor (red, green, blue, alpha);
+}
+
+void
+glClearStencil (GLint s)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glClearStencil (s);
+}
+
+void
+glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glColorMask (red, green, blue, alpha);
+}
+
+void
+glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glCopyTexSubImage2D (target, level, xoffset, yoffset, x, y, width,
+ height);
+}
+
+void
+glDeleteTextures (GLsizei n, const GLuint * textures)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDeleteTextures (n, textures);
+}
+
+void
+glDepthFunc (GLenum func)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDepthFunc (func);
+}
+
+void
+glDepthMask (GLboolean flag)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDepthMask (flag);
+}
+
+void
+glDisable (GLenum cap)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDisable (cap);
+}
+
+void
+glDrawArrays (GLenum mode, GLint first, GLsizei count)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDrawArrays (mode, first, count);
+}
+
+void
+glDrawElements (GLenum mode, GLsizei count, GLenum type,
+ const GLvoid * indices)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDrawElements (mode, count, type, indices);
+}
+
+void
+glEnable (GLenum cap)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glEnable (cap);
+}
+
+void
+glFinish (void)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glFinish ();
+}
+
+void
+glFlush (void)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glFlush ();
+}
+
+void
+glFrontFace (GLenum mode)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glFrontFace (mode);
+}
+
+void
+glCullFace (GLenum mode)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glCullFace (mode);
+}
+
+void
+glGenTextures (GLsizei n, GLuint * textures)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGenTextures (n, textures);
+}
+
+GLenum
+glGetError (void)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glGetError ();
+}
+
+void
+glGetIntegerv (GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetIntegerv (pname, params);
+}
+
+void
+glGetBooleanv (GLenum pname, GLboolean * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetBooleanv (pname, params);
+}
+
+void
+glGetFloatv (GLenum pname, GLfloat * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetFloatv (pname, params);
+}
+
+const GLubyte *
+glGetString (GLenum name)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glGetString (name);
+}
+
+void
+glHint (GLenum target, GLenum mode)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glHint (target, mode);
+}
+
+GLboolean
+glIsTexture (GLuint texture)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glIsTexture (texture);
+}
+
+void
+glPixelStorei (GLenum pname, GLint param)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glPixelStorei (pname, param);
+}
+
+void
+glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+ GLenum type, GLvoid * pixels)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glReadPixels (x, y, width, height, format, type, pixels);
+}
+
+void
+glScissor (GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glScissor (x, y, width, height);
+}
+
+void
+glStencilFunc (GLenum func, GLint ref, GLuint mask)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glStencilFunc (func, ref, mask);
+}
+
+void
+glStencilMask (GLuint mask)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glStencilMask (mask);
+}
+
+void
+glStencilOp (GLenum fail, GLenum zfail, GLenum zpass)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glStencilOp (fail, zfail, zpass);
+}
+
+void
+glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const GLvoid * pixels)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glTexImage2D (target, level, internalformat, width, height, border,
+ format, type, pixels);
+}
+
+void
+glTexParameterf (GLenum target, GLenum pname, GLfloat param)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glTexParameterf (target, pname, param);
+}
+
+void
+glTexParameterfv (GLenum target, GLenum pname, const GLfloat * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glTexParameterfv (target, pname, params);
+}
+
+void
+glTexParameteri (GLenum target, GLenum pname, GLint param)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glTexParameteri (target, pname, param);
+}
+
+void
+glTexParameteriv (GLenum target, GLenum pname, const GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glTexParameteriv (target, pname, params);
+}
+
+void
+glGetTexParameterfv (GLenum target, GLenum pname, GLfloat * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetTexParameterfv (target, pname, params);
+}
+
+void
+glGetTexParameteriv (GLenum target, GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetTexParameteriv (target, pname, params);
+}
+
+void
+glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format, GLenum type,
+ const GLvoid * pixels)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glTexSubImage2D (target, level, xoffset, yoffset, width, height,
+ format, type, pixels);
+}
+
+void
+glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x,
+ GLint y, GLsizei width, GLsizei height, GLint border)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glCopyTexImage2D (target, level, internalformat,
+ x, y, width, height, border);
+}
+
+void
+glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glViewport (x, y, width, height);
+}
+
+GLboolean
+glIsEnabled (GLenum cap)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glIsEnabled (cap);
+}
+
+void
+glLineWidth (GLfloat width)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glLineWidth (width);
+}
+
+void
+glPolygonOffset (GLfloat factor, GLfloat units)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glPolygonOffset (factor, units);
+}
+
+void
+glDepthRangef (GLfloat near_val, GLfloat far_val)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDepthRangef (near_val, far_val);
+}
+
+void
+glClearDepthf (GLclampf depth)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glClearDepthf (depth);
+}
+
+void
+glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const GLvoid * data)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glCompressedTexImage2D (target, level, internalformat, width,
+ height, border, imageSize, data);
+}
+
+void
+glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const GLvoid * data)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glCompressedTexSubImage2D (target, level,
+ xoffset, yoffset, width, height,
+ format, imageSize, data);
+}
+
+void
+glSampleCoverage (GLclampf value, GLboolean invert)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glSampleCoverage (value, invert);
+}
+
+void
+glGetBufferParameteriv (GLenum target, GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetBufferParameteriv (target, pname, params);
+}
+
+void
+glGenBuffers (GLsizei n, GLuint * buffers)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGenBuffers (n, buffers);
+}
+
+void
+glBindBuffer (GLenum target, GLuint buffer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBindBuffer (target, buffer);
+}
+
+void
+glBufferData (GLenum target, GLsizeiptr size, const GLvoid * data,
+ GLenum usage)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBufferData (target, size, data, usage);
+}
+
+void
+glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size,
+ const GLvoid * data)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBufferSubData (target, offset, size, data);
+}
+
+void
+glDeleteBuffers (GLsizei n, const GLuint * buffers)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDeleteBuffers (n, buffers);
+}
+
+GLboolean
+glIsBuffer (GLuint buffer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glIsBuffer (buffer);
+}
+
+void
+glActiveTexture (GLenum texture)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glActiveTexture (texture);
+}
+
+void
+glGenRenderbuffers (GLsizei n, GLuint * renderbuffers)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGenRenderbuffers (n, renderbuffers);
+}
+
+void
+glDeleteRenderbuffers (GLsizei n, const GLuint * renderbuffers)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDeleteRenderbuffers (n, renderbuffers);
+}
+
+void
+glBindRenderbuffer (GLenum target, GLuint renderbuffer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBindRenderbuffer (target, renderbuffer);
+}
+
+void
+glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width,
+ GLsizei height)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glRenderbufferStorage (target, internalformat, width, height);
+}
+
+void
+glGenFramebuffers (GLsizei n, GLuint * framebuffers)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGenFramebuffers (n, framebuffers);
+}
+
+void
+glBindFramebuffer (GLenum target, GLuint framebuffer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBindFramebuffer (target, framebuffer);
+}
+
+void
+glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget,
+ GLuint texture, GLint level)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glFramebufferTexture2D (target, attachment,
+ textarget, texture, level);
+}
+
+void
+glFramebufferRenderbuffer (GLenum target, GLenum attachment,
+ GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glFramebufferRenderbuffer (target, attachment,
+ renderbuffertarget, renderbuffer);
+}
+
+GLboolean
+glIsRenderbuffer (GLuint renderbuffer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glIsRenderbuffer (renderbuffer);
+}
+
+GLenum
+glCheckFramebufferStatus (GLenum target)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glCheckFramebufferStatus (target);
+}
+
+void
+glDeleteFramebuffers (GLsizei n, const GLuint * framebuffers)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDeleteFramebuffers (n, framebuffers);
+}
+
+void
+glGenerateMipmap (GLenum target)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGenerateMipmap (target);
+}
+
+void
+glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment,
+ GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetFramebufferAttachmentParameteriv (target,
+ attachment, pname, params);
+}
+
+void
+glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetRenderbufferParameteriv (target, pname, params);
+}
+
+GLboolean
+glIsFramebuffer (GLuint framebuffer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glIsFramebuffer (framebuffer);
+}
+
+void
+glBlendEquation (GLenum mode)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBlendEquation (mode);
+}
+
+void
+glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBlendColor (red, green, blue, alpha);
+}
+
+void
+glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha,
+ GLenum dstAlpha)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBlendFuncSeparate (srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void
+glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBlendEquationSeparate (modeRGB, modeAlpha);
+}
+
+void
+glReleaseShaderCompiler (void)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glReleaseShaderCompiler ();
+}
+
+void
+glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype,
+ GLint * range, GLint * precision)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetShaderPrecisionFormat (shadertype, precisiontype,
+ range, precision);
+}
+
+void
+glShaderBinary (GLsizei n, const GLuint * shaders, GLenum binaryformat,
+ const GLvoid * binary, GLsizei length)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glShaderBinary (n, shaders, binaryformat, binary, length);
+}
+
+void
+glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glStencilFuncSeparate (face, func, ref, mask);
+}
+
+void
+glStencilMaskSeparate (GLenum face, GLuint mask)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glStencilMaskSeparate (face, mask);
+}
+
+void
+glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glStencilOpSeparate (face, fail, zfail, zpass);
+}
+
+GLuint
+glCreateProgram (void)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glCreateProgram ();
+}
+
+GLuint
+glCreateShader (GLenum shaderType)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glCreateShader (shaderType);
+}
+
+void
+glShaderSource (GLuint shader, GLsizei count,
+ const GLchar * const *string, const GLint * length)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glShaderSource (shader, count, string, length);
+}
+
+void
+glCompileShader (GLuint shader)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glCompileShader (shader);
+}
+
+void
+glDeleteShader (GLuint shader)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDeleteShader (shader);
+}
+
+void
+glAttachShader (GLuint program, GLuint shader)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glAttachShader (program, shader);
+}
+
+void
+glLinkProgram (GLuint program)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glLinkProgram (program);
+}
+
+void
+glUseProgram (GLuint program)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUseProgram (program);
+}
+
+GLint
+glGetUniformLocation (GLuint program, const char *name)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glGetUniformLocation (program, name);
+}
+
+void
+glDeleteProgram (GLuint program)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDeleteProgram (program);
+}
+
+void
+glGetShaderInfoLog (GLuint shader, GLsizei maxLength, GLsizei * length,
+ char *infoLog)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetShaderInfoLog (shader, maxLength, length, infoLog);
+}
+
+void
+glGetShaderiv (GLuint shader, GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetShaderiv (shader, pname, params);
+}
+
+void
+glVertexAttribPointer (GLuint index, GLint size, GLenum type,
+ GLboolean normalized, GLsizei stride,
+ const GLvoid * pointer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttribPointer (index, size, type, normalized, stride,
+ pointer);
+}
+
+void
+glEnableVertexAttribArray (GLuint index)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glEnableVertexAttribArray (index);
+}
+
+void
+glDisableVertexAttribArray (GLuint index)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDisableVertexAttribArray (index);
+}
+
+void
+glUniform1f (GLint location, GLfloat v0)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform1f (location, v0);
+}
+
+void
+glUniform2f (GLint location, GLfloat v0, GLfloat v1)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform2f (location, v0, v1);
+}
+
+void
+glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform3f (location, v0, v1, v2);
+}
+
+void
+glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform4f (location, v0, v1, v2, v3);
+}
+
+void
+glUniform1fv (GLint location, GLsizei count, const GLfloat * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform1fv (location, count, value);
+}
+
+void
+glUniform2fv (GLint location, GLsizei count, const GLfloat * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform2fv (location, count, value);
+}
+
+void
+glUniform3fv (GLint location, GLsizei count, const GLfloat * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform3fv (location, count, value);
+}
+
+void
+glUniform4fv (GLint location, GLsizei count, const GLfloat * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform4fv (location, count, value);
+}
+
+void
+glUniform1i (GLint location, GLint v0)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform1i (location, v0);
+}
+
+void
+glUniform2i (GLint location, GLint v0, GLint v1)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform2i (location, v0, v1);
+}
+
+void
+glUniform3i (GLint location, GLint v0, GLint v1, GLint v2)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform3i (location, v0, v1, v2);
+}
+
+void
+glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform4i (location, v0, v1, v2, v3);
+}
+
+void
+glUniform1iv (GLint location, GLsizei count, const GLint * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform1iv (location, count, value);
+}
+
+void
+glUniform2iv (GLint location, GLsizei count, const GLint * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform2iv (location, count, value);
+}
+
+void
+glUniform3iv (GLint location, GLsizei count, const GLint * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform3iv (location, count, value);
+}
+
+void
+glUniform4iv (GLint location, GLsizei count, const GLint * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniform4iv (location, count, value);
+}
+
+void
+glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniformMatrix2fv (location, count, transpose, value);
+}
+
+void
+glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniformMatrix3fv (location, count, transpose, value);
+}
+
+void
+glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat * value)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glUniformMatrix4fv (location, count, transpose, value);
+}
+
+void
+glGetUniformfv (GLuint program, GLint location, GLfloat * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetUniformfv (program, location, params);
+}
+
+void
+glGetUniformiv (GLuint program, GLint location, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetUniformiv (program, location, params);
+}
+
+void
+glGetProgramiv (GLuint program, GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetProgramiv (program, pname, params);
+}
+
+void
+glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei * length,
+ char *infoLog)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetProgramInfoLog (program, bufSize, length, infoLog);
+}
+
+void
+glVertexAttrib1f (GLuint indx, GLfloat x)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib1f (indx, x);
+}
+
+void
+glVertexAttrib1fv (GLuint indx, const GLfloat * values)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib1fv (indx, values);
+}
+
+void
+glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib2f (indx, x, y);
+}
+
+void
+glVertexAttrib2fv (GLuint indx, const GLfloat * values)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib2fv (indx, values);
+}
+
+void
+glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib3f (indx, x, y, z);
+}
+
+void
+glVertexAttrib3fv (GLuint indx, const GLfloat * values)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib3fv (indx, values);
+}
+
+void
+glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib4f (index, x, y, z, w);
+}
+
+void
+glVertexAttrib4fv (GLuint indx, const GLfloat * values)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glVertexAttrib4fv (indx, values);
+}
+
+void
+glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetVertexAttribfv (index, pname, params);
+}
+
+void
+glGetVertexAttribiv (GLuint index, GLenum pname, GLint * params)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetVertexAttribiv (index, pname, params);
+}
+
+void
+glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid ** pointer)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetVertexAttribPointerv (index, pname, pointer);
+}
+
+GLint
+glGetAttribLocation (GLuint program, const char *name)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glGetAttribLocation (program, name);
+}
+
+void
+glBindAttribLocation (GLuint program, GLuint index, const GLchar * name)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glBindAttribLocation (program, index, name);
+}
+
+void
+glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize,
+ GLsizei * length, GLint * size, GLenum * type,
+ GLchar * name)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetActiveAttrib (program, index, bufsize, length, size, type,
+ name);
+}
+
+void
+glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize,
+ GLsizei * length, GLint * size, GLenum * type,
+ GLchar * name)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetActiveUniform (program, index, bufsize, length, size, type,
+ name);
+}
+
+void
+glDetachShader (GLuint program, GLuint shader)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glDetachShader (program, shader);
+}
+
+void
+glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei * count,
+ GLuint * shaders)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetAttachedShaders (program, maxcount, count, shaders);
+}
+
+void
+glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei * length,
+ GLchar * source)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glGetShaderSource (shader, bufsize, length, source);
+}
+
+GLboolean
+glIsShader (GLuint shader)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glIsShader (shader);
+}
+
+GLboolean
+glIsProgram (GLuint program)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ return vtable->glIsProgram (program);
+}
+
+void
+glValidateProgram (GLuint program)
+{
+ CoglGLES2Vtable *vtable = cogl_gles2_get_current_vtable ();
+ vtable->glValidateProgram (program);
+}
diff --git a/cogl/cogl-gles2/mutter-cogl-gles2-1.0.pc.in b/cogl/cogl-gles2/mutter-cogl-gles2-1.0.pc.in
new file mode 100644
index 000000000..a66935318
--- /dev/null
+++ b/cogl/cogl-gles2/mutter-cogl-gles2-1.0.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@/mutter
+includedir=@includedir@/mutter
+apiversion=1.0
+requires=@COGL_PKG_REQUIRES@ mutter-cogl-1.0
+
+Name: Cogl
+Description: An object oriented GL/GLES Abstraction/Utility Layer
+Version: @COGL_1_VERSION@
+Libs: -L${libdir} -lmutter-cogl-gles2
+Cflags: -I${includedir}/cogl
+Requires: ${requires}
diff --git a/cogl/cogl-pango/Makefile.am b/cogl/cogl-pango/Makefile.am
new file mode 100644
index 000000000..e32ad26a5
--- /dev/null
+++ b/cogl/cogl-pango/Makefile.am
@@ -0,0 +1,109 @@
+NULL =
+
+CLEANFILES =
+DISTCLEANFILES =
+
+EXTRA_DIST =
+
+source_c = \
+ cogl-pango-display-list.c \
+ cogl-pango-fontmap.c \
+ cogl-pango-render.c \
+ cogl-pango-glyph-cache.c \
+ cogl-pango-pipeline-cache.c \
+ $(NULL)
+
+source_h = cogl-pango.h
+
+source_h_priv = \
+ cogl-pango-display-list.h \
+ cogl-pango-private.h \
+ cogl-pango-glyph-cache.h \
+ cogl-pango-pipeline-cache.h \
+ $(NULL)
+
+mutterlibdir = $(libdir)/mutter
+mutterlib_LTLIBRARIES = libmutter-cogl-pango.la
+
+libmutter_cogl_pango_la_SOURCES = $(source_c) $(source_h) $(source_h_priv)
+libmutter_cogl_pango_la_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_PANGO_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
+libmutter_cogl_pango_la_LIBADD = $(top_builddir)/cogl/libmutter-cogl.la
+libmutter_cogl_pango_la_LIBADD += $(COGL_DEP_LIBS) $(COGL_PANGO_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
+libmutter_cogl_pango_la_LDFLAGS = \
+ -export-dynamic \
+ -rpath $(mutterlibdir) \
+ -export-symbols-regex "^cogl_pango_.*" \
+ -no-undefined \
+ -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@
+
+AM_CPPFLAGS = \
+ -DCOGL_COMPILATION \
+ -DG_LOG_DOMAIN=\"CoglPango\" \
+ -I$(top_srcdir)/cogl \
+ -I$(top_builddir)/cogl \
+ -I$(top_srcdir)/cogl/winsys \
+ -I$(top_srcdir) \
+ -I$(top_builddir)
+
+cogl_base_includedir = $(includedir)/mutter
+cogl_pangoheadersdir = $(cogl_base_includedir)/cogl/cogl-pango
+cogl_pangoheaders_HEADERS = $(source_h)
+
+pc_files = mutter-cogl-pango-1.0.pc
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pc_files)
+
+DISTCLEANFILES += $(pc_files)
+
+EXTRA_DIST += cogl-pango.symbols
+
+-include $(INTROSPECTION_MAKEFILE)
+
+INTROSPECTION_GIRS =
+
+if HAVE_INTROSPECTION
+INTROSPECTION_COMPILER_ARGS=--includedir=$(top_builddir)/cogl
+
+CoglPango-1.0.gir: libmutter-cogl-pango.la Makefile
+
+CoglPango_1_0_gir_NAMESPACE = CoglPango
+CoglPango_1_0_gir_VERSION = 1.0
+CoglPango_1_0_gir_LIBS = $(top_builddir)/cogl/libmutter-cogl.la libmutter-cogl-pango.la
+CoglPango_1_0_gir_FILES = $(source_h) $(source_c)
+CoglPango_1_0_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) $(COGL_PANGO_DEP_CFLAGS)
+CoglPango_1_0_gir_INCLUDES = Pango-1.0 PangoCairo-1.0
+CoglPango_1_0_gir_EXPORT_PACKAGES = cogl-pango-1.0
+CoglPango_1_0_gir_SCANNERFLAGS = \
+ --warn-all \
+ --identifier-prefix=CoglPango \
+ --symbol-prefix=cogl_pango \
+ --c-include='cogl-pango/cogl-pango.h' \
+ --include-uninstalled=$(top_builddir)/cogl/Cogl-1.0.gir
+
+CoglPango-2.0.gir: libmutter-cogl-pango.la Makefile
+
+CoglPango_2_0_gir_NAMESPACE = CoglPango
+CoglPango_2_0_gir_VERSION = 2.0
+CoglPango_2_0_gir_LIBS = $(top_builddir)/cogl/libmutter-cogl.la libmutter-cogl-pango.la
+CoglPango_2_0_gir_FILES = $(source_h) $(source_c)
+CoglPango_2_0_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) $(COGL_PANGO_DEP_CFLAGS)
+CoglPango_2_0_gir_INCLUDES = Pango-1.0 PangoCairo-1.0
+CoglPango_2_0_gir_EXPORT_PACKAGES = cogl-pango-2.0-experimental
+CoglPango_2_0_gir_SCANNERFLAGS = \
+ --warn-all \
+ --identifier-prefix=CoglPango \
+ --symbol-prefix=cogl_pango \
+ --c-include='cogl-pango/cogl-pango.h' \
+ --include-uninstalled=$(top_builddir)/cogl/Cogl-2.0.gir
+
+INTROSPECTION_GIRS += CoglPango-1.0.gir CoglPango-2.0.gir
+
+girdir = $(mutterlibdir)
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(mutterlibdir)
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelib_DATA)
+endif
diff --git a/cogl/cogl-pango/cogl-pango-display-list.c b/cogl/cogl-pango/cogl-pango-display-list.c
new file mode 100644
index 000000000..6967ab024
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-display-list.c
@@ -0,0 +1,499 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2009 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <string.h>
+
+#include "cogl-pango-display-list.h"
+#include "cogl-pango-pipeline-cache.h"
+#include "cogl/cogl-context-private.h"
+
+typedef enum
+{
+ COGL_PANGO_DISPLAY_LIST_TEXTURE,
+ COGL_PANGO_DISPLAY_LIST_RECTANGLE,
+ COGL_PANGO_DISPLAY_LIST_TRAPEZOID
+} CoglPangoDisplayListNodeType;
+
+typedef struct _CoglPangoDisplayListNode CoglPangoDisplayListNode;
+typedef struct _CoglPangoDisplayListRectangle CoglPangoDisplayListRectangle;
+
+struct _CoglPangoDisplayList
+{
+ CoglBool color_override;
+ CoglColor color;
+ GSList *nodes;
+ GSList *last_node;
+ CoglPangoPipelineCache *pipeline_cache;
+};
+
+/* This matches the format expected by cogl_rectangles_with_texture_coords */
+struct _CoglPangoDisplayListRectangle
+{
+ float x_1, y_1, x_2, y_2;
+ float s_1, t_1, s_2, t_2;
+};
+
+struct _CoglPangoDisplayListNode
+{
+ CoglPangoDisplayListNodeType type;
+
+ CoglBool color_override;
+ CoglColor color;
+
+ CoglPipeline *pipeline;
+
+ union
+ {
+ struct
+ {
+ /* The texture to render these coords from */
+ CoglTexture *texture;
+ /* Array of rectangles in the format expected by
+ cogl_rectangles_with_texture_coords */
+ GArray *rectangles;
+ /* A primitive representing those vertices */
+ CoglPrimitive *primitive;
+ } texture;
+
+ struct
+ {
+ float x_1, y_1;
+ float x_2, y_2;
+ } rectangle;
+
+ struct
+ {
+ CoglPrimitive *primitive;
+ } trapezoid;
+ } d;
+};
+
+CoglPangoDisplayList *
+_cogl_pango_display_list_new (CoglPangoPipelineCache *pipeline_cache)
+{
+ CoglPangoDisplayList *dl = g_slice_new0 (CoglPangoDisplayList);
+
+ dl->pipeline_cache = pipeline_cache;
+
+ return dl;
+}
+
+static void
+_cogl_pango_display_list_append_node (CoglPangoDisplayList *dl,
+ CoglPangoDisplayListNode *node)
+{
+ if (dl->last_node)
+ dl->last_node = dl->last_node->next = g_slist_prepend (NULL, node);
+ else
+ dl->last_node = dl->nodes = g_slist_prepend (NULL, node);
+}
+
+void
+_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl,
+ const CoglColor *color)
+{
+ dl->color_override = TRUE;
+ dl->color = *color;
+}
+
+void
+_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl)
+{
+ dl->color_override = FALSE;
+}
+
+void
+_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
+ CoglTexture *texture,
+ float x_1, float y_1,
+ float x_2, float y_2,
+ float tx_1, float ty_1,
+ float tx_2, float ty_2)
+{
+ CoglPangoDisplayListNode *node;
+ CoglPangoDisplayListRectangle *rectangle;
+
+ /* Add to the last node if it is a texture node with the same
+ target texture */
+ if (dl->last_node
+ && (node = dl->last_node->data)->type == COGL_PANGO_DISPLAY_LIST_TEXTURE
+ && node->d.texture.texture == texture
+ && (dl->color_override
+ ? (node->color_override && cogl_color_equal (&dl->color, &node->color))
+ : !node->color_override))
+ {
+ /* Get rid of the vertex buffer so that it will be recreated */
+ if (node->d.texture.primitive != NULL)
+ {
+ cogl_object_unref (node->d.texture.primitive);
+ node->d.texture.primitive = NULL;
+ }
+ }
+ else
+ {
+ /* Otherwise create a new node */
+ node = g_slice_new (CoglPangoDisplayListNode);
+
+ node->type = COGL_PANGO_DISPLAY_LIST_TEXTURE;
+ node->color_override = dl->color_override;
+ node->color = dl->color;
+ node->pipeline = NULL;
+ node->d.texture.texture = cogl_object_ref (texture);
+ node->d.texture.rectangles
+ = g_array_new (FALSE, FALSE, sizeof (CoglPangoDisplayListRectangle));
+ node->d.texture.primitive = NULL;
+
+ _cogl_pango_display_list_append_node (dl, node);
+ }
+
+ g_array_set_size (node->d.texture.rectangles,
+ node->d.texture.rectangles->len + 1);
+ rectangle = &g_array_index (node->d.texture.rectangles,
+ CoglPangoDisplayListRectangle,
+ node->d.texture.rectangles->len - 1);
+ rectangle->x_1 = x_1;
+ rectangle->y_1 = y_1;
+ rectangle->x_2 = x_2;
+ rectangle->y_2 = y_2;
+ rectangle->s_1 = tx_1;
+ rectangle->t_1 = ty_1;
+ rectangle->s_2 = tx_2;
+ rectangle->t_2 = ty_2;
+}
+
+void
+_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl,
+ float x_1, float y_1,
+ float x_2, float y_2)
+{
+ CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
+
+ node->type = COGL_PANGO_DISPLAY_LIST_RECTANGLE;
+ node->color_override = dl->color_override;
+ node->color = dl->color;
+ node->d.rectangle.x_1 = x_1;
+ node->d.rectangle.y_1 = y_1;
+ node->d.rectangle.x_2 = x_2;
+ node->d.rectangle.y_2 = y_2;
+ node->pipeline = NULL;
+
+ _cogl_pango_display_list_append_node (dl, node);
+}
+
+void
+_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
+ float y_1,
+ float x_11,
+ float x_21,
+ float y_2,
+ float x_12,
+ float x_22)
+{
+ CoglContext *ctx = dl->pipeline_cache->ctx;
+ CoglPangoDisplayListNode *node = g_slice_new (CoglPangoDisplayListNode);
+ CoglVertexP2 vertices[4] = {
+ { x_11, y_1 },
+ { x_12, y_2 },
+ { x_22, y_2 },
+ { x_21, y_1 }
+ };
+
+ node->type = COGL_PANGO_DISPLAY_LIST_TRAPEZOID;
+ node->color_override = dl->color_override;
+ node->color = dl->color;
+ node->pipeline = NULL;
+
+ node->d.trapezoid.primitive =
+ cogl_primitive_new_p2 (ctx,
+ COGL_VERTICES_MODE_TRIANGLE_FAN,
+ 4,
+ vertices);
+
+ _cogl_pango_display_list_append_node (dl, node);
+}
+
+static void
+emit_rectangles_through_journal (CoglFramebuffer *fb,
+ CoglPipeline *pipeline,
+ CoglPangoDisplayListNode *node)
+{
+ const float *rectangles = (const float *)node->d.texture.rectangles->data;
+
+ cogl_framebuffer_draw_textured_rectangles (fb,
+ pipeline,
+ rectangles,
+ node->d.texture.rectangles->len);
+}
+
+static void
+emit_vertex_buffer_geometry (CoglFramebuffer *fb,
+ CoglPipeline *pipeline,
+ CoglPangoDisplayListNode *node)
+{
+ CoglContext *ctx = fb->context;
+
+ /* It's expensive to go through the Cogl journal for large runs
+ * of text in part because the journal transforms the quads in software
+ * to avoid changing the modelview matrix. So for larger runs of text
+ * we load the vertices into a VBO, and this has the added advantage
+ * that if the text doesn't change from frame to frame the VBO can
+ * be re-used avoiding the repeated cost of validating the data and
+ * mapping it into the GPU... */
+
+ if (node->d.texture.primitive == NULL)
+ {
+ CoglAttributeBuffer *buffer;
+ CoglVertexP2T2 *verts, *v;
+ int n_verts;
+ CoglBool allocated = FALSE;
+ CoglAttribute *attributes[2];
+ CoglPrimitive *prim;
+ int i;
+
+ n_verts = node->d.texture.rectangles->len * 4;
+
+ buffer
+ = cogl_attribute_buffer_new_with_size (ctx,
+ n_verts *
+ sizeof (CoglVertexP2T2));
+
+ if ((verts = cogl_buffer_map (COGL_BUFFER (buffer),
+ COGL_BUFFER_ACCESS_WRITE,
+ COGL_BUFFER_MAP_HINT_DISCARD)) == NULL)
+ {
+ verts = g_new (CoglVertexP2T2, n_verts);
+ allocated = TRUE;
+ }
+
+ v = verts;
+
+ /* Copy the rectangles into the buffer and expand into four
+ vertices instead of just two */
+ for (i = 0; i < node->d.texture.rectangles->len; i++)
+ {
+ const CoglPangoDisplayListRectangle *rectangle
+ = &g_array_index (node->d.texture.rectangles,
+ CoglPangoDisplayListRectangle, i);
+
+ v->x = rectangle->x_1;
+ v->y = rectangle->y_1;
+ v->s = rectangle->s_1;
+ v->t = rectangle->t_1;
+ v++;
+ v->x = rectangle->x_1;
+ v->y = rectangle->y_2;
+ v->s = rectangle->s_1;
+ v->t = rectangle->t_2;
+ v++;
+ v->x = rectangle->x_2;
+ v->y = rectangle->y_2;
+ v->s = rectangle->s_2;
+ v->t = rectangle->t_2;
+ v++;
+ v->x = rectangle->x_2;
+ v->y = rectangle->y_1;
+ v->s = rectangle->s_2;
+ v->t = rectangle->t_1;
+ v++;
+ }
+
+ if (allocated)
+ {
+ cogl_buffer_set_data (COGL_BUFFER (buffer),
+ 0, /* offset */
+ verts,
+ sizeof (CoglVertexP2T2) * n_verts);
+ g_free (verts);
+ }
+ else
+ cogl_buffer_unmap (COGL_BUFFER (buffer));
+
+ attributes[0] = cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (CoglVertexP2T2),
+ G_STRUCT_OFFSET (CoglVertexP2T2, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ attributes[1] = cogl_attribute_new (buffer,
+ "cogl_tex_coord0_in",
+ sizeof (CoglVertexP2T2),
+ G_STRUCT_OFFSET (CoglVertexP2T2, s),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+
+ prim = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ n_verts,
+ attributes,
+ 2 /* n_attributes */);
+
+#ifdef CLUTTER_COGL_HAS_GL
+ if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUADS))
+ cogl_primitive_set_mode (prim, GL_QUADS);
+ else
+#endif
+ {
+ /* GLES doesn't support GL_QUADS so instead we use a VBO
+ with indexed vertices to generate GL_TRIANGLES from the
+ quads */
+
+ CoglIndices *indices =
+ cogl_get_rectangle_indices (ctx, node->d.texture.rectangles->len);
+
+ cogl_primitive_set_indices (prim, indices,
+ node->d.texture.rectangles->len * 6);
+ }
+
+ node->d.texture.primitive = prim;
+
+ cogl_object_unref (buffer);
+ cogl_object_unref (attributes[0]);
+ cogl_object_unref (attributes[1]);
+ }
+
+ cogl_primitive_draw (node->d.texture.primitive,
+ fb,
+ pipeline);
+}
+
+static void
+_cogl_framebuffer_draw_display_list_texture (CoglFramebuffer *fb,
+ CoglPipeline *pipeline,
+ CoglPangoDisplayListNode *node)
+{
+ /* For small runs of text like icon labels, we can get better performance
+ * going through the Cogl journal since text may then be batched together
+ * with other geometry. */
+ /* FIXME: 25 is a number I plucked out of thin air; it would be good
+ * to determine this empirically! */
+ if (node->d.texture.rectangles->len < 25)
+ emit_rectangles_through_journal (fb, pipeline, node);
+ else
+ emit_vertex_buffer_geometry (fb, pipeline, node);
+}
+
+void
+_cogl_pango_display_list_render (CoglFramebuffer *fb,
+ CoglPangoDisplayList *dl,
+ const CoglColor *color)
+{
+ GSList *l;
+
+ for (l = dl->nodes; l; l = l->next)
+ {
+ CoglPangoDisplayListNode *node = l->data;
+ CoglColor draw_color;
+
+ if (node->pipeline == NULL)
+ {
+ if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE)
+ node->pipeline =
+ _cogl_pango_pipeline_cache_get (dl->pipeline_cache,
+ node->d.texture.texture);
+ else
+ node->pipeline =
+ _cogl_pango_pipeline_cache_get (dl->pipeline_cache,
+ NULL);
+ }
+
+ if (node->color_override)
+ /* Use the override color but preserve the alpha from the
+ draw color */
+ cogl_color_init_from_4ub (&draw_color,
+ cogl_color_get_red_byte (&node->color),
+ cogl_color_get_green_byte (&node->color),
+ cogl_color_get_blue_byte (&node->color),
+ cogl_color_get_alpha_byte (color));
+ else
+ draw_color = *color;
+ cogl_color_premultiply (&draw_color);
+
+ cogl_pipeline_set_color (node->pipeline, &draw_color);
+
+ switch (node->type)
+ {
+ case COGL_PANGO_DISPLAY_LIST_TEXTURE:
+ _cogl_framebuffer_draw_display_list_texture (fb, node->pipeline, node);
+ break;
+
+ case COGL_PANGO_DISPLAY_LIST_RECTANGLE:
+ cogl_framebuffer_draw_rectangle (fb,
+ node->pipeline,
+ node->d.rectangle.x_1,
+ node->d.rectangle.y_1,
+ node->d.rectangle.x_2,
+ node->d.rectangle.y_2);
+ break;
+
+ case COGL_PANGO_DISPLAY_LIST_TRAPEZOID:
+ cogl_framebuffer_draw_primitive (fb, node->pipeline,
+ node->d.trapezoid.primitive);
+ break;
+ }
+ }
+}
+
+static void
+_cogl_pango_display_list_node_free (CoglPangoDisplayListNode *node)
+{
+ if (node->type == COGL_PANGO_DISPLAY_LIST_TEXTURE)
+ {
+ g_array_free (node->d.texture.rectangles, TRUE);
+ if (node->d.texture.texture != NULL)
+ cogl_object_unref (node->d.texture.texture);
+ if (node->d.texture.primitive != NULL)
+ cogl_object_unref (node->d.texture.primitive);
+ }
+ else if (node->type == COGL_PANGO_DISPLAY_LIST_TRAPEZOID)
+ cogl_object_unref (node->d.trapezoid.primitive);
+
+ if (node->pipeline)
+ cogl_object_unref (node->pipeline);
+
+ g_slice_free (CoglPangoDisplayListNode, node);
+}
+
+void
+_cogl_pango_display_list_clear (CoglPangoDisplayList *dl)
+{
+ g_slist_foreach (dl->nodes, (GFunc) _cogl_pango_display_list_node_free, NULL);
+ g_slist_free (dl->nodes);
+ dl->nodes = NULL;
+ dl->last_node = NULL;
+}
+
+void
+_cogl_pango_display_list_free (CoglPangoDisplayList *dl)
+{
+ _cogl_pango_display_list_clear (dl);
+ g_slice_free (CoglPangoDisplayList, dl);
+}
diff --git a/cogl/cogl-pango/cogl-pango-display-list.h b/cogl/cogl-pango/cogl-pango-display-list.h
new file mode 100644
index 000000000..5dbc074e0
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-display-list.h
@@ -0,0 +1,84 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2009 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __COGL_PANGO_DISPLAY_LIST_H__
+#define __COGL_PANGO_DISPLAY_LIST_H__
+
+#include <glib.h>
+#include "cogl-pango-pipeline-cache.h"
+
+COGL_BEGIN_DECLS
+
+typedef struct _CoglPangoDisplayList CoglPangoDisplayList;
+
+CoglPangoDisplayList *
+_cogl_pango_display_list_new (CoglPangoPipelineCache *);
+
+void
+_cogl_pango_display_list_set_color_override (CoglPangoDisplayList *dl,
+ const CoglColor *color);
+
+void
+_cogl_pango_display_list_remove_color_override (CoglPangoDisplayList *dl);
+
+void
+_cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
+ CoglTexture *texture,
+ float x_1, float y_1,
+ float x_2, float y_2,
+ float tx_1, float ty_1,
+ float tx_2, float ty_2);
+
+void
+_cogl_pango_display_list_add_rectangle (CoglPangoDisplayList *dl,
+ float x_1, float y_1,
+ float x_2, float y_2);
+
+void
+_cogl_pango_display_list_add_trapezoid (CoglPangoDisplayList *dl,
+ float y_1,
+ float x_11,
+ float x_21,
+ float y_2,
+ float x_12,
+ float x_22);
+
+void
+_cogl_pango_display_list_render (CoglFramebuffer *framebuffer,
+ CoglPangoDisplayList *dl,
+ const CoglColor *color);
+
+void
+_cogl_pango_display_list_clear (CoglPangoDisplayList *dl);
+
+void
+_cogl_pango_display_list_free (CoglPangoDisplayList *dl);
+
+COGL_END_DECLS
+
+#endif /* __COGL_PANGO_DISPLAY_LIST_H__ */
diff --git a/cogl/cogl-pango/cogl-pango-fontmap.c b/cogl/cogl-pango/cogl-pango-fontmap.c
new file mode 100644
index 000000000..a9c7df065
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-fontmap.c
@@ -0,0 +1,184 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * SECTION:cogl-pango
+ * @short_description: COGL-based text rendering using Pango
+ *
+ * FIXME
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* This is needed to get the Pango headers to export stuff needed to
+ subclass */
+#ifndef PANGO_ENABLE_BACKEND
+#define PANGO_ENABLE_BACKEND 1
+#endif
+
+#include <pango/pango-fontmap.h>
+#include <pango/pangocairo.h>
+#include <pango/pango-renderer.h>
+
+#include "cogl-pango.h"
+#include "cogl-pango-private.h"
+#include "cogl-util.h"
+#include "cogl/cogl-context-private.h"
+
+static GQuark cogl_pango_font_map_get_priv_key (void) G_GNUC_CONST;
+
+typedef struct _CoglPangoFontMapPriv
+{
+ CoglContext *ctx;
+ PangoRenderer *renderer;
+} CoglPangoFontMapPriv;
+
+static void
+free_priv (gpointer data)
+{
+ CoglPangoFontMapPriv *priv = data;
+
+ cogl_object_unref (priv->ctx);
+ cogl_object_unref (priv->renderer);
+
+ g_free (priv);
+}
+
+PangoFontMap *
+cogl_pango_font_map_new (void)
+{
+ PangoFontMap *fm = pango_cairo_font_map_new ();
+ CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
+
+ _COGL_GET_CONTEXT (context, NULL);
+
+ priv->ctx = cogl_object_ref (context);
+
+ /* XXX: The public pango api doesn't let us sub-class
+ * PangoCairoFontMap so we attach our own private data using qdata
+ * for now. */
+ g_object_set_qdata_full (G_OBJECT (fm),
+ cogl_pango_font_map_get_priv_key (),
+ priv,
+ free_priv);
+
+ return fm;
+}
+
+PangoContext *
+cogl_pango_font_map_create_context (CoglPangoFontMap *fm)
+{
+ _COGL_RETURN_VAL_IF_FAIL (COGL_PANGO_IS_FONT_MAP (fm), NULL);
+
+#if PANGO_VERSION_CHECK (1, 22, 0)
+ /* We can just directly use the pango context from the Cairo font
+ map */
+ return pango_font_map_create_context (PANGO_FONT_MAP (fm));
+#else
+ return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fm));
+#endif
+}
+
+static CoglPangoFontMapPriv *
+_cogl_pango_font_map_get_priv (CoglPangoFontMap *fm)
+{
+ return g_object_get_qdata (G_OBJECT (fm),
+ cogl_pango_font_map_get_priv_key ());
+}
+
+PangoRenderer *
+_cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm)
+{
+ CoglPangoFontMapPriv *priv = _cogl_pango_font_map_get_priv (fm);
+ if (G_UNLIKELY (!priv->renderer))
+ priv->renderer = _cogl_pango_renderer_new (priv->ctx);
+ return priv->renderer;
+}
+
+PangoRenderer *
+cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm)
+{
+ return _cogl_pango_font_map_get_renderer (fm);
+}
+
+CoglContext *
+_cogl_pango_font_map_get_cogl_context (CoglPangoFontMap *fm)
+{
+ CoglPangoFontMapPriv *priv = _cogl_pango_font_map_get_priv (fm);
+ return priv->ctx;
+}
+
+void
+cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map,
+ double dpi)
+{
+ _COGL_RETURN_IF_FAIL (COGL_PANGO_IS_FONT_MAP (font_map));
+
+ pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (font_map), dpi);
+}
+
+void
+cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *fm)
+{
+ PangoRenderer *renderer = _cogl_pango_font_map_get_renderer (fm);
+
+ _cogl_pango_renderer_clear_glyph_cache (COGL_PANGO_RENDERER (renderer));
+}
+
+void
+cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *fm,
+ CoglBool value)
+{
+ PangoRenderer *renderer = _cogl_pango_font_map_get_renderer (fm);
+
+ _cogl_pango_renderer_set_use_mipmapping (COGL_PANGO_RENDERER (renderer),
+ value);
+}
+
+CoglBool
+cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *fm)
+{
+ PangoRenderer *renderer = _cogl_pango_font_map_get_renderer (fm);
+
+ return
+ _cogl_pango_renderer_get_use_mipmapping (COGL_PANGO_RENDERER (renderer));
+}
+
+static GQuark
+cogl_pango_font_map_get_priv_key (void)
+{
+ static GQuark priv_key = 0;
+
+ if (G_UNLIKELY (priv_key == 0))
+ priv_key = g_quark_from_static_string ("CoglPangoFontMap");
+
+ return priv_key;
+}
diff --git a/cogl/cogl-pango/cogl-pango-glyph-cache.c b/cogl/cogl-pango/cogl-pango-glyph-cache.c
new file mode 100644
index 000000000..093404f28
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-glyph-cache.c
@@ -0,0 +1,433 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "cogl-pango-glyph-cache.h"
+#include "cogl-pango-private.h"
+#include "cogl/cogl-atlas.h"
+#include "cogl/cogl-atlas-texture-private.h"
+
+typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey;
+
+struct _CoglPangoGlyphCache
+{
+ CoglContext *ctx;
+
+ /* Hash table to quickly check whether a particular glyph in a
+ particular font is already cached */
+ GHashTable *hash_table;
+
+ /* List of CoglAtlases */
+ GSList *atlases;
+
+ /* List of callbacks to invoke when an atlas is reorganized */
+ GHookList reorganize_callbacks;
+
+ /* TRUE if we've ever stored a texture in the global atlas. This is
+ used to make sure we only register one callback to listen for
+ global atlas reorganizations */
+ CoglBool using_global_atlas;
+
+ /* True if some of the glyphs are dirty. This is used as an
+ optimization in _cogl_pango_glyph_cache_set_dirty_glyphs to avoid
+ iterating the hash table if we know none of them are dirty */
+ CoglBool has_dirty_glyphs;
+
+ /* Whether mipmapping is being used for this cache. This only
+ affects whether we decide to put the glyph in the global atlas */
+ CoglBool use_mipmapping;
+};
+
+struct _CoglPangoGlyphCacheKey
+{
+ PangoFont *font;
+ PangoGlyph glyph;
+};
+
+static void
+cogl_pango_glyph_cache_value_free (CoglPangoGlyphCacheValue *value)
+{
+ if (value->texture)
+ cogl_object_unref (value->texture);
+ g_slice_free (CoglPangoGlyphCacheValue, value);
+}
+
+static void
+cogl_pango_glyph_cache_key_free (CoglPangoGlyphCacheKey *key)
+{
+ g_object_unref (key->font);
+ g_slice_free (CoglPangoGlyphCacheKey, key);
+}
+
+static unsigned int
+cogl_pango_glyph_cache_hash_func (const void *key)
+{
+ const CoglPangoGlyphCacheKey *cache_key
+ = (const CoglPangoGlyphCacheKey *) key;
+
+ /* Generate a number affected by both the font and the glyph
+ number. We can safely directly compare the pointers because the
+ key holds a reference to the font so it is not possible that a
+ different font will have the same memory address */
+ return GPOINTER_TO_UINT (cache_key->font) ^ cache_key->glyph;
+}
+
+static CoglBool
+cogl_pango_glyph_cache_equal_func (const void *a, const void *b)
+{
+ const CoglPangoGlyphCacheKey *key_a
+ = (const CoglPangoGlyphCacheKey *) a;
+ const CoglPangoGlyphCacheKey *key_b
+ = (const CoglPangoGlyphCacheKey *) b;
+
+ /* We can safely directly compare the pointers for the fonts because
+ the key holds a reference to the font so it is not possible that
+ a different font will have the same memory address */
+ return key_a->font == key_b->font
+ && key_a->glyph == key_b->glyph;
+}
+
+CoglPangoGlyphCache *
+cogl_pango_glyph_cache_new (CoglContext *ctx,
+ CoglBool use_mipmapping)
+{
+ CoglPangoGlyphCache *cache;
+
+ cache = g_malloc (sizeof (CoglPangoGlyphCache));
+
+ /* Note: as a rule we don't take references to a CoglContext
+ * internally since */
+ cache->ctx = ctx;
+
+ cache->hash_table = g_hash_table_new_full
+ (cogl_pango_glyph_cache_hash_func,
+ cogl_pango_glyph_cache_equal_func,
+ (GDestroyNotify) cogl_pango_glyph_cache_key_free,
+ (GDestroyNotify) cogl_pango_glyph_cache_value_free);
+
+ cache->atlases = NULL;
+ g_hook_list_init (&cache->reorganize_callbacks, sizeof (GHook));
+
+ cache->has_dirty_glyphs = FALSE;
+
+ cache->using_global_atlas = FALSE;
+
+ cache->use_mipmapping = use_mipmapping;
+
+ return cache;
+}
+
+static void
+cogl_pango_glyph_cache_reorganize_cb (void *user_data)
+{
+ CoglPangoGlyphCache *cache = user_data;
+
+ g_hook_list_invoke (&cache->reorganize_callbacks, FALSE);
+}
+
+void
+cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache)
+{
+ g_slist_foreach (cache->atlases, (GFunc) cogl_object_unref, NULL);
+ g_slist_free (cache->atlases);
+ cache->atlases = NULL;
+ cache->has_dirty_glyphs = FALSE;
+
+ g_hash_table_remove_all (cache->hash_table);
+}
+
+void
+cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache)
+{
+ if (cache->using_global_atlas)
+ {
+ _cogl_atlas_texture_remove_reorganize_callback (
+ cache->ctx,
+ cogl_pango_glyph_cache_reorganize_cb, cache);
+ }
+
+ cogl_pango_glyph_cache_clear (cache);
+
+ g_hash_table_unref (cache->hash_table);
+
+ g_hook_list_clear (&cache->reorganize_callbacks);
+
+ g_free (cache);
+}
+
+static void
+cogl_pango_glyph_cache_update_position_cb (void *user_data,
+ CoglTexture *new_texture,
+ const CoglRectangleMapEntry *rect)
+{
+ CoglPangoGlyphCacheValue *value = user_data;
+ float tex_width, tex_height;
+
+ if (value->texture)
+ cogl_object_unref (value->texture);
+ value->texture = cogl_object_ref (new_texture);
+
+ tex_width = cogl_texture_get_width (new_texture);
+ tex_height = cogl_texture_get_height (new_texture);
+
+ value->tx1 = rect->x / tex_width;
+ value->ty1 = rect->y / tex_height;
+ value->tx2 = (rect->x + value->draw_width) / tex_width;
+ value->ty2 = (rect->y + value->draw_height) / tex_height;
+
+ value->tx_pixel = rect->x;
+ value->ty_pixel = rect->y;
+
+ /* The glyph has changed position so it will need to be redrawn */
+ value->dirty = TRUE;
+}
+
+static CoglBool
+cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
+ PangoFont *font,
+ PangoGlyph glyph,
+ CoglPangoGlyphCacheValue *value)
+{
+ CoglAtlasTexture *texture;
+ CoglError *ignore_error = NULL;
+
+ if (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SHARED_ATLAS))
+ return FALSE;
+
+ /* If the cache is using mipmapping then we can't use the global
+ atlas because it would just get migrated back out */
+ if (cache->use_mipmapping)
+ return FALSE;
+
+ texture = cogl_atlas_texture_new_with_size (cache->ctx,
+ value->draw_width,
+ value->draw_height);
+ if (!cogl_texture_allocate (COGL_TEXTURE (texture), &ignore_error))
+ {
+ cogl_error_free (ignore_error);
+ return FALSE;
+ }
+
+ value->texture = COGL_TEXTURE (texture);
+ value->tx1 = 0;
+ value->ty1 = 0;
+ value->tx2 = 1;
+ value->ty2 = 1;
+ value->tx_pixel = 0;
+ value->ty_pixel = 0;
+
+ /* The first time we store a texture in the global atlas we'll
+ register for notifications when the global atlas is reorganized
+ so we can forward the notification on as a glyph
+ reorganization */
+ if (!cache->using_global_atlas)
+ {
+ _cogl_atlas_texture_add_reorganize_callback
+ (cache->ctx,
+ cogl_pango_glyph_cache_reorganize_cb, cache);
+ cache->using_global_atlas = TRUE;
+ }
+
+ return TRUE;
+}
+
+static CoglBool
+cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache,
+ PangoFont *font,
+ PangoGlyph glyph,
+ CoglPangoGlyphCacheValue *value)
+{
+ CoglAtlas *atlas = NULL;
+ GSList *l;
+
+ /* Look for an atlas that can reserve the space */
+ for (l = cache->atlases; l; l = l->next)
+ if (_cogl_atlas_reserve_space (l->data,
+ value->draw_width + 1,
+ value->draw_height + 1,
+ value))
+ {
+ atlas = l->data;
+ break;
+ }
+
+ /* If we couldn't find one then start a new atlas */
+ if (atlas == NULL)
+ {
+ atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_A_8,
+ COGL_ATLAS_CLEAR_TEXTURE |
+ COGL_ATLAS_DISABLE_MIGRATION,
+ cogl_pango_glyph_cache_update_position_cb);
+ COGL_NOTE (ATLAS, "Created new atlas for glyphs: %p", atlas);
+ /* If we still can't reserve space then something has gone
+ seriously wrong so we'll just give up */
+ if (!_cogl_atlas_reserve_space (atlas,
+ value->draw_width + 1,
+ value->draw_height + 1,
+ value))
+ {
+ cogl_object_unref (atlas);
+ return FALSE;
+ }
+
+ _cogl_atlas_add_reorganize_callback
+ (atlas, cogl_pango_glyph_cache_reorganize_cb, NULL, cache);
+
+ cache->atlases = g_slist_prepend (cache->atlases, atlas);
+ }
+
+ return TRUE;
+}
+
+CoglPangoGlyphCacheValue *
+cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
+ CoglBool create,
+ PangoFont *font,
+ PangoGlyph glyph)
+{
+ CoglPangoGlyphCacheKey lookup_key;
+ CoglPangoGlyphCacheValue *value;
+
+ lookup_key.font = font;
+ lookup_key.glyph = glyph;
+
+ value = g_hash_table_lookup (cache->hash_table, &lookup_key);
+
+ if (create && value == NULL)
+ {
+ CoglPangoGlyphCacheKey *key;
+ PangoRectangle ink_rect;
+
+ value = g_slice_new (CoglPangoGlyphCacheValue);
+ value->texture = NULL;
+
+ pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
+ pango_extents_to_pixels (&ink_rect, NULL);
+
+ value->draw_x = ink_rect.x;
+ value->draw_y = ink_rect.y;
+ value->draw_width = ink_rect.width;
+ value->draw_height = ink_rect.height;
+
+ /* If the glyph is zero-sized then we don't need to reserve any
+ space for it and we can just avoid painting anything */
+ if (ink_rect.width < 1 || ink_rect.height < 1)
+ value->dirty = FALSE;
+ else
+ {
+ /* Try adding the glyph to the global atlas... */
+ if (!cogl_pango_glyph_cache_add_to_global_atlas (cache,
+ font,
+ glyph,
+ value) &&
+ /* If it fails try the local atlas */
+ !cogl_pango_glyph_cache_add_to_local_atlas (cache,
+ font,
+ glyph,
+ value))
+ {
+ cogl_pango_glyph_cache_value_free (value);
+ return NULL;
+ }
+
+ value->dirty = TRUE;
+ cache->has_dirty_glyphs = TRUE;
+ }
+
+ key = g_slice_new (CoglPangoGlyphCacheKey);
+ key->font = g_object_ref (font);
+ key->glyph = glyph;
+
+ g_hash_table_insert (cache->hash_table, key, value);
+ }
+
+ return value;
+}
+
+static void
+_cogl_pango_glyph_cache_set_dirty_glyphs_cb (void *key_ptr,
+ void *value_ptr,
+ void *user_data)
+{
+ CoglPangoGlyphCacheKey *key = key_ptr;
+ CoglPangoGlyphCacheValue *value = value_ptr;
+ CoglPangoGlyphCacheDirtyFunc func = user_data;
+
+ if (value->dirty)
+ {
+ func (key->font, key->glyph, value);
+
+ value->dirty = FALSE;
+ }
+}
+
+void
+_cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache,
+ CoglPangoGlyphCacheDirtyFunc func)
+{
+ /* If we know that there are no dirty glyphs then we can shortcut
+ out early */
+ if (!cache->has_dirty_glyphs)
+ return;
+
+ g_hash_table_foreach (cache->hash_table,
+ _cogl_pango_glyph_cache_set_dirty_glyphs_cb,
+ func);
+
+ cache->has_dirty_glyphs = FALSE;
+}
+
+void
+_cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache,
+ GHookFunc func,
+ void *user_data)
+{
+ GHook *hook = g_hook_alloc (&cache->reorganize_callbacks);
+ hook->func = func;
+ hook->data = user_data;
+ g_hook_prepend (&cache->reorganize_callbacks, hook);
+}
+
+void
+_cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache,
+ GHookFunc func,
+ void *user_data)
+{
+ GHook *hook = g_hook_find_func_data (&cache->reorganize_callbacks,
+ FALSE,
+ func,
+ user_data);
+
+ if (hook)
+ g_hook_destroy_link (&cache->reorganize_callbacks, hook);
+}
diff --git a/cogl/cogl-pango/cogl-pango-glyph-cache.h b/cogl/cogl-pango/cogl-pango-glyph-cache.h
new file mode 100644
index 000000000..ca33203bc
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-glyph-cache.h
@@ -0,0 +1,100 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __COGL_PANGO_GLYPH_CACHE_H__
+#define __COGL_PANGO_GLYPH_CACHE_H__
+
+#include <glib.h>
+#include <pango/pango-font.h>
+
+#include "cogl/cogl-texture.h"
+
+COGL_BEGIN_DECLS
+
+typedef struct _CoglPangoGlyphCache CoglPangoGlyphCache;
+typedef struct _CoglPangoGlyphCacheValue CoglPangoGlyphCacheValue;
+
+struct _CoglPangoGlyphCacheValue
+{
+ CoglTexture *texture;
+
+ float tx1;
+ float ty1;
+ float tx2;
+ float ty2;
+
+ int tx_pixel;
+ int ty_pixel;
+
+ int draw_x;
+ int draw_y;
+ int draw_width;
+ int draw_height;
+
+ /* This will be set to TRUE when the glyph atlas is reorganized
+ which means the glyph will need to be redrawn */
+ CoglBool dirty;
+};
+
+typedef void (* CoglPangoGlyphCacheDirtyFunc) (PangoFont *font,
+ PangoGlyph glyph,
+ CoglPangoGlyphCacheValue *value);
+
+CoglPangoGlyphCache *
+cogl_pango_glyph_cache_new (CoglContext *ctx,
+ CoglBool use_mipmapping);
+
+void
+cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache);
+
+CoglPangoGlyphCacheValue *
+cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
+ CoglBool create,
+ PangoFont *font,
+ PangoGlyph glyph);
+
+void
+cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache);
+
+void
+_cogl_pango_glyph_cache_add_reorganize_callback (CoglPangoGlyphCache *cache,
+ GHookFunc func,
+ void *user_data);
+
+void
+_cogl_pango_glyph_cache_remove_reorganize_callback (CoglPangoGlyphCache *cache,
+ GHookFunc func,
+ void *user_data);
+
+void
+_cogl_pango_glyph_cache_set_dirty_glyphs (CoglPangoGlyphCache *cache,
+ CoglPangoGlyphCacheDirtyFunc func);
+
+COGL_END_DECLS
+
+#endif /* __COGL_PANGO_GLYPH_CACHE_H__ */
diff --git a/cogl/cogl-pango/cogl-pango-pipeline-cache.c b/cogl/cogl-pango/cogl-pango-pipeline-cache.c
new file mode 100644
index 000000000..625a8fa41
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-pipeline-cache.c
@@ -0,0 +1,242 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ *
+ * Authors:
+ * Neil Roberts <neil@linux.intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include "cogl-pango-pipeline-cache.h"
+
+#include "cogl/cogl-context-private.h"
+#include "cogl/cogl-texture-private.h"
+
+typedef struct _CoglPangoPipelineCacheEntry CoglPangoPipelineCacheEntry;
+
+struct _CoglPangoPipelineCacheEntry
+{
+ /* This will take a reference or it can be NULL to represent the
+ pipeline used to render colors */
+ CoglTexture *texture;
+
+ /* This will only take a weak reference */
+ CoglPipeline *pipeline;
+};
+
+static void
+_cogl_pango_pipeline_cache_key_destroy (void *data)
+{
+ if (data)
+ cogl_object_unref (data);
+}
+
+static void
+_cogl_pango_pipeline_cache_value_destroy (void *data)
+{
+ CoglPangoPipelineCacheEntry *cache_entry = data;
+
+ if (cache_entry->texture)
+ cogl_object_unref (cache_entry->texture);
+
+ /* We don't need to unref the pipeline because it only takes a weak
+ reference */
+
+ g_slice_free (CoglPangoPipelineCacheEntry, cache_entry);
+}
+
+CoglPangoPipelineCache *
+_cogl_pango_pipeline_cache_new (CoglContext *ctx,
+ CoglBool use_mipmapping)
+{
+ CoglPangoPipelineCache *cache = g_new (CoglPangoPipelineCache, 1);
+
+ cache->ctx = cogl_object_ref (ctx);
+
+ /* The key is the pipeline pointer. A reference is taken when the
+ pipeline is used as a key so we should unref it again in the
+ destroy function */
+ cache->hash_table =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ _cogl_pango_pipeline_cache_key_destroy,
+ _cogl_pango_pipeline_cache_value_destroy);
+
+ cache->base_texture_rgba_pipeline = NULL;
+ cache->base_texture_alpha_pipeline = NULL;
+
+ cache->use_mipmapping = use_mipmapping;
+
+ return cache;
+}
+
+static CoglPipeline *
+get_base_texture_rgba_pipeline (CoglPangoPipelineCache *cache)
+{
+ if (cache->base_texture_rgba_pipeline == NULL)
+ {
+ CoglPipeline *pipeline;
+
+ pipeline = cache->base_texture_rgba_pipeline =
+ cogl_pipeline_new (cache->ctx);
+
+ cogl_pipeline_set_layer_wrap_mode (pipeline, 0,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+
+ if (cache->use_mipmapping)
+ cogl_pipeline_set_layer_filters
+ (pipeline, 0,
+ COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR,
+ COGL_PIPELINE_FILTER_LINEAR);
+ }
+
+ return cache->base_texture_rgba_pipeline;
+}
+
+static CoglPipeline *
+get_base_texture_alpha_pipeline (CoglPangoPipelineCache *cache)
+{
+ if (cache->base_texture_alpha_pipeline == NULL)
+ {
+ CoglPipeline *pipeline;
+
+ pipeline = cogl_pipeline_copy (get_base_texture_rgba_pipeline (cache));
+ cache->base_texture_alpha_pipeline = pipeline;
+
+ /* The default combine mode of materials is to modulate (A x B)
+ * the texture RGBA channels with the RGBA channels of the
+ * previous layer (which in our case is just the font color)
+ *
+ * Since the RGB for an alpha texture is defined as 0, this gives us:
+ *
+ * result.rgb = color.rgb * 0
+ * result.a = color.a * texture.a
+ *
+ * What we want is premultiplied rgba values:
+ *
+ * result.rgba = color.rgb * texture.a
+ * result.a = color.a * texture.a
+ */
+ cogl_pipeline_set_layer_combine (pipeline, 0, /* layer */
+ "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
+ NULL);
+ }
+
+ return cache->base_texture_alpha_pipeline;
+}
+
+typedef struct
+{
+ CoglPangoPipelineCache *cache;
+ CoglTexture *texture;
+} PipelineDestroyNotifyData;
+
+static void
+pipeline_destroy_notify_cb (void *user_data)
+{
+ PipelineDestroyNotifyData *data = user_data;
+
+ g_hash_table_remove (data->cache->hash_table, data->texture);
+ g_slice_free (PipelineDestroyNotifyData, data);
+}
+
+CoglPipeline *
+_cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache,
+ CoglTexture *texture)
+{
+ CoglPangoPipelineCacheEntry *entry;
+ PipelineDestroyNotifyData *destroy_data;
+ static CoglUserDataKey pipeline_destroy_notify_key;
+
+ /* Look for an existing entry */
+ entry = g_hash_table_lookup (cache->hash_table, texture);
+
+ if (entry)
+ return cogl_object_ref (entry->pipeline);
+
+ /* No existing pipeline was found so let's create another */
+ entry = g_slice_new (CoglPangoPipelineCacheEntry);
+
+ if (texture)
+ {
+ CoglPipeline *base;
+
+ entry->texture = cogl_object_ref (texture);
+
+ if (_cogl_texture_get_format (entry->texture) == COGL_PIXEL_FORMAT_A_8)
+ base = get_base_texture_alpha_pipeline (cache);
+ else
+ base = get_base_texture_rgba_pipeline (cache);
+
+ entry->pipeline = cogl_pipeline_copy (base);
+
+ cogl_pipeline_set_layer_texture (entry->pipeline, 0 /* layer */, texture);
+ }
+ else
+ {
+ entry->texture = NULL;
+ entry->pipeline = cogl_pipeline_new (cache->ctx);
+ }
+
+ /* Add a weak reference to the pipeline so we can remove it from the
+ hash table when it is destroyed */
+ destroy_data = g_slice_new (PipelineDestroyNotifyData);
+ destroy_data->cache = cache;
+ destroy_data->texture = texture;
+ cogl_object_set_user_data (COGL_OBJECT (entry->pipeline),
+ &pipeline_destroy_notify_key,
+ destroy_data,
+ pipeline_destroy_notify_cb);
+
+ g_hash_table_insert (cache->hash_table,
+ texture ? cogl_object_ref (texture) : NULL,
+ entry);
+
+ /* This doesn't take a reference on the pipeline so that it will use
+ the newly created reference */
+ return entry->pipeline;
+}
+
+void
+_cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache)
+{
+ if (cache->base_texture_rgba_pipeline)
+ cogl_object_unref (cache->base_texture_rgba_pipeline);
+ if (cache->base_texture_alpha_pipeline)
+ cogl_object_unref (cache->base_texture_alpha_pipeline);
+
+ g_hash_table_destroy (cache->hash_table);
+
+ cogl_object_unref (cache->ctx);
+
+ g_free (cache);
+}
diff --git a/cogl/cogl-pango/cogl-pango-pipeline-cache.h b/cogl/cogl-pango/cogl-pango-pipeline-cache.h
new file mode 100644
index 000000000..c8abe2c34
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-pipeline-cache.h
@@ -0,0 +1,72 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ *
+ * Authors:
+ * Neil Roberts <neil@linux.intel.com>
+ */
+
+#ifndef __COGL_PANGO_PIPELINE_CACHE_H__
+#define __COGL_PANGO_PIPELINE_CACHE_H__
+
+#include <glib.h>
+
+#include "cogl/cogl-context-private.h"
+
+COGL_BEGIN_DECLS
+
+typedef struct _CoglPangoPipelineCache
+{
+ CoglContext *ctx;
+
+ GHashTable *hash_table;
+
+ CoglPipeline *base_texture_alpha_pipeline;
+ CoglPipeline *base_texture_rgba_pipeline;
+
+ CoglBool use_mipmapping;
+} CoglPangoPipelineCache;
+
+
+CoglPangoPipelineCache *
+_cogl_pango_pipeline_cache_new (CoglContext *ctx,
+ CoglBool use_mipmapping);
+
+/* Returns a pipeline that can be used to render glyphs in the given
+ texture. The pipeline has a new reference so it is up to the caller
+ to unref it */
+CoglPipeline *
+_cogl_pango_pipeline_cache_get (CoglPangoPipelineCache *cache,
+ CoglTexture *texture);
+
+void
+_cogl_pango_pipeline_cache_free (CoglPangoPipelineCache *cache);
+
+COGL_END_DECLS
+
+#endif /* __COGL_PANGO_PIPELINE_CACHE_H__ */
diff --git a/cogl/cogl-pango/cogl-pango-private.h b/cogl/cogl-pango/cogl-pango-private.h
new file mode 100644
index 000000000..e0d1f51fa
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-private.h
@@ -0,0 +1,65 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008 OpenedHand
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ * Authors:
+ * Neil Roberts <neil@linux.intel.com>
+ * Robert Bragg <robert@linux.intel.com>
+ * Matthew Allum <mallum@openedhand.com>
+ */
+
+#ifndef __COGL_PANGO_PRIVATE_H__
+#define __COGL_PANGO_PRIVATE_H__
+
+#include "cogl-pango.h"
+
+COGL_BEGIN_DECLS
+
+PangoRenderer *
+_cogl_pango_renderer_new (CoglContext *context);
+
+void
+_cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer);
+
+void
+_cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer,
+ CoglBool value);
+CoglBool
+_cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer);
+
+
+
+CoglContext *
+_cogl_pango_font_map_get_cogl_context (CoglPangoFontMap *fm);
+
+PangoRenderer *
+_cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm);
+
+COGL_END_DECLS
+
+#endif /* __COGL_PANGO_PRIVATE_H__ */
diff --git a/cogl/cogl-pango/cogl-pango-render.c b/cogl/cogl-pango/cogl-pango-render.c
new file mode 100644
index 000000000..a8855eac0
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango-render.c
@@ -0,0 +1,929 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008 OpenedHand
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ * Authors:
+ * Neil Roberts <neil@linux.intel.com>
+ * Robert Bragg <robert@linux.intel.com>
+ * Matthew Allum <mallum@openedhand.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef PANGO_ENABLE_BACKEND
+#define PANGO_ENABLE_BACKEND 1
+#endif
+
+#include <pango/pango-fontmap.h>
+#include <pango/pangocairo.h>
+#include <pango/pango-renderer.h>
+#include <cairo.h>
+
+#include "cogl/cogl-debug.h"
+#include "cogl/cogl-context-private.h"
+#include "cogl/cogl-texture-private.h"
+#include "cogl-pango-private.h"
+#include "cogl-pango-glyph-cache.h"
+#include "cogl-pango-display-list.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_COGL_CONTEXT,
+ PROP_LAST
+};
+
+typedef struct
+{
+ CoglPangoGlyphCache *glyph_cache;
+ CoglPangoPipelineCache *pipeline_cache;
+} CoglPangoRendererCaches;
+
+struct _CoglPangoRenderer
+{
+ PangoRenderer parent_instance;
+
+ CoglContext *ctx;
+
+ /* Two caches of glyphs as textures and their corresponding pipeline
+ caches, one with mipmapped textures and one without */
+ CoglPangoRendererCaches no_mipmap_caches;
+ CoglPangoRendererCaches mipmap_caches;
+
+ CoglBool use_mipmapping;
+
+ /* The current display list that is being built */
+ CoglPangoDisplayList *display_list;
+};
+
+struct _CoglPangoRendererClass
+{
+ PangoRendererClass class_instance;
+};
+
+typedef struct _CoglPangoLayoutQdata CoglPangoLayoutQdata;
+
+/* An instance of this struct gets attached to each PangoLayout to
+ cache the VBO and to detect changes to the layout */
+struct _CoglPangoLayoutQdata
+{
+ CoglPangoRenderer *renderer;
+ /* The cache of the geometry for the layout */
+ CoglPangoDisplayList *display_list;
+ /* A reference to the first line of the layout. This is just used to
+ detect changes */
+ PangoLayoutLine *first_line;
+ /* Whether mipmapping was previously used to render this layout. We
+ need to regenerate the display list if the mipmapping value is
+ changed because it will be using a different set of textures */
+ CoglBool mipmapping_used;
+};
+
+static void
+_cogl_pango_ensure_glyph_cache_for_layout_line (PangoLayoutLine *line);
+
+typedef struct
+{
+ CoglPangoDisplayList *display_list;
+ float x1, y1, x2, y2;
+} CoglPangoRendererSliceCbData;
+
+PangoRenderer *
+_cogl_pango_renderer_new (CoglContext *context)
+{
+ return PANGO_RENDERER (g_object_new (COGL_PANGO_TYPE_RENDERER,
+ "context", context, NULL));
+}
+
+static void
+cogl_pango_renderer_slice_cb (CoglTexture *texture,
+ const float *slice_coords,
+ const float *virtual_coords,
+ void *user_data)
+{
+ CoglPangoRendererSliceCbData *data = user_data;
+
+ /* Note: this assumes that there is only one slice containing the
+ whole texture and it doesn't attempt to split up the vertex
+ coordinates based on the virtual_coords */
+
+ _cogl_pango_display_list_add_texture (data->display_list,
+ texture,
+ data->x1,
+ data->y1,
+ data->x2,
+ data->y2,
+ slice_coords[0],
+ slice_coords[1],
+ slice_coords[2],
+ slice_coords[3]);
+}
+
+static void
+cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv,
+ CoglPangoGlyphCacheValue *cache_value,
+ float x1,
+ float y1)
+{
+ CoglPangoRendererSliceCbData data;
+
+ _COGL_RETURN_IF_FAIL (priv->display_list != NULL);
+
+ data.display_list = priv->display_list;
+ data.x1 = x1;
+ data.y1 = y1;
+ data.x2 = x1 + (float) cache_value->draw_width;
+ data.y2 = y1 + (float) cache_value->draw_height;
+
+ /* We iterate the internal sub textures of the texture so that we
+ can get a pointer to the base texture even if the texture is in
+ the global atlas. That way the display list can recognise that
+ the neighbouring glyphs are coming from the same atlas and bundle
+ them together into a single VBO */
+
+ cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (cache_value->texture),
+ cache_value->tx1,
+ cache_value->ty1,
+ cache_value->tx2,
+ cache_value->ty2,
+ COGL_PIPELINE_WRAP_MODE_REPEAT,
+ COGL_PIPELINE_WRAP_MODE_REPEAT,
+ cogl_pango_renderer_slice_cb,
+ &data);
+}
+
+static void cogl_pango_renderer_dispose (GObject *object);
+static void cogl_pango_renderer_finalize (GObject *object);
+static void cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ int x,
+ int y);
+static void cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer,
+ PangoRenderPart part,
+ int x,
+ int y,
+ int width,
+ int height);
+static void cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer,
+ PangoRenderPart part,
+ double y1,
+ double x11,
+ double x21,
+ double y2,
+ double x12,
+ double x22);
+
+G_DEFINE_TYPE (CoglPangoRenderer, cogl_pango_renderer, PANGO_TYPE_RENDERER);
+
+static void
+cogl_pango_renderer_init (CoglPangoRenderer *priv)
+{
+}
+
+static void
+_cogl_pango_renderer_constructed (GObject *gobject)
+{
+ CoglPangoRenderer *renderer = COGL_PANGO_RENDERER (gobject);
+ CoglContext *ctx = renderer->ctx;
+
+ renderer->no_mipmap_caches.pipeline_cache =
+ _cogl_pango_pipeline_cache_new (ctx, FALSE);
+ renderer->mipmap_caches.pipeline_cache =
+ _cogl_pango_pipeline_cache_new (ctx, TRUE);
+
+ renderer->no_mipmap_caches.glyph_cache =
+ cogl_pango_glyph_cache_new (ctx, FALSE);
+ renderer->mipmap_caches.glyph_cache =
+ cogl_pango_glyph_cache_new (ctx, TRUE);
+
+ _cogl_pango_renderer_set_use_mipmapping (renderer, FALSE);
+
+ if (G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->constructed)
+ G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->constructed (gobject);
+}
+
+static void
+cogl_pango_renderer_set_property (GObject *object,
+ unsigned int prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CoglPangoRenderer *renderer = COGL_PANGO_RENDERER (object);
+
+ switch (prop_id)
+ {
+ case PROP_COGL_CONTEXT:
+ renderer->ctx = g_value_get_pointer (value);
+ cogl_object_ref (renderer->ctx);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+cogl_pango_renderer_class_init (CoglPangoRendererClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
+ GParamSpec *pspec;
+
+ object_class->set_property = cogl_pango_renderer_set_property;
+ object_class->constructed = _cogl_pango_renderer_constructed;
+ object_class->dispose = cogl_pango_renderer_dispose;
+ object_class->finalize = cogl_pango_renderer_finalize;
+
+ pspec = g_param_spec_pointer ("context",
+ "Context",
+ "The Cogl Context",
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_property (object_class, PROP_COGL_CONTEXT, pspec);
+
+ renderer_class->draw_glyphs = cogl_pango_renderer_draw_glyphs;
+ renderer_class->draw_rectangle = cogl_pango_renderer_draw_rectangle;
+ renderer_class->draw_trapezoid = cogl_pango_renderer_draw_trapezoid;
+}
+
+static void
+cogl_pango_renderer_dispose (GObject *object)
+{
+ CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object);
+
+ if (priv->ctx)
+ {
+ cogl_object_unref (priv->ctx);
+ priv->ctx = NULL;
+ }
+}
+
+static void
+cogl_pango_renderer_finalize (GObject *object)
+{
+ CoglPangoRenderer *priv = COGL_PANGO_RENDERER (object);
+
+ cogl_pango_glyph_cache_free (priv->no_mipmap_caches.glyph_cache);
+ cogl_pango_glyph_cache_free (priv->mipmap_caches.glyph_cache);
+
+ _cogl_pango_pipeline_cache_free (priv->no_mipmap_caches.pipeline_cache);
+ _cogl_pango_pipeline_cache_free (priv->mipmap_caches.pipeline_cache);
+
+ G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object);
+}
+
+static CoglPangoRenderer *
+cogl_pango_get_renderer_from_context (PangoContext *context)
+{
+ PangoFontMap *font_map;
+ CoglPangoFontMap *cogl_font_map;
+ PangoRenderer *renderer;
+
+ font_map = pango_context_get_font_map (context);
+ g_return_val_if_fail (COGL_PANGO_IS_FONT_MAP (font_map), NULL);
+
+ cogl_font_map = COGL_PANGO_FONT_MAP (font_map);
+
+ renderer = _cogl_pango_font_map_get_renderer (cogl_font_map);
+
+ g_return_val_if_fail (COGL_PANGO_IS_RENDERER (renderer), NULL);
+
+ return COGL_PANGO_RENDERER (renderer);
+}
+
+static GQuark
+cogl_pango_layout_get_qdata_key (void)
+{
+ static GQuark key = 0;
+
+ if (G_UNLIKELY (key == 0))
+ key = g_quark_from_static_string ("CoglPangoDisplayList");
+
+ return key;
+}
+
+static void
+cogl_pango_layout_qdata_forget_display_list (CoglPangoLayoutQdata *qdata)
+{
+ if (qdata->display_list)
+ {
+ CoglPangoRendererCaches *caches = qdata->mipmapping_used ?
+ &qdata->renderer->mipmap_caches :
+ &qdata->renderer->no_mipmap_caches;
+
+ _cogl_pango_glyph_cache_remove_reorganize_callback
+ (caches->glyph_cache,
+ (GHookFunc) cogl_pango_layout_qdata_forget_display_list,
+ qdata);
+
+ _cogl_pango_display_list_free (qdata->display_list);
+
+ qdata->display_list = NULL;
+ }
+}
+
+static void
+cogl_pango_render_qdata_destroy (CoglPangoLayoutQdata *qdata)
+{
+ cogl_pango_layout_qdata_forget_display_list (qdata);
+ if (qdata->first_line)
+ pango_layout_line_unref (qdata->first_line);
+ g_slice_free (CoglPangoLayoutQdata, qdata);
+}
+
+void
+cogl_pango_show_layout (CoglFramebuffer *fb,
+ PangoLayout *layout,
+ float x,
+ float y,
+ const CoglColor *color)
+{
+ PangoContext *context;
+ CoglPangoRenderer *priv;
+ CoglPangoLayoutQdata *qdata;
+
+ context = pango_layout_get_context (layout);
+ priv = cogl_pango_get_renderer_from_context (context);
+ if (G_UNLIKELY (!priv))
+ return;
+
+ qdata = g_object_get_qdata (G_OBJECT (layout),
+ cogl_pango_layout_get_qdata_key ());
+
+ if (qdata == NULL)
+ {
+ qdata = g_slice_new0 (CoglPangoLayoutQdata);
+ qdata->renderer = priv;
+ g_object_set_qdata_full (G_OBJECT (layout),
+ cogl_pango_layout_get_qdata_key (),
+ qdata,
+ (GDestroyNotify)
+ cogl_pango_render_qdata_destroy);
+ }
+
+ /* Check if the layout has changed since the last build of the
+ display list. This trick was suggested by Behdad Esfahbod here:
+ http://mail.gnome.org/archives/gtk-i18n-list/2009-May/msg00019.html */
+ if (qdata->display_list &&
+ ((qdata->first_line &&
+ qdata->first_line->layout != layout) ||
+ qdata->mipmapping_used != priv->use_mipmapping))
+ cogl_pango_layout_qdata_forget_display_list (qdata);
+
+ if (qdata->display_list == NULL)
+ {
+ CoglPangoRendererCaches *caches = priv->use_mipmapping ?
+ &priv->mipmap_caches :
+ &priv->no_mipmap_caches;
+
+ cogl_pango_ensure_glyph_cache_for_layout (layout);
+
+ qdata->display_list =
+ _cogl_pango_display_list_new (caches->pipeline_cache);
+
+ /* Register for notification of when the glyph cache changes so
+ we can rebuild the display list */
+ _cogl_pango_glyph_cache_add_reorganize_callback
+ (caches->glyph_cache,
+ (GHookFunc) cogl_pango_layout_qdata_forget_display_list,
+ qdata);
+
+ priv->display_list = qdata->display_list;
+ pango_renderer_draw_layout (PANGO_RENDERER (priv), layout, 0, 0);
+ priv->display_list = NULL;
+
+ qdata->mipmapping_used = priv->use_mipmapping;
+ }
+
+ cogl_framebuffer_push_matrix (fb);
+ cogl_framebuffer_translate (fb, x, y, 0);
+
+ _cogl_pango_display_list_render (fb,
+ qdata->display_list,
+ color);
+
+ cogl_framebuffer_pop_matrix (fb);
+
+ /* Keep a reference to the first line of the layout so we can detect
+ changes */
+ if (qdata->first_line)
+ {
+ pango_layout_line_unref (qdata->first_line);
+ qdata->first_line = NULL;
+ }
+ if (pango_layout_get_line_count (layout) > 0)
+ {
+ qdata->first_line = pango_layout_get_line (layout, 0);
+ pango_layout_line_ref (qdata->first_line);
+ }
+}
+
+void
+cogl_pango_render_layout_subpixel (PangoLayout *layout,
+ int x,
+ int y,
+ const CoglColor *color,
+ int flags)
+{
+ cogl_pango_show_layout (cogl_get_draw_framebuffer (),
+ layout,
+ x / (float) PANGO_SCALE,
+ y / (float) PANGO_SCALE,
+ color);
+}
+
+void
+cogl_pango_render_layout (PangoLayout *layout,
+ int x,
+ int y,
+ const CoglColor *color,
+ int flags)
+{
+ cogl_pango_render_layout_subpixel (layout,
+ x * PANGO_SCALE,
+ y * PANGO_SCALE,
+ color,
+ flags);
+}
+
+void
+cogl_pango_show_layout_line (CoglFramebuffer *fb,
+ PangoLayoutLine *line,
+ float x,
+ float y,
+ const CoglColor *color)
+{
+ PangoContext *context;
+ CoglPangoRenderer *priv;
+ CoglPangoRendererCaches *caches;
+ int pango_x = x * PANGO_SCALE;
+ int pango_y = y * PANGO_SCALE;
+
+ context = pango_layout_get_context (line->layout);
+ priv = cogl_pango_get_renderer_from_context (context);
+ if (G_UNLIKELY (!priv))
+ return;
+
+ caches = (priv->use_mipmapping ?
+ &priv->mipmap_caches :
+ &priv->no_mipmap_caches);
+
+ priv->display_list = _cogl_pango_display_list_new (caches->pipeline_cache);
+
+ _cogl_pango_ensure_glyph_cache_for_layout_line (line);
+
+ pango_renderer_draw_layout_line (PANGO_RENDERER (priv), line,
+ pango_x, pango_y);
+
+ _cogl_pango_display_list_render (fb,
+ priv->display_list,
+ color);
+
+ _cogl_pango_display_list_free (priv->display_list);
+ priv->display_list = NULL;
+}
+
+void
+cogl_pango_render_layout_line (PangoLayoutLine *line,
+ int x,
+ int y,
+ const CoglColor *color)
+{
+ cogl_pango_show_layout_line (cogl_get_draw_framebuffer (),
+ line,
+ x / (float) PANGO_SCALE,
+ y / (float) PANGO_SCALE,
+ color);
+}
+
+void
+_cogl_pango_renderer_clear_glyph_cache (CoglPangoRenderer *renderer)
+{
+ cogl_pango_glyph_cache_clear (renderer->mipmap_caches.glyph_cache);
+ cogl_pango_glyph_cache_clear (renderer->no_mipmap_caches.glyph_cache);
+}
+
+void
+_cogl_pango_renderer_set_use_mipmapping (CoglPangoRenderer *renderer,
+ CoglBool value)
+{
+ renderer->use_mipmapping = value;
+}
+
+CoglBool
+_cogl_pango_renderer_get_use_mipmapping (CoglPangoRenderer *renderer)
+{
+ return renderer->use_mipmapping;
+}
+
+static CoglPangoGlyphCacheValue *
+cogl_pango_renderer_get_cached_glyph (PangoRenderer *renderer,
+ CoglBool create,
+ PangoFont *font,
+ PangoGlyph glyph)
+{
+ CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
+ CoglPangoRendererCaches *caches = (priv->use_mipmapping ?
+ &priv->mipmap_caches :
+ &priv->no_mipmap_caches);
+
+ return cogl_pango_glyph_cache_lookup (caches->glyph_cache,
+ create, font, glyph);
+}
+
+static void
+cogl_pango_renderer_set_dirty_glyph (PangoFont *font,
+ PangoGlyph glyph,
+ CoglPangoGlyphCacheValue *value)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_scaled_font_t *scaled_font;
+ cairo_glyph_t cairo_glyph;
+ cairo_format_t format_cairo;
+ CoglPixelFormat format_cogl;
+
+ COGL_NOTE (PANGO, "redrawing glyph %i", glyph);
+
+ /* Glyphs that don't take up any space will end up without a
+ texture. These should never become dirty so they shouldn't end up
+ here */
+ _COGL_RETURN_IF_FAIL (value->texture != NULL);
+
+ if (_cogl_texture_get_format (value->texture) == COGL_PIXEL_FORMAT_A_8)
+ {
+ format_cairo = CAIRO_FORMAT_A8;
+ format_cogl = COGL_PIXEL_FORMAT_A_8;
+ }
+ else
+ {
+ format_cairo = CAIRO_FORMAT_ARGB32;
+
+ /* Cairo stores the data in native byte order as ARGB but Cogl's
+ pixel formats specify the actual byte order. Therefore we
+ need to use a different format depending on the
+ architecture */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ format_cogl = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
+#else
+ format_cogl = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
+#endif
+ }
+
+ surface = cairo_image_surface_create (format_cairo,
+ value->draw_width,
+ value->draw_height);
+ cr = cairo_create (surface);
+
+ scaled_font = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
+ cairo_set_scaled_font (cr, scaled_font);
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
+
+ cairo_glyph.x = -value->draw_x;
+ cairo_glyph.y = -value->draw_y;
+ /* The PangoCairo glyph numbers directly map to Cairo glyph
+ numbers */
+ cairo_glyph.index = glyph;
+ cairo_show_glyphs (cr, &cairo_glyph, 1);
+
+ cairo_destroy (cr);
+ cairo_surface_flush (surface);
+
+ /* Copy the glyph to the texture */
+ cogl_texture_set_region (value->texture,
+ 0, /* src_x */
+ 0, /* src_y */
+ value->tx_pixel, /* dst_x */
+ value->ty_pixel, /* dst_y */
+ value->draw_width, /* dst_width */
+ value->draw_height, /* dst_height */
+ value->draw_width, /* width */
+ value->draw_height, /* height */
+ format_cogl,
+ cairo_image_surface_get_stride (surface),
+ cairo_image_surface_get_data (surface));
+
+ cairo_surface_destroy (surface);
+}
+
+static void
+_cogl_pango_ensure_glyph_cache_for_layout_line_internal (PangoLayoutLine *line)
+{
+ PangoContext *context;
+ PangoRenderer *renderer;
+ GSList *l;
+
+ context = pango_layout_get_context (line->layout);
+ renderer =
+ PANGO_RENDERER (cogl_pango_get_renderer_from_context (context));
+
+ for (l = line->runs; l; l = l->next)
+ {
+ PangoLayoutRun *run = l->data;
+ PangoGlyphString *glyphs = run->glyphs;
+ int i;
+
+ for (i = 0; i < glyphs->num_glyphs; i++)
+ {
+ PangoGlyphInfo *gi = &glyphs->glyphs[i];
+
+ /* If the glyph isn't cached then this will reserve
+ space for it now. We won't actually draw the glyph
+ yet because reserving space could cause all of the
+ other glyphs to be moved so we might as well redraw
+ them all later once we know that the position is
+ settled */
+ cogl_pango_renderer_get_cached_glyph (renderer, TRUE,
+ run->item->analysis.font,
+ gi->glyph);
+ }
+ }
+}
+
+static void
+_cogl_pango_set_dirty_glyphs (CoglPangoRenderer *priv)
+{
+ _cogl_pango_glyph_cache_set_dirty_glyphs
+ (priv->mipmap_caches.glyph_cache, cogl_pango_renderer_set_dirty_glyph);
+ _cogl_pango_glyph_cache_set_dirty_glyphs
+ (priv->no_mipmap_caches.glyph_cache, cogl_pango_renderer_set_dirty_glyph);
+}
+
+static void
+_cogl_pango_ensure_glyph_cache_for_layout_line (PangoLayoutLine *line)
+{
+ PangoContext *context;
+ CoglPangoRenderer *priv;
+
+ context = pango_layout_get_context (line->layout);
+ priv = cogl_pango_get_renderer_from_context (context);
+
+ _cogl_pango_ensure_glyph_cache_for_layout_line_internal (line);
+
+ /* Now that we know all of the positions are settled we'll fill in
+ any dirty glyphs */
+ _cogl_pango_set_dirty_glyphs (priv);
+}
+
+void
+cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout)
+{
+ PangoContext *context;
+ CoglPangoRenderer *priv;
+ PangoLayoutIter *iter;
+
+ context = pango_layout_get_context (layout);
+ priv = cogl_pango_get_renderer_from_context (context);
+
+ _COGL_RETURN_IF_FAIL (PANGO_IS_LAYOUT (layout));
+
+ if ((iter = pango_layout_get_iter (layout)) == NULL)
+ return;
+
+ do
+ {
+ PangoLayoutLine *line;
+
+ line = pango_layout_iter_get_line_readonly (iter);
+
+ _cogl_pango_ensure_glyph_cache_for_layout_line_internal (line);
+ }
+ while (pango_layout_iter_next_line (iter));
+
+ pango_layout_iter_free (iter);
+
+ /* Now that we know all of the positions are settled we'll fill in
+ any dirty glyphs */
+ _cogl_pango_set_dirty_glyphs (priv);
+}
+
+static void
+cogl_pango_renderer_set_color_for_part (PangoRenderer *renderer,
+ PangoRenderPart part)
+{
+ PangoColor *pango_color = pango_renderer_get_color (renderer, part);
+ CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
+
+ if (pango_color)
+ {
+ CoglColor color;
+
+ cogl_color_init_from_4ub (&color,
+ pango_color->red >> 8,
+ pango_color->green >> 8,
+ pango_color->blue >> 8,
+ 0xff);
+
+ _cogl_pango_display_list_set_color_override (priv->display_list, &color);
+ }
+ else
+ _cogl_pango_display_list_remove_color_override (priv->display_list);
+}
+
+static void
+cogl_pango_renderer_draw_box (PangoRenderer *renderer,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
+
+ _COGL_RETURN_IF_FAIL (priv->display_list != NULL);
+
+ _cogl_pango_display_list_add_rectangle (priv->display_list,
+ x,
+ y - height,
+ x + width,
+ y);
+}
+
+static void
+cogl_pango_renderer_get_device_units (PangoRenderer *renderer,
+ int xin,
+ int yin,
+ float *xout,
+ float *yout)
+{
+ const PangoMatrix *matrix;
+
+ if ((matrix = pango_renderer_get_matrix (renderer)))
+ {
+ /* Convert user-space coords to device coords */
+ *xout = ((xin * matrix->xx + yin * matrix->xy)
+ / PANGO_SCALE + matrix->x0);
+ *yout = ((yin * matrix->yy + xin * matrix->yx)
+ / PANGO_SCALE + matrix->y0);
+ }
+ else
+ {
+ *xout = PANGO_PIXELS (xin);
+ *yout = PANGO_PIXELS (yin);
+ }
+}
+
+static void
+cogl_pango_renderer_draw_rectangle (PangoRenderer *renderer,
+ PangoRenderPart part,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
+ float x1, x2, y1, y2;
+
+ _COGL_RETURN_IF_FAIL (priv->display_list != NULL);
+
+ cogl_pango_renderer_set_color_for_part (renderer, part);
+
+ cogl_pango_renderer_get_device_units (renderer,
+ x, y,
+ &x1, &y1);
+ cogl_pango_renderer_get_device_units (renderer,
+ x + width, y + height,
+ &x2, &y2);
+
+ _cogl_pango_display_list_add_rectangle (priv->display_list,
+ x1, y1, x2, y2);
+}
+
+static void
+cogl_pango_renderer_draw_trapezoid (PangoRenderer *renderer,
+ PangoRenderPart part,
+ double y1,
+ double x11,
+ double x21,
+ double y2,
+ double x12,
+ double x22)
+{
+ CoglPangoRenderer *priv = COGL_PANGO_RENDERER (renderer);
+
+ _COGL_RETURN_IF_FAIL (priv->display_list != NULL);
+
+ cogl_pango_renderer_set_color_for_part (renderer, part);
+
+ _cogl_pango_display_list_add_trapezoid (priv->display_list,
+ y1,
+ x11,
+ x21,
+ y2,
+ x12,
+ x22);
+}
+
+static void
+cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
+ PangoFont *font,
+ PangoGlyphString *glyphs,
+ int xi,
+ int yi)
+{
+ CoglPangoRenderer *priv = (CoglPangoRenderer *) renderer;
+ CoglPangoGlyphCacheValue *cache_value;
+ int i;
+
+ cogl_pango_renderer_set_color_for_part (renderer,
+ PANGO_RENDER_PART_FOREGROUND);
+
+ for (i = 0; i < glyphs->num_glyphs; i++)
+ {
+ PangoGlyphInfo *gi = glyphs->glyphs + i;
+ float x, y;
+
+ cogl_pango_renderer_get_device_units (renderer,
+ xi + gi->geometry.x_offset,
+ yi + gi->geometry.y_offset,
+ &x, &y);
+
+ if ((gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
+ {
+ if (font == NULL)
+ {
+ cogl_pango_renderer_draw_box (renderer,
+ x,
+ y,
+ PANGO_UNKNOWN_GLYPH_WIDTH,
+ PANGO_UNKNOWN_GLYPH_HEIGHT);
+ }
+ else
+ {
+ PangoRectangle ink_rect;
+
+ pango_font_get_glyph_extents (font, gi->glyph, &ink_rect, NULL);
+ pango_extents_to_pixels (&ink_rect, NULL);
+
+ cogl_pango_renderer_draw_box (renderer,
+ x + ink_rect.x,
+ y + ink_rect.y + ink_rect.height,
+ ink_rect.width,
+ ink_rect.height);
+ }
+ }
+ else
+ {
+ /* Get the texture containing the glyph */
+ cache_value =
+ cogl_pango_renderer_get_cached_glyph (renderer,
+ FALSE,
+ font,
+ gi->glyph);
+
+ /* cogl_pango_ensure_glyph_cache_for_layout should always be
+ called before rendering a layout so we should never have
+ a dirty glyph here */
+ g_assert (cache_value == NULL || !cache_value->dirty);
+
+ if (cache_value == NULL)
+ {
+ cogl_pango_renderer_draw_box (renderer,
+ x,
+ y,
+ PANGO_UNKNOWN_GLYPH_WIDTH,
+ PANGO_UNKNOWN_GLYPH_HEIGHT);
+ }
+ else if (cache_value->texture)
+ {
+ x += (float)(cache_value->draw_x);
+ y += (float)(cache_value->draw_y);
+
+ cogl_pango_renderer_draw_glyph (priv, cache_value, x, y);
+ }
+ }
+
+ xi += gi->geometry.width;
+ }
+}
diff --git a/cogl/cogl-pango/cogl-pango.h b/cogl/cogl-pango/cogl-pango.h
new file mode 100644
index 000000000..871284973
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango.h
@@ -0,0 +1,298 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008 OpenedHand
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Neil Roberts <neil@linux.intel.com>
+ * Robert Bragg <robert@linux.intel.com>
+ * Matthew Allum <mallum@openedhand.com>
+ */
+
+#ifndef __COGL_PANGO_H__
+#define __COGL_PANGO_H__
+
+#include <glib-object.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+/* XXX: Currently this header may be included both as an internal
+ * header (within the cogl-pango implementation) and as a public
+ * header.
+ *
+ * Since <cogl/cogl.h> should not be included for internal use we
+ * determine the current context and switch between including cogl.h
+ * or specific internal cogl headers here...
+ */
+#ifndef COGL_COMPILATION
+#include <cogl/cogl.h>
+#else
+#include "cogl/cogl-context.h"
+#endif
+
+COGL_BEGIN_DECLS
+
+/* It's too difficult to actually subclass the pango cairo font
+ * map. Instead we just make a fake set of macros that actually just
+ * directly use the original type
+ */
+#define COGL_PANGO_TYPE_FONT_MAP PANGO_TYPE_CAIRO_FONT_MAP
+#define COGL_PANGO_FONT_MAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COGL_PANGO_TYPE_FONT_MAP, CoglPangoFontMap))
+#define COGL_PANGO_IS_FONT_MAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COGL_PANGO_TYPE_FONT_MAP))
+
+typedef PangoCairoFontMap CoglPangoFontMap;
+
+/**
+ * cogl_pango_font_map_new:
+ *
+ * Creates a new font map.
+ *
+ * Return value: (transfer full): the newly created #PangoFontMap
+ *
+ * Since: 1.14
+ */
+PangoFontMap *
+cogl_pango_font_map_new (void);
+
+/**
+ * cogl_pango_font_map_create_context:
+ * @font_map: a #CoglPangoFontMap
+ *
+ * Create a #PangoContext for the given @font_map.
+ *
+ * Returns: (transfer full): the newly created context: free with g_object_unref().
+ */
+PangoContext *
+cogl_pango_font_map_create_context (CoglPangoFontMap *font_map);
+
+/**
+ * cogl_pango_font_map_set_resolution:
+ * @font_map: a #CoglPangoFontMap
+ * @dpi: The resolution in "dots per inch". (Physical inches aren't
+ * actually involved; the terminology is conventional.)
+ *
+ * Sets the resolution for the @font_map. This is a scale factor
+ * between points specified in a #PangoFontDescription and Cogl units.
+ * The default value is %96, meaning that a 10 point font will be 13
+ * units high. (10 * 96. / 72. = 13.3).
+ *
+ * Since: 1.14
+ */
+void
+cogl_pango_font_map_set_resolution (CoglPangoFontMap *font_map,
+ double dpi);
+
+/**
+ * cogl_pango_font_map_clear_glyph_cache:
+ * @font_map: a #CoglPangoFontMap
+ *
+ * Clears the glyph cache for @font_map.
+ *
+ * Since: 1.0
+ */
+void
+cogl_pango_font_map_clear_glyph_cache (CoglPangoFontMap *font_map);
+
+/**
+ * cogl_pango_ensure_glyph_cache_for_layout:
+ * @layout: A #PangoLayout
+ *
+ * This updates any internal glyph cache textures as necessary to be
+ * able to render the given @layout.
+ *
+ * This api should be used to avoid mid-scene modifications of
+ * glyph-cache textures which can lead to undefined rendering results.
+ *
+ * Since: 1.0
+ */
+void
+cogl_pango_ensure_glyph_cache_for_layout (PangoLayout *layout);
+
+/**
+ * cogl_pango_font_map_set_use_mipmapping:
+ * @font_map: a #CoglPangoFontMap
+ * @value: %TRUE to enable the use of mipmapping
+ *
+ * Sets whether the renderer for the passed font map should use
+ * mipmapping when rendering a #PangoLayout.
+ *
+ * Since: 1.0
+ */
+void
+cogl_pango_font_map_set_use_mipmapping (CoglPangoFontMap *font_map,
+ CoglBool value);
+
+/**
+ * cogl_pango_font_map_get_use_mipmapping:
+ * @font_map: a #CoglPangoFontMap
+ *
+ * Retrieves whether the #CoglPangoRenderer used by @font_map will use
+ * mipmapping when rendering the glyphs.
+ *
+ * Return value: %TRUE if mipmapping is used, %FALSE otherwise.
+ *
+ * Since: 1.0
+ */
+CoglBool
+cogl_pango_font_map_get_use_mipmapping (CoglPangoFontMap *font_map);
+
+/**
+ * cogl_pango_font_map_get_renderer:
+ * @font_map: a #CoglPangoFontMap
+ *
+ * Retrieves the #CoglPangoRenderer for the passed @font_map.
+ *
+ * Return value: (transfer none): a #PangoRenderer
+ *
+ * Since: 1.0
+ */
+PangoRenderer *
+cogl_pango_font_map_get_renderer (CoglPangoFontMap *font_map);
+
+/**
+ * cogl_pango_show_layout:
+ * @framebuffer: A #CoglFramebuffer to draw too.
+ * @layout: a #PangoLayout
+ * @x: X coordinate to render the layout at
+ * @y: Y coordinate to render the layout at
+ * @color: color to use when rendering the layout
+ *
+ * Draws a solidly coloured @layout on the given @framebuffer at (@x,
+ * @y) within the @framebuffer<!-- -->'s current model-view coordinate
+ * space.
+ *
+ * Since: 1.14
+ */
+void
+cogl_pango_show_layout (CoglFramebuffer *framebuffer,
+ PangoLayout *layout,
+ float x,
+ float y,
+ const CoglColor *color);
+
+/**
+ * cogl_pango_show_layout_line:
+ * @framebuffer: A #CoglFramebuffer to draw too.
+ * @line: a #PangoLayoutLine
+ * @x: X coordinate to render the line at
+ * @y: Y coordinate to render the line at
+ * @color: color to use when rendering the line
+ *
+ * Draws a solidly coloured @line on the given @framebuffer at (@x,
+ * @y) within the @framebuffer<!-- -->'s current model-view coordinate
+ * space.
+ *
+ * Since: 1.14
+ */
+void
+cogl_pango_show_layout_line (CoglFramebuffer *framebuffer,
+ PangoLayoutLine *line,
+ float x,
+ float y,
+ const CoglColor *color);
+
+
+#define COGL_PANGO_TYPE_RENDERER (cogl_pango_renderer_get_type ())
+#define COGL_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COGL_PANGO_TYPE_RENDERER, CoglPangoRenderer))
+#define COGL_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COGL_PANGO_TYPE_RENDERER, CoglPangoRendererClass))
+#define COGL_PANGO_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COGL_PANGO_TYPE_RENDERER))
+#define COGL_PANGO_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COGL_PANGO_TYPE_RENDERER))
+#define COGL_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COGL_PANGO_TYPE_RENDERER, CoglPangoRendererClass))
+
+/* opaque types */
+typedef struct _CoglPangoRenderer CoglPangoRenderer;
+typedef struct _CoglPangoRendererClass CoglPangoRendererClass;
+
+GType cogl_pango_renderer_get_type (void) G_GNUC_CONST;
+
+/**
+ * cogl_pango_render_layout_subpixel:
+ * @layout: a #PangoLayout
+ * @x: X coordinate (in Pango units) to render the layout at
+ * @y: Y coordinate (in Pango units) to render the layout at
+ * @color: color to use when rendering the layout
+ * @flags:
+ *
+ * Draws a solidly coloured @layout on the given @framebuffer at (@x,
+ * @y) within the @framebuffer<!-- -->'s current model-view coordinate
+ * space.
+ *
+ * Since: 1.0
+ * Deprecated: 1.16: Use cogl_pango_show_layout() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_pango_show_layout)
+void
+cogl_pango_render_layout_subpixel (PangoLayout *layout,
+ int x,
+ int y,
+ const CoglColor *color,
+ int flags);
+
+/**
+ * cogl_pango_render_layout:
+ * @layout: a #PangoLayout
+ * @x: X coordinate to render the layout at
+ * @y: Y coordinate to render the layout at
+ * @color: color to use when rendering the layout
+ * @flags:
+ *
+ * Draws a solidly coloured @layout on the given @framebuffer at (@x,
+ * @y) within the @framebuffer<!-- -->'s current model-view coordinate
+ * space.
+ *
+ * Since: 1.0
+ * Deprecated: 1.16: Use cogl_pango_show_layout() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_pango_show_layout)
+void
+cogl_pango_render_layout (PangoLayout *layout,
+ int x,
+ int y,
+ const CoglColor *color,
+ int flags);
+
+/**
+ * cogl_pango_render_layout_line:
+ * @line: a #PangoLayoutLine
+ * @x: X coordinate to render the line at
+ * @y: Y coordinate to render the line at
+ * @color: color to use when rendering the line
+ *
+ * Renders @line at the given coordinates using the given color.
+ *
+ * Since: 1.0
+ * Deprecated: 1.16: Use cogl_pango_show_layout() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_pango_show_layout_line)
+void
+cogl_pango_render_layout_line (PangoLayoutLine *line,
+ int x,
+ int y,
+ const CoglColor *color);
+
+COGL_END_DECLS
+
+#endif /* __COGL_PANGO_H__ */
diff --git a/cogl/cogl-pango/cogl-pango.symbols b/cogl/cogl-pango/cogl-pango.symbols
new file mode 100644
index 000000000..b86c9560e
--- /dev/null
+++ b/cogl/cogl-pango/cogl-pango.symbols
@@ -0,0 +1,12 @@
+cogl_pango_ensure_glyph_cache_for_layout
+cogl_pango_font_map_clear_glyph_cache
+cogl_pango_font_map_create_context
+cogl_pango_font_map_get_renderer
+cogl_pango_font_map_get_use_mipmapping
+cogl_pango_font_map_new
+cogl_pango_font_map_set_resolution
+cogl_pango_font_map_set_use_mipmapping
+cogl_pango_renderer_get_type
+cogl_pango_render_layout
+cogl_pango_render_layout_line
+cogl_pango_render_layout_subpixel
diff --git a/cogl/cogl-pango/mutter-cogl-pango-1.0.pc.in b/cogl/cogl-pango/mutter-cogl-pango-1.0.pc.in
new file mode 100644
index 000000000..64ab7b40b
--- /dev/null
+++ b/cogl/cogl-pango/mutter-cogl-pango-1.0.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@/mutter
+includedir=@includedir@/mutter
+apiversion=1.0
+requires=@COGL_PKG_REQUIRES@ mutter-cogl-1.0
+
+Name: Cogl
+Description: An object oriented GL/GLES Abstraction/Utility Layer
+Version: @COGL_1_VERSION@
+Libs: -L${libdir} -lmutter-cogl-pango
+Cflags: -I${includedir}/cogl
+Requires: ${requires}
diff --git a/cogl/cogl-path/Makefile.am b/cogl/cogl-path/Makefile.am
new file mode 100644
index 000000000..3408c7b88
--- /dev/null
+++ b/cogl/cogl-path/Makefile.am
@@ -0,0 +1,104 @@
+NULL =
+
+BUILT_SOURCES =
+
+CLEANFILES =
+DISTCLEANFILES =
+
+EXTRA_DIST =
+
+# tesselator sources
+cogl_tesselator_sources = \
+ tesselator/dict-list.h \
+ tesselator/dict.c \
+ tesselator/dict.h \
+ tesselator/geom.c \
+ tesselator/geom.h \
+ tesselator/gluos.h \
+ tesselator/memalloc.h \
+ tesselator/mesh.c \
+ tesselator/mesh.h \
+ tesselator/normal.c \
+ tesselator/normal.h \
+ tesselator/priorityq-heap.h \
+ tesselator/priorityq-sort.h \
+ tesselator/priorityq.c \
+ tesselator/priorityq.h \
+ tesselator/render.c \
+ tesselator/render.h \
+ tesselator/sweep.c \
+ tesselator/sweep.h \
+ tesselator/tess.c \
+ tesselator/tess.h \
+ tesselator/tesselator.h \
+ tesselator/tessmono.c \
+ tesselator/tessmono.h \
+ tesselator/GL/glu.h \
+ $(NULL)
+
+source_c = \
+ $(cogl_tesselator_sources) \
+ cogl-path-private.h \
+ cogl1-path.c \
+ cogl-path.c \
+ $(NULL)
+
+EXTRA_DIST += \
+ tesselator/README \
+ tesselator/priorityq-heap.c \
+ cogl-path.symbols \
+ $(NULL)
+
+source_1_x_h = \
+ cogl-path-types.h \
+ cogl1-path-functions.h \
+ $(NULL)
+
+source_h = \
+ cogl-path.h \
+ $(source_1_x_h) \
+ cogl2-path-functions.h \
+ $(NULL)
+
+# glib-mkenums rules
+glib_enum_h = cogl-path-enum-types.h
+glib_enum_c = cogl-path-enum-types.c
+glib_enum_headers = $(source_1_x_h)
+include $(top_srcdir)/build/autotools/Makefile.am.enums
+
+mutterlibdir = $(libdir)/mutter
+mutterlib_LTLIBRARIES = libmutter-cogl-path.la
+
+libmutter_cogl_path_la_SOURCES = $(source_c) $(source_h)
+nodist_libmutter_cogl_path_la_SOURCES = $(BUILT_SOURCES)
+libmutter_cogl_path_la_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
+libmutter_cogl_path_la_LIBADD = $(top_builddir)/cogl/libmutter-cogl.la
+libmutter_cogl_path_la_LIBADD += $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
+libmutter_cogl_path_la_LDFLAGS = \
+ -export-dynamic \
+ -export-symbols-regex "^(cogl|cogl2)_(framebuffer|path|is|clip|[sg]et)_.*" \
+ -no-undefined \
+ -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@ \
+ -rpath $(mutterlibdir)
+
+AM_CPPFLAGS = \
+ -DCOGL_COMPILATION \
+ -DG_LOG_DOMAIN=\"CoglPath\" \
+ -I$(srcdir)/tesselator \
+ -I$(top_srcdir)/cogl \
+ -I$(top_builddir)/cogl \
+ -I$(top_srcdir)/cogl/winsys \
+ -I$(top_srcdir) \
+ -I$(top_builddir)
+
+cogl_base_includedir = $(includedir)/mutter
+cogl_pathheadersdir = $(cogl_base_includedir)/cogl/cogl-path
+cogl_pathheaders_HEADERS = $(source_h)
+nodist_cogl_pathheaders_HEADERS = cogl-path-enum-types.h
+
+pc_files = mutter-cogl-path-1.0.pc
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pc_files)
+
+DISTCLEANFILES += $(pc_files)
diff --git a/cogl/cogl-path/cogl-path-enum-types.c.in b/cogl/cogl-path/cogl-path-enum-types.c.in
new file mode 100644
index 000000000..54746076e
--- /dev/null
+++ b/cogl/cogl-path/cogl-path-enum-types.c.in
@@ -0,0 +1,50 @@
+/*** BEGIN file-header ***/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* We need to undefine this so that we will be sure to include
+ * cogl-path.h instead of cogl2-path.h when we include the framebuffer
+ * header. Otherwise it will include both headers and it won't
+ * compile. */
+#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
+
+#include "cogl-path-enum-types.h"
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+#include "@filename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type (void)
+{
+ static volatile gsize g_enum_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_enum_type_id__volatile))
+ {
+ static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ GType g_enum_type_id;
+
+ g_enum_type_id =
+ g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
+
+ g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
+ }
+
+ return g_enum_type_id__volatile;
+}
+/*** END value-tail ***/
diff --git a/cogl/cogl-path/cogl-path-enum-types.h.in b/cogl/cogl-path/cogl-path-enum-types.h.in
new file mode 100644
index 000000000..071686acd
--- /dev/null
+++ b/cogl/cogl-path/cogl-path-enum-types.h.in
@@ -0,0 +1,25 @@
+/*** BEGIN file-header ***/
+#ifndef __COGL_PATH_ENUM_TYPES_H__
+#define __COGL_PATH_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __COGL_PATH_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define COGL_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
+
+/*** END value-header ***/
diff --git a/cogl/cogl-path/cogl-path-private.h b/cogl/cogl-path/cogl-path-private.h
new file mode 100644
index 000000000..078e58ffc
--- /dev/null
+++ b/cogl/cogl-path/cogl-path-private.h
@@ -0,0 +1,126 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+#ifndef __COGL_PATH_PRIVATE_H
+#define __COGL_PATH_PRIVATE_H
+
+#include "cogl-object.h"
+#include "cogl-attribute-private.h"
+
+typedef struct _floatVec2
+{
+ float x;
+ float y;
+} floatVec2;
+
+typedef struct _CoglPathNode
+{
+ float x;
+ float y;
+ unsigned int path_size;
+} CoglPathNode;
+
+typedef struct _CoglBezQuad
+{
+ floatVec2 p1;
+ floatVec2 p2;
+ floatVec2 p3;
+} CoglBezQuad;
+
+typedef struct _CoglBezCubic
+{
+ floatVec2 p1;
+ floatVec2 p2;
+ floatVec2 p3;
+ floatVec2 p4;
+} CoglBezCubic;
+
+typedef struct _CoglPathData CoglPathData;
+
+struct _CoglPath
+{
+ CoglObject _parent;
+
+ CoglPathData *data;
+};
+
+#define COGL_PATH_N_ATTRIBUTES 2
+
+struct _CoglPathData
+{
+ unsigned int ref_count;
+
+ CoglContext *context;
+
+ CoglPathFillRule fill_rule;
+
+ GArray *path_nodes;
+
+ floatVec2 path_start;
+ floatVec2 path_pen;
+ unsigned int last_path;
+ floatVec2 path_nodes_min;
+ floatVec2 path_nodes_max;
+
+ CoglAttributeBuffer *fill_attribute_buffer;
+ CoglIndices *fill_vbo_indices;
+ unsigned int fill_vbo_n_indices;
+ CoglAttribute *fill_attributes[COGL_PATH_N_ATTRIBUTES + 1];
+ CoglPrimitive *fill_primitive;
+
+ CoglAttributeBuffer *stroke_attribute_buffer;
+ CoglAttribute **stroke_attributes;
+ unsigned int stroke_n_attributes;
+
+ /* This is used as an optimisation for when the path contains a
+ single contour specified using cogl2_path_rectangle. Cogl is more
+ optimised to handle rectangles than paths so we can detect this
+ case and divert to the journal or a rectangle clip. If it is TRUE
+ then the entire path can be described by calling
+ _cogl_path_get_bounds */
+ CoglBool is_rectangle;
+};
+
+void
+_cogl_add_path_to_stencil_buffer (CoglPath *path,
+ CoglBool merge,
+ CoglBool need_clear);
+
+void
+_cogl_path_get_bounds (CoglPath *path,
+ float *min_x,
+ float *min_y,
+ float *max_x,
+ float *max_y);
+
+CoglBool
+_cogl_path_is_rectangle (CoglPath *path);
+
+#endif /* __COGL_PATH_PRIVATE_H */
diff --git a/cogl/cogl-path/cogl-path-types.h b/cogl/cogl-path/cogl-path-types.h
new file mode 100644
index 000000000..53c06ee67
--- /dev/null
+++ b/cogl/cogl-path/cogl-path-types.h
@@ -0,0 +1,85 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008,2009,2013 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL_PATH_TYPES_H__
+#define __COGL_PATH_TYPES_H__
+
+#include <cogl/cogl-types.h>
+
+COGL_BEGIN_DECLS
+
+typedef struct _CoglPath CoglPath;
+
+/**
+ * CoglPathFillRule:
+ * @COGL_PATH_FILL_RULE_NON_ZERO: Each time the line crosses an edge of
+ * the path from left to right one is added to a counter and each time
+ * it crosses from right to left the counter is decremented. If the
+ * counter is non-zero then the point will be filled. See <xref
+ * linkend="fill-rule-non-zero"/>.
+ * @COGL_PATH_FILL_RULE_EVEN_ODD: If the line crosses an edge of the
+ * path an odd number of times then the point will filled, otherwise
+ * it won't. See <xref linkend="fill-rule-even-odd"/>.
+ *
+ * #CoglPathFillRule is used to determine how a path is filled. There
+ * are two options - 'non-zero' and 'even-odd'. To work out whether any
+ * point will be filled imagine drawing an infinetely long line in any
+ * direction from that point. The number of times and the direction
+ * that the edges of the path crosses this line determines whether the
+ * line is filled as described below. Any open sub paths are treated
+ * as if there was an extra line joining the first point and the last
+ * point.
+ *
+ * The default fill rule when creating a path is %COGL_PATH_FILL_RULE_EVEN_ODD.
+ *
+ * <figure id="fill-rule-non-zero">
+ * <title>Example of filling various paths using the non-zero rule</title>
+ * <graphic fileref="fill-rule-non-zero.png" format="PNG"/>
+ * </figure>
+ *
+ * <figure id="fill-rule-even-odd">
+ * <title>Example of filling various paths using the even-odd rule</title>
+ * <graphic fileref="fill-rule-even-odd.png" format="PNG"/>
+ * </figure>
+ *
+ * Since: 1.4
+ */
+typedef enum {
+ COGL_PATH_FILL_RULE_NON_ZERO,
+ COGL_PATH_FILL_RULE_EVEN_ODD
+} CoglPathFillRule;
+
+COGL_END_DECLS
+
+#endif /* __COGL_PATH_TYPES_H__ */
diff --git a/cogl/cogl-path/cogl-path.c b/cogl/cogl-path/cogl-path.c
new file mode 100644
index 000000000..2b4b3c683
--- /dev/null
+++ b/cogl/cogl-path/cogl-path.c
@@ -0,0 +1,1602 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2007,2008,2009,2010,2013 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Ivan Leben <ivan@openedhand.com>
+ * Øyvind Kolås <pippin@linux.intel.com>
+ * Neil Roberts <neil@linux.intel.com>
+ * Robert Bragg <robert@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include "cogl-util.h"
+#include "cogl-object.h"
+#include "cogl-context-private.h"
+#include "cogl-journal-private.h"
+#include "cogl-pipeline-private.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-primitive-private.h"
+#include "cogl-texture-private.h"
+#include "cogl-primitives-private.h"
+#include "cogl-private.h"
+#include "cogl-attribute-private.h"
+#include "cogl1-context.h"
+#include "tesselator/tesselator.h"
+
+#include "cogl-path/cogl-path.h"
+#include "cogl-path-private.h"
+#include "cogl-gtype-private.h"
+
+#include <string.h>
+#include <math.h>
+
+#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
+
+static void _cogl_path_free (CoglPath *path);
+
+static void _cogl_path_build_fill_attribute_buffer (CoglPath *path);
+static CoglPrimitive *_cogl_path_get_fill_primitive (CoglPath *path);
+static void _cogl_path_build_stroke_attribute_buffer (CoglPath *path);
+
+COGL_OBJECT_DEFINE (Path, path);
+COGL_GTYPE_DEFINE_CLASS (Path, path);
+
+static void
+_cogl_path_data_clear_vbos (CoglPathData *data)
+{
+ int i;
+
+ if (data->fill_attribute_buffer)
+ {
+ cogl_object_unref (data->fill_attribute_buffer);
+ cogl_object_unref (data->fill_vbo_indices);
+
+ for (i = 0; i < COGL_PATH_N_ATTRIBUTES; i++)
+ cogl_object_unref (data->fill_attributes[i]);
+
+ data->fill_attribute_buffer = NULL;
+ }
+
+ if (data->fill_primitive)
+ {
+ cogl_object_unref (data->fill_primitive);
+ data->fill_primitive = NULL;
+ }
+
+ if (data->stroke_attribute_buffer)
+ {
+ cogl_object_unref (data->stroke_attribute_buffer);
+
+ for (i = 0; i < data->stroke_n_attributes; i++)
+ cogl_object_unref (data->stroke_attributes[i]);
+
+ g_free (data->stroke_attributes);
+
+ data->stroke_attribute_buffer = NULL;
+ }
+}
+
+static void
+_cogl_path_data_unref (CoglPathData *data)
+{
+ if (--data->ref_count <= 0)
+ {
+ _cogl_path_data_clear_vbos (data);
+
+ g_array_free (data->path_nodes, TRUE);
+
+ g_slice_free (CoglPathData, data);
+ }
+}
+
+static void
+_cogl_path_modify (CoglPath *path)
+{
+ /* This needs to be called whenever the path is about to be modified
+ to implement copy-on-write semantics */
+
+ /* If there is more than one path using the data then we need to
+ copy the data instead */
+ if (path->data->ref_count != 1)
+ {
+ CoglPathData *old_data = path->data;
+
+ path->data = g_slice_dup (CoglPathData, old_data);
+ path->data->path_nodes = g_array_new (FALSE, FALSE,
+ sizeof (CoglPathNode));
+ g_array_append_vals (path->data->path_nodes,
+ old_data->path_nodes->data,
+ old_data->path_nodes->len);
+
+ path->data->fill_attribute_buffer = NULL;
+ path->data->fill_primitive = NULL;
+ path->data->stroke_attribute_buffer = NULL;
+ path->data->ref_count = 1;
+
+ _cogl_path_data_unref (old_data);
+ }
+ else
+ /* The path is altered so the vbos will now be invalid */
+ _cogl_path_data_clear_vbos (path->data);
+}
+
+void
+cogl2_path_set_fill_rule (CoglPath *path,
+ CoglPathFillRule fill_rule)
+{
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ if (path->data->fill_rule != fill_rule)
+ {
+ _cogl_path_modify (path);
+
+ path->data->fill_rule = fill_rule;
+ }
+}
+
+CoglPathFillRule
+cogl2_path_get_fill_rule (CoglPath *path)
+{
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (path), COGL_PATH_FILL_RULE_NON_ZERO);
+
+ return path->data->fill_rule;
+}
+
+static void
+_cogl_path_add_node (CoglPath *path,
+ CoglBool new_sub_path,
+ float x,
+ float y)
+{
+ CoglPathNode new_node;
+ CoglPathData *data;
+
+ _cogl_path_modify (path);
+
+ data = path->data;
+
+ new_node.x = x;
+ new_node.y = y;
+ new_node.path_size = 0;
+
+ if (new_sub_path || data->path_nodes->len == 0)
+ data->last_path = data->path_nodes->len;
+
+ g_array_append_val (data->path_nodes, new_node);
+
+ g_array_index (data->path_nodes, CoglPathNode, data->last_path).path_size++;
+
+ if (data->path_nodes->len == 1)
+ {
+ data->path_nodes_min.x = data->path_nodes_max.x = x;
+ data->path_nodes_min.y = data->path_nodes_max.y = y;
+ }
+ else
+ {
+ if (x < data->path_nodes_min.x)
+ data->path_nodes_min.x = x;
+ if (x > data->path_nodes_max.x)
+ data->path_nodes_max.x = x;
+ if (y < data->path_nodes_min.y)
+ data->path_nodes_min.y = y;
+ if (y > data->path_nodes_max.y)
+ data->path_nodes_max.y = y;
+ }
+
+ /* Once the path nodes have been modified then we'll assume it's no
+ longer a rectangle. cogl2_path_rectangle will set this back to
+ TRUE if this has been called from there */
+ data->is_rectangle = FALSE;
+}
+
+static void
+_cogl_path_stroke_nodes (CoglPath *path,
+ CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline)
+{
+ CoglPathData *data;
+ CoglPipeline *copy = NULL;
+ unsigned int path_start;
+ int path_num = 0;
+ CoglPathNode *node;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+ _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
+ _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
+
+ data = path->data;
+
+ if (data->path_nodes->len == 0)
+ return;
+
+ if (cogl_pipeline_get_n_layers (pipeline) != 0)
+ {
+ copy = cogl_pipeline_copy (pipeline);
+ _cogl_pipeline_prune_to_n_layers (copy, 0);
+ pipeline = copy;
+ }
+
+ _cogl_path_build_stroke_attribute_buffer (path);
+
+ for (path_start = 0;
+ path_start < data->path_nodes->len;
+ path_start += node->path_size)
+ {
+ CoglPrimitive *primitive;
+
+ node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ primitive =
+ cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_LINE_STRIP,
+ node->path_size,
+ &data->stroke_attributes[path_num],
+ 1);
+ cogl_primitive_draw (primitive, framebuffer, pipeline);
+ cogl_object_unref (primitive);
+
+ path_num++;
+ }
+
+ if (copy)
+ cogl_object_unref (copy);
+}
+
+void
+_cogl_path_get_bounds (CoglPath *path,
+ float *min_x,
+ float *min_y,
+ float *max_x,
+ float *max_y)
+{
+ CoglPathData *data = path->data;
+
+ if (data->path_nodes->len == 0)
+ {
+ *min_x = 0.0f;
+ *min_y = 0.0f;
+ *max_x = 0.0f;
+ *max_y = 0.0f;
+ }
+ else
+ {
+ *min_x = data->path_nodes_min.x;
+ *min_y = data->path_nodes_min.y;
+ *max_x = data->path_nodes_max.x;
+ *max_y = data->path_nodes_max.y;
+ }
+}
+
+static void
+_cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path,
+ CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline)
+{
+ /* We need at least three stencil bits to combine clips */
+ if (_cogl_framebuffer_get_stencil_bits (framebuffer) >= 3)
+ {
+ static CoglBool seen_warning = FALSE;
+
+ if (!seen_warning)
+ {
+ g_warning ("Paths can not be filled using materials with "
+ "sliced textures unless there is a stencil "
+ "buffer");
+ seen_warning = TRUE;
+ }
+ }
+
+ cogl_framebuffer_push_path_clip (framebuffer, path);
+ cogl_framebuffer_draw_rectangle (framebuffer,
+ pipeline,
+ path->data->path_nodes_min.x,
+ path->data->path_nodes_min.y,
+ path->data->path_nodes_max.x,
+ path->data->path_nodes_max.y);
+ cogl_framebuffer_pop_clip (framebuffer);
+}
+
+static CoglBool
+validate_layer_cb (CoglPipelineLayer *layer, void *user_data)
+{
+ CoglBool *needs_fallback = user_data;
+ CoglTexture *texture = _cogl_pipeline_layer_get_texture (layer);
+
+ /* If any of the layers of the current pipeline contain sliced
+ * textures or textures with waste then it won't work to draw the
+ * path directly. Instead we fallback to pushing the path as a clip
+ * on the clip-stack and drawing the path's bounding rectangle
+ * instead.
+ */
+
+ if (texture != NULL && (cogl_texture_is_sliced (texture) ||
+ !_cogl_texture_can_hardware_repeat (texture)))
+ *needs_fallback = TRUE;
+
+ return !*needs_fallback;
+}
+
+static void
+_cogl_path_fill_nodes (CoglPath *path,
+ CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ CoglDrawFlags flags)
+{
+ if (path->data->path_nodes->len == 0)
+ return;
+
+ /* If the path is a simple rectangle then we can divert to using
+ cogl_framebuffer_draw_rectangle which should be faster because it
+ can go through the journal instead of uploading the geometry just
+ for two triangles */
+ if (path->data->is_rectangle && flags == 0)
+ {
+ float x_1, y_1, x_2, y_2;
+
+ _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
+ cogl_framebuffer_draw_rectangle (framebuffer,
+ pipeline,
+ x_1, y_1,
+ x_2, y_2);
+ }
+ else
+ {
+ CoglBool needs_fallback = FALSE;
+ CoglPrimitive *primitive;
+
+ _cogl_pipeline_foreach_layer_internal (pipeline,
+ validate_layer_cb,
+ &needs_fallback);
+ if (needs_fallback)
+ {
+ _cogl_path_fill_nodes_with_clipped_rectangle (path,
+ framebuffer,
+ pipeline);
+ return;
+ }
+
+ primitive = _cogl_path_get_fill_primitive (path);
+
+ _cogl_primitive_draw (primitive, framebuffer, pipeline, flags);
+ }
+}
+
+/* TODO: Update to the protoype used in the Cogl master branch.
+ * This is experimental API but not in sync with the cogl_path_fill()
+ * api in Cogl master which takes explicit framebuffer and pipeline
+ * arguments */
+void
+cogl2_path_fill (CoglPath *path)
+{
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ _cogl_path_fill_nodes (path,
+ cogl_get_draw_framebuffer (),
+ cogl_get_source (),
+ 0 /* flags */);
+}
+
+/* TODO: Update to the protoype used in the Cogl master branch.
+ * This is experimental API but not in sync with the cogl_path_fill()
+ * api in Cogl master which takes explicit framebuffer and pipeline
+ * arguments */
+void
+cogl2_path_stroke (CoglPath *path)
+{
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ if (path->data->path_nodes->len == 0)
+ return;
+
+ _cogl_path_stroke_nodes (path,
+ cogl_get_draw_framebuffer (),
+ cogl_get_source ());
+}
+
+void
+cogl2_path_move_to (CoglPath *path,
+ float x,
+ float y)
+{
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ _cogl_path_add_node (path, TRUE, x, y);
+
+ data = path->data;
+
+ data->path_start.x = x;
+ data->path_start.y = y;
+
+ data->path_pen = data->path_start;
+}
+
+void
+cogl2_path_rel_move_to (CoglPath *path,
+ float x,
+ float y)
+{
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ data = path->data;
+
+ cogl2_path_move_to (path,
+ data->path_pen.x + x,
+ data->path_pen.y + y);
+}
+
+void
+cogl2_path_line_to (CoglPath *path,
+ float x,
+ float y)
+{
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ _cogl_path_add_node (path, FALSE, x, y);
+
+ data = path->data;
+
+ data->path_pen.x = x;
+ data->path_pen.y = y;
+}
+
+void
+cogl2_path_rel_line_to (CoglPath *path,
+ float x,
+ float y)
+{
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ data = path->data;
+
+ cogl2_path_line_to (path,
+ data->path_pen.x + x,
+ data->path_pen.y + y);
+}
+
+void
+cogl2_path_close (CoglPath *path)
+{
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ _cogl_path_add_node (path, FALSE, path->data->path_start.x,
+ path->data->path_start.y);
+
+ path->data->path_pen = path->data->path_start;
+}
+
+void
+cogl2_path_line (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ cogl2_path_move_to (path, x_1, y_1);
+ cogl2_path_line_to (path, x_2, y_2);
+}
+
+void
+cogl2_path_polyline (CoglPath *path,
+ const float *coords,
+ int num_points)
+{
+ int c = 0;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ cogl2_path_move_to (path, coords[0], coords[1]);
+
+ for (c = 1; c < num_points; ++c)
+ cogl2_path_line_to (path, coords[2*c], coords[2*c+1]);
+}
+
+void
+cogl2_path_polygon (CoglPath *path,
+ const float *coords,
+ int num_points)
+{
+ cogl2_path_polyline (path, coords, num_points);
+ cogl2_path_close (path);
+}
+
+void
+cogl2_path_rectangle (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ CoglBool is_rectangle;
+
+ /* If the path was previously empty and the rectangle isn't mirrored
+ then we'll record that this is a simple rectangle path so that we
+ can optimise it */
+ is_rectangle = (path->data->path_nodes->len == 0 &&
+ x_2 >= x_1 &&
+ y_2 >= y_1);
+
+ cogl2_path_move_to (path, x_1, y_1);
+ cogl2_path_line_to (path, x_2, y_1);
+ cogl2_path_line_to (path, x_2, y_2);
+ cogl2_path_line_to (path, x_1, y_2);
+ cogl2_path_close (path);
+
+ path->data->is_rectangle = is_rectangle;
+}
+
+CoglBool
+_cogl_path_is_rectangle (CoglPath *path)
+{
+ return path->data->is_rectangle;
+}
+
+static void
+_cogl_path_arc (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2,
+ float angle_step,
+ unsigned int move_first)
+{
+ float a = 0x0;
+ float cosa = 0x0;
+ float sina = 0x0;
+ float px = 0x0;
+ float py = 0x0;
+
+ /* Fix invalid angles */
+
+ if (angle_1 == angle_2 || angle_step == 0x0)
+ return;
+
+ if (angle_step < 0x0)
+ angle_step = -angle_step;
+
+ /* Walk the arc by given step */
+
+ a = angle_1;
+ while (a != angle_2)
+ {
+ cosa = cosf (a * (G_PI/180.0));
+ sina = sinf (a * (G_PI/180.0));
+
+ px = center_x + (cosa * radius_x);
+ py = center_y + (sina * radius_y);
+
+ if (a == angle_1 && move_first)
+ cogl2_path_move_to (path, px, py);
+ else
+ cogl2_path_line_to (path, px, py);
+
+ if (G_LIKELY (angle_2 > angle_1))
+ {
+ a += angle_step;
+ if (a > angle_2)
+ a = angle_2;
+ }
+ else
+ {
+ a -= angle_step;
+ if (a < angle_2)
+ a = angle_2;
+ }
+ }
+
+ /* Make sure the final point is drawn */
+
+ cosa = cosf (angle_2 * (G_PI/180.0));
+ sina = sinf (angle_2 * (G_PI/180.0));
+
+ px = center_x + (cosa * radius_x);
+ py = center_y + (sina * radius_y);
+
+ cogl2_path_line_to (path, px, py);
+}
+
+void
+cogl2_path_arc (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2)
+{
+ float angle_step = 10;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ /* it is documented that a move to is needed to create a freestanding
+ * arc
+ */
+ _cogl_path_arc (path,
+ center_x, center_y,
+ radius_x, radius_y,
+ angle_1, angle_2,
+ angle_step, 0 /* no move */);
+}
+
+
+static void
+_cogl_path_rel_arc (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2,
+ float angle_step)
+{
+ CoglPathData *data;
+
+ data = path->data;
+
+ _cogl_path_arc (path,
+ data->path_pen.x + center_x,
+ data->path_pen.y + center_y,
+ radius_x, radius_y,
+ angle_1, angle_2,
+ angle_step, 0 /* no move */);
+}
+
+void
+cogl2_path_ellipse (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y)
+{
+ float angle_step = 10;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ /* FIXME: if shows to be slow might be optimized
+ * by mirroring just a quarter of it */
+
+ _cogl_path_arc (path,
+ center_x, center_y,
+ radius_x, radius_y,
+ 0, 360,
+ angle_step, 1 /* move first */);
+
+ cogl2_path_close (path);
+}
+
+void
+cogl2_path_round_rectangle (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float radius,
+ float arc_step)
+{
+ float inner_width = x_2 - x_1 - radius * 2;
+ float inner_height = y_2 - y_1 - radius * 2;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ cogl2_path_move_to (path, x_1, y_1 + radius);
+ _cogl_path_rel_arc (path,
+ radius, 0,
+ radius, radius,
+ 180,
+ 270,
+ arc_step);
+
+ cogl2_path_line_to (path,
+ path->data->path_pen.x + inner_width,
+ path->data->path_pen.y);
+ _cogl_path_rel_arc (path,
+ 0, radius,
+ radius, radius,
+ -90,
+ 0,
+ arc_step);
+
+ cogl2_path_line_to (path,
+ path->data->path_pen.x,
+ path->data->path_pen.y + inner_height);
+
+ _cogl_path_rel_arc (path,
+ -radius, 0,
+ radius, radius,
+ 0,
+ 90,
+ arc_step);
+
+ cogl2_path_line_to (path,
+ path->data->path_pen.x - inner_width,
+ path->data->path_pen.y);
+ _cogl_path_rel_arc (path,
+ 0, -radius,
+ radius, radius,
+ 90,
+ 180,
+ arc_step);
+
+ cogl2_path_close (path);
+}
+
+static void
+_cogl_path_bezier3_sub (CoglPath *path,
+ CoglBezCubic *cubic)
+{
+ CoglBezCubic cubics[_COGL_MAX_BEZ_RECURSE_DEPTH];
+ CoglBezCubic *cleft;
+ CoglBezCubic *cright;
+ CoglBezCubic *c;
+ floatVec2 dif1;
+ floatVec2 dif2;
+ floatVec2 mm;
+ floatVec2 c1;
+ floatVec2 c2;
+ floatVec2 c3;
+ floatVec2 c4;
+ floatVec2 c5;
+ int cindex;
+
+ /* Put first curve on stack */
+ cubics[0] = *cubic;
+ cindex = 0;
+
+ while (cindex >= 0)
+ {
+ c = &cubics[cindex];
+
+
+ /* Calculate distance of control points from their
+ * counterparts on the line between end points */
+ dif1.x = (c->p2.x * 3) - (c->p1.x * 2) - c->p4.x;
+ dif1.y = (c->p2.y * 3) - (c->p1.y * 2) - c->p4.y;
+ dif2.x = (c->p3.x * 3) - (c->p4.x * 2) - c->p1.x;
+ dif2.y = (c->p3.y * 3) - (c->p4.y * 2) - c->p1.y;
+
+ if (dif1.x < 0)
+ dif1.x = -dif1.x;
+ if (dif1.y < 0)
+ dif1.y = -dif1.y;
+ if (dif2.x < 0)
+ dif2.x = -dif2.x;
+ if (dif2.y < 0)
+ dif2.y = -dif2.y;
+
+
+ /* Pick the greatest of two distances */
+ if (dif1.x < dif2.x) dif1.x = dif2.x;
+ if (dif1.y < dif2.y) dif1.y = dif2.y;
+
+ /* Cancel if the curve is flat enough */
+ if (dif1.x + dif1.y <= 1.0 ||
+ cindex == _COGL_MAX_BEZ_RECURSE_DEPTH-1)
+ {
+ /* Add subdivision point (skip last) */
+ if (cindex == 0)
+ return;
+
+ _cogl_path_add_node (path, FALSE, c->p4.x, c->p4.y);
+
+ --cindex;
+
+ continue;
+ }
+
+ /* Left recursion goes on top of stack! */
+ cright = c; cleft = &cubics[++cindex];
+
+ /* Subdivide into 2 sub-curves */
+ c1.x = ((c->p1.x + c->p2.x) / 2);
+ c1.y = ((c->p1.y + c->p2.y) / 2);
+ mm.x = ((c->p2.x + c->p3.x) / 2);
+ mm.y = ((c->p2.y + c->p3.y) / 2);
+ c5.x = ((c->p3.x + c->p4.x) / 2);
+ c5.y = ((c->p3.y + c->p4.y) / 2);
+
+ c2.x = ((c1.x + mm.x) / 2);
+ c2.y = ((c1.y + mm.y) / 2);
+ c4.x = ((mm.x + c5.x) / 2);
+ c4.y = ((mm.y + c5.y) / 2);
+
+ c3.x = ((c2.x + c4.x) / 2);
+ c3.y = ((c2.y + c4.y) / 2);
+
+ /* Add left recursion to stack */
+ cleft->p1 = c->p1;
+ cleft->p2 = c1;
+ cleft->p3 = c2;
+ cleft->p4 = c3;
+
+ /* Add right recursion to stack */
+ cright->p1 = c3;
+ cright->p2 = c4;
+ cright->p3 = c5;
+ cright->p4 = c->p4;
+ }
+}
+
+void
+cogl2_path_curve_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3)
+{
+ CoglBezCubic cubic;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ /* Prepare cubic curve */
+ cubic.p1 = path->data->path_pen;
+ cubic.p2.x = x_1;
+ cubic.p2.y = y_1;
+ cubic.p3.x = x_2;
+ cubic.p3.y = y_2;
+ cubic.p4.x = x_3;
+ cubic.p4.y = y_3;
+
+ /* Run subdivision */
+ _cogl_path_bezier3_sub (path, &cubic);
+
+ /* Add last point */
+ _cogl_path_add_node (path, FALSE, cubic.p4.x, cubic.p4.y);
+ path->data->path_pen = cubic.p4;
+}
+
+void
+cogl2_path_rel_curve_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3)
+{
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ data = path->data;
+
+ cogl2_path_curve_to (path,
+ data->path_pen.x + x_1,
+ data->path_pen.y + y_1,
+ data->path_pen.x + x_2,
+ data->path_pen.y + y_2,
+ data->path_pen.x + x_3,
+ data->path_pen.y + y_3);
+}
+
+CoglPath *
+cogl2_path_new (void)
+{
+ CoglPath *path;
+ CoglPathData *data;
+
+ _COGL_GET_CONTEXT (ctx, NULL);
+
+ path = g_slice_new (CoglPath);
+ data = path->data = g_slice_new (CoglPathData);
+
+ data->ref_count = 1;
+ data->context = ctx;
+ data->fill_rule = COGL_PATH_FILL_RULE_EVEN_ODD;
+ data->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
+ data->last_path = 0;
+ data->fill_attribute_buffer = NULL;
+ data->stroke_attribute_buffer = NULL;
+ data->fill_primitive = NULL;
+ data->is_rectangle = FALSE;
+
+ return _cogl_path_object_new (path);
+}
+
+CoglPath *
+cogl_path_copy (CoglPath *old_path)
+{
+ CoglPath *new_path;
+
+ _COGL_RETURN_VAL_IF_FAIL (cogl_is_path (old_path), NULL);
+
+ new_path = g_slice_new (CoglPath);
+ new_path->data = old_path->data;
+ new_path->data->ref_count++;
+
+ return _cogl_path_object_new (new_path);
+}
+
+static void
+_cogl_path_free (CoglPath *path)
+{
+ _cogl_path_data_unref (path->data);
+ g_slice_free (CoglPath, path);
+}
+
+/* If second order beziers were needed the following code could
+ * be re-enabled:
+ */
+#if 0
+
+static void
+_cogl_path_bezier2_sub (CoglPath *path,
+ CoglBezQuad *quad)
+{
+ CoglBezQuad quads[_COGL_MAX_BEZ_RECURSE_DEPTH];
+ CoglBezQuad *qleft;
+ CoglBezQuad *qright;
+ CoglBezQuad *q;
+ floatVec2 mid;
+ floatVec2 dif;
+ floatVec2 c1;
+ floatVec2 c2;
+ floatVec2 c3;
+ int qindex;
+
+ /* Put first curve on stack */
+ quads[0] = *quad;
+ qindex = 0;
+
+ /* While stack is not empty */
+ while (qindex >= 0)
+ {
+
+ q = &quads[qindex];
+
+ /* Calculate distance of control point from its
+ * counterpart on the line between end points */
+ mid.x = ((q->p1.x + q->p3.x) / 2);
+ mid.y = ((q->p1.y + q->p3.y) / 2);
+ dif.x = (q->p2.x - mid.x);
+ dif.y = (q->p2.y - mid.y);
+ if (dif.x < 0) dif.x = -dif.x;
+ if (dif.y < 0) dif.y = -dif.y;
+
+ /* Cancel if the curve is flat enough */
+ if (dif.x + dif.y <= 1.0 ||
+ qindex == _COGL_MAX_BEZ_RECURSE_DEPTH - 1)
+ {
+ /* Add subdivision point (skip last) */
+ if (qindex == 0) return;
+ _cogl_path_add_node (path, FALSE, q->p3.x, q->p3.y);
+ --qindex; continue;
+ }
+
+ /* Left recursion goes on top of stack! */
+ qright = q; qleft = &quads[++qindex];
+
+ /* Subdivide into 2 sub-curves */
+ c1.x = ((q->p1.x + q->p2.x) / 2);
+ c1.y = ((q->p1.y + q->p2.y) / 2);
+ c3.x = ((q->p2.x + q->p3.x) / 2);
+ c3.y = ((q->p2.y + q->p3.y) / 2);
+ c2.x = ((c1.x + c3.x) / 2);
+ c2.y = ((c1.y + c3.y) / 2);
+
+ /* Add left recursion onto stack */
+ qleft->p1 = q->p1;
+ qleft->p2 = c1;
+ qleft->p3 = c2;
+
+ /* Add right recursion onto stack */
+ qright->p1 = c2;
+ qright->p2 = c3;
+ qright->p3 = q->p3;
+ }
+}
+
+void
+cogl_path_curve2_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ CoglBezQuad quad;
+
+ /* Prepare quadratic curve */
+ quad.p1 = path->data->path_pen;
+ quad.p2.x = x_1;
+ quad.p2.y = y_1;
+ quad.p3.x = x_2;
+ quad.p3.y = y_2;
+
+ /* Run subdivision */
+ _cogl_path_bezier2_sub (&quad);
+
+ /* Add last point */
+ _cogl_path_add_node (FALSE, quad.p3.x, quad.p3.y);
+ path->data->path_pen = quad.p3;
+}
+
+void
+cogl_rel_curve2_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ CoglPathData *data;
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ data = path->data;
+
+ cogl_path_curve2_to (data->path_pen.x + x_1,
+ data->path_pen.y + y_1,
+ data->path_pen.x + x_2,
+ data->path_pen.y + y_2);
+}
+
+#endif
+
+typedef struct _CoglPathTesselator CoglPathTesselator;
+typedef struct _CoglPathTesselatorVertex CoglPathTesselatorVertex;
+
+struct _CoglPathTesselator
+{
+ GLUtesselator *glu_tess;
+ GLenum primitive_type;
+ int vertex_number;
+ /* Array of CoglPathTesselatorVertex. This needs to grow when the
+ combine callback is called */
+ GArray *vertices;
+ /* Array of integers for the indices into the vertices array. Each
+ element will either be uint8_t, uint16_t or uint32_t depending on
+ the number of vertices */
+ GArray *indices;
+ CoglIndicesType indices_type;
+ /* Indices used to split fans and strips */
+ int index_a, index_b;
+};
+
+struct _CoglPathTesselatorVertex
+{
+ float x, y, s, t;
+};
+
+static void
+_cogl_path_tesselator_begin (GLenum type,
+ CoglPathTesselator *tess)
+{
+ g_assert (type == GL_TRIANGLES ||
+ type == GL_TRIANGLE_FAN ||
+ type == GL_TRIANGLE_STRIP);
+
+ tess->primitive_type = type;
+ tess->vertex_number = 0;
+}
+
+static CoglIndicesType
+_cogl_path_tesselator_get_indices_type_for_size (int n_vertices)
+{
+ if (n_vertices <= 256)
+ return COGL_INDICES_TYPE_UNSIGNED_BYTE;
+ else if (n_vertices <= 65536)
+ return COGL_INDICES_TYPE_UNSIGNED_SHORT;
+ else
+ return COGL_INDICES_TYPE_UNSIGNED_INT;
+}
+
+static void
+_cogl_path_tesselator_allocate_indices_array (CoglPathTesselator *tess)
+{
+ switch (tess->indices_type)
+ {
+ case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+ tess->indices = g_array_new (FALSE, FALSE, sizeof (uint8_t));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+ tess->indices = g_array_new (FALSE, FALSE, sizeof (uint16_t));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_INT:
+ tess->indices = g_array_new (FALSE, FALSE, sizeof (uint32_t));
+ break;
+ }
+}
+
+static void
+_cogl_path_tesselator_add_index (CoglPathTesselator *tess, int vertex_index)
+{
+ switch (tess->indices_type)
+ {
+ case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+ {
+ uint8_t val = vertex_index;
+ g_array_append_val (tess->indices, val);
+ }
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+ {
+ uint16_t val = vertex_index;
+ g_array_append_val (tess->indices, val);
+ }
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_INT:
+ {
+ uint32_t val = vertex_index;
+ g_array_append_val (tess->indices, val);
+ }
+ break;
+ }
+}
+
+static void
+_cogl_path_tesselator_vertex (void *vertex_data,
+ CoglPathTesselator *tess)
+{
+ int vertex_index;
+
+ vertex_index = GPOINTER_TO_INT (vertex_data);
+
+ /* This tries to convert all of the primitives into GL_TRIANGLES
+ with indices to share vertices */
+ switch (tess->primitive_type)
+ {
+ case GL_TRIANGLES:
+ /* Directly use the vertex */
+ _cogl_path_tesselator_add_index (tess, vertex_index);
+ break;
+
+ case GL_TRIANGLE_FAN:
+ if (tess->vertex_number == 0)
+ tess->index_a = vertex_index;
+ else if (tess->vertex_number == 1)
+ tess->index_b = vertex_index;
+ else
+ {
+ /* Create a triangle with the first vertex, the previous
+ vertex and this vertex */
+ _cogl_path_tesselator_add_index (tess, tess->index_a);
+ _cogl_path_tesselator_add_index (tess, tess->index_b);
+ _cogl_path_tesselator_add_index (tess, vertex_index);
+ /* Next time we will use this vertex as the previous
+ vertex */
+ tess->index_b = vertex_index;
+ }
+ break;
+
+ case GL_TRIANGLE_STRIP:
+ if (tess->vertex_number == 0)
+ tess->index_a = vertex_index;
+ else if (tess->vertex_number == 1)
+ tess->index_b = vertex_index;
+ else
+ {
+ _cogl_path_tesselator_add_index (tess, tess->index_a);
+ _cogl_path_tesselator_add_index (tess, tess->index_b);
+ _cogl_path_tesselator_add_index (tess, vertex_index);
+ if (tess->vertex_number & 1)
+ tess->index_b = vertex_index;
+ else
+ tess->index_a = vertex_index;
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ tess->vertex_number++;
+}
+
+static void
+_cogl_path_tesselator_end (CoglPathTesselator *tess)
+{
+ tess->primitive_type = GL_FALSE;
+}
+
+static void
+_cogl_path_tesselator_combine (double coords[3],
+ void *vertex_data[4],
+ float weight[4],
+ void **out_data,
+ CoglPathTesselator *tess)
+{
+ CoglPathTesselatorVertex *vertex;
+ CoglIndicesType new_indices_type;
+ int i;
+
+ /* Add a new vertex to the array */
+ g_array_set_size (tess->vertices, tess->vertices->len + 1);
+ vertex = &g_array_index (tess->vertices,
+ CoglPathTesselatorVertex,
+ tess->vertices->len - 1);
+ /* The data is just the index to the vertex */
+ *out_data = GINT_TO_POINTER (tess->vertices->len - 1);
+ /* Set the coordinates of the new vertex */
+ vertex->x = coords[0];
+ vertex->y = coords[1];
+ /* Generate the texture coordinates as the weighted average of the
+ four incoming coordinates */
+ vertex->s = 0.0f;
+ vertex->t = 0.0f;
+ for (i = 0; i < 4; i++)
+ {
+ CoglPathTesselatorVertex *old_vertex =
+ &g_array_index (tess->vertices, CoglPathTesselatorVertex,
+ GPOINTER_TO_INT (vertex_data[i]));
+ vertex->s += old_vertex->s * weight[i];
+ vertex->t += old_vertex->t * weight[i];
+ }
+
+ /* Check if we've reached the limit for the data type of our indices */
+ new_indices_type =
+ _cogl_path_tesselator_get_indices_type_for_size (tess->vertices->len);
+ if (new_indices_type != tess->indices_type)
+ {
+ CoglIndicesType old_indices_type = new_indices_type;
+ GArray *old_vertices = tess->indices;
+
+ /* Copy the indices to an array of the new type */
+ tess->indices_type = new_indices_type;
+ _cogl_path_tesselator_allocate_indices_array (tess);
+
+ switch (old_indices_type)
+ {
+ case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+ for (i = 0; i < old_vertices->len; i++)
+ _cogl_path_tesselator_add_index (tess,
+ g_array_index (old_vertices,
+ uint8_t, i));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+ for (i = 0; i < old_vertices->len; i++)
+ _cogl_path_tesselator_add_index (tess,
+ g_array_index (old_vertices,
+ uint16_t, i));
+ break;
+
+ case COGL_INDICES_TYPE_UNSIGNED_INT:
+ for (i = 0; i < old_vertices->len; i++)
+ _cogl_path_tesselator_add_index (tess,
+ g_array_index (old_vertices,
+ uint32_t, i));
+ break;
+ }
+
+ g_array_free (old_vertices, TRUE);
+ }
+}
+
+static void
+_cogl_path_build_fill_attribute_buffer (CoglPath *path)
+{
+ CoglPathTesselator tess;
+ unsigned int path_start = 0;
+ CoglPathData *data = path->data;
+ int i;
+
+ /* If we've already got a vbo then we don't need to do anything */
+ if (data->fill_attribute_buffer)
+ return;
+
+ tess.primitive_type = FALSE;
+
+ /* Generate a vertex for each point on the path */
+ tess.vertices = g_array_new (FALSE, FALSE, sizeof (CoglPathTesselatorVertex));
+ g_array_set_size (tess.vertices, data->path_nodes->len);
+ for (i = 0; i < data->path_nodes->len; i++)
+ {
+ CoglPathNode *node =
+ &g_array_index (data->path_nodes, CoglPathNode, i);
+ CoglPathTesselatorVertex *vertex =
+ &g_array_index (tess.vertices, CoglPathTesselatorVertex, i);
+
+ vertex->x = node->x;
+ vertex->y = node->y;
+
+ /* Add texture coordinates so that a texture would be drawn to
+ fit the bounding box of the path and then cropped by the
+ path */
+ if (data->path_nodes_min.x == data->path_nodes_max.x)
+ vertex->s = 0.0f;
+ else
+ vertex->s = ((node->x - data->path_nodes_min.x)
+ / (data->path_nodes_max.x - data->path_nodes_min.x));
+ if (data->path_nodes_min.y == data->path_nodes_max.y)
+ vertex->t = 0.0f;
+ else
+ vertex->t = ((node->y - data->path_nodes_min.y)
+ / (data->path_nodes_max.y - data->path_nodes_min.y));
+ }
+
+ tess.indices_type =
+ _cogl_path_tesselator_get_indices_type_for_size (data->path_nodes->len);
+ _cogl_path_tesselator_allocate_indices_array (&tess);
+
+ tess.glu_tess = gluNewTess ();
+
+ if (data->fill_rule == COGL_PATH_FILL_RULE_EVEN_ODD)
+ gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
+ GLU_TESS_WINDING_ODD);
+ else
+ gluTessProperty (tess.glu_tess, GLU_TESS_WINDING_RULE,
+ GLU_TESS_WINDING_NONZERO);
+
+ /* All vertices are on the xy-plane */
+ gluTessNormal (tess.glu_tess, 0.0, 0.0, 1.0);
+
+ gluTessCallback (tess.glu_tess, GLU_TESS_BEGIN_DATA,
+ _cogl_path_tesselator_begin);
+ gluTessCallback (tess.glu_tess, GLU_TESS_VERTEX_DATA,
+ _cogl_path_tesselator_vertex);
+ gluTessCallback (tess.glu_tess, GLU_TESS_END_DATA,
+ _cogl_path_tesselator_end);
+ gluTessCallback (tess.glu_tess, GLU_TESS_COMBINE_DATA,
+ _cogl_path_tesselator_combine);
+
+ gluTessBeginPolygon (tess.glu_tess, &tess);
+
+ while (path_start < data->path_nodes->len)
+ {
+ CoglPathNode *node =
+ &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ gluTessBeginContour (tess.glu_tess);
+
+ for (i = 0; i < node->path_size; i++)
+ {
+ double vertex[3] = { node[i].x, node[i].y, 0.0 };
+ gluTessVertex (tess.glu_tess, vertex,
+ GINT_TO_POINTER (i + path_start));
+ }
+
+ gluTessEndContour (tess.glu_tess);
+
+ path_start += node->path_size;
+ }
+
+ gluTessEndPolygon (tess.glu_tess);
+
+ gluDeleteTess (tess.glu_tess);
+
+ data->fill_attribute_buffer =
+ cogl_attribute_buffer_new (data->context,
+ sizeof (CoglPathTesselatorVertex) *
+ tess.vertices->len,
+ tess.vertices->data);
+ g_array_free (tess.vertices, TRUE);
+
+ data->fill_attributes[0] =
+ cogl_attribute_new (data->fill_attribute_buffer,
+ "cogl_position_in",
+ sizeof (CoglPathTesselatorVertex),
+ G_STRUCT_OFFSET (CoglPathTesselatorVertex, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ data->fill_attributes[1] =
+ cogl_attribute_new (data->fill_attribute_buffer,
+ "cogl_tex_coord0_in",
+ sizeof (CoglPathTesselatorVertex),
+ G_STRUCT_OFFSET (CoglPathTesselatorVertex, s),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+
+ data->fill_vbo_indices = cogl_indices_new (data->context,
+ tess.indices_type,
+ tess.indices->data,
+ tess.indices->len);
+ data->fill_vbo_n_indices = tess.indices->len;
+ g_array_free (tess.indices, TRUE);
+}
+
+static CoglPrimitive *
+_cogl_path_get_fill_primitive (CoglPath *path)
+{
+ if (path->data->fill_primitive)
+ return path->data->fill_primitive;
+
+ _cogl_path_build_fill_attribute_buffer (path);
+
+ path->data->fill_primitive =
+ cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ path->data->fill_vbo_n_indices,
+ path->data->fill_attributes,
+ COGL_PATH_N_ATTRIBUTES);
+ cogl_primitive_set_indices (path->data->fill_primitive,
+ path->data->fill_vbo_indices,
+ path->data->fill_vbo_n_indices);
+
+ return path->data->fill_primitive;
+}
+
+static CoglClipStack *
+_cogl_clip_stack_push_from_path (CoglClipStack *stack,
+ CoglPath *path,
+ CoglMatrixEntry *modelview_entry,
+ CoglMatrixEntry *projection_entry,
+ const float *viewport)
+{
+ float x_1, y_1, x_2, y_2;
+
+ _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
+
+ /* If the path is a simple rectangle then we can divert to pushing a
+ rectangle clip instead which usually won't involve the stencil
+ buffer */
+ if (_cogl_path_is_rectangle (path))
+ return _cogl_clip_stack_push_rectangle (stack,
+ x_1, y_1,
+ x_2, y_2,
+ modelview_entry,
+ projection_entry,
+ viewport);
+ else
+ {
+ CoglPrimitive *primitive = _cogl_path_get_fill_primitive (path);
+
+ return _cogl_clip_stack_push_primitive (stack,
+ primitive,
+ x_1, y_1, x_2, y_2,
+ modelview_entry,
+ projection_entry,
+ viewport);
+ }
+}
+
+void
+cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
+ CoglPath *path)
+{
+ CoglMatrixEntry *modelview_entry =
+ _cogl_framebuffer_get_modelview_entry (framebuffer);
+ CoglMatrixEntry *projection_entry =
+ _cogl_framebuffer_get_projection_entry (framebuffer);
+ /* XXX: It would be nicer if we stored the private viewport as a
+ * vec4 so we could avoid this redundant copy. */
+ float viewport[] = {
+ framebuffer->viewport_x,
+ framebuffer->viewport_y,
+ framebuffer->viewport_width,
+ framebuffer->viewport_height
+ };
+
+ framebuffer->clip_stack =
+ _cogl_clip_stack_push_from_path (framebuffer->clip_stack,
+ path,
+ modelview_entry,
+ projection_entry,
+ viewport);
+
+ if (framebuffer->context->current_draw_buffer == framebuffer)
+ framebuffer->context->current_draw_buffer_changes |=
+ COGL_FRAMEBUFFER_STATE_CLIP;
+}
+
+/* XXX: deprecated */
+void
+cogl_clip_push_from_path (CoglPath *path)
+{
+ cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (), path);
+}
+
+static void
+_cogl_path_build_stroke_attribute_buffer (CoglPath *path)
+{
+ CoglPathData *data = path->data;
+ CoglBuffer *buffer;
+ unsigned int n_attributes = 0;
+ unsigned int path_start;
+ CoglPathNode *node;
+ floatVec2 *buffer_p;
+ unsigned int i;
+
+ /* If we've already got a cached vbo then we don't need to do anything */
+ if (data->stroke_attribute_buffer)
+ return;
+
+ data->stroke_attribute_buffer =
+ cogl_attribute_buffer_new_with_size (data->context,
+ data->path_nodes->len *
+ sizeof (floatVec2));
+
+ buffer = COGL_BUFFER (data->stroke_attribute_buffer);
+ buffer_p = _cogl_buffer_map_for_fill_or_fallback (buffer);
+
+ /* Copy the vertices in and count the number of sub paths. Each sub
+ path will form a separate attribute so we can paint the disjoint
+ line strips */
+ for (path_start = 0;
+ path_start < data->path_nodes->len;
+ path_start += node->path_size)
+ {
+ node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ for (i = 0; i < node->path_size; i++)
+ {
+ buffer_p[path_start + i].x = node[i].x;
+ buffer_p[path_start + i].y = node[i].y;
+ }
+
+ n_attributes++;
+ }
+
+ _cogl_buffer_unmap_for_fill_or_fallback (buffer);
+
+ data->stroke_attributes = g_new (CoglAttribute *, n_attributes);
+
+ /* Now we can loop the sub paths again to create the attributes */
+ for (i = 0, path_start = 0;
+ path_start < data->path_nodes->len;
+ i++, path_start += node->path_size)
+ {
+ node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
+
+ data->stroke_attributes[i] =
+ cogl_attribute_new (data->stroke_attribute_buffer,
+ "cogl_position_in",
+ sizeof (floatVec2),
+ path_start * sizeof (floatVec2),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ }
+
+ data->stroke_n_attributes = n_attributes;
+}
+
+/* XXX: deprecated */
+void
+cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ CoglPath *path)
+{
+ _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
+ _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ _cogl_path_fill_nodes (path, framebuffer, pipeline, 0 /* flags */);
+}
+
+/* XXX: deprecated */
+void
+cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ CoglPath *path)
+{
+ _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
+ _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ _cogl_path_stroke_nodes (path, framebuffer, pipeline);
+}
diff --git a/cogl/cogl-path/cogl-path.h b/cogl/cogl-path/cogl-path.h
new file mode 100644
index 000000000..4991bbe67
--- /dev/null
+++ b/cogl/cogl-path/cogl-path.h
@@ -0,0 +1,68 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008,2009,2013 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+#ifndef __COGL_PATH_H__
+#define __COGL_PATH_H__
+
+/**
+ * SECTION:cogl-paths
+ * @short_description: Functions for constructing and drawing 2D paths.
+ *
+ * There are two levels on which drawing with cogl-paths can be used.
+ * The highest level functions construct various simple primitive
+ * shapes to be either filled or stroked. Using a lower-level set of
+ * functions more complex and arbitrary paths can be constructed by
+ * concatenating straight line, bezier curve and arc segments.
+ *
+ * When constructing arbitrary paths, the current pen location is
+ * initialized using the move_to command. The subsequent path segments
+ * implicitly use the last pen location as their first vertex and move
+ * the pen location to the last vertex they produce at the end. Also
+ * there are special versions of functions that allow specifying the
+ * vertices of the path segments relative to the last pen location
+ * rather then in the absolute coordinates.
+ */
+
+#include <cogl/cogl-defines.h>
+
+#ifdef COGL_HAS_GTYPE_SUPPORT
+#include <cogl-path/cogl-path-enum-types.h>
+#endif
+
+#include <cogl-path/cogl-path-types.h>
+
+#ifdef COGL_ENABLE_EXPERIMENTAL_2_0_API
+#include <cogl-path/cogl2-path-functions.h>
+#else
+#include <cogl-path/cogl1-path-functions.h>
+#endif
+
+#endif /* __COGL_PATH_H__ */
+
diff --git a/cogl/cogl-path/cogl-path.symbols b/cogl/cogl-path/cogl-path.symbols
new file mode 100644
index 000000000..b643ec0cd
--- /dev/null
+++ b/cogl/cogl-path/cogl-path.symbols
@@ -0,0 +1,59 @@
+/* cogl1-path-functions.h */
+cogl_clip_push_from_path
+cogl_clip_push_from_path_preserve
+cogl_get_path
+cogl_is_path
+cogl_path_arc
+cogl_path_close
+cogl_path_copy
+cogl_path_curve_to
+cogl_path_ellipse
+cogl_path_fill
+cogl_path_fill_preserve
+cogl_path_get_fill_rule
+#ifdef COGL_HAS_GTYPE_SUPPORT
+cogl_path_get_gtype
+#endif
+cogl_path_line
+cogl_path_line_to
+cogl_path_move_to
+cogl_path_new
+cogl_path_polygon
+cogl_path_polyline
+cogl_path_rectangle
+cogl_path_rel_curve_to
+cogl_path_rel_line_to
+cogl_path_rel_move_to
+cogl_path_round_rectangle
+cogl_path_set_fill_rule
+cogl_path_stroke
+cogl_path_stroke_preserve
+cogl_set_path
+
+/* cogl2-path-functions.h */
+cogl_framebuffer_fill_path
+cogl_framebuffer_push_path_clip
+cogl_framebuffer_stroke_path
+cogl2_clip_push_from_path
+cogl2_path_arc
+cogl2_path_close
+cogl2_path_curve_to
+cogl2_path_ellipse
+cogl2_path_fill
+cogl2_path_get_fill_rule
+cogl2_path_line
+cogl2_path_line_to
+cogl2_path_move_to
+cogl2_path_new
+cogl2_path_polygon
+cogl2_path_polyline
+cogl2_path_rectangle
+cogl2_path_rel_curve_to
+cogl2_path_rel_line_to
+cogl2_path_rel_move_to
+cogl2_path_round_rectangle
+cogl2_path_set_fill_rule
+cogl2_path_stroke
+
+/* cogl-path-enums.h-contents may change as header is generated */
+cogl_path_fill_rule_get_type
diff --git a/cogl/cogl-path/cogl1-path-functions.h b/cogl/cogl-path/cogl1-path-functions.h
new file mode 100644
index 000000000..18315ab8a
--- /dev/null
+++ b/cogl/cogl-path/cogl1-path-functions.h
@@ -0,0 +1,467 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008,2009,2012 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL_PATH_FUNCTIONS_H__
+#define __COGL_PATH_FUNCTIONS_H__
+
+/* The functions are declared separately because cogl-path.c needs to
+ get the function declarations from the old 1.0 API without
+ colliding with the enum declarations from the 2.0 API */
+
+#include <cogl/cogl-types.h>
+
+COGL_BEGIN_DECLS
+
+/**
+ * cogl_is_path:
+ * @handle: A CoglHandle
+ *
+ * Gets whether the given handle references an existing path object.
+ *
+ * Return value: %TRUE if the handle references a #CoglPath,
+ * %FALSE otherwise
+ */
+CoglBool
+cogl_is_path (CoglHandle handle);
+
+/**
+ * cogl_path_set_fill_rule:
+ * @fill_rule: The new fill rule.
+ *
+ * Sets the fill rule of the current path to @fill_rule. This will
+ * affect how the path is filled when cogl_path_fill() is later
+ * called. Note that the fill rule state is attached to the path so
+ * calling cogl_get_path() will preserve the fill rule and calling
+ * cogl_path_new() will reset the fill rule back to the default.
+ *
+ * Since: 1.4
+ */
+void
+cogl_path_set_fill_rule (CoglPathFillRule fill_rule);
+
+/**
+ * cogl_path_get_fill_rule:
+ *
+ * Retrieves the fill rule set using cogl_path_set_fill_rule().
+ *
+ * Return value: the fill rule that is used for the current path.
+ *
+ * Since: 1.4
+ */
+CoglPathFillRule
+cogl_path_get_fill_rule (void);
+
+/**
+ * cogl_path_fill:
+ *
+ * Fills the interior of the constructed shape using the current
+ * drawing color. The current path is then cleared. To use the path
+ * again, call cogl_path_fill_preserve() instead.
+ *
+ * The interior of the shape is determined using the fill rule of the
+ * path. See %CoglPathFillRule for details.
+ **/
+void
+cogl_path_fill (void);
+
+/**
+ * cogl_path_fill_preserve:
+ *
+ * Fills the interior of the constructed shape using the current
+ * drawing color and preserves the path to be used again. See
+ * cogl_path_fill() for a description what is considered the interior
+ * of the shape.
+ *
+ * Since: 1.0
+ **/
+void
+cogl_path_fill_preserve (void);
+
+/**
+ * cogl_path_stroke:
+ *
+ * Strokes the constructed shape using the current drawing color and a
+ * width of 1 pixel (regardless of the current transformation
+ * matrix). To current path is then cleared. To use the path again,
+ * call cogl_path_stroke_preserve() instead.
+ **/
+void
+cogl_path_stroke (void);
+
+/**
+ * cogl_path_stroke_preserve:
+ *
+ * Strokes the constructed shape using the current drawing color and
+ * preserves the path to be used again.
+ *
+ * Since: 1.0
+ **/
+void
+cogl_path_stroke_preserve (void);
+
+/**
+ * cogl_path_new:
+ *
+ * Clears the current path and starts a new one. Creating a new path
+ * also resets the fill rule to the default which is
+ * %COGL_PATH_FILL_RULE_EVEN_ODD.
+ *
+ * Since: 1.0
+ */
+void
+cogl_path_new (void);
+
+/**
+ * cogl_path_move_to:
+ * @x: X coordinate of the pen location to move to.
+ * @y: Y coordinate of the pen location to move to.
+ *
+ * Moves the pen to the given location. If there is an existing path
+ * this will start a new disjoint subpath.
+ **/
+void
+cogl_path_move_to (float x,
+ float y);
+
+
+/**
+ * cogl_path_rel_move_to:
+ * @x: X offset from the current pen location to move the pen to.
+ * @y: Y offset from the current pen location to move the pen to.
+ *
+ * Moves the pen to the given offset relative to the current pen
+ * location. If there is an existing path this will start a new
+ * disjoint subpath.
+ **/
+void
+cogl_path_rel_move_to (float x,
+ float y);
+
+/**
+ * cogl_path_line_to:
+ * @x: X coordinate of the end line vertex
+ * @y: Y coordinate of the end line vertex
+ *
+ * Adds a straight line segment to the current path that ends at the
+ * given coordinates.
+ **/
+void
+cogl_path_line_to (float x,
+ float y);
+
+/**
+ * cogl_path_rel_line_to:
+ * @x: X offset from the current pen location of the end line vertex
+ * @y: Y offset from the current pen location of the end line vertex
+ *
+ * Adds a straight line segment to the current path that ends at the
+ * given coordinates relative to the current pen location.
+ **/
+void
+cogl_path_rel_line_to (float x,
+ float y);
+
+
+/**
+ * cogl_path_arc:
+ * @center_x: X coordinate of the elliptical arc center
+ * @center_y: Y coordinate of the elliptical arc center
+ * @radius_x: X radius of the elliptical arc
+ * @radius_y: Y radius of the elliptical arc
+ * @angle_1: Angle in degrees at which the arc begin
+ * @angle_2: Angle in degrees at which the arc ends
+ *
+ * Adds an elliptical arc segment to the current path. A straight line
+ * segment will link the current pen location with the first vertex
+ * of the arc. If you perform a move_to to the arcs start just before
+ * drawing it you create a free standing arc.
+ *
+ * The angles are measured in degrees where 0° is in the direction of
+ * the positive X axis and 90° is in the direction of the positive Y
+ * axis. The angle of the arc begins at @angle_1 and heads towards
+ * @angle_2 (so if @angle_2 is less than @angle_1 it will decrease,
+ * otherwise it will increase).
+ **/
+void
+cogl_path_arc (float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2);
+
+/**
+ * cogl_path_curve_to:
+ * @x_1: X coordinate of the second bezier control point
+ * @y_1: Y coordinate of the second bezier control point
+ * @x_2: X coordinate of the third bezier control point
+ * @y_2: Y coordinate of the third bezier control point
+ * @x_3: X coordinate of the fourth bezier control point
+ * @y_3: Y coordinate of the fourth bezier control point
+ *
+ * Adds a cubic bezier curve segment to the current path with the given
+ * second, third and fourth control points and using current pen location
+ * as the first control point.
+ **/
+void
+cogl_path_curve_to (float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3);
+
+/**
+ * cogl_path_rel_curve_to:
+ * @x_1: X coordinate of the second bezier control point
+ * @y_1: Y coordinate of the second bezier control point
+ * @x_2: X coordinate of the third bezier control point
+ * @y_2: Y coordinate of the third bezier control point
+ * @x_3: X coordinate of the fourth bezier control point
+ * @y_3: Y coordinate of the fourth bezier control point
+ *
+ * Adds a cubic bezier curve segment to the current path with the given
+ * second, third and fourth control points and using current pen location
+ * as the first control point. The given coordinates are relative to the
+ * current pen location.
+ */
+void
+cogl_path_rel_curve_to (float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3);
+
+/**
+ * cogl_path_close:
+ *
+ * Closes the path being constructed by adding a straight line segment
+ * to it that ends at the first vertex of the path.
+ **/
+void
+cogl_path_close (void);
+
+/**
+ * cogl_path_line:
+ * @x_1: X coordinate of the start line vertex
+ * @y_1: Y coordinate of the start line vertex
+ * @x_2: X coordinate of the end line vertex
+ * @y_2: Y coordinate of the end line vertex
+ *
+ * Constructs a straight line shape starting and ending at the given
+ * coordinates. If there is an existing path this will start a new
+ * disjoint sub-path.
+ **/
+void
+cogl_path_line (float x_1,
+ float y_1,
+ float x_2,
+ float y_2);
+
+/**
+ * cogl_path_polyline:
+ * @coords: (in) (array) (transfer none): A pointer to the first element of an
+ * array of fixed-point values that specify the vertex coordinates.
+ * @num_points: The total number of vertices.
+ *
+ * Constructs a series of straight line segments, starting from the
+ * first given vertex coordinate. If there is an existing path this
+ * will start a new disjoint sub-path. Each subsequent segment starts
+ * where the previous one ended and ends at the next given vertex
+ * coordinate.
+ *
+ * The coords array must contain 2 * num_points values. The first value
+ * represents the X coordinate of the first vertex, the second value
+ * represents the Y coordinate of the first vertex, continuing in the same
+ * fashion for the rest of the vertices. (num_points - 1) segments will
+ * be constructed.
+ **/
+void
+cogl_path_polyline (const float *coords,
+ int num_points);
+
+
+/**
+ * cogl_path_polygon:
+ * @coords: (in) (array) (transfer none): A pointer to the first element of
+ * an array of fixed-point values that specify the vertex coordinates.
+ * @num_points: The total number of vertices.
+ *
+ * Constructs a polygonal shape of the given number of vertices. If
+ * there is an existing path this will start a new disjoint sub-path.
+ *
+ * The coords array must contain 2 * num_points values. The first value
+ * represents the X coordinate of the first vertex, the second value
+ * represents the Y coordinate of the first vertex, continuing in the same
+ * fashion for the rest of the vertices.
+ **/
+void
+cogl_path_polygon (const float *coords,
+ int num_points);
+
+
+/**
+ * cogl_path_rectangle:
+ * @x_1: X coordinate of the top-left corner.
+ * @y_1: Y coordinate of the top-left corner.
+ * @x_2: X coordinate of the bottom-right corner.
+ * @y_2: Y coordinate of the bottom-right corner.
+ *
+ * Constructs a rectangular shape at the given coordinates. If there
+ * is an existing path this will start a new disjoint sub-path.
+ **/
+void
+cogl_path_rectangle (float x_1,
+ float y_1,
+ float x_2,
+ float y_2);
+
+/**
+ * cogl_path_ellipse:
+ * @center_x: X coordinate of the ellipse center
+ * @center_y: Y coordinate of the ellipse center
+ * @radius_x: X radius of the ellipse
+ * @radius_y: Y radius of the ellipse
+ *
+ * Constructs an ellipse shape. If there is an existing path this will
+ * start a new disjoint sub-path.
+ **/
+void
+cogl_path_ellipse (float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y);
+
+/**
+ * cogl_path_round_rectangle:
+ * @x_1: X coordinate of the top-left corner.
+ * @y_1: Y coordinate of the top-left corner.
+ * @x_2: X coordinate of the bottom-right corner.
+ * @y_2: Y coordinate of the bottom-right corner.
+ * @radius: Radius of the corner arcs.
+ * @arc_step: Angle increment resolution for subdivision of
+ * the corner arcs.
+ *
+ * Constructs a rectangular shape with rounded corners. If there is an
+ * existing path this will start a new disjoint sub-path.
+ **/
+void
+cogl_path_round_rectangle (float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float radius,
+ float arc_step);
+
+/**
+ * cogl_get_path: (skip)
+ *
+ * Gets a pointer to the current path. The path can later be used
+ * again by calling cogl_path_set(). Note that the path isn't copied
+ * so if you later call any functions to add to the path it will
+ * affect the returned object too. No reference is taken on the path
+ * so if you want to retain it you should take your own reference with
+ * cogl_object_ref().
+ *
+ * Return value: a pointer to the current path.
+ *
+ * Since: 1.4
+ */
+CoglPath *
+cogl_get_path (void);
+
+/**
+ * cogl_set_path: (skip)
+ * @path: A #CoglPath object
+ *
+ * Replaces the current path with @path. A reference is taken on the
+ * object so if you no longer need the path you should unref with
+ * cogl_object_unref().
+ *
+ * Since: 1.4
+ */
+void
+cogl_set_path (CoglPath *path);
+
+/**
+ * cogl_path_copy: (skip)
+ * @path: A #CoglPath object
+ *
+ * Returns a new copy of the path in @path. The new path has a
+ * reference count of 1 so you should unref it with
+ * cogl_object_unref() if you no longer need it.
+ *
+ * Internally the path will share the data until one of the paths is
+ * modified so copying paths should be relatively cheap.
+ *
+ * Return value: (transfer full): a copy of the path in @path.
+ */
+CoglPath *
+cogl_path_copy (CoglPath *path);
+
+/**
+ * cogl_clip_push_from_path_preserve:
+ *
+ * Sets a new clipping area using the current path. The current path
+ * is then cleared. The clipping area is intersected with the previous
+ * clipping area. To restore the previous clipping area, call
+ * cogl_clip_pop().
+ *
+ * Since: 1.0
+ * Deprecated: 1.16: Use cogl_framebuffer_push_path_clip() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_framebuffer_push_path_clip)
+void
+cogl_clip_push_from_path_preserve (void);
+
+/**
+ * cogl_clip_push_from_path:
+ *
+ * Sets a new clipping area using the current path. The current path
+ * is then cleared. The clipping area is intersected with the previous
+ * clipping area. To restore the previous clipping area, call
+ * cogl_clip_pop().
+ *
+ * Since: 1.0
+ * Deprecated: 1.16: Use cogl_framebuffer_push_path_clip() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_framebuffer_push_path_clip)
+void
+cogl_clip_push_from_path (void);
+
+COGL_END_DECLS
+
+#endif /* __COGL_PATH_FUNCTIONS_H__ */
+
diff --git a/cogl/cogl-path/cogl1-path.c b/cogl/cogl-path/cogl1-path.c
new file mode 100644
index 000000000..b2c59239e
--- /dev/null
+++ b/cogl/cogl-path/cogl1-path.c
@@ -0,0 +1,353 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2010,2013 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Robert Bragg <robert@linux.intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-util.h"
+#include "cogl-object.h"
+#include "cogl-context-private.h"
+
+#include "cogl-path-types.h"
+
+#include "cogl2-path-functions.h"
+
+#undef cogl_path_set_fill_rule
+#undef cogl_path_get_fill_rule
+#undef cogl_path_fill
+#undef cogl_path_fill_preserve
+#undef cogl_path_stroke
+#undef cogl_path_stroke_preserve
+#undef cogl_path_move_to
+#undef cogl_path_rel_move_to
+#undef cogl_path_line_to
+#undef cogl_path_rel_line_to
+#undef cogl_path_close
+#undef cogl_path_new
+#undef cogl_path_line
+#undef cogl_path_polyline
+#undef cogl_path_polygon
+#undef cogl_path_rectangle
+#undef cogl_path_arc
+#undef cogl_path_ellipse
+#undef cogl_path_round_rectangle
+#undef cogl_path_curve_to
+#undef cogl_path_rel_curve_to
+#undef cogl_clip_push_from_path
+
+#include "cogl1-path-functions.h"
+
+#include <string.h>
+#include <math.h>
+
+static void
+ensure_current_path (CoglContext *ctx)
+{
+ if (ctx->current_path == NULL)
+ ctx->current_path = cogl2_path_new ();
+}
+
+static CoglPath *
+get_current_path (CoglContext *ctx)
+{
+ ensure_current_path (ctx);
+ return ctx->current_path;
+}
+
+void
+cogl_path_set_fill_rule (CoglPathFillRule fill_rule)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_set_fill_rule (get_current_path (ctx), fill_rule);
+}
+
+CoglPathFillRule
+cogl_path_get_fill_rule (void)
+{
+ _COGL_GET_CONTEXT (ctx, COGL_PATH_FILL_RULE_EVEN_ODD);
+
+ return cogl2_path_get_fill_rule (get_current_path (ctx));
+}
+
+void
+cogl_path_fill (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_fill (get_current_path (ctx));
+
+ if (ctx->current_path)
+ cogl_object_unref (ctx->current_path);
+ ctx->current_path = cogl2_path_new ();
+}
+
+void
+cogl_path_fill_preserve (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_fill (get_current_path (ctx));
+}
+
+void
+cogl_path_stroke (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_stroke (get_current_path (ctx));
+
+ if (ctx->current_path)
+ cogl_object_unref (ctx->current_path);
+ ctx->current_path = cogl2_path_new ();
+}
+
+void
+cogl_path_stroke_preserve (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_stroke (get_current_path (ctx));
+}
+
+void
+cogl_path_move_to (float x,
+ float y)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_move_to (get_current_path (ctx), x, y);
+}
+
+void
+cogl_path_rel_move_to (float x,
+ float y)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_rel_move_to (get_current_path (ctx), x, y);
+}
+
+void
+cogl_path_line_to (float x,
+ float y)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_line_to (get_current_path (ctx), x, y);
+}
+
+void
+cogl_path_rel_line_to (float x,
+ float y)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_rel_line_to (get_current_path (ctx), x, y);
+}
+
+void
+cogl_path_close (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_close (get_current_path (ctx));
+}
+
+void
+cogl_path_new (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (ctx->current_path)
+ cogl_object_unref (ctx->current_path);
+ ctx->current_path = cogl2_path_new ();
+}
+
+void
+cogl_path_line (float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_line (get_current_path (ctx), x_1, y_1, x_2, y_2);
+}
+
+void
+cogl_path_polyline (const float *coords,
+ int num_points)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_polyline (get_current_path (ctx), coords, num_points);
+}
+
+void
+cogl_path_polygon (const float *coords,
+ int num_points)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_polygon (get_current_path (ctx), coords, num_points);
+}
+
+void
+cogl_path_rectangle (float x_1,
+ float y_1,
+ float x_2,
+ float y_2)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_rectangle (get_current_path (ctx), x_1, y_1, x_2, y_2);
+}
+
+void
+cogl_path_arc (float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_arc (get_current_path (ctx),
+ center_x,
+ center_y,
+ radius_x,
+ radius_y,
+ angle_1,
+ angle_2);
+}
+
+void
+cogl_path_ellipse (float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_ellipse (get_current_path (ctx),
+ center_x,
+ center_y,
+ radius_x,
+ radius_y);
+}
+
+void
+cogl_path_round_rectangle (float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float radius,
+ float arc_step)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_round_rectangle (get_current_path (ctx),
+ x_1, y_1, x_2, y_2, radius, arc_step);
+}
+
+void
+cogl_path_curve_to (float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_curve_to (get_current_path (ctx),
+ x_1, y_1, x_2, y_2, x_3, y_3);
+}
+
+void
+cogl_path_rel_curve_to (float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl2_path_rel_curve_to (get_current_path (ctx),
+ x_1, y_1, x_2, y_2, x_3, y_3);
+}
+
+CoglPath *
+cogl_get_path (void)
+{
+ _COGL_GET_CONTEXT (ctx, NULL);
+
+ return get_current_path (ctx);
+}
+
+void
+cogl_set_path (CoglPath *path)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+ /* Reference the new object first in case it is the same as the old
+ object */
+ cogl_object_ref (path);
+ if (ctx->current_path)
+ cogl_object_unref (ctx->current_path);
+ ctx->current_path = path;
+}
+
+void
+cogl_clip_push_from_path_preserve (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (),
+ get_current_path (ctx));
+}
+
+void
+cogl_clip_push_from_path (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ cogl_clip_push_from_path_preserve ();
+
+ if (ctx->current_path)
+ cogl_object_unref (ctx->current_path);
+ ctx->current_path = cogl2_path_new ();
+}
diff --git a/cogl/cogl-path/cogl2-path-functions.h b/cogl/cogl-path/cogl2-path-functions.h
new file mode 100644
index 000000000..72c1fc84f
--- /dev/null
+++ b/cogl/cogl-path/cogl2-path-functions.h
@@ -0,0 +1,545 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2008,2009,2013 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef __COGL2_PATH_FUNCTIONS_H__
+#define __COGL2_PATH_FUNCTIONS_H__
+
+#include <cogl/cogl-types.h>
+#ifdef COGL_COMPILATION
+#include "cogl-context.h"
+#else
+#include <cogl/cogl.h>
+#endif
+#ifdef COGL_HAS_GTYPE_SUPPORT
+#include <glib-object.h>
+#endif
+
+COGL_BEGIN_DECLS
+
+#ifdef COGL_HAS_GTYPE_SUPPORT
+/**
+ * cogl_path_get_gtype:
+ *
+ * Returns: a #GType that can be used with the GLib type system.
+ */
+GType cogl_path_get_gtype (void);
+#endif
+
+#define cogl_path_new cogl2_path_new
+/**
+ * cogl_path_new:
+ *
+ * Creates a new, empty path object. The default fill rule is
+ * %COGL_PATH_FILL_RULE_EVEN_ODD.
+ *
+ * Return value: A pointer to a newly allocated #CoglPath, which can
+ * be freed using cogl_object_unref().
+ *
+ * Since: 2.0
+ */
+CoglPath *
+cogl_path_new (void);
+
+/**
+ * cogl_path_copy:
+ * @path: A #CoglPath object
+ *
+ * Returns a new copy of the path in @path. The new path has a
+ * reference count of 1 so you should unref it with
+ * cogl_object_unref() if you no longer need it.
+ *
+ * Internally the path will share the data until one of the paths is
+ * modified so copying paths should be relatively cheap.
+ *
+ * Return value: (transfer full): a copy of the path in @path.
+ *
+ * Since: 2.0
+ */
+CoglPath *
+cogl_path_copy (CoglPath *path);
+
+/**
+ * cogl_is_path:
+ * @object: A #CoglObject
+ *
+ * Gets whether the given object references an existing path object.
+ *
+ * Return value: %TRUE if the object references a #CoglPath,
+ * %FALSE otherwise.
+ *
+ * Since: 2.0
+ */
+CoglBool
+cogl_is_path (void *object);
+
+#define cogl_path_move_to cogl2_path_move_to
+/**
+ * cogl_path_move_to:
+ * @x: X coordinate of the pen location to move to.
+ * @y: Y coordinate of the pen location to move to.
+ *
+ * Moves the pen to the given location. If there is an existing path
+ * this will start a new disjoint subpath.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_move_to (CoglPath *path,
+ float x,
+ float y);
+
+#define cogl_path_rel_move_to cogl2_path_rel_move_to
+/**
+ * cogl_path_rel_move_to:
+ * @x: X offset from the current pen location to move the pen to.
+ * @y: Y offset from the current pen location to move the pen to.
+ *
+ * Moves the pen to the given offset relative to the current pen
+ * location. If there is an existing path this will start a new
+ * disjoint subpath.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rel_move_to (CoglPath *path,
+ float x,
+ float y);
+
+#define cogl_path_line_to cogl2_path_line_to
+/**
+ * cogl_path_line_to:
+ * @x: X coordinate of the end line vertex
+ * @y: Y coordinate of the end line vertex
+ *
+ * Adds a straight line segment to the current path that ends at the
+ * given coordinates.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_line_to (CoglPath *path,
+ float x,
+ float y);
+
+#define cogl_path_rel_line_to cogl2_path_rel_line_to
+/**
+ * cogl_path_rel_line_to:
+ * @x: X offset from the current pen location of the end line vertex
+ * @y: Y offset from the current pen location of the end line vertex
+ *
+ * Adds a straight line segment to the current path that ends at the
+ * given coordinates relative to the current pen location.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rel_line_to (CoglPath *path,
+ float x,
+ float y);
+
+#define cogl_path_arc cogl2_path_arc
+/**
+ * cogl_path_arc:
+ * @center_x: X coordinate of the elliptical arc center
+ * @center_y: Y coordinate of the elliptical arc center
+ * @radius_x: X radius of the elliptical arc
+ * @radius_y: Y radius of the elliptical arc
+ * @angle_1: Angle in degrees at which the arc begin
+ * @angle_2: Angle in degrees at which the arc ends
+ *
+ * Adds an elliptical arc segment to the current path. A straight line
+ * segment will link the current pen location with the first vertex
+ * of the arc. If you perform a move_to to the arcs start just before
+ * drawing it you create a free standing arc.
+ *
+ * The angles are measured in degrees where 0° is in the direction of
+ * the positive X axis and 90° is in the direction of the positive Y
+ * axis. The angle of the arc begins at @angle_1 and heads towards
+ * @angle_2 (so if @angle_2 is less than @angle_1 it will decrease,
+ * otherwise it will increase).
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_arc (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y,
+ float angle_1,
+ float angle_2);
+
+#define cogl_path_curve_to cogl2_path_curve_to
+/**
+ * cogl_path_curve_to:
+ * @x_1: X coordinate of the second bezier control point
+ * @y_1: Y coordinate of the second bezier control point
+ * @x_2: X coordinate of the third bezier control point
+ * @y_2: Y coordinate of the third bezier control point
+ * @x_3: X coordinate of the fourth bezier control point
+ * @y_3: Y coordinate of the fourth bezier control point
+ *
+ * Adds a cubic bezier curve segment to the current path with the given
+ * second, third and fourth control points and using current pen location
+ * as the first control point.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_curve_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3);
+
+#define cogl_path_rel_curve_to cogl2_path_rel_curve_to
+/**
+ * cogl_path_rel_curve_to:
+ * @x_1: X coordinate of the second bezier control point
+ * @y_1: Y coordinate of the second bezier control point
+ * @x_2: X coordinate of the third bezier control point
+ * @y_2: Y coordinate of the third bezier control point
+ * @x_3: X coordinate of the fourth bezier control point
+ * @y_3: Y coordinate of the fourth bezier control point
+ *
+ * Adds a cubic bezier curve segment to the current path with the given
+ * second, third and fourth control points and using current pen location
+ * as the first control point. The given coordinates are relative to the
+ * current pen location.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rel_curve_to (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float x_3,
+ float y_3);
+
+#define cogl_path_close cogl2_path_close
+/**
+ * cogl_path_close:
+ *
+ * Closes the path being constructed by adding a straight line segment
+ * to it that ends at the first vertex of the path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_close (CoglPath *path);
+
+#define cogl_path_line cogl2_path_line
+/**
+ * cogl_path_line:
+ * @x_1: X coordinate of the start line vertex
+ * @y_1: Y coordinate of the start line vertex
+ * @x_2: X coordinate of the end line vertex
+ * @y_2: Y coordinate of the end line vertex
+ *
+ * Constructs a straight line shape starting and ending at the given
+ * coordinates. If there is an existing path this will start a new
+ * disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_line (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2);
+
+#define cogl_path_polyline cogl2_path_polyline
+/**
+ * cogl_path_polyline:
+ * @coords: (in) (array) (transfer none): A pointer to the first element of an
+ * array of fixed-point values that specify the vertex coordinates.
+ * @num_points: The total number of vertices.
+ *
+ * Constructs a series of straight line segments, starting from the
+ * first given vertex coordinate. If there is an existing path this
+ * will start a new disjoint sub-path. Each subsequent segment starts
+ * where the previous one ended and ends at the next given vertex
+ * coordinate.
+ *
+ * The coords array must contain 2 * num_points values. The first value
+ * represents the X coordinate of the first vertex, the second value
+ * represents the Y coordinate of the first vertex, continuing in the same
+ * fashion for the rest of the vertices. (num_points - 1) segments will
+ * be constructed.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_polyline (CoglPath *path,
+ const float *coords,
+ int num_points);
+
+#define cogl_path_polygon cogl2_path_polygon
+/**
+ * cogl_path_polygon:
+ * @coords: (in) (array) (transfer none): A pointer to the first element of
+ * an array of fixed-point values that specify the vertex coordinates.
+ * @num_points: The total number of vertices.
+ *
+ * Constructs a polygonal shape of the given number of vertices. If
+ * there is an existing path this will start a new disjoint sub-path.
+ *
+ * The coords array must contain 2 * num_points values. The first value
+ * represents the X coordinate of the first vertex, the second value
+ * represents the Y coordinate of the first vertex, continuing in the same
+ * fashion for the rest of the vertices.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_polygon (CoglPath *path,
+ const float *coords,
+ int num_points);
+
+#define cogl_path_rectangle cogl2_path_rectangle
+/**
+ * cogl_path_rectangle:
+ * @x_1: X coordinate of the top-left corner.
+ * @y_1: Y coordinate of the top-left corner.
+ * @x_2: X coordinate of the bottom-right corner.
+ * @y_2: Y coordinate of the bottom-right corner.
+ *
+ * Constructs a rectangular shape at the given coordinates. If there
+ * is an existing path this will start a new disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_rectangle (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2);
+
+#define cogl_path_ellipse cogl2_path_ellipse
+/**
+ * cogl_path_ellipse:
+ * @center_x: X coordinate of the ellipse center
+ * @center_y: Y coordinate of the ellipse center
+ * @radius_x: X radius of the ellipse
+ * @radius_y: Y radius of the ellipse
+ *
+ * Constructs an ellipse shape. If there is an existing path this will
+ * start a new disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_ellipse (CoglPath *path,
+ float center_x,
+ float center_y,
+ float radius_x,
+ float radius_y);
+
+#define cogl_path_round_rectangle cogl2_path_round_rectangle
+/**
+ * cogl_path_round_rectangle:
+ * @x_1: X coordinate of the top-left corner.
+ * @y_1: Y coordinate of the top-left corner.
+ * @x_2: X coordinate of the bottom-right corner.
+ * @y_2: Y coordinate of the bottom-right corner.
+ * @radius: Radius of the corner arcs.
+ * @arc_step: Angle increment resolution for subdivision of
+ * the corner arcs.
+ *
+ * Constructs a rectangular shape with rounded corners. If there is an
+ * existing path this will start a new disjoint sub-path.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_round_rectangle (CoglPath *path,
+ float x_1,
+ float y_1,
+ float x_2,
+ float y_2,
+ float radius,
+ float arc_step);
+
+#define cogl_path_set_fill_rule cogl2_path_set_fill_rule
+/**
+ * cogl_path_set_fill_rule:
+ * @fill_rule: The new fill rule.
+ *
+ * Sets the fill rule of the current path to @fill_rule. This will
+ * affect how the path is filled when cogl_path_fill() is later
+ * called. Note that the fill rule state is attached to the path so
+ * calling cogl_get_path() will preserve the fill rule and calling
+ * cogl_path_new() will reset the fill rule back to the default.
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule);
+
+#define cogl_path_get_fill_rule cogl2_path_get_fill_rule
+/**
+ * cogl_path_get_fill_rule:
+ *
+ * Retrieves the fill rule set using cogl_path_set_fill_rule().
+ *
+ * Return value: the fill rule that is used for the current path.
+ *
+ * Since: 2.0
+ */
+CoglPathFillRule
+cogl_path_get_fill_rule (CoglPath *path);
+
+#define cogl_path_fill cogl2_path_fill
+/**
+ * cogl_path_fill:
+ *
+ * Fills the interior of the constructed shape using the current
+ * drawing color.
+ *
+ * The interior of the shape is determined using the fill rule of the
+ * path. See %CoglPathFillRule for details.
+ *
+ * <note>The result of referencing sliced textures in your current
+ * pipeline when filling a path are undefined. You should pass
+ * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
+ * use while filling a path.</note>
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_fill (CoglPath *path);
+
+/**
+ * cogl_framebuffer_fill_path:
+ * @framebuffer: A #CoglFramebuffer
+ * @pipeline: A #CoglPipeline to render with
+ * @path: The #CoglPath to fill
+ *
+ * Fills the interior of the path using the fragment operations
+ * defined by the pipeline.
+ *
+ * The interior of the shape is determined using the fill rule of the
+ * path. See %CoglPathFillRule for details.
+ *
+ * <note>The result of referencing sliced textures in your current
+ * pipeline when filling a path are undefined. You should pass
+ * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
+ * use while filling a path.</note>
+ *
+ * Stability: unstable
+ * Deprecated: 1.16: Use cogl_path_fill() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_path_fill)
+void
+cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ CoglPath *path);
+
+#define cogl_path_stroke cogl2_path_stroke
+/**
+ * cogl_path_stroke:
+ *
+ * Strokes the constructed shape using the current drawing color and a
+ * width of 1 pixel (regardless of the current transformation
+ * matrix).
+ *
+ * Since: 2.0
+ */
+void
+cogl_path_stroke (CoglPath *path);
+
+/**
+ * cogl_framebuffer_stroke_path:
+ * @framebuffer: A #CoglFramebuffer
+ * @pipeline: A #CoglPipeline to render with
+ * @path: The #CoglPath to stroke
+ *
+ * Strokes the edge of the path using the fragment operations defined
+ * by the pipeline. The stroke line will have a width of 1 pixel
+ * regardless of the current transformation matrix.
+ *
+ * Stability: unstable
+ * Deprecated: 1.16: Use cogl_path_stroke() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_path_stroke)
+void
+cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
+ CoglPipeline *pipeline,
+ CoglPath *path);
+
+/**
+ * cogl_framebuffer_push_path_clip:
+ * @framebuffer: A #CoglFramebuffer pointer
+ * @path: The path to clip with.
+ *
+ * Sets a new clipping area using the silhouette of the specified,
+ * filled @path. The clipping area is intersected with the previous
+ * clipping area. To restore the previous clipping area, call
+ * cogl_framebuffer_pop_clip().
+ *
+ * Since: 1.0
+ * Stability: unstable
+ */
+void
+cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
+ CoglPath *path);
+
+#define cogl_clip_push_from_path cogl2_clip_push_from_path
+/**
+ * cogl_clip_push_from_path:
+ * @path: The path to clip with.
+ *
+ * Sets a new clipping area using the silhouette of the specified,
+ * filled @path. The clipping area is intersected with the previous
+ * clipping area. To restore the previous clipping area, call
+ * call cogl_clip_pop().
+ *
+ * Since: 1.8
+ * Stability: Unstable
+ * Deprecated: 1.16: Use cogl_framebuffer_push_path_clip() instead
+ */
+COGL_DEPRECATED_IN_1_16_FOR (cogl_framebuffer_push_path_clip)
+void
+cogl_clip_push_from_path (CoglPath *path);
+
+COGL_END_DECLS
+
+#endif /* __COGL2_PATH_FUNCTIONS_H__ */
+
diff --git a/cogl/cogl-path/mutter-cogl-path-1.0.pc.in b/cogl/cogl-path/mutter-cogl-path-1.0.pc.in
new file mode 100644
index 000000000..959b77251
--- /dev/null
+++ b/cogl/cogl-path/mutter-cogl-path-1.0.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@/mutter
+includedir=@includedir@/mutter
+apiversion=1.0
+requires=@COGL_PKG_REQUIRES@ mutter-cogl-1.0
+
+Name: Cogl
+Description: A 2D path drawing library for Cogl
+Version: @COGL_1_VERSION@
+Libs: -L${libdir} -lmutter-cogl-path
+Cflags: -I${includedir}/cogl
+Requires: ${requires}
diff --git a/cogl/cogl-path/tesselator/GL/glu.h b/cogl/cogl-path/tesselator/GL/glu.h
new file mode 100644
index 000000000..18c4024b7
--- /dev/null
+++ b/cogl/cogl-path/tesselator/GL/glu.h
@@ -0,0 +1,47 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/* This is just a wrapper to use our simplified version of glu.h so
+ that the tesselator code can still #include <GL/glu.h> */
+
+#include "../tesselator.h"
+
+/* These aren't defined on GLES and we don't really want the
+ tesselator code to use them but we're also trying to avoid
+ modifying the C files so we just force them to be empty here */
+
+#undef GLAPI
+#define GLAPI
+
+#undef GLAPIENTRY
+#define GLAPIENTRY
+
+/* GLES doesn't define a GLdouble type so lets just force it to a
+ regular double */
+#define GLdouble double
diff --git a/cogl/cogl-path/tesselator/README b/cogl/cogl-path/tesselator/README
new file mode 100644
index 000000000..66a6011e2
--- /dev/null
+++ b/cogl/cogl-path/tesselator/README
@@ -0,0 +1,446 @@
+/*
+*/
+
+General Polygon Tesselation
+---------------------------
+
+ This note describes a tesselator for polygons consisting of one or
+ more closed contours. It is backward-compatible with the current
+ OpenGL Utilities tesselator, and is intended to replace it. Here is
+ a summary of the major differences:
+
+ - input contours can be intersecting, self-intersecting, or degenerate.
+
+ - supports a choice of several winding rules for determining which parts
+ of the polygon are on the "interior". This makes it possible to do
+ CSG operations on polygons.
+
+ - boundary extraction: instead of tesselating the polygon, returns a
+ set of closed contours which separate the interior from the exterior.
+
+ - returns the output as a small number of triangle fans and strips,
+ rather than a list of independent triangles (when possible).
+
+ - output is available as an explicit mesh (a quad-edge structure),
+ in addition to the normal callback interface.
+
+ - the algorithm used is extremely robust.
+
+
+The interface
+-------------
+
+ The tesselator state is maintained in a "tesselator object".
+ These are allocated and destroyed using
+
+ GLUtesselator *gluNewTess( void );
+ void gluDeleteTess( GLUtesselator *tess );
+
+ Several tesselator objects may be used simultaneously.
+
+ Inputs
+ ------
+
+ The input contours are specified with the following routines:
+
+ void gluTessBeginPolygon( GLUtesselator *tess );
+ void gluTessBeginContour( GLUtesselator *tess );
+ void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data );
+ void gluTessEndContour( GLUtesselator *tess );
+ void gluTessEndPolygon( GLUtesselator *tess );
+
+ Within each BeginPolygon/EndPolygon pair, there can be zero or more
+ calls to BeginContour/EndContour. Within each contour, there are zero
+ or more calls to gluTessVertex(). The vertices specify a closed
+ contour (the last vertex of each contour is automatically linked to
+ the first).
+
+ "coords" give the coordinates of the vertex in 3-space. For useful
+ results, all vertices should lie in some plane, since the vertices
+ are projected onto a plane before tesselation. "data" is a pointer
+ to a user-defined vertex structure, which typically contains other
+ information such as color, texture coordinates, normal, etc. It is
+ used to refer to the vertex during rendering.
+
+ The library can be compiled in single- or double-precision; the type
+ GLUcoord represents either "float" or "double" accordingly. The GLU
+ version will be available in double-precision only. Compile with
+ GLU_TESS_API_FLOAT defined to get the single-precision version.
+
+ When EndPolygon is called, the tesselation algorithm determines
+ which regions are interior to the given contours, according to one
+ of several "winding rules" described below. The interior regions
+ are then tesselated, and the output is provided as callbacks.
+
+
+ Rendering Callbacks
+ -------------------
+
+ Callbacks are specified by the client using
+
+ void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)());
+
+ If "fn" is NULL, any previously defined callback is discarded.
+
+ The callbacks used to provide output are: /* which == */
+
+ void begin( GLenum type ); /* GLU_TESS_BEGIN */
+ void edgeFlag( GLboolean flag ); /* GLU_TESS_EDGE_FLAG */
+ void vertex( void *data ); /* GLU_TESS_VERTEX */
+ void end( void ); /* GLU_TESS_END */
+
+ Any of the callbacks may be left undefined; if so, the corresponding
+ information will not be supplied during rendering.
+
+ The "begin" callback indicates the start of a primitive; type is one
+ of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the
+ notes on "boundary extraction" below).
+
+ It is followed by any number of "vertex" callbacks, which supply the
+ vertices in the same order as expected by the corresponding glBegin()
+ call. After the last vertex of a given primitive, there is a callback
+ to "end".
+
+ If the "edgeFlag" callback is provided, no triangle fans or strips
+ will be used. When edgeFlag is called, if "flag" is GL_TRUE then each
+ vertex which follows begins an edge which lies on the polygon boundary
+ (ie. an edge which separates an interior region from an exterior one).
+ If "flag" is GL_FALSE, each vertex which follows begins an edge which lies
+ in the polygon interior. "edgeFlag" will be called before the first
+ call to "vertex".
+
+ Other Callbacks
+ ---------------
+
+ void mesh( GLUmesh *mesh ); /* GLU_TESS_MESH */
+
+ - Returns an explicit mesh, represented using the quad-edge structure
+ (Guibas/Stolfi '85). Other implementations of this interface might
+ use a different mesh structure, so this is available only only as an
+ SGI extension. When the mesh is no longer needed, it should be freed
+ using
+
+ void gluDeleteMesh( GLUmesh *mesh );
+
+ There is a brief description of this data structure in the include
+ file "mesh.h". For the full details, see L. Guibas and J. Stolfi,
+ Primitives for the manipulation of general subdivisions and the
+ computation of Voronoi diagrams, ACM Transactions on Graphics,
+ 4(2):74-123, April 1985. For an introduction, see the course notes
+ for CS348a, "Mathematical Foundations of Computer Graphics",
+ available at the Stanford bookstore (and taught during the fall
+ quarter).
+
+ void error( GLenum errno ); /* GLU_TESS_ERROR */
+
+ - errno is one of GLU_TESS_MISSING_BEGIN_POLYGON,
+ GLU_TESS_MISSING_END_POLYGON,
+ GLU_TESS_MISSING_BEGIN_CONTOUR,
+ GLU_TESS_MISSING_END_CONTOUR,
+ GLU_TESS_COORD_TOO_LARGE,
+ GLU_TESS_NEED_COMBINE_CALLBACK
+
+ The first four are obvious. The interface recovers from these
+ errors by inserting the missing call(s).
+
+ GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded
+ the predefined constant GLU_TESS_MAX_COORD in absolute value, and
+ that the value has been clamped. (Coordinate values must be small
+ enough so that two can be multiplied together without overflow.)
+
+ GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an
+ intersection between two edges in the input data, and the "combine"
+ callback (below) was not provided. No output will be generated.
+
+
+ void combine( GLUcoord coords[3], void *data[4], /* GLU_TESS_COMBINE */
+ GLUcoord weight[4], void **outData );
+
+ - When the algorithm detects an intersection, or wishes to merge
+ features, it needs to create a new vertex. The vertex is defined
+ as a linear combination of up to 4 existing vertices, referenced
+ by data[0..3]. The coefficients of the linear combination are
+ given by weight[0..3]; these weights always sum to 1.0. All vertex
+ pointers are valid even when some of the weights are zero.
+ "coords" gives the location of the new vertex.
+
+ The user must allocate another vertex, interpolate parameters
+ using "data" and "weights", and return the new vertex pointer in
+ "outData". This handle is supplied during rendering callbacks.
+ For example, if the polygon lies in an arbitrary plane in 3-space,
+ and we associate a color with each vertex, the combine callback might
+ look like this:
+
+ void myCombine( GLUcoord coords[3], VERTEX *d[4],
+ GLUcoord w[4], VERTEX **dataOut )
+ {
+ VERTEX *new = new_vertex();
+
+ new->x = coords[0];
+ new->y = coords[1];
+ new->z = coords[2];
+ new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r;
+ new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g;
+ new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b;
+ new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a;
+ *dataOut = new;
+ }
+
+ If the algorithm detects an intersection, then the "combine" callback
+ must be defined, and must write a non-NULL pointer into "dataOut".
+ Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no
+ output is generated. This is the only error that can occur during
+ tesselation and rendering.
+
+
+ Control over Tesselation
+ ------------------------
+
+ void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value );
+
+ Properties defined:
+
+ - GLU_TESS_WINDING_RULE. Possible values:
+
+ GLU_TESS_WINDING_ODD
+ GLU_TESS_WINDING_NONZERO
+ GLU_TESS_WINDING_POSITIVE
+ GLU_TESS_WINDING_NEGATIVE
+ GLU_TESS_WINDING_ABS_GEQ_TWO
+
+ The input contours parition the plane into regions. A winding
+ rule determines which of these regions are inside the polygon.
+
+ For a single contour C, the winding number of a point x is simply
+ the signed number of revolutions we make around x as we travel
+ once around C (where CCW is positive). When there are several
+ contours, the individual winding numbers are summed. This
+ procedure associates a signed integer value with each point x in
+ the plane. Note that the winding number is the same for all
+ points in a single region.
+
+ The winding rule classifies a region as "inside" if its winding
+ number belongs to the chosen category (odd, nonzero, positive,
+ negative, or absolute value of at least two). The current GLU
+ tesselator implements the "odd" rule. The "nonzero" rule is another
+ common way to define the interior. The other three rules are
+ useful for polygon CSG operations (see below).
+
+ - GLU_TESS_BOUNDARY_ONLY. Values: TRUE (non-zero) or FALSE (zero).
+
+ If TRUE, returns a set of closed contours which separate the
+ polygon interior and exterior (rather than a tesselation).
+ Exterior contours are oriented CCW with respect to the normal,
+ interior contours are oriented CW. The GLU_TESS_BEGIN callback
+ uses the type GL_LINE_LOOP for each contour.
+
+ - GLU_TESS_TOLERANCE. Value: a real number between 0.0 and 1.0.
+
+ This specifies a tolerance for merging features to reduce the size
+ of the output. For example, two vertices which are very close to
+ each other might be replaced by a single vertex. The tolerance
+ is multiplied by the largest coordinate magnitude of any input vertex;
+ this specifies the maximum distance that any feature can move as the
+ result of a single merge operation. If a single feature takes part
+ in several merge operations, the total distance moved could be larger.
+
+ Feature merging is completely optional; the tolerance is only a hint.
+ The implementation is free to merge in some cases and not in others,
+ or to never merge features at all. The default tolerance is zero.
+
+ The current implementation merges vertices only if they are exactly
+ coincident, regardless of the current tolerance. A vertex is
+ spliced into an edge only if the implementation is unable to
+ distinguish which side of the edge the vertex lies on.
+ Two edges are merged only when both endpoints are identical.
+
+
+ void gluTessNormal( GLUtesselator *tess,
+ GLUcoord x, GLUcoord y, GLUcoord z )
+
+ - Lets the user supply the polygon normal, if known. All input data
+ is projected into a plane perpendicular to the normal before
+ tesselation. All output triangles are oriented CCW with
+ respect to the normal (CW orientation can be obtained by
+ reversing the sign of the supplied normal). For example, if
+ you know that all polygons lie in the x-y plane, call
+ "gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons.
+
+ - If the supplied normal is (0,0,0) (the default value), the
+ normal is determined as follows. The direction of the normal,
+ up to its sign, is found by fitting a plane to the vertices,
+ without regard to how the vertices are connected. It is
+ expected that the input data lies approximately in plane;
+ otherwise projection perpendicular to the computed normal may
+ substantially change the geometry. The sign of the normal is
+ chosen so that the sum of the signed areas of all input contours
+ is non-negative (where a CCW contour has positive area).
+
+ - The supplied normal persists until it is changed by another
+ call to gluTessNormal.
+
+
+ Backward compatibility with the GLU tesselator
+ ----------------------------------------------
+
+ The preferred interface is the one described above. The following
+ routines are obsolete, and are provided only for backward compatibility:
+
+ typedef GLUtesselator GLUtriangulatorObj; /* obsolete name */
+
+ void gluBeginPolygon( GLUtesselator *tess );
+ void gluNextContour( GLUtesselator *tess, GLenum type );
+ void gluEndPolygon( GLUtesselator *tess );
+
+ "type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or
+ GLU_UNKNOWN. It is ignored by the current GLU tesselator.
+
+ GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined
+ as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END,
+ GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG.
+
+
+Polygon CSG operations
+----------------------
+
+ The features of the tesselator make it easy to find the union, difference,
+ or intersection of several polygons.
+
+ First, assume that each polygon is defined so that the winding number
+ is 0 for each exterior region, and 1 for each interior region. Under
+ this model, CCW contours define the outer boundary of the polygon, and
+ CW contours define holes. Contours may be nested, but a nested
+ contour must be oriented oppositely from the contour that contains it.
+
+ If the original polygons do not satisfy this description, they can be
+ converted to this form by first running the tesselator with the
+ GLU_TESS_BOUNDARY_ONLY property turned on. This returns a list of
+ contours satisfying the restriction above. By allocating two
+ tesselator objects, the callbacks from one tesselator can be fed
+ directly to the input of another.
+
+ Given two or more polygons of the form above, CSG operations can be
+ implemented as follows:
+
+ Union
+ Draw all the input contours as a single polygon. The winding number
+ of each resulting region is the number of original polygons
+ which cover it. The union can be extracted using the
+ GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules.
+ Note that with the nonzero rule, we would get the same result if
+ all contour orientations were reversed.
+
+ Intersection (two polygons at a time only)
+ Draw a single polygon using the contours from both input polygons.
+ Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO. (Since this
+ winding rule looks at the absolute value, reversing all contour
+ orientations does not change the result.)
+
+ Difference
+
+ Suppose we want to compute A \ (B union C union D). Draw a single
+ polygon consisting of the unmodified contours from A, followed by
+ the contours of B,C,D with the vertex order reversed (this changes
+ the winding number of the interior regions to -1). To extract the
+ result, use the GLU_TESS_WINDING_POSITIVE rule.
+
+ If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an
+ alternative to reversing the vertex order is to reverse the sign of
+ the supplied normal. For example in the x-y plane, call
+ gluTessNormal( tess, 0.0, 0.0, -1.0 ).
+
+
+Performance
+-----------
+
+ The tesselator is not intended for immediate-mode rendering; when
+ possible the output should be cached in a user structure or display
+ list. General polygon tesselation is an inherently difficult problem,
+ especially given the goal of extreme robustness.
+
+ The implementation makes an effort to output a small number of fans
+ and strips; this should improve the rendering performance when the
+ output is used in a display list.
+
+ Single-contour input polygons are first tested to see whether they can
+ be rendered as a triangle fan with respect to the first vertex (to
+ avoid running the full decomposition algorithm on convex polygons).
+ Non-convex polygons may be rendered by this "fast path" as well, if
+ the algorithm gets lucky in its choice of a starting vertex.
+
+ For best performance follow these guidelines:
+
+ - supply the polygon normal, if available, using gluTessNormal().
+ This represents about 10% of the computation time. For example,
+ if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1).
+
+ - render many polygons using the same tesselator object, rather than
+ allocating a new tesselator for each one. (In a multi-threaded,
+ multi-processor environment you may get better performance using
+ several tesselators.)
+
+
+Comparison with the GLU tesselator
+----------------------------------
+
+ On polygons which make it through the "fast path", the tesselator is
+ 3 to 5 times faster than the GLU tesselator.
+
+ On polygons which don't make it through the fast path (but which don't
+ have self-intersections or degeneracies), it is about 2 times slower.
+
+ On polygons with self-intersections or degeneraces, there is nothing
+ to compare against.
+
+ The new tesselator generates many more fans and strips, reducing the
+ number of vertices that need to be sent to the hardware.
+
+ Key to the statistics:
+
+ vert number of input vertices on all contours
+ cntr number of input contours
+ tri number of triangles in all output primitives
+ strip number of triangle strips
+ fan number of triangle fans
+ ind number of independent triangles
+ ms number of milliseconds for tesselation
+ (on a 150MHz R4400 Indy)
+
+ Convex polygon examples:
+
+New: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.0459 ms
+Old: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.149 ms
+New: 4 vert, 1 cntr, 2 tri, 0 strip, 1 fan, 0 ind, 0.0459 ms
+Old: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.161 ms
+New: 36 vert, 1 cntr, 34 tri, 0 strip, 1 fan, 0 ind, 0.153 ms
+Old: 36 vert, 1 cntr, 34 tri, 0 strip, 0 fan, 34 ind, 0.621 ms
+
+ Concave single-contour polygons:
+
+New: 5 vert, 1 cntr, 3 tri, 0 strip, 1 fan, 0 ind, 0.052 ms
+Old: 5 vert, 1 cntr, 3 tri, 0 strip, 0 fan, 3 ind, 0.252 ms
+New: 19 vert, 1 cntr, 17 tri, 2 strip, 2 fan, 1 ind, 0.911 ms
+Old: 19 vert, 1 cntr, 17 tri, 0 strip, 0 fan, 17 ind, 0.529 ms
+New: 151 vert, 1 cntr, 149 tri, 13 strip, 18 fan, 3 ind, 6.82 ms
+Old: 151 vert, 1 cntr, 149 tri, 0 strip, 3 fan, 143 ind, 2.7 ms
+New: 574 vert, 1 cntr, 572 tri, 59 strip, 54 fan, 11 ind, 26.6 ms
+Old: 574 vert, 1 cntr, 572 tri, 0 strip, 31 fan, 499 ind, 12.4 ms
+
+ Multiple contours, but no intersections:
+
+New: 7 vert, 2 cntr, 7 tri, 1 strip, 0 fan, 0 ind, 0.527 ms
+Old: 7 vert, 2 cntr, 7 tri, 0 strip, 0 fan, 7 ind, 0.274 ms
+New: 81 vert, 6 cntr, 89 tri, 9 strip, 7 fan, 6 ind, 3.88 ms
+Old: 81 vert, 6 cntr, 89 tri, 0 strip, 13 fan, 61 ind, 2.2 ms
+New: 391 vert, 19 cntr, 413 tri, 37 strip, 32 fan, 26 ind, 20.2 ms
+Old: 391 vert, 19 cntr, 413 tri, 0 strip, 25 fan, 363 ind, 8.68 ms
+
+ Self-intersecting and degenerate examples:
+
+Bowtie: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.483 ms
+Star: 5 vert, 1 cntr, 5 tri, 0 strip, 0 fan, 5 ind, 0.91 ms
+Random: 24 vert, 7 cntr, 46 tri, 2 strip, 12 fan, 7 ind, 5.32 ms
+Font: 333 vert, 2 cntr, 331 tri, 32 strip, 16 fan, 3 ind, 14.1 ms
+: 167 vert, 35 cntr, 254 tri, 8 strip, 56 fan, 52 ind, 46.3 ms
+: 78 vert, 1 cntr, 2675 tri, 148 strip, 207 fan, 180 ind, 243 ms
+: 12480 vert, 2 cntr, 12478 tri, 736 strip,1275 fan, 5 ind, 1010 ms
diff --git a/cogl/cogl-path/tesselator/dict-list.h b/cogl/cogl-path/tesselator/dict-list.h
new file mode 100644
index 000000000..11331a76e
--- /dev/null
+++ b/cogl/cogl-path/tesselator/dict-list.h
@@ -0,0 +1,100 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/cogl/cogl-path/tesselator/dict.c b/cogl/cogl-path/tesselator/dict.c
new file mode 100644
index 000000000..49d4f759e
--- /dev/null
+++ b/cogl/cogl-path/tesselator/dict.c
@@ -0,0 +1,111 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include <stddef.h>
+#include "dict-list.h"
+#include "memalloc.h"
+
+/* really __gl_dictListNewDict */
+Dict *dictNewDict( void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) )
+{
+ Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
+ DictNode *head;
+
+ if (dict == NULL) return NULL;
+
+ head = &dict->head;
+
+ head->key = NULL;
+ head->next = head;
+ head->prev = head;
+
+ dict->frame = frame;
+ dict->leq = leq;
+
+ return dict;
+}
+
+/* really __gl_dictListDeleteDict */
+void dictDeleteDict( Dict *dict )
+{
+ DictNode *node, *next;
+
+ for( node = dict->head.next; node != &dict->head; node = next ) {
+ next = node->next;
+ memFree( node );
+ }
+ memFree( dict );
+}
+
+/* really __gl_dictListInsertBefore */
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key )
+{
+ DictNode *newNode;
+
+ do {
+ node = node->prev;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
+
+ newNode = (DictNode *) memAlloc( sizeof( DictNode ));
+ if (newNode == NULL) return NULL;
+
+ newNode->key = key;
+ newNode->next = node->next;
+ node->next->prev = newNode;
+ newNode->prev = node;
+ node->next = newNode;
+
+ return newNode;
+}
+
+/* really __gl_dictListDelete */
+void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/
+{
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ memFree( node );
+}
+
+/* really __gl_dictListSearch */
+DictNode *dictSearch( Dict *dict, DictKey key )
+{
+ DictNode *node = &dict->head;
+
+ do {
+ node = node->next;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
+
+ return node;
+}
diff --git a/cogl/cogl-path/tesselator/dict.h b/cogl/cogl-path/tesselator/dict.h
new file mode 100644
index 000000000..11331a76e
--- /dev/null
+++ b/cogl/cogl-path/tesselator/dict.h
@@ -0,0 +1,100 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/cogl/cogl-path/tesselator/geom.c b/cogl/cogl-path/tesselator/geom.c
new file mode 100644
index 000000000..35b36a394
--- /dev/null
+++ b/cogl/cogl-path/tesselator/geom.c
@@ -0,0 +1,264 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include "mesh.h"
+#include "geom.h"
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
+{
+ /* Returns TRUE if u is lexicographically <= v. */
+
+ return VertLeq( u, v );
+}
+
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->t = 0 and
+ * let r be the negated result (this evaluates (uw)(v->s)), then
+ * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
+ } else {
+ return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches EdgeEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+/***********************************************************************
+ * Define versions of EdgeSign, EdgeEval with s and t transposed.
+ */
+
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->s = 0 and
+ * let r be the negated result (this evaluates (uw)(v->t)), then
+ * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
+ } else {
+ return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches TransEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* For almost-degenerate situations, the results are not reliable.
+ * Unless the floating-point arithmetic can be performed without
+ * rounding errors, *any* implementation will give incorrect results
+ * on some degenerate inputs, so the client must have some way to
+ * handle this situation.
+ */
+ return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
+}
+
+/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
+ * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
+ * this in the rare case that one argument is slightly negative.
+ * The implementation is extremely stable numerically.
+ * In particular it guarantees that the result r satisfies
+ * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
+ * even when a and b differ greatly in magnitude.
+ */
+#define RealInterpolate(a,x,b,y) \
+ (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
+ ((a <= b) ? ((b == 0) ? ((x+y) / 2) \
+ : (x + (y-x) * (a/(a+b)))) \
+ : (y + (x-y) * (b/(a+b)))))
+
+#ifndef FOR_TRITE_TEST_PROGRAM
+#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y)
+#else
+
+/* Claim: the ONLY property the sweep algorithm relies on is that
+ * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that.
+ */
+#include <stdlib.h>
+extern int RandomInterpolate;
+
+GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
+{
+printf("*********************%d\n",RandomInterpolate);
+ if( RandomInterpolate ) {
+ a = 1.2 * drand48() - 0.1;
+ a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
+ b = 1.0 - a;
+ }
+ return RealInterpolate(a,x,b,y);
+}
+
+#endif
+
+#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while (0)
+
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v )
+/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
+ * The computed point is guaranteed to lie in the intersection of the
+ * bounding rectangles defined by each edge.
+ */
+{
+ GLdouble z1, z2;
+
+ /* This is certainly not the most efficient way to find the intersection
+ * of two line segments, but it is very numerically stable.
+ *
+ * Strategy: find the two middle vertices in the VertLeq ordering,
+ * and interpolate the intersection s-value from these. Then repeat
+ * using the TransLeq ordering to find the intersection t-value.
+ */
+
+ if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! VertLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->s = (o2->s + d1->s) / 2;
+ } else if( VertLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = EdgeEval( o1, o2, d1 );
+ z2 = EdgeEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d1->s );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = EdgeSign( o1, o2, d1 );
+ z2 = -EdgeSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d2->s );
+ }
+
+ /* Now repeat the process for t */
+
+ if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! TransLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->t = (o2->t + d1->t) / 2;
+ } else if( TransLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = TransEval( o1, o2, d1 );
+ z2 = TransEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d1->t );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = TransSign( o1, o2, d1 );
+ z2 = -TransSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d2->t );
+ }
+}
diff --git a/cogl/cogl-path/tesselator/geom.h b/cogl/cogl-path/tesselator/geom.h
new file mode 100644
index 000000000..5cb76c7d1
--- /dev/null
+++ b/cogl/cogl-path/tesselator/geom.h
@@ -0,0 +1,84 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __geom_h_
+#define __geom_h_
+
+#include "mesh.h"
+
+#ifdef NO_BRANCH_CONDITIONS
+/* MIPS architecture has special instructions to evaluate boolean
+ * conditions -- more efficient than branching, IF you can get the
+ * compiler to generate the right instructions (SGI compiler doesn't)
+ */
+#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t))
+#define VertLeq(u,v) (((u)->s < (v)->s) | \
+ ((u)->s == (v)->s & (u)->t <= (v)->t))
+#else
+#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t)
+#define VertLeq(u,v) (((u)->s < (v)->s) || \
+ ((u)->s == (v)->s && (u)->t <= (v)->t))
+#endif
+
+#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
+#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
+
+/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
+
+#define TransLeq(u,v) (((u)->t < (v)->t) || \
+ ((u)->t == (v)->t && (u)->s <= (v)->s))
+#define TransEval(u,v,w) __gl_transEval(u,v,w)
+#define TransSign(u,v,w) __gl_transSign(u,v,w)
+
+
+#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org )
+#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst )
+
+#undef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t))
+
+#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v );
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v );
+
+#endif
diff --git a/cogl/cogl-path/tesselator/gluos.h b/cogl/cogl-path/tesselator/gluos.h
new file mode 100644
index 000000000..d6c3ae998
--- /dev/null
+++ b/cogl/cogl-path/tesselator/gluos.h
@@ -0,0 +1 @@
+/* This is a stub header to avoid having to change tess.c */
diff --git a/cogl/cogl-path/tesselator/memalloc.h b/cogl/cogl-path/tesselator/memalloc.h
new file mode 100644
index 000000000..a094b6cdc
--- /dev/null
+++ b/cogl/cogl-path/tesselator/memalloc.h
@@ -0,0 +1,49 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *
+ */
+
+/* This is a simple replacement for memalloc from the SGI tesselator
+ code to force it to use glib's allocation instead */
+
+#ifndef __MEMALLOC_H__
+#define __MEMALLOC_H__
+
+#include <glib.h>
+
+#define memRealloc g_realloc
+#define memAlloc g_malloc
+#define memFree g_free
+#define memInit(x) 1
+
+/* tess.c defines TRUE and FALSE itself unconditionally so we need to
+ undefine it from the glib headers */
+#undef TRUE
+#undef FALSE
+
+#endif /* __MEMALLOC_H__ */
diff --git a/cogl/cogl-path/tesselator/mesh.c b/cogl/cogl-path/tesselator/mesh.c
new file mode 100644
index 000000000..36cb3a7be
--- /dev/null
+++ b/cogl/cogl-path/tesselator/mesh.c
@@ -0,0 +1,798 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include "mesh.h"
+#include "memalloc.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static GLUvertex *allocVertex()
+{
+ return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
+}
+
+static GLUface *allocFace()
+{
+ return (GLUface *)memAlloc( sizeof( GLUface ));
+}
+
+/************************ Utility Routines ************************/
+
+/* Allocate and free half-edges in pairs for efficiency.
+ * The *only* place that should use this fact is allocation/free.
+ */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+/* MakeEdge creates a new pair of half-edges which form their own loop.
+ * No vertex or face structures are allocated, but these must be assigned
+ * before the current edge operation is completed.
+ */
+static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
+{
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUhalfEdge *ePrev;
+ EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
+ if (pair == NULL) return NULL;
+
+ e = &pair->e;
+ eSym = &pair->eSym;
+
+ /* Make sure eNext points to the first edge of the edge pair */
+ if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
+
+ /* Insert in circular doubly-linked list before eNext.
+ * Note that the prev pointer is stored in Sym->next.
+ */
+ ePrev = eNext->Sym->next;
+ eSym->next = ePrev;
+ ePrev->Sym->next = e;
+ e->next = eNext;
+ eNext->Sym->next = eSym;
+
+ e->Sym = eSym;
+ e->Onext = e;
+ e->Lnext = eSym;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->Sym = e;
+ eSym->Onext = eSym;
+ eSym->Lnext = e;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return e;
+}
+
+/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
+ * CS348a notes (see mesh.h). Basically it modifies the mesh so that
+ * a->Onext and b->Onext are exchanged. This can have various effects
+ * depending on whether a and b belong to different face or vertex rings.
+ * For more explanation see __gl_meshSplice() below.
+ */
+static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
+{
+ GLUhalfEdge *aOnext = a->Onext;
+ GLUhalfEdge *bOnext = b->Onext;
+
+ aOnext->Sym->Lnext = b;
+ bOnext->Sym->Lnext = a;
+ a->Onext = bOnext;
+ b->Onext = aOnext;
+}
+
+/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
+ * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
+ * a place to insert the new vertex in the global vertex list. We insert
+ * the new vertex *before* vNext so that algorithms which walk the vertex
+ * list will not see the newly created vertices.
+ */
+static void MakeVertex( GLUvertex *newVertex,
+ GLUhalfEdge *eOrig, GLUvertex *vNext )
+{
+ GLUhalfEdge *e;
+ GLUvertex *vPrev;
+ GLUvertex *vNew = newVertex;
+
+ assert(vNew != NULL);
+
+ /* insert in circular doubly-linked list before vNext */
+ vPrev = vNext->prev;
+ vNew->prev = vPrev;
+ vPrev->next = vNew;
+ vNew->next = vNext;
+ vNext->prev = vNew;
+
+ vNew->anEdge = eOrig;
+ vNew->data = NULL;
+ /* leave coords, s, t undefined */
+
+ /* fix other edges on this vertex loop */
+ e = eOrig;
+ do {
+ e->Org = vNew;
+ e = e->Onext;
+ } while( e != eOrig );
+}
+
+/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
+ * face of all edges in the face loop to which eOrig belongs. "fNext" gives
+ * a place to insert the new face in the global face list. We insert
+ * the new face *before* fNext so that algorithms which walk the face
+ * list will not see the newly created faces.
+ */
+static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
+{
+ GLUhalfEdge *e;
+ GLUface *fPrev;
+ GLUface *fNew = newFace;
+
+ assert(fNew != NULL);
+
+ /* insert in circular doubly-linked list before fNext */
+ fPrev = fNext->prev;
+ fNew->prev = fPrev;
+ fPrev->next = fNew;
+ fNew->next = fNext;
+ fNext->prev = fNew;
+
+ fNew->anEdge = eOrig;
+ fNew->data = NULL;
+ fNew->trail = NULL;
+ fNew->marked = FALSE;
+
+ /* The new face is marked "inside" if the old one was. This is a
+ * convenience for the common case where a face has been split in two.
+ */
+ fNew->inside = fNext->inside;
+
+ /* fix other edges on this face loop */
+ e = eOrig;
+ do {
+ e->Lface = fNew;
+ e = e->Lnext;
+ } while( e != eOrig );
+}
+
+/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
+ * and removes from the global edge list.
+ */
+static void KillEdge( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *ePrev, *eNext;
+
+ /* Half-edges are allocated in pairs, see EdgePair above */
+ if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
+
+ /* delete from circular doubly-linked list */
+ eNext = eDel->next;
+ ePrev = eDel->Sym->next;
+ eNext->Sym->next = ePrev;
+ ePrev->Sym->next = eNext;
+
+ memFree( eDel );
+}
+
+
+/* KillVertex( vDel ) destroys a vertex and removes it from the global
+ * vertex list. It updates the vertex loop to point to a given new vertex.
+ */
+static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
+{
+ GLUhalfEdge *e, *eStart = vDel->anEdge;
+ GLUvertex *vPrev, *vNext;
+
+ /* change the origin of all affected edges */
+ e = eStart;
+ do {
+ e->Org = newOrg;
+ e = e->Onext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ vPrev = vDel->prev;
+ vNext = vDel->next;
+ vNext->prev = vPrev;
+ vPrev->next = vNext;
+
+ memFree( vDel );
+}
+
+/* KillFace( fDel ) destroys a face and removes it from the global face
+ * list. It updates the face loop to point to a given new face.
+ */
+static void KillFace( GLUface *fDel, GLUface *newLface )
+{
+ GLUhalfEdge *e, *eStart = fDel->anEdge;
+ GLUface *fPrev, *fNext;
+
+ /* change the left face of all affected edges */
+ e = eStart;
+ do {
+ e->Lface = newLface;
+ e = e->Lnext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fDel->prev;
+ fNext = fDel->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fDel );
+}
+
+
+/****************** Basic Edge Operations **********************/
+
+/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
+ * The loop consists of the two new half-edges.
+ */
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
+{
+ GLUvertex *newVertex1= allocVertex();
+ GLUvertex *newVertex2= allocVertex();
+ GLUface *newFace= allocFace();
+ GLUhalfEdge *e;
+
+ /* if any one is null then all get freed */
+ if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
+ if (newVertex1 != NULL) memFree(newVertex1);
+ if (newVertex2 != NULL) memFree(newVertex2);
+ if (newFace != NULL) memFree(newFace);
+ return NULL;
+ }
+
+ e = MakeEdge( &mesh->eHead );
+ if (e == NULL) {
+ memFree(newVertex1);
+ memFree(newVertex2);
+ memFree(newFace);
+ return NULL;
+ }
+
+ MakeVertex( newVertex1, e, &mesh->vHead );
+ MakeVertex( newVertex2, e->Sym, &mesh->vHead );
+ MakeFace( newFace, e, &mesh->fHead );
+ return e;
+}
+
+
+/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * Some special cases:
+ * If eDst == eOrg, the operation has no effect.
+ * If eDst == eOrg->Lnext, the new face will have a single edge.
+ * If eDst == eOrg->Lprev, the old face will have a single edge.
+ * If eDst == eOrg->Onext, the new vertex will have a single edge.
+ * If eDst == eOrg->Oprev, the old vertex will have a single edge.
+ */
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ int joiningLoops = FALSE;
+ int joiningVertices = FALSE;
+
+ if( eOrg == eDst ) return 1;
+
+ if( eDst->Org != eOrg->Org ) {
+ /* We are merging two disjoint vertices -- destroy eDst->Org */
+ joiningVertices = TRUE;
+ KillVertex( eDst->Org, eOrg->Org );
+ }
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Change the edge structure */
+ Splice( eDst, eOrg );
+
+ if( ! joiningVertices ) {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return 0;
+
+ /* We split one vertex into two -- the new vertex is eDst->Org.
+ * Make sure the old vertex points to a valid half-edge.
+ */
+ MakeVertex( newVertex, eDst, eOrg->Org );
+ eOrg->Org->anEdge = eOrg;
+ }
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We split one loop into two -- the new loop is eDst->Lface.
+ * Make sure the old face points to a valid half-edge.
+ */
+ MakeFace( newFace, eDst, eOrg->Lface );
+ eOrg->Lface->anEdge = eOrg;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * This function could be implemented as two calls to __gl_meshSplice
+ * plus a few calls to memFree, but this would allocate and delete
+ * unnecessary vertices and faces.
+ */
+int __gl_meshDelete( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *eDelSym = eDel->Sym;
+ int joiningLoops = FALSE;
+
+ /* First step: disconnect the origin vertex eDel->Org. We make all
+ * changes to get a consistent mesh in this "intermediate" state.
+ */
+ if( eDel->Lface != eDel->Rface ) {
+ /* We are joining two loops into one -- remove the left face */
+ joiningLoops = TRUE;
+ KillFace( eDel->Lface, eDel->Rface );
+ }
+
+ if( eDel->Onext == eDel ) {
+ KillVertex( eDel->Org, NULL );
+ } else {
+ /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
+ eDel->Rface->anEdge = eDel->Oprev;
+ eDel->Org->anEdge = eDel->Onext;
+
+ Splice( eDel, eDel->Oprev );
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We are splitting one loop into two -- create a new loop for eDel. */
+ MakeFace( newFace, eDel, eDel->Lface );
+ }
+ }
+
+ /* Claim: the mesh is now in a consistent state, except that eDel->Org
+ * may have been deleted. Now we disconnect eDel->Dst.
+ */
+ if( eDelSym->Onext == eDelSym ) {
+ KillVertex( eDelSym->Org, NULL );
+ KillFace( eDelSym->Lface, NULL );
+ } else {
+ /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
+ eDel->Lface->anEdge = eDelSym->Oprev;
+ eDelSym->Org->anEdge = eDelSym->Onext;
+ Splice( eDelSym, eDelSym->Oprev );
+ }
+
+ /* Any isolated vertices or faces have already been freed. */
+ KillEdge( eDel );
+
+ return 1;
+}
+
+
+/******************** Other Edge Operations **********************/
+
+/* All these routines can be implemented with the basic edge
+ * operations above. They are provided for convenience and efficiency.
+ */
+
+
+/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNewSym;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return NULL;
+
+ MakeVertex( newVertex, eNewSym, eNew->Org );
+ }
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ return eNew;
+}
+
+
+/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
+ if (tempHalfEdge == NULL) return NULL;
+
+ eNew = tempHalfEdge->Sym;
+
+ /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
+ Splice( eOrg->Sym, eOrg->Sym->Oprev );
+ Splice( eOrg->Sym, eNew );
+
+ /* Set the vertex and face information */
+ eOrg->Dst = eNew->Org;
+ eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
+ eNew->Rface = eOrg->Rface;
+ eNew->winding = eOrg->winding; /* copy old winding information */
+ eNew->Sym->winding = eOrg->Sym->winding;
+
+ return eNew;
+}
+
+
+/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * If (eOrg == eDst), the new face will have only two edges.
+ * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
+ * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
+ */
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ GLUhalfEdge *eNewSym;
+ int joiningLoops = FALSE;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+ Splice( eNewSym, eDst );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ eNewSym->Org = eDst->Org;
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ /* Make sure the old face points to a valid half-edge */
+ eOrg->Lface->anEdge = eNewSym;
+
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return NULL;
+
+ /* We split one loop into two -- the new loop is eNew->Lface */
+ MakeFace( newFace, eNew, eOrg->Lface );
+ }
+ return eNew;
+}
+
+
+/******************** Other Operations **********************/
+
+/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ */
+void __gl_meshZapFace( GLUface *fZap )
+{
+ GLUhalfEdge *eStart = fZap->anEdge;
+ GLUhalfEdge *e, *eNext, *eSym;
+ GLUface *fPrev, *fNext;
+
+ /* walk around face, deleting edges whose right face is also NULL */
+ eNext = eStart->Lnext;
+ do {
+ e = eNext;
+ eNext = e->Lnext;
+
+ e->Lface = NULL;
+ if( e->Rface == NULL ) {
+ /* delete the edge -- see __gl_MeshDelete above */
+
+ if( e->Onext == e ) {
+ KillVertex( e->Org, NULL );
+ } else {
+ /* Make sure that e->Org points to a valid half-edge */
+ e->Org->anEdge = e->Onext;
+ Splice( e, e->Oprev );
+ }
+ eSym = e->Sym;
+ if( eSym->Onext == eSym ) {
+ KillVertex( eSym->Org, NULL );
+ } else {
+ /* Make sure that eSym->Org points to a valid half-edge */
+ eSym->Org->anEdge = eSym->Onext;
+ Splice( eSym, eSym->Oprev );
+ }
+ KillEdge( e );
+ }
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fZap->prev;
+ fNext = fZap->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fZap );
+}
+
+
+/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ */
+GLUmesh *__gl_meshNewMesh( void )
+{
+ GLUvertex *v;
+ GLUface *f;
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
+ if (mesh == NULL) {
+ return NULL;
+ }
+
+ v = &mesh->vHead;
+ f = &mesh->fHead;
+ e = &mesh->eHead;
+ eSym = &mesh->eHeadSym;
+
+ v->next = v->prev = v;
+ v->anEdge = NULL;
+ v->data = NULL;
+
+ f->next = f->prev = f;
+ f->anEdge = NULL;
+ f->data = NULL;
+ f->trail = NULL;
+ f->marked = FALSE;
+ f->inside = FALSE;
+
+ e->next = e;
+ e->Sym = eSym;
+ e->Onext = NULL;
+ e->Lnext = NULL;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->next = eSym;
+ eSym->Sym = e;
+ eSym->Onext = NULL;
+ eSym->Lnext = NULL;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return mesh;
+}
+
+
+/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ */
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
+{
+ GLUface *f1 = &mesh1->fHead;
+ GLUvertex *v1 = &mesh1->vHead;
+ GLUhalfEdge *e1 = &mesh1->eHead;
+ GLUface *f2 = &mesh2->fHead;
+ GLUvertex *v2 = &mesh2->vHead;
+ GLUhalfEdge *e2 = &mesh2->eHead;
+
+ /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
+ if( f2->next != f2 ) {
+ f1->prev->next = f2->next;
+ f2->next->prev = f1->prev;
+ f2->prev->next = f1;
+ f1->prev = f2->prev;
+ }
+
+ if( v2->next != v2 ) {
+ v1->prev->next = v2->next;
+ v2->next->prev = v1->prev;
+ v2->prev->next = v1;
+ v1->prev = v2->prev;
+ }
+
+ if( e2->next != e2 ) {
+ e1->Sym->next->Sym->next = e2->next;
+ e2->next->Sym->next = e1->Sym->next;
+ e2->Sym->next->Sym->next = e1;
+ e1->Sym->next = e2->Sym->next;
+ }
+
+ memFree( mesh2 );
+ return mesh1;
+}
+
+
+#ifdef DELETE_BY_ZAPPING
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+
+ while( fHead->next != fHead ) {
+ __gl_meshZapFace( fHead->next );
+ }
+ assert( mesh->vHead.next == &mesh->vHead );
+
+ memFree( mesh );
+}
+
+#else
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *f, *fNext;
+ GLUvertex *v, *vNext;
+ GLUhalfEdge *e, *eNext;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ memFree( f );
+ }
+
+ for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
+ vNext = v->next;
+ memFree( v );
+ }
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ /* One call frees both e and e->Sym (see EdgePair above) */
+ eNext = e->next;
+ memFree( e );
+ }
+
+ memFree( mesh );
+}
+
+#endif
+
+#ifndef NDEBUG
+
+/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+void __gl_meshCheckMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+ GLUvertex *vHead = &mesh->vHead;
+ GLUhalfEdge *eHead = &mesh->eHead;
+ GLUface *f, *fPrev;
+ GLUvertex *v, *vPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ fPrev = fHead;
+ for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
+ assert( f->prev == fPrev );
+ e = f->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Lface == f );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
+
+ vPrev = vHead;
+ for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
+ assert( v->prev == vPrev );
+ e = v->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Org == v );
+ e = e->Onext;
+ } while( e != v->anEdge );
+ }
+ assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
+
+ ePrev = eHead;
+ for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
+ assert( e->Sym->next == ePrev->Sym );
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Org != NULL );
+ assert( e->Dst != NULL );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ }
+ assert( e->Sym->next == ePrev->Sym
+ && e->Sym == &mesh->eHeadSym
+ && e->Sym->Sym == e
+ && e->Org == NULL && e->Dst == NULL
+ && e->Lface == NULL && e->Rface == NULL );
+}
+
+#endif
diff --git a/cogl/cogl-path/tesselator/mesh.h b/cogl/cogl-path/tesselator/mesh.h
new file mode 100644
index 000000000..690c5f2f6
--- /dev/null
+++ b/cogl/cogl-path/tesselator/mesh.h
@@ -0,0 +1,266 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __mesh_h_
+#define __mesh_h_
+
+#include <GL/glu.h>
+
+typedef struct GLUmesh GLUmesh;
+
+typedef struct GLUvertex GLUvertex;
+typedef struct GLUface GLUface;
+typedef struct GLUhalfEdge GLUhalfEdge;
+
+typedef struct ActiveRegion ActiveRegion; /* Internal data */
+
+/* The mesh structure is similar in spirit, notation, and operations
+ * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
+ * for the manipulation of general subdivisions and the computation of
+ * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
+ * For a simplified description, see the course notes for CS348a,
+ * "Mathematical Foundations of Computer Graphics", available at the
+ * Stanford bookstore (and taught during the fall quarter).
+ * The implementation also borrows a tiny subset of the graph-based approach
+ * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
+ * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
+ *
+ * The fundamental data structure is the "half-edge". Two half-edges
+ * go together to make an edge, but they point in opposite directions.
+ * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
+ * its origin vertex (Org), the face on its left side (Lface), and the
+ * adjacent half-edges in the CCW direction around the origin vertex
+ * (Onext) and around the left face (Lnext). There is also a "next"
+ * pointer for the global edge list (see below).
+ *
+ * The notation used for mesh navigation:
+ * Sym = the mate of a half-edge (same edge, but opposite direction)
+ * Onext = edge CCW around origin vertex (keep same origin)
+ * Dnext = edge CCW around destination vertex (keep same dest)
+ * Lnext = edge CCW around left face (dest becomes new origin)
+ * Rnext = edge CCW around right face (origin becomes new dest)
+ *
+ * "prev" means to substitute CW for CCW in the definitions above.
+ *
+ * The mesh keeps global lists of all vertices, faces, and edges,
+ * stored as doubly-linked circular lists with a dummy header node.
+ * The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
+ *
+ * The circular edge list is special; since half-edges always occur
+ * in pairs (e and e->Sym), each half-edge stores a pointer in only
+ * one direction. Starting at eHead and following the e->next pointers
+ * will visit each *edge* once (ie. e or e->Sym, but not both).
+ * e->Sym stores a pointer in the opposite direction, thus it is
+ * always true that e->Sym->next->Sym->next == e.
+ *
+ * Each vertex has a pointer to next and previous vertices in the
+ * circular list, and a pointer to a half-edge with this vertex as
+ * the origin (NULL if this is the dummy header). There is also a
+ * field "data" for client data.
+ *
+ * Each face has a pointer to the next and previous faces in the
+ * circular list, and a pointer to a half-edge with this face as
+ * the left face (NULL if this is the dummy header). There is also
+ * a field "data" for client data.
+ *
+ * Note that what we call a "face" is really a loop; faces may consist
+ * of more than one loop (ie. not simply connected), but there is no
+ * record of this in the data structure. The mesh may consist of
+ * several disconnected regions, so it may not be possible to visit
+ * the entire mesh by starting at a half-edge and traversing the edge
+ * structure.
+ *
+ * The mesh does NOT support isolated vertices; a vertex is deleted along
+ * with its last edge. Similarly when two faces are merged, one of the
+ * faces is deleted (see __gl_meshDelete below). For mesh operations,
+ * all face (loop) and vertex pointers must not be NULL. However, once
+ * mesh manipulation is finished, __gl_MeshZapFace can be used to delete
+ * faces of the mesh, one at a time. All external faces can be "zapped"
+ * before the mesh is returned to the client; then a NULL face indicates
+ * a region which is not part of the output polygon.
+ */
+
+struct GLUvertex {
+ GLUvertex *next; /* next vertex (never NULL) */
+ GLUvertex *prev; /* previous vertex (never NULL) */
+ GLUhalfEdge *anEdge; /* a half-edge with this origin */
+ void *data; /* client's data */
+
+ /* Internal data (keep hidden) */
+ GLdouble coords[3]; /* vertex location in 3D */
+ GLdouble s, t; /* projection onto the sweep plane */
+ long pqHandle; /* to allow deletion from priority queue */
+};
+
+struct GLUface {
+ GLUface *next; /* next face (never NULL) */
+ GLUface *prev; /* previous face (never NULL) */
+ GLUhalfEdge *anEdge; /* a half edge with this left face */
+ void *data; /* room for client's data */
+
+ /* Internal data (keep hidden) */
+ GLUface *trail; /* "stack" for conversion to strips */
+ GLboolean marked; /* flag for conversion to strips */
+ GLboolean inside; /* this face is in the polygon interior */
+};
+
+struct GLUhalfEdge {
+ GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
+ GLUhalfEdge *Sym; /* same edge, opposite direction */
+ GLUhalfEdge *Onext; /* next edge CCW around origin */
+ GLUhalfEdge *Lnext; /* next edge CCW around left face */
+ GLUvertex *Org; /* origin vertex (Overtex too long) */
+ GLUface *Lface; /* left face */
+
+ /* Internal data (keep hidden) */
+ ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
+ int winding; /* change in winding number when crossing
+ from the right face to the left face */
+};
+
+#define Rface Sym->Lface
+#define Dst Sym->Org
+
+#define Oprev Sym->Lnext
+#define Lprev Onext->Sym
+#define Dprev Lnext->Sym
+#define Rprev Sym->Onext
+#define Dnext Rprev->Sym /* 3 pointers */
+#define Rnext Oprev->Sym /* 3 pointers */
+
+
+struct GLUmesh {
+ GLUvertex vHead; /* dummy header for vertex list */
+ GLUface fHead; /* dummy header for face list */
+ GLUhalfEdge eHead; /* dummy header for edge list */
+ GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
+};
+
+/* The mesh operations below have three motivations: completeness,
+ * convenience, and efficiency. The basic mesh operations are MakeEdge,
+ * Splice, and Delete. All the other edge operations can be implemented
+ * in terms of these. The other operations are provided for convenience
+ * and/or efficiency.
+ *
+ * When a face is split or a vertex is added, they are inserted into the
+ * global list *before* the existing vertex or face (ie. e->Org or e->Lface).
+ * This makes it easier to process all vertices or faces in the global lists
+ * without worrying about processing the same data twice. As a convenience,
+ * when a face is split, the "inside" flag is copied from the old face.
+ * Other internal data (v->data, v->activeRegion, f->data, f->marked,
+ * f->trail, e->winding) is set to zero.
+ *
+ * ********************** Basic Edge Operations **************************
+ *
+ * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
+ * The loop (face) consists of the two new half-edges.
+ *
+ * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * ********************** Other Edge Operations **************************
+ *
+ * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * ************************ Other Operations *****************************
+ *
+ * __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ *
+ * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ *
+ * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ *
+ * __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ *
+ * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh );
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+int __gl_meshDelete( GLUhalfEdge *eDel );
+
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+
+GLUmesh *__gl_meshNewMesh( void );
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
+void __gl_meshDeleteMesh( GLUmesh *mesh );
+void __gl_meshZapFace( GLUface *fZap );
+
+#ifdef NDEBUG
+#define __gl_meshCheckMesh( mesh )
+#else
+void __gl_meshCheckMesh( GLUmesh *mesh );
+#endif
+
+#endif
diff --git a/cogl/cogl-path/tesselator/normal.c b/cogl/cogl-path/tesselator/normal.c
new file mode 100644
index 000000000..9a3bd43d3
--- /dev/null
+++ b/cogl/cogl-path/tesselator/normal.c
@@ -0,0 +1,257 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include "mesh.h"
+#include "tess.h"
+#include "normal.h"
+#include <math.h>
+#include <assert.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
+
+#if 0
+static void Normalize( GLdouble v[3] )
+{
+ GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+
+ assert( len > 0 );
+ len = sqrt( len );
+ v[0] /= len;
+ v[1] /= len;
+ v[2] /= len;
+}
+#endif
+
+#undef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+static int LongAxis( GLdouble v[3] )
+{
+ int i = 0;
+
+ if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
+ if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
+ return i;
+}
+
+static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
+{
+ GLUvertex *v, *v1, *v2;
+ GLdouble c, tLen2, maxLen2;
+ GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
+ GLUvertex *maxVert[3], *minVert[3];
+ GLUvertex *vHead = &tess->mesh->vHead;
+ int i;
+
+ maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
+ minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
+
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ for( i = 0; i < 3; ++i ) {
+ c = v->coords[i];
+ if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
+ if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
+ }
+ }
+
+ /* Find two vertices separated by at least 1/sqrt(3) of the maximum
+ * distance between any two vertices
+ */
+ i = 0;
+ if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
+ if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
+ if( minVal[i] >= maxVal[i] ) {
+ /* All vertices are the same -- normal doesn't matter */
+ norm[0] = 0; norm[1] = 0; norm[2] = 1;
+ return;
+ }
+
+ /* Look for a third vertex which forms the triangle with maximum area
+ * (Length of normal == twice the triangle area)
+ */
+ maxLen2 = 0;
+ v1 = minVert[i];
+ v2 = maxVert[i];
+ d1[0] = v1->coords[0] - v2->coords[0];
+ d1[1] = v1->coords[1] - v2->coords[1];
+ d1[2] = v1->coords[2] - v2->coords[2];
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ d2[0] = v->coords[0] - v2->coords[0];
+ d2[1] = v->coords[1] - v2->coords[1];
+ d2[2] = v->coords[2] - v2->coords[2];
+ tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
+ tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
+ tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
+ tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
+ if( tLen2 > maxLen2 ) {
+ maxLen2 = tLen2;
+ norm[0] = tNorm[0];
+ norm[1] = tNorm[1];
+ norm[2] = tNorm[2];
+ }
+ }
+
+ if( maxLen2 <= 0 ) {
+ /* All points lie on a single line -- any decent normal will do */
+ norm[0] = norm[1] = norm[2] = 0;
+ norm[LongAxis(d1)] = 1;
+ }
+}
+
+
+static void CheckOrientation( GLUtesselator *tess )
+{
+ GLdouble area;
+ GLUface *f, *fHead = &tess->mesh->fHead;
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLUhalfEdge *e;
+
+ /* When we compute the normal automatically, we choose the orientation
+ * so that the sum of the signed areas of all contours is non-negative.
+ */
+ area = 0;
+ for( f = fHead->next; f != fHead; f = f->next ) {
+ e = f->anEdge;
+ if( e->winding <= 0 ) continue;
+ do {
+ area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ if( area < 0 ) {
+ /* Reverse the orientation by flipping all the t-coordinates */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->t = - v->t;
+ }
+ tess->tUnit[0] = - tess->tUnit[0];
+ tess->tUnit[1] = - tess->tUnit[1];
+ tess->tUnit[2] = - tess->tUnit[2];
+ }
+}
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#include <stdlib.h>
+extern int RandomSweep;
+#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
+#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
+#else
+#if defined(SLANTED_SWEEP)
+/* The "feature merging" is not intended to be complete. There are
+ * special cases where edges are nearly parallel to the sweep line
+ * which are not implemented. The algorithm should still behave
+ * robustly (ie. produce a reasonable tesselation) in the presence
+ * of such edges, however it may miss features which could have been
+ * merged. We could minimize this effect by choosing the sweep line
+ * direction to be something unusual (ie. not parallel to one of the
+ * coordinate axes).
+ */
+#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
+#define S_UNIT_Y 0.86052074622010633
+#else
+#define S_UNIT_X 1.0
+#define S_UNIT_Y 0.0
+#endif
+#endif
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess )
+{
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLdouble norm[3];
+ GLdouble *sUnit, *tUnit;
+ int i, computedNormal = FALSE;
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm );
+ computedNormal = TRUE;
+ }
+ sUnit = tess->sUnit;
+ tUnit = tess->tUnit;
+ i = LongAxis( norm );
+
+#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
+ /* Choose the initial sUnit vector to be approximately perpendicular
+ * to the normal.
+ */
+ Normalize( norm );
+
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ /* Now make it exactly perpendicular */
+ w = Dot( sUnit, norm );
+ sUnit[0] -= w * norm[0];
+ sUnit[1] -= w * norm[1];
+ sUnit[2] -= w * norm[2];
+ Normalize( sUnit );
+
+ /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
+ tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
+ tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
+ tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
+ Normalize( tUnit );
+#else
+ /* Project perpendicular to a coordinate axis -- better numerically */
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ tUnit[i] = 0;
+ tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
+ tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
+#endif
+
+ /* Project the vertices onto the sweep plane */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->s = Dot( v->coords, sUnit );
+ v->t = Dot( v->coords, tUnit );
+ }
+ if( computedNormal ) {
+ CheckOrientation( tess );
+ }
+}
diff --git a/cogl/cogl-path/tesselator/normal.h b/cogl/cogl-path/tesselator/normal.h
new file mode 100644
index 000000000..c376ca445
--- /dev/null
+++ b/cogl/cogl-path/tesselator/normal.h
@@ -0,0 +1,45 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __normal_h_
+#define __normal_h_
+
+#include "tess.h"
+
+/* __gl_projectPolygon( tess ) determines the polygon normal
+ * and project vertices onto the plane of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess );
+
+#endif
diff --git a/cogl/cogl-path/tesselator/priorityq-heap.c b/cogl/cogl-path/tesselator/priorityq-heap.c
new file mode 100644
index 000000000..52698b59c
--- /dev/null
+++ b/cogl/cogl-path/tesselator/priorityq-heap.c
@@ -0,0 +1,256 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include <stddef.h>
+#include <assert.h>
+#include "priorityq-heap.h"
+#include "memalloc.h"
+
+#define INIT_SIZE 32
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#define LEQ(x,y) (*pq->leq)(x,y)
+#else
+/* Violates modularity, but a little faster */
+#include "geom.h"
+#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
+#endif
+
+/* really __gl_pqHeapNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
+ if (pq->nodes == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
+ if (pq->handles == NULL) {
+ memFree(pq->nodes);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->initialized = FALSE;
+ pq->freeList = 0;
+ pq->leq = leq;
+
+ pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
+ pq->handles[1].key = NULL;
+ return pq;
+}
+
+/* really __gl_pqHeapDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ memFree( pq->handles );
+ memFree( pq->nodes );
+ memFree( pq );
+}
+
+
+static void FloatDown( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hChild;
+ long child;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ child = curr << 1;
+ if( child < pq->size && LEQ( h[n[child+1].handle].key,
+ h[n[child].handle].key )) {
+ ++child;
+ }
+
+ assert(child <= pq->max);
+
+ hChild = n[child].handle;
+ if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hChild;
+ h[hChild].node = curr;
+ curr = child;
+ }
+}
+
+
+static void FloatUp( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hParent;
+ long parent;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ parent = curr >> 1;
+ hParent = n[parent].handle;
+ if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hParent;
+ h[hParent].node = curr;
+ curr = parent;
+ }
+}
+
+/* really __gl_pqHeapInit */
+void pqInit( PriorityQ *pq )
+{
+ long i;
+
+ /* This method of building a heap is O(n), rather than O(n lg n). */
+
+ for( i = pq->size; i >= 1; --i ) {
+ FloatDown( pq, i );
+ }
+ pq->initialized = TRUE;
+}
+
+/* really __gl_pqHeapInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+ PQhandle free_handle;
+
+ curr = ++ pq->size;
+ if( (curr*2) > pq->max ) {
+ PQnode *saveNodes= pq->nodes;
+ PQhandleElem *saveHandles= pq->handles;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->nodes = (PQnode *)memRealloc( pq->nodes,
+ (size_t)
+ ((pq->max + 1) * sizeof( pq->nodes[0] )));
+ if (pq->nodes == NULL) {
+ pq->nodes = saveNodes; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ pq->handles = (PQhandleElem *)memRealloc( pq->handles,
+ (size_t)
+ ((pq->max + 1) *
+ sizeof( pq->handles[0] )));
+ if (pq->handles == NULL) {
+ pq->handles = saveHandles; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+
+ if( pq->freeList == 0 ) {
+ free_handle = curr;
+ } else {
+ free_handle = pq->freeList;
+ pq->freeList = pq->handles[free_handle].node;
+ }
+
+ pq->nodes[curr].handle = free_handle;
+ pq->handles[free_handle].node = curr;
+ pq->handles[free_handle].key = keyNew;
+
+ if( pq->initialized ) {
+ FloatUp( pq, curr );
+ }
+ assert(free_handle != LONG_MAX);
+ return free_handle;
+}
+
+/* really __gl_pqHeapExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hMin = n[1].handle;
+ PQkey min = h[hMin].key;
+
+ if( pq->size > 0 ) {
+ n[1].handle = n[pq->size].handle;
+ h[n[1].handle].node = 1;
+
+ h[hMin].key = NULL;
+ h[hMin].node = pq->freeList;
+ pq->freeList = hMin;
+
+ if( -- pq->size > 0 ) {
+ FloatDown( pq, 1 );
+ }
+ }
+ return min;
+}
+
+/* really __gl_pqHeapDelete */
+void pqDelete( PriorityQ *pq, PQhandle hCurr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ long curr;
+
+ assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
+
+ curr = h[hCurr].node;
+ n[curr].handle = n[pq->size].handle;
+ h[n[curr].handle].node = curr;
+
+ if( curr <= -- pq->size ) {
+ if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
+ FloatDown( pq, curr );
+ } else {
+ FloatUp( pq, curr );
+ }
+ }
+ h[hCurr].key = NULL;
+ h[hCurr].node = pq->freeList;
+ pq->freeList = hCurr;
+}
diff --git a/cogl/cogl-path/tesselator/priorityq-heap.h b/cogl/cogl-path/tesselator/priorityq-heap.h
new file mode 100644
index 000000000..dc9aaef87
--- /dev/null
+++ b/cogl/cogl-path/tesselator/priorityq-heap.h
@@ -0,0 +1,107 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_heap_h_
+#define __priorityq_heap_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQHeapKey
+#define PQhandle PQHeapHandle
+#define PriorityQ PriorityQHeap
+
+#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqHeapInit(pq)
+#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key)
+#define pqMinimum(pq) __gl_pqHeapMinimum(pq)
+#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef void *PQkey;
+typedef long PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+typedef struct { PQhandle handle; } PQnode;
+typedef struct { PQkey key; PQhandle node; } PQhandleElem;
+
+struct PriorityQ {
+ PQnode *nodes;
+ PQhandleElem *handles;
+ long size, max;
+ PQhandle freeList;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+void pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+
+#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
+#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
+
+#endif
diff --git a/cogl/cogl-path/tesselator/priorityq-sort.h b/cogl/cogl-path/tesselator/priorityq-sort.h
new file mode 100644
index 000000000..746cf5fa6
--- /dev/null
+++ b/cogl/cogl-path/tesselator/priorityq-sort.h
@@ -0,0 +1,117 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/cogl/cogl-path/tesselator/priorityq.c b/cogl/cogl-path/tesselator/priorityq.c
new file mode 100644
index 000000000..db7cd5951
--- /dev/null
+++ b/cogl/cogl-path/tesselator/priorityq.c
@@ -0,0 +1,261 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <limits.h> /* LONG_MAX */
+#include "memalloc.h"
+
+/* Include all the code for the regular heap-based queue here. */
+
+#include "priorityq-heap.c"
+
+/* Now redefine all the function names to map to their "Sort" versions. */
+
+#include "priorityq-sort.h"
+
+/* really __gl_pqSortNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->heap = __gl_pqHeapNewPriorityQ( leq );
+ if (pq->heap == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
+ if (pq->keys == NULL) {
+ __gl_pqHeapDeletePriorityQ(pq->heap);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->order = NULL;
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->initialized = FALSE;
+ pq->leq = leq;
+ return pq;
+}
+
+/* really __gl_pqSortDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ assert(pq != NULL);
+ if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
+ if (pq->order != NULL) memFree( pq->order );
+ if (pq->keys != NULL) memFree( pq->keys );
+ memFree( pq );
+}
+
+
+#define LT(x,y) (! LEQ(y,x))
+#define GT(x,y) (! LEQ(x,y))
+#define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
+
+/* really __gl_pqSortInit */
+int pqInit( PriorityQ *pq )
+{
+ PQkey **p, **r, **i, **j, *piv;
+ struct { PQkey **p, **r; } Stack[50], *top = Stack;
+ unsigned long seed = 2016473283;
+
+ /* Create an array of indirect pointers to the keys, so that we
+ * the handles we have returned are still valid.
+ */
+/*
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ (pq->size * sizeof(pq->order[0])) );
+*/
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ ((pq->size+1) * sizeof(pq->order[0])) );
+/* the previous line is a patch to compensate for the fact that IBM */
+/* machines return a null on a malloc of zero bytes (unlike SGI), */
+/* so we have to put in this defense to guard against a memory */
+/* fault four lines down. from fossum@austin.ibm.com. */
+ if (pq->order == NULL) return 0;
+
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
+ *i = piv;
+ }
+
+ /* Sort the indirect pointers in descending order,
+ * using randomized Quicksort
+ */
+ top->p = p; top->r = r; ++top;
+ while( --top >= Stack ) {
+ p = top->p;
+ r = top->r;
+ while( r > p + 10 ) {
+ seed = seed * 1539415821 + 1;
+ i = p + seed % (r - p + 1);
+ piv = *i;
+ *i = *p;
+ *p = piv;
+ i = p - 1;
+ j = r + 1;
+ do {
+ do { ++i; } while( GT( **i, *piv ));
+ do { --j; } while( LT( **j, *piv ));
+ Swap( i, j );
+ } while( i < j );
+ Swap( i, j ); /* Undo last swap */
+ if( i - p < r - j ) {
+ top->p = j+1; top->r = r; ++top;
+ r = i-1;
+ } else {
+ top->p = p; top->r = i-1; ++top;
+ p = j+1;
+ }
+ }
+ /* Insertion sort small lists */
+ for( i = p+1; i <= r; ++i ) {
+ piv = *i;
+ for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
+ *j = *(j-1);
+ }
+ *j = piv;
+ }
+ }
+ pq->max = pq->size;
+ pq->initialized = TRUE;
+ __gl_pqHeapInit( pq->heap ); /* always succeeds */
+
+#ifndef NDEBUG
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( i = p; i < r; ++i ) {
+ assert( LEQ( **(i+1), **i ));
+ }
+#endif
+
+ return 1;
+}
+
+/* really __gl_pqSortInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+
+ if( pq->initialized ) {
+ return __gl_pqHeapInsert( pq->heap, keyNew );
+ }
+ curr = pq->size;
+ if( ++ pq->size >= pq->max ) {
+ PQkey *saveKey= pq->keys;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->keys = (PQHeapKey *)memRealloc( pq->keys,
+ (size_t)
+ (pq->max * sizeof( pq->keys[0] )));
+ if (pq->keys == NULL) {
+ pq->keys = saveKey; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+ assert(curr != LONG_MAX);
+ pq->keys[curr] = keyNew;
+
+ /* Negative handles index the sorted array. */
+ return -(curr+1);
+}
+
+/* really __gl_pqSortExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ }
+ do {
+ -- pq->size;
+ } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
+ return sortMin;
+}
+
+/* really __gl_pqSortMinimum */
+PQkey pqMinimum( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapMinimum( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return heapMin;
+ }
+ }
+ return sortMin;
+}
+
+/* really __gl_pqSortIsEmpty */
+int pqIsEmpty( PriorityQ *pq )
+{
+ return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
+}
+
+/* really __gl_pqSortDelete */
+void pqDelete( PriorityQ *pq, PQhandle curr )
+{
+ if( curr >= 0 ) {
+ __gl_pqHeapDelete( pq->heap, curr );
+ return;
+ }
+ curr = -(curr+1);
+ assert( curr < pq->max && pq->keys[curr] != NULL );
+
+ pq->keys[curr] = NULL;
+ while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
+ -- pq->size;
+ }
+}
diff --git a/cogl/cogl-path/tesselator/priorityq.h b/cogl/cogl-path/tesselator/priorityq.h
new file mode 100644
index 000000000..746cf5fa6
--- /dev/null
+++ b/cogl/cogl-path/tesselator/priorityq.h
@@ -0,0 +1,117 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/cogl/cogl-path/tesselator/render.c b/cogl/cogl-path/tesselator/render.c
new file mode 100644
index 000000000..bca836f04
--- /dev/null
+++ b/cogl/cogl-path/tesselator/render.c
@@ -0,0 +1,502 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include "mesh.h"
+#include "tess.h"
+#include "render.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* This structure remembers the information we need about a primitive
+ * to be able to render it later, once we have determined which
+ * primitive is able to use the most triangles.
+ */
+struct FaceCount {
+ long size; /* number of triangles used */
+ GLUhalfEdge *eStart; /* edge where this primitive starts */
+ void (*render)(GLUtesselator *, GLUhalfEdge *, long);
+ /* routine to render this primitive */
+};
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
+ long size );
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
+
+
+
+/************************ Strips and Fans decomposition ******************/
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+
+ /* Make a list of separate triangles so we can render them all at once */
+ tess->lonelyTriList = NULL;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ f->marked = FALSE;
+ }
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+
+ /* We examine all faces in an arbitrary order. Whenever we find
+ * an unprocessed face F, we output a group of faces including F
+ * whose size is maximum.
+ */
+ if( f->inside && ! f->marked ) {
+ RenderMaximumFaceGroup( tess, f );
+ assert( f->marked );
+ }
+ }
+ if( tess->lonelyTriList != NULL ) {
+ RenderLonelyTriangles( tess, tess->lonelyTriList );
+ tess->lonelyTriList = NULL;
+ }
+}
+
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
+{
+ /* We want to find the largest triangle fan or strip of unmarked faces
+ * which includes the given face fOrig. There are 3 possible fans
+ * passing through fOrig (one centered at each vertex), and 3 possible
+ * strips (one for each CCW permutation of the vertices). Our strategy
+ * is to try all of these, and take the primitive which uses the most
+ * triangles (a greedy approach).
+ */
+ GLUhalfEdge *e = fOrig->anEdge;
+ struct FaceCount max, newFace;
+
+ max.size = 1;
+ max.eStart = e;
+ max.render = &RenderTriangle;
+
+ if( ! tess->flagBoundary ) {
+ newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+
+ newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+ }
+ (*(max.render))( tess, max.eStart, max.size );
+}
+
+
+/* Macros which keep track of faces we have marked temporarily, and allow
+ * us to backtrack when necessary. With triangle fans, this is not
+ * really necessary, since the only awkward case is a loop of triangles
+ * around a single origin vertex. However with strips the situation is
+ * more complicated, and we need a general tracking method like the
+ * one here.
+ */
+#define Marked(f) (! (f)->inside || (f)->marked)
+
+#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
+
+#define FreeTrail(t) do { \
+ while( (t) != NULL ) { \
+ (t)->marked = FALSE; t = (t)->trail; \
+ } \
+ } while(0) /* absorb trailing semicolon */
+
+
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
+{
+ /* eOrig->Lface is the face we want to render. We want to find the size
+ * of a maximal fan around eOrig->Org. To do this we just walk around
+ * the origin vertex as far as possible in both directions.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderFan };
+ GLUface *trail = NULL;
+ GLUhalfEdge *e;
+
+ for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++newFace.size;
+ }
+ for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
+ AddToTrail( e->Rface, trail );
+ ++newFace.size;
+ }
+ newFace.eStart = e;
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+#define IsEven(n) (((n) & 1) == 0)
+
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
+{
+ /* Here we are looking for a maximal strip that contains the vertices
+ * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
+ * reverse, such that all triangles are oriented CCW).
+ *
+ * Again we walk forward and backward as far as possible. However for
+ * strips there is a twist: to get CCW orientations, there must be
+ * an *even* number of triangles in the strip on one side of eOrig.
+ * We walk the strip starting on a side with an even number of triangles;
+ * if both side have an odd number, we are forced to shorten one side.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderStrip };
+ long headSize = 0, tailSize = 0;
+ GLUface *trail = NULL;
+ GLUhalfEdge *e, *eTail, *eHead;
+
+ for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++tailSize;
+ e = e->Dprev;
+ if( Marked( e->Lface )) break;
+ AddToTrail( e->Lface, trail );
+ }
+ eTail = e;
+
+ for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
+ AddToTrail( e->Rface, trail );
+ ++headSize;
+ e = e->Oprev;
+ if( Marked( e->Rface )) break;
+ AddToTrail( e->Rface, trail );
+ }
+ eHead = e;
+
+ newFace.size = tailSize + headSize;
+ if( IsEven( tailSize )) {
+ newFace.eStart = eTail->Sym;
+ } else if( IsEven( headSize )) {
+ newFace.eStart = eHead;
+ } else {
+ /* Both sides have odd length, we must shorten one of them. In fact,
+ * we must start from eHead to guarantee inclusion of eOrig->Lface.
+ */
+ --newFace.size;
+ newFace.eStart = eHead->Onext;
+ }
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Just add the triangle to a triangle list, so we can render all
+ * the separate triangles at once.
+ */
+ assert( size == 1 );
+ AddToTrail( e->Lface, tess->lonelyTriList );
+}
+
+
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
+{
+ /* Now we render all the separate triangles which could not be
+ * grouped into a triangle fan or strip.
+ */
+ GLUhalfEdge *e;
+ int newState;
+ int edgeState = -1; /* force edge state output for first vertex */
+
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
+
+ for( ; f != NULL; f = f->trail ) {
+ /* Loop once for each edge (there will always be 3 edges) */
+
+ e = f->anEdge;
+ do {
+ if( tess->flagBoundary ) {
+ /* Set the "edge state" to TRUE just before we output the
+ * first vertex of each edge on the polygon boundary.
+ */
+ newState = ! e->Rface->inside;
+ if( edgeState != newState ) {
+ edgeState = newState;
+ CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
+ }
+ }
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a fan starting from
+ * edge "e". The fan *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a strip starting from
+ * edge "e". The strip *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Dprev;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ if( Marked( e->Lface )) break;
+
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+/************************ Boundary contour decomposition ******************/
+
+/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
+ * contour for each face marked "inside". The rendering output is
+ * provided as callbacks (see the api).
+ */
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+ GLUhalfEdge *e;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ if( f->inside ) {
+ CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
+ e = f->anEdge;
+ do {
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ CALL_END_OR_END_DATA();
+ }
+ }
+}
+
+
+/************************ Quick-and-dirty decomposition ******************/
+
+#define SIGN_INCONSISTENT 2
+
+static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
+/*
+ * If check==FALSE, we compute the polygon normal and place it in norm[].
+ * If check==TRUE, we check that each triangle in the fan from v0 has a
+ * consistent orientation with respect to norm[]. If triangles are
+ * consistently oriented CCW, return 1; if CW, return -1; if all triangles
+ * are degenerate return 0; otherwise (no consistent orientation) return
+ * SIGN_INCONSISTENT.
+ */
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
+ int sign = 0;
+
+ /* Find the polygon normal. It is important to get a reasonable
+ * normal even when the polygon is self-intersecting (eg. a bowtie).
+ * Otherwise, the computed normal could be very tiny, but perpendicular
+ * to the true plane of the polygon due to numerical noise. Then all
+ * the triangles would appear to be degenerate and we would incorrectly
+ * decompose the polygon as a fan (or simply not render it at all).
+ *
+ * We use a sum-of-triangles normal algorithm rather than the more
+ * efficient sum-of-trapezoids method (used in CheckOrientation()
+ * in normal.c). This lets us explicitly reverse the signed area
+ * of some triangles to get a reasonable normal in the self-intersecting
+ * case.
+ */
+ if( ! check ) {
+ norm[0] = norm[1] = norm[2] = 0.0;
+ }
+
+ vc = v0 + 1;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+ while( ++vc < vn ) {
+ xp = xc; yp = yc; zp = zc;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+
+ /* Compute (vp - v0) cross (vc - v0) */
+ n[0] = yp*zc - zp*yc;
+ n[1] = zp*xc - xp*zc;
+ n[2] = xp*yc - yp*xc;
+
+ dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
+ if( ! check ) {
+ /* Reverse the contribution of back-facing triangles to get
+ * a reasonable normal for self-intersecting polygons (see above)
+ */
+ if( dot >= 0 ) {
+ norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
+ } else {
+ norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
+ }
+ } else if( dot != 0 ) {
+ /* Check the new orientation for consistency with previous triangles */
+ if( dot > 0 ) {
+ if( sign < 0 ) return SIGN_INCONSISTENT;
+ sign = 1;
+ } else {
+ if( sign > 0 ) return SIGN_INCONSISTENT;
+ sign = -1;
+ }
+ }
+ }
+ return sign;
+}
+
+/* __gl_renderCache( tess ) takes a single contour and tries to render it
+ * as a triangle fan. This handles convex polygons, as well as some
+ * non-convex polygons if we get lucky.
+ *
+ * Returns TRUE if the polygon was successfully rendered. The rendering
+ * output is provided as callbacks (see the api).
+ */
+GLboolean __gl_renderCache( GLUtesselator *tess )
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble norm[3];
+ int sign;
+
+ if( tess->cacheCount < 3 ) {
+ /* Degenerate contour -- no output */
+ return TRUE;
+ }
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm, FALSE );
+ }
+
+ sign = ComputeNormal( tess, norm, TRUE );
+ if( sign == SIGN_INCONSISTENT ) {
+ /* Fan triangles did not have a consistent orientation */
+ return FALSE;
+ }
+ if( sign == 0 ) {
+ /* All triangles were degenerate */
+ return TRUE;
+ }
+
+ /* Make sure we do the right thing for each winding rule */
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ break;
+ case GLU_TESS_WINDING_POSITIVE:
+ if( sign < 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_NEGATIVE:
+ if( sign > 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return TRUE;
+ }
+
+ CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
+ : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
+ : GL_TRIANGLES );
+
+ CALL_VERTEX_OR_VERTEX_DATA( v0->data );
+ if( sign > 0 ) {
+ for( vc = v0+1; vc < vn; ++vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ } else {
+ for( vc = vn-1; vc > v0; --vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ }
+ CALL_END_OR_END_DATA();
+ return TRUE;
+}
diff --git a/cogl/cogl-path/tesselator/render.h b/cogl/cogl-path/tesselator/render.h
new file mode 100644
index 000000000..a298c9a94
--- /dev/null
+++ b/cogl/cogl-path/tesselator/render.h
@@ -0,0 +1,52 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __render_h_
+#define __render_h_
+
+#include "mesh.h"
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
+
+GLboolean __gl_renderCache( GLUtesselator *tess );
+
+#endif
diff --git a/cogl/cogl-path/tesselator/sweep.c b/cogl/cogl-path/tesselator/sweep.c
new file mode 100644
index 000000000..eca828ff6
--- /dev/null
+++ b/cogl/cogl-path/tesselator/sweep.c
@@ -0,0 +1,1361 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include <setjmp.h> /* longjmp */
+#include <limits.h> /* LONG_MAX */
+
+#include "mesh.h"
+#include "geom.h"
+#include "tess.h"
+#include "dict.h"
+#include "priorityq.h"
+#include "memalloc.h"
+#include "sweep.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+extern void DebugEvent( GLUtesselator *tess );
+#else
+#define DebugEvent( tess )
+#endif
+
+/*
+ * Invariants for the Edge Dictionary.
+ * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ * at any valid location of the sweep event
+ * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ * share a common endpoint
+ * - for each e, e->Dst has been processed, but not e->Org
+ * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+ * where "event" is the current sweep line event.
+ * - no edge e has zero length
+ *
+ * Invariants for the Mesh (the processed portion).
+ * - the portion of the mesh left of the sweep line is a planar graph,
+ * ie. there is *some* way to embed it in the plane
+ * - no processed edge has zero length
+ * - no two processed vertices have identical coordinates
+ * - each "inside" region is monotone, ie. can be broken into two chains
+ * of monotonically increasing vertices according to VertLeq(v1,v2)
+ * - a non-invariant: these chains may intersect (very slightly)
+ *
+ * Invariants for the Sweep.
+ * - if none of the edges incident to the event vertex have an activeRegion
+ * (ie. none of these edges are in the edge dictionary), then the vertex
+ * has only right-going edges.
+ * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ * by ConnectRightVertex), then it is the only right-going edge from
+ * its associated vertex. (This says that these edges exist only
+ * when it is necessary.)
+ */
+
+#undef MAX
+#undef MIN
+#define MAX(x,y) ((x) >= (y) ? (x) : (y))
+#define MIN(x,y) ((x) <= (y) ? (x) : (y))
+
+/* When we merge two edges into one, we need to compute the combined
+ * winding of the new edge.
+ */
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );
+
+static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,
+ ActiveRegion *reg2 )
+/*
+ * Both edges must be directed from right to left (this is the canonical
+ * direction for the upper edge of each region).
+ *
+ * The strategy is to evaluate a "t" value for each edge at the
+ * current sweep line position, given by tess->event. The calculations
+ * are designed to be very stable, but of course they are not perfect.
+ *
+ * Special case: if both edge destinations are at the sweep event,
+ * we sort the edges by slope (they would otherwise compare equally).
+ */
+{
+ GLUvertex *event = tess->event;
+ GLUhalfEdge *e1, *e2;
+ GLdouble t1, t2;
+
+ e1 = reg1->eUp;
+ e2 = reg2->eUp;
+
+ if( e1->Dst == event ) {
+ if( e2->Dst == event ) {
+ /* Two edges right of the sweep line which meet at the sweep event.
+ * Sort them by slope.
+ */
+ if( VertLeq( e1->Org, e2->Org )) {
+ return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
+ }
+ return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
+ }
+ return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
+ }
+ if( e2->Dst == event ) {
+ return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
+ }
+
+ /* General case - compute signed distance *from* e1, e2 to event */
+ t1 = EdgeEval( e1->Dst, event, e1->Org );
+ t2 = EdgeEval( e2->Dst, event, e2->Org );
+ return (t1 >= t2);
+}
+
+
+static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg )
+{
+ if( reg->fixUpperEdge ) {
+ /* It was created with zero winding number, so it better be
+ * deleted with zero winding number (ie. it better not get merged
+ * with a real edge).
+ */
+ assert( reg->eUp->winding == 0 );
+ }
+ reg->eUp->activeRegion = NULL;
+ dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */
+ memFree( reg );
+}
+
+
+static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )
+/*
+ * Replace an upper edge which needs fixing (see ConnectRightVertex).
+ */
+{
+ assert( reg->fixUpperEdge );
+ if ( !__gl_meshDelete( reg->eUp ) ) return 0;
+ reg->fixUpperEdge = FALSE;
+ reg->eUp = newEdge;
+ newEdge->activeRegion = reg;
+
+ return 1;
+}
+
+static ActiveRegion *TopLeftRegion( ActiveRegion *reg )
+{
+ GLUvertex *org = reg->eUp->Org;
+ GLUhalfEdge *e;
+
+ /* Find the region above the uppermost edge with the same origin */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Org == org );
+
+ /* If the edge above was a temporary edge introduced by ConnectRightVertex,
+ * now is the time to fix it.
+ */
+ if( reg->fixUpperEdge ) {
+ e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
+ if (e == NULL) return NULL;
+ if ( !FixUpperEdge( reg, e ) ) return NULL;
+ reg = RegionAbove( reg );
+ }
+ return reg;
+}
+
+static ActiveRegion *TopRightRegion( ActiveRegion *reg )
+{
+ GLUvertex *dst = reg->eUp->Dst;
+
+ /* Find the region above the uppermost edge with the same destination */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Dst == dst );
+ return reg;
+}
+
+static ActiveRegion *AddRegionBelow( GLUtesselator *tess,
+ ActiveRegion *regAbove,
+ GLUhalfEdge *eNewUp )
+/*
+ * Add a new active region to the sweep line, *somewhere* below "regAbove"
+ * (according to where the new edge belongs in the sweep-line dictionary).
+ * The upper edge of the new region will be "eNewUp".
+ * Winding number and "inside" flag are not updated.
+ */
+{
+ ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (regNew == NULL) longjmp(tess->env,1);
+
+ regNew->eUp = eNewUp;
+ /* __gl_dictListInsertBefore */
+ regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
+ if (regNew->nodeUp == NULL) longjmp(tess->env,1);
+ regNew->fixUpperEdge = FALSE;
+ regNew->sentinel = FALSE;
+ regNew->dirty = FALSE;
+
+ eNewUp->activeRegion = regNew;
+ return regNew;
+}
+
+static GLboolean IsWindingInside( GLUtesselator *tess, int n )
+{
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ return (n & 1);
+ case GLU_TESS_WINDING_NONZERO:
+ return (n != 0);
+ case GLU_TESS_WINDING_POSITIVE:
+ return (n > 0);
+ case GLU_TESS_WINDING_NEGATIVE:
+ return (n < 0);
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return (n >= 2) || (n <= -2);
+ }
+ /*LINTED*/
+ assert( FALSE );
+ /*NOTREACHED*/
+ return GL_FALSE; /* avoid compiler complaints */
+}
+
+
+static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg )
+{
+ reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+}
+
+
+static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )
+/*
+ * Delete a region from the sweep line. This happens when the upper
+ * and lower chains of a region meet (at a vertex on the sweep line).
+ * The "inside" flag is copied to the appropriate mesh face (we could
+ * not do this before -- since the structure of the mesh is always
+ * changing, this face may not have even existed until now).
+ */
+{
+ GLUhalfEdge *e = reg->eUp;
+ GLUface *f = e->Lface;
+
+ f->inside = reg->inside;
+ f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */
+ DeleteRegion( tess, reg );
+}
+
+
+static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,
+ ActiveRegion *regFirst, ActiveRegion *regLast )
+/*
+ * We are given a vertex with one or more left-going edges. All affected
+ * edges should be in the edge dictionary. Starting at regFirst->eUp,
+ * we walk down deleting all regions where both edges have the same
+ * origin vOrg. At the same time we copy the "inside" flag from the
+ * active region to the face, since at this point each face will belong
+ * to at most one region (this was not necessarily true until this point
+ * in the sweep). The walk stops at the region above regLast; if regLast
+ * is NULL we walk as far as possible. At the same time we relink the
+ * mesh if necessary, so that the ordering of edges around vOrg is the
+ * same as in the dictionary.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ regPrev = regFirst;
+ ePrev = regFirst->eUp;
+ while( regPrev != regLast ) {
+ regPrev->fixUpperEdge = FALSE; /* placement was OK */
+ reg = RegionBelow( regPrev );
+ e = reg->eUp;
+ if( e->Org != ePrev->Org ) {
+ if( ! reg->fixUpperEdge ) {
+ /* Remove the last left-going edge. Even though there are no further
+ * edges in the dictionary with this origin, there may be further
+ * such edges in the mesh (if we are adding left edges to a vertex
+ * that has already been processed). Thus it is important to call
+ * FinishRegion rather than just DeleteRegion.
+ */
+ FinishRegion( tess, regPrev );
+ break;
+ }
+ /* If the edge below was a temporary edge introduced by
+ * ConnectRightVertex, now is the time to fix it.
+ */
+ e = __gl_meshConnect( ePrev->Lprev, e->Sym );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
+ }
+
+ /* Relink edges so that ePrev->Onext == e */
+ if( ePrev->Onext != e ) {
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
+ }
+ FinishRegion( tess, regPrev ); /* may change reg->eUp */
+ ePrev = reg->eUp;
+ regPrev = reg;
+ }
+ return ePrev;
+}
+
+
+static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,
+ GLboolean cleanUp )
+/*
+ * Purpose: insert right-going edges into the edge dictionary, and update
+ * winding numbers and mesh connectivity appropriately. All right-going
+ * edges share a common origin vOrg. Edges are inserted CCW starting at
+ * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any
+ * left-going edges already processed, then eTopLeft must be the edge
+ * such that an imaginary upward vertical segment from vOrg would be
+ * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft
+ * should be NULL.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+ int firstTime = TRUE;
+
+ /* Insert the new right-going edges in the dictionary */
+ e = eFirst;
+ do {
+ assert( VertLeq( e->Org, e->Dst ));
+ AddRegionBelow( tess, regUp, e->Sym );
+ e = e->Onext;
+ } while ( e != eLast );
+
+ /* Walk *all* right-going edges from e->Org, in the dictionary order,
+ * updating the winding numbers of each region, and re-linking the mesh
+ * edges to match the dictionary ordering (if necessary).
+ */
+ if( eTopLeft == NULL ) {
+ eTopLeft = RegionBelow( regUp )->eUp->Rprev;
+ }
+ regPrev = regUp;
+ ePrev = eTopLeft;
+ for( ;; ) {
+ reg = RegionBelow( regPrev );
+ e = reg->eUp->Sym;
+ if( e->Org != ePrev->Org ) break;
+
+ if( e->Onext != ePrev ) {
+ /* Unlink e from its current position, and relink below ePrev */
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
+ }
+ /* Compute the winding number and "inside" flag for the new regions */
+ reg->windingNumber = regPrev->windingNumber - e->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+
+ /* Check for two outgoing edges with same slope -- process these
+ * before any intersection tests (see example in __gl_computeInterior).
+ */
+ regPrev->dirty = TRUE;
+ if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
+ AddWinding( e, ePrev );
+ DeleteRegion( tess, regPrev );
+ if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
+ }
+ firstTime = FALSE;
+ regPrev = reg;
+ ePrev = e;
+ }
+ regPrev->dirty = TRUE;
+ assert( regPrev->windingNumber - e->winding == reg->windingNumber );
+
+ if( cleanUp ) {
+ /* Check for intersections between newly adjacent edges. */
+ WalkDirtyRegions( tess, regPrev );
+ }
+}
+
+
+static void CallCombine( GLUtesselator *tess, GLUvertex *isect,
+ void *data[4], GLfloat weights[4], int needed )
+{
+ GLdouble coords[3];
+
+ /* Copy coord data in case the callback changes it. */
+ coords[0] = isect->coords[0];
+ coords[1] = isect->coords[1];
+ coords[2] = isect->coords[2];
+
+ isect->data = NULL;
+ CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
+ if( isect->data == NULL ) {
+ if( ! needed ) {
+ isect->data = data[0];
+ } else if( ! tess->fatalError ) {
+ /* The only way fatal error is when two edges are found to intersect,
+ * but the user has not provided the callback necessary to handle
+ * generated intersection points.
+ */
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
+ tess->fatalError = TRUE;
+ }
+ }
+}
+
+static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,
+ GLUhalfEdge *e2 )
+/*
+ * Two vertices with idential coordinates are combined into one.
+ * e1->Org is kept, while e2->Org is discarded.
+ */
+{
+ void *data[4] = { NULL, NULL, NULL, NULL };
+ GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
+
+ data[0] = e1->Org->data;
+ data[1] = e2->Org->data;
+ CallCombine( tess, e1->Org, data, weights, FALSE );
+ if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
+}
+
+static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,
+ GLfloat *weights )
+/*
+ * Find some weights which describe how the intersection vertex is
+ * a linear combination of "org" and "dest". Each of the two edges
+ * which generated "isect" is allocated 50% of the weight; each edge
+ * splits the weight between its org and dst according to the
+ * relative distance to "isect".
+ */
+{
+ GLdouble t1 = VertL1dist( org, isect );
+ GLdouble t2 = VertL1dist( dst, isect );
+
+ weights[0] = 0.5 * t2 / (t1 + t2);
+ weights[1] = 0.5 * t1 / (t1 + t2);
+ isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
+ isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
+ isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
+}
+
+
+static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,
+ GLUvertex *orgUp, GLUvertex *dstUp,
+ GLUvertex *orgLo, GLUvertex *dstLo )
+/*
+ * We've computed a new intersection point, now we need a "data" pointer
+ * from the user so that we can refer to this new vertex in the
+ * rendering callbacks.
+ */
+{
+ void *data[4];
+ GLfloat weights[4];
+
+ data[0] = orgUp->data;
+ data[1] = dstUp->data;
+ data[2] = orgLo->data;
+ data[3] = dstLo->data;
+
+ isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
+ VertexWeights( isect, orgUp, dstUp, &weights[0] );
+ VertexWeights( isect, orgLo, dstLo, &weights[2] );
+
+ CallCombine( tess, isect, data, weights, TRUE );
+}
+
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which
+ * origin is leftmost).
+ *
+ * The main purpose is to splice right-going edges with the same
+ * dest vertex and nearly identical slopes (ie. we can't distinguish
+ * the slopes numerically). However the splicing can also help us
+ * to recover from numerical errors. For example, suppose at one
+ * point we checked eUp and eLo, and decided that eUp->Org is barely
+ * above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * our test so that now eUp->Org is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants.
+ *
+ * One possibility is to check these edges for intersection again
+ * (ie. CheckForIntersect). This is what we do if possible. However
+ * CheckForIntersect requires that tess->event lies between eUp and eLo,
+ * so that it has something to fall back on when the intersection
+ * calculation gives us an unusable answer. So, for those cases where
+ * we can't check for intersection, this routine fixes the problem
+ * by just splicing the offending vertex into the other edge.
+ * This is a guaranteed solution, no matter how degenerate things get.
+ * Basically this is a combinatorial solution to a numerical problem.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+
+ if( VertLeq( eUp->Org, eLo->Org )) {
+ if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Org appears to be below eLo */
+ if( ! VertEq( eUp->Org, eLo->Org )) {
+ /* Splice eUp->Org into eLo */
+ if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
+ regUp->dirty = regLo->dirty = TRUE;
+
+ } else if( eUp->Org != eLo->Org ) {
+ /* merge the two vertices, discarding eUp->Org */
+ pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */
+ SpliceMergeVertices( tess, eLo->Oprev, eUp );
+ }
+ } else {
+ if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ }
+ return TRUE;
+}
+
+static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which
+ * destination is rightmost).
+ *
+ * Theoretically, this should always be true. However, splitting an edge
+ * into two pieces can change the results of previous tests. For example,
+ * suppose at one point we checked eUp and eLo, and decided that eUp->Dst
+ * is barely above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * the test so that now eUp->Dst is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants
+ * (otherwise new edges might get inserted in the wrong place in the
+ * dictionary, and bad stuff will happen).
+ *
+ * We fix the problem by just splicing the offending vertex into the
+ * other edge.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( eUp->Dst, eLo->Dst ));
+
+ if( VertLeq( eUp->Dst, eLo->Dst )) {
+ if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ e = __gl_meshSplitEdge( eUp );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
+ e->Lface->inside = regUp->inside;
+ } else {
+ if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */
+ regUp->dirty = regLo->dirty = TRUE;
+ e = __gl_meshSplitEdge( eLo );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
+ e->Rface->inside = regUp->inside;
+ }
+ return TRUE;
+}
+
+
+static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edges of the given region to see if
+ * they intersect. If so, create the intersection and add it
+ * to the data structures.
+ *
+ * Returns TRUE if adding the new intersection resulted in a recursive
+ * call to AddRightEdges(); in this case all "dirty" regions have been
+ * checked for intersections, and possibly regUp has been deleted.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUvertex *orgUp = eUp->Org;
+ GLUvertex *orgLo = eLo->Org;
+ GLUvertex *dstUp = eUp->Dst;
+ GLUvertex *dstLo = eLo->Dst;
+ GLdouble tMinUp, tMaxLo;
+ GLUvertex isect, *orgMin;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( dstLo, dstUp ));
+ assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
+ assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
+ assert( orgUp != tess->event && orgLo != tess->event );
+ assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
+
+ if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */
+
+ tMinUp = MIN( orgUp->t, dstUp->t );
+ tMaxLo = MAX( orgLo->t, dstLo->t );
+ if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */
+
+ if( VertLeq( orgUp, orgLo )) {
+ if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE;
+ } else {
+ if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE;
+ }
+
+ /* At this point the edges intersect, at least marginally */
+ DebugEvent( tess );
+
+ __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
+ /* The following properties are guaranteed: */
+ assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
+ assert( isect.t <= MAX( orgLo->t, dstLo->t ));
+ assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
+ assert( isect.s <= MAX( orgLo->s, orgUp->s ));
+
+ if( VertLeq( &isect, tess->event )) {
+ /* The intersection point lies slightly to the left of the sweep line,
+ * so move it until it''s slightly to the right of the sweep line.
+ * (If we had perfect numerical precision, this would never happen
+ * in the first place). The easiest and safest thing to do is
+ * replace the intersection by tess->event.
+ */
+ isect.s = tess->event->s;
+ isect.t = tess->event->t;
+ }
+ /* Similarly, if the computed intersection lies to the right of the
+ * rightmost origin (which should rarely happen), it can cause
+ * unbelievable inefficiency on sufficiently degenerate inputs.
+ * (If you have the test program, try running test54.d with the
+ * "X zoom" option turned on).
+ */
+ orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
+ if( VertLeq( orgMin, &isect )) {
+ isect.s = orgMin->s;
+ isect.t = orgMin->t;
+ }
+
+ if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
+ /* Easy case -- intersection at one of the right endpoints */
+ (void) CheckForRightSplice( tess, regUp );
+ return FALSE;
+ }
+
+ if( (! VertEq( dstUp, tess->event )
+ && EdgeSign( dstUp, tess->event, &isect ) >= 0)
+ || (! VertEq( dstLo, tess->event )
+ && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
+ {
+ /* Very unusual -- the new upper or lower edge would pass on the
+ * wrong side of the sweep event, or through it. This can happen
+ * due to very small numerical errors in the intersection calculation.
+ */
+ if( dstLo == tess->event ) {
+ /* Splice dstLo into eUp, and process the new region(s) */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eUp = RegionBelow(regUp)->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
+ return TRUE;
+ }
+ if( dstUp == tess->event ) {
+ /* Splice dstUp into eLo, and process the new region(s) */
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
+ regLo = regUp;
+ regUp = TopRightRegion( regUp );
+ e = RegionBelow(regUp)->eUp->Rprev;
+ regLo->eUp = eLo->Oprev;
+ eLo = FinishLeftRegions( tess, regLo, NULL );
+ AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
+ return TRUE;
+ }
+ /* Special case: called from ConnectRightVertex. If either
+ * edge passes on the wrong side of tess->event, split it
+ * (and wait for ConnectRightVertex to splice it appropriately).
+ */
+ if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ eUp->Org->s = tess->event->s;
+ eUp->Org->t = tess->event->t;
+ }
+ if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
+ regUp->dirty = regLo->dirty = TRUE;
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ eLo->Org->s = tess->event->s;
+ eLo->Org->t = tess->event->t;
+ }
+ /* leave the rest for ConnectRightVertex */
+ return FALSE;
+ }
+
+ /* General case -- split both edges, splice into new vertex.
+ * When we do the splice operation, the order of the arguments is
+ * arbitrary as far as correctness goes. However, when the operation
+ * creates a new face, the work done is proportional to the size of
+ * the new face. We expect the faces in the processed part of
+ * the mesh (ie. eUp->Lface) to be smaller than the faces in the
+ * unprocessed original contours (which will be eLo->Oprev->Lface).
+ */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ eUp->Org->s = isect.s;
+ eUp->Org->t = isect.t;
+ eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */
+ if (eUp->Org->pqHandle == LONG_MAX) {
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ longjmp(tess->env,1);
+ }
+ GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
+ RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
+ return FALSE;
+}
+
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * When the upper or lower edge of any region changes, the region is
+ * marked "dirty". This routine walks through all the dirty regions
+ * and makes sure that the dictionary invariants are satisfied
+ * (see the comments at the beginning of this file). Of course
+ * new dirty regions can be created as we make changes to restore
+ * the invariants.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp, *eLo;
+
+ for( ;; ) {
+ /* Find the lowest dirty region (we walk from the bottom up). */
+ while( regLo->dirty ) {
+ regUp = regLo;
+ regLo = RegionBelow(regLo);
+ }
+ if( ! regUp->dirty ) {
+ regLo = regUp;
+ regUp = RegionAbove( regUp );
+ if( regUp == NULL || ! regUp->dirty ) {
+ /* We've walked all the dirty regions */
+ return;
+ }
+ }
+ regUp->dirty = FALSE;
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ if( eUp->Dst != eLo->Dst ) {
+ /* Check that the edge ordering is obeyed at the Dst vertices. */
+ if( CheckForLeftSplice( tess, regUp )) {
+
+ /* If the upper or lower edge was marked fixUpperEdge, then
+ * we no longer need it (since these edges are needed only for
+ * vertices which otherwise have no right-going edges).
+ */
+ if( regLo->fixUpperEdge ) {
+ DeleteRegion( tess, regLo );
+ if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
+ regLo = RegionBelow( regUp );
+ eLo = regLo->eUp;
+ } else if( regUp->fixUpperEdge ) {
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ eUp = regUp->eUp;
+ }
+ }
+ }
+ if( eUp->Org != eLo->Org ) {
+ if( eUp->Dst != eLo->Dst
+ && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
+ && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
+ {
+ /* When all else fails in CheckForIntersect(), it uses tess->event
+ * as the intersection location. To make this possible, it requires
+ * that tess->event lie between the upper and lower edges, and also
+ * that neither of these is marked fixUpperEdge (since in the worst
+ * case it might splice one of these edges into tess->event, and
+ * violate the invariant that fixable edges are the only right-going
+ * edge from their associated vertex).
+ */
+ if( CheckForIntersect( tess, regUp )) {
+ /* WalkDirtyRegions() was called recursively; we're done */
+ return;
+ }
+ } else {
+ /* Even though we can't use CheckForIntersect(), the Org vertices
+ * may violate the dictionary edge ordering. Check and correct this.
+ */
+ (void) CheckForRightSplice( tess, regUp );
+ }
+ }
+ if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
+ /* A degenerate loop consisting of only two edges -- delete it. */
+ AddWinding( eLo, eUp );
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ }
+ }
+}
+
+
+static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eBottomLeft )
+/*
+ * Purpose: connect a "right" vertex vEvent (one where all edges go left)
+ * to the unprocessed portion of the mesh. Since there are no right-going
+ * edges, two regions (one above vEvent and one below) are being merged
+ * into one. "regUp" is the upper of these two regions.
+ *
+ * There are two reasons for doing this (adding a right-going edge):
+ * - if the two regions being merged are "inside", we must add an edge
+ * to keep them separated (the combined region would not be monotone).
+ * - in any case, we must leave some record of vEvent in the dictionary,
+ * so that we can merge vEvent with features that we have not seen yet.
+ * For example, maybe there is a vertical edge which passes just to
+ * the right of vEvent; we would like to splice vEvent into this edge.
+ *
+ * However, we don't want to connect vEvent to just any vertex. We don''t
+ * want the new edge to cross any other edges; otherwise we will create
+ * intersection vertices even when the input data had no self-intersections.
+ * (This is a bad thing; if the user's input data has no intersections,
+ * we don't want to generate any false intersections ourselves.)
+ *
+ * Our eventual goal is to connect vEvent to the leftmost unprocessed
+ * vertex of the combined region (the union of regUp and regLo).
+ * But because of unseen vertices with all right-going edges, and also
+ * new vertices which may be created by edge intersections, we don''t
+ * know where that leftmost unprocessed vertex is. In the meantime, we
+ * connect vEvent to the closest vertex of either chain, and mark the region
+ * as "fixUpperEdge". This flag says to delete and reconnect this edge
+ * to the next processed vertex on the boundary of the combined region.
+ * Quite possibly the vertex we connected to will turn out to be the
+ * closest one, in which case we won''t need to make any changes.
+ */
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *eTopLeft = eBottomLeft->Onext;
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ int degenerate = FALSE;
+
+ if( eUp->Dst != eLo->Dst ) {
+ (void) CheckForIntersect( tess, regUp );
+ }
+
+ /* Possible new degeneracies: upper or lower edge of regUp may pass
+ * through vEvent, or may coincide with new intersection vertex
+ */
+ if( VertEq( eUp->Org, tess->event )) {
+ if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eTopLeft = RegionBelow( regUp )->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ degenerate = TRUE;
+ }
+ if( VertEq( eLo->Org, tess->event )) {
+ if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
+ eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
+ degenerate = TRUE;
+ }
+ if( degenerate ) {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ return;
+ }
+
+ /* Non-degenerate situation -- need to add a temporary, fixable edge.
+ * Connect to the closer of eLo->Org, eUp->Org.
+ */
+ if( VertLeq( eLo->Org, eUp->Org )) {
+ eNew = eLo->Oprev;
+ } else {
+ eNew = eUp;
+ }
+ eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
+ if (eNew == NULL) longjmp(tess->env,1);
+
+ /* Prevent cleanup, otherwise eNew might disappear before we've even
+ * had a chance to mark it as a temporary edge.
+ */
+ AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
+ eNew->Sym->activeRegion->fixUpperEdge = TRUE;
+ WalkDirtyRegions( tess, regUp );
+}
+
+/* Because vertices at exactly the same location are merged together
+ * before we process the sweep event, some degenerate cases can't occur.
+ * However if someone eventually makes the modifications required to
+ * merge features which are close together, the cases below marked
+ * TOLERANCE_NONZERO will be useful. They were debugged before the
+ * code to merge identical vertices in the main loop was added.
+ */
+#define TOLERANCE_NONZERO FALSE
+
+static void ConnectLeftDegenerate( GLUtesselator *tess,
+ ActiveRegion *regUp, GLUvertex *vEvent )
+/*
+ * The event vertex lies exacty on an already-processed edge or vertex.
+ * Adding the new vertex involves splicing it into the already-processed
+ * part of the mesh.
+ */
+{
+ GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast;
+ ActiveRegion *reg;
+
+ e = regUp->eUp;
+ if( VertEq( e->Org, vEvent )) {
+ /* e->Org is an unprocessed vertex - just combine them, and wait
+ * for e->Org to be pulled from the queue
+ */
+ assert( TOLERANCE_NONZERO );
+ SpliceMergeVertices( tess, e, vEvent->anEdge );
+ return;
+ }
+
+ if( ! VertEq( e->Dst, vEvent )) {
+ /* General case -- splice vEvent into edge e which passes through it */
+ if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
+ if( regUp->fixUpperEdge ) {
+ /* This edge was fixable -- delete unused portion of original edge */
+ if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
+ regUp->fixUpperEdge = FALSE;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
+ SweepEvent( tess, vEvent ); /* recurse */
+ return;
+ }
+
+ /* vEvent coincides with e->Dst, which has already been processed.
+ * Splice in the additional right-going edges.
+ */
+ assert( TOLERANCE_NONZERO );
+ regUp = TopRightRegion( regUp );
+ reg = RegionBelow( regUp );
+ eTopRight = reg->eUp->Sym;
+ eTopLeft = eLast = eTopRight->Onext;
+ if( reg->fixUpperEdge ) {
+ /* Here e->Dst has only a single fixable edge going right.
+ * We can delete it since now we have some real right-going edges.
+ */
+ assert( eTopLeft != eTopRight ); /* there are some left edges too */
+ DeleteRegion( tess, reg );
+ if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
+ eTopRight = eTopLeft->Oprev;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
+ if( ! EdgeGoesLeft( eTopLeft )) {
+ /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */
+ eTopLeft = NULL;
+ }
+ AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
+}
+
+
+static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Purpose: connect a "left" vertex (one where both edges go right)
+ * to the processed portion of the mesh. Let R be the active region
+ * containing vEvent, and let U and L be the upper and lower edge
+ * chains of R. There are two possibilities:
+ *
+ * - the normal case: split R into two regions, by connecting vEvent to
+ * the rightmost vertex of U or L lying to the left of the sweep line
+ *
+ * - the degenerate case: if vEvent is close enough to U or L, we
+ * merge vEvent into that edge chain. The subcases are:
+ * - merging with the rightmost vertex of U or L
+ * - merging with the active edge of U or L
+ * - merging with an already-processed portion of U or L
+ */
+{
+ ActiveRegion *regUp, *regLo, *reg;
+ GLUhalfEdge *eUp, *eLo, *eNew;
+ ActiveRegion tmp;
+
+ /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
+
+ /* Get a pointer to the active region containing vEvent */
+ tmp.eUp = vEvent->anEdge->Sym;
+ /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
+ regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
+ regLo = RegionBelow( regUp );
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ /* Try merging with U or L first */
+ if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
+ ConnectLeftDegenerate( tess, regUp, vEvent );
+ return;
+ }
+
+ /* Connect vEvent to rightmost processed vertex of either chain.
+ * e->Dst is the vertex that we will connect to vEvent.
+ */
+ reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
+
+ if( regUp->inside || reg->fixUpperEdge) {
+ if( reg == regUp ) {
+ eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
+ if (eNew == NULL) longjmp(tess->env,1);
+ } else {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
+ if (tempHalfEdge == NULL) longjmp(tess->env,1);
+
+ eNew = tempHalfEdge->Sym;
+ }
+ if( reg->fixUpperEdge ) {
+ if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
+ } else {
+ ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
+ }
+ SweepEvent( tess, vEvent );
+ } else {
+ /* The new vertex is in a region which does not belong to the polygon.
+ * We don''t need to connect this vertex to the rest of the mesh.
+ */
+ AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
+ }
+}
+
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Does everything necessary when the sweep line crosses a vertex.
+ * Updates the mesh and the edge dictionary.
+ */
+{
+ ActiveRegion *regUp, *reg;
+ GLUhalfEdge *e, *eTopLeft, *eBottomLeft;
+
+ tess->event = vEvent; /* for access in EdgeLeq() */
+ DebugEvent( tess );
+
+ /* Check if this vertex is the right endpoint of an edge that is
+ * already in the dictionary. In this case we don't need to waste
+ * time searching for the location to insert new edges.
+ */
+ e = vEvent->anEdge;
+ while( e->activeRegion == NULL ) {
+ e = e->Onext;
+ if( e == vEvent->anEdge ) {
+ /* All edges go right -- not incident to any processed edges */
+ ConnectLeftVertex( tess, vEvent );
+ return;
+ }
+ }
+
+ /* Processing consists of two phases: first we "finish" all the
+ * active regions where both the upper and lower edges terminate
+ * at vEvent (ie. vEvent is closing off these regions).
+ * We mark these faces "inside" or "outside" the polygon according
+ * to their winding number, and delete the edges from the dictionary.
+ * This takes care of all the left-going edges from vEvent.
+ */
+ regUp = TopLeftRegion( e->activeRegion );
+ if (regUp == NULL) longjmp(tess->env,1);
+ reg = RegionBelow( regUp );
+ eTopLeft = reg->eUp;
+ eBottomLeft = FinishLeftRegions( tess, reg, NULL );
+
+ /* Next we process all the right-going edges from vEvent. This
+ * involves adding the edges to the dictionary, and creating the
+ * associated "active regions" which record information about the
+ * regions between adjacent dictionary edges.
+ */
+ if( eBottomLeft->Onext == eTopLeft ) {
+ /* No right-going edges -- add a temporary "fixable" edge */
+ ConnectRightVertex( tess, regUp, eBottomLeft );
+ } else {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ }
+}
+
+
+/* Make the sentinel coordinates big enough that they will never be
+ * merged with real input features. (Even with the largest possible
+ * input contour and the maximum tolerance of 1.0, no merging will be
+ * done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
+ */
+#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD)
+
+static void AddSentinel( GLUtesselator *tess, GLdouble t )
+/*
+ * We add two sentinel edges above and below all other edges,
+ * to avoid special cases at the top and bottom.
+ */
+{
+ GLUhalfEdge *e;
+ ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (reg == NULL) longjmp(tess->env,1);
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) longjmp(tess->env,1);
+
+ e->Org->s = SENTINEL_COORD;
+ e->Org->t = t;
+ e->Dst->s = -SENTINEL_COORD;
+ e->Dst->t = t;
+ tess->event = e->Dst; /* initialize it */
+
+ reg->eUp = e;
+ reg->windingNumber = 0;
+ reg->inside = FALSE;
+ reg->fixUpperEdge = FALSE;
+ reg->sentinel = TRUE;
+ reg->dirty = FALSE;
+ reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */
+ if (reg->nodeUp == NULL) longjmp(tess->env,1);
+}
+
+
+static void InitEdgeDict( GLUtesselator *tess )
+/*
+ * We maintain an ordering of edge intersections with the sweep line.
+ * This order is maintained in a dynamic dictionary.
+ */
+{
+ /* __gl_dictListNewDict */
+ tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq );
+ if (tess->dict == NULL) longjmp(tess->env,1);
+
+ AddSentinel( tess, -SENTINEL_COORD );
+ AddSentinel( tess, SENTINEL_COORD );
+}
+
+
+static void DoneEdgeDict( GLUtesselator *tess )
+{
+ ActiveRegion *reg;
+#ifndef NDEBUG
+ int fixedEdges = 0;
+#endif
+
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
+ /*
+ * At the end of all processing, the dictionary should contain
+ * only the two sentinel edges, plus at most one "fixable" edge
+ * created by ConnectRightVertex().
+ */
+ if( ! reg->sentinel ) {
+ assert( reg->fixUpperEdge );
+ assert( ++fixedEdges == 1 );
+ }
+ assert( reg->windingNumber == 0 );
+ DeleteRegion( tess, reg );
+/* __gl_meshDelete( reg->eUp );*/
+ }
+ dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */
+}
+
+
+static void RemoveDegenerateEdges( GLUtesselator *tess )
+/*
+ * Remove zero-length edges, and contours with fewer than 3 vertices.
+ */
+{
+ GLUhalfEdge *e, *eNext, *eLnext;
+ GLUhalfEdge *eHead = &tess->mesh->eHead;
+
+ /*LINTED*/
+ for( e = eHead->next; e != eHead; e = eNext ) {
+ eNext = e->next;
+ eLnext = e->Lnext;
+
+ if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
+ /* Zero-length edge, contour has at least 3 edges */
+
+ SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */
+ e = eLnext;
+ eLnext = e->Lnext;
+ }
+ if( eLnext->Lnext == e ) {
+ /* Degenerate contour (one or two edges) */
+
+ if( eLnext != e ) {
+ if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
+ }
+ if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
+ }
+ }
+}
+
+static int InitPriorityQ( GLUtesselator *tess )
+/*
+ * Insert all vertices into the priority queue which determines the
+ * order in which vertices cross the sweep line.
+ */
+{
+ PriorityQ *pq;
+ GLUvertex *v, *vHead;
+
+ /* __gl_pqSortNewPriorityQ */
+ pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq );
+ if (pq == NULL) return 0;
+
+ vHead = &tess->mesh->vHead;
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */
+ if (v->pqHandle == LONG_MAX) break;
+ }
+ if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void DonePriorityQ( GLUtesselator *tess )
+{
+ pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */
+}
+
+
+static int RemoveDegenerateFaces( GLUmesh *mesh )
+/*
+ * Delete any degenerate faces with only two edges. WalkDirtyRegions()
+ * will catch almost all of these, but it won't catch degenerate faces
+ * produced by splice operations on already-processed edges.
+ * The two places this can happen are in FinishLeftRegions(), when
+ * we splice in a "temporary" edge produced by ConnectRightVertex(),
+ * and in CheckForLeftSplice(), where we splice already-processed
+ * edges to ensure that our dictionary invariants are not violated
+ * by numerical errors.
+ *
+ * In both these cases it is *very* dangerous to delete the offending
+ * edge at the time, since one of the routines further up the stack
+ * will sometimes be keeping a pointer to that edge.
+ */
+{
+ GLUface *f, *fNext;
+ GLUhalfEdge *e;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ e = f->anEdge;
+ assert( e->Lnext != e );
+
+ if( e->Lnext->Lnext == e ) {
+ /* A face with only two edges */
+ AddWinding( e->Onext, e );
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ return 1;
+}
+
+int __gl_computeInterior( GLUtesselator *tess )
+/*
+ * __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+{
+ GLUvertex *v, *vNext;
+
+ tess->fatalError = FALSE;
+
+ /* Each vertex defines an event for our sweep line. Start by inserting
+ * all the vertices in a priority queue. Events are processed in
+ * lexicographic order, ie.
+ *
+ * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y)
+ */
+ RemoveDegenerateEdges( tess );
+ if ( !InitPriorityQ( tess ) ) return 0; /* if error */
+ InitEdgeDict( tess );
+
+ /* __gl_pqSortExtractMin */
+ while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
+ for( ;; ) {
+ vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */
+ if( vNext == NULL || ! VertEq( vNext, v )) break;
+
+ /* Merge together all vertices at exactly the same location.
+ * This is more efficient than processing them one at a time,
+ * simplifies the code (see ConnectLeftDegenerate), and is also
+ * important for correct handling of certain degenerate cases.
+ * For example, suppose there are two identical edges A and B
+ * that belong to different contours (so without this code they would
+ * be processed by separate sweep events). Suppose another edge C
+ * crosses A and B from above. When A is processed, we split it
+ * at its intersection point with C. However this also splits C,
+ * so when we insert B we may compute a slightly different
+ * intersection point. This might leave two edges with a small
+ * gap between them. This kind of error is especially obvious
+ * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
+ */
+ vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/
+ SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
+ }
+ SweepEvent( tess, v );
+ }
+
+ /* Set tess->event for debugging purposes */
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
+ DebugEvent( tess );
+ DoneEdgeDict( tess );
+ DonePriorityQ( tess );
+
+ if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0;
+ __gl_meshCheckMesh( tess->mesh );
+
+ return 1;
+}
diff --git a/cogl/cogl-path/tesselator/sweep.h b/cogl/cogl-path/tesselator/sweep.h
new file mode 100644
index 000000000..feb68b0ff
--- /dev/null
+++ b/cogl/cogl-path/tesselator/sweep.h
@@ -0,0 +1,77 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __sweep_h_
+#define __sweep_h_
+
+#include "mesh.h"
+
+/* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+int __gl_computeInterior( GLUtesselator *tess );
+
+
+/* The following is here *only* for access by debugging routines */
+
+#include "dict.h"
+
+/* For each pair of adjacent edges crossing the sweep line, there is
+ * an ActiveRegion to represent the region between them. The active
+ * regions are kept in sorted order in a dynamic dictionary. As the
+ * sweep line crosses each vertex, we update the affected regions.
+ */
+
+struct ActiveRegion {
+ GLUhalfEdge *eUp; /* upper edge, directed right to left */
+ DictNode *nodeUp; /* dictionary node corresponding to eUp */
+ int windingNumber; /* used to determine which regions are
+ * inside the polygon */
+ GLboolean inside; /* is this region inside the polygon? */
+ GLboolean sentinel; /* marks fake edges at t = +/-infinity */
+ GLboolean dirty; /* marks regions where the upper or lower
+ * edge has changed, but we haven't checked
+ * whether they intersect yet */
+ GLboolean fixUpperEdge; /* marks temporary edges introduced when
+ * we process a "right vertex" (one without
+ * any edges leaving to the right) */
+};
+
+#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp)))
+#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp)))
+
+#endif
diff --git a/cogl/cogl-path/tesselator/tess.c b/cogl/cogl-path/tesselator/tess.c
new file mode 100644
index 000000000..4a0e8dea7
--- /dev/null
+++ b/cogl/cogl-path/tesselator/tess.c
@@ -0,0 +1,632 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <setjmp.h>
+#include "memalloc.h"
+#include "tess.h"
+#include "mesh.h"
+#include "normal.h"
+#include "sweep.h"
+#include "tessmono.h"
+#include "render.h"
+
+#define GLU_TESS_DEFAULT_TOLERANCE 0.0
+#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **dataOut ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
+
+
+/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
+ void *data[4],
+ GLfloat weight[4],
+ void **outData,
+ void *polygonData ) {}
+
+/* Half-edges are allocated in pairs (see mesh.c) */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+#undef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
+ MAX(sizeof(GLUvertex),sizeof(GLUface))))
+
+
+GLUtesselator * GLAPIENTRY
+gluNewTess( void )
+{
+ GLUtesselator *tess;
+
+ /* Only initialize fields which can be changed by the api. Other fields
+ * are initialized where they are used.
+ */
+
+ if (memInit( MAX_FAST_ALLOC ) == 0) {
+ return 0; /* out of memory */
+ }
+ tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
+ if (tess == NULL) {
+ return 0; /* out of memory */
+ }
+
+ tess->state = T_DORMANT;
+
+ tess->normal[0] = 0;
+ tess->normal[1] = 0;
+ tess->normal[2] = 0;
+
+ tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
+ tess->windingRule = GLU_TESS_WINDING_ODD;
+ tess->flagBoundary = FALSE;
+ tess->boundaryOnly = FALSE;
+
+ tess->callBegin = &noBegin;
+ tess->callEdgeFlag = &noEdgeFlag;
+ tess->callVertex = &noVertex;
+ tess->callEnd = &noEnd;
+
+ tess->callError = &noError;
+ tess->callCombine = &noCombine;
+ tess->callMesh = &noMesh;
+
+ tess->callBeginData= &__gl_noBeginData;
+ tess->callEdgeFlagData= &__gl_noEdgeFlagData;
+ tess->callVertexData= &__gl_noVertexData;
+ tess->callEndData= &__gl_noEndData;
+ tess->callErrorData= &__gl_noErrorData;
+ tess->callCombineData= &__gl_noCombineData;
+
+ tess->polygonData= NULL;
+
+ return tess;
+}
+
+static void MakeDormant( GLUtesselator *tess )
+{
+ /* Return the tessellator to its original dormant state. */
+
+ if( tess->mesh != NULL ) {
+ __gl_meshDeleteMesh( tess->mesh );
+ }
+ tess->state = T_DORMANT;
+ tess->lastEdge = NULL;
+ tess->mesh = NULL;
+}
+
+#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
+
+static void GotoState( GLUtesselator *tess, enum TessState newState )
+{
+ while( tess->state != newState ) {
+ /* We change the current state one level at a time, to get to
+ * the desired state.
+ */
+ if( tess->state < newState ) {
+ switch( tess->state ) {
+ case T_DORMANT:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
+ gluTessBeginPolygon( tess, NULL );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
+ gluTessBeginContour( tess );
+ break;
+ default:
+ ;
+ }
+ } else {
+ switch( tess->state ) {
+ case T_IN_CONTOUR:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
+ gluTessEndContour( tess );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
+ /* gluTessEndPolygon( tess ) is too much work! */
+ MakeDormant( tess );
+ break;
+ default:
+ ;
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+gluDeleteTess( GLUtesselator *tess )
+{
+ RequireState( tess, T_DORMANT );
+ memFree( tess );
+}
+
+
+void GLAPIENTRY
+gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
+{
+ GLenum windingRule;
+
+ switch( which ) {
+ case GLU_TESS_TOLERANCE:
+ if( value < 0.0 || value > 1.0 ) break;
+ tess->relTolerance = value;
+ return;
+
+ case GLU_TESS_WINDING_RULE:
+ windingRule = (GLenum) value;
+ if( windingRule != value ) break; /* not an integer */
+
+ switch( windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ case GLU_TESS_WINDING_POSITIVE:
+ case GLU_TESS_WINDING_NEGATIVE:
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ tess->windingRule = windingRule;
+ return;
+ default:
+ break;
+ }
+
+ case GLU_TESS_BOUNDARY_ONLY:
+ tess->boundaryOnly = (value != 0);
+ return;
+
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
+}
+
+/* Returns tessellator property */
+void GLAPIENTRY
+gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
+{
+ switch (which) {
+ case GLU_TESS_TOLERANCE:
+ /* tolerance should be in range [0..1] */
+ assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
+ *value= tess->relTolerance;
+ break;
+ case GLU_TESS_WINDING_RULE:
+ assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
+ tess->windingRule == GLU_TESS_WINDING_NONZERO ||
+ tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
+ tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
+ tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
+ *value= tess->windingRule;
+ break;
+ case GLU_TESS_BOUNDARY_ONLY:
+ assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
+ *value= tess->boundaryOnly;
+ break;
+ default:
+ *value= 0.0;
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ break;
+ }
+} /* gluGetTessProperty() */
+
+void GLAPIENTRY
+gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
+{
+ tess->normal[0] = x;
+ tess->normal[1] = y;
+ tess->normal[2] = z;
+}
+
+void GLAPIENTRY
+gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
+{
+ switch( which ) {
+ case GLU_TESS_BEGIN:
+ tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_BEGIN_DATA:
+ tess->callBeginData = (fn == NULL) ?
+ &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_EDGE_FLAG:
+ tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
+ (void (GLAPIENTRY *)(GLboolean)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_EDGE_FLAG_DATA:
+ tess->callEdgeFlagData= (fn == NULL) ?
+ &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_VERTEX:
+ tess->callVertex = (fn == NULL) ? &noVertex :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_VERTEX_DATA:
+ tess->callVertexData = (fn == NULL) ?
+ &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
+ return;
+ case GLU_TESS_END:
+ tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
+ return;
+ case GLU_TESS_END_DATA:
+ tess->callEndData = (fn == NULL) ? &__gl_noEndData :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_ERROR:
+ tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_ERROR_DATA:
+ tess->callErrorData = (fn == NULL) ?
+ &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_COMBINE:
+ tess->callCombine = (fn == NULL) ? &noCombine :
+ (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
+ return;
+ case GLU_TESS_COMBINE_DATA:
+ tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
+ (void (GLAPIENTRY *)(GLdouble [3],
+ void *[4],
+ GLfloat [4],
+ void **,
+ void *)) fn;
+ return;
+ case GLU_TESS_MESH:
+ tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
+ return;
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+}
+
+static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ GLUhalfEdge *e;
+
+ e = tess->lastEdge;
+ if( e == NULL ) {
+ /* Make a self-loop (one vertex, one edge). */
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) return 0;
+ if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
+ } else {
+ /* Create a new vertex and edge which immediately follow e
+ * in the ordering around the left face.
+ */
+ if (__gl_meshSplitEdge( e ) == NULL) return 0;
+ e = e->Lnext;
+ }
+
+ /* The new vertex is now e->Org. */
+ e->Org->data = data;
+ e->Org->coords[0] = coords[0];
+ e->Org->coords[1] = coords[1];
+ e->Org->coords[2] = coords[2];
+
+ /* The winding of an edge says how the winding number changes as we
+ * cross from the edge''s right face to its left face. We add the
+ * vertices in such an order that a CCW contour will add +1 to
+ * the winding number of the region inside the contour.
+ */
+ e->winding = 1;
+ e->Sym->winding = -1;
+
+ tess->lastEdge = e;
+
+ return 1;
+}
+
+
+static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ CachedVertex *v = &tess->cache[tess->cacheCount];
+
+ v->data = data;
+ v->coords[0] = coords[0];
+ v->coords[1] = coords[1];
+ v->coords[2] = coords[2];
+ ++tess->cacheCount;
+}
+
+
+static int EmptyCache( GLUtesselator *tess )
+{
+ CachedVertex *v = tess->cache;
+ CachedVertex *vLast;
+
+ tess->mesh = __gl_meshNewMesh();
+ if (tess->mesh == NULL) return 0;
+
+ for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
+ if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
+ }
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+
+ return 1;
+}
+
+
+void GLAPIENTRY
+gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ int i, tooLarge = FALSE;
+ GLdouble x, clamped[3];
+
+ RequireState( tess, T_IN_CONTOUR );
+
+ if( tess->emptyCache ) {
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ tess->lastEdge = NULL;
+ }
+ for( i = 0; i < 3; ++i ) {
+ x = coords[i];
+ if( x < - GLU_TESS_MAX_COORD ) {
+ x = - GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ if( x > GLU_TESS_MAX_COORD ) {
+ x = GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ clamped[i] = x;
+ }
+ if( tooLarge ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
+ }
+
+ if( tess->mesh == NULL ) {
+ if( tess->cacheCount < TESS_MAX_CACHE ) {
+ CacheVertex( tess, clamped, data );
+ return;
+ }
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ }
+ if ( !AddVertex( tess, clamped, data ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ }
+}
+
+
+void GLAPIENTRY
+gluTessBeginPolygon( GLUtesselator *tess, void *data )
+{
+ RequireState( tess, T_DORMANT );
+
+ tess->state = T_IN_POLYGON;
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+ tess->mesh = NULL;
+
+ tess->polygonData= data;
+}
+
+
+void GLAPIENTRY
+gluTessBeginContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_POLYGON );
+
+ tess->state = T_IN_CONTOUR;
+ tess->lastEdge = NULL;
+ if( tess->cacheCount > 0 ) {
+ /* Just set a flag so we don't get confused by empty contours
+ * -- these can be generated accidentally with the obsolete
+ * NextContour() interface.
+ */
+ tess->emptyCache = TRUE;
+ }
+}
+
+
+void GLAPIENTRY
+gluTessEndContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_CONTOUR );
+ tess->state = T_IN_POLYGON;
+}
+
+void GLAPIENTRY
+gluTessEndPolygon( GLUtesselator *tess )
+{
+ GLUmesh *mesh;
+
+ if (setjmp(tess->env) != 0) {
+ /* come back here if out of memory */
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+
+ RequireState( tess, T_IN_POLYGON );
+ tess->state = T_DORMANT;
+
+ if( tess->mesh == NULL ) {
+ if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
+
+ /* Try some special code to make the easy cases go quickly
+ * (eg. convex polygons). This code does NOT handle multiple contours,
+ * intersections, edge flags, and of course it does not generate
+ * an explicit mesh either.
+ */
+ if( __gl_renderCache( tess )) {
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
+ }
+
+ /* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+ __gl_projectPolygon( tess );
+
+ /* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+ if ( !__gl_computeInterior( tess ) ) {
+ longjmp(tess->env,1); /* could've used a label */
+ }
+
+ mesh = tess->mesh;
+ if( ! tess->fatalError ) {
+ int rc = 1;
+
+ /* If the user wants only the boundary contours, we throw away all edges
+ * except those which separate the interior from the exterior.
+ * Otherwise we tessellate all the regions marked "inside".
+ */
+ if( tess->boundaryOnly ) {
+ rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
+ } else {
+ rc = __gl_meshTessellateInterior( mesh );
+ }
+ if (rc == 0) longjmp(tess->env,1); /* could've used a label */
+
+ __gl_meshCheckMesh( mesh );
+
+ if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
+ || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
+ || tess->callBeginData != &__gl_noBeginData
+ || tess->callEndData != &__gl_noEndData
+ || tess->callVertexData != &__gl_noVertexData
+ || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
+ {
+ if( tess->boundaryOnly ) {
+ __gl_renderBoundary( tess, mesh ); /* output boundary contours */
+ } else {
+ __gl_renderMesh( tess, mesh ); /* output strips and fans */
+ }
+ }
+ if( tess->callMesh != &noMesh ) {
+
+ /* Throw away the exterior faces, so that all faces are interior.
+ * This way the user doesn't have to check the "inside" flag,
+ * and we don't need to even reveal its existence. It also leaves
+ * the freedom for an implementation to not generate the exterior
+ * faces in the first place.
+ */
+ __gl_meshDiscardExterior( mesh );
+ (*tess->callMesh)( mesh ); /* user wants the mesh itself */
+ tess->mesh = NULL;
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ __gl_meshDeleteMesh( mesh );
+ tess->polygonData= NULL;
+ tess->mesh = NULL;
+}
+
+
+/*XXXblythe unused function*/
+#if 0
+void GLAPIENTRY
+gluDeleteMesh( GLUmesh *mesh )
+{
+ __gl_meshDeleteMesh( mesh );
+}
+#endif
+
+
+
+/*******************************************************/
+
+/* Obsolete calls -- for backward compatibility */
+
+void GLAPIENTRY
+gluBeginPolygon( GLUtesselator *tess )
+{
+ gluTessBeginPolygon( tess, NULL );
+ gluTessBeginContour( tess );
+}
+
+
+/*ARGSUSED*/
+void GLAPIENTRY
+gluNextContour( GLUtesselator *tess, GLenum type )
+{
+ gluTessEndContour( tess );
+ gluTessBeginContour( tess );
+}
+
+
+void GLAPIENTRY
+gluEndPolygon( GLUtesselator *tess )
+{
+ gluTessEndContour( tess );
+ gluTessEndPolygon( tess );
+}
diff --git a/cogl/cogl-path/tesselator/tess.h b/cogl/cogl-path/tesselator/tess.h
new file mode 100644
index 000000000..162496088
--- /dev/null
+++ b/cogl/cogl-path/tesselator/tess.h
@@ -0,0 +1,165 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __tess_h_
+#define __tess_h_
+
+#include <GL/glu.h>
+#include <setjmp.h>
+#include "mesh.h"
+#include "dict.h"
+#include "priorityq.h"
+
+/* The begin/end calls must be properly nested. We keep track of
+ * the current state to enforce the ordering.
+ */
+enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
+
+/* We cache vertex data for single-contour polygons so that we can
+ * try a quick-and-dirty decomposition first.
+ */
+#define TESS_MAX_CACHE 100
+
+typedef struct CachedVertex {
+ GLdouble coords[3];
+ void *data;
+} CachedVertex;
+
+struct GLUtesselator {
+
+ /*** state needed for collecting the input data ***/
+
+ enum TessState state; /* what begin/end calls have we seen? */
+
+ GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
+ GLUmesh *mesh; /* stores the input contours, and eventually
+ the tessellation itself */
+
+ void (GLAPIENTRY *callError)( GLenum errnum );
+
+ /*** state needed for projecting onto the sweep plane ***/
+
+ GLdouble normal[3]; /* user-specified normal (if provided) */
+ GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */
+ GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */
+
+ /*** state needed for the line sweep ***/
+
+ GLdouble relTolerance; /* tolerance for merging features */
+ GLenum windingRule; /* rule for determining polygon interior */
+ GLboolean fatalError; /* fatal error: needed combine callback */
+
+ Dict *dict; /* edge dictionary for sweep line */
+ PriorityQ *pq; /* priority queue of vertex events */
+ GLUvertex *event; /* current sweep event being processed */
+
+ void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData );
+
+ /*** state needed for rendering callbacks (see render.c) ***/
+
+ GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
+ GLboolean boundaryOnly; /* Extract contours, not triangles */
+ GLUface *lonelyTriList;
+ /* list of triangles which could not be rendered as strips or fans */
+
+ void (GLAPIENTRY *callBegin)( GLenum type );
+ void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
+ void (GLAPIENTRY *callVertex)( void *data );
+ void (GLAPIENTRY *callEnd)( void );
+ void (GLAPIENTRY *callMesh)( GLUmesh *mesh );
+
+
+ /*** state needed to cache single-contour polygons for renderCache() */
+
+ GLboolean emptyCache; /* empty cache on next vertex() call */
+ int cacheCount; /* number of cached vertices */
+ CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */
+
+ /*** rendering callbacks that also pass polygon data ***/
+ void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
+ void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,
+ void *polygonData );
+ void (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
+ void (GLAPIENTRY *callEndData)( void *polygonData );
+ void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
+ void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+ jmp_buf env; /* place to jump to when memAllocs fail */
+
+ void *polygonData; /* client data for current polygon */
+};
+
+void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
+void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
+void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
+void GLAPIENTRY __gl_noEndData( void *polygonData );
+void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
+void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+#define CALL_BEGIN_OR_BEGIN_DATA(a) \
+ if (tess->callBeginData != &__gl_noBeginData) \
+ (*tess->callBeginData)((a),tess->polygonData); \
+ else (*tess->callBegin)((a));
+
+#define CALL_VERTEX_OR_VERTEX_DATA(a) \
+ if (tess->callVertexData != &__gl_noVertexData) \
+ (*tess->callVertexData)((a),tess->polygonData); \
+ else (*tess->callVertex)((a));
+
+#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
+ if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
+ (*tess->callEdgeFlagData)((a),tess->polygonData); \
+ else (*tess->callEdgeFlag)((a));
+
+#define CALL_END_OR_END_DATA() \
+ if (tess->callEndData != &__gl_noEndData) \
+ (*tess->callEndData)(tess->polygonData); \
+ else (*tess->callEnd)();
+
+#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
+ if (tess->callCombineData != &__gl_noCombineData) \
+ (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
+ else (*tess->callCombine)((a),(b),(c),(d));
+
+#define CALL_ERROR_OR_ERROR_DATA(a) \
+ if (tess->callErrorData != &__gl_noErrorData) \
+ (*tess->callErrorData)((a),tess->polygonData); \
+ else (*tess->callError)((a));
+
+#endif
diff --git a/cogl/cogl-path/tesselator/tesselator.h b/cogl/cogl-path/tesselator/tesselator.h
new file mode 100644
index 000000000..5b651be1d
--- /dev/null
+++ b/cogl/cogl-path/tesselator/tesselator.h
@@ -0,0 +1,122 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (C) 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#ifndef __TESSELATOR_H__
+#define __TESSELATOR_H__
+
+/* This just includes the defines needed by the tesselator code */
+
+#include "cogl/cogl-defines.h"
+#include "cogl/cogl-gl-header.h"
+
+typedef struct GLUtesselator GLUtesselator;
+
+#define GLU_TESS_MAX_COORD 1.0e150
+
+void gluBeginPolygon (GLUtesselator* tess);
+void gluDeleteTess (GLUtesselator* tess);
+void gluEndPolygon (GLUtesselator* tess);
+
+typedef void (_GLUfuncptr)();
+
+void gluGetTessProperty (GLUtesselator* tess, GLenum which, double* data);
+
+GLUtesselator *gluNewTess (void);
+void gluNextContour (GLUtesselator* tess, GLenum type);
+
+void gluTessBeginContour (GLUtesselator* tess);
+void gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
+void gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
+void gluTessEndContour (GLUtesselator* tess);
+void gluTessEndPolygon (GLUtesselator* tess);
+void gluTessNormal (GLUtesselator* tess, double valueX, double valueY, double valueZ);
+void gluTessProperty (GLUtesselator* tess, GLenum which, double data);
+void gluTessVertex (GLUtesselator* tess, double *location, GLvoid* data);
+
+/* ErrorCode */
+#define GLU_INVALID_ENUM 100900
+#define GLU_INVALID_VALUE 100901
+#define GLU_OUT_OF_MEMORY 100902
+
+/* TessCallback */
+#define GLU_TESS_BEGIN 100100
+#define GLU_BEGIN 100100
+#define GLU_TESS_VERTEX 100101
+#define GLU_VERTEX 100101
+#define GLU_TESS_END 100102
+#define GLU_END 100102
+#define GLU_TESS_ERROR 100103
+#define GLU_TESS_EDGE_FLAG 100104
+#define GLU_EDGE_FLAG 100104
+#define GLU_TESS_COMBINE 100105
+#define GLU_TESS_BEGIN_DATA 100106
+#define GLU_TESS_VERTEX_DATA 100107
+#define GLU_TESS_END_DATA 100108
+#define GLU_TESS_ERROR_DATA 100109
+#define GLU_TESS_EDGE_FLAG_DATA 100110
+#define GLU_TESS_COMBINE_DATA 100111
+
+/* TessContour */
+#define GLU_CW 100120
+#define GLU_CCW 100121
+#define GLU_INTERIOR 100122
+#define GLU_EXTERIOR 100123
+#define GLU_UNKNOWN 100124
+
+/* TessProperty */
+#define GLU_TESS_WINDING_RULE 100140
+#define GLU_TESS_BOUNDARY_ONLY 100141
+#define GLU_TESS_TOLERANCE 100142
+
+/* TessError */
+#define GLU_TESS_ERROR1 100151
+#define GLU_TESS_ERROR2 100152
+#define GLU_TESS_ERROR3 100153
+#define GLU_TESS_ERROR4 100154
+#define GLU_TESS_ERROR5 100155
+#define GLU_TESS_ERROR6 100156
+#define GLU_TESS_ERROR7 100157
+#define GLU_TESS_ERROR8 100158
+#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
+#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
+#define GLU_TESS_MISSING_END_POLYGON 100153
+#define GLU_TESS_MISSING_END_CONTOUR 100154
+#define GLU_TESS_COORD_TOO_LARGE 100155
+#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
+
+/* TessWinding */
+#define GLU_TESS_WINDING_ODD 100130
+#define GLU_TESS_WINDING_NONZERO 100131
+#define GLU_TESS_WINDING_POSITIVE 100132
+#define GLU_TESS_WINDING_NEGATIVE 100133
+#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
+
+#endif /* __TESSELATOR_H__ */
diff --git a/cogl/cogl-path/tesselator/tessmono.c b/cogl/cogl-path/tesselator/tessmono.c
new file mode 100644
index 000000000..4d0844005
--- /dev/null
+++ b/cogl/cogl-path/tesselator/tessmono.c
@@ -0,0 +1,201 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include "geom.h"
+#include "mesh.h"
+#include "tessmono.h"
+#include <assert.h>
+
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * The basic idea is explained in Preparata and Shamos (which I don''t
+ * have handy right now), although their implementation is more
+ * complicated than this one. The are two edge chains, an upper chain
+ * and a lower chain. We process all vertices from both chains in order,
+ * from right to left.
+ *
+ * The algorithm ensures that the following invariant holds after each
+ * vertex is processed: the untessellated region consists of two
+ * chains, where one chain (say the upper) is a single edge, and
+ * the other chain is concave. The left vertex of the single edge
+ * is always to the left of all vertices in the concave chain.
+ *
+ * Each step consists of adding the rightmost unprocessed vertex to one
+ * of the two chains, and forming a fan of triangles from the rightmost
+ * of two chain endpoints. Determining whether we can add each triangle
+ * to the fan is a simple orientation test. By making the fan as large
+ * as possible, we restore the invariant (check it yourself).
+ */
+int __gl_meshTessellateMonoRegion( GLUface *face )
+{
+ GLUhalfEdge *up, *lo;
+
+ /* All edges are oriented CCW around the boundary of the region.
+ * First, find the half-edge whose origin vertex is rightmost.
+ * Since the sweep goes from left to right, face->anEdge should
+ * be close to the edge we want.
+ */
+ up = face->anEdge;
+ assert( up->Lnext != up && up->Lnext->Lnext != up );
+
+ for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
+ ;
+ for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
+ ;
+ lo = up->Lprev;
+
+ while( up->Lnext != lo ) {
+ if( VertLeq( up->Dst, lo->Org )) {
+ /* up->Dst is on the left. It is safe to form triangles from lo->Org.
+ * The EdgeGoesLeft test guarantees progress even when some triangles
+ * are CW, given that the upper and lower chains are truly monotone.
+ */
+ while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
+ || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+ lo = lo->Lprev;
+ } else {
+ /* lo->Org is on the left. We can make CCW triangles from up->Dst. */
+ while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
+ || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
+ if (tempHalfEdge == NULL) return 0;
+ up = tempHalfEdge->Sym;
+ }
+ up = up->Lnext;
+ }
+ }
+
+ /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
+ * can be tessellated in a fan from this leftmost vertex.
+ */
+ assert( lo->Lnext != up );
+ while( lo->Lnext->Lnext != up ) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ */
+int __gl_meshTessellateInterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Make sure we don''t try to tessellate the new triangles. */
+ next = f->next;
+ if( f->inside ) {
+ if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ */
+void __gl_meshDiscardExterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Since f will be destroyed, save its next pointer. */
+ next = f->next;
+ if( ! f->inside ) {
+ __gl_meshZapFace( f );
+ }
+ }
+}
+
+#define MARKED_FOR_DELETION 0x7fffffff
+
+/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary )
+{
+ GLUhalfEdge *e, *eNext;
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ eNext = e->next;
+ if( e->Rface->inside != e->Lface->inside ) {
+
+ /* This is a boundary edge (one side is interior, one is exterior). */
+ e->winding = (e->Lface->inside) ? value : -value;
+ } else {
+
+ /* Both regions are interior, or both are exterior. */
+ if( ! keepOnlyBoundary ) {
+ e->winding = 0;
+ } else {
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ }
+ return 1;
+}
diff --git a/cogl/cogl-path/tesselator/tessmono.h b/cogl/cogl-path/tesselator/tessmono.h
new file mode 100644
index 000000000..8ee1b2fe3
--- /dev/null
+++ b/cogl/cogl-path/tesselator/tessmono.h
@@ -0,0 +1,71 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __tessmono_h_
+#define __tessmono_h_
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ *
+ * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ *
+ * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+
+int __gl_meshTessellateMonoRegion( GLUface *face );
+int __gl_meshTessellateInterior( GLUmesh *mesh );
+void __gl_meshDiscardExterior( GLUmesh *mesh );
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary );
+
+#endif
diff --git a/cogl/cogl/Makefile.am b/cogl/cogl/Makefile.am
new file mode 100644
index 000000000..e34c76806
--- /dev/null
+++ b/cogl/cogl/Makefile.am
@@ -0,0 +1,547 @@
+# preamble
+
+NULL =
+
+SUBDIRS =
+
+BUILT_SOURCES =
+
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(srcdir)/deprecated \
+ -I$(srcdir)/winsys \
+ -I$(srcdir)/driver/gl \
+ -I$(srcdir)/driver/gl/gl \
+ -I$(srcdir)/driver/gl/gles \
+ $(NULL)
+
+AM_CPPFLAGS += \
+ -DG_LOG_DOMAIN=\"Cogl\" \
+ -DCOGL_COMPILATION \
+ -DCOGL_GL_LIBNAME=\"$(COGL_GL_LIBNAME)\" \
+ -DCOGL_GLES1_LIBNAME=\"$(COGL_GLES1_LIBNAME)\" \
+ -DCOGL_GLES2_LIBNAME=\"$(COGL_GLES2_LIBNAME)\" \
+ -DCOGL_LOCALEDIR=\""$(localedir)"\" \
+ $(NULL)
+
+if HAVE_COGL_DEFAULT_DRIVER
+AM_CPPFLAGS += \
+ -DCOGL_DEFAULT_DRIVER=\"$(COGL_DEFAULT_DRIVER)\"
+endif
+
+
+AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
+
+BUILT_SOURCES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h
+DISTCLEANFILES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h
+EXTRA_DIST += cogl-defines.h.in cogl-egl-defines.h.in cogl-gl-header.h.in
+
+pc_files = mutter-cogl-1.0.pc
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pc_files)
+
+DISTCLEANFILES += $(pc_files)
+
+cogl_deprecated_h = \
+ deprecated/cogl-clip-state.h \
+ deprecated/cogl-fixed.h \
+ deprecated/cogl-material-compat.h \
+ deprecated/cogl-vertex-buffer.h \
+ deprecated/cogl-shader.h \
+ deprecated/cogl-clutter.h \
+ deprecated/cogl-type-casts.h \
+ deprecated/cogl-framebuffer-deprecated.h \
+ deprecated/cogl-texture-deprecated.h \
+ deprecated/cogl-auto-texture.h \
+ $(NULL)
+
+# public 1.x api headers
+cogl_1_public_h = \
+ $(cogl_deprecated_h) \
+ cogl1-context.h \
+ cogl-bitmap.h \
+ cogl-color.h \
+ cogl-matrix.h \
+ cogl-offscreen.h \
+ cogl-primitives.h \
+ cogl-texture.h \
+ cogl-types.h \
+ cogl.h \
+ $(NULL)
+
+# experimental 2.0 api headers
+# Note: we don't run glib-mkenums over these headers
+cogl_experimental_h = \
+ cogl-object.h \
+ cogl-renderer.h \
+ cogl-swap-chain.h \
+ cogl-onscreen-template.h \
+ cogl-display.h \
+ cogl-context.h \
+ cogl-pipeline.h \
+ cogl-pipeline-state.h \
+ cogl-pipeline-layer-state.h \
+ cogl-snippet.h \
+ cogl-gles2.h \
+ cogl-gles2-types.h \
+ cogl-index-buffer.h \
+ cogl-attribute-buffer.h \
+ cogl-indices.h \
+ cogl-attribute.h \
+ cogl-primitive.h \
+ cogl-framebuffer.h \
+ cogl-onscreen.h \
+ cogl-frame-info.h \
+ cogl-vector.h \
+ cogl-euler.h \
+ cogl-output.h \
+ cogl-quaternion.h \
+ cogl-matrix-stack.h \
+ cogl-poll.h \
+ cogl-texture-3d.h \
+ cogl-texture-2d.h \
+ cogl-texture-2d-gl.h \
+ cogl-texture-rectangle.h \
+ cogl-texture-2d-sliced.h \
+ cogl-sub-texture.h \
+ cogl-atlas-texture.h \
+ cogl-meta-texture.h \
+ cogl-primitive-texture.h \
+ cogl-depth-state.h \
+ cogl-buffer.h \
+ cogl-pixel-buffer.h \
+ cogl2-experimental.h \
+ cogl-macros.h \
+ cogl-fence.h \
+ cogl-version.h \
+ cogl-error.h \
+ $(NULL)
+
+cogl_additional_experimental_h = \
+ cogl-bitmap.h \
+ cogl-color.h \
+ cogl-matrix.h \
+ cogl-texture.h \
+ cogl-types.h \
+ cogl-gtype-private.h \
+ $(NULL)
+
+cogl_nodist_experimental_h = \
+ $(NULL)
+
+# nop driver
+cogl_driver_sources = \
+ driver/nop/cogl-driver-nop.c \
+ driver/nop/cogl-framebuffer-nop-private.h \
+ driver/nop/cogl-framebuffer-nop.c \
+ driver/nop/cogl-attribute-nop-private.h \
+ driver/nop/cogl-attribute-nop.c \
+ driver/nop/cogl-clip-stack-nop-private.h \
+ driver/nop/cogl-clip-stack-nop.c \
+ driver/nop/cogl-texture-2d-nop-private.h \
+ driver/nop/cogl-texture-2d-nop.c \
+ $(NULL)
+
+# gl driver sources
+cogl_gl_prototypes_h = \
+ gl-prototypes/cogl-gles2-functions.h \
+ gl-prototypes/cogl-core-functions.h \
+ gl-prototypes/cogl-in-gles-core-functions.h \
+ gl-prototypes/cogl-in-gles2-core-functions.h \
+ gl-prototypes/cogl-glsl-functions.h \
+ $(NULL)
+
+cogl_driver_sources += \
+ driver/gl/cogl-util-gl-private.h \
+ driver/gl/cogl-util-gl.c \
+ driver/gl/cogl-framebuffer-gl-private.h \
+ driver/gl/cogl-framebuffer-gl.c \
+ driver/gl/cogl-texture-gl-private.h \
+ driver/gl/cogl-texture-gl.c \
+ driver/gl/cogl-texture-2d-gl-private.h \
+ driver/gl/cogl-texture-2d-gl.c \
+ driver/gl/cogl-attribute-gl-private.h \
+ driver/gl/cogl-attribute-gl.c \
+ driver/gl/cogl-clip-stack-gl-private.h \
+ driver/gl/cogl-clip-stack-gl.c \
+ driver/gl/cogl-buffer-gl-private.h \
+ driver/gl/cogl-buffer-gl.c \
+ driver/gl/cogl-pipeline-opengl.c \
+ driver/gl/cogl-pipeline-opengl-private.h \
+ driver/gl/cogl-pipeline-fragend-glsl.c \
+ driver/gl/cogl-pipeline-fragend-glsl-private.h \
+ driver/gl/gl/cogl-pipeline-fragend-arbfp.c \
+ driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h \
+ driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c \
+ driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h \
+ driver/gl/cogl-pipeline-fragend-fixed.c \
+ driver/gl/cogl-pipeline-fragend-fixed-private.h \
+ driver/gl/cogl-pipeline-vertend-glsl.c \
+ driver/gl/cogl-pipeline-vertend-glsl-private.h \
+ driver/gl/cogl-pipeline-vertend-fixed.c \
+ driver/gl/cogl-pipeline-vertend-fixed-private.h \
+ driver/gl/cogl-pipeline-progend-fixed.c \
+ driver/gl/cogl-pipeline-progend-fixed-private.h \
+ driver/gl/cogl-pipeline-progend-glsl.c \
+ driver/gl/cogl-pipeline-progend-glsl-private.h \
+ $(NULL)
+
+if COGL_DRIVER_GL_SUPPORTED
+cogl_driver_sources += \
+ driver/gl/gl/cogl-driver-gl.c \
+ driver/gl/gl/cogl-texture-driver-gl.c \
+ $(NULL)
+endif
+
+if COGL_DRIVER_GLES_SUPPORTED
+cogl_driver_sources += \
+ driver/gl/gles/cogl-driver-gles.c \
+ driver/gl/gles/cogl-texture-driver-gles.c \
+ $(NULL)
+endif
+
+# winsys sources, common to all backends
+cogl_winsys_common_sources = \
+ winsys/cogl-winsys-private.h \
+ winsys/cogl-winsys.c \
+ $(NULL)
+
+# sources
+cogl_sources_c = \
+ $(cogl_driver_sources) \
+ $(cogl_winsys_common_sources) \
+ cogl-private.h \
+ cogl-i18n-private.h \
+ cogl-debug.h \
+ cogl-debug-options.h \
+ cogl-gpu-info.c \
+ cogl-gpu-info-private.h \
+ cogl-context-private.h \
+ cogl-context.c \
+ cogl-renderer-private.h \
+ cogl-renderer.h \
+ cogl-renderer.c \
+ cogl-swap-chain-private.h \
+ cogl-swap-chain.h \
+ cogl-swap-chain.c \
+ cogl-onscreen-template-private.h \
+ cogl-onscreen-template.h \
+ cogl-onscreen-template.c \
+ cogl-display-private.h \
+ cogl-display.h \
+ cogl-display.c \
+ cogl-driver.h \
+ cogl.c \
+ cogl-object-private.h \
+ cogl-object.h \
+ cogl-object.c \
+ cogl-util.h \
+ cogl-util.c \
+ cogl-bitmap-private.h \
+ cogl-bitmap.c \
+ cogl-bitmap-conversion.c \
+ cogl-bitmap-packing.h \
+ cogl-primitives-private.h \
+ cogl-primitives.h \
+ cogl-primitives.c \
+ cogl-bitmap-pixbuf.c \
+ cogl-clip-stack.h \
+ cogl-clip-stack.c \
+ cogl-feature-private.h \
+ cogl-feature-private.c \
+ cogl-color-private.h \
+ cogl-color.c \
+ cogl-buffer-private.h \
+ cogl-buffer.c \
+ cogl-pixel-buffer-private.h \
+ cogl-pixel-buffer.c \
+ cogl-index-buffer-private.h \
+ cogl-index-buffer.c \
+ cogl-attribute-buffer-private.h \
+ cogl-attribute-buffer.c \
+ cogl-indices-private.h \
+ cogl-indices.c \
+ cogl-attribute-private.h \
+ cogl-attribute.c \
+ cogl-primitive-private.h \
+ cogl-primitive.c \
+ cogl-matrix.c \
+ cogl-vector.c \
+ cogl-euler.c \
+ cogl-quaternion-private.h \
+ cogl-quaternion.c \
+ cogl-matrix-private.h \
+ cogl-matrix-stack.c \
+ cogl-matrix-stack-private.h \
+ cogl-depth-state.c \
+ cogl-depth-state-private.h \
+ cogl-node.c \
+ cogl-node-private.h \
+ cogl-pipeline.c \
+ cogl-pipeline-private.h \
+ cogl-pipeline-layer.c \
+ cogl-pipeline-layer-private.h \
+ cogl-pipeline-state.c \
+ cogl-pipeline-layer-state-private.h \
+ cogl-pipeline-layer-state.c \
+ cogl-pipeline-state-private.h \
+ cogl-pipeline-debug.c \
+ cogl-glsl-shader.c \
+ cogl-glsl-shader-private.h \
+ cogl-glsl-shader-boilerplate.h \
+ cogl-pipeline-snippet-private.h \
+ cogl-pipeline-snippet.c \
+ cogl-pipeline-cache.h \
+ cogl-pipeline-cache.c \
+ cogl-pipeline-hash-table.h \
+ cogl-pipeline-hash-table.c \
+ cogl-sampler-cache.c \
+ cogl-sampler-cache-private.h \
+ cogl-blend-string.c \
+ cogl-blend-string.h \
+ cogl-debug.c \
+ cogl-sub-texture-private.h \
+ cogl-texture-private.h \
+ cogl-texture-2d-private.h \
+ cogl-texture-2d-sliced-private.h \
+ cogl-texture-3d-private.h \
+ cogl-texture-driver.h \
+ cogl-sub-texture.c \
+ cogl-texture.c \
+ cogl-texture-2d.c \
+ cogl-texture-2d-sliced.c \
+ cogl-texture-3d.c \
+ cogl-texture-rectangle-private.h \
+ cogl-texture-rectangle.c \
+ cogl-rectangle-map.h \
+ cogl-rectangle-map.c \
+ cogl-atlas.h \
+ cogl-atlas.c \
+ cogl-atlas-texture-private.h \
+ cogl-atlas-texture.c \
+ cogl-meta-texture.c \
+ cogl-primitive-texture.c \
+ cogl-blit.h \
+ cogl-blit.c \
+ cogl-spans.h \
+ cogl-spans.c \
+ cogl-journal-private.h \
+ cogl-journal.c \
+ cogl-frame-info-private.h \
+ cogl-frame-info.c \
+ cogl-framebuffer-private.h \
+ cogl-framebuffer.c \
+ cogl-onscreen-private.h \
+ cogl-onscreen.c \
+ cogl-output-private.h \
+ cogl-output.c \
+ cogl-profile.h \
+ cogl-profile.c \
+ cogl-flags.h \
+ cogl-bitmask.h \
+ cogl-bitmask.c \
+ cogl-gtype.c \
+ cogl-gtype-private.h \
+ cogl-point-in-poly-private.h \
+ cogl-point-in-poly.c \
+ cogl-list.c \
+ cogl-list.h \
+ winsys/cogl-winsys-stub-private.h \
+ winsys/cogl-winsys-stub.c \
+ cogl-config-private.h \
+ cogl-config.c \
+ cogl-boxed-value.h \
+ cogl-boxed-value.c \
+ cogl-snippet-private.h \
+ cogl-snippet.c \
+ cogl-poll-private.h \
+ cogl-poll.c \
+ gl-prototypes/cogl-all-functions.h \
+ gl-prototypes/cogl-gles1-functions.h \
+ gl-prototypes/cogl-gles2-functions.h \
+ gl-prototypes/cogl-core-functions.h \
+ gl-prototypes/cogl-in-gles-core-functions.h \
+ gl-prototypes/cogl-in-gles1-core-functions.h \
+ gl-prototypes/cogl-in-gles2-core-functions.h \
+ gl-prototypes/cogl-fixed-functions.h \
+ gl-prototypes/cogl-glsl-functions.h \
+ cogl-memory-stack-private.h \
+ cogl-memory-stack.c \
+ cogl-magazine-private.h \
+ cogl-magazine.c \
+ cogl-gles2-context-private.h \
+ cogl-gles2-context.c \
+ cogl-error-private.h \
+ cogl-error.c \
+ cogl-closure-list-private.h \
+ cogl-closure-list.c \
+ cogl-fence.c \
+ cogl-fence-private.h \
+ deprecated/cogl-clip-state.c \
+ deprecated/cogl-fixed.c \
+ deprecated/cogl-vertex-buffer-private.h \
+ deprecated/cogl-vertex-buffer.c \
+ deprecated/cogl-material-compat.c \
+ deprecated/cogl-program.c \
+ deprecated/cogl-program-private.h \
+ deprecated/cogl-auto-texture.c \
+ deprecated/cogl-shader-private.h \
+ deprecated/cogl-shader.c \
+ deprecated/cogl-clutter.c \
+ deprecated/cogl-framebuffer-deprecated.c \
+ deprecated/cogl-texture-deprecated.c \
+ $(NULL)
+
+cogl_experimental_h += cogl-glib-source.h
+cogl_sources_c += cogl-glib-source.c
+
+if SUPPORT_XLIB
+cogl_deprecated_h += deprecated/cogl-clutter-xlib.h
+cogl_1_public_h += cogl-xlib-renderer.h
+
+cogl_experimental_h += \
+ winsys/cogl-texture-pixmap-x11.h \
+ cogl-xlib.h
+
+cogl_sources_c += \
+ cogl-x11-renderer-private.h \
+ cogl-xlib-renderer-private.h \
+ cogl-xlib-renderer.c \
+ cogl-xlib.c \
+ cogl-xlib-private.h \
+ winsys/cogl-texture-pixmap-x11.c \
+ winsys/cogl-texture-pixmap-x11-private.h
+endif
+if SUPPORT_GLX
+cogl_experimental_h += cogl-glx.h
+cogl_sources_c += \
+ cogl-glx-renderer-private.h \
+ cogl-glx-display-private.h \
+ winsys/cogl-winsys-glx-feature-functions.h \
+ winsys/cogl-winsys-glx-private.h \
+ winsys/cogl-winsys-glx.c
+endif
+if SUPPORT_WAYLAND_EGL_SERVER
+cogl_experimental_h += cogl-wayland-server.h
+endif
+if SUPPORT_EGL_PLATFORM_KMS
+cogl_experimental_h += \
+ cogl-kms-renderer.h \
+ cogl-kms-display.h
+cogl_sources_c += \
+ winsys/cogl-winsys-egl-kms.c \
+ winsys/cogl-winsys-egl-kms-private.h
+endif
+if SUPPORT_EGL_PLATFORM_XLIB
+cogl_sources_c += \
+ winsys/cogl-winsys-egl-x11.c \
+ winsys/cogl-winsys-egl-x11-private.h
+endif
+if SUPPORT_EGL
+cogl_experimental_h += cogl-egl.h
+cogl_nodist_experimental_h += cogl-egl-defines.h
+
+cogl_sources_c += \
+ cogl-egl-private.h \
+ winsys/cogl-winsys-egl.c \
+ winsys/cogl-winsys-egl-feature-functions.h \
+ winsys/cogl-winsys-egl-private.h
+endif
+
+# glib-mkenums rules
+glib_enum_h = cogl-enum-types.h
+glib_enum_c = cogl-enum-types.c
+glib_enum_headers = $(cogl_1_public_h)
+include $(top_srcdir)/build/autotools/Makefile.am.enums
+
+mutterlibdir = $(libdir)/mutter
+mutterlib_LTLIBRARIES = libmutter-cogl.la
+
+libmutter_cogl_la_LIBADD = $(LIBM) $(COGL_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
+if UNIT_TESTS
+libmutter_cogl_la_LIBADD += $(top_builddir)/test-fixtures/libtest-fixtures.la
+endif
+# XXX: The aim is to eventually get rid of all private API exports
+# for cogl-pango.
+libmutter_cogl_la_LDFLAGS = \
+ -no-undefined \
+ -version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@ \
+ -export-dynamic \
+ -rpath $(mutterlibdir) \
+ -export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_).*"
+
+libmutter_cogl_la_SOURCES = $(cogl_sources_c)
+nodist_libmutter_cogl_la_SOURCES = $(BUILT_SOURCES)
+
+# Cogl installed headers
+cogl_headers = \
+ $(cogl_1_public_h) \
+ cogl-deprecated.h \
+ cogl-pango.h \
+ $(NULL)
+
+cogl_base_includedir = $(includedir)/mutter
+cogldeprecatedincludedir = $(cogl_base_includedir)/cogl/cogl/deprecated
+cogldeprecatedinclude_HEADERS = $(cogl_deprecated_h)
+
+coglincludedir = $(cogl_base_includedir)/cogl/cogl
+coglinclude_HEADERS = $(cogl_headers) $(cogl_experimental_h)
+nodist_coglinclude_HEADERS = $(cogl_nodist_experimental_h) cogl-defines.h cogl-enum-types.h
+
+cogl_proto_includedir = $(cogl_base_includedir)/cogl/cogl/gl-prototypes
+cogl_proto_include_HEADERS = $(cogl_gl_prototypes_h)
+
+EXTRA_DIST += \
+ cogl.symbols
+
+-include $(INTROSPECTION_MAKEFILE)
+
+INTROSPECTION_GIRS =
+
+if HAVE_INTROSPECTION
+Cogl-1.0.gir: libmutter-cogl.la Makefile
+
+Cogl_1_0_gir_NAMESPACE = Cogl
+Cogl_1_0_gir_VERSION = 1.0
+Cogl_1_0_gir_LIBS = libmutter-cogl.la
+if UNIT_TESTS
+Cogl_1_0_gir_LIBS += $(top_builddir)/test-fixtures/libtest-fixtures.la
+endif
+Cogl_1_0_gir_FILES = $(cogl_1_public_h) cogl-enum-types.h
+
+Cogl-2.0.gir: libmutter-cogl.la Makefile
+
+Cogl_2_0_gir_NAMESPACE = Cogl
+Cogl_2_0_gir_VERSION = 2.0
+Cogl_2_0_gir_LIBS = libmutter-cogl.la
+if UNIT_TESTS
+Cogl_2_0_gir_LIBS += $(top_builddir)/test-fixtures/libtest-fixtures.la
+endif
+Cogl_2_0_gir_FILES = $(cogl_experimental_h) $(cogl_additional_experimental_h) cogl-enum-types.h
+
+Cogl_1_0_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) -UCOGL_ENABLE_EXPERIMENTAL_API -UCOGL_ENABLE_EXPERIMENTAL_2_0_API -UCOGL_COMPILATION -D__COGL_H_INSIDE__ -D__COGL_XLIB_H_INSIDE__ -D__COGL_EGL_H_INSIDE__ -D__COGL_GLX_H_INSIDE__ -DCOGL_GIR_SCANNING
+Cogl_1_0_gir_INCLUDES = GL-1.0 GObject-2.0
+Cogl_1_0_gir_EXPORT_PACKAGES = cogl-1.0
+Cogl_1_0_gir_SCANNERFLAGS = --warn-all --c-include='cogl/cogl.h'
+
+Cogl_2_0_gir_CFLAGS = $(AM_CPPFLAGS) $(COGL_DEP_CFLAGS) -DCOGL_ENABLE_EXPERIMENTAL_API=1 -UCOGL_COMPILATION -D__COGL_H_INSIDE__ -D__COGL_XLIB_H_INSIDE__ -DCOGL_GIR_SCANNING
+Cogl_2_0_gir_INCLUDES = GL-1.0 GObject-2.0
+Cogl_2_0_gir_EXPORT_PACKAGES = cogl-2.0-experimental
+Cogl_2_0_gir_SCANNERFLAGS = --warn-all --c-include='cogl/cogl.h' --symbol-prefix=cogl --symbol-prefix=cogl2
+
+INTROSPECTION_GIRS += Cogl-1.0.gir Cogl-2.0.gir
+
+girdir = $(mutterlibdir)
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(mutterlibdir)
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelib_DATA)
+endif
diff --git a/cogl/cogl-atlas-texture-private.h b/cogl/cogl/cogl-atlas-texture-private.h
index ba83bf9eb..ba83bf9eb 100644
--- a/cogl/cogl-atlas-texture-private.h
+++ b/cogl/cogl/cogl-atlas-texture-private.h
diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl/cogl-atlas-texture.c
index 1c8b56972..1c8b56972 100644
--- a/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl/cogl-atlas-texture.c
diff --git a/cogl/cogl-atlas-texture.h b/cogl/cogl/cogl-atlas-texture.h
index 79c15b9e9..79c15b9e9 100644
--- a/cogl/cogl-atlas-texture.h
+++ b/cogl/cogl/cogl-atlas-texture.h
diff --git a/cogl/cogl-atlas.c b/cogl/cogl/cogl-atlas.c
index 0fd8b7227..0fd8b7227 100644
--- a/cogl/cogl-atlas.c
+++ b/cogl/cogl/cogl-atlas.c
diff --git a/cogl/cogl-atlas.h b/cogl/cogl/cogl-atlas.h
index e9b3fb069..e9b3fb069 100644
--- a/cogl/cogl-atlas.h
+++ b/cogl/cogl/cogl-atlas.h
diff --git a/cogl/cogl-attribute-buffer-private.h b/cogl/cogl/cogl-attribute-buffer-private.h
index c5e8a276d..c5e8a276d 100644
--- a/cogl/cogl-attribute-buffer-private.h
+++ b/cogl/cogl/cogl-attribute-buffer-private.h
diff --git a/cogl/cogl-attribute-buffer.c b/cogl/cogl/cogl-attribute-buffer.c
index 8d92d29da..8d92d29da 100644
--- a/cogl/cogl-attribute-buffer.c
+++ b/cogl/cogl/cogl-attribute-buffer.c
diff --git a/cogl/cogl-attribute-buffer.h b/cogl/cogl/cogl-attribute-buffer.h
index 189d81ebe..189d81ebe 100644
--- a/cogl/cogl-attribute-buffer.h
+++ b/cogl/cogl/cogl-attribute-buffer.h
diff --git a/cogl/cogl-attribute-private.h b/cogl/cogl/cogl-attribute-private.h
index aac4a887d..aac4a887d 100644
--- a/cogl/cogl-attribute-private.h
+++ b/cogl/cogl/cogl-attribute-private.h
diff --git a/cogl/cogl-attribute.c b/cogl/cogl/cogl-attribute.c
index bcfbf78c6..bcfbf78c6 100644
--- a/cogl/cogl-attribute.c
+++ b/cogl/cogl/cogl-attribute.c
diff --git a/cogl/cogl-attribute.h b/cogl/cogl/cogl-attribute.h
index 736b0c675..736b0c675 100644
--- a/cogl/cogl-attribute.h
+++ b/cogl/cogl/cogl-attribute.h
diff --git a/cogl/cogl-bitmap-conversion.c b/cogl/cogl/cogl-bitmap-conversion.c
index 67168e747..67168e747 100644
--- a/cogl/cogl-bitmap-conversion.c
+++ b/cogl/cogl/cogl-bitmap-conversion.c
diff --git a/cogl/cogl-bitmap-packing.h b/cogl/cogl/cogl-bitmap-packing.h
index 1b8e140ff..1b8e140ff 100644
--- a/cogl/cogl-bitmap-packing.h
+++ b/cogl/cogl/cogl-bitmap-packing.h
diff --git a/cogl/cogl-bitmap-pixbuf.c b/cogl/cogl/cogl-bitmap-pixbuf.c
index 9696de6ec..9696de6ec 100644
--- a/cogl/cogl-bitmap-pixbuf.c
+++ b/cogl/cogl/cogl-bitmap-pixbuf.c
diff --git a/cogl/cogl-bitmap-private.h b/cogl/cogl/cogl-bitmap-private.h
index 676729d55..676729d55 100644
--- a/cogl/cogl-bitmap-private.h
+++ b/cogl/cogl/cogl-bitmap-private.h
diff --git a/cogl/cogl-bitmap.c b/cogl/cogl/cogl-bitmap.c
index fbeb2d1c6..fbeb2d1c6 100644
--- a/cogl/cogl-bitmap.c
+++ b/cogl/cogl/cogl-bitmap.c
diff --git a/cogl/cogl-bitmap.h b/cogl/cogl/cogl-bitmap.h
index 2ef5299c2..2ef5299c2 100644
--- a/cogl/cogl-bitmap.h
+++ b/cogl/cogl/cogl-bitmap.h
diff --git a/cogl/cogl-bitmask.c b/cogl/cogl/cogl-bitmask.c
index 7034bc990..7034bc990 100644
--- a/cogl/cogl-bitmask.c
+++ b/cogl/cogl/cogl-bitmask.c
diff --git a/cogl/cogl-bitmask.h b/cogl/cogl/cogl-bitmask.h
index e0db3df26..e0db3df26 100644
--- a/cogl/cogl-bitmask.h
+++ b/cogl/cogl/cogl-bitmask.h
diff --git a/cogl/cogl-blend-string.c b/cogl/cogl/cogl-blend-string.c
index 5d876bfd8..5d876bfd8 100644
--- a/cogl/cogl-blend-string.c
+++ b/cogl/cogl/cogl-blend-string.c
diff --git a/cogl/cogl-blend-string.h b/cogl/cogl/cogl-blend-string.h
index 355338c61..355338c61 100644
--- a/cogl/cogl-blend-string.h
+++ b/cogl/cogl/cogl-blend-string.h
diff --git a/cogl/cogl-blit.c b/cogl/cogl/cogl-blit.c
index a6d60efbc..a6d60efbc 100644
--- a/cogl/cogl-blit.c
+++ b/cogl/cogl/cogl-blit.c
diff --git a/cogl/cogl-blit.h b/cogl/cogl/cogl-blit.h
index f4e25e7fe..f4e25e7fe 100644
--- a/cogl/cogl-blit.h
+++ b/cogl/cogl/cogl-blit.h
diff --git a/cogl/cogl-boxed-value.c b/cogl/cogl/cogl-boxed-value.c
index bf6a97919..bf6a97919 100644
--- a/cogl/cogl-boxed-value.c
+++ b/cogl/cogl/cogl-boxed-value.c
diff --git a/cogl/cogl-boxed-value.h b/cogl/cogl/cogl-boxed-value.h
index c8eda44dd..c8eda44dd 100644
--- a/cogl/cogl-boxed-value.h
+++ b/cogl/cogl/cogl-boxed-value.h
diff --git a/cogl/cogl-buffer-private.h b/cogl/cogl/cogl-buffer-private.h
index eab81fda4..eab81fda4 100644
--- a/cogl/cogl-buffer-private.h
+++ b/cogl/cogl/cogl-buffer-private.h
diff --git a/cogl/cogl-buffer.c b/cogl/cogl/cogl-buffer.c
index ede46cce6..ede46cce6 100644
--- a/cogl/cogl-buffer.c
+++ b/cogl/cogl/cogl-buffer.c
diff --git a/cogl/cogl-buffer.h b/cogl/cogl/cogl-buffer.h
index adbc51f9c..adbc51f9c 100644
--- a/cogl/cogl-buffer.h
+++ b/cogl/cogl/cogl-buffer.h
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl/cogl-clip-stack.c
index b0e5b0d1b..b0e5b0d1b 100644
--- a/cogl/cogl-clip-stack.c
+++ b/cogl/cogl/cogl-clip-stack.c
diff --git a/cogl/cogl-clip-stack.h b/cogl/cogl/cogl-clip-stack.h
index 56bc3f805..56bc3f805 100644
--- a/cogl/cogl-clip-stack.h
+++ b/cogl/cogl/cogl-clip-stack.h
diff --git a/cogl/cogl-closure-list-private.h b/cogl/cogl/cogl-closure-list-private.h
index 5446cb207..5446cb207 100644
--- a/cogl/cogl-closure-list-private.h
+++ b/cogl/cogl/cogl-closure-list-private.h
diff --git a/cogl/cogl-closure-list.c b/cogl/cogl/cogl-closure-list.c
index eb8cadd27..eb8cadd27 100644
--- a/cogl/cogl-closure-list.c
+++ b/cogl/cogl/cogl-closure-list.c
diff --git a/cogl/cogl-color-private.h b/cogl/cogl/cogl-color-private.h
index bb1a58e25..bb1a58e25 100644
--- a/cogl/cogl-color-private.h
+++ b/cogl/cogl/cogl-color-private.h
diff --git a/cogl/cogl-color.c b/cogl/cogl/cogl-color.c
index 02e501d43..02e501d43 100644
--- a/cogl/cogl-color.c
+++ b/cogl/cogl/cogl-color.c
diff --git a/cogl/cogl-color.h b/cogl/cogl/cogl-color.h
index bdb0bfaf6..bdb0bfaf6 100644
--- a/cogl/cogl-color.h
+++ b/cogl/cogl/cogl-color.h
diff --git a/cogl/cogl-config-private.h b/cogl/cogl/cogl-config-private.h
index 93ff943b2..93ff943b2 100644
--- a/cogl/cogl-config-private.h
+++ b/cogl/cogl/cogl-config-private.h
diff --git a/cogl/cogl-config.c b/cogl/cogl/cogl-config.c
index 6c960d4b5..6c960d4b5 100644
--- a/cogl/cogl-config.c
+++ b/cogl/cogl/cogl-config.c
diff --git a/cogl/cogl-context-private.h b/cogl/cogl/cogl-context-private.h
index 9e6620733..9e6620733 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl/cogl-context-private.h
diff --git a/cogl/cogl-context.c b/cogl/cogl/cogl-context.c
index a7eed29ab..a7eed29ab 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl/cogl-context.c
diff --git a/cogl/cogl-context.h b/cogl/cogl/cogl-context.h
index 529481765..529481765 100644
--- a/cogl/cogl-context.h
+++ b/cogl/cogl/cogl-context.h
diff --git a/cogl/cogl-debug-options.h b/cogl/cogl/cogl-debug-options.h
index 0f3b30731..0f3b30731 100644
--- a/cogl/cogl-debug-options.h
+++ b/cogl/cogl/cogl-debug-options.h
diff --git a/cogl/cogl-debug.c b/cogl/cogl/cogl-debug.c
index 345406c91..345406c91 100644
--- a/cogl/cogl-debug.c
+++ b/cogl/cogl/cogl-debug.c
diff --git a/cogl/cogl-debug.h b/cogl/cogl/cogl-debug.h
index 91a49e163..91a49e163 100644
--- a/cogl/cogl-debug.h
+++ b/cogl/cogl/cogl-debug.h
diff --git a/cogl/cogl-defines.h.in b/cogl/cogl/cogl-defines.h.in
index eb3ad9268..eb3ad9268 100644
--- a/cogl/cogl-defines.h.in
+++ b/cogl/cogl/cogl-defines.h.in
diff --git a/cogl/cogl-deprecated.h b/cogl/cogl/cogl-deprecated.h
index ca56fa18a..ca56fa18a 100644
--- a/cogl/cogl-deprecated.h
+++ b/cogl/cogl/cogl-deprecated.h
diff --git a/cogl/cogl-depth-state-private.h b/cogl/cogl/cogl-depth-state-private.h
index 6c14bb9f2..6c14bb9f2 100644
--- a/cogl/cogl-depth-state-private.h
+++ b/cogl/cogl/cogl-depth-state-private.h
diff --git a/cogl/cogl-depth-state.c b/cogl/cogl/cogl-depth-state.c
index 5ea0aab49..5ea0aab49 100644
--- a/cogl/cogl-depth-state.c
+++ b/cogl/cogl/cogl-depth-state.c
diff --git a/cogl/cogl-depth-state.h b/cogl/cogl/cogl-depth-state.h
index 581b96110..581b96110 100644
--- a/cogl/cogl-depth-state.h
+++ b/cogl/cogl/cogl-depth-state.h
diff --git a/cogl/cogl-display-private.h b/cogl/cogl/cogl-display-private.h
index 9788435bb..9788435bb 100644
--- a/cogl/cogl-display-private.h
+++ b/cogl/cogl/cogl-display-private.h
diff --git a/cogl/cogl-display.c b/cogl/cogl/cogl-display.c
index 039e88199..039e88199 100644
--- a/cogl/cogl-display.c
+++ b/cogl/cogl/cogl-display.c
diff --git a/cogl/cogl-display.h b/cogl/cogl/cogl-display.h
index 47720a3fb..47720a3fb 100644
--- a/cogl/cogl-display.h
+++ b/cogl/cogl/cogl-display.h
diff --git a/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h
index 648228c6f..648228c6f 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl/cogl-driver.h
diff --git a/cogl/cogl-egl-defines.h.in b/cogl/cogl/cogl-egl-defines.h.in
index 648a62ddf..648a62ddf 100644
--- a/cogl/cogl-egl-defines.h.in
+++ b/cogl/cogl/cogl-egl-defines.h.in
diff --git a/cogl/cogl-egl-private.h b/cogl/cogl/cogl-egl-private.h
index c4b0dfe1b..c4b0dfe1b 100644
--- a/cogl/cogl-egl-private.h
+++ b/cogl/cogl/cogl-egl-private.h
diff --git a/cogl/cogl-egl.h b/cogl/cogl/cogl-egl.h
index cea7b1038..cea7b1038 100644
--- a/cogl/cogl-egl.h
+++ b/cogl/cogl/cogl-egl.h
diff --git a/cogl/cogl-enum-types.c.in b/cogl/cogl/cogl-enum-types.c.in
index a08711ba2..a08711ba2 100644
--- a/cogl/cogl-enum-types.c.in
+++ b/cogl/cogl/cogl-enum-types.c.in
diff --git a/cogl/cogl-enum-types.h.in b/cogl/cogl/cogl-enum-types.h.in
index 14bfccc7d..14bfccc7d 100644
--- a/cogl/cogl-enum-types.h.in
+++ b/cogl/cogl/cogl-enum-types.h.in
diff --git a/cogl/cogl-error-private.h b/cogl/cogl/cogl-error-private.h
index d96779fad..d96779fad 100644
--- a/cogl/cogl-error-private.h
+++ b/cogl/cogl/cogl-error-private.h
diff --git a/cogl/cogl-error.c b/cogl/cogl/cogl-error.c
index d83afc3a4..d83afc3a4 100644
--- a/cogl/cogl-error.c
+++ b/cogl/cogl/cogl-error.c
diff --git a/cogl/cogl-error.h b/cogl/cogl/cogl-error.h
index 8682d0e0f..8682d0e0f 100644
--- a/cogl/cogl-error.h
+++ b/cogl/cogl/cogl-error.h
diff --git a/cogl/cogl-euler.c b/cogl/cogl/cogl-euler.c
index f877bbc6e..f877bbc6e 100644
--- a/cogl/cogl-euler.c
+++ b/cogl/cogl/cogl-euler.c
diff --git a/cogl/cogl-euler.h b/cogl/cogl/cogl-euler.h
index 4ccbb2a66..4ccbb2a66 100644
--- a/cogl/cogl-euler.h
+++ b/cogl/cogl/cogl-euler.h
diff --git a/cogl/cogl-feature-private.c b/cogl/cogl/cogl-feature-private.c
index 7c160c3c1..7c160c3c1 100644
--- a/cogl/cogl-feature-private.c
+++ b/cogl/cogl/cogl-feature-private.c
diff --git a/cogl/cogl-feature-private.h b/cogl/cogl/cogl-feature-private.h
index a342d2333..a342d2333 100644
--- a/cogl/cogl-feature-private.h
+++ b/cogl/cogl/cogl-feature-private.h
diff --git a/cogl/cogl-fence-private.h b/cogl/cogl/cogl-fence-private.h
index abbf51ffb..abbf51ffb 100644
--- a/cogl/cogl-fence-private.h
+++ b/cogl/cogl/cogl-fence-private.h
diff --git a/cogl/cogl-fence.c b/cogl/cogl/cogl-fence.c
index 05c91ffd0..05c91ffd0 100644
--- a/cogl/cogl-fence.c
+++ b/cogl/cogl/cogl-fence.c
diff --git a/cogl/cogl-fence.h b/cogl/cogl/cogl-fence.h
index e268f8f5f..e268f8f5f 100644
--- a/cogl/cogl-fence.h
+++ b/cogl/cogl/cogl-fence.h
diff --git a/cogl/cogl-flags.h b/cogl/cogl/cogl-flags.h
index 33633f0d8..33633f0d8 100644
--- a/cogl/cogl-flags.h
+++ b/cogl/cogl/cogl-flags.h
diff --git a/cogl/cogl-frame-info-private.h b/cogl/cogl/cogl-frame-info-private.h
index 32f5ba8e0..32f5ba8e0 100644
--- a/cogl/cogl-frame-info-private.h
+++ b/cogl/cogl/cogl-frame-info-private.h
diff --git a/cogl/cogl-frame-info.c b/cogl/cogl/cogl-frame-info.c
index 2114a64b5..2114a64b5 100644
--- a/cogl/cogl-frame-info.c
+++ b/cogl/cogl/cogl-frame-info.c
diff --git a/cogl/cogl-frame-info.h b/cogl/cogl/cogl-frame-info.h
index 7304c530f..7304c530f 100644
--- a/cogl/cogl-frame-info.h
+++ b/cogl/cogl/cogl-frame-info.h
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl/cogl-framebuffer-private.h
index 99ac2fba9..99ac2fba9 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl/cogl-framebuffer-private.h
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
index 1f70d3dc2..1f70d3dc2 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl/cogl-framebuffer.h
index 56ba4aa25..56ba4aa25 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl/cogl-framebuffer.h
diff --git a/cogl/cogl-gl-header.h.in b/cogl/cogl/cogl-gl-header.h.in
index 0696dcf72..0696dcf72 100644
--- a/cogl/cogl-gl-header.h.in
+++ b/cogl/cogl/cogl-gl-header.h.in
diff --git a/cogl/cogl-gles2-context-private.h b/cogl/cogl/cogl-gles2-context-private.h
index 805b06468..805b06468 100644
--- a/cogl/cogl-gles2-context-private.h
+++ b/cogl/cogl/cogl-gles2-context-private.h
diff --git a/cogl/cogl-gles2-context.c b/cogl/cogl/cogl-gles2-context.c
index 33c438798..33c438798 100644
--- a/cogl/cogl-gles2-context.c
+++ b/cogl/cogl/cogl-gles2-context.c
diff --git a/cogl/cogl-gles2-types.h b/cogl/cogl/cogl-gles2-types.h
index 8f41bf8a7..8f41bf8a7 100644
--- a/cogl/cogl-gles2-types.h
+++ b/cogl/cogl/cogl-gles2-types.h
diff --git a/cogl/cogl-gles2.h b/cogl/cogl/cogl-gles2.h
index 84c9ba15d..84c9ba15d 100644
--- a/cogl/cogl-gles2.h
+++ b/cogl/cogl/cogl-gles2.h
diff --git a/cogl/cogl-glib-source.c b/cogl/cogl/cogl-glib-source.c
index fea254478..fea254478 100644
--- a/cogl/cogl-glib-source.c
+++ b/cogl/cogl/cogl-glib-source.c
diff --git a/cogl/cogl-glib-source.h b/cogl/cogl/cogl-glib-source.h
index ddb7f9957..ddb7f9957 100644
--- a/cogl/cogl-glib-source.h
+++ b/cogl/cogl/cogl-glib-source.h
diff --git a/cogl/cogl-glsl-shader-boilerplate.h b/cogl/cogl/cogl-glsl-shader-boilerplate.h
index 6d882dad2..6d882dad2 100644
--- a/cogl/cogl-glsl-shader-boilerplate.h
+++ b/cogl/cogl/cogl-glsl-shader-boilerplate.h
diff --git a/cogl/cogl-glsl-shader-private.h b/cogl/cogl/cogl-glsl-shader-private.h
index 9899c12c1..9899c12c1 100644
--- a/cogl/cogl-glsl-shader-private.h
+++ b/cogl/cogl/cogl-glsl-shader-private.h
diff --git a/cogl/cogl-glsl-shader.c b/cogl/cogl/cogl-glsl-shader.c
index 196e0c7ae..196e0c7ae 100644
--- a/cogl/cogl-glsl-shader.c
+++ b/cogl/cogl/cogl-glsl-shader.c
diff --git a/cogl/cogl-glx-display-private.h b/cogl/cogl/cogl-glx-display-private.h
index 133c1188c..133c1188c 100644
--- a/cogl/cogl-glx-display-private.h
+++ b/cogl/cogl/cogl-glx-display-private.h
diff --git a/cogl/cogl-glx-renderer-private.h b/cogl/cogl/cogl-glx-renderer-private.h
index cb8ff97f8..cb8ff97f8 100644
--- a/cogl/cogl-glx-renderer-private.h
+++ b/cogl/cogl/cogl-glx-renderer-private.h
diff --git a/cogl/cogl-glx.h b/cogl/cogl/cogl-glx.h
index 15918bba7..15918bba7 100644
--- a/cogl/cogl-glx.h
+++ b/cogl/cogl/cogl-glx.h
diff --git a/cogl/cogl-gpu-info-private.h b/cogl/cogl/cogl-gpu-info-private.h
index e532cdd5c..e532cdd5c 100644
--- a/cogl/cogl-gpu-info-private.h
+++ b/cogl/cogl/cogl-gpu-info-private.h
diff --git a/cogl/cogl-gpu-info.c b/cogl/cogl/cogl-gpu-info.c
index 54dfe18d5..54dfe18d5 100644
--- a/cogl/cogl-gpu-info.c
+++ b/cogl/cogl/cogl-gpu-info.c
diff --git a/cogl/cogl-gtype-private.h b/cogl/cogl/cogl-gtype-private.h
index 849838563..849838563 100644
--- a/cogl/cogl-gtype-private.h
+++ b/cogl/cogl/cogl-gtype-private.h
diff --git a/cogl/cogl-gtype.c b/cogl/cogl/cogl-gtype.c
index 314d8e41f..314d8e41f 100644
--- a/cogl/cogl-gtype.c
+++ b/cogl/cogl/cogl-gtype.c
diff --git a/cogl/cogl-i18n-private.h b/cogl/cogl/cogl-i18n-private.h
index 94202f791..94202f791 100644
--- a/cogl/cogl-i18n-private.h
+++ b/cogl/cogl/cogl-i18n-private.h
diff --git a/cogl/cogl-index-buffer-private.h b/cogl/cogl/cogl-index-buffer-private.h
index d9596cd83..d9596cd83 100644
--- a/cogl/cogl-index-buffer-private.h
+++ b/cogl/cogl/cogl-index-buffer-private.h
diff --git a/cogl/cogl-index-buffer.c b/cogl/cogl/cogl-index-buffer.c
index cddaf4762..cddaf4762 100644
--- a/cogl/cogl-index-buffer.c
+++ b/cogl/cogl/cogl-index-buffer.c
diff --git a/cogl/cogl-index-buffer.h b/cogl/cogl/cogl-index-buffer.h
index 204c85856..204c85856 100644
--- a/cogl/cogl-index-buffer.h
+++ b/cogl/cogl/cogl-index-buffer.h
diff --git a/cogl/cogl-indices-private.h b/cogl/cogl/cogl-indices-private.h
index 3d5891687..3d5891687 100644
--- a/cogl/cogl-indices-private.h
+++ b/cogl/cogl/cogl-indices-private.h
diff --git a/cogl/cogl-indices.c b/cogl/cogl/cogl-indices.c
index 22568304c..22568304c 100644
--- a/cogl/cogl-indices.c
+++ b/cogl/cogl/cogl-indices.c
diff --git a/cogl/cogl-indices.h b/cogl/cogl/cogl-indices.h
index 3cc923911..3cc923911 100644
--- a/cogl/cogl-indices.h
+++ b/cogl/cogl/cogl-indices.h
diff --git a/cogl/cogl-journal-private.h b/cogl/cogl/cogl-journal-private.h
index 8211359fa..8211359fa 100644
--- a/cogl/cogl-journal-private.h
+++ b/cogl/cogl/cogl-journal-private.h
diff --git a/cogl/cogl-journal.c b/cogl/cogl/cogl-journal.c
index 8ffe25f97..8ffe25f97 100644
--- a/cogl/cogl-journal.c
+++ b/cogl/cogl/cogl-journal.c
diff --git a/cogl/cogl-kms-display.h b/cogl/cogl/cogl-kms-display.h
index ebf6471ad..ebf6471ad 100644
--- a/cogl/cogl-kms-display.h
+++ b/cogl/cogl/cogl-kms-display.h
diff --git a/cogl/cogl-kms-renderer.h b/cogl/cogl/cogl-kms-renderer.h
index 4e4948e56..4e4948e56 100644
--- a/cogl/cogl-kms-renderer.h
+++ b/cogl/cogl/cogl-kms-renderer.h
diff --git a/cogl/cogl-list.c b/cogl/cogl/cogl-list.c
index 3fbc675ae..3fbc675ae 100644
--- a/cogl/cogl-list.c
+++ b/cogl/cogl/cogl-list.c
diff --git a/cogl/cogl-list.h b/cogl/cogl/cogl-list.h
index 20cbec82a..20cbec82a 100644
--- a/cogl/cogl-list.h
+++ b/cogl/cogl/cogl-list.h
diff --git a/cogl/cogl-macros.h b/cogl/cogl/cogl-macros.h
index 96c06591f..96c06591f 100644
--- a/cogl/cogl-macros.h
+++ b/cogl/cogl/cogl-macros.h
diff --git a/cogl/cogl-magazine-private.h b/cogl/cogl/cogl-magazine-private.h
index 091801be1..091801be1 100644
--- a/cogl/cogl-magazine-private.h
+++ b/cogl/cogl/cogl-magazine-private.h
diff --git a/cogl/cogl-magazine.c b/cogl/cogl/cogl-magazine.c
index 56177515e..56177515e 100644
--- a/cogl/cogl-magazine.c
+++ b/cogl/cogl/cogl-magazine.c
diff --git a/cogl/cogl-matrix-private.h b/cogl/cogl/cogl-matrix-private.h
index d9fc98eab..d9fc98eab 100644
--- a/cogl/cogl-matrix-private.h
+++ b/cogl/cogl/cogl-matrix-private.h
diff --git a/cogl/cogl-matrix-stack-private.h b/cogl/cogl/cogl-matrix-stack-private.h
index 0d5caf8b9..0d5caf8b9 100644
--- a/cogl/cogl-matrix-stack-private.h
+++ b/cogl/cogl/cogl-matrix-stack-private.h
diff --git a/cogl/cogl-matrix-stack.c b/cogl/cogl/cogl-matrix-stack.c
index 400855f60..400855f60 100644
--- a/cogl/cogl-matrix-stack.c
+++ b/cogl/cogl/cogl-matrix-stack.c
diff --git a/cogl/cogl-matrix-stack.h b/cogl/cogl/cogl-matrix-stack.h
index 6ea323a32..6ea323a32 100644
--- a/cogl/cogl-matrix-stack.h
+++ b/cogl/cogl/cogl-matrix-stack.h
diff --git a/cogl/cogl-matrix.c b/cogl/cogl/cogl-matrix.c
index fd0f6af3c..fd0f6af3c 100644
--- a/cogl/cogl-matrix.c
+++ b/cogl/cogl/cogl-matrix.c
diff --git a/cogl/cogl-matrix.h b/cogl/cogl/cogl-matrix.h
index 58ec5c760..58ec5c760 100644
--- a/cogl/cogl-matrix.h
+++ b/cogl/cogl/cogl-matrix.h
diff --git a/cogl/cogl-memory-stack-private.h b/cogl/cogl/cogl-memory-stack-private.h
index 2b6ee828c..2b6ee828c 100644
--- a/cogl/cogl-memory-stack-private.h
+++ b/cogl/cogl/cogl-memory-stack-private.h
diff --git a/cogl/cogl-memory-stack.c b/cogl/cogl/cogl-memory-stack.c
index f723abc12..f723abc12 100644
--- a/cogl/cogl-memory-stack.c
+++ b/cogl/cogl/cogl-memory-stack.c
diff --git a/cogl/cogl-meta-texture.c b/cogl/cogl/cogl-meta-texture.c
index 554aaad6e..554aaad6e 100644
--- a/cogl/cogl-meta-texture.c
+++ b/cogl/cogl/cogl-meta-texture.c
diff --git a/cogl/cogl-meta-texture.h b/cogl/cogl/cogl-meta-texture.h
index 69c8cb04a..69c8cb04a 100644
--- a/cogl/cogl-meta-texture.h
+++ b/cogl/cogl/cogl-meta-texture.h
diff --git a/cogl/cogl-node-private.h b/cogl/cogl/cogl-node-private.h
index 8fe24775d..8fe24775d 100644
--- a/cogl/cogl-node-private.h
+++ b/cogl/cogl/cogl-node-private.h
diff --git a/cogl/cogl-node.c b/cogl/cogl/cogl-node.c
index 60d3e7338..60d3e7338 100644
--- a/cogl/cogl-node.c
+++ b/cogl/cogl/cogl-node.c
diff --git a/cogl/cogl-object-private.h b/cogl/cogl/cogl-object-private.h
index 7955a35cc..7955a35cc 100644
--- a/cogl/cogl-object-private.h
+++ b/cogl/cogl/cogl-object-private.h
diff --git a/cogl/cogl-object.c b/cogl/cogl/cogl-object.c
index 452f625f9..452f625f9 100644
--- a/cogl/cogl-object.c
+++ b/cogl/cogl/cogl-object.c
diff --git a/cogl/cogl-object.h b/cogl/cogl/cogl-object.h
index a0bed88dc..a0bed88dc 100644
--- a/cogl/cogl-object.h
+++ b/cogl/cogl/cogl-object.h
diff --git a/cogl/cogl-offscreen.h b/cogl/cogl/cogl-offscreen.h
index 9c844426c..9c844426c 100644
--- a/cogl/cogl-offscreen.h
+++ b/cogl/cogl/cogl-offscreen.h
diff --git a/cogl/cogl-onscreen-private.h b/cogl/cogl/cogl-onscreen-private.h
index 0a67832ac..0a67832ac 100644
--- a/cogl/cogl-onscreen-private.h
+++ b/cogl/cogl/cogl-onscreen-private.h
diff --git a/cogl/cogl-onscreen-template-private.h b/cogl/cogl/cogl-onscreen-template-private.h
index 1b19d35d7..1b19d35d7 100644
--- a/cogl/cogl-onscreen-template-private.h
+++ b/cogl/cogl/cogl-onscreen-template-private.h
diff --git a/cogl/cogl-onscreen-template.c b/cogl/cogl/cogl-onscreen-template.c
index 3940627c4..3940627c4 100644
--- a/cogl/cogl-onscreen-template.c
+++ b/cogl/cogl/cogl-onscreen-template.c
diff --git a/cogl/cogl-onscreen-template.h b/cogl/cogl/cogl-onscreen-template.h
index d8714fabf..d8714fabf 100644
--- a/cogl/cogl-onscreen-template.h
+++ b/cogl/cogl/cogl-onscreen-template.h
diff --git a/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c
index 4b53bb25e..4b53bb25e 100644
--- a/cogl/cogl-onscreen.c
+++ b/cogl/cogl/cogl-onscreen.c
diff --git a/cogl/cogl-onscreen.h b/cogl/cogl/cogl-onscreen.h
index 6a55c4c1d..6a55c4c1d 100644
--- a/cogl/cogl-onscreen.h
+++ b/cogl/cogl/cogl-onscreen.h
diff --git a/cogl/cogl-output-private.h b/cogl/cogl/cogl-output-private.h
index d264d482b..d264d482b 100644
--- a/cogl/cogl-output-private.h
+++ b/cogl/cogl/cogl-output-private.h
diff --git a/cogl/cogl-output.c b/cogl/cogl/cogl-output.c
index ae8560518..ae8560518 100644
--- a/cogl/cogl-output.c
+++ b/cogl/cogl/cogl-output.c
diff --git a/cogl/cogl-output.h b/cogl/cogl/cogl-output.h
index 6eec10eeb..6eec10eeb 100644
--- a/cogl/cogl-output.h
+++ b/cogl/cogl/cogl-output.h
diff --git a/cogl/cogl-pango.h b/cogl/cogl/cogl-pango.h
index b24c1b829..b24c1b829 100644
--- a/cogl/cogl-pango.h
+++ b/cogl/cogl/cogl-pango.h
diff --git a/cogl/cogl-pipeline-cache.c b/cogl/cogl/cogl-pipeline-cache.c
index 0a6bb6a90..0a6bb6a90 100644
--- a/cogl/cogl-pipeline-cache.c
+++ b/cogl/cogl/cogl-pipeline-cache.c
diff --git a/cogl/cogl-pipeline-cache.h b/cogl/cogl/cogl-pipeline-cache.h
index bd5862ee5..bd5862ee5 100644
--- a/cogl/cogl-pipeline-cache.h
+++ b/cogl/cogl/cogl-pipeline-cache.h
diff --git a/cogl/cogl-pipeline-debug.c b/cogl/cogl/cogl-pipeline-debug.c
index beb35b34e..beb35b34e 100644
--- a/cogl/cogl-pipeline-debug.c
+++ b/cogl/cogl/cogl-pipeline-debug.c
diff --git a/cogl/cogl-pipeline-hash-table.c b/cogl/cogl/cogl-pipeline-hash-table.c
index 9c8e3df86..9c8e3df86 100644
--- a/cogl/cogl-pipeline-hash-table.c
+++ b/cogl/cogl/cogl-pipeline-hash-table.c
diff --git a/cogl/cogl-pipeline-hash-table.h b/cogl/cogl/cogl-pipeline-hash-table.h
index 035e8dfb3..035e8dfb3 100644
--- a/cogl/cogl-pipeline-hash-table.h
+++ b/cogl/cogl/cogl-pipeline-hash-table.h
diff --git a/cogl/cogl-pipeline-layer-private.h b/cogl/cogl/cogl-pipeline-layer-private.h
index 38cd3b5eb..38cd3b5eb 100644
--- a/cogl/cogl-pipeline-layer-private.h
+++ b/cogl/cogl/cogl-pipeline-layer-private.h
diff --git a/cogl/cogl-pipeline-layer-state-private.h b/cogl/cogl/cogl-pipeline-layer-state-private.h
index 64e70cf3d..64e70cf3d 100644
--- a/cogl/cogl-pipeline-layer-state-private.h
+++ b/cogl/cogl/cogl-pipeline-layer-state-private.h
diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl/cogl-pipeline-layer-state.c
index fb201925b..fb201925b 100644
--- a/cogl/cogl-pipeline-layer-state.c
+++ b/cogl/cogl/cogl-pipeline-layer-state.c
diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl/cogl-pipeline-layer-state.h
index 4be7d398f..4be7d398f 100644
--- a/cogl/cogl-pipeline-layer-state.h
+++ b/cogl/cogl/cogl-pipeline-layer-state.h
diff --git a/cogl/cogl-pipeline-layer.c b/cogl/cogl/cogl-pipeline-layer.c
index 37a512000..37a512000 100644
--- a/cogl/cogl-pipeline-layer.c
+++ b/cogl/cogl/cogl-pipeline-layer.c
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl/cogl-pipeline-private.h
index 845fdd866..845fdd866 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl/cogl-pipeline-private.h
diff --git a/cogl/cogl-pipeline-snippet-private.h b/cogl/cogl/cogl-pipeline-snippet-private.h
index 7a9d233c8..7a9d233c8 100644
--- a/cogl/cogl-pipeline-snippet-private.h
+++ b/cogl/cogl/cogl-pipeline-snippet-private.h
diff --git a/cogl/cogl-pipeline-snippet.c b/cogl/cogl/cogl-pipeline-snippet.c
index 59f85b3ec..59f85b3ec 100644
--- a/cogl/cogl-pipeline-snippet.c
+++ b/cogl/cogl/cogl-pipeline-snippet.c
diff --git a/cogl/cogl-pipeline-state-private.h b/cogl/cogl/cogl-pipeline-state-private.h
index 366683ec4..366683ec4 100644
--- a/cogl/cogl-pipeline-state-private.h
+++ b/cogl/cogl/cogl-pipeline-state-private.h
diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl/cogl-pipeline-state.c
index 04c76f8a7..04c76f8a7 100644
--- a/cogl/cogl-pipeline-state.c
+++ b/cogl/cogl/cogl-pipeline-state.c
diff --git a/cogl/cogl-pipeline-state.h b/cogl/cogl/cogl-pipeline-state.h
index 6acbb6dbf..6acbb6dbf 100644
--- a/cogl/cogl-pipeline-state.h
+++ b/cogl/cogl/cogl-pipeline-state.h
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl/cogl-pipeline.c
index b2fee10d4..b2fee10d4 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl/cogl-pipeline.c
diff --git a/cogl/cogl-pipeline.h b/cogl/cogl/cogl-pipeline.h
index 08ae3f69c..08ae3f69c 100644
--- a/cogl/cogl-pipeline.h
+++ b/cogl/cogl/cogl-pipeline.h
diff --git a/cogl/cogl-pixel-buffer-private.h b/cogl/cogl/cogl-pixel-buffer-private.h
index 2735277e0..2735277e0 100644
--- a/cogl/cogl-pixel-buffer-private.h
+++ b/cogl/cogl/cogl-pixel-buffer-private.h
diff --git a/cogl/cogl-pixel-buffer.c b/cogl/cogl/cogl-pixel-buffer.c
index e2d6565fb..e2d6565fb 100644
--- a/cogl/cogl-pixel-buffer.c
+++ b/cogl/cogl/cogl-pixel-buffer.c
diff --git a/cogl/cogl-pixel-buffer.h b/cogl/cogl/cogl-pixel-buffer.h
index 8ae616483..8ae616483 100644
--- a/cogl/cogl-pixel-buffer.h
+++ b/cogl/cogl/cogl-pixel-buffer.h
diff --git a/cogl/cogl-point-in-poly-private.h b/cogl/cogl/cogl-point-in-poly-private.h
index 1f3f7014c..1f3f7014c 100644
--- a/cogl/cogl-point-in-poly-private.h
+++ b/cogl/cogl/cogl-point-in-poly-private.h
diff --git a/cogl/cogl-point-in-poly.c b/cogl/cogl/cogl-point-in-poly.c
index cf87b9334..cf87b9334 100644
--- a/cogl/cogl-point-in-poly.c
+++ b/cogl/cogl/cogl-point-in-poly.c
diff --git a/cogl/cogl-poll-private.h b/cogl/cogl/cogl-poll-private.h
index bdc9e6d80..bdc9e6d80 100644
--- a/cogl/cogl-poll-private.h
+++ b/cogl/cogl/cogl-poll-private.h
diff --git a/cogl/cogl-poll.c b/cogl/cogl/cogl-poll.c
index 1ce62f67c..1ce62f67c 100644
--- a/cogl/cogl-poll.c
+++ b/cogl/cogl/cogl-poll.c
diff --git a/cogl/cogl-poll.h b/cogl/cogl/cogl-poll.h
index 849e95c92..849e95c92 100644
--- a/cogl/cogl-poll.h
+++ b/cogl/cogl/cogl-poll.h
diff --git a/cogl/cogl-primitive-private.h b/cogl/cogl/cogl-primitive-private.h
index 78627295a..78627295a 100644
--- a/cogl/cogl-primitive-private.h
+++ b/cogl/cogl/cogl-primitive-private.h
diff --git a/cogl/cogl-primitive-texture.c b/cogl/cogl/cogl-primitive-texture.c
index fce97238b..fce97238b 100644
--- a/cogl/cogl-primitive-texture.c
+++ b/cogl/cogl/cogl-primitive-texture.c
diff --git a/cogl/cogl-primitive-texture.h b/cogl/cogl/cogl-primitive-texture.h
index effaac35b..effaac35b 100644
--- a/cogl/cogl-primitive-texture.h
+++ b/cogl/cogl/cogl-primitive-texture.h
diff --git a/cogl/cogl-primitive.c b/cogl/cogl/cogl-primitive.c
index b31a25a86..b31a25a86 100644
--- a/cogl/cogl-primitive.c
+++ b/cogl/cogl/cogl-primitive.c
diff --git a/cogl/cogl-primitive.h b/cogl/cogl/cogl-primitive.h
index 0f20bb58b..0f20bb58b 100644
--- a/cogl/cogl-primitive.h
+++ b/cogl/cogl/cogl-primitive.h
diff --git a/cogl/cogl-primitives-private.h b/cogl/cogl/cogl-primitives-private.h
index 10db86905..10db86905 100644
--- a/cogl/cogl-primitives-private.h
+++ b/cogl/cogl/cogl-primitives-private.h
diff --git a/cogl/cogl-primitives.c b/cogl/cogl/cogl-primitives.c
index bfe773588..bfe773588 100644
--- a/cogl/cogl-primitives.c
+++ b/cogl/cogl/cogl-primitives.c
diff --git a/cogl/cogl-primitives.h b/cogl/cogl/cogl-primitives.h
index 0c9211eee..0c9211eee 100644
--- a/cogl/cogl-primitives.h
+++ b/cogl/cogl/cogl-primitives.h
diff --git a/cogl/cogl-private.h b/cogl/cogl/cogl-private.h
index 333955c65..333955c65 100644
--- a/cogl/cogl-private.h
+++ b/cogl/cogl/cogl-private.h
diff --git a/cogl/cogl-profile.c b/cogl/cogl/cogl-profile.c
index 766e271ed..766e271ed 100644
--- a/cogl/cogl-profile.c
+++ b/cogl/cogl/cogl-profile.c
diff --git a/cogl/cogl-profile.h b/cogl/cogl/cogl-profile.h
index db95647e9..db95647e9 100644
--- a/cogl/cogl-profile.h
+++ b/cogl/cogl/cogl-profile.h
diff --git a/cogl/cogl-quaternion-private.h b/cogl/cogl/cogl-quaternion-private.h
index eda672ea8..eda672ea8 100644
--- a/cogl/cogl-quaternion-private.h
+++ b/cogl/cogl/cogl-quaternion-private.h
diff --git a/cogl/cogl-quaternion.c b/cogl/cogl/cogl-quaternion.c
index 956744322..956744322 100644
--- a/cogl/cogl-quaternion.c
+++ b/cogl/cogl/cogl-quaternion.c
diff --git a/cogl/cogl-quaternion.h b/cogl/cogl/cogl-quaternion.h
index c70eccab4..c70eccab4 100644
--- a/cogl/cogl-quaternion.h
+++ b/cogl/cogl/cogl-quaternion.h
diff --git a/cogl/cogl-rectangle-map.c b/cogl/cogl/cogl-rectangle-map.c
index 69368eed6..69368eed6 100644
--- a/cogl/cogl-rectangle-map.c
+++ b/cogl/cogl/cogl-rectangle-map.c
diff --git a/cogl/cogl-rectangle-map.h b/cogl/cogl/cogl-rectangle-map.h
index 1dd50fdbe..1dd50fdbe 100644
--- a/cogl/cogl-rectangle-map.h
+++ b/cogl/cogl/cogl-rectangle-map.h
diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl/cogl-renderer-private.h
index 080bb325d..080bb325d 100644
--- a/cogl/cogl-renderer-private.h
+++ b/cogl/cogl/cogl-renderer-private.h
diff --git a/cogl/cogl-renderer.c b/cogl/cogl/cogl-renderer.c
index fabaf81f2..fabaf81f2 100644
--- a/cogl/cogl-renderer.c
+++ b/cogl/cogl/cogl-renderer.c
diff --git a/cogl/cogl-renderer.h b/cogl/cogl/cogl-renderer.h
index 20c79068c..20c79068c 100644
--- a/cogl/cogl-renderer.h
+++ b/cogl/cogl/cogl-renderer.h
diff --git a/cogl/cogl-sampler-cache-private.h b/cogl/cogl/cogl-sampler-cache-private.h
index 5688effb9..5688effb9 100644
--- a/cogl/cogl-sampler-cache-private.h
+++ b/cogl/cogl/cogl-sampler-cache-private.h
diff --git a/cogl/cogl-sampler-cache.c b/cogl/cogl/cogl-sampler-cache.c
index e21c64c6a..e21c64c6a 100644
--- a/cogl/cogl-sampler-cache.c
+++ b/cogl/cogl/cogl-sampler-cache.c
diff --git a/cogl/cogl-snippet-private.h b/cogl/cogl/cogl-snippet-private.h
index e3269f20d..e3269f20d 100644
--- a/cogl/cogl-snippet-private.h
+++ b/cogl/cogl/cogl-snippet-private.h
diff --git a/cogl/cogl-snippet.c b/cogl/cogl/cogl-snippet.c
index a3f5d6c31..a3f5d6c31 100644
--- a/cogl/cogl-snippet.c
+++ b/cogl/cogl/cogl-snippet.c
diff --git a/cogl/cogl-snippet.h b/cogl/cogl/cogl-snippet.h
index b8d9efdec..b8d9efdec 100644
--- a/cogl/cogl-snippet.h
+++ b/cogl/cogl/cogl-snippet.h
diff --git a/cogl/cogl-spans.c b/cogl/cogl/cogl-spans.c
index e7ca67830..e7ca67830 100644
--- a/cogl/cogl-spans.c
+++ b/cogl/cogl/cogl-spans.c
diff --git a/cogl/cogl-spans.h b/cogl/cogl/cogl-spans.h
index a236784c4..a236784c4 100644
--- a/cogl/cogl-spans.h
+++ b/cogl/cogl/cogl-spans.h
diff --git a/cogl/cogl-sub-texture-private.h b/cogl/cogl/cogl-sub-texture-private.h
index 75c476d6e..75c476d6e 100644
--- a/cogl/cogl-sub-texture-private.h
+++ b/cogl/cogl/cogl-sub-texture-private.h
diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl/cogl-sub-texture.c
index 7baf95eb6..7baf95eb6 100644
--- a/cogl/cogl-sub-texture.c
+++ b/cogl/cogl/cogl-sub-texture.c
diff --git a/cogl/cogl-sub-texture.h b/cogl/cogl/cogl-sub-texture.h
index ced267787..ced267787 100644
--- a/cogl/cogl-sub-texture.h
+++ b/cogl/cogl/cogl-sub-texture.h
diff --git a/cogl/cogl-swap-chain-private.h b/cogl/cogl/cogl-swap-chain-private.h
index c67e6f08b..c67e6f08b 100644
--- a/cogl/cogl-swap-chain-private.h
+++ b/cogl/cogl/cogl-swap-chain-private.h
diff --git a/cogl/cogl-swap-chain.c b/cogl/cogl/cogl-swap-chain.c
index e5dd2f449..e5dd2f449 100644
--- a/cogl/cogl-swap-chain.c
+++ b/cogl/cogl/cogl-swap-chain.c
diff --git a/cogl/cogl-swap-chain.h b/cogl/cogl/cogl-swap-chain.h
index d0488674b..d0488674b 100644
--- a/cogl/cogl-swap-chain.h
+++ b/cogl/cogl/cogl-swap-chain.h
diff --git a/cogl/cogl-texture-2d-gl.h b/cogl/cogl/cogl-texture-2d-gl.h
index e7b22df91..e7b22df91 100644
--- a/cogl/cogl-texture-2d-gl.h
+++ b/cogl/cogl/cogl-texture-2d-gl.h
diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl/cogl-texture-2d-private.h
index 27847af64..27847af64 100644
--- a/cogl/cogl-texture-2d-private.h
+++ b/cogl/cogl/cogl-texture-2d-private.h
diff --git a/cogl/cogl-texture-2d-sliced-private.h b/cogl/cogl/cogl-texture-2d-sliced-private.h
index e827923c0..e827923c0 100644
--- a/cogl/cogl-texture-2d-sliced-private.h
+++ b/cogl/cogl/cogl-texture-2d-sliced-private.h
diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl/cogl-texture-2d-sliced.c
index e76bef697..e76bef697 100644
--- a/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl/cogl-texture-2d-sliced.c
diff --git a/cogl/cogl-texture-2d-sliced.h b/cogl/cogl/cogl-texture-2d-sliced.h
index ec959a91b..ec959a91b 100644
--- a/cogl/cogl-texture-2d-sliced.h
+++ b/cogl/cogl/cogl-texture-2d-sliced.h
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl/cogl-texture-2d.c
index cc28cd951..cc28cd951 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl/cogl-texture-2d.c
diff --git a/cogl/cogl-texture-2d.h b/cogl/cogl/cogl-texture-2d.h
index c806ced5a..c806ced5a 100644
--- a/cogl/cogl-texture-2d.h
+++ b/cogl/cogl/cogl-texture-2d.h
diff --git a/cogl/cogl-texture-3d-private.h b/cogl/cogl/cogl-texture-3d-private.h
index b6e0066d3..b6e0066d3 100644
--- a/cogl/cogl-texture-3d-private.h
+++ b/cogl/cogl/cogl-texture-3d-private.h
diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl/cogl-texture-3d.c
index 8e2ff0821..8e2ff0821 100644
--- a/cogl/cogl-texture-3d.c
+++ b/cogl/cogl/cogl-texture-3d.c
diff --git a/cogl/cogl-texture-3d.h b/cogl/cogl/cogl-texture-3d.h
index b3b038ae8..b3b038ae8 100644
--- a/cogl/cogl-texture-3d.h
+++ b/cogl/cogl/cogl-texture-3d.h
diff --git a/cogl/cogl-texture-driver.h b/cogl/cogl/cogl-texture-driver.h
index 3ab86edb2..3ab86edb2 100644
--- a/cogl/cogl-texture-driver.h
+++ b/cogl/cogl/cogl-texture-driver.h
diff --git a/cogl/cogl-texture-private.h b/cogl/cogl/cogl-texture-private.h
index 472c41d9d..472c41d9d 100644
--- a/cogl/cogl-texture-private.h
+++ b/cogl/cogl/cogl-texture-private.h
diff --git a/cogl/cogl-texture-rectangle-private.h b/cogl/cogl/cogl-texture-rectangle-private.h
index 75029e76e..75029e76e 100644
--- a/cogl/cogl-texture-rectangle-private.h
+++ b/cogl/cogl/cogl-texture-rectangle-private.h
diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl/cogl-texture-rectangle.c
index 65d2f062b..65d2f062b 100644
--- a/cogl/cogl-texture-rectangle.c
+++ b/cogl/cogl/cogl-texture-rectangle.c
diff --git a/cogl/cogl-texture-rectangle.h b/cogl/cogl/cogl-texture-rectangle.h
index 761968608..761968608 100644
--- a/cogl/cogl-texture-rectangle.h
+++ b/cogl/cogl/cogl-texture-rectangle.h
diff --git a/cogl/cogl-texture.c b/cogl/cogl/cogl-texture.c
index d93db2276..d93db2276 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl/cogl-texture.c
diff --git a/cogl/cogl-texture.h b/cogl/cogl/cogl-texture.h
index 27188309b..27188309b 100644
--- a/cogl/cogl-texture.h
+++ b/cogl/cogl/cogl-texture.h
diff --git a/cogl/cogl-types.h b/cogl/cogl/cogl-types.h
index 6accf8d88..6accf8d88 100644
--- a/cogl/cogl-types.h
+++ b/cogl/cogl/cogl-types.h
diff --git a/cogl/cogl-util.c b/cogl/cogl/cogl-util.c
index a8a650421..a8a650421 100644
--- a/cogl/cogl-util.c
+++ b/cogl/cogl/cogl-util.c
diff --git a/cogl/cogl-util.h b/cogl/cogl/cogl-util.h
index 160c97888..160c97888 100644
--- a/cogl/cogl-util.h
+++ b/cogl/cogl/cogl-util.h
diff --git a/cogl/cogl-vector.c b/cogl/cogl/cogl-vector.c
index 9da94aff4..9da94aff4 100644
--- a/cogl/cogl-vector.c
+++ b/cogl/cogl/cogl-vector.c
diff --git a/cogl/cogl-vector.h b/cogl/cogl/cogl-vector.h
index 08cf017f8..08cf017f8 100644
--- a/cogl/cogl-vector.h
+++ b/cogl/cogl/cogl-vector.h
diff --git a/cogl/cogl-version.h b/cogl/cogl/cogl-version.h
index bc82437ba..bc82437ba 100644
--- a/cogl/cogl-version.h
+++ b/cogl/cogl/cogl-version.h
diff --git a/cogl/cogl-wayland-server.h b/cogl/cogl/cogl-wayland-server.h
index 9c1f35fa0..9c1f35fa0 100644
--- a/cogl/cogl-wayland-server.h
+++ b/cogl/cogl/cogl-wayland-server.h
diff --git a/cogl/cogl-x11-renderer-private.h b/cogl/cogl/cogl-x11-renderer-private.h
index 17655da2b..17655da2b 100644
--- a/cogl/cogl-x11-renderer-private.h
+++ b/cogl/cogl/cogl-x11-renderer-private.h
diff --git a/cogl/cogl-xlib-private.h b/cogl/cogl/cogl-xlib-private.h
index 992a32099..992a32099 100644
--- a/cogl/cogl-xlib-private.h
+++ b/cogl/cogl/cogl-xlib-private.h
diff --git a/cogl/cogl-xlib-renderer-private.h b/cogl/cogl/cogl-xlib-renderer-private.h
index ea0ee906f..ea0ee906f 100644
--- a/cogl/cogl-xlib-renderer-private.h
+++ b/cogl/cogl/cogl-xlib-renderer-private.h
diff --git a/cogl/cogl-xlib-renderer.c b/cogl/cogl/cogl-xlib-renderer.c
index 8801c1cbf..8801c1cbf 100644
--- a/cogl/cogl-xlib-renderer.c
+++ b/cogl/cogl/cogl-xlib-renderer.c
diff --git a/cogl/cogl-xlib-renderer.h b/cogl/cogl/cogl-xlib-renderer.h
index fdce06b03..fdce06b03 100644
--- a/cogl/cogl-xlib-renderer.h
+++ b/cogl/cogl/cogl-xlib-renderer.h
diff --git a/cogl/cogl-xlib.c b/cogl/cogl/cogl-xlib.c
index 315a1bfbc..315a1bfbc 100644
--- a/cogl/cogl-xlib.c
+++ b/cogl/cogl/cogl-xlib.c
diff --git a/cogl/cogl-xlib.h b/cogl/cogl/cogl-xlib.h
index ac4a14004..ac4a14004 100644
--- a/cogl/cogl-xlib.h
+++ b/cogl/cogl/cogl-xlib.h
diff --git a/cogl/cogl.c b/cogl/cogl/cogl.c
index e4e780857..e4e780857 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl/cogl.c
diff --git a/cogl/cogl.h b/cogl/cogl/cogl.h
index 7fa392137..7fa392137 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl/cogl.h
diff --git a/cogl/cogl.symbols b/cogl/cogl/cogl.symbols
index ad4240777..ad4240777 100644
--- a/cogl/cogl.symbols
+++ b/cogl/cogl/cogl.symbols
diff --git a/cogl/cogl1-context.h b/cogl/cogl/cogl1-context.h
index 92ac7d08f..92ac7d08f 100644
--- a/cogl/cogl1-context.h
+++ b/cogl/cogl/cogl1-context.h
diff --git a/cogl/cogl2-experimental.h b/cogl/cogl/cogl2-experimental.h
index e4623d353..e4623d353 100644
--- a/cogl/cogl2-experimental.h
+++ b/cogl/cogl/cogl2-experimental.h
diff --git a/cogl/deprecated/cogl-auto-texture.c b/cogl/cogl/deprecated/cogl-auto-texture.c
index 87b19c566..87b19c566 100644
--- a/cogl/deprecated/cogl-auto-texture.c
+++ b/cogl/cogl/deprecated/cogl-auto-texture.c
diff --git a/cogl/deprecated/cogl-auto-texture.h b/cogl/cogl/deprecated/cogl-auto-texture.h
index 331c5a9e2..331c5a9e2 100644
--- a/cogl/deprecated/cogl-auto-texture.h
+++ b/cogl/cogl/deprecated/cogl-auto-texture.h
diff --git a/cogl/deprecated/cogl-clip-state.c b/cogl/cogl/deprecated/cogl-clip-state.c
index 1e0ec9289..1e0ec9289 100644
--- a/cogl/deprecated/cogl-clip-state.c
+++ b/cogl/cogl/deprecated/cogl-clip-state.c
diff --git a/cogl/deprecated/cogl-clip-state.h b/cogl/cogl/deprecated/cogl-clip-state.h
index 51091abe5..51091abe5 100644
--- a/cogl/deprecated/cogl-clip-state.h
+++ b/cogl/cogl/deprecated/cogl-clip-state.h
diff --git a/cogl/deprecated/cogl-clutter-xlib.h b/cogl/cogl/deprecated/cogl-clutter-xlib.h
index 424ff49b0..424ff49b0 100644
--- a/cogl/deprecated/cogl-clutter-xlib.h
+++ b/cogl/cogl/deprecated/cogl-clutter-xlib.h
diff --git a/cogl/deprecated/cogl-clutter.c b/cogl/cogl/deprecated/cogl-clutter.c
index 4e53a949d..4e53a949d 100644
--- a/cogl/deprecated/cogl-clutter.c
+++ b/cogl/cogl/deprecated/cogl-clutter.c
diff --git a/cogl/deprecated/cogl-clutter.h b/cogl/cogl/deprecated/cogl-clutter.h
index cc6c44644..cc6c44644 100644
--- a/cogl/deprecated/cogl-clutter.h
+++ b/cogl/cogl/deprecated/cogl-clutter.h
diff --git a/cogl/deprecated/cogl-fixed.c b/cogl/cogl/deprecated/cogl-fixed.c
index bdae6cdfd..bdae6cdfd 100644
--- a/cogl/deprecated/cogl-fixed.c
+++ b/cogl/cogl/deprecated/cogl-fixed.c
diff --git a/cogl/deprecated/cogl-fixed.h b/cogl/cogl/deprecated/cogl-fixed.h
index 73d0ed59b..73d0ed59b 100644
--- a/cogl/deprecated/cogl-fixed.h
+++ b/cogl/cogl/deprecated/cogl-fixed.h
diff --git a/cogl/deprecated/cogl-framebuffer-deprecated.c b/cogl/cogl/deprecated/cogl-framebuffer-deprecated.c
index 97a2a0aec..97a2a0aec 100644
--- a/cogl/deprecated/cogl-framebuffer-deprecated.c
+++ b/cogl/cogl/deprecated/cogl-framebuffer-deprecated.c
diff --git a/cogl/deprecated/cogl-framebuffer-deprecated.h b/cogl/cogl/deprecated/cogl-framebuffer-deprecated.h
index 68ed9d336..68ed9d336 100644
--- a/cogl/deprecated/cogl-framebuffer-deprecated.h
+++ b/cogl/cogl/deprecated/cogl-framebuffer-deprecated.h
diff --git a/cogl/deprecated/cogl-material-compat.c b/cogl/cogl/deprecated/cogl-material-compat.c
index 25f97b113..25f97b113 100644
--- a/cogl/deprecated/cogl-material-compat.c
+++ b/cogl/cogl/deprecated/cogl-material-compat.c
diff --git a/cogl/deprecated/cogl-material-compat.h b/cogl/cogl/deprecated/cogl-material-compat.h
index 88d3ac335..88d3ac335 100644
--- a/cogl/deprecated/cogl-material-compat.h
+++ b/cogl/cogl/deprecated/cogl-material-compat.h
diff --git a/cogl/deprecated/cogl-program-private.h b/cogl/cogl/deprecated/cogl-program-private.h
index 64ed72c6e..64ed72c6e 100644
--- a/cogl/deprecated/cogl-program-private.h
+++ b/cogl/cogl/deprecated/cogl-program-private.h
diff --git a/cogl/deprecated/cogl-program.c b/cogl/cogl/deprecated/cogl-program.c
index 9b44d3538..9b44d3538 100644
--- a/cogl/deprecated/cogl-program.c
+++ b/cogl/cogl/deprecated/cogl-program.c
diff --git a/cogl/deprecated/cogl-shader-private.h b/cogl/cogl/deprecated/cogl-shader-private.h
index dcc16b924..dcc16b924 100644
--- a/cogl/deprecated/cogl-shader-private.h
+++ b/cogl/cogl/deprecated/cogl-shader-private.h
diff --git a/cogl/deprecated/cogl-shader.c b/cogl/cogl/deprecated/cogl-shader.c
index 08dcb82c5..08dcb82c5 100644
--- a/cogl/deprecated/cogl-shader.c
+++ b/cogl/cogl/deprecated/cogl-shader.c
diff --git a/cogl/deprecated/cogl-shader.h b/cogl/cogl/deprecated/cogl-shader.h
index af225e878..af225e878 100644
--- a/cogl/deprecated/cogl-shader.h
+++ b/cogl/cogl/deprecated/cogl-shader.h
diff --git a/cogl/deprecated/cogl-texture-deprecated.c b/cogl/cogl/deprecated/cogl-texture-deprecated.c
index d18a01377..d18a01377 100644
--- a/cogl/deprecated/cogl-texture-deprecated.c
+++ b/cogl/cogl/deprecated/cogl-texture-deprecated.c
diff --git a/cogl/deprecated/cogl-texture-deprecated.h b/cogl/cogl/deprecated/cogl-texture-deprecated.h
index 4ab824df4..4ab824df4 100644
--- a/cogl/deprecated/cogl-texture-deprecated.h
+++ b/cogl/cogl/deprecated/cogl-texture-deprecated.h
diff --git a/cogl/deprecated/cogl-type-casts.h b/cogl/cogl/deprecated/cogl-type-casts.h
index ae716e7dd..ae716e7dd 100644
--- a/cogl/deprecated/cogl-type-casts.h
+++ b/cogl/cogl/deprecated/cogl-type-casts.h
diff --git a/cogl/deprecated/cogl-vertex-buffer-private.h b/cogl/cogl/deprecated/cogl-vertex-buffer-private.h
index f803bbba6..f803bbba6 100644
--- a/cogl/deprecated/cogl-vertex-buffer-private.h
+++ b/cogl/cogl/deprecated/cogl-vertex-buffer-private.h
diff --git a/cogl/deprecated/cogl-vertex-buffer.c b/cogl/cogl/deprecated/cogl-vertex-buffer.c
index b51db13bb..b51db13bb 100644
--- a/cogl/deprecated/cogl-vertex-buffer.c
+++ b/cogl/cogl/deprecated/cogl-vertex-buffer.c
diff --git a/cogl/deprecated/cogl-vertex-buffer.h b/cogl/cogl/deprecated/cogl-vertex-buffer.h
index 3b3a8df62..3b3a8df62 100644
--- a/cogl/deprecated/cogl-vertex-buffer.h
+++ b/cogl/cogl/deprecated/cogl-vertex-buffer.h
diff --git a/cogl/driver/gl/cogl-attribute-gl-private.h b/cogl/cogl/driver/gl/cogl-attribute-gl-private.h
index efb3c0ea2..efb3c0ea2 100644
--- a/cogl/driver/gl/cogl-attribute-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-attribute-gl-private.h
diff --git a/cogl/driver/gl/cogl-attribute-gl.c b/cogl/cogl/driver/gl/cogl-attribute-gl.c
index 34ddb5592..34ddb5592 100644
--- a/cogl/driver/gl/cogl-attribute-gl.c
+++ b/cogl/cogl/driver/gl/cogl-attribute-gl.c
diff --git a/cogl/driver/gl/cogl-buffer-gl-private.h b/cogl/cogl/driver/gl/cogl-buffer-gl-private.h
index b8f0435b3..b8f0435b3 100644
--- a/cogl/driver/gl/cogl-buffer-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-buffer-gl-private.h
diff --git a/cogl/driver/gl/cogl-buffer-gl.c b/cogl/cogl/driver/gl/cogl-buffer-gl.c
index 0f984064e..0f984064e 100644
--- a/cogl/driver/gl/cogl-buffer-gl.c
+++ b/cogl/cogl/driver/gl/cogl-buffer-gl.c
diff --git a/cogl/driver/gl/cogl-clip-stack-gl-private.h b/cogl/cogl/driver/gl/cogl-clip-stack-gl-private.h
index ff22d2660..ff22d2660 100644
--- a/cogl/driver/gl/cogl-clip-stack-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-clip-stack-gl-private.h
diff --git a/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c
index ea1ae620a..ea1ae620a 100644
--- a/cogl/driver/gl/cogl-clip-stack-gl.c
+++ b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c
diff --git a/cogl/driver/gl/cogl-framebuffer-gl-private.h b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
index 47a1c1c96..47a1c1c96 100644
--- a/cogl/driver/gl/cogl-framebuffer-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
index a30ccc1f8..a30ccc1f8 100644
--- a/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-fixed-private.h b/cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed-private.h
index 6f259f998..6f259f998 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-fixed-private.h
+++ b/cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed-private.h
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-fixed.c b/cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
index 55b095687..55b095687 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
+++ b/cogl/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h
index 72f5928a8..72f5928a8 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h
+++ b/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c b/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
index 6fdb3a127..6fdb3a127 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
+++ b/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
diff --git a/cogl/driver/gl/cogl-pipeline-opengl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-opengl-private.h
index 0a374be49..0a374be49 100644
--- a/cogl/driver/gl/cogl-pipeline-opengl-private.h
+++ b/cogl/cogl/driver/gl/cogl-pipeline-opengl-private.h
diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/cogl/driver/gl/cogl-pipeline-opengl.c
index c7b44ee73..c7b44ee73 100644
--- a/cogl/driver/gl/cogl-pipeline-opengl.c
+++ b/cogl/cogl/driver/gl/cogl-pipeline-opengl.c
diff --git a/cogl/driver/gl/cogl-pipeline-progend-fixed-private.h b/cogl/cogl/driver/gl/cogl-pipeline-progend-fixed-private.h
index f97e16a99..f97e16a99 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-fixed-private.h
+++ b/cogl/cogl/driver/gl/cogl-pipeline-progend-fixed-private.h
diff --git a/cogl/driver/gl/cogl-pipeline-progend-fixed.c b/cogl/cogl/driver/gl/cogl-pipeline-progend-fixed.c
index 99f71bff1..99f71bff1 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-fixed.c
+++ b/cogl/cogl/driver/gl/cogl-pipeline-progend-fixed.c
diff --git a/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h
index d57519b80..d57519b80 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h
+++ b/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h
diff --git a/cogl/driver/gl/cogl-pipeline-progend-glsl.c b/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl.c
index 8884ce669..8884ce669 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-glsl.c
+++ b/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl.c
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-fixed-private.h b/cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed-private.h
index 97dee5479..97dee5479 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-fixed-private.h
+++ b/cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed-private.h
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-fixed.c b/cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
index f34a012a4..f34a012a4 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
+++ b/cogl/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h
index 4bd3823d0..4bd3823d0 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h
+++ b/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c b/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
index c9e6a2824..c9e6a2824 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h
index e5c658534..e5c658534 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h
diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
index 8675f5205..8675f5205 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
diff --git a/cogl/driver/gl/cogl-texture-gl-private.h b/cogl/cogl/driver/gl/cogl-texture-gl-private.h
index b5baac7bf..b5baac7bf 100644
--- a/cogl/driver/gl/cogl-texture-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-texture-gl-private.h
diff --git a/cogl/driver/gl/cogl-texture-gl.c b/cogl/cogl/driver/gl/cogl-texture-gl.c
index 2e281c03b..2e281c03b 100644
--- a/cogl/driver/gl/cogl-texture-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-gl.c
diff --git a/cogl/driver/gl/cogl-util-gl-private.h b/cogl/cogl/driver/gl/cogl-util-gl-private.h
index dcc61c0c7..dcc61c0c7 100644
--- a/cogl/driver/gl/cogl-util-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-util-gl-private.h
diff --git a/cogl/driver/gl/cogl-util-gl.c b/cogl/cogl/driver/gl/cogl-util-gl.c
index a50a8a305..a50a8a305 100644
--- a/cogl/driver/gl/cogl-util-gl.c
+++ b/cogl/cogl/driver/gl/cogl-util-gl.c
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index 716d1dd0b..716d1dd0b 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
diff --git a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h b/cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h
index f054aada2..f054aada2 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h
+++ b/cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h
diff --git a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c b/cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
index 16b13be8e..16b13be8e 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
+++ b/cogl/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
diff --git a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h b/cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h
index ba0c713cd..ba0c713cd 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h
+++ b/cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h
diff --git a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c b/cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
index 956bffc84..956bffc84 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
+++ b/cogl/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
diff --git a/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
index 109af8133..109af8133 100644
--- a/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index e94449f4a..e94449f4a 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
diff --git a/cogl/driver/gl/gles/cogl-texture-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
index f87f1e907..f87f1e907 100644
--- a/cogl/driver/gl/gles/cogl-texture-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
diff --git a/cogl/driver/nop/cogl-attribute-nop-private.h b/cogl/cogl/driver/nop/cogl-attribute-nop-private.h
index 9c8547dad..9c8547dad 100644
--- a/cogl/driver/nop/cogl-attribute-nop-private.h
+++ b/cogl/cogl/driver/nop/cogl-attribute-nop-private.h
diff --git a/cogl/driver/nop/cogl-attribute-nop.c b/cogl/cogl/driver/nop/cogl-attribute-nop.c
index 5441d5bd4..5441d5bd4 100644
--- a/cogl/driver/nop/cogl-attribute-nop.c
+++ b/cogl/cogl/driver/nop/cogl-attribute-nop.c
diff --git a/cogl/driver/nop/cogl-clip-stack-nop-private.h b/cogl/cogl/driver/nop/cogl-clip-stack-nop-private.h
index 4d8513b06..4d8513b06 100644
--- a/cogl/driver/nop/cogl-clip-stack-nop-private.h
+++ b/cogl/cogl/driver/nop/cogl-clip-stack-nop-private.h
diff --git a/cogl/driver/nop/cogl-clip-stack-nop.c b/cogl/cogl/driver/nop/cogl-clip-stack-nop.c
index 314e7e764..314e7e764 100644
--- a/cogl/driver/nop/cogl-clip-stack-nop.c
+++ b/cogl/cogl/driver/nop/cogl-clip-stack-nop.c
diff --git a/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c
index 53f597564..53f597564 100644
--- a/cogl/driver/nop/cogl-driver-nop.c
+++ b/cogl/cogl/driver/nop/cogl-driver-nop.c
diff --git a/cogl/driver/nop/cogl-framebuffer-nop-private.h b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
index 1e9630feb..1e9630feb 100644
--- a/cogl/driver/nop/cogl-framebuffer-nop-private.h
+++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
diff --git a/cogl/driver/nop/cogl-framebuffer-nop.c b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
index 819078424..819078424 100644
--- a/cogl/driver/nop/cogl-framebuffer-nop.c
+++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
diff --git a/cogl/driver/nop/cogl-texture-2d-nop-private.h b/cogl/cogl/driver/nop/cogl-texture-2d-nop-private.h
index 51de1e3c1..51de1e3c1 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop-private.h
+++ b/cogl/cogl/driver/nop/cogl-texture-2d-nop-private.h
diff --git a/cogl/driver/nop/cogl-texture-2d-nop.c b/cogl/cogl/driver/nop/cogl-texture-2d-nop.c
index b52149831..b52149831 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop.c
+++ b/cogl/cogl/driver/nop/cogl-texture-2d-nop.c
diff --git a/cogl/gl-prototypes/cogl-all-functions.h b/cogl/cogl/gl-prototypes/cogl-all-functions.h
index 7ac9022b7..7ac9022b7 100644
--- a/cogl/gl-prototypes/cogl-all-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-all-functions.h
diff --git a/cogl/gl-prototypes/cogl-core-functions.h b/cogl/cogl/gl-prototypes/cogl-core-functions.h
index f37041b7b..f37041b7b 100644
--- a/cogl/gl-prototypes/cogl-core-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-core-functions.h
diff --git a/cogl/gl-prototypes/cogl-fixed-functions.h b/cogl/cogl/gl-prototypes/cogl-fixed-functions.h
index ce7b4e0de..ce7b4e0de 100644
--- a/cogl/gl-prototypes/cogl-fixed-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-fixed-functions.h
diff --git a/cogl/gl-prototypes/cogl-gles1-functions.h b/cogl/cogl/gl-prototypes/cogl-gles1-functions.h
index 774b9b33b..774b9b33b 100644
--- a/cogl/gl-prototypes/cogl-gles1-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-gles1-functions.h
diff --git a/cogl/gl-prototypes/cogl-gles2-functions.h b/cogl/cogl/gl-prototypes/cogl-gles2-functions.h
index aeb57a487..aeb57a487 100644
--- a/cogl/gl-prototypes/cogl-gles2-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-gles2-functions.h
diff --git a/cogl/gl-prototypes/cogl-glsl-functions.h b/cogl/cogl/gl-prototypes/cogl-glsl-functions.h
index 980f8adf0..980f8adf0 100644
--- a/cogl/gl-prototypes/cogl-glsl-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-glsl-functions.h
diff --git a/cogl/gl-prototypes/cogl-in-gles-core-functions.h b/cogl/cogl/gl-prototypes/cogl-in-gles-core-functions.h
index 5679e7221..5679e7221 100644
--- a/cogl/gl-prototypes/cogl-in-gles-core-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-in-gles-core-functions.h
diff --git a/cogl/gl-prototypes/cogl-in-gles1-core-functions.h b/cogl/cogl/gl-prototypes/cogl-in-gles1-core-functions.h
index 20dc1a81f..20dc1a81f 100644
--- a/cogl/gl-prototypes/cogl-in-gles1-core-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-in-gles1-core-functions.h
diff --git a/cogl/gl-prototypes/cogl-in-gles2-core-functions.h b/cogl/cogl/gl-prototypes/cogl-in-gles2-core-functions.h
index 1e2f79ea4..1e2f79ea4 100644
--- a/cogl/gl-prototypes/cogl-in-gles2-core-functions.h
+++ b/cogl/cogl/gl-prototypes/cogl-in-gles2-core-functions.h
diff --git a/cogl/mutter-cogl-1.0.pc.in b/cogl/cogl/mutter-cogl-1.0.pc.in
index 92e3a4312..92e3a4312 100644
--- a/cogl/mutter-cogl-1.0.pc.in
+++ b/cogl/cogl/mutter-cogl-1.0.pc.in
diff --git a/cogl/winsys/cogl-texture-pixmap-x11-private.h b/cogl/cogl/winsys/cogl-texture-pixmap-x11-private.h
index 5da998f89..5da998f89 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11-private.h
+++ b/cogl/cogl/winsys/cogl-texture-pixmap-x11-private.h
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
index 398c357d3..398c357d3 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.h b/cogl/cogl/winsys/cogl-texture-pixmap-x11.h
index 6340bb54e..6340bb54e 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.h
+++ b/cogl/cogl/winsys/cogl-texture-pixmap-x11.h
diff --git a/cogl/winsys/cogl-winsys-egl-feature-functions.h b/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h
index 17a99f269..17a99f269 100644
--- a/cogl/winsys/cogl-winsys-egl-feature-functions.h
+++ b/cogl/cogl/winsys/cogl-winsys-egl-feature-functions.h
diff --git a/cogl/winsys/cogl-winsys-egl-kms-private.h b/cogl/cogl/winsys/cogl-winsys-egl-kms-private.h
index dea05db47..dea05db47 100644
--- a/cogl/winsys/cogl-winsys-egl-kms-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-egl-kms-private.h
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/cogl/winsys/cogl-winsys-egl-kms.c
index 4da1f1410..4da1f1410 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/cogl/winsys/cogl-winsys-egl-kms.c
diff --git a/cogl/winsys/cogl-winsys-egl-private.h b/cogl/cogl/winsys/cogl-winsys-egl-private.h
index 5d21b4f4e..5d21b4f4e 100644
--- a/cogl/winsys/cogl-winsys-egl-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-egl-private.h
diff --git a/cogl/winsys/cogl-winsys-egl-x11-private.h b/cogl/cogl/winsys/cogl-winsys-egl-x11-private.h
index 206d4850d..206d4850d 100644
--- a/cogl/winsys/cogl-winsys-egl-x11-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-egl-x11-private.h
diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/cogl/winsys/cogl-winsys-egl-x11.c
index 724a4d01a..724a4d01a 100644
--- a/cogl/winsys/cogl-winsys-egl-x11.c
+++ b/cogl/cogl/winsys/cogl-winsys-egl-x11.c
diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/cogl/winsys/cogl-winsys-egl.c
index a53c0c7d7..a53c0c7d7 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/cogl/winsys/cogl-winsys-egl.c
diff --git a/cogl/winsys/cogl-winsys-glx-feature-functions.h b/cogl/cogl/winsys/cogl-winsys-glx-feature-functions.h
index ed9df707f..ed9df707f 100644
--- a/cogl/winsys/cogl-winsys-glx-feature-functions.h
+++ b/cogl/cogl/winsys/cogl-winsys-glx-feature-functions.h
diff --git a/cogl/winsys/cogl-winsys-glx-private.h b/cogl/cogl/winsys/cogl-winsys-glx-private.h
index 9fb386ff7..9fb386ff7 100644
--- a/cogl/winsys/cogl-winsys-glx-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-glx-private.h
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
index 72d9e5627..72d9e5627 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/cogl/winsys/cogl-winsys-private.h
index 85a67c72a..85a67c72a 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-private.h
diff --git a/cogl/winsys/cogl-winsys-stub-private.h b/cogl/cogl/winsys/cogl-winsys-stub-private.h
index 4aaf798a3..4aaf798a3 100644
--- a/cogl/winsys/cogl-winsys-stub-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-stub-private.h
diff --git a/cogl/winsys/cogl-winsys-stub.c b/cogl/cogl/winsys/cogl-winsys-stub.c
index 4fc8c90e5..4fc8c90e5 100644
--- a/cogl/winsys/cogl-winsys-stub.c
+++ b/cogl/cogl/winsys/cogl-winsys-stub.c
diff --git a/cogl/winsys/cogl-winsys.c b/cogl/cogl/winsys/cogl-winsys.c
index fccb94c25..fccb94c25 100644
--- a/cogl/winsys/cogl-winsys.c
+++ b/cogl/cogl/winsys/cogl-winsys.c
diff --git a/cogl/config-custom.h b/cogl/config-custom.h
new file mode 100644
index 000000000..08fb9a40c
--- /dev/null
+++ b/cogl/config-custom.h
@@ -0,0 +1,32 @@
+/*
+ * Cogl
+ *
+ * A Low Level GPU Graphics and Utilities API
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* The contents of this file get #included by config.h so it is
+ intended for extra configuration that needs to be included by all
+ Cogl source files. */
+
diff --git a/cogl/configure.ac b/cogl/configure.ac
new file mode 100644
index 000000000..1ec4dbf10
--- /dev/null
+++ b/cogl/configure.ac
@@ -0,0 +1,1036 @@
+AC_PREREQ(2.59)
+
+dnl ================================================================
+dnl XXX: If you are making a release then you need to check these
+dnl sections:
+dnl » API versions (Only the 1.x version needs to change)
+dnl (the pretty numbers that the users see)
+dnl
+dnl » Interface version details for libtool
+dnl (the shared library versioning information)
+dnl
+dnl » Source code release status
+dnl (mark the source code as being part of a "release" or from "git")
+dnl ================================================================
+
+dnl ================================================================
+dnl API versions (i.e. the pretty numbers that users see)
+dnl ================================================================
+m4_define([cogl_major_version], [2])
+m4_define([cogl_minor_version], [0])
+m4_define([cogl_micro_version], [0])
+m4_define([cogl_version],
+ [cogl_major_version.cogl_minor_version.cogl_micro_version])
+
+dnl Since the core Cogl library has to also maintain support for the
+dnl Cogl 1.x API for Clutter then we track the 1.x version separately.
+m4_define([cogl_1_minor_version], [22])
+m4_define([cogl_1_micro_version], [1])
+m4_define([cogl_1_version], [1.cogl_1_minor_version.cogl_1_micro_version])
+
+dnl ================================================================
+dnl Interface version details for libtool
+dnl ================================================================
+# Note: we don't automatically deduce the libtool version info from
+# the pretty version number that users sees. This is because we want
+# to update the pretty version number before making a release since it
+# can affect the name of our pkg-config file and the naming or
+# location of other installed files which we want to be able to verify
+# as correct well before making a release.
+#
+# For reference on how the various numbers should be updated at
+# release time these rules are adapted from the libtool info pages:
+#
+# 1. Update the version information only immediately before a public
+# release.
+#
+# 2. If the library source code has changed at all since the last
+# update, then increment REVISION (`C:R:A' becomes `C:r+1:A').
+#
+# 3. If any interfaces have been added, removed, or changed since the
+# last update, increment CURRENT, and set REVISION to 0.
+#
+# 4. If any interfaces have been added since the last public release,
+# then increment AGE.
+#
+# 5. If any interfaces have been removed since the last public release,
+# then set AGE to 0.
+m4_define([cogl_lt_current], 24)
+m4_define([cogl_lt_revision], 1)
+m4_define([cogl_lt_age], 4)
+# We do also tell libtool the pretty version:
+m4_define([cogl_lt_release], [cogl_version])
+
+
+dnl ================================================================
+dnl Source code release status
+dnl ================================================================
+# Finally we explicitly track when we are building development source
+# from Git vs building source corresponding to a release. As with the
+# libtool version info we don't automatically derive this from the
+# pretty version number because we want to test the results of
+# updating the version number in advance of a release.
+#
+# Possible status values are: git, snapshot or release
+#
+m4_define([cogl_release_status], [git])
+
+AC_INIT(cogl, [cogl_1_version])
+AC_CONFIG_SRCDIR(cogl/cogl.h)
+AC_CONFIG_AUX_DIR([build])
+AC_CONFIG_MACRO_DIR([build/autotools])
+AC_CONFIG_HEADERS(config.h)
+AC_GNU_SOURCE
+
+dnl ================================================================
+dnl Required versions for dependencies
+dnl ================================================================
+m4_define([glib_req_version], [2.32.0])
+m4_define([pangocairo_req_version], [1.20])
+m4_define([gi_req_version], [0.9.5])
+m4_define([gdk_pixbuf_req_version], [2.0])
+m4_define([uprof_req_version], [0.3])
+m4_define([xfixes_req_version], [3])
+m4_define([xcomposite_req_version], [0.4])
+m4_define([xrandr_req_version], [1.2])
+m4_define([cairo_req_version], [1.10])
+m4_define([wayland_server_req_version], [1.1.90])
+m4_define([mirclient_req_version], [0.9.0])
+
+dnl These variables get copied into the generated README
+AC_SUBST([GLIB_REQ_VERSION], [glib_req_version])
+AC_SUBST([GDK_PIXBUF_REQ_VERSION], [gdk_pixbuf_req_version])
+AC_SUBST([CAIRO_REQ_VERSION], [cairo_req_version])
+AC_SUBST([PANGOCAIRO_REQ_VERSION], [pangocairo_req_version])
+AC_SUBST([XCOMPOSITE_REQ_VERSION], [xcomposite_req_version])
+AC_SUBST([XFIXES_REQ_VERSION], [xfixes_req_version])
+AC_SUBST([GI_REQ_VERSION], [gi_req_version])
+AC_SUBST([UPROF_REQ_VERSION], [uprof_req_version])
+AC_SUBST([WAYLAND_SERVER_REQ_VERSION], [wayland_server_req_version])
+
+# Save this value here, since automake will set cflags later and we
+# want to know if the user specified custom cflags or not.
+cflags_set=${CFLAGS+set}
+
+AM_INIT_AUTOMAKE([1.14 foreign -Wno-portability no-define no-dist-gzip dist-xz tar-ustar subdir-objects])
+AM_SILENT_RULES([yes])
+
+AH_BOTTOM([#include "config-custom.h"])
+
+dnl ================================================================
+dnl Export the API versioning
+dnl ================================================================
+AC_SUBST([COGL_MAJOR_VERSION],[cogl_major_version])
+AC_SUBST([COGL_MINOR_VERSION],[cogl_minor_version])
+AC_SUBST([COGL_MICRO_VERSION],[cogl_micro_version])
+AC_SUBST([COGL_VERSION],[cogl_version])
+AC_SUBST([COGL_API_VERSION],[cogl_major_version.0])
+AC_SUBST([COGL_API_VERSION_AM],[$COGL_MAJOR_VERSION\_0])
+
+AC_SUBST([COGL_1_MINOR_VERSION],[cogl_1_minor_version])
+AC_SUBST([COGL_1_MICRO_VERSION],[cogl_1_micro_version])
+AC_SUBST([COGL_1_VERSION],[cogl_1_version])
+
+
+dnl ================================================================
+dnl Export the libtool versioning
+dnl ================================================================
+AC_SUBST([COGL_LT_CURRENT], [cogl_lt_current])
+AC_SUBST([COGL_LT_REVISION], [cogl_lt_revision])
+AC_SUBST([COGL_LT_AGE], [cogl_lt_age])
+AC_SUBST([COGL_LT_RELEASE], [cogl_lt_release])
+
+
+dnl ================================================================
+dnl Export the source code release status
+dnl ================================================================
+AC_SUBST([COGL_RELEASE_STATUS], [cogl_release_status])
+
+dnl ================================================================
+dnl Compiler stuff.
+dnl ================================================================
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AM_PROG_CC_C_O
+AC_ISC_POSIX
+AC_C_CONST
+
+dnl ============================================================
+dnl Compiler features
+dnl ============================================================
+AC_MSG_CHECKING([for _Static_assert])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_Static_assert (1, "");],
+ [(void) 0])],
+ [AC_DEFINE([HAVE_STATIC_ASSERT], [1],
+ [Whether _Static_assert can be used or not])
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])])
+
+dnl ================================================================
+dnl Libtool stuff.
+dnl ================================================================
+dnl AC_PROG_LIBTOOL
+dnl LIBTOOL="$LIBTOOL --preserve-dup-deps"
+LT_PREREQ([2.2.6])
+LT_INIT([disable-static])
+dnl when using libtool 2.x create libtool early, because it's used in the
+dnl internal glib configure (as-glibconfig.m4)
+m4_ifdef([LT_OUTPUT], [LT_OUTPUT])
+
+dnl ================================================================
+dnl Find an appropriate libm, for sin() etc.
+dnl ================================================================
+LT_LIB_M
+AC_SUBST(LIBM)
+
+dnl ================================================================
+dnl See what platform we are building for
+dnl ================================================================
+AC_CANONICAL_HOST
+
+dnl ============================================================
+dnl Installed tests
+dnl ============================================================
+
+AC_ARG_ENABLE(installed_tests,
+ AS_HELP_STRING([--enable-installed-tests],
+ [Install test programs (default: no)]),,
+ [enable_installed_tests=no])
+AM_CONDITIONAL(ENABLE_INSTALLED_TESTS, test x$enable_installed_tests = xyes)
+
+dnl ============================================================
+dnl Enable debugging
+dnl ============================================================
+m4_define([debug_default], [m4_if(cogl_release_status, [git], [yes], [no])])
+AC_ARG_ENABLE(
+ [debug],
+ [AC_HELP_STRING([--enable-debug=@<:@no/yes@:>@], [Control Cogl debugging level @<:@default=]debug_default[@:>@])],
+ [],
+ enable_debug=debug_default
+)
+AS_CASE(
+ [$enable_debug],
+ [yes],
+ [
+ test "$cflags_set" = set || CFLAGS="$CFLAGS -g -O0"
+ COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DCOGL_GL_DEBUG -DCOGL_OBJECT_DEBUG -DCOGL_ENABLE_DEBUG"
+ ],
+ [no],
+ [
+ COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS"
+ ],
+ [AC_MSG_ERROR([Unknown argument for --enable-debug])]
+)
+
+AC_SUBST(COGL_DEBUG_CFLAGS)
+
+AC_ARG_ENABLE(
+ [unit-tests],
+ [AC_HELP_STRING([--enable-unit-tests=@<:@no/yes@:>@], [Build Cogl unit tests @<:@default=yes@:>@])],
+ [],
+ enable_unit_tests=yes
+)
+AS_IF([test "x$enable_unit_tests" = "xyes"],
+ [
+ AC_DEFINE([ENABLE_UNIT_TESTS], [1], [Whether to enable building unit tests])
+ ]
+)
+AM_CONDITIONAL(UNIT_TESTS, test "x$enable_unit_tests" = "xyes")
+
+dnl ============================================================
+dnl Enable cairo usage for debugging
+dnl (debugging code can use cairo to dump the atlas)
+dnl ============================================================
+
+PKG_CHECK_EXISTS([CAIRO], [cairo >= cairo_req_version], [have_cairo=yes])
+AC_ARG_ENABLE(
+ [cairo],
+ [AC_HELP_STRING([--enable-cairo=@<:@no/yes@:>@], [Control Cairo usage in Cogl debugging code @<:@default=auto@:>@])],
+ [],
+ [
+ AS_IF([test "x$enable_debug" = "xyes"],
+ [enable_cairo=$have_cairo],
+ [enable_cairo=no])
+ ]
+)
+AS_IF([test "x$enable_cairo" = "xyes" && test "x$enable_debug" = "xyes"],
+ [
+ AS_IF([test "x$have_cairo" != "xyes"],
+ [AC_MSG_ERROR([Could not find Cairo])])
+
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES cairo >= cairo_req_version"
+ AC_DEFINE([HAVE_CAIRO], [1], [Whether we have cairo or not])
+ ])
+
+
+dnl ============================================================
+dnl Enable profiling
+dnl ============================================================
+AC_ARG_ENABLE(profile,
+ [AC_HELP_STRING([--enable-profile=@<:@no/yes@:>@],
+ [Turn on uprof profiling support. yes; All UProf profiling probe points are compiled in and may be runtime enabled. no; No profiling support will built into cogl. @<:@default=no@:>@])],
+ [],
+ [enable_profile=no])
+AS_IF([test "x$enable_profile" = "xyes"],
+ [
+ AS_IF([test "x$GCC" = "xyes"],
+ [
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES uprof-0.3"
+ COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DCOGL_ENABLE_PROFILE"
+ AS_IF([test "x$enable_debug" = "xyes"], [COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -DUPROF_DEBUG"])
+ ],
+ [
+ AC_MSG_ERROR([--enable-profile is currently only supported if using GCC])
+ ])
+ ])
+AM_CONDITIONAL(PROFILE, test "x$enable_profile" != "xno")
+
+
+dnl ============================================================
+dnl Enable strict compiler flags
+dnl ============================================================
+
+# use strict compiler flags only when building from git; the rules for
+# distcheck will take care of turning this on when making a release
+m4_define([maintainer_default], [m4_if(cogl_release_status, [git], [yes], [no])])
+AC_ARG_ENABLE(
+ [maintainer-flags],
+ [AC_HELP_STRING([--enable-maintainer-flags=@<:@no/yes/error@:>@], [Use strict compiler flags @<:@default=]maintainer_default[@:>@])],
+ [],
+ enable_maintainer_flags=maintainer_default
+)
+
+MAINTAINER_COMPILER_FLAGS="-Wall -Wcast-align -Wformat -Wformat-security
+ -Werror=uninitialized -Werror=no-strict-aliasing
+ -Werror=empty-body -Werror=init-self -Werror=undef
+ -Werror=declaration-after-statement -Werror=vla
+ -Werror=pointer-arith -Werror=missing-declarations
+ -Werror=maybe-uninitialized"
+
+AS_CASE(
+ [$enable_maintainer_flags],
+ [yes],
+ [
+ AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS])
+ ],
+ [no],
+ [
+ ],
+ [error],
+ [
+ MAINTAINER_COMPILER_FLAGS="$MAINTAINER_COMPILER_FLAGS -Werror"
+ AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS])
+ ],
+ [*],
+ [AC_MSG_ERROR([Invalid option for --enable-maintainer-flags])]
+)
+
+# strip leading spaces
+COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS ${MAINTAINER_CFLAGS#* }"
+
+
+dnl ============================================================
+dnl Enable deprecation guards
+dnl ============================================================
+
+# disable deprecated options from Glib only when building from git;
+# the rules for distcheck will take care of turning this on when
+# making a release
+m4_define([deprecated_default],
+ [m4_if(cogl_release_status, [git], [no], [yes])])
+
+AC_ARG_ENABLE([deprecated],
+ [AS_HELP_STRING([--enable-deprecated=@<:@no/yes@:>@],
+ [Whether deprecated symbols should be disabled when compiling Cogl @<:@default=]deprecated_default[@:>@])],
+ [],
+ [enable_deprecated=deprecated_default])
+
+AS_CASE([$enable_deprecated],
+
+ [no],
+ [
+ DEPRECATED_CFLAGS="-DG_DISABLE_DEPRECATED -DG_DISABLE_SINGLE_INCLUDES"
+ ],
+
+ [yes],
+ [
+ DEPRECATED_CFLAGS=""
+ ],
+
+ [AC_MSG_ERROR([Unknown argument for --enable-deprecated])]
+)
+
+# strip leading spaces
+COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS ${DEPRECATED_CFLAGS#* }"
+
+dnl ================================================================
+dnl Check for dependency packages.
+dnl ================================================================
+
+AM_PATH_GLIB_2_0([glib_req_version],
+ [],
+ [AC_MSG_ERROR([glib-2.0 is required])],
+ [gobject gthread gmodule-no-export])
+
+COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLIB_SUPPORT"
+COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GTYPE_SUPPORT"
+COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gobject-2.0 gmodule-no-export-2.0"
+
+dnl ============================================================
+dnl Should cogl-pango be built?
+dnl ============================================================
+
+AC_ARG_ENABLE(
+ [cogl-pango],
+ [AC_HELP_STRING([--enable-cogl-pango=@<:@no/yes@:>@], [Enable pango support @<:@default=yes@:>@])],
+ [],
+ enable_cogl_pango=yes
+)
+AS_IF([test "x$enable_cogl_pango" = "xyes"],
+ [
+ COGL_PANGO_PKG_REQUIRES="$COGL_PANGO_PKG_REQUIRES pangocairo >= pangocairo_req_version"
+ ]
+)
+
+dnl ============================================================
+dnl Should cogl-path be built?
+dnl ============================================================
+
+AC_ARG_ENABLE(
+ [cogl-path],
+ [AC_HELP_STRING([--enable-cogl-path=@<:@no/yes@:>@], [Enable 2D path support @<:@default=yes@:>@])],
+ [],
+ enable_cogl_path=yes
+)
+AS_IF([test "x$enable_cogl_path" = "xyes"],
+ [
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_COGL_PATH_SUPPORT"
+ ]
+)
+
+dnl ============================================================
+dnl Choose image loading backend
+dnl ============================================================
+COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gdk-pixbuf-2.0 >= gdk_pixbuf_req_version"
+COGL_IMAGE_BACKEND="gdk-pixbuf"
+
+dnl ============================================================
+dnl Determine which drivers and window systems we can support
+dnl ============================================================
+
+dnl ========================================================
+dnl Drivers first...
+dnl ========================================================
+EGL_CHECKED=no
+
+enabled_drivers=""
+
+HAVE_GLES1=0
+AC_ARG_ENABLE(
+ [gles1],
+ [AC_HELP_STRING([--enable-gles1=@<:@no/yes@:>@], [Enable support for OpenGL-ES 1.1 @<:@default=no@:>@])],
+ [],
+ enable_gles1=no
+)
+AS_IF([test "x$enable_gles1" = "xyes"],
+ [
+ enabled_drivers="$enabled_drivers gles1"
+
+ cogl_gl_headers="GLES/gl.h GLES/glext.h"
+
+ AC_DEFINE([HAVE_COGL_GLES], 1, [Have GLES 1.1 for rendering])
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES CLUTTER_COGL_HAS_GLES"
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES1"
+ HAVE_GLES1=1
+
+ PKG_CHECK_EXISTS([glesv1_cm],
+ [COGL_PKG_REQUIRES_GL="$COGL_PKG_REQUIRES_GL glesv1_cm"
+ COGL_GLES1_LIBNAME="libGLESv1_CM.so"
+ ],
+ [
+ # We have to check the two headers independently as GLES/glext.h
+ # needs to include GLES/gl.h to have the GL types defined (eg.
+ # GLenum).
+ AC_CHECK_HEADER([GLES/gl.h],
+ [],
+ [AC_MSG_ERROR([Unable to locate GLES/gl.h])])
+ AC_CHECK_HEADER([GLES/glext.h],
+ [],
+ [AC_MSG_ERROR([Unable to locate GLES/glext.h])],
+ [#include <GLES/gl.h>])
+
+ # Early implementations provided only a GLES/egl.h while Khronos's
+ # implementer guide now states EGL/egl.h is the One. Some
+ # implementations keep a GLES/egl.h wrapper around EGL/egl.h for
+ # backward compatibility while others provide EGL/egl.h only.
+ AC_CHECK_HEADERS([GLES/egl.h EGL/egl.h])
+
+ AS_IF([test "x$ac_cv_header_GLES_egl_h" = "xyes"],
+ [COGL_EGL_INCLUDES="#include <GLES/egl.h>"],
+ [test "x$ac_cv_header_EGL_egl_h" = "xyes"],
+ [
+ COGL_EGL_INCLUDES="#include <EGL/egl.h>"
+ ],
+ [AC_MSG_ERROR([Unable to locate EGL header])])
+ AC_SUBST([COGL_EGL_INCLUDES])
+
+ AC_CHECK_HEADERS([EGL/eglext.h],
+ [COGL_EGL_INCLUDES="$COGL_EGL_INCLUDE
+#include <EGL/eglext.h>"],
+ [],
+ [$COGL_EGL_INCLUDES])
+
+ # Check for a GLES 1.x Common Profile library with/without EGL.
+ #
+ # Note: historically GLES 1 libraries shipped with the
+ # EGL and GLES symbols all bundled in one library. Now
+ # the Khronos Implementers Guide defines two naming
+ # schemes: -lGLES_CM should be used for a library that
+ # bundles the GLES and EGL API together and -lGLESv1_CM
+ # would be used for a standalone GLES API.
+ AC_CHECK_LIB(GLES_CM, [eglInitialize],
+ [COGL_GLES1_LIBNAME="libGLES_CM.so"],
+ [
+ AC_CHECK_LIB(GLESv1_CM, [glFlush],
+ [COGL_GLES1_LIBNAME="libGLESv1_CM.so"
+ NEED_SEPARATE_EGL=yes
+ ],
+ [AC_MSG_ERROR([Unable to locate required GLES 1.x Common Profile library])])
+ ])
+
+ EGL_CHECKED=yes
+ ])
+ ])
+
+HAVE_GLES2=0
+AC_ARG_ENABLE(
+ [gles2],
+ [AC_HELP_STRING([--enable-gles2=@<:@no/yes@:>@], [Enable support for OpenGL-ES 2.0 @<:@default=no@:>@])],
+ [],
+ enable_gles2=no
+)
+AS_IF([test "x$enable_gles2" = "xyes"],
+ [
+ enabled_drivers="$enabled_drivers gles2"
+
+ cogl_gl_headers="GLES2/gl2.h GLES2/gl2ext.h"
+ AC_DEFINE([HAVE_COGL_GLES2], 1, [Have GLES 2.0 for rendering])
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES CLUTTER_COGL_HAS_GLES"
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLES2"
+ HAVE_GLES2=1
+
+ PKG_CHECK_EXISTS([glesv2],
+ [COGL_PKG_REQUIRES_GL="$COGL_PKG_REQUIRES_GL glesv2"
+ COGL_GLES2_LIBNAME="libGLESv2.so"
+ ],
+ [
+ # We have to check the two headers independently as GLES2/gl2ext.h
+ # needs to include GLES2/gl2.h to have the GL types defined (eg.
+ # GLenum).
+ AC_CHECK_HEADER([GLES2/gl2.h],
+ [],
+ [AC_MSG_ERROR([Unable to locate GLES2/gl2.h])])
+ AC_CHECK_HEADER([GLES2/gl2ext.h],
+ [],
+ [AC_MSG_ERROR([Unable to locate GLES2/gl2ext.h])],
+ [#include <GLES2/gl2.h>])
+
+ COGL_GLES2_LIBNAME="libGLESv2.so"
+ ])
+ ])
+
+HAVE_GL=0
+AC_ARG_ENABLE(
+ [gl],
+ [AC_HELP_STRING([--enable-gl=@<:@no/yes@:>@], [Enable support for OpenGL @<:@default=yes@:>@])],
+ [],
+ [enable_gl=yes]
+)
+AS_IF([test "x$enable_gl" = "xyes"],
+ [
+ enabled_drivers="$enabled_drivers gl"
+
+ PKG_CHECK_EXISTS([x11], [ALLOW_GLX=yes])
+
+ cogl_gl_headers="GL/gl.h"
+
+ PKG_CHECK_EXISTS([gl],
+ dnl We don't want to use COGL_PKG_REQUIRES here because we don't want to
+ dnl directly link against libGL
+ [COGL_PKG_REQUIRES_GL="$COGL_PKG_REQUIRES_GL gl"],
+ [AC_CHECK_LIB(GL, [glGetString],
+ ,
+ [AC_MSG_ERROR([Unable to locate required GL library])])
+ ])
+ COGL_GL_LIBNAME="libGL.so.1"
+
+ AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering])
+
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GL"
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS CLUTTER_COGL_HAS_GL"
+ HAVE_GL=1
+ ])
+
+AM_CONDITIONAL([COGL_DRIVER_GL_SUPPORTED], [test "x$enable_gl" = "xyes"])
+AM_CONDITIONAL([COGL_DRIVER_GLES_SUPPORTED],
+ [test "x$enable_gles1" = "xyes" || test "x$enable_gles2" = "xyes"])
+
+dnl Allow the GL library names and default driver to be overridden with configure options
+AC_ARG_WITH([gl-libname],
+ [AS_HELP_STRING([--with-gl-libname],
+ override the name of the GL library to dlopen)],
+ [COGL_GL_LIBNAME="$withval"])
+AC_ARG_WITH([gles1-libname],
+ [AS_HELP_STRING([--with-gles1-libname],
+ override the name of the GLESv1 library to dlopen)],
+ [COGL_GLES1_LIBNAME="$withval"])
+AC_ARG_WITH([gles2-libname],
+ [AS_HELP_STRING([--with-gles2-libname],
+ override the name of the GLESv2 library to dlopen)],
+ [COGL_GLES2_LIBNAME="$withval"])
+AC_ARG_WITH([default-driver],
+ [AS_HELP_STRING([--with-default-driver],
+ specify a default cogl driver)],
+ [COGL_DEFAULT_DRIVER="${withval}"],
+ [COGL_DEFAULT_DRIVER="" ])
+
+AM_CONDITIONAL(HAVE_COGL_DEFAULT_DRIVER,
+ [ test "x$COGL_DEFAULT_DRIVER" != "x" ])
+
+
+AC_SUBST([COGL_GL_LIBNAME])
+AC_SUBST([HAVE_GL])
+AC_SUBST([COGL_GLES1_LIBNAME])
+AC_SUBST([HAVE_GLES1])
+AC_SUBST([COGL_GLES2_LIBNAME])
+AC_SUBST([HAVE_GLES2])
+AC_SUBST([COGL_DEFAULT_DRIVER])
+
+AC_ARG_ENABLE(
+ [cogl-gles2],
+ [AC_HELP_STRING([--enable-cogl-gles2=@<:@no/yes@:>@],
+ [Enable libcogl-gles2 frontend api for OpenGL-ES 2.0 @<:@default=auto@:>@])],
+ [],
+ [
+ AS_IF([test "x$HAVE_GLES2" = "x1"],
+ [enable_cogl_gles2=yes],
+ [enable_cogl_gles2=no])
+ ]
+)
+AS_IF([test "x$enable_cogl_gles2" = "xyes"],
+ [
+ AS_IF([test "x$HAVE_GLES2" != "x1"],
+ [
+ AC_MSG_ERROR([libcogl-gles2 is currently only supported on systems with a native GLES 2.0 library])
+ ])
+ ])
+AM_CONDITIONAL([BUILD_COGL_GLES2], [test "x$enable_cogl_gles2" = "xyes"])
+
+
+dnl ========================================================
+dnl Check window system integration libraries...
+dnl ========================================================
+
+AC_ARG_ENABLE(
+ [glx],
+ [AC_HELP_STRING([--enable-glx=@<:@no/yes@:>@], [Enable support GLX @<:@default=auto@:>@])],
+ [],
+ [AS_IF([test "x$ALLOW_GLX" = "xyes"], [enable_glx=yes], [enable_glx=no])]
+)
+AS_IF([test "x$enable_glx" = "xyes"],
+ [
+ AS_IF([test "x$ALLOW_GLX" != "xyes"],
+ [AC_MSG_ERROR([GLX not supported with this configuration])])
+
+ NEED_XLIB=yes
+ SUPPORT_GLX=yes
+ GL_WINSYS_APIS="$GL_WINSYS_APIS glx"
+
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLX_SUPPORT"
+ ])
+AM_CONDITIONAL(SUPPORT_GLX, [test "x$SUPPORT_GLX" = "xyes"])
+
+EGL_PLATFORM_COUNT=0
+
+AC_ARG_ENABLE(
+ [kms-egl-platform],
+ [AC_HELP_STRING([--enable-kms-egl-platform=@<:@no/yes@:>@], [Enable support for the KMS egl platform @<:@default=no@:>@])],
+ [],
+ enable_kms_egl_platform=no
+)
+AS_IF([test "x$enable_kms_egl_platform" = "xyes"],
+ [
+ EGL_PLATFORM_COUNT=$((EGL_PLATFORM_COUNT+1))
+ NEED_EGL=yes
+ EGL_PLATFORMS="$EGL_PLATFORMS kms"
+
+ PKG_CHECK_EXISTS([gbm],
+ [
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gbm"
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES libdrm"
+ ],
+ [AC_MSG_ERROR([Unable to locate required libgbm library for the KMS egl platform])])
+
+ GBM_VERSION=`$PKG_CONFIG --modversion gbm`
+ GBM_MAJOR=`echo $GBM_VERSION | cut -d'.' -f1`
+ GBM_MINOR=`echo $GBM_VERSION | cut -d'.' -f2`
+ GBM_MICRO=`echo $GBM_VERSION | cut -d'.' -f3 | sed 's/-.*//'`
+
+ AC_DEFINE_UNQUOTED([COGL_GBM_MAJOR], [$GBM_MAJOR], [The major version for libgbm])
+ AC_DEFINE_UNQUOTED([COGL_GBM_MINOR], [$GBM_MINOR], [The minor version for libgbm])
+ AC_DEFINE_UNQUOTED([COGL_GBM_MICRO], [$GBM_MICRO], [The micro version for libgbm])
+
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_PLATFORM_KMS_SUPPORT"
+ ])
+AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_KMS,
+ [test "x$enable_kms_egl_platform" = "xyes"])
+
+AC_ARG_ENABLE(
+ [wayland-egl-server],
+ [AC_HELP_STRING([--enable-wayland-egl-server=@<:@no/yes@:>@], [Enable server side wayland support @<:@default=no@:>@])],
+ [],
+ enable_wayland_egl_server=no
+)
+AS_IF([test "x$enable_wayland_egl_server" = "xyes"],
+ [
+ NEED_EGL=yes
+
+ PKG_CHECK_MODULES(WAYLAND_SERVER,
+ [wayland-server >= wayland_server_req_version])
+ COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES wayland-server >= wayland_server_req_version"
+
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT"
+ ])
+AM_CONDITIONAL(SUPPORT_WAYLAND_EGL_SERVER,
+ [test "x$enable_wayland_egl_server" = "xyes"])
+
+dnl This should go last, since it's the default fallback and we need
+dnl to check the value of $EGL_PLATFORM_COUNT here.
+AC_ARG_ENABLE(
+ [xlib-egl-platform],
+ [AC_HELP_STRING([--enable-xlib-egl-platform=@<:@no/yes@:>@], [Enable support for the Xlib egl platform @<:@default=auto@:>@])],
+ [],
+ AS_IF([test "x$enable_gles1" = "xyes" -o \
+ "x$enable_gles2" = "xyes" && \
+ test $EGL_PLATFORM_COUNT -eq 0],
+ [enable_xlib_egl_platform=yes], [enable_xlib_egl_platform=no])
+)
+AS_IF([test "x$enable_xlib_egl_platform" = "xyes"],
+ [
+ EGL_PLATFORM_COUNT=$((EGL_PLATFORM_COUNT+1))
+ NEED_EGL=yes
+ NEED_XLIB=yes
+ EGL_PLATFORMS="$EGL_PLATFORMS xlib"
+
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT"
+ ])
+AM_CONDITIONAL(SUPPORT_EGL_PLATFORM_XLIB,
+ [test "x$enable_xlib_egl_platform" = "xyes"])
+
+AS_IF([test "x$NEED_EGL" = "xyes" && test "x$EGL_CHECKED" != "xyes"],
+ [
+ PKG_CHECK_EXISTS([egl],
+ [COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES egl"],
+ [
+ AC_CHECK_HEADERS(
+ [EGL/egl.h],
+ [],
+ [AC_MSG_ERROR([Unable to locate required EGL headers])])
+ AC_CHECK_HEADERS(
+ [EGL/eglext.h],
+ [],
+ [AC_MSG_ERROR([Unable to locate required EGL headers])],
+ [#include <EGL/egl.h>])
+
+ AC_CHECK_LIB(EGL, [eglInitialize],
+ [COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -lEGL"],
+ [AC_MSG_ERROR([Unable to locate required EGL library])])
+
+ COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -lEGL"
+ ]
+ )
+
+ COGL_EGL_INCLUDES="#include <EGL/egl.h>
+#include <EGL/eglext.h>"
+ AC_SUBST([COGL_EGL_INCLUDES])
+ ])
+
+AS_IF([test "x$NEED_EGL" = "xyes"],
+ [
+ SUPPORT_EGL=yes
+ GL_WINSYS_APIS="$GL_WINSYS_APIS egl"
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_EGL_SUPPORT"
+ ])
+
+AM_CONDITIONAL(SUPPORT_EGL, [test "x$SUPPORT_EGL" = "xyes"])
+
+dnl ========================================================
+dnl Check X11 dependencies if required
+dnl ========================================================
+AS_IF([test "x$NEED_XLIB" = "xyes"],
+ [
+ X11_MODULES="x11 xext xfixes >= xfixes_req_version xdamage xcomposite >= xcomposite_req_version xrandr >= xrandr_req_version"
+ PKG_CHECK_MODULES(DUMMY, [$X11_MODULES],
+ [COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES $X11_MODULES"])
+ SUPPORT_X11=yes
+ SUPPORT_XLIB=yes
+
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_X11"
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_X11_SUPPORT"
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_XLIB"
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_XLIB_SUPPORT"
+ ])
+
+AM_CONDITIONAL(X11_TESTS, [test "x$SUPPORT_X11" = "xyes"])
+AM_CONDITIONAL(SUPPORT_X11, [test "x$SUPPORT_X11" = "xyes"])
+AM_CONDITIONAL(SUPPORT_XLIB, [test "x$SUPPORT_XLIB" = "xyes"])
+
+dnl ================================================================
+dnl Documentation stuff.
+dnl ================================================================
+GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`"
+GDKPIXBUF_PREFIX="`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`"
+AC_SUBST(GLIB_PREFIX)
+AC_SUBST(GDKPIXBUF_PREFIX)
+
+
+AC_SUBST(COGL_PKG_REQUIRES)
+if test -n "$COGL_PKG_REQUIRES"; then
+ PKG_CHECK_MODULES(COGL_DEP, [$COGL_PKG_REQUIRES])
+
+ if test -n "$COGL_PKG_REQUIRES_GL"; then
+ PKG_CHECK_MODULES(COGL_DEP_GL, [$COGL_PKG_REQUIRES_GL])
+
+ dnl Strip out the GL libraries from the GL pkg-config files so we can
+ dnl dynamically load them instead
+ gl_libs=""
+ for x in $COGL_DEP_GL_LIBS; do
+ AS_CASE([$x],
+ [-lGL], [],
+ [-lGLESv2], [],
+ [-lGLESv1_CM], [],
+ [*], [gl_libs="$gl_libs $x"])
+ done
+ COGL_DEP_CFLAGS="$COGL_DEP_CFLAGS $COGL_DEP_CFLAGS_GL"
+ COGL_DEP_LIBS="$COGL_DEP_LIBS $gl_libs"
+ fi
+fi
+AC_SUBST(COGL_PANGO_PKG_REQUIRES)
+
+AS_IF([test "x$enable_cogl_pango" = "xyes"],
+ [PKG_CHECK_MODULES(COGL_PANGO_DEP, [$COGL_PANGO_PKG_REQUIRES])]
+)
+AM_CONDITIONAL([BUILD_COGL_PANGO], [test "x$enable_cogl_pango" = "xyes"])
+
+AM_CONDITIONAL([BUILD_COGL_PATH], [test "x$enable_cogl_path" = "xyes"])
+
+dnl ================================================================
+dnl Misc program dependencies.
+dnl ================================================================
+AC_PROG_INSTALL
+
+dnl ================================================================
+dnl GObject-Introspection check
+dnl ================================================================
+GOBJECT_INTROSPECTION_CHECK([gi_req_version])
+
+dnl ================================================================
+dnl Checks for header files.
+dnl ================================================================
+AC_PATH_X
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h unistd.h)
+AC_CHECK_HEADER([endian.h],
+ [AC_CHECK_DECL([__FLOAT_WORD_ORDER],
+ AC_DEFINE([HAVE_FLOAT_WORD_ORDER], [1],
+ [Has the __FLOAT_WORD_ORDER macro]))])
+
+dnl ================================================================
+dnl Checks for library functions.
+dnl ================================================================
+
+dnl The 'ffs' function is part of C99 so it isn't always
+dnl available. Cogl has a fallback if needed.
+AC_CHECK_FUNCS([ffs])
+
+dnl 'memmem' is a GNU extension but we have a simple fallback
+AC_CHECK_FUNCS([memmem])
+
+dnl This is used in the cogl-gles2-gears example but it is a GNU extension
+save_libs="$LIBS"
+LIBS="$LIBS $LIBM"
+AC_CHECK_FUNCS([sincos])
+LIBS="$save_libs"
+
+dnl ================================================================
+dnl Platform values
+dnl ================================================================
+
+dnl These are values from system headers that we want to copy into the
+dnl public Cogl headers without having to include the system header
+have_poll_h=no
+AC_CHECK_HEADER(poll.h,
+ [
+ AC_COMPUTE_INT(COGL_SYSDEF_POLLIN, POLLIN, [#include <poll.h>],
+ AC_MSG_ERROR([Unable to get value of POLLIN]))
+ AC_COMPUTE_INT(COGL_SYSDEF_POLLPRI, POLLPRI, [#include <poll.h>],
+ AC_MSG_ERROR([Unable to get value of POLLPRI]))
+ AC_COMPUTE_INT(COGL_SYSDEF_POLLOUT, POLLOUT, [#include <poll.h>],
+ AC_MSG_ERROR([Unable to get value of POLLOUT]))
+ AC_COMPUTE_INT(COGL_SYSDEF_POLLERR, POLLERR, [#include <poll.h>],
+ AC_MSG_ERROR([Unable to get value of POLLERR]))
+ AC_COMPUTE_INT(COGL_SYSDEF_POLLHUP, POLLHUP, [#include <poll.h>],
+ AC_MSG_ERROR([Unable to get value of POLLHUP]))
+ AC_COMPUTE_INT(COGL_SYSDEF_POLLNVAL, POLLNVAL, [#include <poll.h>],
+ AC_MSG_ERROR([Unable to get value of POLLNVAL]))
+ COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_POLL_SUPPORT"
+ have_poll_h=yes
+ ])
+
+AS_IF([test "x$have_poll_h" = "xno"],
+ [
+ COGL_SYSDEF_POLLIN=1
+ COGL_SYSDEF_POLLPRI=2
+ COGL_SYSDEF_POLLOUT=4
+ COGL_SYSDEF_POLLERR=8
+ COGL_SYSDEF_POLLHUP=16
+ COGL_SYSDEF_POLLNVAL=32
+ ])
+
+COGL_DEFINES_EXTRA="$COGL_DEFINES_EXTRA
+#define COGL_SYSDEF_POLLIN $COGL_SYSDEF_POLLIN
+#define COGL_SYSDEF_POLLPRI $COGL_SYSDEF_POLLPRI
+#define COGL_SYSDEF_POLLOUT $COGL_SYSDEF_POLLOUT
+#define COGL_SYSDEF_POLLERR $COGL_SYSDEF_POLLERR
+#define COGL_SYSDEF_POLLHUP $COGL_SYSDEF_POLLHUP
+#define COGL_SYSDEF_POLLNVAL $COGL_SYSDEF_POLLNVAL
+"
+
+dnl ================================================================
+dnl What needs to be substituted in other files
+dnl ================================================================
+COGL_DEFINES="$COGL_DEFINES_EXTRA"
+for x in $COGL_DEFINES_SYMBOLS; do
+ COGL_DEFINES="$COGL_DEFINES
+#define $x 1"
+done;
+AC_SUBST(COGL_DEFINES)
+AM_SUBST_NOTMAKE(COGL_DEFINES)
+
+AS_IF([test "x$cogl_gl_headers" = "x"],
+ [AC_MSG_ERROR([Internal error: no GL header set])])
+dnl cogl_gl_headers is a space separate list of headers to
+dnl include. We'll now convert them to a single variable with a
+dnl #include line for each header
+COGL_GL_HEADER_INCLUDES=""
+for x in $cogl_gl_headers; do
+ COGL_GL_HEADER_INCLUDES="$COGL_GL_HEADER_INCLUDES
+#include <$x>"
+done;
+AC_SUBST(COGL_GL_HEADER_INCLUDES)
+AM_SUBST_NOTMAKE(COGL_GL_HEADER_INCLUDES)
+
+AC_DEFINE([COGL_ENABLE_EXPERIMENTAL_2_0_API], [1],
+ [Can use Cogl 2.0 API internally])
+AC_DEFINE([COGL_ENABLE_EXPERIMENTAL_API], [1],
+ [Can use experimental API internally])
+
+AC_SUBST(COGL_DEP_CFLAGS)
+AC_SUBST(COGL_DEP_LIBS)
+AC_SUBST(COGL_PANGO_DEP_CFLAGS)
+AC_SUBST(COGL_PANGO_DEP_LIBS)
+AC_SUBST(COGL_GST_DEP_CFLAGS)
+AC_SUBST(COGL_GST_DEP_LIBS)
+AC_SUBST(COGL_EXTRA_CFLAGS)
+AC_SUBST(COGL_EXTRA_LDFLAGS)
+
+# just for compatability with the clutter build...
+MAINTAINER_CFLAGS=
+AC_SUBST(MAINTAINER_CFLAGS)
+
+AC_OUTPUT(
+Makefile
+test-fixtures/Makefile
+cogl/Makefile
+cogl/mutter-cogl-1.0.pc
+cogl/cogl-defines.h
+cogl/cogl-gl-header.h
+cogl/cogl-egl-defines.h
+cogl-pango/Makefile
+cogl-pango/mutter-cogl-pango-1.0.pc
+cogl-path/Makefile
+cogl-path/mutter-cogl-path-1.0.pc
+cogl-gles2/Makefile
+cogl-gles2/mutter-cogl-gles2-1.0.pc
+tests/Makefile
+tests/config.env
+tests/conform/Makefile
+tests/unit/Makefile
+tests/micro-perf/Makefile
+tests/data/Makefile
+)
+
+dnl ================================================================
+dnl Dah Da!
+dnl ================================================================
+echo ""
+echo "Cogl - $COGL_1_VERSION/$COGL_VERSION (${COGL_RELEASE_STATUS})"
+
+# Global flags
+echo ""
+echo " • Global:"
+echo " Prefix: ${prefix}"
+if test "x$COGL_DEFAULT_DRIVER" != "x"; then
+echo " Default driver: ${COGL_DEFAULT_DRIVER}"
+fi
+
+echo ""
+# Features
+echo " • Features:"
+echo " Drivers: ${enabled_drivers}"
+for driver in $enabled_drivers; do
+ driver=`echo $driver | tr "[gles]" "[GLES]"`
+ libname=`eval echo \\$COGL_${driver}_LIBNAME`
+ echo " Library name for $driver: $libname"
+done
+echo " GL Window System APIs:${GL_WINSYS_APIS}"
+if test "x$SUPPORT_EGL" = "xyes"; then
+echo " EGL Platforms:${EGL_PLATFORMS}"
+echo " Wayland compositor support: ${enable_wayland_egl_server}"
+fi
+echo " Build libcogl-gles2 GLES 2.0 frontend api: ${enable_cogl_gles2}"
+echo " Image backend: ${COGL_IMAGE_BACKEND}"
+echo " Cogl Pango: ${enable_cogl_pango}"
+echo " Cogl Path: ${enable_cogl_path}"
+
+# Compiler/Debug related flags
+echo ""
+echo " • Build options:"
+echo " Debugging: ${enable_debug}"
+echo " Profiling: ${enable_profile}"
+echo " Enable deprecated symbols: ${enable_deprecated}"
+echo " Compiler flags: ${CFLAGS} ${COGL_EXTRA_CFLAGS}"
+echo " Linker flags: ${LDFLAGS} ${COGL_EXTRA_LDFLAGS}"
+
+# Miscellaneous
+echo ""
+echo " • Extra:"
+echo " Build introspection data: ${enable_introspection}"
+echo " Build unit tests: ${enable_unit_tests}"
+
+echo ""
+
+# General warning about experimental features
+if test "x$EXPERIMENTAL_CONFIG" = "xyes"; then
+echo ""
+echo "☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠"
+echo " *WARNING*"
+echo ""
+echo " The stability of your build might be affected by one or more"
+echo " experimental configuration options."
+echo
+echo " experimental options: $EXPERIMENTAL_OPTIONS"
+echo "☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠"
+echo ""
+fi
diff --git a/cogl/test-fixtures/Makefile.am b/cogl/test-fixtures/Makefile.am
new file mode 100644
index 000000000..aa66216e1
--- /dev/null
+++ b/cogl/test-fixtures/Makefile.am
@@ -0,0 +1,21 @@
+
+noinst_LTLIBRARIES = libtest-fixtures.la
+
+libtest_fixtures_la_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_builddir)/cogl \
+ -Wall \
+ $(NULL)
+
+libtest_fixtures_la_CPPFLAGS += \
+ -DCOGL_DISABLE_DEPRECATED \
+ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" \
+ -DCOGL_COMPILATION
+
+libtest_fixtures_la_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS)
+
+libtest_fixtures_la_SOURCES = \
+ test-unit.h \
+ test-utils.h \
+ test-utils.c
+
diff --git a/cogl/test-fixtures/test-unit.h b/cogl/test-fixtures/test-unit.h
new file mode 100644
index 000000000..270a94134
--- /dev/null
+++ b/cogl/test-fixtures/test-unit.h
@@ -0,0 +1,31 @@
+#ifndef _TEST_UNIT_H_
+#define _TEST_UNIT_H_
+
+#include <test-fixtures/test-utils.h>
+
+#ifdef ENABLE_UNIT_TESTS
+
+typedef struct _CoglUnitTest
+{
+ const char *name;
+ TestFlags requirement_flags;
+ TestFlags known_failure_flags;
+ void (*run) (void);
+} CoglUnitTest;
+
+#define UNIT_TEST(NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS) \
+ static void NAME (void); \
+ \
+ const CoglUnitTest unit_test_##NAME = \
+ { #NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS, NAME }; \
+ \
+ static void NAME (void)
+
+#else /* ENABLE_UNIT_TESTS */
+
+#define UNIT_TEST(NAME, REQUIREMENT_FLAGS, KNOWN_FAILURE_FLAGS) \
+ static inline void NAME (void)
+
+#endif /* ENABLE_UNIT_TESTS */
+
+#endif /* _TEST_UNIT_H_ */
diff --git a/cogl/test-fixtures/test-utils.c b/cogl/test-fixtures/test-utils.c
new file mode 100644
index 000000000..59e3fd8c9
--- /dev/null
+++ b/cogl/test-fixtures/test-utils.c
@@ -0,0 +1,535 @@
+#include <config.h>
+
+#include <stdlib.h>
+
+#include "test-unit.h"
+#include "test-utils.h"
+
+#define FB_WIDTH 512
+#define FB_HEIGHT 512
+
+static CoglBool cogl_test_is_verbose;
+
+CoglContext *test_ctx;
+CoglFramebuffer *test_fb;
+
+static CoglBool
+check_flags (TestFlags flags,
+ CoglRenderer *renderer)
+{
+ if (flags & TEST_REQUIREMENT_GL &&
+ cogl_renderer_get_driver (renderer) != COGL_DRIVER_GL &&
+ cogl_renderer_get_driver (renderer) != COGL_DRIVER_GL3)
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_NPOT &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_TEXTURE_3D &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_3D))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_TEXTURE_RECTANGLE &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_TEXTURE_RG &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RG))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_POINT_SPRITE &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_POINT_SPRITE))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_GLES2_CONTEXT &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_GLES2_CONTEXT))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_MAP_WRITE &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_GLSL &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_GLSL))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_OFFSCREEN &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_OFFSCREEN))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_REQUIREMENT_FENCE &&
+ !cogl_has_feature (test_ctx, COGL_FEATURE_ID_FENCE))
+ {
+ return FALSE;
+ }
+
+ if (flags & TEST_KNOWN_FAILURE)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CoglBool
+is_boolean_env_set (const char *variable)
+{
+ char *val = getenv (variable);
+ CoglBool ret;
+
+ if (!val)
+ return FALSE;
+
+ if (g_ascii_strcasecmp (val, "1") == 0 ||
+ g_ascii_strcasecmp (val, "on") == 0 ||
+ g_ascii_strcasecmp (val, "true") == 0)
+ ret = TRUE;
+ else if (g_ascii_strcasecmp (val, "0") == 0 ||
+ g_ascii_strcasecmp (val, "off") == 0 ||
+ g_ascii_strcasecmp (val, "false") == 0)
+ ret = FALSE;
+ else
+ {
+ g_critical ("Spurious boolean environment variable value (%s=%s)",
+ variable, val);
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+void
+test_utils_init (TestFlags requirement_flags,
+ TestFlags known_failure_flags)
+{
+ static int counter = 0;
+ CoglError *error = NULL;
+ CoglOnscreen *onscreen = NULL;
+ CoglDisplay *display;
+ CoglRenderer *renderer;
+ CoglBool missing_requirement;
+ CoglBool known_failure;
+
+ if (counter != 0)
+ g_critical ("We don't support running more than one test at a time\n"
+ "in a single test run due to the state leakage that can\n"
+ "cause subsequent tests to fail.\n"
+ "\n"
+ "If you want to run all the tests you should run\n"
+ "$ make test-report");
+ counter++;
+
+ if (is_boolean_env_set ("COGL_TEST_VERBOSE") ||
+ is_boolean_env_set ("V"))
+ cogl_test_is_verbose = TRUE;
+
+ /* NB: This doesn't have any effect since commit 47444dac of glib
+ * because the environment variable is read in a magic constructor
+ * so it is too late to set them here */
+ if (g_getenv ("G_DEBUG"))
+ {
+ char *debug = g_strconcat (g_getenv ("G_DEBUG"), ",fatal-warnings", NULL);
+ g_setenv ("G_DEBUG", debug, TRUE);
+ g_free (debug);
+ }
+ else
+ g_setenv ("G_DEBUG", "fatal-warnings", TRUE);
+
+ g_setenv ("COGL_X11_SYNC", "1", 0);
+
+ test_ctx = cogl_context_new (NULL, &error);
+ if (!test_ctx)
+ g_critical ("Failed to create a CoglContext: %s", error->message);
+
+ display = cogl_context_get_display (test_ctx);
+ renderer = cogl_display_get_renderer (display);
+
+ missing_requirement = !check_flags (requirement_flags, renderer);
+ known_failure = !check_flags (known_failure_flags, renderer);
+
+ if (is_boolean_env_set ("COGL_TEST_ONSCREEN"))
+ {
+ onscreen = cogl_onscreen_new (test_ctx, 640, 480);
+ test_fb = COGL_FRAMEBUFFER (onscreen);
+ }
+ else
+ {
+ CoglOffscreen *offscreen;
+ CoglTexture2D *tex = cogl_texture_2d_new_with_size (test_ctx,
+ FB_WIDTH, FB_HEIGHT);
+ offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex));
+ test_fb = COGL_FRAMEBUFFER (offscreen);
+ }
+
+ if (!cogl_framebuffer_allocate (test_fb, &error))
+ g_critical ("Failed to allocate framebuffer: %s", error->message);
+
+ if (onscreen)
+ cogl_onscreen_show (onscreen);
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR |
+ COGL_BUFFER_BIT_DEPTH |
+ COGL_BUFFER_BIT_STENCIL,
+ 0, 0, 0, 1);
+
+ if (missing_requirement)
+ g_print ("WARNING: Missing required feature[s] for this test\n");
+ else if (known_failure)
+ g_print ("WARNING: Test is known to fail\n");
+}
+
+void
+test_utils_fini (void)
+{
+ if (test_fb)
+ cogl_object_unref (test_fb);
+
+ if (test_ctx)
+ cogl_object_unref (test_ctx);
+}
+
+static CoglBool
+compare_component (int a, int b)
+{
+ return ABS (a - b) <= 1;
+}
+
+void
+test_utils_compare_pixel_and_alpha (const uint8_t *screen_pixel,
+ uint32_t expected_pixel)
+{
+ /* Compare each component with a small fuzz factor */
+ if (!compare_component (screen_pixel[0], expected_pixel >> 24) ||
+ !compare_component (screen_pixel[1], (expected_pixel >> 16) & 0xff) ||
+ !compare_component (screen_pixel[2], (expected_pixel >> 8) & 0xff) ||
+ !compare_component (screen_pixel[3], (expected_pixel >> 0) & 0xff))
+ {
+ uint32_t screen_pixel_num = GUINT32_FROM_BE (*(uint32_t *) screen_pixel);
+ char *screen_pixel_string =
+ g_strdup_printf ("#%08x", screen_pixel_num);
+ char *expected_pixel_string =
+ g_strdup_printf ("#%08x", expected_pixel);
+
+ g_assert_cmpstr (screen_pixel_string, ==, expected_pixel_string);
+
+ g_free (screen_pixel_string);
+ g_free (expected_pixel_string);
+ }
+}
+
+void
+test_utils_compare_pixel (const uint8_t *screen_pixel, uint32_t expected_pixel)
+{
+ /* Compare each component with a small fuzz factor */
+ if (!compare_component (screen_pixel[0], expected_pixel >> 24) ||
+ !compare_component (screen_pixel[1], (expected_pixel >> 16) & 0xff) ||
+ !compare_component (screen_pixel[2], (expected_pixel >> 8) & 0xff))
+ {
+ uint32_t screen_pixel_num = GUINT32_FROM_BE (*(uint32_t *) screen_pixel);
+ char *screen_pixel_string =
+ g_strdup_printf ("#%06x", screen_pixel_num >> 8);
+ char *expected_pixel_string =
+ g_strdup_printf ("#%06x", expected_pixel >> 8);
+
+ g_assert_cmpstr (screen_pixel_string, ==, expected_pixel_string);
+
+ g_free (screen_pixel_string);
+ g_free (expected_pixel_string);
+ }
+}
+
+void
+test_utils_check_pixel (CoglFramebuffer *test_fb,
+ int x, int y, uint32_t expected_pixel)
+{
+ uint8_t pixel[4];
+
+ cogl_framebuffer_read_pixels (test_fb,
+ x, y, 1, 1,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+
+ test_utils_compare_pixel (pixel, expected_pixel);
+}
+
+void
+test_utils_check_pixel_and_alpha (CoglFramebuffer *test_fb,
+ int x, int y, uint32_t expected_pixel)
+{
+ uint8_t pixel[4];
+
+ cogl_framebuffer_read_pixels (test_fb,
+ x, y, 1, 1,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+
+ test_utils_compare_pixel_and_alpha (pixel, expected_pixel);
+}
+
+void
+test_utils_check_pixel_rgb (CoglFramebuffer *test_fb,
+ int x, int y, int r, int g, int b)
+{
+ test_utils_check_pixel (test_fb, x, y, (r << 24) | (g << 16) | (b << 8));
+}
+
+void
+test_utils_check_region (CoglFramebuffer *test_fb,
+ int x, int y,
+ int width, int height,
+ uint32_t expected_rgba)
+{
+ uint8_t *pixels, *p;
+
+ pixels = p = g_malloc (width * height * 4);
+ cogl_framebuffer_read_pixels (test_fb,
+ x,
+ y,
+ width,
+ height,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ p);
+
+ /* Check whether the center of each division is the right color */
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ test_utils_compare_pixel (p, expected_rgba);
+ p += 4;
+ }
+
+ g_free (pixels);
+}
+
+CoglTexture *
+test_utils_create_color_texture (CoglContext *context,
+ uint32_t color)
+{
+ CoglTexture2D *tex_2d;
+
+ color = GUINT32_TO_BE (color);
+
+ tex_2d = cogl_texture_2d_new_from_data (context,
+ 1, 1, /* width/height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ (uint8_t *) &color,
+ NULL);
+
+ return COGL_TEXTURE (tex_2d);
+}
+
+CoglBool
+cogl_test_verbose (void)
+{
+ return cogl_test_is_verbose;
+}
+
+static void
+set_auto_mipmap_cb (CoglTexture *sub_texture,
+ const float *sub_texture_coords,
+ const float *meta_coords,
+ void *user_data)
+{
+ cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (sub_texture),
+ FALSE);
+}
+
+CoglTexture *
+test_utils_texture_new_with_size (CoglContext *ctx,
+ int width,
+ int height,
+ TestUtilsTextureFlags flags,
+ CoglTextureComponents components)
+{
+ CoglTexture *tex;
+ CoglError *skip_error = NULL;
+
+ if ((test_utils_is_pot (width) && test_utils_is_pot (height)) ||
+ (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
+ cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP)))
+ {
+ /* First try creating a fast-path non-sliced texture */
+ tex = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx,
+ width, height));
+
+ cogl_texture_set_components (tex, components);
+
+ if (!cogl_texture_allocate (tex, &skip_error))
+ {
+ cogl_error_free (skip_error);
+ cogl_object_unref (tex);
+ tex = NULL;
+ }
+ }
+ else
+ tex = NULL;
+
+ if (!tex)
+ {
+ /* If it fails resort to sliced textures */
+ int max_waste = flags & TEST_UTILS_TEXTURE_NO_SLICING ?
+ -1 : COGL_TEXTURE_MAX_WASTE;
+ CoglTexture2DSliced *tex_2ds =
+ cogl_texture_2d_sliced_new_with_size (ctx,
+ width,
+ height,
+ max_waste);
+ tex = COGL_TEXTURE (tex_2ds);
+
+ cogl_texture_set_components (tex, components);
+ }
+
+ if (flags & TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP)
+ {
+ /* To be able to iterate the slices of a #CoglTexture2DSliced we
+ * need to ensure the texture is allocated... */
+ cogl_texture_allocate (tex, NULL); /* don't catch exceptions */
+
+ cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex),
+ 0, 0, 1, 1,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+ set_auto_mipmap_cb,
+ NULL); /* don't catch exceptions */
+ }
+
+ cogl_texture_allocate (tex, NULL);
+
+ return tex;
+}
+
+CoglTexture *
+test_utils_texture_new_from_bitmap (CoglBitmap *bitmap,
+ TestUtilsTextureFlags flags,
+ CoglBool premultiplied)
+{
+ CoglAtlasTexture *atlas_tex;
+ CoglTexture *tex;
+ CoglError *internal_error = NULL;
+
+ if (!flags)
+ {
+ /* First try putting the texture in the atlas */
+ atlas_tex = cogl_atlas_texture_new_from_bitmap (bitmap);
+
+ cogl_texture_set_premultiplied (COGL_TEXTURE (atlas_tex), premultiplied);
+
+ if (cogl_texture_allocate (COGL_TEXTURE (atlas_tex), &internal_error))
+ return COGL_TEXTURE (atlas_tex);
+
+ cogl_error_free (internal_error);
+ cogl_object_unref (atlas_tex);
+ internal_error = NULL;
+ }
+
+ /* If that doesn't work try a fast path 2D texture */
+ if ((test_utils_is_pot (cogl_bitmap_get_width (bitmap)) &&
+ test_utils_is_pot (cogl_bitmap_get_height (bitmap))) ||
+ (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
+ cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP)))
+ {
+ tex = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
+
+ cogl_texture_set_premultiplied (tex, premultiplied);
+
+ if (cogl_error_matches (internal_error,
+ COGL_SYSTEM_ERROR,
+ COGL_SYSTEM_ERROR_NO_MEMORY))
+ {
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ if (!tex)
+ {
+ cogl_error_free (internal_error);
+ internal_error = NULL;
+ }
+ }
+ else
+ tex = NULL;
+
+ if (!tex)
+ {
+ /* Otherwise create a sliced texture */
+ int max_waste = flags & TEST_UTILS_TEXTURE_NO_SLICING ?
+ -1 : COGL_TEXTURE_MAX_WASTE;
+ CoglTexture2DSliced *tex_2ds =
+ cogl_texture_2d_sliced_new_from_bitmap (bitmap, max_waste);
+ tex = COGL_TEXTURE (tex_2ds);
+
+ cogl_texture_set_premultiplied (tex, premultiplied);
+ }
+
+ if (flags & TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP)
+ {
+ cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex),
+ 0, 0, 1, 1,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+ set_auto_mipmap_cb,
+ NULL); /* don't catch exceptions */
+ }
+
+ cogl_texture_allocate (tex, NULL);
+
+ return tex;
+}
+
+CoglTexture *
+test_utils_texture_new_from_data (CoglContext *ctx,
+ int width,
+ int height,
+ TestUtilsTextureFlags flags,
+ CoglPixelFormat format,
+ int rowstride,
+ const uint8_t *data)
+{
+ CoglBitmap *bmp;
+ CoglTexture *tex;
+
+ g_assert_cmpint (format, !=, COGL_PIXEL_FORMAT_ANY);
+ g_assert (data != NULL);
+
+ /* Wrap the data into a bitmap */
+ bmp = cogl_bitmap_new_for_data (ctx,
+ width, height,
+ format,
+ rowstride,
+ (uint8_t *) data);
+
+ tex = test_utils_texture_new_from_bitmap (bmp, flags, TRUE);
+
+ cogl_object_unref (bmp);
+
+ return tex;
+}
diff --git a/cogl/test-fixtures/test-utils.h b/cogl/test-fixtures/test-utils.h
new file mode 100644
index 000000000..9c3ced9b3
--- /dev/null
+++ b/cogl/test-fixtures/test-utils.h
@@ -0,0 +1,287 @@
+#ifndef _TEST_UTILS_H_
+#define _TEST_UTILS_H_
+
+/* NB: This header is for private and public api testing and so
+ * we need consider that if we are testing the public api we should
+ * just include <cogl/cogl.h> but since that will only provide
+ * opaque typedefs we need to include the specific internal headers
+ * for testing private apis...
+ */
+#ifdef COGL_COMPILATION
+#include <cogl/cogl-context.h>
+#include <cogl/cogl-onscreen.h>
+#include <cogl/cogl-offscreen.h>
+#include <cogl/cogl-texture-2d.h>
+#include <cogl/cogl-primitive-texture.h>
+#include <cogl/cogl-texture-2d-sliced.h>
+#include <cogl/cogl-meta-texture.h>
+#include <cogl/cogl-atlas-texture.h>
+#else
+#include <cogl/cogl.h>
+#endif
+
+#include <glib.h>
+
+/* We don't really care about functions that are defined without a
+ header for the unit tests so we can just disable it here */
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wmissing-declarations"
+#endif
+
+typedef enum _TestFlags
+{
+ TEST_KNOWN_FAILURE = 1<<0,
+ TEST_REQUIREMENT_GL = 1<<1,
+ TEST_REQUIREMENT_NPOT = 1<<2,
+ TEST_REQUIREMENT_TEXTURE_3D = 1<<3,
+ TEST_REQUIREMENT_TEXTURE_RECTANGLE = 1<<4,
+ TEST_REQUIREMENT_TEXTURE_RG = 1<<5,
+ TEST_REQUIREMENT_POINT_SPRITE = 1<<6,
+ TEST_REQUIREMENT_GLES2_CONTEXT = 1<<7,
+ TEST_REQUIREMENT_MAP_WRITE = 1<<8,
+ TEST_REQUIREMENT_GLSL = 1<<9,
+ TEST_REQUIREMENT_OFFSCREEN = 1<<10,
+ TEST_REQUIREMENT_FENCE = 1<<11,
+ TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE = 1<<12
+} TestFlags;
+
+ /**
+ * TestUtilsTextureFlags:
+ * @TEST_UTILS_TEXTURE_NONE: No flags specified
+ * @TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of
+ * the mipmap pyramid from the base level image whenever it is
+ * updated. The mipmaps are only generated when the texture is
+ * rendered with a mipmap filter so it should be free to leave out
+ * this flag when using other filtering modes
+ * @TEST_UTILS_TEXTURE_NO_SLICING: Disables the slicing of the texture
+ * @TEST_UTILS_TEXTURE_NO_ATLAS: Disables the insertion of the texture inside
+ * the texture atlas used by Cogl
+ *
+ * Flags to pass to the test_utils_texture_new_* family of functions.
+ */
+typedef enum {
+ TEST_UTILS_TEXTURE_NONE = 0,
+ TEST_UTILS_TEXTURE_NO_AUTO_MIPMAP = 1 << 0,
+ TEST_UTILS_TEXTURE_NO_SLICING = 1 << 1,
+ TEST_UTILS_TEXTURE_NO_ATLAS = 1 << 2
+} TestUtilsTextureFlags;
+
+extern CoglContext *test_ctx;
+extern CoglFramebuffer *test_fb;
+
+void
+test_utils_init (TestFlags requirement_flags,
+ TestFlags known_failure_flags);
+
+void
+test_utils_fini (void);
+
+/*
+ * test_utils_texture_new_with_size:
+ * @context: A #CoglContext
+ * @width: width of texture in pixels.
+ * @height: height of texture in pixels.
+ * @flags: Optional flags for the texture, or %TEST_UTILS_TEXTURE_NONE
+ * @components: What texture components are required
+ *
+ * Creates a new #CoglTexture with the specified dimensions and pixel format.
+ *
+ * The storage for the texture is not necesarily created before this
+ * function returns. The storage can be explicitly allocated using
+ * cogl_texture_allocate() or preferably you can let Cogl
+ * automatically allocate the storage lazily when uploading data when
+ * Cogl may know more about how the texture will be used and can
+ * optimize how it is allocated.
+ *
+ * Return value: A newly created #CoglTexture
+ */
+CoglTexture *
+test_utils_texture_new_with_size (CoglContext *ctx,
+ int width,
+ int height,
+ TestUtilsTextureFlags flags,
+ CoglTextureComponents components);
+
+/*
+ * test_utils_texture_new_from_data:
+ * @context: A #CoglContext
+ * @width: width of texture in pixels
+ * @height: height of texture in pixels
+ * @flags: Optional flags for the texture, or %TEST_UTILS_TEXTURE_NONE
+ * @format: the #CoglPixelFormat the buffer is stored in in RAM
+ * @rowstride: the memory offset in bytes between the starts of
+ * scanlines in @data
+ * @data: pointer the memory region where the source buffer resides
+ * @error: A #CoglError to catch exceptional errors or %NULL
+ *
+ * Creates a new #CoglTexture based on data residing in memory.
+ *
+ * Note: If the given @format has an alpha channel then the data
+ * will be loaded into a premultiplied internal format. If you want
+ * to avoid having the source data be premultiplied then you can
+ * either specify that the data is already premultiplied or use
+ * test_utils_texture_new_from_bitmap which lets you explicitly
+ * request whether the data should internally be premultipled or not.
+ *
+ * Return value: A newly created #CoglTexture or %NULL on failure
+ */
+CoglTexture *
+test_utils_texture_new_from_data (CoglContext *ctx,
+ int width,
+ int height,
+ TestUtilsTextureFlags flags,
+ CoglPixelFormat format,
+ int rowstride,
+ const uint8_t *data);
+
+/*
+ * test_utils_texture_new_from_bitmap:
+ * @bitmap: A #CoglBitmap pointer
+ * @flags: Optional flags for the texture, or %TEST_UTILS_TEXTURE_NONE
+ * @premultiplied: Whether the texture should hold premultipled data.
+ * (if the bitmap already holds premultiplied data
+ * and %TRUE is given then no premultiplication will
+ * be done. The data will be premultipled while
+ * uploading if the bitmap has an alpha channel but
+ * does not already have a premultiplied format.)
+ *
+ * Creates a #CoglTexture from a #CoglBitmap.
+ *
+ * Return value: A newly created #CoglTexture or %NULL on failure
+ */
+CoglTexture *
+test_utils_texture_new_from_bitmap (CoglBitmap *bitmap,
+ TestUtilsTextureFlags flags,
+ CoglBool premultiplied);
+
+/*
+ * test_utils_check_pixel:
+ * @framebuffer: The #CoglFramebuffer to read from
+ * @x: x co-ordinate of the pixel to test
+ * @y: y co-ordinate of the pixel to test
+ * @pixel: An integer of the form 0xRRGGBBAA representing the expected
+ * pixel value
+ *
+ * This performs reads a pixel on the given cogl @framebuffer and
+ * asserts that it matches the given color. The alpha channel of the
+ * color is ignored. The pixels are converted to a string and compared
+ * with g_assert_cmpstr so that if the comparison fails then the
+ * assert will display a meaningful message
+ */
+void
+test_utils_check_pixel (CoglFramebuffer *framebuffer,
+ int x, int y, uint32_t expected_pixel);
+
+/**
+ * @framebuffer: The #CoglFramebuffer to read from
+ * @x: x co-ordinate of the pixel to test
+ * @y: y co-ordinate of the pixel to test
+ * @pixel: An integer of the form 0xRRGGBBAA representing the expected
+ * pixel value
+ *
+ * This performs reads a pixel on the given cogl @framebuffer and
+ * asserts that it matches the given color. The alpha channel is also
+ * checked unlike with test_utils_check_pixel(). The pixels are
+ * converted to a string and compared with g_assert_cmpstr so that if
+ * the comparison fails then the assert will display a meaningful
+ * message.
+ */
+void
+test_utils_check_pixel_and_alpha (CoglFramebuffer *fb,
+ int x, int y, uint32_t expected_pixel);
+
+/*
+ * test_utils_check_pixel:
+ * @framebuffer: The #CoglFramebuffer to read from
+ * @x: x co-ordinate of the pixel to test
+ * @y: y co-ordinate of the pixel to test
+ * @pixel: An integer of the form 0xrrggbb representing the expected pixel value
+ *
+ * This performs reads a pixel on the given cogl @framebuffer and
+ * asserts that it matches the given color. The alpha channel of the
+ * color is ignored. The pixels are converted to a string and compared
+ * with g_assert_cmpstr so that if the comparison fails then the
+ * assert will display a meaningful message
+ */
+void
+test_utils_check_pixel_rgb (CoglFramebuffer *framebuffer,
+ int x, int y, int r, int g, int b);
+
+/*
+ * test_utils_check_region:
+ * @framebuffer: The #CoglFramebuffer to read from
+ * @x: x co-ordinate of the region to test
+ * @y: y co-ordinate of the region to test
+ * @width: width of the region to test
+ * @height: height of the region to test
+ * @pixel: An integer of the form 0xrrggbb representing the expected region color
+ *
+ * Performs a read pixel on the specified region of the given cogl
+ * @framebuffer and asserts that it matches the given color. The alpha
+ * channel of the color is ignored. The pixels are converted to a
+ * string and compared with g_assert_cmpstr so that if the comparison
+ * fails then the assert will display a meaningful message
+ */
+void
+test_utils_check_region (CoglFramebuffer *framebuffer,
+ int x, int y,
+ int width, int height,
+ uint32_t expected_rgba);
+
+/*
+ * test_utils_compare_pixel:
+ * @screen_pixel: A pixel stored in memory
+ * @expected_pixel: The expected RGBA value
+ *
+ * Compares a pixel from a buffer to an expected value. The pixels are
+ * converted to a string and compared with g_assert_cmpstr so that if
+ * the comparison fails then the assert will display a meaningful
+ * message.
+ */
+void
+test_utils_compare_pixel (const uint8_t *screen_pixel, uint32_t expected_pixel);
+
+/*
+ * test_utils_compare_pixel_and_alpha:
+ * @screen_pixel: A pixel stored in memory
+ * @expected_pixel: The expected RGBA value
+ *
+ * Compares a pixel from a buffer to an expected value. This is
+ * similar to test_utils_compare_pixel() except that it doesn't ignore
+ * the alpha component.
+ */
+void
+test_utils_compare_pixel_and_alpha (const uint8_t *screen_pixel,
+ uint32_t expected_pixel);
+
+/*
+ * test_utils_create_color_texture:
+ * @context: A #CoglContext
+ * @color: A color to put in the texture
+ *
+ * Creates a 1x1-pixel RGBA texture filled with the given color.
+ */
+CoglTexture *
+test_utils_create_color_texture (CoglContext *context,
+ uint32_t color);
+
+/* cogl_test_verbose:
+ *
+ * Queries if the user asked for verbose output or not.
+ */
+CoglBool
+cogl_test_verbose (void);
+
+/* test_util_is_pot:
+ * @number: A number to test
+ *
+ * Returns whether the given integer is a power of two
+ */
+static inline CoglBool
+test_utils_is_pot (unsigned int number)
+{
+ /* Make sure there is only one bit set */
+ return (number & (number - 1)) == 0;
+}
+
+#endif /* _TEST_UTILS_H_ */
diff --git a/cogl/tests/Makefile.am b/cogl/tests/Makefile.am
new file mode 100644
index 000000000..94ba34a6f
--- /dev/null
+++ b/cogl/tests/Makefile.am
@@ -0,0 +1,31 @@
+SUBDIRS = conform
+
+if UNIT_TESTS
+SUBDIRS += unit
+endif
+
+SUBDIRS += micro-perf data
+
+DIST_SUBDIRS = conform unit micro-perf data
+
+EXTRA_DIST = README test-launcher.sh run-tests.sh
+
+if UNIT_TESTS
+test conform:
+ ( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$?
+ ( cd ./unit && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$?
+else
+test conform:
+ ( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$?
+endif
+
+.PHONY: test conform
+
+# run make test as part of make check
+check-local: test
+
+if ENABLE_INSTALLED_TESTS
+insttestdir = $(libexecdir)/installed-tests/$(PACKAGE)
+insttest_SCRIPTS = run-tests.sh
+insttest_DATA = config.env
+endif
diff --git a/cogl/tests/README b/cogl/tests/README
new file mode 100644
index 000000000..cc6dbb97a
--- /dev/null
+++ b/cogl/tests/README
@@ -0,0 +1,63 @@
+Outline of test categories:
+
+The conform/ tests:
+-------------------
+These tests should be non-interactive unit-tests that verify a single
+feature is behaving as documented. See conform/ADDING_NEW_TESTS for more
+details.
+
+Although it may seem a bit awkward; all the tests are built into a
+single binary because it makes building the tests *much* faster by avoiding
+lots of linking.
+
+Each test has a wrapper script generated though so running the individual tests
+should be convenient enough. Running the wrapper script will also print out for
+convenience how you could run the test under gdb or valgrind like this for
+example:
+
+ NOTE: For debugging purposes, you can run this single test as follows:
+ $ libtool --mode=execute \
+ gdb --eval-command="b test_cogl_depth_test" \
+ --args ./test-conformance -p /conform/cogl/test_cogl_depth_test
+ or:
+ $ env G_SLICE=always-malloc \
+ libtool --mode=execute \
+ valgrind ./test-conformance -p /conform/cogl/test_cogl_depth_test
+
+By default the conformance tests are run offscreen. This makes the tests run
+much faster and they also don't interfere with other work you may want to do by
+constantly stealing focus. CoglOnscreen framebuffers obviously don't get tested
+this way so it's important that the tests also get run onscreen every once in a
+while, especially if changes are being made to CoglFramebuffer related code.
+Onscreen testing can be enabled by setting COGL_TEST_ONSCREEN=1 in your
+environment.
+
+The micro-bench/ tests:
+-----------------------
+These should be focused performance tests, ideally testing a
+single metric. Please never forget that these tests are synthetic and if you
+are using them then you understand what metric is being tested. They probably
+don't reflect any real world application loads and the intention is that you
+use these tests once you have already determined the crux of your problem and
+need focused feedback that your changes are indeed improving matters. There is
+no exit status requirements for these tests, but they should give clear
+feedback as to their performance. If the framerate is the feedback metric, then
+the test should forcibly enable FPS debugging.
+
+The data/ directory:
+--------------------
+This contains optional data (like images) that can be referenced by a test.
+
+
+Misc notes:
+-----------
+• All tests should ideally include a detailed description in the source
+explaining exactly what the test is for, how the test was designed to work,
+and possibly a rationale for the approach taken for testing.
+
+• When running tests under Valgrind, you should follow the instructions
+available here:
+
+ http://live.gnome.org/Valgrind
+
+and also use the suppression file available inside the data/ directory.
diff --git a/cogl/tests/config.env.in b/cogl/tests/config.env.in
new file mode 100644
index 000000000..d3777565d
--- /dev/null
+++ b/cogl/tests/config.env.in
@@ -0,0 +1,3 @@
+HAVE_GL=@HAVE_GL@
+HAVE_GLES1=@HAVE_GLES1@
+HAVE_GLES2=@HAVE_GLES2@
diff --git a/cogl/tests/conform/Makefile.am b/cogl/tests/conform/Makefile.am
new file mode 100644
index 000000000..f1c4d6fa5
--- /dev/null
+++ b/cogl/tests/conform/Makefile.am
@@ -0,0 +1,176 @@
+NULL =
+
+noinst_PROGRAMS = test-conformance
+
+common_sources = \
+ test-conform-main.c \
+ $(NULL)
+
+unported_test_sources = \
+ test-fixed.c \
+ test-materials.c \
+ test-viewport.c \
+ test-multitexture.c \
+ test-npot-texture.c \
+ test-object.c \
+ test-readpixels.c \
+ test-texture-mipmaps.c \
+ test-texture-pixmap-x11.c \
+ test-texture-rectangle.c \
+ test-vertex-buffer-contiguous.c \
+ test-vertex-buffer-interleved.c \
+ test-vertex-buffer-mutability.c \
+ $(NULL)
+
+test_sources = \
+ test-atlas-migration.c \
+ test-blend-strings.c \
+ test-blend.c \
+ test-depth-test.c \
+ test-color-hsl.c \
+ test-color-mask.c \
+ test-backface-culling.c \
+ test-just-vertex-shader.c \
+ test-pipeline-user-matrix.c \
+ test-pipeline-uniforms.c \
+ test-pixel-buffer.c \
+ test-premult.c \
+ test-snippets.c \
+ test-wrap-modes.c \
+ test-sub-texture.c \
+ test-custom-attributes.c \
+ test-offscreen.c \
+ test-primitive.c \
+ test-texture-3d.c \
+ test-sparse-pipeline.c \
+ test-read-texture-formats.c \
+ test-write-texture-formats.c \
+ test-point-size.c \
+ test-point-size-attribute.c \
+ test-point-sprite.c \
+ test-no-gl-header.c \
+ test-version.c \
+ test-gles2-context.c \
+ test-euler-quaternion.c \
+ test-layer-remove.c \
+ test-alpha-test.c \
+ test-map-buffer-range.c \
+ test-npot-texture.c \
+ test-alpha-textures.c \
+ test-wrap-rectangle-textures.c \
+ test-texture-get-set-data.c \
+ test-framebuffer-get-bits.c \
+ test-primitive-and-journal.c \
+ test-copy-replace-texture.c \
+ test-pipeline-cache-unrefs-texture.c \
+ test-texture-no-allocate.c \
+ test-pipeline-shader-state.c \
+ test-texture-rg.c \
+ test-fence.c \
+ $(NULL)
+
+if BUILD_COGL_PATH
+test_sources += \
+ test-path.c \
+ test-path-clip.c
+endif
+
+test_conformance_SOURCES = $(common_sources) $(test_sources)
+
+SHEXT = $(EXEEXT)
+
+# For convenience, this provides a way to easily run individual unit tests:
+.PHONY: wrappers clean-wrappers
+
+wrappers: stamp-test-conformance
+ @true
+stamp-test-conformance: Makefile $(srcdir)/test-conform-main.c
+ @mkdir -p wrappers
+ @sed -n -e 's/^ \{1,\}ADD_TEST *( *\([a-zA-Z0-9_]\{1,\}\).*/\1/p' $(srcdir)/test-conform-main.c > unit-tests
+ @chmod +x $(top_srcdir)/tests/test-launcher.sh
+ @( echo "/stamp-test-conformance" ; \
+ echo "/test-conformance$(EXEEXT)" ; \
+ echo "*.o" ; \
+ echo ".gitignore" ; \
+ echo "unit-tests" ; ) > .gitignore
+ @for i in `cat unit-tests`; \
+ do \
+ unit=`basename $$i | sed -e s/_/-/g`; \
+ echo " GEN $$unit"; \
+ ( echo "#!/bin/sh" ; echo "$(top_srcdir)/tests/test-launcher.sh $(abs_builddir)/test-conformance$(EXEEXT) '' '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \
+ chmod +x $$unit$(SHEXT); \
+ echo "/$$unit$(SHEXT)" >> .gitignore; \
+ done \
+ && echo timestamp > $(@F)
+
+clean-wrappers:
+ @for i in `cat unit-tests`; \
+ do \
+ unit=`basename $$i | sed -e s/_/-/g`; \
+ echo " RM $$unit"; \
+ rm -f $$unit$(SHEXT) ; \
+ done \
+ && rm -f unit-tests \
+ && rm -f stamp-test-conformance
+
+# NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting
+# a phony rule that will generate symlink scripts for running individual tests
+BUILT_SOURCES = wrappers
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_builddir)/cogl \
+ -I$(top_srcdir)/test-fixtures
+
+AM_CPPFLAGS += \
+ -DCOGL_ENABLE_EXPERIMENTAL_API \
+ -DCOGL_DISABLE_DEPRECATED \
+ -DCOGL_DISABLE_DEPRECATION_WARNINGS \
+ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\"
+
+test_conformance_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS)
+test_conformance_LDADD = \
+ $(COGL_DEP_LIBS) \
+ $(top_builddir)/cogl/libmutter-cogl.la \
+ $(LIBM)
+if BUILD_COGL_PATH
+test_conformance_LDADD += $(top_builddir)/cogl-path/libmutter-cogl-path.la
+endif
+test_conformance_LDFLAGS = -export-dynamic
+
+test: wrappers
+ @$(top_srcdir)/tests/run-tests.sh $(abs_builddir)/../config.env $(abs_builddir)/test-conformance$(EXEEXT)
+
+# XXX: we could prevent the conformance test suite from running
+# by simply defining this variable conditionally
+TEST_PROGS = test-conformance
+
+.PHONY: test
+
+DISTCLEANFILES = .gitignore
+
+# we override the clean-generic target to clean up the wrappers so
+# we cannot use CLEANFILES
+clean-generic: clean-wrappers
+ $(QUIET_RM)rm -f .log
+
+
+if ENABLE_INSTALLED_TESTS
+
+insttestdir = $(libexecdir)/installed-tests/$(PACKAGE)/conform
+insttest_PROGRAMS = test-conformance
+insttest_DATA = unit-tests
+
+testmetadir = $(datadir)/installed-tests/$(PACKAGE)
+testmeta_DATA = conform.test
+
+conform.test:
+ echo " GEN $@"; \
+ echo "[Test]" > $@.tmp; \
+ echo "Type=session" >> $@.tmp; \
+ echo "Exec=sh -c \"cd $(libexecdir)/installed-tests/$(PACKAGE)/conform; ../run-tests.sh ../config.env ./test-conformance\"" >> $@.tmp; \
+ mv $@.tmp $@
+
+CLEANFILES = conform.test
+
+endif
diff --git a/cogl/tests/conform/test-alpha-test.c b/cogl/tests/conform/test-alpha-test.c
new file mode 100644
index 000000000..e74f6d8e0
--- /dev/null
+++ b/cogl/tests/conform/test-alpha-test.c
@@ -0,0 +1,73 @@
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+static CoglTexture2D *
+create_texture (CoglContext *context)
+{
+ static const uint8_t data[] =
+ {
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xfa, 0x00, 0xfa
+ };
+
+ return cogl_texture_2d_new_from_data (context,
+ 2, 1, /* width/height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ data,
+ NULL /* error */);
+}
+
+void
+test_alpha_test (void)
+{
+ CoglTexture *tex = create_texture (test_ctx);
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ CoglColor clear_color;
+
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+ cogl_pipeline_set_layer_filters (pipeline, 0,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+ cogl_pipeline_set_alpha_test_function (pipeline,
+ COGL_PIPELINE_ALPHA_FUNC_GEQUAL,
+ 254 / 255.0f /* alpha reference */);
+
+ cogl_color_init_from_4ub (&clear_color, 0x00, 0x00, 0xff, 0xff);
+ cogl_framebuffer_clear (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ &clear_color);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1, -1,
+ 1, 1);
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (tex);
+
+ /* The left side of the framebuffer should use the first pixel from
+ * the texture which is red */
+ test_utils_check_region (test_fb,
+ 2, 2,
+ fb_width / 2 - 4,
+ fb_height - 4,
+ 0xff0000ff);
+ /* The right side of the framebuffer should use the clear color
+ * because the second pixel from the texture is clipped from the
+ * alpha test */
+ test_utils_check_region (test_fb,
+ fb_width / 2 + 2,
+ 2,
+ fb_width / 2 - 4,
+ fb_height - 4,
+ 0x0000ffff);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-alpha-textures.c b/cogl/tests/conform/test-alpha-textures.c
new file mode 100644
index 000000000..dccd30e11
--- /dev/null
+++ b/cogl/tests/conform/test-alpha-textures.c
@@ -0,0 +1,123 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+static void
+create_pipeline (CoglTexture **tex_out,
+ CoglPipeline **pipeline_out)
+{
+ CoglTexture2D *tex;
+ CoglPipeline *pipeline;
+ static const uint8_t tex_data[] =
+ { 0x00, 0x44, 0x88, 0xcc };
+
+ tex = cogl_texture_2d_new_from_data (test_ctx,
+ 2, 2, /* width/height */
+ COGL_PIXEL_FORMAT_A_8, /* format */
+ 2, /* rowstride */
+ tex_data,
+ NULL);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_filters (pipeline,
+ 0, /* layer */
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+ cogl_pipeline_set_layer_wrap_mode (pipeline,
+ 0, /* layer */
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+
+ /* This is the layer combine used by cogl-pango */
+ cogl_pipeline_set_layer_combine (pipeline,
+ 0, /* layer */
+ "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
+ NULL);
+
+ cogl_pipeline_set_layer_texture (pipeline,
+ 0, /* layer */
+ tex);
+
+ *pipeline_out = pipeline;
+ *tex_out = tex;
+}
+
+void
+test_alpha_textures (void)
+{
+ CoglTexture *tex1, *tex2;
+ CoglPipeline *pipeline1, *pipeline2;
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ uint8_t replacement_data[1] = { 0xff };
+
+ create_pipeline (&tex1, &pipeline1);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline1,
+ -1.0f, 1.0f, /* x1/y1 */
+ 1.0f, 0.0f /* x2/y2 */);
+
+ create_pipeline (&tex2, &pipeline2);
+
+ cogl_texture_set_region (tex2,
+ 0, 0, /* src_x/y */
+ 1, 1, /* dst_x/y */
+ 1, 1, /* dst_width / dst_height */
+ 1, 1, /* width / height */
+ COGL_PIXEL_FORMAT_A_8,
+ 1, /* rowstride */
+ replacement_data);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline2,
+ -1.0f, 0.0f, /* x1/y1 */
+ 1.0f, -1.0f /* x2/y2 */);
+
+ cogl_object_unref (tex1);
+ cogl_object_unref (tex2);
+ cogl_object_unref (pipeline1);
+ cogl_object_unref (pipeline2);
+
+ /* Unmodified texture */
+ test_utils_check_pixel (test_fb,
+ fb_width / 4,
+ fb_height / 8,
+ 0x000000ff);
+ test_utils_check_pixel (test_fb,
+ fb_width * 3 / 4,
+ fb_height / 8,
+ 0x444444ff);
+ test_utils_check_pixel (test_fb,
+ fb_width / 4,
+ fb_height * 3 / 8,
+ 0x888888ff);
+ test_utils_check_pixel (test_fb,
+ fb_width * 3 / 4,
+ fb_height * 3 / 8,
+ 0xccccccff);
+
+ /* Modified texture */
+ test_utils_check_pixel (test_fb,
+ fb_width / 4,
+ fb_height * 5 / 8,
+ 0x000000ff);
+ test_utils_check_pixel (test_fb,
+ fb_width * 3 / 4,
+ fb_height * 5 / 8,
+ 0x444444ff);
+ test_utils_check_pixel (test_fb,
+ fb_width / 4,
+ fb_height * 7 / 8,
+ 0x888888ff);
+ test_utils_check_pixel (test_fb,
+ fb_width * 3 / 4,
+ fb_height * 7 / 8,
+ 0xffffffff);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-atlas-migration.c b/cogl/tests/conform/test-atlas-migration.c
new file mode 100644
index 000000000..39e8a3c1f
--- /dev/null
+++ b/cogl/tests/conform/test-atlas-migration.c
@@ -0,0 +1,145 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+#define N_TEXTURES 128
+
+#define OPACITY_FOR_ROW(y) \
+ (0xff - ((y) & 0xf) * 0x10)
+
+#define COLOR_FOR_SIZE(size) \
+ (colors + (size) % 3)
+
+typedef struct
+{
+ uint8_t red, green, blue, alpha;
+} TestColor;
+
+static const TestColor colors[] =
+ { { 0xff, 0x00, 0x00, 0xff },
+ { 0x00, 0xff, 0x00, 0xff },
+ { 0x00, 0x00, 0xff, 0xff } };
+
+static CoglTexture *
+create_texture (int size)
+{
+ CoglTexture *texture;
+ const TestColor *color;
+ uint8_t *data, *p;
+ int x, y;
+
+ /* Create a red, green or blue texture depending on the size */
+ color = COLOR_FOR_SIZE (size);
+
+ p = data = g_malloc (size * size * 4);
+
+ /* Fill the data with the color but fade the opacity out with
+ increasing y coordinates so that we can see the blending it the
+ atlas migration accidentally blends with garbage in the
+ texture */
+ for (y = 0; y < size; y++)
+ {
+ int opacity = OPACITY_FOR_ROW (y);
+
+ for (x = 0; x < size; x++)
+ {
+ /* Store the colors premultiplied */
+ p[0] = color->red * opacity / 255;
+ p[1] = color->green * opacity / 255;
+ p[2] = color->blue * opacity / 255;
+ p[3] = opacity;
+
+ p += 4;
+ }
+ }
+
+ texture = test_utils_texture_new_from_data (test_ctx,
+ size, /* width */
+ size, /* height */
+ TEST_UTILS_TEXTURE_NONE, /* flags */
+ /* format */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ /* rowstride */
+ size * 4,
+ data);
+
+ g_free (data);
+
+ return texture;
+}
+
+static void
+verify_texture (CoglTexture *texture, int size)
+{
+ uint8_t *data, *p;
+ int x, y;
+ const TestColor *color;
+
+ color = COLOR_FOR_SIZE (size);
+
+ p = data = g_malloc (size * size * 4);
+
+ cogl_texture_get_data (texture,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ size * 4,
+ data);
+
+ for (y = 0; y < size; y++)
+ {
+ int opacity = OPACITY_FOR_ROW (y);
+
+ for (x = 0; x < size; x++)
+ {
+ TestColor real_color =
+ {
+ color->red * opacity / 255,
+ color->green * opacity / 255,
+ color->blue * opacity / 255
+ };
+
+ test_utils_compare_pixel (p,
+ (real_color.red << 24) |
+ (real_color.green << 16) |
+ (real_color.blue << 8) |
+ opacity);
+ g_assert_cmpint (p[3], ==, opacity);
+
+ p += 4;
+ }
+ }
+
+ g_free (data);
+}
+
+void
+test_atlas_migration (void)
+{
+ CoglTexture *textures[N_TEXTURES];
+ int i, tex_num;
+
+ /* Create and destroy all of the textures a few times to increase
+ the chances that we'll end up reusing the buffers for previously
+ discarded atlases */
+ for (i = 0; i < 5; i++)
+ {
+ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
+ textures[tex_num] = create_texture (tex_num + 1);
+ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
+ cogl_object_unref (textures[tex_num]);
+ }
+
+ /* Create all the textures again */
+ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
+ textures[tex_num] = create_texture (tex_num + 1);
+
+ /* Verify that they all still have the right data */
+ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
+ verify_texture (textures[tex_num], tex_num + 1);
+
+ /* Destroy them all */
+ for (tex_num = 0; tex_num < N_TEXTURES; tex_num++)
+ cogl_object_unref (textures[tex_num]);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-backface-culling.c b/cogl/tests/conform/test-backface-culling.c
new file mode 100644
index 000000000..e90c2f5ec
--- /dev/null
+++ b/cogl/tests/conform/test-backface-culling.c
@@ -0,0 +1,311 @@
+#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0
+
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+/* Size the texture so that it is just off a power of two to encourage
+ it so use software tiling when NPOTs aren't available */
+#define TEXTURE_SIZE 257
+
+/* Amount of pixels to skip off the top, bottom, left and right of the
+ texture when reading back the stage */
+#define TEST_INSET 2
+
+/* Size to actually render the texture at */
+#define TEXTURE_RENDER_SIZE 8
+
+typedef struct _TestState
+{
+ CoglTexture *texture;
+ CoglFramebuffer *offscreen;
+ CoglTexture *offscreen_tex;
+ int width, height;
+} TestState;
+
+static void
+validate_part (CoglFramebuffer *framebuffer,
+ int xnum, int ynum, CoglBool shown)
+{
+ test_utils_check_region (framebuffer,
+ xnum * TEXTURE_RENDER_SIZE + TEST_INSET,
+ ynum * TEXTURE_RENDER_SIZE + TEST_INSET,
+ TEXTURE_RENDER_SIZE - TEST_INSET * 2,
+ TEXTURE_RENDER_SIZE - TEST_INSET * 2,
+ shown ? 0xff0000ff : 0x000000ff);
+}
+
+/* We draw everything 16 times. The draw number is used as a bitmask
+ to test all of the combinations of enabling legacy state, both
+ winding orders and all four culling modes */
+
+#define USE_LEGACY_STATE(draw_num) (((draw_num) & 0x01) >> 0)
+#define FRONT_WINDING(draw_num) (((draw_num) & 0x02) >> 1)
+#define CULL_FACE_MODE(draw_num) (((draw_num) & 0x0c) >> 2)
+
+static void
+paint_test_backface_culling (TestState *state,
+ CoglFramebuffer *framebuffer)
+{
+ int draw_num;
+ CoglPipeline *base_pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_framebuffer_orthographic (framebuffer,
+ 0, 0,
+ state->width,
+ state->height,
+ -1,
+ 100);
+
+ cogl_framebuffer_clear4f (framebuffer,
+ COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_STENCIL,
+ 0, 0, 0, 1);
+
+ cogl_pipeline_set_layer_texture (base_pipeline, 0, state->texture);
+
+ cogl_pipeline_set_layer_filters (base_pipeline, 0,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+
+ cogl_push_framebuffer (framebuffer);
+
+ /* Render the scene sixteen times to test all of the combinations of
+ cull face mode, legacy state and winding orders */
+ for (draw_num = 0; draw_num < 16; draw_num++)
+ {
+ float x1 = 0, x2, y1 = 0, y2 = (float)(TEXTURE_RENDER_SIZE);
+ CoglTextureVertex verts[4];
+ CoglPipeline *pipeline;
+
+ cogl_push_matrix ();
+ cogl_translate (0, TEXTURE_RENDER_SIZE * draw_num, 0);
+
+ pipeline = cogl_pipeline_copy (base_pipeline);
+
+ cogl_set_backface_culling_enabled (USE_LEGACY_STATE (draw_num));
+ cogl_pipeline_set_front_face_winding (pipeline, FRONT_WINDING (draw_num));
+ cogl_pipeline_set_cull_face_mode (pipeline, CULL_FACE_MODE (draw_num));
+
+ cogl_push_source (pipeline);
+
+ memset (verts, 0, sizeof (verts));
+
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a front-facing texture */
+ cogl_rectangle (x1, y1, x2, y2);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a front-facing texture with flipped texcoords */
+ cogl_rectangle_with_texture_coords (x1, y1, x2, y2,
+ 1.0, 0.0, 0.0, 1.0);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a back-facing texture */
+ cogl_rectangle (x2, y1, x1, y2);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* If the texture is sliced then cogl_polygon doesn't work so
+ we'll just use a solid color instead */
+ if (cogl_texture_is_sliced (state->texture))
+ cogl_set_source_color4ub (255, 0, 0, 255);
+
+ /* Draw a front-facing polygon */
+ verts[0].x = x1; verts[0].y = y2;
+ verts[1].x = x2; verts[1].y = y2;
+ verts[2].x = x2; verts[2].y = y1;
+ verts[3].x = x1; verts[3].y = y1;
+ verts[0].tx = 0; verts[0].ty = 0;
+ verts[1].tx = 1.0; verts[1].ty = 0;
+ verts[2].tx = 1.0; verts[2].ty = 1.0;
+ verts[3].tx = 0; verts[3].ty = 1.0;
+ cogl_polygon (verts, 4, FALSE);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ /* Draw a back-facing polygon */
+ verts[0].x = x1; verts[0].y = y1;
+ verts[1].x = x2; verts[1].y = y1;
+ verts[2].x = x2; verts[2].y = y2;
+ verts[3].x = x1; verts[3].y = y2;
+ verts[0].tx = 0; verts[0].ty = 0;
+ verts[1].tx = 1.0; verts[1].ty = 0;
+ verts[2].tx = 1.0; verts[2].ty = 1.0;
+ verts[3].tx = 0; verts[3].ty = 1.0;
+ cogl_polygon (verts, 4, FALSE);
+
+ x1 = x2;
+ x2 = x1 + (float)(TEXTURE_RENDER_SIZE);
+
+ cogl_pop_matrix ();
+
+ cogl_pop_source ();
+ cogl_object_unref (pipeline);
+ }
+
+ cogl_pop_framebuffer ();
+
+ cogl_object_unref (base_pipeline);
+}
+
+static void
+validate_result (CoglFramebuffer *framebuffer, int y_offset)
+{
+ int draw_num;
+
+ for (draw_num = 0; draw_num < 16; draw_num++)
+ {
+ CoglBool cull_front, cull_back;
+ CoglPipelineCullFaceMode cull_mode;
+
+ if (USE_LEGACY_STATE (draw_num))
+ cull_mode = COGL_PIPELINE_CULL_FACE_MODE_BACK;
+ else
+ cull_mode = CULL_FACE_MODE (draw_num);
+
+ switch (cull_mode)
+ {
+ case COGL_PIPELINE_CULL_FACE_MODE_NONE:
+ cull_front = FALSE;
+ cull_back = FALSE;
+ break;
+
+ case COGL_PIPELINE_CULL_FACE_MODE_FRONT:
+ cull_front = TRUE;
+ cull_back = FALSE;
+ break;
+
+ case COGL_PIPELINE_CULL_FACE_MODE_BACK:
+ cull_front = FALSE;
+ cull_back = TRUE;
+ break;
+
+ case COGL_PIPELINE_CULL_FACE_MODE_BOTH:
+ cull_front = TRUE;
+ cull_back = TRUE;
+ break;
+ }
+
+ if (FRONT_WINDING (draw_num) == COGL_WINDING_CLOCKWISE)
+ {
+ CoglBool tmp = cull_front;
+ cull_front = cull_back;
+ cull_back = tmp;
+ }
+
+ /* Front-facing texture */
+ validate_part (framebuffer,
+ 0, y_offset + draw_num, !cull_front);
+ /* Front-facing texture with flipped tex coords */
+ validate_part (framebuffer,
+ 1, y_offset + draw_num, !cull_front);
+ /* Back-facing texture */
+ validate_part (framebuffer,
+ 2, y_offset + draw_num, !cull_back);
+ /* Front-facing texture polygon */
+ validate_part (framebuffer,
+ 3, y_offset + draw_num, !cull_front);
+ /* Back-facing texture polygon */
+ validate_part (framebuffer,
+ 4, y_offset + draw_num, !cull_back);
+ }
+}
+
+static void
+paint (TestState *state)
+{
+ CoglPipeline *pipeline;
+
+ paint_test_backface_culling (state, test_fb);
+
+ /*
+ * Now repeat the test but rendered to an offscreen
+ * framebuffer. Note that by default the conformance tests are
+ * always run to an offscreen buffer but we might as well have this
+ * check anyway in case it is being run with COGL_TEST_ONSCREEN=1
+ */
+ paint_test_backface_culling (state, state->offscreen);
+
+ /* Copy the result of the offscreen rendering for validation and
+ * also so we can have visual feedback. */
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_layer_texture (pipeline, 0, state->offscreen_tex);
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ 0, TEXTURE_RENDER_SIZE * 16,
+ state->width,
+ state->height + TEXTURE_RENDER_SIZE * 16);
+ cogl_object_unref (pipeline);
+
+ validate_result (test_fb, 0);
+ validate_result (test_fb, 16);
+}
+
+static CoglTexture *
+make_texture (void)
+{
+ guchar *tex_data, *p;
+ CoglTexture *tex;
+
+ tex_data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4);
+
+ for (p = tex_data + TEXTURE_SIZE * TEXTURE_SIZE * 4; p > tex_data;)
+ {
+ *(--p) = 255;
+ *(--p) = 0;
+ *(--p) = 0;
+ *(--p) = 255;
+ }
+
+ tex = test_utils_texture_new_from_data (test_ctx,
+ TEXTURE_SIZE,
+ TEXTURE_SIZE,
+ TEST_UTILS_TEXTURE_NO_ATLAS,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ TEXTURE_SIZE * 4,
+ tex_data);
+
+ g_free (tex_data);
+
+ return tex;
+}
+
+void
+test_backface_culling (void)
+{
+ TestState state;
+ CoglTexture *tex;
+
+ state.width = cogl_framebuffer_get_width (test_fb);
+ state.height = cogl_framebuffer_get_height (test_fb);
+
+ state.offscreen = NULL;
+
+ state.texture = make_texture ();
+
+ tex = test_utils_texture_new_with_size (test_ctx,
+ state.width, state.height,
+ TEST_UTILS_TEXTURE_NO_SLICING,
+ COGL_TEXTURE_COMPONENTS_RGBA);
+ state.offscreen = cogl_offscreen_new_with_texture (tex);
+ state.offscreen_tex = tex;
+
+ paint (&state);
+
+ cogl_object_unref (state.offscreen);
+ cogl_object_unref (state.offscreen_tex);
+ cogl_object_unref (state.texture);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-blend-strings.c b/cogl/tests/conform/test-blend-strings.c
new file mode 100644
index 000000000..f49c8603b
--- /dev/null
+++ b/cogl/tests/conform/test-blend-strings.c
@@ -0,0 +1,430 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define QUAD_WIDTH 20
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define ALPHA 3
+
+#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
+#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
+#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
+#define MASK_ALPHA(COLOR) (COLOR & 0xff)
+
+#define BLEND_CONSTANT_UNUSED 0xDEADBEEF
+#define TEX_CONSTANT_UNUSED 0xDEADBEEF
+
+typedef struct _TestState
+{
+ CoglContext *ctx;
+} TestState;
+
+
+static void
+test_blend (TestState *state,
+ int x,
+ int y,
+ uint32_t src_color,
+ uint32_t dst_color,
+ const char *blend_string,
+ uint32_t blend_constant,
+ uint32_t expected_result)
+{
+ /* src color */
+ uint8_t Sr = MASK_RED (src_color);
+ uint8_t Sg = MASK_GREEN (src_color);
+ uint8_t Sb = MASK_BLUE (src_color);
+ uint8_t Sa = MASK_ALPHA (src_color);
+ /* dest color */
+ uint8_t Dr = MASK_RED (dst_color);
+ uint8_t Dg = MASK_GREEN (dst_color);
+ uint8_t Db = MASK_BLUE (dst_color);
+ uint8_t Da = MASK_ALPHA (dst_color);
+ /* blend constant - when applicable */
+ uint8_t Br = MASK_RED (blend_constant);
+ uint8_t Bg = MASK_GREEN (blend_constant);
+ uint8_t Bb = MASK_BLUE (blend_constant);
+ uint8_t Ba = MASK_ALPHA (blend_constant);
+ CoglColor blend_const_color;
+
+ CoglHandle material;
+ CoglPipeline *pipeline;
+ CoglBool status;
+ CoglError *error = NULL;
+ int y_off;
+ int x_off;
+
+ /* First write out the destination color without any blending... */
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_color4ub (pipeline, Dr, Dg, Db, Da);
+ cogl_pipeline_set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL);
+ cogl_set_source (pipeline);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ cogl_object_unref (pipeline);
+
+ /*
+ * Now blend a rectangle over our well defined destination:
+ */
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_color4ub (pipeline, Sr, Sg, Sb, Sa);
+
+ status = cogl_pipeline_set_blend (pipeline, blend_string, &error);
+ if (!status)
+ {
+ /* It's not strictly a test failure; you need a more capable GPU or
+ * driver to test this blend string. */
+ if (cogl_test_verbose ())
+ {
+ g_debug ("Failed to test blend string %s: %s",
+ blend_string, error->message);
+ g_print ("Skipping\n");
+ }
+ return;
+ }
+
+ cogl_color_init_from_4ub (&blend_const_color, Br, Bg, Bb, Ba);
+ cogl_pipeline_set_blend_constant (pipeline, &blend_const_color);
+
+ cogl_set_source (pipeline);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ cogl_object_unref (pipeline);
+
+ /* See what we got... */
+
+ y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
+ x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
+
+ if (cogl_test_verbose ())
+ {
+ g_print ("test_blend (%d, %d):\n%s\n", x, y, blend_string);
+ g_print (" src color = %02x, %02x, %02x, %02x\n", Sr, Sg, Sb, Sa);
+ g_print (" dst color = %02x, %02x, %02x, %02x\n", Dr, Dg, Db, Da);
+ if (blend_constant != BLEND_CONSTANT_UNUSED)
+ g_print (" blend constant = %02x, %02x, %02x, %02x\n",
+ Br, Bg, Bb, Ba);
+ else
+ g_print (" blend constant = UNUSED\n");
+ }
+
+ test_utils_check_pixel (test_fb, x_off, y_off, expected_result);
+
+
+ /*
+ * Test with legacy API
+ */
+
+ /* Clear previous work */
+ cogl_set_source_color4ub (0, 0, 0, 0xff);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+
+ /* First write out the destination color without any blending... */
+ material = cogl_material_new ();
+ cogl_material_set_color4ub (material, Dr, Dg, Db, Da);
+ cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
+ cogl_set_source (material);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ cogl_handle_unref (material);
+
+ /*
+ * Now blend a rectangle over our well defined destination:
+ */
+
+ material = cogl_material_new ();
+ cogl_material_set_color4ub (material, Sr, Sg, Sb, Sa);
+
+ status = cogl_material_set_blend (material, blend_string, &error);
+ if (!status)
+ {
+ /* This is a failure as it must be equivalent to the new API */
+ g_warning ("Error setting blend string %s: %s",
+ blend_string, error->message);
+ g_assert_not_reached ();
+ }
+
+ cogl_color_init_from_4ub (&blend_const_color, Br, Bg, Bb, Ba);
+ cogl_material_set_blend_constant (material, &blend_const_color);
+
+ cogl_set_source (material);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ cogl_handle_unref (material);
+
+ /* See what we got... */
+
+ test_utils_check_pixel (test_fb, x_off, y_off, expected_result);
+}
+
+static CoglTexture *
+make_texture (uint32_t color)
+{
+ guchar *tex_data, *p;
+ uint8_t r = MASK_RED (color);
+ uint8_t g = MASK_GREEN (color);
+ uint8_t b = MASK_BLUE (color);
+ uint8_t a = MASK_ALPHA (color);
+ CoglTexture *tex;
+
+ tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 4);
+
+ for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;)
+ {
+ *(--p) = a;
+ *(--p) = b;
+ *(--p) = g;
+ *(--p) = r;
+ }
+
+ /* Note: we claim that the data is premultiplied so that Cogl won't
+ * premultiply the data on upload */
+ tex = test_utils_texture_new_from_data (test_ctx,
+ QUAD_WIDTH,
+ QUAD_WIDTH,
+ TEST_UTILS_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ QUAD_WIDTH * 4,
+ tex_data);
+
+ g_free (tex_data);
+
+ return tex;
+}
+
+static void
+test_tex_combine (TestState *state,
+ int x,
+ int y,
+ uint32_t tex0_color,
+ uint32_t tex1_color,
+ uint32_t combine_constant,
+ const char *combine_string,
+ uint32_t expected_result)
+{
+ CoglTexture *tex0, *tex1;
+
+ /* combine constant - when applicable */
+ uint8_t Cr = MASK_RED (combine_constant);
+ uint8_t Cg = MASK_GREEN (combine_constant);
+ uint8_t Cb = MASK_BLUE (combine_constant);
+ uint8_t Ca = MASK_ALPHA (combine_constant);
+ CoglColor combine_const_color;
+
+ CoglHandle material;
+ CoglBool status;
+ CoglError *error = NULL;
+ int y_off;
+ int x_off;
+
+
+ tex0 = make_texture (tex0_color);
+ tex1 = make_texture (tex1_color);
+
+ material = cogl_material_new ();
+
+ cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80);
+ cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
+
+ cogl_material_set_layer (material, 0, tex0);
+ cogl_material_set_layer_combine (material, 0,
+ "RGBA = REPLACE (TEXTURE)", NULL);
+
+ cogl_material_set_layer (material, 1, tex1);
+ status = cogl_material_set_layer_combine (material, 1,
+ combine_string, &error);
+ if (!status)
+ {
+ /* It's not strictly a test failure; you need a more capable GPU or
+ * driver to test this texture combine string. */
+ g_debug ("Failed to test texture combine string %s: %s",
+ combine_string, error->message);
+ }
+
+ cogl_color_init_from_4ub (&combine_const_color, Cr, Cg, Cb, Ca);
+ cogl_material_set_layer_combine_constant (material, 1, &combine_const_color);
+
+ cogl_set_source (material);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+
+ cogl_handle_unref (material);
+ cogl_object_unref (tex0);
+ cogl_object_unref (tex1);
+
+ /* See what we got... */
+
+ y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
+ x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
+
+ if (cogl_test_verbose ())
+ {
+ g_print ("test_tex_combine (%d, %d):\n%s\n", x, y, combine_string);
+ g_print (" texture 0 color = 0x%08lX\n", (unsigned long)tex0_color);
+ g_print (" texture 1 color = 0x%08lX\n", (unsigned long)tex1_color);
+ if (combine_constant != TEX_CONSTANT_UNUSED)
+ g_print (" combine constant = %02x, %02x, %02x, %02x\n",
+ Cr, Cg, Cb, Ca);
+ else
+ g_print (" combine constant = UNUSED\n");
+ }
+
+ test_utils_check_pixel (test_fb, x_off, y_off, expected_result);
+}
+
+static void
+paint (TestState *state)
+{
+ test_blend (state, 0, 0, /* position */
+ 0xff0000ff, /* src */
+ 0xffffffff, /* dst */
+ "RGBA = ADD (SRC_COLOR, 0)",
+ BLEND_CONSTANT_UNUSED,
+ 0xff0000ff); /* expected */
+
+ test_blend (state, 1, 0, /* position */
+ 0x11223344, /* src */
+ 0x11223344, /* dst */
+ "RGBA = ADD (SRC_COLOR, DST_COLOR)",
+ BLEND_CONSTANT_UNUSED,
+ 0x22446688); /* expected */
+
+ test_blend (state, 2, 0, /* position */
+ 0x80808080, /* src */
+ 0xffffffff, /* dst */
+ "RGBA = ADD (SRC_COLOR * (CONSTANT), 0)",
+ 0x80808080, /* constant (RGBA all = 0.5 when normalized) */
+ 0x40404040); /* expected */
+
+ test_blend (state, 3, 0, /* position */
+ 0x80000080, /* src (alpha = 0.5 when normalized) */
+ 0x40000000, /* dst */
+ "RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]),"
+ " DST_COLOR * (1-SRC_COLOR[A]))",
+ BLEND_CONSTANT_UNUSED,
+ 0x60000040); /* expected */
+
+ /* XXX:
+ * For all texture combine tests tex0 will use a combine mode of
+ * "RGBA = REPLACE (TEXTURE)"
+ */
+
+ test_tex_combine (state, 4, 0, /* position */
+ 0x11111111, /* texture 0 color */
+ 0x22222222, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGBA = ADD (PREVIOUS, TEXTURE)", /* tex combine */
+ 0x33333333); /* expected */
+
+ test_tex_combine (state, 5, 0, /* position */
+ 0x40404040, /* texture 0 color */
+ 0x80808080, /* texture 1 color (RGBA all = 0.5) */
+ TEX_CONSTANT_UNUSED,
+ "RGBA = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */
+ 0x20202020); /* expected */
+
+ test_tex_combine (state, 6, 0, /* position */
+ 0xffffff80, /* texture 0 color (alpha = 0.5) */
+ 0xDEADBE40, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGB = REPLACE (PREVIOUS)"
+ "A = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */
+ 0xffffff20); /* expected */
+
+ /* XXX: we are assuming test_tex_combine creates a material with
+ * a color of 0x80808080 (i.e. the "PRIMARY" color) */
+ test_tex_combine (state, 7, 0, /* position */
+ 0xffffff80, /* texture 0 color (alpha = 0.5) */
+ 0xDEADBE20, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGB = REPLACE (PREVIOUS)"
+ "A = MODULATE (PRIMARY, TEXTURE)", /* tex combine */
+ 0xffffff10); /* expected */
+
+ test_tex_combine (state, 8, 0, /* position */
+ 0x11111111, /* texture 0 color */
+ 0x22222222, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGBA = ADD (PREVIOUS, 1-TEXTURE)", /* tex combine */
+ 0xeeeeeeee); /* expected */
+
+ /* this is again assuming a primary color of 0x80808080 */
+ test_tex_combine (state, 9, 0, /* position */
+ 0x10101010, /* texture 0 color */
+ 0x20202020, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGBA = INTERPOLATE (PREVIOUS, TEXTURE, PRIMARY)",
+ 0x18181818); /* expected */
+
+#if 0 /* using TEXTURE_N appears to be broken in cogl-blend-string.c */
+ test_tex_combine (state, 0, 1, /* position */
+ 0xDEADBEEF, /* texture 0 color (not used) */
+ 0x11223344, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGBA = ADD (TEXTURE_1, TEXTURE)", /* tex combine */
+ 0x22446688); /* expected */
+#endif
+
+ test_tex_combine (state, 1, 1, /* position */
+ 0x21314151, /* texture 0 color */
+ 0x99999999, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGBA = ADD_SIGNED (PREVIOUS, TEXTURE)", /* tex combine */
+ 0x3a4a5a6a); /* expected */
+
+ test_tex_combine (state, 2, 1, /* position */
+ 0xfedcba98, /* texture 0 color */
+ 0x11111111, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGBA = SUBTRACT (PREVIOUS, TEXTURE)", /* tex combine */
+ 0xedcba987); /* expected */
+
+ test_tex_combine (state, 3, 1, /* position */
+ 0x8899aabb, /* texture 0 color */
+ 0xbbaa9988, /* texture 1 color */
+ TEX_CONSTANT_UNUSED,
+ "RGB = DOT3_RGBA (PREVIOUS, TEXTURE)"
+ "A = REPLACE (PREVIOUS)",
+ 0x2a2a2abb); /* expected */
+}
+
+void
+test_blend_strings (void)
+{
+ TestState state;
+
+ cogl_framebuffer_orthographic (test_fb, 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ /* XXX: we have to push/pop a framebuffer since this test currently
+ * uses the legacy cogl_rectangle() api. */
+ cogl_push_framebuffer (test_fb);
+ paint (&state);
+ cogl_pop_framebuffer ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-blend.c b/cogl/tests/conform/test-blend.c
new file mode 100644
index 000000000..3c6235b5f
--- /dev/null
+++ b/cogl/tests/conform/test-blend.c
@@ -0,0 +1,64 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+static void
+paint (void)
+{
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ int width = cogl_framebuffer_get_width (test_fb);
+ int half_width = width / 2;
+ int height = cogl_framebuffer_get_height (test_fb);
+ CoglVertexP2 tri0_vertices[] = {
+ { 0, 0 },
+ { 0, height },
+ { half_width, height },
+ };
+ CoglVertexP2C4 tri1_vertices[] = {
+ { half_width, 0, 0x80, 0x80, 0x80, 0x80 },
+ { half_width, height, 0x80, 0x80, 0x80, 0x80 },
+ { width, height, 0x80, 0x80, 0x80, 0x80 },
+ };
+ CoglPrimitive *tri0;
+ CoglPrimitive *tri1;
+
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 0);
+
+ tri0 = cogl_primitive_new_p2 (test_ctx, COGL_VERTICES_MODE_TRIANGLES,
+ 3, tri0_vertices);
+ tri1 = cogl_primitive_new_p2c4 (test_ctx, COGL_VERTICES_MODE_TRIANGLES,
+ 3, tri1_vertices);
+
+ /* Check that cogl correctly handles the case where we draw
+ * different primitives same pipeline and switch from using the
+ * opaque color associated with the pipeline and using a colour
+ * attribute with an alpha component which implies blending is
+ * required.
+ *
+ * If Cogl gets this wrong then then in all likelyhood the second
+ * primitive will be drawn with blending still disabled.
+ */
+
+ cogl_primitive_draw (tri0, test_fb, pipeline);
+ cogl_primitive_draw (tri1, test_fb, pipeline);
+
+ test_utils_check_pixel_and_alpha (test_fb,
+ half_width + 5,
+ height - 5,
+ 0x80808080);
+}
+
+void
+test_blend (void)
+{
+ cogl_framebuffer_orthographic (test_fb, 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ paint ();
+}
+
diff --git a/cogl/tests/conform/test-color-hsl.c b/cogl/tests/conform/test-color-hsl.c
new file mode 100644
index 000000000..651ce5208
--- /dev/null
+++ b/cogl/tests/conform/test-color-hsl.c
@@ -0,0 +1,45 @@
+#include <math.h>
+#include <string.h>
+
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+#define cogl_assert_float(a, b) \
+ do { \
+ if (fabsf ((a) - (b)) >= 0.0001f) \
+ g_assert_cmpfloat ((a), ==, (b)); \
+ } while (0)
+
+void
+test_color_hsl (void)
+{
+ CoglColor color;
+ float hue, saturation, luminance;
+
+ cogl_color_init_from_4ub(&color, 108, 198, 78, 255);
+ cogl_color_to_hsl(&color, &hue, &saturation, &luminance);
+
+ cogl_assert_float(hue, 105.f);
+ cogl_assert_float(saturation, 0.512821);
+ cogl_assert_float(luminance, 0.541176);
+
+ memset(&color, 0, sizeof (CoglColor));
+ cogl_color_init_from_hsl(&color, hue, saturation, luminance);
+
+ g_assert_cmpint (cogl_color_get_red_byte (&color), ==, 108);
+ g_assert_cmpint (cogl_color_get_green_byte (&color), ==, 198);
+ g_assert_cmpint (cogl_color_get_blue_byte (&color), ==, 78);
+ g_assert_cmpint (cogl_color_get_alpha_byte (&color), ==, 255);
+
+ memset(&color, 0, sizeof (CoglColor));
+ cogl_color_init_from_hsl(&color, hue, 0, luminance);
+
+ cogl_assert_float (cogl_color_get_red_float (&color), luminance);
+ cogl_assert_float (cogl_color_get_green_float (&color), luminance);
+ cogl_assert_float (cogl_color_get_blue_float (&color), luminance);
+ cogl_assert_float (cogl_color_get_alpha_float (&color), 1.0f);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-color-mask.c b/cogl/tests/conform/test-color-mask.c
new file mode 100644
index 000000000..e80f46dae
--- /dev/null
+++ b/cogl/tests/conform/test-color-mask.c
@@ -0,0 +1,110 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+#define TEX_SIZE 128
+
+#define NUM_FBOS 3
+
+typedef struct _TestState
+{
+ int width;
+ int height;
+
+ CoglTexture *tex[NUM_FBOS];
+ CoglFramebuffer *fbo[NUM_FBOS];
+} TestState;
+
+static void
+paint (TestState *state)
+{
+ CoglColor bg;
+ int i;
+
+ cogl_set_source_color4ub (255, 255, 255, 255);
+
+ /* We push the third framebuffer first so that later we can switch
+ back to it by popping to test that that works */
+ cogl_push_framebuffer (state->fbo[2]);
+
+ cogl_push_framebuffer (state->fbo[0]);
+ cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
+ cogl_pop_framebuffer ();
+
+ cogl_push_framebuffer (state->fbo[1]);
+ cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
+ cogl_pop_framebuffer ();
+
+ /* We should now be back on the third framebuffer */
+ cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
+ cogl_pop_framebuffer ();
+
+ cogl_color_init_from_4ub (&bg, 128, 128, 128, 255);
+ cogl_clear (&bg, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH);
+
+ /* Render all of the textures to the screen */
+ for (i = 0; i < NUM_FBOS; i++)
+ {
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_layer_texture (pipeline, 0, state->tex[i]);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline,
+ 2.0f / NUM_FBOS * i - 1.0f, -1.0f,
+ 2.0f / NUM_FBOS * (i + 1) - 1.0f, 1.0f);
+ cogl_object_unref (pipeline);
+ }
+
+ /* Verify all of the fbos drew the right color */
+ for (i = 0; i < NUM_FBOS; i++)
+ {
+ uint8_t expected_colors[NUM_FBOS][4] =
+ { { 0xff, 0x00, 0x00, 0xff },
+ { 0x00, 0xff, 0x00, 0xff },
+ { 0x00, 0x00, 0xff, 0xff } };
+
+ test_utils_check_pixel_rgb (test_fb,
+ state->width * (i + 0.5f) / NUM_FBOS,
+ state->height / 2,
+ expected_colors[i][0],
+ expected_colors[i][1],
+ expected_colors[i][2]);
+ }
+}
+
+void
+test_color_mask (void)
+{
+ TestState state;
+ int i;
+
+ state.width = cogl_framebuffer_get_width (test_fb);
+ state.height = cogl_framebuffer_get_height (test_fb);
+
+ for (i = 0; i < NUM_FBOS; i++)
+ {
+ state.tex[i] = test_utils_texture_new_with_size (test_ctx, 128, 128,
+ TEST_UTILS_TEXTURE_NO_ATLAS,
+ COGL_TEXTURE_COMPONENTS_RGB);
+
+
+ state.fbo[i] = cogl_offscreen_new_with_texture (state.tex[i]);
+
+ /* Clear the texture color bits */
+ cogl_framebuffer_clear4f (state.fbo[i],
+ COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+
+ cogl_framebuffer_set_color_mask (state.fbo[i],
+ i == 0 ? COGL_COLOR_MASK_RED :
+ i == 1 ? COGL_COLOR_MASK_GREEN :
+ COGL_COLOR_MASK_BLUE);
+ }
+
+ /* XXX: we have to push/pop a framebuffer since this test currently
+ * uses the legacy cogl_rectangle() api. */
+ cogl_push_framebuffer (test_fb);
+ paint (&state);
+ cogl_pop_framebuffer ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-conform-main.c b/cogl/tests/conform/test-conform-main.c
new file mode 100644
index 000000000..9b6573d92
--- /dev/null
+++ b/cogl/tests/conform/test-conform-main.c
@@ -0,0 +1,157 @@
+#include "config.h"
+
+#include <cogl/cogl.h>
+
+#include <glib.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+/* A bit of sugar for adding new conformance tests */
+#define ADD_TEST(FUNC, REQUIREMENTS, KNOWN_FAIL_REQUIREMENTS) \
+ G_STMT_START { \
+ extern void FUNC (void); \
+ if (strcmp (#FUNC, argv[1]) == 0) \
+ { \
+ test_utils_init (REQUIREMENTS, KNOWN_FAIL_REQUIREMENTS); \
+ FUNC (); \
+ test_utils_fini (); \
+ exit (0); \
+ } \
+ } G_STMT_END
+
+#define UNPORTED_TEST(FUNC)
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ if (argc != 2)
+ {
+ g_printerr ("usage %s UNIT_TEST\n", argv[0]);
+ exit (1);
+ }
+
+ /* Just for convenience in case people try passing the wrapper
+ * filenames for the UNIT_TEST argument we normalize '-' characters
+ * to '_' characters... */
+ for (i = 0; argv[1][i]; i++)
+ {
+ if (argv[1][i] == '-')
+ argv[1][i] = '_';
+ }
+
+ /* This file is run through a sed script during the make step so the
+ * lines containing the tests need to be formatted on a single line
+ * each.
+ */
+
+ UNPORTED_TEST (test_object);
+ UNPORTED_TEST (test_fixed);
+ UNPORTED_TEST (test_materials);
+ ADD_TEST (test_pipeline_user_matrix, 0, 0);
+ ADD_TEST (test_blend_strings, 0, 0);
+ ADD_TEST (test_blend, 0, 0);
+ ADD_TEST (test_premult, 0, TEST_KNOWN_FAILURE);
+ UNPORTED_TEST (test_readpixels);
+#ifdef COGL_HAS_COGL_PATH_SUPPORT
+ ADD_TEST (test_path, 0, 0);
+ ADD_TEST (test_path_clip, 0, 0);
+#endif
+ ADD_TEST (test_depth_test, 0, 0);
+ ADD_TEST (test_color_mask, 0, 0);
+ ADD_TEST (test_backface_culling, 0, TEST_REQUIREMENT_NPOT);
+ ADD_TEST (test_layer_remove, 0, 0);
+
+ ADD_TEST (test_sparse_pipeline, 0, 0);
+
+ ADD_TEST (test_npot_texture, 0, 0);
+ UNPORTED_TEST (test_multitexture);
+ UNPORTED_TEST (test_texture_mipmaps);
+ ADD_TEST (test_sub_texture, 0, 0);
+ ADD_TEST (test_pixel_buffer_map, 0, 0);
+ ADD_TEST (test_pixel_buffer_set_data, 0, 0);
+ ADD_TEST (test_pixel_buffer_sub_region, 0, 0);
+ UNPORTED_TEST (test_texture_rectangle);
+ ADD_TEST (test_texture_3d, TEST_REQUIREMENT_TEXTURE_3D, 0);
+ ADD_TEST (test_wrap_modes, 0, 0);
+ UNPORTED_TEST (test_texture_pixmap_x11);
+ ADD_TEST (test_texture_get_set_data, 0, 0);
+ ADD_TEST (test_atlas_migration, 0, 0);
+ ADD_TEST (test_read_texture_formats, 0, TEST_KNOWN_FAILURE);
+ ADD_TEST (test_write_texture_formats, 0, 0);
+ ADD_TEST (test_alpha_textures, 0, 0);
+ ADD_TEST (test_wrap_rectangle_textures,
+ TEST_REQUIREMENT_TEXTURE_RECTANGLE,
+ TEST_KNOWN_FAILURE);
+
+ UNPORTED_TEST (test_vertex_buffer_contiguous);
+ UNPORTED_TEST (test_vertex_buffer_interleved);
+ UNPORTED_TEST (test_vertex_buffer_mutability);
+
+ ADD_TEST (test_primitive, 0, 0);
+
+ ADD_TEST (test_just_vertex_shader, TEST_REQUIREMENT_GLSL, 0);
+ ADD_TEST (test_pipeline_uniforms, TEST_REQUIREMENT_GLSL, 0);
+ ADD_TEST (test_snippets, TEST_REQUIREMENT_GLSL, 0);
+ ADD_TEST (test_custom_attributes, TEST_REQUIREMENT_GLSL, 0);
+
+ ADD_TEST (test_offscreen, 0, 0);
+ ADD_TEST (test_framebuffer_get_bits,
+ TEST_REQUIREMENT_OFFSCREEN | TEST_REQUIREMENT_GL,
+ 0);
+
+ ADD_TEST (test_point_size, 0, 0);
+ ADD_TEST (test_point_size_attribute,
+ TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE, 0);
+ ADD_TEST (test_point_size_attribute_snippet,
+ TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE |
+ TEST_REQUIREMENT_GLSL, 0);
+ ADD_TEST (test_point_sprite,
+ TEST_REQUIREMENT_POINT_SPRITE,
+ 0);
+ ADD_TEST (test_point_sprite_orientation,
+ TEST_REQUIREMENT_POINT_SPRITE,
+ TEST_KNOWN_FAILURE);
+ ADD_TEST (test_point_sprite_glsl,
+ TEST_REQUIREMENT_POINT_SPRITE |
+ TEST_REQUIREMENT_GLSL,
+ 0);
+
+ ADD_TEST (test_version, 0, 0);
+
+ ADD_TEST (test_alpha_test, 0, 0);
+
+ ADD_TEST (test_map_buffer_range, TEST_REQUIREMENT_MAP_WRITE, 0);
+
+ ADD_TEST (test_primitive_and_journal, 0, 0);
+
+ ADD_TEST (test_copy_replace_texture, 0, 0);
+
+ ADD_TEST (test_pipeline_cache_unrefs_texture, 0, 0);
+ ADD_TEST (test_pipeline_shader_state, TEST_REQUIREMENT_GLSL, 0);
+
+ UNPORTED_TEST (test_viewport);
+
+ ADD_TEST (test_gles2_context, TEST_REQUIREMENT_GLES2_CONTEXT, 0);
+ ADD_TEST (test_gles2_context_fbo, TEST_REQUIREMENT_GLES2_CONTEXT, 0);
+ ADD_TEST (test_gles2_context_copy_tex_image,
+ TEST_REQUIREMENT_GLES2_CONTEXT,
+ 0);
+
+ ADD_TEST (test_euler_quaternion, 0, 0);
+ ADD_TEST (test_color_hsl, 0, 0);
+
+ ADD_TEST (test_fence, TEST_REQUIREMENT_FENCE, 0);
+
+ ADD_TEST (test_texture_no_allocate, 0, 0);
+
+ ADD_TEST (test_texture_rg, TEST_REQUIREMENT_TEXTURE_RG, 0);
+
+ g_printerr ("Unknown test name \"%s\"\n", argv[1]);
+
+ return 1;
+}
diff --git a/cogl/tests/conform/test-copy-replace-texture.c b/cogl/tests/conform/test-copy-replace-texture.c
new file mode 100644
index 000000000..f11070ee8
--- /dev/null
+++ b/cogl/tests/conform/test-copy-replace-texture.c
@@ -0,0 +1,120 @@
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+/* Keep track of the number of textures that we've created and are
+ * still alive */
+static int alive_texture_mask = 0;
+
+#define N_LAYERS 3
+#define N_PIPELINES 4
+
+#define PIPELINE_LAYER_MASK(pipeline_num) \
+ (((1 << N_LAYERS) - 1) << (N_LAYERS * (pipeline_num) + 1))
+#define LAST_PIPELINE_MASK PIPELINE_LAYER_MASK (N_PIPELINES - 1)
+#define FIRST_PIPELINE_MASK PIPELINE_LAYER_MASK (0)
+
+static void
+free_texture_cb (void *user_data)
+{
+ int texture_num = GPOINTER_TO_INT (user_data);
+
+ alive_texture_mask &= ~(1 << texture_num);
+}
+
+static CoglTexture *
+create_texture (void)
+{
+ static const guint8 data[] =
+ { 0xff, 0xff, 0xff, 0xff };
+ static CoglUserDataKey texture_data_key;
+ CoglTexture2D *tex_2d;
+ static int texture_num = 1;
+
+ alive_texture_mask |= (1 << texture_num);
+
+ tex_2d = cogl_texture_2d_new_from_data (test_ctx,
+ 1, 1, /* width / height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ data,
+ NULL);
+
+ /* Set some user data on the texture so we can track when it has
+ * been destroyed */
+ cogl_object_set_user_data (COGL_OBJECT (tex_2d),
+ &texture_data_key,
+ GINT_TO_POINTER (texture_num),
+ free_texture_cb);
+
+ texture_num++;
+
+ return tex_2d;
+}
+
+void
+test_copy_replace_texture (void)
+{
+ CoglPipeline *pipelines[N_PIPELINES];
+ int pipeline_num;
+
+ /* Create a set of pipeline copies each with three of their own
+ * replacement textures */
+ for (pipeline_num = 0; pipeline_num < N_PIPELINES; pipeline_num++)
+ {
+ int layer_num;
+
+ if (pipeline_num == 0)
+ pipelines[pipeline_num] = cogl_pipeline_new (test_ctx);
+ else
+ pipelines[pipeline_num] =
+ cogl_pipeline_copy (pipelines[pipeline_num - 1]);
+
+ for (layer_num = 0; layer_num < N_LAYERS; layer_num++)
+ {
+ CoglTexture *tex = create_texture ();
+ cogl_pipeline_set_layer_texture (pipelines[pipeline_num],
+ layer_num,
+ tex);
+ cogl_object_unref (tex);
+ }
+ }
+
+ /* Unref everything but the last pipeline */
+ for (pipeline_num = 0; pipeline_num < N_PIPELINES - 1; pipeline_num++)
+ cogl_object_unref (pipelines[pipeline_num]);
+
+ if (alive_texture_mask && cogl_test_verbose ())
+ {
+ int i;
+
+ g_print ("Alive textures:");
+
+ for (i = 0; i < N_PIPELINES * N_LAYERS; i++)
+ if ((alive_texture_mask & (1 << (i + 1))))
+ g_print (" %i", i);
+
+ g_print ("\n");
+ }
+
+ /* Ideally there should only be the textures from the last pipeline
+ * left alive. We also let Cogl keep the textures from the first
+ * texture alive because currently the child of the third layer in
+ * the first pipeline will retain its authority on the unit index
+ * state so that it can set it to 2. If there are more textures then
+ * it means the pipeline isn't correctly pruning redundant
+ * ancestors */
+ g_assert_cmpint (alive_texture_mask & ~FIRST_PIPELINE_MASK,
+ ==,
+ LAST_PIPELINE_MASK);
+
+ /* Clean up the last pipeline */
+ cogl_object_unref (pipelines[N_PIPELINES - 1]);
+
+ /* That should get rid of the last of the textures */
+ g_assert_cmpint (alive_texture_mask, ==, 0);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-custom-attributes.c b/cogl/tests/conform/test-custom-attributes.c
new file mode 100644
index 000000000..633dc2ad8
--- /dev/null
+++ b/cogl/tests/conform/test-custom-attributes.c
@@ -0,0 +1,301 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+ CoglPipeline *pipeline;
+} TestState;
+
+typedef struct
+{
+ int16_t x, y;
+ float r, g, b, a;
+} FloatVert;
+
+typedef struct
+{
+ int16_t x, y;
+ uint8_t r, g, b, a;
+} ByteVert;
+
+typedef struct
+{
+ int16_t x, y;
+ int16_t r, g, b, a;
+} ShortVert;
+
+static void
+test_float_verts (TestState *state, int offset_x, int offset_y)
+{
+ CoglAttribute *attributes[2];
+ CoglAttributeBuffer *buffer;
+ CoglPrimitive *primitive;
+
+ static const FloatVert float_verts[] =
+ {
+ { 0, 10, /**/ 1, 0, 0, 1 },
+ { 10, 10, /**/ 1, 0, 0, 1 },
+ { 5, 0, /**/ 1, 0, 0, 1 },
+
+ { 10, 10, /**/ 0, 1, 0, 1 },
+ { 20, 10, /**/ 0, 1, 0, 1 },
+ { 15, 0, /**/ 0, 1, 0, 1 }
+ };
+
+ buffer = cogl_attribute_buffer_new (test_ctx,
+ sizeof (float_verts), float_verts);
+ attributes[0] = cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (FloatVert),
+ G_STRUCT_OFFSET (FloatVert, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_SHORT);
+ attributes[1] = cogl_attribute_new (buffer,
+ "color",
+ sizeof (FloatVert),
+ G_STRUCT_OFFSET (FloatVert, r),
+ 4, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb, offset_x, offset_y, 0.0f);
+
+ primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ 6, /* n_vertices */
+ attributes,
+ 2); /* n_attributes */
+ cogl_primitive_draw (primitive, test_fb, state->pipeline);
+ cogl_object_unref (primitive);
+
+ cogl_framebuffer_pop_matrix (test_fb);
+
+ cogl_object_unref (attributes[1]);
+ cogl_object_unref (attributes[0]);
+ cogl_object_unref (buffer);
+
+ test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff);
+ test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff);
+}
+
+static void
+test_byte_verts (TestState *state, int offset_x, int offset_y)
+{
+ CoglAttribute *attributes[2];
+ CoglAttributeBuffer *buffer, *unnorm_buffer;
+ CoglPrimitive *primitive;
+
+ static const ByteVert norm_verts[] =
+ {
+ { 0, 10, /**/ 255, 0, 0, 255 },
+ { 10, 10, /**/ 255, 0, 0, 255 },
+ { 5, 0, /**/ 255, 0, 0, 255 },
+
+ { 10, 10, /**/ 0, 255, 0, 255 },
+ { 20, 10, /**/ 0, 255, 0, 255 },
+ { 15, 0, /**/ 0, 255, 0, 255 }
+ };
+
+ static const ByteVert unnorm_verts[] =
+ {
+ { 0, 0, /**/ 0, 0, 1, 1 },
+ { 0, 0, /**/ 0, 0, 1, 1 },
+ { 0, 0, /**/ 0, 0, 1, 1 },
+ };
+
+ buffer = cogl_attribute_buffer_new (test_ctx,
+ sizeof (norm_verts), norm_verts);
+ attributes[0] = cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (ByteVert),
+ G_STRUCT_OFFSET (ByteVert, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_SHORT);
+ attributes[1] = cogl_attribute_new (buffer,
+ "color",
+ sizeof (ByteVert),
+ G_STRUCT_OFFSET (ByteVert, r),
+ 4, /* n_components */
+ COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
+ cogl_attribute_set_normalized (attributes[1], TRUE);
+
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb, offset_x, offset_y, 0.0f);
+
+ primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ 6, /* n_vertices */
+ attributes,
+ 2); /* n_attributes */
+ cogl_primitive_draw (primitive, test_fb, state->pipeline);
+ cogl_object_unref (primitive);
+
+ cogl_object_unref (attributes[1]);
+
+ /* Test again with unnormalized attributes */
+ unnorm_buffer = cogl_attribute_buffer_new (test_ctx,
+ sizeof (unnorm_verts),
+ unnorm_verts);
+ attributes[1] = cogl_attribute_new (unnorm_buffer,
+ "color",
+ sizeof (ByteVert),
+ G_STRUCT_OFFSET (ByteVert, r),
+ 4, /* n_components */
+ COGL_ATTRIBUTE_TYPE_BYTE);
+
+ cogl_framebuffer_translate (test_fb, 20, 0, 0);
+
+ primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ attributes,
+ 2); /* n_attributes */
+ cogl_primitive_draw (primitive, test_fb, state->pipeline);
+ cogl_object_unref (primitive);
+
+ cogl_framebuffer_pop_matrix (test_fb);
+
+ cogl_object_unref (attributes[0]);
+ cogl_object_unref (attributes[1]);
+ cogl_object_unref (buffer);
+ cogl_object_unref (unnorm_buffer);
+
+ test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff);
+ test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff);
+ test_utils_check_pixel (test_fb, offset_x + 25, offset_y + 5, 0x0000ffff);
+}
+
+static void
+test_short_verts (TestState *state, int offset_x, int offset_y)
+{
+ CoglAttribute *attributes[2];
+ CoglAttributeBuffer *buffer;
+ CoglPipeline *pipeline, *pipeline2;
+ CoglSnippet *snippet;
+ CoglPrimitive *primitive;
+
+ static const ShortVert short_verts[] =
+ {
+ { -10, -10, /**/ 0xffff, 0, 0, 0xffff },
+ { -1, -10, /**/ 0xffff, 0, 0, 0xffff },
+ { -5, -1, /**/ 0xffff, 0, 0, 0xffff }
+ };
+
+
+ pipeline = cogl_pipeline_copy (state->pipeline);
+
+ cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255);
+
+ buffer = cogl_attribute_buffer_new (test_ctx,
+ sizeof (short_verts), short_verts);
+ attributes[0] = cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (ShortVert),
+ G_STRUCT_OFFSET (ShortVert, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_SHORT);
+ attributes[1] = cogl_attribute_new (buffer,
+ "color",
+ sizeof (ShortVert),
+ G_STRUCT_OFFSET (ShortVert, r),
+ 4, /* n_components */
+ COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT);
+ cogl_attribute_set_normalized (attributes[1], TRUE);
+
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb,
+ offset_x + 10.0f,
+ offset_y + 10.0f,
+ 0.0f);
+
+ primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ attributes,
+ 2); /* n_attributes */
+ cogl_primitive_draw (primitive, test_fb, pipeline);
+ cogl_object_unref (primitive);
+
+ cogl_framebuffer_pop_matrix (test_fb);
+
+ cogl_object_unref (attributes[0]);
+
+ /* Test again treating the attribute as unsigned */
+ attributes[0] = cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (ShortVert),
+ G_STRUCT_OFFSET (ShortVert, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT);
+
+ /* XXX: this is a hack to force the pipeline to use the glsl backend
+ * because we know it's not possible to test short vertex position
+ * components with the legacy GL backend since which might otherwise
+ * be used internally... */
+ pipeline2 = cogl_pipeline_new (test_ctx);
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
+ "attribute vec4 color;",
+ "cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);");
+ cogl_pipeline_add_snippet (pipeline2, snippet);
+
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb,
+ offset_x + 10.0f - 65525.0f,
+ offset_y - 65525,
+ 0.0f);
+
+ primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ attributes,
+ 1); /* n_attributes */
+ cogl_primitive_draw (primitive, test_fb, pipeline2);
+ cogl_object_unref (primitive);
+
+ cogl_framebuffer_pop_matrix (test_fb);
+
+ cogl_object_unref (attributes[0]);
+
+ cogl_object_unref (pipeline2);
+ cogl_object_unref (pipeline);
+ cogl_object_unref (buffer);
+
+ test_utils_check_pixel (test_fb, offset_x + 5, offset_y + 5, 0xff0000ff);
+ test_utils_check_pixel (test_fb, offset_x + 15, offset_y + 5, 0x00ff00ff);
+}
+
+static void
+paint (TestState *state)
+{
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+
+ test_float_verts (state, 0, 0);
+ test_byte_verts (state, 0, 10);
+ test_short_verts (state, 0, 20);
+}
+
+void
+test_custom_attributes (void)
+{
+ CoglSnippet *snippet;
+ TestState state;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ state.pipeline = cogl_pipeline_new (test_ctx);
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
+ "attribute vec4 color;",
+ "cogl_color_out = color;");
+ cogl_pipeline_add_snippet (state.pipeline, snippet);
+
+ paint (&state);
+
+ cogl_object_unref (state.pipeline);
+ cogl_object_unref (snippet);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-depth-test.c b/cogl/tests/conform/test-depth-test.c
new file mode 100644
index 000000000..bfa9d0e1f
--- /dev/null
+++ b/cogl/tests/conform/test-depth-test.c
@@ -0,0 +1,301 @@
+#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0
+
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define QUAD_WIDTH 20
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define ALPHA 3
+
+#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
+#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
+#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
+#define MASK_ALPHA(COLOR) (COLOR & 0xff)
+
+typedef struct _TestState
+{
+ int padding;
+} TestState;
+
+typedef struct
+{
+ uint32_t color;
+ float depth;
+ CoglBool test_enable;
+ CoglDepthTestFunction test_function;
+ CoglBool write_enable;
+ CoglBool fb_write_enable;
+ float range_near;
+ float range_far;
+} TestDepthState;
+
+static CoglBool
+draw_rectangle (TestState *state,
+ int x,
+ int y,
+ TestDepthState *rect_state,
+ CoglBool legacy_mode)
+{
+ uint8_t Cr = MASK_RED (rect_state->color);
+ uint8_t Cg = MASK_GREEN (rect_state->color);
+ uint8_t Cb = MASK_BLUE (rect_state->color);
+ uint8_t Ca = MASK_ALPHA (rect_state->color);
+ CoglPipeline *pipeline;
+ CoglDepthState depth_state;
+
+ cogl_depth_state_init (&depth_state);
+ cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable);
+ cogl_depth_state_set_test_function (&depth_state, rect_state->test_function);
+ cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable);
+ cogl_depth_state_set_range (&depth_state,
+ rect_state->range_near,
+ rect_state->range_far);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL))
+ {
+ cogl_object_unref (pipeline);
+ return FALSE;
+ }
+
+ if (!legacy_mode)
+ {
+ cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca);
+
+ cogl_framebuffer_set_depth_write_enabled (test_fb,
+ rect_state->fb_write_enable);
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb, 0, 0, rect_state->depth);
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ cogl_framebuffer_pop_matrix (test_fb);
+ }
+ else
+ {
+ cogl_push_framebuffer (test_fb);
+ cogl_push_matrix ();
+ cogl_set_source_color4ub (Cr, Cg, Cb, Ca);
+ cogl_translate (0, 0, rect_state->depth);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ cogl_pop_matrix ();
+ cogl_pop_framebuffer ();
+ }
+
+ cogl_object_unref (pipeline);
+
+ return TRUE;
+}
+
+static void
+test_depth (TestState *state,
+ int x,
+ int y,
+ TestDepthState *rect0_state,
+ TestDepthState *rect1_state,
+ TestDepthState *rect2_state,
+ CoglBool legacy_mode,
+ uint32_t expected_result)
+{
+ CoglBool missing_feature = FALSE;
+
+ if (rect0_state)
+ missing_feature |= !draw_rectangle (state, x, y, rect0_state, legacy_mode);
+ if (rect1_state)
+ missing_feature |= !draw_rectangle (state, x, y, rect1_state, legacy_mode);
+ if (rect2_state)
+ missing_feature |= !draw_rectangle (state, x, y, rect2_state, legacy_mode);
+
+ /* We don't consider it an error that we can't test something
+ * the driver doesn't support. */
+ if (missing_feature)
+ return;
+
+ test_utils_check_pixel (test_fb,
+ x * QUAD_WIDTH + (QUAD_WIDTH / 2),
+ y * QUAD_WIDTH + (QUAD_WIDTH / 2),
+ expected_result);
+}
+
+static void
+paint (TestState *state)
+{
+ /* Sanity check a few of the different depth test functions
+ * and that depth writing can be disabled... */
+
+ {
+ /* Closest */
+ TestDepthState rect0_state = {
+ 0xff0000ff, /* rgba color */
+ -10, /* depth */
+ FALSE, /* depth test enable */
+ COGL_DEPTH_TEST_FUNCTION_ALWAYS,
+ TRUE, /* depth write enable */
+ TRUE, /* FB depth write enable */
+ 0, 1 /* depth range */
+ };
+ /* Furthest */
+ TestDepthState rect1_state = {
+ 0x00ff00ff, /* rgba color */
+ -70, /* depth */
+ TRUE, /* depth test enable */
+ COGL_DEPTH_TEST_FUNCTION_ALWAYS,
+ TRUE, /* depth write enable */
+ TRUE, /* FB depth write enable */
+ 0, 1 /* depth range */
+ };
+ /* In the middle */
+ TestDepthState rect2_state = {
+ 0x0000ffff, /* rgba color */
+ -20, /* depth */
+ TRUE, /* depth test enable */
+ COGL_DEPTH_TEST_FUNCTION_NEVER,
+ TRUE, /* depth write enable */
+ TRUE, /* FB depth write enable */
+ 0, 1 /* depth range */
+ };
+
+ test_depth (state, 0, 0, /* position */
+ &rect0_state, &rect1_state, &rect2_state,
+ FALSE, /* legacy mode */
+ 0x00ff00ff); /* expected */
+
+ rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_ALWAYS;
+ test_depth (state, 1, 0, /* position */
+ &rect0_state, &rect1_state, &rect2_state,
+ FALSE, /* legacy mode */
+ 0x0000ffff); /* expected */
+
+ rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_LESS;
+ test_depth (state, 2, 0, /* position */
+ &rect0_state, &rect1_state, &rect2_state,
+ FALSE, /* legacy mode */
+ 0x0000ffff); /* expected */
+
+ rect2_state.test_function = COGL_DEPTH_TEST_FUNCTION_GREATER;
+ test_depth (state, 3, 0, /* position */
+ &rect0_state, &rect1_state, &rect2_state,
+ FALSE, /* legacy mode */
+ 0x00ff00ff); /* expected */
+
+ rect0_state.test_enable = TRUE;
+ rect1_state.write_enable = FALSE;
+ test_depth (state, 4, 0, /* position */
+ &rect0_state, &rect1_state, &rect2_state,
+ FALSE, /* legacy mode */
+ 0x0000ffff); /* expected */
+
+ rect1_state.write_enable = TRUE;
+ rect1_state.fb_write_enable = FALSE;
+ test_depth (state, 4, 0, /* position */
+ &rect0_state, &rect1_state, &rect2_state,
+ FALSE, /* legacy mode */
+ 0x0000ffff); /* expected */
+
+ /* Re-enable FB depth writing to verify state flush */
+ rect1_state.write_enable = TRUE;
+ rect1_state.fb_write_enable = TRUE;
+ test_depth (state, 4, 0, /* position */
+ &rect0_state, &rect1_state, &rect2_state,
+ FALSE, /* legacy mode */
+ 0x00ff00ff); /* expected */
+ }
+
+ /* Check that the depth buffer values can be mapped into different
+ * ranges... */
+
+ {
+ /* Closest by depth, furthest by depth range */
+ TestDepthState rect0_state = {
+ 0xff0000ff, /* rgba color */
+ -10, /* depth */
+ TRUE, /* depth test enable */
+ COGL_DEPTH_TEST_FUNCTION_ALWAYS,
+ TRUE, /* depth write enable */
+ TRUE, /* FB depth write enable */
+ 0.5, 1 /* depth range */
+ };
+ /* Furthest by depth, nearest by depth range */
+ TestDepthState rect1_state = {
+ 0x00ff00ff, /* rgba color */
+ -70, /* depth */
+ TRUE, /* depth test enable */
+ COGL_DEPTH_TEST_FUNCTION_GREATER,
+ TRUE, /* depth write enable */
+ TRUE, /* FB depth write enable */
+ 0, 0.5 /* depth range */
+ };
+
+ test_depth (state, 0, 1, /* position */
+ &rect0_state, &rect1_state, NULL,
+ FALSE, /* legacy mode */
+ 0xff0000ff); /* expected */
+ }
+
+ /* Test that the legacy cogl_set_depth_test_enabled() API still
+ * works... */
+
+ {
+ /* Nearest */
+ TestDepthState rect0_state = {
+ 0xff0000ff, /* rgba color */
+ -10, /* depth */
+ FALSE, /* depth test enable */
+ COGL_DEPTH_TEST_FUNCTION_LESS,
+ TRUE, /* depth write enable */
+ TRUE, /* FB depth write enable */
+ 0, 1 /* depth range */
+ };
+ /* Furthest */
+ TestDepthState rect1_state = {
+ 0x00ff00ff, /* rgba color */
+ -70, /* depth */
+ FALSE, /* depth test enable */
+ COGL_DEPTH_TEST_FUNCTION_LESS,
+ TRUE, /* depth write enable */
+ TRUE, /* FB depth write enable */
+ 0, 1 /* depth range */
+ };
+
+ cogl_set_depth_test_enabled (TRUE);
+ test_depth (state, 0, 2, /* position */
+ &rect0_state, &rect1_state, NULL,
+ TRUE, /* legacy mode */
+ 0xff0000ff); /* expected */
+ cogl_set_depth_test_enabled (FALSE);
+ test_depth (state, 1, 2, /* position */
+ &rect0_state, &rect1_state, NULL,
+ TRUE, /* legacy mode */
+ 0x00ff00ff); /* expected */
+ }
+}
+
+void
+test_depth_test (void)
+{
+ TestState state;
+
+ cogl_framebuffer_orthographic (test_fb, 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ paint (&state);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-euler-quaternion.c b/cogl/tests/conform/test-euler-quaternion.c
new file mode 100644
index 000000000..c250bec0b
--- /dev/null
+++ b/cogl/tests/conform/test-euler-quaternion.c
@@ -0,0 +1,81 @@
+#include <cogl/cogl.h>
+#include <math.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+/* Macros are used here instead of functions so that the
+ * g_assert_cmpfloat will give a more interesting message when it
+ * fails */
+
+#define COMPARE_FLOATS(a, b) \
+ do { \
+ if (fabsf ((a) - (b)) >= 0.0001f) \
+ g_assert_cmpfloat ((a), ==, (b)); \
+ } while (0)
+
+#define COMPARE_MATRICES(a, b) \
+ do { \
+ COMPARE_FLOATS ((a)->xx, (b)->xx); \
+ COMPARE_FLOATS ((a)->yx, (b)->yx); \
+ COMPARE_FLOATS ((a)->zx, (b)->zx); \
+ COMPARE_FLOATS ((a)->wx, (b)->wx); \
+ COMPARE_FLOATS ((a)->xy, (b)->xy); \
+ COMPARE_FLOATS ((a)->yy, (b)->yy); \
+ COMPARE_FLOATS ((a)->zy, (b)->zy); \
+ COMPARE_FLOATS ((a)->wy, (b)->wy); \
+ COMPARE_FLOATS ((a)->xz, (b)->xz); \
+ COMPARE_FLOATS ((a)->yz, (b)->yz); \
+ COMPARE_FLOATS ((a)->zz, (b)->zz); \
+ COMPARE_FLOATS ((a)->wz, (b)->wz); \
+ COMPARE_FLOATS ((a)->xw, (b)->xw); \
+ COMPARE_FLOATS ((a)->yw, (b)->yw); \
+ COMPARE_FLOATS ((a)->zw, (b)->zw); \
+ COMPARE_FLOATS ((a)->ww, (b)->ww); \
+ } while (0)
+
+void
+test_euler_quaternion (void)
+{
+ CoglEuler euler;
+ CoglQuaternion quaternion;
+ CoglMatrix matrix_a, matrix_b;
+
+ /* Try doing the rotation with three separate rotations */
+ cogl_matrix_init_identity (&matrix_a);
+ cogl_matrix_rotate (&matrix_a, -30.0f, 0.0f, 1.0f, 0.0f);
+ cogl_matrix_rotate (&matrix_a, 40.0f, 1.0f, 0.0f, 0.0f);
+ cogl_matrix_rotate (&matrix_a, 50.0f, 0.0f, 0.0f, 1.0f);
+
+ /* And try the same rotation with a euler */
+ cogl_euler_init (&euler, -30, 40, 50);
+ cogl_matrix_init_from_euler (&matrix_b, &euler);
+
+ /* Verify that the matrices are approximately the same */
+ COMPARE_MATRICES (&matrix_a, &matrix_b);
+
+ /* Try converting the euler to a matrix via a quaternion */
+ cogl_quaternion_init_from_euler (&quaternion, &euler);
+ memset (&matrix_b, 0, sizeof (matrix_b));
+ cogl_matrix_init_from_quaternion (&matrix_b, &quaternion);
+ COMPARE_MATRICES (&matrix_a, &matrix_b);
+
+ /* Try applying the rotation from a euler to a framebuffer */
+ cogl_framebuffer_identity_matrix (test_fb);
+ cogl_framebuffer_rotate_euler (test_fb, &euler);
+ memset (&matrix_b, 0, sizeof (matrix_b));
+ cogl_framebuffer_get_modelview_matrix (test_fb, &matrix_b);
+ COMPARE_MATRICES (&matrix_a, &matrix_b);
+
+ /* And again with a quaternion */
+ cogl_framebuffer_identity_matrix (test_fb);
+ cogl_framebuffer_rotate_quaternion (test_fb, &quaternion);
+ memset (&matrix_b, 0, sizeof (matrix_b));
+ cogl_framebuffer_get_modelview_matrix (test_fb, &matrix_b);
+ COMPARE_MATRICES (&matrix_a, &matrix_b);
+
+ /* FIXME: This needs a lot more tests! */
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-fence.c b/cogl/tests/conform/test-fence.c
new file mode 100644
index 000000000..d5e3586f5
--- /dev/null
+++ b/cogl/tests/conform/test-fence.c
@@ -0,0 +1,63 @@
+#include <cogl/cogl.h>
+
+/* These will be redefined in config.h */
+#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
+#undef COGL_ENABLE_EXPERIMENTAL_API
+
+#include "test-utils.h"
+#include "config.h"
+
+/* I'm writing this on the train after having dinner at a churrascuria. */
+#define MAGIC_CHUNK_O_DATA ((void *) 0xdeadbeef)
+
+static GMainLoop *loop;
+
+gboolean
+timeout (void *user_data)
+{
+ g_assert (!"timeout not reached");
+
+ return FALSE;
+}
+
+void
+callback (CoglFence *fence,
+ void *user_data)
+{
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+
+ test_utils_check_pixel (test_fb, fb_width - 1, fb_height - 1, 0x00ff0000);
+ g_assert (user_data == MAGIC_CHUNK_O_DATA && "callback data not mangled");
+
+ g_main_loop_quit (loop);
+}
+
+void
+test_fence (void)
+{
+ GSource *cogl_source;
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ CoglFenceClosure *closure;
+
+ cogl_source = cogl_glib_source_new (test_ctx, G_PRIORITY_DEFAULT);
+ g_source_attach (cogl_source, NULL);
+ loop = g_main_loop_new (NULL, TRUE);
+
+ cogl_framebuffer_orthographic (test_fb, 0, 0, fb_width, fb_height, -1, 100);
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR,
+ 0.0f, 1.0f, 0.0f, 0.0f);
+
+ closure = cogl_framebuffer_add_fence_callback (test_fb,
+ callback,
+ MAGIC_CHUNK_O_DATA);
+ g_assert (closure != NULL);
+
+ g_timeout_add_seconds (5, timeout, NULL);
+
+ g_main_loop_run (loop);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-fixed.c b/cogl/tests/conform/test-fixed.c
new file mode 100644
index 000000000..175b2d195
--- /dev/null
+++ b/cogl/tests/conform/test-fixed.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <clutter/clutter.h>
+
+#include "test-conform-common.h"
+
+void
+test_fixed (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ g_assert_cmpint (COGL_FIXED_1, ==, COGL_FIXED_FROM_FLOAT (1.0));
+ g_assert_cmpint (COGL_FIXED_1, ==, COGL_FIXED_FROM_INT (1));
+
+ g_assert_cmpint (COGL_FIXED_0_5, ==, COGL_FIXED_FROM_FLOAT (0.5));
+
+ g_assert_cmpfloat (COGL_FIXED_TO_FLOAT (COGL_FIXED_1), ==, 1.0);
+ g_assert_cmpfloat (COGL_FIXED_TO_FLOAT (COGL_FIXED_0_5), ==, 0.5);
+}
+
diff --git a/cogl/tests/conform/test-fixtures.c b/cogl/tests/conform/test-fixtures.c
new file mode 100644
index 000000000..dfc20437d
--- /dev/null
+++ b/cogl/tests/conform/test-fixtures.c
@@ -0,0 +1,12 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+
+void
+test_simple_rig (void)
+{
+ ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
+ stage = clutter_stage_get_default ();
+
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+}
diff --git a/cogl/tests/conform/test-framebuffer-get-bits.c b/cogl/tests/conform/test-framebuffer-get-bits.c
new file mode 100644
index 000000000..31c220d78
--- /dev/null
+++ b/cogl/tests/conform/test-framebuffer-get-bits.c
@@ -0,0 +1,40 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+void
+test_framebuffer_get_bits (void)
+{
+ CoglTexture2D *tex_a =
+ cogl_texture_2d_new_with_size (test_ctx,
+ 16, 16); /* width/height */
+ CoglOffscreen *offscreen_a =
+ cogl_offscreen_new_with_texture (tex_a);
+ CoglFramebuffer *fb_a = offscreen_a;
+ CoglTexture2D *tex_rgba =
+ cogl_texture_2d_new_with_size (test_ctx,
+ 16, 16); /* width/height */
+ CoglOffscreen *offscreen_rgba =
+ cogl_offscreen_new_with_texture (tex_rgba);
+ CoglFramebuffer *fb_rgba = offscreen_rgba;
+
+ cogl_texture_set_components (tex_a,
+ COGL_TEXTURE_COMPONENTS_A);
+ cogl_framebuffer_allocate (fb_a, NULL);
+ cogl_framebuffer_allocate (fb_rgba, NULL);
+
+ g_assert_cmpint (cogl_framebuffer_get_red_bits (fb_a), ==, 0);
+ g_assert_cmpint (cogl_framebuffer_get_green_bits (fb_a), ==, 0);
+ g_assert_cmpint (cogl_framebuffer_get_blue_bits (fb_a), ==, 0);
+ g_assert_cmpint (cogl_framebuffer_get_alpha_bits (fb_a), >=, 1);
+
+ g_assert_cmpint (cogl_framebuffer_get_red_bits (fb_rgba), >=, 1);
+ g_assert_cmpint (cogl_framebuffer_get_green_bits (fb_rgba), >=, 1);
+ g_assert_cmpint (cogl_framebuffer_get_blue_bits (fb_rgba), >=, 1);
+ g_assert_cmpint (cogl_framebuffer_get_alpha_bits (fb_rgba), >=, 1);
+
+ cogl_object_unref (fb_rgba);
+ cogl_object_unref (tex_rgba);
+ cogl_object_unref (fb_a);
+ cogl_object_unref (tex_a);
+}
diff --git a/cogl/tests/conform/test-gles2-context.c b/cogl/tests/conform/test-gles2-context.c
new file mode 100644
index 000000000..bedc30a02
--- /dev/null
+++ b/cogl/tests/conform/test-gles2-context.c
@@ -0,0 +1,962 @@
+
+#include <cogl/cogl.h>
+#include <cogl/cogl-gles2.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+ CoglTexture *offscreen_texture;
+ CoglOffscreen *offscreen;
+ CoglGLES2Context *gles2_ctx;
+ const CoglGLES2Vtable *gles2;
+} TestState;
+
+static void
+test_push_pop_single_context (void)
+{
+ CoglTexture *offscreen_texture;
+ CoglOffscreen *offscreen;
+ CoglPipeline *pipeline;
+ CoglGLES2Context *gles2_ctx;
+ const CoglGLES2Vtable *gles2;
+ CoglError *error = NULL;
+
+ offscreen_texture =
+ cogl_texture_2d_new_with_size (test_ctx,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb));
+ offscreen = cogl_offscreen_new_with_texture (offscreen_texture);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_layer_texture (pipeline, 0, offscreen_texture);
+
+ gles2_ctx = cogl_gles2_context_new (test_ctx, &error);
+ if (!gles2_ctx)
+ g_error ("Failed to create GLES2 context: %s\n", error->message);
+
+ gles2 = cogl_gles2_context_get_vtable (gles2_ctx);
+
+ /* Clear onscreen to 0xffff00 using GLES2 */
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ test_fb,
+ test_fb,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ gles2->glClearColor (1, 1, 0, 1);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0xffff00ff);
+
+ /* Clear offscreen to 0xff0000 using GLES2 and then copy the result
+ * onscreen.
+ *
+ * If we fail to bind the new context here then we'd probably end up
+ * clearing onscreen to 0xff0000 and copying 0xffff00 to onscreen
+ * instead.
+ */
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ offscreen,
+ offscreen,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ gles2->glClearColor (1, 0, 0, 1);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1, 1, 1, -1);
+ /* NB: Cogl doesn't automatically support mid-scene modifications
+ * of textures and so we explicitly flush the drawn rectangle to the
+ * framebuffer now otherwise it may be batched until after the
+ * offscreen texture has been modified again. */
+ cogl_flush ();
+
+ /* Clear the offscreen framebuffer to blue using GLES2 before
+ * reading back from the onscreen framebuffer in case we mistakenly
+ * read from the offscreen framebuffer and get a false positive
+ */
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ offscreen,
+ offscreen,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ gles2->glClearColor (0, 0, 1, 1);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0xff0000ff);
+
+ /* Now copy the offscreen blue clear to the onscreen framebufer and
+ * check that too */
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1, 1, 1, -1);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0x0000ffff);
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ test_fb,
+ test_fb,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ gles2->glClearColor (1, 0, 1, 1);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0xff00ffff);
+
+
+ cogl_object_unref (gles2_ctx);
+
+ cogl_object_unref (pipeline);
+}
+
+static void
+create_gles2_context (CoglTexture **offscreen_texture,
+ CoglOffscreen **offscreen,
+ CoglPipeline **pipeline,
+ CoglGLES2Context **gles2_ctx,
+ const CoglGLES2Vtable **gles2)
+{
+ CoglError *error = NULL;
+
+ *offscreen_texture =
+ cogl_texture_2d_new_with_size (test_ctx,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb));
+ *offscreen = cogl_offscreen_new_with_texture (*offscreen_texture);
+
+ *pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_layer_texture (*pipeline, 0, *offscreen_texture);
+
+ *gles2_ctx = cogl_gles2_context_new (test_ctx, &error);
+ if (!*gles2_ctx)
+ g_error ("Failed to create GLES2 context: %s\n", error->message);
+
+ *gles2 = cogl_gles2_context_get_vtable (*gles2_ctx);
+}
+
+static void
+test_push_pop_multi_context (void)
+{
+ CoglTexture *offscreen_texture0;
+ CoglOffscreen *offscreen0;
+ CoglPipeline *pipeline0;
+ CoglGLES2Context *gles2_ctx0;
+ const CoglGLES2Vtable *gles20;
+ CoglTexture *offscreen_texture1;
+ CoglOffscreen *offscreen1;
+ CoglPipeline *pipeline1;
+ CoglGLES2Context *gles2_ctx1;
+ const CoglGLES2Vtable *gles21;
+ CoglError *error = NULL;
+
+ create_gles2_context (&offscreen_texture0,
+ &offscreen0,
+ &pipeline0,
+ &gles2_ctx0,
+ &gles20);
+
+ create_gles2_context (&offscreen_texture1,
+ &offscreen1,
+ &pipeline1,
+ &gles2_ctx1,
+ &gles21);
+
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1);
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx0,
+ offscreen0,
+ offscreen0,
+ &error))
+ {
+ g_error ("Failed to push gles2 context 0: %s\n", error->message);
+ }
+
+ gles20->glClearColor (1, 0, 0, 1);
+ gles20->glClear (GL_COLOR_BUFFER_BIT);
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx1,
+ offscreen1,
+ offscreen1,
+ &error))
+ {
+ g_error ("Failed to push gles2 context 1: %s\n", error->message);
+ }
+
+ gles21->glClearColor (0, 1, 0, 1);
+ gles21->glClear (GL_COLOR_BUFFER_BIT);
+
+ cogl_pop_gles2_context (test_ctx);
+ cogl_pop_gles2_context (test_ctx);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0xffffffff);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline0,
+ -1, 1, 1, -1);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0xff0000ff);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline1,
+ -1, 1, 1, -1);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0x00ff00ff);
+}
+
+static GLuint
+create_gles2_framebuffer (const CoglGLES2Vtable *gles2,
+ int width,
+ int height)
+{
+ GLuint texture_handle;
+ GLuint fbo_handle;
+ GLenum status;
+
+ gles2->glGenTextures (1, &texture_handle);
+ gles2->glGenFramebuffers (1, &fbo_handle);
+
+ gles2->glBindTexture (GL_TEXTURE_2D, texture_handle);
+ gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gles2->glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL);
+ gles2->glBindTexture (GL_TEXTURE_2D, 0);
+
+ gles2->glBindFramebuffer (GL_FRAMEBUFFER, fbo_handle);
+ gles2->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, texture_handle, 0);
+
+ status = gles2->glCheckFramebufferStatus (GL_FRAMEBUFFER);
+ if (cogl_test_verbose ())
+ g_print ("status for gles2 framebuffer = 0x%x %s\n",
+ status, status == GL_FRAMEBUFFER_COMPLETE ? "(complete)" : "(?)");
+
+ gles2->glBindFramebuffer (GL_FRAMEBUFFER, 0);
+
+ return fbo_handle;
+}
+
+static void
+test_gles2_read_pixels (void)
+{
+ CoglTexture *offscreen_texture;
+ CoglOffscreen *offscreen;
+ CoglPipeline *pipeline;
+ CoglGLES2Context *gles2_ctx;
+ const CoglGLES2Vtable *gles2;
+ CoglError *error = NULL;
+ GLubyte pixel[4];
+ GLuint fbo_handle;
+
+ create_gles2_context (&offscreen_texture,
+ &offscreen,
+ &pipeline,
+ &gles2_ctx,
+ &gles2);
+
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1);
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ offscreen,
+ offscreen,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ gles2->glClearColor (1, 0, 0, 1);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+ gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+
+ test_utils_compare_pixel (pixel, 0xff0000ff);
+
+ fbo_handle = create_gles2_framebuffer (gles2, 256, 256);
+
+ gles2->glBindFramebuffer (GL_FRAMEBUFFER, fbo_handle);
+
+ gles2->glClearColor (0, 1, 0, 1);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+ gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+
+ test_utils_compare_pixel (pixel, 0x00ff00ff);
+
+ gles2->glBindFramebuffer (GL_FRAMEBUFFER, 0);
+
+ gles2->glClearColor (0, 1, 1, 1);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+ gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+
+ test_utils_compare_pixel (pixel, 0x00ffffff);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0xffffffff);
+
+ /* Bind different read and write buffers */
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ offscreen,
+ test_fb,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+
+ test_utils_compare_pixel (pixel, 0x00ffffff);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ test_utils_check_pixel (test_fb, 0, 0, 0xffffffff);
+
+ /* Bind different read and write buffers (the other way around from
+ * before so when we test with COGL_TEST_ONSCREEN=1 we will read
+ * from an onscreen framebuffer) */
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ test_fb,
+ offscreen,
+ &error))
+ {
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+ }
+
+ gles2->glReadPixels (0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+
+ test_utils_compare_pixel (pixel, 0xffffffff);
+
+ cogl_pop_gles2_context (test_ctx);
+}
+
+void
+test_gles2_context (void)
+{
+ test_push_pop_single_context ();
+ test_push_pop_multi_context ();
+ test_gles2_read_pixels ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
+static GLuint
+create_shader (const CoglGLES2Vtable *gles2,
+ GLenum type,
+ const char *source)
+{
+ GLuint shader;
+ GLint status;
+ int length = strlen (source);
+
+ shader = gles2->glCreateShader (type);
+ gles2->glShaderSource (shader, 1, &source, &length);
+ gles2->glCompileShader (shader);
+ gles2->glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
+
+ if (!status)
+ {
+ char buf[512];
+
+ gles2->glGetShaderInfoLog (shader, sizeof (buf), NULL, buf);
+
+ g_error ("Shader compilation failed:\n%s", buf);
+ }
+
+ return shader;
+}
+
+static GLuint
+create_program (const CoglGLES2Vtable *gles2,
+ const char *vertex_shader_source,
+ const char *fragment_shader_source)
+{
+ GLuint fragment_shader, vertex_shader, program;
+ GLint status;
+
+ vertex_shader =
+ create_shader (gles2, GL_VERTEX_SHADER, vertex_shader_source);
+ fragment_shader =
+ create_shader (gles2, GL_FRAGMENT_SHADER, fragment_shader_source);
+
+ program = gles2->glCreateProgram ();
+ gles2->glAttachShader (program, vertex_shader);
+ gles2->glAttachShader (program, fragment_shader);
+ gles2->glLinkProgram (program);
+
+ gles2->glGetProgramiv (program, GL_LINK_STATUS, &status);
+
+ if (!status)
+ {
+ char buf[512];
+
+ gles2->glGetProgramInfoLog (program, sizeof (buf), NULL, buf);
+
+ g_error ("Program linking failed:\n%s", buf);
+ }
+
+ return program;
+}
+
+typedef struct
+{
+ const CoglGLES2Vtable *gles2;
+ GLint color_location;
+ GLint pos_location;
+ int fb_width, fb_height;
+} PaintData;
+
+typedef void (* PaintMethod) (PaintData *data);
+
+/* Top vertices are counter-clockwise */
+static const float top_vertices[] =
+ {
+ -1.0f, 0.0f,
+ 1.0f, 0.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f
+ };
+/* Bottom vertices are clockwise */
+static const float bottom_vertices[] =
+ {
+ 1.0f, 0.0f,
+ 1.0f, -1.0f,
+ -1.0f, 0.0f,
+ -1.0f, -1.0f
+ };
+
+static void
+paint_quads (PaintData *data)
+{
+ const CoglGLES2Vtable *gles2 = data->gles2;
+
+ gles2->glEnableVertexAttribArray (data->pos_location);
+
+ /* Paint the top half in red */
+ gles2->glUniform4f (data->color_location,
+ 1.0f, 0.0f, 0.0f, 1.0f);
+ gles2->glVertexAttribPointer (data->pos_location,
+ 2, /* size */
+ GL_FLOAT,
+ GL_FALSE, /* not normalized */
+ sizeof (float) * 2,
+ top_vertices);
+ gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+ /* Paint the bottom half in blue */
+ gles2->glUniform4f (data->color_location,
+ 0.0f, 0.0f, 1.0f, 1.0f);
+ gles2->glVertexAttribPointer (data->pos_location,
+ 2, /* size */
+ GL_FLOAT,
+ GL_FALSE, /* not normalized */
+ sizeof (float) * 2,
+ bottom_vertices);
+ gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+}
+
+static void
+paint_viewport (PaintData *data)
+{
+ const CoglGLES2Vtable *gles2 = data->gles2;
+ int viewport[4];
+
+ /* Vertices to fill the entire framebuffer */
+ static const float vertices[] =
+ {
+ -1.0f, -1.0f,
+ 1.0f, -1.0f,
+ -1.0f, 1.0f,
+ 1.0f, 1.0f
+ };
+
+ gles2->glEnableVertexAttribArray (data->pos_location);
+ gles2->glVertexAttribPointer (data->pos_location,
+ 2, /* size */
+ GL_FLOAT,
+ GL_FALSE, /* not normalized */
+ sizeof (float) * 2,
+ vertices);
+
+ /* Paint the top half in red */
+ gles2->glViewport (0, data->fb_height / 2,
+ data->fb_width, data->fb_height / 2);
+ gles2->glUniform4f (data->color_location,
+ 1.0f, 0.0f, 0.0f, 1.0f);
+ gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+ /* Paint the bottom half in blue */
+ gles2->glViewport (0, 0, data->fb_width, data->fb_height / 2);
+ gles2->glUniform4f (data->color_location,
+ 0.0f, 0.0f, 1.0f, 1.0f);
+ gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+ gles2->glGetIntegerv (GL_VIEWPORT, viewport);
+ g_assert_cmpint (viewport[0], ==, 0.0f);
+ g_assert_cmpint (viewport[1], ==, 0.0f);
+ g_assert_cmpint (viewport[2], ==, data->fb_width);
+ g_assert_cmpint (viewport[3], ==, data->fb_height / 2);
+}
+
+static void
+paint_scissor (PaintData *data)
+{
+ const CoglGLES2Vtable *gles2 = data->gles2;
+ float scissor[4];
+
+ gles2->glEnable (GL_SCISSOR_TEST);
+
+ /* Paint the top half in red */
+ gles2->glScissor (0, data->fb_height / 2,
+ data->fb_width, data->fb_height / 2);
+ gles2->glClearColor (1.0, 0.0, 0.0, 1.0);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ /* Paint the bottom half in blue */
+ gles2->glScissor (0, 0, data->fb_width, data->fb_height / 2);
+ gles2->glClearColor (0.0, 0.0, 1.0, 1.0);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ gles2->glGetFloatv (GL_SCISSOR_BOX, scissor);
+ g_assert_cmpfloat (scissor[0], ==, 0.0f);
+ g_assert_cmpfloat (scissor[1], ==, 0.0f);
+ g_assert_cmpfloat (scissor[2], ==, data->fb_width);
+ g_assert_cmpfloat (scissor[3], ==, data->fb_height / 2);
+}
+
+static void
+paint_cull (PaintData *data)
+{
+ const CoglGLES2Vtable *gles2 = data->gles2;
+ GLint front_face;
+ int i;
+
+ gles2->glEnableVertexAttribArray (data->pos_location);
+ gles2->glEnable (GL_CULL_FACE);
+
+ /* First time round we'll use GL_CCW as the front face so that the
+ * bottom quad will be culled */
+ gles2->glFrontFace (GL_CCW);
+ gles2->glUniform4f (data->color_location,
+ 1.0f, 0.0f, 0.0f, 1.0f);
+
+ gles2->glGetIntegerv (GL_FRONT_FACE, &front_face);
+ g_assert_cmpint (front_face, ==, GL_CCW);
+
+ for (i = 0; i < 2; i++)
+ {
+ /* Paint both quads in the same color. One of these will be
+ * culled */
+ gles2->glVertexAttribPointer (data->pos_location,
+ 2, /* size */
+ GL_FLOAT,
+ GL_FALSE, /* not normalized */
+ sizeof (float) * 2,
+ top_vertices);
+ gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+ gles2->glVertexAttribPointer (data->pos_location,
+ 2, /* size */
+ GL_FLOAT,
+ GL_FALSE, /* not normalized */
+ sizeof (float) * 2,
+ bottom_vertices);
+ gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+ /* Second time round we'll use GL_CW as the front face so that the
+ * top quad will be culled */
+ gles2->glFrontFace (GL_CW);
+ gles2->glUniform4f (data->color_location,
+ 0.0f, 0.0f, 1.0f, 1.0f);
+
+ gles2->glGetIntegerv (GL_FRONT_FACE, &front_face);
+ g_assert_cmpint (front_face, ==, GL_CW);
+ }
+}
+
+static void
+verify_read_pixels (const PaintData *data)
+{
+ int stride = data->fb_width * 4;
+ uint8_t *buf = g_malloc (data->fb_height * stride);
+
+ data->gles2->glReadPixels (0, 0, /* x/y */
+ data->fb_width, data->fb_height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ buf);
+
+ /* In GL, the lines earlier in the buffer are the bottom */
+ /* Bottom should be blue */
+ test_utils_compare_pixel (buf + data->fb_width / 2 * 4 +
+ data->fb_height / 4 * stride,
+ 0x0000ffff);
+ /* Top should be red */
+ test_utils_compare_pixel (buf + data->fb_width / 2 * 4 +
+ data->fb_height * 3 / 4 * stride,
+ 0xff0000ff);
+
+ g_free (buf);
+}
+
+void
+test_gles2_context_fbo (void)
+{
+ static const char vertex_shader_source[] =
+ "attribute vec2 pos;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " gl_Position = vec4 (pos, 0.0, 1.0);\n"
+ "}\n";
+ static const char fragment_shader_source[] =
+ "precision mediump float;\n"
+ "uniform vec4 color;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+ static const PaintMethod paint_methods[] =
+ {
+ paint_quads,
+ paint_viewport,
+ paint_scissor,
+ paint_cull
+ };
+ int i;
+ PaintData data;
+
+ data.fb_width = cogl_framebuffer_get_width (test_fb);
+ data.fb_height = cogl_framebuffer_get_height (test_fb);
+
+ for (i = 0; i < G_N_ELEMENTS (paint_methods); i++)
+ {
+ CoglTexture *offscreen_texture;
+ CoglOffscreen *offscreen;
+ CoglPipeline *pipeline;
+ CoglGLES2Context *gles2_ctx;
+ GLuint program;
+ CoglError *error = NULL;
+
+ create_gles2_context (&offscreen_texture,
+ &offscreen,
+ &pipeline,
+ &gles2_ctx,
+ &data.gles2);
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ offscreen,
+ offscreen,
+ &error))
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+
+ program = create_program (data.gles2,
+ vertex_shader_source,
+ fragment_shader_source);
+
+ data.gles2->glClearColor (1.0, 1.0, 0.0, 1.0);
+ data.gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ data.gles2->glUseProgram (program);
+
+ data.color_location = data.gles2->glGetUniformLocation (program, "color");
+ if (data.color_location == -1)
+ g_error ("Couldn't find ‘color’ uniform");
+
+ data.pos_location = data.gles2->glGetAttribLocation (program, "pos");
+ if (data.pos_location == -1)
+ g_error ("Couldn't find ‘pos’ attribute");
+
+ paint_methods[i] (&data);
+
+ verify_read_pixels (&data);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ cogl_object_unref (offscreen);
+ cogl_object_unref (gles2_ctx);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1.0f, 1.0f,
+ 1.0f, -1.0f);
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (offscreen_texture);
+
+ /* Top half of the framebuffer should be red */
+ test_utils_check_pixel (test_fb,
+ data.fb_width / 2, data.fb_height / 4,
+ 0xff0000ff);
+ /* Bottom half should be blue */
+ test_utils_check_pixel (test_fb,
+ data.fb_width / 2, data.fb_height * 3 / 4,
+ 0x0000ffff);
+ }
+}
+
+/* Position to draw a rectangle in. The top half of this rectangle
+ * will be red, and the bottom will be blue */
+#define RECTANGLE_DRAW_X 10
+#define RECTANGLE_DRAW_Y 15
+
+/* Position to copy the rectangle to in the destination texture */
+#define RECTANGLE_COPY_X 110
+#define RECTANGLE_COPY_Y 115
+
+#define RECTANGLE_WIDTH 30
+#define RECTANGLE_HEIGHT 40
+
+static void
+verify_region (const CoglGLES2Vtable *gles2,
+ int x,
+ int y,
+ int width,
+ int height,
+ uint32_t expected_pixel)
+{
+ uint8_t *buf, *p;
+
+ buf = g_malloc (width * height * 4);
+
+ gles2->glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buf);
+
+ for (p = buf + width * height * 4; p > buf; p -= 4)
+ test_utils_compare_pixel (p - 4, expected_pixel);
+
+ g_free (buf);
+}
+
+void
+test_gles2_context_copy_tex_image (void)
+{
+ static const char vertex_shader_source[] =
+ "attribute vec2 pos;\n"
+ "attribute vec2 tex_coord_attrib;\n"
+ "varying vec2 tex_coord_varying;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " gl_Position = vec4 (pos, 0.0, 1.0);\n"
+ " tex_coord_varying = tex_coord_attrib;\n"
+ "}\n";
+ static const char fragment_shader_source[] =
+ "precision mediump float;\n"
+ "varying vec2 tex_coord_varying;\n"
+ "uniform sampler2D tex;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " gl_FragColor = texture2D (tex, tex_coord_varying);\n"
+ "}\n";
+ static const float verts[] =
+ {
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f
+ };
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ CoglTexture *offscreen_texture;
+ CoglOffscreen *offscreen;
+ CoglPipeline *pipeline;
+ CoglGLES2Context *gles2_ctx;
+ const CoglGLES2Vtable *gles2;
+ CoglError *error = NULL;
+ GLuint tex;
+ GLint tex_uniform_location;
+ GLint pos_location;
+ GLint tex_coord_location;
+ GLuint program;
+
+ create_gles2_context (&offscreen_texture,
+ &offscreen,
+ &pipeline,
+ &gles2_ctx,
+ &gles2);
+
+ if (!cogl_push_gles2_context (test_ctx,
+ gles2_ctx,
+ offscreen,
+ offscreen,
+ &error))
+ g_error ("Failed to push gles2 context: %s\n", error->message);
+
+ gles2->glClearColor (1.0, 1.0, 0.0, 1.0);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ /* Draw a rectangle using clear and the scissor so that we don't
+ * have to create a shader */
+ gles2->glEnable (GL_SCISSOR_TEST);
+
+ /* Top half red */
+ gles2->glScissor (RECTANGLE_DRAW_X,
+ RECTANGLE_DRAW_Y + RECTANGLE_HEIGHT / 2,
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT / 2);
+ gles2->glClearColor (1.0, 0.0, 0.0, 1.0);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+ /* Bottom half blue */
+ gles2->glScissor (RECTANGLE_DRAW_X,
+ RECTANGLE_DRAW_Y,
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT / 2);
+ gles2->glClearColor (0.0, 0.0, 1.0, 1.0);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ /* Draw where the rectangle would be if the coordinates were flipped
+ * in white to make it obvious that that is the problem if the
+ * assertion fails */
+ gles2->glScissor (RECTANGLE_DRAW_X,
+ fb_width - (RECTANGLE_DRAW_Y + RECTANGLE_HEIGHT),
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT);
+ gles2->glClearColor (1.0, 1.0, 1.0, 1.0);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ gles2->glDisable (GL_SCISSOR_TEST);
+
+ /* Create a texture */
+ gles2->glGenTextures (1, &tex);
+ gles2->glBindTexture (GL_TEXTURE_2D, tex);
+ gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ gles2->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ /* Copy the entire framebuffer into the texture */
+ gles2->glCopyTexImage2D (GL_TEXTURE_2D,
+ 0, /* level */
+ GL_RGBA,
+ 0, 0, /* x/y */
+ fb_width, fb_height,
+ 0 /* border */);
+
+ /* Copy the rectangle into another part of the texture */
+ gles2->glCopyTexSubImage2D (GL_TEXTURE_2D,
+ 0, /* level */
+ RECTANGLE_COPY_X,
+ RECTANGLE_COPY_Y,
+ RECTANGLE_DRAW_X,
+ RECTANGLE_DRAW_Y,
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT);
+
+ /* Clear the framebuffer to make the test more thorough */
+ gles2->glClearColor (1.0, 1.0, 0.0, 1.0);
+ gles2->glClear (GL_COLOR_BUFFER_BIT);
+
+ /* Create a program to render the texture */
+ program = create_program (gles2,
+ vertex_shader_source,
+ fragment_shader_source);
+
+ pos_location =
+ gles2->glGetAttribLocation (program, "pos");
+ if (pos_location == -1)
+ g_error ("Couldn't find ‘pos’ attribute");
+
+ tex_coord_location =
+ gles2->glGetAttribLocation (program, "tex_coord_attrib");
+ if (tex_coord_location == -1)
+ g_error ("Couldn't find ‘tex_coord_attrib’ attribute");
+
+ tex_uniform_location =
+ gles2->glGetUniformLocation (program, "tex");
+ if (tex_uniform_location == -1)
+ g_error ("Couldn't find ‘tex’ uniform");
+
+ gles2->glUseProgram (program);
+
+ gles2->glUniform1i (tex_uniform_location, 0);
+
+ /* Render the texture to fill the framebuffer */
+ gles2->glEnableVertexAttribArray (pos_location);
+ gles2->glVertexAttribPointer (pos_location,
+ 2, /* n_components */
+ GL_FLOAT,
+ FALSE, /* normalized */
+ sizeof (float) * 4,
+ verts);
+ gles2->glEnableVertexAttribArray (tex_coord_location);
+ gles2->glVertexAttribPointer (tex_coord_location,
+ 2, /* n_components */
+ GL_FLOAT,
+ FALSE, /* normalized */
+ sizeof (float) * 4,
+ verts + 2);
+
+ gles2->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+ /* Verify top of drawn rectangle is red */
+ verify_region (gles2,
+ RECTANGLE_DRAW_X,
+ RECTANGLE_DRAW_Y + RECTANGLE_HEIGHT / 2,
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT / 2,
+ 0xff0000ff);
+ /* Verify bottom of drawn rectangle is blue */
+ verify_region (gles2,
+ RECTANGLE_DRAW_X,
+ RECTANGLE_DRAW_Y,
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT / 2,
+ 0x0000ffff);
+ /* Verify top of copied rectangle is red */
+ verify_region (gles2,
+ RECTANGLE_COPY_X,
+ RECTANGLE_COPY_Y + RECTANGLE_HEIGHT / 2,
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT / 2,
+ 0xff0000ff);
+ /* Verify bottom of copied rectangle is blue */
+ verify_region (gles2,
+ RECTANGLE_COPY_X,
+ RECTANGLE_COPY_Y,
+ RECTANGLE_WIDTH,
+ RECTANGLE_HEIGHT / 2,
+ 0x0000ffff);
+
+ cogl_pop_gles2_context (test_ctx);
+
+ cogl_object_unref (offscreen);
+ cogl_object_unref (gles2_ctx);
+ cogl_object_unref (pipeline);
+ cogl_object_unref (offscreen_texture);
+}
diff --git a/cogl/tests/conform/test-just-vertex-shader.c b/cogl/tests/conform/test-just-vertex-shader.c
new file mode 100644
index 000000000..60fcaf74c
--- /dev/null
+++ b/cogl/tests/conform/test-just-vertex-shader.c
@@ -0,0 +1,205 @@
+#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0
+
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+ int paddiing;
+} TestState;
+
+static CoglTexture *
+create_dummy_texture (void)
+{
+ /* Create a dummy 1x1 green texture to replace the color from the
+ vertex shader */
+ static const uint8_t data[4] = { 0x00, 0xff, 0x00, 0xff };
+
+ return test_utils_texture_new_from_data (test_ctx,
+ 1, 1, /* size */
+ TEST_UTILS_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGB_888,
+ 4, /* rowstride */
+ data);
+}
+
+static void
+paint_legacy (TestState *state)
+{
+ CoglHandle material = cogl_material_new ();
+ CoglTexture *tex;
+ CoglColor color;
+ CoglError *error = NULL;
+ CoglHandle shader, program;
+
+ cogl_color_init_from_4ub (&color, 0, 0, 0, 255);
+ cogl_clear (&color, COGL_BUFFER_BIT_COLOR);
+
+ /* Set the primary vertex color as red */
+ cogl_color_set_from_4ub (&color, 0xff, 0x00, 0x00, 0xff);
+ cogl_material_set_color (material, &color);
+
+ /* Override the vertex color in the texture environment with a
+ constant green color provided by a texture */
+ tex = create_dummy_texture ();
+ cogl_material_set_layer (material, 0, tex);
+ cogl_object_unref (tex);
+ if (!cogl_material_set_layer_combine (material, 0,
+ "RGBA=REPLACE(TEXTURE)",
+ &error))
+ {
+ g_warning ("Error setting layer combine: %s", error->message);
+ g_assert_not_reached ();
+ }
+
+ /* Set up a dummy vertex shader that does nothing but the usual
+ fixed function transform */
+ shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX);
+ cogl_shader_source (shader,
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_position_out = "
+ "cogl_modelview_projection_matrix * "
+ "cogl_position_in;\n"
+ " cogl_color_out = cogl_color_in;\n"
+ " cogl_tex_coord_out[0] = cogl_tex_coord_in;\n"
+ "}\n");
+ cogl_shader_compile (shader);
+ if (!cogl_shader_is_compiled (shader))
+ {
+ char *log = cogl_shader_get_info_log (shader);
+ g_warning ("Shader compilation failed:\n%s", log);
+ g_free (log);
+ g_assert_not_reached ();
+ }
+
+ program = cogl_create_program ();
+ cogl_program_attach_shader (program, shader);
+ cogl_program_link (program);
+
+ cogl_handle_unref (shader);
+
+ /* Draw something using the material */
+ cogl_set_source (material);
+ cogl_rectangle (0, 0, 50, 50);
+
+ /* Draw it again using the program. It should look exactly the same */
+ cogl_program_use (program);
+ cogl_rectangle (50, 0, 100, 50);
+ cogl_program_use (COGL_INVALID_HANDLE);
+
+ cogl_handle_unref (material);
+ cogl_handle_unref (program);
+}
+
+static void
+paint (TestState *state)
+{
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ CoglTexture *tex;
+ CoglColor color;
+ CoglError *error = NULL;
+ CoglHandle shader, program;
+
+ cogl_color_init_from_4ub (&color, 0, 0, 0, 255);
+ cogl_clear (&color, COGL_BUFFER_BIT_COLOR);
+
+ /* Set the primary vertex color as red */
+ cogl_color_set_from_4ub (&color, 0xff, 0x00, 0x00, 0xff);
+ cogl_pipeline_set_color (pipeline, &color);
+
+ /* Override the vertex color in the texture environment with a
+ constant green color provided by a texture */
+ tex = create_dummy_texture ();
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+ cogl_object_unref (tex);
+ if (!cogl_pipeline_set_layer_combine (pipeline, 0,
+ "RGBA=REPLACE(TEXTURE)",
+ &error))
+ {
+ g_warning ("Error setting layer combine: %s", error->message);
+ g_assert_not_reached ();
+ }
+
+ /* Set up a dummy vertex shader that does nothing but the usual
+ fixed function transform */
+ shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX);
+ cogl_shader_source (shader,
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_position_out = "
+ "cogl_modelview_projection_matrix * "
+ "cogl_position_in;\n"
+ " cogl_color_out = cogl_color_in;\n"
+ " cogl_tex_coord_out[0] = cogl_tex_coord_in;\n"
+ "}\n");
+ cogl_shader_compile (shader);
+ if (!cogl_shader_is_compiled (shader))
+ {
+ char *log = cogl_shader_get_info_log (shader);
+ g_warning ("Shader compilation failed:\n%s", log);
+ g_free (log);
+ g_assert_not_reached ();
+ }
+
+ program = cogl_create_program ();
+ cogl_program_attach_shader (program, shader);
+ cogl_program_link (program);
+
+ cogl_handle_unref (shader);
+
+ /* Draw something without the program */
+ cogl_set_source (pipeline);
+ cogl_rectangle (0, 0, 50, 50);
+
+ /* Draw it again using the program. It should look exactly the same */
+ cogl_pipeline_set_user_program (pipeline, program);
+ cogl_handle_unref (program);
+
+ cogl_rectangle (50, 0, 100, 50);
+ cogl_pipeline_set_user_program (pipeline, COGL_INVALID_HANDLE);
+
+ cogl_object_unref (pipeline);
+}
+
+static void
+validate_result (CoglFramebuffer *framebuffer)
+{
+ /* Non-shader version */
+ test_utils_check_pixel (framebuffer, 25, 25, 0x00ff0000);
+ /* Shader version */
+ test_utils_check_pixel (framebuffer, 75, 25, 0x00ff0000);
+}
+
+void
+test_just_vertex_shader (void)
+{
+ TestState state;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ /* XXX: we have to push/pop a framebuffer since this test currently
+ * uses the legacy cogl_rectangle() api. */
+ cogl_push_framebuffer (test_fb);
+
+ paint_legacy (&state);
+ validate_result (test_fb);
+
+ paint (&state);
+ validate_result (test_fb);
+
+ cogl_pop_framebuffer ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-layer-remove.c b/cogl/tests/conform/test-layer-remove.c
new file mode 100644
index 000000000..de1efeccd
--- /dev/null
+++ b/cogl/tests/conform/test-layer-remove.c
@@ -0,0 +1,145 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+#define TEST_SQUARE_SIZE 10
+
+static CoglPipeline *
+create_two_layer_pipeline (void)
+{
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ CoglColor color;
+
+ /* The pipeline is initially black */
+ cogl_pipeline_set_color4ub (pipeline, 0, 0, 0, 255);
+
+ /* The first layer adds a full red component */
+ cogl_color_init_from_4ub (&color, 255, 0, 0, 255);
+ cogl_pipeline_set_layer_combine_constant (pipeline, 0, &color);
+ cogl_pipeline_set_layer_combine (pipeline,
+ 0, /* layer_num */
+ "RGBA=ADD(PREVIOUS,CONSTANT)",
+ NULL);
+
+ /* The second layer adds a full green component */
+ cogl_color_init_from_4ub (&color, 0, 255, 0, 255);
+ cogl_pipeline_set_layer_combine_constant (pipeline, 1, &color);
+ cogl_pipeline_set_layer_combine (pipeline,
+ 1, /* layer_num */
+ "RGBA=ADD(PREVIOUS,CONSTANT)",
+ NULL);
+
+ return pipeline;
+}
+
+static void
+test_color (CoglPipeline *pipeline,
+ uint32_t color,
+ int pos)
+{
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ pos * TEST_SQUARE_SIZE,
+ 0,
+ pos * TEST_SQUARE_SIZE + TEST_SQUARE_SIZE,
+ TEST_SQUARE_SIZE);
+ test_utils_check_pixel (test_fb,
+ pos * TEST_SQUARE_SIZE + TEST_SQUARE_SIZE / 2,
+ TEST_SQUARE_SIZE / 2,
+ color);
+}
+
+void
+test_layer_remove (void)
+{
+ CoglPipeline *pipeline0, *pipeline1;
+ CoglColor color;
+ int pos = 0;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ /** TEST 1 **/
+ /* Basic sanity check that the pipeline combines the two colors
+ * together properly */
+ pipeline0 = create_two_layer_pipeline ();
+ test_color (pipeline0, 0xffff00ff, pos++);
+ cogl_object_unref (pipeline0);
+
+ /** TEST 2 **/
+ /* Check that we can remove the second layer */
+ pipeline0 = create_two_layer_pipeline ();
+ cogl_pipeline_remove_layer (pipeline0, 1);
+ test_color (pipeline0, 0xff0000ff, pos++);
+ cogl_object_unref (pipeline0);
+
+ /** TEST 3 **/
+ /* Check that we can remove the first layer */
+ pipeline0 = create_two_layer_pipeline ();
+ cogl_pipeline_remove_layer (pipeline0, 0);
+ test_color (pipeline0, 0x00ff00ff, pos++);
+ cogl_object_unref (pipeline0);
+
+ /** TEST 4 **/
+ /* Check that we can make a copy and remove a layer from the
+ * original pipeline */
+ pipeline0 = create_two_layer_pipeline ();
+ pipeline1 = cogl_pipeline_copy (pipeline0);
+ cogl_pipeline_remove_layer (pipeline0, 1);
+ test_color (pipeline0, 0xff0000ff, pos++);
+ test_color (pipeline1, 0xffff00ff, pos++);
+ cogl_object_unref (pipeline0);
+ cogl_object_unref (pipeline1);
+
+ /** TEST 5 **/
+ /* Check that we can make a copy and remove the second layer from the
+ * new pipeline */
+ pipeline0 = create_two_layer_pipeline ();
+ pipeline1 = cogl_pipeline_copy (pipeline0);
+ cogl_pipeline_remove_layer (pipeline1, 1);
+ test_color (pipeline0, 0xffff00ff, pos++);
+ test_color (pipeline1, 0xff0000ff, pos++);
+ cogl_object_unref (pipeline0);
+ cogl_object_unref (pipeline1);
+
+ /** TEST 6 **/
+ /* Check that we can make a copy and remove the first layer from the
+ * new pipeline */
+ pipeline0 = create_two_layer_pipeline ();
+ pipeline1 = cogl_pipeline_copy (pipeline0);
+ cogl_pipeline_remove_layer (pipeline1, 0);
+ test_color (pipeline0, 0xffff00ff, pos++);
+ test_color (pipeline1, 0x00ff00ff, pos++);
+ cogl_object_unref (pipeline0);
+ cogl_object_unref (pipeline1);
+
+ /** TEST 7 **/
+ /* Check that we can modify a layer in a child pipeline */
+ pipeline0 = create_two_layer_pipeline ();
+ pipeline1 = cogl_pipeline_copy (pipeline0);
+ cogl_color_init_from_4ub (&color, 0, 0, 255, 255);
+ cogl_pipeline_set_layer_combine_constant (pipeline1, 0, &color);
+ test_color (pipeline0, 0xffff00ff, pos++);
+ test_color (pipeline1, 0x00ffffff, pos++);
+ cogl_object_unref (pipeline0);
+ cogl_object_unref (pipeline1);
+
+ /** TEST 8 **/
+ /* Check that we can modify a layer in a child pipeline but then remove it */
+ pipeline0 = create_two_layer_pipeline ();
+ pipeline1 = cogl_pipeline_copy (pipeline0);
+ cogl_color_init_from_4ub (&color, 0, 0, 255, 255);
+ cogl_pipeline_set_layer_combine_constant (pipeline1, 0, &color);
+ cogl_pipeline_remove_layer (pipeline1, 0);
+ test_color (pipeline0, 0xffff00ff, pos++);
+ test_color (pipeline1, 0x00ff00ff, pos++);
+ cogl_object_unref (pipeline0);
+ cogl_object_unref (pipeline1);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-map-buffer-range.c b/cogl/tests/conform/test-map-buffer-range.c
new file mode 100644
index 000000000..e9792405f
--- /dev/null
+++ b/cogl/tests/conform/test-map-buffer-range.c
@@ -0,0 +1,123 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+static uint8_t
+tex_data[2 * 2 * 4] =
+ {
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff
+ };
+
+/* Vertex data for a quad with all of the texture coordinates set to
+ * the top left (red) pixel */
+static CoglVertexP2T2
+vertex_data[4] =
+ {
+ { -1, -1, 0, 0 },
+ { 1, -1, 0, 0 },
+ { -1, 1, 0, 0 },
+ { 1, 1, 0, 0 }
+ };
+
+void
+test_map_buffer_range (void)
+{
+ CoglTexture2D *tex;
+ CoglPipeline *pipeline;
+ int fb_width, fb_height;
+ CoglAttributeBuffer *buffer;
+ CoglVertexP2T2 *data;
+ CoglAttribute *pos_attribute;
+ CoglAttribute *tex_coord_attribute;
+ CoglPrimitive *primitive;
+
+ tex = cogl_texture_2d_new_from_data (test_ctx,
+ 2, 2, /* width/height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 2 * 4, /* rowstride */
+ tex_data,
+ NULL /* error */);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+ cogl_pipeline_set_layer_filters (pipeline,
+ 0, /* layer */
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+ cogl_pipeline_set_layer_wrap_mode (pipeline,
+ 0, /* layer */
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+
+ fb_width = cogl_framebuffer_get_width (test_fb);
+ fb_height = cogl_framebuffer_get_height (test_fb);
+
+ buffer = cogl_attribute_buffer_new (test_ctx,
+ sizeof (vertex_data),
+ vertex_data);
+
+ /* Replace the texture coordinates of the third vertex with the
+ * coordinates for a green texel */
+ data = cogl_buffer_map_range (buffer,
+ sizeof (vertex_data[0]) * 2,
+ sizeof (vertex_data[0]),
+ COGL_BUFFER_ACCESS_WRITE,
+ COGL_BUFFER_MAP_HINT_DISCARD_RANGE,
+ NULL); /* don't catch errors */
+ g_assert (data != NULL);
+
+ data->x = vertex_data[2].x;
+ data->y = vertex_data[2].y;
+ data->s = 1.0f;
+ data->t = 0.0f;
+
+ cogl_buffer_unmap (buffer);
+
+ pos_attribute =
+ cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (vertex_data[0]),
+ offsetof (CoglVertexP2T2, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ tex_coord_attribute =
+ cogl_attribute_new (buffer,
+ "cogl_tex_coord_in",
+ sizeof (vertex_data[0]),
+ offsetof (CoglVertexP2T2, s),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 0, 0, 0, 1);
+
+ primitive =
+ cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLE_STRIP,
+ 4, /* n_vertices */
+ pos_attribute,
+ tex_coord_attribute,
+ NULL);
+ cogl_primitive_draw (primitive, test_fb, pipeline);
+ cogl_object_unref (primitive);
+
+ /* Top left pixel should be the one that is replaced to be green */
+ test_utils_check_pixel (test_fb, 1, 1, 0x00ff00ff);
+ /* The other three corners should be left as red */
+ test_utils_check_pixel (test_fb, fb_width - 2, 1, 0xff0000ff);
+ test_utils_check_pixel (test_fb, 1, fb_height - 2, 0xff0000ff);
+ test_utils_check_pixel (test_fb, fb_width - 2, fb_height - 2, 0xff0000ff);
+
+ cogl_object_unref (buffer);
+ cogl_object_unref (pos_attribute);
+ cogl_object_unref (tex_coord_attribute);
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (tex);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-materials.c b/cogl/tests/conform/test-materials.c
new file mode 100644
index 000000000..69c9c746f
--- /dev/null
+++ b/cogl/tests/conform/test-materials.c
@@ -0,0 +1,253 @@
+#include "config.h"
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-conform-common.h"
+
+static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
+
+#define QUAD_WIDTH 20
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define ALPHA 3
+
+#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
+#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
+#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
+#define MASK_ALPHA(COLOR) (COLOR & 0xff)
+
+typedef struct _TestState
+{
+ ClutterGeometry stage_geom;
+} TestState;
+
+static void
+check_quad (int quad_x, int quad_y, uint32_t color)
+{
+ test_utils_check_pixel (x * QUAD_WIDTH + (QUAD_WIDTH / 2),
+ y * QUAD_WIDTH + (QUAD_WIDTH / 2),
+ color);
+}
+
+static void
+test_material_with_primitives (TestState *state,
+ int x, int y,
+ uint32_t color)
+{
+ CoglTextureVertex verts[4] = {
+ { .x = 0, .y = 0, .z = 0 },
+ { .x = 0, .y = QUAD_WIDTH, .z = 0 },
+ { .x = QUAD_WIDTH, .y = QUAD_WIDTH, .z = 0 },
+ { .x = QUAD_WIDTH, .y = 0, .z = 0 },
+ };
+ CoglHandle vbo;
+
+ cogl_push_matrix ();
+
+ cogl_translate (x * QUAD_WIDTH, y * QUAD_WIDTH, 0);
+
+ cogl_rectangle (0, 0, QUAD_WIDTH, QUAD_WIDTH);
+
+ cogl_translate (0, QUAD_WIDTH, 0);
+ cogl_polygon (verts, 4, FALSE);
+
+ cogl_translate (0, QUAD_WIDTH, 0);
+ vbo = cogl_vertex_buffer_new (4);
+ cogl_vertex_buffer_add (vbo,
+ "gl_Vertex",
+ 2, /* n components */
+ COGL_ATTRIBUTE_TYPE_FLOAT,
+ FALSE, /* normalized */
+ sizeof (CoglTextureVertex), /* stride */
+ verts);
+ cogl_vertex_buffer_draw (vbo,
+ COGL_VERTICES_MODE_TRIANGLE_FAN,
+ 0, /* first */
+ 4); /* count */
+ cogl_handle_unref (vbo);
+
+ cogl_pop_matrix ();
+
+ check_quad (x, y, color);
+ check_quad (x, y+1, color);
+ check_quad (x, y+2, color);
+}
+
+static void
+test_invalid_texture_layers (TestState *state, int x, int y)
+{
+ CoglHandle material = cogl_material_new ();
+
+ /* explicitly create a layer with an invalid handle. This may be desireable
+ * if the user also sets a texture combine string that e.g. refers to a
+ * constant color. */
+ cogl_material_set_layer (material, 0, NULL);
+
+ cogl_set_source (material);
+
+ cogl_handle_unref (material);
+
+ /* We expect a white fallback material to be used */
+ test_material_with_primitives (state, x, y, 0xffffffff);
+}
+
+static void
+test_using_all_layers (TestState *state, int x, int y)
+{
+ CoglHandle material = cogl_material_new ();
+ uint8_t white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
+ uint8_t red_pixel[] = { 0xff, 0x00, 0x00, 0xff };
+ CoglHandle white_texture;
+ CoglHandle red_texture;
+ GLint n_layers;
+ int i;
+
+ /* Create a material that uses the maximum number of layers. All but
+ the last layer will use a solid white texture. The last layer
+ will use a red texture. The layers will all be modulated together
+ so the final fragment should be red. */
+
+ white_texture = test_utils_texture_new_from_data (1, 1, TEST_UTILS_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ COGL_PIXEL_FORMAT_ANY,
+ 4, white_pixel);
+ red_texture = test_utils_texture_new_from_data (1, 1, TEST_UTILS_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ COGL_PIXEL_FORMAT_ANY,
+ 4, red_pixel);
+
+ /* FIXME: Cogl doesn't provide a way to query the maximum number of
+ texture layers so for now we'll just ask GL directly. */
+#ifdef HAVE_COGL_GLES2
+ {
+ GLint n_image_units, n_attribs;
+ /* GLES 2 doesn't have GL_MAX_TEXTURE_UNITS and it uses
+ GL_MAX_TEXTURE_IMAGE_UNITS instead */
+ glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &n_image_units);
+ /* Cogl needs a vertex attrib for each layer to upload the texture
+ coordinates */
+ glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, &n_attribs);
+ /* We can't use two of the attribs because they are used by the
+ position and color */
+ n_attribs -= 2;
+ n_layers = MIN (n_attribs, n_image_units);
+ }
+#else
+ glGetIntegerv (GL_MAX_TEXTURE_UNITS, &n_layers);
+#endif
+ /* FIXME: is this still true? */
+ /* Cogl currently can't cope with more than 32 layers so we'll also
+ limit the maximum to that. */
+ if (n_layers > 32)
+ n_layers = 32;
+
+ for (i = 0; i < n_layers; i++)
+ {
+ cogl_material_set_layer_filters (material, i,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+ cogl_material_set_layer (material, i,
+ i == n_layers - 1 ? red_texture : white_texture);
+ }
+
+ cogl_set_source (material);
+
+ cogl_handle_unref (material);
+ cogl_handle_unref (white_texture);
+ cogl_handle_unref (red_texture);
+
+ /* We expect the final fragment to be red */
+ test_material_with_primitives (state, x, y, 0xff0000ff);
+}
+
+static void
+test_invalid_texture_layers_with_constant_colors (TestState *state,
+ int x, int y)
+{
+ CoglHandle material = cogl_material_new ();
+ CoglColor constant_color;
+
+ /* explicitly create a layer with an invalid handle */
+ cogl_material_set_layer (material, 0, NULL);
+
+ /* ignore the fallback texture on the layer and use a constant color
+ instead */
+ cogl_color_init_from_4ub (&constant_color, 0, 0, 255, 255);
+ cogl_material_set_layer_combine (material, 0,
+ "RGBA=REPLACE(CONSTANT)",
+ NULL);
+ cogl_material_set_layer_combine_constant (material, 0, &constant_color);
+
+ cogl_set_source (material);
+
+ cogl_handle_unref (material);
+
+ /* We expect the final fragments to be green */
+ test_material_with_primitives (state, x, y, 0x0000ffff);
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ test_invalid_texture_layers (state,
+ 0, 0 /* position */
+ );
+ test_invalid_texture_layers_with_constant_colors (state,
+ 1, 0 /* position */
+ );
+ test_using_all_layers (state,
+ 2, 0 /* position */
+ );
+
+ /* Comment this out if you want visual feedback for what this test paints */
+#if 1
+ clutter_main_quit ();
+#endif
+}
+
+static CoglBool
+queue_redraw (void *stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+void
+test_materials (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ ClutterActor *stage;
+ ClutterActor *group;
+ unsigned int idle_source;
+
+ stage = clutter_stage_get_default ();
+
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+ clutter_actor_get_geometry (stage, &state.stage_geom);
+
+ group = clutter_group_new ();
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+
+ /* We force continuous redrawing of the stage, since we need to skip
+ * the first few frames, and we wont be doing anything else that
+ * will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+
+ g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
+
+ clutter_actor_show_all (stage);
+
+ clutter_main ();
+
+ g_source_remove (idle_source);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-multitexture.c b/cogl/tests/conform/test-multitexture.c
new file mode 100644
index 000000000..da38766aa
--- /dev/null
+++ b/cogl/tests/conform/test-multitexture.c
@@ -0,0 +1,206 @@
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-conform-common.h"
+
+static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
+
+#define QUAD_WIDTH 20
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define ALPHA 3
+
+typedef struct _TestState
+{
+ unsigned int padding;
+} TestState;
+
+static void
+assert_region_color (int x,
+ int y,
+ int width,
+ int height,
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t alpha)
+{
+ uint8_t *data = g_malloc0 (width * height * 4);
+ cogl_read_pixels (x, y, width, height,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ data);
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ uint8_t *pixel = &data[y * width * 4 + x * 4];
+#if 1
+ g_assert (pixel[RED] == red &&
+ pixel[GREEN] == green &&
+ pixel[BLUE] == blue);
+#endif
+ }
+ g_free (data);
+}
+
+/* Creates a texture divided into 4 quads with colors arranged as follows:
+ * (The same value are used in all channels for each texel)
+ *
+ * |-----------|
+ * |0x11 |0x00 |
+ * |+ref | |
+ * |-----------|
+ * |0x00 |0x33 |
+ * | |+ref |
+ * |-----------|
+ *
+ *
+ */
+static CoglHandle
+make_texture (guchar ref)
+{
+ int x;
+ int y;
+ guchar *tex_data, *p;
+ CoglHandle tex;
+ guchar val;
+
+ tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 16);
+
+ for (y = 0; y < QUAD_WIDTH * 2; y++)
+ for (x = 0; x < QUAD_WIDTH * 2; x++)
+ {
+ p = tex_data + (QUAD_WIDTH * 8 * y) + x * 4;
+ if (x < QUAD_WIDTH && y < QUAD_WIDTH)
+ val = 0x11 + ref;
+ else if (x >= QUAD_WIDTH && y >= QUAD_WIDTH)
+ val = 0x33 + ref;
+ else
+ val = 0x00;
+ p[0] = p[1] = p[2] = p[3] = val;
+ }
+
+ /* Note: we don't use COGL_PIXEL_FORMAT_ANY for the internal format here
+ * since we don't want to allow Cogl to premultiply our data. */
+ tex = test_utils_texture_new_from_data (QUAD_WIDTH * 2,
+ QUAD_WIDTH * 2,
+ TEST_UTILS_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ QUAD_WIDTH * 8,
+ tex_data);
+
+ g_free (tex_data);
+
+ return tex;
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ CoglHandle tex0, tex1;
+ CoglHandle material;
+ CoglBool status;
+ CoglError *error = NULL;
+ float tex_coords[] = {
+ 0, 0, 0.5, 0.5, /* tex0 */
+ 0.5, 0.5, 1, 1 /* tex1 */
+ };
+
+ tex0 = make_texture (0x00);
+ tex1 = make_texture (0x11);
+
+ material = cogl_material_new ();
+
+ /* An arbitrary color which should be replaced by the first texture layer */
+ cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80);
+ cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
+
+ cogl_material_set_layer (material, 0, tex0);
+ cogl_material_set_layer_combine (material, 0,
+ "RGBA = REPLACE (TEXTURE)", NULL);
+ /* We'll use nearest filtering mode on the textures, otherwise the
+ edge of the quad can pull in texels from the neighbouring
+ quarters of the texture due to imprecision */
+ cogl_material_set_layer_filters (material, 0,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+
+ cogl_material_set_layer (material, 1, tex1);
+ cogl_material_set_layer_filters (material, 1,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+ status = cogl_material_set_layer_combine (material, 1,
+ "RGBA = ADD (PREVIOUS, TEXTURE)",
+ &error);
+ if (!status)
+ {
+ /* It's not strictly a test failure; you need a more capable GPU or
+ * driver to test this texture combine string. */
+ g_debug ("Failed to setup texture combine string "
+ "RGBA = ADD (PREVIOUS, TEXTURE): %s",
+ error->message);
+ }
+
+ cogl_set_source (material);
+ cogl_rectangle_with_multitexture_coords (0, 0, QUAD_WIDTH, QUAD_WIDTH,
+ tex_coords, 8);
+
+ cogl_handle_unref (material);
+ cogl_handle_unref (tex0);
+ cogl_handle_unref (tex1);
+
+ /* See what we got... */
+
+ assert_region_color (0, 0, QUAD_WIDTH, QUAD_WIDTH,
+ 0x55, 0x55, 0x55, 0x55);
+
+ /* Comment this out if you want visual feedback for what this test paints */
+#if 1
+ clutter_main_quit ();
+#endif
+}
+
+static CoglBool
+queue_redraw (void *stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+void
+test_multitexture (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ ClutterActor *stage;
+ ClutterActor *group;
+ unsigned int idle_source;
+
+ stage = clutter_stage_get_default ();
+
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+
+ group = clutter_group_new ();
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+
+ /* We force continuous redrawing incase someone comments out the
+ * clutter_main_quit and wants visual feedback for the test since we
+ * wont be doing anything else that will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+
+ g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
+
+ clutter_actor_show_all (stage);
+
+ clutter_main ();
+
+ g_source_remove (idle_source);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-no-gl-header.c b/cogl/tests/conform/test-no-gl-header.c
new file mode 100644
index 000000000..9618d840e
--- /dev/null
+++ b/cogl/tests/conform/test-no-gl-header.c
@@ -0,0 +1,16 @@
+#undef COGL_COMPILATION
+#include <cogl/cogl.h>
+
+/* If you just include cogl/cogl.h, you shouldn't end up including any
+ GL headers */
+#ifdef GL_TRUE
+#error "Including cogl.h shouldn't be including any GL headers"
+#endif
+
+void test_no_gl_header (void);
+
+void
+test_no_gl_header (void)
+{
+}
+
diff --git a/cogl/tests/conform/test-npot-texture.c b/cogl/tests/conform/test-npot-texture.c
new file mode 100644
index 000000000..85c16c960
--- /dev/null
+++ b/cogl/tests/conform/test-npot-texture.c
@@ -0,0 +1,170 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+/* Non-power-of-two sized texture that should cause slicing */
+#define TEXTURE_SIZE 384
+/* Number of times to split the texture up on each axis */
+#define PARTS 2
+/* The texture is split into four parts, each with a different colour */
+#define PART_SIZE (TEXTURE_SIZE / PARTS)
+
+/* Amount of pixels to skip off the top, bottom, left and right of the
+ texture when reading back the stage */
+#define TEST_INSET 4
+
+/* Size to actually render the texture at */
+#define TEXTURE_RENDER_SIZE TEXTURE_SIZE
+/* The size of a part once rendered */
+#define PART_RENDER_SIZE (TEXTURE_RENDER_SIZE / PARTS)
+
+static const uint32_t corner_colors[PARTS * PARTS] =
+ {
+ /* Top left - red */ 0xff0000ff,
+ /* Top right - green */ 0x00ff00ff,
+ /* Bottom left - blue */ 0x0000ffff,
+ /* Bottom right - yellow */ 0xffff00ff
+ };
+
+static void
+validate_part (int xnum,
+ int ynum,
+ uint32_t color)
+{
+ test_utils_check_region (test_fb,
+ xnum * PART_RENDER_SIZE + TEST_INSET,
+ ynum * PART_RENDER_SIZE + TEST_INSET,
+ PART_RENDER_SIZE - TEST_INSET * 2,
+ PART_RENDER_SIZE - TEST_INSET * 2,
+ color);
+}
+
+static void
+validate_result (void)
+{
+ /* Validate that all four corners of the texture are drawn in the
+ right color */
+ validate_part (0, 0, corner_colors[0]);
+ validate_part (1, 0, corner_colors[1]);
+ validate_part (0, 1, corner_colors[2]);
+ validate_part (1, 1, corner_colors[3]);
+}
+
+static CoglTexture *
+make_texture (void)
+{
+ void *tex_data;
+ uint32_t *p;
+ CoglTexture *tex;
+ int partx, party, width, height;
+
+ p = tex_data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4);
+
+ /* Make a texture with a different color for each part */
+ for (party = 0; party < PARTS; party++)
+ {
+ height = (party < PARTS - 1
+ ? PART_SIZE
+ : TEXTURE_SIZE - PART_SIZE * (PARTS - 1));
+
+ for (partx = 0; partx < PARTS; partx++)
+ {
+ uint32_t color = corner_colors[party * PARTS + partx];
+ width = (partx < PARTS - 1
+ ? PART_SIZE
+ : TEXTURE_SIZE - PART_SIZE * (PARTS - 1));
+
+ while (width-- > 0)
+ *(p++) = GUINT32_TO_BE (color);
+ }
+
+ while (--height > 0)
+ {
+ memcpy (p, p - TEXTURE_SIZE, TEXTURE_SIZE * 4);
+ p += TEXTURE_SIZE;
+ }
+ }
+
+ tex = test_utils_texture_new_from_data (test_ctx,
+ TEXTURE_SIZE,
+ TEXTURE_SIZE,
+ TEST_UTILS_TEXTURE_NO_ATLAS,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ TEXTURE_SIZE * 4,
+ tex_data);
+
+ g_free (tex_data);
+
+ if (cogl_test_verbose ())
+ {
+ if (cogl_texture_is_sliced (tex))
+ g_print ("Texture is sliced\n");
+ else
+ g_print ("Texture is not sliced\n");
+ }
+
+ /* The texture should be sliced unless NPOTs are supported */
+ g_assert (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT)
+ ? !cogl_texture_is_sliced (tex)
+ : cogl_texture_is_sliced (tex));
+
+ return tex;
+}
+
+static void
+paint (void)
+{
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ CoglTexture *texture = make_texture ();
+ int y, x;
+
+ cogl_pipeline_set_layer_texture (pipeline, 0, texture);
+
+ /* Just render the texture in the top left corner */
+ /* Render the texture using four separate rectangles */
+ for (y = 0; y < 2; y++)
+ for (x = 0; x < 2; x++)
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ x * TEXTURE_RENDER_SIZE / 2,
+ y * TEXTURE_RENDER_SIZE / 2,
+ (x + 1) *
+ TEXTURE_RENDER_SIZE / 2,
+ (y + 1) *
+ TEXTURE_RENDER_SIZE / 2,
+ x / 2.0f,
+ y / 2.0f,
+ (x + 1) / 2.0f,
+ (y + 1) / 2.0f);
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (texture);
+}
+
+void
+test_npot_texture (void)
+{
+ if (cogl_test_verbose ())
+ {
+ if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_NPOT))
+ g_print ("NPOT textures are supported\n");
+ else
+ g_print ("NPOT textures are not supported\n");
+ }
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ paint ();
+ validate_result ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-object.c b/cogl/tests/conform/test-object.c
new file mode 100644
index 000000000..0a6dcab62
--- /dev/null
+++ b/cogl/tests/conform/test-object.c
@@ -0,0 +1,86 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-conform-common.h"
+
+CoglUserDataKey private_key0;
+CoglUserDataKey private_key1;
+CoglUserDataKey private_key2;
+
+static int user_data0;
+static int user_data1;
+static int user_data2;
+
+static int destroy0_count = 0;
+static int destroy1_count = 0;
+static int destroy2_count = 0;
+
+static void
+destroy0_cb (void *user_data)
+{
+ g_assert (user_data == &user_data0);
+ destroy0_count++;
+}
+
+static void
+destroy1_cb (void *user_data)
+{
+ g_assert (user_data == &user_data1);
+ destroy1_count++;
+}
+
+static void
+destroy2_cb (void *user_data)
+{
+ g_assert (user_data == &user_data2);
+ destroy2_count++;
+}
+
+void
+test_object (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ CoglPath *path;
+
+ /* Assuming that COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES == 2
+ * test associating 2 pointers to private data with an object */
+ cogl_path_new ();
+ path = cogl_get_path ();
+
+ cogl_object_set_user_data (COGL_OBJECT (path),
+ &private_key0,
+ &user_data0,
+ destroy0_cb);
+
+ cogl_object_set_user_data (COGL_OBJECT (path),
+ &private_key1,
+ &user_data1,
+ destroy1_cb);
+
+ cogl_object_set_user_data (COGL_OBJECT (path),
+ &private_key2,
+ &user_data2,
+ destroy2_cb);
+
+ cogl_object_set_user_data (COGL_OBJECT (path),
+ &private_key1,
+ NULL,
+ destroy1_cb);
+
+ cogl_object_set_user_data (COGL_OBJECT (path),
+ &private_key1,
+ &user_data1,
+ destroy1_cb);
+
+ cogl_object_unref (path);
+
+ g_assert_cmpint (destroy0_count, ==, 1);
+ g_assert_cmpint (destroy1_count, ==, 2);
+ g_assert_cmpint (destroy2_count, ==, 1);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-offscreen.c b/cogl/tests/conform/test-offscreen.c
new file mode 100644
index 000000000..9bc14b7da
--- /dev/null
+++ b/cogl/tests/conform/test-offscreen.c
@@ -0,0 +1,199 @@
+#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0
+
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+typedef struct _TestState
+{
+ int fb_width;
+ int fb_height;
+} TestState;
+
+static void
+check_quadrant (TestState *state,
+ int qx,
+ int qy,
+ uint32_t expected_rgba)
+{
+ /* The quadrants are all stuffed into the top right corner of the
+ framebuffer */
+ int x = state->fb_width * qx / 4 + state->fb_width / 2;
+ int y = state->fb_height * qy / 4;
+ int width = state->fb_width / 4;
+ int height = state->fb_height / 4;
+
+ /* Subtract a two-pixel gap around the edges to allow some rounding
+ differences */
+ x += 2;
+ y += 2;
+ width -= 4;
+ height -= 4;
+
+ test_utils_check_region (test_fb, x, y, width, height, expected_rgba);
+}
+
+static void
+test_paint (TestState *state)
+{
+ CoglTexture2D *tex_2d;
+ CoglTexture *tex;
+ CoglOffscreen *offscreen;
+
+ tex_2d = cogl_texture_2d_new_with_size (test_ctx,
+ state->fb_width,
+ state->fb_height);
+ tex = tex_2d;
+
+ offscreen = cogl_offscreen_new_with_texture (tex);
+
+ /* Set a scale and translate transform on the window framebuffer
+ * before switching to the offscreen framebuffer so we can verify it
+ * gets restored when we switch back
+ *
+ * The test is going to draw a grid of 4 colors to a texture which
+ * we subsequently draw to the window with a fullscreen rectangle.
+ * This transform will flip the texture left to right, scale it to a
+ * quarter of the window size and slide it to the top right of the
+ * window.
+ */
+ cogl_push_matrix ();
+ cogl_translate (0.5, 0.5, 0);
+ cogl_scale (-0.5, 0.5, 1);
+
+ cogl_push_framebuffer (offscreen);
+
+ /* Cogl should release the last reference when we call cogl_pop_framebuffer()
+ */
+ cogl_object_unref (offscreen);
+
+ /* Setup something other than the identity matrix for the modelview so we can
+ * verify it gets restored when we call cogl_pop_framebuffer () */
+ cogl_scale (2, 2, 1);
+
+ /* red, top left */
+ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
+ cogl_rectangle (-0.5, 0.5, 0, 0);
+ /* green, top right */
+ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
+ cogl_rectangle (0, 0.5, 0.5, 0);
+ /* blue, bottom left */
+ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
+ cogl_rectangle (-0.5, 0, 0, -0.5);
+ /* white, bottom right */
+ cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
+ cogl_rectangle (0, 0, 0.5, -0.5);
+
+ cogl_pop_framebuffer ();
+
+ cogl_set_source_texture (tex);
+ cogl_rectangle (-1, 1, 1, -1);
+
+ cogl_object_unref (tex_2d);
+
+ cogl_pop_matrix ();
+
+ /* NB: The texture is drawn flipped horizontally and scaled to fit in the
+ * top right corner of the window. */
+
+ /* red, top right */
+ check_quadrant (state, 1, 0, 0xff0000ff);
+ /* green, top left */
+ check_quadrant (state, 0, 0, 0x00ff00ff);
+ /* blue, bottom right */
+ check_quadrant (state, 1, 1, 0x0000ffff);
+ /* white, bottom left */
+ check_quadrant (state, 0, 1, 0xffffffff);
+}
+
+static void
+test_flush (TestState *state)
+{
+ CoglTexture2D *tex_2d;
+ CoglTexture *tex;
+ CoglOffscreen *offscreen;
+ CoglColor clear_color;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ /* This tests that rendering to a framebuffer and then reading back
+ the contents of the texture will automatically flush the
+ journal */
+
+ tex_2d = cogl_texture_2d_new_with_size (test_ctx,
+ 16, 16); /* width/height */
+ tex = tex_2d;
+
+ offscreen = cogl_offscreen_new_with_texture (tex);
+
+ cogl_push_framebuffer (offscreen);
+
+ cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 255);
+ cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
+
+ cogl_set_source_color4ub (255, 0, 0, 255);
+ cogl_rectangle (-1, -1, 1, 1);
+
+ if (i == 0)
+ /* First time check using read pixels on the offscreen */
+ test_utils_check_region (offscreen,
+ 1, 1, 15, 15, 0xff0000ff);
+ else if (i == 1)
+ {
+ uint8_t data[16 * 4 * 16];
+ int x, y;
+
+ /* Second time try reading back the texture contents */
+ cogl_texture_get_data (tex,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 16 * 4, /* rowstride */
+ data);
+
+ for (y = 1; y < 15; y++)
+ for (x = 1; x < 15; x++)
+ test_utils_compare_pixel (data + x * 4 + y * 16 * 4,
+ 0xff0000ff);
+ }
+
+ cogl_pop_framebuffer ();
+
+ if (i == 2)
+ {
+ /* Third time try drawing the texture to the screen */
+ cogl_set_source_texture (tex);
+ cogl_rectangle (-1, -1, 1, 1);
+ test_utils_check_region (test_fb,
+ 2, 2, /* x/y */
+ state->fb_width - 4,
+ state->fb_height - 4,
+ 0xff0000ff);
+ }
+
+ cogl_object_unref (tex_2d);
+ cogl_object_unref (offscreen);
+ }
+}
+
+void
+test_offscreen (void)
+{
+ TestState state;
+
+ state.fb_width = cogl_framebuffer_get_width (test_fb);
+ state.fb_height = cogl_framebuffer_get_height (test_fb);
+
+ /* XXX: we have to push/pop a framebuffer since this test currently
+ * uses the legacy cogl_rectangle() api. */
+ cogl_push_framebuffer (test_fb);
+ test_paint (&state);
+ test_flush (&state);
+ cogl_pop_framebuffer ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-path-clip.c b/cogl/tests/conform/test-path-clip.c
new file mode 100644
index 000000000..95ad00b96
--- /dev/null
+++ b/cogl/tests/conform/test-path-clip.c
@@ -0,0 +1,68 @@
+#define COGL_ENABLE_EXPERIMENTAL_2_0_API
+#include <cogl/cogl.h>
+#include <cogl-path/cogl-path.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+void
+test_path_clip (void)
+{
+ CoglPath *path;
+ CoglPipeline *pipeline;
+ int fb_width, fb_height;
+
+ fb_width = cogl_framebuffer_get_width (test_fb);
+ fb_height = cogl_framebuffer_get_height (test_fb);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, fb_width, fb_height, -1, 100);
+
+ path = cogl_path_new ();
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 1.0f, 0.0f, 0.0f, 1.0f);
+
+ /* Make an L-shape with the top right corner left untouched */
+ cogl_path_move_to (path, 0, fb_height);
+ cogl_path_line_to (path, fb_width, fb_height);
+ cogl_path_line_to (path, fb_width, fb_height / 2);
+ cogl_path_line_to (path, fb_width / 2, fb_height / 2);
+ cogl_path_line_to (path, fb_width / 2, 0);
+ cogl_path_line_to (path, 0, 0);
+ cogl_path_close (path);
+
+ cogl_framebuffer_push_path_clip (test_fb, path);
+
+ /* Try to fill the framebuffer with a blue rectangle. This should be
+ * clipped to leave the top right quadrant as is */
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_color4ub (pipeline, 0, 0, 255, 255);
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ 0, 0, fb_width, fb_height);
+
+ cogl_framebuffer_pop_clip (test_fb);
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (path);
+
+ /* Check each of the four quadrants */
+ test_utils_check_pixel (test_fb,
+ fb_width / 4, fb_height / 4,
+ 0x0000ffff);
+ test_utils_check_pixel (test_fb,
+ fb_width * 3 / 4, fb_height / 4,
+ 0xff0000ff);
+ test_utils_check_pixel (test_fb,
+ fb_width / 4, fb_height * 3 / 4,
+ 0x0000ffff);
+ test_utils_check_pixel (test_fb,
+ fb_width * 3 / 4, fb_height * 3 / 4,
+ 0x0000ffff);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-path.c b/cogl/tests/conform/test-path.c
new file mode 100644
index 000000000..11f7f1583
--- /dev/null
+++ b/cogl/tests/conform/test-path.c
@@ -0,0 +1,215 @@
+#define COGL_ENABLE_EXPERIMENTAL_2_0_API
+#include <cogl/cogl.h>
+#include <cogl-path/cogl-path.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define BLOCK_SIZE 16
+
+/* Number of pixels at the border of a block quadrant to skip when verifying */
+#define TEST_INSET 1
+
+typedef struct _TestState
+{
+ int dummy;
+} TestState;
+
+static void
+draw_path_at (CoglPath *path, CoglPipeline *pipeline, int x, int y)
+{
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb, x * BLOCK_SIZE, y * BLOCK_SIZE, 0.0f);
+
+ cogl_set_framebuffer (test_fb);
+ cogl_set_source (pipeline);
+ cogl_path_fill (path);
+
+ cogl_framebuffer_pop_matrix (test_fb);
+}
+
+static void
+check_block (int block_x, int block_y, int block_mask)
+{
+ uint32_t data[BLOCK_SIZE * BLOCK_SIZE];
+ int qx, qy;
+
+ /* Block mask represents which quarters of the block should be
+ filled. The bits from 0->3 represent the top left, top right,
+ bottom left and bottom right respectively */
+
+ cogl_framebuffer_read_pixels (test_fb,
+ block_x * BLOCK_SIZE,
+ block_y * BLOCK_SIZE,
+ BLOCK_SIZE, BLOCK_SIZE,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ (uint8_t *)data);
+
+ for (qy = 0; qy < 2; qy++)
+ for (qx = 0; qx < 2; qx++)
+ {
+ int bit = qx | (qy << 1);
+ const char *intended_pixel = ((block_mask & (1 << bit)) ? "#ffffff" : "#000000");
+ int x, y;
+
+ for (x = 0; x < BLOCK_SIZE / 2 - TEST_INSET * 2; x++)
+ for (y = 0; y < BLOCK_SIZE / 2 - TEST_INSET * 2; y++)
+ {
+ const uint32_t *p = data + (qx * BLOCK_SIZE / 2 +
+ qy * BLOCK_SIZE * BLOCK_SIZE / 2 +
+ (x + TEST_INSET) +
+ (y + TEST_INSET) * BLOCK_SIZE);
+ char *screen_pixel = g_strdup_printf ("#%06x", GUINT32_FROM_BE (*p) >> 8);
+ g_assert_cmpstr (screen_pixel, ==, intended_pixel);
+ g_free (screen_pixel);
+ }
+ }
+}
+
+static void
+paint (TestState *state)
+{
+ CoglPath *path_a, *path_b, *path_c;
+ CoglPipeline *white = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4f (white, 1, 1, 1, 1);
+
+ /* Create a path filling just a quarter of a block. It will use two
+ rectangles so that we have a sub path in the path */
+ path_a = cogl_path_new ();
+ cogl_path_rectangle (path_a,
+ BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2,
+ BLOCK_SIZE, BLOCK_SIZE);
+ cogl_path_rectangle (path_a,
+ BLOCK_SIZE / 2, BLOCK_SIZE / 2,
+ BLOCK_SIZE * 3 / 4, BLOCK_SIZE);
+ draw_path_at (path_a, white, 0, 0);
+
+ /* Create another path filling the whole block */
+ path_b = cogl_path_new ();
+ cogl_path_rectangle (path_b, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
+ draw_path_at (path_b, white, 1, 0);
+
+ /* Draw the first path again */
+ draw_path_at (path_a, white, 2, 0);
+
+ /* Draw a copy of path a */
+ path_c = cogl_path_copy (path_a);
+ draw_path_at (path_c, white, 3, 0);
+
+ /* Add another rectangle to path a. We'll use line_to's instead of
+ cogl_rectangle so that we don't create another sub-path because
+ that is more likely to break the copy */
+ cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2);
+ cogl_path_line_to (path_a, 0, 0);
+ cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
+ cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
+ draw_path_at (path_a, white, 4, 0);
+
+ /* Draw the copy again. It should not have changed */
+ draw_path_at (path_c, white, 5, 0);
+
+ /* Add another rectangle to path c. It will be added in two halves,
+ one as an extension of the previous path and the other as a new
+ sub path */
+ cogl_path_line_to (path_c, BLOCK_SIZE / 2, 0);
+ cogl_path_line_to (path_c, BLOCK_SIZE * 3 / 4, 0);
+ cogl_path_line_to (path_c, BLOCK_SIZE * 3 / 4, BLOCK_SIZE / 2);
+ cogl_path_line_to (path_c, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
+ cogl_path_rectangle (path_c,
+ BLOCK_SIZE * 3 / 4, 0, BLOCK_SIZE, BLOCK_SIZE / 2);
+ draw_path_at (path_c, white, 6, 0);
+
+ /* Draw the original path again. It should not have changed */
+ draw_path_at (path_a, white, 7, 0);
+
+ cogl_object_unref (path_a);
+ cogl_object_unref (path_b);
+ cogl_object_unref (path_c);
+
+ /* Draw a self-intersecting path. The part that intersects should be
+ inverted */
+ path_a = cogl_path_new ();
+ cogl_path_rectangle (path_a, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
+ cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2);
+ cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
+ cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
+ cogl_path_close (path_a);
+ draw_path_at (path_a, white, 8, 0);
+ cogl_object_unref (path_a);
+
+ /* Draw two sub paths. Where the paths intersect it should be
+ inverted */
+ path_a = cogl_path_new ();
+ cogl_path_rectangle (path_a, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
+ cogl_path_rectangle (path_a,
+ BLOCK_SIZE / 2, BLOCK_SIZE / 2, BLOCK_SIZE, BLOCK_SIZE);
+ draw_path_at (path_a, white, 9, 0);
+ cogl_object_unref (path_a);
+
+ /* Draw a clockwise outer path */
+ path_a = cogl_path_new ();
+ cogl_path_move_to (path_a, 0, 0);
+ cogl_path_line_to (path_a, BLOCK_SIZE, 0);
+ cogl_path_line_to (path_a, BLOCK_SIZE, BLOCK_SIZE);
+ cogl_path_line_to (path_a, 0, BLOCK_SIZE);
+ cogl_path_close (path_a);
+ /* Add a clockwise sub path in the upper left quadrant */
+ cogl_path_move_to (path_a, 0, 0);
+ cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
+ cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
+ cogl_path_line_to (path_a, 0, BLOCK_SIZE / 2);
+ cogl_path_close (path_a);
+ /* Add a counter-clockwise sub path in the upper right quadrant */
+ cogl_path_move_to (path_a, BLOCK_SIZE / 2, 0);
+ cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
+ cogl_path_line_to (path_a, BLOCK_SIZE, BLOCK_SIZE / 2);
+ cogl_path_line_to (path_a, BLOCK_SIZE, 0);
+ cogl_path_close (path_a);
+ /* Retain the path for the next test */
+ draw_path_at (path_a, white, 10, 0);
+
+ /* Draw the same path again with the other fill rule */
+ cogl_path_set_fill_rule (path_a, COGL_PATH_FILL_RULE_NON_ZERO);
+ draw_path_at (path_a, white, 11, 0);
+
+ cogl_object_unref (path_a);
+}
+
+static void
+validate_result ()
+{
+ check_block (0, 0, 0x8 /* bottom right */);
+ check_block (1, 0, 0xf /* all of them */);
+ check_block (2, 0, 0x8 /* bottom right */);
+ check_block (3, 0, 0x8 /* bottom right */);
+ check_block (4, 0, 0x9 /* top left and bottom right */);
+ check_block (5, 0, 0x8 /* bottom right */);
+ check_block (6, 0, 0xa /* bottom right and top right */);
+ check_block (7, 0, 0x9 /* top_left and bottom right */);
+ check_block (8, 0, 0xe /* all but top left */);
+ check_block (9, 0, 0x7 /* all but bottom right */);
+ check_block (10, 0, 0xc /* bottom two */);
+ check_block (11, 0, 0xd /* all but top right */);
+}
+
+void
+test_path (void)
+{
+ TestState state;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ paint (&state);
+ validate_result ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-pipeline-cache-unrefs-texture.c b/cogl/tests/conform/test-pipeline-cache-unrefs-texture.c
new file mode 100644
index 000000000..5d278dcd0
--- /dev/null
+++ b/cogl/tests/conform/test-pipeline-cache-unrefs-texture.c
@@ -0,0 +1,91 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+/* Keep track of the number of textures that we've created and are
+ * still alive */
+static int destroyed_texture_count = 0;
+
+#define N_TEXTURES 3
+
+static void
+free_texture_cb (void *user_data)
+{
+ destroyed_texture_count++;
+}
+
+static CoglTexture *
+create_texture (void)
+{
+ static const guint8 data[] =
+ { 0xff, 0xff, 0xff, 0xff };
+ static CoglUserDataKey texture_data_key;
+ CoglTexture2D *tex_2d;
+
+ tex_2d = cogl_texture_2d_new_from_data (test_ctx,
+ 1, 1, /* width / height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ data,
+ NULL);
+
+ /* Set some user data on the texture so we can track when it has
+ * been destroyed */
+ cogl_object_set_user_data (COGL_OBJECT (tex_2d),
+ &texture_data_key,
+ GINT_TO_POINTER (1),
+ free_texture_cb);
+
+ return tex_2d;
+}
+
+void
+test_pipeline_cache_unrefs_texture (void)
+{
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ CoglPipeline *simple_pipeline;
+ int i;
+
+ /* Create a pipeline with three texture layers. That way we can be
+ * pretty sure the pipeline will cause a unique shader to be
+ * generated in the cache */
+ for (i = 0; i < N_TEXTURES; i++)
+ {
+ CoglTexture *tex = create_texture ();
+ cogl_pipeline_set_layer_texture (pipeline, i, tex);
+ cogl_object_unref (tex);
+ }
+
+ /* Draw something with the pipeline to ensure it gets into the
+ * pipeline cache */
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ 0, 0, 10, 10);
+ cogl_framebuffer_finish (test_fb);
+
+ /* Draw something else so that it is no longer the current flushed
+ * pipeline, and the units have a different texture bound */
+ simple_pipeline = cogl_pipeline_new (test_ctx);
+ for (i = 0; i < N_TEXTURES; i++)
+ {
+ CoglColor combine_constant;
+ cogl_color_init_from_4ub (&combine_constant, i, 0, 0, 255);
+ cogl_pipeline_set_layer_combine_constant (simple_pipeline,
+ i,
+ &combine_constant);
+ }
+ cogl_framebuffer_draw_rectangle (test_fb, simple_pipeline, 0, 0, 10, 10);
+ cogl_framebuffer_finish (test_fb);
+ cogl_object_unref (simple_pipeline);
+
+ g_assert_cmpint (destroyed_texture_count, ==, 0);
+
+ /* Destroy the pipeline. This should immediately cause the textures
+ * to be freed */
+ cogl_object_unref (pipeline);
+
+ g_assert_cmpint (destroyed_texture_count, ==, N_TEXTURES);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-pipeline-shader-state.c b/cogl/tests/conform/test-pipeline-shader-state.c
new file mode 100644
index 000000000..4d1e5f2b7
--- /dev/null
+++ b/cogl/tests/conform/test-pipeline-shader-state.c
@@ -0,0 +1,93 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+void
+test_pipeline_shader_state (void)
+{
+ CoglOffscreen *offscreen;
+ CoglFramebuffer *fb;
+ CoglPipeline *base_pipeline;
+ CoglPipeline *draw_pipeline;
+ CoglTexture2D *tex;
+ CoglSnippet *snippet;
+
+ float width = cogl_framebuffer_get_width (test_fb);
+ float height = cogl_framebuffer_get_height (test_fb);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, width, height,
+ -1,
+ 100);
+
+ tex = cogl_texture_2d_new_with_size (test_ctx, 128, 128);
+ offscreen = cogl_offscreen_new_with_texture (tex);
+ fb = offscreen;
+ cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+ cogl_object_unref (offscreen);
+
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 1, 1, 0, 1);
+
+
+ /* Setup a template pipeline... */
+
+ base_pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_layer_texture (base_pipeline, 1, tex);
+ cogl_pipeline_set_color4f (base_pipeline, 1, 0, 0, 1);
+
+
+ /* Derive a pipeline from the template, making a change that affects
+ * fragment processing but making sure not to affect vertex
+ * processing... */
+
+ draw_pipeline = cogl_pipeline_copy (base_pipeline);
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL, /* declarations */
+ "cogl_color_out = vec4 (0.0, 1.0, 0.1, 1.1);");
+ cogl_pipeline_add_snippet (draw_pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb, draw_pipeline,
+ 0, 0, width, height);
+
+ cogl_object_unref (draw_pipeline);
+
+ cogl_framebuffer_finish (test_fb);
+
+
+ /* At this point we should have provoked cogl to cache some vertex
+ * shader state for the draw_pipeline with the base_pipeline because
+ * none of the changes made to the draw_pipeline affected vertex
+ * processing. (NB: cogl will cache shader state with the oldest
+ * ancestor that the state is still valid for to maximize the chance
+ * that it can be used with other derived pipelines)
+ *
+ * Now we make a change to the base_pipeline to make sure that this
+ * cached vertex shader gets invalidated.
+ */
+
+ cogl_pipeline_set_layer_texture (base_pipeline, 0, tex);
+
+
+ /* Now we derive another pipeline from base_pipeline to verify that
+ * it doesn't end up re-using the old cached state
+ */
+
+ draw_pipeline = cogl_pipeline_copy (base_pipeline);
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL, /* declarations */
+ "cogl_color_out = vec4 (0.0, 0.0, 1.1, 1.1);");
+ cogl_pipeline_add_snippet (draw_pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb, draw_pipeline,
+ 0, 0, width, height);
+
+ cogl_object_unref (draw_pipeline);
+
+
+ test_utils_check_region (test_fb, 0, 0, width, height,
+ 0x0000ffff);
+}
diff --git a/cogl/tests/conform/test-pipeline-uniforms.c b/cogl/tests/conform/test-pipeline-uniforms.c
new file mode 100644
index 000000000..4d27558d2
--- /dev/null
+++ b/cogl/tests/conform/test-pipeline-uniforms.c
@@ -0,0 +1,415 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define LONG_ARRAY_SIZE 128
+
+typedef struct _TestState
+{
+ CoglPipeline *pipeline_red;
+ CoglPipeline *pipeline_green;
+ CoglPipeline *pipeline_blue;
+
+ CoglPipeline *matrix_pipeline;
+ CoglPipeline *vector_pipeline;
+ CoglPipeline *int_pipeline;
+
+ CoglPipeline *long_pipeline;
+ int long_uniform_locations[LONG_ARRAY_SIZE];
+} TestState;
+
+static const char
+color_source[] =
+ "uniform float red, green, blue;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = vec4 (red, green, blue, 1.0);\n"
+ "}\n";
+
+static const char
+matrix_source[] =
+ "uniform mat4 matrix_array[4];\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " vec4 color = vec4 (0.0, 0.0, 0.0, 1.0);\n"
+ " int i;\n"
+ "\n"
+ " for (i = 0; i < 4; i++)\n"
+ " color = matrix_array[i] * color;\n"
+ "\n"
+ " cogl_color_out = color;\n"
+ "}\n";
+
+static const char
+vector_source[] =
+ "uniform vec4 vector_array[2];\n"
+ "uniform vec3 short_vector;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = (vector_array[0] +\n"
+ " vector_array[1] +\n"
+ " vec4 (short_vector, 1.0));\n"
+ "}\n";
+
+static const char
+int_source[] =
+ "uniform ivec4 vector_array[2];\n"
+ "uniform int single_value;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = (vec4 (vector_array[0]) +\n"
+ " vec4 (vector_array[1]) +\n"
+ " vec4 (float (single_value), 0.0, 0.0, 255.0)) / 255.0;\n"
+ "}\n";
+
+static const char
+long_source[] =
+ "uniform int long_array[" G_STRINGIFY (LONG_ARRAY_SIZE) "];\n"
+ "const int last_index = " G_STRINGIFY (LONG_ARRAY_SIZE) " - 1;\n"
+ "\n"
+ "void\n"
+ "main ()\n"
+ "{\n"
+ " cogl_color_out = vec4 (float (long_array[last_index]), 0.0, 0.0, 1.0);\n"
+ "}\n";
+
+static CoglPipeline *
+create_pipeline_for_shader (TestState *state, const char *shader_source)
+{
+ CoglPipeline *pipeline;
+ CoglHandle shader;
+ CoglHandle program;
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
+ cogl_shader_source (shader, shader_source);
+
+ program = cogl_create_program ();
+ cogl_program_attach_shader (program, shader);
+
+ cogl_pipeline_set_user_program (pipeline, program);
+
+ cogl_handle_unref (shader);
+ cogl_handle_unref (program);
+
+ return pipeline;
+}
+
+static void
+init_state (TestState *state)
+{
+ int uniform_location;
+
+ state->pipeline_red = create_pipeline_for_shader (state, color_source);
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_red, "red");
+ cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 1.0f);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_red, "green");
+ cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_red, "blue");
+ cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f);
+
+ state->pipeline_green = cogl_pipeline_copy (state->pipeline_red);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_green, "green");
+ cogl_pipeline_set_uniform_1f (state->pipeline_green, uniform_location, 1.0f);
+
+ state->pipeline_blue = cogl_pipeline_copy (state->pipeline_red);
+ uniform_location =
+ cogl_pipeline_get_uniform_location (state->pipeline_blue, "blue");
+ cogl_pipeline_set_uniform_1f (state->pipeline_blue, uniform_location, 1.0f);
+
+ state->matrix_pipeline = create_pipeline_for_shader (state, matrix_source);
+ state->vector_pipeline = create_pipeline_for_shader (state, vector_source);
+ state->int_pipeline = create_pipeline_for_shader (state, int_source);
+
+ state->long_pipeline = NULL;
+}
+
+static void
+init_long_pipeline_state (TestState *state)
+{
+ int i;
+
+ state->long_pipeline = create_pipeline_for_shader (state, long_source);
+
+ /* This tries to lookup a large number of uniform names to make sure
+ that the bitmask of overriden uniforms flows over the size of a
+ single long so that it has to resort to allocating it */
+ for (i = 0; i < LONG_ARRAY_SIZE; i++)
+ {
+ char *uniform_name = g_strdup_printf ("long_array[%i]", i);
+ state->long_uniform_locations[i] =
+ cogl_pipeline_get_uniform_location (state->long_pipeline,
+ uniform_name);
+ g_free (uniform_name);
+ }
+}
+
+static void
+destroy_state (TestState *state)
+{
+ cogl_object_unref (state->pipeline_red);
+ cogl_object_unref (state->pipeline_green);
+ cogl_object_unref (state->pipeline_blue);
+ cogl_object_unref (state->matrix_pipeline);
+ cogl_object_unref (state->vector_pipeline);
+ cogl_object_unref (state->int_pipeline);
+
+ if (state->long_pipeline)
+ cogl_object_unref (state->long_pipeline);
+}
+
+static void
+paint_pipeline (CoglPipeline *pipeline, int pos)
+{
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline,
+ pos * 10, 0, pos * 10 + 10, 10);
+}
+
+static void
+paint_color_pipelines (TestState *state)
+{
+ CoglPipeline *temp_pipeline;
+ int uniform_location;
+ int i;
+
+ /* Paint with the first pipeline that sets the uniforms to bright
+ red */
+ paint_pipeline (state->pipeline_red, 0);
+
+ /* Paint with the two other pipelines. These inherit from the red
+ pipeline and only override one other component. The values for
+ the two other components should be inherited from the red
+ pipeline. */
+ paint_pipeline (state->pipeline_green, 1);
+ paint_pipeline (state->pipeline_blue, 2);
+
+ /* Try modifying a single pipeline for multiple rectangles */
+ temp_pipeline = cogl_pipeline_copy (state->pipeline_green);
+ uniform_location = cogl_pipeline_get_uniform_location (temp_pipeline,
+ "green");
+
+ for (i = 0; i <= 8; i++)
+ {
+ cogl_pipeline_set_uniform_1f (temp_pipeline, uniform_location,
+ i / 8.0f);
+ paint_pipeline (temp_pipeline, i + 3);
+ }
+
+ cogl_object_unref (temp_pipeline);
+}
+
+static void
+paint_matrix_pipeline (CoglPipeline *pipeline)
+{
+ CoglMatrix matrices[4];
+ float matrix_floats[16 * 4];
+ int uniform_location;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ cogl_matrix_init_identity (matrices + i);
+
+ /* Use the first matrix to make the color red */
+ cogl_matrix_translate (matrices + 0, 1.0f, 0.0f, 0.0f);
+
+ /* Rotate the vertex so that it ends up green */
+ cogl_matrix_rotate (matrices + 1, 90.0f, 0.0f, 0.0f, 1.0f);
+
+ /* Scale the vertex so it ends up halved */
+ cogl_matrix_scale (matrices + 2, 0.5f, 0.5f, 0.5f);
+
+ /* Add a blue component in the final matrix. The final matrix is
+ uploaded as transposed so we need to transpose first to cancel
+ that out */
+ cogl_matrix_translate (matrices + 3, 0.0f, 0.0f, 1.0f);
+ cogl_matrix_transpose (matrices + 3);
+
+ for (i = 0; i < 4; i++)
+ memcpy (matrix_floats + i * 16,
+ cogl_matrix_get_array (matrices + i),
+ sizeof (float) * 16);
+
+ /* Set the first three matrices as transposed */
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "matrix_array");
+ cogl_pipeline_set_uniform_matrix (pipeline,
+ uniform_location,
+ 4, /* dimensions */
+ 3, /* count */
+ FALSE, /* not transposed */
+ matrix_floats);
+
+ /* Set the last matrix as untransposed */
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "matrix_array[3]");
+ cogl_pipeline_set_uniform_matrix (pipeline,
+ uniform_location,
+ 4, /* dimensions */
+ 1, /* count */
+ TRUE, /* transposed */
+ matrix_floats + 16 * 3);
+
+ paint_pipeline (pipeline, 12);
+}
+
+static void
+paint_vector_pipeline (CoglPipeline *pipeline)
+{
+ float vector_array_values[] = { 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f };
+ float short_vector_values[] = { 0.0f, 0.0f, 1.0f };
+ int uniform_location;
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "vector_array");
+ cogl_pipeline_set_uniform_float (pipeline,
+ uniform_location,
+ 4, /* n_components */
+ 2, /* count */
+ vector_array_values);
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "short_vector");
+ cogl_pipeline_set_uniform_float (pipeline,
+ uniform_location,
+ 3, /* n_components */
+ 1, /* count */
+ short_vector_values);
+
+ paint_pipeline (pipeline, 13);
+}
+
+static void
+paint_int_pipeline (CoglPipeline *pipeline)
+{
+ int vector_array_values[] = { 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00 };
+ int single_value = 0x80;
+ int uniform_location;
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "vector_array");
+ cogl_pipeline_set_uniform_int (pipeline,
+ uniform_location,
+ 4, /* n_components */
+ 2, /* count */
+ vector_array_values);
+
+ uniform_location =
+ cogl_pipeline_get_uniform_location (pipeline, "single_value");
+ cogl_pipeline_set_uniform_1i (pipeline,
+ uniform_location,
+ single_value);
+
+ paint_pipeline (pipeline, 14);
+}
+
+static void
+paint_long_pipeline (TestState *state)
+{
+ int i;
+
+ for (i = 0; i < LONG_ARRAY_SIZE; i++)
+ {
+ int location = state->long_uniform_locations[i];
+
+ cogl_pipeline_set_uniform_1i (state->long_pipeline,
+ location,
+ i == LONG_ARRAY_SIZE - 1);
+ }
+
+ paint_pipeline (state->long_pipeline, 15);
+}
+
+static void
+paint (TestState *state)
+{
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+
+ paint_color_pipelines (state);
+ paint_matrix_pipeline (state->matrix_pipeline);
+ paint_vector_pipeline (state->vector_pipeline);
+ paint_int_pipeline (state->int_pipeline);
+}
+
+static void
+check_pos (int pos, uint32_t color)
+{
+ test_utils_check_pixel (test_fb, pos * 10 + 5, 5, color);
+}
+
+static void
+validate_result (void)
+{
+ int i;
+
+ check_pos (0, 0xff0000ff);
+ check_pos (1, 0xffff00ff);
+ check_pos (2, 0xff00ffff);
+
+ for (i = 0; i <= 8; i++)
+ {
+ int green_value = i / 8.0f * 255.0f + 0.5f;
+ check_pos (i + 3, 0xff0000ff + (green_value << 16));
+ }
+
+ check_pos (12, 0x0080ffff);
+ check_pos (13, 0xffffffff);
+ check_pos (14, 0x80ffffff);
+}
+
+static void
+validate_long_pipeline_result (void)
+{
+ check_pos (15, 0xff0000ff);
+}
+
+void
+test_pipeline_uniforms (void)
+{
+ TestState state;
+
+ init_state (&state);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ paint (&state);
+ validate_result ();
+
+ /* Try the test again after querying the location of a large
+ number of uniforms. This should verify that the bitmasks
+ still work even if they have to allocate a separate array to
+ store the bits */
+
+ init_long_pipeline_state (&state);
+ paint (&state);
+ paint_long_pipeline (&state);
+ validate_result ();
+ validate_long_pipeline_result ();
+
+ destroy_state (&state);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-pipeline-user-matrix.c b/cogl/tests/conform/test-pipeline-user-matrix.c
new file mode 100644
index 000000000..f7cdee8c8
--- /dev/null
+++ b/cogl/tests/conform/test-pipeline-user-matrix.c
@@ -0,0 +1,140 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+ int width;
+ int height;
+} TestState;
+
+static void
+validate_result (TestState *state)
+{
+ uint32_t *pixels, *p;
+ char *screen_pixel;
+ const char *intended_pixel = "#ffffff";
+
+ /* The textures are setup so that when added together with the
+ correct matrices then all of the pixels should be white. We can
+ verify this by reading back the entire stage */
+ pixels = g_malloc (state->width * state->height * 4);
+
+ cogl_framebuffer_read_pixels (test_fb, 0, 0, state->width, state->height,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ (uint8_t *)pixels);
+
+ for (p = pixels; p < pixels + state->width * state->height; p++)
+ {
+ screen_pixel = g_strdup_printf ("#%06x", GUINT32_FROM_BE (*p) >> 8);
+ g_assert_cmpstr (screen_pixel, ==, intended_pixel);
+ g_free (screen_pixel);
+ }
+}
+
+static void
+paint (TestState *state)
+{
+ /* This texture is painted mirrored around the x-axis */
+ uint8_t data0[] = {
+ 0xff, 0x00, 0x00, /* red -> becomes bottom left */
+ 0x00, 0xff, 0x00, /* green -> becomes bottom right */
+ 0x00, 0x00, 0xff, /* blue -> becomes top left */
+ 0xff, 0x00, 0xff /* magenta -> becomes top right */
+ };
+ /* This texture is painted mirrored about the y-axis */
+ uint8_t data1[] = {
+ 0x00, 0xff, 0x00, /* green -> becomes top right */
+ 0xff, 0xff, 0x00, /* yellow -> becomes top left */
+ 0xff, 0x00, 0xff, /* magenta -> becomes bottom right */
+ 0x00, 0xff, 0xff /* cyan -> becomes bottom left */
+ };
+ CoglTexture *tex0, *tex1;
+ CoglPipeline *pipeline;
+ CoglMatrix matrix;
+ CoglError *error = NULL;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ state->width,
+ state->height,
+ -1,
+ 100);
+
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+
+ cogl_matrix_init_identity (&matrix);
+ cogl_framebuffer_set_modelview_matrix (test_fb, &matrix);
+
+ tex0 = cogl_texture_new_from_data (2, 2,
+ COGL_TEXTURE_NO_ATLAS,
+ COGL_PIXEL_FORMAT_RGB_888,
+ COGL_PIXEL_FORMAT_ANY,
+ 6,
+ data0);
+ tex1 = cogl_texture_new_from_data (2, 2,
+ COGL_TEXTURE_NO_ATLAS,
+ COGL_PIXEL_FORMAT_RGB_888,
+ COGL_PIXEL_FORMAT_ANY,
+ 6,
+ data1);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ /* Set the two textures as layers */
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex0);
+ cogl_pipeline_set_layer_filters (pipeline, 0,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+ cogl_pipeline_set_layer_texture (pipeline, 1, tex1);
+ cogl_pipeline_set_layer_filters (pipeline, 1,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+
+ /* Set a combine mode so that the two textures get added together */
+ if (!cogl_pipeline_set_layer_combine (pipeline, 1,
+ "RGBA=ADD(PREVIOUS, TEXTURE)",
+ &error))
+ {
+ g_warning ("Error setting blend string: %s", error->message);
+ g_assert_not_reached ();
+ }
+
+ /* Set a matrix on the first layer so that it will mirror about the y-axis */
+ cogl_matrix_init_identity (&matrix);
+ cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f);
+ cogl_matrix_scale (&matrix, 1.0f, -1.0f, 1.0f);
+ cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
+
+ /* Set a matrix on the second layer so that it will mirror about the x-axis */
+ cogl_matrix_init_identity (&matrix);
+ cogl_matrix_translate (&matrix, 1.0f, 0.0f, 0.0f);
+ cogl_matrix_scale (&matrix, -1.0f, 1.0f, 1.0f);
+ cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ 0, 0,
+ state->width, state->height);
+
+ cogl_object_unref (tex1);
+ cogl_object_unref (tex0);
+ cogl_object_unref (pipeline);
+}
+
+void
+test_pipeline_user_matrix (void)
+{
+ TestState state;
+
+ state.width = cogl_framebuffer_get_width (test_fb);
+ state.height = cogl_framebuffer_get_height (test_fb);
+
+ paint (&state);
+ validate_result (&state);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-pixel-buffer.c b/cogl/tests/conform/test-pixel-buffer.c
new file mode 100644
index 000000000..a78516d06
--- /dev/null
+++ b/cogl/tests/conform/test-pixel-buffer.c
@@ -0,0 +1,269 @@
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+#define BITMAP_SIZE 256
+
+/*
+ * Creates a 256 x 256 with image data split into four quadrants. The
+ * colours of these in reading order will be: blue, green, cyan,
+ * red */
+static void
+generate_bitmap_data (uint8_t *data,
+ int stride)
+{
+ int y, x;
+
+ for (y = 0; y < BITMAP_SIZE; y++)
+ {
+ for (x = 0; x < BITMAP_SIZE; x++)
+ {
+ int color_num = x / (BITMAP_SIZE / 2) + y / (BITMAP_SIZE / 2) * 2 + 1;
+ *(data++) = (color_num & 4) ? 255 : 0;
+ *(data++) = (color_num & 2) ? 255 : 0;
+ *(data++) = (color_num & 1) ? 255 : 0;
+ *(data++) = 255;
+ }
+ data += stride - BITMAP_SIZE * 4;
+ }
+}
+
+static CoglBitmap *
+create_bitmap (void)
+{
+ CoglBitmap *bitmap;
+ CoglBuffer *buffer;
+
+ bitmap = cogl_bitmap_new_with_size (test_ctx,
+ BITMAP_SIZE,
+ BITMAP_SIZE,
+ COGL_PIXEL_FORMAT_RGBA_8888);
+ buffer = cogl_bitmap_get_buffer (bitmap);
+
+ g_assert (cogl_is_pixel_buffer (buffer));
+ g_assert (cogl_is_buffer (buffer));
+
+ cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC);
+ g_assert_cmpint (cogl_buffer_get_update_hint (buffer),
+ ==,
+ COGL_BUFFER_UPDATE_HINT_DYNAMIC);
+
+ return bitmap;
+}
+
+static CoglBitmap *
+create_and_fill_bitmap (void)
+{
+ CoglBitmap *bitmap = create_bitmap ();
+ CoglBuffer *buffer = cogl_bitmap_get_buffer (bitmap);
+ uint8_t *map;
+ unsigned int stride;
+
+ stride = cogl_bitmap_get_rowstride (bitmap);
+
+ map = cogl_buffer_map (buffer,
+ COGL_BUFFER_ACCESS_WRITE,
+ COGL_BUFFER_MAP_HINT_DISCARD);
+ g_assert (map);
+
+ generate_bitmap_data (map, stride);
+
+ cogl_buffer_unmap (buffer);
+
+ return bitmap;
+}
+
+static CoglTexture *
+create_texture_from_bitmap (CoglBitmap *bitmap)
+{
+ CoglTexture2D *texture;
+
+ texture = cogl_texture_2d_new_from_bitmap (bitmap);
+
+ g_assert (texture != NULL);
+
+ return texture;
+}
+
+static CoglPipeline *
+create_pipeline_from_texture (CoglTexture *texture)
+{
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_texture (pipeline, 0, texture);
+ cogl_pipeline_set_layer_filters (pipeline,
+ 0, /* layer_num */
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+
+ return pipeline;
+}
+
+static void
+check_colours (uint32_t color0,
+ uint32_t color1,
+ uint32_t color2,
+ uint32_t color3)
+{
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+
+ test_utils_check_region (test_fb,
+ 1, 1, /* x/y */
+ fb_width / 2 - 2, /* width */
+ fb_height / 2 - 2, /* height */
+ color0);
+ test_utils_check_region (test_fb,
+ fb_width / 2 + 1, /* x */
+ 1, /* y */
+ fb_width / 2 - 2, /* width */
+ fb_height / 2 - 2, /* height */
+ color1);
+ test_utils_check_region (test_fb,
+ 1, /* x */
+ fb_height / 2 + 1, /* y */
+ fb_width / 2 - 2, /* width */
+ fb_height / 2 - 2, /* height */
+ color2);
+ test_utils_check_region (test_fb,
+ fb_width / 2 + 1, /* x */
+ fb_height / 2 + 1, /* y */
+ fb_width / 2 - 2, /* width */
+ fb_height / 2 - 2, /* height */
+ color3);
+}
+
+void
+test_pixel_buffer_map (void)
+{
+ CoglBitmap *bitmap = create_and_fill_bitmap ();
+ CoglPipeline *pipeline;
+ CoglTexture *texture;
+
+ texture = create_texture_from_bitmap (bitmap);
+ pipeline = create_pipeline_from_texture (texture);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1.0f, 1.0f,
+ 1.0f, -1.0f);
+
+ cogl_object_unref (bitmap);
+ cogl_object_unref (texture);
+ cogl_object_unref (pipeline);
+
+ check_colours (0x0000ffff,
+ 0x00ff00ff,
+ 0x00ffffff,
+ 0xff0000ff);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
+void
+test_pixel_buffer_set_data (void)
+{
+ CoglBitmap *bitmap = create_bitmap ();
+ CoglBuffer *buffer = cogl_bitmap_get_buffer (bitmap);
+ CoglPipeline *pipeline;
+ CoglTexture *texture;
+ uint8_t *data;
+ unsigned int stride;
+
+ stride = cogl_bitmap_get_rowstride (bitmap);
+
+ data = g_malloc (stride * BITMAP_SIZE);
+
+ generate_bitmap_data (data, stride);
+
+ cogl_buffer_set_data (buffer,
+ 0, /* offset */
+ data,
+ stride * (BITMAP_SIZE - 1) +
+ BITMAP_SIZE * 4);
+
+ g_free (data);
+
+ texture = create_texture_from_bitmap (bitmap);
+ pipeline = create_pipeline_from_texture (texture);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1.0f, 1.0f,
+ 1.0f, -1.0f);
+
+ cogl_object_unref (bitmap);
+ cogl_object_unref (texture);
+ cogl_object_unref (pipeline);
+
+ check_colours (0x0000ffff,
+ 0x00ff00ff,
+ 0x00ffffff,
+ 0xff0000ff);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
+static CoglTexture *
+create_white_texture (void)
+{
+ CoglTexture2D *texture;
+ uint8_t *data = g_malloc (BITMAP_SIZE * BITMAP_SIZE * 4);
+
+ memset (data, 255, BITMAP_SIZE * BITMAP_SIZE * 4);
+
+ texture = cogl_texture_2d_new_from_data (test_ctx,
+ BITMAP_SIZE,
+ BITMAP_SIZE,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ BITMAP_SIZE * 4, /* rowstride */
+ data,
+ NULL); /* don't catch errors */
+
+ g_free (data);
+
+ return texture;
+}
+
+void
+test_pixel_buffer_sub_region (void)
+{
+ CoglBitmap *bitmap = create_and_fill_bitmap ();
+ CoglPipeline *pipeline;
+ CoglTexture *texture;
+
+ texture = create_white_texture ();
+
+ /* Replace the top-right quadrant of the texture with the red part
+ * of the bitmap */
+ cogl_texture_set_region_from_bitmap (texture,
+ BITMAP_SIZE / 2, /* src_x */
+ BITMAP_SIZE / 2, /* src_y */
+ BITMAP_SIZE / 2, /* dst_x */
+ 0, /* dst_y */
+ BITMAP_SIZE / 2, /* width */
+ BITMAP_SIZE / 2, /* height */
+ bitmap);
+
+ pipeline = create_pipeline_from_texture (texture);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1.0f, 1.0f,
+ 1.0f, -1.0f);
+
+ cogl_object_unref (bitmap);
+ cogl_object_unref (texture);
+ cogl_object_unref (pipeline);
+
+ check_colours (0xffffffff,
+ 0xff0000ff,
+ 0xffffffff,
+ 0xffffffff);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-point-size-attribute.c b/cogl/tests/conform/test-point-size-attribute.c
new file mode 100644
index 000000000..a08d1daa9
--- /dev/null
+++ b/cogl/tests/conform/test-point-size-attribute.c
@@ -0,0 +1,166 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+/* This test assumes the GL driver supports point sizes up to 16
+ pixels. Cogl should probably have some way of querying the size so
+ we start from that instead */
+#define MAX_POINT_SIZE 16
+#define MIN_POINT_SIZE 4
+#define N_POINTS (MAX_POINT_SIZE - MIN_POINT_SIZE + 1)
+/* The size of the area that we'll paint each point in */
+#define POINT_BOX_SIZE (MAX_POINT_SIZE * 2)
+
+typedef struct
+{
+ float x, y;
+ float point_size;
+} PointVertex;
+
+static int
+calc_coord_offset (int pos, int pos_index, int point_size)
+{
+ switch (pos_index)
+ {
+ case 0: return pos - point_size / 2 - 2;
+ case 1: return pos - point_size / 2 + 2;
+ case 2: return pos + point_size / 2 - 2;
+ case 3: return pos + point_size / 2 + 2;
+ }
+
+ g_assert_not_reached ();
+}
+
+static void
+verify_point_size (CoglFramebuffer *test_fb,
+ int x_pos,
+ int y_pos,
+ int point_size)
+{
+ int y, x;
+
+ for (y = 0; y < 4; y++)
+ for (x = 0; x < 4; x++)
+ {
+ CoglBool in_point = x >= 1 && x <= 2 && y >= 1 && y <= 2;
+ uint32_t expected_pixel = in_point ? 0x00ff00ff : 0xff0000ff;
+
+ test_utils_check_pixel (test_fb,
+ calc_coord_offset (x_pos, x, point_size),
+ calc_coord_offset (y_pos, y, point_size),
+ expected_pixel);
+ }
+}
+
+static CoglPrimitive *
+create_primitive (const char *attribute_name)
+{
+ PointVertex vertices[N_POINTS];
+ CoglAttributeBuffer *buffer;
+ CoglAttribute *attributes[2];
+ CoglPrimitive *prim;
+ int i;
+
+ for (i = 0; i < N_POINTS; i++)
+ {
+ vertices[i].x = i * POINT_BOX_SIZE + POINT_BOX_SIZE / 2;
+ vertices[i].y = POINT_BOX_SIZE / 2;
+ vertices[i].point_size = MAX_POINT_SIZE - i;
+ }
+
+ buffer = cogl_attribute_buffer_new (test_ctx,
+ sizeof (vertices),
+ vertices);
+
+ attributes[0] = cogl_attribute_new (buffer,
+ "cogl_position_in",
+ sizeof (PointVertex),
+ G_STRUCT_OFFSET (PointVertex, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ attributes[1] = cogl_attribute_new (buffer,
+ attribute_name,
+ sizeof (PointVertex),
+ G_STRUCT_OFFSET (PointVertex, point_size),
+ 1, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+
+ prim = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_POINTS,
+ N_POINTS,
+ attributes,
+ 2 /* n_attributes */);
+
+ for (i = 0; i < 2; i++)
+ cogl_object_unref (attributes[i]);
+
+ return prim;
+}
+
+static void
+do_test (const char *attribute_name,
+ void (* pipeline_setup_func) (CoglPipeline *pipeline))
+{
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ CoglPrimitive *primitive;
+ CoglPipeline *pipeline;
+ int i;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, /* x_1, y_1 */
+ fb_width, /* x_2 */
+ fb_height /* y_2 */,
+ -1, 100 /* near/far */);
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 1.0f, 0.0f, 0.0f, 1.0f);
+
+ primitive = create_primitive (attribute_name);
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_color4ub (pipeline, 0x00, 0xff, 0x00, 0xff);
+ cogl_pipeline_set_per_vertex_point_size (pipeline, TRUE, NULL);
+ if (pipeline_setup_func)
+ pipeline_setup_func (pipeline);
+ cogl_primitive_draw (primitive, test_fb, pipeline);
+ cogl_object_unref (pipeline);
+ cogl_object_unref (primitive);
+
+ /* Verify all of the points where drawn at the right size */
+ for (i = 0; i < N_POINTS; i++)
+ verify_point_size (test_fb,
+ i * POINT_BOX_SIZE + POINT_BOX_SIZE / 2, /* x */
+ POINT_BOX_SIZE / 2, /* y */
+ MAX_POINT_SIZE - i /* point size */);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
+void
+test_point_size_attribute (void)
+{
+ do_test ("cogl_point_size_in", NULL);
+}
+
+static void
+setup_snippet (CoglPipeline *pipeline)
+{
+ CoglSnippet *snippet;
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_POINT_SIZE,
+ "attribute float "
+ "my_super_duper_point_size_attrib;\n",
+ NULL);
+ cogl_snippet_set_replace (snippet,
+ "cogl_point_size_out = "
+ "my_super_duper_point_size_attrib;\n");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+}
+
+void
+test_point_size_attribute_snippet (void)
+{
+ do_test ("my_super_duper_point_size_attrib", setup_snippet);
+}
diff --git a/cogl/tests/conform/test-point-size.c b/cogl/tests/conform/test-point-size.c
new file mode 100644
index 000000000..3c3af0f5e
--- /dev/null
+++ b/cogl/tests/conform/test-point-size.c
@@ -0,0 +1,99 @@
+#include <cogl/cogl2-experimental.h>
+
+#include "test-utils.h"
+
+/* This test assumes the GL driver supports point sizes up to 16
+ pixels. Cogl should probably have some way of querying the size so
+ we start from that instead */
+#define MAX_POINT_SIZE 16
+/* The size of the area that we'll paint each point in */
+#define POINT_BOX_SIZE (MAX_POINT_SIZE * 2)
+
+static int
+calc_coord_offset (int pos, int pos_index, int point_size)
+{
+ switch (pos_index)
+ {
+ case 0: return pos - point_size / 2 - 2;
+ case 1: return pos - point_size / 2 + 2;
+ case 2: return pos + point_size / 2 - 2;
+ case 3: return pos + point_size / 2 + 2;
+ }
+
+ g_assert_not_reached ();
+}
+
+static void
+verify_point_size (CoglFramebuffer *test_fb,
+ int x_pos,
+ int y_pos,
+ int point_size)
+{
+ int y, x;
+
+ for (y = 0; y < 4; y++)
+ for (x = 0; x < 4; x++)
+ {
+ CoglBool in_point = x >= 1 && x <= 2 && y >= 1 && y <= 2;
+ uint32_t expected_pixel = in_point ? 0x00ff00ff : 0xff0000ff;
+
+ test_utils_check_pixel (test_fb,
+ calc_coord_offset (x_pos, x, point_size),
+ calc_coord_offset (y_pos, y, point_size),
+ expected_pixel);
+ }
+}
+
+void
+test_point_size (void)
+{
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ int point_size;
+ int x_pos;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, /* x_1, y_1 */
+ fb_width, /* x_2 */
+ fb_height /* y_2 */,
+ -1, 100 /* near/far */);
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 1.0f, 0.0f, 0.0f, 1.0f);
+
+ /* Try a rendering a single point with a few different point
+ sizes */
+ for (x_pos = 0, point_size = MAX_POINT_SIZE;
+ point_size >= 4;
+ x_pos += POINT_BOX_SIZE, point_size /= 2)
+ {
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ CoglVertexP2 point = { x_pos + POINT_BOX_SIZE / 2,
+ POINT_BOX_SIZE / 2 };
+ CoglPrimitive *prim =
+ cogl_primitive_new_p2 (test_ctx,
+ COGL_VERTICES_MODE_POINTS,
+ 1, /* n_vertices */
+ &point);
+
+ cogl_pipeline_set_point_size (pipeline, point_size);
+ cogl_pipeline_set_color4ub (pipeline, 0, 255, 0, 255);
+ cogl_primitive_draw (prim, test_fb, pipeline);
+
+ cogl_object_unref (prim);
+ cogl_object_unref (pipeline);
+ }
+
+ /* Verify all of the points where drawn at the right size */
+ for (x_pos = 0, point_size = MAX_POINT_SIZE;
+ point_size >= 4;
+ x_pos += POINT_BOX_SIZE, point_size /= 2)
+ verify_point_size (test_fb,
+ x_pos + POINT_BOX_SIZE / 2,
+ POINT_BOX_SIZE / 2,
+ point_size);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-point-sprite.c b/cogl/tests/conform/test-point-sprite.c
new file mode 100644
index 000000000..eb80cfb0a
--- /dev/null
+++ b/cogl/tests/conform/test-point-sprite.c
@@ -0,0 +1,194 @@
+#include <cogl/cogl2-experimental.h>
+
+#include "test-utils.h"
+
+#define POINT_SIZE 8
+
+static const CoglVertexP2T2
+point =
+ {
+ POINT_SIZE, POINT_SIZE,
+ 0.0f, 0.0f
+ };
+
+static const uint8_t
+tex_data[3 * 2 * 2] =
+ {
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00
+ };
+
+static void
+do_test (CoglBool check_orientation,
+ CoglBool use_glsl)
+{
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+ CoglPrimitive *prim;
+ CoglError *error = NULL;
+ CoglTexture2D *tex_2d;
+ CoglPipeline *pipeline, *solid_pipeline;
+ int tex_height;
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, /* x_1, y_1 */
+ fb_width, /* x_2 */
+ fb_height /* y_2 */,
+ -1, 100 /* near/far */);
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 1.0f, 1.0f, 1.0f, 1.0f);
+
+ /* If we're not checking the orientation of the point sprite then
+ * we'll set the height of the texture to 1 so that the vertical
+ * orientation does not matter */
+ if (check_orientation)
+ tex_height = 2;
+ else
+ tex_height = 1;
+
+ tex_2d = cogl_texture_2d_new_from_data (test_ctx,
+ 2, tex_height, /* width/height */
+ COGL_PIXEL_FORMAT_RGB_888,
+ 6, /* row stride */
+ tex_data,
+ &error);
+ g_assert (tex_2d != NULL);
+ g_assert (error == NULL);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex_2d);
+
+ cogl_pipeline_set_layer_filters (pipeline,
+ 0, /* layer_index */
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+ cogl_pipeline_set_point_size (pipeline, POINT_SIZE);
+
+ /* If we're using GLSL then we don't need to enable point sprite
+ * coords and we can just directly reference cogl_point_coord in the
+ * snippet */
+ if (use_glsl)
+ {
+ CoglSnippet *snippet =
+ cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
+ NULL, /* declarations */
+ NULL /* post */);
+ static const char source[] =
+ " cogl_texel = texture2D (cogl_sampler, cogl_point_coord);\n";
+
+ cogl_snippet_set_replace (snippet, source);
+
+ /* Keep a reference to the original pipeline because there is no
+ * way to remove a snippet in order to recreate the solid
+ * pipeline */
+ solid_pipeline = cogl_pipeline_copy (pipeline);
+
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+
+ cogl_object_unref (snippet);
+ }
+ else
+ {
+ CoglBool res =
+ cogl_pipeline_set_layer_point_sprite_coords_enabled (pipeline,
+ /* layer_index */
+ 0,
+ /* enable */
+ TRUE,
+ &error);
+ g_assert (res == TRUE);
+ g_assert (error == NULL);
+
+ solid_pipeline = cogl_pipeline_copy (pipeline);
+
+ res =
+ cogl_pipeline_set_layer_point_sprite_coords_enabled (solid_pipeline,
+ /* layer_index */
+ 0,
+ /* enable */
+ FALSE,
+ &error);
+
+ g_assert (res == TRUE);
+ g_assert (error == NULL);
+ }
+
+ prim = cogl_primitive_new_p2t2 (test_ctx,
+ COGL_VERTICES_MODE_POINTS,
+ 1, /* n_vertices */
+ &point);
+
+ cogl_primitive_draw (prim, test_fb, pipeline);
+
+ /* Render the primitive again without point sprites to make sure
+ disabling it works */
+
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb,
+ POINT_SIZE * 2, /* x */
+ 0.0f, /* y */
+ 0.0f /* z */);
+ cogl_primitive_draw (prim, test_fb, solid_pipeline);
+ cogl_framebuffer_pop_matrix (test_fb);
+
+ cogl_object_unref (prim);
+ cogl_object_unref (solid_pipeline);
+ cogl_object_unref (pipeline);
+ cogl_object_unref (tex_2d);
+
+ test_utils_check_pixel (test_fb,
+ POINT_SIZE - POINT_SIZE / 4,
+ POINT_SIZE - POINT_SIZE / 4,
+ 0x0000ffff);
+ test_utils_check_pixel (test_fb,
+ POINT_SIZE + POINT_SIZE / 4,
+ POINT_SIZE - POINT_SIZE / 4,
+ 0x00ff00ff);
+ test_utils_check_pixel (test_fb,
+ POINT_SIZE - POINT_SIZE / 4,
+ POINT_SIZE + POINT_SIZE / 4,
+ check_orientation ?
+ 0x00ffffff :
+ 0x0000ffff);
+ test_utils_check_pixel (test_fb,
+ POINT_SIZE + POINT_SIZE / 4,
+ POINT_SIZE + POINT_SIZE / 4,
+ check_orientation ?
+ 0xff0000ff :
+ 0x00ff00ff);
+
+ /* When rendering without the point sprites all of the texture
+ coordinates should be 0,0 so it should get the top-left texel
+ which is blue */
+ test_utils_check_region (test_fb,
+ POINT_SIZE * 3 - POINT_SIZE / 2 + 1,
+ POINT_SIZE - POINT_SIZE / 2 + 1,
+ POINT_SIZE - 2, POINT_SIZE - 2,
+ 0x0000ffff);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
+void
+test_point_sprite (void)
+{
+ do_test (FALSE /* don't check orientation */,
+ FALSE /* don't use GLSL */);
+}
+
+void
+test_point_sprite_orientation (void)
+{
+ do_test (TRUE /* check orientation */,
+ FALSE /* don't use GLSL */);
+}
+
+void
+test_point_sprite_glsl (void)
+{
+ do_test (FALSE /* don't check orientation */,
+ TRUE /* use GLSL */);
+}
diff --git a/cogl/tests/conform/test-premult.c b/cogl/tests/conform/test-premult.c
new file mode 100644
index 000000000..fa60bdf1e
--- /dev/null
+++ b/cogl/tests/conform/test-premult.c
@@ -0,0 +1,301 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define QUAD_WIDTH 32
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define ALPHA 3
+
+#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
+#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
+#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
+#define MASK_ALPHA(COLOR) (COLOR & 0xff)
+
+typedef enum _MakeTextureFlags
+{
+ TEXTURE_FLAG_SET_PREMULTIPLIED = 1,
+ TEXTURE_FLAG_SET_UNPREMULTIPLIED = 1<<1,
+} MakeTextureFlags;
+
+static guchar *
+gen_tex_data (uint32_t color)
+{
+ guchar *tex_data, *p;
+ uint8_t r = MASK_RED (color);
+ uint8_t g = MASK_GREEN (color);
+ uint8_t b = MASK_BLUE (color);
+ uint8_t a = MASK_ALPHA (color);
+
+ tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 4);
+
+ for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;)
+ {
+ *(--p) = a;
+ *(--p) = b;
+ *(--p) = g;
+ *(--p) = r;
+ }
+
+ return tex_data;
+}
+
+static CoglTexture *
+make_texture (uint32_t color,
+ CoglPixelFormat src_format,
+ MakeTextureFlags flags)
+{
+ CoglTexture2D *tex_2d;
+ guchar *tex_data = gen_tex_data (color);
+ CoglBitmap *bmp = cogl_bitmap_new_for_data (test_ctx,
+ QUAD_WIDTH,
+ QUAD_WIDTH,
+ src_format,
+ QUAD_WIDTH * 4,
+ tex_data);
+
+ tex_2d = cogl_texture_2d_new_from_bitmap (bmp);
+
+ if (flags & TEXTURE_FLAG_SET_PREMULTIPLIED)
+ cogl_texture_set_premultiplied (tex_2d, TRUE);
+ else if (flags & TEXTURE_FLAG_SET_UNPREMULTIPLIED)
+ cogl_texture_set_premultiplied (tex_2d, FALSE);
+
+ cogl_object_unref (bmp);
+ g_free (tex_data);
+
+ return tex_2d;
+}
+
+static void
+set_region (CoglTexture *tex,
+ uint32_t color,
+ CoglPixelFormat format)
+{
+ guchar *tex_data = gen_tex_data (color);
+
+ cogl_texture_set_region (tex,
+ 0, 0, /* src x, y */
+ 0, 0, /* dst x, y */
+ QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
+ QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
+ format,
+ 0, /* auto compute row stride */
+ tex_data);
+}
+
+static void
+check_texture (CoglPipeline *pipeline,
+ CoglHandle material,
+ int x,
+ int y,
+ CoglTexture *tex,
+ uint32_t expected_result)
+{
+ /* Legacy */
+ cogl_push_framebuffer (test_fb);
+ cogl_material_set_layer (material, 0, tex);
+ cogl_set_source (material);
+ cogl_rectangle (x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ test_utils_check_pixel (test_fb, x * QUAD_WIDTH + QUAD_WIDTH / 2, y * QUAD_WIDTH + QUAD_WIDTH / 2, expected_result);
+ cogl_pop_framebuffer ();
+
+ /* New API */
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline,
+ x * QUAD_WIDTH,
+ y * QUAD_WIDTH,
+ x * QUAD_WIDTH + QUAD_WIDTH,
+ y * QUAD_WIDTH + QUAD_WIDTH);
+ test_utils_check_pixel (test_fb, x * QUAD_WIDTH + QUAD_WIDTH / 2, y * QUAD_WIDTH + QUAD_WIDTH / 2, expected_result);
+}
+
+void
+test_premult (void)
+{
+ CoglPipeline *pipeline;
+ CoglHandle material;
+ CoglTexture *tex;
+
+ cogl_framebuffer_orthographic (test_fb, 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 1.0f, 1.0f, 1.0f, 1.0f);
+
+ /* Legacy */
+ material = cogl_material_new ();
+ cogl_material_set_blend (material,
+ "RGBA = ADD (SRC_COLOR, 0)", NULL);
+ cogl_material_set_layer_combine (material, 0,
+ "RGBA = REPLACE (TEXTURE)", NULL);
+
+ /* New API */
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_blend (pipeline,
+ "RGBA = ADD (SRC_COLOR, 0)", NULL);
+ cogl_pipeline_set_layer_combine (pipeline, 0,
+ "RGBA = REPLACE (TEXTURE)", NULL);
+
+ /* If the user explicitly specifies an unmultiplied internal format then
+ * Cogl shouldn't automatically premultiply the given texture data... */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0xff00ff80, "
+ "src = RGBA_8888, internal = RGBA_8888)\n");
+ tex = make_texture (0xff00ff80,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
+ TEXTURE_FLAG_SET_UNPREMULTIPLIED);
+ check_texture (pipeline, material, 0, 0, /* position */
+ tex,
+ 0xff00ff80); /* expected */
+
+ /* If the user explicitly requests a premultiplied internal format and
+ * gives unmultiplied src data then Cogl should always premultiply that
+ * for us */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0xff00ff80, "
+ "src = RGBA_8888, internal = RGBA_8888_PRE)\n");
+ tex = make_texture (0xff00ff80,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
+ TEXTURE_FLAG_SET_PREMULTIPLIED);
+ check_texture (pipeline, material, 1, 0, /* position */
+ tex,
+ 0x80008080); /* expected */
+
+ /* If the user doesn't explicitly declare that the texture is premultiplied
+ * then Cogl should assume it is by default should premultiply
+ * unpremultiplied texture data...
+ */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0xff00ff80, "
+ "src = RGBA_8888, internal = ANY)\n");
+ tex = make_texture (0xff00ff80,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
+ 0); /* default premultiplied status */
+ check_texture (pipeline, material, 2, 0, /* position */
+ tex,
+ 0x80008080); /* expected */
+
+ /* If the user requests a premultiplied internal texture format and supplies
+ * premultiplied source data, Cogl should never modify that source data...
+ */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0x80008080, "
+ "src = RGBA_8888_PRE, "
+ "internal = RGBA_8888_PRE)\n");
+ tex = make_texture (0x80008080,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
+ TEXTURE_FLAG_SET_PREMULTIPLIED);
+ check_texture (pipeline, material, 3, 0, /* position */
+ tex,
+ 0x80008080); /* expected */
+
+ /* If the user requests an unmultiplied internal texture format, but
+ * supplies premultiplied source data, then Cogl should always
+ * un-premultiply the source data... */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0x80008080, "
+ "src = RGBA_8888_PRE, internal = RGBA_8888)\n");
+ tex = make_texture (0x80008080,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
+ TEXTURE_FLAG_SET_UNPREMULTIPLIED);
+ check_texture (pipeline, material, 4, 0, /* position */
+ tex,
+ 0xff00ff80); /* expected */
+
+ /* If the user allows any internal texture format and provides premultipled
+ * source data then by default Cogl shouldn't modify the source data...
+ * (In the future there will be additional Cogl API to control this
+ * behaviour) */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0x80008080, "
+ "src = RGBA_8888_PRE, internal = ANY)\n");
+ tex = make_texture (0x80008080,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
+ 0); /* default premultiplied status */
+ check_texture (pipeline, material, 5, 0, /* position */
+ tex,
+ 0x80008080); /* expected */
+
+ /*
+ * Test cogl_texture_set_region() ....
+ */
+
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0xDEADBEEF, "
+ "src = RGBA_8888, internal = RGBA_8888)\n");
+ tex = make_texture (0xDEADBEEF,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
+ TEXTURE_FLAG_SET_UNPREMULTIPLIED);
+ if (cogl_test_verbose ())
+ g_print ("set_region (0xff00ff80, RGBA_8888)\n");
+ set_region (tex, 0xff00ff80, COGL_PIXEL_FORMAT_RGBA_8888);
+ check_texture (pipeline, material, 6, 0, /* position */
+ tex,
+ 0xff00ff80); /* expected */
+
+ /* Updating a texture region for an unmultiplied texture using premultiplied
+ * region data should result in Cogl unmultiplying the given region data...
+ */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0xDEADBEEF, "
+ "src = RGBA_8888, internal = RGBA_8888)\n");
+ tex = make_texture (0xDEADBEEF,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
+ TEXTURE_FLAG_SET_UNPREMULTIPLIED);
+ if (cogl_test_verbose ())
+ g_print ("set_region (0x80008080, RGBA_8888_PRE)\n");
+ set_region (tex, 0x80008080, COGL_PIXEL_FORMAT_RGBA_8888_PRE);
+ check_texture (pipeline, material, 7, 0, /* position */
+ tex,
+ 0xff00ff80); /* expected */
+
+
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0xDEADBEEF, "
+ "src = RGBA_8888_PRE, "
+ "internal = RGBA_8888_PRE)\n");
+ tex = make_texture (0xDEADBEEF,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
+ TEXTURE_FLAG_SET_PREMULTIPLIED);
+ if (cogl_test_verbose ())
+ g_print ("set_region (0x80008080, RGBA_8888_PRE)\n");
+ set_region (tex, 0x80008080, COGL_PIXEL_FORMAT_RGBA_8888_PRE);
+ check_texture (pipeline, material, 8, 0, /* position */
+ tex,
+ 0x80008080); /* expected */
+
+
+ /* Updating a texture region for a premultiplied texture using unmultiplied
+ * region data should result in Cogl premultiplying the given region data...
+ */
+ if (cogl_test_verbose ())
+ g_print ("make_texture (0xDEADBEEF, "
+ "src = RGBA_8888_PRE, "
+ "internal = RGBA_8888_PRE)\n");
+ tex = make_texture (0xDEADBEEF,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
+ TEXTURE_FLAG_SET_PREMULTIPLIED);
+ if (cogl_test_verbose ())
+ g_print ("set_region (0xff00ff80, RGBA_8888)\n");
+ set_region (tex, 0xff00ff80, COGL_PIXEL_FORMAT_RGBA_8888);
+ check_texture (pipeline, material, 9, 0, /* position */
+ tex,
+ 0x80008080); /* expected */
+
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-primitive-and-journal.c b/cogl/tests/conform/test-primitive-and-journal.c
new file mode 100644
index 000000000..f978cd5ee
--- /dev/null
+++ b/cogl/tests/conform/test-primitive-and-journal.c
@@ -0,0 +1,122 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+typedef CoglVertexP2C4 Vertex;
+
+static void
+setup_orthographic_modelview (void)
+{
+ CoglMatrix matrix;
+ int fb_width = cogl_framebuffer_get_width (test_fb);
+ int fb_height = cogl_framebuffer_get_height (test_fb);
+
+ /* Set up a non-identity modelview matrix. When the journal is
+ * flushed it will usually flush the identity matrix. Using the
+ * non-default matrix ensures that we test that Cogl restores the
+ * matrix we asked for. The matrix sets up an orthographic transform
+ * in the modelview matrix */
+
+ cogl_matrix_init_identity (&matrix);
+ cogl_matrix_orthographic (&matrix,
+ 0.0f, 0.0f, /* x_1 y_1 */
+ fb_width,
+ fb_height,
+ -1.0f, /* nearval */
+ 1.0f /* farval */);
+ cogl_framebuffer_set_modelview_matrix (test_fb, &matrix);
+}
+
+static void
+create_primitives (CoglPrimitive *primitives[2])
+{
+ static const Vertex vertex_data[8] =
+ {
+ /* triangle strip 1 */
+ { 0, 0, 255, 0, 0, 255 },
+ { 0, 100, 255, 0, 0, 255 },
+ { 100, 0, 255, 0, 0, 255 },
+ { 100, 100, 255, 0, 0, 255 },
+ /* triangle strip 2 */
+ { 200, 0, 0, 0, 255, 255 },
+ { 200, 100, 0, 0, 255, 255 },
+ { 300, 0, 0, 0, 255, 255 },
+ { 300, 100, 0, 0, 255, 255 },
+ };
+
+ primitives[0] = cogl_primitive_new_p2c4 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLE_STRIP,
+ G_N_ELEMENTS (vertex_data),
+ vertex_data);
+ cogl_primitive_set_n_vertices (primitives[0], 4);
+
+ primitives[1] = cogl_primitive_copy (primitives[0]);
+ cogl_primitive_set_first_vertex (primitives[1], 4);
+ cogl_primitive_set_n_vertices (primitives[1], 4);
+}
+
+static CoglPipeline *
+create_pipeline (void)
+{
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4ub (pipeline, 0, 255, 0, 255);
+
+ return pipeline;
+}
+
+void
+test_primitive_and_journal (void)
+{
+ CoglPrimitive *primitives[2];
+ CoglPipeline *pipeline;
+
+ setup_orthographic_modelview ();
+ create_primitives (primitives);
+ pipeline = create_pipeline ();
+
+ /* Set a clip to clip all three rectangles to just the bottom half.
+ * The journal flushes its own clip state so this verifies that the
+ * clip state is correctly restored for the second primitive. */
+ cogl_framebuffer_push_rectangle_clip (test_fb,
+ 0, 50, 300, 100);
+
+ cogl_primitive_draw (primitives[0], test_fb, pipeline);
+
+ /* Draw a rectangle using the journal in-between the two primitives.
+ * This should test that the journal gets flushed correctly and that
+ * the modelview matrix is restored. Half of the rectangle should be
+ * overriden by the second primitive */
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ 100, 0, /* x1/y1 */
+ 300, 100 /* x2/y2 */);
+
+ cogl_primitive_draw (primitives[1], test_fb, pipeline);
+
+ /* Check the three rectangles */
+ test_utils_check_region (test_fb,
+ 1, 51,
+ 98, 48,
+ 0xff0000ff);
+ test_utils_check_region (test_fb,
+ 101, 51,
+ 98, 48,
+ 0x00ff00ff);
+ test_utils_check_region (test_fb,
+ 201, 51,
+ 98, 48,
+ 0x0000ffff);
+
+ /* Check that the top half of all of the rectangles was clipped */
+ test_utils_check_region (test_fb,
+ 1, 1,
+ 298, 48,
+ 0x000000ff);
+
+ cogl_framebuffer_pop_clip (test_fb);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-primitive.c b/cogl/tests/conform/test-primitive.c
new file mode 100644
index 000000000..db264fc1c
--- /dev/null
+++ b/cogl/tests/conform/test-primitive.c
@@ -0,0 +1,334 @@
+#include <cogl/cogl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+ int fb_width;
+ int fb_height;
+} TestState;
+
+#define PRIM_COLOR 0xff00ffff
+#define TEX_COLOR 0x0000ffff
+
+#define N_ATTRIBS 8
+
+typedef CoglPrimitive * (* TestPrimFunc) (CoglContext *ctx, uint32_t *expected_color);
+
+static CoglPrimitive *
+test_prim_p2 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP2 verts[] =
+ { { 0, 0 }, { 0, 10 }, { 10, 0 } };
+
+ return cogl_primitive_new_p2 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static CoglPrimitive *
+test_prim_p3 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP3 verts[] =
+ { { 0, 0, 0 }, { 0, 10, 0 }, { 10, 0, 0 } };
+
+ return cogl_primitive_new_p3 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static CoglPrimitive *
+test_prim_p2c4 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP2C4 verts[] =
+ { { 0, 0, 255, 255, 0, 255 },
+ { 0, 10, 255, 255, 0, 255 },
+ { 10, 0, 255, 255, 0, 255 } };
+
+ *expected_color = 0xffff00ff;
+
+ return cogl_primitive_new_p2c4 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static CoglPrimitive *
+test_prim_p3c4 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP3C4 verts[] =
+ { { 0, 0, 0, 255, 255, 0, 255 },
+ { 0, 10, 0, 255, 255, 0, 255 },
+ { 10, 0, 0, 255, 255, 0, 255 } };
+
+ *expected_color = 0xffff00ff;
+
+ return cogl_primitive_new_p3c4 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static CoglPrimitive *
+test_prim_p2t2 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP2T2 verts[] =
+ { { 0, 0, 1, 0 },
+ { 0, 10, 1, 0 },
+ { 10, 0, 1, 0 } };
+
+ *expected_color = TEX_COLOR;
+
+ return cogl_primitive_new_p2t2 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static CoglPrimitive *
+test_prim_p3t2 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP3T2 verts[] =
+ { { 0, 0, 0, 1, 0 },
+ { 0, 10, 0, 1, 0 },
+ { 10, 0, 0, 1, 0 } };
+
+ *expected_color = TEX_COLOR;
+
+ return cogl_primitive_new_p3t2 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static CoglPrimitive *
+test_prim_p2t2c4 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP2T2C4 verts[] =
+ { { 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
+ { 0, 10, 1, 0, 0xff, 0xff, 0xf0, 0xff },
+ { 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } };
+
+ /* The blue component of the texture color should be replaced with 0xf0 */
+ *expected_color = (TEX_COLOR & 0xffff00ff) | 0x0000f000;
+
+ return cogl_primitive_new_p2t2c4 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static CoglPrimitive *
+test_prim_p3t2c4 (CoglContext *ctx, uint32_t *expected_color)
+{
+ static const CoglVertexP3T2C4 verts[] =
+ { { 0, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
+ { 0, 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
+ { 10, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } };
+
+ /* The blue component of the texture color should be replaced with 0xf0 */
+ *expected_color = (TEX_COLOR & 0xffff00ff) | 0x0000f000;
+
+ return cogl_primitive_new_p3t2c4 (test_ctx,
+ COGL_VERTICES_MODE_TRIANGLES,
+ 3, /* n_vertices */
+ verts);
+}
+
+static const TestPrimFunc
+test_prim_funcs[] =
+ {
+ test_prim_p2,
+ test_prim_p3,
+ test_prim_p2c4,
+ test_prim_p3c4,
+ test_prim_p2t2,
+ test_prim_p3t2,
+ test_prim_p2t2c4,
+ test_prim_p3t2c4
+ };
+
+static void
+test_paint (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglTexture *tex;
+ uint8_t tex_data[6];
+ int i;
+
+ /* Create a two pixel texture. The first pixel is white and the
+ second pixel is tex_color. The assumption is that if no texture
+ coordinates are specified then it will default to 0,0 and get
+ white */
+ tex_data[0] = 255;
+ tex_data[1] = 255;
+ tex_data[2] = 255;
+ tex_data[3] = (TEX_COLOR >> 24) & 0xff;
+ tex_data[4] = (TEX_COLOR >> 16) & 0xff;
+ tex_data[5] = (TEX_COLOR >> 8) & 0xff;
+ tex = test_utils_texture_new_from_data (test_ctx,
+ 2, 1, /* size */
+ TEST_UTILS_TEXTURE_NO_ATLAS,
+ COGL_PIXEL_FORMAT_RGB_888,
+ 6, /* rowstride */
+ tex_data);
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_color4ub (pipeline,
+ (PRIM_COLOR >> 24) & 0xff,
+ (PRIM_COLOR >> 16) & 0xff,
+ (PRIM_COLOR >> 8) & 0xff,
+ (PRIM_COLOR >> 0) & 0xff);
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+ cogl_object_unref (tex);
+
+ for (i = 0; i < G_N_ELEMENTS (test_prim_funcs); i++)
+ {
+ CoglPrimitive *prim;
+ uint32_t expected_color = PRIM_COLOR;
+
+ prim = test_prim_funcs[i] (test_ctx, &expected_color);
+
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb, i * 10, 0, 0);
+ cogl_primitive_draw (prim, test_fb, pipeline);
+ cogl_framebuffer_pop_matrix (test_fb);
+
+ test_utils_check_pixel (test_fb, i * 10 + 2, 2, expected_color);
+
+ cogl_object_unref (prim);
+ }
+
+ cogl_object_unref (pipeline);
+}
+
+static CoglBool
+get_attributes_cb (CoglPrimitive *prim,
+ CoglAttribute *attrib,
+ void *user_data)
+{
+ CoglAttribute ***p = user_data;
+ *((* p)++) = attrib;
+ return TRUE;
+}
+
+static int
+compare_pointers (const void *a, const void *b)
+{
+ CoglAttribute *pa = *(CoglAttribute **) a;
+ CoglAttribute *pb = *(CoglAttribute **) b;
+
+ if (pa < pb)
+ return -1;
+ else if (pa > pb)
+ return 1;
+ else
+ return 0;
+}
+
+static void
+test_copy (TestState *state)
+{
+ static const uint16_t indices_data[2] = { 1, 2 };
+ CoglAttributeBuffer *buffer =
+ cogl_attribute_buffer_new (test_ctx, 100, NULL);
+ CoglAttribute *attributes[N_ATTRIBS];
+ CoglAttribute *attributes_a[N_ATTRIBS], *attributes_b[N_ATTRIBS];
+ CoglAttribute **p;
+ CoglPrimitive *prim_a, *prim_b;
+ CoglIndices *indices;
+ int i;
+
+ for (i = 0; i < N_ATTRIBS; i++)
+ {
+ char *name = g_strdup_printf ("foo_%i", i);
+ attributes[i] = cogl_attribute_new (buffer,
+ name,
+ 16, /* stride */
+ 16, /* offset */
+ 2, /* components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ g_free (name);
+ }
+
+ prim_a = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ 8, /* n_vertices */
+ attributes,
+ N_ATTRIBS);
+
+ indices = cogl_indices_new (test_ctx,
+ COGL_INDICES_TYPE_UNSIGNED_SHORT,
+ indices_data,
+ 2 /* n_indices */);
+
+ cogl_primitive_set_first_vertex (prim_a, 12);
+ cogl_primitive_set_indices (prim_a, indices, 2);
+
+ prim_b = cogl_primitive_copy (prim_a);
+
+ p = attributes_a;
+ cogl_primitive_foreach_attribute (prim_a,
+ get_attributes_cb,
+ &p);
+ g_assert_cmpint (p - attributes_a, ==, N_ATTRIBS);
+
+ p = attributes_b;
+ cogl_primitive_foreach_attribute (prim_b,
+ get_attributes_cb,
+ &p);
+ g_assert_cmpint (p - attributes_b, ==, N_ATTRIBS);
+
+ qsort (attributes_a, N_ATTRIBS, sizeof (CoglAttribute *), compare_pointers);
+ qsort (attributes_b, N_ATTRIBS, sizeof (CoglAttribute *), compare_pointers);
+
+ g_assert (memcmp (attributes_a, attributes_b, sizeof (attributes_a)) == 0);
+
+ g_assert_cmpint (cogl_primitive_get_first_vertex (prim_a),
+ ==,
+ cogl_primitive_get_first_vertex (prim_b));
+
+ g_assert_cmpint (cogl_primitive_get_n_vertices (prim_a),
+ ==,
+ cogl_primitive_get_n_vertices (prim_b));
+
+ g_assert_cmpint (cogl_primitive_get_mode (prim_a),
+ ==,
+ cogl_primitive_get_mode (prim_b));
+
+ g_assert (cogl_primitive_get_indices (prim_a) ==
+ cogl_primitive_get_indices (prim_b));
+
+ cogl_object_unref (prim_a);
+ cogl_object_unref (prim_b);
+ cogl_object_unref (indices);
+
+ for (i = 0; i < N_ATTRIBS; i++)
+ cogl_object_unref (attributes[i]);
+
+ cogl_object_unref (buffer);
+}
+
+void
+test_primitive (void)
+{
+ TestState state;
+
+ state.fb_width = cogl_framebuffer_get_width (test_fb);
+ state.fb_height = cogl_framebuffer_get_height (test_fb);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ state.fb_width,
+ state.fb_height,
+ -1,
+ 100);
+
+ test_paint (&state);
+ test_copy (&state);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-read-texture-formats.c b/cogl/tests/conform/test-read-texture-formats.c
new file mode 100644
index 000000000..3fa4d8eea
--- /dev/null
+++ b/cogl/tests/conform/test-read-texture-formats.c
@@ -0,0 +1,222 @@
+#include <cogl/cogl2-experimental.h>
+#include <stdarg.h>
+
+#include "test-utils.h"
+
+/*
+ * This tests reading back an RGBA texture in all of the available
+ * pixel formats
+ */
+
+static const uint8_t tex_data[4] = { 0x12, 0x34, 0x56, 0x78 };
+
+static void
+test_read_byte (CoglTexture2D *tex_2d,
+ CoglPixelFormat format,
+ uint8_t expected_byte)
+{
+ uint8_t received_byte;
+
+ cogl_texture_get_data (tex_2d,
+ format,
+ 1, /* rowstride */
+ &received_byte);
+
+ g_assert_cmpint (expected_byte, ==, received_byte);
+}
+
+static void
+test_read_short (CoglTexture2D *tex_2d,
+ CoglPixelFormat format,
+ ...)
+{
+ va_list ap;
+ int bits;
+ uint16_t received_value;
+ uint16_t expected_value = 0;
+ char *received_value_str;
+ char *expected_value_str;
+ int bits_sum = 0;
+
+ cogl_texture_get_data (tex_2d,
+ format,
+ 2, /* rowstride */
+ (uint8_t *) &received_value);
+
+ va_start (ap, format);
+
+ /* Convert the va args into a single 16-bit expected value */
+ while ((bits = va_arg (ap, int)) != -1)
+ {
+ int value = (va_arg (ap, int) * ((1 << bits) - 1) + 128) / 255;
+
+ bits_sum += bits;
+
+ expected_value |= value << (16 - bits_sum);
+ }
+
+ va_end (ap);
+
+ received_value_str = g_strdup_printf ("0x%04x", received_value);
+ expected_value_str = g_strdup_printf ("0x%04x", expected_value);
+ g_assert_cmpstr (received_value_str, ==, expected_value_str);
+ g_free (received_value_str);
+ g_free (expected_value_str);
+}
+
+static void
+test_read_888 (CoglTexture2D *tex_2d,
+ CoglPixelFormat format,
+ uint32_t expected_pixel)
+{
+ uint8_t pixel[4];
+
+ cogl_texture_get_data (tex_2d,
+ format,
+ 4, /* rowstride */
+ pixel);
+
+ test_utils_compare_pixel (pixel, expected_pixel);
+}
+
+static void
+test_read_88 (CoglTexture2D *tex_2d,
+ CoglPixelFormat format,
+ uint32_t expected_pixel)
+{
+ uint8_t pixel[4];
+
+ pixel[2] = 0x00;
+
+ cogl_texture_get_data (tex_2d,
+ format,
+ 2, /* rowstride */
+ pixel);
+
+ test_utils_compare_pixel (pixel, expected_pixel);
+}
+
+static void
+test_read_8888 (CoglTexture2D *tex_2d,
+ CoglPixelFormat format,
+ uint32_t expected_pixel)
+{
+ uint32_t received_pixel;
+ char *received_value_str;
+ char *expected_value_str;
+
+ cogl_texture_get_data (tex_2d,
+ format,
+ 4, /* rowstride */
+ (uint8_t *) &received_pixel);
+
+ received_pixel = GUINT32_FROM_BE (received_pixel);
+
+ received_value_str = g_strdup_printf ("0x%08x", received_pixel);
+ expected_value_str = g_strdup_printf ("0x%08x", expected_pixel);
+ g_assert_cmpstr (received_value_str, ==, expected_value_str);
+ g_free (received_value_str);
+ g_free (expected_value_str);
+}
+
+static void
+test_read_int (CoglTexture2D *tex_2d,
+ CoglPixelFormat format,
+ ...)
+{
+ va_list ap;
+ int bits;
+ uint32_t received_value;
+ uint32_t expected_value = 0;
+ char *received_value_str;
+ char *expected_value_str;
+ int bits_sum = 0;
+
+ cogl_texture_get_data (tex_2d,
+ format,
+ 4, /* rowstride */
+ (uint8_t *) &received_value);
+
+ va_start (ap, format);
+
+ /* Convert the va args into a single 32-bit expected value */
+ while ((bits = va_arg (ap, int)) != -1)
+ {
+ uint32_t value = (va_arg (ap, int) * ((1 << bits) - 1) + 128) / 255;
+
+ bits_sum += bits;
+
+ expected_value |= value << (32 - bits_sum);
+ }
+
+ va_end (ap);
+
+ received_value_str = g_strdup_printf ("0x%08x", received_value);
+ expected_value_str = g_strdup_printf ("0x%08x", expected_value);
+ g_assert_cmpstr (received_value_str, ==, expected_value_str);
+ g_free (received_value_str);
+ g_free (expected_value_str);
+}
+
+void
+test_read_texture_formats (void)
+{
+ CoglTexture2D *tex_2d;
+
+ tex_2d = cogl_texture_2d_new_from_data (test_ctx,
+ 1, 1, /* width / height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ tex_data,
+ NULL);
+
+ test_read_byte (tex_2d, COGL_PIXEL_FORMAT_A_8, 0x78);
+
+#if 0
+ /* I'm not sure what's the right value to put here because Nvidia
+ and Mesa seem to behave differently so one of them must be
+ wrong. */
+ test_read_byte (tex_2d, COGL_PIXEL_FORMAT_G_8, 0x9c);
+#endif
+
+ /* We should always be able to read into an RG buffer regardless of
+ * whether RG textures are supported because Cogl will do the
+ * conversion for us */
+ test_read_88 (tex_2d, COGL_PIXEL_FORMAT_RG_88, 0x123400ff);
+
+ test_read_short (tex_2d, COGL_PIXEL_FORMAT_RGB_565,
+ 5, 0x12, 6, 0x34, 5, 0x56,
+ -1);
+ test_read_short (tex_2d, COGL_PIXEL_FORMAT_RGBA_4444_PRE,
+ 4, 0x12, 4, 0x34, 4, 0x56, 4, 0x78,
+ -1);
+ test_read_short (tex_2d, COGL_PIXEL_FORMAT_RGBA_5551_PRE,
+ 5, 0x12, 5, 0x34, 5, 0x56, 1, 0x78,
+ -1);
+
+ test_read_888 (tex_2d, COGL_PIXEL_FORMAT_RGB_888, 0x123456ff);
+ test_read_888 (tex_2d, COGL_PIXEL_FORMAT_BGR_888, 0x563412ff);
+
+ test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_RGBA_8888_PRE, 0x12345678);
+ test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_BGRA_8888_PRE, 0x56341278);
+ test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_ARGB_8888_PRE, 0x78123456);
+ test_read_8888 (tex_2d, COGL_PIXEL_FORMAT_ABGR_8888_PRE, 0x78563412);
+
+ test_read_int (tex_2d, COGL_PIXEL_FORMAT_RGBA_1010102_PRE,
+ 10, 0x12, 10, 0x34, 10, 0x56, 2, 0x78,
+ -1);
+ test_read_int (tex_2d, COGL_PIXEL_FORMAT_BGRA_1010102_PRE,
+ 10, 0x56, 10, 0x34, 10, 0x12, 2, 0x78,
+ -1);
+ test_read_int (tex_2d, COGL_PIXEL_FORMAT_ARGB_2101010_PRE,
+ 2, 0x78, 10, 0x12, 10, 0x34, 10, 0x56,
+ -1);
+ test_read_int (tex_2d, COGL_PIXEL_FORMAT_ABGR_2101010_PRE,
+ 2, 0x78, 10, 0x56, 10, 0x34, 10, 0x12,
+ -1);
+
+ cogl_object_unref (tex_2d);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-readpixels.c b/cogl/tests/conform/test-readpixels.c
new file mode 100644
index 000000000..131b08b23
--- /dev/null
+++ b/cogl/tests/conform/test-readpixels.c
@@ -0,0 +1,178 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+
+#include "test-conform-common.h"
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+#define FRAMEBUFFER_WIDTH 640
+#define FRAMEBUFFER_HEIGHT 480
+
+static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
+
+
+static void
+on_paint (ClutterActor *actor, void *state)
+{
+ float saved_viewport[4];
+ CoglMatrix saved_projection;
+ CoglMatrix projection;
+ CoglMatrix modelview;
+ guchar *data;
+ CoglHandle tex;
+ CoglHandle offscreen;
+ uint32_t *pixels;
+ uint8_t *pixelsc;
+
+ /* Save the Clutter viewport/matrices and load identity matrices */
+
+ cogl_get_viewport (saved_viewport);
+ cogl_get_projection_matrix (&saved_projection);
+ cogl_push_matrix ();
+
+ cogl_matrix_init_identity (&projection);
+ cogl_matrix_init_identity (&modelview);
+
+ cogl_set_projection_matrix (&projection);
+ cogl_set_modelview_matrix (&modelview);
+
+ /* All offscreen rendering is done upside down so the first thing we
+ * verify is reading back grid of colors from a CoglOffscreen framebuffer
+ */
+
+ data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
+ tex = test_utils_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
+ TEST_UTILS_TEXTURE_NO_SLICING,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */
+ COGL_PIXEL_FORMAT_ANY, /* internal fmt */
+ FRAMEBUFFER_WIDTH * 4, /* rowstride */
+ data);
+ g_free (data);
+ offscreen = cogl_offscreen_new_with_texture (tex);
+
+ cogl_push_framebuffer (offscreen);
+
+ /* red, top left */
+ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
+ cogl_rectangle (-1, 1, 0, 0);
+ /* green, top right */
+ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
+ cogl_rectangle (0, 1, 1, 0);
+ /* blue, bottom left */
+ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
+ cogl_rectangle (-1, 0, 0, -1);
+ /* white, bottom right */
+ cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
+ cogl_rectangle (0, 0, 1, -1);
+
+ pixels = g_malloc0 (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
+ cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ (guchar *)pixels);
+
+ g_assert_cmpint (pixels[0], ==, 0xff0000ff);
+ g_assert_cmpint (pixels[FRAMEBUFFER_WIDTH - 1], ==, 0xff00ff00);
+ g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH], ==, 0xffff0000);
+ g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH + FRAMEBUFFER_WIDTH - 1], ==, 0xffffffff);
+ g_free (pixels);
+
+ cogl_pop_framebuffer ();
+ cogl_handle_unref (offscreen);
+
+ /* Now verify reading back from an onscreen framebuffer...
+ */
+
+ cogl_set_source_texture (tex);
+ cogl_rectangle (-1, 1, 1, -1);
+
+ pixels = g_malloc0 (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
+ cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ (guchar *)pixels);
+
+ g_assert_cmpint (pixels[0], ==, 0xff0000ff);
+ g_assert_cmpint (pixels[FRAMEBUFFER_WIDTH - 1], ==, 0xff00ff00);
+ g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH], ==, 0xffff0000);
+ g_assert_cmpint (pixels[(FRAMEBUFFER_HEIGHT - 1) * FRAMEBUFFER_WIDTH + FRAMEBUFFER_WIDTH - 1], ==, 0xffffffff);
+ g_free (pixels);
+
+ /* Verify using BGR format */
+
+ cogl_set_source_texture (tex);
+ cogl_rectangle (-1, 1, 1, -1);
+
+ pixelsc = g_malloc0 (FRAMEBUFFER_WIDTH * 3 * FRAMEBUFFER_HEIGHT);
+ cogl_read_pixels (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_BGR_888,
+ (guchar *)pixelsc);
+
+ g_assert_cmpint (pixelsc[0], ==, 0x00);
+ g_assert_cmpint (pixelsc[1], ==, 0x00);
+ g_assert_cmpint (pixelsc[2], ==, 0xff);
+
+ g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 0], ==, 0x00);
+ g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 1], ==, 0xff);
+ g_assert_cmpint (pixelsc[(FRAMEBUFFER_WIDTH - 1) * 3 + 2], ==, 0x00);
+
+ g_free (pixelsc);
+
+ cogl_handle_unref (tex);
+
+ /* Restore the viewport and matrices state */
+ cogl_set_viewport (saved_viewport[0],
+ saved_viewport[1],
+ saved_viewport[2],
+ saved_viewport[3]);
+ cogl_set_projection_matrix (&saved_projection);
+ cogl_pop_matrix ();
+
+ /* Comment this out if you want visual feedback of what this test
+ * paints.
+ */
+ clutter_main_quit ();
+}
+
+static CoglBool
+queue_redraw (void *stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+void
+test_readpixels (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ unsigned int idle_source;
+ ClutterActor *stage;
+
+ stage = clutter_stage_get_default ();
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+
+ /* We force continuous redrawing of the stage, since we need to skip
+ * the first few frames, and we wont be doing anything else that
+ * will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+ g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), NULL);
+
+ clutter_actor_show (stage);
+ clutter_main ();
+
+ g_source_remove (idle_source);
+
+ /* Remove all of the actors from the stage */
+ clutter_container_foreach (CLUTTER_CONTAINER (stage),
+ (ClutterCallback) clutter_actor_destroy,
+ NULL);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-snippets.c b/cogl/tests/conform/test-snippets.c
new file mode 100644
index 000000000..a251fc162
--- /dev/null
+++ b/cogl/tests/conform/test-snippets.c
@@ -0,0 +1,815 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+ int fb_width, fb_height;
+} TestState;
+
+typedef void (* SnippetTestFunc) (TestState *state);
+
+static CoglPipeline *
+create_texture_pipeline (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglTexture *tex;
+ static const uint8_t tex_data[] =
+ {
+ 0xff, 0x00, 0x00, 0xff, /* red */ 0x00, 0xff, 0x00, 0xff, /* green */
+ 0x00, 0x00, 0xff, 0xff, /* blue */ 0xff, 0xff, 0x00, 0xff, /* yellow */
+ };
+
+ tex = test_utils_texture_new_from_data (test_ctx,
+ 2, 2, /* width/height */
+ TEST_UTILS_TEXTURE_NO_ATLAS,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 8, /* rowstride */
+ tex_data);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+
+ cogl_pipeline_set_layer_filters (pipeline, 0,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+
+ cogl_object_unref (tex);
+
+ return pipeline;
+}
+
+static void
+simple_fragment_snippet (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Simple fragment snippet */
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL, /* declarations */
+ "cogl_color_out.g += 1.0;");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10);
+
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff);
+}
+
+static void
+simple_vertex_snippet (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Simple vertex snippet */
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
+ NULL,
+ "cogl_color_out.b += 1.0;");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 10, 0, 20, 10);
+
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 15, 5, 0xff00ffff);
+}
+
+static void
+shared_uniform (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+ int location;
+
+ /* Snippets sharing a uniform across the vertex and fragment
+ hooks */
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ location = cogl_pipeline_get_uniform_location (pipeline, "a_value");
+ cogl_pipeline_set_uniform_1f (pipeline, location, 0.25f);
+
+ cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
+ "uniform float a_value;",
+ "cogl_color_out.b += a_value;");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ "uniform float a_value;",
+ "cogl_color_out.b += a_value;");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ 20, 0, 30, 10);
+
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 25, 5, 0xff0080ff);
+}
+
+static void
+lots_snippets (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+ int location;
+ int i;
+
+ /* Lots of snippets on one pipeline */
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4ub (pipeline, 0, 0, 0, 255);
+
+ for (i = 0; i < 3; i++)
+ {
+ char letter = 'x' + i;
+ char *uniform_name = g_strdup_printf ("%c_value", letter);
+ char *declarations = g_strdup_printf ("uniform float %s;\n",
+ uniform_name);
+ char *code = g_strdup_printf ("cogl_color_out.%c = %s;\n",
+ letter,
+ uniform_name);
+
+ location = cogl_pipeline_get_uniform_location (pipeline, uniform_name);
+ cogl_pipeline_set_uniform_1f (pipeline, location, (i + 1) * 0.1f);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ declarations,
+ code);
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ g_free (code);
+ g_free (uniform_name);
+ g_free (declarations);
+ }
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 30, 0, 40, 10);
+
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 35, 5, 0x19334cff);
+}
+
+static void
+shared_variable_pre_post (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Test that the pre string can declare variables used by the post
+ string */
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4ub (pipeline, 255, 255, 255, 255);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL, /* declarations */
+ "cogl_color_out = redvec;");
+ cogl_snippet_set_pre (snippet, "vec4 redvec = vec4 (1.0, 0.0, 0.0, 1.0);");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 40, 0, 50, 10);
+
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 45, 5, 0xff0000ff);
+}
+
+static void
+test_pipeline_caching (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Check that the pipeline caching works when unrelated pipelines
+ share snippets state. It's too hard to actually assert this in
+ the conformance test but at least it should be possible to see by
+ setting COGL_DEBUG=show-source to check whether this shader gets
+ generated twice */
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ "/* This comment should only be seen ONCE\n"
+ " when COGL_DEBUG=show-source is TRUE\n"
+ " even though it is used in two different\n"
+ " unrelated pipelines */",
+ "cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);\n");
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 50, 0, 60, 10);
+ cogl_object_unref (pipeline);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 60, 0, 70, 10);
+ cogl_object_unref (pipeline);
+
+ cogl_object_unref (snippet);
+
+ test_utils_check_pixel (test_fb, 55, 5, 0x00ff00ff);
+ test_utils_check_pixel (test_fb, 65, 5, 0x00ff00ff);
+}
+
+static void
+test_replace_string (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Check the replace string */
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, NULL);
+ cogl_snippet_set_pre (snippet,
+ "cogl_color_out = vec4 (0.0, 0.5, 0.0, 1.0);");
+ /* Remove the generated output. If the replace string isn't working
+ then the code from the pre string would get overwritten with
+ white */
+ cogl_snippet_set_replace (snippet, "/* do nothing */");
+ cogl_snippet_set_post (snippet,
+ "cogl_color_out += vec4 (0.5, 0.0, 0.0, 1.0);");
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 70, 0, 80, 10);
+ cogl_object_unref (pipeline);
+
+ cogl_object_unref (snippet);
+
+ test_utils_check_pixel (test_fb, 75, 5, 0x808000ff);
+}
+
+static void
+test_texture_lookup_hook (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Check the texture lookup hook */
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
+ NULL,
+ "cogl_texel.b += 1.0;");
+ /* Flip the texture coordinates around the y axis so that it will
+ get the green texel */
+ cogl_snippet_set_pre (snippet, "cogl_tex_coord.x = 1.0 - cogl_tex_coord.x;");
+
+ pipeline = create_texture_pipeline (state);
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ 80, 0, 90, 10,
+ 0, 0, 0, 0);
+ cogl_object_unref (pipeline);
+
+ cogl_object_unref (snippet);
+
+ test_utils_check_pixel (test_fb, 85, 5, 0x00ffffff);
+}
+
+static void
+test_multiple_samples (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Check that we can use the passed in sampler in the texture lookup
+ to sample multiple times */
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
+ NULL,
+ NULL);
+ cogl_snippet_set_replace (snippet,
+ "cogl_texel = "
+ "texture2D (cogl_sampler, vec2 (0.25, 0.25)) + "
+ "texture2D (cogl_sampler, vec2 (0.75, 0.25));");
+
+ pipeline = create_texture_pipeline (state);
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10);
+ cogl_object_unref (pipeline);
+
+ cogl_object_unref (snippet);
+
+ test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff);
+}
+
+static void
+test_replace_lookup_hook (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Check replacing the texture lookup hook */
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, NULL, NULL);
+ cogl_snippet_set_replace (snippet, "cogl_texel = vec4 (0.0, 0.0, 1.0, 0.0);");
+
+ pipeline = create_texture_pipeline (state);
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ 90, 0, 100, 10,
+ 0, 0, 0, 0);
+ cogl_object_unref (pipeline);
+
+ cogl_object_unref (snippet);
+
+ test_utils_check_pixel (test_fb, 95, 5, 0x0000ffff);
+}
+
+static void
+test_replace_snippet (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Test replacing a previous snippet */
+ pipeline = create_texture_pipeline (state);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL,
+ "cogl_color_out = vec4 (0.5, 0.5, 0.5, 1.0);");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, NULL);
+ cogl_snippet_set_pre (snippet, "cogl_color_out = vec4 (1.0, 1.0, 1.0, 1.0);");
+ cogl_snippet_set_replace (snippet,
+ "cogl_color_out *= vec4 (1.0, 0.0, 0.0, 1.0);");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ 100, 0, 110, 10,
+ 0, 0, 0, 0);
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 105, 5, 0xff0000ff);
+}
+
+static void
+test_replace_fragment_layer (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Test replacing the fragment layer code */
+ pipeline = create_texture_pipeline (state);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT, NULL, NULL);
+ cogl_snippet_set_replace (snippet, "cogl_layer = vec4 (0.0, 0.0, 1.0, 1.0);");
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+ cogl_object_unref (snippet);
+
+ /* Add a second layer which samples from the texture in the first
+ layer. The snippet override should cause the first layer not to
+ generate the code for the texture lookup but this second layer
+ should still be able to cause it to be generated */
+ cogl_pipeline_set_layer_combine (pipeline, 1,
+ "RGB = ADD(TEXTURE_0, PREVIOUS)"
+ "A = REPLACE(PREVIOUS)",
+ NULL);
+
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ 110, 0, 120, 10,
+ 0, 0, 0, 0);
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 115, 5, 0xff00ffff);
+}
+
+static void
+test_modify_fragment_layer (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Test modifying the fragment layer code */
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_uniform_1f (pipeline,
+ cogl_pipeline_get_uniform_location (pipeline,
+ "a_value"),
+ 0.5);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
+ "uniform float a_value;",
+ "cogl_layer.g = a_value;");
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ 120, 0, 130, 10,
+ 0, 0, 0, 0);
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 125, 5, 0xff80ffff);
+}
+
+static void
+test_modify_vertex_layer (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+ CoglMatrix matrix;
+
+ /* Test modifying the vertex layer code */
+ pipeline = create_texture_pipeline (state);
+
+ cogl_matrix_init_identity (&matrix);
+ cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f);
+ cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM,
+ NULL,
+ "cogl_tex_coord.x = 1.0;");
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ 130, 0, 140, 10,
+ 0, 0, 0, 0);
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 135, 5, 0xffff00ff);
+}
+
+static void
+test_replace_vertex_layer (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+ CoglMatrix matrix;
+
+ /* Test replacing the vertex layer code */
+ pipeline = create_texture_pipeline (state);
+
+ cogl_matrix_init_identity (&matrix);
+ cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f);
+ cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM,
+ NULL,
+ NULL);
+ cogl_snippet_set_replace (snippet, "cogl_tex_coord.x = 1.0;\n");
+ cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ 140, 0, 150, 10,
+ 0, 0, 0, 0);
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 145, 5, 0x00ff00ff);
+}
+
+static void
+test_vertex_transform_hook (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+ CoglMatrix identity_matrix;
+ CoglMatrix matrix;
+ int location;
+
+ /* Test the vertex transform hook */
+
+ cogl_matrix_init_identity (&identity_matrix);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4ub (pipeline, 255, 0, 255, 255);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_TRANSFORM,
+ "uniform mat4 pmat;",
+ NULL);
+ cogl_snippet_set_replace (snippet, "cogl_position_out = "
+ "pmat * cogl_position_in;");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ /* Copy the current projection matrix to a uniform */
+ cogl_framebuffer_get_projection_matrix (test_fb, &matrix);
+ location = cogl_pipeline_get_uniform_location (pipeline, "pmat");
+ cogl_pipeline_set_uniform_matrix (pipeline,
+ location,
+ 4, /* dimensions */
+ 1, /* count */
+ FALSE, /* don't transpose */
+ cogl_matrix_get_array (&matrix));
+
+ /* Replace the real projection matrix with the identity. This should
+ mess up the drawing unless the snippet replacement is working */
+ cogl_framebuffer_set_projection_matrix (test_fb, &identity_matrix);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 150, 0, 160, 10);
+ cogl_object_unref (pipeline);
+
+ /* Restore the projection matrix */
+ cogl_framebuffer_set_projection_matrix (test_fb, &matrix);
+
+ test_utils_check_pixel (test_fb, 155, 5, 0xff00ffff);
+}
+
+static void
+test_global_vertex_hook (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ /* Creates a function in the global declarations hook which is used
+ * by a subsequent snippet. The subsequent snippets replace any
+ * previous snippets but this shouldn't prevent the global
+ * declarations from being generated */
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
+ /* declarations */
+ "float\n"
+ "multiply_by_two (float number)\n"
+ "{\n"
+ " return number * 2.0;\n"
+ "}\n",
+ /* post */
+ "This string shouldn't be used so "
+ "we can safely put garbage in here.");
+ cogl_snippet_set_pre (snippet,
+ "This string shouldn't be used so "
+ "we can safely put garbage in here.");
+ cogl_snippet_set_replace (snippet,
+ "This string shouldn't be used so "
+ "we can safely put garbage in here.");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
+ NULL, /* declarations */
+ NULL /* replace */);
+ cogl_snippet_set_replace (snippet,
+ "cogl_color_out.r = multiply_by_two (0.5);\n"
+ "cogl_color_out.gba = vec3 (0.0, 0.0, 1.0);\n"
+ "cogl_position_out = cogl_position_in;\n");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1, 1,
+ 10.0f * 2.0f / state->fb_width - 1.0f,
+ 10.0f * 2.0f / state->fb_height - 1.0f);
+
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 5, 5, 0xff0000ff);
+}
+
+static void
+test_global_fragment_hook (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ /* Creates a function in the global declarations hook which is used
+ * by a subsequent snippet. The subsequent snippets replace any
+ * previous snippets but this shouldn't prevent the global
+ * declarations from being generated */
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
+ /* declarations */
+ "float\n"
+ "multiply_by_four (float number)\n"
+ "{\n"
+ " return number * 4.0;\n"
+ "}\n",
+ /* post */
+ "This string shouldn't be used so "
+ "we can safely put garbage in here.");
+ cogl_snippet_set_pre (snippet,
+ "This string shouldn't be used so "
+ "we can safely put garbage in here.");
+ cogl_snippet_set_replace (snippet,
+ "This string shouldn't be used so "
+ "we can safely put garbage in here.");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL, /* declarations */
+ NULL /* replace */);
+ cogl_snippet_set_replace (snippet,
+ "cogl_color_out.r = multiply_by_four (0.25);\n"
+ "cogl_color_out.gba = vec3 (0.0, 0.0, 1.0);\n");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ 0, 0, 10, 10);
+
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 5, 5, 0xff0000ff);
+}
+
+static void
+test_snippet_order (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+
+ /* Verify that the snippets are executed in the right order. We'll
+ replace the r component of the color in the pre sections of the
+ snippets and the g component in the post. The pre sections should
+ be executed in the reverse order they were added and the post
+ sections in the same order as they were added. Therefore the r
+ component should be taken from the the second snippet and the g
+ component from the first */
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_color4ub (pipeline, 0, 0, 0, 255);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL,
+ "cogl_color_out.g = 0.5;\n");
+ cogl_snippet_set_pre (snippet, "cogl_color_out.r = 0.5;\n");
+ cogl_snippet_set_replace (snippet, "cogl_color_out.ba = vec2 (0.0, 1.0);");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL,
+ "cogl_color_out.g = 1.0;\n");
+ cogl_snippet_set_pre (snippet, "cogl_color_out.r = 1.0;\n");
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ cogl_object_unref (snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 160, 0, 170, 10);
+ cogl_object_unref (pipeline);
+
+ test_utils_check_pixel (test_fb, 165, 5, 0x80ff00ff);
+}
+
+static void
+test_naming_texture_units (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglSnippet *snippet;
+ CoglTexture *tex1, *tex2;
+
+ /* Test that we can sample from an arbitrary texture unit by naming
+ its layer number */
+
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+ NULL,
+ NULL);
+ cogl_snippet_set_replace (snippet,
+ "cogl_color_out = "
+ "texture2D (cogl_sampler100, vec2 (0.0, 0.0)) + "
+ "texture2D (cogl_sampler200, vec2 (0.0, 0.0));");
+
+ tex1 = test_utils_create_color_texture (test_ctx, 0xff0000ff);
+ tex2 = test_utils_create_color_texture (test_ctx, 0x00ff00ff);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_texture (pipeline, 100, tex1);
+ cogl_pipeline_set_layer_texture (pipeline, 200, tex2);
+
+ cogl_pipeline_add_snippet (pipeline, snippet);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10);
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (snippet);
+ cogl_object_unref (tex1);
+ cogl_object_unref (tex2);
+
+ test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff);
+}
+
+static void
+test_snippet_properties (TestState *state)
+{
+ CoglSnippet *snippet;
+
+ /* Sanity check modifying the snippet */
+ snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "foo", "bar");
+ g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo");
+ g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar");
+ g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL);
+ g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL);
+
+ cogl_snippet_set_declarations (snippet, "fu");
+ g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu");
+ g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar");
+ g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL);
+ g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL);
+
+ cogl_snippet_set_post (snippet, "ba");
+ g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu");
+ g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba");
+ g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL);
+ g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL);
+
+ cogl_snippet_set_pre (snippet, "fuba");
+ g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu");
+ g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba");
+ g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL);
+ g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba");
+
+ cogl_snippet_set_replace (snippet, "baba");
+ g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu");
+ g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba");
+ g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, "baba");
+ g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba");
+
+ g_assert_cmpint (cogl_snippet_get_hook (snippet),
+ ==,
+ COGL_SNIPPET_HOOK_FRAGMENT);
+}
+
+static SnippetTestFunc
+tests[] =
+ {
+ simple_fragment_snippet,
+ simple_vertex_snippet,
+ shared_uniform,
+ lots_snippets,
+ shared_variable_pre_post,
+ test_pipeline_caching,
+ test_replace_string,
+ test_texture_lookup_hook,
+ test_multiple_samples,
+ test_replace_lookup_hook,
+ test_replace_snippet,
+ test_replace_fragment_layer,
+ test_modify_fragment_layer,
+ test_modify_vertex_layer,
+ test_replace_vertex_layer,
+ test_vertex_transform_hook,
+ test_global_fragment_hook,
+ test_global_vertex_hook,
+ test_snippet_order,
+ test_naming_texture_units,
+ test_snippet_properties
+ };
+
+static void
+run_tests (TestState *state)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (tests); i++)
+ {
+ cogl_framebuffer_clear4f (test_fb,
+ COGL_BUFFER_BIT_COLOR,
+ 0, 0, 0, 1);
+
+ tests[i] (state);
+ }
+}
+
+void
+test_snippets (void)
+{
+ TestState state;
+
+ state.fb_width = cogl_framebuffer_get_width (test_fb);
+ state.fb_height = cogl_framebuffer_get_height (test_fb);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ state.fb_width,
+ state.fb_height,
+ -1,
+ 100);
+
+ run_tests (&state);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-sparse-pipeline.c b/cogl/tests/conform/test-sparse-pipeline.c
new file mode 100644
index 000000000..04c81d27c
--- /dev/null
+++ b/cogl/tests/conform/test-sparse-pipeline.c
@@ -0,0 +1,62 @@
+#include <cogl/cogl2-experimental.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+typedef struct _TestState
+{
+ int fb_width;
+ int fb_height;
+} TestState;
+
+static void
+test_sparse_layer_combine (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglTexture *tex1, *tex2;
+
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+
+ /* This tests that the TEXTURE_* numbers used in the layer combine
+ string refer to the layer number rather than the unit numbers by
+ creating a pipeline with very large layer numbers. This should
+ end up being mapped to much smaller unit numbers */
+
+ tex1 = test_utils_create_color_texture (test_ctx, 0xff0000ff);
+ tex2 = test_utils_create_color_texture (test_ctx, 0x00ff00ff);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_texture (pipeline, 50, tex1);
+ cogl_pipeline_set_layer_texture (pipeline, 100, tex2);
+ cogl_pipeline_set_layer_combine (pipeline, 200,
+ "RGBA = ADD(TEXTURE_50, TEXTURE_100)",
+ NULL);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, -1, -1, 1, 1);
+
+ test_utils_check_pixel (test_fb, 2, 2, 0xffff00ff);
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (tex1);
+ cogl_object_unref (tex2);
+}
+
+void
+test_sparse_pipeline (void)
+{
+ TestState state;
+
+ state.fb_width = cogl_framebuffer_get_width (test_fb);
+ state.fb_height = cogl_framebuffer_get_height (test_fb);
+
+ test_sparse_layer_combine (&state);
+
+ /* FIXME: This should have a lot more tests, for example testing
+ whether using an attribute with sparse texture coordinates will
+ work */
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-sub-texture.c b/cogl/tests/conform/test-sub-texture.c
new file mode 100644
index 000000000..f049f3fae
--- /dev/null
+++ b/cogl/tests/conform/test-sub-texture.c
@@ -0,0 +1,325 @@
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+#define SOURCE_SIZE 32
+#define SOURCE_DIVISIONS_X 2
+#define SOURCE_DIVISIONS_Y 2
+#define DIVISION_WIDTH (SOURCE_SIZE / SOURCE_DIVISIONS_X)
+#define DIVISION_HEIGHT (SOURCE_SIZE / SOURCE_DIVISIONS_Y)
+
+#define TEST_INSET 1
+
+static const uint32_t
+corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] =
+ {
+ 0xff0000ff, /* red top left */
+ 0x00ff00ff, /* green top right */
+ 0x0000ffff, /* blue bottom left */
+ 0xff00ffff /* purple bottom right */
+ };
+
+typedef struct _TestState
+{
+ CoglTexture2D *tex;
+} TestState;
+
+static CoglTexture2D *
+create_source (TestState *state)
+{
+ int dx, dy;
+ uint8_t *data = g_malloc (SOURCE_SIZE * SOURCE_SIZE * 4);
+ CoglTexture2D *tex;
+
+ /* Create a texture with a different coloured rectangle at each
+ corner */
+ for (dy = 0; dy < SOURCE_DIVISIONS_Y; dy++)
+ for (dx = 0; dx < SOURCE_DIVISIONS_X; dx++)
+ {
+ uint8_t *p = (data + dy * DIVISION_HEIGHT * SOURCE_SIZE * 4 +
+ dx * DIVISION_WIDTH * 4);
+ int x, y;
+
+ for (y = 0; y < DIVISION_HEIGHT; y++)
+ {
+ for (x = 0; x < DIVISION_WIDTH; x++)
+ {
+ uint32_t color = GUINT32_FROM_BE (corner_colors[dx + dy * SOURCE_DIVISIONS_X]);
+ memcpy (p, &color, 4);
+ p += 4;
+ }
+
+ p += SOURCE_SIZE * 4 - DIVISION_WIDTH * 4;
+ }
+ }
+
+ tex = cogl_texture_2d_new_from_data (test_ctx,
+ SOURCE_SIZE, SOURCE_SIZE,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ SOURCE_SIZE * 4,
+ data,
+ NULL);
+ return tex;
+}
+
+static CoglTexture2D *
+create_test_texture (TestState *state)
+{
+ CoglTexture2D *tex;
+ uint8_t *data = g_malloc (256 * 256 * 4), *p = data;
+ int x, y;
+
+ /* Create a texture that is 256x256 where the red component ranges
+ from 0->255 along the x axis and the green component ranges from
+ 0->255 along the y axis. The blue and alpha components are all
+ 255 */
+ for (y = 0; y < 256; y++)
+ for (x = 0; x < 256; x++)
+ {
+ *(p++) = x;
+ *(p++) = y;
+ *(p++) = 255;
+ *(p++) = 255;
+ }
+
+ tex = cogl_texture_2d_new_from_data (test_ctx,
+ 256, 256,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 256 * 4,
+ data,
+ NULL);
+ g_free (data);
+
+ return tex;
+}
+
+static void
+paint (TestState *state)
+{
+ CoglTexture2D *full_texture;
+ CoglSubTexture *sub_texture, *sub_sub_texture;
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+
+ /* Create a sub texture of the bottom right quarter of the texture */
+ sub_texture = cogl_sub_texture_new (test_ctx,
+ state->tex,
+ DIVISION_WIDTH,
+ DIVISION_HEIGHT,
+ DIVISION_WIDTH,
+ DIVISION_HEIGHT);
+
+ /* Paint it */
+ cogl_pipeline_set_layer_texture (pipeline, 0, sub_texture);
+ cogl_object_unref (sub_texture);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline,
+ 0.0f, 0.0f, DIVISION_WIDTH, DIVISION_HEIGHT);
+
+
+ /* Repeat a sub texture of the top half of the full texture. This is
+ documented to be undefined so it doesn't technically have to work
+ but it will with the current implementation */
+ sub_texture = cogl_sub_texture_new (test_ctx,
+ state->tex,
+ 0, 0,
+ SOURCE_SIZE,
+ DIVISION_HEIGHT);
+ cogl_pipeline_set_layer_texture (pipeline, 0, sub_texture);
+ cogl_object_unref (sub_texture);
+ cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline,
+ 0.0f,
+ SOURCE_SIZE,
+ SOURCE_SIZE * 2.0f,
+ SOURCE_SIZE * 1.5f,
+ 0.0f, 0.0f,
+ 2.0f, 1.0f);
+
+ /* Create a sub texture of a sub texture */
+ full_texture = create_test_texture (state);
+ sub_texture = cogl_sub_texture_new (test_ctx,
+ full_texture,
+ 20, 10, 30, 20);
+ cogl_object_unref (full_texture);
+ sub_sub_texture = cogl_sub_texture_new (test_ctx,
+ sub_texture,
+ 20, 10, 10, 10);
+ cogl_object_unref (sub_texture);
+ cogl_pipeline_set_layer_texture (pipeline, 0, sub_sub_texture);
+ cogl_object_unref (sub_sub_texture);
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline,
+ 0.0f, SOURCE_SIZE * 2.0f,
+ 10.0f, SOURCE_SIZE * 2.0f + 10.0f);
+
+ cogl_object_unref (pipeline);
+}
+
+static void
+validate_part (int xpos, int ypos,
+ int width, int height,
+ uint32_t color)
+{
+ test_utils_check_region (test_fb,
+ xpos + TEST_INSET,
+ ypos + TEST_INSET,
+ width - TEST_INSET - 2,
+ height - TEST_INSET - 2,
+ color);
+}
+
+static uint8_t *
+create_update_data (void)
+{
+ uint8_t *data = g_malloc (256 * 256 * 4), *p = data;
+ int x, y;
+
+ /* Create some image data that is 256x256 where the blue component
+ ranges from 0->255 along the x axis and the alpha component
+ ranges from 0->255 along the y axis. The red and green components
+ are all zero */
+ for (y = 0; y < 256; y++)
+ for (x = 0; x < 256; x++)
+ {
+ *(p++) = 0;
+ *(p++) = 0;
+ *(p++) = x;
+ *(p++) = y;
+ }
+
+ return data;
+}
+
+static void
+validate_result (TestState *state)
+{
+ int i, division_num, x, y;
+ CoglTexture2D *test_tex;
+ CoglSubTexture *sub_texture;
+ uint8_t *texture_data, *p;
+ int tex_width, tex_height;
+
+ /* Sub texture of the bottom right corner of the texture */
+ validate_part (0, 0, DIVISION_WIDTH, DIVISION_HEIGHT,
+ corner_colors[
+ (SOURCE_DIVISIONS_Y - 1) * SOURCE_DIVISIONS_X +
+ SOURCE_DIVISIONS_X - 1]);
+
+ /* Sub texture of the top half repeated horizontally */
+ for (i = 0; i < 2; i++)
+ for (division_num = 0; division_num < SOURCE_DIVISIONS_X; division_num++)
+ validate_part (i * SOURCE_SIZE + division_num * DIVISION_WIDTH,
+ SOURCE_SIZE,
+ DIVISION_WIDTH, DIVISION_HEIGHT,
+ corner_colors[division_num]);
+
+ /* Sub sub texture */
+ p = texture_data = g_malloc (10 * 10 * 4);
+ cogl_flush ();
+ cogl_framebuffer_read_pixels (test_fb,
+ 0, SOURCE_SIZE * 2, 10, 10,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ p);
+ for (y = 0; y < 10; y++)
+ for (x = 0; x < 10; x++)
+ {
+ g_assert (*(p++) == x + 40);
+ g_assert (*(p++) == y + 20);
+ p += 2;
+ }
+ g_free (texture_data);
+
+ /* Try reading back the texture data */
+ sub_texture = cogl_sub_texture_new (test_ctx,
+ state->tex,
+ SOURCE_SIZE / 4,
+ SOURCE_SIZE / 4,
+ SOURCE_SIZE / 2,
+ SOURCE_SIZE / 2);
+ tex_width = cogl_texture_get_width (sub_texture);
+ tex_height = cogl_texture_get_height (sub_texture);
+ p = texture_data = g_malloc (tex_width * tex_height * 4);
+ cogl_texture_get_data (sub_texture,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ tex_width * 4,
+ texture_data);
+ for (y = 0; y < tex_height; y++)
+ for (x = 0; x < tex_width; x++)
+ {
+ int div_x = ((x * SOURCE_SIZE / 2 / tex_width + SOURCE_SIZE / 4) /
+ DIVISION_WIDTH);
+ int div_y = ((y * SOURCE_SIZE / 2 / tex_height + SOURCE_SIZE / 4) /
+ DIVISION_HEIGHT);
+ uint32_t reference = corner_colors[div_x + div_y * SOURCE_DIVISIONS_X] >> 8;
+ uint32_t color = GUINT32_FROM_BE (*((uint32_t *)p)) >> 8;
+ g_assert (color == reference);
+ p += 4;
+ }
+ g_free (texture_data);
+ cogl_object_unref (sub_texture);
+
+ /* Create a 256x256 test texture */
+ test_tex = create_test_texture (state);
+ /* Create a sub texture the views the center half of the texture */
+ sub_texture = cogl_sub_texture_new (test_ctx,
+ test_tex,
+ 64, 64, 128, 128);
+ /* Update the center half of the sub texture */
+ texture_data = create_update_data ();
+ cogl_texture_set_region (sub_texture,
+ 0, 0, 32, 32, 64, 64, 256, 256,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE, 256 * 4,
+ texture_data);
+ g_free (texture_data);
+ cogl_object_unref (sub_texture);
+ /* Get the texture data */
+ p = texture_data = g_malloc (256 * 256 * 4);
+ cogl_texture_get_data (test_tex,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 256 * 4, texture_data);
+
+ /* Verify the texture data */
+ for (y = 0; y < 256; y++)
+ for (x = 0; x < 256; x++)
+ {
+ /* If we're in the center quarter */
+ if (x >= 96 && x < 160 && y >= 96 && y < 160)
+ {
+ g_assert ((*p++) == 0);
+ g_assert ((*p++) == 0);
+ g_assert ((*p++) == x - 96);
+ g_assert ((*p++) == y - 96);
+ }
+ else
+ {
+ g_assert ((*p++) == x);
+ g_assert ((*p++) == y);
+ g_assert ((*p++) == 255);
+ g_assert ((*p++) == 255);
+ }
+ }
+ g_free (texture_data);
+ cogl_object_unref (test_tex);
+}
+
+void
+test_sub_texture (void)
+{
+ TestState state;
+
+ state.tex = create_source (&state);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ cogl_framebuffer_get_width (test_fb),
+ cogl_framebuffer_get_height (test_fb),
+ -1,
+ 100);
+
+ paint (&state);
+ validate_result (&state);
+
+ cogl_object_unref (state.tex);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-texture-3d.c b/cogl/tests/conform/test-texture-3d.c
new file mode 100644
index 000000000..8cc5bb595
--- /dev/null
+++ b/cogl/tests/conform/test-texture-3d.c
@@ -0,0 +1,274 @@
+#include <cogl/cogl2-experimental.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+#define TEX_WIDTH 4
+#define TEX_HEIGHT 8
+#define TEX_DEPTH 16
+/* Leave four bytes of padding between each row */
+#define TEX_ROWSTRIDE (TEX_WIDTH * 4 + 4)
+/* Leave four rows of padding between each image */
+#define TEX_IMAGE_STRIDE ((TEX_HEIGHT + 4) * TEX_ROWSTRIDE)
+
+typedef struct _TestState
+{
+ int fb_width;
+ int fb_height;
+} TestState;
+
+static CoglTexture3D *
+create_texture_3d (CoglContext *context)
+{
+ int x, y, z;
+ uint8_t *data = g_malloc (TEX_IMAGE_STRIDE * TEX_DEPTH);
+ uint8_t *p = data;
+ CoglTexture3D *tex;
+ CoglError *error = NULL;
+
+ for (z = 0; z < TEX_DEPTH; z++)
+ {
+ for (y = 0; y < TEX_HEIGHT; y++)
+ {
+ for (x = 0; x < TEX_WIDTH; x++)
+ {
+ /* Set red, green, blue to values based on x, y, z */
+ *(p++) = 255 - x * 8;
+ *(p++) = y * 8;
+ *(p++) = 255 - z * 8;
+ /* Fully opaque */
+ *(p++) = 0xff;
+ }
+
+ /* Set the padding between rows to 0xde */
+ memset (p, 0xde, TEX_ROWSTRIDE - (TEX_WIDTH * 4));
+ p += TEX_ROWSTRIDE - (TEX_WIDTH * 4);
+ }
+ /* Set the padding between images to 0xad */
+ memset (p, 0xba, TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE));
+ p += TEX_IMAGE_STRIDE - (TEX_HEIGHT * TEX_ROWSTRIDE);
+ }
+
+ tex = cogl_texture_3d_new_from_data (context,
+ TEX_WIDTH, TEX_HEIGHT, TEX_DEPTH,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ TEX_ROWSTRIDE,
+ TEX_IMAGE_STRIDE,
+ data,
+ &error);
+
+ if (tex == NULL)
+ {
+ g_assert (error != NULL);
+ g_warning ("Failed to create 3D texture: %s", error->message);
+ g_assert_not_reached ();
+ }
+
+ g_free (data);
+
+ return tex;
+}
+
+static void
+draw_frame (TestState *state)
+{
+ CoglTexture *tex = create_texture_3d (test_ctx);
+ CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
+ typedef struct { float x, y, s, t, r; } Vert;
+ CoglPrimitive *primitive;
+ CoglAttributeBuffer *attribute_buffer;
+ CoglAttribute *attributes[2];
+ Vert *verts, *v;
+ int i;
+
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+ cogl_object_unref (tex);
+ cogl_pipeline_set_layer_filters (pipeline, 0,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+
+ /* Render the texture repeated horizontally twice using a regular
+ cogl rectangle. This should end up with the r texture coordinates
+ as zero */
+ cogl_framebuffer_draw_textured_rectangle (test_fb, pipeline,
+ 0.0f, 0.0f, TEX_WIDTH * 2, TEX_HEIGHT,
+ 0.0f, 0.0f, 2.0f, 1.0f);
+
+ /* Render all of the images in the texture using coordinates from a
+ CoglPrimitive */
+ v = verts = g_new (Vert, 4 * TEX_DEPTH);
+ for (i = 0; i < TEX_DEPTH; i++)
+ {
+ float r = (i + 0.5f) / TEX_DEPTH;
+
+ v->x = i * TEX_WIDTH;
+ v->y = TEX_HEIGHT;
+ v->s = 0;
+ v->t = 0;
+ v->r = r;
+ v++;
+
+ v->x = i * TEX_WIDTH;
+ v->y = TEX_HEIGHT * 2;
+ v->s = 0;
+ v->t = 1;
+ v->r = r;
+ v++;
+
+ v->x = i * TEX_WIDTH + TEX_WIDTH;
+ v->y = TEX_HEIGHT * 2;
+ v->s = 1;
+ v->t = 1;
+ v->r = r;
+ v++;
+
+ v->x = i * TEX_WIDTH + TEX_WIDTH;
+ v->y = TEX_HEIGHT;
+ v->s = 1;
+ v->t = 0;
+ v->r = r;
+ v++;
+ }
+
+ attribute_buffer = cogl_attribute_buffer_new (test_ctx,
+ 4 * TEX_DEPTH * sizeof (Vert),
+ verts);
+ attributes[0] = cogl_attribute_new (attribute_buffer,
+ "cogl_position_in",
+ sizeof (Vert),
+ G_STRUCT_OFFSET (Vert, x),
+ 2, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ attributes[1] = cogl_attribute_new (attribute_buffer,
+ "cogl_tex_coord_in",
+ sizeof (Vert),
+ G_STRUCT_OFFSET (Vert, s),
+ 3, /* n_components */
+ COGL_ATTRIBUTE_TYPE_FLOAT);
+ primitive = cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
+ 6 * TEX_DEPTH,
+ attributes,
+ 2 /* n_attributes */);
+
+ cogl_primitive_set_indices (primitive,
+ cogl_get_rectangle_indices (test_ctx,
+ TEX_DEPTH),
+ 6 * TEX_DEPTH);
+
+ cogl_primitive_draw (primitive, test_fb, pipeline);
+
+ g_free (verts);
+
+ cogl_object_unref (primitive);
+ cogl_object_unref (attributes[0]);
+ cogl_object_unref (attributes[1]);
+ cogl_object_unref (attribute_buffer);
+ cogl_object_unref (pipeline);
+}
+
+static void
+validate_block (int block_x, int block_y, int z)
+{
+ int x, y;
+
+ for (y = 0; y < TEX_HEIGHT; y++)
+ for (x = 0; x < TEX_WIDTH; x++)
+ test_utils_check_pixel_rgb (test_fb,
+ block_x * TEX_WIDTH + x,
+ block_y * TEX_HEIGHT + y,
+ 255 - x * 8,
+ y * 8,
+ 255 - z * 8);
+}
+
+static void
+validate_result (void)
+{
+ int i;
+
+ validate_block (0, 0, 0);
+
+ for (i = 0; i < TEX_DEPTH; i++)
+ validate_block (i, 1, i);
+}
+
+static void
+test_multi_texture (TestState *state)
+{
+ CoglPipeline *pipeline;
+ CoglTexture3D *tex_3d;
+ CoglTexture2D *tex_2d;
+ uint8_t tex_data[4];
+
+ cogl_framebuffer_clear4f (test_fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
+
+ /* Tests a pipeline that is using multi-texturing to combine a 3D
+ texture with a 2D texture. The texture from another layer is
+ sampled with TEXTURE_? just to pick up a specific bug that was
+ happening with the ARBfp fragend */
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ tex_data[0] = 0xff;
+ tex_data[1] = 0x00;
+ tex_data[2] = 0x00;
+ tex_data[3] = 0xff;
+ tex_2d = cogl_texture_2d_new_from_data (test_ctx,
+ 1, 1, /* width/height */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ tex_data,
+ NULL);
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex_2d);
+
+ tex_data[0] = 0x00;
+ tex_data[1] = 0xff;
+ tex_data[2] = 0x00;
+ tex_data[3] = 0xff;
+ tex_3d = cogl_texture_3d_new_from_data (test_ctx,
+ 1, 1, 1, /* width/height/depth */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ 4, /* image_stride */
+ tex_data,
+ NULL);
+ cogl_pipeline_set_layer_texture (pipeline, 1, tex_3d);
+
+ cogl_pipeline_set_layer_combine (pipeline, 0,
+ "RGBA = REPLACE(PREVIOUS)",
+ NULL);
+ cogl_pipeline_set_layer_combine (pipeline, 1,
+ "RGBA = ADD(TEXTURE_0, TEXTURE_1)",
+ NULL);
+
+ cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 10, 10);
+
+ test_utils_check_pixel (test_fb, 5, 5, 0xffff00ff);
+
+ cogl_object_unref (tex_2d);
+ cogl_object_unref (tex_3d);
+ cogl_object_unref (pipeline);
+}
+
+void
+test_texture_3d (void)
+{
+ TestState state;
+
+ state.fb_width = cogl_framebuffer_get_width (test_fb);
+ state.fb_height = cogl_framebuffer_get_height (test_fb);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, /* x_1, y_1 */
+ state.fb_width, /* x_2 */
+ state.fb_height /* y_2 */,
+ -1, 100 /* near/far */);
+
+ draw_frame (&state);
+ validate_result ();
+
+ test_multi_texture (&state);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-texture-get-set-data.c b/cogl/tests/conform/test-texture-get-set-data.c
new file mode 100644
index 000000000..59bd0f635
--- /dev/null
+++ b/cogl/tests/conform/test-texture-get-set-data.c
@@ -0,0 +1,144 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+static void
+check_texture (int width, int height, TestUtilsTextureFlags flags)
+{
+ CoglTexture *tex;
+ uint8_t *data, *p;
+ int y, x;
+ int rowstride;
+ CoglBitmap *bmp;
+
+ p = data = g_malloc (width * height * 4);
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ *(p++) = x;
+ *(p++) = y;
+ *(p++) = 128;
+ *(p++) = (x ^ y);
+ }
+
+ bmp = cogl_bitmap_new_for_data (test_ctx,
+ width, height,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ width * 4,
+ data);
+
+ tex = test_utils_texture_new_from_bitmap (bmp, flags,
+ FALSE);
+
+ /* Replace the bottom right quarter of the data with negated data to
+ test set_region */
+ rowstride = width * 4;
+ p = data + (height / 2) * rowstride + rowstride / 2;
+ for (y = 0; y < height / 2; y++)
+ {
+ for (x = 0; x < width / 2; x++)
+ {
+ p[0] = ~p[0];
+ p[1] = ~p[1];
+ p[2] = ~p[2];
+ p[3] = ~p[3];
+ p += 4;
+ }
+ p += width * 2;
+ }
+ cogl_texture_set_region (tex,
+ width / 2,
+ height / 2,
+ width / 2, /* dest x */
+ height / 2, /* dest y */
+ width / 2, /* region width */
+ height / 2, /* region height */
+ width, /* src width */
+ height, /* src height */
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ rowstride,
+ data);
+
+ /* Check passing a NULL pointer and a zero rowstride. The texture
+ should calculate the needed data size and return it */
+ g_assert_cmpint (cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_ANY, 0, NULL),
+ ==,
+ width * height * 4);
+
+ /* Try first receiving the data as RGB. This should cause a
+ * conversion */
+ memset (data, 0, width * height * 4);
+
+ cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_RGB_888,
+ width * 3, data);
+
+ p = data;
+
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ if (x >= width / 2 && y >= height / 2)
+ {
+ g_assert_cmpint (p[0], ==, ~x & 0xff);
+ g_assert_cmpint (p[1], ==, ~y & 0xff);
+ g_assert_cmpint (p[2], ==, ~128 & 0xff);
+ }
+ else
+ {
+ g_assert_cmpint (p[0], ==, x & 0xff);
+ g_assert_cmpint (p[1], ==, y & 0xff);
+ g_assert_cmpint (p[2], ==, 128);
+ }
+ p += 3;
+ }
+
+ /* Now try receiving the data as RGBA. This should not cause a
+ * conversion and no unpremultiplication because we explicitly set
+ * the internal format when we created the texture */
+ memset (data, 0, width * height * 4);
+
+ cogl_texture_get_data (tex, COGL_PIXEL_FORMAT_RGBA_8888,
+ width * 4, data);
+
+ p = data;
+
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ if (x >= width / 2 && y >= height / 2)
+ {
+ g_assert_cmpint (p[0], ==, ~x & 0xff);
+ g_assert_cmpint (p[1], ==, ~y & 0xff);
+ g_assert_cmpint (p[2], ==, ~128 & 0xff);
+ g_assert_cmpint (p[3], ==, ~(x ^ y) & 0xff);
+ }
+ else
+ {
+ g_assert_cmpint (p[0], ==, x & 0xff);
+ g_assert_cmpint (p[1], ==, y & 0xff);
+ g_assert_cmpint (p[2], ==, 128);
+ g_assert_cmpint (p[3], ==, (x ^ y) & 0xff);
+ }
+ p += 4;
+ }
+
+ cogl_object_unref (tex);
+ g_free (data);
+}
+
+void
+test_texture_get_set_data (void)
+{
+ /* First try without atlasing */
+ check_texture (256, 256, TEST_UTILS_TEXTURE_NO_ATLAS);
+ /* Try again with atlasing. This should end up testing the atlas
+ backend and the sub texture backend */
+ check_texture (256, 256, 0);
+ /* Try with a really big texture in the hope that it will end up
+ sliced. */
+ check_texture (4, 5128, TEST_UTILS_TEXTURE_NO_ATLAS);
+ /* And in the other direction. */
+ check_texture (5128, 4, TEST_UTILS_TEXTURE_NO_ATLAS);
+}
diff --git a/cogl/tests/conform/test-texture-mipmaps.c b/cogl/tests/conform/test-texture-mipmaps.c
new file mode 100644
index 000000000..3118ba86d
--- /dev/null
+++ b/cogl/tests/conform/test-texture-mipmaps.c
@@ -0,0 +1,136 @@
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-conform-common.h"
+
+static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
+
+#define TEX_SIZE 64
+
+typedef struct _TestState
+{
+ unsigned int padding;
+} TestState;
+
+/* Creates a texture where the pixels are evenly divided between
+ selecting just one of the R,G and B components */
+static CoglHandle
+make_texture (void)
+{
+ guchar *tex_data = g_malloc (TEX_SIZE * TEX_SIZE * 3), *p = tex_data;
+ CoglHandle tex;
+ int x, y;
+
+ for (y = 0; y < TEX_SIZE; y++)
+ for (x = 0; x < TEX_SIZE; x++)
+ {
+ memset (p, 0, 3);
+ /* Set one of the components to full. The components should be
+ evenly represented so that each gets a third of the
+ texture */
+ p[(p - tex_data) / (TEX_SIZE * TEX_SIZE * 3 / 3)] = 255;
+ p += 3;
+ }
+
+ tex = test_utils_texture_new_from_data (TEX_SIZE, TEX_SIZE, TEST_UTILS_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGB_888,
+ COGL_PIXEL_FORMAT_ANY,
+ TEX_SIZE * 3,
+ tex_data);
+
+ g_free (tex_data);
+
+ return tex;
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ CoglHandle tex;
+ CoglHandle material;
+ uint8_t pixels[8];
+
+ tex = make_texture ();
+ material = cogl_material_new ();
+ cogl_material_set_layer (material, 0, tex);
+ cogl_handle_unref (tex);
+
+ /* Render a 1x1 pixel quad without mipmaps */
+ cogl_set_source (material);
+ cogl_material_set_layer_filters (material, 0,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+ cogl_rectangle (0, 0, 1, 1);
+ /* Then with mipmaps */
+ cogl_material_set_layer_filters (material, 0,
+ COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+ cogl_rectangle (1, 0, 2, 1);
+
+ cogl_handle_unref (material);
+
+ /* Read back the two pixels we rendered */
+ cogl_read_pixels (0, 0, 2, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixels);
+
+ /* The first pixel should be just one of the colors from the
+ texture. It doesn't matter which one */
+ g_assert ((pixels[0] == 255 && pixels[1] == 0 && pixels[2] == 0) ||
+ (pixels[0] == 0 && pixels[1] == 255 && pixels[2] == 0) ||
+ (pixels[0] == 0 && pixels[1] == 0 && pixels[2] == 255));
+ /* The second pixel should be more or less the average of all of the
+ pixels in the texture. Each component gets a third of the image
+ so each component should be approximately 255/3 */
+ g_assert (ABS (pixels[4] - 255 / 3) <= 3 &&
+ ABS (pixels[5] - 255 / 3) <= 3 &&
+ ABS (pixels[6] - 255 / 3) <= 3);
+
+ /* Comment this out if you want visual feedback for what this test paints */
+#if 1
+ clutter_main_quit ();
+#endif
+}
+
+static CoglBool
+queue_redraw (void *stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+void
+test_texture_mipmaps (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ ClutterActor *stage;
+ ClutterActor *group;
+ unsigned int idle_source;
+
+ stage = clutter_stage_get_default ();
+
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+
+ group = clutter_group_new ();
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+
+ /* We force continuous redrawing of the stage, since we need to skip
+ * the first few frames, and we wont be doing anything else that
+ * will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+
+ g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
+
+ clutter_actor_show_all (stage);
+
+ clutter_main ();
+
+ g_source_remove (idle_source);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-texture-no-allocate.c b/cogl/tests/conform/test-texture-no-allocate.c
new file mode 100644
index 000000000..b0199a988
--- /dev/null
+++ b/cogl/tests/conform/test-texture-no-allocate.c
@@ -0,0 +1,80 @@
+#include <cogl/cogl.h>
+
+#include "test-utils.h"
+
+/* Tests that the various texture types can be freed without being
+ * allocated */
+
+/* Texture size that is probably to big to fit within the texture
+ * limits */
+#define BIG_TEX_WIDTH 16384
+#define BIG_TEX_HEIGHT 128
+
+void
+test_texture_no_allocate (void)
+{
+ uint8_t *tex_data;
+ CoglTexture *texture;
+ CoglTexture2D *texture_2d;
+ GError *error = NULL;
+
+ tex_data = g_malloc (BIG_TEX_WIDTH * BIG_TEX_HEIGHT * 4);
+
+ /* NB: if we make the atlas and sliced texture APIs public then this
+ * could changed to explicitly use that instead of the magic texture
+ * API */
+
+ /* Try to create an atlas texture that is too big so it will
+ * internally be freed without allocating */
+ texture =
+ cogl_atlas_texture_new_from_data (test_ctx,
+ BIG_TEX_WIDTH,
+ BIG_TEX_HEIGHT,
+ /* format */
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ /* rowstride */
+ BIG_TEX_WIDTH * 4,
+ tex_data,
+ &error);
+
+ g_free (tex_data);
+
+ /* It's ok if this causes an error, we just don't want it to
+ * crash */
+
+ if (texture == NULL)
+ cogl_error_free (error);
+ else
+ cogl_object_unref (texture);
+
+ /* Try to create a sliced texture without allocating it */
+ texture =
+ cogl_texture_2d_sliced_new_with_size (test_ctx,
+ BIG_TEX_WIDTH,
+ BIG_TEX_HEIGHT,
+ COGL_TEXTURE_MAX_WASTE);
+ cogl_object_unref (texture);
+
+ /* 2D texture */
+ texture_2d = cogl_texture_2d_new_with_size (test_ctx,
+ 64, 64);
+ cogl_object_unref (texture_2d);
+
+ /* 3D texture */
+ if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_3D))
+ {
+ CoglTexture3D *texture_3d =
+ cogl_texture_3d_new_with_size (test_ctx,
+ 64, 64, 64);
+ cogl_object_unref (texture_3d);
+ }
+
+ /* Rectangle texture */
+ if (cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
+ {
+ CoglTextureRectangle *texture_rect =
+ cogl_texture_rectangle_new_with_size (test_ctx,
+ 64, 64);
+ cogl_object_unref (texture_rect);
+ }
+}
diff --git a/cogl/tests/conform/test-texture-pixmap-x11.c b/cogl/tests/conform/test-texture-pixmap-x11.c
new file mode 100644
index 000000000..4e8d55059
--- /dev/null
+++ b/cogl/tests/conform/test-texture-pixmap-x11.c
@@ -0,0 +1,245 @@
+#include <clutter/clutter.h>
+
+#include "test-conform-common.h"
+
+static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
+
+#ifdef COGL_HAS_XLIB
+
+#include <clutter/x11/clutter-x11.h>
+#include <cogl/cogl-texture-pixmap-x11.h>
+
+#define PIXMAP_WIDTH 512
+#define PIXMAP_HEIGHT 256
+#define GRID_SQUARE_SIZE 16
+
+/* Coordinates of a square that we'll update */
+#define PIXMAP_CHANGE_X 1
+#define PIXMAP_CHANGE_Y 1
+
+typedef struct _TestState
+{
+ ClutterActor *stage;
+ CoglHandle tfp;
+ Pixmap pixmap;
+ unsigned int frame_count;
+ Display *display;
+} TestState;
+
+static Pixmap
+create_pixmap (TestState *state)
+{
+ Pixmap pixmap;
+ XGCValues gc_values = { 0, };
+ GC black_gc, white_gc;
+ int screen = DefaultScreen (state->display);
+ int x, y;
+
+ pixmap = XCreatePixmap (state->display,
+ DefaultRootWindow (state->display),
+ PIXMAP_WIDTH, PIXMAP_HEIGHT,
+ DefaultDepth (state->display, screen));
+
+ gc_values.foreground = BlackPixel (state->display, screen);
+ black_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values);
+ gc_values.foreground = WhitePixel (state->display, screen);
+ white_gc = XCreateGC (state->display, pixmap, GCForeground, &gc_values);
+
+ /* Draw a grid of alternative black and white rectangles to the
+ pixmap */
+ for (y = 0; y < PIXMAP_HEIGHT / GRID_SQUARE_SIZE; y++)
+ for (x = 0; x < PIXMAP_WIDTH / GRID_SQUARE_SIZE; x++)
+ XFillRectangle (state->display, pixmap,
+ ((x ^ y) & 1) ? black_gc : white_gc,
+ x * GRID_SQUARE_SIZE,
+ y * GRID_SQUARE_SIZE,
+ GRID_SQUARE_SIZE,
+ GRID_SQUARE_SIZE);
+
+ XFreeGC (state->display, black_gc);
+ XFreeGC (state->display, white_gc);
+
+ return pixmap;
+}
+
+static void
+update_pixmap (TestState *state)
+{
+ XGCValues gc_values = { 0, };
+ GC black_gc;
+ int screen = DefaultScreen (state->display);
+
+ gc_values.foreground = BlackPixel (state->display, screen);
+ black_gc = XCreateGC (state->display, state->pixmap,
+ GCForeground, &gc_values);
+
+ /* Fill in one the rectangles with black */
+ XFillRectangle (state->display, state->pixmap,
+ black_gc,
+ PIXMAP_CHANGE_X * GRID_SQUARE_SIZE,
+ PIXMAP_CHANGE_Y * GRID_SQUARE_SIZE,
+ GRID_SQUARE_SIZE, GRID_SQUARE_SIZE);
+
+ XFreeGC (state->display, black_gc);
+}
+
+static CoglBool
+check_paint (TestState *state, int x, int y, int scale)
+{
+ uint8_t *data, *p, update_value = 0;
+
+ p = data = g_malloc (PIXMAP_WIDTH * PIXMAP_HEIGHT * 4);
+
+ cogl_read_pixels (x, y, PIXMAP_WIDTH / scale, PIXMAP_HEIGHT / scale,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ data);
+
+ for (y = 0; y < PIXMAP_HEIGHT / scale; y++)
+ for (x = 0; x < PIXMAP_WIDTH / scale; x++)
+ {
+ int grid_x = x * scale / GRID_SQUARE_SIZE;
+ int grid_y = y * scale / GRID_SQUARE_SIZE;
+
+ /* If this is the updatable square then we'll let it be either
+ color but we'll return which one it was */
+ if (grid_x == PIXMAP_CHANGE_X && grid_y == PIXMAP_CHANGE_Y)
+ {
+ if (x % (GRID_SQUARE_SIZE / scale) == 0 &&
+ y % (GRID_SQUARE_SIZE / scale) == 0)
+ update_value = *p;
+ else
+ g_assert_cmpint (p[0], ==, update_value);
+
+ g_assert (p[1] == update_value);
+ g_assert (p[2] == update_value);
+ p += 4;
+ }
+ else
+ {
+ uint8_t value = ((grid_x ^ grid_y) & 1) ? 0x00 : 0xff;
+ g_assert_cmpint (*(p++), ==, value);
+ g_assert_cmpint (*(p++), ==, value);
+ g_assert_cmpint (*(p++), ==, value);
+ p++;
+ }
+ }
+
+ g_free (data);
+
+ return update_value == 0x00;
+}
+
+/* We skip these frames first */
+#define FRAME_COUNT_BASE 5
+/* First paint the tfp with no mipmaps */
+#define FRAME_COUNT_NORMAL 6
+/* Then use mipmaps */
+#define FRAME_COUNT_MIPMAP 7
+/* After this frame will start waiting for the pixmap to change */
+#define FRAME_COUNT_UPDATED 8
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ CoglHandle material;
+
+ material = cogl_material_new ();
+ cogl_material_set_layer (material, 0, state->tfp);
+ if (state->frame_count == FRAME_COUNT_MIPMAP)
+ {
+ const CoglMaterialFilter min_filter =
+ COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST;
+ cogl_material_set_layer_filters (material, 0,
+ min_filter,
+ COGL_MATERIAL_FILTER_NEAREST);
+ }
+ else
+ cogl_material_set_layer_filters (material, 0,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+ cogl_set_source (material);
+
+ cogl_rectangle (0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
+
+ cogl_rectangle (0, PIXMAP_HEIGHT,
+ PIXMAP_WIDTH / 4, PIXMAP_HEIGHT * 5 / 4);
+
+ if (state->frame_count >= 5)
+ {
+ CoglBool big_updated, small_updated;
+
+ big_updated = check_paint (state, 0, 0, 1);
+ small_updated = check_paint (state, 0, PIXMAP_HEIGHT, 4);
+
+ g_assert (big_updated == small_updated);
+
+ if (state->frame_count < FRAME_COUNT_UPDATED)
+ g_assert (big_updated == FALSE);
+ else if (state->frame_count == FRAME_COUNT_UPDATED)
+ /* Change the pixmap and keep drawing until it updates */
+ update_pixmap (state);
+ else if (big_updated)
+ /* If we successfully got the update then the test is over */
+ clutter_main_quit ();
+ }
+
+ state->frame_count++;
+}
+
+static CoglBool
+queue_redraw (void *stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+#endif /* COGL_HAS_XLIB */
+
+void
+test_texture_pixmap_x11 (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+#ifdef COGL_HAS_XLIB
+
+ TestState state;
+ unsigned int idle_handler;
+ unsigned int paint_handler;
+
+ state.frame_count = 0;
+ state.stage = clutter_stage_get_default ();
+
+ state.display = clutter_x11_get_default_display ();
+
+ state.pixmap = create_pixmap (&state);
+ state.tfp = cogl_texture_pixmap_x11_new (state.pixmap, TRUE);
+
+ clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
+
+ paint_handler = g_signal_connect_after (state.stage, "paint",
+ G_CALLBACK (on_paint), &state);
+
+ idle_handler = g_idle_add (queue_redraw, state.stage);
+
+ clutter_actor_show_all (state.stage);
+
+ clutter_main ();
+
+ g_signal_handler_disconnect (state.stage, paint_handler);
+
+ g_source_remove (idle_handler);
+
+ XFreePixmap (state.display, state.pixmap);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+
+#else /* COGL_HAS_XLIB */
+
+ if (cogl_test_verbose ())
+ g_print ("Skipping\n");
+
+#endif /* COGL_HAS_XLIB */
+}
+
diff --git a/cogl/tests/conform/test-texture-rectangle.c b/cogl/tests/conform/test-texture-rectangle.c
new file mode 100644
index 000000000..3784cdcfe
--- /dev/null
+++ b/cogl/tests/conform/test-texture-rectangle.c
@@ -0,0 +1,276 @@
+#include <clutter/clutter.h>
+#include <string.h>
+
+#include "test-conform-common.h"
+
+static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
+
+typedef struct _TestState
+{
+ ClutterActor *stage;
+} TestState;
+
+static CoglHandle
+create_source_rect (void)
+{
+#ifdef GL_TEXTURE_RECTANGLE_ARB
+
+ int x, y;
+ GLint prev_unpack_row_length;
+ GLint prev_unpack_alignment;
+ GLint prev_unpack_skip_rows;
+ GLint prev_unpack_skip_pixles;
+ GLint prev_rectangle_binding;
+ uint8_t *data = g_malloc (256 * 256 * 4), *p = data;
+ CoglHandle tex;
+ GLuint gl_tex;
+
+ for (y = 0; y < 256; y++)
+ for (x = 0; x < 256; x++)
+ {
+ *(p++) = x;
+ *(p++) = y;
+ *(p++) = 0;
+ *(p++) = 255;
+ }
+
+ /* We are about to use OpenGL directly to create a TEXTURE_RECTANGLE
+ * texture so we need to save the state that we modify so we can
+ * restore it afterwards and be sure not to interfere with any state
+ * caching that Cogl may do internally.
+ */
+ glGetIntegerv (GL_UNPACK_ROW_LENGTH, &prev_unpack_row_length);
+ glGetIntegerv (GL_UNPACK_ALIGNMENT, &prev_unpack_alignment);
+ glGetIntegerv (GL_UNPACK_SKIP_ROWS, &prev_unpack_skip_rows);
+ glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &prev_unpack_skip_pixles);
+ glGetIntegerv (GL_TEXTURE_BINDING_RECTANGLE_ARB, &prev_rectangle_binding);
+
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, 256);
+ glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+ glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
+
+ glGenTextures (1, &gl_tex);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, gl_tex);
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
+ GL_RGBA, 256, 256, 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data);
+
+ /* Now restore the original GL state as Cogl had left it */
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, prev_unpack_row_length);
+ glPixelStorei (GL_UNPACK_ALIGNMENT, prev_unpack_alignment);
+ glPixelStorei (GL_UNPACK_SKIP_ROWS, prev_unpack_skip_rows);
+ glPixelStorei (GL_UNPACK_SKIP_PIXELS, prev_unpack_skip_pixles);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, prev_rectangle_binding);
+
+ g_assert (glGetError () == GL_NO_ERROR);
+
+ g_free (data);
+
+ tex = test_utils_texture_new_from_foreign (gl_tex,
+ GL_TEXTURE_RECTANGLE_ARB,
+ 256, 256, 0, 0,
+ COGL_PIXEL_FORMAT_RGBA_8888);
+
+ return tex;
+
+#else /* GL_TEXTURE_RECTANGLE_ARB */
+
+ return NULL;
+
+#endif /* GL_TEXTURE_RECTANGLE_ARB */
+}
+
+static CoglHandle
+create_source_2d (void)
+{
+ int x, y;
+ uint8_t *data = g_malloc (256 * 256 * 4), *p = data;
+ CoglHandle tex;
+
+ for (y = 0; y < 256; y++)
+ for (x = 0; x < 256; x++)
+ {
+ *(p++) = 0;
+ *(p++) = x;
+ *(p++) = y;
+ *(p++) = 255;
+ }
+
+ tex = test_utils_texture_new_from_data (256, 256, TEST_UTILS_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ COGL_PIXEL_FORMAT_ANY,
+ 256 * 4,
+ data);
+
+ g_free (data);
+
+ return tex;
+}
+
+static void
+draw_frame (TestState *state)
+{
+ GLuint gl_tex;
+ CoglHandle tex_rect = create_source_rect ();
+ CoglHandle material_rect = cogl_material_new ();
+ CoglHandle tex_2d = create_source_2d ();
+ CoglHandle material_2d = cogl_material_new ();
+
+ g_assert (tex_rect != NULL);
+
+ cogl_material_set_layer (material_rect, 0, tex_rect);
+ cogl_material_set_layer_filters (material_rect, 0,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+
+ cogl_material_set_layer (material_2d, 0, tex_2d);
+ cogl_material_set_layer_filters (material_2d, 0,
+ COGL_MATERIAL_FILTER_NEAREST,
+ COGL_MATERIAL_FILTER_NEAREST);
+
+ cogl_set_source (material_rect);
+
+ /* Render the texture repeated horizontally twice */
+ cogl_rectangle_with_texture_coords (0.0f, 0.0f, 512.0f, 256.0f,
+ 0.0f, 0.0f, 2.0f, 1.0f);
+ /* Render the top half of the texture to test without repeating */
+ cogl_rectangle_with_texture_coords (0.0f, 256.0f, 256.0f, 384.0f,
+ 0.0f, 0.0f, 1.0f, 0.5f);
+
+ cogl_set_source (material_2d);
+
+ /* Render the top half of a regular 2D texture */
+ cogl_rectangle_with_texture_coords (256.0f, 256.0f, 512.0f, 384.0f,
+ 0.0f, 0.0f, 1.0f, 0.5f);
+
+ /* Flush the rendering now so we can safely delete the texture */
+ cogl_flush ();
+
+ cogl_handle_unref (material_rect);
+
+ /* Cogl doesn't destroy foreign textures so we have to do it manually */
+ cogl_texture_get_gl_texture (tex_rect, &gl_tex, NULL);
+ glDeleteTextures (1, &gl_tex);
+ cogl_handle_unref (tex_rect);
+}
+
+static void
+validate_result (TestState *state)
+{
+ uint8_t *data, *p;
+ int x, y;
+
+ p = data = g_malloc (512 * 384 * 4);
+
+ cogl_read_pixels (0, 0, 512, 384,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ data);
+
+ for (y = 0; y < 384; y++)
+ for (x = 0; x < 512; x++)
+ {
+ if (x >= 256 && y >= 256)
+ {
+ g_assert_cmpint (p[0], ==, 0);
+ g_assert_cmpint (p[1], ==, x & 0xff);
+ g_assert_cmpint (p[2], ==, y & 0xff);
+ }
+ else
+ {
+ g_assert_cmpint (p[0], ==, x & 0xff);
+ g_assert_cmpint (p[1], ==, y & 0xff);
+ g_assert_cmpint (p[2], ==, 0);
+ }
+ p += 4;
+ }
+
+ g_free (data);
+
+ /* Comment this out to see what the test paints */
+ clutter_main_quit ();
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ draw_frame (state);
+
+ validate_result (state);
+}
+
+static CoglBool
+queue_redraw (void *stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+static CoglBool
+check_rectangle_extension (void)
+{
+ static const char rect_extension[] = "GL_ARB_texture_rectangle";
+ const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
+ const char *extensions_end;
+
+ extensions_end = extensions + strlen (extensions);
+
+ while (extensions < extensions_end)
+ {
+ const char *end = strchr (extensions, ' ');
+
+ if (end == NULL)
+ end = extensions_end;
+
+ if (end - extensions == sizeof (rect_extension) - 1 &&
+ !memcmp (extensions, rect_extension, sizeof (rect_extension) - 1))
+ return TRUE;
+
+ extensions = end + 1;
+ }
+
+ return FALSE;
+}
+
+void
+test_texture_rectangle (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ unsigned int idle_source;
+ unsigned int paint_handler;
+
+ state.stage = clutter_stage_get_default ();
+
+ /* Check whether GL supports the rectangle extension. If not we'll
+ just assume the test passes */
+ if (check_rectangle_extension ())
+ {
+ clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
+
+ /* We force continuous redrawing of the stage, since we need to skip
+ * the first few frames, and we wont be doing anything else that
+ * will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, state.stage);
+
+ paint_handler = g_signal_connect_after (state.stage, "paint",
+ G_CALLBACK (on_paint), &state);
+
+ clutter_actor_show_all (state.stage);
+
+ clutter_main ();
+
+ g_source_remove (idle_source);
+ g_signal_handler_disconnect (state.stage, paint_handler);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+ }
+ else if (cogl_test_verbose ())
+ g_print ("Skipping\n");
+}
+
diff --git a/cogl/tests/conform/test-texture-rg.c b/cogl/tests/conform/test-texture-rg.c
new file mode 100644
index 000000000..72a5ae930
--- /dev/null
+++ b/cogl/tests/conform/test-texture-rg.c
@@ -0,0 +1,74 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define TEX_WIDTH 8
+#define TEX_HEIGHT 8
+
+static CoglTexture2D *
+make_texture (void)
+{
+ uint8_t tex_data[TEX_WIDTH * TEX_HEIGHT * 2], *p = tex_data;
+ int x, y;
+
+ for (y = 0; y < TEX_HEIGHT; y++)
+ for (x = 0; x < TEX_WIDTH; x++)
+ {
+ *(p++) = x * 256 / TEX_WIDTH;
+ *(p++) = y * 256 / TEX_HEIGHT;
+ }
+
+ return cogl_texture_2d_new_from_data (test_ctx,
+ TEX_WIDTH, TEX_HEIGHT,
+ COGL_PIXEL_FORMAT_RG_88,
+ TEX_WIDTH * 2,
+ tex_data,
+ NULL);
+}
+
+void
+test_texture_rg (void)
+{
+ CoglPipeline *pipeline;
+ CoglTexture2D *tex;
+ int fb_width, fb_height;
+ int x, y;
+
+ fb_width = cogl_framebuffer_get_width (test_fb);
+ fb_height = cogl_framebuffer_get_height (test_fb);
+
+ tex = make_texture ();
+
+ g_assert (cogl_texture_get_components (tex) == COGL_TEXTURE_COMPONENTS_RG);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_texture (pipeline, 0, tex);
+ cogl_pipeline_set_layer_filters (pipeline,
+ 0,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+
+ cogl_framebuffer_draw_rectangle (test_fb,
+ pipeline,
+ -1.0f, 1.0f,
+ 1.0f, -1.0f);
+
+ for (y = 0; y < TEX_HEIGHT; y++)
+ for (x = 0; x < TEX_WIDTH; x++)
+ {
+ test_utils_check_pixel_rgb (test_fb,
+ x * fb_width / TEX_WIDTH +
+ fb_width / (TEX_WIDTH * 2),
+ y * fb_height / TEX_HEIGHT +
+ fb_height / (TEX_HEIGHT * 2),
+ x * 256 / TEX_WIDTH,
+ y * 256 / TEX_HEIGHT,
+ 0);
+ }
+
+ cogl_object_unref (pipeline);
+ cogl_object_unref (tex);
+}
diff --git a/cogl/tests/conform/test-version.c b/cogl/tests/conform/test-version.c
new file mode 100644
index 000000000..b651165e8
--- /dev/null
+++ b/cogl/tests/conform/test-version.c
@@ -0,0 +1,85 @@
+#include <cogl/cogl.h>
+
+/* These will be redefined in config.h */
+#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
+#undef COGL_ENABLE_EXPERIMENTAL_API
+
+#include "test-utils.h"
+#include "config.h"
+
+/* So we can use _COGL_STATIC_ASSERT we include the internal
+ * cogl-util.h header. Since internal headers explicitly guard against
+ * applications including them directly instead of including
+ * <cogl/cogl.h> we define __COGL_H_INSIDE__ here to subvert those
+ * guards in this case... */
+#define __COGL_H_INSIDE__
+#include <cogl/cogl-util.h>
+#undef __COGL_H_INSIDE__
+
+_COGL_STATIC_ASSERT (COGL_VERSION_ENCODE (COGL_VERSION_MAJOR,
+ COGL_VERSION_MINOR,
+ COGL_VERSION_MICRO) ==
+ COGL_VERSION,
+ "The pre-encoded Cogl version does not match the version "
+ "encoding macro");
+
+_COGL_STATIC_ASSERT (COGL_VERSION_GET_MAJOR (COGL_VERSION_ENCODE (100,
+ 200,
+ 300)) ==
+ 100,
+ "Getting the major component out of a encoded version "
+ "does not work");
+_COGL_STATIC_ASSERT (COGL_VERSION_GET_MINOR (COGL_VERSION_ENCODE (100,
+ 200,
+ 300)) ==
+ 200,
+ "Getting the minor component out of a encoded version "
+ "does not work");
+_COGL_STATIC_ASSERT (COGL_VERSION_GET_MICRO (COGL_VERSION_ENCODE (100,
+ 200,
+ 300)) ==
+ 300,
+ "Getting the micro component out of a encoded version "
+ "does not work");
+
+_COGL_STATIC_ASSERT (COGL_VERSION_CHECK (COGL_VERSION_MAJOR,
+ COGL_VERSION_MINOR,
+ COGL_VERSION_MICRO),
+ "Checking the Cogl version against the current version "
+ "does not pass");
+_COGL_STATIC_ASSERT (!COGL_VERSION_CHECK (COGL_VERSION_MAJOR,
+ COGL_VERSION_MINOR,
+ COGL_VERSION_MICRO + 1),
+ "Checking the Cogl version against a later micro version "
+ "should not pass");
+_COGL_STATIC_ASSERT (!COGL_VERSION_CHECK (COGL_VERSION_MAJOR,
+ COGL_VERSION_MINOR + 1,
+ COGL_VERSION_MICRO),
+ "Checking the Cogl version against a later minor version "
+ "should not pass");
+_COGL_STATIC_ASSERT (!COGL_VERSION_CHECK (COGL_VERSION_MAJOR + 1,
+ COGL_VERSION_MINOR,
+ COGL_VERSION_MICRO),
+ "Checking the Cogl version against a later major version "
+ "should not pass");
+
+_COGL_STATIC_ASSERT (COGL_VERSION_CHECK (COGL_VERSION_MAJOR - 1,
+ COGL_VERSION_MINOR,
+ COGL_VERSION_MICRO),
+ "Checking the Cogl version against a older major version "
+ "should pass");
+
+void
+test_version (void)
+{
+ const char *version = g_strdup_printf ("version = %i.%i.%i",
+ COGL_VERSION_MAJOR,
+ COGL_VERSION_MINOR,
+ COGL_VERSION_MICRO);
+
+ g_assert_cmpstr (version, ==, "version = " COGL_VERSION_STRING);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-vertex-buffer-contiguous.c b/cogl/tests/conform/test-vertex-buffer-contiguous.c
new file mode 100644
index 000000000..1cd7b456b
--- /dev/null
+++ b/cogl/tests/conform/test-vertex-buffer-contiguous.c
@@ -0,0 +1,257 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+
+#include "test-conform-common.h"
+
+/* This test verifies that the simplest usage of the vertex buffer API,
+ * where we add contiguous (x,y) GLfloat vertices, and RGBA GLubyte color
+ * attributes to a buffer, submit, and draw.
+ *
+ * It also tries to verify that the enable/disable attribute APIs are working
+ * too.
+ *
+ * If you want visual feedback of what this test paints for debugging purposes,
+ * then remove the call to clutter_main_quit() in validate_result.
+ */
+
+typedef struct _TestState
+{
+ CoglHandle buffer;
+ CoglHandle texture;
+ CoglHandle material;
+ ClutterGeometry stage_geom;
+} TestState;
+
+static void
+validate_result (TestState *state)
+{
+ GLubyte pixel[4];
+ GLint y_off = 90;
+
+ if (cogl_test_verbose ())
+ g_print ("y_off = %d\n", y_off);
+
+ /* NB: We ignore the alpha, since we don't know if our render target is
+ * RGB or RGBA */
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+ /* Should see a blue pixel */
+ cogl_read_pixels (10, y_off, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0);
+
+ /* Should see a red pixel */
+ cogl_read_pixels (110, y_off, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 1 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[RED] != 0 && pixel[GREEN] == 0 && pixel[BLUE] == 0);
+
+ /* Should see a blue pixel */
+ cogl_read_pixels (210, y_off, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 2 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0);
+
+ /* Should see a green pixel, at bottom of 4th triangle */
+ cogl_read_pixels (310, y_off, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 3 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[GREEN] > pixel[RED] && pixel[GREEN] > pixel[BLUE]);
+
+ /* Should see a red pixel, at top of 4th triangle */
+ cogl_read_pixels (310, y_off - 70, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 4 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[RED] > pixel[GREEN] && pixel[RED] > pixel[BLUE]);
+
+
+#undef RED
+#undef GREEN
+#undef BLUE
+
+ /* Comment this out if you want visual feedback of what this test
+ * paints.
+ */
+ clutter_main_quit ();
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ /* Draw a faded blue triangle */
+ cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue");
+ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
+ cogl_vertex_buffer_draw (state->buffer,
+ GL_TRIANGLE_STRIP, /* mode */
+ 0, /* first */
+ 3); /* count */
+
+ /* Draw a red triangle */
+ /* Here we are testing that the disable attribute works; if it doesn't
+ * the triangle will remain faded blue */
+ cogl_translate (100, 0, 0);
+ cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue");
+ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
+ cogl_vertex_buffer_draw (state->buffer,
+ GL_TRIANGLE_STRIP, /* mode */
+ 0, /* first */
+ 3); /* count */
+
+ /* Draw a faded blue triangle */
+ /* Here we are testing that the re-enable works; if it doesn't
+ * the triangle will remain red */
+ cogl_translate (100, 0, 0);
+ cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue");
+ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
+ cogl_vertex_buffer_draw (state->buffer,
+ GL_TRIANGLE_STRIP, /* mode */
+ 0, /* first */
+ 3); /* count */
+
+ /* Draw a textured triangle */
+ cogl_translate (100, 0, 0);
+ cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue");
+ cogl_set_source (state->material);
+ cogl_material_set_color4ub (state->material, 0xff, 0xff, 0xff, 0xff);
+ cogl_vertex_buffer_draw (state->buffer,
+ GL_TRIANGLE_STRIP, /* mode */
+ 0, /* first */
+ 3); /* count */
+
+ validate_result (state);
+}
+
+static CoglBool
+queue_redraw (gpointer stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+
+
+void
+test_vertex_buffer_contiguous (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ ClutterActor *stage;
+ ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff};
+ ClutterActor *group;
+ unsigned int idle_source;
+ guchar tex_data[] = {
+ 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff
+ };
+
+ stage = clutter_stage_get_default ();
+
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
+ clutter_actor_get_geometry (stage, &state.stage_geom);
+
+ group = clutter_group_new ();
+ clutter_actor_set_size (group,
+ state.stage_geom.width,
+ state.stage_geom.height);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+
+ /* We force continuous redrawing incase someone comments out the
+ * clutter_main_quit and wants visual feedback for the test since we
+ * wont be doing anything else that will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+
+ g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
+
+ state.texture = cogl_texture_new_from_data (2, 2,
+ COGL_TEXTURE_NO_SLICING,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ COGL_PIXEL_FORMAT_ANY,
+ 0, /* auto calc row stride */
+ tex_data);
+
+ state.material = cogl_material_new ();
+ cogl_material_set_color4ub (state.material, 0x00, 0xff, 0x00, 0xff);
+ cogl_material_set_layer (state.material, 0, state.texture);
+
+ {
+ GLfloat triangle_verts[3][2] =
+ {
+ {0.0, 0.0},
+ {100.0, 100.0},
+ {0.0, 100.0}
+ };
+ GLbyte triangle_colors[3][4] =
+ {
+ {0x00, 0x00, 0xff, 0xff}, /* blue */
+ {0x00, 0x00, 0xff, 0x00}, /* transparent blue */
+ {0x00, 0x00, 0xff, 0x00} /* transparent blue */
+ };
+ GLfloat triangle_tex_coords[3][2] =
+ {
+ {0.0, 0.0},
+ {1.0, 1.0},
+ {0.0, 1.0}
+ };
+ state.buffer = cogl_vertex_buffer_new (3 /* n vertices */);
+ cogl_vertex_buffer_add (state.buffer,
+ "gl_Vertex",
+ 2, /* n components */
+ GL_FLOAT,
+ FALSE, /* normalized */
+ 0, /* stride */
+ triangle_verts);
+ cogl_vertex_buffer_add (state.buffer,
+ "gl_Color::blue",
+ 4, /* n components */
+ GL_UNSIGNED_BYTE,
+ FALSE, /* normalized */
+ 0, /* stride */
+ triangle_colors);
+ cogl_vertex_buffer_add (state.buffer,
+ "gl_MultiTexCoord0",
+ 2, /* n components */
+ GL_FLOAT,
+ FALSE, /* normalized */
+ 0, /* stride */
+ triangle_tex_coords);
+
+ cogl_vertex_buffer_submit (state.buffer);
+ }
+
+ clutter_actor_show_all (stage);
+
+ clutter_main ();
+
+ cogl_handle_unref (state.buffer);
+ cogl_handle_unref (state.material);
+ cogl_handle_unref (state.texture);
+
+ g_source_remove (idle_source);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-vertex-buffer-interleved.c b/cogl/tests/conform/test-vertex-buffer-interleved.c
new file mode 100644
index 000000000..2d31e364a
--- /dev/null
+++ b/cogl/tests/conform/test-vertex-buffer-interleved.c
@@ -0,0 +1,162 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+
+#include "test-conform-common.h"
+
+/* This test verifies that interleved attributes work with the vertex buffer
+ * API. We add (x,y) GLfloat vertices, interleved with RGBA GLubyte color
+ * attributes to a buffer, submit and draw.
+ *
+ * If you want visual feedback of what this test paints for debugging purposes,
+ * then remove the call to clutter_main_quit() in validate_result.
+ */
+
+typedef struct _TestState
+{
+ CoglHandle buffer;
+ ClutterGeometry stage_geom;
+} TestState;
+
+typedef struct _InterlevedVertex
+{
+ GLfloat x;
+ GLfloat y;
+
+ GLubyte r;
+ GLubyte g;
+ GLubyte b;
+ GLubyte a;
+} InterlevedVertex;
+
+
+static void
+validate_result (TestState *state)
+{
+ GLubyte pixel[4];
+ GLint y_off = 90;
+
+ /* NB: We ignore the alpha, since we don't know if our render target is
+ * RGB or RGBA */
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+ /* Should see a blue pixel */
+ cogl_read_pixels (10, y_off, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0);
+
+#undef RED
+#undef GREEN
+#undef BLUE
+
+ /* Comment this out if you want visual feedback of what this test
+ * paints.
+ */
+ clutter_main_quit ();
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ /* Draw a faded blue triangle */
+ cogl_vertex_buffer_draw (state->buffer,
+ GL_TRIANGLE_STRIP, /* mode */
+ 0, /* first */
+ 3); /* count */
+
+ validate_result (state);
+}
+
+static CoglBool
+queue_redraw (gpointer stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+void
+test_vertex_buffer_interleved (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ ClutterActor *stage;
+ ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff};
+ ClutterActor *group;
+ unsigned int idle_source;
+
+ stage = clutter_stage_get_default ();
+
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
+ clutter_actor_get_geometry (stage, &state.stage_geom);
+
+ group = clutter_group_new ();
+ clutter_actor_set_size (group,
+ state.stage_geom.width,
+ state.stage_geom.height);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+
+ /* We force continuous redrawing incase someone comments out the
+ * clutter_main_quit and wants visual feedback for the test since we
+ * wont be doing anything else that will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+
+ g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
+
+ {
+ InterlevedVertex verts[3] =
+ {
+ { /* .x = */ 0.0, /* .y = */ 0.0,
+ /* blue */
+ /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0xff },
+
+ { /* .x = */ 100.0, /* .y = */ 100.0,
+ /* transparent blue */
+ /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 },
+
+ { /* .x = */ 0.0, /* .y = */ 100.0,
+ /* transparent blue */
+ /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 },
+ };
+
+ /* We assume the compiler is doing no funny struct padding for this test:
+ */
+ g_assert (sizeof (InterlevedVertex) == 12);
+
+ state.buffer = cogl_vertex_buffer_new (3 /* n vertices */);
+ cogl_vertex_buffer_add (state.buffer,
+ "gl_Vertex",
+ 2, /* n components */
+ GL_FLOAT,
+ FALSE, /* normalized */
+ 12, /* stride */
+ &verts[0].x);
+ cogl_vertex_buffer_add (state.buffer,
+ "gl_Color",
+ 4, /* n components */
+ GL_UNSIGNED_BYTE,
+ FALSE, /* normalized */
+ 12, /* stride */
+ &verts[0].r);
+ cogl_vertex_buffer_submit (state.buffer);
+ }
+
+ clutter_actor_show_all (stage);
+
+ clutter_main ();
+
+ cogl_handle_unref (state.buffer);
+
+ g_source_remove (idle_source);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-vertex-buffer-mutability.c b/cogl/tests/conform/test-vertex-buffer-mutability.c
new file mode 100644
index 000000000..9c8d5da8c
--- /dev/null
+++ b/cogl/tests/conform/test-vertex-buffer-mutability.c
@@ -0,0 +1,198 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+
+#include "test-conform-common.h"
+
+/* This test verifies that modifying a vertex buffer works, by updating
+ * vertex positions, and deleting and re-adding different color attributes.
+ *
+ * If you want visual feedback of what this test paints for debugging purposes,
+ * then remove the call to clutter_main_quit() in validate_result.
+ */
+
+typedef struct _TestState
+{
+ CoglHandle buffer;
+ ClutterGeometry stage_geom;
+} TestState;
+
+static void
+validate_result (TestState *state)
+{
+ GLubyte pixel[4];
+ GLint y_off = 90;
+
+ /* NB: We ignore the alpha, since we don't know if our render target is
+ * RGB or RGBA */
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+
+ /* Should see a red pixel */
+ cogl_read_pixels (110, y_off, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[RED] != 0 && pixel[GREEN] == 0 && pixel[BLUE] == 0);
+
+ /* Should see a green pixel */
+ cogl_read_pixels (210, y_off, 1, 1,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ pixel);
+ if (cogl_test_verbose ())
+ g_print ("pixel 1 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]);
+ g_assert (pixel[RED] == 0 && pixel[GREEN] != 0 && pixel[BLUE] == 0);
+
+#undef RED
+#undef GREEN
+#undef BLUE
+
+ /* Comment this out if you want visual feedback of what this test
+ * paints.
+ */
+ clutter_main_quit ();
+}
+
+static void
+on_paint (ClutterActor *actor, TestState *state)
+{
+ GLfloat triangle_verts[3][2] =
+ {
+ {100.0, 0.0},
+ {200.0, 100.0},
+ {100.0, 100.0}
+ };
+ GLbyte triangle_colors[3][4] =
+ {
+ {0x00, 0xff, 0x00, 0xff}, /* blue */
+ {0x00, 0xff, 0x00, 0x00}, /* transparent blue */
+ {0x00, 0xff, 0x00, 0x00} /* transparent blue */
+ };
+
+ /*
+ * Draw a red triangle
+ */
+
+ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
+
+ cogl_vertex_buffer_add (state->buffer,
+ "gl_Vertex",
+ 2, /* n components */
+ GL_FLOAT,
+ FALSE, /* normalized */
+ 0, /* stride */
+ triangle_verts);
+ cogl_vertex_buffer_delete (state->buffer, "gl_Color");
+ cogl_vertex_buffer_submit (state->buffer);
+
+ cogl_vertex_buffer_draw (state->buffer,
+ GL_TRIANGLE_STRIP, /* mode */
+ 0, /* first */
+ 3); /* count */
+
+ /*
+ * Draw a faded green triangle
+ */
+
+ cogl_vertex_buffer_add (state->buffer,
+ "gl_Color",
+ 4, /* n components */
+ GL_UNSIGNED_BYTE,
+ FALSE, /* normalized */
+ 0, /* stride */
+ triangle_colors);
+ cogl_vertex_buffer_submit (state->buffer);
+
+ cogl_translate (100, 0, 0);
+ cogl_vertex_buffer_draw (state->buffer,
+ GL_TRIANGLE_STRIP, /* mode */
+ 0, /* first */
+ 3); /* count */
+
+ validate_result (state);
+}
+
+static CoglBool
+queue_redraw (gpointer stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+void
+test_vertex_buffer_mutability (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ TestState state;
+ ClutterActor *stage;
+ ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff};
+ ClutterActor *group;
+ unsigned int idle_source;
+
+ stage = clutter_stage_get_default ();
+
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr);
+ clutter_actor_get_geometry (stage, &state.stage_geom);
+
+ group = clutter_group_new ();
+ clutter_actor_set_size (group,
+ state.stage_geom.width,
+ state.stage_geom.height);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
+
+ /* We force continuous redrawing incase someone comments out the
+ * clutter_main_quit and wants visual feedback for the test since we
+ * wont be doing anything else that will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+
+ g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
+
+ {
+ GLfloat triangle_verts[3][2] =
+ {
+ {0.0, 0.0},
+ {100.0, 100.0},
+ {0.0, 100.0}
+ };
+ GLbyte triangle_colors[3][4] =
+ {
+ {0x00, 0x00, 0xff, 0xff}, /* blue */
+ {0x00, 0x00, 0xff, 0x00}, /* transparent blue */
+ {0x00, 0x00, 0xff, 0x00} /* transparent blue */
+ };
+ state.buffer = cogl_vertex_buffer_new (3 /* n vertices */);
+ cogl_vertex_buffer_add (state.buffer,
+ "gl_Vertex",
+ 2, /* n components */
+ GL_FLOAT,
+ FALSE, /* normalized */
+ 0, /* stride */
+ triangle_verts);
+ cogl_vertex_buffer_add (state.buffer,
+ "gl_Color",
+ 4, /* n components */
+ GL_UNSIGNED_BYTE,
+ FALSE, /* normalized */
+ 0, /* stride */
+ triangle_colors);
+ cogl_vertex_buffer_submit (state.buffer);
+ }
+
+ clutter_actor_show_all (stage);
+
+ clutter_main ();
+
+ cogl_handle_unref (state.buffer);
+
+ g_source_remove (idle_source);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-viewport.c b/cogl/tests/conform/test-viewport.c
new file mode 100644
index 000000000..a1937c42a
--- /dev/null
+++ b/cogl/tests/conform/test-viewport.c
@@ -0,0 +1,416 @@
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+
+#include "test-conform-common.h"
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define ALPHA 3
+
+#define FRAMEBUFFER_WIDTH 640
+#define FRAMEBUFFER_HEIGHT 480
+
+static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
+
+static void
+assert_region_color (int x,
+ int y,
+ int width,
+ int height,
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t alpha)
+{
+ uint8_t *data = g_malloc0 (width * height * 4);
+ cogl_read_pixels (x, y, width, height,
+ COGL_READ_PIXELS_COLOR_BUFFER,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ data);
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ uint8_t *pixel = &data[y*width*4 + x*4];
+#if 1
+ g_assert (pixel[RED] == red &&
+ pixel[GREEN] == green &&
+ pixel[BLUE] == blue &&
+ pixel[ALPHA] == alpha);
+#endif
+ }
+ g_free (data);
+}
+
+static void
+assert_rectangle_color_and_black_border (int x,
+ int y,
+ int width,
+ int height,
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue)
+{
+ /* check the rectangle itself... */
+ assert_region_color (x, y, width, height, red, green, blue, 0xff);
+ /* black to left of the rectangle */
+ assert_region_color (x-10, y-10, 10, height+20, 0x00, 0x00, 0x00, 0xff);
+ /* black to right of the rectangle */
+ assert_region_color (x+width, y-10, 10, height+20, 0x00, 0x00, 0x00, 0xff);
+ /* black above the rectangle */
+ assert_region_color (x-10, y-10, width+20, 10, 0x00, 0x00, 0x00, 0xff);
+ /* and black below the rectangle */
+ assert_region_color (x-10, y+height, width+20, 10, 0x00, 0x00, 0x00, 0xff);
+}
+
+
+static void
+on_paint (ClutterActor *actor, void *state)
+{
+ float saved_viewport[4];
+ CoglMatrix saved_projection;
+ CoglMatrix projection;
+ CoglMatrix modelview;
+ guchar *data;
+ CoglHandle tex;
+ CoglHandle offscreen;
+ CoglColor black;
+ float x0;
+ float y0;
+ float width;
+ float height;
+
+ /* for clearing the offscreen framebuffer to black... */
+ cogl_color_init_from_4ub (&black, 0x00, 0x00, 0x00, 0xff);
+
+ cogl_get_viewport (saved_viewport);
+ cogl_get_projection_matrix (&saved_projection);
+ cogl_push_matrix ();
+
+ cogl_matrix_init_identity (&projection);
+ cogl_matrix_init_identity (&modelview);
+
+ cogl_set_projection_matrix (&projection);
+ cogl_set_modelview_matrix (&modelview);
+
+ /* - Create a 100x200 viewport (i.e. smaller than the onscreen framebuffer)
+ * and position it a (20, 10) inside the framebuffer.
+ * - Fill the whole viewport with a purple rectangle
+ * - Verify that the framebuffer is black with a 100x200 purple rectangle at
+ * (20, 10)
+ */
+ cogl_set_viewport (20, /* x */
+ 10, /* y */
+ 100, /* width */
+ 200); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ /* fill the viewport with purple.. */
+ cogl_set_source_color4ub (0xff, 0x00, 0xff, 0xff);
+ cogl_rectangle (-1, 1, 1, -1);
+ assert_rectangle_color_and_black_border (20, 10, 100, 200,
+ 0xff, 0x00, 0xff);
+
+
+ /* - Create a viewport twice the size of the onscreen framebuffer with
+ * a negative offset positioning it at (-20, -10) relative to the
+ * buffer itself.
+ * - Draw a 100x200 green rectangle at (40, 20) within the viewport (which
+ * is (20, 10) within the framebuffer)
+ * - Verify that the framebuffer is black with a 100x200 green rectangle at
+ * (20, 10)
+ */
+ cogl_set_viewport (-20, /* x */
+ -10, /* y */
+ FRAMEBUFFER_WIDTH * 2, /* width */
+ FRAMEBUFFER_HEIGHT * 2); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ /* draw a 100x200 green rectangle offset into the viewport such that its
+ * top left corner should be found at (20, 10) in the offscreen buffer */
+ /* (offset 40 pixels right from the left of the viewport) */
+ x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
+ /* (offset 20 pixels down from the top of the viewport) */
+ y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
+ width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
+ height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
+ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
+ cogl_rectangle (x0, y0, x0 + width, y0 - height);
+ assert_rectangle_color_and_black_border (20, 10, 100, 200,
+ 0x00, 0xff, 0x00);
+
+
+ /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
+ * buffer.
+ * - Push a 100x200 window space clip rectangle at (20, 10)
+ * - Fill the whole viewport with a blue rectangle
+ * - Verify that the framebuffer is black with a 100x200 blue rectangle at
+ * (20, 10)
+ */
+ cogl_set_viewport (20, /* x */
+ 10, /* y */
+ 200, /* width */
+ 400); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ cogl_clip_push_window_rectangle (20, 10, 100, 200);
+ /* fill the viewport with blue.. */
+ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
+ cogl_rectangle (-1, 1, 1, -1);
+ cogl_clip_pop ();
+ assert_rectangle_color_and_black_border (20, 10, 100, 200,
+ 0x00, 0x00, 0xff);
+
+
+ /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
+ * buffer.
+ * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
+ * (i.e. (40, 20) inside the framebuffer)
+ * - Fill the whole viewport with a green rectangle
+ * - Verify that the framebuffer is black with a 100x200 green rectangle at
+ * (40, 20)
+ */
+ cogl_set_viewport (20, /* x */
+ 10, /* y */
+ 200, /* width */
+ 400); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ /* figure out where to position our clip rectangle in model space
+ * coordinates... */
+ /* (offset 40 pixels right from the left of the viewport) */
+ x0 = -1.0f + (2.0f / 200) * 20.f;
+ /* (offset 20 pixels down from the top of the viewport) */
+ y0 = 1.0f - (2.0f / 400) * 10.0f;
+ width = (2.0f / 200) * 100;
+ height = (2.0f / 400) * 200;
+ /* add the clip rectangle... */
+ cogl_push_matrix ();
+ cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
+ /* XXX: Rotate just enough to stop Cogl from converting our model space
+ * rectangle into a window space rectangle.. */
+ cogl_rotate (0.1, 0, 0, 1);
+ cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
+ width/2.0, height/2.0);
+ cogl_pop_matrix ();
+ /* fill the viewport with green.. */
+ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
+ cogl_rectangle (-1, 1, 1, -1);
+ cogl_clip_pop ();
+ assert_rectangle_color_and_black_border (40, 20, 100, 200,
+ 0x00, 0xff, 0x00);
+
+
+ /* Set the viewport to something specific so we can verify that it gets
+ * restored after we are done testing with an offscreen framebuffer... */
+ cogl_set_viewport (20, 10, 100, 200);
+
+ /*
+ * Next test offscreen drawing...
+ */
+ data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
+ tex = test_utils_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
+ TEST_UTILS_TEXTURE_NO_SLICING,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */
+ COGL_PIXEL_FORMAT_ANY, /* internal fmt */
+ FRAMEBUFFER_WIDTH * 4, /* rowstride */
+ data);
+ g_free (data);
+ offscreen = cogl_offscreen_new_with_texture (tex);
+
+ cogl_push_framebuffer (offscreen);
+
+
+ /* - Create a 100x200 viewport (i.e. smaller than the offscreen framebuffer)
+ * and position it a (20, 10) inside the framebuffer.
+ * - Fill the whole viewport with a blue rectangle
+ * - Verify that the framebuffer is black with a 100x200 blue rectangle at
+ * (20, 10)
+ */
+ cogl_set_viewport (20, /* x */
+ 10, /* y */
+ 100, /* width */
+ 200); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ /* fill the viewport with blue.. */
+ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
+ cogl_rectangle (-1, 1, 1, -1);
+ assert_rectangle_color_and_black_border (20, 10, 100, 200,
+ 0x00, 0x00, 0xff);
+
+
+ /* - Create a viewport twice the size of the offscreen framebuffer with
+ * a negative offset positioning it at (-20, -10) relative to the
+ * buffer itself.
+ * - Draw a 100x200 red rectangle at (40, 20) within the viewport (which
+ * is (20, 10) within the framebuffer)
+ * - Verify that the framebuffer is black with a 100x200 red rectangle at
+ * (20, 10)
+ */
+ cogl_set_viewport (-20, /* x */
+ -10, /* y */
+ FRAMEBUFFER_WIDTH * 2, /* width */
+ FRAMEBUFFER_HEIGHT * 2); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ /* draw a 100x200 red rectangle offset into the viewport such that its
+ * top left corner should be found at (20, 10) in the offscreen buffer */
+ /* (offset 40 pixels right from the left of the viewport) */
+ x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
+ /* (offset 20 pixels down from the top of the viewport) */
+ y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
+ width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
+ height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
+ cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
+ cogl_rectangle (x0, y0, x0 + width, y0 - height);
+ assert_rectangle_color_and_black_border (20, 10, 100, 200,
+ 0xff, 0x00, 0x00);
+
+
+ /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
+ * buffer.
+ * - Push a 100x200 window space clip rectangle at (20, 10)
+ * - Fill the whole viewport with a blue rectangle
+ * - Verify that the framebuffer is black with a 100x200 blue rectangle at
+ * (20, 10)
+ */
+ cogl_set_viewport (20, /* x */
+ 10, /* y */
+ 200, /* width */
+ 400); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ cogl_clip_push_window_rectangle (20, 10, 100, 200);
+ /* fill the viewport with blue.. */
+ cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
+ cogl_rectangle (-1, 1, 1, -1);
+ cogl_clip_pop ();
+ assert_rectangle_color_and_black_border (20, 10, 100, 200,
+ 0x00, 0x00, 0xff);
+
+
+ /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
+ * buffer.
+ * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
+ * (i.e. (40, 20) inside the framebuffer)
+ * - Fill the whole viewport with a green rectangle
+ * - Verify that the framebuffer is black with a 100x200 green rectangle at
+ * (40, 20)
+ */
+ cogl_set_viewport (20, /* x */
+ 10, /* y */
+ 200, /* width */
+ 400); /* height */
+ /* clear everything... */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ /* figure out where to position our clip rectangle in model space
+ * coordinates... */
+ /* (offset 40 pixels right from the left of the viewport) */
+ x0 = -1.0f + (2.0f / 200) * 20.f;
+ /* (offset 20 pixels down from the top of the viewport) */
+ y0 = 1.0f - (2.0f / 400) * 10.0f;
+ width = (2.0f / 200) * 100;
+ height = (2.0f / 400) * 200;
+ /* add the clip rectangle... */
+ cogl_push_matrix ();
+ cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
+ /* XXX: Rotate just enough to stop Cogl from converting our model space
+ * rectangle into a window space rectangle.. */
+ cogl_rotate (0.1, 0, 0, 1);
+ cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
+ width/2, height/2);
+ cogl_pop_matrix ();
+ /* fill the viewport with green.. */
+ cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
+ cogl_rectangle (-1, 1, 1, -1);
+ cogl_clip_pop ();
+ assert_rectangle_color_and_black_border (40, 20, 100, 200,
+ 0x00, 0xff, 0x00);
+
+
+ /* Set the viewport to something obscure to verify that it gets
+ * replace when we switch back to the onscreen framebuffer... */
+ cogl_set_viewport (0, 0, 10, 10);
+
+ cogl_pop_framebuffer ();
+ cogl_handle_unref (offscreen);
+
+ /*
+ * Verify that the previous onscreen framebuffer's viewport was restored
+ * by drawing a white rectangle across the whole viewport. This should
+ * draw a 100x200 rectangle at (20,10) relative to the onscreen draw
+ * buffer...
+ */
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
+ cogl_rectangle (-1, 1, 1, -1);
+ assert_rectangle_color_and_black_border (20, 10, 100, 200,
+ 0xff, 0xff, 0xff);
+
+
+ /* Uncomment to display the last contents of the offscreen framebuffer */
+#if 1
+ cogl_matrix_init_identity (&projection);
+ cogl_matrix_init_identity (&modelview);
+ cogl_set_viewport (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
+ cogl_set_projection_matrix (&projection);
+ cogl_set_modelview_matrix (&modelview);
+ cogl_set_source_texture (tex);
+ cogl_rectangle (-1, 1, 1, -1);
+#endif
+
+ cogl_handle_unref (tex);
+
+ /* Finally restore the stage's original state... */
+ cogl_pop_matrix ();
+ cogl_set_projection_matrix (&saved_projection);
+ cogl_set_viewport (saved_viewport[0], saved_viewport[1],
+ saved_viewport[2], saved_viewport[3]);
+
+
+ /* Comment this out if you want visual feedback of what this test
+ * paints.
+ */
+ clutter_main_quit ();
+}
+
+static CoglBool
+queue_redraw (void *stage)
+{
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+ return TRUE;
+}
+
+void
+test_viewport (TestUtilsGTestFixture *fixture,
+ void *data)
+{
+ unsigned int idle_source;
+ ClutterActor *stage;
+
+ stage = clutter_stage_get_default ();
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+
+ /* We force continuous redrawing of the stage, since we need to skip
+ * the first few frames, and we wont be doing anything else that
+ * will trigger redrawing. */
+ idle_source = g_idle_add (queue_redraw, stage);
+ g_signal_connect_after (stage, "paint", G_CALLBACK (on_paint), NULL);
+
+ clutter_actor_show (stage);
+ clutter_main ();
+
+ g_source_remove (idle_source);
+
+ /* Remove all of the actors from the stage */
+ clutter_container_foreach (CLUTTER_CONTAINER (stage),
+ (ClutterCallback) clutter_actor_destroy,
+ NULL);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
+
diff --git a/cogl/tests/conform/test-wrap-modes.c b/cogl/tests/conform/test-wrap-modes.c
new file mode 100644
index 000000000..e5a2a1a61
--- /dev/null
+++ b/cogl/tests/conform/test-wrap-modes.c
@@ -0,0 +1,296 @@
+#define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0
+
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "test-utils.h"
+
+#define TEX_SIZE 4
+
+typedef struct _TestState
+{
+ int width;
+ int height;
+ CoglTexture *texture;
+} TestState;
+
+static CoglTexture *
+create_texture (TestUtilsTextureFlags flags)
+{
+ uint8_t *data = g_malloc (TEX_SIZE * TEX_SIZE * 4), *p = data;
+ CoglTexture *tex;
+ int x, y;
+
+ for (y = 0; y < TEX_SIZE; y++)
+ for (x = 0; x < TEX_SIZE; x++)
+ {
+ *(p++) = 0;
+ *(p++) = (x & 1) * 255;
+ *(p++) = (y & 1) * 255;
+ *(p++) = 255;
+ }
+
+ tex = test_utils_texture_new_from_data (test_ctx,
+ TEX_SIZE, TEX_SIZE, flags,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ TEX_SIZE * 4,
+ data);
+ g_free (data);
+
+ return tex;
+}
+
+static CoglPipeline *
+create_pipeline (TestState *state,
+ CoglPipelineWrapMode wrap_mode_s,
+ CoglPipelineWrapMode wrap_mode_t)
+{
+ CoglPipeline *pipeline;
+
+ pipeline = cogl_pipeline_new (test_ctx);
+ cogl_pipeline_set_layer_texture (pipeline, 0, state->texture);
+ cogl_pipeline_set_layer_filters (pipeline, 0,
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+ cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0, wrap_mode_s);
+ cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0, wrap_mode_t);
+
+ return pipeline;
+}
+
+static CoglPipelineWrapMode
+wrap_modes[] =
+ {
+ COGL_PIPELINE_WRAP_MODE_REPEAT,
+ COGL_PIPELINE_WRAP_MODE_REPEAT,
+
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+
+ COGL_PIPELINE_WRAP_MODE_REPEAT,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
+ COGL_PIPELINE_WRAP_MODE_REPEAT,
+
+ COGL_PIPELINE_WRAP_MODE_AUTOMATIC,
+ COGL_PIPELINE_WRAP_MODE_AUTOMATIC,
+
+ COGL_PIPELINE_WRAP_MODE_AUTOMATIC,
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE
+ };
+
+static void
+draw_tests (TestState *state)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
+ {
+ CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
+ CoglPipeline *pipeline;
+
+ /* Create a separate pipeline for each pair of wrap modes so
+ that we can verify whether the batch splitting works */
+ wrap_mode_s = wrap_modes[i];
+ wrap_mode_t = wrap_modes[i + 1];
+ pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t);
+ /* Render the pipeline at four times the size of the texture */
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ i * TEX_SIZE,
+ 0,
+ (i + 2) * TEX_SIZE,
+ TEX_SIZE * 2,
+ 0, 0, 2, 2);
+ cogl_object_unref (pipeline);
+ }
+}
+
+static const CoglTextureVertex vertices[4] =
+ {
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, TEX_SIZE * 2, 0.0f, 0.0f, 2.0f },
+ { TEX_SIZE * 2, TEX_SIZE * 2, 0.0f, 2.0f, 2.0f },
+ { TEX_SIZE * 2, 0.0f, 0.0f, 2.0f, 0.0f }
+ };
+
+static void
+draw_tests_polygon (TestState *state)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
+ {
+ CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
+ CoglPipeline *pipeline;
+
+ wrap_mode_s = wrap_modes[i];
+ wrap_mode_t = wrap_modes[i + 1];
+ pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t);
+ cogl_set_source (pipeline);
+ cogl_object_unref (pipeline);
+ cogl_push_matrix ();
+ cogl_translate (TEX_SIZE * i, 0.0f, 0.0f);
+ /* Render the pipeline at four times the size of the texture */
+ cogl_polygon (vertices, G_N_ELEMENTS (vertices), FALSE);
+ cogl_pop_matrix ();
+ }
+}
+
+static void
+draw_tests_vbo (TestState *state)
+{
+ CoglHandle vbo;
+ int i;
+
+ vbo = cogl_vertex_buffer_new (4);
+ cogl_vertex_buffer_add (vbo, "gl_Vertex", 3,
+ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
+ sizeof (vertices[0]),
+ &vertices[0].x);
+ cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0", 2,
+ COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
+ sizeof (vertices[0]),
+ &vertices[0].tx);
+ cogl_vertex_buffer_submit (vbo);
+
+ for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
+ {
+ CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
+ CoglPipeline *pipeline;
+
+ wrap_mode_s = wrap_modes[i];
+ wrap_mode_t = wrap_modes[i + 1];
+ pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t);
+ cogl_set_source (pipeline);
+ cogl_object_unref (pipeline);
+ cogl_push_matrix ();
+ cogl_translate (TEX_SIZE * i, 0.0f, 0.0f);
+ /* Render the pipeline at four times the size of the texture */
+ cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, 4);
+ cogl_pop_matrix ();
+ }
+
+ cogl_handle_unref (vbo);
+}
+
+static void
+validate_set (TestState *state, int offset)
+{
+ uint8_t data[TEX_SIZE * 2 * TEX_SIZE * 2 * 4], *p;
+ int x, y, i;
+
+ for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
+ {
+ CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
+
+ wrap_mode_s = wrap_modes[i];
+ wrap_mode_t = wrap_modes[i + 1];
+
+ cogl_framebuffer_read_pixels (test_fb, i * TEX_SIZE, offset * TEX_SIZE * 2,
+ TEX_SIZE * 2, TEX_SIZE * 2,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ data);
+
+ p = data;
+
+ for (y = 0; y < TEX_SIZE * 2; y++)
+ for (x = 0; x < TEX_SIZE * 2; x++)
+ {
+ uint8_t green, blue;
+
+ if (x < TEX_SIZE ||
+ wrap_mode_s == COGL_PIPELINE_WRAP_MODE_REPEAT ||
+ wrap_mode_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
+ green = (x & 1) * 255;
+ else
+ green = ((TEX_SIZE - 1) & 1) * 255;
+
+ if (y < TEX_SIZE ||
+ wrap_mode_t == COGL_PIPELINE_WRAP_MODE_REPEAT ||
+ wrap_mode_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
+ blue = (y & 1) * 255;
+ else
+ blue = ((TEX_SIZE - 1) & 1) * 255;
+
+ g_assert_cmpint (p[0], ==, 0);
+ g_assert_cmpint (p[1], ==, green);
+ g_assert_cmpint (p[2], ==, blue);
+
+ p += 4;
+ }
+ }
+}
+
+static void
+validate_result (TestState *state)
+{
+ validate_set (state, 0); /* non-atlased rectangle */
+#if 0 /* this doesn't currently work */
+ validate_set (state, 1); /* atlased rectangle */
+#endif
+ validate_set (state, 2); /* cogl_polygon */
+ validate_set (state, 3); /* vertex buffer */
+}
+
+static void
+paint (TestState *state)
+{
+ /* Draw the tests first with a non atlased texture */
+ state->texture = create_texture (TEST_UTILS_TEXTURE_NO_ATLAS);
+ draw_tests (state);
+ cogl_object_unref (state->texture);
+
+ /* Draw the tests again with a possible atlased texture. This should
+ end up testing software repeats */
+ state->texture = create_texture (TEST_UTILS_TEXTURE_NONE);
+ cogl_framebuffer_push_matrix (test_fb);
+ cogl_framebuffer_translate (test_fb, 0.0f, TEX_SIZE * 2.0f, 0.0f);
+ draw_tests (state);
+ cogl_pop_matrix ();
+ cogl_object_unref (state->texture);
+
+ /* Draw the tests using cogl_polygon */
+ state->texture = create_texture (COGL_TEXTURE_NO_ATLAS);
+ cogl_push_matrix ();
+ cogl_translate (0.0f, TEX_SIZE * 4.0f, 0.0f);
+ draw_tests_polygon (state);
+ cogl_pop_matrix ();
+ cogl_object_unref (state->texture);
+
+ /* Draw the tests using a vertex buffer */
+ state->texture = create_texture (COGL_TEXTURE_NO_ATLAS);
+ cogl_push_matrix ();
+ cogl_translate (0.0f, TEX_SIZE * 6.0f, 0.0f);
+ draw_tests_vbo (state);
+ cogl_pop_matrix ();
+ cogl_object_unref (state->texture);
+
+ validate_result (state);
+}
+
+void
+test_wrap_modes (void)
+{
+ TestState state;
+
+ state.width = cogl_framebuffer_get_width (test_fb);
+ state.height = cogl_framebuffer_get_height (test_fb);
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0,
+ state.width,
+ state.height,
+ -1,
+ 100);
+
+ /* XXX: we have to push/pop a framebuffer since this test currently
+ * uses the legacy cogl_vertex_buffer_draw() api. */
+ cogl_push_framebuffer (test_fb);
+ paint (&state);
+ cogl_pop_framebuffer ();
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/conform/test-wrap-rectangle-textures.c b/cogl/tests/conform/test-wrap-rectangle-textures.c
new file mode 100644
index 000000000..73b357536
--- /dev/null
+++ b/cogl/tests/conform/test-wrap-rectangle-textures.c
@@ -0,0 +1,175 @@
+#include <cogl/cogl.h>
+
+#include <string.h>
+
+#include "test-utils.h"
+
+#define DRAW_SIZE 64
+
+static CoglPipeline *
+create_base_pipeline (void)
+{
+ CoglBitmap *bmp;
+ CoglTextureRectangle *tex;
+ CoglPipeline *pipeline;
+ uint8_t tex_data[] =
+ {
+ 0x44, 0x44, 0x44, 0x88, 0x88, 0x88,
+ 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0xff
+ };
+
+ bmp = cogl_bitmap_new_for_data (test_ctx,
+ 2, 2, /* width/height */
+ COGL_PIXEL_FORMAT_RGB_888,
+ 2 * 3, /* rowstride */
+ tex_data);
+
+ tex = cogl_texture_rectangle_new_from_bitmap (bmp);
+
+ cogl_object_unref (bmp);
+
+ pipeline = cogl_pipeline_new (test_ctx);
+
+ cogl_pipeline_set_layer_filters (pipeline,
+ 0, /* layer */
+ COGL_PIPELINE_FILTER_NEAREST,
+ COGL_PIPELINE_FILTER_NEAREST);
+
+ cogl_pipeline_set_layer_texture (pipeline,
+ 0, /* layer */
+ tex);
+
+ cogl_object_unref (tex);
+
+ return pipeline;
+}
+
+static void
+check_colors (int x_offset,
+ int y_offset,
+ const uint8_t expected_colors[9])
+{
+ int x, y;
+
+ for (y = 0; y < 4; y++)
+ for (x = 0; x < 4; x++)
+ {
+ uint32_t color = expected_colors[x + y * 4];
+ test_utils_check_region (test_fb,
+ x * DRAW_SIZE / 4 + 1 + x_offset,
+ y * DRAW_SIZE / 4 + 1 + y_offset,
+ DRAW_SIZE / 4 - 2,
+ DRAW_SIZE / 4 - 2,
+ 0xff |
+ (color << 8) |
+ (color << 16) |
+ (color << 24));
+ }
+}
+
+static void
+test_pipeline (CoglPipeline *pipeline,
+ int x_offset,
+ int y_offset,
+ const uint8_t expected_colors[9])
+{
+ float x1 = x_offset;
+ float y1 = y_offset;
+ float x2 = x1 + DRAW_SIZE;
+ float y2 = y1 + DRAW_SIZE;
+ int y, x;
+
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ x1, y1,
+ x2, y2,
+ -0.5f, /* s1 */
+ -0.5f, /* t1 */
+ 1.5f, /* s2 */
+ 1.5f /* t2 */);
+
+ check_colors (x_offset, y_offset, expected_colors);
+
+ /* Also try drawing each quadrant of the rectangle with a small
+ * rectangle */
+
+ for (y = -1; y < 3; y++)
+ for (x = -1; x < 3; x++)
+ {
+ x1 = x_offset + (x + 1) * DRAW_SIZE / 4 + DRAW_SIZE;
+ y1 = y_offset + (y + 1) * DRAW_SIZE / 4;
+ x2 = x1 + DRAW_SIZE / 4;
+ y2 = y1 + DRAW_SIZE / 4;
+
+ cogl_framebuffer_draw_textured_rectangle (test_fb,
+ pipeline,
+ x1, y1,
+ x2, y2,
+ x / 2.0f, /* s1 */
+ y / 2.0f, /* t1 */
+ (x + 1) / 2.0f, /* s2 */
+ (y + 1) / 2.0f /* t2 */);
+ }
+
+ check_colors (x_offset + DRAW_SIZE, y_offset, expected_colors);
+}
+
+void
+test_wrap_rectangle_textures (void)
+{
+ float fb_width = cogl_framebuffer_get_width (test_fb);
+ float fb_height = cogl_framebuffer_get_height (test_fb);
+ CoglPipeline *base_pipeline;
+ CoglPipeline *clamp_pipeline;
+ CoglPipeline *repeat_pipeline;
+ /* The textures are drawn with the texture coordinates from
+ * -0.5→1.5. That means we get one complete copy of the texture and
+ * an extra half of the texture surrounding it. The drawing is
+ * tested against a 4x4 grid of colors. The center 2x2 colours
+ * specify the normal texture colors and the other colours specify
+ * what the wrap mode should generate */
+ static const uint8_t clamp_colors[] =
+ {
+ 0x44, 0x44, 0x88, 0x88,
+ 0x44, 0x44, 0x88, 0x88,
+ 0xcc, 0xcc, 0xff, 0xff,
+ 0xcc, 0xcc, 0xff, 0xff
+ };
+ static const uint8_t repeat_colors[] =
+ {
+ 0xff, 0xcc, 0xff, 0xcc,
+ 0x88, 0x44, 0x88, 0x44,
+ 0xff, 0xcc, 0xff, 0xcc,
+ 0x88, 0x44, 0x88, 0x44
+ };
+
+ cogl_framebuffer_orthographic (test_fb,
+ 0, 0, /* x_1, y_1 */
+ fb_width, /* x_2 */
+ fb_height /* y_2 */,
+ -1, 100 /* near/far */);
+
+ base_pipeline = create_base_pipeline ();
+
+ clamp_pipeline = cogl_pipeline_copy (base_pipeline);
+ cogl_pipeline_set_layer_wrap_mode (clamp_pipeline,
+ 0, /* layer */
+ COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+
+ repeat_pipeline = cogl_pipeline_copy (base_pipeline);
+ cogl_pipeline_set_layer_wrap_mode (repeat_pipeline,
+ 0, /* layer */
+ COGL_PIPELINE_WRAP_MODE_REPEAT);
+
+ test_pipeline (clamp_pipeline,
+ 0, 0, /* x/y offset */
+ clamp_colors);
+
+ test_pipeline (repeat_pipeline,
+ 0, DRAW_SIZE * 2, /* x/y offset */
+ repeat_colors);
+
+ cogl_object_unref (repeat_pipeline);
+ cogl_object_unref (clamp_pipeline);
+ cogl_object_unref (base_pipeline);
+}
diff --git a/cogl/tests/conform/test-write-texture-formats.c b/cogl/tests/conform/test-write-texture-formats.c
new file mode 100644
index 000000000..d415df0a7
--- /dev/null
+++ b/cogl/tests/conform/test-write-texture-formats.c
@@ -0,0 +1,184 @@
+#include <cogl/cogl2-experimental.h>
+#include <stdarg.h>
+
+#include "test-utils.h"
+
+/*
+ * This tests writing data to an RGBA texture in all of the available
+ * pixel formats
+ */
+
+static void
+test_color (CoglTexture *texture,
+ uint32_t expected_pixel)
+{
+ uint8_t received_pixel[4];
+
+ cogl_texture_get_data (texture,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 4, /* rowstride */
+ received_pixel);
+
+ test_utils_compare_pixel_and_alpha (received_pixel, expected_pixel);
+}
+
+static void
+test_write_byte (CoglContext *context,
+ CoglPixelFormat format,
+ uint8_t byte,
+ uint32_t expected_pixel)
+{
+ CoglTexture *texture = test_utils_create_color_texture (context, 0);
+
+ cogl_texture_set_region (texture,
+ 0, 0, /* src_x / src_y */
+ 0, 0, /* dst_x / dst_y */
+ 1, 1, /* dst_w / dst_h */
+ 1, 1, /* width / height */
+ format,
+ 1, /* rowstride */
+ &byte);
+
+ test_color (texture, expected_pixel);
+
+ cogl_object_unref (texture);
+}
+
+static void
+test_write_short (CoglContext *context,
+ CoglPixelFormat format,
+ uint16_t value,
+ uint32_t expected_pixel)
+{
+ CoglTexture *texture = test_utils_create_color_texture (context, 0);
+
+ cogl_texture_set_region (texture,
+ 0, 0, /* src_x / src_y */
+ 0, 0, /* dst_x / dst_y */
+ 1, 1, /* dst_w / dst_h */
+ 1, 1, /* width / height */
+ format,
+ 2, /* rowstride */
+ (uint8_t *) &value);
+
+ test_color (texture, expected_pixel);
+
+ cogl_object_unref (texture);
+}
+
+static void
+test_write_bytes (CoglContext *context,
+ CoglPixelFormat format,
+ uint32_t value,
+ uint32_t expected_pixel)
+{
+ CoglTexture *texture = test_utils_create_color_texture (context, 0);
+
+ value = GUINT32_TO_BE (value);
+
+ cogl_texture_set_region (texture,
+ 0, 0, /* src_x / src_y */
+ 0, 0, /* dst_x / dst_y */
+ 1, 1, /* dst_w / dst_h */
+ 1, 1, /* width / height */
+ format,
+ 4, /* rowstride */
+ (uint8_t *) &value);
+
+ test_color (texture, expected_pixel);
+
+ cogl_object_unref (texture);
+}
+
+static void
+test_write_int (CoglContext *context,
+ CoglPixelFormat format,
+ uint32_t expected_pixel,
+ ...)
+{
+ va_list ap;
+ int bits;
+ uint32_t tex_data = 0;
+ int bits_sum = 0;
+ CoglTexture *texture = test_utils_create_color_texture (context, 0);
+
+ va_start (ap, expected_pixel);
+
+ /* Convert the va args into a single 32-bit value */
+ while ((bits = va_arg (ap, int)) != -1)
+ {
+ uint32_t value = (va_arg (ap, int) * ((1 << bits) - 1) + 127) / 255;
+
+ bits_sum += bits;
+
+ tex_data |= value << (32 - bits_sum);
+ }
+
+ va_end (ap);
+
+ cogl_texture_set_region (texture,
+ 0, 0, /* src_x / src_y */
+ 0, 0, /* dst_x / dst_y */
+ 1, 1, /* dst_w / dst_h */
+ 1, 1, /* width / height */
+ format,
+ 4, /* rowstride */
+ (uint8_t *) &tex_data);
+
+ test_color (texture, expected_pixel);
+
+ cogl_object_unref (texture);
+}
+
+void
+test_write_texture_formats (void)
+{
+ test_write_byte (test_ctx, COGL_PIXEL_FORMAT_A_8, 0x34, 0x00000034);
+#if 0
+ /* I'm not sure what's the right value to put here because Nvidia
+ and Mesa seem to behave differently so one of them must be
+ wrong. */
+ test_write_byte (test_ctx, COGL_PIXEL_FORMAT_G_8, 0x34, 0x340000ff);
+#endif
+
+ /* We should always be able to read from an RG buffer regardless of
+ * whether RG textures are supported because Cogl will do the
+ * conversion for us */
+ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_RG_88, 0x123456ff, 0x123400ff);
+
+ test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGB_565, 0x0843, 0x080819ff);
+ test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGBA_4444_PRE, 0x1234, 0x11223344);
+ test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGBA_5551_PRE, 0x0887, 0x081019ff);
+
+ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_RGB_888, 0x123456ff, 0x123456ff);
+ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_BGR_888, 0x563412ff, 0x123456ff);
+
+ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ 0x12345678, 0x12345678);
+ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_BGRA_8888_PRE,
+ 0x56341278, 0x12345678);
+ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_ARGB_8888_PRE,
+ 0x78123456, 0x12345678);
+ test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_ABGR_8888_PRE,
+ 0x78563412, 0x12345678);
+
+ test_write_int (test_ctx, COGL_PIXEL_FORMAT_RGBA_1010102_PRE,
+ 0x123456ff,
+ 10, 0x12, 10, 0x34, 10, 0x56, 2, 0xff,
+ -1);
+ test_write_int (test_ctx, COGL_PIXEL_FORMAT_BGRA_1010102_PRE,
+ 0x123456ff,
+ 10, 0x56, 10, 0x34, 10, 0x12, 2, 0xff,
+ -1);
+ test_write_int (test_ctx, COGL_PIXEL_FORMAT_ARGB_2101010_PRE,
+ 0x123456ff,
+ 2, 0xff, 10, 0x12, 10, 0x34, 10, 0x56,
+ -1);
+ test_write_int (test_ctx, COGL_PIXEL_FORMAT_ABGR_2101010_PRE,
+ 0x123456ff,
+ 2, 0xff, 10, 0x56, 10, 0x34, 10, 0x12,
+ -1);
+
+ if (cogl_test_verbose ())
+ g_print ("OK\n");
+}
diff --git a/cogl/tests/data/Makefile.am b/cogl/tests/data/Makefile.am
new file mode 100644
index 000000000..3a2030a77
--- /dev/null
+++ b/cogl/tests/data/Makefile.am
@@ -0,0 +1,3 @@
+NULL =
+
+EXTRA_DIST = valgrind.suppressions
diff --git a/cogl/tests/data/valgrind.suppressions b/cogl/tests/data/valgrind.suppressions
new file mode 100644
index 000000000..f47498d16
--- /dev/null
+++ b/cogl/tests/data/valgrind.suppressions
@@ -0,0 +1,173 @@
+{
+ ioctl_1
+ Memcheck:Param
+ ioctl(generic)
+ fun:ioctl
+ fun:driDrawableInitVBlank
+ fun:intelMakeCurrent
+ fun:glXMakeContextCurrent
+}
+
+{
+ ioctl_2
+ Memcheck:Param
+ ioctl(generic)
+ fun:ioctl
+ fun:driDrawableGetMSC32
+ fun:clutter_backend_glx_redraw
+}
+
+{
+ ioctl_3
+ Memcheck:Param
+ ioctl(generic)
+ fun:ioctl
+ fun:driWaitForMSC32
+ fun:clutter_backend_glx_redraw
+}
+
+{
+ mesa_init_context
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:glXCreateNewContext
+}
+
+{
+ type_register
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:g_type_register_*
+}
+
+{
+ type_ref
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:g_type_class_ref
+}
+
+{
+ type_interface_prereq
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:g_type_interface_add_prerequisite
+}
+
+{
+ get_charset
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:g_get_charset
+}
+
+{
+ cogl_features
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:cogl_get_features
+}
+
+{
+ glx_query_version
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:glXQueryVersion
+}
+
+{
+ glx_create_context
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:glXCreateNewContext
+}
+
+{
+ glx_make_current
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:glXMakeContextCurrent
+}
+
+{
+ gl_draw_arrays
+ Memcheck:Leak
+ fun:*malloc
+ ...
+ fun:glDrawArrays
+}
+
+{
+ cogl_clear
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:cogl_clear
+}
+
+{
+ default_font
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:clutter_backend_get_font_name
+}
+
+{
+ id_pool
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:clutter_id_pool_new
+}
+
+{
+ x_open_display
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:XOpenDisplay
+}
+
+# ... and font descriptions from every "sans 12" type string
+{
+ pango_font_description_from_string
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:pango_font_description_from_string
+}
+
+# other lib init
+{
+ fontconfig_init
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:FcConfigParseAndLoad
+}
+
+{
+ freetype_init
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:FT_Open_Face
+}
+
+{
+ x_init_ext
+ Memcheck:Leak
+ fun:*alloc
+ ...
+ fun:XInitExtension
+}
diff --git a/cogl/tests/micro-perf/Makefile.am b/cogl/tests/micro-perf/Makefile.am
new file mode 100644
index 000000000..75d02b2ce
--- /dev/null
+++ b/cogl/tests/micro-perf/Makefile.am
@@ -0,0 +1,24 @@
+NULL =
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)
+
+test_conformance_CPPFLAGS = \
+ -DCOGL_ENABLE_EXPERIMENTAL_API \
+ -DCOGL_DISABLE_DEPRECATED \
+ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\"
+
+
+noinst_PROGRAMS =
+
+noinst_PROGRAMS += test-journal
+
+AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS)
+
+common_ldadd = \
+ $(COGL_DEP_LIBS) \
+ $(top_builddir)/cogl/libmutter-cogl.la \
+ $(LIBM)
+
+test_journal_SOURCES = test-journal.c
+test_journal_LDADD = $(common_ldadd)
diff --git a/cogl/tests/micro-perf/test-journal.c b/cogl/tests/micro-perf/test-journal.c
new file mode 100644
index 000000000..35e3cd5a3
--- /dev/null
+++ b/cogl/tests/micro-perf/test-journal.c
@@ -0,0 +1,190 @@
+#include <glib.h>
+#include <cogl/cogl2-experimental.h>
+#include <math.h>
+
+#include "cogl/cogl-profile.h"
+
+#define FRAMEBUFFER_WIDTH 800
+#define FRAMEBUFFER_HEIGHT 600
+
+CoglBool run_all = FALSE;
+
+typedef struct _Data
+{
+ CoglContext *ctx;
+ CoglFramebuffer *fb;
+ CoglPipeline *pipeline;
+ CoglPipeline *alpha_pipeline;
+ GTimer *timer;
+ int frame;
+} Data;
+
+static void
+test_rectangles (Data *data)
+{
+#define RECT_WIDTH 5
+#define RECT_HEIGHT 5
+ int x;
+ int y;
+
+ cogl_framebuffer_clear4f (data->fb, COGL_BUFFER_BIT_COLOR, 1, 1, 1, 1);
+
+ cogl_framebuffer_push_rectangle_clip (data->fb,
+ 10,
+ 10,
+ FRAMEBUFFER_WIDTH - 10,
+ FRAMEBUFFER_HEIGHT - 10);
+
+ /* Should the rectangles be randomly positioned/colored/rotated?
+ *
+ * It could be good to develop equivalent GL and Cairo tests so we can
+ * have a sanity check for our Cogl performance.
+ *
+ * The color should vary to check that we correctly batch color changes
+ * The use of alpha should vary so we have a variation of which rectangles
+ * require blending.
+ * Should this be a random variation?
+ * It could be good to experiment with focibly enabling blending for
+ * rectangles that don't technically need it for the sake of extending
+ * batching. E.g. if you a long run of interleved rectangles with every
+ * other rectangle needing blending then it may be worth enabling blending
+ * for all the rectangles to avoid the state changes.
+ * The modelview should change between rectangles to check the software
+ * transform codepath.
+ * Should we group some rectangles under the same modelview? Potentially
+ * we could avoid software transform for long runs of rectangles with the
+ * same modelview.
+ *
+ */
+ for (y = 0; y < FRAMEBUFFER_HEIGHT; y += RECT_HEIGHT)
+ {
+ for (x = 0; x < FRAMEBUFFER_WIDTH; x += RECT_WIDTH)
+ {
+ cogl_framebuffer_push_matrix (data->fb);
+ cogl_framebuffer_translate (data->fb, x, y, 0);
+ cogl_framebuffer_rotate (data->fb, 45, 0, 0, 1);
+
+ cogl_pipeline_set_color4f (data->pipeline,
+ 1,
+ (1.0f/FRAMEBUFFER_WIDTH)*y,
+ (1.0f/FRAMEBUFFER_HEIGHT)*x,
+ 1);
+ cogl_framebuffer_draw_rectangle (data->fb,
+ data->pipeline,
+ 0, 0, RECT_WIDTH, RECT_HEIGHT);
+
+ cogl_framebuffer_pop_matrix (data->fb);
+ }
+ }
+
+ for (y = 0; y < FRAMEBUFFER_HEIGHT; y += RECT_HEIGHT)
+ {
+ for (x = 0; x < FRAMEBUFFER_WIDTH; x += RECT_WIDTH)
+ {
+ cogl_framebuffer_push_matrix (data->fb);
+ cogl_framebuffer_translate (data->fb, x, y, 0);
+
+ cogl_pipeline_set_color4f (data->alpha_pipeline,
+ 1,
+ (1.0f/FRAMEBUFFER_WIDTH)*x,
+ (1.0f/FRAMEBUFFER_HEIGHT)*y,
+ (1.0f/FRAMEBUFFER_WIDTH)*x);
+ cogl_framebuffer_draw_rectangle (data->fb,
+ data->alpha_pipeline,
+ 0, 0, RECT_WIDTH, RECT_HEIGHT);
+
+ cogl_framebuffer_pop_matrix (data->fb);
+ }
+ }
+
+ cogl_framebuffer_pop_clip (data->fb);
+}
+
+static CoglBool
+paint_cb (void *user_data)
+{
+ Data *data = user_data;
+ double elapsed;
+
+ data->frame++;
+
+ test_rectangles (data);
+
+ cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb));
+
+ elapsed = g_timer_elapsed (data->timer, NULL);
+ if (elapsed > 1.0)
+ {
+ g_print ("fps = %f\n", data->frame / elapsed);
+ g_timer_start (data->timer);
+ data->frame = 0;
+ }
+
+ return FALSE; /* remove the callback */
+}
+
+static void
+frame_event_cb (CoglOnscreen *onscreen,
+ CoglFrameEvent event,
+ CoglFrameInfo *info,
+ void *user_data)
+{
+ if (event == COGL_FRAME_EVENT_SYNC)
+ paint_cb (user_data);
+}
+
+int
+main (int argc, char **argv)
+{
+ Data data;
+ CoglOnscreen *onscreen;
+ GSource *cogl_source;
+ GMainLoop *loop;
+ COGL_STATIC_TIMER (mainloop_timer,
+ NULL, //no parent
+ "Mainloop",
+ "The time spent in the glib mainloop",
+ 0); // no application private data
+
+ data.ctx = cogl_context_new (NULL, NULL);
+
+ onscreen = cogl_onscreen_new (data.ctx,
+ FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
+ cogl_onscreen_set_swap_throttled (onscreen, FALSE);
+ cogl_onscreen_show (onscreen);
+
+ data.fb = onscreen;
+ cogl_framebuffer_orthographic (data.fb,
+ 0, 0,
+ FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
+ -1,
+ 100);
+
+ data.pipeline = cogl_pipeline_new (data.ctx);
+ cogl_pipeline_set_color4f (data.pipeline, 1, 1, 1, 1);
+ data.alpha_pipeline = cogl_pipeline_new (data.ctx);
+ cogl_pipeline_set_color4f (data.alpha_pipeline, 1, 1, 1, 0.5);
+
+ cogl_source = cogl_glib_source_new (data.ctx, G_PRIORITY_DEFAULT);
+
+ g_source_attach (cogl_source, NULL);
+
+ cogl_onscreen_add_frame_callback (COGL_ONSCREEN (data.fb),
+ frame_event_cb,
+ &data,
+ NULL); /* destroy notify */
+
+ g_idle_add (paint_cb, &data);
+
+ data.frame = 0;
+ data.timer = g_timer_new ();
+ g_timer_start (data.timer);
+
+ loop = g_main_loop_new (NULL, TRUE);
+ COGL_TIMER_START (uprof_get_mainloop_context (), mainloop_timer);
+ g_main_loop_run (loop);
+ COGL_TIMER_STOP (uprof_get_mainloop_context (), mainloop_timer);
+
+ return 0;
+}
+
diff --git a/cogl/tests/run-tests.sh b/cogl/tests/run-tests.sh
new file mode 100755
index 000000000..7e62bf0f6
--- /dev/null
+++ b/cogl/tests/run-tests.sh
@@ -0,0 +1,157 @@
+#!/bin/bash
+
+if test -z "$G_DEBUG"; then
+ G_DEBUG=fatal-warnings
+else
+ G_DEBUG="$G_DEBUG,fatal-warnings"
+fi
+
+export G_DEBUG
+
+ENVIRONMENT_CONFIG=$1
+shift
+
+TEST_BINARY=$1
+shift
+
+. $ENVIRONMENT_CONFIG
+
+set +m
+
+trap "" ERR
+trap "" SIGABRT
+trap "" SIGFPE
+trap "" SIGSEGV
+
+EXIT=0
+MISSING_FEATURE="WARNING: Missing required feature";
+KNOWN_FAILURE="WARNING: Test is known to fail";
+
+echo "Key:"
+echo "ok = Test passed"
+echo "n/a = Driver is missing a feature required for the test"
+echo "FAIL = Unexpected failure"
+echo "FIXME = Test failed, but it was an expected failure"
+echo "PASS! = Unexpected pass"
+echo ""
+
+get_status()
+{
+ case $1 in
+ # Special value we use to indicate that the test failed
+ # but it was an expected failure so don't fail the
+ # overall test run as a result...
+ 300)
+ echo -n "FIXME";;
+ # Special value we use to indicate that the test passed
+ # but we weren't expecting it to pass‽
+ 400)
+ echo -n 'PASS!';;
+
+ # Special value to indicate the test is missing a required feature
+ 500)
+ echo -n "n/a";;
+
+ 0)
+ echo -n "ok";;
+
+ *)
+ echo -n "FAIL";;
+ esac
+}
+
+run_test()
+{
+ $($TEST_BINARY $1 &>.log)
+ TMP=$?
+ var_name=$2_result
+ eval $var_name=$TMP
+ if grep -q "$MISSING_FEATURE" .log; then
+ if test $TMP -ne 0; then
+ eval $var_name=500
+ else
+ eval $var_name=400
+ fi
+ elif grep -q "$KNOWN_FAILURE" .log; then
+ if test $TMP -ne 0; then
+ eval $var_name=300
+ else
+ eval $var_name=400
+ fi
+ else
+ if test $TMP -ne 0; then EXIT=$TMP; fi
+ fi
+}
+
+TITLE_FORMAT="%35s"
+printf $TITLE_FORMAT "Test"
+
+if test $HAVE_GL -eq 1; then
+ GL_FORMAT=" %6s %8s %7s %6s %6s"
+ printf "$GL_FORMAT" "GL+FF" "GL+ARBFP" "GL+GLSL" "GL-NPT" "GL3"
+fi
+if test $HAVE_GLES2 -eq 1; then
+ GLES2_FORMAT=" %6s %7s"
+ printf "$GLES2_FORMAT" "ES2" "ES2-NPT"
+fi
+
+echo ""
+echo ""
+
+for test in `cat unit-tests`
+do
+ export COGL_DEBUG=
+
+ if test $HAVE_GL -eq 1; then
+ export COGL_DRIVER=gl
+ export COGL_DEBUG=disable-glsl,disable-arbfp
+ run_test $test gl_ff
+
+ export COGL_DRIVER=gl
+ # NB: we can't explicitly disable fixed + glsl in this case since
+ # the arbfp code only supports fragment processing so we need either
+ # the fixed or glsl vertends
+ export COGL_DEBUG=
+ run_test $test gl_arbfp
+
+ export COGL_DRIVER=gl
+ export COGL_DEBUG=disable-fixed,disable-arbfp
+ run_test $test gl_glsl
+
+ export COGL_DRIVER=gl
+ export COGL_DEBUG=disable-npot-textures
+ run_test $test gl_npot
+
+ export COGL_DRIVER=gl3
+ export COGL_DEBUG=
+ run_test $test gl3
+ fi
+
+ if test $HAVE_GLES2 -eq 1; then
+ export COGL_DRIVER=gles2
+ export COGL_DEBUG=
+ run_test $test gles2
+
+ export COGL_DRIVER=gles2
+ export COGL_DEBUG=disable-npot-textures
+ run_test $test gles2_npot
+ fi
+
+ printf $TITLE_FORMAT "$test:"
+ if test $HAVE_GL -eq 1; then
+ printf "$GL_FORMAT" \
+ "`get_status $gl_ff_result`" \
+ "`get_status $gl_arbfp_result`" \
+ "`get_status $gl_glsl_result`" \
+ "`get_status $gl_npot_result`" \
+ "`get_status $gl3_result`"
+ fi
+ if test $HAVE_GLES2 -eq 1; then
+ printf "$GLES2_FORMAT" \
+ "`get_status $gles2_result`" \
+ "`get_status $gles2_npot_result`"
+ fi
+ echo ""
+done
+
+exit $EXIT
diff --git a/cogl/tests/test-launcher.sh b/cogl/tests/test-launcher.sh
new file mode 100755
index 000000000..e159e2e49
--- /dev/null
+++ b/cogl/tests/test-launcher.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+TEST_BINARY=$1
+shift
+
+SYMBOL_PREFIX=$1
+shift
+
+UNIT_TEST=$1
+shift
+
+test -z ${UNIT_TEST} && {
+ echo "Usage: $0 UNIT_TEST"
+ exit 1
+}
+
+BINARY_NAME=`basename $TEST_BINARY`
+UNIT_TEST=`echo $UNIT_TEST|sed 's/-/_/g'`
+
+echo "Running: ./$BINARY_NAME ${UNIT_TEST} $@"
+echo ""
+COGL_TEST_VERBOSE=1 $TEST_BINARY ${UNIT_TEST} "$@"
+exit_val=$?
+
+if test $exit_val -eq 0; then
+ echo "OK"
+fi
+
+echo ""
+echo "NOTE: For debugging purposes, you can run this single test as follows:"
+echo "$ libtool --mode=execute \\"
+echo " gdb --eval-command=\"start\" --eval-command=\"b ${UNIT_TEST#${SYMBOL_PREFIX}}\" \\"
+echo " --args ./$BINARY_NAME ${UNIT_TEST}"
+echo "or:"
+echo "$ env G_SLICE=always-malloc \\"
+echo " libtool --mode=execute \\"
+echo " valgrind ./$BINARY_NAME ${UNIT_TEST}"
+
+exit $exit_val
diff --git a/cogl/tests/unit/Makefile.am b/cogl/tests/unit/Makefile.am
new file mode 100644
index 000000000..5c1c08100
--- /dev/null
+++ b/cogl/tests/unit/Makefile.am
@@ -0,0 +1,83 @@
+NULL =
+
+noinst_PROGRAMS = test-unit
+
+test_unit_SOURCES = test-unit-main.c
+
+SHEXT = $(EXEEXT)
+
+# For convenience, this provides a way to easily run individual unit tests:
+.PHONY: wrappers clean-wrappers
+
+wrappers: stamp-test-unit
+ @true
+stamp-test-unit: Makefile test-unit$(EXEEXT)
+ @mkdir -p wrappers
+ . $(top_builddir)/cogl/libmutter-cogl.la ; \
+ $(NM) $(top_builddir)/cogl/.libs/"$$dlname"| \
+ grep '[DR] _\?unit_test_'|sed 's/.\+ [DR] _\?//' > unit-tests
+ @chmod +x $(top_srcdir)/tests/test-launcher.sh
+ @( echo "/stamp-test-unit" ; \
+ echo "/test-unit$(EXEEXT)" ; \
+ echo "*.o" ; \
+ echo ".gitignore" ; \
+ echo "unit-tests" ; ) > .gitignore
+ @for i in `cat unit-tests`; \
+ do \
+ unit=`echo $$i | sed -e s/_/-/g | sed s/unit-test-//`; \
+ echo " GEN $$unit"; \
+ ( echo "#!/bin/sh" ; echo "$(top_srcdir)/tests/test-launcher.sh $(abs_builddir)/test-unit$(EXEEXT) 'unit_test_' '$$i' \"\$$@\"" ) > $$unit$(SHEXT) ; \
+ chmod +x $$unit$(SHEXT); \
+ echo "/$$unit$(SHEXT)" >> .gitignore; \
+ done \
+ && echo timestamp > $(@F)
+
+clean-wrappers:
+ @for i in `cat unit-tests`; \
+ do \
+ unit=`echo $$i | sed -e s/_/-/g | sed s/unit-test-//`; \
+ echo " RM $$unit"; \
+ rm -f $$unit$(SHEXT) ; \
+ done \
+ && rm -f unit-tests \
+ && rm -f stamp-test-unit
+
+# NB: BUILT_SOURCES here a misnomer. We aren't building source, just inserting
+# a phony rule that will generate symlink scripts for running individual tests
+BUILT_SOURCES = wrappers
+
+# The include of the $(buildir)/cogl directory here is to make it so
+# that tests that directly include Cogl source code for whitebox
+# testing (such as test-bitmask) will still compile
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/test-fixtures \
+ -I$(top_builddir)/cogl
+
+AM_CPPFLAGS += \
+ -DCOGL_DISABLE_DEPRECATED \
+ -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" \
+ -DCOGL_COMPILATION
+
+test_unit_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS)
+test_unit_LDADD = \
+ $(COGL_DEP_LIBS) \
+ $(top_builddir)/cogl/libmutter-cogl.la \
+ $(LIBM)
+test_unit_LDFLAGS = -export-dynamic
+
+test: wrappers
+ @$(top_srcdir)/tests/run-tests.sh $(abs_builddir)/../config.env $(abs_builddir)/test-unit$(EXEEXT)
+
+# XXX: we could prevent the unit test suite from running
+# by simply defining this variable conditionally
+TEST_PROGS = test-unit
+
+.PHONY: test
+
+DISTCLEANFILES = .gitignore
+
+# we override the clean-generic target to clean up the wrappers so
+# we cannot use CLEANFILES
+clean-generic: clean-wrappers
+ $(QUIET_RM)rm -f .log
diff --git a/cogl/tests/unit/test-unit-main.c b/cogl/tests/unit/test-unit-main.c
new file mode 100644
index 000000000..b1f78645e
--- /dev/null
+++ b/cogl/tests/unit/test-unit-main.c
@@ -0,0 +1,45 @@
+#include <config.h>
+
+#include <gmodule.h>
+
+#include <test-fixtures/test-unit.h>
+#include <stdlib.h>
+
+int
+main (int argc, char **argv)
+{
+ GModule *main_module;
+ const CoglUnitTest *unit_test;
+ int i;
+
+ if (argc != 2)
+ {
+ g_printerr ("usage %s UNIT_TEST\n", argv[0]);
+ exit (1);
+ }
+
+ /* Just for convenience in case people try passing the wrapper
+ * filenames for the UNIT_TEST argument we normalize '-' characters
+ * to '_' characters... */
+ for (i = 0; argv[1][i]; i++)
+ {
+ if (argv[1][i] == '-')
+ argv[1][i] = '_';
+ }
+
+ main_module = g_module_open (NULL, /* use main module */
+ 0 /* flags */);
+
+ if (!g_module_symbol (main_module, argv[1], (void **) &unit_test))
+ {
+ g_printerr ("Unknown test name \"%s\"\n", argv[1]);
+ return 1;
+ }
+
+ test_utils_init (unit_test->requirement_flags,
+ unit_test->known_failure_flags);
+ unit_test->run ();
+ test_utils_fini ();
+
+ return 0;
+}