diff options
author | Rui Matos <tiagomatos@gmail.com> | 2016-04-22 16:44:31 +0200 |
---|---|---|
committer | Rui Matos <tiagomatos@gmail.com> | 2016-04-22 16:44:31 +0200 |
commit | 2d2835f02a80cc34feb5c4384a6a75c2406d4381 (patch) | |
tree | b3c362ca6331b664524796ad04f7bd6e910875c1 /cogl | |
parent | e6b14a36c55ecc3b077b5c9d21d1ad6d493f438d (diff) | |
download | mutter-2d2835f02a80cc34feb5c4384a6a75c2406d4381.tar.gz |
move everything into a cogl/ directory
Diffstat (limited to 'cogl')
-rw-r--r-- | cogl/.gitignore | 107 | ||||
-rw-r--r-- | cogl/Makefile.am | 560 | ||||
-rw-r--r-- | cogl/build/autotools/Makefile.am.enums | 52 | ||||
-rw-r--r-- | cogl/build/autotools/as-compiler-flag.m4 | 62 | ||||
-rw-r--r-- | cogl/build/autotools/introspection.m4 | 94 | ||||
-rw-r--r-- | cogl/cogl-gles2/GLES2/gl2.h | 169 | ||||
-rw-r--r-- | cogl/cogl-gles2/GLES2/gl2ext.h | 1498 | ||||
-rw-r--r-- | cogl/cogl-gles2/GLES2/gl2platform.h | 28 | ||||
-rw-r--r-- | cogl/cogl-gles2/Makefile.am | 31 | ||||
-rw-r--r-- | cogl/cogl-gles2/cogl-gles2-api.c | 1048 | ||||
-rw-r--r-- | cogl/cogl-gles2/mutter-cogl-gles2-1.0.pc.in | 13 | ||||
-rw-r--r-- | cogl/cogl-pango/Makefile.am | 109 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-display-list.c | 499 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-display-list.h | 84 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-fontmap.c | 184 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-glyph-cache.c | 433 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-glyph-cache.h | 100 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-pipeline-cache.c | 242 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-pipeline-cache.h | 72 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-private.h | 65 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango-render.c | 929 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango.h | 298 | ||||
-rw-r--r-- | cogl/cogl-pango/cogl-pango.symbols | 12 | ||||
-rw-r--r-- | cogl/cogl-pango/mutter-cogl-pango-1.0.pc.in | 13 | ||||
-rw-r--r-- | cogl/cogl-path/Makefile.am | 104 | ||||
-rw-r--r-- | cogl/cogl-path/cogl-path-enum-types.c.in | 50 | ||||
-rw-r--r-- | cogl/cogl-path/cogl-path-enum-types.h.in | 25 | ||||
-rw-r--r-- | cogl/cogl-path/cogl-path-private.h | 126 | ||||
-rw-r--r-- | cogl/cogl-path/cogl-path-types.h | 85 | ||||
-rw-r--r-- | cogl/cogl-path/cogl-path.c | 1602 | ||||
-rw-r--r-- | cogl/cogl-path/cogl-path.h | 68 | ||||
-rw-r--r-- | cogl/cogl-path/cogl-path.symbols | 59 | ||||
-rw-r--r-- | cogl/cogl-path/cogl1-path-functions.h | 467 | ||||
-rw-r--r-- | cogl/cogl-path/cogl1-path.c | 353 | ||||
-rw-r--r-- | cogl/cogl-path/cogl2-path-functions.h | 545 | ||||
-rw-r--r-- | cogl/cogl-path/mutter-cogl-path-1.0.pc.in | 13 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/GL/glu.h | 47 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/README | 446 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/dict-list.h | 100 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/dict.c | 111 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/dict.h | 100 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/geom.c | 264 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/geom.h | 84 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/gluos.h | 1 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/memalloc.h | 49 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/mesh.c | 798 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/mesh.h | 266 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/normal.c | 257 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/normal.h | 45 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/priorityq-heap.c | 256 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/priorityq-heap.h | 107 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/priorityq-sort.h | 117 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/priorityq.c | 261 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/priorityq.h | 117 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/render.c | 502 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/render.h | 52 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/sweep.c | 1361 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/sweep.h | 77 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/tess.c | 632 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/tess.h | 165 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/tesselator.h | 122 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/tessmono.c | 201 | ||||
-rw-r--r-- | cogl/cogl-path/tesselator/tessmono.h | 71 | ||||
-rw-r--r-- | cogl/cogl/Makefile.am | 547 | ||||
-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.h | 32 | ||||
-rw-r--r-- | cogl/configure.ac | 1036 | ||||
-rw-r--r-- | cogl/test-fixtures/Makefile.am | 21 | ||||
-rw-r--r-- | cogl/test-fixtures/test-unit.h | 31 | ||||
-rw-r--r-- | cogl/test-fixtures/test-utils.c | 535 | ||||
-rw-r--r-- | cogl/test-fixtures/test-utils.h | 287 | ||||
-rw-r--r-- | cogl/tests/Makefile.am | 31 | ||||
-rw-r--r-- | cogl/tests/README | 63 | ||||
-rw-r--r-- | cogl/tests/config.env.in | 3 | ||||
-rw-r--r-- | cogl/tests/conform/Makefile.am | 176 | ||||
-rw-r--r-- | cogl/tests/conform/test-alpha-test.c | 73 | ||||
-rw-r--r-- | cogl/tests/conform/test-alpha-textures.c | 123 | ||||
-rw-r--r-- | cogl/tests/conform/test-atlas-migration.c | 145 | ||||
-rw-r--r-- | cogl/tests/conform/test-backface-culling.c | 311 | ||||
-rw-r--r-- | cogl/tests/conform/test-blend-strings.c | 430 | ||||
-rw-r--r-- | cogl/tests/conform/test-blend.c | 64 | ||||
-rw-r--r-- | cogl/tests/conform/test-color-hsl.c | 45 | ||||
-rw-r--r-- | cogl/tests/conform/test-color-mask.c | 110 | ||||
-rw-r--r-- | cogl/tests/conform/test-conform-main.c | 157 | ||||
-rw-r--r-- | cogl/tests/conform/test-copy-replace-texture.c | 120 | ||||
-rw-r--r-- | cogl/tests/conform/test-custom-attributes.c | 301 | ||||
-rw-r--r-- | cogl/tests/conform/test-depth-test.c | 301 | ||||
-rw-r--r-- | cogl/tests/conform/test-euler-quaternion.c | 81 | ||||
-rw-r--r-- | cogl/tests/conform/test-fence.c | 63 | ||||
-rw-r--r-- | cogl/tests/conform/test-fixed.c | 18 | ||||
-rw-r--r-- | cogl/tests/conform/test-fixtures.c | 12 | ||||
-rw-r--r-- | cogl/tests/conform/test-framebuffer-get-bits.c | 40 | ||||
-rw-r--r-- | cogl/tests/conform/test-gles2-context.c | 962 | ||||
-rw-r--r-- | cogl/tests/conform/test-just-vertex-shader.c | 205 | ||||
-rw-r--r-- | cogl/tests/conform/test-layer-remove.c | 145 | ||||
-rw-r--r-- | cogl/tests/conform/test-map-buffer-range.c | 123 | ||||
-rw-r--r-- | cogl/tests/conform/test-materials.c | 253 | ||||
-rw-r--r-- | cogl/tests/conform/test-multitexture.c | 206 | ||||
-rw-r--r-- | cogl/tests/conform/test-no-gl-header.c | 16 | ||||
-rw-r--r-- | cogl/tests/conform/test-npot-texture.c | 170 | ||||
-rw-r--r-- | cogl/tests/conform/test-object.c | 86 | ||||
-rw-r--r-- | cogl/tests/conform/test-offscreen.c | 199 | ||||
-rw-r--r-- | cogl/tests/conform/test-path-clip.c | 68 | ||||
-rw-r--r-- | cogl/tests/conform/test-path.c | 215 | ||||
-rw-r--r-- | cogl/tests/conform/test-pipeline-cache-unrefs-texture.c | 91 | ||||
-rw-r--r-- | cogl/tests/conform/test-pipeline-shader-state.c | 93 | ||||
-rw-r--r-- | cogl/tests/conform/test-pipeline-uniforms.c | 415 | ||||
-rw-r--r-- | cogl/tests/conform/test-pipeline-user-matrix.c | 140 | ||||
-rw-r--r-- | cogl/tests/conform/test-pixel-buffer.c | 269 | ||||
-rw-r--r-- | cogl/tests/conform/test-point-size-attribute.c | 166 | ||||
-rw-r--r-- | cogl/tests/conform/test-point-size.c | 99 | ||||
-rw-r--r-- | cogl/tests/conform/test-point-sprite.c | 194 | ||||
-rw-r--r-- | cogl/tests/conform/test-premult.c | 301 | ||||
-rw-r--r-- | cogl/tests/conform/test-primitive-and-journal.c | 122 | ||||
-rw-r--r-- | cogl/tests/conform/test-primitive.c | 334 | ||||
-rw-r--r-- | cogl/tests/conform/test-read-texture-formats.c | 222 | ||||
-rw-r--r-- | cogl/tests/conform/test-readpixels.c | 178 | ||||
-rw-r--r-- | cogl/tests/conform/test-snippets.c | 815 | ||||
-rw-r--r-- | cogl/tests/conform/test-sparse-pipeline.c | 62 | ||||
-rw-r--r-- | cogl/tests/conform/test-sub-texture.c | 325 | ||||
-rw-r--r-- | cogl/tests/conform/test-texture-3d.c | 274 | ||||
-rw-r--r-- | cogl/tests/conform/test-texture-get-set-data.c | 144 | ||||
-rw-r--r-- | cogl/tests/conform/test-texture-mipmaps.c | 136 | ||||
-rw-r--r-- | cogl/tests/conform/test-texture-no-allocate.c | 80 | ||||
-rw-r--r-- | cogl/tests/conform/test-texture-pixmap-x11.c | 245 | ||||
-rw-r--r-- | cogl/tests/conform/test-texture-rectangle.c | 276 | ||||
-rw-r--r-- | cogl/tests/conform/test-texture-rg.c | 74 | ||||
-rw-r--r-- | cogl/tests/conform/test-version.c | 85 | ||||
-rw-r--r-- | cogl/tests/conform/test-vertex-buffer-contiguous.c | 257 | ||||
-rw-r--r-- | cogl/tests/conform/test-vertex-buffer-interleved.c | 162 | ||||
-rw-r--r-- | cogl/tests/conform/test-vertex-buffer-mutability.c | 198 | ||||
-rw-r--r-- | cogl/tests/conform/test-viewport.c | 416 | ||||
-rw-r--r-- | cogl/tests/conform/test-wrap-modes.c | 296 | ||||
-rw-r--r-- | cogl/tests/conform/test-wrap-rectangle-textures.c | 175 | ||||
-rw-r--r-- | cogl/tests/conform/test-write-texture-formats.c | 184 | ||||
-rw-r--r-- | cogl/tests/data/Makefile.am | 3 | ||||
-rw-r--r-- | cogl/tests/data/valgrind.suppressions | 173 | ||||
-rw-r--r-- | cogl/tests/micro-perf/Makefile.am | 24 | ||||
-rw-r--r-- | cogl/tests/micro-perf/test-journal.c | 190 | ||||
-rwxr-xr-x | cogl/tests/run-tests.sh | 157 | ||||
-rwxr-xr-x | cogl/tests/test-launcher.sh | 39 | ||||
-rw-r--r-- | cogl/tests/unit/Makefile.am | 83 | ||||
-rw-r--r-- | cogl/tests/unit/test-unit-main.c | 45 |
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; +} |